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:
Khopa 2020-12-18 00:23:53 +01:00
commit 23a0846533
21 changed files with 305 additions and 400 deletions

View File

@ -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:

View File

@ -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.

View File

@ -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]] = {

View File

@ -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]

View File

@ -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:

View 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))

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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 = {

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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"
]
]
}

View File

@ -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.

View File

@ -282,7 +282,7 @@ local unitPayloads = {
},
},
[8] = {
["name"] = "RUNWAY STRIKE",
["name"] = "RUNWAY_ATTACK",
["pylons"] = {
[1] = {
["CLSID"] = "{5335D97A-35A5-4643-9D9B-026C75961E52}",

View File

@ -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"] = {

View File

@ -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.