From aac7f43d16bdd6538c22419c2772845ecba8d6c6 Mon Sep 17 00:00:00 2001 From: 332FG Raven <332fg.raven@gmail.com> Date: Wed, 17 Jan 2024 14:45:57 -0800 Subject: [PATCH 1/3] Fix for WeaponType.Auto * DCS seems to generate .miz files with Auto as 9663676414 --- dcs/task.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dcs/task.py b/dcs/task.py index 40e769f3..39831cfe 100644 --- a/dcs/task.py +++ b/dcs/task.py @@ -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 From 773e90b2bf9446be59e6dfaa4c968e581f0d5fce Mon Sep 17 00:00:00 2001 From: 332FG Raven <332fg.raven@gmail.com> Date: Fri, 19 Jan 2024 11:15:00 -0800 Subject: [PATCH 2/3] Support for briefing pictures for neutral side --- dcs/mission.py | 20 ++++++++++++++++++++ tests/test_mission.py | 3 +++ 2 files changed, 23 insertions(+) diff --git a/dcs/mission.py b/dcs/mission.py index 448b2d42..da3832b6 100644 --- a/dcs/mission.py +++ b/dcs/mission.py @@ -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 @@ -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}) @@ -476,6 +480,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 @@ -2052,6 +2069,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: diff --git a/tests/test_mission.py b/tests/test_mission.py index 3e3c395c..ec2ff50c 100644 --- a/tests/test_mission.py +++ b/tests/test_mission.py @@ -730,6 +730,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) @@ -741,6 +742,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() From 71cb35518ba6190f66ae6dc72af3e7eeeef3a59a Mon Sep 17 00:00:00 2001 From: 332fg-raven <152709000+332fg-raven@users.noreply.github.com> Date: Thu, 25 Jan 2024 17:18:18 -0800 Subject: [PATCH 3/3] Support for CarpetBombing task (#356) This change allows WWIIBigFormation to use Carpet Bombing task. Removed duplicate tests for big formation which crept in with PR #351 --- dcs/task.py | 40 ++++++++++++ .../missions/big-formation-carpet-bombing.miz | Bin 0 -> 30299 bytes tests/test_mission.py | 57 ++++++++++++++++++ 3 files changed, 97 insertions(+) create mode 100755 tests/missions/big-formation-carpet-bombing.miz diff --git a/dcs/task.py b/dcs/task.py index 39831cfe..bd66d840 100644 --- a/dcs/task.py +++ b/dcs/task.py @@ -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 @@ -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, @@ -1110,6 +1149,7 @@ def __eq__(self, other) -> bool: AttackMapObject.Id: AttackMapObject, EngageTargets.Id: EngageTargets, WWIIFollowBigFormation.Id: WWIIFollowBigFormation, + CarpetBombing.Id: CarpetBombing, } diff --git a/tests/missions/big-formation-carpet-bombing.miz b/tests/missions/big-formation-carpet-bombing.miz new file mode 100755 index 0000000000000000000000000000000000000000..06a56e682bd3a56eb52d5b01d4741dae81b56970 GIT binary patch literal 30299 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 baQvUKmX`vD`27Y1;9DOsDtmypfPnrVR{gy> literal 0 HcmV?d00001 diff --git a/tests/test_mission.py b/tests/test_mission.py index ec2ff50c..275eca4e 100644 --- a/tests/test_mission.py +++ b/tests/test_mission.py @@ -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): @@ -1240,3 +1244,56 @@ def test_action_a_out_picture_u(self) -> None: m2.load_file(m2_name) self.assertEqual(m_action, m2.triggerrules.triggers[0].actions[5]) + + 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)