mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
Compare commits
3 Commits
develop_2_
...
2.2.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2891649531 | ||
|
|
4b40739918 | ||
|
|
e26e7f53c5 |
@@ -31,10 +31,6 @@ First, a big thanks to shdwp, for starting the original DCS Liberation project.
|
|||||||
|
|
||||||
Then, DCS Liberation uses [pydcs](http://github.com/pydcs/dcs) for mission generation, and nothing would be possible without this.
|
Then, DCS Liberation uses [pydcs](http://github.com/pydcs/dcs) for mission generation, and nothing would be possible without this.
|
||||||
It also uses the popular [Mist](https://github.com/mrSkortch/MissionScriptingTools) lua framework for mission scripting.
|
It also uses the popular [Mist](https://github.com/mrSkortch/MissionScriptingTools) lua framework for mission scripting.
|
||||||
|
And for the JTAC feature, DCS Liberation embed Ciribob's JTAC Autolase [script](https://github.com/ciribob/DCS-JTACAutoLaze).
|
||||||
Excellent lua scripts DCS Liberation uses as plugins:
|
|
||||||
|
|
||||||
* For the JTAC feature, DCS Liberation embeds Ciribob's JTAC Autolase [script](https://github.com/ciribob/DCS-JTACAutoLaze).
|
|
||||||
* Walder's [Skynet-IADS](https://github.com/walder/Skynet-IADS) is used for Integrated Air Defense System.
|
|
||||||
|
|
||||||
Please also show some support to these projects !
|
Please also show some support to these projects !
|
||||||
|
|||||||
18
changelog.md
18
changelog.md
@@ -1,21 +1,3 @@
|
|||||||
# 2.2.1
|
|
||||||
|
|
||||||
# Features/Improvements
|
|
||||||
* **[Factions]** Added factions : Georgia 2008, USN 1985, France 2005 Frenchpack by HerrTom
|
|
||||||
* **[Factions]** Added map Persian Gulf full by Plob
|
|
||||||
* **[Flight Planner]** Player flights with start delays under ten minutes will spawn immediately.
|
|
||||||
* **[UI]** Mission start screen now informs players about delayed flights.
|
|
||||||
* **[Units]** Added support for F-14A-135-GR
|
|
||||||
* **[Modding]** Possible to setup liveries overrides in factions definition files
|
|
||||||
|
|
||||||
## Fixes :
|
|
||||||
* **[Flight Planner]** Hold, join, and split points are planned cautiously near enemy airfields. Ascend/descend points are no longer planned.
|
|
||||||
* **[Flight Planner]** Custom waypoints are usable again. Not that in most cases custom flight plans will revert to the 2.1 flight planning behavior.
|
|
||||||
* **[Flight Planner]** Fixed UI bug that made it possible to create empty flights which would throw an error.
|
|
||||||
* **[Flight Planner]** Player flights from carriers will now be delayed correctly according to the player's settings.
|
|
||||||
* **[Misc]** Spitfire variant with clipped wings was not seen as flyable by DCS Liberation (hence could not be setup as client/player slot)
|
|
||||||
* **[Misc]** Updated Syria terrain parking slots database, the out-of-date database could end up generating aircraft in wrong slots (We are still experiencing issues with somes airbases, such as Khalkhalah though)
|
|
||||||
|
|
||||||
# 2.2.0
|
# 2.2.0
|
||||||
|
|
||||||
## Features/Improvements :
|
## Features/Improvements :
|
||||||
|
|||||||
@@ -16,8 +16,6 @@ class Doctrine:
|
|||||||
sead_max_range: int
|
sead_max_range: int
|
||||||
|
|
||||||
rendezvous_altitude: int
|
rendezvous_altitude: int
|
||||||
hold_distance: int
|
|
||||||
push_distance: int
|
|
||||||
join_distance: int
|
join_distance: int
|
||||||
split_distance: int
|
split_distance: int
|
||||||
ingress_egress_distance: int
|
ingress_egress_distance: int
|
||||||
@@ -46,8 +44,6 @@ MODERN_DOCTRINE = Doctrine(
|
|||||||
strike_max_range=1500000,
|
strike_max_range=1500000,
|
||||||
sead_max_range=1500000,
|
sead_max_range=1500000,
|
||||||
rendezvous_altitude=feet_to_meter(25000),
|
rendezvous_altitude=feet_to_meter(25000),
|
||||||
hold_distance=nm_to_meter(15),
|
|
||||||
push_distance=nm_to_meter(20),
|
|
||||||
join_distance=nm_to_meter(20),
|
join_distance=nm_to_meter(20),
|
||||||
split_distance=nm_to_meter(20),
|
split_distance=nm_to_meter(20),
|
||||||
ingress_egress_distance=nm_to_meter(45),
|
ingress_egress_distance=nm_to_meter(45),
|
||||||
@@ -73,8 +69,6 @@ COLDWAR_DOCTRINE = Doctrine(
|
|||||||
strike_max_range=1500000,
|
strike_max_range=1500000,
|
||||||
sead_max_range=1500000,
|
sead_max_range=1500000,
|
||||||
rendezvous_altitude=feet_to_meter(22000),
|
rendezvous_altitude=feet_to_meter(22000),
|
||||||
hold_distance=nm_to_meter(10),
|
|
||||||
push_distance=nm_to_meter(10),
|
|
||||||
join_distance=nm_to_meter(10),
|
join_distance=nm_to_meter(10),
|
||||||
split_distance=nm_to_meter(10),
|
split_distance=nm_to_meter(10),
|
||||||
ingress_egress_distance=nm_to_meter(30),
|
ingress_egress_distance=nm_to_meter(30),
|
||||||
@@ -99,8 +93,6 @@ WWII_DOCTRINE = Doctrine(
|
|||||||
antiship=True,
|
antiship=True,
|
||||||
strike_max_range=1500000,
|
strike_max_range=1500000,
|
||||||
sead_max_range=1500000,
|
sead_max_range=1500000,
|
||||||
hold_distance=nm_to_meter(5),
|
|
||||||
push_distance=nm_to_meter(5),
|
|
||||||
join_distance=nm_to_meter(5),
|
join_distance=nm_to_meter(5),
|
||||||
split_distance=nm_to_meter(5),
|
split_distance=nm_to_meter(5),
|
||||||
rendezvous_altitude=feet_to_meter(10000),
|
rendezvous_altitude=feet_to_meter(10000),
|
||||||
|
|||||||
98
game/db.py
98
game/db.py
@@ -2,7 +2,9 @@ from datetime import datetime
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import Dict, List, Optional, Tuple, Type, Union
|
from typing import Dict, List, Optional, Tuple, Type, Union
|
||||||
|
|
||||||
|
from dcs import Mission
|
||||||
from dcs.countries import country_dict
|
from dcs.countries import country_dict
|
||||||
|
from dcs.country import Country
|
||||||
from dcs.helicopters import (
|
from dcs.helicopters import (
|
||||||
AH_1W,
|
AH_1W,
|
||||||
AH_64A,
|
AH_64A,
|
||||||
@@ -44,7 +46,6 @@ from dcs.planes import (
|
|||||||
FW_190A8,
|
FW_190A8,
|
||||||
FW_190D9,
|
FW_190D9,
|
||||||
F_117A,
|
F_117A,
|
||||||
F_14A_135_GR,
|
|
||||||
F_14B,
|
F_14B,
|
||||||
F_15C,
|
F_15C,
|
||||||
F_15E,
|
F_15E,
|
||||||
@@ -104,7 +105,7 @@ from dcs.planes import (
|
|||||||
Tu_95MS,
|
Tu_95MS,
|
||||||
WingLoong_I,
|
WingLoong_I,
|
||||||
Yak_40,
|
Yak_40,
|
||||||
plane_map
|
plane_map,
|
||||||
)
|
)
|
||||||
from dcs.ships import (
|
from dcs.ships import (
|
||||||
Armed_speedboat,
|
Armed_speedboat,
|
||||||
@@ -154,6 +155,7 @@ from dcs.vehicles import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
import pydcs_extensions.frenchpack.frenchpack as frenchpack
|
import pydcs_extensions.frenchpack.frenchpack as frenchpack
|
||||||
|
from game.factions.faction import Faction
|
||||||
# PATCH pydcs data with MODS
|
# PATCH pydcs data with MODS
|
||||||
from game.factions.faction_loader import FactionLoader
|
from game.factions.faction_loader import FactionLoader
|
||||||
from pydcs_extensions.a4ec.a4ec import A_4E_C
|
from pydcs_extensions.a4ec.a4ec import A_4E_C
|
||||||
@@ -202,6 +204,7 @@ vehicle_map["Toyota_vert"] = frenchpack.DIM__TOYOTA_GREEN
|
|||||||
vehicle_map["Toyota_desert"] = frenchpack.DIM__TOYOTA_DESERT
|
vehicle_map["Toyota_desert"] = frenchpack.DIM__TOYOTA_DESERT
|
||||||
vehicle_map["Kamikaze"] = frenchpack.DIM__KAMIKAZE
|
vehicle_map["Kamikaze"] = frenchpack.DIM__KAMIKAZE
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
---------- BEGINNING OF CONFIGURATION SECTION
|
---------- BEGINNING OF CONFIGURATION SECTION
|
||||||
"""
|
"""
|
||||||
@@ -270,7 +273,6 @@ PRICES = {
|
|||||||
F_15E: 24,
|
F_15E: 24,
|
||||||
F_16C_50: 20,
|
F_16C_50: 20,
|
||||||
F_16A: 14,
|
F_16A: 14,
|
||||||
F_14A_135_GR: 20,
|
|
||||||
F_14B: 24,
|
F_14B: 24,
|
||||||
Tornado_IDS: 20,
|
Tornado_IDS: 20,
|
||||||
Tornado_GR4: 20,
|
Tornado_GR4: 20,
|
||||||
@@ -399,20 +401,20 @@ PRICES = {
|
|||||||
Unarmed.Transport_M818: 3,
|
Unarmed.Transport_M818: 3,
|
||||||
|
|
||||||
# WW2
|
# WW2
|
||||||
Armor.MT_Pz_Kpfw_V_Panther_Ausf_G: 24,
|
Armor.MT_Pz_Kpfw_V_Panther_Ausf_G:24,
|
||||||
Armor.MT_Pz_Kpfw_IV_Ausf_H: 16,
|
Armor.MT_Pz_Kpfw_IV_Ausf_H:16,
|
||||||
Armor.HT_Pz_Kpfw_VI_Tiger_I: 24,
|
Armor.HT_Pz_Kpfw_VI_Tiger_I:24,
|
||||||
Armor.HT_Pz_Kpfw_VI_Ausf__B_Tiger_II: 26,
|
Armor.HT_Pz_Kpfw_VI_Ausf__B_Tiger_II:26,
|
||||||
Armor.TD_Jagdpanther_G1: 18,
|
Armor.TD_Jagdpanther_G1: 18,
|
||||||
Armor.TD_Jagdpanzer_IV: 11,
|
Armor.TD_Jagdpanzer_IV: 11,
|
||||||
Armor.Sd_Kfz_184_Elefant: 18,
|
Armor.Sd_Kfz_184_Elefant: 18,
|
||||||
Armor.APC_Sd_Kfz_251: 4,
|
Armor.APC_Sd_Kfz_251:4,
|
||||||
Armor.AC_Sd_Kfz_234_2_Puma: 8,
|
Armor.AC_Sd_Kfz_234_2_Puma:8,
|
||||||
Armor.MT_M4_Sherman: 12,
|
Armor.MT_M4_Sherman:12,
|
||||||
Armor.MT_M4A4_Sherman_Firefly: 16,
|
Armor.MT_M4A4_Sherman_Firefly:16,
|
||||||
Armor.CT_Cromwell_IV: 12,
|
Armor.CT_Cromwell_IV:12,
|
||||||
Armor.M30_Cargo_Carrier: 2,
|
Armor.M30_Cargo_Carrier:2,
|
||||||
Armor.APC_M2A1: 4,
|
Armor.APC_M2A1:4,
|
||||||
Armor.CT_Centaur_IV: 10,
|
Armor.CT_Centaur_IV: 10,
|
||||||
Armor.HIT_Churchill_VII: 16,
|
Armor.HIT_Churchill_VII: 16,
|
||||||
Armor.LAC_M8_Greyhound: 8,
|
Armor.LAC_M8_Greyhound: 8,
|
||||||
@@ -575,7 +577,6 @@ UNIT_BY_TASK = {
|
|||||||
MiG_31,
|
MiG_31,
|
||||||
FA_18C_hornet,
|
FA_18C_hornet,
|
||||||
F_15C,
|
F_15C,
|
||||||
F_14A_135_GR,
|
|
||||||
F_14B,
|
F_14B,
|
||||||
F_16A,
|
F_16A,
|
||||||
F_16C_50,
|
F_16C_50,
|
||||||
@@ -901,6 +902,7 @@ SAM_CONVERT = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Units that will always be spawned in the air
|
Units that will always be spawned in the air
|
||||||
"""
|
"""
|
||||||
@@ -911,7 +913,7 @@ TAKEOFF_BAN: List[Type[FlyingType]] = [
|
|||||||
Units that will be always spawned in the air if launched from the carrier
|
Units that will be always spawned in the air if launched from the carrier
|
||||||
"""
|
"""
|
||||||
CARRIER_TAKEOFF_BAN: List[Type[FlyingType]] = [
|
CARRIER_TAKEOFF_BAN: List[Type[FlyingType]] = [
|
||||||
Su_33, # Kuznecow is bugged in a way that only 2 aircraft could be spawned
|
Su_33, # Kuznecow is bugged in a way that only 2 aircraft could be spawned
|
||||||
]
|
]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@@ -922,7 +924,6 @@ FACTIONS = FactionLoader()
|
|||||||
|
|
||||||
CARRIER_TYPE_BY_PLANE = {
|
CARRIER_TYPE_BY_PLANE = {
|
||||||
FA_18C_hornet: CVN_74_John_C__Stennis,
|
FA_18C_hornet: CVN_74_John_C__Stennis,
|
||||||
F_14A_135_GR: CVN_74_John_C__Stennis,
|
|
||||||
F_14B: CVN_74_John_C__Stennis,
|
F_14B: CVN_74_John_C__Stennis,
|
||||||
Ka_50: LHA_1_Tarawa,
|
Ka_50: LHA_1_Tarawa,
|
||||||
SA342M: LHA_1_Tarawa,
|
SA342M: LHA_1_Tarawa,
|
||||||
@@ -996,7 +997,6 @@ PLANE_PAYLOAD_OVERRIDES: Dict[Type[PlaneType], Dict[Type[Task], str]] = {
|
|||||||
AV8BNA: COMMON_OVERRIDE,
|
AV8BNA: COMMON_OVERRIDE,
|
||||||
C_101CC: COMMON_OVERRIDE,
|
C_101CC: COMMON_OVERRIDE,
|
||||||
F_5E_3: COMMON_OVERRIDE,
|
F_5E_3: COMMON_OVERRIDE,
|
||||||
F_14A_135_GR: COMMON_OVERRIDE,
|
|
||||||
F_14B: COMMON_OVERRIDE,
|
F_14B: COMMON_OVERRIDE,
|
||||||
F_15C: COMMON_OVERRIDE,
|
F_15C: COMMON_OVERRIDE,
|
||||||
F_16C_50: COMMON_OVERRIDE,
|
F_16C_50: COMMON_OVERRIDE,
|
||||||
@@ -1006,14 +1006,14 @@ PLANE_PAYLOAD_OVERRIDES: Dict[Type[PlaneType], Dict[Type[Task], str]] = {
|
|||||||
MiG_19P: COMMON_OVERRIDE,
|
MiG_19P: COMMON_OVERRIDE,
|
||||||
MiG_21Bis: COMMON_OVERRIDE,
|
MiG_21Bis: COMMON_OVERRIDE,
|
||||||
AJS37: COMMON_OVERRIDE,
|
AJS37: COMMON_OVERRIDE,
|
||||||
Su_25T: COMMON_OVERRIDE,
|
Su_25T:COMMON_OVERRIDE,
|
||||||
Su_25: COMMON_OVERRIDE,
|
Su_25:COMMON_OVERRIDE,
|
||||||
Su_27: COMMON_OVERRIDE,
|
Su_27:COMMON_OVERRIDE,
|
||||||
Su_33: COMMON_OVERRIDE,
|
Su_33:COMMON_OVERRIDE,
|
||||||
MiG_29A: COMMON_OVERRIDE,
|
MiG_29A:COMMON_OVERRIDE,
|
||||||
MiG_29G: COMMON_OVERRIDE,
|
MiG_29G:COMMON_OVERRIDE,
|
||||||
MiG_29S: COMMON_OVERRIDE,
|
MiG_29S:COMMON_OVERRIDE,
|
||||||
Su_24M: COMMON_OVERRIDE,
|
Su_24M:COMMON_OVERRIDE,
|
||||||
Su_30: COMMON_OVERRIDE,
|
Su_30: COMMON_OVERRIDE,
|
||||||
Su_34: COMMON_OVERRIDE,
|
Su_34: COMMON_OVERRIDE,
|
||||||
Su_57: COMMON_OVERRIDE,
|
Su_57: COMMON_OVERRIDE,
|
||||||
@@ -1022,21 +1022,21 @@ PLANE_PAYLOAD_OVERRIDES: Dict[Type[PlaneType], Dict[Type[Task], str]] = {
|
|||||||
Tornado_GR4: COMMON_OVERRIDE,
|
Tornado_GR4: COMMON_OVERRIDE,
|
||||||
Tornado_IDS: COMMON_OVERRIDE,
|
Tornado_IDS: COMMON_OVERRIDE,
|
||||||
Mirage_2000_5: COMMON_OVERRIDE,
|
Mirage_2000_5: COMMON_OVERRIDE,
|
||||||
MiG_31: COMMON_OVERRIDE,
|
MiG_31:COMMON_OVERRIDE,
|
||||||
SA342M: COMMON_OVERRIDE,
|
SA342M:COMMON_OVERRIDE,
|
||||||
SA342L: COMMON_OVERRIDE,
|
SA342L:COMMON_OVERRIDE,
|
||||||
SA342Mistral: COMMON_OVERRIDE,
|
SA342Mistral:COMMON_OVERRIDE,
|
||||||
Mi_8MT: COMMON_OVERRIDE,
|
Mi_8MT:COMMON_OVERRIDE,
|
||||||
Mi_24V: COMMON_OVERRIDE,
|
Mi_24V:COMMON_OVERRIDE,
|
||||||
Mi_28N: COMMON_OVERRIDE,
|
Mi_28N:COMMON_OVERRIDE,
|
||||||
Ka_50: COMMON_OVERRIDE,
|
Ka_50:COMMON_OVERRIDE,
|
||||||
L_39ZA: COMMON_OVERRIDE,
|
L_39ZA:COMMON_OVERRIDE,
|
||||||
L_39C: COMMON_OVERRIDE,
|
L_39C:COMMON_OVERRIDE,
|
||||||
Su_17M4: COMMON_OVERRIDE,
|
Su_17M4: COMMON_OVERRIDE,
|
||||||
F_4E: COMMON_OVERRIDE,
|
F_4E: COMMON_OVERRIDE,
|
||||||
P_47D_30: COMMON_OVERRIDE,
|
P_47D_30:COMMON_OVERRIDE,
|
||||||
P_47D_30bl1: COMMON_OVERRIDE,
|
P_47D_30bl1:COMMON_OVERRIDE,
|
||||||
P_47D_40: COMMON_OVERRIDE,
|
P_47D_40:COMMON_OVERRIDE,
|
||||||
B_17G: COMMON_OVERRIDE,
|
B_17G: COMMON_OVERRIDE,
|
||||||
P_51D: COMMON_OVERRIDE,
|
P_51D: COMMON_OVERRIDE,
|
||||||
P_51D_30_NA: COMMON_OVERRIDE,
|
P_51D_30_NA: COMMON_OVERRIDE,
|
||||||
@@ -1129,7 +1129,6 @@ PLAYER_BUDGET_BASE = 20
|
|||||||
|
|
||||||
CARRIER_CAPABLE = [
|
CARRIER_CAPABLE = [
|
||||||
FA_18C_hornet,
|
FA_18C_hornet,
|
||||||
F_14A_135_GR,
|
|
||||||
F_14B,
|
F_14B,
|
||||||
AV8BNA,
|
AV8BNA,
|
||||||
Su_33,
|
Su_33,
|
||||||
@@ -1165,6 +1164,7 @@ LHA_CAPABLE = [
|
|||||||
SA342Mistral
|
SA342Mistral
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
---------- END OF CONFIGURATION SECTION
|
---------- END OF CONFIGURATION SECTION
|
||||||
"""
|
"""
|
||||||
@@ -1216,20 +1216,16 @@ def find_unittype(for_task: Task, country_name: str) -> List[UnitType]:
|
|||||||
|
|
||||||
def find_infantry(country_name: str) -> List[UnitType]:
|
def find_infantry(country_name: str) -> List[UnitType]:
|
||||||
inf = [
|
inf = [
|
||||||
Infantry.Paratrooper_AKS, Infantry.Paratrooper_AKS, Infantry.Paratrooper_AKS, Infantry.Paratrooper_AKS,
|
Infantry.Paratrooper_AKS, Infantry.Paratrooper_AKS, Infantry.Paratrooper_AKS, Infantry.Paratrooper_AKS, Infantry.Paratrooper_AKS,
|
||||||
Infantry.Paratrooper_AKS,
|
|
||||||
Infantry.Soldier_RPG,
|
Infantry.Soldier_RPG,
|
||||||
Infantry.Infantry_M4, Infantry.Infantry_M4, Infantry.Infantry_M4, Infantry.Infantry_M4, Infantry.Infantry_M4,
|
Infantry.Infantry_M4, Infantry.Infantry_M4, Infantry.Infantry_M4, Infantry.Infantry_M4, Infantry.Infantry_M4,
|
||||||
Infantry.Soldier_M249,
|
Infantry.Soldier_M249,
|
||||||
Infantry.Soldier_AK, Infantry.Soldier_AK, Infantry.Soldier_AK, Infantry.Soldier_AK, Infantry.Soldier_AK,
|
Infantry.Soldier_AK, Infantry.Soldier_AK, Infantry.Soldier_AK, Infantry.Soldier_AK, Infantry.Soldier_AK,
|
||||||
Infantry.Paratrooper_RPG_16,
|
Infantry.Paratrooper_RPG_16,
|
||||||
Infantry.Georgian_soldier_with_M4, Infantry.Georgian_soldier_with_M4, Infantry.Georgian_soldier_with_M4,
|
Infantry.Georgian_soldier_with_M4, Infantry.Georgian_soldier_with_M4, Infantry.Georgian_soldier_with_M4, Infantry.Georgian_soldier_with_M4,
|
||||||
Infantry.Georgian_soldier_with_M4,
|
Infantry.Infantry_Soldier_Rus, Infantry.Infantry_Soldier_Rus, Infantry.Infantry_Soldier_Rus, Infantry.Infantry_Soldier_Rus,
|
||||||
Infantry.Infantry_Soldier_Rus, Infantry.Infantry_Soldier_Rus, Infantry.Infantry_Soldier_Rus,
|
|
||||||
Infantry.Infantry_Soldier_Rus,
|
|
||||||
Infantry.Infantry_SMLE_No_4_Mk_1, Infantry.Infantry_SMLE_No_4_Mk_1, Infantry.Infantry_SMLE_No_4_Mk_1,
|
Infantry.Infantry_SMLE_No_4_Mk_1, Infantry.Infantry_SMLE_No_4_Mk_1, Infantry.Infantry_SMLE_No_4_Mk_1,
|
||||||
Infantry.Infantry_Mauser_98, Infantry.Infantry_Mauser_98, Infantry.Infantry_Mauser_98,
|
Infantry.Infantry_Mauser_98, Infantry.Infantry_Mauser_98, Infantry.Infantry_Mauser_98, Infantry.Infantry_Mauser_98,
|
||||||
Infantry.Infantry_Mauser_98,
|
|
||||||
Infantry.Infantry_M1_Garand, Infantry.Infantry_M1_Garand, Infantry.Infantry_M1_Garand,
|
Infantry.Infantry_M1_Garand, Infantry.Infantry_M1_Garand, Infantry.Infantry_M1_Garand,
|
||||||
Infantry.Infantry_Soldier_Insurgents, Infantry.Infantry_Soldier_Insurgents, Infantry.Infantry_Soldier_Insurgents
|
Infantry.Infantry_Soldier_Insurgents, Infantry.Infantry_Soldier_Insurgents, Infantry.Infantry_Soldier_Insurgents
|
||||||
]
|
]
|
||||||
@@ -1360,7 +1356,7 @@ def unitdict_from(fd: AssignedUnitsDict) -> Dict:
|
|||||||
|
|
||||||
|
|
||||||
def country_id_from_name(name):
|
def country_id_from_name(name):
|
||||||
for k, v in country_dict.items():
|
for k,v in country_dict.items():
|
||||||
if v.name == name:
|
if v.name == name:
|
||||||
return k
|
return k
|
||||||
return -1
|
return -1
|
||||||
@@ -1378,10 +1374,8 @@ def _validate_db():
|
|||||||
for unit_type in total_set:
|
for unit_type in total_set:
|
||||||
assert unit_type in PRICES, "{} not in prices".format(unit_type)
|
assert unit_type in PRICES, "{} not in prices".format(unit_type)
|
||||||
|
|
||||||
|
|
||||||
_validate_db()
|
_validate_db()
|
||||||
|
|
||||||
|
|
||||||
class DefaultLiveries:
|
class DefaultLiveries:
|
||||||
class Default(Enum):
|
class Default(Enum):
|
||||||
af_standard = ""
|
af_standard = ""
|
||||||
@@ -1391,4 +1385,4 @@ OH_58D.Liveries = DefaultLiveries
|
|||||||
F_16C_50.Liveries = DefaultLiveries
|
F_16C_50.Liveries = DefaultLiveries
|
||||||
P_51D_30_NA.Liveries = DefaultLiveries
|
P_51D_30_NA.Liveries = DefaultLiveries
|
||||||
Ju_88A4.Liveries = DefaultLiveries
|
Ju_88A4.Liveries = DefaultLiveries
|
||||||
B_17G.Liveries = DefaultLiveries
|
B_17G.Liveries = DefaultLiveries
|
||||||
@@ -105,9 +105,6 @@ class Faction:
|
|||||||
# List of available buildings for this faction
|
# List of available buildings for this faction
|
||||||
building_set: List[str] = field(default_factory=list)
|
building_set: List[str] = field(default_factory=list)
|
||||||
|
|
||||||
# List of default livery overrides
|
|
||||||
liveries_overrides: Dict[UnitType, List[str]] = field(default_factory=dict)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_json(cls: Type[Faction], json: Dict[str, Any]) -> Faction:
|
def from_json(cls: Type[Faction], json: Dict[str, Any]) -> Faction:
|
||||||
|
|
||||||
@@ -186,14 +183,6 @@ class Faction:
|
|||||||
else:
|
else:
|
||||||
faction.building_set = DEFAULT_AVAILABLE_BUILDINGS
|
faction.building_set = DEFAULT_AVAILABLE_BUILDINGS
|
||||||
|
|
||||||
# Load liveries override
|
|
||||||
faction.liveries_overrides = {}
|
|
||||||
liveries_overrides = json.get("liveries_overrides", {})
|
|
||||||
for k, v in liveries_overrides.items():
|
|
||||||
k = load_aircraft(k)
|
|
||||||
if k is not None:
|
|
||||||
faction.liveries_overrides[k] = [s.lower() for s in v]
|
|
||||||
|
|
||||||
return faction
|
return faction
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ class Game:
|
|||||||
reward = PLAYER_BUDGET_BASE * len(self.theater.player_points())
|
reward = PLAYER_BUDGET_BASE * len(self.theater.player_points())
|
||||||
for cp in self.theater.player_points():
|
for cp in self.theater.player_points():
|
||||||
for g in cp.ground_objects:
|
for g in cp.ground_objects:
|
||||||
if g.category in REWARDS.keys() and not g.is_dead:
|
if g.category in REWARDS.keys():
|
||||||
reward = reward + REWARDS[g.category]
|
reward = reward + REWARDS[g.category]
|
||||||
return reward
|
return reward
|
||||||
else:
|
else:
|
||||||
@@ -277,7 +277,7 @@ class Game:
|
|||||||
production = 0.0
|
production = 0.0
|
||||||
for enemy_point in self.theater.enemy_points():
|
for enemy_point in self.theater.enemy_points():
|
||||||
for g in enemy_point.ground_objects:
|
for g in enemy_point.ground_objects:
|
||||||
if g.category in REWARDS.keys() and not g.is_dead:
|
if g.category in REWARDS.keys():
|
||||||
production = production + REWARDS[g.category]
|
production = production + REWARDS[g.category]
|
||||||
|
|
||||||
production = production * 0.75
|
production = production * 0.75
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class Settings:
|
|||||||
self.night_disabled = False
|
self.night_disabled = False
|
||||||
self.external_views_allowed = True
|
self.external_views_allowed = True
|
||||||
self.supercarrier = False
|
self.supercarrier = False
|
||||||
self.multiplier = 1.0
|
self.multiplier = 1
|
||||||
self.generate_marks = True
|
self.generate_marks = True
|
||||||
self.sams = True # Legacy parameter do not use
|
self.sams = True # Legacy parameter do not use
|
||||||
self.cold_start = False # Legacy parameter do not use
|
self.cold_start = False # Legacy parameter do not use
|
||||||
|
|||||||
@@ -713,17 +713,6 @@ class AircraftConflictGenerator:
|
|||||||
for unit_instance in group.units:
|
for unit_instance in group.units:
|
||||||
unit_instance.livery_id = db.PLANE_LIVERY_OVERRIDES[unit_type]
|
unit_instance.livery_id = db.PLANE_LIVERY_OVERRIDES[unit_type]
|
||||||
|
|
||||||
# Override livery by faction file data
|
|
||||||
if flight.from_cp.captured:
|
|
||||||
faction = self.game.player_faction
|
|
||||||
else:
|
|
||||||
faction = self.game.enemy_faction
|
|
||||||
|
|
||||||
if unit_type in faction.liveries_overrides:
|
|
||||||
livery = random.choice(faction.liveries_overrides[unit_type])
|
|
||||||
for unit_instance in group.units:
|
|
||||||
unit_instance.livery_id = livery
|
|
||||||
|
|
||||||
for idx in range(0, min(len(group.units), flight.client_count)):
|
for idx in range(0, min(len(group.units), flight.client_count)):
|
||||||
unit = group.units[idx]
|
unit = group.units[idx]
|
||||||
if self.use_client:
|
if self.use_client:
|
||||||
@@ -1173,13 +1162,12 @@ class AircraftConflictGenerator:
|
|||||||
viggen_target_points = [
|
viggen_target_points = [
|
||||||
(idx, point) for idx, point in enumerate(filtered_points) if point.waypoint_type in TARGET_WAYPOINTS
|
(idx, point) for idx, point in enumerate(filtered_points) if point.waypoint_type in TARGET_WAYPOINTS
|
||||||
]
|
]
|
||||||
if viggen_target_points:
|
keep_target = viggen_target_points[random.randint(0, len(viggen_target_points) - 1)]
|
||||||
keep_target = viggen_target_points[random.randint(0, len(viggen_target_points) - 1)]
|
filtered_points = [
|
||||||
filtered_points = [
|
point for idx, point in enumerate(filtered_points) if (
|
||||||
point for idx, point in enumerate(filtered_points) if (
|
point.waypoint_type not in TARGET_WAYPOINTS or idx == keep_target[0]
|
||||||
point.waypoint_type not in TARGET_WAYPOINTS or idx == keep_target[0]
|
)
|
||||||
)
|
]
|
||||||
]
|
|
||||||
|
|
||||||
for idx, point in enumerate(filtered_points):
|
for idx, point in enumerate(filtered_points):
|
||||||
PydcsWaypointBuilder.for_waypoint(
|
PydcsWaypointBuilder.for_waypoint(
|
||||||
@@ -1199,12 +1187,6 @@ class AircraftConflictGenerator:
|
|||||||
if not flight.client_count:
|
if not flight.client_count:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if start_time < timedelta(minutes=10):
|
|
||||||
# Don't bother delaying client flights with short start delays. Much
|
|
||||||
# more than ten minutes starts to eat into fuel a bit more
|
|
||||||
# (espeicially for something fuel limited like a Harrier).
|
|
||||||
return False
|
|
||||||
|
|
||||||
return not self.settings.never_delay_player_flights
|
return not self.settings.never_delay_player_flights
|
||||||
|
|
||||||
def set_takeoff_time(self, waypoint: FlightWaypoint, package: Package,
|
def set_takeoff_time(self, waypoint: FlightWaypoint, package: Package,
|
||||||
@@ -1231,6 +1213,15 @@ class AircraftConflictGenerator:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def should_activate_late(flight: Flight) -> bool:
|
def should_activate_late(flight: Flight) -> bool:
|
||||||
|
if flight.client_count:
|
||||||
|
# Never delay players. Note that cold start player flights with
|
||||||
|
# AI members will still be marked as uncontrolled until the start
|
||||||
|
# trigger fires to postpone engine start.
|
||||||
|
#
|
||||||
|
# Player flights that start on the runway or in the air will start
|
||||||
|
# immediately, and AI flight members will not be delayed.
|
||||||
|
return False
|
||||||
|
|
||||||
if flight.start_type != "Cold":
|
if flight.start_type != "Cold":
|
||||||
# Avoid spawning aircraft in the air or on the runway until it's
|
# Avoid spawning aircraft in the air or on the runway until it's
|
||||||
# time for their mission. Also avoid burning through gas spawning
|
# time for their mission. Also avoid burning through gas spawning
|
||||||
|
|||||||
@@ -144,16 +144,6 @@ class Conflict:
|
|||||||
position = middle_point.point_from_heading(attack_heading, strength_delta * attack_distance / 2 - FRONTLINE_MIN_CP_DISTANCE)
|
position = middle_point.point_from_heading(attack_heading, strength_delta * attack_distance / 2 - FRONTLINE_MIN_CP_DISTANCE)
|
||||||
return position, _opposite_heading(attack_heading)
|
return position, _opposite_heading(attack_heading)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def flight_frontline_vector(cls, from_cp: ControlPoint, to_cp: ControlPoint, theater: ConflictTheater) -> Tuple[Point, int, int]:
|
|
||||||
"""Returns the frontline vector without regard for exclusion zones, used in CAS flight plan"""
|
|
||||||
frontline = cls.frontline_position(theater, from_cp, to_cp)
|
|
||||||
center_position, heading = frontline
|
|
||||||
left_position = center_position.point_from_heading(_heading_sum(heading, -90), int(FRONTLINE_LENGTH/2))
|
|
||||||
right_position = center_position.point_from_heading(_heading_sum(heading, 90), int(FRONTLINE_LENGTH/2))
|
|
||||||
|
|
||||||
return left_position, _heading_sum(heading, 90), int(right_position.distance_to_point(left_position))
|
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def frontline_vector(cls, from_cp: ControlPoint, to_cp: ControlPoint, theater: ConflictTheater) -> Tuple[Point, int, int]:
|
def frontline_vector(cls, from_cp: ControlPoint, to_cp: ControlPoint, theater: ConflictTheater) -> Tuple[Point, int, int]:
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ from dcs.planes import (
|
|||||||
FW_190A8,
|
FW_190A8,
|
||||||
FW_190D9,
|
FW_190D9,
|
||||||
F_117A,
|
F_117A,
|
||||||
F_14A_135_GR,
|
|
||||||
F_14B,
|
F_14B,
|
||||||
F_15C,
|
F_15C,
|
||||||
F_15E,
|
F_15E,
|
||||||
@@ -105,7 +104,6 @@ INTERCEPT_CAPABLE = [
|
|||||||
Mirage_2000_5,
|
Mirage_2000_5,
|
||||||
Rafale_M,
|
Rafale_M,
|
||||||
|
|
||||||
F_14A_135_GR,
|
|
||||||
F_14B,
|
F_14B,
|
||||||
F_15C,
|
F_15C,
|
||||||
|
|
||||||
@@ -137,7 +135,6 @@ CAP_CAPABLE = [
|
|||||||
F_86F_Sabre,
|
F_86F_Sabre,
|
||||||
F_4E,
|
F_4E,
|
||||||
F_5E_3,
|
F_5E_3,
|
||||||
F_14A_135_GR,
|
|
||||||
F_14B,
|
F_14B,
|
||||||
F_15C,
|
F_15C,
|
||||||
F_15E,
|
F_15E,
|
||||||
@@ -186,7 +183,6 @@ CAP_PREFERRED = [
|
|||||||
Mirage_2000_5,
|
Mirage_2000_5,
|
||||||
|
|
||||||
F_86F_Sabre,
|
F_86F_Sabre,
|
||||||
F_14A_135_GR,
|
|
||||||
F_14B,
|
F_14B,
|
||||||
F_15C,
|
F_15C,
|
||||||
|
|
||||||
@@ -230,7 +226,6 @@ CAS_CAPABLE = [
|
|||||||
|
|
||||||
F_86F_Sabre,
|
F_86F_Sabre,
|
||||||
F_5E_3,
|
F_5E_3,
|
||||||
F_14A_135_GR,
|
|
||||||
F_14B,
|
F_14B,
|
||||||
F_15E,
|
F_15E,
|
||||||
F_16A,
|
F_16A,
|
||||||
@@ -395,7 +390,6 @@ STRIKE_CAPABLE = [
|
|||||||
|
|
||||||
F_86F_Sabre,
|
F_86F_Sabre,
|
||||||
F_5E_3,
|
F_5E_3,
|
||||||
F_14A_135_GR,
|
|
||||||
F_14B,
|
F_14B,
|
||||||
F_15E,
|
F_15E,
|
||||||
F_16A,
|
F_16A,
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ generating the waypoints for the mission.
|
|||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import math
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from functools import cached_property
|
from functools import cached_property
|
||||||
import logging
|
import logging
|
||||||
@@ -276,14 +275,18 @@ class PatrollingFlightPlan(FlightPlan):
|
|||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class BarCapFlightPlan(PatrollingFlightPlan):
|
class BarCapFlightPlan(PatrollingFlightPlan):
|
||||||
takeoff: FlightWaypoint
|
takeoff: FlightWaypoint
|
||||||
|
ascent: FlightWaypoint
|
||||||
|
descent: FlightWaypoint
|
||||||
land: FlightWaypoint
|
land: FlightWaypoint
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def waypoints(self) -> List[FlightWaypoint]:
|
def waypoints(self) -> List[FlightWaypoint]:
|
||||||
return [
|
return [
|
||||||
self.takeoff,
|
self.takeoff,
|
||||||
|
self.ascent,
|
||||||
self.patrol_start,
|
self.patrol_start,
|
||||||
self.patrol_end,
|
self.patrol_end,
|
||||||
|
self.descent,
|
||||||
self.land,
|
self.land,
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -291,16 +294,20 @@ class BarCapFlightPlan(PatrollingFlightPlan):
|
|||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class CasFlightPlan(PatrollingFlightPlan):
|
class CasFlightPlan(PatrollingFlightPlan):
|
||||||
takeoff: FlightWaypoint
|
takeoff: FlightWaypoint
|
||||||
|
ascent: FlightWaypoint
|
||||||
target: FlightWaypoint
|
target: FlightWaypoint
|
||||||
|
descent: FlightWaypoint
|
||||||
land: FlightWaypoint
|
land: FlightWaypoint
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def waypoints(self) -> List[FlightWaypoint]:
|
def waypoints(self) -> List[FlightWaypoint]:
|
||||||
return [
|
return [
|
||||||
self.takeoff,
|
self.takeoff,
|
||||||
|
self.ascent,
|
||||||
self.patrol_start,
|
self.patrol_start,
|
||||||
self.target,
|
self.target,
|
||||||
self.patrol_end,
|
self.patrol_end,
|
||||||
|
self.descent,
|
||||||
self.land,
|
self.land,
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -314,14 +321,18 @@ class CasFlightPlan(PatrollingFlightPlan):
|
|||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class FrontLineCapFlightPlan(PatrollingFlightPlan):
|
class FrontLineCapFlightPlan(PatrollingFlightPlan):
|
||||||
takeoff: FlightWaypoint
|
takeoff: FlightWaypoint
|
||||||
|
ascent: FlightWaypoint
|
||||||
|
descent: FlightWaypoint
|
||||||
land: FlightWaypoint
|
land: FlightWaypoint
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def waypoints(self) -> List[FlightWaypoint]:
|
def waypoints(self) -> List[FlightWaypoint]:
|
||||||
return [
|
return [
|
||||||
self.takeoff,
|
self.takeoff,
|
||||||
|
self.ascent,
|
||||||
self.patrol_start,
|
self.patrol_start,
|
||||||
self.patrol_end,
|
self.patrol_end,
|
||||||
|
self.descent,
|
||||||
self.land,
|
self.land,
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -349,24 +360,28 @@ class FrontLineCapFlightPlan(PatrollingFlightPlan):
|
|||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class StrikeFlightPlan(FormationFlightPlan):
|
class StrikeFlightPlan(FormationFlightPlan):
|
||||||
takeoff: FlightWaypoint
|
takeoff: FlightWaypoint
|
||||||
|
ascent: FlightWaypoint
|
||||||
hold: FlightWaypoint
|
hold: FlightWaypoint
|
||||||
join: FlightWaypoint
|
join: FlightWaypoint
|
||||||
ingress: FlightWaypoint
|
ingress: FlightWaypoint
|
||||||
targets: List[FlightWaypoint]
|
targets: List[FlightWaypoint]
|
||||||
egress: FlightWaypoint
|
egress: FlightWaypoint
|
||||||
split: FlightWaypoint
|
split: FlightWaypoint
|
||||||
|
descent: FlightWaypoint
|
||||||
land: FlightWaypoint
|
land: FlightWaypoint
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def waypoints(self) -> List[FlightWaypoint]:
|
def waypoints(self) -> List[FlightWaypoint]:
|
||||||
return [
|
return [
|
||||||
self.takeoff,
|
self.takeoff,
|
||||||
|
self.ascent,
|
||||||
self.hold,
|
self.hold,
|
||||||
self.join,
|
self.join,
|
||||||
self.ingress
|
self.ingress
|
||||||
] + self.targets + [
|
] + self.targets + [
|
||||||
self.egress,
|
self.egress,
|
||||||
self.split,
|
self.split,
|
||||||
|
self.descent,
|
||||||
self.land,
|
self.land,
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -558,8 +573,8 @@ class FlightPlanBuilder:
|
|||||||
def regenerate_package_waypoints(self) -> None:
|
def regenerate_package_waypoints(self) -> None:
|
||||||
ingress_point = self._ingress_point()
|
ingress_point = self._ingress_point()
|
||||||
egress_point = self._egress_point()
|
egress_point = self._egress_point()
|
||||||
join_point = self._rendezvous_point(ingress_point)
|
join_point = self._join_point(ingress_point)
|
||||||
split_point = self._rendezvous_point(egress_point)
|
split_point = self._split_point(egress_point)
|
||||||
|
|
||||||
from gen.ato import PackageWaypoints
|
from gen.ato import PackageWaypoints
|
||||||
self.package.waypoints = PackageWaypoints(
|
self.package.waypoints = PackageWaypoints(
|
||||||
@@ -659,15 +674,18 @@ class FlightPlanBuilder:
|
|||||||
|
|
||||||
builder = WaypointBuilder(self.game.conditions, flight, self.doctrine)
|
builder = WaypointBuilder(self.game.conditions, flight, self.doctrine)
|
||||||
start, end = builder.race_track(start, end, patrol_alt)
|
start, end = builder.race_track(start, end, patrol_alt)
|
||||||
|
descent, land = builder.rtb(flight.from_cp)
|
||||||
|
|
||||||
return BarCapFlightPlan(
|
return BarCapFlightPlan(
|
||||||
package=self.package,
|
package=self.package,
|
||||||
flight=flight,
|
flight=flight,
|
||||||
patrol_duration=self.doctrine.cap_duration,
|
patrol_duration=self.doctrine.cap_duration,
|
||||||
takeoff=builder.takeoff(flight.from_cp),
|
takeoff=builder.takeoff(flight.from_cp),
|
||||||
|
ascent=builder.ascent(flight.from_cp),
|
||||||
patrol_start=start,
|
patrol_start=start,
|
||||||
patrol_end=end,
|
patrol_end=end,
|
||||||
land=builder.land(flight.from_cp)
|
descent=descent,
|
||||||
|
land=land
|
||||||
)
|
)
|
||||||
|
|
||||||
def generate_frontline_cap(self, flight: Flight) -> FrontLineCapFlightPlan:
|
def generate_frontline_cap(self, flight: Flight) -> FrontLineCapFlightPlan:
|
||||||
@@ -706,8 +724,9 @@ class FlightPlanBuilder:
|
|||||||
|
|
||||||
# Create points
|
# Create points
|
||||||
builder = WaypointBuilder(self.game.conditions, flight, self.doctrine)
|
builder = WaypointBuilder(self.game.conditions, flight, self.doctrine)
|
||||||
start, end = builder.race_track(orbit0p, orbit1p, patrol_alt)
|
|
||||||
|
|
||||||
|
start, end = builder.race_track(orbit0p, orbit1p, patrol_alt)
|
||||||
|
descent, land = builder.rtb(flight.from_cp)
|
||||||
return FrontLineCapFlightPlan(
|
return FrontLineCapFlightPlan(
|
||||||
package=self.package,
|
package=self.package,
|
||||||
flight=flight,
|
flight=flight,
|
||||||
@@ -717,9 +736,11 @@ class FlightPlanBuilder:
|
|||||||
# duration of the escorted mission, or until it is winchester/bingo.
|
# duration of the escorted mission, or until it is winchester/bingo.
|
||||||
patrol_duration=self.doctrine.cap_duration,
|
patrol_duration=self.doctrine.cap_duration,
|
||||||
takeoff=builder.takeoff(flight.from_cp),
|
takeoff=builder.takeoff(flight.from_cp),
|
||||||
|
ascent=builder.ascent(flight.from_cp),
|
||||||
patrol_start=start,
|
patrol_start=start,
|
||||||
patrol_end=end,
|
patrol_end=end,
|
||||||
land=builder.land(flight.from_cp)
|
descent=descent,
|
||||||
|
land=land
|
||||||
)
|
)
|
||||||
|
|
||||||
def generate_dead(self, flight: Flight,
|
def generate_dead(self, flight: Flight,
|
||||||
@@ -778,18 +799,21 @@ class FlightPlanBuilder:
|
|||||||
ingress, target, egress = builder.escort(
|
ingress, target, egress = builder.escort(
|
||||||
self.package.waypoints.ingress, self.package.target,
|
self.package.waypoints.ingress, self.package.target,
|
||||||
self.package.waypoints.egress)
|
self.package.waypoints.egress)
|
||||||
|
descent, land = builder.rtb(flight.from_cp)
|
||||||
|
|
||||||
return StrikeFlightPlan(
|
return StrikeFlightPlan(
|
||||||
package=self.package,
|
package=self.package,
|
||||||
flight=flight,
|
flight=flight,
|
||||||
takeoff=builder.takeoff(flight.from_cp),
|
takeoff=builder.takeoff(flight.from_cp),
|
||||||
|
ascent=builder.ascent(flight.from_cp),
|
||||||
hold=builder.hold(self._hold_point(flight)),
|
hold=builder.hold(self._hold_point(flight)),
|
||||||
join=builder.join(self.package.waypoints.join),
|
join=builder.join(self.package.waypoints.join),
|
||||||
ingress=ingress,
|
ingress=ingress,
|
||||||
targets=[target],
|
targets=[target],
|
||||||
egress=egress,
|
egress=egress,
|
||||||
split=builder.split(self.package.waypoints.split),
|
split=builder.split(self.package.waypoints.split),
|
||||||
land=builder.land(flight.from_cp)
|
descent=descent,
|
||||||
|
land=land
|
||||||
)
|
)
|
||||||
|
|
||||||
def generate_cas(self, flight: Flight) -> CasFlightPlan:
|
def generate_cas(self, flight: Flight) -> CasFlightPlan:
|
||||||
@@ -803,7 +827,7 @@ class FlightPlanBuilder:
|
|||||||
if not isinstance(location, FrontLine):
|
if not isinstance(location, FrontLine):
|
||||||
raise InvalidObjectiveLocation(flight.flight_type, location)
|
raise InvalidObjectiveLocation(flight.flight_type, location)
|
||||||
|
|
||||||
ingress, heading, distance = Conflict.flight_frontline_vector(
|
ingress, heading, distance = Conflict.frontline_vector(
|
||||||
location.control_points[0], location.control_points[1],
|
location.control_points[0], location.control_points[1],
|
||||||
self.game.theater
|
self.game.theater
|
||||||
)
|
)
|
||||||
@@ -811,16 +835,19 @@ class FlightPlanBuilder:
|
|||||||
egress = ingress.point_from_heading(heading, distance)
|
egress = ingress.point_from_heading(heading, distance)
|
||||||
|
|
||||||
builder = WaypointBuilder(self.game.conditions, flight, self.doctrine)
|
builder = WaypointBuilder(self.game.conditions, flight, self.doctrine)
|
||||||
|
descent, land = builder.rtb(flight.from_cp)
|
||||||
|
|
||||||
return CasFlightPlan(
|
return CasFlightPlan(
|
||||||
package=self.package,
|
package=self.package,
|
||||||
flight=flight,
|
flight=flight,
|
||||||
patrol_duration=self.doctrine.cas_duration,
|
patrol_duration=self.doctrine.cas_duration,
|
||||||
takeoff=builder.takeoff(flight.from_cp),
|
takeoff=builder.takeoff(flight.from_cp),
|
||||||
|
ascent=builder.ascent(flight.from_cp),
|
||||||
patrol_start=builder.ingress_cas(ingress, location),
|
patrol_start=builder.ingress_cas(ingress, location),
|
||||||
target=builder.cas(center),
|
target=builder.cas(center),
|
||||||
patrol_end=builder.egress(egress, location),
|
patrol_end=builder.egress(egress, location),
|
||||||
land=builder.land(flight.from_cp)
|
descent=descent,
|
||||||
|
land=land
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -844,52 +871,36 @@ class FlightPlanBuilder:
|
|||||||
return builder.strike_area(location)
|
return builder.strike_area(location)
|
||||||
|
|
||||||
def _hold_point(self, flight: Flight) -> Point:
|
def _hold_point(self, flight: Flight) -> Point:
|
||||||
assert self.package.waypoints is not None
|
heading = flight.from_cp.position.heading_between_point(
|
||||||
origin = flight.from_cp.position
|
self.package.target.position
|
||||||
target = self.package.target.position
|
)
|
||||||
join = self.package.waypoints.join
|
return flight.from_cp.position.point_from_heading(
|
||||||
origin_to_target = origin.distance_to_point(target)
|
heading, nm_to_meter(15)
|
||||||
join_to_target = join.distance_to_point(target)
|
|
||||||
if origin_to_target < join_to_target:
|
|
||||||
# If the origin airfield is closer to the target than the join
|
|
||||||
# point, plan the hold point such that it retreats from the origin
|
|
||||||
# airfield.
|
|
||||||
return join.point_from_heading(target.heading_between_point(origin),
|
|
||||||
self.doctrine.push_distance)
|
|
||||||
|
|
||||||
heading_to_join = origin.heading_between_point(join)
|
|
||||||
hold_point = origin.point_from_heading(heading_to_join,
|
|
||||||
self.doctrine.push_distance)
|
|
||||||
if hold_point.distance_to_point(join) >= self.doctrine.push_distance:
|
|
||||||
# Hold point is between the origin airfield and the join point and
|
|
||||||
# spaced sufficiently.
|
|
||||||
return hold_point
|
|
||||||
|
|
||||||
# The hold point is between the origin airfield and the join point, but
|
|
||||||
# the distance between the hold point and the join point is too short.
|
|
||||||
# Bend the hold point out to extend the distance while maintaining the
|
|
||||||
# minimum distance from the origin airfield to keep the AI flying
|
|
||||||
# properly.
|
|
||||||
origin_to_join = origin.distance_to_point(join)
|
|
||||||
cos_theta = (
|
|
||||||
(self.doctrine.hold_distance ** 2 +
|
|
||||||
origin_to_join ** 2 -
|
|
||||||
self.doctrine.join_distance ** 2) /
|
|
||||||
(2 * self.doctrine.hold_distance * origin_to_join)
|
|
||||||
)
|
)
|
||||||
try:
|
|
||||||
theta = math.acos(cos_theta)
|
|
||||||
except ValueError:
|
|
||||||
# No solution that maintains hold and join distances. Extend the
|
|
||||||
# hold point away from the target.
|
|
||||||
return origin.point_from_heading(
|
|
||||||
target.heading_between_point(origin),
|
|
||||||
self.doctrine.hold_distance)
|
|
||||||
|
|
||||||
return origin.point_from_heading(heading_to_join - theta,
|
|
||||||
self.doctrine.hold_distance)
|
|
||||||
|
|
||||||
# TODO: Make a model for the waypoint builder and use that in the UI.
|
# TODO: Make a model for the waypoint builder and use that in the UI.
|
||||||
|
def generate_ascend_point(self, flight: Flight,
|
||||||
|
departure: ControlPoint) -> FlightWaypoint:
|
||||||
|
"""Generate ascend point.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
flight: The flight to generate the descend point for.
|
||||||
|
departure: Departure airfield or carrier.
|
||||||
|
"""
|
||||||
|
builder = WaypointBuilder(self.game.conditions, flight, self.doctrine)
|
||||||
|
return builder.ascent(departure)
|
||||||
|
|
||||||
|
def generate_descend_point(self, flight: Flight,
|
||||||
|
arrival: ControlPoint) -> FlightWaypoint:
|
||||||
|
"""Generate approach/descend point.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
flight: The flight to generate the descend point for.
|
||||||
|
arrival: Arrival airfield or carrier.
|
||||||
|
"""
|
||||||
|
builder = WaypointBuilder(self.game.conditions, flight, self.doctrine)
|
||||||
|
return builder.descent(arrival)
|
||||||
|
|
||||||
def generate_rtb_waypoint(self, flight: Flight,
|
def generate_rtb_waypoint(self, flight: Flight,
|
||||||
arrival: ControlPoint) -> FlightWaypoint:
|
arrival: ControlPoint) -> FlightWaypoint:
|
||||||
"""Generate RTB landing point.
|
"""Generate RTB landing point.
|
||||||
@@ -928,54 +939,31 @@ class FlightPlanBuilder:
|
|||||||
target_waypoints.append(
|
target_waypoints.append(
|
||||||
self.target_area_waypoint(flight, location, builder))
|
self.target_area_waypoint(flight, location, builder))
|
||||||
|
|
||||||
|
descent, land = builder.rtb(flight.from_cp)
|
||||||
return StrikeFlightPlan(
|
return StrikeFlightPlan(
|
||||||
package=self.package,
|
package=self.package,
|
||||||
flight=flight,
|
flight=flight,
|
||||||
takeoff=builder.takeoff(flight.from_cp),
|
takeoff=builder.takeoff(flight.from_cp),
|
||||||
|
ascent=builder.ascent(flight.from_cp),
|
||||||
hold=builder.hold(self._hold_point(flight)),
|
hold=builder.hold(self._hold_point(flight)),
|
||||||
join=builder.join(self.package.waypoints.join),
|
join=builder.join(self.package.waypoints.join),
|
||||||
ingress=ingress,
|
ingress=ingress,
|
||||||
targets=target_waypoints,
|
targets=target_waypoints,
|
||||||
egress=builder.egress(self.package.waypoints.egress, location),
|
egress=builder.egress(self.package.waypoints.egress, location),
|
||||||
split=builder.split(self.package.waypoints.split),
|
split=builder.split(self.package.waypoints.split),
|
||||||
land=builder.land(flight.from_cp)
|
descent=descent,
|
||||||
|
land=land
|
||||||
)
|
)
|
||||||
|
|
||||||
def _retreating_rendezvous_point(self, attack_transition: Point) -> Point:
|
def _join_point(self, ingress_point: Point) -> Point:
|
||||||
"""Creates a rendezvous point that retreats from the origin airfield."""
|
heading = self._heading_to_package_airfield(ingress_point)
|
||||||
return attack_transition.point_from_heading(
|
return ingress_point.point_from_heading(heading,
|
||||||
self.package.target.position.heading_between_point(
|
-self.doctrine.join_distance)
|
||||||
self.package_airfield().position),
|
|
||||||
self.doctrine.join_distance)
|
|
||||||
|
|
||||||
def _advancing_rendezvous_point(self, attack_transition: Point) -> Point:
|
def _split_point(self, egress_point: Point) -> Point:
|
||||||
"""Creates a rendezvous point that advances toward the target."""
|
heading = self._heading_to_package_airfield(egress_point)
|
||||||
heading = self._heading_to_package_airfield(attack_transition)
|
return egress_point.point_from_heading(heading,
|
||||||
return attack_transition.point_from_heading(heading,
|
-self.doctrine.split_distance)
|
||||||
-self.doctrine.join_distance)
|
|
||||||
|
|
||||||
def _rendezvous_should_retreat(self, attack_transition: Point) -> bool:
|
|
||||||
transition_target_distance = attack_transition.distance_to_point(
|
|
||||||
self.package.target.position
|
|
||||||
)
|
|
||||||
origin_target_distance = self._distance_to_package_airfield(
|
|
||||||
self.package.target.position
|
|
||||||
)
|
|
||||||
|
|
||||||
# If the origin point is closer to the target than the ingress point,
|
|
||||||
# the rendezvous point should be positioned in a position that retreats
|
|
||||||
# from the origin airfield.
|
|
||||||
return origin_target_distance < transition_target_distance
|
|
||||||
|
|
||||||
def _rendezvous_point(self, attack_transition: Point) -> Point:
|
|
||||||
"""Returns the position of the rendezvous point.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
attack_transition: The ingress or egress point for this rendezvous.
|
|
||||||
"""
|
|
||||||
if self._rendezvous_should_retreat(attack_transition):
|
|
||||||
return self._retreating_rendezvous_point(attack_transition)
|
|
||||||
return self._advancing_rendezvous_point(attack_transition)
|
|
||||||
|
|
||||||
def _ingress_point(self) -> Point:
|
def _ingress_point(self) -> Point:
|
||||||
heading = self._target_heading_to_package_airfield()
|
heading = self._target_heading_to_package_airfield()
|
||||||
@@ -995,9 +983,6 @@ class FlightPlanBuilder:
|
|||||||
def _heading_to_package_airfield(self, point: Point) -> int:
|
def _heading_to_package_airfield(self, point: Point) -> int:
|
||||||
return self.package_airfield().position.heading_between_point(point)
|
return self.package_airfield().position.heading_between_point(point)
|
||||||
|
|
||||||
def _distance_to_package_airfield(self, point: Point) -> int:
|
|
||||||
return self.package_airfield().position.distance_to_point(point)
|
|
||||||
|
|
||||||
def package_airfield(self) -> ControlPoint:
|
def package_airfield(self) -> ControlPoint:
|
||||||
# We'll always have a package, but if this is being planned via the UI
|
# We'll always have a package, but if this is being planned via the UI
|
||||||
# it could be the first flight in the package.
|
# it could be the first flight in the package.
|
||||||
|
|||||||
@@ -96,11 +96,6 @@ class TotEstimator:
|
|||||||
|
|
||||||
def mission_start_time(self, flight: Flight) -> timedelta:
|
def mission_start_time(self, flight: Flight) -> timedelta:
|
||||||
takeoff_time = self.takeoff_time_for_flight(flight)
|
takeoff_time = self.takeoff_time_for_flight(flight)
|
||||||
if takeoff_time is None:
|
|
||||||
# Could not determine takeoff time, probably due to a custom flight
|
|
||||||
# plan. Start immediately.
|
|
||||||
return timedelta()
|
|
||||||
|
|
||||||
startup_time = self.estimate_startup(flight)
|
startup_time = self.estimate_startup(flight)
|
||||||
ground_ops_time = self.estimate_ground_ops(flight)
|
ground_ops_time = self.estimate_ground_ops(flight)
|
||||||
start_time = takeoff_time - startup_time - ground_ops_time
|
start_time = takeoff_time - startup_time - ground_ops_time
|
||||||
@@ -115,15 +110,13 @@ class TotEstimator:
|
|||||||
# Round down so *barely* above zero start times are just zero.
|
# Round down so *barely* above zero start times are just zero.
|
||||||
return timedelta(seconds=math.floor(start_time.total_seconds()))
|
return timedelta(seconds=math.floor(start_time.total_seconds()))
|
||||||
|
|
||||||
def takeoff_time_for_flight(self, flight: Flight) -> Optional[timedelta]:
|
def takeoff_time_for_flight(self, flight: Flight) -> timedelta:
|
||||||
travel_time = self.travel_time_to_rendezvous_or_target(flight)
|
travel_time = self.travel_time_to_rendezvous_or_target(flight)
|
||||||
if travel_time is None:
|
if travel_time is None:
|
||||||
from gen.flights.flightplan import CustomFlightPlan
|
logging.warning("Found no join point or patrol point. Cannot "
|
||||||
if not isinstance(flight.flight_plan, CustomFlightPlan):
|
f"estimate takeoff time takeoff time for {flight}")
|
||||||
logging.warning(
|
# Takeoff immediately.
|
||||||
"Found no rendezvous or target point. Cannot estimate "
|
return timedelta()
|
||||||
f"takeoff time takeoff time for {flight}.")
|
|
||||||
return None
|
|
||||||
|
|
||||||
from gen.flights.flightplan import FormationFlightPlan
|
from gen.flights.flightplan import FormationFlightPlan
|
||||||
if isinstance(flight.flight_plan, FormationFlightPlan):
|
if isinstance(flight.flight_plan, FormationFlightPlan):
|
||||||
@@ -133,7 +126,7 @@ class TotEstimator:
|
|||||||
logging.warning(
|
logging.warning(
|
||||||
"Could not determine the TOT of the join point. Takeoff "
|
"Could not determine the TOT of the join point. Takeoff "
|
||||||
f"time for {flight} will be immediate.")
|
f"time for {flight} will be immediate.")
|
||||||
return None
|
return timedelta()
|
||||||
else:
|
else:
|
||||||
tot = self.package.time_over_target
|
tot = self.package.time_over_target
|
||||||
return tot - travel_time - self.HOLD_TIME
|
return tot - travel_time - self.HOLD_TIME
|
||||||
|
|||||||
@@ -7,9 +7,11 @@ from dcs.mapping import Point
|
|||||||
from dcs.unit import Unit
|
from dcs.unit import Unit
|
||||||
|
|
||||||
from game.data.doctrine import Doctrine
|
from game.data.doctrine import Doctrine
|
||||||
|
from game.utils import nm_to_meter
|
||||||
from game.weather import Conditions
|
from game.weather import Conditions
|
||||||
from theater import ControlPoint, MissionTarget, TheaterGroundObject
|
from theater import ControlPoint, MissionTarget, TheaterGroundObject
|
||||||
from .flight import Flight, FlightWaypoint, FlightWaypointType
|
from .flight import Flight, FlightWaypoint, FlightWaypointType
|
||||||
|
from ..runways import RunwayAssigner
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
@@ -55,6 +57,52 @@ class WaypointBuilder:
|
|||||||
waypoint.pretty_name = "Takeoff"
|
waypoint.pretty_name = "Takeoff"
|
||||||
return waypoint
|
return waypoint
|
||||||
|
|
||||||
|
def ascent(self, departure: ControlPoint) -> FlightWaypoint:
|
||||||
|
"""Create ascent waypoint for the given departure airfield or carrier.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
departure: Departure airfield or carrier.
|
||||||
|
"""
|
||||||
|
heading = RunwayAssigner(self.conditions).takeoff_heading(departure)
|
||||||
|
position = departure.position.point_from_heading(
|
||||||
|
heading, nm_to_meter(5)
|
||||||
|
)
|
||||||
|
waypoint = FlightWaypoint(
|
||||||
|
FlightWaypointType.ASCEND_POINT,
|
||||||
|
position.x,
|
||||||
|
position.y,
|
||||||
|
500 if self.is_helo else self.doctrine.pattern_altitude
|
||||||
|
)
|
||||||
|
waypoint.name = "ASCEND"
|
||||||
|
waypoint.alt_type = "RADIO"
|
||||||
|
waypoint.description = "Ascend"
|
||||||
|
waypoint.pretty_name = "Ascend"
|
||||||
|
return waypoint
|
||||||
|
|
||||||
|
def descent(self, arrival: ControlPoint) -> FlightWaypoint:
|
||||||
|
"""Create descent waypoint for the given arrival airfield or carrier.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
arrival: Arrival airfield or carrier.
|
||||||
|
"""
|
||||||
|
landing_heading = RunwayAssigner(self.conditions).landing_heading(
|
||||||
|
arrival)
|
||||||
|
heading = (landing_heading + 180) % 360
|
||||||
|
position = arrival.position.point_from_heading(
|
||||||
|
heading, nm_to_meter(5)
|
||||||
|
)
|
||||||
|
waypoint = FlightWaypoint(
|
||||||
|
FlightWaypointType.DESCENT_POINT,
|
||||||
|
position.x,
|
||||||
|
position.y,
|
||||||
|
300 if self.is_helo else self.doctrine.pattern_altitude
|
||||||
|
)
|
||||||
|
waypoint.name = "DESCEND"
|
||||||
|
waypoint.alt_type = "RADIO"
|
||||||
|
waypoint.description = "Descend to pattern altitude"
|
||||||
|
waypoint.pretty_name = "Descend"
|
||||||
|
return waypoint
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def land(arrival: ControlPoint) -> FlightWaypoint:
|
def land(arrival: ControlPoint) -> FlightWaypoint:
|
||||||
"""Create descent waypoint for the given arrival airfield or carrier.
|
"""Create descent waypoint for the given arrival airfield or carrier.
|
||||||
@@ -183,7 +231,6 @@ class WaypointBuilder:
|
|||||||
waypoint.description = description
|
waypoint.description = description
|
||||||
waypoint.pretty_name = description
|
waypoint.pretty_name = description
|
||||||
waypoint.name = target.name
|
waypoint.name = target.name
|
||||||
waypoint.alt_type = "RADIO"
|
|
||||||
# The target waypoints are only for the player's benefit. AI tasks for
|
# The target waypoints are only for the player's benefit. AI tasks for
|
||||||
# the target are set on the ingress point so they begin their attack
|
# the target are set on the ingress point so they begin their attack
|
||||||
# *before* reaching the target.
|
# *before* reaching the target.
|
||||||
@@ -210,7 +257,6 @@ class WaypointBuilder:
|
|||||||
waypoint.description = name
|
waypoint.description = name
|
||||||
waypoint.pretty_name = name
|
waypoint.pretty_name = name
|
||||||
waypoint.name = name
|
waypoint.name = name
|
||||||
waypoint.alt_type = "RADIO"
|
|
||||||
# The target waypoints are only for the player's benefit. AI tasks for
|
# The target waypoints are only for the player's benefit. AI tasks for
|
||||||
# the target are set on the ingress point so they begin their attack
|
# the target are set on the ingress point so they begin their attack
|
||||||
# *before* reaching the target.
|
# *before* reaching the target.
|
||||||
@@ -280,6 +326,15 @@ class WaypointBuilder:
|
|||||||
return (self.race_track_start(start, altitude),
|
return (self.race_track_start(start, altitude),
|
||||||
self.race_track_end(end, altitude))
|
self.race_track_end(end, altitude))
|
||||||
|
|
||||||
|
def rtb(self,
|
||||||
|
arrival: ControlPoint) -> Tuple[FlightWaypoint, FlightWaypoint]:
|
||||||
|
"""Creates descent ant landing waypoints for the given control point.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
arrival: Arrival airfield or carrier.
|
||||||
|
"""
|
||||||
|
return self.descent(arrival), self.land(arrival)
|
||||||
|
|
||||||
def escort(self, ingress: Point, target: MissionTarget, egress: Point) -> \
|
def escort(self, ingress: Point, target: MissionTarget, egress: Point) -> \
|
||||||
Tuple[FlightWaypoint, FlightWaypoint, FlightWaypoint]:
|
Tuple[FlightWaypoint, FlightWaypoint, FlightWaypoint]:
|
||||||
"""Creates the waypoints needed to escort the package.
|
"""Creates the waypoints needed to escort the package.
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ RADIOS: List[Radio] = [
|
|||||||
Radio("RSIU-4V", MHz(100), MHz(150), step=MHz(1)),
|
Radio("RSIU-4V", MHz(100), MHz(150), step=MHz(1)),
|
||||||
|
|
||||||
# MiG-21bis
|
# MiG-21bis
|
||||||
Radio("RSIU-5V", MHz(118), MHz(140), step=MHz(1)),
|
Radio("RSIU-5V", MHz(100), MHz(150), step=MHz(1)),
|
||||||
|
|
||||||
# Ka-50
|
# Ka-50
|
||||||
# Note: Also capable of 100MHz-150MHz, but we can't model gaps.
|
# Note: Also capable of 100MHz-150MHz, but we can't model gaps.
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from dcs.action import MarkToAll
|
from dcs.action import MarkToAll
|
||||||
from dcs.condition import TimeAfter
|
from dcs.condition import TimeAfter
|
||||||
from dcs.mission import Mission
|
from dcs.mission import Mission
|
||||||
@@ -7,7 +5,7 @@ from dcs.task import Option
|
|||||||
from dcs.translation import String
|
from dcs.translation import String
|
||||||
from dcs.triggers import Event, TriggerOnce
|
from dcs.triggers import Event, TriggerOnce
|
||||||
from dcs.unit import Skill
|
from dcs.unit import Skill
|
||||||
from dcs.unitgroup import FlyingGroup
|
|
||||||
from .conflictgen import Conflict
|
from .conflictgen import Conflict
|
||||||
|
|
||||||
PUSH_TRIGGER_SIZE = 3000
|
PUSH_TRIGGER_SIZE = 3000
|
||||||
@@ -75,9 +73,8 @@ class TriggersGenerator:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
for country in coalition.countries.values():
|
for country in coalition.countries.values():
|
||||||
flying_groups = country.plane_group + country.helicopter_group # type: FlyingGroup
|
for plane_group in country.plane_group:
|
||||||
for flying_group in flying_groups:
|
for plane_unit in plane_group.units:
|
||||||
for plane_unit in flying_group.units:
|
|
||||||
if plane_unit.skill != Skill.Client and plane_unit.skill != Skill.Player:
|
if plane_unit.skill != Skill.Client and plane_unit.skill != Skill.Player:
|
||||||
plane_unit.skill = Skill(skill_level[0])
|
plane_unit.skill = Skill(skill_level[0])
|
||||||
|
|
||||||
|
|||||||
2
pydcs
2
pydcs
Submodule pydcs updated: 2883be31c2...fa9195fbcc
@@ -48,14 +48,12 @@ class QTopPanel(QFrame):
|
|||||||
self.passTurnButton.setIcon(CONST.ICONS["PassTurn"])
|
self.passTurnButton.setIcon(CONST.ICONS["PassTurn"])
|
||||||
self.passTurnButton.setProperty("style", "btn-primary")
|
self.passTurnButton.setProperty("style", "btn-primary")
|
||||||
self.passTurnButton.clicked.connect(self.passTurn)
|
self.passTurnButton.clicked.connect(self.passTurn)
|
||||||
if not self.game:
|
|
||||||
self.passTurnButton.setEnabled(False)
|
|
||||||
|
|
||||||
self.proceedButton = QPushButton("Take off")
|
self.proceedButton = QPushButton("Take off")
|
||||||
self.proceedButton.setIcon(CONST.ICONS["Proceed"])
|
self.proceedButton.setIcon(CONST.ICONS["Proceed"])
|
||||||
self.proceedButton.setProperty("style", "start-button")
|
self.proceedButton.setProperty("style", "start-button")
|
||||||
self.proceedButton.clicked.connect(self.launch_mission)
|
self.proceedButton.clicked.connect(self.launch_mission)
|
||||||
if not self.game or self.game.turn == 0:
|
if self.game and self.game.turn == 0:
|
||||||
self.proceedButton.setEnabled(False)
|
self.proceedButton.setEnabled(False)
|
||||||
|
|
||||||
self.factionsInfos = QFactionsInfos(self.game)
|
self.factionsInfos = QFactionsInfos(self.game)
|
||||||
@@ -103,8 +101,6 @@ class QTopPanel(QFrame):
|
|||||||
self.budgetBox.setGame(game)
|
self.budgetBox.setGame(game)
|
||||||
self.factionsInfos.setGame(game)
|
self.factionsInfos.setGame(game)
|
||||||
|
|
||||||
self.passTurnButton.setEnabled(True)
|
|
||||||
|
|
||||||
if game and game.turn == 0:
|
if game and game.turn == 0:
|
||||||
self.proceedButton.setEnabled(False)
|
self.proceedButton.setEnabled(False)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
"""Combo box for selecting a departure airfield."""
|
"""Combo box for selecting a departure airfield."""
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
|
|
||||||
from PySide2.QtCore import Signal
|
|
||||||
from PySide2.QtWidgets import QComboBox
|
from PySide2.QtWidgets import QComboBox
|
||||||
from dcs.planes import PlaneType
|
|
||||||
|
|
||||||
|
from dcs.planes import PlaneType
|
||||||
from game.inventory import GlobalAircraftInventory
|
from game.inventory import GlobalAircraftInventory
|
||||||
from theater.controlpoint import ControlPoint
|
from theater.controlpoint import ControlPoint
|
||||||
|
|
||||||
@@ -16,8 +15,6 @@ class QOriginAirfieldSelector(QComboBox):
|
|||||||
that have unassigned inventory of the given aircraft type.
|
that have unassigned inventory of the given aircraft type.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
availability_changed = Signal(int)
|
|
||||||
|
|
||||||
def __init__(self, global_inventory: GlobalAircraftInventory,
|
def __init__(self, global_inventory: GlobalAircraftInventory,
|
||||||
origins: Iterable[ControlPoint],
|
origins: Iterable[ControlPoint],
|
||||||
aircraft: PlaneType) -> None:
|
aircraft: PlaneType) -> None:
|
||||||
@@ -26,7 +23,6 @@ class QOriginAirfieldSelector(QComboBox):
|
|||||||
self.origins = list(origins)
|
self.origins = list(origins)
|
||||||
self.aircraft = aircraft
|
self.aircraft = aircraft
|
||||||
self.rebuild_selector()
|
self.rebuild_selector()
|
||||||
self.currentIndexChanged.connect(self.index_changed)
|
|
||||||
|
|
||||||
def change_aircraft(self, aircraft: PlaneType) -> None:
|
def change_aircraft(self, aircraft: PlaneType) -> None:
|
||||||
if self.aircraft == aircraft:
|
if self.aircraft == aircraft:
|
||||||
@@ -51,10 +47,3 @@ class QOriginAirfieldSelector(QComboBox):
|
|||||||
return 0
|
return 0
|
||||||
inventory = self.global_inventory.for_control_point(origin)
|
inventory = self.global_inventory.for_control_point(origin)
|
||||||
return inventory.available(self.aircraft)
|
return inventory.available(self.aircraft)
|
||||||
|
|
||||||
def index_changed(self, index: int) -> None:
|
|
||||||
origin = self.itemData(index)
|
|
||||||
if origin is None:
|
|
||||||
return
|
|
||||||
inventory = self.global_inventory.for_control_point(origin)
|
|
||||||
self.availability_changed.emit(inventory.available(self.aircraft))
|
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ class QPredefinedWaypointSelectionComboBox(QFilteredComboBox):
|
|||||||
i = 0
|
i = 0
|
||||||
|
|
||||||
def add_model_item(i, model, name, wpt):
|
def add_model_item(i, model, name, wpt):
|
||||||
|
print(name)
|
||||||
item = QStandardItem(name)
|
item = QStandardItem(name)
|
||||||
model.setItem(i, 0, item)
|
model.setItem(i, 0, item)
|
||||||
self.wpts.append(wpt)
|
self.wpts.append(wpt)
|
||||||
@@ -78,7 +79,7 @@ class QPredefinedWaypointSelectionComboBox(QFilteredComboBox):
|
|||||||
0
|
0
|
||||||
)
|
)
|
||||||
wpt.alt_type = "RADIO"
|
wpt.alt_type = "RADIO"
|
||||||
wpt.name = ground_object.waypoint_name
|
wpt.name = wpt.name = "[" + str(ground_object.obj_name) + "] : " + ground_object.category + " #" + str(ground_object.object_id)
|
||||||
wpt.pretty_name = wpt.name
|
wpt.pretty_name = wpt.name
|
||||||
wpt.obj_name = ground_object.obj_name
|
wpt.obj_name = ground_object.obj_name
|
||||||
wpt.targets.append(ground_object)
|
wpt.targets.append(ground_object)
|
||||||
|
|||||||
@@ -241,12 +241,11 @@ class QLiberationWindow(QMainWindow):
|
|||||||
"<h4>Authors</h4>" + \
|
"<h4>Authors</h4>" + \
|
||||||
"<p>DCS Liberation was originally developed by <b>shdwp</b>, DCS Liberation 2.0 is a partial rewrite based on this work by <b>Khopa</b>." \
|
"<p>DCS Liberation was originally developed by <b>shdwp</b>, DCS Liberation 2.0 is a partial rewrite based on this work by <b>Khopa</b>." \
|
||||||
"<h4>Contributors</h4>" + \
|
"<h4>Contributors</h4>" + \
|
||||||
"shdwp, Khopa, ColonelPanic, Roach, Wrycu, calvinmorrow, JohanAberg, Deus, root0fall, Captain Cody, steveveepee, pedromagueija, parithon, bwRavencl, davidp57" + \
|
"shdwp, Khopa, ColonelPanic, Wrycu, calvinmorrow, JohanAberg, Deus, root0fall, Captain Cody, steveveepee, pedromagueija, parithon, bwRavencl, davidp57" + \
|
||||||
"<h4>Special Thanks :</h4>" \
|
"<h4>Special Thanks :</h4>" \
|
||||||
"<b>rp-</b> <i>for the pydcs framework</i><br/>"\
|
"<b>rp-</b> <i>for the pydcs framework</i><br/>"\
|
||||||
"<b>Grimes (mrSkortch)</b> & <b>Speed</b> <i>for the MIST framework</i><br/>"\
|
"<b>Grimes (mrSkortch)</b> & <b>Speed</b> <i>for the MIST framework</i><br/>"\
|
||||||
"<b>Ciribob </b> <i>for the JTACAutoLase.lua script</i><br/>"\
|
"<b>Ciribob </b> <i>for the JTACAutoLase.lua script</i><br/>"
|
||||||
"<b>Walder </b> <i>for the Skynet-IADS script</i><br/>"
|
|
||||||
about = QMessageBox()
|
about = QMessageBox()
|
||||||
about.setWindowTitle("About DCS Liberation")
|
about.setWindowTitle("About DCS Liberation")
|
||||||
about.setIcon(QMessageBox.Icon.Information)
|
about.setIcon(QMessageBox.Icon.Information)
|
||||||
|
|||||||
@@ -13,9 +13,8 @@ from PySide2.QtWidgets import (
|
|||||||
QLabel,
|
QLabel,
|
||||||
QMessageBox,
|
QMessageBox,
|
||||||
QPushButton,
|
QPushButton,
|
||||||
QTextBrowser,
|
QTextEdit,
|
||||||
)
|
)
|
||||||
from jinja2 import Environment, FileSystemLoader, select_autoescape
|
|
||||||
|
|
||||||
from game.debriefing import Debriefing, wait_for_debriefing
|
from game.debriefing import Debriefing, wait_for_debriefing
|
||||||
from game.game import Event, Game, logging
|
from game.game import Event, Game, logging
|
||||||
@@ -66,21 +65,27 @@ class QWaitingForMissionResultWindow(QDialog):
|
|||||||
self.layout.addWidget(header, 0, 0)
|
self.layout.addWidget(header, 0, 0)
|
||||||
|
|
||||||
self.gridLayout = QGridLayout()
|
self.gridLayout = QGridLayout()
|
||||||
|
TEXT = "" + \
|
||||||
|
"<b>You are clear for takeoff</b>" + \
|
||||||
|
"" + \
|
||||||
|
"<h2>For Singleplayer :</h2>\n" + \
|
||||||
|
"In DCS, open the Mission Editor, and load the file : \n" + \
|
||||||
|
"<i>liberation_nextturn</i>\n" + \
|
||||||
|
"<p>Then once the mission is loaded in ME, in menu \"Flight\",\n" + \
|
||||||
|
"click on FLY Mission to launch.</p>\n" + \
|
||||||
|
"" + \
|
||||||
|
"<h2>For Multiplayer :</h2>" + \
|
||||||
|
"In DCS, open the Mission Editor, and load the file : " + \
|
||||||
|
"<i>liberation_nextturn</i>" + \
|
||||||
|
"<p>Click on File/Save. Then exit the mission editor, and go to Multiplayer.</p>" + \
|
||||||
|
"<p>Then host a server with the mission, and tell your friends to join !</p>" + \
|
||||||
|
"<i>(The step in the mission editor is important, and fix a game breaking bug.)</i>" + \
|
||||||
|
"<h2>Finishing</h2>" + \
|
||||||
|
"<p>Once you have played the mission, click on the \"Accept Results\" button.</p>" + \
|
||||||
|
"<p>If DCS Liberation does not detect mission end, use the manually submit button, and choose the state.json file.</p>"
|
||||||
|
|
||||||
jinja = Environment(
|
self.instructions_text = QTextEdit(TEXT)
|
||||||
loader=FileSystemLoader("resources/ui/templates"),
|
self.instructions_text.setReadOnly(True)
|
||||||
autoescape=select_autoescape(
|
|
||||||
disabled_extensions=("",),
|
|
||||||
default_for_string=True,
|
|
||||||
default=True,
|
|
||||||
),
|
|
||||||
trim_blocks=True,
|
|
||||||
lstrip_blocks=True,
|
|
||||||
)
|
|
||||||
self.instructions_text = QTextBrowser()
|
|
||||||
self.instructions_text.setHtml(
|
|
||||||
jinja.get_template("mission_start_EN.j2").render())
|
|
||||||
self.instructions_text.setOpenExternalLinks(True)
|
|
||||||
self.gridLayout.addWidget(self.instructions_text, 1, 0)
|
self.gridLayout.addWidget(self.instructions_text, 1, 0)
|
||||||
|
|
||||||
progress = QLabel("")
|
progress = QLabel("")
|
||||||
|
|||||||
@@ -54,11 +54,11 @@ class QFlightCreator(QDialog):
|
|||||||
[cp for cp in game.theater.controlpoints if cp.captured],
|
[cp for cp in game.theater.controlpoints if cp.captured],
|
||||||
self.aircraft_selector.currentData()
|
self.aircraft_selector.currentData()
|
||||||
)
|
)
|
||||||
self.airfield_selector.availability_changed.connect(self.update_max_size)
|
self.airfield_selector.currentIndexChanged.connect(self.update_max_size)
|
||||||
layout.addLayout(QLabeledWidget("Airfield:", self.airfield_selector))
|
layout.addLayout(QLabeledWidget("Airfield:", self.airfield_selector))
|
||||||
|
|
||||||
self.flight_size_spinner = QFlightSizeSpinner()
|
self.flight_size_spinner = QFlightSizeSpinner()
|
||||||
self.update_max_size(self.airfield_selector.available)
|
self.update_max_size()
|
||||||
layout.addLayout(QLabeledWidget("Size:", self.flight_size_spinner))
|
layout.addLayout(QLabeledWidget("Size:", self.flight_size_spinner))
|
||||||
|
|
||||||
self.client_slots_spinner = QFlightSizeSpinner(
|
self.client_slots_spinner = QFlightSizeSpinner(
|
||||||
@@ -91,8 +91,6 @@ class QFlightCreator(QDialog):
|
|||||||
return f"{origin.name} has no {aircraft.id} available."
|
return f"{origin.name} has no {aircraft.id} available."
|
||||||
if size > available:
|
if size > available:
|
||||||
return f"{origin.name} has only {available} {aircraft.id} available."
|
return f"{origin.name} has only {available} {aircraft.id} available."
|
||||||
if size <= 0:
|
|
||||||
return f"Flight must have at least one aircraft."
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def create_flight(self) -> None:
|
def create_flight(self) -> None:
|
||||||
@@ -122,8 +120,7 @@ class QFlightCreator(QDialog):
|
|||||||
new_aircraft = self.aircraft_selector.itemData(index)
|
new_aircraft = self.aircraft_selector.itemData(index)
|
||||||
self.airfield_selector.change_aircraft(new_aircraft)
|
self.airfield_selector.change_aircraft(new_aircraft)
|
||||||
|
|
||||||
def update_max_size(self, available: int) -> None:
|
def update_max_size(self) -> None:
|
||||||
self.flight_size_spinner.setMaximum(min(available, 4))
|
self.flight_size_spinner.setMaximum(
|
||||||
if self.flight_size_spinner.maximum() >= 2:
|
min(self.airfield_selector.available, 4)
|
||||||
if self.flight_size_spinner.value() < 2:
|
)
|
||||||
self.flight_size_spinner.setValue(2)
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from typing import Iterable, List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from PySide2.QtCore import Signal
|
from PySide2.QtCore import Signal
|
||||||
from PySide2.QtWidgets import (
|
from PySide2.QtWidgets import (
|
||||||
@@ -12,15 +12,11 @@ from PySide2.QtWidgets import (
|
|||||||
|
|
||||||
from game import Game
|
from game import Game
|
||||||
from gen.ato import Package
|
from gen.ato import Package
|
||||||
from gen.flights.flight import Flight, FlightType, FlightWaypoint
|
from gen.flights.flight import Flight, FlightType
|
||||||
from gen.flights.flightplan import (
|
from gen.flights.flightplan import FlightPlanBuilder
|
||||||
CustomFlightPlan,
|
|
||||||
FlightPlanBuilder,
|
|
||||||
StrikeFlightPlan,
|
|
||||||
)
|
|
||||||
from qt_ui.windows.mission.flight.waypoints.QFlightWaypointList import \
|
from qt_ui.windows.mission.flight.waypoints.QFlightWaypointList import \
|
||||||
QFlightWaypointList
|
QFlightWaypointList
|
||||||
from qt_ui.windows.mission.flight.waypoints \
|
from qt_ui.windows.mission.flight.waypoints\
|
||||||
.QPredefinedWaypointSelectionWindow import \
|
.QPredefinedWaypointSelectionWindow import \
|
||||||
QPredefinedWaypointSelectionWindow
|
QPredefinedWaypointSelectionWindow
|
||||||
from theater import FrontLine
|
from theater import FrontLine
|
||||||
@@ -38,6 +34,8 @@ class QFlightWaypointTab(QFrame):
|
|||||||
self.planner = FlightPlanBuilder(self.game, package, is_player=True)
|
self.planner = FlightPlanBuilder(self.game, package, is_player=True)
|
||||||
|
|
||||||
self.flight_waypoint_list: Optional[QFlightWaypointList] = None
|
self.flight_waypoint_list: Optional[QFlightWaypointList] = None
|
||||||
|
self.ascend_waypoint: Optional[QPushButton] = None
|
||||||
|
self.descend_waypoint: Optional[QPushButton] = None
|
||||||
self.rtb_waypoint: Optional[QPushButton] = None
|
self.rtb_waypoint: Optional[QPushButton] = None
|
||||||
self.delete_selected: Optional[QPushButton] = None
|
self.delete_selected: Optional[QPushButton] = None
|
||||||
self.open_fast_waypoint_button: Optional[QPushButton] = None
|
self.open_fast_waypoint_button: Optional[QPushButton] = None
|
||||||
@@ -80,6 +78,14 @@ class QFlightWaypointTab(QFrame):
|
|||||||
rlayout.addWidget(QLabel("<strong>Advanced : </strong>"))
|
rlayout.addWidget(QLabel("<strong>Advanced : </strong>"))
|
||||||
rlayout.addWidget(QLabel("<small>Do not use for AI flights</small>"))
|
rlayout.addWidget(QLabel("<small>Do not use for AI flights</small>"))
|
||||||
|
|
||||||
|
self.ascend_waypoint = QPushButton("Add Ascend Waypoint")
|
||||||
|
self.ascend_waypoint.clicked.connect(self.on_ascend_waypoint)
|
||||||
|
rlayout.addWidget(self.ascend_waypoint)
|
||||||
|
|
||||||
|
self.descend_waypoint = QPushButton("Add Descend Waypoint")
|
||||||
|
self.descend_waypoint.clicked.connect(self.on_descend_waypoint)
|
||||||
|
rlayout.addWidget(self.descend_waypoint)
|
||||||
|
|
||||||
self.rtb_waypoint = QPushButton("Add RTB Waypoint")
|
self.rtb_waypoint = QPushButton("Add RTB Waypoint")
|
||||||
self.rtb_waypoint.clicked.connect(self.on_rtb_waypoint)
|
self.rtb_waypoint.clicked.connect(self.on_rtb_waypoint)
|
||||||
rlayout.addWidget(self.rtb_waypoint)
|
rlayout.addWidget(self.rtb_waypoint)
|
||||||
@@ -97,51 +103,35 @@ class QFlightWaypointTab(QFrame):
|
|||||||
def on_delete_waypoint(self):
|
def on_delete_waypoint(self):
|
||||||
wpt = self.flight_waypoint_list.selectionModel().currentIndex().row()
|
wpt = self.flight_waypoint_list.selectionModel().currentIndex().row()
|
||||||
if wpt > 0:
|
if wpt > 0:
|
||||||
self.delete_waypoint(self.flight.flight_plan.waypoints[wpt])
|
del self.flight.points[wpt-1]
|
||||||
self.flight_waypoint_list.update_list()
|
self.flight_waypoint_list.update_list()
|
||||||
self.on_change()
|
self.on_change()
|
||||||
|
|
||||||
def delete_waypoint(self, waypoint: FlightWaypoint) -> None:
|
|
||||||
# Need to degrade to a custom flight plan and remove the waypoint.
|
|
||||||
# If the waypoint is a target waypoint and is not the last target
|
|
||||||
# waypoint, we don't need to degrade.
|
|
||||||
if isinstance(self.flight.flight_plan, StrikeFlightPlan):
|
|
||||||
is_target = waypoint in self.flight.flight_plan.targets
|
|
||||||
if is_target and len(self.flight.flight_plan.targets) > 1:
|
|
||||||
self.flight.flight_plan.targets.remove(waypoint)
|
|
||||||
return
|
|
||||||
|
|
||||||
self.degrade_to_custom_flight_plan()
|
|
||||||
self.flight.flight_plan.waypoints.remove(waypoint)
|
|
||||||
|
|
||||||
def on_fast_waypoint(self):
|
def on_fast_waypoint(self):
|
||||||
self.subwindow = QPredefinedWaypointSelectionWindow(self.game, self.flight, self.flight_waypoint_list)
|
self.subwindow = QPredefinedWaypointSelectionWindow(self.game, self.flight, self.flight_waypoint_list)
|
||||||
self.subwindow.waypoints_added.connect(self.on_waypoints_added)
|
self.subwindow.finished.connect(self.on_change)
|
||||||
self.subwindow.show()
|
self.subwindow.show()
|
||||||
|
|
||||||
def on_waypoints_added(self, waypoints: Iterable[FlightWaypoint]) -> None:
|
def on_ascend_waypoint(self):
|
||||||
if not waypoints:
|
ascend = self.planner.generate_ascend_point(self.flight,
|
||||||
return
|
self.flight.from_cp)
|
||||||
self.degrade_to_custom_flight_plan()
|
self.flight.points.append(ascend)
|
||||||
self.flight.flight_plan.waypoints.extend(waypoints)
|
|
||||||
self.flight_waypoint_list.update_list()
|
self.flight_waypoint_list.update_list()
|
||||||
self.on_change()
|
self.on_change()
|
||||||
|
|
||||||
def on_rtb_waypoint(self):
|
def on_rtb_waypoint(self):
|
||||||
rtb = self.planner.generate_rtb_waypoint(self.flight,
|
rtb = self.planner.generate_rtb_waypoint(self.flight,
|
||||||
self.flight.from_cp)
|
self.flight.from_cp)
|
||||||
self.degrade_to_custom_flight_plan()
|
self.flight.points.append(rtb)
|
||||||
self.flight.flight_plan.waypoints.append(rtb)
|
|
||||||
self.flight_waypoint_list.update_list()
|
self.flight_waypoint_list.update_list()
|
||||||
self.on_change()
|
self.on_change()
|
||||||
|
|
||||||
def degrade_to_custom_flight_plan(self) -> None:
|
def on_descend_waypoint(self):
|
||||||
if not isinstance(self.flight.flight_plan, CustomFlightPlan):
|
descend = self.planner.generate_descend_point(self.flight,
|
||||||
self.flight.flight_plan = CustomFlightPlan(
|
self.flight.from_cp)
|
||||||
package=self.flight.package,
|
self.flight.points.append(descend)
|
||||||
flight=self.flight,
|
self.flight_waypoint_list.update_list()
|
||||||
custom_waypoints=self.flight.flight_plan.waypoints
|
self.on_change()
|
||||||
)
|
|
||||||
|
|
||||||
def confirm_recreate(self, task: FlightType) -> None:
|
def confirm_recreate(self, task: FlightType) -> None:
|
||||||
result = QMessageBox.question(
|
result = QMessageBox.question(
|
||||||
|
|||||||
@@ -1,20 +1,11 @@
|
|||||||
from PySide2.QtCore import Qt, Signal
|
from PySide2.QtCore import Qt
|
||||||
from PySide2.QtWidgets import (
|
from PySide2.QtWidgets import QDialog, QLabel, QHBoxLayout, QVBoxLayout, QPushButton, QCheckBox
|
||||||
QCheckBox,
|
|
||||||
QDialog,
|
|
||||||
QHBoxLayout,
|
|
||||||
QLabel,
|
|
||||||
QPushButton,
|
|
||||||
QVBoxLayout,
|
|
||||||
)
|
|
||||||
|
|
||||||
from game import Game
|
from game import Game
|
||||||
from gen.flights.flight import Flight
|
from gen.flights.flight import Flight
|
||||||
from qt_ui.uiconstants import EVENT_ICONS
|
from qt_ui.uiconstants import EVENT_ICONS
|
||||||
from qt_ui.widgets.combos.QPredefinedWaypointSelectionComboBox import \
|
from qt_ui.widgets.combos.QPredefinedWaypointSelectionComboBox import QPredefinedWaypointSelectionComboBox
|
||||||
QPredefinedWaypointSelectionComboBox
|
from qt_ui.windows.mission.flight.waypoints.QFlightWaypointInfoBox import QFlightWaypointInfoBox
|
||||||
from qt_ui.windows.mission.flight.waypoints.QFlightWaypointInfoBox import \
|
|
||||||
QFlightWaypointInfoBox
|
|
||||||
|
|
||||||
PREDEFINED_WAYPOINT_CATEGORIES = [
|
PREDEFINED_WAYPOINT_CATEGORIES = [
|
||||||
"Frontline (CAS AREA)",
|
"Frontline (CAS AREA)",
|
||||||
@@ -26,8 +17,6 @@ PREDEFINED_WAYPOINT_CATEGORIES = [
|
|||||||
|
|
||||||
class QPredefinedWaypointSelectionWindow(QDialog):
|
class QPredefinedWaypointSelectionWindow(QDialog):
|
||||||
|
|
||||||
# List of FlightWaypoint
|
|
||||||
waypoints_added = Signal(list)
|
|
||||||
|
|
||||||
def __init__(self, game: Game, flight: Flight, flight_waypoint_list):
|
def __init__(self, game: Game, flight: Flight, flight_waypoint_list):
|
||||||
super(QPredefinedWaypointSelectionWindow, self).__init__()
|
super(QPredefinedWaypointSelectionWindow, self).__init__()
|
||||||
@@ -55,6 +44,7 @@ class QPredefinedWaypointSelectionWindow(QDialog):
|
|||||||
|
|
||||||
self.init_ui()
|
self.init_ui()
|
||||||
self.on_select_wpt_changed()
|
self.on_select_wpt_changed()
|
||||||
|
print("DONE")
|
||||||
|
|
||||||
|
|
||||||
def init_ui(self):
|
def init_ui(self):
|
||||||
@@ -87,5 +77,12 @@ class QPredefinedWaypointSelectionWindow(QDialog):
|
|||||||
self.add_button.setDisabled(False)
|
self.add_button.setDisabled(False)
|
||||||
|
|
||||||
def add_waypoint(self):
|
def add_waypoint(self):
|
||||||
self.waypoints_added.emit(self.selected_waypoints)
|
|
||||||
|
for wpt in self.selected_waypoints:
|
||||||
|
self.flight.points.append(wpt)
|
||||||
|
|
||||||
|
self.flight_waypoint_list.update_list()
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -62,9 +62,7 @@ class NewGameWizard(QtWidgets.QWizard):
|
|||||||
|
|
||||||
timePeriod = db.TIME_PERIODS[list(db.TIME_PERIODS.keys())[self.field("timePeriod")]]
|
timePeriod = db.TIME_PERIODS[list(db.TIME_PERIODS.keys())[self.field("timePeriod")]]
|
||||||
midGame = self.field("midGame")
|
midGame = self.field("midGame")
|
||||||
# QSlider forces integers, so we use 1 to 50 and divide by 10 to give
|
multiplier = self.field("multiplier")
|
||||||
# 0.1 to 5.0.
|
|
||||||
multiplier = self.field("multiplier") / 10
|
|
||||||
no_carrier = self.field("no_carrier")
|
no_carrier = self.field("no_carrier")
|
||||||
no_lha = self.field("no_lha")
|
no_lha = self.field("no_lha")
|
||||||
supercarrier = self.field("supercarrier")
|
supercarrier = self.field("supercarrier")
|
||||||
@@ -326,44 +324,6 @@ class BudgetInputs(QtWidgets.QGridLayout):
|
|||||||
self.addWidget(self.starting_money, 1, 1)
|
self.addWidget(self.starting_money, 1, 1)
|
||||||
|
|
||||||
|
|
||||||
class ForceMultiplierSpinner(QtWidgets.QSpinBox):
|
|
||||||
def __init__(self, minimum: Optional[int] = None,
|
|
||||||
maximum: Optional[int] = None,
|
|
||||||
initial: Optional[int] = None) -> None:
|
|
||||||
super().__init__()
|
|
||||||
|
|
||||||
if minimum is not None:
|
|
||||||
self.setMinimum(minimum)
|
|
||||||
if maximum is not None:
|
|
||||||
self.setMaximum(maximum)
|
|
||||||
if initial is not None:
|
|
||||||
self.setValue(initial)
|
|
||||||
|
|
||||||
def textFromValue(self, val: int) -> str:
|
|
||||||
return f"X {val / 10:.1f}"
|
|
||||||
|
|
||||||
|
|
||||||
class ForceMultiplierInputs(QtWidgets.QGridLayout):
|
|
||||||
def __init__(self) -> None:
|
|
||||||
super().__init__()
|
|
||||||
self.addWidget(QtWidgets.QLabel("Enemy forces multiplier"), 0, 0)
|
|
||||||
|
|
||||||
minimum = 1
|
|
||||||
maximum = 50
|
|
||||||
initial = 10
|
|
||||||
|
|
||||||
slider = QtWidgets.QSlider(Qt.Horizontal)
|
|
||||||
slider.setMinimum(minimum)
|
|
||||||
slider.setMaximum(maximum)
|
|
||||||
slider.setValue(initial)
|
|
||||||
self.multiplier = ForceMultiplierSpinner(minimum, maximum, initial)
|
|
||||||
slider.valueChanged.connect(lambda x: self.multiplier.setValue(x))
|
|
||||||
self.multiplier.valueChanged.connect(lambda x: slider.setValue(x))
|
|
||||||
|
|
||||||
self.addWidget(slider, 1, 0)
|
|
||||||
self.addWidget(self.multiplier, 1, 1)
|
|
||||||
|
|
||||||
|
|
||||||
class MiscOptions(QtWidgets.QWizardPage):
|
class MiscOptions(QtWidgets.QWizardPage):
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super(MiscOptions, self).__init__(parent)
|
super(MiscOptions, self).__init__(parent)
|
||||||
@@ -374,12 +334,14 @@ class MiscOptions(QtWidgets.QWizardPage):
|
|||||||
QtGui.QPixmap('./resources/ui/wizard/logo1.png'))
|
QtGui.QPixmap('./resources/ui/wizard/logo1.png'))
|
||||||
|
|
||||||
midGame = QtWidgets.QCheckBox()
|
midGame = QtWidgets.QCheckBox()
|
||||||
multiplier_inputs = ForceMultiplierInputs()
|
multiplier = QtWidgets.QSpinBox()
|
||||||
self.registerField('multiplier', multiplier_inputs.multiplier)
|
multiplier.setEnabled(False)
|
||||||
|
multiplier.setMinimum(1)
|
||||||
|
multiplier.setMaximum(5)
|
||||||
|
|
||||||
miscSettingsGroup = QtWidgets.QGroupBox("Misc Settings")
|
miscSettingsGroup = QtWidgets.QGroupBox("Misc Settings")
|
||||||
self.registerField('midGame', midGame)
|
self.registerField('midGame', midGame)
|
||||||
|
self.registerField('multiplier', multiplier)
|
||||||
|
|
||||||
# Campaign settings
|
# Campaign settings
|
||||||
generatorSettingsGroup = QtWidgets.QGroupBox("Generator Settings")
|
generatorSettingsGroup = QtWidgets.QGroupBox("Generator Settings")
|
||||||
@@ -397,7 +359,8 @@ class MiscOptions(QtWidgets.QWizardPage):
|
|||||||
layout = QtWidgets.QGridLayout()
|
layout = QtWidgets.QGridLayout()
|
||||||
layout.addWidget(QtWidgets.QLabel("Start at mid game"), 1, 0)
|
layout.addWidget(QtWidgets.QLabel("Start at mid game"), 1, 0)
|
||||||
layout.addWidget(midGame, 1, 1)
|
layout.addWidget(midGame, 1, 1)
|
||||||
layout.addLayout(multiplier_inputs, 2, 0)
|
layout.addWidget(QtWidgets.QLabel("Ennemy forces multiplier [Disabled for Now]"), 2, 0)
|
||||||
|
layout.addWidget(multiplier, 2, 1)
|
||||||
miscSettingsGroup.setLayout(layout)
|
miscSettingsGroup.setLayout(layout)
|
||||||
|
|
||||||
generatorLayout = QtWidgets.QGridLayout()
|
generatorLayout = QtWidgets.QGridLayout()
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ We do not have a single vehicle available to hold our position. The situation i
|
|||||||
{% if frontline.enemy_zero %}
|
{% if frontline.enemy_zero %}
|
||||||
The enemy forces have been crushed, we will be able to make significant progress toward {{ frontline.enemy_base.name }}
|
The enemy forces have been crushed, we will be able to make significant progress toward {{ frontline.enemy_base.name }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if not frontline.player_zero %}
|
|
||||||
{# Pick a random sentence to describe each frontline #}
|
{# Pick a random sentence to describe each frontline #}
|
||||||
{% set fl_sent1 %}There are combats between {{ frontline.player_base.name }} and {{frontline.enemy_base.name}}. {%+ endset %}
|
{% set fl_sent1 %}There are combats between {{ frontline.player_base.name }} and {{frontline.enemy_base.name}}. {%+ endset %}
|
||||||
{% set fl_sent2 %}The war on the ground is still going on between {{frontline.player_base.name}} and {{frontline.enemy_base.name}}. {%+ endset %}
|
{% set fl_sent2 %}The war on the ground is still going on between {{frontline.player_base.name}} and {{frontline.enemy_base.name}}. {%+ endset %}
|
||||||
@@ -58,9 +57,8 @@ On this location, our ground forces have been ordered to hold still, and defend
|
|||||||
{# TODO: Write a retreat sentence #}
|
{# TODO: Write a retreat sentence #}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{%+ endfor %}{% endif %}
|
{% endfor %}{% endif %}
|
||||||
|
|
||||||
Your flights:
|
Your flights:
|
||||||
====================
|
====================
|
||||||
|
|||||||
@@ -1,137 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Persian Gulf - Full Map",
|
|
||||||
"theater": "Persian Gulf",
|
|
||||||
"authors": "Plob",
|
|
||||||
"description": "<p>In this scenario, you start at Liwa Airfield, and must work your way north through the whole map.</p>",
|
|
||||||
"player_points": [
|
|
||||||
{
|
|
||||||
"type": "airbase",
|
|
||||||
"id": "Liwa Airbase",
|
|
||||||
"size": 1000,
|
|
||||||
"importance": 0.2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "lha",
|
|
||||||
"id": 1002,
|
|
||||||
"x": -164000,
|
|
||||||
"y": -257000,
|
|
||||||
"captured_invert": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "carrier",
|
|
||||||
"id": 1001,
|
|
||||||
"x": -124000,
|
|
||||||
"y": -303000,
|
|
||||||
"captured_invert": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"enemy_points": [
|
|
||||||
{
|
|
||||||
"type": "airbase",
|
|
||||||
"id": "Al Ain International Airport",
|
|
||||||
"size": 1000,
|
|
||||||
"importance": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "airbase",
|
|
||||||
"id": "Al Dhafra AB",
|
|
||||||
"size": 2000,
|
|
||||||
"importance": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "airbase",
|
|
||||||
"id": "Al Minhad AB",
|
|
||||||
"size": 1000,
|
|
||||||
"importance": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "airbase",
|
|
||||||
"id": "Ras Al Khaimah",
|
|
||||||
"size": 1000,
|
|
||||||
"importance": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "airbase",
|
|
||||||
"id": "Khasab",
|
|
||||||
"size": 1000,
|
|
||||||
"importance": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "airbase",
|
|
||||||
"id": "Bandar Abbas Intl",
|
|
||||||
"size": 2000,
|
|
||||||
"importance": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "airbase",
|
|
||||||
"id": "Jiroft Airport",
|
|
||||||
"size": 2000,
|
|
||||||
"importance": 1.4
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "airbase",
|
|
||||||
"id": "Kerman Airport",
|
|
||||||
"size": 2000,
|
|
||||||
"importance": 1.7,
|
|
||||||
"captured_invert": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "airbase",
|
|
||||||
"id": "Lar Airbase",
|
|
||||||
"size": 1000,
|
|
||||||
"importance": 1.4
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "airbase",
|
|
||||||
"id": "Shiraz International Airport",
|
|
||||||
"size": 2000,
|
|
||||||
"importance": 1
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"links": [
|
|
||||||
[
|
|
||||||
"Al Dhafra AB",
|
|
||||||
"Liwa Airbase"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Al Dhafra AB",
|
|
||||||
"Al Ain International Airport"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Al Ain International Airport",
|
|
||||||
"Al Minhad AB"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Al Dhafra AB",
|
|
||||||
"Al Minhad AB"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Al Minhad AB",
|
|
||||||
"Ras Al Khaimah"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Khasab",
|
|
||||||
"Ras Al Khaimah"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Bandar Abbas Intl",
|
|
||||||
"Lar Airbase"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Shiraz International Airport",
|
|
||||||
"Lar Airbase"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Shiraz International Airport",
|
|
||||||
"Kerman Airport"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Jiroft Airport",
|
|
||||||
"Lar Airbase"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Jiroft Airport",
|
|
||||||
"Kerman Airport"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -5,37 +5,28 @@ local unitPayloads = {
|
|||||||
["name"] = "CAS",
|
["name"] = "CAS",
|
||||||
["pylons"] = {
|
["pylons"] = {
|
||||||
[1] = {
|
[1] = {
|
||||||
["CLSID"] = "{RB75}",
|
["CLSID"] = "{ARAKM70BHE}",
|
||||||
["num"] = 5,
|
|
||||||
},
|
|
||||||
[2] = {
|
|
||||||
["CLSID"] = "{RB75}",
|
|
||||||
["num"] = 3,
|
["num"] = 3,
|
||||||
},
|
},
|
||||||
[3] = {
|
[2] = {
|
||||||
["CLSID"] = "{RB75}",
|
["CLSID"] = "{ARAKM70BHE}",
|
||||||
["num"] = 2,
|
["num"] = 2,
|
||||||
},
|
},
|
||||||
[4] = {
|
[3] = {
|
||||||
["CLSID"] = "{RB75}",
|
|
||||||
["num"] = 6,
|
|
||||||
},
|
|
||||||
[5] = {
|
|
||||||
["CLSID"] = "{Robot24J}",
|
|
||||||
["num"] = 1,
|
|
||||||
},
|
|
||||||
[6] = {
|
|
||||||
["CLSID"] = "{Robot24J}",
|
|
||||||
["num"] = 7,
|
|
||||||
},
|
|
||||||
[7] = {
|
|
||||||
["CLSID"] = "{VIGGEN_X-TANK}",
|
["CLSID"] = "{VIGGEN_X-TANK}",
|
||||||
["num"] = 4,
|
["num"] = 4,
|
||||||
},
|
},
|
||||||
|
[4] = {
|
||||||
|
["CLSID"] = "{ARAKM70BHE}",
|
||||||
|
["num"] = 5,
|
||||||
|
},
|
||||||
|
[5] = {
|
||||||
|
["CLSID"] = "{ARAKM70BHE}",
|
||||||
|
["num"] = 6,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
["tasks"] = {
|
["tasks"] = {
|
||||||
[1] = 32,
|
[1] = 31,
|
||||||
[2] = 31,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
[2] = {
|
[2] = {
|
||||||
|
|||||||
@@ -1,343 +0,0 @@
|
|||||||
local unitPayloads = {
|
|
||||||
["name"] = "F-14A",
|
|
||||||
["payloads"] = {
|
|
||||||
[1] = {
|
|
||||||
["name"] = "CAP",
|
|
||||||
["pylons"] = {
|
|
||||||
[1] = {
|
|
||||||
["CLSID"] = "{LAU-138 wtip - AIM-9M}",
|
|
||||||
["num"] = 10,
|
|
||||||
},
|
|
||||||
[2] = {
|
|
||||||
["CLSID"] = "{LAU-138 wtip - AIM-9M}",
|
|
||||||
["num"] = 1,
|
|
||||||
},
|
|
||||||
[3] = {
|
|
||||||
["CLSID"] = "{SHOULDER AIM_54C_Mk47 L}",
|
|
||||||
["num"] = 2,
|
|
||||||
},
|
|
||||||
[4] = {
|
|
||||||
["CLSID"] = "{SHOULDER AIM_54C_Mk47 R}",
|
|
||||||
["num"] = 9,
|
|
||||||
},
|
|
||||||
[5] = {
|
|
||||||
["CLSID"] = "{F14-300gal}",
|
|
||||||
["num"] = 8,
|
|
||||||
},
|
|
||||||
[6] = {
|
|
||||||
["CLSID"] = "{F14-300gal}",
|
|
||||||
["num"] = 3,
|
|
||||||
},
|
|
||||||
[7] = {
|
|
||||||
["CLSID"] = "{AIM_54C_Mk47}",
|
|
||||||
["num"] = 7,
|
|
||||||
},
|
|
||||||
[8] = {
|
|
||||||
["CLSID"] = "{AIM_54C_Mk47}",
|
|
||||||
["num"] = 4,
|
|
||||||
},
|
|
||||||
[9] = {
|
|
||||||
["CLSID"] = "{AIM_54C_Mk47}",
|
|
||||||
["num"] = 6,
|
|
||||||
},
|
|
||||||
[10] = {
|
|
||||||
["CLSID"] = "{AIM_54C_Mk47}",
|
|
||||||
["num"] = 5,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
["tasks"] = {
|
|
||||||
[1] = 10,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[2] = {
|
|
||||||
["name"] = "CAS",
|
|
||||||
["pylons"] = {
|
|
||||||
[1] = {
|
|
||||||
["CLSID"] = "{LAU-138 wtip - AIM-9M}",
|
|
||||||
["num"] = 10,
|
|
||||||
},
|
|
||||||
[2] = {
|
|
||||||
["CLSID"] = "{LAU-138 wtip - AIM-9M}",
|
|
||||||
["num"] = 1,
|
|
||||||
},
|
|
||||||
[3] = {
|
|
||||||
["CLSID"] = "{F14-LANTIRN-TP}",
|
|
||||||
["num"] = 9,
|
|
||||||
},
|
|
||||||
[4] = {
|
|
||||||
["CLSID"] = "{PHXBRU3242_2*LAU10 LS}",
|
|
||||||
["num"] = 2,
|
|
||||||
},
|
|
||||||
[5] = {
|
|
||||||
["CLSID"] = "{F14-300gal}",
|
|
||||||
["num"] = 8,
|
|
||||||
},
|
|
||||||
[6] = {
|
|
||||||
["CLSID"] = "{F14-300gal}",
|
|
||||||
["num"] = 3,
|
|
||||||
},
|
|
||||||
[7] = {
|
|
||||||
["CLSID"] = "{BRU-32 MK-82}",
|
|
||||||
["num"] = 7,
|
|
||||||
},
|
|
||||||
[8] = {
|
|
||||||
["CLSID"] = "{BRU-32 MK-82}",
|
|
||||||
["num"] = 4,
|
|
||||||
},
|
|
||||||
[9] = {
|
|
||||||
["CLSID"] = "{BRU-32 MK-82}",
|
|
||||||
["num"] = 6,
|
|
||||||
},
|
|
||||||
[10] = {
|
|
||||||
["CLSID"] = "{BRU-32 MK-82}",
|
|
||||||
["num"] = 5,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
["tasks"] = {
|
|
||||||
[1] = 10,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[3] = {
|
|
||||||
["name"] = "SEAD",
|
|
||||||
["pylons"] = {
|
|
||||||
[1] = {
|
|
||||||
["CLSID"] = "{LAU-138 wtip - AIM-9M}",
|
|
||||||
["num"] = 10,
|
|
||||||
},
|
|
||||||
[2] = {
|
|
||||||
["CLSID"] = "{LAU-138 wtip - AIM-9M}",
|
|
||||||
["num"] = 1,
|
|
||||||
},
|
|
||||||
[3] = {
|
|
||||||
["CLSID"] = "{SHOULDER AIM_54C_Mk47 R}",
|
|
||||||
["num"] = 9,
|
|
||||||
},
|
|
||||||
[4] = {
|
|
||||||
["CLSID"] = "{SHOULDER AIM_54C_Mk47 L}",
|
|
||||||
["num"] = 2,
|
|
||||||
},
|
|
||||||
[5] = {
|
|
||||||
["CLSID"] = "{F14-300gal}",
|
|
||||||
["num"] = 8,
|
|
||||||
},
|
|
||||||
[6] = {
|
|
||||||
["CLSID"] = "{F14-300gal}",
|
|
||||||
["num"] = 3,
|
|
||||||
},
|
|
||||||
[7] = {
|
|
||||||
["CLSID"] = "{BRU3242_ADM141}",
|
|
||||||
["num"] = 7,
|
|
||||||
},
|
|
||||||
[8] = {
|
|
||||||
["CLSID"] = "{BRU3242_ADM141}",
|
|
||||||
["num"] = 4,
|
|
||||||
},
|
|
||||||
[9] = {
|
|
||||||
["CLSID"] = "{BRU3242_ADM141}",
|
|
||||||
["num"] = 6,
|
|
||||||
},
|
|
||||||
[10] = {
|
|
||||||
["CLSID"] = "{BRU3242_ADM141}",
|
|
||||||
["num"] = 5,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
["tasks"] = {
|
|
||||||
[1] = 10,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[4] = {
|
|
||||||
["name"] = "DEAD",
|
|
||||||
["pylons"] = {
|
|
||||||
[1] = {
|
|
||||||
["CLSID"] = "{LAU-138 wtip - AIM-9M}",
|
|
||||||
["num"] = 10,
|
|
||||||
},
|
|
||||||
[2] = {
|
|
||||||
["CLSID"] = "{LAU-138 wtip - AIM-9M}",
|
|
||||||
["num"] = 1,
|
|
||||||
},
|
|
||||||
[3] = {
|
|
||||||
["CLSID"] = "{F14-LANTIRN-TP}",
|
|
||||||
["num"] = 9,
|
|
||||||
},
|
|
||||||
[4] = {
|
|
||||||
["CLSID"] = "{PHXBRU3242_2*LAU10 LS}",
|
|
||||||
["num"] = 2,
|
|
||||||
},
|
|
||||||
[5] = {
|
|
||||||
["CLSID"] = "{F14-300gal}",
|
|
||||||
["num"] = 8,
|
|
||||||
},
|
|
||||||
[6] = {
|
|
||||||
["CLSID"] = "{F14-300gal}",
|
|
||||||
["num"] = 3,
|
|
||||||
},
|
|
||||||
[7] = {
|
|
||||||
["CLSID"] = "{BRU-32 GBU-12}",
|
|
||||||
["num"] = 7,
|
|
||||||
},
|
|
||||||
[8] = {
|
|
||||||
["CLSID"] = "{BRU-32 GBU-12}",
|
|
||||||
["num"] = 4,
|
|
||||||
},
|
|
||||||
[9] = {
|
|
||||||
["CLSID"] = "{BRU-32 GBU-12}",
|
|
||||||
["num"] = 6,
|
|
||||||
},
|
|
||||||
[10] = {
|
|
||||||
["CLSID"] = "{BRU-32 GBU-12}",
|
|
||||||
["num"] = 5,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
["tasks"] = {
|
|
||||||
[1] = 10,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[5] = {
|
|
||||||
["name"] = "STRIKE",
|
|
||||||
["pylons"] = {
|
|
||||||
[1] = {
|
|
||||||
["CLSID"] = "{LAU-138 wtip - AIM-9M}",
|
|
||||||
["num"] = 10,
|
|
||||||
},
|
|
||||||
[2] = {
|
|
||||||
["CLSID"] = "{LAU-138 wtip - AIM-9M}",
|
|
||||||
["num"] = 1,
|
|
||||||
},
|
|
||||||
[3] = {
|
|
||||||
["CLSID"] = "{F14-LANTIRN-TP}",
|
|
||||||
["num"] = 9,
|
|
||||||
},
|
|
||||||
[4] = {
|
|
||||||
["CLSID"] = "{SHOULDER AIM-7MH}",
|
|
||||||
["num"] = 2,
|
|
||||||
},
|
|
||||||
[5] = {
|
|
||||||
["CLSID"] = "{F14-300gal}",
|
|
||||||
["num"] = 8,
|
|
||||||
},
|
|
||||||
[6] = {
|
|
||||||
["CLSID"] = "{F14-300gal}",
|
|
||||||
["num"] = 3,
|
|
||||||
},
|
|
||||||
[7] = {
|
|
||||||
["CLSID"] = "{BRU-32 GBU-16}",
|
|
||||||
["num"] = 7,
|
|
||||||
},
|
|
||||||
[8] = {
|
|
||||||
["CLSID"] = "{BRU-32 GBU-16}",
|
|
||||||
["num"] = 4,
|
|
||||||
},
|
|
||||||
[9] = {
|
|
||||||
["CLSID"] = "{BRU-32 GBU-16}",
|
|
||||||
["num"] = 6,
|
|
||||||
},
|
|
||||||
[10] = {
|
|
||||||
["CLSID"] = "{BRU-32 GBU-16}",
|
|
||||||
["num"] = 5,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
["tasks"] = {
|
|
||||||
[1] = 10,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[6] = {
|
|
||||||
["name"] = "BAI",
|
|
||||||
["pylons"] = {
|
|
||||||
[1] = {
|
|
||||||
["CLSID"] = "{LAU-138 wtip - AIM-9M}",
|
|
||||||
["num"] = 10,
|
|
||||||
},
|
|
||||||
[2] = {
|
|
||||||
["CLSID"] = "{LAU-138 wtip - AIM-9M}",
|
|
||||||
["num"] = 1,
|
|
||||||
},
|
|
||||||
[3] = {
|
|
||||||
["CLSID"] = "{F14-LANTIRN-TP}",
|
|
||||||
["num"] = 9,
|
|
||||||
},
|
|
||||||
[4] = {
|
|
||||||
["CLSID"] = "{PHXBRU3242_2*LAU10 LS}",
|
|
||||||
["num"] = 2,
|
|
||||||
},
|
|
||||||
[5] = {
|
|
||||||
["CLSID"] = "{F14-300gal}",
|
|
||||||
["num"] = 8,
|
|
||||||
},
|
|
||||||
[6] = {
|
|
||||||
["CLSID"] = "{F14-300gal}",
|
|
||||||
["num"] = 3,
|
|
||||||
},
|
|
||||||
[7] = {
|
|
||||||
["CLSID"] = "{BRU-32 MK-82}",
|
|
||||||
["num"] = 7,
|
|
||||||
},
|
|
||||||
[8] = {
|
|
||||||
["CLSID"] = "{BRU-32 MK-82}",
|
|
||||||
["num"] = 4,
|
|
||||||
},
|
|
||||||
[9] = {
|
|
||||||
["CLSID"] = "{BRU-32 MK-20}",
|
|
||||||
["num"] = 6,
|
|
||||||
},
|
|
||||||
[10] = {
|
|
||||||
["CLSID"] = "{BRU-32 MK-20}",
|
|
||||||
["num"] = 5,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
["tasks"] = {
|
|
||||||
[1] = 10,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[7] = {
|
|
||||||
["name"] = "ANTISHIP",
|
|
||||||
["pylons"] = {
|
|
||||||
[1] = {
|
|
||||||
["CLSID"] = "{F14-LANTIRN-TP}",
|
|
||||||
["num"] = 9,
|
|
||||||
},
|
|
||||||
[2] = {
|
|
||||||
["CLSID"] = "{LAU-138 wtip - AIM-9M}",
|
|
||||||
["num"] = 10,
|
|
||||||
},
|
|
||||||
[3] = {
|
|
||||||
["CLSID"] = "{LAU-138 wtip - AIM-9M}",
|
|
||||||
["num"] = 1,
|
|
||||||
},
|
|
||||||
[4] = {
|
|
||||||
["CLSID"] = "{PHXBRU3242_2*LAU10 LS}",
|
|
||||||
["num"] = 2,
|
|
||||||
},
|
|
||||||
[5] = {
|
|
||||||
["CLSID"] = "{BRU-32 GBU-16}",
|
|
||||||
["num"] = 7,
|
|
||||||
},
|
|
||||||
[6] = {
|
|
||||||
["CLSID"] = "{BRU-32 GBU-16}",
|
|
||||||
["num"] = 4,
|
|
||||||
},
|
|
||||||
[7] = {
|
|
||||||
["CLSID"] = "{BRU3242_ADM141}",
|
|
||||||
["num"] = 6,
|
|
||||||
},
|
|
||||||
[8] = {
|
|
||||||
["CLSID"] = "{BRU3242_ADM141}",
|
|
||||||
["num"] = 5,
|
|
||||||
},
|
|
||||||
[9] = {
|
|
||||||
["CLSID"] = "{F14-300gal}",
|
|
||||||
["num"] = 3,
|
|
||||||
},
|
|
||||||
[10] = {
|
|
||||||
["CLSID"] = "{F14-300gal}",
|
|
||||||
["num"] = 8,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
["tasks"] = {
|
|
||||||
[1] = 10,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
["unitType"] = "F-14A-135-GR",
|
|
||||||
}
|
|
||||||
return unitPayloads
|
|
||||||
@@ -4,7 +4,6 @@
|
|||||||
"authors": "Khopa",
|
"authors": "Khopa",
|
||||||
"description": "<p>A generic bluefor coldwar faction.</p>",
|
"description": "<p>A generic bluefor coldwar faction.</p>",
|
||||||
"aircrafts": [
|
"aircrafts": [
|
||||||
"F_14A_135_GR",
|
|
||||||
"F_14B",
|
"F_14B",
|
||||||
"F_4E",
|
"F_4E",
|
||||||
"F_5E_3",
|
"F_5E_3",
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
"authors": "Khopa",
|
"authors": "Khopa",
|
||||||
"description": "<p>A generic bluefor coldwar faction. (With the A-4E-C mod)</p>",
|
"description": "<p>A generic bluefor coldwar faction. (With the A-4E-C mod)</p>",
|
||||||
"aircrafts": [
|
"aircrafts": [
|
||||||
"F_14A_135_GR",
|
|
||||||
"F_14B",
|
"F_14B",
|
||||||
"F_4E",
|
"F_4E",
|
||||||
"F_5E_3",
|
"F_5E_3",
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
"authors": "Khopa",
|
"authors": "Khopa",
|
||||||
"description": "<p>A generic bluefor coldwar faction. (With the A-4E-C and the MB-339 mods)</p>",
|
"description": "<p>A generic bluefor coldwar faction. (With the A-4E-C and the MB-339 mods)</p>",
|
||||||
"aircrafts": [
|
"aircrafts": [
|
||||||
"F_14A_135_GR",
|
|
||||||
"F_14B",
|
"F_14B",
|
||||||
"F_4E",
|
"F_4E",
|
||||||
"F_5E_3",
|
"F_5E_3",
|
||||||
|
|||||||
@@ -1,84 +0,0 @@
|
|||||||
{
|
|
||||||
"country": "France",
|
|
||||||
"name": "France 2005 (Frenchpack)",
|
|
||||||
"authors": "HerrTom",
|
|
||||||
"description": "<p>French equipment using the Frenchpack, but without the Rafale mod.</p>",
|
|
||||||
"aircrafts": [
|
|
||||||
"M_2000C",
|
|
||||||
"Mirage_2000_5",
|
|
||||||
"SA342M",
|
|
||||||
"SA342L",
|
|
||||||
"SA342Mistral"
|
|
||||||
],
|
|
||||||
"awacs": [
|
|
||||||
"E_3A"
|
|
||||||
],
|
|
||||||
"tankers": [
|
|
||||||
"KC_135",
|
|
||||||
"KC130"
|
|
||||||
],
|
|
||||||
"frontline_units": [
|
|
||||||
"AMX_10RCR",
|
|
||||||
"AMX_10RCR_SEPAR",
|
|
||||||
"ERC_90",
|
|
||||||
"TRM_2000_PAMELA",
|
|
||||||
"VAB__50",
|
|
||||||
"VAB_MEPHISTO",
|
|
||||||
"VAB_T20_13",
|
|
||||||
"VAB_T20_13",
|
|
||||||
"VBL__50",
|
|
||||||
"VBL_AANF1",
|
|
||||||
"VBAE_CRAB",
|
|
||||||
"VBAE_CRAB_MMP",
|
|
||||||
"AMX_30B2",
|
|
||||||
"Leclerc_Serie_XXI"
|
|
||||||
],
|
|
||||||
"artillery_units": [
|
|
||||||
"MLRS_M270",
|
|
||||||
"SPH_M109_Paladin"
|
|
||||||
],
|
|
||||||
"logistics_units": [
|
|
||||||
"Transport_M818"
|
|
||||||
],
|
|
||||||
"infantry_units": [
|
|
||||||
"Infantry_M4",
|
|
||||||
"Soldier_M249",
|
|
||||||
"Stinger_MANPADS"
|
|
||||||
],
|
|
||||||
"shorads": [
|
|
||||||
"HQ7Generator",
|
|
||||||
"RolandGenerator"
|
|
||||||
],
|
|
||||||
"sams": [
|
|
||||||
"RolandGenerator",
|
|
||||||
"HawkGenerator"
|
|
||||||
],
|
|
||||||
"aircraft_carrier": [
|
|
||||||
"CVN_74_John_C__Stennis"
|
|
||||||
],
|
|
||||||
"helicopter_carrier": [
|
|
||||||
"LHA_1_Tarawa"
|
|
||||||
],
|
|
||||||
"destroyers": [
|
|
||||||
"USS_Arleigh_Burke_IIa"
|
|
||||||
],
|
|
||||||
"cruisers": [
|
|
||||||
"Ticonderoga_class"
|
|
||||||
],
|
|
||||||
"requirements": {
|
|
||||||
"frenchpack V3.5": "https://forums.eagle.ru/showthread.php?t=279974"
|
|
||||||
},
|
|
||||||
"carrier_names": [
|
|
||||||
"L9013 Mistral",
|
|
||||||
"L9014 Tonerre",
|
|
||||||
"L9015 Dixmude"
|
|
||||||
],
|
|
||||||
"helicopter_carrier_names": [
|
|
||||||
"Jeanne d'Arc"
|
|
||||||
],
|
|
||||||
"navy_generators": [
|
|
||||||
"ArleighBurkeGroupGenerator"
|
|
||||||
],
|
|
||||||
"has_jtac": true,
|
|
||||||
"jtac_unit": "MQ_9_Reaper"
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
{
|
|
||||||
"country": "Georgia",
|
|
||||||
"name": "Georgia 2008",
|
|
||||||
"authors": "HerrTom",
|
|
||||||
"description": "<p>A faction that represents Georgia during the South Ossetian War. They will have a lot more aircraft than historically, and no real A2A capability.</p>",
|
|
||||||
"aircrafts": [
|
|
||||||
"L_39ZA",
|
|
||||||
"Su_25",
|
|
||||||
"Mi_8MT",
|
|
||||||
"Mi_24V",
|
|
||||||
"UH_1H"
|
|
||||||
],
|
|
||||||
"frontline_units": [
|
|
||||||
"APC_BTR_80",
|
|
||||||
"APC_MTLB",
|
|
||||||
"APC_Cobra",
|
|
||||||
"IFV_BMP_1",
|
|
||||||
"IFV_BMP_2",
|
|
||||||
"MBT_T_72B",
|
|
||||||
"MBT_T_55"
|
|
||||||
],
|
|
||||||
"artillery_units": [
|
|
||||||
"MLRS_BM21_Grad",
|
|
||||||
"SPH_2S1_Gvozdika",
|
|
||||||
"SPH_2S3_Akatsia"
|
|
||||||
],
|
|
||||||
"logistics_units": [
|
|
||||||
"Transport_Ural_375",
|
|
||||||
"Transport_UAZ_469"
|
|
||||||
],
|
|
||||||
"infantry_units": [
|
|
||||||
"Paratrooper_AKS",
|
|
||||||
"Paratrooper_RPG_16"
|
|
||||||
],
|
|
||||||
"shorads": [
|
|
||||||
"SA13Generator",
|
|
||||||
"SA8Generator"
|
|
||||||
],
|
|
||||||
"sams": [
|
|
||||||
"SA6Generator",
|
|
||||||
"SA11Generator"
|
|
||||||
],
|
|
||||||
"requirements": {},
|
|
||||||
"has_jtac": true,
|
|
||||||
"jtac_unit": "MQ_9_Reaper"
|
|
||||||
}
|
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
"MiG_29A",
|
"MiG_29A",
|
||||||
"F_4E",
|
"F_4E",
|
||||||
"F_5E_3",
|
"F_5E_3",
|
||||||
"F_14A_135_GR",
|
"F_14B",
|
||||||
"Su_17M4",
|
"Su_17M4",
|
||||||
"Su_24M",
|
"Su_24M",
|
||||||
"Su_25",
|
"Su_25",
|
||||||
|
|||||||
@@ -61,24 +61,5 @@
|
|||||||
"OliverHazardPerryGroupGenerator"
|
"OliverHazardPerryGroupGenerator"
|
||||||
],
|
],
|
||||||
"has_jtac": true,
|
"has_jtac": true,
|
||||||
"jtac_unit": "MQ_9_Reaper",
|
"jtac_unit": "MQ_9_Reaper"
|
||||||
"liveries_overrides": {
|
|
||||||
"FA_18C_hornet": [
|
|
||||||
"NSAWC brown splinter",
|
|
||||||
"NAWDC black",
|
|
||||||
"VFC-12"
|
|
||||||
],
|
|
||||||
"F_15C": [
|
|
||||||
"65th Aggressor SQN (WA) MiG",
|
|
||||||
"65th Aggressor SQN (WA) MiG",
|
|
||||||
"65th Aggressor SQN (WA) SUPER_Flanker"
|
|
||||||
],
|
|
||||||
"F_16C_50": [
|
|
||||||
"usaf 64th aggressor sqn - shark",
|
|
||||||
"usaf 64th aggressor sqn-splinter",
|
|
||||||
"64th_aggressor_squadron_ghost"
|
|
||||||
], "F_14B": [
|
|
||||||
"vf-74 adversary"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
"aircrafts": [
|
"aircrafts": [
|
||||||
"F_5E_3",
|
"F_5E_3",
|
||||||
"F_4E",
|
"F_4E",
|
||||||
"F_14A_135_GR",
|
"F_14B",
|
||||||
"B_52H",
|
"B_52H",
|
||||||
"UH_1H"
|
"UH_1H"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
"aircrafts": [
|
"aircrafts": [
|
||||||
"F_15C",
|
"F_15C",
|
||||||
"F_15E",
|
"F_15E",
|
||||||
"F_14A_135_GR",
|
|
||||||
"F_14B",
|
"F_14B",
|
||||||
"FA_18C_hornet",
|
"FA_18C_hornet",
|
||||||
"F_16C_50",
|
"F_16C_50",
|
||||||
@@ -86,25 +85,5 @@
|
|||||||
"ArleighBurkeGroupGenerator"
|
"ArleighBurkeGroupGenerator"
|
||||||
],
|
],
|
||||||
"has_jtac": true,
|
"has_jtac": true,
|
||||||
"jtac_unit": "MQ_9_Reaper",
|
"jtac_unit": "MQ_9_Reaper"
|
||||||
"liveries_overrides": {
|
|
||||||
"FA_18C_hornet": [
|
|
||||||
"VFA-37",
|
|
||||||
"VFA-106",
|
|
||||||
"VFA-113",
|
|
||||||
"VFA-122",
|
|
||||||
"VFA-131",
|
|
||||||
"VFA-192",
|
|
||||||
"VFA-34",
|
|
||||||
"VFA-83",
|
|
||||||
"VFA-87",
|
|
||||||
"VFA-97",
|
|
||||||
"VMFA-122",
|
|
||||||
"VMFA-132",
|
|
||||||
"VMFA-251",
|
|
||||||
"VMFA-312",
|
|
||||||
"VMFA-314",
|
|
||||||
"VMFA-323"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -86,25 +86,5 @@
|
|||||||
"OliverHazardPerryGroupGenerator"
|
"OliverHazardPerryGroupGenerator"
|
||||||
],
|
],
|
||||||
"has_jtac": true,
|
"has_jtac": true,
|
||||||
"jtac_unit": "MQ_9_Reaper",
|
"jtac_unit": "MQ_9_Reaper"
|
||||||
"liveries_overrides": {
|
|
||||||
"FA_18C_hornet": [
|
|
||||||
"VFA-37",
|
|
||||||
"VFA-106",
|
|
||||||
"VFA-113",
|
|
||||||
"VFA-122",
|
|
||||||
"VFA-131",
|
|
||||||
"VFA-192",
|
|
||||||
"VFA-34",
|
|
||||||
"VFA-83",
|
|
||||||
"VFA-87",
|
|
||||||
"VFA-97",
|
|
||||||
"VMFA-122",
|
|
||||||
"VMFA-132",
|
|
||||||
"VMFA-251",
|
|
||||||
"VMFA-312",
|
|
||||||
"VMFA-314",
|
|
||||||
"VMFA-323"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
{
|
|
||||||
"country": "USA",
|
|
||||||
"name": "US Navy 1985",
|
|
||||||
"authors": "HerrTom",
|
|
||||||
"description": "<p>Highway to the Danger Zone! For Tomcat lovers.</p>",
|
|
||||||
"aircrafts": [
|
|
||||||
"F_4E",
|
|
||||||
"F_14A_135_GR",
|
|
||||||
"F_14B",
|
|
||||||
"S_3B",
|
|
||||||
"UH_1H",
|
|
||||||
"AH_1W"
|
|
||||||
],
|
|
||||||
"awacs": [
|
|
||||||
"E_3A"
|
|
||||||
],
|
|
||||||
"tankers": [
|
|
||||||
"S_3B_Tanker"
|
|
||||||
],
|
|
||||||
"frontline_units": [
|
|
||||||
"MBT_M60A3_Patton",
|
|
||||||
"APC_M113",
|
|
||||||
"APC_M1025_HMMWV"
|
|
||||||
],
|
|
||||||
"artillery_units": [
|
|
||||||
"SPH_M109_Paladin",
|
|
||||||
"MLRS_M270"
|
|
||||||
],
|
|
||||||
"logistics_units": [
|
|
||||||
"Transport_M818"
|
|
||||||
],
|
|
||||||
"infantry_units": [
|
|
||||||
"Infantry_M4",
|
|
||||||
"Soldier_M249"
|
|
||||||
],
|
|
||||||
"shorads": [
|
|
||||||
"VulcanGenerator",
|
|
||||||
"ChaparralGenerator"
|
|
||||||
],
|
|
||||||
"sams": [
|
|
||||||
"HawkGenerator",
|
|
||||||
"ChaparralGenerator"
|
|
||||||
],
|
|
||||||
"aircraft_carrier": [
|
|
||||||
"CVN_74_John_C__Stennis"
|
|
||||||
],
|
|
||||||
"helicopter_carrier": [
|
|
||||||
"LHA_1_Tarawa"
|
|
||||||
],
|
|
||||||
"destroyers": [
|
|
||||||
"Oliver_Hazzard_Perry_class"
|
|
||||||
],
|
|
||||||
"cruisers": [
|
|
||||||
"Ticonderoga_class"
|
|
||||||
],
|
|
||||||
"carrier_names": [
|
|
||||||
"CVN-71 Theodore Roosevelt",
|
|
||||||
"CVN-72 Abraham Lincoln",
|
|
||||||
"CVN-73 George Washington",
|
|
||||||
"CVN-74 John C. Stennis"
|
|
||||||
],
|
|
||||||
"helicopter_carrier_names": [
|
|
||||||
"LHA-1 Tarawa",
|
|
||||||
"LHA-2 Saipan",
|
|
||||||
"LHA-3 Belleau Wood",
|
|
||||||
"LHA-4 Nassau",
|
|
||||||
"LHA-5 Peleliu"
|
|
||||||
],
|
|
||||||
"navy_generators": [
|
|
||||||
"OliverHazardPerryGroupGenerator"
|
|
||||||
],
|
|
||||||
"requirements": {},
|
|
||||||
"doctrine": "coldwar",
|
|
||||||
"liveries_overrides": {
|
|
||||||
"FA_18C_hornet": [
|
|
||||||
"VFA-37",
|
|
||||||
"VFA-106",
|
|
||||||
"VFA-113",
|
|
||||||
"VFA-122",
|
|
||||||
"VFA-131",
|
|
||||||
"VFA-192",
|
|
||||||
"VFA-34",
|
|
||||||
"VFA-83",
|
|
||||||
"VFA-87",
|
|
||||||
"VFA-97"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
<b>You are clear for takeoff</b>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Some player flights may be delayed to start. For such flights, it will not be
|
|
||||||
possible to enter the cockpit for a delayed flight until its mission start
|
|
||||||
time, shown in the flight information window.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
To reduce delays, schedule packages with player flights with an earlier TOT.
|
|
||||||
Note that if some flights within the package will take a long time to reach the
|
|
||||||
target, a player flight may still be delayed.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
To avoid delays entirely, use the "Never delay player flights" option in the
|
|
||||||
mission generation settings. Note that this will <strong>not</strong> adjust
|
|
||||||
the timing of your mission; this option only allows you to wait in the
|
|
||||||
cockpit.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
For more information, see the mission planning documentation on
|
|
||||||
<a href="https://github.com/Khopa/dcs_liberation/wiki/Mission-planning">
|
|
||||||
the wiki</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2>For Singleplayer:</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
In DCS, open the Mission Editor and load the file: <i>liberation_nextturn</i>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Once the mission is loaded in the ME, use the "FLY" option in the "Flight"
|
|
||||||
menu to launch.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2>For Multiplayer:</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
In DCS, open the Mission Editor, and load the file: <i>liberation_nextturn</i>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>Select File/Save, exit the mission editor, and then select Multiplayer.</p>
|
|
||||||
|
|
||||||
<p>Then host a server with the mission, and tell your friends to join!</p>
|
|
||||||
|
|
||||||
<i>(The step in the mission editor is important, and fix a game breaking bug.)</i>
|
|
||||||
|
|
||||||
<h2>Finishing</h2>
|
|
||||||
|
|
||||||
<p>Once you have played the mission, click on the \"Accept Results\" button.</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
If DCS Liberation does not detect mission end, use the manually submit button,
|
|
||||||
and choose the state.json file.
|
|
||||||
</p>
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1010 B After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1010 B |
Binary file not shown.
|
Before Width: | Height: | Size: 1010 B |
@@ -99,10 +99,6 @@ class TheaterGroundObject(MissionTarget):
|
|||||||
"""The name of the unit group."""
|
"""The name of the unit group."""
|
||||||
return f"{self.category}|{self.group_id}"
|
return f"{self.category}|{self.group_id}"
|
||||||
|
|
||||||
@property
|
|
||||||
def waypoint_name(self) -> str:
|
|
||||||
return f"[{self.name}] {self.category}"
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return NAME_BY_CATEGORY[self.category]
|
return NAME_BY_CATEGORY[self.category]
|
||||||
|
|
||||||
@@ -140,10 +136,6 @@ class BuildingGroundObject(TheaterGroundObject):
|
|||||||
"""The name of the unit group."""
|
"""The name of the unit group."""
|
||||||
return f"{self.category}|{self.group_id}|{self.object_id}"
|
return f"{self.category}|{self.group_id}|{self.object_id}"
|
||||||
|
|
||||||
@property
|
|
||||||
def waypoint_name(self) -> str:
|
|
||||||
return f"{super().waypoint_name} #{self.object_id}"
|
|
||||||
|
|
||||||
|
|
||||||
class GenericCarrierGroundObject(TheaterGroundObject):
|
class GenericCarrierGroundObject(TheaterGroundObject):
|
||||||
pass
|
pass
|
||||||
|
|||||||
Reference in New Issue
Block a user