From 24a90b71c0d6041f2c14a030a36e45628f0d5c2f Mon Sep 17 00:00:00 2001 From: 332fg-raven <152709000+332fg-raven@users.noreply.github.com> Date: Fri, 12 Jan 2024 16:45:14 -0800 Subject: [PATCH] Added support for FollowBigFormations task (#353) --- dcs/mapping.py | 7 ++ dcs/task.py | 52 +++++++++++++- tests/missions/big-formation.miz | Bin 0 -> 29506 bytes tests/test_mission.py | 117 +++++++++++++++++++++++++++++++ 4 files changed, 173 insertions(+), 3 deletions(-) create mode 100755 tests/missions/big-formation.miz diff --git a/dcs/mapping.py b/dcs/mapping.py index 9c83c414..073370b7 100644 --- a/dcs/mapping.py +++ b/dcs/mapping.py @@ -98,6 +98,13 @@ class Vector2: y: float +@dataclass(frozen=True) +class Vector3: + x: int + y: int + z: int + + class Point(Vector2): def __init__(self, x: float, y: float, terrain: Terrain) -> None: super().__init__(x, y) diff --git a/dcs/task.py b/dcs/task.py index 6dc6c7df..87eefc82 100644 --- a/dcs/task.py +++ b/dcs/task.py @@ -9,7 +9,7 @@ """ from typing import List, Dict, Optional, Type, Any, Union from enum import Enum, IntEnum -from dcs.mapping import Vector2 +from dcs.mapping import Vector2, Vector3 from dcs.unit import Unit @@ -536,7 +536,7 @@ def __init__(self, "targetTypes": {i: targets[i - 1] for i in range(1, len(targets) + 1)}, "pos": position } - if group_id: + if group_id is not None: self.params["groupId"] = group_id if lastwpt: self.params["lastWptIndexFlagChangedManually"] = True @@ -1048,6 +1048,51 @@ def __init__(self, from_index=None, to_index=None): self.params["nWaypointIndx"] = to_index +class WWIIFollowBigFormation(Task): + Id = "FollowBigFormation" + + class FormationType(IntEnum): + COMBAT_BOX_FOR_OPEN_FORMATION = 18 + JAVELIN_DOWN = 16 + COMBAT_BOX = 15 + + def __init__(self, + group_id: Optional[int] = None, + position: Vector3 = Vector3(0, 0, 0), + last_wpt_index_flag: bool = False, + last_wpt_index_flag_changed_manually: bool = False, + formation_type: FormationType = FormationType.COMBAT_BOX_FOR_OPEN_FORMATION, + pos_in_box: int = 0, + pos_in_group: int = 0, + pos_in_wing: int = 0, + last_wpt_index: Optional[int] = None) -> None: + super().__init__(self.Id) + + self.params = { + "pos": { + "x": position.x, + "y": position.y, + "z": position.z + }, + "lastWptIndexFlag": last_wpt_index_flag, + "lastWptIndexFlagChangedManually": last_wpt_index_flag_changed_manually, + "lastWptIndex": last_wpt_index, + "formationType": formation_type, + "posInBox": pos_in_box, + "posInGroup": pos_in_group, + "posInWing": pos_in_wing + } + if group_id is not None: + self.params["groupId"] = group_id + if last_wpt_index: + self.params["lastWptIndex"] = last_wpt_index + + def __eq__(self, other) -> bool: + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + tasks_map: Dict[str, Type[Task]] = { ControlledTask.Id: ControlledTask, EscortTaskAction.Id: EscortTaskAction, @@ -1079,7 +1124,8 @@ def __init__(self, from_index=None, to_index=None): FireAtPoint.Id: FireAtPoint, AttackUnit.Id: AttackUnit, AttackMapObject.Id: AttackMapObject, - EngageTargets.Id: EngageTargets + EngageTargets.Id: EngageTargets, + WWIIFollowBigFormation.Id: WWIIFollowBigFormation, } diff --git a/tests/missions/big-formation.miz b/tests/missions/big-formation.miz new file mode 100755 index 0000000000000000000000000000000000000000..de44e2ee39437fbfd4dfff21be7b61cfa59b026f GIT binary patch literal 29506 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 literal 0 HcmV?d00001 diff --git a/tests/test_mission.py b/tests/test_mission.py index 4c49ea3c..7c4cd0b6 100644 --- a/tests/test_mission.py +++ b/tests/test_mission.py @@ -11,6 +11,7 @@ from dcs.status_message import MessageSeverity, MessageType from dcs.flyingunit import FlyingUnit from dcs.unit import Ship +from dcs.task import WWIIFollowBigFormation class BasicTests(unittest.TestCase): @@ -884,3 +885,119 @@ def test_smoke_required_modules(self) -> None: m2 = dcs.mission.Mission() m2.load_file(saved_miz) self.assertEqual(m.required_modules, m2.required_modules) + + def test_big_formation_action_leader(self) -> None: + m_name = "tests/missions/big-formation.miz" + m = dcs.mission.Mission() + m.load_file(m_name) + + assert isinstance(m.coalition['blue'].country("Combined Joint Task Forces Blue") + .plane_group[0].points[0].tasks[5], WWIIFollowBigFormation) + + task = m.coalition['blue'].country("Combined Joint Task Forces Blue").plane_group[0].points[0].tasks[5] + + self.assertNotIn("groupId", task.params) + self.assertNotIn("lastWptIndex", task.params) + self.assertEqual(task.params["formationType"], WWIIFollowBigFormation.FormationType.COMBAT_BOX_FOR_OPEN_FORMATION) + self.assertEqual(task.params["pos"], {"x": 0, "y": 0, "z": 0}) + self.assertTrue(task.params["lastWptIndexFlagChangedManually"]) + self.assertEqual(len(task.params), 7) + + m2_name = "missions/saved_big-formation.miz" + m.save(m2_name) + + m2 = dcs.mission.Mission() + m2.load_file(m2_name) + + assert isinstance(m2.coalition['blue'].country("Combined Joint Task Forces Blue") + .plane_group[0].points[0].tasks[5], WWIIFollowBigFormation) + m2_task = m.coalition['blue'].country("Combined Joint Task Forces Blue").plane_group[0].points[0].tasks[5] + + self.assertEqual(task, m2_task) + + def test_big_formation_action_left(self) -> None: + m_name = "tests/missions/big-formation.miz" + m = dcs.mission.Mission() + m.load_file(m_name) + + assert isinstance(m.coalition['blue'].country("Combined Joint Task Forces Blue") + .plane_group[1].points[0].tasks[5], WWIIFollowBigFormation) + task = m.coalition['blue'].country("Combined Joint Task Forces Blue").plane_group[1].points[0].tasks[5] + + self.assertEqual(task.params["formationType"], WWIIFollowBigFormation.FormationType.JAVELIN_DOWN) + self.assertEqual(task.params["pos"], {"x": -480, "y": -70, "z": -240}) + self.assertEqual(task.params["groupId"], 2) + self.assertEqual(task.params["posInGroup"], 2) + self.assertEqual(task.params["lastWptIndex"], 3) + self.assertTrue(task.params["lastWptIndexFlag"]) + self.assertEqual(len(task.params), 9) + + m2_name = "missions/saved_big-formation.miz" + m.save(m2_name) + + m2 = dcs.mission.Mission() + m2.load_file(m2_name) + + assert isinstance(m2.coalition['blue'].country("Combined Joint Task Forces Blue") + .plane_group[1].points[0].tasks[5], WWIIFollowBigFormation) + m2_task = m.coalition['blue'].country("Combined Joint Task Forces Blue").plane_group[1].points[0].tasks[5] + + self.assertEqual(task, m2_task) + + def test_big_formation_action_back(self) -> None: + m_name = "tests/missions/big-formation.miz" + m = dcs.mission.Mission() + m.load_file(m_name) + + assert isinstance(m.coalition['blue'].country("Combined Joint Task Forces Blue") + .plane_group[2].points[0].tasks[5], WWIIFollowBigFormation) + task = m.coalition['blue'].country("Combined Joint Task Forces Blue").plane_group[2].points[0].tasks[5] + + self.assertEqual(task.params["formationType"], WWIIFollowBigFormation.FormationType.COMBAT_BOX) + self.assertEqual(task.params["pos"], {"x": -320, "y": -50, "z": -0}) + self.assertEqual(task.params["groupId"], 2) + self.assertEqual(task.params["posInBox"], 3) + self.assertEqual(task.params["lastWptIndex"], 3) + self.assertFalse(task.params["lastWptIndexFlag"]) + self.assertEqual(len(task.params), 9) + + m2_name = "missions/saved_big-formation.miz" + m.save(m2_name) + + m2 = dcs.mission.Mission() + m2.load_file(m2_name) + + assert isinstance(m2.coalition['blue'].country("Combined Joint Task Forces Blue") + .plane_group[2].points[0].tasks[5], WWIIFollowBigFormation) + m2_task = m.coalition['blue'].country("Combined Joint Task Forces Blue").plane_group[2].points[0].tasks[5] + + self.assertEqual(task, m2_task) + + def test_big_formation_action_right(self) -> None: + m_name = "tests/missions/big-formation.miz" + m = dcs.mission.Mission() + m.load_file(m_name) + + assert isinstance(m.coalition['blue'].country("Combined Joint Task Forces Blue") + .plane_group[3].points[0].tasks[5], WWIIFollowBigFormation) + task = m.coalition['blue'].country("Combined Joint Task Forces Blue").plane_group[3].points[0].tasks[5] + + self.assertEqual(task.params["formationType"], WWIIFollowBigFormation.FormationType.COMBAT_BOX_FOR_OPEN_FORMATION) + self.assertEqual(task.params["pos"], {"x": -160, "y": 50, "z": 240}) + self.assertEqual(task.params["groupId"], 2) + self.assertEqual(task.params["posInBox"], 1) + self.assertEqual(task.params["lastWptIndex"], 3) + self.assertTrue(task.params["lastWptIndexFlag"]) + self.assertEqual(len(task.params), 9) + + m2_name = "missions/saved_big-formation.miz" + m.save(m2_name) + + m2 = dcs.mission.Mission() + m2.load_file(m2_name) + + assert isinstance(m2.coalition['blue'].country("Combined Joint Task Forces Blue") + .plane_group[3].points[0].tasks[5], WWIIFollowBigFormation) + m2_task = m.coalition['blue'].country("Combined Joint Task Forces Blue").plane_group[3].points[0].tasks[5] + + self.assertEqual(task, m2_task)