mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Improve Layout System and adopt to review
- adopted to review comments - removed the role from layouts - reworked the Groups within the layouts - added more documentation - rebased to latest changes
This commit is contained in:
parent
2c17a9a52e
commit
54e24dff39
@ -1,157 +1,120 @@
|
||||
# ArmedForces and the Layout System
|
||||
# The Layout System
|
||||
|
||||
Armed Forces and the Layout System is a complete rework of the generator-based logic to build theater-ground-objects (Liberation Objects which group ground units).
|
||||
This will change underlying parts of the code base which will allow major improvements to the Ground Warfare in upcoming features.
|
||||
The Layout System is a new way of defining how ground objects like SAM Sites or other Vehicle / Ship Groups will be generated (which type of units, how many units, alignment and orientation). It is a complete rework of the previous generator-based logic which was written in python code. The new system allows to define layouts with easy to write yaml code and the use of the DCS Mission Editor for easier placement of the units. The layout system also introduced a new logical grouping of Units and layouts for them, the Armed Forces, which will allow major improvements to the Ground Warfare in upcoming features.
|
||||
|
||||
**Armed Forces**\
|
||||
TODO Describe the introduction of ArmedForces which are similar to the AirWing and Squadrons.
|
||||
The armed forces of each coalition contain multiple ForceGroups. A ForceGroup is a logical set of units (Vehicles, Ships, Statics) and corresponding Layouts for these units.
|
||||
|
||||
TODO Picture / Example to describe what it is... for example with Hawk Battery or S-300 Battery
|
||||
The Armed Forces is a new system introduced with the layout system which will allow to identitfy and group possible units from the faction together with available layouts for these groups. It is comparable to the AirWing and Squadron implementation but just for Ground and Naval Forces. All possible Force Groups (grouping of 1 or more units and and the available layouts for them) will be generated during campaign initialization and will be used later by many different systems. A Force Group can also include static objects which was not possible before the introduction of the layout system. It is also possible to define presets of these Force Groups within the faction file which is handy for more complex groups like a SA-10 Battery or similar. Example: [SA-10/S-300PS](/resources/groups/SA-10.yaml) which includes all the units like SR, TR, LN and has the layout of a [S-300 Battery](/resources/layouts/anti_air/S-300_Site.yaml)
|
||||
|
||||
**The Layout System**\
|
||||
In the previous system the generator was written in python and generated a group with a defined and static logic, written in code.
|
||||
The layout sytem will now decouple the alignment / positioning from units and the definition of theire actual type (like Ural-375).
|
||||
The template system allows to define the layout and set which unit types or classes (All logistic units for example) are able to fit into the template.
|
||||
Ultimately this will allow to have generalized templates which can be reused by multiple types of units. Best example is the definition of a SAM layout.
|
||||
Previously we had a generator for every different SAM Site, now we can just reuse the alignemnt (e.g. 6 Launchers in a circle alignment) with more generalization.
|
||||
In the previous system the generator which created the ground object was written in python which made modifications and reusability very complicated. To allow easier handling of the layouts and decoupling of alignment of units and the actual unit type (for example Ural-375) the layout system was introduced. Previously we had a generator for every different SAM Site, now we can just reuse the alignemnt (e.g. 6 Launchers in a circle alignment) for multiple SAM Systems and introduce more variety.
|
||||
|
||||
This new System allows Users and Designers to easily create or modify layouts as the new alginment and orientation of units is defined with the DCS Mission editor. An additional .yaml file allows the configuration of the layout with settings like allow unit types or random amounts of units. In total the new system reduces the complexity and allows to precisely align / orient units as needed and create realistic looking ground units.
|
||||
|
||||
This also allows Users and Designers to easily create or modify templates as the new templates are defined with the DCS Mission editor and an additional .yaml file which provides mapping information.
|
||||
In total the new system reduces the complexity and allows to precisely align / orient units as needed and create realistic looking ground units.
|
||||
As the whole ground unit generation and handling was reworked it is now also possible to add static units to a ground object, so even Fortifcation or similar can be added to templates in the future.
|
||||
|
||||
## General Concept
|
||||
### General Concept
|
||||
|
||||
|
||||

|
||||
|
||||
TODO: Describe the general flow of the Template system
|
||||
|
||||
TODO: Describe the serialization (Developer Tools: Import Templates)
|
||||
All possible Force Groups will be generated during campaign initialization by checking all possible units for the specific faction and all available layouts. The code will automatically match general layouts with available units. It is also possible to define preset groups within the faction files which group many units and the prefered layouts for the group. This is especially handy for unique layouts which are not defined as `global`. For example complex sam sites like the S-300 or Patriot which have very specific alignment of the different units.
|
||||
|
||||
TODO Lifecycle:
|
||||
The template will be automatically validated on campaign generation against the player and enemy factions.
|
||||
If the factions support the template (based on the unit_types and unit_classes) then it will be added to the game.
|
||||
If a faction does not support a group from the template it will be removed if optional == True otherwise the complete template will be marked as unsupported and will not be used for the game.
|
||||
During campaign initialization the start_generator will request unit_groups for the preset locations defined by the campaign designer. The faction will then offer possible groups and the matching template.
|
||||
The Liberation Group (TheaterGroundObject) is then being generated from this UnitGroup.
|
||||
Layouts will be matched to units based on the special definition given in the corresponding yaml file. For example a layout which is defined as global and allows the unit_class SHORAD will automatically be used for all available SHORAD units which are defined in the faction file.
|
||||
|
||||
- GroundWar (Frontline) currently does **not** use the template system
|
||||
- User can buy new SAM or ArmorGroup using this template system
|
||||
- Campaign Designers can also define precicsly (if needed) which template or UnitGroup should be placed at a specific location by using TriggerZones with custom properties
|
||||
TODO Describe the optional flag.
|
||||
|
||||
All these generated ForceGroups will be managed by the ArmedForces class of the specific coalition. This class will be used by other parts of the system like the start_generator or the BuyMenu. The ArmedForces class will then generate the TheaterGroundObject which will be used by liberation.
|
||||
|
||||
Example for a customized Ground Object Buy Menu which makes use of Templates and UnitGroups:
|
||||
|
||||

|
||||
|
||||
|
||||
### The template miz
|
||||
## How to modify or add layouts
|
||||
|
||||
*Important*: Every unit_type has to be in a separate Group for the template to work.
|
||||
The template system merges the groups back together later with the group_id property (defaults to 1 which means that all groups in the template will be merged to group 1)
|
||||
A layout consists of two special files:
|
||||
|
||||
The function of the miz is to have the positioning and alignment of all the units within the template. Coordinates and headings will be used for the generated group.
|
||||
- layout.miz which defines the actual positioning and alignment of the groups / units
|
||||
- layout.yaml which defines the necessary information like amount of units, possible types or classes.
|
||||
|
||||
Unit Count per group has to be the amount set with the unit_count property.
|
||||
To add a new template a new yaml has to be created as every yaml can only define exact one template. Best practice is to copy paste an existing template which is similar to the one to be created as starting point. The next step is to create a new .miz file and align Units and statics to the wishes. Even if existing ones can be reused, best practice is to always create a fresh one to prevent side effects.
|
||||
The most important part is to use a new Group for every different Unit Type. It is not possible to mix Unit Types in one group within a template. For example it is not possible to have a logistic truck and a AAA in the same group. The miz file will only be used to get the exact position and orientation of the units, therefore it is irrelevant which type of unit will be used. The unit type will be later defined inside the yaml file.
|
||||
For the next step all Group names have to be added to the yaml file. Take care to that these names match exactly! Assign the unit_types or unit_classes properties to math the needs.
|
||||
|
||||
During template generation the system will go through all possible units and will assign the respective unit_type to the units up to the maximum allow unit_count from the mapping.
|
||||
**Important**: Whenever changes were made to layouts they have to be re-imported into Liberation. See below.
|
||||
|
||||
|
||||
### The Layout miz
|
||||
|
||||
The miz file is used to define the positioning and orientation of the different units for the template. The actual unit which is used is irrelevant. It is important to use a unique and meaningful name for the groups as this will be used in the yaml file as well. The information which will be extracted from the miz file are just the coordinates and heading of the units.
|
||||
|
||||
*Important*: Every different unit type has to be in a separate Group for the template to work. You can not add units of different types to the same group. They can get merged back together during generation by setting the group property. In the example below both groups `AAA Site 0` and `AAA Site 1` have the group = 1 which means that they will be in the same dcs group during generation.
|
||||
|
||||
TODO max amount of possible units is defined from the miz. Example if later the group should have 6 units than there have to be 6 defined in the miz.
|
||||
|
||||

|
||||
|
||||
### The template yaml
|
||||
### The Layout configuration file
|
||||
|
||||
TODO Description about the layout yaml file.\
|
||||
|
||||
Possible Information:
|
||||
|
||||
| Property | Type | Required | Description | Example |
|
||||
|---------------|-----------------------|----------|----------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------|
|
||||
| Name | (str) | Yes | A name to identify the template | `name: Armor Group` |
|
||||
| Role | (GroupRole) | Yes | The role which the template should fit in | `role: AntiAir` or `role: GroundForce` |
|
||||
| Tasks | (list of GroupTask) | Yes | A list of tasks which the template can fullfill | `tasks: - AAA - SHORAD` |
|
||||
| Generic | (bool, default False) | No | If this is true this template will be used to create general unitGroups | |
|
||||
| Description | (str) | No | Short description of the template | |
|
||||
| category | (str) | No | Only used for building templates to identify the type of the building | `category: ammo` |
|
||||
| Groups | (list of Groups) | Yes | see below for definition of a group | |
|
||||
| template_file | (str) | No | the .miz file which has the template included. Only needed if the file has a different name than the yaml file | `template_file: resources/templates/anti_air/legacy_ground_templates.miz` |
|
||||
| layout_file | (str) | No | the .miz file which has the groups / units of the layout included. Only needed if the file has a different name than the yaml file | `layout_file: resources/layouts/naval/legacy_naval_templates.miz` |
|
||||
|
||||
Groups within the template are defined as following:
|
||||
TODO Group and SubGroup
|
||||
|
||||
A group has 1..N sub groups. The name of the Group will be used later within the DCS group name.
|
||||
|
||||
All SubGroups will be merged into one DCS Group
|
||||
|
||||
Every unit type has to be defined as a sub group as following:
|
||||
|
||||
| Property | Type | Required | Description | Example |
|
||||
|--------------|------------------------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|
|
||||
| name | (str) | Yes | The group name used in the .miz. Must match exactly! | |
|
||||
| optional | (bool, default: False) | No | Defines wether the template can be used without this group if the faction has no access to the unit type or the user wants to disable this group | |
|
||||
| group | (int, default: 1) | No | The ID of the group which the templategroup will be merged into | |
|
||||
| unit_count | (list of int) | No | Amount of units to be generated for this group. Can be fixed or a range where it will be picked randomly | |
|
||||
| unit_types | (list dcs unit types) | No | Specific unit_types for ground units. Complete list from pydcs: [Vehicles.py](https://github.com/pydcs/dcs/blob/master/dcs/vehicles.py). This list is extended by all supported mods! | |
|
||||
| unit_classes | (list unit classes) | No | Unit_classes of supported units. Defined in [UnitClass](/game/data/units.py) | |
|
||||
| statics | (list static types) | No | Specific unit_types of statics. Complete list from pydcs: [Statics.py](https://github.com/pydcs/dcs/blob/master/dcs/statics.py) | |
|
||||
|
||||
Complete example of a generic template for AAA Groups:
|
||||
Complete example of a generic template for an Aircraft Carrier group:
|
||||
|
||||
```
|
||||
name: AAA Site
|
||||
description: A standard AAA template
|
||||
name: Carrier Group
|
||||
generic: true
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- AAA
|
||||
- AircraftCarrier
|
||||
groups:
|
||||
- name: AAA Site 0
|
||||
group: 1
|
||||
unit_count:
|
||||
- 2
|
||||
- 6
|
||||
unit_classes:
|
||||
- AAA
|
||||
- name: AAA Site 1
|
||||
optional: true
|
||||
group: 1
|
||||
unit_count:
|
||||
- 1
|
||||
- 2
|
||||
unit_classes:
|
||||
- Logistics
|
||||
template_file: resources/templates/anti_air/AAA.miz
|
||||
- Carrier: # Group Name of the DCS Group
|
||||
- name: Carrier Group 0 # Sub Group used in the layout.miz
|
||||
unit_count:
|
||||
- 1
|
||||
unit_classes:
|
||||
- AircraftCarrier
|
||||
- Escort: # Group name of the 2nd Group
|
||||
- name: Carrier Group 1
|
||||
unit_count:
|
||||
- 4
|
||||
unit_classes:
|
||||
- Destroyer
|
||||
layout_file: resources/layouts/naval/legacy_naval_templates.miz
|
||||
```
|
||||
|
||||
### Roles, Tasks and Classes
|
||||
|
||||
TODO Describe Role, Tasking and Classes
|
||||
|
||||
[GroupRole and GroupTask](/game/data/groups.py)
|
||||
|
||||
[UnitClass](/game/data/units.py)
|
||||
|
||||
## How to add / modify a template
|
||||
|
||||
A template consists of two special files:
|
||||
|
||||
- template.miz which defines the actual positioning and alignment of the groups / units
|
||||
- template.yaml which defines the necessary information like amount of units, possible types or classes.
|
||||
|
||||
To add a new template a new yaml has to be created as every yaml can only define exact one template. Best practice is to copy paste an existing template which is similar to the one to be created as starting point. The next step is to create a new .miz file and align Units and statics to the wishes. Even if existing ones can be reused, best practice is to always create a fresh one to prevent side effects.
|
||||
The most important part is to use a new Group for every different Unit Type. It is not possible to mix Unit Types in one group within a template. For example it is not possible to have a logistic truck and a AAA in the same group. The miz file will only be used to get the exact position and orientation of the units, therefore it is irrelevant which type of unit will be used. The unit type will be later defined inside the yaml file.
|
||||
For the next step all Group names have to be added to the yaml file. Take care to that these names match exactly! Assign the unit_types or unit_classes properties to math the needs.
|
||||
|
||||
TODO Improve this with images and more detailed description
|
||||
|
||||
**IMPORTANT**: Due to performance increase the templates get serialized to a pickle file in the save dir as `templates.p`. When templates were modified a manual re-import of all templates has to be triggered.
|
||||
This can be done by either deleting this file or using the Liberation UI. There is a special option in the ToolBar under Tools: Import Templates.
|
||||
|
||||
|
||||
## Import Layouts into Liberation
|
||||
TODO Describe the serialization and import.
|
||||
|
||||
For performance improvements all layouts are serialized to a so called pickle file. Every time changes are made to the layouts this file has to be recreated.
|
||||
It will also be recreated after each Liberation update as it will check the Version Number and recreate it when changes are recognized.
|
||||
|
||||
This file is stored in the save folder
|
||||
### Import Layouts into Liberation
|
||||
For performance improvements all layouts are serialized to a so called pickle file inside the save folder defined in the liberation preferences. Every time changes are made to the layouts this file has to be recreated. It can be recreated by either deleting the layouts.p file manually or using the special option in the Liberation Toolbar (Developer Tools -> Import Layouts). It will also be recreated after each Liberation update as it will check the Version Number and recreate it when changes are recognized.
|
||||
|
||||
|
||||
## Migration from Generators
|
||||
|
||||
- All generators removed and migrated to templates
|
||||
- These templates will in the next step be generalized
|
||||
|
||||
The previous generators were migrated using a script which build a group using the generator. All of these groups were save into one .miz file [original_generator_layouts.miz](/resources/layouts/original_generator_layouts.miz).
|
||||
This miz file can be used to verify the templates and to generalize similar templates to decouple the layout from the actual units. As this is a time-consuming and sphisticated task this will be done over time.
|
||||
With the first step the technical requirements will be fulfilled so that the generalization can happen afterwards the technical pr gets merged.
|
||||
@ -165,53 +128,39 @@ During migration all default factions were automatically updated, so they will w
|
||||
What was changed:
|
||||
- Removed the `ewrs` list. All EWRs are now defined in the list "air_defense_units".
|
||||
- Added the `air_defense_units` list. All units with the Role AntiAir can be defined here as [GroundUnitType](/game/dcs/groundunittype.py). All possible units are defined in [/resources/units/ground_units](/resources/units/ground_units)
|
||||
- Added `preset_groups`. This list allows to define Preset Groups (described above) like SAM Systems consisting of Launcher, SR, TR and so on instead of adding them each to "air_defense_units". The presets are defined in [/resources/units/unit_groups](/resources/units/groups)
|
||||
- Added `preset_groups`. This list allows to define Preset Groups (described above) like SAM Systems consisting of Launcher, SR, TR and so on instead of adding them each to "air_defense_units". The presets are defined in [/resources/groups](/resources/groups)
|
||||
- Migrated `air_defenses` to air_defense_units and preset_sets.
|
||||
- `Missiles` are migrated to GroundUnitTypes instead of Generator names (see air_defense_units for how to use)
|
||||
- Removed `cruisers`, `destroyers` and `naval_generators`. Migrated them to naval_units and preset_groups
|
||||
- added `naval_units` with the correct ship name found here [/resources/units/ships](/resources/units/ships)
|
||||
- `aircraft_carrier` and `helicopter_carrier` were moved to `naval_units` as well.
|
||||
|
||||
## Unit Groups
|
||||
## Preset Groups
|
||||
|
||||
TODO Explain more
|
||||
|
||||
- Sum up groups of different units which are used together (like a sam site).
|
||||
- UnitGroup allows to define this logical group and add this to the faction file.
|
||||
- UnitGroups can have preferred templates
|
||||
Instead of adding the exact name of the previous generator to add complex groups like SAM sites or similar to the faction it is now possible to add preset groups to the faction file. As described earlier such a preset group (Force Group) can be defined very easy with a yaml file. This file allows to define the name, tasking, units, statics and the prefered layouts. The first task defines the primary role of the ForceGroup which gets generated from the preset.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
name: SA-10/S-300PS # The name which will be used in the faction file
|
||||
role: AntiAir # The role of the Group
|
||||
tasks:
|
||||
- LORAD # The task the Group can fulfill
|
||||
ground_units:
|
||||
name: SA-10/S-300PS # The name of the group
|
||||
tasks: # Define at least 1 task
|
||||
- LORAD # The task(s) the Group can fulfill
|
||||
units: # Define at least 1 unit
|
||||
- SAM SA-10 S-300 "Grumble" Clam Shell SR
|
||||
- SAM SA-10 S-300 "Grumble" Big Bird SR
|
||||
- SAM SA-10 S-300 "Grumble" C2
|
||||
- SAM SA-10 S-300 "Grumble" Flap Lid TR
|
||||
- SAM SA-10 S-300 "Grumble" TEL D
|
||||
- SAM SA-10 S-300 "Grumble" TEL C
|
||||
ship_units:
|
||||
- # Add some naval units here
|
||||
statics:
|
||||
statics: # Optional
|
||||
- # Add some statics here
|
||||
templates:
|
||||
- S-300 Site # The template names which should be used by this group
|
||||
layouts: # Define at least one layout
|
||||
- S-300 Site # prefered layouts for these groups
|
||||
```
|
||||
|
||||
A list of all available units is accessible here: [/resources/units/unit_groups](/resources/units/groups)
|
||||
|
||||
|
||||
### Optional Tasks which can be done later
|
||||
- [ ] Complex Presets which allow campaign designer to specify the exact forcegroup or layout which should be used.
|
||||
- [ ] Generalize all layouts (Like MERAD or SHORAD templates)
|
||||
- [ ] Reuse the layouts for the frontline
|
||||
- [ ] Add UI Implementation to choose which templates should be used during new game wizard (like AirWing Config)
|
||||
- [ ] Rework "Names_By_Category" to just use the Tasking instead of a string.
|
||||
- [ ] Add remaining missing classes to the units which currently dont have a class
|
||||
|
||||
Resources:
|
||||
- A list of all available preset groups can be found here: [/resources/groups](/resources/groups)
|
||||
- All possible tasks can be found in the [/game/data/groups.py](/game/data/groups.py)
|
||||
- Units are defined with the variant name found in [/resources/units](/resources/units)
|
||||
|
||||
|
||||
|
||||
@ -2,21 +2,20 @@ from __future__ import annotations
|
||||
|
||||
import random
|
||||
from typing import TYPE_CHECKING, Iterator, Optional
|
||||
from game import db
|
||||
from game.data.groups import GroupRole, GroupTask
|
||||
from game.data.groups import GroupTask
|
||||
from game.armedforces.forcegroup import ForceGroup
|
||||
from game.layout import LAYOUTS
|
||||
from game.profiling import logged_duration
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game.factions.faction import Faction
|
||||
|
||||
|
||||
# TODO More comments and rename
|
||||
class ArmedForces:
|
||||
"""TODO Description"""
|
||||
|
||||
# All available force groups for a specific Role
|
||||
forces: dict[GroupRole, list[ForceGroup]]
|
||||
forces: list[ForceGroup]
|
||||
|
||||
def __init__(self, faction: Faction):
|
||||
with logged_duration(f"Loading armed forces for {faction.name}"):
|
||||
@ -24,50 +23,36 @@ class ArmedForces:
|
||||
|
||||
def add_or_update_force_group(self, new_group: ForceGroup) -> None:
|
||||
"""TODO Description"""
|
||||
if new_group.role in self.forces:
|
||||
# Check if a force group with the same units exists
|
||||
for force_group in self.forces[new_group.role]:
|
||||
if (
|
||||
force_group.units == new_group.units
|
||||
and force_group.tasks == new_group.tasks
|
||||
):
|
||||
# Update existing group if units and tasks are equal
|
||||
force_group.update_group(new_group)
|
||||
return
|
||||
# Check if a force group with the same units exists
|
||||
for force_group in self.forces:
|
||||
if (
|
||||
force_group.units == new_group.units
|
||||
and force_group.tasks == new_group.tasks
|
||||
):
|
||||
# Update existing group if units and tasks are equal
|
||||
force_group.update_group(new_group)
|
||||
return
|
||||
# Add a new force group
|
||||
self.add_force_group(new_group)
|
||||
|
||||
def add_force_group(self, force_group: ForceGroup) -> None:
|
||||
"""Adds a force group to the forces"""
|
||||
if force_group.role in self.forces:
|
||||
self.forces[force_group.role].append(force_group)
|
||||
else:
|
||||
self.forces[force_group.role] = [force_group]
|
||||
self.forces.append(new_group)
|
||||
|
||||
def _load_forces(self, faction: Faction) -> None:
|
||||
"""Initialize all armed_forces for the given faction"""
|
||||
# This function will create a ForgeGroup for each global Layout and PresetGroup
|
||||
self.forces = {}
|
||||
"""Initialize the ArmedForces for the given faction.
|
||||
This will create a ForceGroup for each generic Layout and PresetGroup"""
|
||||
|
||||
preset_layouts = [
|
||||
layout
|
||||
for preset_group in faction.preset_groups
|
||||
for layout in preset_group.layouts
|
||||
]
|
||||
# Initialize with preset_groups from the faction
|
||||
self.forces = [preset_group for preset_group in faction.preset_groups]
|
||||
|
||||
# Generate Troops for all generic layouts and presets
|
||||
for layout in db.LAYOUTS.layouts:
|
||||
if (
|
||||
layout.generic or layout in preset_layouts
|
||||
) and layout.usable_by_faction(faction):
|
||||
# Generate ForceGroup for all generic layouts by iterating over
|
||||
# all layouts which are usable by the given faction.
|
||||
for layout in LAYOUTS.layouts:
|
||||
if layout.generic and layout.usable_by_faction(faction):
|
||||
# Creates a faction compatible GorceGroup
|
||||
self.add_or_update_force_group(ForceGroup.for_layout(layout, faction))
|
||||
|
||||
def groups_for_task(self, group_task: GroupTask) -> Iterator[ForceGroup]:
|
||||
for groups in self.forces.values():
|
||||
for unit_group in groups:
|
||||
if group_task in unit_group.tasks:
|
||||
yield unit_group
|
||||
for force_group in self.forces:
|
||||
if group_task in force_group.tasks:
|
||||
yield force_group
|
||||
|
||||
def groups_for_tasks(self, tasks: list[GroupTask]) -> list[ForceGroup]:
|
||||
groups = []
|
||||
|
||||
@ -9,18 +9,20 @@ from typing import ClassVar, TYPE_CHECKING, Type, Any, Iterator, Optional
|
||||
import yaml
|
||||
from dcs import Point
|
||||
|
||||
from game import db
|
||||
from game.data.groups import GroupRole, GroupTask
|
||||
from game.data.groups import GroupTask
|
||||
from game.data.radar_db import UNITS_WITH_RADAR
|
||||
from game.dcs.groundunittype import GroundUnitType
|
||||
from game.dcs.helpers import static_type_from_name
|
||||
from game.dcs.shipunittype import ShipUnitType
|
||||
from game.dcs.unittype import UnitType
|
||||
from game.point_with_heading import PointWithHeading
|
||||
from game.layout.layout import TheaterLayout, AntiAirLayout, GroupLayout
|
||||
from game.layout.layout import TgoLayout, AntiAirLayout, TgoLayoutGroup
|
||||
from dcs.unittype import UnitType as DcsUnitType, VehicleType, ShipType, StaticType
|
||||
|
||||
from game.theater.theatergroup import TheaterGroup
|
||||
|
||||
from game.layout import LAYOUTS
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game import Game
|
||||
from game.factions.faction import Faction
|
||||
@ -29,25 +31,40 @@ if TYPE_CHECKING:
|
||||
|
||||
@dataclass
|
||||
class ForceGroup:
|
||||
"""A logical group of multiple units and layouts which have a specific tasking"""
|
||||
"""A logical group of multiple units and layouts which have a specific tasking.
|
||||
|
||||
ForceGroups will be generated during game and coalition initialization based on
|
||||
generic layouts and preset forcegroups.
|
||||
|
||||
Every ForceGroup must have at least one unit, one task and one layout.
|
||||
|
||||
A preset ForceGroup can for example be a S-300 SAM Battery which used many
|
||||
different unit types which all together handle a specific tasking (AirDefense)
|
||||
For this example the ForceGroup would consist of SR, TR, LN and so on next to
|
||||
statics. This group also has the Tasking LORAD and can have multiple (at least one)
|
||||
layouts which will be used to generate the actual DCS Group from it.
|
||||
"""
|
||||
|
||||
name: str
|
||||
units: list[UnitType[Any]]
|
||||
statics: list[Type[DcsUnitType]]
|
||||
role: GroupRole
|
||||
tasks: list[GroupTask] = field(default_factory=list)
|
||||
layouts: list[TheaterLayout] = field(default_factory=list)
|
||||
layouts: list[TgoLayout] = field(default_factory=list)
|
||||
|
||||
_by_name: ClassVar[dict[str, ForceGroup]] = {}
|
||||
_by_role: ClassVar[dict[GroupRole, list[ForceGroup]]] = {}
|
||||
_loaded: bool = False
|
||||
|
||||
@staticmethod
|
||||
def for_layout(layout: TheaterLayout, faction: Faction) -> ForceGroup:
|
||||
"""TODO Documentation"""
|
||||
def for_layout(layout: TgoLayout, faction: Faction) -> ForceGroup:
|
||||
"""Create a ForceGroup from the given TgoLayout which is usable by the faction
|
||||
|
||||
This will iterate through all possible TgoLayoutGroups and check if the
|
||||
unit_types are accessible by the faction. All accessible units will be added to
|
||||
the force group
|
||||
"""
|
||||
units: set[UnitType[Any]] = set()
|
||||
statics: set[Type[DcsUnitType]] = set()
|
||||
for group in layout.groups:
|
||||
for group in layout.all_groups:
|
||||
for unit_type in group.possible_types_for_faction(faction):
|
||||
if issubclass(unit_type, VehicleType):
|
||||
units.add(next(GroundUnitType.for_dcs_type(unit_type)))
|
||||
@ -57,10 +74,9 @@ class ForceGroup:
|
||||
statics.add(unit_type)
|
||||
|
||||
return ForceGroup(
|
||||
f"{layout.role.value}: {', '.join([t.description for t in layout.tasks])}",
|
||||
", ".join([t.description for t in layout.tasks]),
|
||||
list(units),
|
||||
list(statics),
|
||||
layout.role,
|
||||
layout.tasks,
|
||||
[layout],
|
||||
)
|
||||
@ -80,33 +96,38 @@ class ForceGroup:
|
||||
or type in self.statics
|
||||
)
|
||||
|
||||
def dcs_unit_types_for_group(self, group: GroupLayout) -> list[Type[DcsUnitType]]:
|
||||
"""TODO Description"""
|
||||
def dcs_unit_types_for_group(
|
||||
self, group: TgoLayoutGroup
|
||||
) -> list[Type[DcsUnitType]]:
|
||||
"""Return all available DCS Unit Types which can be used in the given
|
||||
TgoLayoutGroup"""
|
||||
unit_types = [t for t in group.unit_types if self.has_access_to_dcs_type(t)]
|
||||
|
||||
alternative_types = []
|
||||
for accessible_unit in self.units:
|
||||
if accessible_unit.unit_class in group.unit_classes:
|
||||
unit_types.append(accessible_unit.dcs_unit_type)
|
||||
if accessible_unit.unit_class in group.alternative_classes:
|
||||
if accessible_unit.unit_class in group.fallback_classes:
|
||||
alternative_types.append(accessible_unit.dcs_unit_type)
|
||||
|
||||
return unit_types or alternative_types
|
||||
|
||||
def unit_types_for_group(self, group: GroupLayout) -> Iterator[UnitType[Any]]:
|
||||
def unit_types_for_group(self, group: TgoLayoutGroup) -> Iterator[UnitType[Any]]:
|
||||
for dcs_type in self.dcs_unit_types_for_group(group):
|
||||
if issubclass(dcs_type, VehicleType):
|
||||
yield next(GroundUnitType.for_dcs_type(dcs_type))
|
||||
elif issubclass(dcs_type, ShipType):
|
||||
yield next(ShipUnitType.for_dcs_type(dcs_type))
|
||||
|
||||
def statics_for_group(self, group: GroupLayout) -> Iterator[Type[DcsUnitType]]:
|
||||
def statics_for_group(self, group: TgoLayoutGroup) -> Iterator[Type[DcsUnitType]]:
|
||||
for dcs_type in self.dcs_unit_types_for_group(group):
|
||||
if issubclass(dcs_type, StaticType):
|
||||
yield dcs_type
|
||||
|
||||
def random_dcs_unit_type_for_group(self, group: GroupLayout) -> Type[DcsUnitType]:
|
||||
"""TODO Description"""
|
||||
def random_dcs_unit_type_for_group(
|
||||
self, group: TgoLayoutGroup
|
||||
) -> Type[DcsUnitType]:
|
||||
"""Return random DCS Unit Type which can be used in the given TgoLayoutGroup"""
|
||||
return random.choice(self.dcs_unit_types_for_group(group))
|
||||
|
||||
def update_group(self, new_group: ForceGroup) -> None:
|
||||
@ -130,7 +151,7 @@ class ForceGroup:
|
||||
|
||||
def create_ground_object_for_layout(
|
||||
self,
|
||||
layout: TheaterLayout,
|
||||
layout: TgoLayout,
|
||||
name: str,
|
||||
position: PointWithHeading,
|
||||
control_point: ControlPoint,
|
||||
@ -139,25 +160,31 @@ class ForceGroup:
|
||||
"""Create a TheaterGroundObject for the given template"""
|
||||
go = layout.create_ground_object(name, position, control_point)
|
||||
# Generate all groups using the randomization if it defined
|
||||
for group in layout.groups:
|
||||
# Choose a random unit_type for the group
|
||||
try:
|
||||
unit_type = self.random_dcs_unit_type_for_group(group)
|
||||
except IndexError:
|
||||
if group.optional:
|
||||
# If group is optional it is ok when no unit_type is available
|
||||
continue
|
||||
# if non-optional this is a error
|
||||
raise RuntimeError(f"No accessible unit for {self.name} - {group.name}")
|
||||
self.create_theater_group_for_tgo(go, group, name, game, unit_type)
|
||||
for group_name, groups in layout.groups.items():
|
||||
for group in groups:
|
||||
# Choose a random unit_type for the group
|
||||
try:
|
||||
unit_type = self.random_dcs_unit_type_for_group(group)
|
||||
except IndexError:
|
||||
if group.optional:
|
||||
# If group is optional it is ok when no unit_type is available
|
||||
continue
|
||||
# if non-optional this is a error
|
||||
raise RuntimeError(
|
||||
f"No accessible unit for {self.name} - {group.name}"
|
||||
)
|
||||
tgo_group_name = f"{name} ({group_name})"
|
||||
self.create_theater_group_for_tgo(
|
||||
go, group, tgo_group_name, game, unit_type
|
||||
)
|
||||
|
||||
return go
|
||||
|
||||
def create_theater_group_for_tgo(
|
||||
self,
|
||||
ground_object: TheaterGroundObject,
|
||||
group: GroupLayout,
|
||||
name: str,
|
||||
group: TgoLayoutGroup,
|
||||
group_name: str,
|
||||
game: Game,
|
||||
unit_type: Type[DcsUnitType],
|
||||
unit_count: Optional[int] = None,
|
||||
@ -165,25 +192,29 @@ class ForceGroup:
|
||||
"""Create a TheaterGroup and add it to the given TGO"""
|
||||
# Random UnitCounter if not forced
|
||||
if unit_count is None:
|
||||
unit_count = group.unit_counter
|
||||
# Static and non Static groups have to be separated
|
||||
group_id = group.group - 1
|
||||
if len(ground_object.groups) <= group_id:
|
||||
# Requested group was not yet created
|
||||
ground_group = TheaterGroup.from_template(
|
||||
game.next_group_id(), group, ground_object, unit_type, unit_count
|
||||
)
|
||||
# Set Group Name
|
||||
ground_group.name = f"{name} {group_id}"
|
||||
ground_object.groups.append(ground_group)
|
||||
units = ground_group.units
|
||||
else:
|
||||
ground_group = ground_object.groups[group_id]
|
||||
units = group.generate_units(ground_object, unit_type, unit_count)
|
||||
unit_count = group.group_size
|
||||
# Generate Units
|
||||
units = group.generate_units(ground_object, unit_type, unit_count)
|
||||
# Get or create the TheaterGroup
|
||||
ground_group = ground_object.group_by_name(group_name)
|
||||
if ground_group is not None:
|
||||
# TheaterGroup with this name exists already. Extend it
|
||||
ground_group.units.extend(units)
|
||||
else:
|
||||
# TheaterGroup with the name was not created yet
|
||||
ground_object.groups.append(
|
||||
TheaterGroup.from_template(
|
||||
game.next_group_id(),
|
||||
group_name,
|
||||
units,
|
||||
ground_object,
|
||||
unit_type,
|
||||
unit_count,
|
||||
)
|
||||
)
|
||||
|
||||
# Assign UniqueID, name and align relative to ground_object
|
||||
for u_id, unit in enumerate(units):
|
||||
for unit in units:
|
||||
unit.id = game.next_unit_id()
|
||||
unit.name = unit.unit_type.name if unit.unit_type else unit.type.name
|
||||
unit.position = PointWithHeading.from_point(
|
||||
@ -209,42 +240,46 @@ class ForceGroup:
|
||||
|
||||
@classmethod
|
||||
def _load_all(cls) -> None:
|
||||
for file in Path("resources/units/groups").glob("*.yaml"):
|
||||
for file in Path("resources/groups").glob("*.yaml"):
|
||||
if not file.is_file():
|
||||
raise RuntimeError(f"{file.name} is not a valid ForceGroup")
|
||||
|
||||
with file.open(encoding="utf-8") as data_file:
|
||||
data = yaml.safe_load(data_file)
|
||||
|
||||
group_role = GroupRole(data.get("role"))
|
||||
name = data["name"]
|
||||
|
||||
group_tasks = [GroupTask.by_description(n) for n in data.get("tasks", [])]
|
||||
group_tasks = [GroupTask.by_description(n) for n in data.get("tasks")]
|
||||
if not group_tasks:
|
||||
logging.error(f"ForceGroup {name} has no valid tasking")
|
||||
continue
|
||||
|
||||
units = [UnitType.named(unit) for unit in data.get("units", [])]
|
||||
units = [UnitType.named(unit) for unit in data.get("units")]
|
||||
if not units:
|
||||
logging.error(f"ForceGroup {name} has no valid units")
|
||||
continue
|
||||
|
||||
statics = []
|
||||
for static in data.get("statics", []):
|
||||
static_type = db.static_type_from_name(static)
|
||||
static_type = static_type_from_name(static)
|
||||
if static_type is None:
|
||||
logging.error(f"Static {static} for {file} is not valid")
|
||||
else:
|
||||
statics.append(static_type)
|
||||
|
||||
layouts = [next(db.LAYOUTS.by_name(n)) for n in data.get("layouts")]
|
||||
layouts = [LAYOUTS.by_name(n) for n in data.get("layouts")]
|
||||
if not layouts:
|
||||
logging.error(f"ForceGroup {name} has no valid layouts")
|
||||
continue
|
||||
|
||||
force_group = ForceGroup(
|
||||
name=data.get("name"),
|
||||
name=name,
|
||||
units=units,
|
||||
statics=statics,
|
||||
role=group_role,
|
||||
tasks=group_tasks,
|
||||
layouts=layouts,
|
||||
)
|
||||
|
||||
cls._by_name[force_group.name] = force_group
|
||||
if group_role in cls._by_role:
|
||||
cls._by_role[group_role].append(force_group)
|
||||
else:
|
||||
cls._by_role[group_role] = [force_group]
|
||||
|
||||
cls._loaded = True
|
||||
|
||||
@ -11,6 +11,7 @@ from pydantic.dataclasses import dataclass
|
||||
|
||||
from game.ato.flightwaypointtype import FlightWaypointType
|
||||
from game.theater import LatLon
|
||||
from game.theater.theatergroup import TheaterUnit
|
||||
from game.utils import Distance, meters
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -94,7 +95,7 @@ class FlightWaypoint(BaseFlightWaypoint):
|
||||
# having three names. A short and long form is enough.
|
||||
description: str = ""
|
||||
|
||||
targets: Sequence[MissionTarget | Unit] = []
|
||||
targets: Sequence[MissionTarget | TheaterUnit] = []
|
||||
obj_name: str = ""
|
||||
pretty_name: str = ""
|
||||
only_for_player: bool = False
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
from .faction import Faction
|
||||
from .faction_loader import FactionLoader
|
||||
from .factionloader import FactionLoader
|
||||
|
||||
FACTIONS = FactionLoader()
|
||||
|
||||
@ -150,7 +150,7 @@ class Faction:
|
||||
for unit in preset_group.units
|
||||
),
|
||||
)
|
||||
return list(all_units)
|
||||
return list(set(all_units))
|
||||
|
||||
@property
|
||||
def air_defenses(self) -> list[str]:
|
||||
@ -158,7 +158,11 @@ class Faction:
|
||||
# This is used for the faction overview in NewGameWizard
|
||||
air_defenses = [a.name for a in self.air_defense_units]
|
||||
air_defenses.extend(
|
||||
[pg.name for pg in self.preset_groups if pg.role == GroupRole.AIR_DEFENSE]
|
||||
[
|
||||
pg.name
|
||||
for pg in self.preset_groups
|
||||
if any(task.role == GroupRole.AIR_DEFENSE for task in pg.tasks)
|
||||
]
|
||||
)
|
||||
return sorted(air_defenses)
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
from layout import TheaterLayout
|
||||
from game.layout.layoutloader import LayoutLoader
|
||||
from .layout import TgoLayout, TgoLayoutGroup
|
||||
from .layoutloader import LayoutLoader
|
||||
|
||||
LAYOUTS = LayoutLoader()
|
||||
LAYOUTS = LayoutLoader()
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
from __future__ import annotations
|
||||
from collections import defaultdict
|
||||
|
||||
import logging
|
||||
import random
|
||||
from dataclasses import dataclass, field
|
||||
from typing import TYPE_CHECKING, Type
|
||||
from typing import TYPE_CHECKING, Iterator, Type
|
||||
|
||||
from dcs import Point
|
||||
from dcs.unit import Unit
|
||||
@ -50,98 +51,121 @@ class LayoutUnit:
|
||||
"""Creates a LayoutUnit from a DCS Unit"""
|
||||
return LayoutUnit(
|
||||
unit.name,
|
||||
Point(int(unit.position.x), int(unit.position.y)),
|
||||
unit.position,
|
||||
int(unit.heading),
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class GroupLayout:
|
||||
"""The Layout of a TheaterGroup"""
|
||||
class TgoLayoutGroup:
|
||||
"""The layout of a single type of unit within the TgoLayout
|
||||
|
||||
Each DCS group that is spawned in the mission is composed of one or more
|
||||
TgoLayoutGroup. Each TgoLayoutGroup will generate only a single type of unit.
|
||||
|
||||
The merging of multiple TgoLayoutGroups to a single DCS group is defined in the
|
||||
TgoLayout with a dict which uses the Dcs group name as key and the corresponding
|
||||
TgoLayoutGroups as values.
|
||||
|
||||
Each TgoLayoutGroup will be filled with a single type of unit when generated. The
|
||||
types compatible with the position can either be specified precisely (with
|
||||
unit_types) or generically (with unit_classes). If neither list specifies units
|
||||
that can be fulfilled by the faction, fallback_classes will be used. This allows
|
||||
the early-warning radar template, which prefers units that are defined as early
|
||||
warning radars like the 55G6, but to fall back to any radar usable by the faction
|
||||
if EWRs are not available.
|
||||
|
||||
A TgoLayoutGroup may be optional. Factions or ForceGroups that are not able to
|
||||
provide an actual unit for the TgoLayoutGroup will still be able to use the layout;
|
||||
the optional TgoLayoutGroup will be omitted.
|
||||
"""
|
||||
|
||||
name: str
|
||||
units: list[LayoutUnit]
|
||||
layout_units: list[LayoutUnit]
|
||||
|
||||
# The group this template will be merged into
|
||||
group: int = 1
|
||||
|
||||
# Define the amount of random units to be created by the randomizer.
|
||||
# This can be a fixed int or a random value from a range of two ints as tuple
|
||||
# Define the amount of units to be created. This can be a fixed int or a random
|
||||
# choice from a range of two ints. If the list is empty it will use the whole group
|
||||
# size / all available LayoutUnits
|
||||
unit_count: list[int] = field(default_factory=list)
|
||||
|
||||
# defintion which unit types are supported
|
||||
unit_types: list[Type[DcsUnitType]] = field(default_factory=list)
|
||||
unit_classes: list[UnitClass] = field(default_factory=list)
|
||||
alternative_classes: list[UnitClass] = field(default_factory=list)
|
||||
fallback_classes: list[UnitClass] = field(default_factory=list)
|
||||
|
||||
# Defines if this groupTemplate is required or not
|
||||
optional: bool = False
|
||||
|
||||
# if enabled the specific group will be generated during generation
|
||||
# Can only be set to False if Optional = True
|
||||
enabled: bool = True
|
||||
|
||||
# TODO Caching for faction!
|
||||
def possible_types_for_faction(self, faction: Faction) -> list[Type[DcsUnitType]]:
|
||||
"""TODO Description"""
|
||||
"""Determine the possible dcs unit types for the TgoLayoutGroup and the given faction"""
|
||||
unit_types = [t for t in self.unit_types if faction.has_access_to_dcs_type(t)]
|
||||
|
||||
alternative_types = []
|
||||
for accessible_unit in faction.accessible_units:
|
||||
if accessible_unit.unit_class in self.unit_classes:
|
||||
unit_types.append(accessible_unit.dcs_unit_type)
|
||||
if accessible_unit.unit_class in self.alternative_classes:
|
||||
if accessible_unit.unit_class in self.fallback_classes:
|
||||
alternative_types.append(accessible_unit.dcs_unit_type)
|
||||
|
||||
if not unit_types and not alternative_types and not self.optional:
|
||||
raise LayoutException
|
||||
raise LayoutException(f"{self.name} not usable by faction {faction.name}")
|
||||
|
||||
return unit_types or alternative_types
|
||||
|
||||
@property
|
||||
def unit_counter(self) -> int:
|
||||
"""TODO Documentation"""
|
||||
default = len(self.units)
|
||||
def group_size(self) -> int:
|
||||
"""The amount of units to be generated. If unit_count is defined in the layout this will be randomized accordingly. Otherwise this will be the maximum size."""
|
||||
if self.unit_count:
|
||||
if len(self.unit_count) == 1:
|
||||
count = self.unit_count[0]
|
||||
else:
|
||||
count = random.choice(range(min(self.unit_count), max(self.unit_count)))
|
||||
if count > default:
|
||||
logging.error(
|
||||
f"UnitCount for Group Layout {self.name} "
|
||||
f"exceeds max available units for this group"
|
||||
)
|
||||
return default
|
||||
return count
|
||||
return default
|
||||
return self.unit_count[0]
|
||||
return random.choice(range(min(self.unit_count), max(self.unit_count)))
|
||||
return self.max_size
|
||||
|
||||
@property
|
||||
def max_size(self) -> int:
|
||||
return len(self.units)
|
||||
return len(self.layout_units)
|
||||
|
||||
def generate_units(
|
||||
self, go: TheaterGroundObject, unit_type: Type[DcsUnitType], amount: int
|
||||
) -> list[TheaterUnit]:
|
||||
"""TODO Documentation"""
|
||||
"""Generate units of the given unit type and amount for the TgoLayoutGroup"""
|
||||
return [
|
||||
TheaterUnit.from_template(i, unit_type, self.units[i], go)
|
||||
TheaterUnit.from_template(i, unit_type, self.layout_units[i], go)
|
||||
for i in range(amount)
|
||||
]
|
||||
|
||||
|
||||
class TheaterLayout:
|
||||
"""TODO Documentation"""
|
||||
class TgoLayout:
|
||||
"""TgoLayout defines how a TheaterGroundObject will be generated from a ForceGroup. This defines the positioning, orientation, type and amount of the actual units
|
||||
|
||||
def __init__(self, name: str, role: GroupRole, description: str = "") -> None:
|
||||
Each TgoLayout is defined in resources/layouts with a .yaml file which has all the
|
||||
information about the Layout next to a .miz file which gives information about the
|
||||
actual position (x, y) and orientation (heading) of the units. The layout file also
|
||||
defines the structure of the DCS group (or groups) that will be spawned in the
|
||||
mission. Complex groups like SAMs protected by point-defense require specific
|
||||
grouping when used with plugins like Skynet. One group would define the main
|
||||
battery (the search and track radars, launchers, C2 units, etc), another would
|
||||
define PD units, and others could define SHORADs or resupply units.
|
||||
|
||||
Each group (representing a DCS group) is further divided into TgoLayoutGroups. As
|
||||
a TgoLayoutGroup only represents a single dcs unit type the logical dcs group of multiple unit types will be created with the usage of a dict which has the DCS Group name as key and a list of TgoLayoutGroups which will be merged into this single dcs group.
|
||||
|
||||
As the TgoLayout will be used to create a TheaterGroundObject for a ForceGroup,
|
||||
specialized classes inherit from this base class. For example there is a special
|
||||
AiDefenseLayout which will be used to create the SamGroundObject from it.
|
||||
"""
|
||||
|
||||
def __init__(self, name: str, description: str = "") -> None:
|
||||
self.name = name
|
||||
self.role = role
|
||||
self.description = description
|
||||
self.tasks: list[GroupTask] = [] # The supported tasks
|
||||
self.groups: list[GroupLayout] = []
|
||||
self.tasks: list[GroupTask] = [] # The supported
|
||||
|
||||
# If the template is generic it will be used the generate the general
|
||||
# UnitGroups during faction initialization. Generic Groups allow to be mixed
|
||||
# Mapping of group name and LayoutGroups for a specific TgoGroup
|
||||
# A Group can have multiple TgoLayoutGroups which get merged together
|
||||
self.groups: dict[str, list[TgoLayoutGroup]] = defaultdict(list)
|
||||
|
||||
# A generic layout will be used to create generic ForceGroups during the
|
||||
# campaign initialization. For each generic layout a new Group will be created.
|
||||
self.generic: bool = False
|
||||
|
||||
def usable_by_faction(self, faction: Faction) -> bool:
|
||||
@ -156,7 +180,7 @@ class TheaterLayout:
|
||||
try:
|
||||
return all(
|
||||
len(group.possible_types_for_faction(faction)) > 0
|
||||
for group in self.groups
|
||||
for group in self.all_groups
|
||||
if not group.optional
|
||||
)
|
||||
except LayoutException:
|
||||
@ -168,22 +192,20 @@ class TheaterLayout:
|
||||
position: PointWithHeading,
|
||||
control_point: ControlPoint,
|
||||
) -> TheaterGroundObject:
|
||||
"""TODO Documentation"""
|
||||
"""Create the TheaterGroundObject for the TgoLayout
|
||||
|
||||
This function has to be implemented by the inheriting class to create
|
||||
a specific TGO like SamGroundObject or BuildingGroundObject
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def add_group(self, new_group: GroupLayout, index: int = 0) -> None:
|
||||
"""Adds a group in the correct order to the template"""
|
||||
if len(self.groups) > index:
|
||||
self.groups.insert(index, new_group)
|
||||
else:
|
||||
self.groups.append(new_group)
|
||||
|
||||
@property
|
||||
def size(self) -> int:
|
||||
return sum([len(group.units) for group in self.groups])
|
||||
def all_groups(self) -> Iterator[TgoLayoutGroup]:
|
||||
for groups in self.groups.values():
|
||||
yield from groups
|
||||
|
||||
|
||||
class AntiAirLayout(TheaterLayout):
|
||||
class AntiAirLayout(TgoLayout):
|
||||
def create_ground_object(
|
||||
self,
|
||||
name: str,
|
||||
@ -200,7 +222,7 @@ class AntiAirLayout(TheaterLayout):
|
||||
)
|
||||
|
||||
|
||||
class BuildingLayout(TheaterLayout):
|
||||
class BuildingLayout(TgoLayout):
|
||||
def create_ground_object(
|
||||
self,
|
||||
name: str,
|
||||
@ -224,7 +246,7 @@ class BuildingLayout(TheaterLayout):
|
||||
raise RuntimeError(f"Building Template {self.name} has no building category")
|
||||
|
||||
|
||||
class NavalLayout(TheaterLayout):
|
||||
class NavalLayout(TgoLayout):
|
||||
def create_ground_object(
|
||||
self,
|
||||
name: str,
|
||||
@ -240,7 +262,7 @@ class NavalLayout(TheaterLayout):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class DefensesLayout(TheaterLayout):
|
||||
class DefensesLayout(TgoLayout):
|
||||
def create_ground_object(
|
||||
self,
|
||||
name: str,
|
||||
@ -258,7 +280,7 @@ class DefensesLayout(TheaterLayout):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class GroundForceLayout(TheaterLayout):
|
||||
class GroundForceLayout(TgoLayout):
|
||||
def create_ground_object(
|
||||
self,
|
||||
name: str,
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
from __future__ import annotations
|
||||
from collections import defaultdict
|
||||
|
||||
import itertools
|
||||
import logging
|
||||
@ -13,10 +14,10 @@ from dcs import Point
|
||||
from dcs.unitgroup import StaticGroup
|
||||
|
||||
from game import persistency
|
||||
from game.data.groups import GroupRole, GroupTask
|
||||
from game.data.groups import GroupRole
|
||||
from game.layout.layout import (
|
||||
TheaterLayout,
|
||||
GroupLayout,
|
||||
TgoLayout,
|
||||
TgoLayoutGroup,
|
||||
LayoutUnit,
|
||||
AntiAirLayout,
|
||||
BuildingLayout,
|
||||
@ -24,7 +25,7 @@ from game.layout.layout import (
|
||||
GroundForceLayout,
|
||||
DefensesLayout,
|
||||
)
|
||||
from game.layout.layoutmapping import GroupLayoutMapping, LayoutMapping
|
||||
from game.layout.layoutmapping import LayoutMapping
|
||||
from game.profiling import logged_duration
|
||||
from game.version import VERSION
|
||||
|
||||
@ -41,21 +42,21 @@ TEMPLATE_TYPES = {
|
||||
|
||||
|
||||
class LayoutLoader:
|
||||
# list of layouts per category. e.g. AA or similar
|
||||
_templates: dict[str, TheaterLayout] = {}
|
||||
# Map of all available layouts indexed by name
|
||||
_layouts: dict[str, TgoLayout] = {}
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._templates = {}
|
||||
self._layouts = {}
|
||||
|
||||
def initialize(self) -> None:
|
||||
if not self._templates:
|
||||
if not self._layouts:
|
||||
with logged_duration("Loading layouts"):
|
||||
self.load_templates()
|
||||
|
||||
@property
|
||||
def layouts(self) -> Iterator[TheaterLayout]:
|
||||
def layouts(self) -> Iterator[TgoLayout]:
|
||||
self.initialize()
|
||||
yield from self._templates.values()
|
||||
yield from self._layouts.values()
|
||||
|
||||
def load_templates(self) -> None:
|
||||
"""This will load all pre-loaded layouts from a pickle file.
|
||||
@ -66,60 +67,43 @@ class LayoutLoader:
|
||||
# Load from pickle if existing
|
||||
with file.open("rb") as f:
|
||||
try:
|
||||
version, self._templates = pickle.load(f)
|
||||
version, self._layouts = pickle.load(f)
|
||||
# Check if the game version of the dump is identical to the current
|
||||
if version == VERSION:
|
||||
return
|
||||
except Exception as e:
|
||||
logging.error(f"Error {e} reading layouts dump. Recreating.")
|
||||
logging.exception(f"Error {e} reading layouts dump. Recreating.")
|
||||
# If no dump is available or game version is different create a new dump
|
||||
self.import_templates()
|
||||
|
||||
def import_templates(self) -> None:
|
||||
"""This will import all layouts from the template folder
|
||||
and dumps them to a pickle"""
|
||||
mappings: dict[str, list[LayoutMapping]] = {}
|
||||
self._layouts = {}
|
||||
mappings: dict[str, list[LayoutMapping]] = defaultdict(list)
|
||||
with logged_duration("Parsing mapping yamls"):
|
||||
for file in Path(TEMPLATE_DIR).rglob("*.yaml"):
|
||||
if not file.is_file():
|
||||
continue
|
||||
raise RuntimeError(f"{file.name} is not a file")
|
||||
with file.open("r", encoding="utf-8") as f:
|
||||
mapping_dict = yaml.safe_load(f)
|
||||
|
||||
template_map = LayoutMapping.from_dict(mapping_dict, f.name)
|
||||
|
||||
if template_map.layout_file in mappings:
|
||||
mappings[template_map.layout_file].append(template_map)
|
||||
else:
|
||||
mappings[template_map.layout_file] = [template_map]
|
||||
mappings[template_map.layout_file].append(template_map)
|
||||
|
||||
with logged_duration(f"Parsing all layout miz multithreaded"):
|
||||
with ThreadPoolExecutor() as exe:
|
||||
for miz, maps in mappings.items():
|
||||
exe.submit(self._load_from_miz, miz, maps)
|
||||
exe.map(self._load_from_miz, mappings.keys(), mappings.values())
|
||||
|
||||
logging.info(f"Imported {len(self._templates)} layouts")
|
||||
logging.info(f"Imported {len(self._layouts)} layouts")
|
||||
self._dump_templates()
|
||||
|
||||
def _dump_templates(self) -> None:
|
||||
file = Path(persistency.base_path()) / TEMPLATE_DUMP
|
||||
dump = (VERSION, self._templates)
|
||||
dump = (VERSION, self._layouts)
|
||||
with file.open("wb") as fdata:
|
||||
pickle.dump(dump, fdata)
|
||||
|
||||
@staticmethod
|
||||
def mapping_for_group(
|
||||
mappings: list[LayoutMapping], group_name: str
|
||||
) -> tuple[LayoutMapping, int, GroupLayoutMapping]:
|
||||
for mapping in mappings:
|
||||
for g_id, group_mapping in enumerate(mapping.groups):
|
||||
if (
|
||||
group_mapping.name == group_name
|
||||
or group_name in group_mapping.statics
|
||||
):
|
||||
return mapping, g_id, group_mapping
|
||||
raise KeyError
|
||||
|
||||
def _load_from_miz(self, miz: str, mappings: list[LayoutMapping]) -> None:
|
||||
template_position: dict[str, Point] = {}
|
||||
temp_mis = dcs.Mission()
|
||||
@ -130,74 +114,68 @@ class LayoutLoader:
|
||||
# the .load_file() method: 0:00:00.920409
|
||||
temp_mis.load_file(miz)
|
||||
|
||||
for country in itertools.chain(
|
||||
temp_mis.coalition["red"].countries.values(),
|
||||
temp_mis.coalition["blue"].countries.values(),
|
||||
):
|
||||
for dcs_group in itertools.chain(
|
||||
temp_mis.country(country.name).vehicle_group,
|
||||
temp_mis.country(country.name).ship_group,
|
||||
temp_mis.country(country.name).static_group,
|
||||
for mapping in mappings:
|
||||
# Find the group from the mapping in any coalition
|
||||
for country in itertools.chain(
|
||||
temp_mis.coalition["red"].countries.values(),
|
||||
temp_mis.coalition["blue"].countries.values(),
|
||||
):
|
||||
try:
|
||||
mapping, group_id, group_mapping = self.mapping_for_group(
|
||||
mappings, dcs_group.name
|
||||
)
|
||||
except KeyError:
|
||||
logging.warning(f"No mapping for dcs group {dcs_group.name}")
|
||||
continue
|
||||
for dcs_group in itertools.chain(
|
||||
temp_mis.country(country.name).vehicle_group,
|
||||
temp_mis.country(country.name).ship_group,
|
||||
temp_mis.country(country.name).static_group,
|
||||
):
|
||||
|
||||
template = self._templates.get(mapping.name, None)
|
||||
if template is None:
|
||||
# Create a new template
|
||||
template = TEMPLATE_TYPES[mapping.role](
|
||||
mapping.name, mapping.role, mapping.description
|
||||
)
|
||||
template.generic = mapping.generic
|
||||
template.tasks = mapping.tasks
|
||||
self._templates[template.name] = template
|
||||
|
||||
for i, unit in enumerate(dcs_group.units):
|
||||
group_template = None
|
||||
for group in template.groups:
|
||||
if group.name == group_mapping.name:
|
||||
# We already have a layoutgroup for this dcs_group
|
||||
group_template = group
|
||||
if not group_template:
|
||||
group_template = GroupLayout(
|
||||
group_mapping.name,
|
||||
[],
|
||||
group_mapping.group,
|
||||
group_mapping.unit_count,
|
||||
group_mapping.unit_types,
|
||||
group_mapping.unit_classes,
|
||||
group_mapping.alternative_classes,
|
||||
try:
|
||||
group_name, group_mapping = mapping.group_for_name(
|
||||
dcs_group.name
|
||||
)
|
||||
group_template.optional = group_mapping.optional
|
||||
# Add the group at the correct position
|
||||
template.add_group(group_template, group_id)
|
||||
unit_template = LayoutUnit.from_unit(unit)
|
||||
if i == 0 and template.name not in template_position:
|
||||
template_position[template.name] = unit.position
|
||||
unit_template.position = (
|
||||
unit_template.position - template_position[template.name]
|
||||
)
|
||||
group_template.units.append(unit_template)
|
||||
except KeyError:
|
||||
continue
|
||||
|
||||
def by_name(self, template_name: str) -> Iterator[TheaterLayout]:
|
||||
for template in self.layouts:
|
||||
if template.name == template_name:
|
||||
yield template
|
||||
if not isinstance(dcs_group, StaticGroup) and max(
|
||||
group_mapping.unit_count
|
||||
) > len(dcs_group.units):
|
||||
logging.error(
|
||||
f"Incorrect unit_count found in Layout {mapping.name}-{group_mapping.name}"
|
||||
)
|
||||
|
||||
def by_task(self, group_task: GroupTask) -> Iterator[TheaterLayout]:
|
||||
for template in self.layouts:
|
||||
if not group_task or group_task in template.tasks:
|
||||
yield template
|
||||
layout = self._layouts.get(mapping.name, None)
|
||||
if layout is None:
|
||||
# Create a new template
|
||||
layout = TEMPLATE_TYPES[mapping.primary_role](
|
||||
mapping.name, mapping.description
|
||||
)
|
||||
layout.generic = mapping.generic
|
||||
layout.tasks = mapping.tasks
|
||||
self._layouts[layout.name] = layout
|
||||
|
||||
def by_tasks(self, group_tasks: list[GroupTask]) -> Iterator[TheaterLayout]:
|
||||
unique_templates = []
|
||||
for group_task in group_tasks:
|
||||
for template in self.by_task(group_task):
|
||||
if template not in unique_templates:
|
||||
unique_templates.append(template)
|
||||
yield from unique_templates
|
||||
for i, unit in enumerate(dcs_group.units):
|
||||
group_layout = None
|
||||
for group in layout.all_groups:
|
||||
if group.name == group_mapping.name:
|
||||
# We already have a layoutgroup for this dcs_group
|
||||
group_layout = group
|
||||
if not group_layout:
|
||||
group_layout = TgoLayoutGroup(
|
||||
group_mapping.name,
|
||||
[],
|
||||
group_mapping.unit_count,
|
||||
group_mapping.unit_types,
|
||||
group_mapping.unit_classes,
|
||||
group_mapping.fallback_classes,
|
||||
)
|
||||
group_layout.optional = group_mapping.optional
|
||||
# Add the group at the correct position
|
||||
layout.groups[group_name].append(group_layout)
|
||||
layout_unit = LayoutUnit.from_unit(unit)
|
||||
if i == 0 and layout.name not in template_position:
|
||||
template_position[layout.name] = unit.position
|
||||
layout_unit.position = (
|
||||
layout_unit.position - template_position[layout.name]
|
||||
)
|
||||
group_layout.layout_units.append(layout_unit)
|
||||
|
||||
def by_name(self, name: str) -> TgoLayout:
|
||||
self.initialize()
|
||||
return self._layouts[name]
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
from __future__ import annotations
|
||||
from collections import defaultdict
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any, Type
|
||||
|
||||
from dcs.unittype import UnitType as DcsUnitType
|
||||
|
||||
from game import db
|
||||
from game.data.groups import GroupRole, GroupTask
|
||||
from game.data.units import UnitClass
|
||||
from game.dcs.helpers import unit_type_from_name
|
||||
|
||||
|
||||
@dataclass
|
||||
@ -21,10 +22,6 @@ class GroupLayoutMapping:
|
||||
# All static units for the group
|
||||
statics: list[str] = field(default_factory=list)
|
||||
|
||||
# Defines to which tgo group the groupTemplate will be added
|
||||
# This allows to merge groups back together. Default: Merge all to group 1
|
||||
group: int = field(default=1)
|
||||
|
||||
# How many units should be generated from the grouplayout. If only one value is
|
||||
# added this will be an exact amount. If 2 values are used it will be a random
|
||||
# amount between these values.
|
||||
@ -36,31 +33,9 @@ class GroupLayoutMapping:
|
||||
# All unit classes the template supports.
|
||||
unit_classes: list[UnitClass] = field(default_factory=list)
|
||||
|
||||
# TODO Clarify if this is required. Only used for EWRs to also Use SR when no
|
||||
# Fallback Classes which are used when the unit_classes and unit_types do not fit any accessible unit from the faction. Only used for EWRs to also Use SR when no
|
||||
# dedicated EWRs are available to the faction
|
||||
alternative_classes: list[UnitClass] = field(default_factory=list)
|
||||
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
d = self.__dict__
|
||||
if not self.optional:
|
||||
d.pop("optional")
|
||||
if not self.statics:
|
||||
d.pop("statics")
|
||||
if not self.unit_types:
|
||||
d.pop("unit_types")
|
||||
if not self.unit_classes:
|
||||
d.pop("unit_classes")
|
||||
else:
|
||||
d["unit_classes"] = [unit_class.value for unit_class in self.unit_classes]
|
||||
if not self.alternative_classes:
|
||||
d.pop("alternative_classes")
|
||||
else:
|
||||
d["alternative_classes"] = [
|
||||
unit_class.value for unit_class in self.alternative_classes
|
||||
]
|
||||
if not self.unit_count:
|
||||
d.pop("unit_count")
|
||||
return d
|
||||
fallback_classes: list[UnitClass] = field(default_factory=list)
|
||||
|
||||
@staticmethod
|
||||
def from_dict(d: dict[str, Any]) -> GroupLayoutMapping:
|
||||
@ -70,27 +45,25 @@ class GroupLayoutMapping:
|
||||
unit_types = []
|
||||
if "unit_types" in d:
|
||||
for u in d["unit_types"]:
|
||||
unit_type = db.unit_type_from_name(u)
|
||||
unit_type = unit_type_from_name(u)
|
||||
if unit_type:
|
||||
unit_types.append(unit_type)
|
||||
group = d["group"] if "group" in d else 1
|
||||
unit_classes = (
|
||||
[UnitClass(u) for u in d["unit_classes"]] if "unit_classes" in d else []
|
||||
)
|
||||
alternative_classes = (
|
||||
[UnitClass(u) for u in d["alternative_classes"]]
|
||||
if "alternative_classes" in d
|
||||
fallback_classes = (
|
||||
[UnitClass(u) for u in d["fallback_classes"]]
|
||||
if "fallback_classes" in d
|
||||
else []
|
||||
)
|
||||
return GroupLayoutMapping(
|
||||
d["name"],
|
||||
optional,
|
||||
statics,
|
||||
group,
|
||||
unit_count,
|
||||
unit_types,
|
||||
unit_classes,
|
||||
alternative_classes,
|
||||
fallback_classes,
|
||||
)
|
||||
|
||||
|
||||
@ -105,40 +78,31 @@ class LayoutMapping:
|
||||
# Optional field to define if the template can be used to create generic groups
|
||||
generic: bool
|
||||
|
||||
# The role the template can be used for
|
||||
role: GroupRole
|
||||
|
||||
# All taskings the template can be used for
|
||||
tasks: list[GroupTask]
|
||||
|
||||
# All Groups the template has
|
||||
groups: list[GroupLayoutMapping]
|
||||
groups: dict[str, list[GroupLayoutMapping]]
|
||||
|
||||
# Define the miz file for the template. Optional. If empty use the mapping name
|
||||
layout_file: str
|
||||
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
d = {
|
||||
"name": self.name,
|
||||
"description": self.description,
|
||||
"generic": self.generic,
|
||||
"role": self.role.value,
|
||||
"tasks": [task.description for task in self.tasks],
|
||||
"groups": [group.to_dict() for group in self.groups],
|
||||
"layout_file": self.layout_file,
|
||||
}
|
||||
if not self.description:
|
||||
d.pop("description")
|
||||
if not self.generic:
|
||||
# Only save if true
|
||||
d.pop("generic")
|
||||
if not self.layout_file:
|
||||
d.pop("layout_file")
|
||||
return d
|
||||
@property
|
||||
def primary_role(self) -> GroupRole:
|
||||
return self.tasks[0].role
|
||||
|
||||
@staticmethod
|
||||
def from_dict(d: dict[str, Any], file_name: str) -> LayoutMapping:
|
||||
groups = [GroupLayoutMapping.from_dict(group) for group in d["groups"]]
|
||||
groups: dict[str, list[GroupLayoutMapping]] = defaultdict(list)
|
||||
for group in d["groups"]:
|
||||
for group_name, group_layouts in group.items():
|
||||
groups[group_name].extend(
|
||||
[
|
||||
GroupLayoutMapping.from_dict(group_layout)
|
||||
for group_layout in group_layouts
|
||||
]
|
||||
)
|
||||
|
||||
description = d["description"] if "description" in d else ""
|
||||
generic = d["generic"] if "generic" in d else False
|
||||
layout_file = (
|
||||
@ -149,8 +113,14 @@ class LayoutMapping:
|
||||
d["name"],
|
||||
description,
|
||||
generic,
|
||||
GroupRole(d["role"]),
|
||||
tasks,
|
||||
groups,
|
||||
layout_file,
|
||||
)
|
||||
|
||||
def group_for_name(self, name: str) -> tuple[str, GroupLayoutMapping]:
|
||||
for group_name, group_mappings in self.groups.items():
|
||||
for group_mapping in group_mappings:
|
||||
if group_mapping.name == name or name in group_mapping.statics:
|
||||
return group_name, group_mapping
|
||||
raise KeyError
|
||||
|
||||
@ -153,11 +153,6 @@ class ControlPointGroundObjectGenerator:
|
||||
self.generate_navy()
|
||||
return True
|
||||
|
||||
def generate_random_ground_object(
|
||||
self, unit_groups: list[ForceGroup], position: PointWithHeading
|
||||
) -> None:
|
||||
self.generate_ground_object_from_group(random.choice(unit_groups), position)
|
||||
|
||||
def generate_ground_object_from_group(
|
||||
self, unit_group: ForceGroup, position: PointWithHeading
|
||||
) -> None:
|
||||
|
||||
@ -3,7 +3,7 @@ from __future__ import annotations
|
||||
import itertools
|
||||
import logging
|
||||
from abc import ABC
|
||||
from typing import Iterator, List, TYPE_CHECKING
|
||||
from typing import Iterator, List, TYPE_CHECKING, Optional
|
||||
|
||||
from dcs.unittype import VehicleType
|
||||
from dcs.vehicles import vehicle_map
|
||||
@ -205,6 +205,12 @@ class TheaterGroundObject(MissionTarget):
|
||||
def purchasable(self) -> bool:
|
||||
raise NotImplementedError
|
||||
|
||||
def group_by_name(self, name: str) -> Optional[TheaterGroup]:
|
||||
for group in self.groups:
|
||||
if group.name == name:
|
||||
return group
|
||||
return None
|
||||
|
||||
|
||||
class BuildingGroundObject(TheaterGroundObject):
|
||||
def __init__(
|
||||
|
||||
@ -16,7 +16,7 @@ from game.point_with_heading import PointWithHeading
|
||||
from game.utils import Heading
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game.layout.layout import LayoutUnit, GroupLayout
|
||||
from game.layout.layout import LayoutUnit, TgoLayoutGroup
|
||||
from game.theater import TheaterGroundObject
|
||||
|
||||
|
||||
@ -141,16 +141,17 @@ class TheaterGroup:
|
||||
@staticmethod
|
||||
def from_template(
|
||||
id: int,
|
||||
g: GroupLayout,
|
||||
name: str,
|
||||
units: list[TheaterUnit],
|
||||
go: TheaterGroundObject,
|
||||
unit_type: Type[DcsUnitType],
|
||||
unit_count: int,
|
||||
) -> TheaterGroup:
|
||||
return TheaterGroup(
|
||||
id,
|
||||
g.name,
|
||||
name,
|
||||
PointWithHeading.from_point(go.position, go.heading),
|
||||
g.generate_units(go, unit_type, unit_count),
|
||||
units,
|
||||
go,
|
||||
)
|
||||
|
||||
|
||||
@ -18,10 +18,11 @@ from PySide2.QtWidgets import (
|
||||
)
|
||||
|
||||
import qt_ui.uiconstants as CONST
|
||||
from game import Game, VERSION, persistency, db
|
||||
from game import Game, VERSION, persistency
|
||||
from game.debriefing import Debriefing
|
||||
from game.server import EventStream, GameContext
|
||||
from game.server.security import ApiKeyManager
|
||||
from game.layout import LAYOUTS
|
||||
from qt_ui import liberation_install
|
||||
from qt_ui.dialogs import Dialog
|
||||
from qt_ui.models import GameModel
|
||||
@ -400,7 +401,7 @@ class QLiberationWindow(QMainWindow):
|
||||
self.dialog.show()
|
||||
|
||||
def import_templates(self):
|
||||
db.LAYOUTS.import_templates()
|
||||
LAYOUTS.import_templates()
|
||||
|
||||
def showLogsDialog(self):
|
||||
self.dialog = QLogsWindow()
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
from collections import defaultdict
|
||||
import logging
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Type
|
||||
@ -14,6 +15,7 @@ from PySide2.QtWidgets import (
|
||||
QSpinBox,
|
||||
QVBoxLayout,
|
||||
QCheckBox,
|
||||
QWidget,
|
||||
)
|
||||
from dcs.unittype import UnitType
|
||||
|
||||
@ -29,16 +31,17 @@ from game.theater.theatergroundobject import (
|
||||
)
|
||||
from game.theater.theatergroup import TheaterGroup
|
||||
from game.layout.layout import (
|
||||
TheaterLayout,
|
||||
GroupLayout,
|
||||
LayoutException,
|
||||
TgoLayout,
|
||||
TgoLayoutGroup,
|
||||
)
|
||||
from qt_ui.uiconstants import EVENT_ICONS
|
||||
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
|
||||
|
||||
|
||||
@dataclass
|
||||
class QGroupLayout:
|
||||
layout: GroupLayout
|
||||
class QTgoLayoutGroup:
|
||||
layout: TgoLayoutGroup
|
||||
dcs_unit_type: Type[UnitType]
|
||||
amount: int
|
||||
unit_price: int
|
||||
@ -50,41 +53,45 @@ class QGroupLayout:
|
||||
|
||||
|
||||
@dataclass
|
||||
class QLayout:
|
||||
layout: TheaterLayout
|
||||
class QTgoLayout:
|
||||
layout: TgoLayout
|
||||
force_group: ForceGroup
|
||||
group_layouts: list[QGroupLayout] = field(default_factory=list)
|
||||
groups: dict[str, list[QTgoLayoutGroup]] = field(default_factory=dict)
|
||||
|
||||
@property
|
||||
def price(self) -> int:
|
||||
return sum(group.price for group in self.group_layouts)
|
||||
return sum(group.price for groups in self.groups.values() for group in groups)
|
||||
|
||||
|
||||
class QGroundObjectGroupTemplate(QGroupBox):
|
||||
class QTgoLayoutGroupRow(QWidget):
|
||||
group_template_changed = Signal()
|
||||
|
||||
def __init__(
|
||||
self, group_id: int, force_group: ForceGroup, group_layout: GroupLayout
|
||||
) -> None:
|
||||
super().__init__(f"{group_id + 1}: {group_layout.name}")
|
||||
def __init__(self, force_group: ForceGroup, group: TgoLayoutGroup) -> None:
|
||||
super().__init__()
|
||||
self.grid_layout = QGridLayout()
|
||||
self.setLayout(self.grid_layout)
|
||||
|
||||
self.grid_layout.setColumnStretch(0, 100)
|
||||
self.amount_selector = QSpinBox()
|
||||
self.unit_selector = QComboBox()
|
||||
self.unit_selector.setMinimumWidth(250)
|
||||
self.group_selector = QCheckBox()
|
||||
|
||||
# Add all possible units with the price
|
||||
for unit_type in force_group.unit_types_for_group(group_layout):
|
||||
for unit_type in force_group.unit_types_for_group(group):
|
||||
self.unit_selector.addItem(
|
||||
f"{unit_type.name} [${unit_type.price}M]",
|
||||
userData=(unit_type.dcs_unit_type, unit_type.price),
|
||||
)
|
||||
# Add all possible statics with price = 0
|
||||
for static_type in force_group.statics_for_group(group_layout):
|
||||
for static_type in force_group.statics_for_group(group):
|
||||
self.unit_selector.addItem(
|
||||
f"{static_type} (Static)", userData=(static_type, 0)
|
||||
)
|
||||
|
||||
if self.unit_selector.count() == 0:
|
||||
raise LayoutException("No units available for the TgoLayoutGroup")
|
||||
|
||||
self.unit_selector.adjustSize()
|
||||
self.unit_selector.setEnabled(self.unit_selector.count() > 1)
|
||||
self.grid_layout.addWidget(self.unit_selector, 0, 0, alignment=Qt.AlignRight)
|
||||
self.grid_layout.addWidget(self.amount_selector, 0, 1, alignment=Qt.AlignRight)
|
||||
@ -93,9 +100,7 @@ class QGroundObjectGroupTemplate(QGroupBox):
|
||||
self.unit_selector.currentIndex()
|
||||
)
|
||||
|
||||
self.group_layout = QGroupLayout(
|
||||
group_layout, unit_type, group_layout.unit_counter, price
|
||||
)
|
||||
self.group_layout = QTgoLayoutGroup(group, unit_type, group.group_size, price)
|
||||
|
||||
self.group_selector.setChecked(self.group_layout.enabled)
|
||||
self.group_selector.setEnabled(self.group_layout.layout.optional)
|
||||
@ -127,11 +132,11 @@ class QGroundObjectTemplateLayout(QGroupBox):
|
||||
self,
|
||||
game: Game,
|
||||
ground_object: TheaterGroundObject,
|
||||
layout: QLayout,
|
||||
layout_changed_signal: Signal(QLayout),
|
||||
layout: QTgoLayout,
|
||||
layout_changed_signal: Signal(QTgoLayout),
|
||||
current_group_value: int,
|
||||
):
|
||||
super().__init__("Groups:")
|
||||
super().__init__()
|
||||
# Connect to the signal to handle template updates
|
||||
self.game = game
|
||||
self.ground_object = ground_object
|
||||
@ -158,21 +163,32 @@ class QGroundObjectTemplateLayout(QGroupBox):
|
||||
# Load Layout
|
||||
self.load_for_layout(self.layout_model)
|
||||
|
||||
def load_for_layout(self, layout: QLayout) -> None:
|
||||
def load_for_layout(self, layout: QTgoLayout) -> None:
|
||||
self.layout_model = layout
|
||||
# Clean the current grid
|
||||
self.layout_model.groups = defaultdict(list)
|
||||
for id in range(self.template_grid.count()):
|
||||
self.template_grid.itemAt(id).widget().deleteLater()
|
||||
for g_id, layout_group in enumerate(self.layout_model.layout.groups):
|
||||
group_row = QGroundObjectGroupTemplate(
|
||||
g_id, self.layout_model.force_group, layout_group
|
||||
)
|
||||
self.layout_model.group_layouts.append(group_row.group_layout)
|
||||
group_row.group_template_changed.connect(self.group_template_changed)
|
||||
self.template_grid.addWidget(group_row)
|
||||
|
||||
for group_name, groups in self.layout_model.layout.groups.items():
|
||||
self.add_theater_group(group_name, self.layout_model.force_group, groups)
|
||||
self.group_template_changed()
|
||||
|
||||
def add_theater_group(
|
||||
self, group_name: str, force_group: ForceGroup, groups: list[TgoLayoutGroup]
|
||||
) -> None:
|
||||
group_box = QGroupBox(group_name)
|
||||
vbox_layout = QVBoxLayout()
|
||||
for group in groups:
|
||||
try:
|
||||
group_row = QTgoLayoutGroupRow(force_group, group)
|
||||
except LayoutException:
|
||||
continue
|
||||
self.layout_model.groups[group_name].append(group_row.group_layout)
|
||||
group_row.group_template_changed.connect(self.group_template_changed)
|
||||
vbox_layout.addWidget(group_row)
|
||||
group_box.setLayout(vbox_layout)
|
||||
self.template_grid.addWidget(group_box)
|
||||
|
||||
def group_template_changed(self) -> None:
|
||||
price = self.layout_model.price
|
||||
self.buy_button.setText(f"Buy [${price}M][-${self.current_group_value}M]")
|
||||
@ -182,54 +198,40 @@ class QGroundObjectTemplateLayout(QGroupBox):
|
||||
else:
|
||||
self.buy_button.setToolTip("Not enough money to buy this group")
|
||||
|
||||
def buy_group(self):
|
||||
if not self.layout:
|
||||
raise RuntimeError("No template selected. GroundObject can not be bought.")
|
||||
|
||||
def buy_group(self) -> None:
|
||||
price = self.layout_model.price
|
||||
if price > self.game.blue.budget:
|
||||
# Somethin went wrong. Buy button should be disabled!
|
||||
# Something went wrong. Buy button should be disabled!
|
||||
logging.error("Not enough money to buy the group")
|
||||
return
|
||||
self.game.blue.budget -= price - self.current_group_value
|
||||
self.ground_object.groups = self.generate_groups()
|
||||
self.ground_object.groups = []
|
||||
for group_name, groups in self.layout_model.groups.items():
|
||||
for group in groups:
|
||||
self.layout_model.force_group.create_theater_group_for_tgo(
|
||||
self.ground_object,
|
||||
group.layout,
|
||||
f"{self.ground_object.name} ({group_name})",
|
||||
self.game,
|
||||
group.dcs_unit_type, # Forced Type
|
||||
group.amount, # Forced Amount
|
||||
)
|
||||
|
||||
# Replan redfor missions
|
||||
self.game.initialize_turn(for_red=True, for_blue=False)
|
||||
GameUpdateSignal.get_instance().updateGame(self.game)
|
||||
|
||||
def generate_groups(self) -> list[TheaterGroup]:
|
||||
go = self.layout_model.layout.create_ground_object(
|
||||
self.ground_object.name,
|
||||
PointWithHeading.from_point(
|
||||
self.ground_object.position, self.ground_object.heading
|
||||
),
|
||||
self.ground_object.control_point,
|
||||
)
|
||||
|
||||
for group in self.layout_model.group_layouts:
|
||||
self.layout_model.force_group.create_theater_group_for_tgo(
|
||||
go,
|
||||
group.layout,
|
||||
self.ground_object.name,
|
||||
self.game,
|
||||
group.dcs_unit_type, # Forced Type
|
||||
group.amount, # Forced Amount
|
||||
)
|
||||
|
||||
return go.groups
|
||||
|
||||
|
||||
class QGroundObjectBuyMenu(QDialog):
|
||||
layout_changed_signal = Signal(QLayout)
|
||||
layout_changed_signal = Signal(QTgoLayout)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
parent,
|
||||
parent: QWidget,
|
||||
ground_object: TheaterGroundObject,
|
||||
game: Game,
|
||||
current_group_value: int,
|
||||
):
|
||||
) -> None:
|
||||
super().__init__(parent)
|
||||
|
||||
self.setMinimumWidth(350)
|
||||
@ -241,7 +243,9 @@ class QGroundObjectBuyMenu(QDialog):
|
||||
self.setLayout(self.mainLayout)
|
||||
|
||||
self.force_group_selector = QComboBox()
|
||||
self.force_group_selector.setMinimumWidth(250)
|
||||
self.layout_selector = QComboBox()
|
||||
self.layout_selector.setMinimumWidth(250)
|
||||
self.layout_selector.setEnabled(False)
|
||||
|
||||
# Get the layouts and fill the combobox
|
||||
@ -262,19 +266,19 @@ class QGroundObjectBuyMenu(QDialog):
|
||||
for group in game.blue.armed_forces.groups_for_tasks(tasks):
|
||||
self.force_group_selector.addItem(group.name, userData=group)
|
||||
self.force_group_selector.setEnabled(self.force_group_selector.count() > 1)
|
||||
|
||||
self.force_group_selector.adjustSize()
|
||||
force_group = self.force_group_selector.itemData(
|
||||
self.force_group_selector.currentIndex()
|
||||
)
|
||||
|
||||
for layout in force_group.layouts:
|
||||
self.layout_selector.addItem(layout.name, userData=layout)
|
||||
|
||||
self.layout_selector.adjustSize()
|
||||
selected_template = self.layout_selector.itemData(
|
||||
self.layout_selector.currentIndex()
|
||||
)
|
||||
|
||||
self.layout_model = QLayout(selected_template, force_group)
|
||||
self.theater_layout = QTgoLayout(selected_template, force_group)
|
||||
|
||||
self.layout_selector.currentIndexChanged.connect(self.layout_changed)
|
||||
self.force_group_selector.currentIndexChanged.connect(self.force_group_changed)
|
||||
@ -295,7 +299,7 @@ class QGroundObjectBuyMenu(QDialog):
|
||||
self.template_layout = QGroundObjectTemplateLayout(
|
||||
game,
|
||||
ground_object,
|
||||
self.layout_model,
|
||||
self.theater_layout,
|
||||
self.layout_changed_signal,
|
||||
current_group_value,
|
||||
)
|
||||
@ -311,19 +315,19 @@ class QGroundObjectBuyMenu(QDialog):
|
||||
self.layout_selector.clear()
|
||||
for layout in unit_group.layouts:
|
||||
self.layout_selector.addItem(layout.name, userData=layout)
|
||||
self.layout_selector.adjustSize()
|
||||
# Enable if more than one template is available
|
||||
self.layout_selector.setEnabled(len(unit_group.layouts) > 1)
|
||||
# Enable Combobox Signals again
|
||||
self.layout_selector.blockSignals(False)
|
||||
self.layout_changed()
|
||||
|
||||
def layout_changed(self):
|
||||
def layout_changed(self) -> None:
|
||||
self.layout()
|
||||
self.layout_model.layout = self.layout_selector.itemData(
|
||||
self.theater_layout.layout = self.layout_selector.itemData(
|
||||
self.layout_selector.currentIndex()
|
||||
)
|
||||
self.layout_model.force_group = self.force_group_selector.itemData(
|
||||
self.theater_layout.force_group = self.force_group_selector.itemData(
|
||||
self.force_group_selector.currentIndex()
|
||||
)
|
||||
self.layout_model.group_layouts = []
|
||||
self.layout_changed_signal.emit(self.layout_model)
|
||||
self.layout_changed_signal.emit(self.theater_layout)
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
name: Ally Flak
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- AAA
|
||||
units:
|
||||
@ -1,5 +1,4 @@
|
||||
name: Carrier Strike Group 8
|
||||
role: Naval
|
||||
tasks:
|
||||
- Navy
|
||||
units:
|
||||
@ -1,5 +1,4 @@
|
||||
name: Chinese Navy
|
||||
role: Naval
|
||||
tasks:
|
||||
- Navy
|
||||
units:
|
||||
@ -1,5 +1,4 @@
|
||||
name: Cold-War-Flak
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- AAA
|
||||
units:
|
||||
@ -1,5 +1,4 @@
|
||||
name: Flak
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- AAA
|
||||
units:
|
||||
@ -1,5 +1,4 @@
|
||||
name: Freya
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- SHORAD
|
||||
units:
|
||||
@ -1,5 +1,4 @@
|
||||
name: HQ-7
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- SHORAD
|
||||
units:
|
||||
@ -1,5 +1,4 @@
|
||||
name: Hawk
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- MERAD
|
||||
units:
|
||||
@ -1,5 +1,4 @@
|
||||
name: KS-19
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- AAA
|
||||
units:
|
||||
@ -1,5 +1,4 @@
|
||||
name: NASAMS AIM-120B
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- MERAD
|
||||
units:
|
||||
@ -1,5 +1,4 @@
|
||||
name: NASAMS AIM-120C
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- MERAD
|
||||
units:
|
||||
@ -1,5 +1,4 @@
|
||||
name: Patriot
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- LORAD
|
||||
units:
|
||||
@ -1,5 +1,4 @@
|
||||
name: Rapier
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- SHORAD
|
||||
units:
|
||||
@ -1,5 +1,4 @@
|
||||
name: Roland
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- SHORAD
|
||||
units:
|
||||
@ -1,5 +1,4 @@
|
||||
name: Russian Navy
|
||||
role: Naval
|
||||
tasks:
|
||||
- Navy
|
||||
units:
|
||||
@ -1,5 +1,4 @@
|
||||
name: SA-10/S-300PS
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- LORAD
|
||||
units:
|
||||
@ -1,5 +1,4 @@
|
||||
name: SA-10B/S-300PS
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- LORAD
|
||||
units:
|
||||
@ -1,5 +1,4 @@
|
||||
name: SA-11
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- MERAD
|
||||
units:
|
||||
@ -1,5 +1,4 @@
|
||||
name: SA-12/S-300V
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- LORAD
|
||||
units:
|
||||
@ -1,5 +1,4 @@
|
||||
name: SA-17
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- MERAD
|
||||
units:
|
||||
@ -1,5 +1,4 @@
|
||||
name: SA-2/S-75
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- MERAD
|
||||
units:
|
||||
@ -1,5 +1,4 @@
|
||||
name: SA-20/S-300PMU-1
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- LORAD
|
||||
units:
|
||||
@ -1,5 +1,4 @@
|
||||
name: SA-20B/S-300PMU-2
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- LORAD
|
||||
units:
|
||||
@ -1,5 +1,4 @@
|
||||
name: SA-23/S-300VM
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- LORAD
|
||||
units:
|
||||
@ -1,5 +1,4 @@
|
||||
name: SA-3/S-125
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- MERAD
|
||||
units:
|
||||
@ -1,5 +1,4 @@
|
||||
name: SA-5/S-200
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- LORAD
|
||||
units:
|
||||
@ -1,5 +1,4 @@
|
||||
name: SA-6
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- MERAD
|
||||
units:
|
||||
@ -1,5 +1,4 @@
|
||||
name: Silkworm
|
||||
role: Defenses
|
||||
tasks:
|
||||
- Coastal
|
||||
units:
|
||||
@ -1,5 +1,4 @@
|
||||
name: WW2LST
|
||||
role: Naval
|
||||
tasks:
|
||||
- Navy
|
||||
units:
|
||||
@ -1,23 +1,21 @@
|
||||
name: AAA Mobile
|
||||
description: A standard AAA template
|
||||
generic: true
|
||||
role: AntiAir
|
||||
generic: true # This Layout will be used to generate ForceGroups
|
||||
tasks:
|
||||
- AAA
|
||||
groups:
|
||||
- name: AAA Mobile 0
|
||||
group: 1
|
||||
unit_count:
|
||||
- 2
|
||||
- 6
|
||||
unit_classes:
|
||||
- AAA
|
||||
- name: AAA Mobile 1
|
||||
optional: true
|
||||
group: 1
|
||||
unit_count:
|
||||
- 1
|
||||
- 2
|
||||
unit_classes:
|
||||
- Logistics
|
||||
- AAA: # Group Name
|
||||
- name: AAA Mobile 0 # Sub group which will be merged into the group
|
||||
unit_count:
|
||||
- 2
|
||||
- 6
|
||||
unit_classes:
|
||||
- AAA
|
||||
- name: AAA Mobile 1 # Sub group which will be merged into the group
|
||||
optional: true
|
||||
unit_count:
|
||||
- 1
|
||||
- 2
|
||||
unit_classes:
|
||||
- Logistics
|
||||
layout_file: resources/layouts/anti_air/AAA.miz
|
||||
@ -1,29 +1,26 @@
|
||||
name: AAA Radar Site
|
||||
description: AAA Template with a Radar
|
||||
generic: false
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- AAA
|
||||
groups:
|
||||
- name: AAA Radar Site 0
|
||||
group: 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_classes:
|
||||
- SearchRadar
|
||||
- name: AAA Radar Site 1
|
||||
group: 1
|
||||
unit_count:
|
||||
- 2
|
||||
- 6
|
||||
unit_classes:
|
||||
- AAA
|
||||
- name: AAA Radar Site 2
|
||||
optional: true
|
||||
group: 1
|
||||
unit_count:
|
||||
- 1
|
||||
- 2
|
||||
unit_classes:
|
||||
- Logistics
|
||||
- AAA:
|
||||
- name: AAA Radar Site 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_classes:
|
||||
- SearchRadar
|
||||
- name: AAA Radar Site 1
|
||||
unit_count:
|
||||
- 2
|
||||
- 6
|
||||
unit_classes:
|
||||
- AAA
|
||||
- name: AAA Radar Site 2
|
||||
optional: true
|
||||
unit_count:
|
||||
- 1
|
||||
- 2
|
||||
unit_classes:
|
||||
- Logistics
|
||||
layout_file: resources/layouts/anti_air/AAA.miz
|
||||
@ -1,23 +1,21 @@
|
||||
name: AAA Site
|
||||
description: A standard AAA template
|
||||
generic: true
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- AAA
|
||||
groups:
|
||||
- name: AAA Site 0
|
||||
group: 1
|
||||
unit_count:
|
||||
- 2
|
||||
- 6
|
||||
unit_classes:
|
||||
- AAA
|
||||
- name: AAA Site 1
|
||||
optional: true
|
||||
group: 1
|
||||
unit_count:
|
||||
- 1
|
||||
- 2
|
||||
unit_classes:
|
||||
- Logistics
|
||||
- AAA:
|
||||
- name: AAA Site 0
|
||||
unit_count:
|
||||
- 2
|
||||
- 6
|
||||
unit_classes:
|
||||
- AAA
|
||||
- name: AAA Site 1
|
||||
optional: true
|
||||
unit_count:
|
||||
- 1
|
||||
- 2
|
||||
unit_classes:
|
||||
- Logistics
|
||||
layout_file: resources/layouts/anti_air/AAA.miz
|
||||
@ -1,36 +1,36 @@
|
||||
name: Cold War Flak Site
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- AAA
|
||||
groups:
|
||||
- name: Cold War Flak Site Radar
|
||||
optional: true # Only available to Late Cold War
|
||||
unit_count:
|
||||
- 1
|
||||
unit_classes:
|
||||
- SearchRadar
|
||||
- name: Cold War Flak Site Flak
|
||||
unit_count:
|
||||
- 4
|
||||
- 6
|
||||
unit_types:
|
||||
- flak18
|
||||
- name: Cold War Flak Site S-60
|
||||
unit_count:
|
||||
- 2
|
||||
unit_types:
|
||||
- S-60_Type59_Artillery
|
||||
- name: Cold War Flak Site AAA
|
||||
optional: true
|
||||
unit_count:
|
||||
- 2
|
||||
unit_classes:
|
||||
- AAA
|
||||
- name: Cold War Flak Site Logistics
|
||||
optional: true
|
||||
unit_count:
|
||||
- 1
|
||||
- 2
|
||||
unit_classes:
|
||||
- Logistics
|
||||
- AAA:
|
||||
- name: Cold War Flak Site Radar
|
||||
optional: true # Only available to Late Cold War
|
||||
unit_count:
|
||||
- 1
|
||||
unit_classes:
|
||||
- SearchRadar
|
||||
- name: Cold War Flak Site Flak
|
||||
unit_count:
|
||||
- 4
|
||||
- 6
|
||||
unit_types:
|
||||
- flak18
|
||||
- name: Cold War Flak Site S-60
|
||||
unit_count:
|
||||
- 2
|
||||
unit_types:
|
||||
- S-60_Type59_Artillery
|
||||
- name: Cold War Flak Site AAA
|
||||
optional: true
|
||||
unit_count:
|
||||
- 2
|
||||
unit_classes:
|
||||
- AAA
|
||||
- name: Cold War Flak Site Logistics
|
||||
optional: true
|
||||
unit_count:
|
||||
- 1
|
||||
- 2
|
||||
unit_classes:
|
||||
- Logistics
|
||||
layout_file: resources/layouts/anti_air/flak.miz
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
name: Early-Warning Radar
|
||||
generic: true
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- EarlyWarningRadar
|
||||
groups:
|
||||
- name: Early-Warning Radar 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_classes:
|
||||
- EarlyWarningRadar
|
||||
alternative_classes:
|
||||
- SearchRadar
|
||||
- SearchTrackRadar
|
||||
- EWR:
|
||||
- name: Early-Warning Radar 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_classes:
|
||||
- EarlyWarningRadar
|
||||
alternative_classes:
|
||||
- SearchRadar
|
||||
- SearchTrackRadar
|
||||
layout_file: resources/layouts/anti_air/legacy_ground_templates.miz
|
||||
|
||||
@ -1,51 +1,51 @@
|
||||
name: Flak Site
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- AAA
|
||||
groups:
|
||||
- name: Flak Site 0
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- flak38
|
||||
- flak18
|
||||
- flak36
|
||||
- flak37
|
||||
- flak41
|
||||
- flak30
|
||||
- name: Flak Site 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- flak38
|
||||
- name: Flak Site 2
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- flak36
|
||||
- name: Flak Site 3
|
||||
unit_count:
|
||||
- 2
|
||||
unit_types:
|
||||
- Flakscheinwerfer_37
|
||||
- name: Flak Site 4
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Maschinensatz_33
|
||||
- name: Flak Site 5
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- KDO_Mod40
|
||||
- name: Flak Site 6
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Kubelwagen_82
|
||||
- name: Flak Site 7
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- Blitz_36-6700A
|
||||
- Flak:
|
||||
- name: Flak Site 0
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- flak38
|
||||
- flak18
|
||||
- flak36
|
||||
- flak37
|
||||
- flak41
|
||||
- flak30
|
||||
- name: Flak Site 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- flak38
|
||||
- name: Flak Site 2
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- flak36
|
||||
- name: Flak Site 3
|
||||
unit_count:
|
||||
- 2
|
||||
unit_types:
|
||||
- Flakscheinwerfer_37
|
||||
- name: Flak Site 4
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Maschinensatz_33
|
||||
- name: Flak Site 5
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- KDO_Mod40
|
||||
- name: Flak Site 6
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Kubelwagen_82
|
||||
- name: Flak Site 7
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- Blitz_36-6700A
|
||||
layout_file: resources/layouts/anti_air/legacy_ground_templates.miz
|
||||
|
||||
@ -1,51 +1,51 @@
|
||||
name: Freya EWR Site
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- SHORAD
|
||||
groups:
|
||||
- name: Freya EWR Site 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- FuMG-401
|
||||
- name: Freya EWR Site 1
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- flak38
|
||||
- name: Freya EWR Site 2
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- flak18
|
||||
- name: Freya EWR Site 3
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Kubelwagen_82
|
||||
- name: Freya EWR Site 4
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Sd_Kfz_7
|
||||
- name: Freya EWR Site 5
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Sd_Kfz_2
|
||||
- name: Freya EWR Site 6
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Maschinensatz_33
|
||||
- name: Freya EWR Site 7
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- KDO_Mod40
|
||||
- name: Freya EWR Site 8
|
||||
unit_count:
|
||||
- 3
|
||||
unit_types:
|
||||
- soldier_mauser98
|
||||
- Freya:
|
||||
- name: Freya EWR Site 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- FuMG-401
|
||||
- name: Freya EWR Site 1
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- flak38
|
||||
- name: Freya EWR Site 2
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- flak18
|
||||
- name: Freya EWR Site 3
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Kubelwagen_82
|
||||
- name: Freya EWR Site 4
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Sd_Kfz_7
|
||||
- name: Freya EWR Site 5
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Sd_Kfz_2
|
||||
- name: Freya EWR Site 6
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Maschinensatz_33
|
||||
- name: Freya EWR Site 7
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- KDO_Mod40
|
||||
- name: Freya EWR Site 8
|
||||
unit_count:
|
||||
- 3
|
||||
unit_types:
|
||||
- soldier_mauser98
|
||||
layout_file: resources/layouts/anti_air/legacy_ground_templates.miz
|
||||
|
||||
@ -1,24 +1,21 @@
|
||||
name: HQ-7 Site
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- SHORAD
|
||||
groups:
|
||||
- name: HQ-7 Site 0
|
||||
group: 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- HQ-7_STR_SP
|
||||
- name: HQ-7 Site 1
|
||||
group: 1
|
||||
unit_count:
|
||||
- 2
|
||||
unit_types:
|
||||
- HQ-7_LN_SP
|
||||
- name: HQ-7 Site 2
|
||||
group: 2
|
||||
unit_count:
|
||||
- 2
|
||||
unit_types:
|
||||
- Ural-375 ZU-23
|
||||
- HQ-7:
|
||||
- name: HQ-7 Site 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- HQ-7_STR_SP
|
||||
- name: HQ-7 Site 1
|
||||
unit_count:
|
||||
- 2
|
||||
unit_types:
|
||||
- HQ-7_LN_SP
|
||||
- name: HQ-7 Site 2
|
||||
unit_count:
|
||||
- 2
|
||||
unit_types:
|
||||
- Ural-375 ZU-23
|
||||
layout_file: resources/layouts/anti_air/legacy_ground_templates.miz
|
||||
|
||||
@ -1,36 +1,33 @@
|
||||
name: Hawk Site
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- MERAD
|
||||
groups:
|
||||
- name: Hawk Site 0
|
||||
group: 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Hawk sr
|
||||
- name: Hawk Site 1
|
||||
group: 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Hawk pcp
|
||||
- name: Hawk Site 2
|
||||
group: 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Hawk tr
|
||||
- name: Hawk Site 3
|
||||
group: 1
|
||||
unit_count:
|
||||
- 6
|
||||
unit_types:
|
||||
- Hawk ln
|
||||
- name: Hawk Site 4
|
||||
group: 2
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Vulcan
|
||||
- Hawk: # Main Battery as one group
|
||||
- name: Hawk Site 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Hawk sr
|
||||
- name: Hawk Site 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Hawk pcp
|
||||
- name: Hawk Site 2
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Hawk tr
|
||||
- name: Hawk Site 3
|
||||
unit_count:
|
||||
- 6
|
||||
unit_types:
|
||||
- Hawk ln
|
||||
- PD: # Point Defense as separate group
|
||||
- name: Hawk Site 4
|
||||
optional: true
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Vulcan
|
||||
layout_file: resources/layouts/anti_air/legacy_ground_templates.miz
|
||||
|
||||
@ -1,21 +1,21 @@
|
||||
name: NASAMS AIM-120B
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- MERAD
|
||||
groups:
|
||||
- name: NASAMS AIM-120B 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- NASAMS_Radar_MPQ64F1
|
||||
- name: NASAMS AIM-120B 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- NASAMS_Command_Post
|
||||
- name: NASAMS AIM-120B 2
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- NASAMS_LN_B
|
||||
- NASAMS:
|
||||
- name: NASAMS AIM-120B 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- NASAMS_Radar_MPQ64F1
|
||||
- name: NASAMS AIM-120B 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- NASAMS_Command_Post
|
||||
- name: NASAMS AIM-120B 2
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- NASAMS_LN_B
|
||||
layout_file: resources/layouts/anti_air/legacy_ground_templates.miz
|
||||
|
||||
@ -1,21 +1,21 @@
|
||||
name: NASAMS AIM-120C
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- MERAD
|
||||
groups:
|
||||
- name: NASAMS AIM-120C 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- NASAMS_Radar_MPQ64F1
|
||||
- name: NASAMS AIM-120C 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- NASAMS_Command_Post
|
||||
- name: NASAMS AIM-120C 2
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- NASAMS_LN_C
|
||||
- NASAMS:
|
||||
- name: NASAMS AIM-120C 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- NASAMS_Radar_MPQ64F1
|
||||
- name: NASAMS AIM-120C 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- NASAMS_Command_Post
|
||||
- name: NASAMS AIM-120C 2
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- NASAMS_LN_C
|
||||
layout_file: resources/layouts/anti_air/legacy_ground_templates.miz
|
||||
|
||||
@ -1,56 +1,50 @@
|
||||
name: Patriot Battery
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- LORAD
|
||||
groups:
|
||||
- name: Patriot Battery 0
|
||||
group: 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Patriot str
|
||||
- name: Patriot Battery 1
|
||||
group: 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Patriot AMG
|
||||
- name: Patriot Battery 2
|
||||
group: 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Patriot ECS
|
||||
- name: Patriot Battery 3
|
||||
group: 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Patriot cp
|
||||
- name: Patriot Battery 4
|
||||
group: 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Patriot EPP
|
||||
- name: Patriot Battery 5
|
||||
group: 1
|
||||
unit_count:
|
||||
- 8
|
||||
unit_types:
|
||||
- Patriot ln
|
||||
- name: Patriot Battery 6
|
||||
optional: true
|
||||
group: 2
|
||||
unit_count:
|
||||
- 2
|
||||
unit_classes:
|
||||
- AAA
|
||||
- name: Patriot Battery 7
|
||||
optional: true
|
||||
group: 2
|
||||
unit_count:
|
||||
- 2
|
||||
unit_classes:
|
||||
- SHORAD
|
||||
- Patriot:
|
||||
- name: Patriot Battery 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Patriot str
|
||||
- name: Patriot Battery 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Patriot AMG
|
||||
- name: Patriot Battery 2
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Patriot ECS
|
||||
- name: Patriot Battery 3
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Patriot cp
|
||||
- name: Patriot Battery 4
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Patriot EPP
|
||||
- name: Patriot Battery 5
|
||||
unit_count:
|
||||
- 8
|
||||
unit_types:
|
||||
- Patriot ln
|
||||
- AAA:
|
||||
- name: Patriot Battery 6
|
||||
optional: true
|
||||
unit_count:
|
||||
- 2
|
||||
unit_classes:
|
||||
- AAA
|
||||
- PD:
|
||||
- name: Patriot Battery 7
|
||||
optional: true
|
||||
unit_count:
|
||||
- 2
|
||||
unit_classes:
|
||||
- SHORAD
|
||||
layout_file: resources/layouts/anti_air/legacy_ground_templates.miz
|
||||
|
||||
@ -1,21 +1,21 @@
|
||||
name: Rapier AA Site
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- SHORAD
|
||||
groups:
|
||||
- name: Rapier AA Site 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- rapier_fsa_blindfire_radar
|
||||
- name: Rapier AA Site 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- rapier_fsa_optical_tracker_unit
|
||||
- name: Rapier AA Site 2
|
||||
unit_count:
|
||||
- 2
|
||||
unit_types:
|
||||
- rapier_fsa_launcher
|
||||
- Rapier:
|
||||
- name: Rapier AA Site 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- rapier_fsa_blindfire_radar
|
||||
- name: Rapier AA Site 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- rapier_fsa_optical_tracker_unit
|
||||
- name: Rapier AA Site 2
|
||||
unit_count:
|
||||
- 2
|
||||
unit_types:
|
||||
- rapier_fsa_launcher
|
||||
layout_file: resources/layouts/anti_air/legacy_ground_templates.miz
|
||||
|
||||
@ -1,21 +1,21 @@
|
||||
name: Roland Site
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- SHORAD
|
||||
groups:
|
||||
- name: Roland Site 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Roland Radar
|
||||
- name: Roland Site 1
|
||||
unit_count:
|
||||
- 2
|
||||
unit_types:
|
||||
- Roland ADS
|
||||
- name: Roland Site 2
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- M 818
|
||||
- Roland:
|
||||
- name: Roland Site 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Roland Radar
|
||||
- name: Roland Site 1
|
||||
unit_count:
|
||||
- 2
|
||||
unit_types:
|
||||
- Roland ADS
|
||||
- name: Roland Site 2
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- M 818
|
||||
layout_file: resources/layouts/anti_air/legacy_ground_templates.miz
|
||||
|
||||
@ -1,89 +1,85 @@
|
||||
name: S-300 Site
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- LORAD
|
||||
groups:
|
||||
- name: S-300 Site SR1
|
||||
group: 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- S-300PS 40B6MD sr # SA-10
|
||||
- S-300PS SA-10B 40B6MD MAST sr # SA-10B
|
||||
- S-300V 9S15 sr # SA-12
|
||||
- S-300PMU1 40B6MD sr # SA-20 + B, is the 5N66E
|
||||
- S-300VM 9S15M2 sr # SA-23
|
||||
- name: S-300 Site SR2
|
||||
group: 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- S-300PS 64H6E sr # SA-10
|
||||
- S-300PS 64H6E TRAILER sr # SA-10B
|
||||
- S-300V 9S19 sr # SA-12
|
||||
- S-300PMU1 64N6E sr # SA-20 + B
|
||||
- S-300VM 9S19M2 sr # SA-23
|
||||
- name: S-300 Site CP
|
||||
group: 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- S-300PS 54K6 cp # SA-10
|
||||
- S-300PS SA-10B 54K6 cp # SA-10B
|
||||
- S-300V 9S457 cp # SA-12
|
||||
- S-300PMU1 54K6 cp # SA-20
|
||||
- S-300PMU2 54K6E2 cp # SA-20B
|
||||
- S-300VM 9S457ME cp # SA-23
|
||||
- name: S-300 Site TR
|
||||
group: 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- S-300PS 40B6M tr # SA-10
|
||||
- S-300PS 30N6 TRAILER tr # SA-10B
|
||||
- S-300V 9S32 tr # SA-12
|
||||
- S-300PMU1 40B6M tr # SA-20, is the 30N6E!
|
||||
- S-300PMU2 92H6E tr # SA-20B
|
||||
- S-300VM 9S32ME tr # SA-23
|
||||
- name: S-300 Site LN1
|
||||
group: 1
|
||||
unit_count:
|
||||
- 3
|
||||
unit_types:
|
||||
- S-300PS 5P85C ln # SA-10
|
||||
- S-300PS 5P85SE_mod ln # SA-10B
|
||||
- S-300V 9A82 ln # SA-12
|
||||
- S-300PMU1 5P85CE ln # SA-20
|
||||
- S-300PMU2 5P85SE2 ln # SA-20B
|
||||
- S-300VM 9A82ME ln # SA-23
|
||||
- name: S-300 Site LN2
|
||||
group: 1
|
||||
unit_count:
|
||||
- 3
|
||||
unit_types:
|
||||
- S-300PS 5P85D ln # SA-10
|
||||
- S-300PS 5P85SU_mod ln # SA-10B
|
||||
- S-300V 9A83 ln # SA-12
|
||||
- S-300PMU1 5P85DE ln # SA-20
|
||||
- S-300PMU2 5P85SE2 ln # SA-20B
|
||||
- S-300VM 9A83ME ln # SA-23
|
||||
- name: S-300 Site AAA
|
||||
group: 2
|
||||
unit_count:
|
||||
- 2
|
||||
unit_classes:
|
||||
- AAA
|
||||
- name: S-300 Site SHORAD1
|
||||
group: 3
|
||||
unit_count:
|
||||
- 0
|
||||
- 2
|
||||
unit_classes:
|
||||
- SHORAD
|
||||
- name: S-300 Site SHORAD2
|
||||
group: 3
|
||||
unit_count:
|
||||
- 0
|
||||
- 2
|
||||
unit_classes:
|
||||
- SHORAD
|
||||
- S-300:
|
||||
- name: S-300 Site SR1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- S-300PS 40B6MD sr # SA-10
|
||||
- S-300PS SA-10B 40B6MD MAST sr # SA-10B
|
||||
- S-300V 9S15 sr # SA-12
|
||||
- S-300PMU1 40B6MD sr # SA-20 + B, is the 5N66E
|
||||
- S-300VM 9S15M2 sr # SA-23
|
||||
- name: S-300 Site SR2
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- S-300PS 64H6E sr # SA-10
|
||||
- S-300PS 64H6E TRAILER sr # SA-10B
|
||||
- S-300V 9S19 sr # SA-12
|
||||
- S-300PMU1 64N6E sr # SA-20 + B
|
||||
- S-300VM 9S19M2 sr # SA-23
|
||||
- name: S-300 Site CP
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- S-300PS 54K6 cp # SA-10
|
||||
- S-300PS SA-10B 54K6 cp # SA-10B
|
||||
- S-300V 9S457 cp # SA-12
|
||||
- S-300PMU1 54K6 cp # SA-20
|
||||
- S-300PMU2 54K6E2 cp # SA-20B
|
||||
- S-300VM 9S457ME cp # SA-23
|
||||
- name: S-300 Site TR
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- S-300PS 40B6M tr # SA-10
|
||||
- S-300PS 30N6 TRAILER tr # SA-10B
|
||||
- S-300V 9S32 tr # SA-12
|
||||
- S-300PMU1 40B6M tr # SA-20, is the 30N6E!
|
||||
- S-300PMU2 92H6E tr # SA-20B
|
||||
- S-300VM 9S32ME tr # SA-23
|
||||
- name: S-300 Site LN1
|
||||
unit_count:
|
||||
- 3
|
||||
unit_types:
|
||||
- S-300PS 5P85C ln # SA-10
|
||||
- S-300PS 5P85SE_mod ln # SA-10B
|
||||
- S-300V 9A82 ln # SA-12
|
||||
- S-300PMU1 5P85CE ln # SA-20
|
||||
- S-300PMU2 5P85SE2 ln # SA-20B
|
||||
- S-300VM 9A82ME ln # SA-23
|
||||
- name: S-300 Site LN2
|
||||
unit_count:
|
||||
- 3
|
||||
unit_types:
|
||||
- S-300PS 5P85D ln # SA-10
|
||||
- S-300PS 5P85SU_mod ln # SA-10B
|
||||
- S-300V 9A83 ln # SA-12
|
||||
- S-300PMU1 5P85DE ln # SA-20
|
||||
- S-300PMU2 5P85SE2 ln # SA-20B
|
||||
- S-300VM 9A83ME ln # SA-23
|
||||
- AAA:
|
||||
- name: S-300 Site AAA
|
||||
optional: true
|
||||
unit_count:
|
||||
- 2
|
||||
unit_classes:
|
||||
- AAA
|
||||
- PD:
|
||||
- name: S-300 Site SHORAD1
|
||||
optional: true
|
||||
unit_count:
|
||||
- 0
|
||||
- 2
|
||||
unit_classes:
|
||||
- SHORAD
|
||||
- name: S-300 Site SHORAD2
|
||||
optional: true
|
||||
unit_count:
|
||||
- 0
|
||||
- 2
|
||||
unit_classes:
|
||||
- SHORAD
|
||||
|
||||
@ -1,21 +1,21 @@
|
||||
name: SA-11 Buk Battery
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- MERAD
|
||||
groups:
|
||||
- name: SA-11 Buk Battery 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- SA-11 Buk SR 9S18M1
|
||||
- name: SA-11 Buk Battery 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- SA-11 Buk CC 9S470M1
|
||||
- name: SA-11 Buk Battery 2
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- SA-11 Buk LN 9A310M1
|
||||
- SA-11:
|
||||
- name: SA-11 Buk Battery 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- SA-11 Buk SR 9S18M1
|
||||
- name: SA-11 Buk Battery 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- SA-11 Buk CC 9S470M1
|
||||
- name: SA-11 Buk Battery 2
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- SA-11 Buk LN 9A310M1
|
||||
layout_file: resources/layouts/anti_air/legacy_ground_templates.miz
|
||||
|
||||
@ -1,21 +1,21 @@
|
||||
name: SA-17 Grizzly Battery
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- MERAD
|
||||
groups:
|
||||
- name: SA-17 Grizzly Battery 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- SA-11 Buk SR 9S18M1
|
||||
- name: SA-17 Grizzly Battery 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- SA-11 Buk CC 9S470M1
|
||||
- name: SA-17 Grizzly Battery 2
|
||||
unit_count:
|
||||
- 3
|
||||
unit_types:
|
||||
- SA-17 Buk M1-2 LN 9A310M1-2
|
||||
- SA-17:
|
||||
- name: SA-17 Grizzly Battery 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- SA-11 Buk SR 9S18M1
|
||||
- name: SA-17 Grizzly Battery 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- SA-11 Buk CC 9S470M1
|
||||
- name: SA-17 Grizzly Battery 2
|
||||
unit_count:
|
||||
- 3
|
||||
unit_types:
|
||||
- SA-17 Buk M1-2 LN 9A310M1-2
|
||||
layout_file: resources/layouts/anti_air/legacy_ground_templates.miz
|
||||
|
||||
@ -1,21 +1,21 @@
|
||||
name: SA-2/S-75 Site
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- MERAD
|
||||
groups:
|
||||
- name: SA-2/S-75 Site 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- p-19 s-125 sr
|
||||
- name: SA-2/S-75 Site 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- SNR_75V
|
||||
- name: SA-2/S-75 Site 2
|
||||
unit_count:
|
||||
- 6
|
||||
unit_types:
|
||||
- S_75M_Volhov
|
||||
- SA-2:
|
||||
- name: SA-2/S-75 Site 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- p-19 s-125 sr
|
||||
- name: SA-2/S-75 Site 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- SNR_75V
|
||||
- name: SA-2/S-75 Site 2
|
||||
unit_count:
|
||||
- 6
|
||||
unit_types:
|
||||
- S_75M_Volhov
|
||||
layout_file: resources/layouts/anti_air/legacy_ground_templates.miz
|
||||
|
||||
@ -1,21 +1,21 @@
|
||||
name: SA-3/S-125 Site
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- MERAD
|
||||
groups:
|
||||
- name: SA-3/S-125 Site 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- p-19 s-125 sr
|
||||
- name: SA-3/S-125 Site 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- snr s-125 tr
|
||||
- name: SA-3/S-125 Site 2
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- 5p73 s-125 ln
|
||||
- SA-3:
|
||||
- name: SA-3/S-125 Site 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- p-19 s-125 sr
|
||||
- name: SA-3/S-125 Site 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- snr s-125 tr
|
||||
- name: SA-3/S-125 Site 2
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- 5p73 s-125 ln
|
||||
layout_file: resources/layouts/anti_air/legacy_ground_templates.miz
|
||||
|
||||
@ -1,26 +1,26 @@
|
||||
name: SA-5/S-200 Site
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- LORAD
|
||||
groups:
|
||||
- name: SA-5/S-200 Site 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- RLS_19J6
|
||||
- name: SA-5/S-200 Site 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- RPC_5N62V
|
||||
- name: SA-5/S-200 Site 2
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Ural-375
|
||||
- name: SA-5/S-200 Site 3
|
||||
unit_count:
|
||||
- 6
|
||||
unit_types:
|
||||
- S-200_Launcher
|
||||
- SA-5:
|
||||
- name: SA-5/S-200 Site 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- RLS_19J6
|
||||
- name: SA-5/S-200 Site 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- RPC_5N62V
|
||||
- name: SA-5/S-200 Site 2
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Ural-375
|
||||
- name: SA-5/S-200 Site 3
|
||||
unit_count:
|
||||
- 6
|
||||
unit_types:
|
||||
- S-200_Launcher
|
||||
layout_file: resources/layouts/anti_air/legacy_ground_templates.miz
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
name: SA-6 Kub Site
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- MERAD
|
||||
groups:
|
||||
- name: SA-6 Kub Site 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Kub 1S91 str
|
||||
- name: SA-6 Kub Site 1
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- Kub 2P25 ln
|
||||
- SA-6:
|
||||
- name: SA-6 Kub Site 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Kub 1S91 str
|
||||
- name: SA-6 Kub Site 1
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- Kub 2P25 ln
|
||||
layout_file: resources/layouts/anti_air/legacy_ground_templates.miz
|
||||
|
||||
@ -1,19 +1,19 @@
|
||||
name: Short Range Anti Air Group
|
||||
role: AntiAir
|
||||
generic: true
|
||||
tasks:
|
||||
- SHORAD
|
||||
groups:
|
||||
- name: SHORAD Group 0
|
||||
unit_count:
|
||||
- 2
|
||||
unit_classes:
|
||||
- SHORAD
|
||||
- name: SHORAD Group 1
|
||||
optional: true
|
||||
unit_count:
|
||||
- 1
|
||||
- 2
|
||||
unit_classes:
|
||||
- Logistics
|
||||
- SHORAD:
|
||||
- name: SHORAD Group 0
|
||||
unit_count:
|
||||
- 2
|
||||
unit_classes:
|
||||
- SHORAD
|
||||
- name: SHORAD Group 1
|
||||
optional: true
|
||||
unit_count:
|
||||
- 1
|
||||
- 2
|
||||
unit_classes:
|
||||
- Logistics
|
||||
layout_file: resources/layouts/anti_air/shorad.miz
|
||||
|
||||
@ -1,41 +1,41 @@
|
||||
name: WW2 Ally Flak Site
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- AAA
|
||||
groups:
|
||||
- name: WW2 Ally Flak Site 0
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- QF_37_AA
|
||||
- name: WW2 Ally Flak Site 1
|
||||
unit_count:
|
||||
- 8
|
||||
unit_types:
|
||||
- M1_37mm
|
||||
- name: WW2 Ally Flak Site 2
|
||||
unit_count:
|
||||
- 8
|
||||
unit_types:
|
||||
- M45_Quadmount
|
||||
- name: WW2 Ally Flak Site 3
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Willys_MB
|
||||
- name: WW2 Ally Flak Site 4
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- M30_CC
|
||||
- name: WW2 Ally Flak Site 5
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- M4_Tractor
|
||||
- name: WW2 Ally Flak Site 6
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Bedford_MWD
|
||||
- Flak:
|
||||
- name: WW2 Ally Flak Site 0
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- QF_37_AA
|
||||
- name: WW2 Ally Flak Site 1
|
||||
unit_count:
|
||||
- 8
|
||||
unit_types:
|
||||
- M1_37mm
|
||||
- name: WW2 Ally Flak Site 2
|
||||
unit_count:
|
||||
- 8
|
||||
unit_types:
|
||||
- M45_Quadmount
|
||||
- name: WW2 Ally Flak Site 3
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Willys_MB
|
||||
- name: WW2 Ally Flak Site 4
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- M30_CC
|
||||
- name: WW2 Ally Flak Site 5
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- M4_Tractor
|
||||
- name: WW2 Ally Flak Site 6
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Bedford_MWD
|
||||
layout_file: resources/layouts/anti_air/legacy_ground_templates.miz
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
name: WW2 Flak Site
|
||||
role: AntiAir
|
||||
tasks:
|
||||
- AAA
|
||||
groups:
|
||||
- name: WW2 Flak Site 0
|
||||
unit_count:
|
||||
- 6
|
||||
unit_types:
|
||||
- flak18
|
||||
- name: WW2 Flak Site 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Blitz_36-6700A
|
||||
- Flak:
|
||||
- name: WW2 Flak Site 0
|
||||
unit_count:
|
||||
- 6
|
||||
unit_types:
|
||||
- flak18
|
||||
- name: WW2 Flak Site 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Blitz_36-6700A
|
||||
layout_file: resources/layouts/anti_air/legacy_ground_templates.miz
|
||||
|
||||
Binary file not shown.
@ -1,84 +1,84 @@
|
||||
name: allycamp1
|
||||
generic: true
|
||||
role: Building
|
||||
tasks:
|
||||
- StrikeTarget
|
||||
- AllyCamp
|
||||
groups:
|
||||
- name: allycamp1 0
|
||||
statics:
|
||||
- allycamp1 0-0
|
||||
- allycamp1 0-1
|
||||
- allycamp1 0-2
|
||||
- allycamp1 0-3
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- FARP Tent
|
||||
- name: allycamp1 1
|
||||
statics:
|
||||
- allycamp1 1-0
|
||||
- allycamp1 1-1
|
||||
- allycamp1 1-2
|
||||
- allycamp1 1-3
|
||||
- allycamp1 1-4
|
||||
- allycamp1 1-5
|
||||
- allycamp1 1-6
|
||||
- allycamp1 1-7
|
||||
- allycamp1 1-8
|
||||
- allycamp1 1-9
|
||||
- allycamp1 1-10
|
||||
- allycamp1 1-11
|
||||
- allycamp1 1-12
|
||||
- allycamp1 1-13
|
||||
- allycamp1 1-14
|
||||
- allycamp1 1-15
|
||||
- allycamp1 1-16
|
||||
- allycamp1 1-17
|
||||
- allycamp1 1-18
|
||||
- allycamp1 1-19
|
||||
- allycamp1 1-20
|
||||
- allycamp1 1-21
|
||||
unit_count:
|
||||
- 22
|
||||
unit_types:
|
||||
- Haystack 4
|
||||
- name: allycamp1 2
|
||||
statics:
|
||||
- allycamp1 2-0
|
||||
- allycamp1 2-1
|
||||
- allycamp1 2-2
|
||||
- allycamp1 2-3
|
||||
- allycamp1 2-4
|
||||
- allycamp1 2-5
|
||||
- allycamp1 2-6
|
||||
- allycamp1 2-7
|
||||
- allycamp1 2-8
|
||||
- allycamp1 2-9
|
||||
- allycamp1 2-10
|
||||
- allycamp1 2-11
|
||||
unit_count:
|
||||
- 12
|
||||
unit_types:
|
||||
- Haystack 3
|
||||
- name: allycamp1 3
|
||||
statics:
|
||||
- allycamp1 3-0
|
||||
- allycamp1 3-1
|
||||
- allycamp1 3-2
|
||||
- allycamp1 3-3
|
||||
- allycamp1 3-4
|
||||
- allycamp1 3-5
|
||||
- allycamp1 3-6
|
||||
- allycamp1 3-7
|
||||
unit_count:
|
||||
- 8
|
||||
unit_types:
|
||||
- Concertina wire
|
||||
- name: allycamp1 4
|
||||
group: 2 # Vehicle and static can not be mixed
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- house2arm
|
||||
- AllyCamp:
|
||||
- name: allycamp1 0
|
||||
statics:
|
||||
- allycamp1 0-0
|
||||
- allycamp1 0-1
|
||||
- allycamp1 0-2
|
||||
- allycamp1 0-3
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- FARP Tent
|
||||
- name: allycamp1 1
|
||||
statics:
|
||||
- allycamp1 1-0
|
||||
- allycamp1 1-1
|
||||
- allycamp1 1-2
|
||||
- allycamp1 1-3
|
||||
- allycamp1 1-4
|
||||
- allycamp1 1-5
|
||||
- allycamp1 1-6
|
||||
- allycamp1 1-7
|
||||
- allycamp1 1-8
|
||||
- allycamp1 1-9
|
||||
- allycamp1 1-10
|
||||
- allycamp1 1-11
|
||||
- allycamp1 1-12
|
||||
- allycamp1 1-13
|
||||
- allycamp1 1-14
|
||||
- allycamp1 1-15
|
||||
- allycamp1 1-16
|
||||
- allycamp1 1-17
|
||||
- allycamp1 1-18
|
||||
- allycamp1 1-19
|
||||
- allycamp1 1-20
|
||||
- allycamp1 1-21
|
||||
unit_count:
|
||||
- 22
|
||||
unit_types:
|
||||
- Haystack 4
|
||||
- name: allycamp1 2
|
||||
statics:
|
||||
- allycamp1 2-0
|
||||
- allycamp1 2-1
|
||||
- allycamp1 2-2
|
||||
- allycamp1 2-3
|
||||
- allycamp1 2-4
|
||||
- allycamp1 2-5
|
||||
- allycamp1 2-6
|
||||
- allycamp1 2-7
|
||||
- allycamp1 2-8
|
||||
- allycamp1 2-9
|
||||
- allycamp1 2-10
|
||||
- allycamp1 2-11
|
||||
unit_count:
|
||||
- 12
|
||||
unit_types:
|
||||
- Haystack 3
|
||||
- name: allycamp1 3
|
||||
statics:
|
||||
- allycamp1 3-0
|
||||
- allycamp1 3-1
|
||||
- allycamp1 3-2
|
||||
- allycamp1 3-3
|
||||
- allycamp1 3-4
|
||||
- allycamp1 3-5
|
||||
- allycamp1 3-6
|
||||
- allycamp1 3-7
|
||||
unit_count:
|
||||
- 8
|
||||
unit_types:
|
||||
- Concertina wire
|
||||
- AllyCamp2: # Vehicle and static can not be mixed
|
||||
- name: allycamp1 4
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- house2arm
|
||||
layout_file: resources/layouts/buildings/buildings.miz
|
||||
|
||||
@ -1,22 +1,22 @@
|
||||
name: ammo1
|
||||
generic: true
|
||||
role: Building
|
||||
tasks:
|
||||
- Ammo
|
||||
groups:
|
||||
- name: ammo1 0
|
||||
statics:
|
||||
- ammo1 0-0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- .Ammunition depot
|
||||
- name: ammo1 1
|
||||
statics:
|
||||
- ammo1 1-0
|
||||
- ammo1 1-1
|
||||
unit_count:
|
||||
- 2
|
||||
unit_types:
|
||||
- Hangar B
|
||||
- Ammo:
|
||||
- name: ammo1 0
|
||||
statics:
|
||||
- ammo1 0-0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- .Ammunition depot
|
||||
- name: ammo1 1
|
||||
statics:
|
||||
- ammo1 1-0
|
||||
- ammo1 1-1
|
||||
unit_count:
|
||||
- 2
|
||||
unit_types:
|
||||
- Hangar B
|
||||
layout_file: resources/layouts/buildings/buildings.miz
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
name: comms
|
||||
generic: true
|
||||
role: Building
|
||||
tasks:
|
||||
- StrikeTarget
|
||||
- Comms
|
||||
groups:
|
||||
- name: comms1 0
|
||||
statics:
|
||||
- comms1 0-0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- TV tower
|
||||
- Comms tower M
|
||||
- Comms:
|
||||
- name: comms1 0
|
||||
statics:
|
||||
- comms1 0-0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- TV tower
|
||||
- Comms tower M
|
||||
layout_file: resources/layouts/buildings/buildings.miz
|
||||
|
||||
@ -1,31 +1,31 @@
|
||||
name: derrick1
|
||||
generic: true
|
||||
role: Building
|
||||
tasks:
|
||||
- StrikeTarget
|
||||
- Derrick
|
||||
groups:
|
||||
- name: derrick1 0
|
||||
statics:
|
||||
- derrick1 0-0
|
||||
- derrick1 0-1
|
||||
unit_count:
|
||||
- 2
|
||||
unit_types:
|
||||
- Oil derrick
|
||||
- name: derrick1 1
|
||||
statics:
|
||||
- derrick1 1-0
|
||||
- derrick1 1-1
|
||||
unit_count:
|
||||
- 2
|
||||
unit_types:
|
||||
- Pump station
|
||||
- name: derrick1 2
|
||||
statics:
|
||||
- derrick1 2-0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Subsidiary structure 2
|
||||
- Derrick:
|
||||
- name: derrick1 0
|
||||
statics:
|
||||
- derrick1 0-0
|
||||
- derrick1 0-1
|
||||
unit_count:
|
||||
- 2
|
||||
unit_types:
|
||||
- Oil derrick
|
||||
- name: derrick1 1
|
||||
statics:
|
||||
- derrick1 1-0
|
||||
- derrick1 1-1
|
||||
unit_count:
|
||||
- 2
|
||||
unit_types:
|
||||
- Pump station
|
||||
- name: derrick1 2
|
||||
statics:
|
||||
- derrick1 2-0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Subsidiary structure 2
|
||||
layout_file: resources/layouts/buildings/buildings.miz
|
||||
|
||||
@ -1,23 +1,23 @@
|
||||
name: factory1
|
||||
generic: true
|
||||
role: Building
|
||||
tasks:
|
||||
- Factory
|
||||
groups:
|
||||
- name: factory1 0
|
||||
statics:
|
||||
- factory1 0-0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Tech combine
|
||||
- name: factory1 1
|
||||
statics:
|
||||
- factory1 1-0
|
||||
- factory1 1-1
|
||||
- factory1 1-2
|
||||
unit_count:
|
||||
- 3
|
||||
unit_types:
|
||||
- Tech hangar A
|
||||
- Factory:
|
||||
- name: factory1 0
|
||||
statics:
|
||||
- factory1 0-0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Tech combine
|
||||
- name: factory1 1
|
||||
statics:
|
||||
- factory1 1-0
|
||||
- factory1 1-1
|
||||
- factory1 1-2
|
||||
unit_count:
|
||||
- 3
|
||||
unit_types:
|
||||
- Tech hangar A
|
||||
layout_file: resources/layouts/buildings/buildings.miz
|
||||
|
||||
@ -1,41 +1,41 @@
|
||||
name: farp1
|
||||
generic: true
|
||||
role: Building
|
||||
tasks:
|
||||
- StrikeTarget
|
||||
- Farp
|
||||
groups:
|
||||
- name: farp1 0
|
||||
statics:
|
||||
- farp1 0-0
|
||||
- farp1 0-1
|
||||
- farp1 0-2
|
||||
- farp1 0-3
|
||||
- farp1 0-4
|
||||
unit_count:
|
||||
- 5
|
||||
unit_types:
|
||||
- FARP Tent
|
||||
- name: farp1 1
|
||||
statics:
|
||||
- farp1 1-0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- FARP Ammo Dump Coating
|
||||
- name: farp1 2
|
||||
statics:
|
||||
- farp1 2-0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- FARP CP Blindage
|
||||
- name: farp1 3
|
||||
statics:
|
||||
- farp1 3-0
|
||||
- farp1 3-1
|
||||
unit_count:
|
||||
- 2
|
||||
unit_types:
|
||||
- FARP Fuel Depot
|
||||
- Farp:
|
||||
- name: farp1 0
|
||||
statics:
|
||||
- farp1 0-0
|
||||
- farp1 0-1
|
||||
- farp1 0-2
|
||||
- farp1 0-3
|
||||
- farp1 0-4
|
||||
unit_count:
|
||||
- 5
|
||||
unit_types:
|
||||
- FARP Tent
|
||||
- name: farp1 1
|
||||
statics:
|
||||
- farp1 1-0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- FARP Ammo Dump Coating
|
||||
- name: farp1 2
|
||||
statics:
|
||||
- farp1 2-0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- FARP CP Blindage
|
||||
- name: farp1 3
|
||||
statics:
|
||||
- farp1 3-0
|
||||
- farp1 3-1
|
||||
unit_count:
|
||||
- 2
|
||||
unit_types:
|
||||
- FARP Fuel Depot
|
||||
layout_file: resources/layouts/buildings/buildings.miz
|
||||
|
||||
@ -1,31 +1,31 @@
|
||||
name: fob1
|
||||
generic: true
|
||||
role: Building
|
||||
tasks:
|
||||
- FOB
|
||||
groups:
|
||||
- name: fob1 0
|
||||
statics:
|
||||
- fob1 0-0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- .Command Center
|
||||
- name: fob1 1
|
||||
statics:
|
||||
- fob1 1-0
|
||||
- fob1 1-1
|
||||
- fob1 1-2
|
||||
unit_count:
|
||||
- 3
|
||||
unit_types:
|
||||
- Barracks 2
|
||||
- name: fob1 2
|
||||
statics:
|
||||
- fob1 2-0
|
||||
- fob1 2-1
|
||||
unit_count:
|
||||
- 2
|
||||
unit_types:
|
||||
- Garage small B
|
||||
- FOB:
|
||||
- name: fob1 0
|
||||
statics:
|
||||
- fob1 0-0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- .Command Center
|
||||
- name: fob1 1
|
||||
statics:
|
||||
- fob1 1-0
|
||||
- fob1 1-1
|
||||
- fob1 1-2
|
||||
unit_count:
|
||||
- 3
|
||||
unit_types:
|
||||
- Barracks 2
|
||||
- name: fob1 2
|
||||
statics:
|
||||
- fob1 2-0
|
||||
- fob1 2-1
|
||||
unit_count:
|
||||
- 2
|
||||
unit_types:
|
||||
- Garage small B
|
||||
layout_file: resources/layouts/buildings/buildings.miz
|
||||
|
||||
@ -1,28 +1,28 @@
|
||||
name: fuel1
|
||||
generic: true
|
||||
role: Building
|
||||
tasks:
|
||||
- StrikeTarget
|
||||
- Fuel
|
||||
groups:
|
||||
- name: fuel1 0
|
||||
statics:
|
||||
- fuel1 0-0
|
||||
- fuel1 0-1
|
||||
- fuel1 0-2
|
||||
- fuel1 0-3
|
||||
- fuel1 0-4
|
||||
- fuel1 0-5
|
||||
unit_count:
|
||||
- 6
|
||||
unit_types:
|
||||
- Tank
|
||||
- name: fuel1 1
|
||||
statics:
|
||||
- fuel1 1-0
|
||||
- fuel1 1-1
|
||||
unit_count:
|
||||
- 2
|
||||
unit_types:
|
||||
- Tank 3
|
||||
- Fuel:
|
||||
- name: fuel1 0
|
||||
statics:
|
||||
- fuel1 0-0
|
||||
- fuel1 0-1
|
||||
- fuel1 0-2
|
||||
- fuel1 0-3
|
||||
- fuel1 0-4
|
||||
- fuel1 0-5
|
||||
unit_count:
|
||||
- 6
|
||||
unit_types:
|
||||
- Tank
|
||||
- name: fuel1 1
|
||||
statics:
|
||||
- fuel1 1-0
|
||||
- fuel1 1-1
|
||||
unit_count:
|
||||
- 2
|
||||
unit_types:
|
||||
- Tank 3
|
||||
layout_file: resources/layouts/buildings/buildings.miz
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
name: oil1
|
||||
generic: true
|
||||
role: Building
|
||||
tasks:
|
||||
- OffShoreStrikeTarget
|
||||
- Oil
|
||||
groups:
|
||||
- name: oil1 0
|
||||
statics:
|
||||
- oil1 0-0
|
||||
- oil1 0-1
|
||||
- oil1 0-2
|
||||
- oil1 0-3
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- Oil platform
|
||||
- Oil:
|
||||
- name: oil1 0
|
||||
statics:
|
||||
- oil1 0-0
|
||||
- oil1 0-1
|
||||
- oil1 0-2
|
||||
- oil1 0-3
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- Oil platform
|
||||
layout_file: resources/layouts/buildings/buildings.miz
|
||||
|
||||
@ -1,37 +1,37 @@
|
||||
name: power1
|
||||
generic: true
|
||||
role: Building
|
||||
tasks:
|
||||
- StrikeTarget
|
||||
- Power
|
||||
groups:
|
||||
- name: power1 0
|
||||
statics:
|
||||
- power1 0-0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Repair workshop
|
||||
- name: power1 1
|
||||
statics:
|
||||
- power1 1-0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Workshop A
|
||||
- name: power1 2
|
||||
statics:
|
||||
- power1 2-0
|
||||
- power1 2-1
|
||||
unit_count:
|
||||
- 2
|
||||
unit_types:
|
||||
- Garage B
|
||||
- name: power1 3
|
||||
statics:
|
||||
- power1 3-0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Farm B
|
||||
- Power:
|
||||
- name: power1 0
|
||||
statics:
|
||||
- power1 0-0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Repair workshop
|
||||
- name: power1 1
|
||||
statics:
|
||||
- power1 1-0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Workshop A
|
||||
- name: power1 2
|
||||
statics:
|
||||
- power1 2-0
|
||||
- power1 2-1
|
||||
unit_count:
|
||||
- 2
|
||||
unit_types:
|
||||
- Garage B
|
||||
- name: power1 3
|
||||
statics:
|
||||
- power1 3-0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Farm B
|
||||
layout_file: resources/layouts/buildings/buildings.miz
|
||||
|
||||
@ -1,39 +1,39 @@
|
||||
name: village1
|
||||
generic: true
|
||||
role: Building
|
||||
tasks:
|
||||
- StrikeTarget
|
||||
- Village
|
||||
groups:
|
||||
- name: village1 0
|
||||
statics:
|
||||
- village1 0-0
|
||||
- village1 0-1
|
||||
unit_count:
|
||||
- 2
|
||||
unit_types:
|
||||
- Small house 1A
|
||||
- name: village1 1
|
||||
statics:
|
||||
- village1 1-0
|
||||
- village1 1-1
|
||||
- village1 1-2
|
||||
- village1 1-3
|
||||
- village1 1-4
|
||||
- village1 1-5
|
||||
- village1 1-6
|
||||
- village1 1-7
|
||||
unit_count:
|
||||
- 8
|
||||
unit_types:
|
||||
- Small werehouse 1
|
||||
- name: village1 2
|
||||
statics:
|
||||
- village1 2-0
|
||||
- village1 2-1
|
||||
- village1 2-2
|
||||
unit_count:
|
||||
- 3
|
||||
unit_types:
|
||||
- Small house 1B
|
||||
- Village:
|
||||
- name: village1 0
|
||||
statics:
|
||||
- village1 0-0
|
||||
- village1 0-1
|
||||
unit_count:
|
||||
- 2
|
||||
unit_types:
|
||||
- Small house 1A
|
||||
- name: village1 1
|
||||
statics:
|
||||
- village1 1-0
|
||||
- village1 1-1
|
||||
- village1 1-2
|
||||
- village1 1-3
|
||||
- village1 1-4
|
||||
- village1 1-5
|
||||
- village1 1-6
|
||||
- village1 1-7
|
||||
unit_count:
|
||||
- 8
|
||||
unit_types:
|
||||
- Small werehouse 1
|
||||
- name: village1 2
|
||||
statics:
|
||||
- village1 2-0
|
||||
- village1 2-1
|
||||
- village1 2-2
|
||||
unit_count:
|
||||
- 3
|
||||
unit_types:
|
||||
- Small house 1B
|
||||
layout_file: resources/layouts/buildings/buildings.miz
|
||||
|
||||
@ -1,24 +1,24 @@
|
||||
name: ware1
|
||||
generic: true
|
||||
role: Building
|
||||
tasks:
|
||||
- StrikeTarget
|
||||
- Ware
|
||||
groups:
|
||||
- name: ware1 0
|
||||
statics:
|
||||
- ware1 0-0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Warehouse
|
||||
- name: ware1 1
|
||||
statics:
|
||||
- ware1 1-0
|
||||
- ware1 1-1
|
||||
- ware1 1-2
|
||||
unit_count:
|
||||
- 3
|
||||
unit_types:
|
||||
- Hangar A
|
||||
- Ware:
|
||||
- name: ware1 0
|
||||
statics:
|
||||
- ware1 0-0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Warehouse
|
||||
- name: ware1 1
|
||||
statics:
|
||||
- ware1 1-0
|
||||
- ware1 1-1
|
||||
- ware1 1-2
|
||||
unit_count:
|
||||
- 3
|
||||
unit_types:
|
||||
- Hangar A
|
||||
layout_file: resources/layouts/buildings/buildings.miz
|
||||
|
||||
@ -1,34 +1,34 @@
|
||||
name: ww2bunker1
|
||||
generic: true
|
||||
role: Building
|
||||
tasks:
|
||||
- StrikeTarget
|
||||
- WW2Bunker
|
||||
groups:
|
||||
- name: ww2bunker1 0
|
||||
statics:
|
||||
- ww2bunker1 0-0
|
||||
- ww2bunker1 0-1
|
||||
- ww2bunker1 0-2
|
||||
- ww2bunker1 0-3
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- Siegfried Line
|
||||
- name: ww2bunker1 1
|
||||
statics:
|
||||
- ww2bunker1 1-0
|
||||
- ww2bunker1 1-1
|
||||
- ww2bunker1 1-2
|
||||
- ww2bunker1 1-3
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- Fire Control Bunker
|
||||
- name: ww2bunker1 2
|
||||
group: 2 # Vehicle and static can not be mixed
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- SK_C_28_naval_gun
|
||||
- Bunker:
|
||||
- name: ww2bunker1 0
|
||||
statics:
|
||||
- ww2bunker1 0-0
|
||||
- ww2bunker1 0-1
|
||||
- ww2bunker1 0-2
|
||||
- ww2bunker1 0-3
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- Siegfried Line
|
||||
- name: ww2bunker1 1
|
||||
statics:
|
||||
- ww2bunker1 1-0
|
||||
- ww2bunker1 1-1
|
||||
- ww2bunker1 1-2
|
||||
- ww2bunker1 1-3
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- Fire Control Bunker
|
||||
- Bunker2: # Vehicle and static can not be mixed
|
||||
- name: ww2bunker1 2
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- SK_C_28_naval_gun
|
||||
layout_file: resources/layouts/buildings/buildings.miz
|
||||
|
||||
@ -1,57 +1,57 @@
|
||||
name: ww2bunker2
|
||||
generic: true
|
||||
role: Building
|
||||
tasks:
|
||||
- StrikeTarget
|
||||
- WW2Bunker
|
||||
groups:
|
||||
- name: ww2bunker2 0
|
||||
statics:
|
||||
- ww2bunker2 0-0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Fire Control Bunker
|
||||
- name: ww2bunker2 1
|
||||
statics:
|
||||
- ww2bunker2 1-0
|
||||
- ww2bunker2 1-1
|
||||
unit_count:
|
||||
- 2
|
||||
unit_types:
|
||||
- Siegfried Line
|
||||
- name: ww2bunker2 2
|
||||
statics:
|
||||
- ww2bunker2 2-0
|
||||
- ww2bunker2 2-1
|
||||
- ww2bunker2 2-2
|
||||
- ww2bunker2 2-3
|
||||
- ww2bunker2 2-4
|
||||
- ww2bunker2 2-5
|
||||
- ww2bunker2 2-6
|
||||
- ww2bunker2 2-7
|
||||
unit_count:
|
||||
- 8
|
||||
unit_types:
|
||||
- Concertina wire
|
||||
- name: ww2bunker2 3
|
||||
statics:
|
||||
- ww2bunker2 3-0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Belgian gate
|
||||
- name: ww2bunker2 4
|
||||
statics:
|
||||
- ww2bunker2 4-0
|
||||
- ww2bunker2 4-1
|
||||
- ww2bunker2 4-2
|
||||
- ww2bunker2 4-3
|
||||
- ww2bunker2 4-4
|
||||
- ww2bunker2 4-5
|
||||
- ww2bunker2 4-6
|
||||
unit_count:
|
||||
- 7
|
||||
unit_types:
|
||||
- Czech hedgehogs 1
|
||||
- Bunker:
|
||||
- name: ww2bunker2 0
|
||||
statics:
|
||||
- ww2bunker2 0-0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Fire Control Bunker
|
||||
- name: ww2bunker2 1
|
||||
statics:
|
||||
- ww2bunker2 1-0
|
||||
- ww2bunker2 1-1
|
||||
unit_count:
|
||||
- 2
|
||||
unit_types:
|
||||
- Siegfried Line
|
||||
- name: ww2bunker2 2
|
||||
statics:
|
||||
- ww2bunker2 2-0
|
||||
- ww2bunker2 2-1
|
||||
- ww2bunker2 2-2
|
||||
- ww2bunker2 2-3
|
||||
- ww2bunker2 2-4
|
||||
- ww2bunker2 2-5
|
||||
- ww2bunker2 2-6
|
||||
- ww2bunker2 2-7
|
||||
unit_count:
|
||||
- 8
|
||||
unit_types:
|
||||
- Concertina wire
|
||||
- name: ww2bunker2 3
|
||||
statics:
|
||||
- ww2bunker2 3-0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Belgian gate
|
||||
- name: ww2bunker2 4
|
||||
statics:
|
||||
- ww2bunker2 4-0
|
||||
- ww2bunker2 4-1
|
||||
- ww2bunker2 4-2
|
||||
- ww2bunker2 4-3
|
||||
- ww2bunker2 4-4
|
||||
- ww2bunker2 4-5
|
||||
- ww2bunker2 4-6
|
||||
unit_count:
|
||||
- 7
|
||||
unit_types:
|
||||
- Czech hedgehogs 1
|
||||
layout_file: resources/layouts/buildings/buildings.miz
|
||||
|
||||
@ -1,34 +1,34 @@
|
||||
name: Silkworm
|
||||
role: Defenses
|
||||
tasks:
|
||||
- Coastal
|
||||
groups:
|
||||
- name: SilkwormGenerator 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_classes:
|
||||
- SearchRadar
|
||||
- name: SilkwormGenerator 1
|
||||
unit_count:
|
||||
- 5
|
||||
unit_classes:
|
||||
- Missile
|
||||
- name: SilkwormGenerator 2
|
||||
optional: true
|
||||
unit_count:
|
||||
- 1
|
||||
unit_classes:
|
||||
- Logistics
|
||||
- name: SilkwormGenerator 3
|
||||
optional: true
|
||||
unit_count:
|
||||
- 1
|
||||
unit_classes:
|
||||
- AAA
|
||||
- name: SilkwormGenerator 4
|
||||
optional: true
|
||||
unit_count:
|
||||
- 1
|
||||
unit_classes:
|
||||
- SHORAD
|
||||
- Silkworm:
|
||||
- name: SilkwormGenerator 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_classes:
|
||||
- SearchRadar
|
||||
- name: SilkwormGenerator 1
|
||||
unit_count:
|
||||
- 5
|
||||
unit_classes:
|
||||
- Missile
|
||||
- name: SilkwormGenerator 2
|
||||
optional: true
|
||||
unit_count:
|
||||
- 1
|
||||
unit_classes:
|
||||
- Logistics
|
||||
- name: SilkwormGenerator 3
|
||||
optional: true
|
||||
unit_count:
|
||||
- 1
|
||||
unit_classes:
|
||||
- AAA
|
||||
- name: SilkwormGenerator 4
|
||||
optional: true
|
||||
unit_count:
|
||||
- 1
|
||||
unit_classes:
|
||||
- SHORAD
|
||||
layout_file: resources/layouts/defenses/defenses.miz
|
||||
@ -1,29 +1,29 @@
|
||||
name: Missile
|
||||
role: Defenses
|
||||
generic: true
|
||||
tasks:
|
||||
- Missile
|
||||
groups:
|
||||
- name: ScudGenerator 0
|
||||
unit_count:
|
||||
- 3
|
||||
unit_classes:
|
||||
- Missile
|
||||
- name: ScudGenerator 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_classes:
|
||||
- Logistics
|
||||
- name: ScudGenerator 2
|
||||
optional: true
|
||||
unit_count:
|
||||
- 1
|
||||
unit_classes:
|
||||
- AAA
|
||||
- name: ScudGenerator 3
|
||||
optional: true
|
||||
unit_count:
|
||||
- 1
|
||||
unit_classes:
|
||||
- SHORAD
|
||||
- Missile:
|
||||
- name: ScudGenerator 0
|
||||
unit_count:
|
||||
- 3
|
||||
unit_classes:
|
||||
- Missile
|
||||
- name: ScudGenerator 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_classes:
|
||||
- Logistics
|
||||
- name: ScudGenerator 2
|
||||
optional: true
|
||||
unit_count:
|
||||
- 1
|
||||
unit_classes:
|
||||
- AAA
|
||||
- name: ScudGenerator 3
|
||||
optional: true
|
||||
unit_count:
|
||||
- 1
|
||||
unit_classes:
|
||||
- SHORAD
|
||||
layout_file: resources/layouts/defenses/defenses.miz
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
name: Armor Group
|
||||
role: GroundForce
|
||||
generic: true
|
||||
tasks:
|
||||
- BaseDefense
|
||||
- FrontLine
|
||||
groups:
|
||||
- name: Armor Group 0
|
||||
unit_count:
|
||||
- 2
|
||||
- 6
|
||||
unit_classes:
|
||||
- APC
|
||||
- ATGM
|
||||
- IFV
|
||||
- Tank
|
||||
- Armor Group:
|
||||
- name: Armor Group 0
|
||||
unit_count:
|
||||
- 2
|
||||
- 6
|
||||
unit_classes:
|
||||
- APC
|
||||
- ATGM
|
||||
- IFV
|
||||
- Tank
|
||||
layout_file: resources/layouts/ground_forces/ground_forces.miz
|
||||
|
||||
@ -1,26 +1,26 @@
|
||||
name: Armor Group with Anti-Air
|
||||
role: GroundForce
|
||||
generic: true
|
||||
tasks:
|
||||
- BaseDefense
|
||||
- FrontLine
|
||||
groups:
|
||||
- name: Armor Group with Anti-Air 0
|
||||
unit_count:
|
||||
- 2
|
||||
- 6
|
||||
unit_classes:
|
||||
- APC
|
||||
- ATGM
|
||||
- IFV
|
||||
- Tank
|
||||
- name: Armor Group with Anti-Air 1
|
||||
optional: true
|
||||
unit_count:
|
||||
- 1
|
||||
- 2
|
||||
unit_classes:
|
||||
- AAA
|
||||
- SHORAD
|
||||
- Manpad
|
||||
- Armor Group:
|
||||
- name: Armor Group with Anti-Air 0
|
||||
unit_count:
|
||||
- 2
|
||||
- 6
|
||||
unit_classes:
|
||||
- APC
|
||||
- ATGM
|
||||
- IFV
|
||||
- Tank
|
||||
- name: Armor Group with Anti-Air 1
|
||||
optional: true
|
||||
unit_count:
|
||||
- 1
|
||||
- 2
|
||||
unit_classes:
|
||||
- AAA
|
||||
- SHORAD
|
||||
- Manpad
|
||||
layout_file: resources/layouts/ground_forces/ground_forces.miz
|
||||
|
||||
@ -1,19 +1,18 @@
|
||||
name: Carrier Group
|
||||
role: Naval
|
||||
generic: true
|
||||
tasks:
|
||||
- AircraftCarrier
|
||||
groups:
|
||||
- name: Carrier Group 0
|
||||
group: 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_classes:
|
||||
- AircraftCarrier
|
||||
- name: Carrier Group 1
|
||||
group: 2
|
||||
unit_count:
|
||||
- 4
|
||||
unit_classes:
|
||||
- Destroyer
|
||||
- Carrier:
|
||||
- name: Carrier Group 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_classes:
|
||||
- AircraftCarrier
|
||||
- Escort:
|
||||
- name: Carrier Group 1
|
||||
unit_count:
|
||||
- 4
|
||||
unit_classes:
|
||||
- Destroyer
|
||||
layout_file: resources/layouts/naval/legacy_naval_templates.miz
|
||||
|
||||
@ -1,25 +1,23 @@
|
||||
name: Carrier Strike Group 8
|
||||
role: Naval
|
||||
generic: true
|
||||
tasks:
|
||||
- AircraftCarrier
|
||||
groups:
|
||||
- name: Carrier Strike Group 8 0
|
||||
group: 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Stennis
|
||||
- name: Carrier Strike Group 8 1
|
||||
group: 2
|
||||
unit_count:
|
||||
- 5
|
||||
unit_types:
|
||||
- USS_Arleigh_Burke_IIa
|
||||
- name: Carrier Strike Group 8 2
|
||||
group: 2
|
||||
unit_count:
|
||||
- 2
|
||||
unit_types:
|
||||
- TICONDEROG
|
||||
- Carrier:
|
||||
- name: Carrier Strike Group 8 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- Stennis
|
||||
- Escort:
|
||||
- name: Carrier Strike Group 8 1
|
||||
unit_count:
|
||||
- 4
|
||||
unit_types:
|
||||
- USS_Arleigh_Burke_IIa
|
||||
- name: Carrier Strike Group 8 2
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- TICONDEROG
|
||||
layout_file: resources/layouts/naval/legacy_naval_templates.miz
|
||||
|
||||
@ -1,19 +1,18 @@
|
||||
name: LHA Group
|
||||
generic: true
|
||||
role: Naval
|
||||
tasks:
|
||||
- HelicopterCarrier
|
||||
groups:
|
||||
- name: LHA Group 0
|
||||
group: 1
|
||||
unit_count:
|
||||
- 1
|
||||
unit_classes:
|
||||
- HelicopterCarrier
|
||||
- name: LHA Group 1
|
||||
group: 2
|
||||
unit_count:
|
||||
- 2
|
||||
unit_classes:
|
||||
- Destroyer
|
||||
- LHA:
|
||||
- name: LHA Group 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_classes:
|
||||
- HelicopterCarrier
|
||||
- Escort:
|
||||
- name: LHA Group 1
|
||||
unit_count:
|
||||
- 2
|
||||
unit_classes:
|
||||
- Destroyer
|
||||
layout_file: resources/layouts/naval/legacy_naval_templates.miz
|
||||
|
||||
@ -1,23 +1,23 @@
|
||||
name: Naval Group
|
||||
role: Naval
|
||||
tasks:
|
||||
- Navy
|
||||
groups:
|
||||
- name: Naval Group 0
|
||||
unit_count:
|
||||
- 2
|
||||
unit_classes:
|
||||
- Frigate
|
||||
- name: Naval Group 1
|
||||
unit_count:
|
||||
- 2
|
||||
unit_classes:
|
||||
- Destroyer
|
||||
- name: Naval Group 2
|
||||
optional: true
|
||||
unit_count:
|
||||
- 0
|
||||
- 1
|
||||
unit_classes:
|
||||
- Cruiser
|
||||
- Naval Group:
|
||||
- name: Naval Group 0
|
||||
unit_count:
|
||||
- 2
|
||||
unit_classes:
|
||||
- Frigate
|
||||
- name: Naval Group 1
|
||||
unit_count:
|
||||
- 2
|
||||
unit_classes:
|
||||
- Destroyer
|
||||
- name: Naval Group 2
|
||||
optional: true
|
||||
unit_count:
|
||||
- 0
|
||||
- 1
|
||||
unit_classes:
|
||||
- Cruiser
|
||||
layout_file: resources/layouts/naval/naval.miz
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
name: Naval Two Ship
|
||||
role: Naval
|
||||
generic: true
|
||||
tasks:
|
||||
- Navy
|
||||
groups:
|
||||
- name: Naval Two Ship
|
||||
unit_count:
|
||||
- 2
|
||||
unit_classes:
|
||||
- Frigate
|
||||
- Destroyer
|
||||
- Cruiser
|
||||
- Boat
|
||||
- Submarine
|
||||
- LandingShip
|
||||
- Naval Two Ship:
|
||||
- name: Naval Two Ship
|
||||
unit_count:
|
||||
- 2
|
||||
unit_classes:
|
||||
- Frigate
|
||||
- Destroyer
|
||||
- Cruiser
|
||||
- Boat
|
||||
- Submarine
|
||||
- LandingShip
|
||||
layout_file: resources/layouts/naval/naval.miz
|
||||
|
||||
@ -3,14 +3,15 @@ role: Naval
|
||||
tasks:
|
||||
- Navy
|
||||
groups:
|
||||
- name: WW2 LST Group 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- USS_Samuel_Chase
|
||||
- name: WW2 LST Group 1
|
||||
unit_count:
|
||||
- 3
|
||||
unit_types:
|
||||
- LST_Mk2
|
||||
- LST:
|
||||
- name: WW2 LST Group 0
|
||||
unit_count:
|
||||
- 1
|
||||
unit_types:
|
||||
- USS_Samuel_Chase
|
||||
- name: WW2 LST Group 1
|
||||
unit_count:
|
||||
- 3
|
||||
unit_types:
|
||||
- LST_Mk2
|
||||
layout_file: resources/layouts/naval/legacy_naval_templates.miz
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user