mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
Allow in-line definitions of campaign factions.
A lot of campaigns want to define custom factions. This allows them to do so without us having to fill the built-in factions list with a bunch of campaign-specific factions. It also makes custom campaigns more portable as they don't need to also distribute the custom faction files.
This commit is contained in:
parent
dca256364a
commit
1ac36d03da
@ -13,6 +13,7 @@ Saves from 6.x are not compatible with 7.0.
|
||||
* **[Modding]** Updated Community A-4E-C mod version support to 2.1.0 release.
|
||||
* **[Modding]** Add support for VSN F-4B and F-4C mod.
|
||||
* **[Modding]** Custom factions can now be defined in YAML as well as JSON. JSON support may be removed in the future if having both formats causes confusion.
|
||||
* **[Modding]** Campaigns which require custom factions can now define those factions directly in the campaign YAML. See Operation Aliied Sword for an example.
|
||||
|
||||
## Fixes
|
||||
|
||||
|
||||
@ -5,22 +5,24 @@ import logging
|
||||
from collections.abc import Iterator
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, Tuple
|
||||
from typing import Any, Dict, TYPE_CHECKING, Tuple
|
||||
|
||||
import yaml
|
||||
from packaging.version import Version
|
||||
|
||||
from game import persistence
|
||||
from game.profiling import logged_duration
|
||||
from game.theater import (
|
||||
ConflictTheater,
|
||||
)
|
||||
from game.theater import ConflictTheater
|
||||
from game.theater.iadsnetwork.iadsnetwork import IadsNetwork
|
||||
from game.theater.theaterloader import TheaterLoader
|
||||
from game.version import CAMPAIGN_FORMAT_VERSION
|
||||
from .campaignairwingconfig import CampaignAirWingConfig
|
||||
from .factionrecommendation import FactionRecommendation
|
||||
from .mizcampaignloader import MizCampaignLoader
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game.factions.factions import Factions
|
||||
|
||||
PERF_FRIENDLY = 0
|
||||
PERF_MEDIUM = 1
|
||||
PERF_HARD = 2
|
||||
@ -40,8 +42,8 @@ class Campaign:
|
||||
#: selecting a campaign that is not up to date.
|
||||
version: Tuple[int, int]
|
||||
|
||||
recommended_player_faction: str
|
||||
recommended_enemy_faction: str
|
||||
recommended_player_faction: FactionRecommendation
|
||||
recommended_enemy_faction: FactionRecommendation
|
||||
recommended_start_date: datetime.date | None
|
||||
recommended_start_time: datetime.time | None
|
||||
|
||||
@ -60,7 +62,6 @@ class Campaign:
|
||||
with path.open(encoding="utf-8") as campaign_file:
|
||||
data = yaml.safe_load(campaign_file)
|
||||
|
||||
sanitized_theater = data["theater"].replace(" ", "")
|
||||
version_field = data.get("version", "0")
|
||||
try:
|
||||
version = Version(version_field)
|
||||
@ -93,8 +94,12 @@ class Campaign:
|
||||
data.get("authors", "???"),
|
||||
data.get("description", ""),
|
||||
(version.major, version.minor),
|
||||
data.get("recommended_player_faction", "USA 2005"),
|
||||
data.get("recommended_enemy_faction", "Russia 1990"),
|
||||
FactionRecommendation.from_field(
|
||||
data.get("recommended_player_faction"), player=True
|
||||
),
|
||||
FactionRecommendation.from_field(
|
||||
data.get("recommended_enemy_faction"), player=False
|
||||
),
|
||||
start_date,
|
||||
start_time,
|
||||
data.get("recommended_player_money", DEFAULT_BUDGET),
|
||||
@ -163,6 +168,10 @@ class Campaign:
|
||||
return False
|
||||
return True
|
||||
|
||||
def register_campaign_specific_factions(self, factions: Factions) -> None:
|
||||
self.recommended_player_faction.register_campaign_specific_faction(factions)
|
||||
self.recommended_enemy_faction.register_campaign_specific_faction(factions)
|
||||
|
||||
@staticmethod
|
||||
def iter_campaigns_in_dir(path: Path) -> Iterator[Path]:
|
||||
yield from path.glob("*.yaml")
|
||||
|
||||
53
game/campaignloader/factionrecommendation.py
Normal file
53
game/campaignloader/factionrecommendation.py
Normal file
@ -0,0 +1,53 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Any, TYPE_CHECKING
|
||||
|
||||
from game.factions import Faction
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game.factions.factions import Factions
|
||||
|
||||
|
||||
class FactionRecommendation(ABC):
|
||||
def __init__(self, name: str) -> None:
|
||||
self.name = name
|
||||
|
||||
@abstractmethod
|
||||
def register_campaign_specific_faction(self, factions: Factions) -> None:
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def get_faction(self, factions: Factions) -> Faction:
|
||||
...
|
||||
|
||||
@staticmethod
|
||||
def from_field(
|
||||
data: str | dict[str, Any] | None, player: bool
|
||||
) -> FactionRecommendation:
|
||||
if data is None:
|
||||
name = "USA 2005" if player else "Russia 1990"
|
||||
return BuiltinFactionRecommendation(name)
|
||||
if isinstance(data, str):
|
||||
return BuiltinFactionRecommendation(data)
|
||||
return CampaignDefinedFactionRecommendation(Faction.from_dict(data))
|
||||
|
||||
|
||||
class BuiltinFactionRecommendation(FactionRecommendation):
|
||||
def register_campaign_specific_faction(self, factions: Factions) -> None:
|
||||
pass
|
||||
|
||||
def get_faction(self, factions: Factions) -> Faction:
|
||||
return factions.get_by_name(self.name)
|
||||
|
||||
|
||||
class CampaignDefinedFactionRecommendation(FactionRecommendation):
|
||||
def __init__(self, faction: Faction) -> None:
|
||||
super().__init__(faction.name)
|
||||
self.faction = faction
|
||||
|
||||
def register_campaign_specific_faction(self, factions: Factions) -> None:
|
||||
factions.add_campaign_defined(self.faction)
|
||||
|
||||
def get_faction(self, factions: Factions) -> Faction:
|
||||
return self.faction
|
||||
@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import itertools
|
||||
import json
|
||||
import logging
|
||||
from collections.abc import Iterator
|
||||
@ -14,12 +15,29 @@ from .faction import Faction
|
||||
class Factions:
|
||||
def __init__(self, factions: dict[str, Faction]) -> None:
|
||||
self.factions = factions
|
||||
self.campaign_defined_factions: dict[str, Faction] = {}
|
||||
|
||||
def get_by_name(self, name: str) -> Faction:
|
||||
return self.factions[name]
|
||||
try:
|
||||
return self.factions[name]
|
||||
except KeyError:
|
||||
return self.campaign_defined_factions[name]
|
||||
|
||||
def iter_faction_names(self) -> Iterator[str]:
|
||||
return iter(self.factions.keys())
|
||||
# Campaign defined factions first so they show up at the top of the list in the
|
||||
# UI.
|
||||
return itertools.chain(self.campaign_defined_factions, self.factions)
|
||||
|
||||
def add_campaign_defined(self, faction: Faction) -> None:
|
||||
if (
|
||||
faction.name in self.factions
|
||||
or faction.name in self.campaign_defined_factions
|
||||
):
|
||||
raise KeyError(f"Duplicate faction {faction.name}")
|
||||
self.campaign_defined_factions[faction.name] = faction
|
||||
|
||||
def reset_campaign_defined(self) -> None:
|
||||
self.campaign_defined_factions = {}
|
||||
|
||||
@staticmethod
|
||||
def iter_faction_files_in(path: Path) -> Iterator[Path]:
|
||||
|
||||
@ -169,4 +169,7 @@ VERSION = _build_version_string()
|
||||
#:
|
||||
#: Version 10.5
|
||||
#: * Support for scenery objectives defined by quad zones.
|
||||
CAMPAIGN_FORMAT_VERSION = (10, 5)
|
||||
#:
|
||||
#: Version 10.6
|
||||
#: * Support in-line definitions of campaign-specific factions.
|
||||
CAMPAIGN_FORMAT_VERSION = (10, 6)
|
||||
|
||||
@ -83,9 +83,11 @@ class NewGameWizard(QtWidgets.QWizard):
|
||||
def __init__(self, parent=None):
|
||||
super(NewGameWizard, self).__init__(parent)
|
||||
|
||||
factions = Factions.load()
|
||||
|
||||
self.campaigns = list(sorted(Campaign.load_each(), key=lambda x: x.name))
|
||||
|
||||
self.faction_selection_page = FactionSelection()
|
||||
self.faction_selection_page = FactionSelection(factions)
|
||||
self.addPage(IntroPage())
|
||||
self.theater_page = TheaterConfiguration(
|
||||
self.campaigns, self.faction_selection_page
|
||||
@ -222,10 +224,10 @@ class IntroPage(QtWidgets.QWizardPage):
|
||||
|
||||
|
||||
class FactionSelection(QtWidgets.QWizardPage):
|
||||
def __init__(self, parent=None):
|
||||
super(FactionSelection, self).__init__(parent)
|
||||
def __init__(self, factions: Factions, parent=None) -> None:
|
||||
super().__init__(parent)
|
||||
|
||||
self.factions = Factions.load()
|
||||
self.factions = factions
|
||||
|
||||
self.setTitle("Faction selection")
|
||||
self.setSubTitle(
|
||||
@ -308,15 +310,15 @@ class FactionSelection(QtWidgets.QWizardPage):
|
||||
self.blueFactionSelect.clear()
|
||||
self.redFactionSelect.clear()
|
||||
|
||||
for f in self.factions.iter_faction_names():
|
||||
self.blueFactionSelect.addItem(f)
|
||||
self.factions.reset_campaign_defined()
|
||||
campaign.register_campaign_specific_factions(self.factions)
|
||||
|
||||
for i, r in enumerate(self.factions.iter_faction_names()):
|
||||
self.redFactionSelect.addItem(r)
|
||||
if r == campaign.recommended_enemy_faction:
|
||||
self.redFactionSelect.setCurrentIndex(i)
|
||||
if r == campaign.recommended_player_faction:
|
||||
self.blueFactionSelect.setCurrentIndex(i)
|
||||
for name in self.factions.iter_faction_names():
|
||||
self.blueFactionSelect.addItem(name)
|
||||
self.redFactionSelect.addItem(name)
|
||||
|
||||
self.blueFactionSelect.setCurrentText(campaign.recommended_player_faction.name)
|
||||
self.redFactionSelect.setCurrentText(campaign.recommended_enemy_faction.name)
|
||||
|
||||
self.updateUnitRecap()
|
||||
|
||||
|
||||
@ -2,10 +2,181 @@
|
||||
name: Syria - Operation Allied Sword
|
||||
theater: Syria
|
||||
authors: Fuzzle
|
||||
recommended_player_faction: Israel-USN 2005 (Allied Sword)
|
||||
recommended_enemy_faction: Syria-Lebanon 2005 (Allied Sword)
|
||||
description: <p>In this fictional scenario, a US/Israeli coalition must push north from the Israeli border, through Syria and Lebanon to Aleppo.</p><p><strong>Backstory:</strong> A Syrian-Lebanese joint force (with Russian materiel support) has attacked Israel, attmepting to cross the northern border. With the arrival of a US carrier group, Israel prepares its counterattack. The US Navy will handle the Beirut region's coastal arena, while the IAF will push through Damascus and the inland mountain ranges.</p>
|
||||
version: "10.1"
|
||||
recommended_player_faction:
|
||||
country: Combined Joint Task Forces Blue
|
||||
name: Israel-USN 2005
|
||||
authors: Fuzzle
|
||||
description:
|
||||
<p>A joint US Navy/Israeli modern faction for use with the Operation Allied
|
||||
Sword scenario.</p>
|
||||
locales:
|
||||
- en_US
|
||||
aircrafts:
|
||||
- F-4E Phantom II
|
||||
- F-15C Eagle
|
||||
- F-15E Strike Eagle
|
||||
- F-16CM Fighting Falcon (Block 50)
|
||||
- F-14B Tomcat
|
||||
- F/A-18C Hornet (Lot 20)
|
||||
- AV-8B Harrier II Night Attack
|
||||
- AH-1W SuperCobra
|
||||
- AH-64D Apache Longbow
|
||||
- AH-64D Apache Longbow (AI)
|
||||
- S-3B Viking
|
||||
- SH-60B Seahawk
|
||||
- UH-1H Iroquois
|
||||
- UH-60L
|
||||
awacs:
|
||||
- E-2C Hawkeye
|
||||
tankers:
|
||||
- KC-130
|
||||
- S-3B Tanker
|
||||
frontline_units:
|
||||
- M113
|
||||
- M1043 HMMWV (M2 HMG)
|
||||
- M1045 HMMWV (BGM-71 TOW)
|
||||
- Merkava Mk IV
|
||||
- M163 Vulcan Air Defense System
|
||||
artillery_units:
|
||||
- M109A6 Paladin
|
||||
- M270 Multiple Launch Rocket System
|
||||
logistics_units:
|
||||
- Truck M818 6x6
|
||||
infantry_units:
|
||||
- Infantry M4
|
||||
- Infantry M249
|
||||
- MANPADS Stinger
|
||||
preset_groups:
|
||||
- Hawk
|
||||
- Patriot
|
||||
naval_units:
|
||||
- FFG Oliver Hazard Perry
|
||||
- DDG Arleigh Burke IIa
|
||||
- CG Ticonderoga
|
||||
- LHA-1 Tarawa
|
||||
- CVN-74 John C. Stennis
|
||||
missiles: []
|
||||
air_defense_units:
|
||||
- SAM Hawk SR (AN/MPQ-50)
|
||||
- M163 Vulcan Air Defense System
|
||||
- M48 Chaparral
|
||||
requirements: {}
|
||||
carrier_names:
|
||||
- CVN-71 Theodore Roosevelt
|
||||
- CVN-72 Abraham Lincoln
|
||||
- CVN-73 George Washington
|
||||
- CVN-74 John C. Stennis
|
||||
- CVN-75 Harry S. Truman
|
||||
helicopter_carrier_names:
|
||||
- LHA-1 Tarawa
|
||||
- LHA-2 Saipan
|
||||
- LHA-3 Belleau Wood
|
||||
- LHA-4 Nassau
|
||||
- LHA-5 Peleliu
|
||||
has_jtac: true
|
||||
jtac_unit: MQ-9 Reaper
|
||||
doctrine: modern
|
||||
liveries_overrides:
|
||||
F-14B Tomcat:
|
||||
- VF-142 Ghostriders
|
||||
F/A-18C Hornet (Lot 20):
|
||||
- VMFA-251 high visibility
|
||||
AV-8B Harrier II Night Attack:
|
||||
- VMAT-542
|
||||
AH-1W SuperCobra:
|
||||
- Marines
|
||||
UH-1H Iroquois:
|
||||
- US NAVY
|
||||
UH-60L:
|
||||
- Israeli Air Force
|
||||
unrestricted_satnav: true
|
||||
recommended_enemy_faction:
|
||||
country: Combined Joint Task Forces Red
|
||||
name: Syria-Lebanon 2005 (Allied Sword)
|
||||
authors: Fuzzle
|
||||
description:
|
||||
<p>Syria-Lebanon alliance in a modern setting with several imported Russian
|
||||
assets. Designed for use with the Allied Sword scenario.</p>
|
||||
aircrafts:
|
||||
- MiG-23ML Flogger-G
|
||||
- MiG-25RBT Foxbat-B
|
||||
- MiG-29A Fulcrum-A
|
||||
- Su-17M4 Fitter-K
|
||||
- Su-24M Fencer-D
|
||||
- Su-30 Flanker-C
|
||||
- Su-34 Fullback
|
||||
- L-39ZA Albatros
|
||||
- Tu-22M3 Backfire-C
|
||||
- Mi-24V Hind-E
|
||||
- Mi-8MTV2 Hip
|
||||
- SA 342M Gazelle
|
||||
- SA 342L Gazelle
|
||||
- IL-76MD
|
||||
awacs:
|
||||
- A-50
|
||||
tankers:
|
||||
- IL-78M
|
||||
frontline_units:
|
||||
- BMP-1
|
||||
- BMP-2
|
||||
- BTR-80
|
||||
- BRDM-2
|
||||
- MT-LB
|
||||
- T-55A
|
||||
- T-72B with Kontakt-1 ERA
|
||||
- T-90A
|
||||
- ZSU-57-2 'Sparka'
|
||||
artillery_units:
|
||||
- BM-21 Grad
|
||||
- 2S1 Gvozdika
|
||||
logistics_units:
|
||||
- Truck Ural-375
|
||||
- LUV UAZ-469 Jeep
|
||||
infantry_units:
|
||||
- Paratrooper AKS
|
||||
- Infantry AK-74 Rus
|
||||
- Paratrooper RPG-16
|
||||
- MANPADS SA-18 Igla-S "Grouse"
|
||||
preset_groups:
|
||||
- SA-2/S-75
|
||||
- SA-3/S-125
|
||||
- SA-6
|
||||
- SA-11
|
||||
- SA-10/S-300PS
|
||||
- Silkworm
|
||||
- Cold-War-Flak
|
||||
- Russian Navy
|
||||
naval_units:
|
||||
- Corvette 1124.4 Grish
|
||||
- Corvette 1241.1 Molniya
|
||||
- FAC La Combattante IIa
|
||||
- Frigate 1135M Rezky
|
||||
air_defense_units:
|
||||
- SAM P19 "Flat Face" SR (SA-2/3)
|
||||
- EWR 1L13
|
||||
- EWR 55G6
|
||||
- SAM SA-8 Osa "Gecko" TEL
|
||||
- SA-9 Strela
|
||||
- SA-13 Gopher (9K35 Strela-10M3)
|
||||
- SA-19 Grison (2K22 Tunguska)
|
||||
- ZSU-57-2 'Sparka'
|
||||
- AAA ZU-23 Closed Emplacement
|
||||
- ZU-23 on Ural-375
|
||||
- ZSU-23-4 Shilka
|
||||
missiles:
|
||||
- SSM SS-1C Scud-B
|
||||
helicopter_carrier_names: []
|
||||
requirements: {}
|
||||
carrier_names: []
|
||||
description:
|
||||
<p>In this fictional scenario, a US/Israeli coalition must push north from the
|
||||
Israeli border, through Syria and Lebanon to
|
||||
Aleppo.</p><p><strong>Backstory:</strong> A Syrian-Lebanese joint force (with
|
||||
Russian materiel support) has attacked Israel, attmepting to cross the
|
||||
northern border. With the arrival of a US carrier group, Israel prepares its
|
||||
counterattack. The US Navy will handle the Beirut region's coastal arena,
|
||||
while the IAF will push through Damascus and the inland mountain ranges.</p>
|
||||
version: "10.6"
|
||||
miz: operation_allied_sword.miz
|
||||
performance: 2
|
||||
recommended_start_date: 2004-07-17
|
||||
@ -217,4 +388,4 @@ squadrons:
|
||||
- primary: Transport
|
||||
secondary: air-to-ground
|
||||
aircraft:
|
||||
- Mi-8MTV2 Hip
|
||||
- Mi-8MTV2 Hip
|
||||
|
||||
@ -1,88 +0,0 @@
|
||||
---
|
||||
country: Combined Joint Task Forces Blue
|
||||
name: Israel-USN 2005 (Allied Sword)
|
||||
authors: Fuzzle
|
||||
description:
|
||||
<p>A joint US Navy/Israeli modern faction for use with the Operation
|
||||
Allied Sword scenario.</p>
|
||||
locales:
|
||||
- en_US
|
||||
aircrafts:
|
||||
- F-4E Phantom II
|
||||
- F-15C Eagle
|
||||
- F-15E Strike Eagle
|
||||
- F-16CM Fighting Falcon (Block 50)
|
||||
- F-14B Tomcat
|
||||
- F/A-18C Hornet (Lot 20)
|
||||
- AV-8B Harrier II Night Attack
|
||||
- AH-1W SuperCobra
|
||||
- AH-64D Apache Longbow
|
||||
- AH-64D Apache Longbow (AI)
|
||||
- S-3B Viking
|
||||
- SH-60B Seahawk
|
||||
- UH-1H Iroquois
|
||||
- UH-60L
|
||||
awacs:
|
||||
- E-2C Hawkeye
|
||||
tankers:
|
||||
- KC-130
|
||||
- S-3B Tanker
|
||||
frontline_units:
|
||||
- M113
|
||||
- M1043 HMMWV (M2 HMG)
|
||||
- M1045 HMMWV (BGM-71 TOW)
|
||||
- Merkava Mk IV
|
||||
- M163 Vulcan Air Defense System
|
||||
artillery_units:
|
||||
- M109A6 Paladin
|
||||
- M270 Multiple Launch Rocket System
|
||||
logistics_units:
|
||||
- Truck M818 6x6
|
||||
infantry_units:
|
||||
- Infantry M4
|
||||
- Infantry M249
|
||||
- MANPADS Stinger
|
||||
preset_groups:
|
||||
- Hawk
|
||||
- Patriot
|
||||
naval_units:
|
||||
- FFG Oliver Hazard Perry
|
||||
- DDG Arleigh Burke IIa
|
||||
- CG Ticonderoga
|
||||
- LHA-1 Tarawa
|
||||
- CVN-74 John C. Stennis
|
||||
missiles: []
|
||||
air_defense_units:
|
||||
- SAM Hawk SR (AN/MPQ-50)
|
||||
- M163 Vulcan Air Defense System
|
||||
- M48 Chaparral
|
||||
requirements: {}
|
||||
carrier_names:
|
||||
- CVN-71 Theodore Roosevelt
|
||||
- CVN-72 Abraham Lincoln
|
||||
- CVN-73 George Washington
|
||||
- CVN-74 John C. Stennis
|
||||
- CVN-75 Harry S. Truman
|
||||
helicopter_carrier_names:
|
||||
- LHA-1 Tarawa
|
||||
- LHA-2 Saipan
|
||||
- LHA-3 Belleau Wood
|
||||
- LHA-4 Nassau
|
||||
- LHA-5 Peleliu
|
||||
has_jtac: true
|
||||
jtac_unit: MQ-9 Reaper
|
||||
doctrine: modern
|
||||
liveries_overrides:
|
||||
F-14B Tomcat:
|
||||
- VF-142 Ghostriders
|
||||
F/A-18C Hornet (Lot 20):
|
||||
- VMFA-251 high visibility
|
||||
AV-8B Harrier II Night Attack:
|
||||
- VMAT-542
|
||||
AH-1W SuperCobra:
|
||||
- Marines
|
||||
UH-1H Iroquois:
|
||||
- US NAVY
|
||||
UH-60L:
|
||||
- Israeli Air Force
|
||||
unrestricted_satnav: true
|
||||
@ -1,78 +0,0 @@
|
||||
---
|
||||
country: Combined Joint Task Forces Red
|
||||
name: Syria-Lebanon 2005 (Allied Sword)
|
||||
authors: Fuzzle
|
||||
description:
|
||||
<p>Syria-Lebanon alliance in a modern setting with several imported Russian
|
||||
assets. Designed for use with the Allied Sword scenario.</p>
|
||||
aircrafts:
|
||||
- MiG-23ML Flogger-G
|
||||
- MiG-25RBT Foxbat-B
|
||||
- MiG-29A Fulcrum-A
|
||||
- Su-17M4 Fitter-K
|
||||
- Su-24M Fencer-D
|
||||
- Su-30 Flanker-C
|
||||
- Su-34 Fullback
|
||||
- L-39ZA Albatros
|
||||
- Tu-22M3 Backfire-C
|
||||
- Mi-24V Hind-E
|
||||
- Mi-8MTV2 Hip
|
||||
- SA 342M Gazelle
|
||||
- SA 342L Gazelle
|
||||
- IL-76MD
|
||||
awacs:
|
||||
- A-50
|
||||
tankers:
|
||||
- IL-78M
|
||||
frontline_units:
|
||||
- BMP-1
|
||||
- BMP-2
|
||||
- BTR-80
|
||||
- BRDM-2
|
||||
- MT-LB
|
||||
- T-55A
|
||||
- T-72B with Kontakt-1 ERA
|
||||
- T-90A
|
||||
- ZSU-57-2 'Sparka'
|
||||
artillery_units:
|
||||
- BM-21 Grad
|
||||
- 2S1 Gvozdika
|
||||
logistics_units:
|
||||
- Truck Ural-375
|
||||
- LUV UAZ-469 Jeep
|
||||
infantry_units:
|
||||
- Paratrooper AKS
|
||||
- Infantry AK-74 Rus
|
||||
- Paratrooper RPG-16
|
||||
- MANPADS SA-18 Igla-S "Grouse"
|
||||
preset_groups:
|
||||
- SA-2/S-75
|
||||
- SA-3/S-125
|
||||
- SA-6
|
||||
- SA-11
|
||||
- SA-10/S-300PS
|
||||
- Silkworm
|
||||
- Cold-War-Flak
|
||||
- Russian Navy
|
||||
naval_units:
|
||||
- Corvette 1124.4 Grish
|
||||
- Corvette 1241.1 Molniya
|
||||
- FAC La Combattante IIa
|
||||
- Frigate 1135M Rezky
|
||||
air_defense_units:
|
||||
- SAM P19 "Flat Face" SR (SA-2/3)
|
||||
- EWR 1L13
|
||||
- EWR 55G6
|
||||
- SAM SA-8 Osa "Gecko" TEL
|
||||
- SA-9 Strela
|
||||
- SA-13 Gopher (9K35 Strela-10M3)
|
||||
- SA-19 Grison (2K22 Tunguska)
|
||||
- ZSU-57-2 'Sparka'
|
||||
- AAA ZU-23 Closed Emplacement
|
||||
- ZU-23 on Ural-375
|
||||
- ZSU-23-4 Shilka
|
||||
missiles:
|
||||
- SSM SS-1C Scud-B
|
||||
helicopter_carrier_names: []
|
||||
requirements: {}
|
||||
carrier_names: []
|
||||
@ -20,6 +20,6 @@ bugs.</p>
|
||||
{% endif %}
|
||||
|
||||
<p><strong>Default factions:</strong></p>
|
||||
<p><span style="color:#82A466">{{campaign.recommended_player_faction}}</span> VS <span style="color:orange"> {{campaign.recommended_enemy_faction}}</span></p>
|
||||
<p><span style="color:#82A466">{{campaign.recommended_player_faction.name}}</span> VS <span style="color:orange"> {{campaign.recommended_enemy_faction.name}}</span></p>
|
||||
|
||||
{{ campaign.description|safe }}
|
||||
@ -1,7 +1,7 @@
|
||||
<strong>Auteur(s) : {{ campaign.authors }}</strong>
|
||||
|
||||
<strong>Factions par défaut :</strong>
|
||||
<span style="color:#82A466"> {{campaign.recommended_player_faction}}</span> VS <span style="color:orange"> {{campaign.recommended_enemy_faction}}</span>
|
||||
<span style="color:#82A466"> {{campaign.recommended_player_faction.name}}</span> VS <span style="color:orange"> {{campaign.recommended_enemy_faction.name}}</span>
|
||||
<br/>
|
||||
|
||||
{{ campaign.description|safe }}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user