Merge branch 'develop' into frontline_vector

This commit is contained in:
walterroach 2020-11-27 13:47:10 -06:00
commit edbe2d86f2
26 changed files with 3269 additions and 902 deletions

View File

@ -160,13 +160,14 @@ 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
from pydcs_extensions.f22a.f22a import F_22A from pydcs_extensions.f22a.f22a import F_22A
from pydcs_extensions.mb339.mb339 import MB_339PAN from pydcs_extensions.mb339.mb339 import MB_339PAN
from pydcs_extensions.rafale.rafale import Rafale_A_S, Rafale_M from pydcs_extensions.rafale.rafale import Rafale_A_S, Rafale_M, Rafale_B
from pydcs_extensions.su57.su57 import Su_57 from pydcs_extensions.su57.su57 import Su_57
plane_map["A-4E-C"] = A_4E_C plane_map["A-4E-C"] = A_4E_C
plane_map["MB-339PAN"] = MB_339PAN plane_map["MB-339PAN"] = MB_339PAN
plane_map["Rafale_M"] = Rafale_M plane_map["Rafale_M"] = Rafale_M
plane_map["Rafale_A_S"] = Rafale_A_S plane_map["Rafale_A_S"] = Rafale_A_S
plane_map["Rafale_B"] = Rafale_B
plane_map["Su-57"] = Su_57 plane_map["Su-57"] = Su_57
vehicle_map["FieldHL"] = frenchpack._FIELD_HIDE vehicle_map["FieldHL"] = frenchpack._FIELD_HIDE
@ -352,6 +353,7 @@ PRICES = {
# Modded # Modded
Rafale_M: 26, Rafale_M: 26,
Rafale_A_S: 26, Rafale_A_S: 26,
Rafale_B: 26,
# armor # armor
Armor.APC_MTLB: 4, Armor.APC_MTLB: 4,
@ -641,6 +643,7 @@ UNIT_BY_TASK = {
P_47D_40, P_47D_40,
RQ_1A_Predator, RQ_1A_Predator,
Rafale_A_S, Rafale_A_S,
Rafale_B,
SA342L, SA342L,
SA342M, SA342M,
SA342Minigun, SA342Minigun,
@ -1063,6 +1066,7 @@ PLANE_PAYLOAD_OVERRIDES: Dict[Type[PlaneType], Dict[Type[Task], str]] = {
MB_339PAN: COMMON_OVERRIDE, MB_339PAN: COMMON_OVERRIDE,
Rafale_M: COMMON_OVERRIDE, Rafale_M: COMMON_OVERRIDE,
Rafale_A_S: COMMON_OVERRIDE, Rafale_A_S: COMMON_OVERRIDE,
Rafale_B: COMMON_OVERRIDE,
OH_58D: COMMON_OVERRIDE, OH_58D: COMMON_OVERRIDE,
F_16A: COMMON_OVERRIDE, F_16A: COMMON_OVERRIDE,
MQ_9_Reaper: COMMON_OVERRIDE, MQ_9_Reaper: COMMON_OVERRIDE,

View File

@ -1,3 +1,4 @@
import datetime
class Information(): class Information():
@ -5,7 +6,12 @@ class Information():
self.title = title self.title = title
self.text = text self.text = text
self.turn = turn self.turn = turn
self.timestamp = datetime.datetime.now()
def __str__(self): def __str__(self):
s = "[" + str(self.turn) + "] " + self.title + "\n" + self.text return '[{}][{}] {} {}'.format(
return s self.timestamp.strftime("%Y-%m-%d %H:%M:%S") if self.timestamp is not None else '',
self.turn,
self.title,
self.text
)

View File

@ -7,7 +7,7 @@ from dataclasses import dataclass
from functools import cached_property from functools import cached_property
from itertools import tee from itertools import tee
from pathlib import Path from pathlib import Path
from typing import Any, Dict, Iterator, List, Optional, Tuple, Union, cast from typing import Any, Dict, Iterator, List, Optional, Set, Tuple, Union, cast
from dcs import Mission from dcs import Mission
from dcs.countries import ( from dcs.countries import (
@ -96,17 +96,17 @@ class MizCampaignLoader:
COASTAL_DEFENSE_UNIT_TYPE = MissilesSS.SS_N_2_Silkworm.id COASTAL_DEFENSE_UNIT_TYPE = MissilesSS.SS_N_2_Silkworm.id
# Multiple options for the required SAMs so campaign designers can more # Multiple options for the required SAMs so campaign designers can more
# easily see the coverage of their IADS. Designers focused on campaigns that # accurately see the coverage of their IADS for the expected type.
# will primarily use SA-2s can place SA-2 launchers to ensure that they will REQUIRED_LONG_RANGE_SAM_UNIT_TYPES = {
# have adequate coverage, and designers focused on campaigns that will AirDefence.SAM_Patriot_LN_M901.id,
# primarily use SA-10s can do the same. AirDefence.SAM_SA_10_S_300PS_LN_5P85C.id,
REQUIRED_SAM_UNIT_TYPES = { AirDefence.SAM_SA_10_S_300PS_LN_5P85D.id,
AirDefence.SAM_Hawk_LN_M192, }
AirDefence.SAM_Patriot_LN_M901,
AirDefence.SAM_SA_10_S_300PS_LN_5P85C, REQUIRED_MEDIUM_RANGE_SAM_UNIT_TYPES = {
AirDefence.SAM_SA_10_S_300PS_LN_5P85D, AirDefence.SAM_Hawk_LN_M192.id,
AirDefence.SAM_SA_2_LN_SM_90, AirDefence.SAM_SA_2_LN_SM_90.id,
AirDefence.SAM_SA_3_S_125_LN_5P73, AirDefence.SAM_SA_3_S_125_LN_5P73.id,
} }
BASE_DEFENSE_RADIUS = nm_to_meter(2) BASE_DEFENSE_RADIUS = nm_to_meter(2)
@ -221,9 +221,15 @@ class MizCampaignLoader:
yield group yield group
@property @property
def required_sams(self) -> Iterator[VehicleGroup]: def required_long_range_sams(self) -> Iterator[VehicleGroup]:
for group in self.red.vehicle_group: for group in self.red.vehicle_group:
if group.units[0].type == self.REQUIRED_SAM_UNIT_TYPES: if group.units[0].type in self.REQUIRED_LONG_RANGE_SAM_UNIT_TYPES:
yield group
@property
def required_medium_range_sams(self) -> Iterator[VehicleGroup]:
for group in self.red.vehicle_group:
if group.units[0].type in self.REQUIRED_MEDIUM_RANGE_SAM_UNIT_TYPES:
yield group yield group
@cached_property @cached_property
@ -335,9 +341,17 @@ class MizCampaignLoader:
closest, distance = self.objective_info(group) closest, distance = self.objective_info(group)
closest.preset_locations.coastal_defenses.append(group.position) closest.preset_locations.coastal_defenses.append(group.position)
for group in self.required_sams: for group in self.required_long_range_sams:
closest, distance = self.objective_info(group) closest, distance = self.objective_info(group)
closest.preset_locations.required_sams.append(group.position) closest.preset_locations.required_long_range_sams.append(
group.position
)
for group in self.required_medium_range_sams:
closest, distance = self.objective_info(group)
closest.preset_locations.required_medium_range_sams.append(
group.position
)
def populate_theater(self) -> None: def populate_theater(self) -> None:
for control_point in self.control_points.values(): for control_point in self.control_points.values():

View File

@ -95,8 +95,11 @@ class PresetLocations:
#: Locations used by missile sites like scuds and V-2s. #: Locations used by missile sites like scuds and V-2s.
missile_sites: List[Point] = field(default_factory=list) missile_sites: List[Point] = field(default_factory=list)
#: Locations of SAMs which should always be spawned. #: Locations of long range SAMs which should always be spawned.
required_sams: List[Point] = field(default_factory=list) required_long_range_sams: List[Point] = field(default_factory=list)
#: Locations of medium range SAMs which should always be spawned.
required_medium_range_sams: List[Point] = field(default_factory=list)
@staticmethod @staticmethod
def _random_from(points: List[Point]) -> Optional[Point]: def _random_from(points: List[Point]) -> Optional[Point]:

View File

@ -4,7 +4,7 @@ import logging
import math import math
import pickle import pickle
import random import random
from typing import Any, Dict, Optional from typing import Any, Dict, Iterable, Optional
from dcs.mapping import Point from dcs.mapping import Point
from dcs.task import CAP, CAS, PinpointStrike from dcs.task import CAP, CAS, PinpointStrike
@ -36,7 +36,7 @@ from gen.fleet.ship_group_generator import (
from gen.locations.preset_location_finder import MizDataLocationFinder from gen.locations.preset_location_finder import MizDataLocationFinder
from gen.missiles.missiles_group_generator import generate_missile_group from gen.missiles.missiles_group_generator import generate_missile_group
from gen.sam.sam_group_generator import ( from gen.sam.sam_group_generator import (
generate_anti_air_group, LONG_RANGE_SAMS, MEDIUM_RANGE_SAMS, generate_anti_air_group,
generate_ewr_group, generate_shorad_group, generate_ewr_group, generate_shorad_group,
) )
from . import ( from . import (
@ -268,7 +268,6 @@ class LocationFinder:
Find a valid ground object location Find a valid ground object location
:param on_ground: Whether it should be on ground or on sea (True = on :param on_ground: Whether it should be on ground or on sea (True = on
ground) ground)
:param theater: Theater object
:param min_range: Minimal range from point :param min_range: Minimal range from point
:param max_range: Max range from point :param max_range: Max range from point
:param is_base_defense: True if the location is for base defense. :param is_base_defense: True if the location is for base defense.
@ -459,8 +458,9 @@ class BaseDefenseGenerator:
g = EwrGroundObject(namegen.random_objective_name(), group_id, g = EwrGroundObject(namegen.random_objective_name(), group_id,
position, self.control_point) position, self.control_point)
group = generate_ewr_group(self.game, g, self.faction_name) group = generate_ewr_group(self.game, g, self.faction)
if group is None: if group is None:
logging.error(f"Could not generate EWR at {self.control_point}")
return return
g.groups = [group] g.groups = [group]
@ -492,8 +492,11 @@ class BaseDefenseGenerator:
for_airbase=True) for_airbase=True)
group = generate_armor_group(self.faction_name, self.game, g) group = generate_armor_group(self.faction_name, self.game, g)
if group is not None: if group is None:
g.groups.append(group) logging.error(
f"Could not generate garrison at {self.control_point}")
return
g.groups.append(group)
self.control_point.base_defenses.append(g) self.control_point.base_defenses.append(g)
def generate_sam(self) -> None: def generate_sam(self) -> None:
@ -507,9 +510,11 @@ class BaseDefenseGenerator:
g = SamGroundObject(namegen.random_objective_name(), group_id, g = SamGroundObject(namegen.random_objective_name(), group_id,
position, self.control_point, for_airbase=True) position, self.control_point, for_airbase=True)
group = generate_anti_air_group(self.game, g, self.faction_name) group = generate_anti_air_group(self.game, g, self.faction)
if group is not None: if group is None:
g.groups.append(group) logging.error(f"Could not generate SAM at {self.control_point}")
return
g.groups.append(group)
self.control_point.base_defenses.append(g) self.control_point.base_defenses.append(g)
def generate_shorad(self) -> None: def generate_shorad(self) -> None:
@ -523,9 +528,12 @@ class BaseDefenseGenerator:
g = SamGroundObject(namegen.random_objective_name(), group_id, g = SamGroundObject(namegen.random_objective_name(), group_id,
position, self.control_point, for_airbase=True) position, self.control_point, for_airbase=True)
group = generate_shorad_group(self.game, g, self.faction_name) group = generate_shorad_group(self.game, g, self.faction)
if group is not None: if group is None:
g.groups.append(group) logging.error(
f"Could not generate SHORAD group at {self.control_point}")
return
g.groups.append(group)
self.control_point.base_defenses.append(g) self.control_point.base_defenses.append(g)
@ -549,14 +557,14 @@ class AirbaseGroundObjectGenerator(ControlPointGroundObjectGenerator):
def generate_ground_points(self) -> None: def generate_ground_points(self) -> None:
"""Generate ground objects and AA sites for the control point.""" """Generate ground objects and AA sites for the control point."""
skip_sams = self.generate_required_aa()
if self.control_point.is_global: if self.control_point.is_global:
return return
# Always generate at least one AA point. # Always generate at least one AA point.
self.generate_aa_site() self.generate_aa_site()
skip_sams = self.generate_required_aa()
# And between 2 and 7 other objectives. # And between 2 and 7 other objectives.
amount = random.randrange(2, 7) amount = random.randrange(2, 7)
for i in range(amount): for i in range(amount):
@ -575,10 +583,13 @@ class AirbaseGroundObjectGenerator(ControlPointGroundObjectGenerator):
Returns: Returns:
The number of AA sites that were generated. The number of AA sites that were generated.
""" """
sams = self.control_point.preset_locations.required_sams presets = self.control_point.preset_locations
for position in sams: for position in presets.required_long_range_sams:
self.generate_aa_at(position) self.generate_aa_at(position, filter_names=LONG_RANGE_SAMS)
return len(sams) for position in presets.required_medium_range_sams:
self.generate_aa_at(position, filter_names=MEDIUM_RANGE_SAMS)
return (len(presets.required_long_range_sams) +
len(presets.required_medium_range_sams))
def generate_ground_point(self) -> None: def generate_ground_point(self) -> None:
try: try:
@ -620,14 +631,25 @@ class AirbaseGroundObjectGenerator(ControlPointGroundObjectGenerator):
return return
self.generate_aa_at(position) self.generate_aa_at(position)
def generate_aa_at(self, position: Point) -> None: def generate_aa_at(self, position: Point,
filter_names: Optional[Iterable[str]] = None) -> None:
group_id = self.game.next_group_id() group_id = self.game.next_group_id()
g = SamGroundObject(namegen.random_objective_name(), group_id, g = SamGroundObject(namegen.random_objective_name(), group_id,
position, self.control_point, for_airbase=False) position, self.control_point, for_airbase=False)
group = generate_anti_air_group(self.game, g, self.faction_name) group = generate_anti_air_group(self.game, g, self.faction,
if group is not None: filter_names)
g.groups = [group] if group is None:
location = f"{g.name} at {self.control_point}"
if filter_names is not None:
logging.warning(
"Could not generate SAM group for %s from types: %s",
location, ", ".join(filter_names)
)
else:
logging.error("Could not generate SAM group for %s", location)
return
g.groups = [group]
self.control_point.connected_objectives.append(g) self.control_point.connected_objectives.append(g)
def generate_missile_sites(self) -> None: def generate_missile_sites(self) -> None:

View File

@ -86,7 +86,7 @@ from dcs.planes import (
from pydcs_extensions.a4ec.a4ec import A_4E_C from pydcs_extensions.a4ec.a4ec import A_4E_C
from pydcs_extensions.f22a.f22a import F_22A from pydcs_extensions.f22a.f22a import F_22A
from pydcs_extensions.mb339.mb339 import MB_339PAN from pydcs_extensions.mb339.mb339 import MB_339PAN
from pydcs_extensions.rafale.rafale import Rafale_A_S, Rafale_M from pydcs_extensions.rafale.rafale import Rafale_A_S, Rafale_M, Rafale_B
# TODO: These lists really ought to be era (faction) dependent. # TODO: These lists really ought to be era (faction) dependent.
# Factions which have F-5s, F-86s, and A-4s will should prefer F-5s for CAP, but # Factions which have F-5s, F-86s, and A-4s will should prefer F-5s for CAP, but
@ -292,6 +292,7 @@ CAS_CAPABLE = [
A_4E_C, A_4E_C,
Rafale_A_S, Rafale_A_S,
Rafale_B,
WingLoong_I, WingLoong_I,
MQ_9_Reaper, MQ_9_Reaper,
@ -340,6 +341,7 @@ CAS_PREFERRED = [
A_4E_C, A_4E_C,
Rafale_A_S, Rafale_A_S,
Rafale_B,
WingLoong_I, WingLoong_I,
MQ_9_Reaper, MQ_9_Reaper,
@ -367,7 +369,8 @@ SEAD_CAPABLE = [
Tornado_GR4, Tornado_GR4,
A_4E_C, A_4E_C,
Rafale_A_S Rafale_A_S,
Rafale_B
] ]
SEAD_PREFERRED = [ SEAD_PREFERRED = [
@ -385,6 +388,7 @@ SEAD_PREFERRED = [
# Aircraft used for Strike mission # Aircraft used for Strike mission
STRIKE_CAPABLE = [ STRIKE_CAPABLE = [
MiG_15bis, MiG_15bis,
MiG_21Bis,
MiG_27K, MiG_27K,
MB_339PAN, MB_339PAN,
@ -452,7 +456,8 @@ STRIKE_CAPABLE = [
FW_190A8, FW_190A8,
A_4E_C, A_4E_C,
Rafale_A_S Rafale_A_S,
Rafale_B
] ]
@ -493,6 +498,7 @@ ANTISHIP_CAPABLE = [
Ju_88A4, Ju_88A4,
Rafale_A_S, Rafale_A_S,
Rafale_B
] ]
ANTISHIP_PREFERRED = [ ANTISHIP_PREFERRED = [
@ -500,6 +506,7 @@ ANTISHIP_PREFERRED = [
FA_18C_hornet, FA_18C_hornet,
JF_17, JF_17,
Rafale_A_S, Rafale_A_S,
Rafale_B,
Su_24M, Su_24M,
Su_30, Su_30,
Su_34, Su_34,

View File

@ -1,10 +1,11 @@
import random import random
from typing import List, Optional, Type from typing import Iterable, List, Optional, Type
from dcs.unitgroup import VehicleGroup from dcs.unitgroup import VehicleGroup
from dcs.vehicles import AirDefence from dcs.vehicles import AirDefence
from game import Game, db from game import Game
from game.factions.faction import Faction
from game.theater import TheaterGroundObject from game.theater import TheaterGroundObject
from game.theater.theatergroundobject import SamGroundObject from game.theater.theatergroundobject import SamGroundObject
from gen.sam.aaa_bofors import BoforsGenerator from gen.sam.aaa_bofors import BoforsGenerator
@ -90,6 +91,16 @@ SAM_MAP = {
"AllyWW2FlakGenerator": AllyWW2FlakGenerator "AllyWW2FlakGenerator": AllyWW2FlakGenerator
} }
#: Used to fill the long-range required SAM locations in the campaign.
LONG_RANGE_SAMS = {
"SA10Generator",
"PatriotGenerator",
}
#: Used to fill the medium-range required SAM location in the campaign.
MEDIUM_RANGE_SAMS = SAM_MAP.keys() - LONG_RANGE_SAMS
SAM_PRICES = { SAM_PRICES = {
AirDefence.SAM_Hawk_PCP: 35, AirDefence.SAM_Hawk_PCP: 35,
AirDefence.AAA_ZU_23_Emplacement: 10, AirDefence.AAA_ZU_23_Emplacement: 10,
@ -138,34 +149,41 @@ EWR_MAP = {
} }
def get_faction_possible_sams_generator(faction: str) -> List[Type[GroupGenerator]]: def get_faction_possible_sams_generator(
faction: Faction,
filter_names: Optional[Iterable[str]] = None
) -> List[Type[GroupGenerator]]:
"""
Return the list of possible SAM generator for the given faction
:param faction: Faction name to search units for
:param filter_names: Optional list of names to filter allowed SAMs by.
"""
return [SAM_MAP[s] for s in faction.sams if
filter_names is None or s in filter_names]
def get_faction_possible_ewrs_generator(faction: Faction) -> List[Type[GroupGenerator]]:
""" """
Return the list of possible SAM generator for the given faction Return the list of possible SAM generator for the given faction
:param faction: Faction name to search units for :param faction: Faction name to search units for
""" """
return [SAM_MAP[s] for s in db.FACTIONS[faction].sams if s in SAM_MAP] return [EWR_MAP[s] for s in faction.ewrs]
def get_faction_possible_ewrs_generator(faction: str) -> List[Type[GroupGenerator]]: def generate_anti_air_group(
""" game: Game, ground_object: TheaterGroundObject, faction: Faction,
Return the list of possible SAM generator for the given faction filter_names: Optional[Iterable[str]] = None) -> Optional[VehicleGroup]:
:param faction: Faction name to search units for
"""
return [EWR_MAP[s] for s in db.FACTIONS[faction].ewrs if s in EWR_MAP]
def generate_anti_air_group(game: Game, ground_object: TheaterGroundObject,
faction: str) -> Optional[VehicleGroup]:
""" """
This generate a SAM group This generate a SAM group
:param game: The Game. :param game: The Game.
:param ground_object: The ground object which will own the sam group. :param ground_object: The ground object which will own the sam group.
:param faction: Owner faction. :param faction: Owner faction.
:param filter_names: Optional list of names to filter allowed SAMs by.
:return: The generated group, or None if one could not be generated. :return: The generated group, or None if one could not be generated.
""" """
possible_sams_generators = get_faction_possible_sams_generator(faction) generators = get_faction_possible_sams_generator(faction, filter_names)
if len(possible_sams_generators) > 0: if len(generators) > 0:
sam_generator_class = random.choice(possible_sams_generators) sam_generator_class = random.choice(generators)
generator = sam_generator_class(game, ground_object) generator = sam_generator_class(game, ground_object)
generator.generate() generator.generate()
return generator.get_generated_group() return generator.get_generated_group()
@ -173,7 +191,7 @@ def generate_anti_air_group(game: Game, ground_object: TheaterGroundObject,
def generate_ewr_group(game: Game, ground_object: TheaterGroundObject, def generate_ewr_group(game: Game, ground_object: TheaterGroundObject,
faction: str) -> Optional[VehicleGroup]: faction: Faction) -> Optional[VehicleGroup]:
"""Generates an early warning radar group. """Generates an early warning radar group.
:param game: The Game. :param game: The Game.
@ -191,13 +209,11 @@ def generate_ewr_group(game: Game, ground_object: TheaterGroundObject,
def generate_shorad_group(game: Game, ground_object: SamGroundObject, def generate_shorad_group(game: Game, ground_object: SamGroundObject,
faction_name: str) -> Optional[VehicleGroup]: faction: Faction) -> Optional[VehicleGroup]:
faction = db.FACTIONS[faction_name]
if len(faction.shorads) > 0: if len(faction.shorads) > 0:
sam = random.choice(faction.shorads) sam = random.choice(faction.shorads)
generator = SAM_MAP[sam](game, ground_object) generator = SAM_MAP[sam](game, ground_object)
generator.generate() generator.generate()
return generator.get_generated_group() return generator.get_generated_group()
else: else:
return generate_anti_air_group(game, ground_object, faction_name) return generate_anti_air_group(game, ground_object, faction)

View File

@ -2,11 +2,11 @@ from pydcs_extensions.a4ec.a4ec import A_4E_C
from pydcs_extensions.f22a.f22a import F_22A from pydcs_extensions.f22a.f22a import F_22A
from pydcs_extensions.highdigitsams import highdigitsams from pydcs_extensions.highdigitsams import highdigitsams
from pydcs_extensions.mb339.mb339 import MB_339PAN from pydcs_extensions.mb339.mb339 import MB_339PAN
from pydcs_extensions.rafale.rafale import Rafale_M, Rafale_A_S from pydcs_extensions.rafale.rafale import Rafale_M, Rafale_A_S, Rafale_B
from pydcs_extensions.su57.su57 import Su_57 from pydcs_extensions.su57.su57 import Su_57
import pydcs_extensions.frenchpack.frenchpack as frenchpack import pydcs_extensions.frenchpack.frenchpack as frenchpack
MODDED_AIRPLANES = [A_4E_C, MB_339PAN, Rafale_A_S, Rafale_M, Su_57, F_22A] MODDED_AIRPLANES = [A_4E_C, MB_339PAN, Rafale_A_S, Rafale_M, Rafale_B, Su_57, F_22A]
MODDED_VEHICLES = [ MODDED_VEHICLES = [
frenchpack._FIELD_HIDE, frenchpack._FIELD_HIDE,
frenchpack._FIELD_HIDE_SMALL, frenchpack._FIELD_HIDE_SMALL,

File diff suppressed because it is too large Load Diff

View File

@ -128,7 +128,7 @@ def parse_args() -> argparse.Namespace:
def create_game(campaign_path: Path, blue: str, red: str, def create_game(campaign_path: Path, blue: str, red: str,
supercarrier: bool) -> Game: supercarrier: bool) -> Game:
campaign = Campaign.from_json(campaign_path) campaign = Campaign.from_json(campaign_path)
generator = GameGenerator(blue, red, campaign.theater, generator = GameGenerator(blue, red, campaign.load_theater(),
Settings(supercarrier=supercarrier), Settings(supercarrier=supercarrier),
start_date=datetime.today(), start_date=datetime.today(),
starting_budget=650, starting_budget=650,

View File

@ -18,6 +18,7 @@ class QBudgetBox(QGroupBox):
self.money_amount = QLabel() self.money_amount = QLabel()
self.finances = QPushButton("Details") self.finances = QPushButton("Details")
self.finances.setDisabled(True)
self.finances.setProperty("style", "btn-primary") self.finances.setProperty("style", "btn-primary")
self.finances.clicked.connect(self.openFinances) self.finances.clicked.connect(self.openFinances)
@ -36,8 +37,12 @@ class QBudgetBox(QGroupBox):
self.money_amount.setText(str(budget) + "M (+" + str(reward) + "M)") self.money_amount.setText(str(budget) + "M (+" + str(reward) + "M)")
def setGame(self, game): def setGame(self, game):
if game is None:
return
self.game = game self.game = game
self.setBudget(self.game.budget, self.game.budget_reward_amount) self.setBudget(self.game.budget, self.game.budget_reward_amount)
self.finances.setEnabled(True)
def openFinances(self): def openFinances(self):
self.subwindow = QFinancesMenu(self.game) self.subwindow = QFinancesMenu(self.game)

View File

@ -60,11 +60,13 @@ class QTopPanel(QFrame):
self.factionsInfos = QFactionsInfos(self.game) self.factionsInfos = QFactionsInfos(self.game)
self.settings = QPushButton("Settings") self.settings = QPushButton("Settings")
self.settings.setDisabled(True)
self.settings.setIcon(CONST.ICONS["Settings"]) self.settings.setIcon(CONST.ICONS["Settings"])
self.settings.setProperty("style", "btn-primary") self.settings.setProperty("style", "btn-primary")
self.settings.clicked.connect(self.openSettings) self.settings.clicked.connect(self.openSettings)
self.statistics = QPushButton("Statistics") self.statistics = QPushButton("Statistics")
self.statistics.setDisabled(True)
self.statistics.setIcon(CONST.ICONS["Statistics"]) self.statistics.setIcon(CONST.ICONS["Statistics"])
self.statistics.setProperty("style", "btn-primary") self.statistics.setProperty("style", "btn-primary")
self.statistics.clicked.connect(self.openStatisticsWindow) self.statistics.clicked.connect(self.openStatisticsWindow)
@ -100,6 +102,9 @@ class QTopPanel(QFrame):
if game is None: if game is None:
return return
self.settings.setEnabled(True)
self.statistics.setEnabled(True)
self.conditionsWidget.setCurrentTurn(game.turn, game.conditions) self.conditionsWidget.setCurrentTurn(game.turn, game.conditions)
self.budgetBox.setGame(game) self.budgetBox.setGame(game)
self.factionsInfos.setGame(game) self.factionsInfos.setGame(game)

View File

@ -248,7 +248,7 @@ class QBuyGroupForGroundObjectDialog(QDialog):
self.init_ui() self.init_ui()
def init_ui(self): def init_ui(self):
faction = self.game.player_name faction = self.game.player_faction
# Sams # Sams
@ -268,7 +268,7 @@ class QBuyGroupForGroundObjectDialog(QDialog):
# Armored units # Armored units
armored_units = db.find_unittype(PinpointStrike, faction) # Todo : refactor this legacy nonsense armored_units = db.find_unittype(PinpointStrike, faction.name) # Todo : refactor this legacy nonsense
for unit in set(armored_units): for unit in set(armored_units):
self.buyArmorCombo.addItem(db.unit_type_name_2(unit) + " [$" + str(db.PRICES[unit]) + "M]", userData=unit) self.buyArmorCombo.addItem(db.unit_type_name_2(unit) + " [$" + str(db.PRICES[unit]) + "M]", userData=unit)
self.buyArmorCombo.currentIndexChanged.connect(self.armorComboChanged) self.buyArmorCombo.currentIndexChanged.connect(self.armorComboChanged)

View File

@ -8,5 +8,5 @@ class QInfoItem(QStandardItem):
def __init__(self, info: Information): def __init__(self, info: Information):
super(QInfoItem, self).__init__() super(QInfoItem, self).__init__()
self.info = info self.info = info
self.setText("[%02d]" % self.info.turn + " " + self.info.title + ' : {:<16}'.format(info.text)) self.setText(str(info))
self.setEditable(False) self.setEditable(False)

View File

@ -4,7 +4,7 @@ import json
import logging import logging
from dataclasses import dataclass from dataclasses import dataclass
from pathlib import Path from pathlib import Path
from typing import List from typing import Any, Dict, List
from PySide2 import QtGui from PySide2 import QtGui
from PySide2.QtCore import QItemSelectionModel from PySide2.QtCore import QItemSelectionModel
@ -21,7 +21,8 @@ class Campaign:
icon_name: str icon_name: str
authors: str authors: str
description: str description: str
theater: ConflictTheater data: Dict[str, Any]
path: Path
@classmethod @classmethod
def from_json(cls, path: Path) -> Campaign: def from_json(cls, path: Path) -> Campaign:
@ -29,10 +30,17 @@ class Campaign:
data = json.load(campaign_file) data = json.load(campaign_file)
sanitized_theater = data["theater"].replace(" ", "") sanitized_theater = data["theater"].replace(" ", "")
return cls(data["name"], f"Terrain_{sanitized_theater}", return cls(
data.get("authors", "???"), data["name"],
data.get("description", ""), f"Terrain_{sanitized_theater}",
ConflictTheater.from_json(path.parent, data)) data.get("authors", "???"),
data.get("description", ""),
data,
path
)
def load_theater(self) -> ConflictTheater:
return ConflictTheater.from_json(self.path.parent, self.data)
def load_campaigns() -> List[Campaign]: def load_campaigns() -> List[Campaign]:

View File

@ -58,7 +58,7 @@ class NewGameWizard(QtWidgets.QWizard):
if selectedCampaign is None: if selectedCampaign is None:
selectedCampaign = self.campaigns[0] selectedCampaign = self.campaigns[0]
conflictTheater = selectedCampaign.theater conflictTheater = selectedCampaign.load_theater()
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")

View File

@ -2,38 +2,14 @@ local unitPayloads = {
["name"] = "Rafale_A_S", ["name"] = "Rafale_A_S",
["payloads"] = { ["payloads"] = {
[1] = { [1] = {
["name"] = "CAP",
["pylons"] = {
[1] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}",
["num"] = 10,
},
[2] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}",
["num"] = 1,
},
[3] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}",
["num"] = 6,
},
[4] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}",
["num"] = 4,
},
},
["tasks"] = {
[1] = 11,
},
},
[2] = {
["name"] = "CAS", ["name"] = "CAS",
["pylons"] = { ["pylons"] = {
[1] = { [1] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 10, ["num"] = 10,
}, },
[2] = { [2] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 1, ["num"] = 1,
}, },
[3] = { [3] = {
@ -73,15 +49,15 @@ local unitPayloads = {
[1] = 11, [1] = 11,
}, },
}, },
[3] = { [2] = {
["name"] = "ANTISHIP", ["name"] = "ANTISHIP",
["pylons"] = { ["pylons"] = {
[1] = { [1] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 10, ["num"] = 10,
}, },
[2] = { [2] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 1, ["num"] = 1,
}, },
[3] = { [3] = {
@ -121,15 +97,39 @@ local unitPayloads = {
[1] = 11, [1] = 11,
}, },
}, },
[3] = {
["name"] = "CAP",
["pylons"] = {
[1] = {
["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 10,
},
[2] = {
["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 1,
},
[3] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}",
["num"] = 6,
},
[4] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}",
["num"] = 4,
},
},
["tasks"] = {
[1] = 11,
},
},
[4] = { [4] = {
["name"] = "SEAD", ["name"] = "SEAD",
["pylons"] = { ["pylons"] = {
[1] = { [1] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 10, ["num"] = 10,
}, },
[2] = { [2] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 1, ["num"] = 1,
}, },
[3] = { [3] = {
@ -173,11 +173,11 @@ local unitPayloads = {
["name"] = "STRIKE", ["name"] = "STRIKE",
["pylons"] = { ["pylons"] = {
[1] = { [1] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 10, ["num"] = 10,
}, },
[2] = { [2] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 1, ["num"] = 1,
}, },
[3] = { [3] = {
@ -193,11 +193,11 @@ local unitPayloads = {
["num"] = 9, ["num"] = 9,
}, },
[6] = { [6] = {
["CLSID"] = "{SCALP}", ["CLSID"] = "{GBU_49}",
["num"] = 8, ["num"] = 8,
}, },
[7] = { [7] = {
["CLSID"] = "{SCALP}", ["CLSID"] = "{GBU_49}",
["num"] = 3, ["num"] = 3,
}, },
[8] = { [8] = {

View File

@ -0,0 +1,265 @@
local unitPayloads = {
["name"] = "Rafale_B",
["payloads"] = {
[1] = {
["name"] = "CAP",
["pylons"] = {
[1] = {
["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 10,
},
[2] = {
["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 1,
},
[3] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}",
["num"] = 6,
},
[4] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}",
["num"] = 4,
},
},
["tasks"] = {
[1] = 32,
},
},
[2] = {
["name"] = "CAS",
["pylons"] = {
[1] = {
["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 10,
},
[2] = {
["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 1,
},
[3] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}",
["num"] = 6,
},
[4] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}",
["num"] = 4,
},
[5] = {
["CLSID"] = "{DAMOCLES}",
["num"] = 7,
},
[6] = {
["CLSID"] = "{AS_30L}",
["num"] = 8,
},
[7] = {
["CLSID"] = "{AS_30L}",
["num"] = 3,
},
[8] = {
["CLSID"] = "{AS_30L}",
["num"] = 2,
},
[9] = {
["CLSID"] = "{AS_30L}",
["num"] = 9,
},
},
["tasks"] = {
[1] = 32,
},
},
[3] = {
["name"] = "ANTISHIP",
["pylons"] = {
[1] = {
["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 10,
},
[2] = {
["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 1,
},
[3] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}",
["num"] = 6,
},
[4] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}",
["num"] = 4,
},
[5] = {
["CLSID"] = "{DAMOCLES}",
["num"] = 7,
},
[6] = {
["CLSID"] = "{AS_30L}",
["num"] = 8,
},
[7] = {
["CLSID"] = "{AS_30L}",
["num"] = 3,
},
[8] = {
["CLSID"] = "{AS_30L}",
["num"] = 2,
},
[9] = {
["CLSID"] = "{AS_30L}",
["num"] = 9,
},
[10] = {
["CLSID"] = "{Exocet}",
["num"] = 5,
},
},
["tasks"] = {
[1] = 32,
},
},
[4] = {
["name"] = "SEAD",
["pylons"] = {
[1] = {
["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 10,
},
[2] = {
["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 1,
},
[3] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}",
["num"] = 6,
},
[4] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}",
["num"] = 4,
},
[5] = {
["CLSID"] = "{DAMOCLES}",
["num"] = 7,
},
[6] = {
["CLSID"] = "{B06DD79A-F21E-4EB9-BD9D-AB3844618C93}",
["num"] = 8,
},
[7] = {
["CLSID"] = "{B06DD79A-F21E-4EB9-BD9D-AB3844618C93}",
["num"] = 3,
},
[8] = {
["CLSID"] = "{B06DD79A-F21E-4EB9-BD9D-AB3844618C93}",
["num"] = 2,
},
[9] = {
["CLSID"] = "{B06DD79A-F21E-4EB9-BD9D-AB3844618C93}",
["num"] = 9,
},
[10] = {
["CLSID"] = "{SCALP}",
["num"] = 5,
},
},
["tasks"] = {
[1] = 32,
},
},
[5] = {
["name"] = "BAI",
["pylons"] = {
[1] = {
["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 10,
},
[2] = {
["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 1,
},
[3] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}",
["num"] = 6,
},
[4] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}",
["num"] = 4,
},
[5] = {
["CLSID"] = "{DAMOCLES}",
["num"] = 7,
},
[6] = {
["CLSID"] = "{AS_30L}",
["num"] = 8,
},
[7] = {
["CLSID"] = "{AS_30L}",
["num"] = 3,
},
[8] = {
["CLSID"] = "{AS_30L}",
["num"] = 2,
},
[9] = {
["CLSID"] = "{AS_30L}",
["num"] = 9,
},
},
["tasks"] = {
[1] = 32,
},
},
[6] = {
["name"] = "STRIKE",
["pylons"] = {
[1] = {
["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 10,
},
[2] = {
["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 1,
},
[3] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}",
["num"] = 6,
},
[4] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}",
["num"] = 4,
},
[5] = {
["CLSID"] = "{DAMOCLES}",
["num"] = 7,
},
[6] = {
["CLSID"] = "{GBU_49}",
["num"] = 8,
},
[7] = {
["CLSID"] = "{GBU_49}",
["num"] = 3,
},
[8] = {
["CLSID"] = "{GBU_49}",
["num"] = 2,
},
[9] = {
["CLSID"] = "{GBU_49}",
["num"] = 9,
},
[10] = {
["CLSID"] = "{GBU_49}",
["num"] = 5,
},
},
["tasks"] = {
[1] = 32,
},
},
},
["tasks"] = {
},
["unitType"] = "Rafale_B",
}
return unitPayloads

View File

@ -2,10 +2,10 @@ local unitPayloads = {
["name"] = "Rafale_M", ["name"] = "Rafale_M",
["payloads"] = { ["payloads"] = {
[1] = { [1] = {
["name"] = "CAP", ["name"] = "CAS",
["pylons"] = { ["pylons"] = {
[1] = { [1] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 10, ["num"] = 10,
}, },
[2] = { [2] = {
@ -13,15 +13,15 @@ local unitPayloads = {
["num"] = 1, ["num"] = 1,
}, },
[3] = { [3] = {
["CLSID"] = "LAU-115_2*LAU-127_AIM-120C", ["CLSID"] = "LAU3_HE5",
["num"] = 2, ["num"] = 2,
}, },
[4] = { [4] = {
["CLSID"] = "LAU-115_2*LAU-127_AIM-120C", ["CLSID"] = "LAU3_HE5",
["num"] = 9, ["num"] = 9,
}, },
[5] = { [5] = {
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", ["CLSID"] = "LAU3_WP156",
["num"] = 8, ["num"] = 8,
}, },
[6] = { [6] = {
@ -29,39 +29,47 @@ local unitPayloads = {
["num"] = 6, ["num"] = 6,
}, },
[7] = { [7] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", ["CLSID"] = "{RAFALE_MBDA_METEOR}",
["num"] = 5, ["num"] = 5,
}, },
[8] = { [8] = {
["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", ["CLSID"] = "LAU3_WP156",
["num"] = 3, ["num"] = 3,
}, },
[9] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}",
["num"] = 4,
},
[10] = {
["CLSID"] = "{DAMOCLES}",
["num"] = 7,
},
}, },
["tasks"] = { ["tasks"] = {
[1] = 11, [1] = 11,
}, },
}, },
[2] = { [2] = {
["name"] = "CAS", ["name"] = "STRIKE",
["pylons"] = { ["pylons"] = {
[1] = { [1] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 10, ["num"] = 10,
}, },
[2] = { [2] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 1, ["num"] = 1,
}, },
[3] = { [3] = {
["CLSID"] = "LAU3_HE5", ["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}",
["num"] = 2, ["num"] = 2,
}, },
[4] = { [4] = {
["CLSID"] = "LAU3_HE5", ["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}",
["num"] = 9, ["num"] = 9,
}, },
[5] = { [5] = {
["CLSID"] = "LAU3_WP156", ["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}",
["num"] = 8, ["num"] = 8,
}, },
[6] = { [6] = {
@ -69,39 +77,47 @@ local unitPayloads = {
["num"] = 6, ["num"] = 6,
}, },
[7] = { [7] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", ["CLSID"] = "{RAFALE_MBDA_METEOR}",
["num"] = 5, ["num"] = 5,
}, },
[8] = { [8] = {
["CLSID"] = "LAU3_WP156", ["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}",
["num"] = 3, ["num"] = 3,
}, },
[9] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}",
["num"] = 4,
},
[10] = {
["CLSID"] = "{DAMOCLES}",
["num"] = 7,
},
}, },
["tasks"] = { ["tasks"] = {
[1] = 11, [1] = 11,
}, },
}, },
[3] = { [3] = {
["name"] = "STRIKE", ["name"] = "CAP",
["pylons"] = { ["pylons"] = {
[1] = { [1] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 10, ["num"] = 10,
}, },
[2] = { [2] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 1, ["num"] = 1,
}, },
[3] = { [3] = {
["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", ["CLSID"] = "{RAFALE_MBDA_METEOR}",
["num"] = 2, ["num"] = 2,
}, },
[4] = { [4] = {
["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", ["CLSID"] = "{RAFALE_MBDA_METEOR}",
["num"] = 9, ["num"] = 9,
}, },
[5] = { [5] = {
["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", ["CLSID"] = "{RAFALE_MBDA_METEOR}",
["num"] = 8, ["num"] = 8,
}, },
[6] = { [6] = {
@ -109,13 +125,17 @@ local unitPayloads = {
["num"] = 6, ["num"] = 6,
}, },
[7] = { [7] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", ["CLSID"] = "{RAFALE_MBDA_METEOR}",
["num"] = 5, ["num"] = 5,
}, },
[8] = { [8] = {
["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", ["CLSID"] = "{RAFALE_MBDA_METEOR}",
["num"] = 3, ["num"] = 3,
}, },
[9] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}",
["num"] = 4,
},
}, },
["tasks"] = { ["tasks"] = {
[1] = 11, [1] = 11,
@ -125,11 +145,11 @@ local unitPayloads = {
["name"] = "SEAD", ["name"] = "SEAD",
["pylons"] = { ["pylons"] = {
[1] = { [1] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 10, ["num"] = 10,
}, },
[2] = { [2] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 1, ["num"] = 1,
}, },
[3] = { [3] = {
@ -149,13 +169,21 @@ local unitPayloads = {
["num"] = 6, ["num"] = 6,
}, },
[7] = { [7] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", ["CLSID"] = "{RAFALE_MBDA_METEOR}",
["num"] = 5, ["num"] = 5,
}, },
[8] = { [8] = {
["CLSID"] = "{D5D51E24-348C-4702-96AF-97A714E72697}", ["CLSID"] = "{D5D51E24-348C-4702-96AF-97A714E72697}",
["num"] = 3, ["num"] = 3,
}, },
[9] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}",
["num"] = 4,
},
[10] = {
["CLSID"] = "{DAMOCLES}",
["num"] = 7,
},
}, },
["tasks"] = { ["tasks"] = {
[1] = 11, [1] = 11,
@ -165,11 +193,11 @@ local unitPayloads = {
["name"] = "ANTISHIP", ["name"] = "ANTISHIP",
["pylons"] = { ["pylons"] = {
[1] = { [1] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 10, ["num"] = 10,
}, },
[2] = { [2] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 1, ["num"] = 1,
}, },
[3] = { [3] = {
@ -189,13 +217,69 @@ local unitPayloads = {
["num"] = 6, ["num"] = 6,
}, },
[7] = { [7] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", ["CLSID"] = "{RAFALE_MBDA_METEOR}",
["num"] = 5, ["num"] = 5,
}, },
[8] = { [8] = {
["CLSID"] = "{18617C93-78E7-4359-A8CE-D754103EDF63}", ["CLSID"] = "{18617C93-78E7-4359-A8CE-D754103EDF63}",
["num"] = 3, ["num"] = 3,
}, },
[9] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}",
["num"] = 4,
},
[10] = {
["CLSID"] = "{DAMOCLES}",
["num"] = 7,
},
},
["tasks"] = {
[1] = 11,
},
},
[6] = {
["name"] = "BAI",
["pylons"] = {
[1] = {
["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 10,
},
[2] = {
["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
["num"] = 1,
},
[3] = {
["CLSID"] = "{60CC734F-0AFA-4E2E-82B8-93B941AB11CF}",
["num"] = 2,
},
[4] = {
["CLSID"] = "{60CC734F-0AFA-4E2E-82B8-93B941AB11CF}",
["num"] = 3,
},
[5] = {
["CLSID"] = "{60CC734F-0AFA-4E2E-82B8-93B941AB11CF}",
["num"] = 8,
},
[6] = {
["CLSID"] = "{60CC734F-0AFA-4E2E-82B8-93B941AB11CF}",
["num"] = 9,
},
[7] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}",
["num"] = 6,
},
[8] = {
["CLSID"] = "{RAFALE_MBDA_METEOR}",
["num"] = 5,
},
[9] = {
["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}",
["num"] = 4,
},
[10] = {
["CLSID"] = "{DAMOCLES}",
["num"] = 7,
},
}, },
["tasks"] = { ["tasks"] = {
[1] = 11, [1] = 11,

View File

@ -69,13 +69,14 @@
"frenchpack V3.5": "https://forums.eagle.ru/showthread.php?t=279974" "frenchpack V3.5": "https://forums.eagle.ru/showthread.php?t=279974"
}, },
"carrier_names": [ "carrier_names": [
"R91 Charles de Gaulle"
],
"helicopter_carrier_names": [
"R97 Jeanne d'Arc",
"L9013 Mistral", "L9013 Mistral",
"L9014 Tonerre", "L9014 Tonerre",
"L9015 Dixmude" "L9015 Dixmude"
], ],
"helicopter_carrier_names": [
"Jeanne d'Arc"
],
"navy_generators": [ "navy_generators": [
"ArleighBurkeGroupGenerator" "ArleighBurkeGroupGenerator"
], ],

View File

@ -8,6 +8,7 @@
"Mirage_2000_5", "Mirage_2000_5",
"Rafale_M", "Rafale_M",
"Rafale_A_S", "Rafale_A_S",
"Rafale_B",
"SA342M", "SA342M",
"SA342L", "SA342L",
"SA342Mistral" "SA342Mistral"
@ -71,16 +72,17 @@
], ],
"requirements": { "requirements": {
"frenchpack V3.5": "https://forums.eagle.ru/showthread.php?t=279974", "frenchpack V3.5": "https://forums.eagle.ru/showthread.php?t=279974",
"RAFALE 2.5.5": "https://www.digitalcombatsimulator.com/fr/files/3307478/" "RAFALE 2.5.6": "https://forums.eagle.ru/forum/english/dcs-world-topics/mods-and-apps/dcs-mods/7135261-download-rafales-pack-2-5-6-55960-and-openbeta-2-5-6-57530-by-cuesta-brothers"
}, },
"carrier_names": [ "carrier_names": [
"R91 Charles de Gaulle"
],
"helicopter_carrier_names": [
"R97 Jeanne d'Arc",
"L9013 Mistral", "L9013 Mistral",
"L9014 Tonerre", "L9014 Tonerre",
"L9015 Dixmude" "L9015 Dixmude"
], ],
"helicopter_carrier_names": [
"Jeanne d'Arc"
],
"navy_generators": [ "navy_generators": [
"ArleighBurkeGroupGenerator" "ArleighBurkeGroupGenerator"
], ],

View File

@ -20,7 +20,7 @@
"MBT_T_55" "MBT_T_55"
], ],
"artillery_units": [ "artillery_units": [
"MLRS_BM21_Grad", "MLRS_BM_21_Grad",
"SPH_2S1_Gvozdika", "SPH_2S1_Gvozdika",
"SPH_2S3_Akatsia" "SPH_2S3_Akatsia"
], ],

View File

@ -49,7 +49,6 @@
"AvengerGenerator" "AvengerGenerator"
], ],
"sams": [ "sams": [
"HawkGenerator",
"PatriotGenerator" "PatriotGenerator"
], ],
"ewrs": [ "ewrs": [

View File

@ -1,7 +1,3 @@
<strong>Author(s): {{ campaign.authors }}</strong> <strong>Author(s): {{ campaign.authors }}</strong>
<br/>
<br/>
<strong>Number of control points:</strong> {{ campaign.theater.controlpoints|length }}
<br/>
{{ campaign.description|safe }} {{ campaign.description|safe }}

View File

@ -1,7 +1,3 @@
<strong>Auteur(s) : {{ campaign.authors }}</strong> <strong>Auteur(s) : {{ campaign.authors }}</strong>
<br/>
<br/>
<strong>Nombre de points :</strong> {{ campaign.theater.controlpoints|length }}
<br/>
{{ campaign.description|safe }} {{ campaign.description|safe }}