Skip to content

Commit

Permalink
Merge branch 'master' into feature/save-coalition-countries-even-with…
Browse files Browse the repository at this point in the history
…-no-units
  • Loading branch information
DanAlbert committed Jan 26, 2024
2 parents 44e3e58 + 71cb355 commit 32911f8
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 2 deletions.
20 changes: 20 additions & 0 deletions dcs/mission.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ def __init__(self, terrain: Optional[Terrain] = None) -> None:
self._sortie = self.string("")
self.pictureFileNameR: List[Union[ResourceKey, str]] = []
self.pictureFileNameB: List[Union[ResourceKey, str]] = []
self.pictureFileNameN: List[Union[ResourceKey, str]] = []
self.version = Mission._CURRENT_MIZ_VERSION
self.currentKey = 0
self.start_time = datetime.fromtimestamp(1306886400 + 43200, timezone.utc) # 01-06-2011 12:00:00 UTC
Expand Down Expand Up @@ -314,6 +315,9 @@ def loaddict(fname: str, mizfile: zipfile.ZipFile, reserved_files: List[str]) ->
self.pictureFileNameR.append(imp_mission["pictureFileNameR"][pic])
for pic in sorted(imp_mission["pictureFileNameB"]):
self.pictureFileNameB.append(imp_mission["pictureFileNameB"][pic])
if "pictureFileNameN" in imp_mission:
for pic in sorted(imp_mission["pictureFileNameN"]):
self.pictureFileNameN.append(imp_mission["pictureFileNameN"][pic])
self.version = imp_mission["version"]
self.currentKey = imp_mission["currentKey"]
imp_date = imp_mission.get("date", {"Year": 2011, "Month": 6, "Day": 1})
Expand Down Expand Up @@ -477,6 +481,19 @@ def add_picture_blue(self, filepath: str) -> ResourceKey:
self.pictureFileNameB.append(reskey)
return reskey

def add_picture_neutral(self, filepath: str) -> ResourceKey:
"""Adds a new briefing picture to the neutral coalition.
Args:
filepath: path to the image, jpg or bmp.
Returns:
the resource key of the picture
"""
reskey = self.map_resource.add_resource_file(filepath)
self.pictureFileNameN.append(reskey)
return reskey

def next_group_id(self):
"""Get the next free group id
Expand Down Expand Up @@ -2053,6 +2070,9 @@ def dict(self):
m["pictureFileNameB"] = {}
for i in range(0, len(self.pictureFileNameB)):
m["pictureFileNameB"][i + 1] = str(self.pictureFileNameB[i])
m["pictureFileNameN"] = {}
for i in range(0, len(self.pictureFileNameN)):
m["pictureFileNameN"][i + 1] = str(self.pictureFileNameN[i])
m["descriptionBlueTask"] = self._description_bluetask.id
m["descriptionRedTask"] = self._description_redtask.id
if self.init_script_file is not None:
Expand Down
44 changes: 42 additions & 2 deletions dcs/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,8 @@ def stop_after_duration(self, duration: int):
self.params["stopCondition"]["duration"] = duration


class WeaponType(Enum):
Auto = 1073741822
class WeaponType(IntEnum):
Auto = 9663676414
NoWeapon = 0
All = 4294967295
Unguided = 805339120
Expand Down Expand Up @@ -323,6 +323,13 @@ class Expend(Enum):
Half = "Half"
All = "All"

def __eq__(self, other: Any) -> bool:
if isinstance(other, str):
return self.value == other
if isinstance(other, Expend):
return self.value == other.value
return False


class AttackGroup(Task):
"""Attack group task action
Expand Down Expand Up @@ -1077,6 +1084,38 @@ def __eq__(self, other) -> bool:
return False


class CarpetBombing(Task):
"""Create Carpet Bombing Task object
:param alt_above: AGL altitude (in meters) from which bombing is to be performed. Defaults to 2000.
:param pattern_length: The pattern length (in meters) of the carpet bombing run. Defaults to 500.
:param release_qty: How many weapons to release. Defaults to Expend.Auto. See :py:class:`dcs.task.Expend`
:param weapon_type: The weapon to be used. Defaults to WeaponType.Auto. See :py:class:`dcs.task.WeaponType`
"""
Id = "CarpetBombing"
DEFAULT_ALT: int = 2000

def __init__(self, alt_above: int = DEFAULT_ALT,
pattern_length: int = 500,
release_qty: Expend = Expend.Auto,
weapon_type: WeaponType = WeaponType.Auto) -> None:
super().__init__(self.Id)
# hardcoded parameters are present in .miz file, but not visible in Mission Editor
self.params = {
"altitude": alt_above,
"altitudeEnabled": True if alt_above != CarpetBombing.DEFAULT_ALT else False,
"attackQty": 1,
"attackQtyLimit": False,
"attackType": "Carpet",
"carpetLength": pattern_length,
"expend": release_qty.value,
"groupAttack": False,
"weaponType": weapon_type.value,
"x": -52946.816024994,
"y": -52425.804462374,
}


tasks_map: Dict[str, Type[Task]] = {
ControlledTask.Id: ControlledTask,
EscortTaskAction.Id: EscortTaskAction,
Expand Down Expand Up @@ -1110,6 +1149,7 @@ def __eq__(self, other) -> bool:
AttackMapObject.Id: AttackMapObject,
EngageTargets.Id: EngageTargets,
WWIIFollowBigFormation.Id: WWIIFollowBigFormation,
CarpetBombing.Id: CarpetBombing,
}


Expand Down
Binary file added tests/missions/big-formation-carpet-bombing.miz
Binary file not shown.
60 changes: 60 additions & 0 deletions tests/test_mission.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
from dcs.task import WWIIFollowBigFormation
from dcs.action import PictureAction
from dcs.action import PictureToAll, PictureToCoalition, PictureToCountry, PictureToGroup, PictureToUnit
from dcs.task import Task, CarpetBombing, Expend, WeaponType
from dcs.action import Coalition
from dcs.mission import Mission
from enum import IntEnum


class BasicTests(unittest.TestCase):
Expand Down Expand Up @@ -730,6 +734,7 @@ def test_mission_save_pictureFileName(self):
image_path = 'tests/images/blue.png'
reskey_b = m.add_picture_blue(image_path)
reskey_r = m.add_picture_red(image_path)
reskey_n = m.add_picture_neutral(image_path)

mission_path = 'missions/test_mission_pictureFileName.miz'
m.save(mission_path)
Expand All @@ -741,6 +746,8 @@ def test_mission_save_pictureFileName(self):
self.assertEqual(m2.pictureFileNameB[0], reskey_b.key)
self.assertEqual(len(m2.pictureFileNameR), 1)
self.assertEqual(m2.pictureFileNameR[0], reskey_r.key)
self.assertEqual(len(m2.pictureFileNameN), 1)
self.assertEqual(m2.pictureFileNameN[0], reskey_n.key)

def test_create_quad_point_zone(self):
caucasus = dcs.terrain.Caucasus()
Expand Down Expand Up @@ -1264,3 +1271,56 @@ def test_empty_mission_with_coalitions(self) -> None:
self.assertEqual(len(m.coalition['blue'].countries["UK"].plane_group),
len(m2.coalition['blue'].countries["UK"].plane_group))


def test_smoke_action_carpet_bombing(self) -> None:

# this is fictional enum to simplify addressing as defined
# in big-formation-carpet-bombing.miz
class FormationPosition(IntEnum):
Leader = 0,
Right = 1,
Back = 2,
Left = 3,

def get_task(m: Mission, coalition: Coalition, country_name: str,
plane_group_idx: FormationPosition, point_idx: int, task_idx: int) -> Task:
return m.coalition[coalition.value].country(
country_name).plane_group[plane_group_idx].points[point_idx].tasks[task_idx]

def get_carpetbombing_task(m: Mission, coalition: Coalition, country_name: str,
plane_group_idx: FormationPosition, point_idx: int, task_idx: int) -> CarpetBombing:
task = get_task(m, coalition, country_name, plane_group_idx, point_idx, task_idx)
assert isinstance(task, CarpetBombing)
return task

m_name = "tests/missions/big-formation-carpet-bombing.miz"
m = dcs.mission.Mission()
m.load_file(m_name)

m2_name = "missions/saved.big-formation-carpet-bombing.miz"
m.save(m2_name)

m2 = dcs.mission.Mission()
m2.load_file(m2_name)

coalition = Coalition.Blue
country = "USA"

def validate_formation(m: Mission, m2: Mission, position: FormationPosition, expend: Expend,
weapon_type: WeaponType, altitude_enabled: bool) -> None:
point_idx = 2
task_idx = 0

m_task = get_carpetbombing_task(m, coalition, country, position, point_idx, task_idx)

self.assertEqual(m_task.params["expend"], expend)
self.assertEqual(m_task.params["weaponType"], weapon_type)
self.assertEqual(m_task.params["altitudeEnabled"], altitude_enabled)

m2_task = get_carpetbombing_task(m2, coalition, country, position, point_idx, task_idx)
self.assertEqual(m_task, m2_task)

validate_formation(m, m2, FormationPosition.Leader, Expend.Auto, WeaponType.Auto, True)
validate_formation(m, m2, FormationPosition.Left, Expend.Four, WeaponType.IronBombs, False)
validate_formation(m, m2, FormationPosition.Back, Expend.Auto, WeaponType.IronBombs, False)
validate_formation(m, m2, FormationPosition.Right, Expend.Auto, WeaponType.Auto, False)

0 comments on commit 32911f8

Please sign in to comment.