Skip to content

Commit

Permalink
Added support for a_out_picture action (pydcs#351)
Browse files Browse the repository at this point in the history
supports sending picture to all, coalition, country, group and unit.
DCS UI issue allows picture to be sent to unit without picture
resource, so a dedicated test covers that.
  • Loading branch information
332fg-raven authored and Raffson committed Feb 18, 2024
1 parent 24a90b7 commit 1454bdc
Show file tree
Hide file tree
Showing 7 changed files with 496 additions and 9 deletions.
211 changes: 209 additions & 2 deletions dcs/action.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
from typing import Any, Dict, List, Type, Optional
from __future__ import annotations

from typing import Any, Dict, List, Type, Optional, TYPE_CHECKING
from dcs.lua.serialize import dumps
from dcs.translation import String, ResourceKey
from enum import Enum, IntEnum
import dcs.countries as countries

if TYPE_CHECKING:
from .mission import Mission
from .country import Country
from .unitgroup import Group


class Action:
Expand Down Expand Up @@ -1787,6 +1795,200 @@ def dict(self):
return d


class PictureAction(Action):

class HorzAlignment(Enum):
Left = "0"
Center = "1"
Right = "2"

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

class VertAlignment(Enum):
Top = "0"
Center = "1"
Bottom = "2"

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

class SizeUnits(Enum):
OriginalSize = "0"
WindowSize = "1"

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

def __init__(self, predicate: str, file_res_key: ResourceKey, seconds: int,
clearview: bool, start_delay: int,
horz_alignment: HorzAlignment, vert_alignment: VertAlignment,
size: int, size_units: SizeUnits) -> None:
super().__init__(predicate)
self.file_res_key = file_res_key
self.seconds = seconds
self.clearview = clearview
self.start_delay = start_delay
self.horz_alignment = horz_alignment
self.vert_alignment = vert_alignment
self.size_units = size_units
self.size = size
if size not in range(1, 101):
raise ValueError

def dict(self) -> Dict[str, Any]:
d = super().dict()
d["file"] = self.file_res_key.key
d["seconds"] = self.seconds
d["clearview"] = self.clearview
d["start_delay"] = self.start_delay
d["horzAlignment"] = self.horz_alignment
d["vertAlignment"] = self.vert_alignment
d["size_units"] = self.size_units
d["size"] = self.size
return d

def __eq__(self, other: Any) -> bool:
if isinstance(other, self.__class__):
return self.__dict__ == other.__dict__
return False


class PictureToAll(PictureAction):
predicate = "a_out_picture"

def __init__(self, file_res_key: ResourceKey, seconds: int,
clearview: bool, start_delay: int,
horz_alignment: PictureAction.HorzAlignment, vert_alignment: PictureAction.VertAlignment,
size: int, size_units: PictureAction.SizeUnits) -> None:
super().__init__(predicate=self.predicate, file_res_key=file_res_key,
seconds=seconds, clearview=clearview,
start_delay=start_delay, horz_alignment=horz_alignment,
vert_alignment=vert_alignment, size=size, size_units=size_units)
self.params = [self.file_res_key, seconds, clearview, start_delay,
horz_alignment, vert_alignment, size, size_units]

@classmethod
def create_from_dict(cls, d: Dict[str, Any], mission: Mission) -> PictureToAll:
return cls(ResourceKey(d["file"]), d["seconds"], d["clearview"], d["start_delay"],
d["horzAlignment"], d["vertAlignment"], d["size"], d["size_units"])


class PictureToCoalition(PictureAction):
predicate = "a_out_picture_s"

def __init__(self, coalition: Coalition, file_res_key: ResourceKey, seconds: int,
clearview: bool, start_delay: int,
horz_alignment: PictureAction.HorzAlignment, vert_alignment: PictureAction.VertAlignment,
size: int, size_units: PictureAction.SizeUnits) -> None:
super().__init__(predicate=self.predicate, file_res_key=file_res_key,
seconds=seconds, clearview=clearview,
start_delay=start_delay, horz_alignment=horz_alignment,
vert_alignment=vert_alignment, size=size, size_units=size_units)
self.coalition = coalition
self.params = [self.coalition, self.file_res_key, seconds, clearview,
start_delay, horz_alignment, vert_alignment, size, size_units]

@classmethod
def create_from_dict(cls, d: Dict[str, Any], mission: Mission) -> PictureToCoalition:
return cls(d["coalitionlist"], ResourceKey(d["file"]), d["seconds"], d["clearview"], d["start_delay"],
d["horzAlignment"], d["vertAlignment"], d["size"], d["size_units"])

def dict(self) -> Dict[str, Any]:
d = super().dict()
d["coalitionlist"] = self.coalition
return d


class PictureToCountry(PictureAction):
predicate = "a_out_picture_c"

def __init__(self, country: Country, file_res_key: ResourceKey, seconds: int,
clearview: bool, start_delay: int,
horz_alignment: PictureAction.HorzAlignment, vert_alignment: PictureAction.VertAlignment,
size: int, size_units: PictureAction.SizeUnits) -> None:
super().__init__(predicate=self.predicate, file_res_key=file_res_key,
seconds=seconds, clearview=clearview,
start_delay=start_delay, horz_alignment=horz_alignment,
vert_alignment=vert_alignment, size=size, size_units=size_units)
self.country = country
self.params = [self.country.id, self.file_res_key, seconds, clearview,
start_delay, horz_alignment, vert_alignment, size, size_units]

@classmethod
def create_from_dict(cls, d: Dict[str, Any], mission: Mission) -> PictureToCountry:
return cls(countries.get_by_id(d["countrylist"]), ResourceKey(d["file"]),
d["seconds"], d["clearview"], d["start_delay"],
d["horzAlignment"], d["vertAlignment"], d["size"], d["size_units"])

def dict(self) -> Dict[str, Any]:
d = super().dict()
d["countrylist"] = self.country.id
return d


class PictureToGroup(PictureAction):
predicate = "a_out_picture_g"

def __init__(self, group: Group, file_res_key: ResourceKey, seconds: int,
clearview: bool, start_delay: int,
horz_alignment: PictureAction.HorzAlignment, vert_alignment: PictureAction.VertAlignment,
size: int, size_units: PictureAction.SizeUnits) -> None:
super().__init__(predicate=self.predicate, file_res_key=file_res_key,
seconds=seconds, clearview=clearview,
start_delay=start_delay, horz_alignment=horz_alignment,
vert_alignment=vert_alignment, size=size, size_units=size_units)
self.group = group
self.params = [self.group.id, self.file_res_key, seconds, clearview,
start_delay, horz_alignment, vert_alignment, size, size_units]

@classmethod
def create_from_dict(cls, d: Dict[str, Any], mission: Mission) -> PictureToGroup:
group = mission.find_group_by_id(d["group"])
if group is None:
raise RuntimeError("Group id {} found in PictureToGroup action, "
"but it does not exist in the mission.".format(d["group"]))
return cls(group, ResourceKey(d["file"]), d["seconds"], d["clearview"], d["start_delay"],
d["horzAlignment"], d["vertAlignment"], d["size"], d["size_units"])

def dict(self) -> Dict[str, Any]:
d = super().dict()
d["group"] = self.group.id
return d


class PictureToUnit(PictureAction):
predicate = "a_out_picture_u"

def __init__(self, unit_id: int, file_res_key: ResourceKey, seconds: int,
clearview: bool, start_delay: int,
horz_alignment: PictureAction.HorzAlignment, vert_alignment: PictureAction.VertAlignment,
size: int, size_units: PictureAction.SizeUnits) -> None:
super().__init__(predicate=self.predicate, file_res_key=file_res_key,
seconds=seconds, clearview=clearview,
start_delay=start_delay, horz_alignment=horz_alignment,
vert_alignment=vert_alignment, size=size, size_units=size_units)
self.unit_id = unit_id
self.params = [self.unit_id, self.file_res_key, seconds, clearview,
start_delay, horz_alignment, vert_alignment, size, size_units]

@classmethod
def create_from_dict(cls, d: Dict[str, Any], mission: Mission) -> PictureToUnit:
return cls(d["unit"], ResourceKey(d["file"]), d["seconds"], d["clearview"], d["start_delay"],
d["horzAlignment"], d["vertAlignment"], d["size"], d["size_units"])

def dict(self) -> Dict[str, Any]:
d = super().dict()
d["unit"] = self.unit_id
return d


actions_map: Dict[str, Type[Action]] = {
"a_activate_group": ActivateGroup,
"a_add_radio_item": AddRadioItem,
Expand Down Expand Up @@ -1865,5 +2067,10 @@ def dict(self):
"a_set_ai_task": AITaskSet,
"a_remove_scene_objects": RemoveSceneObjects,
"a_scenery_destruction_zone": SceneryDestructionZone,
"a_zone_increment_resize": ZoneIncrementResize
"a_zone_increment_resize": ZoneIncrementResize,
"a_out_picture": PictureToAll,
"a_out_picture_s": PictureToCoalition,
"a_out_picture_c": PictureToCountry,
"a_out_picture_g": PictureToGroup,
"a_out_picture_u": PictureToUnit,
}
11 changes: 10 additions & 1 deletion dcs/coalition.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import sys
from typing import Dict, Union, List, TYPE_CHECKING
from typing import Dict, Union, List, TYPE_CHECKING, Optional
import dcs.countries as countries
from dcs.mapping import Point
import dcs.unitgroup as unitgroup
Expand All @@ -11,6 +11,7 @@
from dcs.point import MovingPoint, StaticPoint
from dcs.country import Country
from dcs.status_message import StatusMessage, MessageType, MessageSeverity
from dcs.unitgroup import Group

if TYPE_CHECKING:
from . import Mission
Expand Down Expand Up @@ -298,6 +299,14 @@ def find_group(self, group_name, search="exact"):

return None

def find_group_by_id(self, group_id: int) -> Optional[Group]:
for c in self.countries:
g = self.countries[c].find_group_by_id(group_id)
if g is not None:
return g

return None

def dict(self):
d = {"name": self.name}
if self.bullseye:
Expand Down
14 changes: 14 additions & 0 deletions dcs/country.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from dcs.helicopters import HelicopterType
from dcs.planes import PlaneType
from dcs.unitgroup import VehicleGroup, ShipGroup, PlaneGroup, StaticGroup, HelicopterGroup, FlyingGroup, Group
from typing import List, Dict, Optional, Set, Type, Sequence


def find_exact(group_name, find_name):
Expand Down Expand Up @@ -83,6 +84,19 @@ def find_group(self, group_name, search="exact"):
return group
return None

def find_group_by_id(self, group_id: int) -> Optional[Group]:
groups: List[Sequence[Group]] = [self.vehicle_group,
self.ship_group,
self.plane_group,
self.helicopter_group,
self.static_group]
for search_group in groups:
for group in search_group:
if group.id == group_id:
return group

return None

def find_vehicle_group(self, name: str, search="exact"):
for group in self.vehicle_group:
if find_map[search](group.name, name):
Expand Down
28 changes: 22 additions & 6 deletions dcs/mission.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
from dcs.helicopters import HelicopterType
from dcs.planes import PlaneType
from dcs.status_message import StatusMessage, MessageType, MessageSeverity
from dcs.unitgroup import Group


class StartType(Enum):
Expand Down Expand Up @@ -348,6 +349,12 @@ def loaddict(fname: str, mizfile: zipfile.ZipFile, reserved_files: List[str]) ->
self.init_script_file = imp_mission.get("initScriptFile")
self.init_script = imp_mission.get("initScript")

# import coalition with countries and units
for col_name in ["blue", "red", "neutrals"]:
if col_name in imp_mission["coalition"]:
self.coalition[col_name] = Coalition(col_name, imp_mission["coalition"][col_name]["bullseye"])
status += self.coalition[col_name].load_from_dict(self, imp_mission["coalition"][col_name])

# triggers
self.bypassed_triggers = None
self.bypassed_trigrules = None
Expand Down Expand Up @@ -378,12 +385,6 @@ def loaddict(fname: str, mizfile: zipfile.ZipFile, reserved_files: List[str]) ->
self.weather = weather.Weather(self.terrain)
self.weather.load_from_dict(imp_weather)

# import coalition with countries and units
for col_name in ["blue", "red", "neutrals"]:
if col_name in imp_mission["coalition"]:
self.coalition[col_name] = Coalition(col_name, imp_mission["coalition"][col_name]["bullseye"])
status += self.coalition[col_name].load_from_dict(self, imp_mission["coalition"][col_name])

return status

def sortie_text(self) -> str:
Expand Down Expand Up @@ -1883,6 +1884,21 @@ def find_group(self, group_name, search="exact") -> Optional[unitgroup.Group]:
return g
return None

def find_group_by_id(self, group_id: int) -> Optional[Group]:
"""Searches a group with the given groupId
Args:
group_id: group identifier assigned by the mission file
Returns:
Group: the group found, otherwise None
"""
for k in self.coalition:
g = self.coalition[k].find_group_by_id(group_id)
if g is not None:
return g
return None

def is_red(self, country: Country) -> bool:
"""Checks if the given country object is part o the red coalition.
Expand Down
5 changes: 5 additions & 0 deletions dcs/translation.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ def key(self) -> str:
def __str__(self):
return self.res_key

def __eq__(self, other):
if isinstance(other, ResourceKey):
return self.__dict__ == other.__dict__
return False


class Translation:
def __init__(self, _mission):
Expand Down
Binary file added tests/missions/a_out_picture.miz
Binary file not shown.
Loading

0 comments on commit 1454bdc

Please sign in to comment.