mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Merge branch 'develop_2_3_x' into develop
# Conflicts: # changelog.md # qt_ui/windows/QLiberationWindow.py # resources/campaigns/syria_full_map_remastered.json
This commit is contained in:
commit
23a0846533
15
.github/workflows/release.yml
vendored
15
.github/workflows/release.yml
vendored
@ -53,11 +53,6 @@ jobs:
|
||||
env:
|
||||
TAG_NAME: ${{ github.ref }}
|
||||
run: |
|
||||
$version = ($env:TAG_NAME -split "/") | Select-Object -Last 1
|
||||
(Get-Content .\installer\dcs_liberation.iss) -replace "{{version}}",$version | Out-File .\build\installer.iss
|
||||
cd .\installer
|
||||
iscc.exe ..\build\installer.iss
|
||||
cd ..
|
||||
Copy-Item .\changelog.md .\dist
|
||||
|
||||
- uses: actions/upload-artifact@v2
|
||||
@ -100,15 +95,7 @@ jobs:
|
||||
body_path: releasenotes.md
|
||||
draft: false
|
||||
prerelease: ${{ steps.version.outputs.prerelease }}
|
||||
|
||||
- uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./dcs_liberation.exe
|
||||
asset_name: dcs_liberation.${{ steps.version.outputs.number }}.exe
|
||||
asset_content_type: application/exe
|
||||
|
||||
|
||||
- uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
|
||||
13
changelog.md
13
changelog.md
@ -1,12 +1,17 @@
|
||||
# 2.3.1
|
||||
|
||||
## Fixes:
|
||||
## Features/Improvements
|
||||
* **[UX]** Added a warning message when the player is attempting to buy more planes at an already full airbase.
|
||||
* **[Campaigns]** Migrated Syria full map to new format. (Thanks to Hawkmoon)
|
||||
* **[Faction]** Added NATO desert Storm faction (Thanks to Hawkmoon)
|
||||
|
||||
## Fixes:
|
||||
* **[AI]** CAP flights will engage enemies again.
|
||||
* **[Campaigns]** Fixed a missing path on the Caucasus Full Map campaign
|
||||
|
||||
# 2.3.0
|
||||
|
||||
# Features/Improvements
|
||||
## Features/Improvements
|
||||
* **[Campaign Map]** Overhauled the campaign model
|
||||
* **[Campaign Map]** Possible to add FOB as control points
|
||||
* **[Campaign Map]** Added off-map spawn locations
|
||||
@ -17,6 +22,7 @@
|
||||
* **[Mission Generator]** Infantry squads on frontline can have manpads
|
||||
* **[Mission Generator]** Unused aircraft now spawned to allow for OCA strikes
|
||||
* **[Mission Generator]** Opfor now obeys parking limits
|
||||
* **[Mission Generator]** Support for Anubis C-130 Hercules mod
|
||||
* **[Flight Planner]** Added fighter sweep missions.
|
||||
* **[Flight Planner]** Added BAI missions.
|
||||
* **[Flight Planner]** Added anti-ship missions.
|
||||
@ -27,6 +33,7 @@
|
||||
* **[QOL]** On liberation startup, your latest save game is loaded automatically
|
||||
* **[Units]** Reduced starting fuel load for C101
|
||||
* **[UI]** Inform the user of the weather
|
||||
* **[UI]** Added toolbar buttons to change map display settings
|
||||
* **[Game]** Added new Economy options for adjusting income multipliers and starting budgets.
|
||||
|
||||
## Fixes :
|
||||
@ -40,7 +47,7 @@
|
||||
|
||||
# 2.2.1
|
||||
|
||||
# Features/Improvements
|
||||
## Features/Improvements
|
||||
* **[Factions]** Added factions : Georgia 2008, USN 1985, France 2005 Frenchpack by HerrTom
|
||||
* **[Factions]** Added map Persian Gulf full by Plob
|
||||
* **[Flight Planner]** Player flights with start delays under ten minutes will spawn immediately.
|
||||
|
||||
@ -142,6 +142,7 @@ from dcs.task import (
|
||||
SEAD,
|
||||
Task,
|
||||
Transport,
|
||||
RunwayAttack,
|
||||
)
|
||||
from dcs.terrain.terrain import Airport
|
||||
from dcs.unit import Ship, Unit, Vehicle
|
||||
@ -823,6 +824,8 @@ UNIT_BY_TASK = {
|
||||
Armor.StuG_III_Ausf__G,
|
||||
Artillery.M12_GMC,
|
||||
Artillery.Sturmpanzer_IV_Brummbär,
|
||||
Armor.Daimler_Armoured_Car,
|
||||
Armor.LT_Mk_VII_Tetrarch,
|
||||
|
||||
Artillery.MLRS_M270,
|
||||
Artillery.SPH_M109_Paladin,
|
||||
@ -986,6 +989,7 @@ COMMON_OVERRIDE = {
|
||||
AntishipStrike: "ANTISHIP",
|
||||
GroundAttack: "STRIKE",
|
||||
Escort: "CAP",
|
||||
RunwayAttack: "RUNWAY_ATTACK"
|
||||
}
|
||||
|
||||
PLANE_PAYLOAD_OVERRIDES: Dict[Type[PlaneType], Dict[Type[Task], str]] = {
|
||||
|
||||
@ -9,6 +9,9 @@ from itertools import tee
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, Iterator, List, Optional, Set, Tuple, Union, cast
|
||||
|
||||
from shapely import geometry
|
||||
from shapely import ops
|
||||
|
||||
from dcs import Mission
|
||||
from dcs.countries import (
|
||||
CombinedJointTaskForcesBlue,
|
||||
@ -472,6 +475,34 @@ class ConflictTheater:
|
||||
|
||||
return True
|
||||
|
||||
def nearest_land_pos(self, point: Point, extend_dist: int = 50) -> Point:
|
||||
"""Returns the nearest point inside a land exclusion zone from point
|
||||
`extend_dist` determines how far inside the zone the point should be placed"""
|
||||
if self.is_on_land(point):
|
||||
return point
|
||||
point = geometry.Point(point.x, point.y)
|
||||
nearest_points = []
|
||||
if not self.landmap:
|
||||
raise RuntimeError("Landmap not initialized")
|
||||
for inclusion_zone in self.landmap[0]:
|
||||
nearest_pair = ops.nearest_points(point, inclusion_zone)
|
||||
nearest_points.append(nearest_pair[1])
|
||||
min_distance = point.distance(nearest_points[0]) # type: geometry.Point
|
||||
nearest_point = nearest_points[0] # type: geometry.Point
|
||||
for pt in nearest_points[1:]:
|
||||
distance = point.distance(pt)
|
||||
if distance < min_distance:
|
||||
min_distance = distance
|
||||
nearest_point = pt
|
||||
assert isinstance(nearest_point, geometry.Point)
|
||||
point = Point(point.x, point.y)
|
||||
nearest_point = Point(nearest_point.x, nearest_point.y)
|
||||
new_point = point.point_from_heading(
|
||||
point.heading_between_point(nearest_point),
|
||||
point.distance_to_point(nearest_point) + extend_dist
|
||||
)
|
||||
return new_point
|
||||
|
||||
def player_points(self) -> List[ControlPoint]:
|
||||
return [point for point in self.controlpoints if point.captured]
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@ from pathlib import Path
|
||||
|
||||
|
||||
def _build_version_string() -> str:
|
||||
components = ["2.3.0"]
|
||||
components = ["2.3.1"]
|
||||
build_number_path = Path("resources/buildnumber")
|
||||
if build_number_path.exists():
|
||||
with build_number_path.open("r") as build_number_file:
|
||||
|
||||
@ -65,6 +65,7 @@ from dcs.task import (
|
||||
Targets,
|
||||
Task,
|
||||
WeaponType,
|
||||
PinpointStrike,
|
||||
)
|
||||
from dcs.terrain.terrain import Airport, NoParkingSlotError
|
||||
from dcs.translation import String
|
||||
@ -728,6 +729,11 @@ class AircraftConflictGenerator:
|
||||
if for_task in db.PLANE_PAYLOAD_OVERRIDES[unit_type]:
|
||||
payload_name = db.PLANE_PAYLOAD_OVERRIDES[unit_type][for_task]
|
||||
group.load_loadout(payload_name)
|
||||
if not group.units[0].pylons and for_task == RunwayAttack:
|
||||
if PinpointStrike in db.PLANE_PAYLOAD_OVERRIDES[unit_type]:
|
||||
logging.warning("No loadout for \"Runway Attack\" for the {}, defaulting to Strike loadout".format(str(unit_type)))
|
||||
payload_name = db.PLANE_PAYLOAD_OVERRIDES[unit_type][PinpointStrike]
|
||||
group.load_loadout(payload_name)
|
||||
did_load_loadout = True
|
||||
logging.info("Loaded overridden payload for {} - {} for task {}".format(unit_type, payload_name, for_task))
|
||||
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import logging
|
||||
from dataclasses import dataclass, field
|
||||
from typing import List, Type
|
||||
from typing import List, Type, Tuple
|
||||
|
||||
from dcs.mission import Mission, StartType
|
||||
from dcs.planes import IL_78M
|
||||
from dcs.planes import IL_78M, KC130, KC135MPRS, KC_135
|
||||
from dcs.unittype import UnitType
|
||||
from dcs.task import (
|
||||
AWACS,
|
||||
ActivateBeaconCommand,
|
||||
@ -68,13 +69,24 @@ class AirSupportConflictGenerator:
|
||||
def support_tasks(cls) -> List[Type[MainTask]]:
|
||||
return [Refueling, AWACS]
|
||||
|
||||
@staticmethod
|
||||
def _get_tanker_params(unit_type: Type[UnitType]) -> Tuple[int, int]:
|
||||
if unit_type is KC130:
|
||||
return (TANKER_ALT - 500, 596)
|
||||
elif unit_type is KC_135:
|
||||
return (TANKER_ALT, 770)
|
||||
elif unit_type is KC135MPRS:
|
||||
return (TANKER_ALT + 500, 596)
|
||||
return (TANKER_ALT, 574)
|
||||
|
||||
def generate(self):
|
||||
player_cp = self.conflict.from_cp if self.conflict.from_cp.captured else self.conflict.to_cp
|
||||
|
||||
fallback_tanker_number = 0
|
||||
|
||||
for i, tanker_unit_type in enumerate(db.find_unittype(Refueling, self.conflict.attackers_side)):
|
||||
variant = db.unit_type_name(tanker_unit_type)
|
||||
alt, airspeed = self._get_tanker_params(tanker_unit_type)
|
||||
variant = db.unit_type_name(tanker_unit_type)
|
||||
freq = self.radio_registry.alloc_uhf()
|
||||
tacan = self.tacan_registry.alloc_for_band(TacanBand.Y)
|
||||
tanker_heading = self.conflict.to_cp.position.heading_between_point(self.conflict.from_cp.position) + TANKER_HEADING_OFFSET * i
|
||||
@ -85,11 +97,11 @@ class AirSupportConflictGenerator:
|
||||
airport=None,
|
||||
plane_type=tanker_unit_type,
|
||||
position=tanker_position,
|
||||
altitude=TANKER_ALT,
|
||||
altitude=alt,
|
||||
race_distance=58000,
|
||||
frequency=freq.mhz,
|
||||
start_type=StartType.Warm,
|
||||
speed=574,
|
||||
speed=airspeed,
|
||||
tacanchannel=str(tacan),
|
||||
)
|
||||
tanker_group.set_frequency(freq.mhz)
|
||||
|
||||
113
gen/armor.py
113
gen/armor.py
@ -177,8 +177,15 @@ class GroundConflictGenerator:
|
||||
forward_heading: int
|
||||
) -> None:
|
||||
|
||||
infantry_position = group.points[0].position.random_point_within(250, 50)
|
||||
|
||||
infantry_position = self.conflict.find_ground_position(
|
||||
group.points[0].position.random_point_within(250, 50),
|
||||
500,
|
||||
forward_heading,
|
||||
self.conflict.theater
|
||||
)
|
||||
if not infantry_position:
|
||||
logging.warning("Could not find infantry position")
|
||||
return
|
||||
if side == self.conflict.attackers_country:
|
||||
cp = self.conflict.from_cp
|
||||
else:
|
||||
@ -230,6 +237,17 @@ class GroundConflictGenerator:
|
||||
heading=forward_heading,
|
||||
move_formation=PointAction.OffRoad)
|
||||
|
||||
def _set_reform_waypoint(
|
||||
self,
|
||||
dcs_group: VehicleGroup,
|
||||
forward_heading: int
|
||||
) -> None:
|
||||
"""Setting a waypoint close to the spawn position allows the group to reform gracefully
|
||||
rather than spin
|
||||
"""
|
||||
reform_point = dcs_group.position.point_from_heading(forward_heading, 50)
|
||||
dcs_group.add_waypoint(reform_point)
|
||||
|
||||
def _plan_artillery_action(
|
||||
self,
|
||||
stance: CombatStance,
|
||||
@ -242,6 +260,7 @@ class GroundConflictGenerator:
|
||||
Handles adding the DCS tasks for artillery groups for all combat stances.
|
||||
Returns True if tasking was added, returns False if the stance was not a combat stance.
|
||||
"""
|
||||
self._set_reform_waypoint(dcs_group, forward_heading)
|
||||
if stance != CombatStance.RETREAT:
|
||||
hold_task = Hold()
|
||||
hold_task.number = 1
|
||||
@ -261,10 +280,10 @@ class GroundConflictGenerator:
|
||||
if stance != CombatStance.RETREAT:
|
||||
|
||||
# Hold position
|
||||
dcs_group.points[0].tasks.append(Hold())
|
||||
retreat = self.find_retreat_point(dcs_group, forward_heading, (int)(RETREAT_DISTANCE/3))
|
||||
dcs_group.add_waypoint(dcs_group.position.point_from_heading(forward_heading, 1), PointAction.OffRoad)
|
||||
dcs_group.points[1].tasks.append(Hold())
|
||||
retreat = self.find_retreat_point(dcs_group, heading_sum(forward_heading, 180), (int)(RETREAT_DISTANCE/3))
|
||||
dcs_group.add_waypoint(dcs_group.position.point_from_heading(forward_heading, 1), PointAction.OffRoad)
|
||||
dcs_group.points[2].tasks.append(Hold())
|
||||
dcs_group.add_waypoint(retreat, PointAction.OffRoad)
|
||||
|
||||
artillery_fallback = TriggerOnce(Event.NoEvent, "ArtilleryRetreat #" + str(dcs_group.id))
|
||||
@ -302,6 +321,7 @@ class GroundConflictGenerator:
|
||||
Handles adding the DCS tasks for tank and IFV groups for all combat stances.
|
||||
Returns True if tasking was added, returns False if the stance was not a combat stance.
|
||||
"""
|
||||
self._set_reform_waypoint(dcs_group, forward_heading)
|
||||
if stance == CombatStance.AGGRESSIVE:
|
||||
# Attack nearest enemy if any
|
||||
# Then move forward OR Attack enemy base if it is not too far away
|
||||
@ -315,15 +335,20 @@ class GroundConflictGenerator:
|
||||
-RANDOM_OFFSET_ATTACK, RANDOM_OFFSET_ATTACK
|
||||
)
|
||||
)
|
||||
dcs_group.add_waypoint(target.points[0].position + rand_offset, PointAction.OffRoad)
|
||||
dcs_group.points[1].tasks.append(AttackGroup(target.id))
|
||||
target_point = self.conflict.theater.nearest_land_pos(
|
||||
target.points[0].position + rand_offset
|
||||
)
|
||||
dcs_group.add_waypoint(target_point)
|
||||
dcs_group.points[2].tasks.append(AttackGroup(target.id))
|
||||
|
||||
if (
|
||||
to_cp.position.distance_to_point(dcs_group.points[0].position)
|
||||
<=
|
||||
AGGRESIVE_MOVE_DISTANCE
|
||||
):
|
||||
attack_point = to_cp.position.random_point_within(500, 0)
|
||||
attack_point = self.conflict.theater.nearest_land_pos(
|
||||
to_cp.position.random_point_within(500, 0)
|
||||
)
|
||||
else:
|
||||
attack_point = self.find_offensive_point(
|
||||
dcs_group,
|
||||
@ -336,7 +361,9 @@ class GroundConflictGenerator:
|
||||
# If the enemy base is close enough, the units will attack the base
|
||||
if to_cp.position.distance_to_point(
|
||||
dcs_group.points[0].position) <= BREAKTHROUGH_OFFENSIVE_DISTANCE:
|
||||
attack_point = to_cp.position.random_point_within(500, 0)
|
||||
attack_point = self.conflict.theater.nearest_land_pos(
|
||||
to_cp.position.random_point_within(500, 0)
|
||||
)
|
||||
else:
|
||||
attack_point = self.find_offensive_point(dcs_group, forward_heading, BREAKTHROUGH_OFFENSIVE_DISTANCE)
|
||||
dcs_group.add_waypoint(attack_point, PointAction.OffRoad)
|
||||
@ -353,10 +380,15 @@ class GroundConflictGenerator:
|
||||
RANDOM_OFFSET_ATTACK
|
||||
)
|
||||
)
|
||||
dcs_group.add_waypoint(target.points[0].position+rand_offset, PointAction.OffRoad)
|
||||
dcs_group.points[i].tasks.append(AttackGroup(target.id))
|
||||
target_point = self.conflict.theater.nearest_land_pos(
|
||||
target.points[0].position+rand_offset
|
||||
)
|
||||
dcs_group.add_waypoint(target_point, PointAction.OffRoad)
|
||||
dcs_group.points[i + 1].tasks.append(AttackGroup(target.id))
|
||||
if to_cp.position.distance_to_point(dcs_group.points[0].position) <= AGGRESIVE_MOVE_DISTANCE:
|
||||
attack_point = to_cp.position.random_point_within(500, 0)
|
||||
attack_point = self.conflict.theater.nearest_land_pos(
|
||||
to_cp.position.random_point_within(500, 0)
|
||||
)
|
||||
dcs_group.add_waypoint(attack_point)
|
||||
|
||||
if stance != CombatStance.RETREAT:
|
||||
@ -375,10 +407,11 @@ class GroundConflictGenerator:
|
||||
Handles adding the DCS tasks for APC and ATGM groups for all combat stances.
|
||||
Returns True if tasking was added, returns False if the stance was not a combat stance.
|
||||
"""
|
||||
self._set_reform_waypoint(dcs_group, forward_heading)
|
||||
if stance in [CombatStance.AGGRESSIVE, CombatStance.BREAKTHROUGH, CombatStance.ELIMINATION]:
|
||||
# APC & ATGM will never move too much forward, but will follow along any offensive
|
||||
if to_cp.position.distance_to_point(dcs_group.points[0].position) <= AGGRESIVE_MOVE_DISTANCE:
|
||||
attack_point = to_cp.position.random_point_within(500, 0)
|
||||
attack_point = self.conflict.theater.nearest_land_pos(to_cp.position.random_point_within(500, 0))
|
||||
else:
|
||||
attack_point = self.find_offensive_point(dcs_group, forward_heading, AGGRESIVE_MOVE_DISTANCE)
|
||||
dcs_group.add_waypoint(attack_point, PointAction.OffRoad)
|
||||
@ -466,8 +499,8 @@ class GroundConflictGenerator:
|
||||
|
||||
self.mission.triggerrules.triggers.append(fallback)
|
||||
|
||||
@staticmethod
|
||||
def find_retreat_point(
|
||||
self,
|
||||
dcs_group: VehicleGroup,
|
||||
frontline_heading: int,
|
||||
distance: int = RETREAT_DISTANCE
|
||||
@ -478,10 +511,14 @@ class GroundConflictGenerator:
|
||||
:param frontline_heading: Heading of the frontline
|
||||
:return: dcs.mapping.Point object with the desired position
|
||||
"""
|
||||
return dcs_group.points[0].position.point_from_heading(frontline_heading-180, distance)
|
||||
desired_point = dcs_group.points[0].position.point_from_heading(heading_sum(frontline_heading, +180), distance)
|
||||
if self.conflict.theater.is_on_land(desired_point):
|
||||
return desired_point
|
||||
return self.conflict.theater.nearest_land_pos(desired_point)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def find_offensive_point(
|
||||
self,
|
||||
dcs_group: VehicleGroup,
|
||||
frontline_heading: int,
|
||||
distance: int
|
||||
@ -493,7 +530,10 @@ class GroundConflictGenerator:
|
||||
:param distance: Distance of the offensive (how far unit should move)
|
||||
:return: dcs.mapping.Point object with the desired position
|
||||
"""
|
||||
return dcs_group.points[0].position.point_from_heading(frontline_heading, distance)
|
||||
desired_point = dcs_group.points[0].position.point_from_heading(frontline_heading, distance)
|
||||
if self.conflict.theater.is_on_land(desired_point):
|
||||
return desired_point
|
||||
return self.conflict.theater.nearest_land_pos(desired_point)
|
||||
|
||||
@staticmethod
|
||||
def find_n_nearest_enemy_groups(
|
||||
@ -559,15 +599,22 @@ class GroundConflictGenerator:
|
||||
return potential_target.points[0].position
|
||||
return None
|
||||
|
||||
def get_artilery_group_distance_from_frontline(self, group):
|
||||
@staticmethod
|
||||
def get_artilery_group_distance_from_frontline(group: CombatGroup) -> int:
|
||||
"""
|
||||
For artilery group, decide the distance from frontline with the range of the unit
|
||||
"""
|
||||
rg = group.units[0].threat_range - 7500
|
||||
if rg > DISTANCE_FROM_FRONTLINE[CombatGroupRole.ARTILLERY]:
|
||||
rg = DISTANCE_FROM_FRONTLINE[CombatGroupRole.ARTILLERY]
|
||||
if rg < DISTANCE_FROM_FRONTLINE[CombatGroupRole.TANK]:
|
||||
rg = DISTANCE_FROM_FRONTLINE[CombatGroupRole.TANK] + 100
|
||||
if rg > DISTANCE_FROM_FRONTLINE[CombatGroupRole.ARTILLERY][1]:
|
||||
rg = random.randint(
|
||||
DISTANCE_FROM_FRONTLINE[CombatGroupRole.ARTILLERY][0],
|
||||
DISTANCE_FROM_FRONTLINE[CombatGroupRole.ARTILLERY][1]
|
||||
)
|
||||
elif rg < DISTANCE_FROM_FRONTLINE[CombatGroupRole.ARTILLERY][1]:
|
||||
rg = random.randint(
|
||||
DISTANCE_FROM_FRONTLINE[CombatGroupRole.TANK][0],
|
||||
DISTANCE_FROM_FRONTLINE[CombatGroupRole.TANK][1]
|
||||
)
|
||||
return rg
|
||||
|
||||
def get_valid_position_for_group(
|
||||
@ -578,16 +625,13 @@ class GroundConflictGenerator:
|
||||
heading: int,
|
||||
spawn_heading: int
|
||||
):
|
||||
i = 0
|
||||
while i < 1000:
|
||||
shifted = conflict_position.point_from_heading(heading, random.randint(0, combat_width))
|
||||
final_position = shifted.point_from_heading(spawn_heading, distance_from_frontline)
|
||||
shifted = conflict_position.point_from_heading(heading, random.randint(0, combat_width))
|
||||
desired_point = shifted.point_from_heading(
|
||||
spawn_heading,
|
||||
distance_from_frontline
|
||||
)
|
||||
return Conflict.find_ground_position(desired_point, combat_width, heading, self.conflict.theater)
|
||||
|
||||
if self.conflict.theater.is_on_land(final_position):
|
||||
return final_position
|
||||
i += 1
|
||||
continue
|
||||
return None
|
||||
|
||||
def _generate_groups(
|
||||
self,
|
||||
@ -604,7 +648,10 @@ class GroundConflictGenerator:
|
||||
if group.role == CombatGroupRole.ARTILLERY:
|
||||
distance_from_frontline = self.get_artilery_group_distance_from_frontline(group)
|
||||
else:
|
||||
distance_from_frontline = DISTANCE_FROM_FRONTLINE[group.role]
|
||||
distance_from_frontline = random.randint(
|
||||
DISTANCE_FROM_FRONTLINE[group.role][0],
|
||||
DISTANCE_FROM_FRONTLINE[group.role][1]
|
||||
)
|
||||
|
||||
final_position = self.get_valid_position_for_group(
|
||||
position,
|
||||
@ -659,7 +706,7 @@ class GroundConflictGenerator:
|
||||
group = self.mission.vehicle_group(
|
||||
side,
|
||||
namegen.next_unit_name(side, cp.id, unit), unit,
|
||||
position=self._group_point(at, distance_from_frontline),
|
||||
position=at,
|
||||
group_size=count,
|
||||
heading=heading,
|
||||
move_formation=move_formation)
|
||||
|
||||
@ -91,8 +91,12 @@ class Conflict:
|
||||
return pos
|
||||
|
||||
@classmethod
|
||||
def find_ground_position(cls, initial: Point, max_distance: int, heading: int, theater: ConflictTheater) -> Point:
|
||||
"""Finds the nearest valid ground position along a provided heading and it's inverse"""
|
||||
def find_ground_position(cls, initial: Point, max_distance: int, heading: int, theater: ConflictTheater, coerce=True) -> Optional[Point]:
|
||||
"""
|
||||
Finds the nearest valid ground position along a provided heading and it's inverse up to max_distance.
|
||||
`coerce=True` will return the closest land position to `initial` regardless of heading or distance
|
||||
`coerce=False` will return None if a point isn't found
|
||||
"""
|
||||
pos = initial
|
||||
if theater.is_on_land(pos):
|
||||
return pos
|
||||
@ -101,5 +105,9 @@ class Conflict:
|
||||
if theater.is_on_land(pos):
|
||||
return pos
|
||||
pos = initial.point_from_heading(opposite_heading(heading), distance)
|
||||
if coerce:
|
||||
pos = theater.nearest_land_pos(initial)
|
||||
return pos
|
||||
logging.error("Didn't find ground position ({})!".format(initial))
|
||||
return initial
|
||||
return None
|
||||
|
||||
|
||||
@ -234,7 +234,7 @@ class WaypointBuilder:
|
||||
return self._target_area(f"STRIKE {target.name}", target)
|
||||
|
||||
def sead_area(self, target: MissionTarget) -> FlightWaypoint:
|
||||
return self._target_area(f"SEAD on {target.name}", target)
|
||||
return self._target_area(f"SEAD on {target.name}", target, flyover=True)
|
||||
|
||||
def dead_area(self, target: MissionTarget) -> FlightWaypoint:
|
||||
return self._target_area(f"DEAD on {target.name}", target)
|
||||
|
||||
@ -187,14 +187,14 @@ class CombatGroupRole(Enum):
|
||||
|
||||
|
||||
DISTANCE_FROM_FRONTLINE = {
|
||||
CombatGroupRole.TANK:3200,
|
||||
CombatGroupRole.APC:8000,
|
||||
CombatGroupRole.IFV:3700,
|
||||
CombatGroupRole.ARTILLERY:18000,
|
||||
CombatGroupRole.SHORAD:13000,
|
||||
CombatGroupRole.LOGI:20000,
|
||||
CombatGroupRole.INFANTRY:3000,
|
||||
CombatGroupRole.ATGM:6200
|
||||
CombatGroupRole.TANK: (2200, 3200),
|
||||
CombatGroupRole.APC: (7500, 8500),
|
||||
CombatGroupRole.IFV: (2700, 3700),
|
||||
CombatGroupRole.ARTILLERY: (16000, 18000),
|
||||
CombatGroupRole.SHORAD: (12000, 13000),
|
||||
CombatGroupRole.LOGI: (18000, 20000),
|
||||
CombatGroupRole.INFANTRY: (2800, 3300),
|
||||
CombatGroupRole.ATGM: (5200, 6200),
|
||||
}
|
||||
|
||||
GROUP_SIZES_BY_COMBAT_STANCE = {
|
||||
|
||||
@ -82,7 +82,13 @@ class TriggersGenerator:
|
||||
airport.operating_level_air = 0
|
||||
airport.operating_level_equipment = 0
|
||||
airport.operating_level_fuel = 0
|
||||
|
||||
|
||||
for airport in self.mission.terrain.airport_list():
|
||||
if airport.id not in cp_ids:
|
||||
airport.unlimited_fuel = True
|
||||
airport.unlimited_munitions = True
|
||||
airport.unlimited_aircrafts = True
|
||||
|
||||
for cp in self.game.theater.controlpoints:
|
||||
if isinstance(cp, Airfield):
|
||||
self.mission.terrain.airport_by_id(cp.at.id).set_coalition(cp.captured and player_coalition or enemy_coalition)
|
||||
|
||||
@ -284,12 +284,13 @@ class QLiberationWindow(QMainWindow):
|
||||
"<h4>Authors</h4>" + \
|
||||
"<p>DCS Liberation was originally developed by <b>shdwp</b>, DCS Liberation 2.0 is a partial rewrite based on this work by <b>Khopa</b>." \
|
||||
"<h4>Contributors</h4>" + \
|
||||
"shdwp, Khopa, ColonelPanic, Roach, Wrycu, calvinmorrow, JohanAberg, Deus, root0fall, Captain Cody, steveveepee, pedromagueija, parithon, bwRavencl, davidp57, Plob" + \
|
||||
"shdwp, Khopa, ColonelPanic, Roach, Wrycu, calvinmorrow, JohanAberg, Deus, root0fall, Captain Cody, steveveepee, pedromagueija, parithon, bwRavencl, davidp57, Plob, Hawkmoon" + \
|
||||
"<h4>Special Thanks :</h4>" \
|
||||
"<b>rp-</b> <i>for the pydcs framework</i><br/>"\
|
||||
"<b>Grimes (mrSkortch)</b> & <b>Speed</b> <i>for the MIST framework</i><br/>"\
|
||||
"<b>Ciribob </b> <i>for the JTACAutoLase.lua script</i><br/>"\
|
||||
"<b>Walder </b> <i>for the Skynet-IADS script</i><br/>"
|
||||
"<b>Walder </b> <i>for the Skynet-IADS script</i><br/>"\
|
||||
"<b>Anubis Yinepu </b> <i>for the Hercules Cargo script</i><br/>"
|
||||
about = QMessageBox()
|
||||
about.setWindowTitle("About DCS Liberation")
|
||||
about.setIcon(QMessageBox.Icon.Information)
|
||||
|
||||
@ -88,6 +88,9 @@ class QAircraftRecruitmentMenu(QFrame, QRecruitBehaviour):
|
||||
if self.maximum_units > 0:
|
||||
if self.cp.unclaimed_parking(self.game_model.game) <= 0:
|
||||
logging.debug(f"No space for additional aircraft at {self.cp}.")
|
||||
QMessageBox.warning(
|
||||
self, "No space for additional aircraft",
|
||||
f"There is no parking space left at {self.cp.name} to accommodate another plane.", QMessageBox.Ok)
|
||||
return
|
||||
|
||||
super().buy(unit_type)
|
||||
|
||||
@ -1,185 +0,0 @@
|
||||
{
|
||||
"name": "Syria - Full Map",
|
||||
"theater": "Syria",
|
||||
"authors": "Khopa",
|
||||
"description": "<p>Full map of Syria</p><p><strong>Note:</strong> This scenario is heavy on performance, enabling \"culling\" in settings is highly recommended.</p>",
|
||||
"player_points": [
|
||||
{
|
||||
"type": "airbase",
|
||||
"id": "Ramat David",
|
||||
"size": 1000,
|
||||
"importance": 1.4
|
||||
},
|
||||
{
|
||||
"type": "carrier",
|
||||
"id": 1001,
|
||||
"x": -151000,
|
||||
"y": -106000,
|
||||
"captured_invert": true
|
||||
},
|
||||
{
|
||||
"type": "lha",
|
||||
"id": 1002,
|
||||
"x": -131000,
|
||||
"y": -161000,
|
||||
"captured_invert": true
|
||||
}
|
||||
],
|
||||
"enemy_points": [
|
||||
{
|
||||
"type": "airbase",
|
||||
"id": "King Hussein Air College",
|
||||
"size": 1000,
|
||||
"importance": 1.4
|
||||
},
|
||||
{
|
||||
"type": "airbase",
|
||||
"id": "Khalkhalah",
|
||||
"size": 1000,
|
||||
"importance": 1.2
|
||||
},
|
||||
{
|
||||
"type": "airbase",
|
||||
"id": "Al-Dumayr",
|
||||
"size": 1000,
|
||||
"importance": 1.2
|
||||
},
|
||||
{
|
||||
"type": "airbase",
|
||||
"id": "Al Qusayr",
|
||||
"size": 1000,
|
||||
"importance": 1
|
||||
},
|
||||
{
|
||||
"type": "airbase",
|
||||
"id": "Rene Mouawad",
|
||||
"size": 1000,
|
||||
"importance": 1.4
|
||||
},
|
||||
{
|
||||
"type": "airbase",
|
||||
"id": "Hama",
|
||||
"size": 1000,
|
||||
"importance": 1
|
||||
},
|
||||
{
|
||||
"type": "airbase",
|
||||
"id": "Bassel Al-Assad",
|
||||
"size": 1000,
|
||||
"importance": 1.4
|
||||
},
|
||||
{
|
||||
"type": "airbase",
|
||||
"id": "Palmyra",
|
||||
"size": 1000,
|
||||
"importance": 1
|
||||
},
|
||||
{
|
||||
"type": "airbase",
|
||||
"id": "Tabqa",
|
||||
"size": 1000,
|
||||
"importance": 1
|
||||
},
|
||||
{
|
||||
"type": "airbase",
|
||||
"id": "Jirah",
|
||||
"size": 1000,
|
||||
"importance": 1
|
||||
},
|
||||
{
|
||||
"type": "airbase",
|
||||
"id": "Aleppo",
|
||||
"size": 1000,
|
||||
"importance": 1.2
|
||||
},
|
||||
{
|
||||
"type": "airbase",
|
||||
"id": "Minakh",
|
||||
"size": 1000,
|
||||
"importance": 1
|
||||
},
|
||||
{
|
||||
"type": "airbase",
|
||||
"id": "Hatay",
|
||||
"size": 1000,
|
||||
"importance": 1.4
|
||||
},
|
||||
{
|
||||
"type": "airbase",
|
||||
"id": "Incirlik",
|
||||
"size": 1000,
|
||||
"importance": 1.4,
|
||||
"captured_invert": true
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
"King Hussein Air College",
|
||||
"Ramat David"
|
||||
],
|
||||
[
|
||||
"Khalkhalah",
|
||||
"King Hussein Air College"
|
||||
],
|
||||
[
|
||||
"Al-Dumayr",
|
||||
"Khalkhalah"
|
||||
],
|
||||
[
|
||||
"Al Qusayr",
|
||||
"Al-Dumayr"
|
||||
],
|
||||
[
|
||||
"Al Qusayr",
|
||||
"Hama"
|
||||
],
|
||||
[
|
||||
"Al Qusayr",
|
||||
"Palmyra"
|
||||
],
|
||||
[
|
||||
"Al Qusayr",
|
||||
"Rene Mouawad"
|
||||
],
|
||||
[
|
||||
"Bassel Al-Assad",
|
||||
"Rene Mouawad"
|
||||
],
|
||||
[
|
||||
"Aleppo",
|
||||
"Hama"
|
||||
],
|
||||
[
|
||||
"Bassel Al-Assad",
|
||||
"Hama"
|
||||
],
|
||||
[
|
||||
"Bassel Al-Assad",
|
||||
"Hatay"
|
||||
],
|
||||
[
|
||||
"Palmyra",
|
||||
"Tabqa"
|
||||
],
|
||||
[
|
||||
"Jirah",
|
||||
"Tabqa"
|
||||
],
|
||||
[
|
||||
"Aleppo",
|
||||
"Jirah"
|
||||
],
|
||||
[
|
||||
"Aleppo",
|
||||
"Minakh"
|
||||
],
|
||||
[
|
||||
"Hatay",
|
||||
"Minakh"
|
||||
],
|
||||
[
|
||||
"Incirlik",
|
||||
"Minakh"
|
||||
]
|
||||
]
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "Syria - Full Map Remastered",
|
||||
"name": "Syria - Full Map",
|
||||
"theater": "Syria",
|
||||
"authors": "Hawkmoon",
|
||||
"description": "<p>Full map of Syria remastered for 2.3</p><p><strong>Note:</strong>For a better early game experience is suggested to give the AI an high amount of starting money This scenario is heavy on performance, enabling \"culling\" in settings is highly recommended.</p>",
|
||||
"description": "<p>Full map of Syria</p><p><strong>Note:</strong>For a better early game experience is suggested to give the AI an high amount of starting money This scenario is heavy on performance, enabling \"culling\" in settings is highly recommended.</p>",
|
||||
"miz": "syria_full_map_remastered.miz"
|
||||
}
|
||||
Binary file not shown.
@ -282,7 +282,7 @@ local unitPayloads = {
|
||||
},
|
||||
},
|
||||
[8] = {
|
||||
["name"] = "RUNWAY STRIKE",
|
||||
["name"] = "RUNWAY_ATTACK",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{5335D97A-35A5-4643-9D9B-026C75961E52}",
|
||||
|
||||
@ -2,27 +2,15 @@ local unitPayloads = {
|
||||
["name"] = "Hercules",
|
||||
["payloads"] = {
|
||||
[1] = {
|
||||
["name"] = "CAS",
|
||||
["name"] = "DEAD",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "Herc_BattleStation",
|
||||
["num"] = 9,
|
||||
["CLSID"] = "Herc_GBU-43/B(MOAB)",
|
||||
["num"] = 11,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{Herc_105mm_Howitzer}",
|
||||
["num"] = 8,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{Herc_GAU_23A_Chain_Gun}",
|
||||
["num"] = 7,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{Herc_M61_Vulcan_Rotary_Cannon}",
|
||||
["num"] = 6,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "Herc_JATO",
|
||||
["num"] = 1,
|
||||
["CLSID"] = "Herc_Soldier_Squad",
|
||||
["num"] = 12,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
@ -33,24 +21,12 @@ local unitPayloads = {
|
||||
["name"] = "STRIKE",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "Herc_BattleStation",
|
||||
["num"] = 9,
|
||||
["CLSID"] = "Herc_Soldier_Squad",
|
||||
["num"] = 12,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{Herc_105mm_Howitzer}",
|
||||
["num"] = 8,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{Herc_GAU_23A_Chain_Gun}",
|
||||
["num"] = 7,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{Herc_M61_Vulcan_Rotary_Cannon}",
|
||||
["num"] = 6,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "Herc_JATO",
|
||||
["num"] = 1,
|
||||
["CLSID"] = "Herc_GBU-43/B(MOAB)",
|
||||
["num"] = 11,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
@ -61,24 +37,12 @@ local unitPayloads = {
|
||||
["name"] = "ANTISHIP",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "Herc_BattleStation",
|
||||
["num"] = 9,
|
||||
["CLSID"] = "Herc_GBU-43/B(MOAB)",
|
||||
["num"] = 11,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{Herc_105mm_Howitzer}",
|
||||
["num"] = 8,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{Herc_GAU_23A_Chain_Gun}",
|
||||
["num"] = 7,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{Herc_M61_Vulcan_Rotary_Cannon}",
|
||||
["num"] = 6,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "Herc_JATO",
|
||||
["num"] = 1,
|
||||
["CLSID"] = "Herc_Soldier_Squad",
|
||||
["num"] = 12,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
@ -86,27 +50,15 @@ local unitPayloads = {
|
||||
},
|
||||
},
|
||||
[4] = {
|
||||
["name"] = "SEAD",
|
||||
["name"] = "OCA",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "Herc_BattleStation",
|
||||
["num"] = 9,
|
||||
["CLSID"] = "Herc_Soldier_Squad",
|
||||
["num"] = 12,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{Herc_105mm_Howitzer}",
|
||||
["num"] = 8,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{Herc_GAU_23A_Chain_Gun}",
|
||||
["num"] = 7,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{Herc_M61_Vulcan_Rotary_Cannon}",
|
||||
["num"] = 6,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "Herc_JATO",
|
||||
["num"] = 1,
|
||||
["CLSID"] = "Herc_GBU-43/B(MOAB)",
|
||||
["num"] = 11,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
@ -114,27 +66,15 @@ local unitPayloads = {
|
||||
},
|
||||
},
|
||||
[5] = {
|
||||
["name"] = "DEAD",
|
||||
["name"] = "CAS",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "Herc_BattleStation",
|
||||
["num"] = 9,
|
||||
["CLSID"] = "Herc_GBU-43/B(MOAB)",
|
||||
["num"] = 11,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{Herc_105mm_Howitzer}",
|
||||
["num"] = 8,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{Herc_GAU_23A_Chain_Gun}",
|
||||
["num"] = 7,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{Herc_M61_Vulcan_Rotary_Cannon}",
|
||||
["num"] = 6,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "Herc_JATO",
|
||||
["num"] = 1,
|
||||
["CLSID"] = "Herc_Soldier_Squad",
|
||||
["num"] = 12,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
@ -142,27 +82,15 @@ local unitPayloads = {
|
||||
},
|
||||
},
|
||||
[6] = {
|
||||
["name"] = "OCA",
|
||||
["name"] = "SEAD",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "Herc_BattleStation",
|
||||
["num"] = 9,
|
||||
["CLSID"] = "Herc_GBU-43/B(MOAB)",
|
||||
["num"] = 11,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{Herc_105mm_Howitzer}",
|
||||
["num"] = 8,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{Herc_GAU_23A_Chain_Gun}",
|
||||
["num"] = 7,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{Herc_M61_Vulcan_Rotary_Cannon}",
|
||||
["num"] = 6,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "Herc_JATO",
|
||||
["num"] = 1,
|
||||
["CLSID"] = "Herc_Soldier_Squad",
|
||||
["num"] = 12,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
@ -171,10 +99,22 @@ local unitPayloads = {
|
||||
},
|
||||
[7] = {
|
||||
["name"] = "CAP",
|
||||
["pylons"] = {
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 31,
|
||||
},
|
||||
},
|
||||
[8] = {
|
||||
["name"] = "RUNWAY_STRIKE",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "Herc_JATO",
|
||||
["num"] = 1,
|
||||
["CLSID"] = "Herc_Soldier_Squad",
|
||||
["num"] = 12,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "Herc_GBU-43/B(MOAB)",
|
||||
["num"] = 11,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
|
||||
@ -2,44 +2,6 @@ local unitPayloads = {
|
||||
["name"] = "JF-17",
|
||||
["payloads"] = {
|
||||
[1] = {
|
||||
["name"] = "CAP",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "DIS_TANK800",
|
||||
["num"] = 5,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "DIS_TANK800",
|
||||
["num"] = 3,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "DIS_WMD7",
|
||||
["num"] = 4,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "DIS_PL-5EII",
|
||||
["num"] = 1,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "DIS_PL-5EII",
|
||||
["num"] = 7,
|
||||
},
|
||||
[6] = {
|
||||
["CLSID"] = "DIS_SD-10_DUAL_R",
|
||||
["num"] = 6,
|
||||
},
|
||||
[7] = {
|
||||
["CLSID"] = "DIS_SD-10_DUAL_L",
|
||||
["num"] = 2,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 10,
|
||||
[2] = 11,
|
||||
[3] = 19,
|
||||
},
|
||||
},
|
||||
[2] = {
|
||||
["name"] = "CAS",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
@ -69,7 +31,7 @@ local unitPayloads = {
|
||||
[3] = 19,
|
||||
},
|
||||
},
|
||||
[3] = {
|
||||
[2] = {
|
||||
["name"] = "STRIKE",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
@ -103,6 +65,44 @@ local unitPayloads = {
|
||||
[3] = 19,
|
||||
},
|
||||
},
|
||||
[3] = {
|
||||
["name"] = "CAP",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "DIS_TANK800",
|
||||
["num"] = 5,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "DIS_TANK800",
|
||||
["num"] = 3,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "DIS_WMD7",
|
||||
["num"] = 4,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "DIS_PL-5EII",
|
||||
["num"] = 1,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "DIS_PL-5EII",
|
||||
["num"] = 7,
|
||||
},
|
||||
[6] = {
|
||||
["CLSID"] = "DIS_SD-10_DUAL_R",
|
||||
["num"] = 6,
|
||||
},
|
||||
[7] = {
|
||||
["CLSID"] = "DIS_SD-10_DUAL_L",
|
||||
["num"] = 2,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 10,
|
||||
[2] = 11,
|
||||
[3] = 19,
|
||||
},
|
||||
},
|
||||
[4] = {
|
||||
["name"] = "SEAD",
|
||||
["pylons"] = {
|
||||
@ -179,6 +179,44 @@ local unitPayloads = {
|
||||
[3] = 19,
|
||||
},
|
||||
},
|
||||
[6] = {
|
||||
["name"] = "RUNWAY_ATTACK",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "DIS_TYPE200_DUAL_R",
|
||||
["num"] = 6,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "DIS_TANK800",
|
||||
["num"] = 5,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "DIS_TANK800",
|
||||
["num"] = 3,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "DIS_TYPE200_DUAL_L",
|
||||
["num"] = 2,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "DIS_PL-5EII",
|
||||
["num"] = 1,
|
||||
},
|
||||
[6] = {
|
||||
["CLSID"] = "DIS_PL-5EII",
|
||||
["num"] = 7,
|
||||
},
|
||||
[7] = {
|
||||
["CLSID"] = "DIS_WMD7",
|
||||
["num"] = 4,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 10,
|
||||
[2] = 11,
|
||||
[3] = 19,
|
||||
},
|
||||
},
|
||||
},
|
||||
["unitType"] = "JF-17",
|
||||
}
|
||||
|
||||
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user