mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7824039e3 | ||
|
|
bb9247e821 | ||
|
|
4bc04ec031 | ||
|
|
8fd91e6c5c | ||
|
|
ee137d086a | ||
|
|
fcd81850cb | ||
|
|
aa4b07d024 | ||
|
|
16a096d288 | ||
|
|
b219b2a71b | ||
|
|
ce70242c35 | ||
|
|
dec01e2611 | ||
|
|
4373d89661 | ||
|
|
c73290eebb | ||
|
|
a022f9c2e1 | ||
|
|
5adb25a695 | ||
|
|
08c2972cf9 | ||
|
|
8132c7e676 | ||
|
|
8c68c9f703 | ||
|
|
000b6142fd | ||
|
|
c203ded1cd | ||
|
|
64c5c39b2a | ||
|
|
a8d2a1e371 | ||
|
|
9e5846b24a | ||
|
|
836ff9122c | ||
|
|
75d836358b | ||
|
|
bb11e7f90c | ||
|
|
cf6a71ab86 | ||
|
|
7f7288937d | ||
|
|
a38f9c2183 | ||
|
|
7ee880cadc | ||
|
|
9ae34d474b | ||
|
|
2817e2f2c8 | ||
|
|
02886a09d3 | ||
|
|
0b9d827ad6 | ||
|
|
ab3ea84d70 | ||
|
|
03a1c44659 | ||
|
|
53364444fd | ||
|
|
94040e8551 | ||
|
|
34d46ee28e |
26
README.md
26
README.md
@@ -1,26 +1,12 @@
|
||||

|
||||
|
||||
[DCS World](https://www.digitalcombatsimulator.com/en/products/world/) single-player dynamic campaign.
|
||||
[DCS World](https://www.digitalcombatsimulator.com/en/products/world/) single-player semi dynamic campaign.
|
||||
|
||||
Uses [pydcs](http://github.com/pydcs/dcs) for mission generation.
|
||||
DCS Liberation uses [pydcs](http://github.com/pydcs/dcs) for mission generation
|
||||
and [Mist](https://github.com/mrSkortch/MissionScriptingTools) for mission scripting
|
||||
|
||||
## Tutorials
|
||||
* [Manual](https://github.com/shdwp/dcs_liberation/wiki/Manual)
|
||||
## Resources
|
||||
|
||||
You should start with the manual, it covers everything you need to know before playing the campaign.
|
||||
* [Getting Started](https://github.com/Khopa/dcs_liberation/wiki/Getting-started)
|
||||
|
||||
* [Strike objectives reference images](https://imgur.com/a/vCSHa9f)
|
||||
|
||||
If you can't find the strike objective you can see here how it's supposed to look.
|
||||
|
||||
* [Troubleshooting](https://github.com/shdwp/dcs_liberation/wiki/Troubleshooting)
|
||||
|
||||
You could also briefly check the troubleshooting page to get familiar with the known issues that you could probably fix by yourself.
|
||||
|
||||
* [Modding tutorial](https://github.com/shdwp/dcs_liberation/wiki/Modding-tutorial)
|
||||
|
||||
Modding tutorial will cover how to change default loadouts, configure which planes are present in the campaign (or add new altogether) and more. Check this out if you find that something is not going for your liking, there could be a tutorial for changing that. Although be aware that it would require changing source files and could easily result in non functioning application.
|
||||
|
||||
* [Development guide](https://github.com/shdwp/dcs_liberation/wiki/Development-guide)
|
||||
|
||||
If you want to contribute to the project, this will give you a brief overview and on how to actually run it from source files.
|
||||
* [Tutorials](https://github.com/Khopa/dcs_liberation/wiki/Tutorial-01-:-UI)
|
||||
|
||||
57
changelog.md
Normal file
57
changelog.md
Normal file
@@ -0,0 +1,57 @@
|
||||
#2.0 RC 7
|
||||
|
||||
##Features/Improvements :
|
||||
* **[Units/Factions]** Added P-47D-30 for factions allies_1944
|
||||
* **[Units/Factions]** Replaced S3-B Tanker by KC130 for most factions
|
||||
* **[Mission Generator]** AI Flight generator has been reworked
|
||||
* **[Mission Generator]** Add PP points for JF-17 on STRIKE missions
|
||||
* **[Mission Generator]** Add ST point for F-14B on STRIKE missions
|
||||
* **[Mission Generator]** Flights with client slots will never be delayed
|
||||
* **[Mission Generator]** AI units can start from parking (Added a new setting)
|
||||
* **[Mission Generator]** Tacan for carrier will only be in Mode X from now
|
||||
* **[Mission Generator]** RTB waypoints for autogenerated flights
|
||||
* **[Info Panel]** Added information about destroyed buildings in info panel
|
||||
* **[Info Panel]** Added information about destroyed units at SAM site in info panel
|
||||
* **[Info Panel]** Added information about units destroyed outside the frontline in the debriefing window
|
||||
* **[Info Panel]** Added information about buildings destroyed in the debriefing window
|
||||
* **[Map]** Tooltip now contains the list of building for Strike targets on the map
|
||||
* **[Map]** Added "Oil derrick" building
|
||||
* **[Misc]** Made it possible to setup DCS Saved Games directory and DCS installation directory manually
|
||||
|
||||
##Fixed issues :
|
||||
* **[Mission Generator]** When playing as RED the activation trigger would not be properly generated
|
||||
* **[Mission Generator]** Changed "strike" payload for Su-24M that was innefective
|
||||
* **[Mission Generator]** Changed "strike" payload for JF-17 to use LS-6 bombs instead of GBU
|
||||
* **[Mission Generator]** FW-190A8 is now properly considered as a flyable
|
||||
* **[Maps/Campaign]** Now using Vasiani airport instead of Soganlung in North Caucasus campaign (More parking slots)
|
||||
* **[Info Panel]** Message displayed on base capture event stated that the ennemy captured an airbase, while it was the player who captured it.
|
||||
* **[Map]** Graphical glitch on map when one building of an objective was destroyed, but not the others
|
||||
* **[Map]** Change power station template. (Buildings could end up superposed).
|
||||
|
||||
#2.0 RC 6
|
||||
|
||||
Saves file from RC5 are not compatible with the new version.
|
||||
Sorry :(
|
||||
|
||||
##Features/Improvements :
|
||||
* **[Units/Factions]** Supercarrier support (You have to go to settings to enable it, if you have the supercarrier module)
|
||||
* **[Units/Factions]** Added 'Modern Bluefor' factions, containing all most popular DCS flyable units
|
||||
* **[Units/Factions]** Factions US 2005 / 1990 will now sometimes have Arleigh Burke class ships instead of Perry as carrier escorts
|
||||
* **[Units/Factions]** Added support for newest WW2 Units
|
||||
* **[Campaign logic]** When a base is captured, refill the "base defenses" group with units for the new owner.
|
||||
* **[Mission Generator]** Carrier ICLS channel will now be configured (check your briefing)
|
||||
* **[Mission Generator]** SAM units will spawn on RED Alarm state
|
||||
* **[Mission Generator]** AI Flight planner now creates its own STRIKE flights
|
||||
* **[Mission Generator]** AI units assigned to Strike flight will now actually engage the buildings they have been assigned.
|
||||
* **[Mission Generator]** Added performance settings to allow disabling : smoke, artillery strike, moving units, infantry, SAM Red alert mode.
|
||||
* **[Mission Generator]** Using Late Activation & Trigger in attempt to improve performance & reduce stutter (Previously they were spawned through 'ETA' feature)
|
||||
* **[UX]** : Improved flight selection behaviour in the Mission Planning Window
|
||||
|
||||
##Fixed issues :
|
||||
* **[Mission Generator]** Payloads were not correctly assigned in the release version.
|
||||
* **[Mission Generator]** Game generation does not work when "no night mission" settings was selected and the current time was "day"
|
||||
* **[Mission Generator]** Game generation does not work when the player selected faction has no AWACS
|
||||
* **[Mission Generator]** Planned flights will spawn even if their home base has been captured or is being contested by enemy ground units.
|
||||
* **[Campaign Generator]** Base defenses would not be generated on Normandy map and in some rare cases on others maps as well
|
||||
* **[Mission Planning]** CAS waypoints created from the "Predefined waypoint selector" would not be at the exact location of the frontline
|
||||
* **[Naming]** CAP mission flown from airbase are not named BARCAP anymore (CAP from carrier is still named BARCAP)
|
||||
145
game/db.py
145
game/db.py
@@ -44,6 +44,7 @@ from game.factions.usa_1960 import USA_1960
|
||||
from game.factions.usa_1965 import USA_1965
|
||||
from game.factions.usa_1990 import USA_1990
|
||||
from game.factions.usa_2005 import USA_2005
|
||||
from game.factions.bluefor_modern import BLUEFOR_MODERN
|
||||
|
||||
"""
|
||||
---------- BEGINNING OF CONFIGURATION SECTION
|
||||
@@ -83,11 +84,14 @@ PRICES = {
|
||||
J_11A: 26,
|
||||
JF_17: 20,
|
||||
Su_30: 24,
|
||||
SpitfireLFMkIX:3,
|
||||
SpitfireLFMkIXCW:3,
|
||||
Bf_109K_4:3,
|
||||
FW_190D9:3,
|
||||
FW_190A8:3,
|
||||
|
||||
SpitfireLFMkIX: 8,
|
||||
SpitfireLFMkIXCW: 8,
|
||||
Bf_109K_4: 8,
|
||||
FW_190D9: 8,
|
||||
FW_190A8: 8,
|
||||
A_20G: 12,
|
||||
Ju_88A4: 12,
|
||||
|
||||
F_5E_3: 8,
|
||||
MiG_15bis: 4,
|
||||
@@ -146,18 +150,20 @@ PRICES = {
|
||||
S_3B_Tanker: 13,
|
||||
IL_78M: 13,
|
||||
KC_135: 13,
|
||||
KC130: 13,
|
||||
|
||||
A_50: 8,
|
||||
E_3A: 8,
|
||||
C_130: 8,
|
||||
|
||||
# WW2
|
||||
P_51D_30_NA: 3,
|
||||
P_51D: 3,
|
||||
P_51D_30_NA: 6,
|
||||
P_51D: 6,
|
||||
P_47D_30: 6,
|
||||
|
||||
# armor
|
||||
Armor.APC_MTLB: 4,
|
||||
Armor.ARV_MTLB_U_BOMAN: 5,
|
||||
Armor.FDDM_Grad: 5,
|
||||
Armor.ARV_BRDM_2: 6,
|
||||
Armor.ARV_BTR_RD: 8,
|
||||
Armor.APC_BTR_80: 8,
|
||||
@@ -227,22 +233,31 @@ PRICES = {
|
||||
AirDefence.SAM_Chaparral_M48: 10,
|
||||
|
||||
# WW2
|
||||
Armor.MT_Pz_Kpfw_V_Panther_Ausf_G:7,
|
||||
Armor.MT_Pz_Kpfw_IV_Ausf_H:4,
|
||||
Armor.HT_Pz_Kpfw_VI_Tiger_I:10,
|
||||
Armor.HT_Pz_Kpfw_VI_Ausf__B__Tiger_II:12,
|
||||
Armor.APC_Sd_Kfz_251:3,
|
||||
Armor.IFV_Sd_Kfz_234_2_Puma:4,
|
||||
Armor.MT_M4_Sherman:4,
|
||||
Armor.MT_M4A4_Sherman_Firefly:6,
|
||||
Armor.MT_Pz_Kpfw_V_Panther_Ausf_G:18,
|
||||
Armor.MT_Pz_Kpfw_IV_Ausf_H:8,
|
||||
Armor.HT_Pz_Kpfw_VI_Tiger_I:22,
|
||||
Armor.HT_Pz_Kpfw_VI_Ausf__B__Tiger_II:26,
|
||||
Armor.TD_Jagdpanther_G1: 16,
|
||||
Armor.TD_Jagdpanzer_IV: 10,
|
||||
Armor.Sd_Kfz_184_Elefant: 18,
|
||||
Armor.APC_Sd_Kfz_251:2,
|
||||
Armor.IFV_Sd_Kfz_234_2_Puma:6,
|
||||
Armor.MT_M4_Sherman:5,
|
||||
Armor.MT_M4A4_Sherman_Firefly:8,
|
||||
Armor.CT_Cromwell_IV:8,
|
||||
Armor.M30_Cargo_Carrier:2,
|
||||
Armor.APC_M2A1:2,
|
||||
AirDefence.AAA_Bofors_40mm:4,
|
||||
AirDefence.AAA_Flak_36:6,
|
||||
AirDefence.AAA_Flak_18:4,
|
||||
Artillery.M12_GMC:2,
|
||||
Artillery.Sturmpanzer_IV_Brummbär:2,
|
||||
Armor.ST_Centaur_IV: 8,
|
||||
Armor.HIT_Churchill_VII: 12,
|
||||
Armor.LAC_M8_Greyhound: 4,
|
||||
Armor.TD_M10_GMC: 8,
|
||||
Armor.StuG_III_Ausf__G: 6,
|
||||
AirDefence.AAA_Bofors_40mm: 4,
|
||||
AirDefence.AAA_8_8cm_Flak_36: 6,
|
||||
AirDefence.AAA_8_8cm_Flak_18: 4,
|
||||
Artillery.M12_GMC: 2,
|
||||
Artillery.Sturmpanzer_IV_Brummbär: 2,
|
||||
|
||||
|
||||
# ship
|
||||
CV_1143_5_Admiral_Kuznetsov: 100,
|
||||
@@ -299,7 +314,7 @@ UNIT_BY_TASK = {
|
||||
FW_190D9,
|
||||
FW_190A8,
|
||||
SpitfireLFMkIXCW,
|
||||
SpitfireLFMkIX
|
||||
SpitfireLFMkIX,
|
||||
],
|
||||
CAS: [
|
||||
F_86F_Sabre,
|
||||
@@ -330,6 +345,9 @@ UNIT_BY_TASK = {
|
||||
Mi_28N,
|
||||
Mi_24V,
|
||||
MiG_27K,
|
||||
A_20G,
|
||||
P_47D_30,
|
||||
Ju_88A4,
|
||||
],
|
||||
Transport: [
|
||||
IL_76MD,
|
||||
@@ -342,6 +360,7 @@ UNIT_BY_TASK = {
|
||||
Refueling: [
|
||||
IL_78M,
|
||||
KC_135,
|
||||
KC130,
|
||||
S_3B_Tanker,
|
||||
],
|
||||
AWACS: [E_3A, A_50, ],
|
||||
@@ -351,11 +370,11 @@ UNIT_BY_TASK = {
|
||||
Armor.APC_MTLB,
|
||||
Armor.APC_MTLB,
|
||||
Armor.APC_MTLB,
|
||||
Armor.ARV_MTLB_U_BOMAN,
|
||||
Armor.ARV_MTLB_U_BOMAN,
|
||||
Armor.ARV_MTLB_U_BOMAN,
|
||||
Armor.ARV_MTLB_U_BOMAN,
|
||||
Armor.ARV_MTLB_U_BOMAN,
|
||||
Armor.FDDM_Grad,
|
||||
Armor.FDDM_Grad,
|
||||
Armor.FDDM_Grad,
|
||||
Armor.FDDM_Grad,
|
||||
Armor.FDDM_Grad,
|
||||
Armor.ARV_BRDM_2,
|
||||
Armor.ARV_BRDM_2,
|
||||
Armor.ARV_BRDM_2,
|
||||
@@ -450,6 +469,33 @@ UNIT_BY_TASK = {
|
||||
Armor.APC_M2A1,
|
||||
Armor.APC_M2A1,
|
||||
Armor.APC_M2A1,
|
||||
Armor.MT_Pz_Kpfw_V_Panther_Ausf_G,
|
||||
Armor.MT_Pz_Kpfw_IV_Ausf_H,
|
||||
Armor.HT_Pz_Kpfw_VI_Tiger_I,
|
||||
Armor.HT_Pz_Kpfw_VI_Ausf__B__Tiger_II,
|
||||
Armor.TD_Jagdpanther_G1,
|
||||
Armor.TD_Jagdpanzer_IV,
|
||||
Armor.Sd_Kfz_184_Elefant,
|
||||
Armor.APC_Sd_Kfz_251,
|
||||
Armor.IFV_Sd_Kfz_234_2_Puma,
|
||||
Armor.MT_M4_Sherman,
|
||||
Armor.MT_M4A4_Sherman_Firefly,
|
||||
Armor.CT_Cromwell_IV,
|
||||
Armor.M30_Cargo_Carrier,
|
||||
Armor.M30_Cargo_Carrier,
|
||||
Armor.M30_Cargo_Carrier,
|
||||
Armor.APC_M2A1,
|
||||
Armor.APC_M2A1,
|
||||
Armor.ST_Centaur_IV,
|
||||
Armor.ST_Centaur_IV,
|
||||
Armor.HIT_Churchill_VII,
|
||||
Armor.LAC_M8_Greyhound,
|
||||
Armor.LAC_M8_Greyhound,
|
||||
Armor.TD_M10_GMC,
|
||||
Armor.TD_M10_GMC,
|
||||
Armor.StuG_III_Ausf__G,
|
||||
Artillery.M12_GMC,
|
||||
Artillery.Sturmpanzer_IV_Brummbär,
|
||||
|
||||
Artillery.MLRS_M270,
|
||||
Artillery.SPH_M109_Paladin,
|
||||
@@ -534,6 +580,7 @@ SAM_CONVERT = {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
"""
|
||||
Units that will always be spawned in the air
|
||||
"""
|
||||
@@ -568,9 +615,10 @@ FACTIONS = {
|
||||
"USA 1965": USA_1965,
|
||||
"USA 1960": USA_1960,
|
||||
"USA 1955 (Require WW2 Pack)": USA_1955,
|
||||
"USA 1944 (Require WW2 Pack)": USA_1944,
|
||||
"France 1995": France_1995,
|
||||
"Allies 1944 (Require WW2 Pack)": USA_1944,
|
||||
"Bluefor Modern": BLUEFOR_MODERN,
|
||||
"France 2005": France_2005,
|
||||
"France 1995": France_1995,
|
||||
"Germany 1990": Germany_1990,
|
||||
"Netherlands 1990": Netherlands_1990,
|
||||
"United Kingdown 1990": UnitedKingdom_1990,
|
||||
@@ -637,7 +685,15 @@ PLANE_PAYLOAD_OVERRIDES = {
|
||||
AntishipStrike: "ANTISHIP",
|
||||
GroundAttack: "STRIKE"
|
||||
},
|
||||
|
||||
F_A_18C: {
|
||||
CAP: "CAP HEAVY",
|
||||
Intercept: "CAP HEAVY",
|
||||
CAS: "CAS MAVERICK F",
|
||||
PinpointStrike: "STRIKE",
|
||||
SEAD: "SEAD",
|
||||
AntishipStrike: "ANTISHIP",
|
||||
GroundAttack: "STRIKE"
|
||||
},
|
||||
A_10A: COMMON_OVERRIDE,
|
||||
A_10C: COMMON_OVERRIDE,
|
||||
AV8BNA: COMMON_OVERRIDE,
|
||||
@@ -741,7 +797,8 @@ TIME_PERIODS = {
|
||||
|
||||
REWARDS = {
|
||||
"power": 4, "warehouse": 2, "fuel": 2, "ammo": 2,
|
||||
"farp": 1, "fob": 1, "factory": 10, "comms": 10, "oil": 10
|
||||
"farp": 1, "fob": 1, "factory": 10, "comms": 10, "oil": 10,
|
||||
"derrick": 8
|
||||
}
|
||||
|
||||
# Base post-turn bonus value
|
||||
@@ -797,6 +854,21 @@ TaskForceDict = typing.Dict[typing.Type[Task], AssignedUnitsDict]
|
||||
StartingPosition = typing.Optional[typing.Union[ShipGroup, StaticGroup, Airport, Point]]
|
||||
|
||||
|
||||
def upgrade_to_supercarrier(unit, name: str):
|
||||
if unit == CVN_74_John_C__Stennis:
|
||||
if name == "CVN-71 Theodore Roosevelt":
|
||||
return CVN_71_Theodore_Roosevelt
|
||||
elif name == "CVN-72 Abraham Lincoln":
|
||||
return CVN_72_Abraham_Lincoln
|
||||
elif name == "CVN-73 George Washington":
|
||||
return CVN_73_George_Washington
|
||||
else:
|
||||
return CVN_71_Theodore_Roosevelt
|
||||
elif unit == CV_1143_5_Admiral_Kuznetsov:
|
||||
return CV_1143_5_Admiral_Kuznetsov_2017
|
||||
else:
|
||||
return unit
|
||||
|
||||
def unit_task(unit: UnitType) -> Task:
|
||||
for task, units in UNIT_BY_TASK.items():
|
||||
if unit in units:
|
||||
@@ -962,14 +1034,6 @@ def _validate_db():
|
||||
assert unit_type not in total_set, "{} is duplicate for task {}".format(unit_type, t)
|
||||
total_set.add(unit_type)
|
||||
|
||||
# check country allegiance
|
||||
for unit_type in total_set:
|
||||
did_find = False
|
||||
for country_units_list in FACTIONS.values():
|
||||
if unit_type in country_units_list["units"]:
|
||||
did_find = True
|
||||
print("WARN : {} not in country list".format(unit_type))
|
||||
|
||||
# check prices
|
||||
for unit_type in total_set:
|
||||
assert unit_type in PRICES, "{} not in prices".format(unit_type)
|
||||
@@ -982,4 +1046,5 @@ class DefaultLiveries:
|
||||
|
||||
OH_58D.Liveries = DefaultLiveries
|
||||
F_16C_50.Liveries = DefaultLiveries
|
||||
P_51D_30_NA.Liveries = DefaultLiveries
|
||||
P_51D_30_NA.Liveries = DefaultLiveries
|
||||
Ju_88A4.Liveries = DefaultLiveries
|
||||
@@ -13,6 +13,7 @@ from theater import *
|
||||
from gen.environmentgen import EnvironmentSettings
|
||||
from gen.conflictgen import Conflict
|
||||
from game.db import assigned_units_from, unitdict_from
|
||||
from theater.start_generator import generate_airbase_defense_group
|
||||
|
||||
from userdata.debriefing import Debriefing
|
||||
from userdata import persistency
|
||||
@@ -126,17 +127,6 @@ class Event:
|
||||
self.operation.current_mission.save(persistency.mission_path_for("liberation_nextturn.miz"))
|
||||
self.environment_settings = self.operation.environment_settings
|
||||
|
||||
def generate_quick(self):
|
||||
pass
|
||||
# TODO : This is not needed anymore. The player can start mission in flight from the flight planner if he want it to be quick.
|
||||
# TODO : remove this method
|
||||
#self.operation.is_awacs_enabled = self.is_awacs_enabled
|
||||
#self.operation.environment_settings = self.environment_settings
|
||||
#
|
||||
#self.operation.prepare(self.game.theater.terrain, is_quick=True)
|
||||
#self.operation.generate()
|
||||
#self.operation.current_mission.save(persistency.mission_path_for("liberation_nextturn_quick.miz"))
|
||||
|
||||
def commit(self, debriefing: Debriefing):
|
||||
|
||||
logging.info("Commiting mission results")
|
||||
@@ -189,16 +179,30 @@ class Event:
|
||||
logging.info("cp {} killing ground object {}".format(cp, ground_object.string_identifier))
|
||||
cp.ground_objects[i].is_dead = True
|
||||
|
||||
info = Information("Building destroyed",
|
||||
ground_object.dcs_identifier + " has been destroyed at location " + ground_object.obj_name,
|
||||
self.game.turn)
|
||||
self.game.informations.append(info)
|
||||
|
||||
|
||||
# -- AA Site groups
|
||||
destroyed_units = 0
|
||||
info = Information("Units destroyed at " + ground_object.obj_name,
|
||||
"",
|
||||
self.game.turn)
|
||||
for i, ground_object in enumerate(cp.ground_objects):
|
||||
if ground_object.dcs_identifier in ["AA", "CARRIER", "LHA"]:
|
||||
for g in ground_object.groups:
|
||||
for u in g.units:
|
||||
if u.name == destroyed_ground_unit_name:
|
||||
g.units.remove(u)
|
||||
destroyed_units = destroyed_units + 1
|
||||
info.text = u.type
|
||||
ucount = sum([len(g.units) for g in ground_object.groups])
|
||||
if ucount == 0:
|
||||
ground_object.is_dead = True
|
||||
if destroyed_units > 0:
|
||||
self.game.informations.append(info)
|
||||
|
||||
# ------------------------------
|
||||
# Captured bases
|
||||
@@ -212,30 +216,40 @@ class Event:
|
||||
id = int(captured.split("||")[0])
|
||||
new_owner_coalition = int(captured.split("||")[1])
|
||||
|
||||
captured_cps = []
|
||||
for cp in self.game.theater.controlpoints:
|
||||
if cp.id == id:
|
||||
|
||||
if cp.captured and new_owner_coalition != coalition:
|
||||
cp.captured = False
|
||||
cp.base.aircraft = {}
|
||||
cp.base.armor = {}
|
||||
cp.base.aa = {}
|
||||
for g in cp.ground_objects:
|
||||
g.groups = []
|
||||
info = Information(cp.name + " lost !",
|
||||
"The ennemy took control of " + cp.name + "\nShame on us !",
|
||||
self.game.turn)
|
||||
info = Information(cp.name + " lost !", "The ennemy took control of " + cp.name + "\nShame on us !", self.game.turn)
|
||||
self.game.informations.append(info)
|
||||
pname = self.game.enemy_name
|
||||
captured_cps.append(cp)
|
||||
elif not(cp.captured) and new_owner_coalition == coalition:
|
||||
cp.captured = True
|
||||
cp.base.aircraft = {}
|
||||
cp.base.armor = {}
|
||||
cp.base.aa = {}
|
||||
for g in cp.ground_objects:
|
||||
g.groups = []
|
||||
info = Information(cp.name + " captured !",
|
||||
"The ennemy took control of " + cp.name + "\nShame on us !",
|
||||
self.game.turn)
|
||||
info = Information(cp.name + " captured !", "We took control of " + cp.name + "! Great job !", self.game.turn)
|
||||
self.game.informations.append(info)
|
||||
pname = self.game.player_name
|
||||
captured_cps.append(cp)
|
||||
else:
|
||||
continue
|
||||
|
||||
cp.base.aircraft = {}
|
||||
cp.base.armor = {}
|
||||
|
||||
airbase_def_id = 0
|
||||
for g in cp.ground_objects:
|
||||
g.groups = []
|
||||
if g.airbase_group and pname != "":
|
||||
generate_airbase_defense_group(airbase_def_id, g, pname, self.game, cp)
|
||||
airbase_def_id = airbase_def_id + 1
|
||||
|
||||
for cp in captured_cps:
|
||||
logging.info("Will run redeploy for " + cp.name)
|
||||
self.redeploy_units(cp)
|
||||
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
@@ -313,6 +327,47 @@ class Event:
|
||||
def skip(self):
|
||||
pass
|
||||
|
||||
def redeploy_units(self, cp):
|
||||
""""
|
||||
Auto redeploy units to newly captured base
|
||||
"""
|
||||
|
||||
ally_connected_cps = [ocp for ocp in cp.connected_points if cp.captured == ocp.captured]
|
||||
enemy_connected_cps = [ocp for ocp in cp.connected_points if cp.captured != ocp.captured]
|
||||
|
||||
# If the newly captured cp does not have enemy connected cp,
|
||||
# then it is not necessary to redeploy frontline units there.
|
||||
if len(enemy_connected_cps) == 0:
|
||||
return
|
||||
else:
|
||||
# From each ally cp, send reinforcements
|
||||
for ally_cp in ally_connected_cps:
|
||||
total_units_redeployed = 0
|
||||
own_enemy_cp = [ocp for ocp in ally_cp.connected_points if ally_cp.captured != ocp.captured]
|
||||
|
||||
moved_units = {}
|
||||
|
||||
# If the connected base, does not have any more enemy cp connected.
|
||||
# Or if it is not the opponent redeploying forces there (enemy AI will never redeploy all their forces at once)
|
||||
if len(own_enemy_cp) > 0 or not cp.captured:
|
||||
for frontline_unit, count in ally_cp.base.armor.items():
|
||||
moved_units[frontline_unit] = int(count/2)
|
||||
total_units_redeployed = total_units_redeployed + int(count/2)
|
||||
else: # So if the old base, does not have any more enemy cp connected, or if it is an enemy base
|
||||
for frontline_unit, count in ally_cp.base.armor.items():
|
||||
moved_units[frontline_unit] = count
|
||||
total_units_redeployed = total_units_redeployed + count
|
||||
|
||||
cp.base.commision_units(moved_units)
|
||||
ally_cp.base.commit_losses(moved_units)
|
||||
|
||||
if total_units_redeployed > 0:
|
||||
info = Information("Units redeployed", "", self.game.turn)
|
||||
info.text = str(total_units_redeployed) + " units have been redeployed from " + ally_cp.name + " to " + cp.name
|
||||
self.game.informations.append(info)
|
||||
logging.info(info.text)
|
||||
|
||||
|
||||
|
||||
class UnitsDeliveryEvent(Event):
|
||||
informational = True
|
||||
|
||||
78
game/factions/bluefor_modern.py
Normal file
78
game/factions/bluefor_modern.py
Normal file
@@ -0,0 +1,78 @@
|
||||
from dcs.vehicles import *
|
||||
from dcs.ships import *
|
||||
from dcs.planes import *
|
||||
from dcs.helicopters import *
|
||||
|
||||
BLUEFOR_MODERN = {
|
||||
"country": "USA",
|
||||
"side": "blue",
|
||||
"units": [
|
||||
|
||||
F_15C,
|
||||
F_14B,
|
||||
FA_18C_hornet,
|
||||
F_16C_50,
|
||||
JF_17,
|
||||
M_2000C,
|
||||
F_5E_3,
|
||||
Su_27,
|
||||
|
||||
Su_25T,
|
||||
A_10A,
|
||||
A_10C,
|
||||
AV8BNA,
|
||||
AJS37,
|
||||
|
||||
KC_135,
|
||||
KC130,
|
||||
C_130,
|
||||
E_3A,
|
||||
|
||||
UH_1H,
|
||||
AH_64D,
|
||||
Ka_50,
|
||||
|
||||
Armor.MBT_M1A2_Abrams,
|
||||
Armor.MBT_Leopard_2,
|
||||
Armor.ATGM_M1134_Stryker,
|
||||
Armor.IFV_M2A2_Bradley,
|
||||
Armor.IFV_Marder,
|
||||
Armor.APC_M1043_HMMWV_Armament,
|
||||
|
||||
Artillery.MLRS_M270,
|
||||
Artillery.SPH_M109_Paladin,
|
||||
|
||||
Unarmed.Transport_M818,
|
||||
Infantry.Infantry_M4,
|
||||
Infantry.Soldier_M249,
|
||||
|
||||
AirDefence.SAM_Hawk_PCP,
|
||||
AirDefence.SAM_Patriot_EPP_III,
|
||||
|
||||
CVN_74_John_C__Stennis,
|
||||
LHA_1_Tarawa,
|
||||
Armed_speedboat,
|
||||
], "shorad": [
|
||||
AirDefence.SAM_Avenger_M1097,
|
||||
], "aircraft_carrier": [
|
||||
CVN_74_John_C__Stennis,
|
||||
], "helicopter_carrier": [
|
||||
LHA_1_Tarawa,
|
||||
], "destroyer": [
|
||||
Oliver_Hazzard_Perry_class,
|
||||
USS_Arleigh_Burke_IIa,
|
||||
], "cruiser": [
|
||||
Ticonderoga_class,
|
||||
], "carrier_names": [
|
||||
"CVN-71 Theodore Roosevelt",
|
||||
"CVN-72 Abraham Lincoln",
|
||||
"CVN-73 George Washington",
|
||||
"CVN-74 John C. Stennis",
|
||||
], "lhanames": [
|
||||
"LHA-1 Tarawa",
|
||||
"LHA-2 Saipan",
|
||||
"LHA-3 Belleau Wood",
|
||||
"LHA-4 Nassau",
|
||||
"LHA-5 Peleliu"
|
||||
]
|
||||
}
|
||||
@@ -11,7 +11,7 @@ France_1995 = {
|
||||
Mirage_2000_5,
|
||||
|
||||
KC_135,
|
||||
S_3B_Tanker,
|
||||
KC130,
|
||||
C_130,
|
||||
E_3A,
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ France_2005 = {
|
||||
FA_18C_hornet, # Standing as Rafale M
|
||||
|
||||
KC_135,
|
||||
S_3B_Tanker,
|
||||
KC130,
|
||||
C_130,
|
||||
E_3A,
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ Germany_1944 = {
|
||||
FW_190A8,
|
||||
FW_190D9,
|
||||
Bf_109K_4,
|
||||
Ju_88A4,
|
||||
|
||||
Armor.MT_Pz_Kpfw_V_Panther_Ausf_G,
|
||||
Armor.MT_Pz_Kpfw_IV_Ausf_H,
|
||||
@@ -16,13 +17,20 @@ Germany_1944 = {
|
||||
Armor.HT_Pz_Kpfw_VI_Ausf__B__Tiger_II,
|
||||
Armor.APC_Sd_Kfz_251,
|
||||
Armor.IFV_Sd_Kfz_234_2_Puma,
|
||||
Armor.Sd_Kfz_184_Elefant,
|
||||
Armor.TD_Jagdpanther_G1,
|
||||
Armor.TD_Jagdpanzer_IV,
|
||||
|
||||
Artillery.Sturmpanzer_IV_Brummbär,
|
||||
|
||||
Unarmed.Sd_Kfz_2,
|
||||
Unarmed.Sd_Kfz_7,
|
||||
Unarmed.Kübelwagen_82,
|
||||
|
||||
Infantry.Infantry_Mauser_98,
|
||||
|
||||
AirDefence.AAA_Flak_36,
|
||||
AirDefence.AAA_8_8cm_Flak_36,
|
||||
],
|
||||
"shorad":[
|
||||
AirDefence.AAA_8_8cm_Flak_36,
|
||||
]
|
||||
}
|
||||
@@ -12,7 +12,7 @@ Germany_1990 = {
|
||||
F_4E,
|
||||
|
||||
KC_135,
|
||||
S_3B_Tanker,
|
||||
KC130,
|
||||
C_130,
|
||||
E_3A,
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ India_2010 = {
|
||||
Su_30,
|
||||
|
||||
KC_135,
|
||||
S_3B_Tanker,
|
||||
KC130,
|
||||
C_130,
|
||||
E_3A,
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ Israel_2000 = {
|
||||
F_4E,
|
||||
|
||||
KC_135,
|
||||
S_3B_Tanker,
|
||||
KC130,
|
||||
C_130,
|
||||
E_3A,
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ Lybia_2011 = {
|
||||
AirDefence.HQ_7_Self_Propelled_LN,
|
||||
|
||||
Armor.IFV_BMP_1,
|
||||
Armor.ARV_MTLB_U_BOMAN,
|
||||
Armor.FDDM_Grad,
|
||||
Armor.ARV_BRDM_2,
|
||||
Armor.MBT_T_55,
|
||||
Armor.MBT_T_72B,
|
||||
|
||||
@@ -11,7 +11,7 @@ Netherlands_1990 = {
|
||||
F_5E_3,
|
||||
|
||||
KC_135,
|
||||
S_3B_Tanker,
|
||||
KC130,
|
||||
C_130,
|
||||
E_3A,
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ Russia_1955 = {
|
||||
AirDefence.AAA_ZU_23_Closed,
|
||||
AirDefence.AAA_ZU_23_on_Ural_375,
|
||||
Armor.ARV_BRDM_2,
|
||||
Armor.ARV_MTLB_U_BOMAN,
|
||||
Armor.FDDM_Grad,
|
||||
Armor.APC_MTLB,
|
||||
Armor.MBT_T_55,
|
||||
Artillery.MLRS_BM_21_Grad,
|
||||
|
||||
@@ -12,7 +12,7 @@ Spain_1990 = {
|
||||
C_101CC,
|
||||
|
||||
KC_135,
|
||||
S_3B_Tanker,
|
||||
KC130,
|
||||
C_130,
|
||||
E_3A,
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ Turkey_2005 = {
|
||||
F_4E,
|
||||
|
||||
KC_135,
|
||||
S_3B_Tanker,
|
||||
KC130,
|
||||
C_130,
|
||||
E_3A,
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ UAE_2005 = {
|
||||
F_16C_50,
|
||||
|
||||
KC_135,
|
||||
S_3B_Tanker,
|
||||
KC130,
|
||||
C_130,
|
||||
E_3A,
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ UnitedKingdom_1990 = {
|
||||
F_4E,
|
||||
|
||||
KC_135,
|
||||
S_3B_Tanker,
|
||||
KC130,
|
||||
C_130,
|
||||
E_3A,
|
||||
|
||||
|
||||
@@ -8,17 +8,25 @@ USA_1944 = {
|
||||
"units": [
|
||||
P_51D,
|
||||
P_51D_30_NA,
|
||||
P_47D_30,
|
||||
SpitfireLFMkIX,
|
||||
SpitfireLFMkIXCW,
|
||||
A_20G,
|
||||
|
||||
Armor.MT_M4_Sherman,
|
||||
Armor.MT_M4A4_Sherman_Firefly,
|
||||
Armor.CT_Cromwell_IV,
|
||||
Armor.M30_Cargo_Carrier,
|
||||
Armor.APC_M2A1,
|
||||
Armor.CT_Cromwell_IV,
|
||||
Armor.ST_Centaur_IV,
|
||||
Armor.HIT_Churchill_VII,
|
||||
Armor.LAC_M8_Greyhound,
|
||||
Armor.TD_M10_GMC,
|
||||
Artillery.M12_GMC,
|
||||
|
||||
Infantry.Infantry_M1_Garand,
|
||||
Infantry.Infantry_SMLE_No_4_Mk_1,
|
||||
|
||||
LS_Samuel_Chase,
|
||||
LST_Mk_II,
|
||||
@@ -26,5 +34,7 @@ USA_1944 = {
|
||||
|
||||
Unarmed.CCKW_353,
|
||||
AirDefence.AAA_Bofors_40mm,
|
||||
], "shorad":[
|
||||
AirDefence.AAA_Bofors_40mm,
|
||||
]
|
||||
}
|
||||
@@ -11,7 +11,7 @@ USA_1955 = {
|
||||
P_51D,
|
||||
|
||||
KC_135,
|
||||
S_3B_Tanker,
|
||||
KC130,
|
||||
C_130,
|
||||
E_3A,
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ USA_1960 = {
|
||||
P_51D,
|
||||
|
||||
KC_135,
|
||||
S_3B_Tanker,
|
||||
KC130,
|
||||
C_130,
|
||||
E_3A,
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ USA_1965 = {
|
||||
F_4E,
|
||||
|
||||
KC_135,
|
||||
S_3B_Tanker,
|
||||
KC130,
|
||||
C_130,
|
||||
E_3A,
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ USA_1990 = {
|
||||
B_1B,
|
||||
|
||||
KC_135,
|
||||
S_3B_Tanker,
|
||||
KC130,
|
||||
C_130,
|
||||
E_3A,
|
||||
|
||||
@@ -46,6 +46,7 @@ USA_1990 = {
|
||||
LHA_1_Tarawa,
|
||||
], "destroyer": [
|
||||
Oliver_Hazzard_Perry_class,
|
||||
USS_Arleigh_Burke_IIa,
|
||||
], "cruiser": [
|
||||
Ticonderoga_class,
|
||||
], "carrier_names": [
|
||||
|
||||
@@ -12,12 +12,11 @@ USA_2005 = {
|
||||
FA_18C_hornet,
|
||||
F_16C_50,
|
||||
JF_17,
|
||||
|
||||
A_10C,
|
||||
AV8BNA,
|
||||
|
||||
KC_135,
|
||||
S_3B_Tanker,
|
||||
KC130,
|
||||
C_130,
|
||||
E_3A,
|
||||
|
||||
@@ -53,11 +52,13 @@ USA_2005 = {
|
||||
LHA_1_Tarawa,
|
||||
], "destroyer": [
|
||||
Oliver_Hazzard_Perry_class,
|
||||
USS_Arleigh_Burke_IIa,
|
||||
], "cruiser": [
|
||||
Ticonderoga_class,
|
||||
], "carrier_names": [
|
||||
"CVN-71 Theodore Roosevelt",
|
||||
"CVN-72 Abraham Lincoln",
|
||||
"CVN-73 Georges Washington",
|
||||
"CVN-73 George Washington",
|
||||
"CVN-74 John C. Stennis",
|
||||
], "lhanames": [
|
||||
"LHA-1 Tarawa",
|
||||
|
||||
36
game/game.py
36
game/game.py
@@ -1,24 +1,11 @@
|
||||
import logging
|
||||
import typing
|
||||
import random
|
||||
import math
|
||||
|
||||
from dcs.task import *
|
||||
from dcs.vehicles import *
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from game.db import REWARDS, PLAYER_BUDGET_BASE
|
||||
from game.game_stats import GameStats
|
||||
from game.infos.information import Information
|
||||
from gen.conflictgen import Conflict
|
||||
from gen.flights.ai_flight_planner import FlightPlanner
|
||||
from gen.ground_forces.ai_ground_planner import GroundPlanner
|
||||
from userdata.debriefing import Debriefing
|
||||
from theater import *
|
||||
|
||||
from . import db
|
||||
from .settings import Settings
|
||||
from .event import *
|
||||
from datetime import datetime, timedelta
|
||||
from .settings import Settings
|
||||
|
||||
COMMISION_UNIT_VARIETY = 4
|
||||
COMMISION_LIMITS_SCALE = 1.5
|
||||
@@ -158,11 +145,8 @@ class Game:
|
||||
|
||||
def initiate_event(self, event: Event):
|
||||
assert event in self.events
|
||||
|
||||
logging.info("Generating {} (regular)".format(event))
|
||||
event.generate()
|
||||
logging.info("Generating {} (quick)".format(event))
|
||||
event.generate_quick()
|
||||
|
||||
def finish_event(self, event: Event, debriefing: Debriefing):
|
||||
logging.info("Finishing event {}".format(event))
|
||||
@@ -181,6 +165,18 @@ class Game:
|
||||
else:
|
||||
return event.name == self.player_name
|
||||
|
||||
def get_player_coalition_id(self):
|
||||
if self.player_country in db.BLUEFOR_FACTIONS:
|
||||
return 2
|
||||
else:
|
||||
return 1
|
||||
|
||||
def get_enemy_coalition_id(self):
|
||||
if self.get_player_coalition_id() == 1:
|
||||
return 2
|
||||
else:
|
||||
return 1
|
||||
|
||||
def pass_turn(self, no_action=False, ignored_cps: typing.Collection[ControlPoint] = None):
|
||||
logging.info("Pass turn")
|
||||
self.informations.append(Information("End of turn #" + str(self.turn), "-" * 40, 0))
|
||||
@@ -230,6 +226,10 @@ class Game:
|
||||
self.ground_planners[cp.id] = gplanner
|
||||
|
||||
def _enemy_reinforcement(self):
|
||||
"""
|
||||
Compute and commision reinforcement for enemy bases
|
||||
"""
|
||||
|
||||
MAX_ARMOR = 30 * self.settings.multiplier
|
||||
MAX_AIRCRAFT = 25 * self.settings.multiplier
|
||||
|
||||
|
||||
@@ -47,11 +47,9 @@ class GameStats:
|
||||
for cp in game.theater.controlpoints:
|
||||
if cp.captured:
|
||||
turn_data.allied_units.aircraft_count += sum(cp.base.aircraft.values())
|
||||
turn_data.allied_units.sam_count += sum(cp.base.aa.values())
|
||||
turn_data.allied_units.vehicles_count += sum(cp.base.armor.values())
|
||||
else:
|
||||
turn_data.enemy_units.aircraft_count += sum(cp.base.aircraft.values())
|
||||
turn_data.enemy_units.sam_count += sum(cp.base.aa.values())
|
||||
turn_data.enemy_units.vehicles_count += sum(cp.base.armor.values())
|
||||
|
||||
self.data_per_turn.append(turn_data)
|
||||
|
||||
@@ -64,7 +64,7 @@ class Operation:
|
||||
def initialize(self, mission: Mission, conflict: Conflict):
|
||||
self.current_mission = mission
|
||||
self.conflict = conflict
|
||||
self.airgen = AircraftConflictGenerator(mission, conflict, self.game.settings)
|
||||
self.airgen = AircraftConflictGenerator(mission, conflict, self.game.settings, self.game)
|
||||
self.shipgen = ShipGenerator(mission, conflict)
|
||||
self.airsupportgen = AirSupportConflictGenerator(mission, conflict, self.game)
|
||||
self.triggersgen = TriggersGenerator(mission, conflict, self.game)
|
||||
@@ -172,7 +172,8 @@ class Operation:
|
||||
self.forcedoptionsgen.generate()
|
||||
|
||||
# Generate Visuals Smoke Effects
|
||||
self.visualgen.generate()
|
||||
if self.game.settings.perf_smoke_gen:
|
||||
self.visualgen.generate()
|
||||
|
||||
# Inject Lua Scripts
|
||||
load_mist = TriggerStart(comment="Load Mist Lua Framework")
|
||||
@@ -198,8 +199,6 @@ class Operation:
|
||||
self.briefinggen.append_frequency("AWACS", "133 MHz AM")
|
||||
|
||||
self.briefinggen.append_frequency("Flight", "251 MHz AM")
|
||||
if self.departure_cp.is_global or self.conflict.to_cp.is_global:
|
||||
self.briefinggen.append_frequency("Carrier", "20X/ICLS CHAN1")
|
||||
|
||||
# Generate the briefing
|
||||
self.briefinggen.generate()
|
||||
|
||||
@@ -1,14 +1,26 @@
|
||||
|
||||
class Settings:
|
||||
|
||||
# Difficulty settings
|
||||
player_skill = "Good"
|
||||
enemy_skill = "Average"
|
||||
enemy_vehicle_skill = "Average"
|
||||
map_coalition_visibility = "All Units"
|
||||
labels = "Full"
|
||||
only_player_takeoff = True
|
||||
only_player_takeoff = True # Legacy parameter do not use
|
||||
night_disabled = False
|
||||
supercarrier = False
|
||||
multiplier = 1
|
||||
sams = True
|
||||
cold_start = False
|
||||
sams = True # Legacy parameter do not use
|
||||
cold_start = False # Legacy parameter do not use
|
||||
version = None
|
||||
|
||||
# Performance oriented
|
||||
perf_red_alert_state = True
|
||||
perf_smoke_gen = True
|
||||
perf_artillery = True
|
||||
perf_moving_units = True
|
||||
perf_infantry = True
|
||||
perf_ai_parking_start = True
|
||||
|
||||
|
||||
|
||||
523
gen/aircraft.py
523
gen/aircraft.py
@@ -1,21 +1,16 @@
|
||||
import logging
|
||||
|
||||
from dcs.action import ActivateGroup, AITaskPush
|
||||
from dcs.condition import TimeAfter, CoalitionHasAirdrome
|
||||
from dcs.helicopters import UH_1H
|
||||
from dcs.terrain.terrain import NoParkingSlotError
|
||||
from dcs.triggers import TriggerOnce, Event
|
||||
|
||||
from game import db
|
||||
from game.settings import Settings
|
||||
from gen.flights.ai_flight_planner import FlightPlanner
|
||||
from gen.flights.flight import Flight, FlightType
|
||||
from gen.flights.ai_flight_planner import FlightPlanner, CAP_DEFAULT_ENGAGE_DISTANCE, nm_to_meter
|
||||
from gen.flights.flight import Flight, FlightType, FlightWaypointType
|
||||
from .conflictgen import *
|
||||
from .naming import *
|
||||
from .triggergen import TRIGGER_WAYPOINT_OFFSET
|
||||
|
||||
from dcs.mission import *
|
||||
from dcs.unitgroup import *
|
||||
from dcs.unittype import *
|
||||
from dcs.task import *
|
||||
from dcs.terrain.terrain import NoParkingSlotError, RunwayOccupiedError
|
||||
|
||||
SPREAD_DISTANCE_FACTOR = 1, 2
|
||||
ESCORT_ENGAGEMENT_MAX_DIST = 100000
|
||||
WORKAROUND_WAYP_DIST = 1000
|
||||
@@ -46,8 +41,9 @@ INTERCEPT_MAX_DISTANCE = 200000
|
||||
class AircraftConflictGenerator:
|
||||
escort_targets = [] # type: typing.List[typing.Tuple[FlyingGroup, int]]
|
||||
|
||||
def __init__(self, mission: Mission, conflict: Conflict, settings: Settings):
|
||||
def __init__(self, mission: Mission, conflict: Conflict, settings: Settings, game):
|
||||
self.m = mission
|
||||
self.game = game
|
||||
self.settings = settings
|
||||
self.conflict = conflict
|
||||
self.escort_targets = []
|
||||
@@ -55,33 +51,6 @@ class AircraftConflictGenerator:
|
||||
def _start_type(self) -> StartType:
|
||||
return self.settings.cold_start and StartType.Cold or StartType.Warm
|
||||
|
||||
def _group_point(self, point) -> Point:
|
||||
distance = randint(
|
||||
int(self.conflict.size * SPREAD_DISTANCE_FACTOR[0]),
|
||||
int(self.conflict.size * SPREAD_DISTANCE_FACTOR[1]),
|
||||
)
|
||||
return point.random_point_within(distance, self.conflict.size * SPREAD_DISTANCE_FACTOR[0])
|
||||
|
||||
def _split_to_groups(self, dict: db.PlaneDict, clients: db.PlaneDict = None) -> typing.Collection[typing.Tuple[FlyingType, int, int]]:
|
||||
for flying_type, count in dict.items():
|
||||
if clients:
|
||||
client_count = clients.get(flying_type, 0)
|
||||
else:
|
||||
client_count = 0
|
||||
|
||||
if flying_type == F_14B:
|
||||
# workaround since 2 and 3 tomcat collide on carrier
|
||||
group_size = 2
|
||||
else:
|
||||
group_size = 4
|
||||
|
||||
while count > 0:
|
||||
group_size = min(count, group_size)
|
||||
client_size = max(min(client_count, group_size), 0)
|
||||
|
||||
yield (flying_type, group_size, client_size)
|
||||
count -= group_size
|
||||
client_count -= client_size
|
||||
|
||||
def _setup_group(self, group: FlyingGroup, for_task: typing.Type[Task], client_count: int):
|
||||
did_load_loadout = False
|
||||
@@ -255,37 +224,6 @@ class AircraftConflictGenerator:
|
||||
else:
|
||||
assert False
|
||||
|
||||
def _generate_escort(self, side: Country, units: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition, cp, is_quick=False, should_orbit=False):
|
||||
groups = []
|
||||
for flying_type, count, client_count in self._split_to_groups(units, clients):
|
||||
group = self._generate_group(
|
||||
name=namegen.next_unit_name(side, cp.id, flying_type),
|
||||
side=side,
|
||||
unit_type=flying_type,
|
||||
count=count,
|
||||
client_count=client_count,
|
||||
at=at)
|
||||
|
||||
group.task = Escort.name
|
||||
self._setup_group(group, CAP, client_count)
|
||||
|
||||
for escorted_group, waypoint_index in self.escort_targets:
|
||||
waypoint_index += 1
|
||||
if not is_quick:
|
||||
waypoint_index += TRIGGER_WAYPOINT_OFFSET
|
||||
|
||||
group.points[0].tasks.append(EscortTaskAction(escorted_group.id, engagement_max_dist=ESCORT_ENGAGEMENT_MAX_DIST, lastwpt=waypoint_index))
|
||||
|
||||
if should_orbit:
|
||||
orbit_task = ControlledTask(OrbitAction(ATTACK_CIRCLE_ALT, pattern=OrbitAction.OrbitPattern.Circle))
|
||||
orbit_task.stop_after_duration(ATTACK_CIRCLE_DURATION * 60)
|
||||
|
||||
orbit_waypoint = self._add_radio_waypoint(group, self.conflict.position, CAS_ALTITUDE)
|
||||
orbit_waypoint.tasks.append(orbit_task)
|
||||
orbit_waypoint.tasks.append(EngageTargets(max_distance=DEFENCE_ENGAGEMENT_MAX_DISTANCE))
|
||||
|
||||
groups.append(group)
|
||||
return groups
|
||||
|
||||
def _setup_custom_payload(self, flight, group:FlyingGroup):
|
||||
if flight.use_custom_loadout:
|
||||
@@ -307,47 +245,56 @@ class AircraftConflictGenerator:
|
||||
|
||||
def generate_flights(self, cp, country, flight_planner:FlightPlanner):
|
||||
|
||||
for flight in flight_planner.interceptor_flights:
|
||||
group = self.generate_planned_flight(cp, country, flight)
|
||||
self.setup_group_as_intercept_flight(group, flight)
|
||||
self._setup_custom_payload(flight, group)
|
||||
|
||||
for flight in flight_planner.cap_flights:
|
||||
group = self.generate_planned_flight(cp, country, flight)
|
||||
self.setup_group_as_cap_flight(group, flight)
|
||||
self._setup_custom_payload(flight, group)
|
||||
|
||||
for flight in flight_planner.cas_flights:
|
||||
group = self.generate_planned_flight(cp, country, flight)
|
||||
self.setup_group_as_cas_flight(group, flight)
|
||||
self._setup_custom_payload(flight, group)
|
||||
|
||||
for flight in flight_planner.sead_flights:
|
||||
group = self.generate_planned_flight(cp, country, flight)
|
||||
self.setup_group_as_sead_flight(group, flight)
|
||||
self._setup_custom_payload(flight, group)
|
||||
|
||||
for flight in flight_planner.custom_flights:
|
||||
for flight in flight_planner.flights:
|
||||
group = self.generate_planned_flight(cp, country, flight)
|
||||
if flight.flight_type == FlightType.INTERCEPTION:
|
||||
self.setup_group_as_intercept_flight(group, flight)
|
||||
elif flight.flight_type in [FlightType.CAP, FlightType.TARCAP, FlightType.BARCAP]:
|
||||
self.setup_group_as_cap_flight(group, flight)
|
||||
elif flight.flight_type in [FlightType.CAS, FlightType.BAI]:
|
||||
self.setup_group_as_cas_flight(group, flight)
|
||||
elif flight.flight_type in [FlightType.STRIKE]:
|
||||
self.setup_group_as_strike_flight(group, flight)
|
||||
elif flight.flight_type in [FlightType.ANTISHIP]:
|
||||
self.setup_group_as_antiship_flight(group, flight)
|
||||
elif flight.flight_type in [FlightType.SEAD, FlightType.DEAD]:
|
||||
self.setup_group_as_sead_flight(group, flight)
|
||||
self._setup_custom_payload(flight, group)
|
||||
else:
|
||||
self.setup_group_as_cap_flight(group, flight)
|
||||
self._setup_custom_payload(flight, group)
|
||||
self.setup_flight_group(group, flight, flight.flight_type)
|
||||
self.setup_group_activation_trigger(flight, group)
|
||||
|
||||
|
||||
def setup_group_activation_trigger(self, flight, group):
|
||||
if flight.scheduled_in > 0 and flight.client_count == 0:
|
||||
|
||||
if flight.start_type != "In Flight":
|
||||
group.late_activation = False
|
||||
group.uncontrolled = True
|
||||
|
||||
activation_trigger = TriggerOnce(Event.NoEvent, "LiberationControlTriggerForGroup" + str(group.id))
|
||||
activation_trigger.add_condition(TimeAfter(seconds=flight.scheduled_in * 60))
|
||||
if (flight.from_cp.cptype == ControlPointType.AIRBASE):
|
||||
if flight.from_cp.captured:
|
||||
activation_trigger.add_condition(
|
||||
CoalitionHasAirdrome(self.game.get_player_coalition_id(), flight.from_cp.id))
|
||||
else:
|
||||
activation_trigger.add_condition(
|
||||
CoalitionHasAirdrome(self.game.get_enemy_coalition_id(), flight.from_cp.id))
|
||||
|
||||
group.add_trigger_action(StartCommand())
|
||||
activation_trigger.add_action(AITaskPush(group.id, len(group.tasks)))
|
||||
self.m.triggerrules.triggers.append(activation_trigger)
|
||||
else:
|
||||
group.late_activation = True
|
||||
activation_trigger = TriggerOnce(Event.NoEvent, "LiberationActivationTriggerForGroup" + str(group.id))
|
||||
activation_trigger.add_condition(TimeAfter(seconds=flight.scheduled_in*60))
|
||||
|
||||
if(flight.from_cp.cptype == ControlPointType.AIRBASE):
|
||||
if flight.from_cp.captured:
|
||||
activation_trigger.add_condition(CoalitionHasAirdrome(self.game.get_player_coalition_id(), flight.from_cp.id))
|
||||
else:
|
||||
activation_trigger.add_condition(CoalitionHasAirdrome(self.game.get_enemy_coalition_id(), flight.from_cp.id))
|
||||
|
||||
activation_trigger.add_action(ActivateGroup(group.id))
|
||||
self.m.triggerrules.triggers.append(activation_trigger)
|
||||
|
||||
def generate_planned_flight(self, cp, country, flight:Flight):
|
||||
try:
|
||||
if flight.start_type == "In Flight" or flight.client_count == 0:
|
||||
if flight.client_count == 0 and self.game.settings.perf_ai_parking_start:
|
||||
flight.start_type = "Warm"
|
||||
|
||||
if flight.start_type == "In Flight":
|
||||
group = self._generate_group(
|
||||
name=namegen.next_unit_name(country, cp.id, flight.unit_type),
|
||||
side=country,
|
||||
@@ -356,7 +303,6 @@ class AircraftConflictGenerator:
|
||||
client_count=0,
|
||||
at=cp.position)
|
||||
else:
|
||||
|
||||
st = StartType.Runway
|
||||
if flight.start_type == "Cold":
|
||||
st = StartType.Cold
|
||||
@@ -383,6 +329,7 @@ class AircraftConflictGenerator:
|
||||
start_type=st)
|
||||
except Exception:
|
||||
# Generated when there is no place on Runway or on Parking Slots
|
||||
flight.start_type = "In Flight"
|
||||
group = self._generate_group(
|
||||
name=namegen.next_unit_name(country, cp.id, flight.unit_type),
|
||||
side=country,
|
||||
@@ -391,7 +338,6 @@ class AircraftConflictGenerator:
|
||||
client_count=0,
|
||||
at=cp.position)
|
||||
group.points[0].alt = 1500
|
||||
group.points[0].ETA = flight.scheduled_in * 60
|
||||
|
||||
return group
|
||||
|
||||
@@ -403,53 +349,75 @@ class AircraftConflictGenerator:
|
||||
group.add_waypoint(Point(point.x,point.y), point.alt)
|
||||
|
||||
|
||||
def setup_group_as_cap_flight(self, group, flight):
|
||||
self._setup_group(group, CAP, flight.client_count)
|
||||
for point in flight.points:
|
||||
group.add_waypoint(Point(point.x,point.y), point.alt)
|
||||
def setup_flight_group(self, group, flight, flight_type):
|
||||
|
||||
def setup_group_as_cas_flight(self, group, flight):
|
||||
group.task = CAS.name
|
||||
self._setup_group(group, CAS, flight.client_count)
|
||||
if flight_type in [FlightType.CAP, FlightType.BARCAP, FlightType.TARCAP]:
|
||||
group.task = CAP.name
|
||||
self._setup_group(group, CAP, flight.client_count)
|
||||
# group.points[0].tasks.clear()
|
||||
# group.tasks.clear()
|
||||
# group.tasks.append(EngageTargets(max_distance=40, targets=[Targets.All.Air]))
|
||||
# group.tasks.append(EngageTargets(max_distance=nm_to_meter(120), targets=[Targets.All.Air]))
|
||||
pass
|
||||
elif flight_type in [FlightType.CAS, FlightType.BAI]:
|
||||
group.task = CAS.name
|
||||
self._setup_group(group, CAS, flight.client_count)
|
||||
group.points[0].tasks.clear()
|
||||
group.points[0].tasks.append(CASTaskAction())
|
||||
group.points[0].tasks.append(OptReactOnThreat(OptReactOnThreat.Values.EvadeFire))
|
||||
group.points[0].tasks.append(OptROE(OptROE.Values.OpenFireWeaponFree))
|
||||
elif flight_type in [FlightType.SEAD, FlightType.DEAD]:
|
||||
group.task = SEAD.name
|
||||
self._setup_group(group, SEAD, flight.client_count)
|
||||
group.points[0].tasks.clear()
|
||||
group.points[0].tasks.append(SEADTaskAction())
|
||||
group.points[0].tasks.append(OptReactOnThreat(OptReactOnThreat.Values.EvadeFire))
|
||||
group.points[0].tasks.append(OptROE(OptROE.Values.OpenFireWeaponFree))
|
||||
group.points[0].tasks.append(OptRestrictJettison(True))
|
||||
elif flight_type in [FlightType.STRIKE]:
|
||||
group.task = PinpointStrike.name
|
||||
self._setup_group(group, GroundAttack, flight.client_count)
|
||||
group.points[0].tasks.clear()
|
||||
group.points[0].tasks.append(OptReactOnThreat(OptReactOnThreat.Values.EvadeFire))
|
||||
group.points[0].tasks.append(OptROE(OptROE.Values.OpenFire))
|
||||
group.points[0].tasks.append(OptRestrictJettison(True))
|
||||
elif flight_type in [FlightType.ANTISHIP]:
|
||||
group.task = AntishipStrike.name
|
||||
self._setup_group(group, AntishipStrike, flight.client_count)
|
||||
group.points[0].tasks.clear()
|
||||
group.points[0].tasks.append(OptReactOnThreat(OptReactOnThreat.Values.EvadeFire))
|
||||
group.points[0].tasks.append(OptROE(OptROE.Values.OpenFire))
|
||||
group.points[0].tasks.append(OptRestrictJettison(True))
|
||||
|
||||
group.points[0].tasks.clear()
|
||||
group.points[0].tasks.append(CASTaskAction())
|
||||
group.points[0].tasks.append(OptReactOnThreat(OptReactOnThreat.Values.EvadeFire))
|
||||
group.points[0].tasks.append(OptROE(OptROE.Values.OpenFireWeaponFree))
|
||||
group.points[0].tasks.append(OptRestrictJettison(True))
|
||||
for i, point in enumerate(flight.points):
|
||||
if not point.only_for_player or (point.only_for_player and flight.client_count > 0):
|
||||
pt = group.add_waypoint(Point(point.x, point.y), point.alt)
|
||||
if point.waypoint_type == FlightWaypointType.PATROL_TRACK:
|
||||
action = OrbitAction(altitude=pt.alt, pattern=OrbitAction.OrbitPattern.RaceTrack)
|
||||
pt.tasks.append(action)
|
||||
#for tgt in point.targets:
|
||||
# if hasattr(tgt, "position"):
|
||||
# engagetgt = EngageTargetsInZone(tgt.position, radius=CAP_DEFAULT_ENGAGE_DISTANCE, targets=[Targets.All.Air])
|
||||
# pt.tasks.append(engagetgt)
|
||||
elif point.waypoint_type == FlightWaypointType.LANDING_POINT:
|
||||
pt.type = "Land"
|
||||
elif point.waypoint_type == FlightWaypointType.INGRESS_STRIKE:
|
||||
print("TGTS :")
|
||||
print(point.targets)
|
||||
for j, t in enumerate(point.targets):
|
||||
print(t.position)
|
||||
pt.tasks.append(Bombing(t.position))
|
||||
if group.units[0].unit_type == JF_17 and j < 4:
|
||||
group.add_nav_target_point(t.position, "PP" + str(j + 1))
|
||||
if group.units[0].unit_type == F_14B and j == 0:
|
||||
group.add_nav_target_point(t.position, "ST")
|
||||
|
||||
for point in flight.points:
|
||||
group.add_waypoint(Point(point.x,point.y), point.alt)
|
||||
if pt is not None:
|
||||
pt.alt_type = point.alt_type
|
||||
pt.name = String(point.name)
|
||||
|
||||
def setup_group_as_sead_flight(self, group, flight):
|
||||
group.task = SEAD.name
|
||||
self._setup_group(group, SEAD, flight.client_count)
|
||||
self._setup_custom_payload(flight, group)
|
||||
|
||||
group.points[0].tasks.clear()
|
||||
group.points[0].tasks.append(SEADTaskAction())
|
||||
group.points[0].tasks.append(OptReactOnThreat(OptReactOnThreat.Values.EvadeFire))
|
||||
group.points[0].tasks.append(OptROE(OptROE.Values.OpenFireWeaponFree))
|
||||
group.points[0].tasks.append(OptRestrictJettison(True))
|
||||
|
||||
i = 1
|
||||
for point in flight.points:
|
||||
group.add_waypoint(Point(point.x,point.y), point.alt)
|
||||
group.points[i].tasks.clear()
|
||||
group.points[i].tasks.append(SEADTaskAction())
|
||||
i = i + 1
|
||||
|
||||
def setup_group_as_strike_flight(self, group, flight):
|
||||
group.task = PinpointStrike.name
|
||||
self._setup_group(group, GroundAttack, flight.client_count)
|
||||
|
||||
group.points[0].tasks.clear()
|
||||
group.points[0].tasks.append(CASTaskAction())
|
||||
group.points[0].tasks.append(OptReactOnThreat(OptReactOnThreat.Values.EvadeFire))
|
||||
group.points[0].tasks.append(OptROE(OptROE.Values.OpenFireWeaponFree))
|
||||
group.points[0].tasks.append(OptRestrictJettison(True))
|
||||
|
||||
for point in flight.points:
|
||||
group.add_waypoint(Point(point.x,point.y), point.alt)
|
||||
|
||||
def setup_group_as_antiship_flight(self, group, flight):
|
||||
group.task = AntishipStrike.name
|
||||
@@ -464,263 +432,4 @@ class AircraftConflictGenerator:
|
||||
for point in flight.points:
|
||||
group.add_waypoint(Point(point.x,point.y), point.alt)
|
||||
|
||||
def generate_cas_strikegroup(self, attackers: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None, escort=True):
|
||||
assert not escort or len(self.escort_targets) == 0
|
||||
|
||||
for flying_type, count, client_count in self._split_to_groups(attackers, clients):
|
||||
group = self._generate_group(
|
||||
name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type),
|
||||
side=self.conflict.attackers_country,
|
||||
unit_type=flying_type,
|
||||
count=count,
|
||||
client_count=client_count,
|
||||
at=at and at or self._group_point(self.conflict.air_attackers_location))
|
||||
|
||||
waypoint = self._add_radio_waypoint(group, self.conflict.position, CAS_ALTITUDE, WARM_START_AIRSPEED)
|
||||
if self.conflict.is_vector:
|
||||
self._add_radio_waypoint(group, self.conflict.tail, CAS_ALTITUDE, WARM_START_AIRSPEED)
|
||||
|
||||
group.task = CAS.name
|
||||
self._setup_group(group, CAS, client_count)
|
||||
if escort:
|
||||
self.escort_targets.append((group, group.points.index(waypoint)))
|
||||
self._rtb_for(group, self.conflict.from_cp, at)
|
||||
|
||||
def generate_ground_attack_strikegroup(self, strikegroup: db.PlaneDict, clients: db.PlaneDict, targets: typing.List[typing.Tuple[str, Point]], at: db.StartingPosition = None, escort=True):
|
||||
assert not escort or len(self.escort_targets) == 0
|
||||
|
||||
for flying_type, count, client_count in self._split_to_groups(strikegroup, clients):
|
||||
group = self._generate_group(
|
||||
name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type),
|
||||
side=self.conflict.attackers_country,
|
||||
unit_type=flying_type,
|
||||
count=count,
|
||||
client_count=client_count,
|
||||
at=at and at or self._group_point(self.conflict.air_attackers_location))
|
||||
|
||||
escort_until_waypoint = None
|
||||
|
||||
for name, pos in targets:
|
||||
waypoint = group.add_waypoint(pos, 0, WARM_START_AIRSPEED, self.m.translation.create_string(name))
|
||||
waypoint.tasks.append(Bombing(pos, attack_qty=2))
|
||||
if escort_until_waypoint is None:
|
||||
escort_until_waypoint = waypoint
|
||||
|
||||
group.task = GroundAttack.name
|
||||
self._setup_group(group, GroundAttack, client_count)
|
||||
if escort:
|
||||
self.escort_targets.append((group, group.points.index(escort_until_waypoint)))
|
||||
self._rtb_for(group, self.conflict.from_cp, at)
|
||||
|
||||
def generate_sead_strikegroup(self, strikegroup: db.PlaneDict, clients: db.PlaneDict, targets: typing.List[typing.Tuple[str, Point]], at: db.StartingPosition, escort=True):
|
||||
assert not escort or len(self.escort_targets) == 0
|
||||
|
||||
for flying_type, count, client_count in self._split_to_groups(strikegroup, clients):
|
||||
group = self._generate_group(
|
||||
name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type),
|
||||
side=self.conflict.attackers_country,
|
||||
unit_type=flying_type,
|
||||
count=count,
|
||||
client_count=client_count,
|
||||
at=at and at or self._group_point(self.conflict.air_attackers_location))
|
||||
|
||||
escort_until_waypoint = None
|
||||
|
||||
for name, pos in targets:
|
||||
waypoint = group.add_waypoint(pos, 0, WARM_START_AIRSPEED, self.m.translation.create_string(name))
|
||||
if escort_until_waypoint is None:
|
||||
escort_until_waypoint = waypoint
|
||||
|
||||
group.task = SEAD.name
|
||||
self._setup_group(group, SEAD, client_count)
|
||||
if escort:
|
||||
self.escort_targets.append((group, group.points.index(escort_until_waypoint)))
|
||||
|
||||
self._rtb_for(group, self.conflict.from_cp, at)
|
||||
|
||||
def generate_defenders_cas(self, defenders: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None, escort=True):
|
||||
assert not escort or len(self.escort_targets) == 0
|
||||
|
||||
for flying_type, count, client_count in self._split_to_groups(defenders, clients):
|
||||
group = self._generate_group(
|
||||
name=namegen.next_unit_name(self.conflict.defenders_country, self.conflict.to_cp.id, flying_type),
|
||||
side=self.conflict.defenders_country,
|
||||
unit_type=flying_type,
|
||||
count=count,
|
||||
client_count=client_count,
|
||||
at=at and at or self._group_point(self.conflict.air_defenders_location))
|
||||
|
||||
location = self._group_point(self.conflict.air_defenders_location)
|
||||
insertion_point = self.conflict.find_insertion_point(location)
|
||||
waypoint = self._add_radio_waypoint(group, insertion_point, CAS_ALTITUDE, WARM_START_AIRSPEED)
|
||||
|
||||
if self.conflict.is_vector:
|
||||
destination_tail = self.conflict.tail.distance_to_point(insertion_point) > self.conflict.position.distance_to_point(insertion_point)
|
||||
self._add_radio_waypoint(group, destination_tail and self.conflict.tail or self.conflict.position, CAS_ALTITUDE, WARM_START_AIRSPEED)
|
||||
|
||||
group.task = CAS.name
|
||||
self._setup_group(group, CAS, client_count)
|
||||
if escort:
|
||||
self.escort_targets.append((group, group.points.index(waypoint)))
|
||||
self._rtb_for(group, self.conflict.to_cp, at)
|
||||
|
||||
def generate_ship_strikegroup(self, attackers: db.PlaneDict, clients: db.PlaneDict, target_groups: typing.Collection[ShipGroup], at: db.StartingPosition = None, escort=True):
|
||||
assert not escort or len(self.escort_targets) == 0
|
||||
|
||||
for flying_type, count, client_count in self._split_to_groups(attackers, clients):
|
||||
group = self._generate_group(
|
||||
name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type),
|
||||
side=self.conflict.attackers_country,
|
||||
unit_type=flying_type,
|
||||
count=count,
|
||||
client_count=client_count,
|
||||
at=at and at or self._group_point(self.conflict.air_attackers_location))
|
||||
|
||||
wayp = self._add_radio_waypoint(group, self.conflict.position, CAS_ALTITUDE, WARM_START_AIRSPEED)
|
||||
for target_group in target_groups:
|
||||
wayp.tasks.append(AttackGroup(target_group.id))
|
||||
|
||||
group.task = AntishipStrike.name
|
||||
self._setup_group(group, AntishipStrike, client_count)
|
||||
if escort:
|
||||
self.escort_targets.append((group, group.points.index(wayp)))
|
||||
self._rtb_for(group, self.conflict.from_cp, at)
|
||||
|
||||
def generate_attackers_escort(self, attackers: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None):
|
||||
for g in self._generate_escort(
|
||||
side=self.conflict.attackers_country,
|
||||
units=attackers,
|
||||
clients=clients,
|
||||
at=at and at or self._group_point(self.conflict.air_attackers_location),
|
||||
is_quick=at is None,
|
||||
cp=self.conflict.from_cp,
|
||||
should_orbit=True):
|
||||
self._rtb_for(g, self.conflict.from_cp, at)
|
||||
|
||||
def generate_defenders_escort(self, escort: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None):
|
||||
for g in self._generate_escort(
|
||||
side=self.conflict.defenders_country,
|
||||
units=escort,
|
||||
clients=clients,
|
||||
at=at and at or self._group_point(self.conflict.air_defenders_location),
|
||||
is_quick=at is None,
|
||||
cp=self.conflict.to_cp,
|
||||
should_orbit=False):
|
||||
self._rtb_for(g, self.conflict.to_cp, at)
|
||||
|
||||
def generate_defense(self, defenders: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None):
|
||||
for flying_type, count, client_count in self._split_to_groups(defenders, clients):
|
||||
group = self._generate_group(
|
||||
name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.to_cp.id, flying_type),
|
||||
side=self.conflict.defenders_country,
|
||||
unit_type=flying_type,
|
||||
count=count,
|
||||
client_count=client_count,
|
||||
at=at and at or self._group_point(self.conflict.air_defenders_location))
|
||||
|
||||
group.task = CAP.name
|
||||
wayp = self._add_radio_waypoint(group, self.conflict.position, CAS_ALTITUDE, WARM_START_AIRSPEED)
|
||||
wayp.tasks.append(dcs.task.EngageTargets(max_distance=DEFENCE_ENGAGEMENT_MAX_DISTANCE))
|
||||
wayp.tasks.append(dcs.task.OrbitAction(ATTACK_CIRCLE_ALT, pattern=OrbitAction.OrbitPattern.Circle))
|
||||
self._setup_group(group, CAP, client_count)
|
||||
self._rtb_for(group, self.conflict.to_cp, at)
|
||||
|
||||
def generate_migcap(self, patrol: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None):
|
||||
for flying_type, count, client_count in self._split_to_groups(patrol, clients):
|
||||
group = self._generate_group(
|
||||
name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type),
|
||||
side=self.conflict.attackers_country,
|
||||
unit_type=flying_type,
|
||||
count=count,
|
||||
client_count=client_count,
|
||||
at=at and at or self._group_point(self.conflict.air_attackers_location))
|
||||
|
||||
waypoint = self._add_radio_waypoint(group, self.conflict.position, WARM_START_ALTITUDE, WARM_START_AIRSPEED)
|
||||
if self.conflict.is_vector:
|
||||
self._add_radio_waypoint(group, self.conflict.tail, WARM_START_ALTITUDE, WARM_START_AIRSPEED)
|
||||
|
||||
group.task = CAP.name
|
||||
self._setup_group(group, CAP, client_count)
|
||||
self._rtb_for(group, self.conflict.from_cp, at)
|
||||
|
||||
def generate_barcap(self, patrol: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None):
|
||||
for flying_type, count, client_count in self._split_to_groups(patrol, clients):
|
||||
group = self._generate_group(
|
||||
name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type),
|
||||
side=self.conflict.defenders_country,
|
||||
unit_type=flying_type,
|
||||
count=count,
|
||||
client_count=client_count,
|
||||
at=at and at or self._group_point(self.conflict.air_defenders_location))
|
||||
|
||||
waypoint = self._add_radio_waypoint(group, self.conflict.position, WARM_START_ALTITUDE, WARM_START_AIRSPEED)
|
||||
if self.conflict.is_vector:
|
||||
self._add_radio_waypoint(group, self.conflict.tail, WARM_START_ALTITUDE, WARM_START_AIRSPEED)
|
||||
else:
|
||||
heading = group.position.heading_between_point(self.conflict.position)
|
||||
waypoint = self._add_radio_waypoint(group, self.conflict.position.point_from_heading(heading, BARCAP_RACETRACK_DISTANCE),
|
||||
WARM_START_ALTITUDE,
|
||||
WARM_START_AIRSPEED)
|
||||
waypoint.tasks.append(OrbitAction(WARM_START_ALTITUDE, WARM_START_AIRSPEED))
|
||||
|
||||
group.task = CAP.name
|
||||
self._setup_group(group, CAP, client_count)
|
||||
self._rtb_for(group, self.conflict.to_cp, at)
|
||||
|
||||
def generate_transport(self, transport: db.PlaneDict, destination: Airport, escort=True):
|
||||
assert not escort or len(self.escort_targets) == 0
|
||||
|
||||
for flying_type, count, client_count in self._split_to_groups(transport):
|
||||
group = self._generate_group(
|
||||
name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type),
|
||||
side=self.conflict.defenders_country,
|
||||
unit_type=flying_type,
|
||||
count=count,
|
||||
client_count=client_count,
|
||||
at=self._group_point(self.conflict.air_defenders_location))
|
||||
|
||||
waypoint = self._rtb_for(group, self.conflict.to_cp)
|
||||
if escort:
|
||||
self.escort_targets.append((group, group.points.index(waypoint)))
|
||||
|
||||
self._add_radio_waypoint(group, destination.position, RTB_ALTITUDE)
|
||||
group.task = Transport.name
|
||||
group.land_at(destination)
|
||||
|
||||
def generate_interception(self, interceptors: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None):
|
||||
for flying_type, count, client_count in self._split_to_groups(interceptors, clients):
|
||||
group = self._generate_group(
|
||||
name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type),
|
||||
side=self.conflict.attackers_country,
|
||||
unit_type=flying_type,
|
||||
count=count,
|
||||
client_count=client_count,
|
||||
at=at and at or self._group_point(self.conflict.air_attackers_location))
|
||||
|
||||
group.task = CAP.name
|
||||
group.points[0].tasks.append(EngageTargets(max_distance=INTERCEPT_MAX_DISTANCE))
|
||||
|
||||
wayp = self._add_radio_waypoint(group, self.conflict.position, WARM_START_ALTITUDE, INTERCEPTION_AIRSPEED)
|
||||
wayp.tasks.append(EngageTargets(max_distance=INTERCEPT_MAX_DISTANCE))
|
||||
|
||||
if self.conflict.is_vector:
|
||||
self._add_radio_waypoint(group, self.conflict.tail, CAS_ALTITUDE, WARM_START_ALTITUDE)
|
||||
|
||||
self._setup_group(group, CAP, client_count)
|
||||
self._rtb_for(group, self.conflict.from_cp, at)
|
||||
|
||||
def generate_passenger_transport(self, helis: db.HeliDict, clients: db.HeliDict, at: db.StartingPosition):
|
||||
for heli_type, count, client_count in self._split_to_groups(helis, clients):
|
||||
group = self._generate_group(
|
||||
name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, heli_type),
|
||||
side=self.conflict.attackers_country,
|
||||
unit_type=heli_type,
|
||||
count=count,
|
||||
client_count=client_count,
|
||||
at=at and at or self._group_point(self.conflict.air_attackers_location)
|
||||
)
|
||||
|
||||
self._add_radio_waypoint(group, self.conflict.position, HELI_ALT)
|
||||
self._setup_group(group, Transport, client_count)
|
||||
|
||||
|
||||
|
||||
@@ -53,17 +53,20 @@ class AirSupportConflictGenerator:
|
||||
tanker_group.points[0].tasks.append(SetImmortalCommand(True))
|
||||
|
||||
if is_awacs_enabled:
|
||||
awacs_unit = db.find_unittype(AWACS, self.conflict.attackers_side)[0]
|
||||
awacs_flight = self.mission.awacs_flight(
|
||||
country=self.mission.country(self.game.player_country),
|
||||
name=namegen.next_awacs_name(self.mission.country(self.game.player_country)),
|
||||
plane_type=awacs_unit,
|
||||
altitude=AWACS_ALT,
|
||||
airport=None,
|
||||
position=self.conflict.position.random_point_within(AWACS_DISTANCE, AWACS_DISTANCE),
|
||||
frequency=133,
|
||||
start_type=StartType.Warm,
|
||||
)
|
||||
try:
|
||||
awacs_unit = db.find_unittype(AWACS, self.conflict.attackers_side)[0]
|
||||
awacs_flight = self.mission.awacs_flight(
|
||||
country=self.mission.country(self.game.player_country),
|
||||
name=namegen.next_awacs_name(self.mission.country(self.game.player_country)),
|
||||
plane_type=awacs_unit,
|
||||
altitude=AWACS_ALT,
|
||||
airport=None,
|
||||
position=self.conflict.position.random_point_within(AWACS_DISTANCE, AWACS_DISTANCE),
|
||||
frequency=133,
|
||||
start_type=StartType.Warm,
|
||||
)
|
||||
awacs_flight.points[0].tasks.append(SetInvisibleCommand(True))
|
||||
awacs_flight.points[0].tasks.append(SetImmortalCommand(True))
|
||||
except:
|
||||
print("No AWACS for faction")
|
||||
|
||||
awacs_flight.points[0].tasks.append(SetInvisibleCommand(True))
|
||||
awacs_flight.points[0].tasks.append(SetImmortalCommand(True))
|
||||
|
||||
15
gen/armor.py
15
gen/armor.py
@@ -96,6 +96,11 @@ class GroundConflictGenerator:
|
||||
|
||||
|
||||
def gen_infantry_group_for_group(self, group, is_player, side:Country, forward_heading):
|
||||
|
||||
# Disable infantry unit gen if disabled
|
||||
if not self.game.settings.perf_infantry:
|
||||
return
|
||||
|
||||
infantry_position = group.points[0].position.random_point_within(250, 50)
|
||||
|
||||
if side == self.conflict.attackers_country:
|
||||
@@ -135,12 +140,16 @@ class GroundConflictGenerator:
|
||||
|
||||
def plan_action_for_groups(self, stance, ally_groups, enemy_groups, forward_heading, from_cp, to_cp):
|
||||
|
||||
if not self.game.settings.perf_moving_units:
|
||||
return
|
||||
|
||||
for dcs_group, group in ally_groups:
|
||||
if group.role == CombatGroupRole.ARTILLERY:
|
||||
# Fire on any ennemy in range
|
||||
target = self.get_artillery_target_in_range(dcs_group, group, enemy_groups)
|
||||
if target is not None:
|
||||
dcs_group.points[0].tasks.append(FireAtPoint(target, len(group.units) * 10, 100))
|
||||
if self.game.settings.perf_artillery:
|
||||
target = self.get_artillery_target_in_range(dcs_group, group, enemy_groups)
|
||||
if target is not None:
|
||||
dcs_group.points[0].tasks.append(FireAtPoint(target, len(group.units) * 10, 100))
|
||||
elif group.role in [CombatGroupRole.TANK, CombatGroupRole.IFV]:
|
||||
if stance == CombatStance.AGGRESIVE:
|
||||
# Attack nearest enemy if any
|
||||
|
||||
@@ -57,11 +57,7 @@ class BriefingGenerator:
|
||||
self.description += "-"*50 + "\n"
|
||||
|
||||
for planner in self.game.planners.values():
|
||||
for flight in planner.cap_flights:
|
||||
self.add_flight_description(flight)
|
||||
for flight in planner.cas_flights:
|
||||
self.add_flight_description(flight)
|
||||
for flight in planner.sead_flights:
|
||||
for flight in planner.flights:
|
||||
self.add_flight_description(flight)
|
||||
|
||||
if self.freqs:
|
||||
@@ -69,10 +65,9 @@ class BriefingGenerator:
|
||||
self.description += "-" * 50 + "\n"
|
||||
for name, freq in self.freqs:
|
||||
self.description += "\n{}: {}".format(name, freq)
|
||||
|
||||
self.description += "\n" + ("-" * 50) + "\n"
|
||||
for cp in self.game.theater.controlpoints:
|
||||
if cp.captured and cp.cptype in [ControlPointType.LHA_GROUP, ControlPointType.AIRCRAFT_CARRIER_GROUP]:
|
||||
self.description += "\n"
|
||||
self.description += cp.name + " TACAN : "
|
||||
|
||||
self.description += str(cp.tacanN)
|
||||
@@ -82,6 +77,9 @@ class BriefingGenerator:
|
||||
self.description += "X"
|
||||
self.description += " " + str(cp.tacanI) + "\n"
|
||||
|
||||
if cp.cptype == ControlPointType.AIRCRAFT_CARRIER_GROUP and hasattr(cp, "icls"):
|
||||
self.description += "ICLS Channel : " + str(cp.icls) + "\n"
|
||||
self.description += "-" * 50 + "\n"
|
||||
|
||||
self.m.set_description_text(self.description)
|
||||
|
||||
|
||||
@@ -172,13 +172,6 @@ class Conflict:
|
||||
position = middle_point.point_from_heading(attack_heading, strength_delta * attack_distance / 2 - FRONTLINE_MIN_CP_DISTANCE)
|
||||
return position, _opposite_heading(attack_heading)
|
||||
|
||||
ground_position = cls._find_ground_position(position, attack_distance / 2 - FRONTLINE_MIN_CP_DISTANCE, attack_heading, theater)
|
||||
if ground_position:
|
||||
return ground_position, _opposite_heading(attack_heading)
|
||||
else:
|
||||
logging.warning("Coudn't find frontline position between {} and {}!".format(from_cp, to_cp))
|
||||
return position, _opposite_heading(attack_heading)
|
||||
|
||||
|
||||
@classmethod
|
||||
def frontline_vector(cls, from_cp: ControlPoint, to_cp: ControlPoint, theater: ConflictTheater) -> typing.Optional[typing.Tuple[Point, int, int]]:
|
||||
|
||||
@@ -61,12 +61,14 @@ class EnviromentGenerator:
|
||||
logging.info("Skip Night mission due to user settings")
|
||||
if daytime == "dawn":
|
||||
time_range = (8, 9)
|
||||
elif daytime == "noon":
|
||||
elif daytime == "day":
|
||||
time_range = (10, 12)
|
||||
elif daytime == "dusk":
|
||||
time_range = (12, 14)
|
||||
elif daytime == "night":
|
||||
time_range = (14, 17)
|
||||
else:
|
||||
time_range = (10, 12)
|
||||
else:
|
||||
time_range = self.game.theater.daytime_map[daytime]
|
||||
|
||||
|
||||
@@ -5,8 +5,25 @@ import random
|
||||
|
||||
from game import db
|
||||
from gen import Conflict
|
||||
from gen.flights.ai_flight_planner_db import INTERCEPT_CAPABLE, CAP_CAPABLE, CAS_CAPABLE, SEAD_CAPABLE
|
||||
from gen.flights.flight import Flight, FlightType, FlightWaypoint
|
||||
from gen.flights.ai_flight_planner_db import INTERCEPT_CAPABLE, CAP_CAPABLE, CAS_CAPABLE, SEAD_CAPABLE, STRIKE_CAPABLE
|
||||
from gen.flights.flight import Flight, FlightType, FlightWaypoint, FlightWaypointType
|
||||
|
||||
|
||||
def meter_to_feet(value_in_meter):
|
||||
return int(3.28084 * value_in_meter)
|
||||
|
||||
|
||||
def feet_to_meter(value_in_feet):
|
||||
return int(float(value_in_feet)/3.048)
|
||||
|
||||
|
||||
def meter_to_nm(value_in_meter):
|
||||
return int(float(value_in_meter)*0.000539957)
|
||||
|
||||
|
||||
def nm_to_meter(value_in_nm):
|
||||
return int(float(value_in_nm)*1852)
|
||||
|
||||
|
||||
# TODO : Ideally should be based on the aircraft type instead / Availability of fuel
|
||||
STRIKE_MAX_RANGE = 1500000
|
||||
@@ -17,6 +34,16 @@ MISSION_DURATION = 120 # in minutes
|
||||
CAP_EVERY_X_MINUTES = 20
|
||||
CAS_EVERY_X_MINUTES = 30
|
||||
SEAD_EVERY_X_MINUTES = 40
|
||||
STRIKE_EVERY_X_MINUTES = 40
|
||||
|
||||
INGRESS_EGRESS_DISTANCE = nm_to_meter(45)
|
||||
INGRESS_ALT = feet_to_meter(20000)
|
||||
EGRESS_ALT = feet_to_meter(20000)
|
||||
PATROL_ALT_RANGE = (feet_to_meter(15000), feet_to_meter(33000))
|
||||
NAV_ALT = 9144
|
||||
PATTERN_ALTITUDE = feet_to_meter(5000)
|
||||
|
||||
CAP_DEFAULT_ENGAGE_DISTANCE = nm_to_meter(40)
|
||||
|
||||
|
||||
class FlightPlanner:
|
||||
@@ -53,7 +80,7 @@ class FlightPlanner:
|
||||
#self.commision_interceptors()
|
||||
|
||||
# Then some CAP patrol for the next 2 hours
|
||||
self.commision_barcap()
|
||||
self.commision_cap()
|
||||
|
||||
# Then setup cas
|
||||
self.commision_cas()
|
||||
@@ -61,7 +88,9 @@ class FlightPlanner:
|
||||
# Then prepare some sead flights if required
|
||||
self.commision_sead()
|
||||
|
||||
# TODO : commision STRIKE / ANTISHIP
|
||||
self.commision_strike()
|
||||
|
||||
# TODO : commision ANTISHIP
|
||||
|
||||
def remove_flight(self, index):
|
||||
try:
|
||||
@@ -107,7 +136,7 @@ class FlightPlanner:
|
||||
for k, v in inventory.items():
|
||||
self.aircraft_inventory[k] = v
|
||||
|
||||
def commision_barcap(self):
|
||||
def commision_cap(self):
|
||||
"""
|
||||
Pick some aircraft to assign them to defensive CAP roles (BARCAP)
|
||||
"""
|
||||
@@ -124,32 +153,67 @@ class FlightPlanner:
|
||||
break
|
||||
|
||||
inventory[unit] = inventory[unit] - 2
|
||||
flight = Flight(unit, 2, self.from_cp, FlightType.BARCAP)
|
||||
ftype = FlightType.BARCAP if self.from_cp.is_carrier else FlightType.CAP
|
||||
flight = Flight(unit, 2, self.from_cp, ftype)
|
||||
|
||||
# Flight path : fly over each ground object (TODO : improve)
|
||||
flight.points = []
|
||||
flight.scheduled_in = offset + i*random.randint(CAP_EVERY_X_MINUTES-5, CAP_EVERY_X_MINUTES+5)
|
||||
|
||||
patrol_alt = random.randint(3600, 7000)
|
||||
patrol_alt = random.randint(PATROL_ALT_RANGE[0], PATROL_ALT_RANGE[1])
|
||||
|
||||
patrolled = []
|
||||
# Choose a location for CAP patrols (Either behind frontline if there is one, or to protect ground objects)
|
||||
if len(self._get_cas_locations()) > 0:
|
||||
loc = random.choice(self._get_cas_locations())
|
||||
ingress, heading, distance = Conflict.frontline_vector(self.from_cp, loc, self.game.theater)
|
||||
center = ingress.point_from_heading(heading, distance / 2)
|
||||
orbit_center = center.point_from_heading(heading - 90, random.randint(nm_to_meter(6), nm_to_meter(15)))
|
||||
radius = distance * 2
|
||||
orbit0p = orbit_center.point_from_heading(heading, radius)
|
||||
orbit1p = orbit_center.point_from_heading(heading + 180, radius)
|
||||
elif len(self.from_cp.ground_objects) > 0:
|
||||
loc = random.choice(self.from_cp.ground_objects)
|
||||
hdg = self.from_cp.position.heading_between_point(loc.position)
|
||||
radius = random.randint(nm_to_meter(5), nm_to_meter(10))
|
||||
orbit0p = loc.position.point_from_heading(hdg - 90, radius)
|
||||
orbit1p = loc.position.point_from_heading(hdg + 90, radius)
|
||||
else:
|
||||
loc = self.from_cp.position.point_from_heading(random.randint(0, 360), random.randint(nm_to_meter(5), nm_to_meter(40)))
|
||||
hdg = self.from_cp.position.heading_between_point(loc.position)
|
||||
radius = random.randint(nm_to_meter(40), nm_to_meter(120))
|
||||
orbit0p = loc.position.point_from_heading(hdg - 90, radius)
|
||||
orbit1p = loc.position.point_from_heading(hdg + 90, radius)
|
||||
|
||||
|
||||
# Create points
|
||||
ascend = self.generate_ascend_point(self.from_cp)
|
||||
flight.points.append(ascend)
|
||||
|
||||
orbit0 = FlightWaypoint(orbit0p.x, orbit0p.y, patrol_alt)
|
||||
orbit0.name = "ORBIT 0"
|
||||
orbit0.description = "Standby between this point and the next one"
|
||||
orbit0.pretty_name = "Orbit race-track start"
|
||||
orbit0.waypoint_type = FlightWaypointType.PATROL_TRACK
|
||||
flight.points.append(orbit0)
|
||||
|
||||
orbit1 = FlightWaypoint(orbit1p.x, orbit1p.y, patrol_alt)
|
||||
orbit1.name = "ORBIT 1"
|
||||
orbit1.description = "Standby between this point and the previous one"
|
||||
orbit1.pretty_name = "Orbit race-track end"
|
||||
orbit1.waypoint_type = FlightWaypointType.PATROL
|
||||
flight.points.append(orbit1)
|
||||
|
||||
orbit0.targets.append(self.from_cp)
|
||||
obj_added = []
|
||||
for ground_object in self.from_cp.ground_objects:
|
||||
if ground_object.group_id not in patrolled and not ground_object.airbase_group:
|
||||
point = FlightWaypoint(ground_object.position.x, ground_object.position.y, patrol_alt)
|
||||
point.name = "Patrol point"
|
||||
point.description = "Patrol #" + str(len(flight.points))
|
||||
point.pretty_name = "Patrol #" + str(len(flight.points))
|
||||
flight.points.append(point)
|
||||
patrolled.append(ground_object.group_id)
|
||||
if ground_object.obj_name not in obj_added and not ground_object.airbase_group:
|
||||
orbit0.targets.append(ground_object)
|
||||
obj_added.append(ground_object.obj_name)
|
||||
|
||||
if len(flight.points) == 0:
|
||||
for i in range(3):
|
||||
pos = self.from_cp.position.point_from_heading(random.randint(0,360), random.randint(30000, 80000))
|
||||
point = FlightWaypoint(pos.x, pos.y, patrol_alt)
|
||||
point.name = "Patrol point"
|
||||
point.description = "Patrol #" + str(len(flight.points))
|
||||
point.pretty_name = "Patrol #" + str(len(flight.points))
|
||||
flight.points.append(point)
|
||||
descend = self.generate_descend_point(self.from_cp)
|
||||
flight.points.append(descend)
|
||||
|
||||
rtb = self.generate_rtb_waypoint(self.from_cp)
|
||||
flight.points.append(rtb)
|
||||
|
||||
self.cap_flights.append(flight)
|
||||
self.flights.append(flight)
|
||||
@@ -188,26 +252,39 @@ class FlightPlanner:
|
||||
center = ingress.point_from_heading(heading, distance/2)
|
||||
egress = ingress.point_from_heading(heading, distance)
|
||||
|
||||
flight.targets.append(center)
|
||||
ascend = self.generate_ascend_point(self.from_cp)
|
||||
flight.points.append(ascend)
|
||||
|
||||
ingress_point = FlightWaypoint(ingress.x, ingress.y, 1000)
|
||||
ingress_point.alt_type = "RADIO"
|
||||
ingress_point.name = "INGRESS"
|
||||
ingress_point.pretty_name = "INGRESS"
|
||||
ingress_point.description = "Ingress into CAS area"
|
||||
ingress_point.waypoint_type = FlightWaypointType.INGRESS_CAS
|
||||
flight.points.append(ingress_point)
|
||||
|
||||
center_point = FlightWaypoint(center.x, center.y, 1000)
|
||||
center_point.alt_type = "RADIO"
|
||||
center_point.description = "Provide CAS"
|
||||
center_point.name = "CAS"
|
||||
center_point.pretty_name = "INGRESS"
|
||||
center_point.pretty_name = "CAS"
|
||||
center_point.waypoint_type = FlightWaypointType.CAS
|
||||
flight.points.append(center_point)
|
||||
|
||||
egress_point = FlightWaypoint(egress.x, egress.y, 1000)
|
||||
egress_point.alt_type = "RADIO"
|
||||
egress_point.description = "Egress from CAS area"
|
||||
egress_point.name = "EGRESS"
|
||||
egress_point.pretty_name = "EGRESS"
|
||||
egress_point.waypoint_type = FlightWaypointType.EGRESS
|
||||
flight.points.append(egress_point)
|
||||
|
||||
descend = self.generate_descend_point(self.from_cp)
|
||||
flight.points.append(descend)
|
||||
|
||||
rtb = self.generate_rtb_waypoint(self.from_cp)
|
||||
flight.points.append(rtb)
|
||||
|
||||
self.cas_flights.append(flight)
|
||||
self.flights.append(flight)
|
||||
|
||||
@@ -242,15 +319,50 @@ class FlightPlanner:
|
||||
flight.points = []
|
||||
flight.scheduled_in = offset + i*random.randint(SEAD_EVERY_X_MINUTES-5, SEAD_EVERY_X_MINUTES+5)
|
||||
|
||||
ascend = self.generate_ascend_point(self.from_cp)
|
||||
flight.points.append(ascend)
|
||||
|
||||
location = self.potential_sead_targets[0][0]
|
||||
self.potential_sead_targets.pop(0)
|
||||
|
||||
point = FlightWaypoint(location.position.x, location.position.y, 1000)
|
||||
point.description = "SEAD"
|
||||
point.pretty_name = "SEAD"
|
||||
point.targets.append(location)
|
||||
heading = self.from_cp.position.heading_between_point(location.position)
|
||||
ingress_heading = heading - 180 + 25
|
||||
egress_heading = heading - 180 - 25
|
||||
|
||||
ingress_pos = location.position.point_from_heading(ingress_heading, INGRESS_EGRESS_DISTANCE)
|
||||
ingress_point = FlightWaypoint(ingress_pos.x, ingress_pos.y, INGRESS_ALT)
|
||||
ingress_point.pretty_name = "INGRESS on " + location.obj_name
|
||||
ingress_point.description = "INGRESS on " + location.obj_name
|
||||
ingress_point.waypoint_type = FlightWaypointType.INGRESS_SEAD
|
||||
flight.points.append(ingress_point)
|
||||
|
||||
point = FlightWaypoint(location.position.x, location.position.y, 0)
|
||||
point.alt_type = "RADIO"
|
||||
if flight.flight_type == FlightType.DEAD:
|
||||
point.description = "SEAD on " + location.obj_name
|
||||
point.pretty_name = "SEAD on " + location.obj_name
|
||||
point.only_for_player = True
|
||||
else:
|
||||
point.description = "DEAD on " + location.obj_name
|
||||
point.pretty_name = "DEAD on " + location.obj_name
|
||||
point.only_for_player = True
|
||||
|
||||
ingress_point.targets.append(location)
|
||||
flight.points.append(point)
|
||||
|
||||
egress_pos = location.position.point_from_heading(egress_heading, INGRESS_EGRESS_DISTANCE)
|
||||
egress_point = FlightWaypoint(egress_pos.x, egress_pos.y, EGRESS_ALT)
|
||||
egress_point.pretty_name = "EGRESS from " + location.obj_name
|
||||
egress_point.description = "EGRESS from " + location.obj_name
|
||||
egress_point.waypoint_type = FlightWaypointType.EGRESS
|
||||
flight.points.append(egress_point)
|
||||
|
||||
descend = self.generate_descend_point(self.from_cp)
|
||||
flight.points.append(descend)
|
||||
|
||||
rtb = self.generate_rtb_waypoint(self.from_cp)
|
||||
flight.points.append(rtb)
|
||||
|
||||
self.sead_flights.append(flight)
|
||||
self.flights.append(flight)
|
||||
|
||||
@@ -258,6 +370,110 @@ class FlightPlanner:
|
||||
for k, v in inventory.items():
|
||||
self.aircraft_inventory[k] = v
|
||||
|
||||
|
||||
def commision_strike(self):
|
||||
"""
|
||||
Pick some aircraft to assign them to STRIKE tasks
|
||||
"""
|
||||
possible_aircraft = [k for k, v in self.aircraft_inventory.items() if k in STRIKE_CAPABLE and v >= 2]
|
||||
inventory = dict({k: v for k, v in self.aircraft_inventory.items() if k in possible_aircraft})
|
||||
|
||||
if len(self.potential_strike_targets) > 0:
|
||||
|
||||
offset = random.randint(0,5)
|
||||
for i in range(int(MISSION_DURATION/STRIKE_EVERY_X_MINUTES)):
|
||||
|
||||
if len(self.potential_strike_targets) <= 0:
|
||||
break
|
||||
|
||||
try:
|
||||
unit = random.choice([k for k, v in inventory.items() if v >= 2])
|
||||
except IndexError:
|
||||
break
|
||||
|
||||
inventory[unit] = inventory[unit] - 2
|
||||
flight = Flight(unit, 2, self.from_cp, FlightType.STRIKE)
|
||||
|
||||
flight.points = []
|
||||
flight.scheduled_in = offset + i*random.randint(SEAD_EVERY_X_MINUTES-5, SEAD_EVERY_X_MINUTES+5)
|
||||
|
||||
ascend = self.generate_ascend_point(self.from_cp)
|
||||
flight.points.append(ascend)
|
||||
|
||||
location = self.potential_strike_targets[0][0]
|
||||
self.potential_strike_targets.pop(0)
|
||||
|
||||
heading = self.from_cp.position.heading_between_point(location.position)
|
||||
ingress_heading = heading - 180 + 25
|
||||
egress_heading = heading - 180 - 25
|
||||
|
||||
ingress_pos = location.position.point_from_heading(ingress_heading, INGRESS_EGRESS_DISTANCE)
|
||||
ingress_point = FlightWaypoint(ingress_pos.x, ingress_pos.y, INGRESS_ALT)
|
||||
ingress_point.pretty_name = "INGRESS on " + location.obj_name
|
||||
ingress_point.description = "INGRESS on " + location.obj_name
|
||||
ingress_point.name = "INGRESS"
|
||||
ingress_point.waypoint_type = FlightWaypointType.INGRESS_STRIKE
|
||||
flight.points.append(ingress_point)
|
||||
|
||||
if len(location.groups) > 0 and location.dcs_identifier == "AA":
|
||||
for g in location.groups:
|
||||
for j, u in enumerate(g.units):
|
||||
point = FlightWaypoint(u.position.x, u.position.y, 0)
|
||||
point.description = "STRIKE " + "[" + str(location.obj_name) + "] : " + u.type + " #" + str(j)
|
||||
point.pretty_name = "STRIKE " + "[" + str(location.obj_name) + "] : " + u.type + " #" + str(j)
|
||||
point.name = location.obj_name + "#" + str(j)
|
||||
point.only_for_player = True
|
||||
ingress_point.targets.append(location)
|
||||
flight.points.append(point)
|
||||
else:
|
||||
if hasattr(location, "obj_name"):
|
||||
buildings = self.game.theater.find_ground_objects_by_obj_name(location.obj_name)
|
||||
print(buildings)
|
||||
for building in buildings:
|
||||
print("BUILDING " + str(building.is_dead) + " " + str(building.dcs_identifier))
|
||||
if building.is_dead:
|
||||
continue
|
||||
|
||||
point = FlightWaypoint(building.position.x, building.position.y, 0)
|
||||
point.description = "STRIKE on " + building.obj_name + " " + str(building.category)
|
||||
point.pretty_name = "STRIKE on " + building.obj_name + " " + str(building.category)
|
||||
point.name = building.obj_name
|
||||
point.only_for_player = True
|
||||
ingress_point.targets.append(building)
|
||||
flight.points.append(point)
|
||||
else:
|
||||
point = FlightWaypoint(location.position.x, location.position.y, 0)
|
||||
point.description = "STRIKE on " + location.obj_name + " " + str(location.category)
|
||||
point.pretty_name = "STRIKE on " + location.obj_name + " " + str(location.category)
|
||||
point.name = location.obj_name
|
||||
point.only_for_player = True
|
||||
ingress_point.targets.append(location)
|
||||
flight.points.append(point)
|
||||
|
||||
|
||||
|
||||
|
||||
egress_pos = location.position.point_from_heading(egress_heading, INGRESS_EGRESS_DISTANCE)
|
||||
egress_point = FlightWaypoint(egress_pos.x, egress_pos.y, EGRESS_ALT)
|
||||
egress_point.name = "EGRESS"
|
||||
egress_point.pretty_name = "EGRESS from " + location.obj_name
|
||||
egress_point.description = "EGRESS from " + location.obj_name
|
||||
egress_point.waypoint_type = FlightWaypointType.EGRESS
|
||||
flight.points.append(egress_point)
|
||||
|
||||
descend = self.generate_descend_point(self.from_cp)
|
||||
flight.points.append(descend)
|
||||
|
||||
rtb = self.generate_rtb_waypoint(self.from_cp)
|
||||
flight.points.append(rtb)
|
||||
|
||||
self.strike_flights.append(flight)
|
||||
self.flights.append(flight)
|
||||
|
||||
# Update inventory
|
||||
for k, v in inventory.items():
|
||||
self.aircraft_inventory[k] = v
|
||||
|
||||
def _get_cas_locations(self):
|
||||
cas_locations = []
|
||||
for cp in self.from_cp.connected_points:
|
||||
@@ -285,7 +501,7 @@ class FlightPlanner:
|
||||
|
||||
added_group = []
|
||||
for g in cp.ground_objects:
|
||||
if g.group_id in added_group: continue
|
||||
if g.group_id in added_group or g.is_dead: continue
|
||||
|
||||
# Compute distance to current cp
|
||||
distance = math.hypot(cp.position.x - self.from_cp.position.x,
|
||||
@@ -347,3 +563,35 @@ class FlightPlanner:
|
||||
del base_aircraft_inventory[f.unit_type]
|
||||
return base_aircraft_inventory
|
||||
|
||||
def generate_ascend_point(self, from_cp):
|
||||
ascend_heading = from_cp.heading
|
||||
pos_ascend = from_cp.position.point_from_heading(ascend_heading, 10000)
|
||||
ascend = FlightWaypoint(pos_ascend.x, pos_ascend.y, PATTERN_ALTITUDE)
|
||||
ascend.name = "ASCEND"
|
||||
ascend.alt_type = "RADIO"
|
||||
ascend.description = "Ascend to alt [" + str(meter_to_feet(PATTERN_ALTITUDE)) + " ft AGL], then proceed to next waypoint"
|
||||
ascend.pretty_name = "Ascend to alt [" + str(meter_to_feet(PATTERN_ALTITUDE)) + " ft AGL]"
|
||||
ascend.waypoint_type = FlightWaypointType.ASCEND_POINT
|
||||
return ascend
|
||||
|
||||
def generate_descend_point(self, from_cp):
|
||||
ascend_heading = from_cp.heading
|
||||
descend = from_cp.position.point_from_heading(ascend_heading - 180, 30000)
|
||||
descend = FlightWaypoint(descend.x, descend.y, PATTERN_ALTITUDE)
|
||||
descend.name = "DESCEND"
|
||||
descend.alt_type = "RADIO"
|
||||
descend.description = "Descend to pattern alt [" + str(meter_to_feet(PATTERN_ALTITUDE)) + " ft AGL], contact tower, and land"
|
||||
descend.pretty_name = "Descend to pattern alt [" + str(meter_to_feet(PATTERN_ALTITUDE)) + " ft AGL]"
|
||||
descend.waypoint_type = FlightWaypointType.DESCENT_POINT
|
||||
return descend
|
||||
|
||||
def generate_rtb_waypoint(self, from_cp):
|
||||
rtb = from_cp.position
|
||||
rtb = FlightWaypoint(rtb.x, rtb.y, 0)
|
||||
rtb.name = "LANDING"
|
||||
rtb.alt_type = "RADIO"
|
||||
rtb.description = "RTB"
|
||||
rtb.pretty_name = "RTB"
|
||||
rtb.waypoint_type = FlightWaypointType.LANDING_POINT
|
||||
return rtb
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ CAP_CAPABLE = [
|
||||
|
||||
P_51D_30_NA,
|
||||
P_51D,
|
||||
P_47D_30,
|
||||
|
||||
SpitfireLFMkIXCW,
|
||||
SpitfireLFMkIX,
|
||||
@@ -106,6 +107,8 @@ CAS_CAPABLE = [
|
||||
|
||||
P_51D_30_NA,
|
||||
P_51D,
|
||||
P_47D_30,
|
||||
A_20G,
|
||||
|
||||
SpitfireLFMkIXCW,
|
||||
SpitfireLFMkIX,
|
||||
@@ -119,7 +122,7 @@ CAS_CAPABLE = [
|
||||
SEAD_CAPABLE = [
|
||||
F_4E,
|
||||
FA_18C_hornet,
|
||||
F_16C_50,
|
||||
# F_16C_50, Not yet
|
||||
AV8BNA,
|
||||
JF_17,
|
||||
|
||||
@@ -164,10 +167,10 @@ STRIKE_CAPABLE = [
|
||||
L_39ZA,
|
||||
AJS37,
|
||||
|
||||
M_2000C,
|
||||
|
||||
P_51D_30_NA,
|
||||
P_51D,
|
||||
P_47D_30,
|
||||
A_20G,
|
||||
|
||||
SpitfireLFMkIXCW,
|
||||
SpitfireLFMkIX,
|
||||
@@ -175,11 +178,18 @@ STRIKE_CAPABLE = [
|
||||
Bf_109K_4,
|
||||
FW_190D9,
|
||||
FW_190A8,
|
||||
|
||||
]
|
||||
|
||||
ANTISHIP_CAPABLE = [
|
||||
Su_24M,
|
||||
Su_17M4,
|
||||
F_A_18C,
|
||||
AV8BNA,
|
||||
JF_17
|
||||
JF_17,
|
||||
F_16C_50,
|
||||
A_10C,
|
||||
A_10A,
|
||||
|
||||
Ju_88A4,
|
||||
]
|
||||
@@ -30,17 +30,38 @@ class FlightType(Enum):
|
||||
EWAR = 16
|
||||
|
||||
|
||||
class FlightWaypoint():
|
||||
class FlightWaypointType(Enum):
|
||||
TAKEOFF = 0 # Take off point
|
||||
ASCEND_POINT = 1 # Ascension point after take off
|
||||
PATROL = 2 # Patrol point
|
||||
PATROL_TRACK = 3 # Patrol race track
|
||||
NAV = 4 # Nav point
|
||||
INGRESS_STRIKE = 5 # Ingress strike (For generator, means that this should have bombing on next TARGET_POINT points)
|
||||
INGRESS_SEAD = 6 # Ingress sead (For generator, means that this should attack groups on TARGET_GROUP_LOC points)
|
||||
INGRESS_CAS = 7 # Ingress cas (should start CAS task)
|
||||
CAS = 8 # Should do CAS there
|
||||
EGRESS = 9 # Should stop attack
|
||||
DESCENT_POINT = 10 # Should start descending to pattern alt
|
||||
LANDING_POINT = 11 # Should land there
|
||||
TARGET_POINT = 12 # A target building or static object, position
|
||||
TARGET_GROUP_LOC = 13 # A target group approximate location
|
||||
TARGET_SHIP = 14 # A target ship known location
|
||||
|
||||
|
||||
class FlightWaypoint:
|
||||
|
||||
def __init__(self, x: float, y: float, alt=0):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.alt = alt
|
||||
self.alt_type = "BARO"
|
||||
self.name = ""
|
||||
self.description = ""
|
||||
self.targets = []
|
||||
self.obj_name = ""
|
||||
self.pretty_name = ""
|
||||
self.waypoint_type = FlightWaypointType.TAKEOFF # type: FlightWaypointType
|
||||
self.only_for_player = False
|
||||
|
||||
|
||||
class Flight:
|
||||
|
||||
@@ -19,6 +19,9 @@ TYPE_TANKS = [
|
||||
Armor.MBT_M1A2_Abrams,
|
||||
Armor.MBT_M60A3_Patton,
|
||||
Armor.MBT_Merkava_Mk__4,
|
||||
Armor.ZTZ_96B,
|
||||
|
||||
# WW2
|
||||
Armor.MT_Pz_Kpfw_V_Panther_Ausf_G,
|
||||
Armor.MT_Pz_Kpfw_IV_Ausf_H,
|
||||
Armor.HT_Pz_Kpfw_VI_Tiger_I,
|
||||
@@ -26,13 +29,21 @@ TYPE_TANKS = [
|
||||
Armor.MT_M4_Sherman,
|
||||
Armor.MT_M4A4_Sherman_Firefly,
|
||||
Armor.StuG_IV,
|
||||
Armor.ZTZ_96B
|
||||
Armor.ST_Centaur_IV,
|
||||
Armor.CT_Cromwell_IV,
|
||||
Armor.HIT_Churchill_VII,
|
||||
]
|
||||
|
||||
TYPE_ATGM = [
|
||||
Armor.ATGM_M1045_HMMWV_TOW,
|
||||
Armor.ATGM_M1134_Stryker,
|
||||
Armor.IFV_BMP_2,
|
||||
|
||||
# WW2 (Tank Destroyers)
|
||||
Armor.M30_Cargo_Carrier,
|
||||
Armor.TD_Jagdpanzer_IV,
|
||||
Armor.TD_Jagdpanther_G1,
|
||||
Armor.TD_M10_GMC,
|
||||
]
|
||||
|
||||
TYPE_IFV = [
|
||||
@@ -46,8 +57,10 @@ TYPE_IFV = [
|
||||
Armor.IFV_M2A2_Bradley,
|
||||
Armor.IFV_BMD_1,
|
||||
Armor.ZBD_04A,
|
||||
Armor.APC_Sd_Kfz_251,
|
||||
|
||||
# WW2
|
||||
Armor.IFV_Sd_Kfz_234_2_Puma,
|
||||
Armor.LAC_M8_Greyhound,
|
||||
]
|
||||
|
||||
TYPE_APC = [
|
||||
@@ -63,9 +76,11 @@ TYPE_APC = [
|
||||
Armor.TPz_Fuchs,
|
||||
Armor.ARV_BRDM_2,
|
||||
Armor.ARV_BTR_RD,
|
||||
Armor.ARV_MTLB_U_BOMAN,
|
||||
Armor.M30_Cargo_Carrier,
|
||||
Armor.FDDM_Grad,
|
||||
|
||||
# WW2
|
||||
Armor.APC_M2A1,
|
||||
Armor.APC_Sd_Kfz_251,
|
||||
]
|
||||
|
||||
TYPE_ARTILLERY = [
|
||||
@@ -79,9 +94,11 @@ TYPE_ARTILLERY = [
|
||||
Artillery.SPH_2S9_Nona,
|
||||
Artillery.SpGH_Dana,
|
||||
Artillery.SPH_2S19_Msta,
|
||||
Artillery.M12_GMC,
|
||||
Artillery.MLRS_FDDM,
|
||||
Artillery.Sturmpanzer_IV_Brummbär
|
||||
|
||||
# WW2
|
||||
Artillery.Sturmpanzer_IV_Brummbär,
|
||||
Artillery.M12_GMC
|
||||
]
|
||||
|
||||
TYPE_LOGI = [
|
||||
|
||||
@@ -77,14 +77,23 @@ class GroundObjectsGenerator:
|
||||
vehicle.position.y = u.position.y
|
||||
vehicle.heading = u.heading
|
||||
vg.add_unit(vehicle)
|
||||
|
||||
if self.game.settings.perf_red_alert_state:
|
||||
vg.points[0].tasks.append(OptAlarmState(2))
|
||||
else:
|
||||
vg.points[0].tasks.append(OptAlarmState(1))
|
||||
|
||||
elif ground_object.dcs_identifier in ["CARRIER", "LHA"]:
|
||||
for g in ground_object.groups:
|
||||
if len(g.units) > 0:
|
||||
|
||||
utype = unit_type_from_name(g.units[0].type)
|
||||
sg = self.m.ship_group(side, g.name, utype, position=g.position, heading=g.units[0].heading)
|
||||
if ground_object.dcs_identifier == "CARRIER" and self.game.settings.supercarrier == True:
|
||||
utype = db.upgrade_to_supercarrier(utype, cp.name)
|
||||
|
||||
sg = self.m.ship_group(side, g.name, utype, position=g.position, heading=g.units[0].heading)
|
||||
sg.units[0].name = self.m.string(g.units[0].name)
|
||||
|
||||
for i, u in enumerate(g.units):
|
||||
if i > 0:
|
||||
ship = Ship(self.m.next_unit_id(), self.m.string(u.name), unit_type_from_name(u.type))
|
||||
@@ -100,6 +109,9 @@ class GroundObjectsGenerator:
|
||||
modeChannel = "X" if not cp.tacanY else "Y"
|
||||
sg.points[0].tasks.append(ActivateBeaconCommand(channel=cp.tacanN, modechannel=modeChannel, callsign=cp.tacanI, unit_id=sg.units[0].id))
|
||||
|
||||
if ground_object.dcs_identifier == "CARRIER" and hasattr(cp, "icls"):
|
||||
sg.points[0].tasks.append(ActivateICLSCommand(cp.icls, unit_id=sg.units[0].id))
|
||||
|
||||
else:
|
||||
if ground_object.dcs_identifier in warehouse_map:
|
||||
static_type = warehouse_map[ground_object.dcs_identifier]
|
||||
@@ -110,16 +122,6 @@ class GroundObjectsGenerator:
|
||||
print("Didn't find {} in static _map(s)!".format(ground_object.dcs_identifier))
|
||||
continue
|
||||
|
||||
if ground_object.group_id not in consumed_farps:
|
||||
consumed_farps.add(ground_object.group_id)
|
||||
if random.randint(0, 100) > 50:
|
||||
farp_aa(
|
||||
self.m,
|
||||
side,
|
||||
ground_object.string_identifier,
|
||||
ground_object.position,
|
||||
)
|
||||
|
||||
group = self.m.static_group(
|
||||
country=side,
|
||||
name=ground_object.string_identifier,
|
||||
|
||||
@@ -68,7 +68,7 @@ class NameGenerator:
|
||||
|
||||
def random_objective_name(self):
|
||||
if len(self.ANIMALS) == 0:
|
||||
random.choice(ALPHA_MILITARY).upper() + " #" + str(random.randint(0, 100))
|
||||
return random.choice(ALPHA_MILITARY).upper() + "#" + str(random.randint(0, 100))
|
||||
else:
|
||||
animal = random.choice(self.ANIMALS)
|
||||
self.ANIMALS.remove(animal)
|
||||
|
||||
@@ -4,7 +4,7 @@ from dcs.vehicles import AirDefence, Unarmed
|
||||
|
||||
from gen.sam.group_generator import GroupGenerator
|
||||
|
||||
GFLAK = [AirDefence.AAA_Flak_Vierling_38, AirDefence.AAA_Flak_Vierling_38, AirDefence.AAA_Flak_18, AirDefence.AAA_Flak_36, AirDefence.AAA_Flak_37, AirDefence.AAA_Flak_38]
|
||||
GFLAK = [AirDefence.AAA_Flak_Vierling_38, AirDefence.AAA_8_8cm_Flak_18, AirDefence.AAA_8_8cm_Flak_36, AirDefence.AAA_8_8cm_Flak_37, AirDefence.AAA_8_8cm_Flak_41, AirDefence.AAA_Flak_38]
|
||||
|
||||
class FlakGenerator(GroupGenerator):
|
||||
"""
|
||||
@@ -31,7 +31,7 @@ class FlakGenerator(GroupGenerator):
|
||||
if(mixed):
|
||||
unit_type = random.choice(GFLAK)
|
||||
|
||||
# Enough Opel truck to transport the guns
|
||||
# Enough Opel Blitz truck to transport the guns
|
||||
for i in range(grid_x):
|
||||
for j in range(grid_y):
|
||||
self.add_unit(Unarmed.Blitz_3_6_6700A, "AAA#" + str(index),
|
||||
|
||||
@@ -50,7 +50,7 @@ SAM_MAP = {
|
||||
AirDefence.SAM_Patriot_EPP_III: PatriotGenerator,
|
||||
AirDefence.SAM_Chaparral_M48: ChaparralGenerator,
|
||||
AirDefence.AAA_Bofors_40mm: BoforsGenerator,
|
||||
AirDefence.AAA_Flak_36: FlakGenerator,
|
||||
AirDefence.AAA_8_8cm_Flak_36: FlakGenerator,
|
||||
AirDefence.SAM_SA_2_LN_SM_90: SA2Generator,
|
||||
AirDefence.SAM_SA_3_S_125_LN_5P73: SA3Generator,
|
||||
AirDefence.SAM_SA_6_Kub_LN_2P25: SA6Generator,
|
||||
|
||||
@@ -4,6 +4,7 @@ import sys
|
||||
from shutil import copyfile
|
||||
|
||||
import dcs
|
||||
from PySide2 import QtWidgets
|
||||
from PySide2.QtGui import QPixmap
|
||||
from PySide2.QtWidgets import QApplication, QSplashScreen
|
||||
from dcs import installation
|
||||
@@ -11,21 +12,40 @@ from dcs import installation
|
||||
from qt_ui import uiconstants
|
||||
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
|
||||
from qt_ui.windows.QLiberationWindow import QLiberationWindow
|
||||
from userdata import persistency, logging as logging_module
|
||||
from qt_ui.windows.preferences.QLiberationFirstStartWindow import QLiberationFirstStartWindow
|
||||
from userdata import persistency, logging as logging_module, liberation_install
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
persistency.setup(installation.get_dcs_saved_games_directory())
|
||||
app = QApplication(sys.argv)
|
||||
|
||||
css = ""
|
||||
with open("./resources/stylesheets/style.css") as stylesheet:
|
||||
app.setStyleSheet(stylesheet.read())
|
||||
|
||||
# Logging setup
|
||||
VERSION_STRING = "2.0RC6"
|
||||
logging_module.setup_version_string(VERSION_STRING)
|
||||
|
||||
# Inject custom payload in pydcs framework
|
||||
custom_payloads = os.path.join(os.path.dirname(os.path.realpath(__file__)), "..\\resources\\customized_payloads")
|
||||
if os.path.exists(custom_payloads):
|
||||
dcs.planes.FlyingType.payload_dirs.append(custom_payloads)
|
||||
else:
|
||||
# For release version the path is different.
|
||||
custom_payloads = os.path.join(os.path.dirname(os.path.realpath(__file__)),
|
||||
"resources\\customized_payloads")
|
||||
if os.path.exists(custom_payloads):
|
||||
dcs.planes.FlyingType.payload_dirs.append(custom_payloads)
|
||||
|
||||
VERSION_STRING = "2.0"
|
||||
logging_module.setup_version_string(VERSION_STRING)
|
||||
logging.info("Using {} as userdata folder".format(persistency.base_path()))
|
||||
|
||||
app = QApplication(sys.argv)
|
||||
first_start = liberation_install.init()
|
||||
if first_start:
|
||||
window = QLiberationFirstStartWindow()
|
||||
window.exec_()
|
||||
|
||||
logging.info("Using {} as 'Saved Game Folder'".format(persistency.base_path()))
|
||||
logging.info("Using {} as 'DCS installation folder'".format(liberation_install.get_dcs_install_directory()))
|
||||
|
||||
# Splash screen setup
|
||||
pixmap = QPixmap("./resources/ui/splash_screen.png")
|
||||
@@ -38,24 +58,28 @@ if __name__ == "__main__":
|
||||
uiconstants.load_aircraft_icons()
|
||||
uiconstants.load_vehicle_icons()
|
||||
|
||||
|
||||
css = ""
|
||||
with open("./resources/stylesheets/style.css") as stylesheet:
|
||||
css = stylesheet.read()
|
||||
|
||||
# Replace DCS Mission scripting file to allow DCS Liberation to work
|
||||
print("Replace : " + installation.get_dcs_install_directory() + os.path.sep + "Scripts/MissionScripting.lua")
|
||||
copyfile("./resources/scripts/MissionScripting.lua", installation.get_dcs_install_directory() + os.path.sep + "Scripts/MissionScripting.lua")
|
||||
app.processEvents()
|
||||
try:
|
||||
liberation_install.replace_mission_scripting_file()
|
||||
except:
|
||||
error_dialog = QtWidgets.QErrorMessage()
|
||||
error_dialog.setWindowTitle("Wrong DCS installation directory.")
|
||||
error_dialog.showMessage("Unable to modify Mission Scripting file. Possible issues with rights. Try running as admin, or please perform the modification of the MissionScripting file manually.")
|
||||
error_dialog.exec_()
|
||||
|
||||
# Apply CSS (need works)
|
||||
app.setStyleSheet(css)
|
||||
GameUpdateSignal()
|
||||
|
||||
# Start window
|
||||
window = QLiberationWindow()
|
||||
window.showMaximized()
|
||||
|
||||
splash.finish(window)
|
||||
sys.exit(app.exec_())
|
||||
qt_execution_code = app.exec_()
|
||||
|
||||
# Restore Mission Scripting file
|
||||
logging.info("QT App terminated with status code : " + str(qt_execution_code))
|
||||
logging.info("Attempt to restore original mission scripting file")
|
||||
liberation_install.restore_original_mission_scripting()
|
||||
sys.exit(qt_execution_code)
|
||||
|
||||
|
||||
|
||||
@@ -8,12 +8,12 @@ from game.event import UnitsDeliveryEvent, FrontlineAttackEvent
|
||||
from theater.theatergroundobject import CATEGORY_MAP
|
||||
|
||||
URLS : Dict[str, str] = {
|
||||
"Manual": "https://github.com/shdwp/dcs_liberation/wiki/Manual",
|
||||
"Manual": "https://github.com/khopa/dcs_liberation/wiki",
|
||||
"Troubleshooting": "https://github.com/shdwp/dcs_liberation/wiki/Troubleshooting",
|
||||
"Modding": "https://github.com/shdwp/dcs_liberation/wiki/Modding-tutorial",
|
||||
"Repository": "https://github.com/shdwp/dcs_liberation",
|
||||
"Repository": "https://github.com/khopa/dcs_liberation",
|
||||
"ForumThread": "https://forums.eagle.ru/showthread.php?t=214834",
|
||||
"Issues": "https://github.com/shdwp/dcs_liberation/issues"
|
||||
"Issues": "https://github.com/khopa/dcs_liberation/issues"
|
||||
}
|
||||
|
||||
LABELS_OPTIONS = ["Full", "Abbreviated", "Dot Only", "Off"]
|
||||
|
||||
@@ -2,6 +2,7 @@ from PySide2.QtCore import QSortFilterProxyModel, Qt, QModelIndex
|
||||
from PySide2.QtGui import QStandardItem, QStandardItemModel
|
||||
from PySide2.QtWidgets import QComboBox, QCompleter
|
||||
from game import Game
|
||||
from gen import Conflict
|
||||
from gen.flights.flight import FlightWaypoint
|
||||
from theater import ControlPointType
|
||||
|
||||
@@ -89,20 +90,23 @@ class QPredefinedWaypointSelectionComboBox(QComboBox):
|
||||
if cp.captured:
|
||||
enemy_cp = [ecp for ecp in cp.connected_points if ecp.captured != cp.captured]
|
||||
for ecp in enemy_cp:
|
||||
wpt = FlightWaypoint((cp.position.x + ecp.position.x)/2, (cp.position.y + ecp.position.y)/2, 800)
|
||||
pos = Conflict.frontline_position(self.game.theater, cp, ecp)[0]
|
||||
wpt = FlightWaypoint(pos.x, pos.y, 800)
|
||||
wpt.name = "Frontline " + cp.name + "/" + ecp.name + " [CAS]"
|
||||
wpt.alt_type = "RADIO"
|
||||
wpt.pretty_name = wpt.name
|
||||
wpt.description = "Frontline"
|
||||
i = add_model_item(i, model, wpt.pretty_name, wpt)
|
||||
|
||||
|
||||
for cp in self.game.theater.controlpoints:
|
||||
for ground_object in cp.ground_objects:
|
||||
if not ground_object.is_dead and not ground_object.dcs_identifier == "AA":
|
||||
wpt = FlightWaypoint(ground_object.position.x,ground_object.position.y, 0)
|
||||
wpt.alt_type = "RADIO"
|
||||
wpt.name = wpt.name = "[" + str(ground_object.obj_name) + "] : " + ground_object.category + " #" + str(ground_object.object_id)
|
||||
wpt.pretty_name = wpt.name
|
||||
wpt.obj_name = ground_object.obj_name
|
||||
wpt.targets.append(ground_object)
|
||||
if cp.captured:
|
||||
wpt.description = "Friendly Building"
|
||||
else:
|
||||
@@ -116,8 +120,10 @@ class QPredefinedWaypointSelectionComboBox(QComboBox):
|
||||
for g in ground_object.groups:
|
||||
for j, u in enumerate(g.units):
|
||||
wpt = FlightWaypoint(u.position.x, u.position.y, 0)
|
||||
wpt.alt_type = "RADIO"
|
||||
wpt.name = wpt.name = "[" + str(ground_object.obj_name) + "] : " + u.type + " #" + str(j)
|
||||
wpt.pretty_name = wpt.name
|
||||
wpt.targets.append(u)
|
||||
wpt.obj_name = ground_object.obj_name
|
||||
if cp.captured:
|
||||
wpt.description = "Friendly unit : " + u.type
|
||||
@@ -128,6 +134,7 @@ class QPredefinedWaypointSelectionComboBox(QComboBox):
|
||||
for cp in self.game.theater.controlpoints:
|
||||
|
||||
wpt = FlightWaypoint(cp.position.x, cp.position.y, 0)
|
||||
wpt.alt_type = "RADIO"
|
||||
wpt.name = cp.name
|
||||
if cp.captured:
|
||||
wpt.description = "Position of " + cp.name + " [Friendly Airbase]"
|
||||
|
||||
@@ -83,11 +83,16 @@ class QLiberationMap(QGraphicsView):
|
||||
pen = QPen(brush=CONST.COLORS["red"])
|
||||
brush = CONST.COLORS["red_transparent"]
|
||||
|
||||
added_objects = []
|
||||
for ground_object in cp.ground_objects:
|
||||
if ground_object.obj_name in added_objects:
|
||||
continue
|
||||
|
||||
|
||||
go_pos = self._transform_point(ground_object.position)
|
||||
if not ground_object.airbase_group:
|
||||
scene.addItem(QMapGroundObject(self, go_pos[0], go_pos[1], 12, 12, cp, ground_object))
|
||||
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))
|
||||
|
||||
if ground_object.category == "aa" and self.get_display_rule("sam"):
|
||||
max_range = 0
|
||||
@@ -99,6 +104,7 @@ class QLiberationMap(QGraphicsView):
|
||||
max_range = unit.threat_range
|
||||
if max_range >= 6000:
|
||||
scene.addEllipse(go_pos[0] - max_range/300.0 + 8, go_pos[1] - max_range/300.0 + 8, max_range/150.0, max_range/150.0, pen, brush)
|
||||
added_objects.append(ground_object.obj_name)
|
||||
|
||||
for cp in self.game.theater.enemy_points():
|
||||
if self.get_display_rule("lines"):
|
||||
|
||||
@@ -9,13 +9,14 @@ from theater import TheaterGroundObject, ControlPoint
|
||||
|
||||
class QMapGroundObject(QGraphicsRectItem):
|
||||
|
||||
def __init__(self, parent, x: float, y: float, w: float, h: float, cp: ControlPoint, model: TheaterGroundObject):
|
||||
def __init__(self, parent, x: float, y: float, w: float, h: float, cp: ControlPoint, model: TheaterGroundObject, buildings=[]):
|
||||
super(QMapGroundObject, self).__init__(x, y, w, h)
|
||||
self.model = model
|
||||
self.cp = cp
|
||||
self.parent = parent
|
||||
self.setAcceptHoverEvents(True)
|
||||
self.setZValue(2)
|
||||
self.buildings = buildings
|
||||
#self.setFlag(QGraphicsItem.ItemIgnoresTransformations, True)
|
||||
|
||||
if len(self.model.groups) > 0:
|
||||
@@ -32,7 +33,11 @@ class QMapGroundObject(QGraphicsRectItem):
|
||||
tooltip = tooltip + str(unit) + "x" + str(units[unit]) + "\n"
|
||||
self.setToolTip(tooltip[:-1])
|
||||
else:
|
||||
self.setToolTip("[" + self.model.obj_name + "] : " + self.model.category)
|
||||
tooltip = "[" + self.model.obj_name + "]" + "\n"
|
||||
for building in buildings:
|
||||
if not building.is_dead:
|
||||
tooltip = tooltip + str(building.dcs_identifier) + "\n"
|
||||
self.setToolTip(tooltip[:-1])
|
||||
|
||||
|
||||
def paint(self, painter, option, widget=None):
|
||||
|
||||
@@ -57,6 +57,14 @@ class QDebriefingWindow(QDialog):
|
||||
except:
|
||||
print("Issue adding " + str(unit_type) + " to debriefing information")
|
||||
|
||||
for building, count in self.debriefing.player_dead_buildings_dict.items():
|
||||
try:
|
||||
lostUnitsLayout.addWidget(QLabel(building, row, 0))
|
||||
lostUnitsLayout.addWidget(QLabel("{}".format(count)), row, 1)
|
||||
row += 1
|
||||
except:
|
||||
print("Issue adding " + str(building) + " to debriefing information")
|
||||
|
||||
self.layout.addWidget(lostUnits)
|
||||
|
||||
# Enemy lost units
|
||||
@@ -87,6 +95,14 @@ class QDebriefingWindow(QDialog):
|
||||
enemylostUnitsLayout.addWidget(QLabel("{}".format(count)), row, 1)
|
||||
row += 1
|
||||
|
||||
for building, count in self.debriefing.enemy_dead_buildings_dict.items():
|
||||
try:
|
||||
enemylostUnitsLayout.addWidget(QLabel(building), row, 0)
|
||||
enemylostUnitsLayout.addWidget(QLabel("{}".format(count)), row, 1)
|
||||
row += 1
|
||||
except:
|
||||
print("Issue adding " + str(building) + " to debriefing information")
|
||||
|
||||
self.layout.addWidget(enemylostUnits)
|
||||
|
||||
# confirm button
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import sys
|
||||
import webbrowser
|
||||
|
||||
from PySide2 import QtGui
|
||||
from PySide2.QtCore import Qt
|
||||
from PySide2.QtGui import QIcon
|
||||
from PySide2.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QMainWindow, QAction, QMessageBox, QDesktopWidget, \
|
||||
from PySide2.QtWidgets import QWidget, QVBoxLayout, QMainWindow, QAction, QMessageBox, QDesktopWidget, \
|
||||
QSplitter
|
||||
|
||||
import qt_ui.uiconstants as CONST
|
||||
@@ -12,10 +11,12 @@ from game import Game
|
||||
from qt_ui.uiconstants import URLS
|
||||
from qt_ui.widgets.QTopPanel import QTopPanel
|
||||
from qt_ui.widgets.map.QLiberationMap import QLiberationMap
|
||||
from qt_ui.windows.preferences import QLiberationPreferences
|
||||
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal, DebriefingSignal
|
||||
from qt_ui.windows.QDebriefingWindow import QDebriefingWindow
|
||||
from qt_ui.windows.QNewGameWizard import NewGameWizard
|
||||
from qt_ui.windows.infos.QInfoPanel import QInfoPanel
|
||||
from qt_ui.windows.preferences.QLiberationPreferencesWindow import QLiberationPreferencesWindow
|
||||
from userdata import persistency
|
||||
|
||||
|
||||
@@ -79,6 +80,10 @@ class QLiberationWindow(QMainWindow):
|
||||
self.showAboutDialogAction.setIcon(QIcon.fromTheme("help-about"))
|
||||
self.showAboutDialogAction.triggered.connect(self.showAboutDialog)
|
||||
|
||||
self.showLiberationPrefDialogAction = QAction("Preferences", self)
|
||||
self.showLiberationPrefDialogAction.setIcon(QIcon.fromTheme("help-about"))
|
||||
self.showLiberationPrefDialogAction.triggered.connect(self.showLiberationDialog)
|
||||
|
||||
def initToolbar(self):
|
||||
self.tool_bar = self.addToolBar("File")
|
||||
self.tool_bar.addAction(self.newGameAction)
|
||||
@@ -92,17 +97,21 @@ class QLiberationWindow(QMainWindow):
|
||||
file_menu.addAction(self.newGameAction)
|
||||
#file_menu.addAction(QIcon(CONST.ICONS["Open"]), "Open") # TODO : implement
|
||||
file_menu.addAction(self.saveGameAction)
|
||||
file_menu.addSeparator()
|
||||
file_menu.addAction(self.showLiberationPrefDialogAction)
|
||||
file_menu.addSeparator()
|
||||
#file_menu.addAction("Save As") # TODO : implement
|
||||
#file_menu.addAction("Close Current Game", lambda: self.closeGame()) # Not working
|
||||
file_menu.addAction("Exit" , lambda: self.exit())
|
||||
|
||||
|
||||
help_menu = self.menu.addMenu("Help")
|
||||
#help_menu.addAction("Online Manual", lambda: webbrowser.open_new_tab(URLS["Manual"]))
|
||||
help_menu.addAction("Online Manual", lambda: webbrowser.open_new_tab(URLS["Manual"]))
|
||||
help_menu.addAction("Discord", lambda: webbrowser.open_new_tab("https://" + "discord.gg" + "/" + "bKrt" + "rkJ"))
|
||||
#help_menu.addAction("Troubleshooting Guide", lambda: webbrowser.open_new_tab(URLS["Troubleshooting"]))
|
||||
#help_menu.addAction("Modding Guide", lambda: webbrowser.open_new_tab(URLS["Modding"]))
|
||||
#help_menu.addSeparator() ----> Note from Khopa : I disable these links since it's not up to date for this branch
|
||||
help_menu.addAction("Contribute", lambda: webbrowser.open_new_tab(URLS["Repository"]))
|
||||
#help_menu.addAction("Contribute", lambda: webbrowser.open_new_tab(URLS["Repository"]))
|
||||
help_menu.addAction("Forum Thread", lambda: webbrowser.open_new_tab(URLS["ForumThread"]))
|
||||
help_menu.addAction("Report an issue", lambda: webbrowser.open_new_tab(URLS["Issues"]))
|
||||
help_menu.addSeparator()
|
||||
@@ -192,6 +201,10 @@ class QLiberationWindow(QMainWindow):
|
||||
print(about.textFormat())
|
||||
about.exec_()
|
||||
|
||||
def showLiberationDialog(self):
|
||||
self.subwindow = QLiberationPreferencesWindow()
|
||||
self.subwindow.show()
|
||||
|
||||
def onDebriefing(self, debrief: DebriefingSignal):
|
||||
print("On Debriefing")
|
||||
self.debriefing = QDebriefingWindow(debrief.debriefing, debrief.gameEvent, debrief.game)
|
||||
|
||||
@@ -7,6 +7,7 @@ from dcs.task import CAP, CAS
|
||||
|
||||
import qt_ui.uiconstants as CONST
|
||||
from game import db, Game
|
||||
from gen import namegen
|
||||
from theater import start_generator, persiangulf, nevada, caucasus, ConflictTheater, normandy
|
||||
from userdata.logging import version_string
|
||||
|
||||
@@ -29,6 +30,7 @@ class NewGameWizard(QtWidgets.QWizard):
|
||||
self.generatedGame = None
|
||||
|
||||
def accept(self):
|
||||
|
||||
blueFaction = [c for c in db.FACTIONS if db.FACTIONS[c]["side"] == "blue"][self.field("blueFaction")]
|
||||
redFaction = [c for c in db.FACTIONS if db.FACTIONS[c]["side"] == "red"][self.field("redFaction")]
|
||||
playerIsBlue = self.field("playerIsBlue")
|
||||
@@ -36,11 +38,11 @@ class NewGameWizard(QtWidgets.QWizard):
|
||||
isTerrainNttr = self.field("isTerrainNttr")
|
||||
isTerrainCaucasusSmall = self.field("isTerrainCaucasusSmall")
|
||||
isTerrainCaucasusSmallInverted = self.field("isTerrainCaucasusSmallInverted")
|
||||
isTerrainCaucasusNorth= self.field("isTerrainCaucasusNorth")
|
||||
isIranianCampaignTheater = self.field("isIranianCampaignTheater")
|
||||
isTerrainNormandy = self.field("isTerrainNormandy")
|
||||
isTerrainEmirates = self.field("isTerrainEmirates")
|
||||
timePeriod = db.TIME_PERIODS[list(db.TIME_PERIODS.keys())[self.field("timePeriod")]]
|
||||
sams = self.field("sams")
|
||||
midGame = self.field("midGame")
|
||||
multiplier = self.field("multiplier")
|
||||
|
||||
@@ -55,6 +57,8 @@ class NewGameWizard(QtWidgets.QWizard):
|
||||
conflicttheater = caucasus.WesternGeorgia()
|
||||
elif isTerrainCaucasusSmallInverted:
|
||||
conflicttheater = caucasus.WesternGeorgiaInverted()
|
||||
elif isTerrainCaucasusNorth:
|
||||
conflicttheater = caucasus.NorthCaucasus()
|
||||
elif isIranianCampaignTheater:
|
||||
conflicttheater = persiangulf.IranianCampaign()
|
||||
elif isTerrainEmirates:
|
||||
@@ -64,27 +68,38 @@ class NewGameWizard(QtWidgets.QWizard):
|
||||
else:
|
||||
conflicttheater = caucasus.CaucasusTheater()
|
||||
|
||||
self.generatedGame = self.start_new_game(player_name, enemy_name, conflicttheater, sams, midGame, multiplier,
|
||||
self.generatedGame = self.start_new_game(player_name, enemy_name, conflicttheater, midGame, multiplier,
|
||||
timePeriod)
|
||||
|
||||
super(NewGameWizard, self).accept()
|
||||
|
||||
def start_new_game(self, player_name: str, enemy_name: str, conflicttheater: ConflictTheater, sams: bool,
|
||||
def start_new_game(self, player_name: str, enemy_name: str, conflicttheater: ConflictTheater,
|
||||
midgame: bool, multiplier: float, period: datetime):
|
||||
|
||||
if midgame:
|
||||
for i in range(0, int(len(conflicttheater.controlpoints) / 2)):
|
||||
conflicttheater.controlpoints[i].captured = True
|
||||
|
||||
start_generator.generate_inital_units(conflicttheater, enemy_name, sams, multiplier)
|
||||
# Reset name generator
|
||||
namegen.reset()
|
||||
|
||||
print("-- Starting New Game Generator")
|
||||
print("Enemy name : " + enemy_name)
|
||||
print("Player name : " + player_name)
|
||||
print("Midgame : " + str(midgame))
|
||||
start_generator.generate_inital_units(conflicttheater, enemy_name, True, multiplier)
|
||||
|
||||
print("-- Initial units generated")
|
||||
game = Game(player_name=player_name,
|
||||
enemy_name=enemy_name,
|
||||
theater=conflicttheater,
|
||||
start_date=period)
|
||||
|
||||
print("-- Game Object generated")
|
||||
start_generator.generate_groundobjects(conflicttheater, game)
|
||||
game.budget = int(game.budget * multiplier)
|
||||
game.settings.multiplier = multiplier
|
||||
game.settings.sams = sams
|
||||
game.settings.sams = True
|
||||
game.settings.version = version_string()
|
||||
|
||||
if midgame:
|
||||
@@ -206,12 +221,14 @@ class TheaterConfiguration(QtWidgets.QWizardPage):
|
||||
|
||||
# Terrain selection
|
||||
terrainGroup = QtWidgets.QGroupBox("Terrain")
|
||||
terrainCaucasusSmall = QtWidgets.QRadioButton("Caucasus - Western Georgia [RECOMMENDED]")
|
||||
terrainCaucasusSmall = QtWidgets.QRadioButton("Caucasus - Western Georgia [RECOMMENDED - Early Cold War Era]")
|
||||
terrainCaucasusSmall.setIcon(QtGui.QIcon(CONST.ICONS["Terrain_Caucasus"]))
|
||||
terrainCaucasusSmallInverted = QtWidgets.QRadioButton("Caucasus - Western Georgia Inverted [RECOMMENDED]")
|
||||
terrainCaucasusSmallInverted = QtWidgets.QRadioButton("Caucasus - Western Georgia Inverted [RECOMMENDED - Early Cold War Era]")
|
||||
terrainCaucasusSmallInverted.setIcon(QtGui.QIcon(CONST.ICONS["Terrain_Caucasus"]))
|
||||
terrainCaucasus = QtWidgets.QRadioButton("Caucasus - Full map [NOT TESTED]")
|
||||
terrainCaucasus.setIcon(QtGui.QIcon(CONST.ICONS["Terrain_Caucasus"]))
|
||||
terrainCaucasusNorth = QtWidgets.QRadioButton("Caucasus - North - [RECOMMENDED - Modern Era]")
|
||||
terrainCaucasusNorth.setIcon(QtGui.QIcon(CONST.ICONS["Terrain_Caucasus"]))
|
||||
|
||||
terrainPg = QtWidgets.QRadioButton("Persian Gulf - Full Map [NOT TESTED]")
|
||||
terrainPg.setIcon(QtGui.QIcon(CONST.ICONS["Terrain_Persian_Gulf"]))
|
||||
@@ -238,6 +255,7 @@ class TheaterConfiguration(QtWidgets.QWizardPage):
|
||||
self.registerField('isTerrainCaucasus', terrainCaucasus)
|
||||
self.registerField('isTerrainCaucasusSmall', terrainCaucasusSmall)
|
||||
self.registerField('isTerrainCaucasusSmallInverted', terrainCaucasusSmallInverted)
|
||||
self.registerField('isTerrainCaucasusNorth', terrainCaucasusNorth)
|
||||
self.registerField('isTerrainPg', terrainPg)
|
||||
self.registerField('isIranianCampaignTheater', terrainIran)
|
||||
self.registerField('isTerrainEmirates', terrainEmirates)
|
||||
@@ -249,6 +267,7 @@ class TheaterConfiguration(QtWidgets.QWizardPage):
|
||||
terrainGroupLayout = QtWidgets.QVBoxLayout()
|
||||
terrainGroupLayout.addWidget(terrainCaucasusSmall)
|
||||
terrainGroupLayout.addWidget(terrainCaucasusSmallInverted)
|
||||
terrainGroupLayout.addWidget(terrainCaucasusNorth)
|
||||
terrainGroupLayout.addWidget(terrainCaucasus)
|
||||
terrainGroupLayout.addWidget(terrainIran)
|
||||
terrainGroupLayout.addWidget(terrainEmirates)
|
||||
@@ -278,21 +297,16 @@ class MiscOptions(QtWidgets.QWizardPage):
|
||||
self.setPixmap(QtWidgets.QWizard.LogoPixmap,
|
||||
QtGui.QPixmap('./resources/ui/wizard/logo1.png'))
|
||||
|
||||
sams = QtWidgets.QCheckBox()
|
||||
sams.setChecked(True)
|
||||
midGame = QtWidgets.QCheckBox()
|
||||
multiplier = QtWidgets.QSpinBox()
|
||||
multiplier.setEnabled(False)
|
||||
multiplier.setMinimum(1)
|
||||
multiplier.setMaximum(5)
|
||||
|
||||
self.registerField('sams', sams)
|
||||
self.registerField('midGame', midGame)
|
||||
self.registerField('multiplier', multiplier)
|
||||
|
||||
layout = QtWidgets.QGridLayout()
|
||||
#layout.addWidget(QtWidgets.QLabel("With SAM Systems :"), 0, 0)
|
||||
#layout.addWidget(sams, 0, 1)
|
||||
layout.addWidget(QtWidgets.QLabel("Start at mid game"), 1, 0)
|
||||
layout.addWidget(midGame, 1, 1)
|
||||
layout.addWidget(QtWidgets.QLabel("Ennemy forces multiplier [Disabled for Now]"), 2, 0)
|
||||
|
||||
@@ -38,7 +38,7 @@ class QMissionPlanning(QDialog):
|
||||
self.planned_flight_view.set_flight_planner(self.planner)
|
||||
self.selected_cp = self.captured_cp[0]
|
||||
|
||||
self.planned_flight_view.selectionModel().setCurrentIndex(self.planned_flight_view.indexAt(QPoint(1, 1)), QItemSelectionModel.Select)
|
||||
self.planned_flight_view.selectionModel().setCurrentIndex(self.planned_flight_view.indexAt(QPoint(1, 1)), QItemSelectionModel.Rows)
|
||||
self.planned_flight_view.selectionModel().selectionChanged.connect(self.on_flight_selection_change)
|
||||
|
||||
if len(self.planned_flight_view.flight_planner.flights) > 0:
|
||||
@@ -83,15 +83,24 @@ class QMissionPlanning(QDialog):
|
||||
else:
|
||||
self.planned_flight_view.set_flight_planner(None)
|
||||
|
||||
print(self.selected_cp.id)
|
||||
|
||||
def on_flight_selection_change(self):
|
||||
index = self.planned_flight_view.selectionModel().currentIndex().row()
|
||||
flight = self.planner.flights[index]
|
||||
|
||||
print("On flight selection change")
|
||||
|
||||
index = self.planned_flight_view.selectionModel().currentIndex().row()
|
||||
self.planned_flight_view.repaint();
|
||||
|
||||
if self.flight_planner is not None:
|
||||
self.flight_planner.clearTabs()
|
||||
|
||||
try:
|
||||
flight = self.planner.flights[index]
|
||||
except IndexError:
|
||||
flight = None
|
||||
self.flight_planner = QFlightPlanner(flight, self.game, self.planner)
|
||||
self.layout.addWidget(self.flight_planner, 0, 1)
|
||||
|
||||
|
||||
def on_add_flight(self):
|
||||
possible_aircraft_type = list(self.selected_cp.base.aircraft.keys())
|
||||
|
||||
@@ -110,7 +119,8 @@ class QMissionPlanning(QDialog):
|
||||
def on_delete_flight(self):
|
||||
index = self.planned_flight_view.selectionModel().currentIndex().row()
|
||||
self.planner.remove_flight(index)
|
||||
self.planned_flight_view.set_flight_planner(self.planner)
|
||||
self.planned_flight_view.set_flight_planner(self.planner, index)
|
||||
|
||||
|
||||
def on_start(self):
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from PySide2.QtCore import QSize
|
||||
from PySide2.QtCore import QSize, QItemSelectionModel, QPoint
|
||||
from PySide2.QtGui import QStandardItemModel
|
||||
from PySide2.QtWidgets import QListView
|
||||
from PySide2.QtWidgets import QListView, QAbstractItemView
|
||||
|
||||
from gen.flights.ai_flight_planner import FlightPlanner
|
||||
from qt_ui.windows.mission.QFlightItem import QFlightItem
|
||||
@@ -13,18 +13,29 @@ class QPlannedFlightsView(QListView):
|
||||
self.model = QStandardItemModel(self)
|
||||
self.setModel(self.model)
|
||||
self.setIconSize(QSize(91, 24))
|
||||
self.setSelectionBehavior(QAbstractItemView.SelectItems)
|
||||
if flight_planner:
|
||||
self.set_flight_planner(flight_planner)
|
||||
|
||||
def update_content(self):
|
||||
def update_content(self, row=0):
|
||||
for i, f in enumerate(self.flight_planner.flights):
|
||||
self.model.appendRow(QFlightItem(f))
|
||||
self.setSelectedFlight(row)
|
||||
self.repaint()
|
||||
|
||||
def setSelectedFlight(self, row):
|
||||
self.selectionModel().clearSelection()
|
||||
index = self.model.index(row, 0)
|
||||
if not index.isValid():
|
||||
index = self.model.index(0, 0)
|
||||
self.selectionModel().setCurrentIndex(index, QItemSelectionModel.Select)
|
||||
self.repaint()
|
||||
|
||||
def clear_layout(self):
|
||||
self.model.removeRows(0, self.model.rowCount())
|
||||
|
||||
def set_flight_planner(self, flight_planner: FlightPlanner):
|
||||
def set_flight_planner(self, flight_planner: FlightPlanner, row=0):
|
||||
self.clear_layout()
|
||||
self.flight_planner = flight_planner
|
||||
if self.flight_planner:
|
||||
self.update_content()
|
||||
self.update_content(row)
|
||||
|
||||
@@ -111,6 +111,6 @@ class QFlightCreator(QDialog):
|
||||
self.planner.flights.append(flight)
|
||||
self.planner.custom_flights.append(flight)
|
||||
if self.flight_view is not None:
|
||||
self.flight_view.set_flight_planner(self.planner)
|
||||
self.flight_view.set_flight_planner(self.planner, len(self.planner.flights)-1)
|
||||
self.close()
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ class QFlightPlanner(QTabWidget):
|
||||
|
||||
def __init__(self, flight: Flight, game: Game, planner):
|
||||
super(QFlightPlanner, self).__init__()
|
||||
self.tabCount = 0
|
||||
if flight:
|
||||
self.general_settings_tab = QGeneralFlightSettingsTab(flight, game, planner)
|
||||
self.payload_tab = QFlightPayloadTab(flight, game)
|
||||
@@ -18,9 +19,15 @@ class QFlightPlanner(QTabWidget):
|
||||
self.addTab(self.general_settings_tab, "General Flight settings")
|
||||
self.addTab(self.payload_tab, "Payload")
|
||||
self.addTab(self.waypoint_tab, "Waypoints")
|
||||
self.tabCount = 3
|
||||
else:
|
||||
tabError = QFrame()
|
||||
l = QGridLayout()
|
||||
l.addWidget(QLabel("No flight selected"))
|
||||
tabError.setLayout(l)
|
||||
self.addTab(tabError, "No flight")
|
||||
self.addTab(tabError, "No flight")
|
||||
self.tabCount = 1
|
||||
|
||||
def clearTabs(self):
|
||||
for i in range(self.tabCount):
|
||||
self.removeTab(i)
|
||||
80
qt_ui/windows/preferences/QLiberationFirstStartWindow.py
Normal file
80
qt_ui/windows/preferences/QLiberationFirstStartWindow.py
Normal file
@@ -0,0 +1,80 @@
|
||||
from PySide2.QtGui import QIcon, Qt
|
||||
from PySide2.QtWidgets import QDialog, QVBoxLayout, QPushButton, QHBoxLayout, QPlainTextEdit, QTextEdit
|
||||
|
||||
from qt_ui.windows.preferences.QLiberationPreferences import QLiberationPreferences
|
||||
|
||||
|
||||
class QLiberationFirstStartWindow(QDialog):
|
||||
|
||||
def __init__(self):
|
||||
super(QLiberationFirstStartWindow, self).__init__()
|
||||
|
||||
self.setModal(True)
|
||||
self.setWindowTitle("First start configuration")
|
||||
self.setMinimumSize(500, 200)
|
||||
self.setWindowIcon(QIcon("./resources/icon.png"))
|
||||
self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.Dialog | Qt.WindowTitleHint)
|
||||
self.setWindowModality(Qt.WindowModal)
|
||||
self.preferences = QLiberationPreferences()
|
||||
|
||||
WARN_TEXT = """
|
||||
<strong>Welcome to DCS Liberation !</strong>
|
||||
<br/><br>
|
||||
<strong>Please take 30 seconds to read this :</strong>
|
||||
|
||||
<p>DCS Liberation will modify this file in your DCS installation directory :</p>
|
||||
<br/>
|
||||
<strong><dcs_installation_directory>/Scripts/MissionScripting.lua</strong><br/>
|
||||
|
||||
<p>
|
||||
This will disable some security limits of the DCS World Lua scripting environment, in order to allow communication between DCS World and DCS Liberation.
|
||||
However, the modification of this file could potentially grant access to your filesystem to malicious DCS mission files.
|
||||
</p>
|
||||
|
||||
<p>So, you should not join untrusted servers or open untrusted mission files within DCS world while DCS Liberation is running.</p>
|
||||
|
||||
<p>
|
||||
DCS Liberation will restore your original MissionScripting file when it close.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
However, should DCS Liberation encounter an unexpected crash (which should not happen), the MissionScripting file might not be restored.
|
||||
If that occurs, you can use the backup file saved in the DCS Liberation directory there :
|
||||
</p>
|
||||
|
||||
<br/>
|
||||
<strong>./resources/scripts/MissionScripting.original.lua</strong><br/>
|
||||
|
||||
<p>Then copy it in your DCS installation directory to replace this file :</p>
|
||||
|
||||
<br/>
|
||||
<strong><dcs_installation_directory>/Scripts/MissionScripting.lua</strong><br/>
|
||||
|
||||
<p>As you click on the button below, the file will be replaced in your DCS installation directory.</p>
|
||||
|
||||
<br/><br/>
|
||||
|
||||
<strong>Thank you for reading !</strong>
|
||||
"""
|
||||
self.warning_text = QTextEdit(WARN_TEXT)
|
||||
self.warning_text.setReadOnly(True)
|
||||
self.apply_button = QPushButton("I have read everything and I Accept")
|
||||
self.apply_button.clicked.connect(lambda : self.apply())
|
||||
self.initUI()
|
||||
|
||||
def initUI(self):
|
||||
layout = QVBoxLayout()
|
||||
layout.addWidget(self.preferences)
|
||||
layout.addWidget(self.warning_text)
|
||||
layout.addStretch()
|
||||
apply_btn_layout = QHBoxLayout()
|
||||
apply_btn_layout.addStretch()
|
||||
apply_btn_layout.addWidget(self.apply_button)
|
||||
layout.addLayout(apply_btn_layout)
|
||||
self.setLayout(layout)
|
||||
|
||||
def apply(self):
|
||||
print("Applying changes")
|
||||
if self.preferences.apply():
|
||||
self.close()
|
||||
|
||||
93
qt_ui/windows/preferences/QLiberationPreferences.py
Normal file
93
qt_ui/windows/preferences/QLiberationPreferences.py
Normal file
@@ -0,0 +1,93 @@
|
||||
import os
|
||||
|
||||
from PySide2 import QtWidgets
|
||||
from PySide2.QtGui import Qt
|
||||
from PySide2.QtWidgets import QFrame, QLineEdit, QGridLayout, QVBoxLayout, QLabel, QPushButton, \
|
||||
QFileDialog, QMessageBox, QDialog
|
||||
|
||||
from userdata import liberation_install
|
||||
|
||||
|
||||
class QLiberationPreferences(QFrame):
|
||||
|
||||
def __init__(self):
|
||||
super(QLiberationPreferences, self).__init__()
|
||||
self.saved_game_dir = ""
|
||||
self.dcs_install_dir = ""
|
||||
|
||||
self.dcs_install_dir = liberation_install.get_dcs_install_directory()
|
||||
self.saved_game_dir = liberation_install.get_saved_game_dir()
|
||||
|
||||
self.edit_dcs_install_dir = QLineEdit(self.dcs_install_dir)
|
||||
self.edit_saved_game_dir = QLineEdit(self.saved_game_dir)
|
||||
|
||||
self.edit_dcs_install_dir.setMinimumWidth(300)
|
||||
self.edit_saved_game_dir.setMinimumWidth(300)
|
||||
|
||||
self.browse_saved_game = QPushButton("Browse...")
|
||||
self.browse_saved_game.clicked.connect(self.on_browse_saved_games)
|
||||
self.browse_install_dir = QPushButton("Browse...")
|
||||
self.browse_install_dir.clicked.connect(self.on_browse_installation_dir)
|
||||
|
||||
self.initUi()
|
||||
|
||||
def initUi(self):
|
||||
main_layout = QVBoxLayout()
|
||||
layout = QGridLayout()
|
||||
layout.addWidget(QLabel("<strong>DCS saved game directory:</strong>"), 0, 0, alignment=Qt.AlignLeft)
|
||||
layout.addWidget(self.edit_saved_game_dir, 1, 0, alignment=Qt.AlignRight)
|
||||
layout.addWidget(self.browse_saved_game, 1, 1, alignment=Qt.AlignRight)
|
||||
layout.addWidget(QLabel("<strong>DCS installation directory:</strong>"), 2, 0, alignment=Qt.AlignLeft)
|
||||
layout.addWidget(self.edit_dcs_install_dir, 3, 0, alignment=Qt.AlignRight)
|
||||
layout.addWidget(self.browse_install_dir, 3, 1, alignment=Qt.AlignRight)
|
||||
|
||||
main_layout.addLayout(layout)
|
||||
main_layout.addStretch()
|
||||
|
||||
self.setLayout(main_layout)
|
||||
|
||||
def on_browse_saved_games(self):
|
||||
saved_game_dir = str(QFileDialog.getExistingDirectory(self, "Select DCS Saved Game Directory"))
|
||||
if saved_game_dir:
|
||||
self.saved_game_dir = saved_game_dir
|
||||
self.edit_saved_game_dir.setText(saved_game_dir)
|
||||
|
||||
def on_browse_installation_dir(self):
|
||||
install_dir = str(QFileDialog.getExistingDirectory(self, "Select DCS Installation Directory"))
|
||||
if install_dir:
|
||||
self.dcs_install_dir = install_dir
|
||||
self.edit_dcs_install_dir.setText(install_dir)
|
||||
|
||||
def apply(self):
|
||||
|
||||
print("Applying changes")
|
||||
self.saved_game_dir = self.edit_saved_game_dir.text()
|
||||
self.dcs_install_dir = self.edit_dcs_install_dir.text()
|
||||
|
||||
if not os.path.isdir(self.saved_game_dir):
|
||||
error_dialog = QMessageBox.critical(self, "Wrong DCS Saved Games directory.",
|
||||
self.saved_game_dir + " is not a valid directory",
|
||||
QMessageBox.StandardButton.Ok)
|
||||
error_dialog.exec_()
|
||||
return False
|
||||
|
||||
if not os.path.isdir(self.dcs_install_dir):
|
||||
error_dialog = QMessageBox.critical(self, "Wrong DCS installation directory.",
|
||||
self.dcs_install_dir + " is not a valid directory",
|
||||
QMessageBox.StandardButton.Ok)
|
||||
error_dialog.exec_()
|
||||
return False
|
||||
|
||||
if not os.path.isdir(os.path.join(self.dcs_install_dir, "Scripts")) and os.path.isfile(os.path.join(self.dcs_install_dir, "bin", "DCS.exe")):
|
||||
error_dialog = QMessageBox.critical(self, "Wrong DCS installation directory.",
|
||||
self.dcs_install_dir + " is not a valid DCS installation directory",
|
||||
QMessageBox.StandardButton.Ok)
|
||||
error_dialog.exec_()
|
||||
return False
|
||||
|
||||
liberation_install.setup(self.saved_game_dir, self.dcs_install_dir)
|
||||
liberation_install.save_config()
|
||||
return True
|
||||
|
||||
|
||||
|
||||
37
qt_ui/windows/preferences/QLiberationPreferencesWindow.py
Normal file
37
qt_ui/windows/preferences/QLiberationPreferencesWindow.py
Normal file
@@ -0,0 +1,37 @@
|
||||
from PySide2.QtGui import QIcon, Qt
|
||||
from PySide2.QtWidgets import QDialog, QVBoxLayout, QPushButton, QHBoxLayout
|
||||
|
||||
from qt_ui.windows.preferences.QLiberationPreferences import QLiberationPreferences
|
||||
|
||||
|
||||
class QLiberationPreferencesWindow(QDialog):
|
||||
|
||||
def __init__(self):
|
||||
super(QLiberationPreferencesWindow, self).__init__()
|
||||
|
||||
self.setModal(True)
|
||||
self.setWindowTitle("Preferences")
|
||||
self.setMinimumSize(300, 200)
|
||||
self.setWindowIcon(QIcon("./resources/icon.png"))
|
||||
self.preferences = QLiberationPreferences()
|
||||
self.apply_button = QPushButton("Apply")
|
||||
self.apply_button.clicked.connect(lambda : self.apply())
|
||||
self.initUI()
|
||||
|
||||
def initUI(self):
|
||||
layout = QVBoxLayout()
|
||||
layout.addWidget(self.preferences)
|
||||
layout.addStretch()
|
||||
apply_btn_layout = QHBoxLayout()
|
||||
apply_btn_layout.addStretch()
|
||||
apply_btn_layout.addWidget(self.apply_button)
|
||||
layout.addLayout(apply_btn_layout)
|
||||
self.setLayout(layout)
|
||||
|
||||
def apply(self):
|
||||
if self.preferences.apply():
|
||||
print("Closing")
|
||||
self.close()
|
||||
else:
|
||||
print("Not Closing")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
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, \
|
||||
QAbstractItemView, QPushButton, QGroupBox, QCheckBox
|
||||
QAbstractItemView, QPushButton, QGroupBox, QCheckBox, QVBoxLayout
|
||||
|
||||
import qt_ui.uiconstants as CONST
|
||||
from game.game import Game
|
||||
@@ -98,11 +98,11 @@ class QSettingsWindow(QDialog):
|
||||
self.enemyAASkill.currentIndexChanged.connect(self.applySettings)
|
||||
|
||||
self.difficultyLayout.addWidget(QLabel("Player coalition skill"), 0, 0)
|
||||
self.difficultyLayout.addWidget(self.playerCoalitionSkill, 0, 1)
|
||||
self.difficultyLayout.addWidget(self.playerCoalitionSkill, 0, 1, Qt.AlignRight)
|
||||
self.difficultyLayout.addWidget(QLabel("Enemy skill"), 1, 0)
|
||||
self.difficultyLayout.addWidget(self.enemyCoalitionSkill, 1, 1)
|
||||
self.difficultyLayout.addWidget(self.enemyCoalitionSkill, 1, 1, Qt.AlignRight)
|
||||
self.difficultyLayout.addWidget(QLabel("Enemy AA and vehicles skill"), 2, 0)
|
||||
self.difficultyLayout.addWidget(self.enemyAASkill, 2, 1)
|
||||
self.difficultyLayout.addWidget(self.enemyAASkill, 2, 1, Qt.AlignRight)
|
||||
|
||||
self.difficultyLabel = QComboBox()
|
||||
[self.difficultyLabel.addItem(t) for t in CONST.LABELS_OPTIONS]
|
||||
@@ -110,43 +110,78 @@ class QSettingsWindow(QDialog):
|
||||
self.difficultyLabel.currentIndexChanged.connect(self.applySettings)
|
||||
|
||||
self.difficultyLayout.addWidget(QLabel("In Game Labels"), 3, 0)
|
||||
self.difficultyLayout.addWidget(self.difficultyLabel, 3, 1)
|
||||
self.difficultyLayout.addWidget(self.difficultyLabel, 3, 1, Qt.AlignRight)
|
||||
|
||||
self.noNightMission = QCheckBox()
|
||||
self.noNightMission.setChecked(self.game.settings.night_disabled)
|
||||
self.noNightMission.toggled.connect(self.applySettings)
|
||||
self.difficultyLayout.addWidget(QLabel("No night missions"), 4, 0)
|
||||
self.difficultyLayout.addWidget(self.noNightMission, 4, 1)
|
||||
self.difficultyLayout.addWidget(self.noNightMission, 4, 1, Qt.AlignRight)
|
||||
|
||||
|
||||
def initGeneratorLayout(self):
|
||||
self.generatorPage = QWidget()
|
||||
self.generatorLayout = QGridLayout()
|
||||
self.generatorLayout = QVBoxLayout()
|
||||
self.generatorLayout.setAlignment(Qt.AlignTop)
|
||||
self.generatorPage.setLayout(self.generatorLayout)
|
||||
|
||||
self.coldStart = QCheckBox()
|
||||
self.coldStart.setChecked(self.game.settings.cold_start)
|
||||
self.coldStart.toggled.connect(self.applySettings)
|
||||
self.takeOffOnlyForPlayerGroup = QCheckBox()
|
||||
self.takeOffOnlyForPlayerGroup.setChecked(self.game.settings.only_player_takeoff)
|
||||
self.takeOffOnlyForPlayerGroup.toggled.connect(self.applySettings)
|
||||
|
||||
self.coldStart = QCheckBox()
|
||||
self.coldStart.setChecked(self.game.settings.cold_start)
|
||||
self.coldStart.toggled.connect(self.applySettings)
|
||||
self.gameplay = QGroupBox("Gameplay")
|
||||
self.gameplayLayout = QGridLayout();
|
||||
self.gameplayLayout.setAlignment(Qt.AlignTop)
|
||||
self.gameplay.setLayout(self.gameplayLayout)
|
||||
|
||||
self.supercarrier = QCheckBox()
|
||||
self.supercarrier.setChecked(self.game.settings.supercarrier)
|
||||
self.supercarrier.toggled.connect(self.applySettings)
|
||||
|
||||
# Settings not used anymore
|
||||
# self.generatorLayout.addWidget(QLabel("Aircraft cold start"), 0, 0)
|
||||
# self.generatorLayout.addWidget(self.coldStart, 0, 1)
|
||||
# self.generatorLayout.addWidget(QLabel("Takeoff only for player group"), 1, 0)
|
||||
# self.generatorLayout.addWidget(self.takeOffOnlyForPlayerGroup, 1, 1)
|
||||
self.generatorLayout.addWidget(QLabel("Use Supercarrier Module"), 0, 0)
|
||||
self.generatorLayout.addWidget(self.supercarrier, 0, 1)
|
||||
self.gameplayLayout.addWidget(QLabel("Use Supercarrier Module"), 0, 0)
|
||||
self.gameplayLayout.addWidget(self.supercarrier, 0, 1, Qt.AlignRight)
|
||||
|
||||
self.performance = QGroupBox("Performance")
|
||||
self.performanceLayout = QGridLayout();
|
||||
self.performanceLayout.setAlignment(Qt.AlignTop)
|
||||
self.performance.setLayout(self.performanceLayout)
|
||||
|
||||
self.smoke = QCheckBox()
|
||||
self.smoke.setChecked(self.game.settings.perf_smoke_gen)
|
||||
self.smoke.toggled.connect(self.applySettings)
|
||||
|
||||
self.red_alert = QCheckBox()
|
||||
self.red_alert.setChecked(self.game.settings.perf_red_alert_state)
|
||||
self.red_alert.toggled.connect(self.applySettings)
|
||||
|
||||
self.arti = QCheckBox()
|
||||
self.arti.setChecked(self.game.settings.perf_artillery)
|
||||
self.arti.toggled.connect(self.applySettings)
|
||||
|
||||
self.moving_units = QCheckBox()
|
||||
self.moving_units.setChecked(self.game.settings.perf_moving_units)
|
||||
self.moving_units.toggled.connect(self.applySettings)
|
||||
|
||||
self.infantry = QCheckBox()
|
||||
self.infantry.setChecked(self.game.settings.perf_infantry)
|
||||
self.infantry.toggled.connect(self.applySettings)
|
||||
|
||||
self.ai_parking_start = QCheckBox()
|
||||
self.ai_parking_start.setChecked(self.game.settings.perf_ai_parking_start)
|
||||
self.ai_parking_start.toggled.connect(self.applySettings)
|
||||
|
||||
self.performanceLayout.addWidget(QLabel("Smoke visual effect on frontline"), 0, 0)
|
||||
self.performanceLayout.addWidget(self.smoke, 0, 1, alignment=Qt.AlignRight)
|
||||
self.performanceLayout.addWidget(QLabel("SAM starts in RED alert mode"), 1, 0)
|
||||
self.performanceLayout.addWidget(self.red_alert, 1, 1, alignment=Qt.AlignRight)
|
||||
self.performanceLayout.addWidget(QLabel("Artillery strikes"), 2, 0)
|
||||
self.performanceLayout.addWidget(self.arti, 2, 1, alignment=Qt.AlignRight)
|
||||
self.performanceLayout.addWidget(QLabel("Moving ground units"), 3, 0)
|
||||
self.performanceLayout.addWidget(self.moving_units, 3, 1, alignment=Qt.AlignRight)
|
||||
self.performanceLayout.addWidget(QLabel("Generate infantry squads along vehicles"), 4, 0)
|
||||
self.performanceLayout.addWidget(self.infantry, 4, 1, alignment=Qt.AlignRight)
|
||||
self.performanceLayout.addWidget(QLabel("AI planes parking start (AI starts in flight if disabled)"), 5, 0)
|
||||
self.performanceLayout.addWidget(self.ai_parking_start, 5, 1, alignment=Qt.AlignRight)
|
||||
|
||||
self.generatorLayout.addWidget(self.gameplay)
|
||||
self.generatorLayout.addWidget(QLabel("Disabling settings below may improve performance, but will impact the overall quality of the experience."))
|
||||
self.generatorLayout.addWidget(self.performance)
|
||||
|
||||
|
||||
def initCheatLayout(self):
|
||||
@@ -194,10 +229,15 @@ class QSettingsWindow(QDialog):
|
||||
self.game.settings.enemy_vehicle_skill = CONST.SKILL_OPTIONS[self.enemyAASkill.currentIndex()]
|
||||
self.game.settings.labels = CONST.LABELS_OPTIONS[self.difficultyLabel.currentIndex()]
|
||||
self.game.settings.night_disabled = self.noNightMission.isChecked()
|
||||
self.game.settings.only_player_takeoff = self.takeOffOnlyForPlayerGroup.isChecked()
|
||||
self.game.settings.cold_start = self.coldStart.isChecked()
|
||||
self.game.settings.supercarrier = self.supercarrier.isChecked()
|
||||
|
||||
self.game.settings.perf_red_alert_state = self.red_alert.isChecked()
|
||||
self.game.settings.perf_smoke_gen = self.smoke.isChecked()
|
||||
self.game.settings.perf_artillery = self.arti.isChecked()
|
||||
self.game.settings.perf_moving_units = self.moving_units.isChecked()
|
||||
self.game.settings.perf_infantry = self.infantry.isChecked()
|
||||
self.game.settings.perf_ai_parking_start = self.ai_parking_start.isChecked()
|
||||
|
||||
GameUpdateSignal.get_instance().updateGame(self.game)
|
||||
|
||||
def onSelectionChanged(self):
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
pydcs>=0.9.4
|
||||
Pyside2>=5.13.0
|
||||
pyinstaller==3.5
|
||||
pyproj==2.6.1.post1
|
||||
|
||||
Binary file not shown.
62
resources/customized_payloads/Bf-109K-4.lua
Normal file
62
resources/customized_payloads/Bf-109K-4.lua
Normal file
@@ -0,0 +1,62 @@
|
||||
local unitPayloads = {
|
||||
["name"] = "Bf-109K-4",
|
||||
["payloads"] = {
|
||||
[1] = {
|
||||
["name"] = "STRIKE",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "SC_501_SC500",
|
||||
["num"] = 1,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 34,
|
||||
[2] = 31,
|
||||
[3] = 30,
|
||||
[4] = 32,
|
||||
},
|
||||
},
|
||||
[2] = {
|
||||
["name"] = "CAS",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "SC_501_SC250",
|
||||
["num"] = 1,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 34,
|
||||
[2] = 31,
|
||||
[3] = 30,
|
||||
[4] = 32,
|
||||
},
|
||||
},
|
||||
[3] = {
|
||||
["name"] = "CAP",
|
||||
["pylons"] = {
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 31,
|
||||
},
|
||||
},
|
||||
[4] = {
|
||||
["name"] = "ANTISHIP",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "SC_501_SC500",
|
||||
["num"] = 1,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 34,
|
||||
[2] = 31,
|
||||
[3] = 30,
|
||||
[4] = 32,
|
||||
},
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
},
|
||||
["unitType"] = "Bf-109K-4",
|
||||
}
|
||||
return unitPayloads
|
||||
61
resources/customized_payloads/FW-190A8.lua
Normal file
61
resources/customized_payloads/FW-190A8.lua
Normal file
@@ -0,0 +1,61 @@
|
||||
local unitPayloads = {
|
||||
["name"] = "FW-190A8",
|
||||
["payloads"] = {
|
||||
[1] = {
|
||||
["name"] = "CAS",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{WGr21}",
|
||||
["num"] = 3,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{WGr21}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{SC_250_T1_L2}",
|
||||
["num"] = 1,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 31,
|
||||
},
|
||||
},
|
||||
[2] = {
|
||||
["name"] = "STRIKE",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{SD_500_A}",
|
||||
["num"] = 1,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 31,
|
||||
},
|
||||
},
|
||||
[3] = {
|
||||
["name"] = "ANTISHIP",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{SD_500_A}",
|
||||
["num"] = 1,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 31,
|
||||
},
|
||||
},
|
||||
[4] = {
|
||||
["name"] = "CAP",
|
||||
["pylons"] = {
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 31,
|
||||
},
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
},
|
||||
["unitType"] = "FW-190A8",
|
||||
}
|
||||
return unitPayloads
|
||||
70
resources/customized_payloads/FW-190D9.lua
Normal file
70
resources/customized_payloads/FW-190D9.lua
Normal file
@@ -0,0 +1,70 @@
|
||||
local unitPayloads = {
|
||||
["name"] = "FW-190D9",
|
||||
["payloads"] = {
|
||||
[1] = {
|
||||
["name"] = "ANTISHIP",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{WGr21}",
|
||||
["num"] = 3,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{WGr21}",
|
||||
["num"] = 2,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 11,
|
||||
[2] = 10,
|
||||
[3] = 32,
|
||||
[4] = 31,
|
||||
},
|
||||
},
|
||||
[2] = {
|
||||
["name"] = "STRIKE",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "SC_501_SC500",
|
||||
["num"] = 1,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 34,
|
||||
[2] = 31,
|
||||
[3] = 30,
|
||||
[4] = 32,
|
||||
},
|
||||
},
|
||||
[3] = {
|
||||
["name"] = "CAS",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{WGr21}",
|
||||
["num"] = 3,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{WGr21}",
|
||||
["num"] = 2,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 11,
|
||||
[2] = 10,
|
||||
[3] = 32,
|
||||
[4] = 31,
|
||||
},
|
||||
},
|
||||
[4] = {
|
||||
["name"] = "CAP",
|
||||
["pylons"] = {
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 31,
|
||||
},
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
},
|
||||
["unitType"] = "FW-190D9",
|
||||
}
|
||||
return unitPayloads
|
||||
@@ -73,33 +73,29 @@ local unitPayloads = {
|
||||
["name"] = "STRIKE",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "DIS_WMD7",
|
||||
["num"] = 4,
|
||||
["CLSID"] = "DIS_LS_6_500",
|
||||
["num"] = 6,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "DIS_LS_6_500",
|
||||
["num"] = 5,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "DIS_LS_6_500",
|
||||
["num"] = 3,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "DIS_LS_6_500",
|
||||
["num"] = 2,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "DIS_PL-5EII",
|
||||
["num"] = 1,
|
||||
},
|
||||
[3] = {
|
||||
[6] = {
|
||||
["CLSID"] = "DIS_PL-5EII",
|
||||
["num"] = 7,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "DIS_GBU_12_DUAL",
|
||||
["num"] = 6,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "DIS_GBU_12_DUAL",
|
||||
["num"] = 2,
|
||||
},
|
||||
[6] = {
|
||||
["CLSID"] = "DIS_GBU_16",
|
||||
["num"] = 3,
|
||||
},
|
||||
[7] = {
|
||||
["CLSID"] = "DIS_GBU_16",
|
||||
["num"] = 5,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 10,
|
||||
|
||||
49
resources/customized_payloads/Ju-88A4.lua
Normal file
49
resources/customized_payloads/Ju-88A4.lua
Normal file
@@ -0,0 +1,49 @@
|
||||
local unitPayloads = {
|
||||
["name"] = "Ju-88A4",
|
||||
["payloads"] = {
|
||||
[1] = {
|
||||
["name"] = "ANTISHIP",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{LTF_5B}",
|
||||
["num"] = 1,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{LTF_5B}",
|
||||
["num"] = 3,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 32,
|
||||
},
|
||||
},
|
||||
[2] = {
|
||||
["name"] = "CAS",
|
||||
["pylons"] = {
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 32,
|
||||
},
|
||||
},
|
||||
[3] = {
|
||||
["name"] = "STRIKE",
|
||||
["pylons"] = {
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 32,
|
||||
},
|
||||
},
|
||||
[4] = {
|
||||
["name"] = "CAP",
|
||||
["pylons"] = {
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 32,
|
||||
},
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
},
|
||||
["unitType"] = "Ju-88A4",
|
||||
}
|
||||
return unitPayloads
|
||||
85
resources/customized_payloads/P-47D-30.lua
Normal file
85
resources/customized_payloads/P-47D-30.lua
Normal file
@@ -0,0 +1,85 @@
|
||||
local unitPayloads = {
|
||||
["name"] = "P-47D-30",
|
||||
["payloads"] = {
|
||||
[1] = {
|
||||
["name"] = "CAS",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{AN-M64}",
|
||||
["num"] = 3,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{AN-M64}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{AN-M64}",
|
||||
["num"] = 1,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 11,
|
||||
},
|
||||
},
|
||||
[2] = {
|
||||
["name"] = "STRIKE",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{AN_M65}",
|
||||
["num"] = 3,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{AN_M65}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{AN-M64}",
|
||||
["num"] = 1,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 11,
|
||||
},
|
||||
},
|
||||
[3] = {
|
||||
["name"] = "ANTISTRIKE",
|
||||
["pylons"] = {
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 11,
|
||||
},
|
||||
},
|
||||
[4] = {
|
||||
["name"] = "CAP",
|
||||
["pylons"] = {
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 11,
|
||||
},
|
||||
},
|
||||
[5] = {
|
||||
["name"] = "SEAD",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{AN_M57}",
|
||||
["num"] = 3,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{AN_M57}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{AN_M57}",
|
||||
["num"] = 1,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 11,
|
||||
},
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
},
|
||||
["unitType"] = "P-47D-30",
|
||||
}
|
||||
return unitPayloads
|
||||
141
resources/customized_payloads/P-51D-30-NA.lua
Normal file
141
resources/customized_payloads/P-51D-30-NA.lua
Normal file
@@ -0,0 +1,141 @@
|
||||
local unitPayloads = {
|
||||
["name"] = "P-51D-30-NA",
|
||||
["payloads"] = {
|
||||
[1] = {
|
||||
["name"] = "CAS",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 10,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 9,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 8,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{AN-M64}",
|
||||
["num"] = 7,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "{AN-M64}",
|
||||
["num"] = 4,
|
||||
},
|
||||
[6] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 3,
|
||||
},
|
||||
[7] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[8] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 1,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 31,
|
||||
[2] = 32,
|
||||
[3] = 30,
|
||||
},
|
||||
},
|
||||
[2] = {
|
||||
["name"] = "STRIKE",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 10,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 9,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 8,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{AN-M64}",
|
||||
["num"] = 7,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "{AN-M64}",
|
||||
["num"] = 4,
|
||||
},
|
||||
[6] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 3,
|
||||
},
|
||||
[7] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[8] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 1,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 31,
|
||||
[2] = 32,
|
||||
[3] = 30,
|
||||
},
|
||||
},
|
||||
[3] = {
|
||||
["name"] = "CAP",
|
||||
["pylons"] = {
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 31,
|
||||
},
|
||||
},
|
||||
[4] = {
|
||||
["name"] = "ANTISHIP",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 10,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 9,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 8,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{AN-M64}",
|
||||
["num"] = 7,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "{AN-M64}",
|
||||
["num"] = 4,
|
||||
},
|
||||
[6] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 3,
|
||||
},
|
||||
[7] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[8] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 1,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 31,
|
||||
[2] = 32,
|
||||
[3] = 30,
|
||||
},
|
||||
},
|
||||
},
|
||||
["unitType"] = "P-51D-30-NA",
|
||||
}
|
||||
return unitPayloads
|
||||
133
resources/customized_payloads/P-51D.lua
Normal file
133
resources/customized_payloads/P-51D.lua
Normal file
@@ -0,0 +1,133 @@
|
||||
local unitPayloads = {
|
||||
["name"] = "P-51D",
|
||||
["payloads"] = {
|
||||
[1] = {
|
||||
["name"] = "CAS",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 10,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 9,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 8,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{AN-M64}",
|
||||
["num"] = 7,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "{AN-M64}",
|
||||
["num"] = 4,
|
||||
},
|
||||
[6] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 3,
|
||||
},
|
||||
[7] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[8] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 1,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 31,
|
||||
[2] = 32,
|
||||
[3] = 30,
|
||||
},
|
||||
},
|
||||
[2] = {
|
||||
["name"] = "STRIKE",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 10,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 9,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 8,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{AN-M64}",
|
||||
["num"] = 7,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "{AN-M64}",
|
||||
["num"] = 4,
|
||||
},
|
||||
[6] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 3,
|
||||
},
|
||||
[7] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[8] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 1,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 31,
|
||||
[2] = 32,
|
||||
[3] = 30,
|
||||
},
|
||||
},
|
||||
[3] = {
|
||||
["name"] = "ANTISHIP",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 10,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 9,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 8,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{AN-M64}",
|
||||
["num"] = 7,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "{AN-M64}",
|
||||
["num"] = 4,
|
||||
},
|
||||
[6] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 3,
|
||||
},
|
||||
[7] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[8] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 1,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 31,
|
||||
[2] = 32,
|
||||
[3] = 30,
|
||||
},
|
||||
},
|
||||
},
|
||||
["unitType"] = "P-51D",
|
||||
}
|
||||
return unitPayloads
|
||||
77
resources/customized_payloads/SpitfireLFMkIX.lua
Normal file
77
resources/customized_payloads/SpitfireLFMkIX.lua
Normal file
@@ -0,0 +1,77 @@
|
||||
local unitPayloads = {
|
||||
["name"] = "SpitfireLFMkIX",
|
||||
["payloads"] = {
|
||||
[1] = {
|
||||
["name"] = "CAP",
|
||||
["pylons"] = {
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 31,
|
||||
},
|
||||
},
|
||||
[2] = {
|
||||
["name"] = "STRIKE",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "British_GP_500LBS_Bomb_MK4_on_British_UniversalBC_MK3",
|
||||
["num"] = 2,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "British_GP_250LBS_Bomb_MK4_on_LH_Spitfire_Wing_Carrier",
|
||||
["num"] = 1,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "British_GP_250LBS_Bomb_MK4_on_RH_Spitfire_Wing_Carrier",
|
||||
["num"] = 3,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 31,
|
||||
},
|
||||
},
|
||||
[3] = {
|
||||
["name"] = "CAS",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "British_GP_500LBS_Bomb_MK4_on_British_UniversalBC_MK3",
|
||||
["num"] = 2,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "British_GP_250LBS_Bomb_MK4_on_LH_Spitfire_Wing_Carrier",
|
||||
["num"] = 1,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "British_GP_250LBS_Bomb_MK4_on_RH_Spitfire_Wing_Carrier",
|
||||
["num"] = 3,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 31,
|
||||
},
|
||||
},
|
||||
[4] = {
|
||||
["name"] = "ANTISHIP",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "British_GP_500LBS_Bomb_MK4_on_British_UniversalBC_MK3",
|
||||
["num"] = 2,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "British_GP_250LBS_Bomb_MK4_on_LH_Spitfire_Wing_Carrier",
|
||||
["num"] = 1,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "British_GP_250LBS_Bomb_MK4_on_RH_Spitfire_Wing_Carrier",
|
||||
["num"] = 3,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 31,
|
||||
},
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
},
|
||||
["unitType"] = "SpitfireLFMkIX",
|
||||
}
|
||||
return unitPayloads
|
||||
77
resources/customized_payloads/SpitfireLFMkIXCW.lua
Normal file
77
resources/customized_payloads/SpitfireLFMkIXCW.lua
Normal file
@@ -0,0 +1,77 @@
|
||||
local unitPayloads = {
|
||||
["name"] = "SpitfireLFMkIXCW",
|
||||
["payloads"] = {
|
||||
[1] = {
|
||||
["name"] = "CAP",
|
||||
["pylons"] = {
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 31,
|
||||
},
|
||||
},
|
||||
[2] = {
|
||||
["name"] = "CAS",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "British_GP_250LBS_Bomb_MK4_on_RH_Spitfire_Wing_Carrier",
|
||||
["num"] = 3,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "British_GP_250LBS_Bomb_MK4_on_LH_Spitfire_Wing_Carrier",
|
||||
["num"] = 1,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "British_GP_500LBS_Bomb_MK4_on_British_UniversalBC_MK3",
|
||||
["num"] = 2,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 31,
|
||||
},
|
||||
},
|
||||
[3] = {
|
||||
["name"] = "STRIKE",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "British_GP_250LBS_Bomb_MK4_on_RH_Spitfire_Wing_Carrier",
|
||||
["num"] = 3,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "British_GP_250LBS_Bomb_MK4_on_LH_Spitfire_Wing_Carrier",
|
||||
["num"] = 1,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "British_GP_500LBS_Bomb_MK4_on_British_UniversalBC_MK3",
|
||||
["num"] = 2,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 31,
|
||||
},
|
||||
},
|
||||
[4] = {
|
||||
["name"] = "ANTISHIP",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "British_GP_250LBS_Bomb_MK4_on_RH_Spitfire_Wing_Carrier",
|
||||
["num"] = 3,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "British_GP_250LBS_Bomb_MK4_on_LH_Spitfire_Wing_Carrier",
|
||||
["num"] = 1,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "British_GP_500LBS_Bomb_MK4_on_British_UniversalBC_MK3",
|
||||
["num"] = 2,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 31,
|
||||
},
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
},
|
||||
["unitType"] = "SpitfireLFMkIXCW",
|
||||
}
|
||||
return unitPayloads
|
||||
@@ -2,156 +2,150 @@ local unitPayloads = {
|
||||
["name"] = "Su-24M",
|
||||
["payloads"] = {
|
||||
[1] = {
|
||||
["name"] = "ANTISHIP",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
|
||||
["num"] = 1,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{D8F2C90B-887B-4B9E-9FE2-996BC9E9AF03}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{0519A264-0AB6-11d6-9193-00A0249B6F00}",
|
||||
["num"] = 5,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{D8F2C90B-887B-4B9E-9FE2-996BC9E9AF03}",
|
||||
["num"] = 7,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
|
||||
["num"] = 8,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 29,
|
||||
[2] = 30,
|
||||
},
|
||||
},
|
||||
[2] = {
|
||||
["name"] = "CAS",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{292960BB-6518-41AC-BADA-210D65D5073C}",
|
||||
["num"] = 1,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{292960BB-6518-41AC-BADA-210D65D5073C}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{292960BB-6518-41AC-BADA-210D65D5073C}",
|
||||
["num"] = 7,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{292960BB-6518-41AC-BADA-210D65D5073C}",
|
||||
["num"] = 8,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}",
|
||||
["num"] = 6,
|
||||
},
|
||||
[6] = {
|
||||
["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}",
|
||||
["num"] = 3,
|
||||
},
|
||||
[7] = {
|
||||
["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}",
|
||||
["num"] = 4,
|
||||
},
|
||||
[8] = {
|
||||
["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}",
|
||||
["num"] = 5,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 31,
|
||||
},
|
||||
},
|
||||
[3] = {
|
||||
["name"] = "STRIKE",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{4203753F-8198-4E85-9924-6F8FF679F9FF}",
|
||||
["num"] = 1,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{4203753F-8198-4E85-9924-6F8FF679F9FF}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{4203753F-8198-4E85-9924-6F8FF679F9FF}",
|
||||
["num"] = 3,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{4203753F-8198-4E85-9924-6F8FF679F9FF}",
|
||||
["num"] = 4,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "{4203753F-8198-4E85-9924-6F8FF679F9FF}",
|
||||
["num"] = 5,
|
||||
},
|
||||
[6] = {
|
||||
["CLSID"] = "{4203753F-8198-4E85-9924-6F8FF679F9FF}",
|
||||
["num"] = 6,
|
||||
},
|
||||
[7] = {
|
||||
["CLSID"] = "{4203753F-8198-4E85-9924-6F8FF679F9FF}",
|
||||
["num"] = 7,
|
||||
},
|
||||
[8] = {
|
||||
["CLSID"] = "{4203753F-8198-4E85-9924-6F8FF679F9FF}",
|
||||
["num"] = 8,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 31,
|
||||
},
|
||||
},
|
||||
[4] = {
|
||||
["name"] = "SEAD",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
|
||||
["num"] = 1,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{FE382A68-8620-4AC0-BDF5-709BFE3977D7}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{0519A264-0AB6-11d6-9193-00A0249B6F00}",
|
||||
["num"] = 5,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{FE382A68-8620-4AC0-BDF5-709BFE3977D7}",
|
||||
["num"] = 7,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
|
||||
[2] = {
|
||||
["CLSID"] = "{E86C5AA5-6D49-4F00-AD2E-79A62D6DDE26}",
|
||||
["num"] = 8,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{E86C5AA5-6D49-4F00-AD2E-79A62D6DDE26}",
|
||||
["num"] = 1,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{FE382A68-8620-4AC0-BDF5-709BFE3977D7}",
|
||||
["num"] = 2,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 29,
|
||||
},
|
||||
},
|
||||
[5] = {
|
||||
[2] = {
|
||||
["name"] = "STRIKE",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{KAB_1500LG_LOADOUT}",
|
||||
["num"] = 7,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}",
|
||||
["num"] = 8,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}",
|
||||
["num"] = 1,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{KAB_1500LG_LOADOUT}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "{E2C426E3-8B10-4E09-B733-9CDC26520F48}",
|
||||
["num"] = 3,
|
||||
},
|
||||
[6] = {
|
||||
["CLSID"] = "{E2C426E3-8B10-4E09-B733-9CDC26520F48}",
|
||||
["num"] = 6,
|
||||
},
|
||||
[7] = {
|
||||
["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}",
|
||||
["num"] = 4,
|
||||
},
|
||||
[8] = {
|
||||
["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}",
|
||||
["num"] = 5,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
},
|
||||
},
|
||||
[3] = {
|
||||
["name"] = "CAP",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{B0DBC591-0F52-4F7D-AD7B-51E67725FB81}",
|
||||
["num"] = 1,
|
||||
["CLSID"] = "{7D7EC917-05F6-49D4-8045-61FC587DD019}",
|
||||
["num"] = 7,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{275A2855-4A79-4B2D-B082-91EA2ADF4691}",
|
||||
["num"] = 8,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{B0DBC591-0F52-4F7D-AD7B-51E67725FB81}",
|
||||
["num"] = 1,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{7D7EC917-05F6-49D4-8045-61FC587DD019}",
|
||||
["num"] = 2,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
},
|
||||
},
|
||||
[4] = {
|
||||
["name"] = "ANTISHIP",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{D8F2C90B-887B-4B9E-9FE2-996BC9E9AF03}",
|
||||
["num"] = 7,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{E86C5AA5-6D49-4F00-AD2E-79A62D6DDE26}",
|
||||
["num"] = 8,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{E86C5AA5-6D49-4F00-AD2E-79A62D6DDE26}",
|
||||
["num"] = 1,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{D8F2C90B-887B-4B9E-9FE2-996BC9E9AF03}",
|
||||
["num"] = 2,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
},
|
||||
},
|
||||
[5] = {
|
||||
["name"] = "CAS",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
|
||||
["num"] = 8,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
|
||||
["num"] = 1,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}",
|
||||
["num"] = 7,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}",
|
||||
["num"] = 6,
|
||||
},
|
||||
[6] = {
|
||||
["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}",
|
||||
["num"] = 3,
|
||||
},
|
||||
[7] = {
|
||||
["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}",
|
||||
["num"] = 5,
|
||||
},
|
||||
[8] = {
|
||||
["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}",
|
||||
["num"] = 4,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 32,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -9,7 +9,7 @@ dcs.planes.FlyingType.payload_dirs = [os.path.join(os.path.dirname(os.path.realp
|
||||
|
||||
mis = dcs.Mission(dcs.terrain.PersianGulf())
|
||||
pos = dcs.terrain.PersianGulf().khasab().position
|
||||
airgen = AircraftConflictGenerator(mis, None, None)
|
||||
airgen = AircraftConflictGenerator(mis, None, None, None)
|
||||
|
||||
for t, uts in db.UNIT_BY_TASK.items():
|
||||
if t != dcs.task.CAP and t != dcs.task.CAS:
|
||||
|
||||
Binary file not shown.
@@ -120,34 +120,13 @@ class Base:
|
||||
target_dict[unit_type] = target_dict.get(unit_type, 0) + unit_count
|
||||
|
||||
def commit_losses(self, units_lost: typing.Dict[typing.Any, int]):
|
||||
# advanced SAM sites have multiple units - this code was not at all set up to handle that
|
||||
# to avoid having to restructure a bunch of upstream code, we track total destroyed units and
|
||||
# use that to determine if a site was destroyed
|
||||
# this can be thought of as the enemy re-distributing parts of SAM sites to keep as many
|
||||
# operational as possible (pulling specific units from ...storage... to bring them back online
|
||||
# if non-letal damage was done)
|
||||
# in the future, I may add more depth to this (e.g. a base having a certain number of spares and tracking
|
||||
# the number of pieces of each site), but for now this is what we get
|
||||
sams_destroyed = {}
|
||||
# we count complex SAM sites at the end - don't double count
|
||||
aa_skip = [
|
||||
AirDefence.SAM_SA_6_Kub_LN_2P25,
|
||||
AirDefence.SAM_SA_3_S_125_LN_5P73,
|
||||
AirDefence.SAM_SA_11_Buk_LN_9A310M1
|
||||
]
|
||||
|
||||
for unit_type, count in units_lost.items():
|
||||
if unit_type in db.SAM_CONVERT or unit_type in db.SAM_CONVERT['except']:
|
||||
# unit is part of an advanced SAM site, which means it will fail the below check
|
||||
try:
|
||||
sams_destroyed[unit_type] += 1
|
||||
except KeyError:
|
||||
sams_destroyed[unit_type] = 1
|
||||
|
||||
if unit_type in self.aircraft:
|
||||
target_array = self.aircraft
|
||||
elif unit_type in self.armor:
|
||||
target_array = self.armor
|
||||
elif unit_type in self.aa and unit_type not in aa_skip:
|
||||
target_array = self.aa
|
||||
else:
|
||||
print("Base didn't find event type {}".format(unit_type))
|
||||
continue
|
||||
@@ -160,22 +139,6 @@ class Base:
|
||||
if target_array[unit_type] == 0:
|
||||
del target_array[unit_type]
|
||||
|
||||
# now that we have a complete picture of the SAM sites destroyed, determine if any were destroyed
|
||||
for sam_site, count in sams_destroyed.items():
|
||||
dead_count = aaa.num_sam_dead(sam_site, count)
|
||||
try:
|
||||
modified_sam_site = db.SAM_CONVERT[sam_site]
|
||||
except KeyError:
|
||||
modified_sam_site = db.SAM_CONVERT[sam_site]['except']
|
||||
|
||||
if modified_sam_site in self.aa:
|
||||
self.aa[modified_sam_site] = max(
|
||||
self.aa[modified_sam_site] - dead_count,
|
||||
0
|
||||
)
|
||||
if self.aa[modified_sam_site] == 0:
|
||||
del self.aa[modified_sam_site]
|
||||
|
||||
def affect_strength(self, amount):
|
||||
self.strength += amount
|
||||
if self.strength > BASE_MAX_STRENGTH:
|
||||
|
||||
@@ -73,11 +73,6 @@ class CaucasusTheater(ConflictTheater):
|
||||
self.carrier_1.captured = True
|
||||
self.batumi.captured = True
|
||||
|
||||
def add_controlpoint(self, point: ControlPoint, connected_to: typing.Collection[ControlPoint] = []):
|
||||
point.name = " ".join(re.split(r"[ -]", point.name)[:1])
|
||||
|
||||
super(CaucasusTheater, self).add_controlpoint(point, connected_to=connected_to)
|
||||
|
||||
|
||||
"""
|
||||
A smaller version of the caucasus map in western georgia.
|
||||
@@ -160,4 +155,51 @@ class WesternGeorgiaInverted(ConflictTheater):
|
||||
self.add_controlpoint(self.carrier_1)
|
||||
|
||||
self.carrier_1.captured = True
|
||||
self.sochi.captured = True
|
||||
self.sochi.captured = True
|
||||
|
||||
|
||||
|
||||
|
||||
class NorthCaucasus(ConflictTheater):
|
||||
terrain = caucasus.Caucasus()
|
||||
overview_image = "caumap.gif"
|
||||
reference_points = {(-317948.32727306, 635639.37385346): (278.5*4, 319*4),
|
||||
(-355692.3067714, 617269.96285781): (263*4, 352*4), }
|
||||
|
||||
landmap = load_landmap("resources\\caulandmap.p")
|
||||
daytime_map = {
|
||||
"dawn": (6, 9),
|
||||
"day": (9, 18),
|
||||
"dusk": (18, 20),
|
||||
"night": (0, 5),
|
||||
}
|
||||
|
||||
carrier_1 = ControlPoint.carrier("Carrier", mapping.Point(-305810.6875, 406399.1875))
|
||||
|
||||
def __init__(self, load_ground_objects=True):
|
||||
super(NorthCaucasus, self).__init__()
|
||||
|
||||
self.kutaisi = ControlPoint.from_airport(caucasus.Kutaisi, LAND, SIZE_SMALL, IMPORTANCE_LOW)
|
||||
self.vaziani = ControlPoint.from_airport(caucasus.Vaziani, LAND, SIZE_SMALL, IMPORTANCE_LOW)
|
||||
self.maykop = ControlPoint.from_airport(caucasus.Maykop_Khanskaya, LAND, SIZE_LARGE, IMPORTANCE_HIGH)
|
||||
self.beslan = ControlPoint.from_airport(caucasus.Beslan, LAND, SIZE_REGULAR, IMPORTANCE_LOW)
|
||||
self.nalchik = ControlPoint.from_airport(caucasus.Nalchik, LAND, SIZE_REGULAR, 1.1)
|
||||
self.mineralnye = ControlPoint.from_airport(caucasus.Mineralnye_Vody, LAND, SIZE_BIG, 1.3)
|
||||
self.mozdok = ControlPoint.from_airport(caucasus.Mozdok, LAND, SIZE_BIG, 1.1)
|
||||
self.carrier_1 = ControlPoint.carrier("Carrier", mapping.Point(-285810.6875, 496399.1875))
|
||||
|
||||
self.vaziani.frontline_offset = 0.5
|
||||
self.vaziani.base.strength = 1
|
||||
|
||||
self.add_controlpoint(self.kutaisi, connected_to=[self.vaziani])
|
||||
self.add_controlpoint(self.vaziani, connected_to=[self.beslan, self.kutaisi])
|
||||
self.add_controlpoint(self.beslan, connected_to=[self.vaziani, self.mozdok, self.nalchik])
|
||||
self.add_controlpoint(self.nalchik, connected_to=[self.beslan, self.mozdok, self.mineralnye])
|
||||
self.add_controlpoint(self.mozdok, connected_to=[self.nalchik, self.beslan, self.mineralnye])
|
||||
self.add_controlpoint(self.mineralnye, connected_to=[self.nalchik, self.mozdok, self.maykop])
|
||||
self.add_controlpoint(self.maykop, connected_to=[self.mineralnye])
|
||||
self.add_controlpoint(self.carrier_1, connected_to=[])
|
||||
|
||||
self.carrier_1.captured = True
|
||||
self.vaziani.captured = True
|
||||
self.kutaisi.captured = True
|
||||
|
||||
@@ -72,6 +72,14 @@ class ConflictTheater:
|
||||
|
||||
self.controlpoints.append(point)
|
||||
|
||||
def find_ground_objects_by_obj_name(self, obj_name):
|
||||
found = []
|
||||
for cp in self.controlpoints:
|
||||
for g in cp.ground_objects:
|
||||
if g.obj_name == obj_name:
|
||||
found.append(g)
|
||||
return found
|
||||
|
||||
def is_in_sea(self, point: Point) -> bool:
|
||||
if not self.landmap:
|
||||
return False
|
||||
|
||||
@@ -27,6 +27,7 @@ class ControlPoint:
|
||||
full_name = None # type: str
|
||||
base = None # type: theater.base.Base
|
||||
at = None # type: db.StartPosition
|
||||
icls = 1
|
||||
|
||||
connected_points = None # type: typing.List[ControlPoint]
|
||||
ground_objects = None # type: typing.List[TheaterGroundObject]
|
||||
@@ -36,6 +37,9 @@ class ControlPoint:
|
||||
frontline_offset = 0.0
|
||||
cptype: ControlPointType = None
|
||||
|
||||
ICLS_counter = 1
|
||||
alt = 0
|
||||
|
||||
def __init__(self, id: int, name: str, position: Point, at, radials: typing.Collection[int], size: int, importance: float,
|
||||
has_frontline=True, cptype=ControlPointType.AIRBASE):
|
||||
import theater.base
|
||||
@@ -60,20 +64,26 @@ class ControlPoint:
|
||||
self.tacanY = False
|
||||
self.tacanN = None
|
||||
self.tacanI = "TAC"
|
||||
self.icls = 0
|
||||
self.airport = None
|
||||
|
||||
@classmethod
|
||||
def from_airport(cls, airport: Airport, radials: typing.Collection[int], size: int, importance: float, has_frontline=True):
|
||||
assert airport
|
||||
return cls(airport.id, airport.name, airport.position, airport, radials, size, importance, has_frontline, cptype=ControlPointType.AIRBASE)
|
||||
obj = cls(airport.id, airport.name, airport.position, airport, radials, size, importance, has_frontline, cptype=ControlPointType.AIRBASE)
|
||||
obj.airport = airport()
|
||||
return obj
|
||||
|
||||
@classmethod
|
||||
def carrier(cls, name: str, at: Point, id: int = 1001):
|
||||
import theater.conflicttheater
|
||||
cp = cls(id, name, at, at, theater.conflicttheater.LAND, theater.conflicttheater.SIZE_SMALL, 1,
|
||||
has_frontline=False, cptype=ControlPointType.AIRCRAFT_CARRIER_GROUP)
|
||||
cp.tacanY = random.choice([True, False])
|
||||
cp.tacanY = False
|
||||
cp.tacanN = random.randint(26, 49)
|
||||
cp.tacanI = random.choice(["STE", "CVN", "CVH", "CCV", "ACC", "ARC", "GER", "ABR", "LIN", "TRU"])
|
||||
ControlPoint.ICLS_counter = ControlPoint.ICLS_counter + 1
|
||||
cp.icls = ControlPoint.ICLS_counter
|
||||
return cp
|
||||
|
||||
@classmethod
|
||||
@@ -81,11 +91,20 @@ class ControlPoint:
|
||||
import theater.conflicttheater
|
||||
cp = cls(id, name, at, at, theater.conflicttheater.LAND, theater.conflicttheater.SIZE_SMALL, 1,
|
||||
has_frontline=False, cptype=ControlPointType.LHA_GROUP)
|
||||
cp.tacanY = random.choice([True, False])
|
||||
cp.tacanY = False
|
||||
cp.tacanN = random.randint(1,25)
|
||||
cp.tacanI = random.choice(["LHD", "LHA", "LHB", "LHC", "LHD", "LDS"])
|
||||
return cp
|
||||
|
||||
@property
|
||||
def heading(self):
|
||||
if self.cptype == ControlPointType.AIRBASE:
|
||||
return self.airport.runways[0].heading
|
||||
elif self.cptype in [ControlPointType.AIRCRAFT_CARRIER_GROUP, ControlPointType.LHA_GROUP]:
|
||||
return 0 # TODO compute heading
|
||||
else:
|
||||
return 0
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@@ -170,3 +189,10 @@ class ControlPoint:
|
||||
|
||||
return closest_radial
|
||||
|
||||
def find_ground_objects_by_obj_name(self, obj_name):
|
||||
found = []
|
||||
for g in self.ground_objects:
|
||||
if g.obj_name == obj_name:
|
||||
found.append(g)
|
||||
return found
|
||||
|
||||
|
||||
@@ -112,11 +112,15 @@ def generate_groundobjects(theater: ConflictTheater, game):
|
||||
if "lhanames" in db.FACTIONS[faction]:
|
||||
cp.name = random.choice(db.FACTIONS[faction]["lhanames"])
|
||||
else:
|
||||
|
||||
for i in range(random.randint(2,6)):
|
||||
point = find_location(True, cp.position, theater, 1000, 2800, [])
|
||||
|
||||
print("GENERATE BASE DEFENSE")
|
||||
point = find_location(True, cp.position, theater, 1000, 2800, [], True)
|
||||
print(point)
|
||||
|
||||
if point is None:
|
||||
print("Couldn't find point for {}".format(cp))
|
||||
print("Couldn't find point for {} base defense".format(cp))
|
||||
continue
|
||||
|
||||
group_id = group_id + 1
|
||||
@@ -131,18 +135,7 @@ def generate_groundobjects(theater: ConflictTheater, game):
|
||||
g.heading = 0
|
||||
g.position = Point(point.x, point.y)
|
||||
|
||||
if i == 0:
|
||||
group = generate_armor_group(faction, game, g)
|
||||
elif i == 1 and random.randint(0,1) == 0:
|
||||
group = generate_anti_air_group(game, cp, g, faction)
|
||||
elif random.randint(0, 2) == 1:
|
||||
group = generate_shorad_group(game, cp, g, faction)
|
||||
else:
|
||||
group = generate_armor_group(faction, game, g)
|
||||
|
||||
g.groups = []
|
||||
if group is not None:
|
||||
g.groups.append(group)
|
||||
generate_airbase_defense_group(i, g, faction, game, cp)
|
||||
cp.ground_objects.append(g)
|
||||
|
||||
print("---------------------------")
|
||||
@@ -151,7 +144,27 @@ def generate_groundobjects(theater: ConflictTheater, game):
|
||||
print(ground_object.groups)
|
||||
|
||||
|
||||
def find_location(on_ground, near, theater, min, max, others) -> typing.Optional[Point]:
|
||||
def generate_airbase_defense_group(airbase_defense_group_id, ground_obj:TheaterGroundObject, faction, game, cp):
|
||||
|
||||
print("GENERATE AIR DEFENSE GROUP")
|
||||
print(faction)
|
||||
print(airbase_defense_group_id)
|
||||
|
||||
if airbase_defense_group_id == 0:
|
||||
group = generate_armor_group(faction, game, ground_obj)
|
||||
elif airbase_defense_group_id == 1 and random.randint(0, 1) == 0:
|
||||
group = generate_anti_air_group(game, cp, ground_obj, faction)
|
||||
elif random.randint(0, 2) == 1:
|
||||
group = generate_shorad_group(game, cp, ground_obj, faction)
|
||||
else:
|
||||
group = generate_armor_group(faction, game, ground_obj)
|
||||
|
||||
ground_obj.groups = []
|
||||
if group is not None:
|
||||
ground_obj.groups.append(group)
|
||||
|
||||
|
||||
def find_location(on_ground, near, theater, min, max, others, is_base_defense=False) -> typing.Optional[Point]:
|
||||
"""
|
||||
Find a valid ground object location
|
||||
:param on_ground: Whether it should be on ground or on sea (True = on ground)
|
||||
@@ -163,7 +176,7 @@ def find_location(on_ground, near, theater, min, max, others) -> typing.Optional
|
||||
:return:
|
||||
"""
|
||||
point = None
|
||||
for _ in range(1000):
|
||||
for _ in range(300):
|
||||
|
||||
# Check if on land or sea
|
||||
p = near.random_point_within(max, min)
|
||||
@@ -189,6 +202,7 @@ def find_location(on_ground, near, theater, min, max, others) -> typing.Optional
|
||||
|
||||
if point:
|
||||
for other in theater.controlpoints:
|
||||
if is_base_defense: break
|
||||
if other.position != near:
|
||||
if point is None:
|
||||
break
|
||||
@@ -254,7 +268,7 @@ def generate_cp_ground_points(cp: ControlPoint, theater, game, group_id, templat
|
||||
g.group_id = group_id
|
||||
g.object_id = object_id
|
||||
g.cp_id = cp.id
|
||||
g.airbase_gorup = False
|
||||
g.airbase_group = False
|
||||
g.obj_name = obj_name
|
||||
|
||||
g.dcs_identifier = object["type"]
|
||||
|
||||
@@ -30,10 +30,12 @@ ABBREV_NAME = {
|
||||
}
|
||||
|
||||
CATEGORY_MAP = {
|
||||
# Special cases
|
||||
"CARRIER": ["CARRIER"],
|
||||
"LHA": ["LHA"],
|
||||
"aa": ["AA"],
|
||||
"power": ["Workshop A", "Electric power box", "Garage small A"],
|
||||
# Buildings
|
||||
"power": ["Workshop A", "Electric power box", "Garage small A", "Farm B", "Repair workshop", "Garage B"],
|
||||
"warehouse": ["Warehouse", "Hangar A"],
|
||||
"fuel": ["Tank", "Tank 2", "Tank 3", "Fuel tank"],
|
||||
"ammo": [".Ammunition depot", "Hangar B"],
|
||||
@@ -42,6 +44,7 @@ CATEGORY_MAP = {
|
||||
"factory": ["Tech combine", "Tech hangar A"],
|
||||
"comms": ["TV tower", "Comms tower M"],
|
||||
"oil": ["Oil platform"],
|
||||
"derrick": ["Oil derrick", "Pump station", "Subsidiary structure 2"],
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
"""
|
||||
This utility classes provides methods to check players installed DCS environment.
|
||||
|
||||
TODO : add method 'is_using_open_beta', 'is_using_stable'
|
||||
TODO : [NICE to have] add method to check list of installed DCS modules (could be done either through window registry, or through filesystem analysis)
|
||||
"""
|
||||
|
||||
import winreg
|
||||
import os
|
||||
|
||||
|
||||
def is_using_dcs_steam_edition():
|
||||
"""
|
||||
Check if DCS World : Steam Edition version is installed on this computer
|
||||
:return True if DCS Steam edition is installed,
|
||||
-1 if DCS Steam Edition is registered in Steam apps but not installed,
|
||||
False if never installed in Steam
|
||||
"""
|
||||
try:
|
||||
# Note : Steam App ID for DCS World is 223750
|
||||
dcs_steam_app_key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\Valve\\Steam\\Apps\\223750")
|
||||
installed = winreg.QueryValueEx(dcs_steam_app_key, "Installed")
|
||||
winreg.CloseKey(dcs_steam_app_key)
|
||||
if installed[0] == 1:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
except FileNotFoundError as fnfe:
|
||||
return False
|
||||
|
||||
|
||||
def is_using_dcs_standalone_edition():
|
||||
"""
|
||||
Check if DCS World standalone edition is installed on this computer
|
||||
:return True if Standalone is installed, False if it is not
|
||||
"""
|
||||
try:
|
||||
dcs_path_key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\Eagle Dynamics\\DCS World")
|
||||
winreg.CloseKey(dcs_path_key)
|
||||
return True
|
||||
except FileNotFoundError as fnfe:
|
||||
return False
|
||||
|
||||
|
||||
def _find_steam_directory():
|
||||
"""
|
||||
Get the Steam install directory for this computer from registry
|
||||
:return Steam installation path
|
||||
"""
|
||||
try:
|
||||
steam_key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\Valve\\Steam")
|
||||
path = winreg.QueryValueEx(steam_key, "SteamPath")[0]
|
||||
winreg.CloseKey(steam_key)
|
||||
return path
|
||||
except FileNotFoundError as fnfe:
|
||||
print(fnfe)
|
||||
return ""
|
||||
|
||||
|
||||
def _get_steam_library_folders():
|
||||
"""
|
||||
Get the installation directory for Steam games
|
||||
:return List of Steam library folders where games can be installed
|
||||
"""
|
||||
try:
|
||||
steam_dir = _find_steam_directory()
|
||||
"""
|
||||
For reference here is what the vdf file is supposed to look like :
|
||||
|
||||
"LibraryFolders"
|
||||
{
|
||||
"TimeNextStatsReport" "1561832478"
|
||||
"ContentStatsID" "-158337411110787451"
|
||||
"1" "D:\\Games\\Steam"
|
||||
"2" "E:\\Steam"
|
||||
}
|
||||
"""
|
||||
vdf_file_location = steam_dir + os.path.sep + "steamapps" + os.path.sep + "libraryfolders.vdf"
|
||||
with open(vdf_file_location) as adf_file:
|
||||
paths = [l.split("\"")[3] for l in adf_file.readlines()[1:] if ':\\\\' in l]
|
||||
return paths
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return []
|
||||
|
||||
|
||||
def _find_steam_dcs_directory():
|
||||
"""
|
||||
Find the DCS install directory for DCS World Steam Edition
|
||||
:return: Install directory as string, empty string if not found
|
||||
"""
|
||||
for library_folder in _get_steam_library_folders():
|
||||
folder = library_folder + os.path.sep + "steamapps" + os.path.sep + "common" + os.path.sep + "DCSWorld"
|
||||
if os.path.isdir(folder):
|
||||
return folder + os.path.sep
|
||||
return ""
|
||||
|
||||
|
||||
def get_dcs_install_directory():
|
||||
"""
|
||||
Get the DCS World install directory for this computer
|
||||
:return DCS World install directory
|
||||
"""
|
||||
if is_using_dcs_standalone_edition():
|
||||
try:
|
||||
dcs_path_key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\Eagle Dynamics\\DCS World")
|
||||
path = winreg.QueryValueEx(dcs_path_key, "Path")
|
||||
dcs_dir = path[0] + os.path.sep
|
||||
winreg.CloseKey(dcs_path_key)
|
||||
return dcs_dir
|
||||
except Exception as e:
|
||||
print("Couldn't detect DCS World installation folder")
|
||||
return ""
|
||||
elif is_using_dcs_steam_edition():
|
||||
return _find_steam_dcs_directory()
|
||||
else:
|
||||
print("Couldn't detect any installed DCS World version")
|
||||
|
||||
|
||||
def get_dcs_saved_games_directory():
|
||||
"""
|
||||
Get the save game directory for DCS World
|
||||
:return: Save game directory as string
|
||||
"""
|
||||
return os.path.join(os.path.expanduser("~"), "Saved Games", "DCS")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("Using STEAM Edition : " + str(is_using_dcs_steam_edition()))
|
||||
print("Using Standalone Edition : " + str(is_using_dcs_standalone_edition()))
|
||||
print("DCS Installation directory : " + get_dcs_install_directory())
|
||||
print("DCS saved games directory : " + get_dcs_saved_games_directory())
|
||||
@@ -47,6 +47,8 @@ class Debriefing:
|
||||
|
||||
self.dead_aircraft = []
|
||||
self.dead_units = []
|
||||
self.dead_aaa_groups = []
|
||||
self.dead_buildings = []
|
||||
|
||||
for aircraft in self.killed_aircrafts:
|
||||
try:
|
||||
@@ -70,10 +72,36 @@ class Debriefing:
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
for unit in self.killed_ground_units:
|
||||
for cp in game.theater.controlpoints:
|
||||
|
||||
print(cp.name)
|
||||
print(cp.captured)
|
||||
if cp.captured:
|
||||
country = self.player_country_id
|
||||
else:
|
||||
country = self.enemy_country_id
|
||||
player_unit = (country == self.player_country_id)
|
||||
|
||||
for i, ground_object in enumerate(cp.ground_objects):
|
||||
print(unit)
|
||||
print(ground_object.string_identifier)
|
||||
if ground_object.matches_string_identifier(unit):
|
||||
unit = DebriefingDeadUnitInfo(country, player_unit, ground_object.dcs_identifier)
|
||||
self.dead_buildings.append(unit)
|
||||
elif ground_object.dcs_identifier in ["AA", "CARRIER", "LHA"]:
|
||||
for g in ground_object.groups:
|
||||
for u in g.units:
|
||||
if u.name == unit:
|
||||
unit = DebriefingDeadUnitInfo(country, player_unit, db.unit_type_from_name(u.type))
|
||||
self.dead_units.append(unit)
|
||||
|
||||
self.player_dead_aircraft = [a for a in self.dead_aircraft if a.country_id == self.player_country_id]
|
||||
self.enemy_dead_aircraft = [a for a in self.dead_aircraft if a.country_id == self.enemy_country_id]
|
||||
self.player_dead_units = [a for a in self.dead_units if a.country_id == self.player_country_id]
|
||||
self.enemy_dead_units = [a for a in self.dead_units if a.country_id == self.enemy_country_id]
|
||||
self.player_dead_buildings = [a for a in self.dead_buildings if a.country_id == self.player_country_id]
|
||||
self.enemy_dead_buildings = [a for a in self.dead_buildings if a.country_id == self.enemy_country_id]
|
||||
|
||||
print(self.player_dead_aircraft)
|
||||
print(self.enemy_dead_aircraft)
|
||||
@@ -108,10 +136,27 @@ class Debriefing:
|
||||
else:
|
||||
self.enemy_dead_units_dict[a.type] = 1
|
||||
|
||||
self.player_dead_buildings_dict = {}
|
||||
for a in self.player_dead_buildings:
|
||||
if a.type in self.player_dead_buildings_dict.keys():
|
||||
self.player_dead_buildings_dict[a.type] = self.player_dead_buildings_dict[a.type] + 1
|
||||
else:
|
||||
self.player_dead_buildings_dict[a.type] = 1
|
||||
|
||||
self.enemy_dead_buildings_dict = {}
|
||||
for a in self.enemy_dead_buildings:
|
||||
if a.type in self.enemy_dead_buildings_dict.keys():
|
||||
self.enemy_dead_buildings_dict[a.type] = self.enemy_dead_buildings_dict[a.type] + 1
|
||||
else:
|
||||
self.enemy_dead_buildings_dict[a.type] = 1
|
||||
|
||||
print("DEBRIEFING PRE PROCESS")
|
||||
print(self.player_dead_aircraft_dict)
|
||||
print(self.enemy_dead_aircraft_dict)
|
||||
print(self.player_dead_units_dict)
|
||||
print(self.enemy_dead_units_dict)
|
||||
print(self.player_dead_buildings_dict)
|
||||
print(self.enemy_dead_buildings_dict)
|
||||
|
||||
|
||||
def _poll_new_debriefing_log(callback: typing.Callable, game):
|
||||
|
||||
99
userdata/liberation_install.py
Normal file
99
userdata/liberation_install.py
Normal file
@@ -0,0 +1,99 @@
|
||||
import json
|
||||
import os
|
||||
from shutil import copyfile
|
||||
|
||||
import dcs
|
||||
|
||||
from userdata import persistency
|
||||
|
||||
global __dcs_saved_game_directory
|
||||
global __dcs_installation_directory
|
||||
|
||||
PREFERENCES_FILE_PATH = "liberation_preferences.json"
|
||||
|
||||
def init():
|
||||
global __dcs_saved_game_directory
|
||||
global __dcs_installation_directory
|
||||
|
||||
if os.path.isfile(PREFERENCES_FILE_PATH):
|
||||
try:
|
||||
with(open(PREFERENCES_FILE_PATH)) as prefs:
|
||||
pref_data = json.loads(prefs.read())
|
||||
__dcs_saved_game_directory = pref_data["saved_game_dir"]
|
||||
__dcs_installation_directory = pref_data["dcs_install_dir"]
|
||||
is_first_start = False
|
||||
except:
|
||||
__dcs_saved_game_directory = ""
|
||||
__dcs_installation_directory = ""
|
||||
is_first_start = True
|
||||
else:
|
||||
try:
|
||||
__dcs_saved_game_directory = dcs.installation.get_dcs_saved_games_directory()
|
||||
if os.path.exists(__dcs_saved_game_directory + ".openbeta"):
|
||||
__dcs_saved_game_directory = dcs.installation.get_dcs_saved_games_directory() + ".openbeta"
|
||||
except:
|
||||
__dcs_saved_game_directory = ""
|
||||
try:
|
||||
__dcs_installation_directory = dcs.installation.get_dcs_install_directory()
|
||||
except:
|
||||
__dcs_installation_directory = ""
|
||||
|
||||
is_first_start = True
|
||||
persistency.setup(__dcs_saved_game_directory)
|
||||
return is_first_start
|
||||
|
||||
|
||||
def setup(saved_game_dir, install_dir):
|
||||
global __dcs_saved_game_directory
|
||||
global __dcs_installation_directory
|
||||
__dcs_saved_game_directory = saved_game_dir
|
||||
__dcs_installation_directory = install_dir
|
||||
persistency.setup(__dcs_saved_game_directory)
|
||||
|
||||
|
||||
def save_config():
|
||||
global __dcs_saved_game_directory
|
||||
global __dcs_installation_directory
|
||||
pref_data = {"saved_game_dir": __dcs_saved_game_directory,
|
||||
"dcs_install_dir": __dcs_installation_directory}
|
||||
with(open(PREFERENCES_FILE_PATH, "w")) as prefs:
|
||||
prefs.write(json.dumps(pref_data))
|
||||
|
||||
|
||||
def get_dcs_install_directory():
|
||||
global __dcs_installation_directory
|
||||
return __dcs_installation_directory
|
||||
|
||||
|
||||
def get_saved_game_dir():
|
||||
global __dcs_saved_game_directory
|
||||
return __dcs_saved_game_directory
|
||||
|
||||
|
||||
def replace_mission_scripting_file():
|
||||
install_dir = get_dcs_install_directory()
|
||||
mission_scripting_path = os.path.join(install_dir, "Scripts", "MissionScripting.lua")
|
||||
liberation_scripting_path = "./resources/scripts/MissionScripting.lua"
|
||||
backup_scripting_path = "./resources/scripts/MissionScripting.original.lua"
|
||||
if os.path.isfile(mission_scripting_path):
|
||||
with open(mission_scripting_path, "r") as ms:
|
||||
current_file_content = ms.read()
|
||||
with open(liberation_scripting_path, "r") as libe_ms:
|
||||
liberation_file_content = libe_ms.read()
|
||||
|
||||
# Save original file
|
||||
if current_file_content != liberation_file_content:
|
||||
copyfile(mission_scripting_path, backup_scripting_path)
|
||||
|
||||
# Replace DCS file
|
||||
copyfile(liberation_scripting_path, mission_scripting_path)
|
||||
|
||||
|
||||
def restore_original_mission_scripting():
|
||||
install_dir = get_dcs_install_directory()
|
||||
mission_scripting_path = os.path.join(install_dir, "Scripts", "MissionScripting.lua")
|
||||
backup_scripting_path = "./resources/scripts/MissionScripting.original.lua"
|
||||
|
||||
if os.path.isfile(backup_scripting_path) and os.path.isfile(mission_scripting_path):
|
||||
copyfile(backup_scripting_path, mission_scripting_path)
|
||||
|
||||
@@ -46,4 +46,4 @@ else:
|
||||
logging.basicConfig(stream=log_stream, level=logging.INFO)
|
||||
Tk.report_callback_exception = _handle_exception
|
||||
|
||||
logging.info("DCS Libration {}".format(_version_string))
|
||||
logging.info("DCS Liberation {}".format(_version_string))
|
||||
|
||||
@@ -2,9 +2,6 @@ import logging
|
||||
import os
|
||||
import pickle
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
from dcs import installation
|
||||
|
||||
_dcs_saved_game_folder = None # type: str
|
||||
|
||||
@@ -17,12 +14,7 @@ def setup(user_folder: str):
|
||||
def base_path() -> str:
|
||||
global _dcs_saved_game_folder
|
||||
assert _dcs_saved_game_folder
|
||||
|
||||
openbeta_path = _dcs_saved_game_folder + ".openbeta"
|
||||
if os.path.exists(openbeta_path):
|
||||
return openbeta_path # For standalone openbeta users
|
||||
else:
|
||||
return _dcs_saved_game_folder # For standalone stable users & steam users (any branch)
|
||||
return _dcs_saved_game_folder
|
||||
|
||||
|
||||
def _save_file() -> str:
|
||||
@@ -46,7 +38,12 @@ def restore_game():
|
||||
return None
|
||||
|
||||
with open(_save_file(), "rb") as f:
|
||||
return pickle.load(f)
|
||||
try:
|
||||
save = pickle.load(f)
|
||||
return save
|
||||
except:
|
||||
print("Invalid Save game")
|
||||
return None
|
||||
|
||||
|
||||
def save_game(game) -> bool:
|
||||
|
||||
Reference in New Issue
Block a user