diff --git a/game/armedforces/forcegroup.py b/game/armedforces/forcegroup.py index 0bafacfe..731dfbe1 100644 --- a/game/armedforces/forcegroup.py +++ b/game/armedforces/forcegroup.py @@ -15,7 +15,12 @@ from game.dcs.helpers import static_type_from_name from game.dcs.shipunittype import ShipUnitType from game.dcs.unittype import UnitType from game.layout import LAYOUTS -from game.layout.layout import TgoLayout, TgoLayoutUnitGroup +from game.layout.layout import ( + TgoLayout, + TgoLayoutUnitGroup, + FIXED_POS_ARG, + FIXED_HDG_ARG, +) from game.point_with_heading import PointWithHeading from game.theater.theatergroundobject import ( IadsGroundObject, @@ -249,7 +254,11 @@ class ForceGroup: # No units to be created so dont create a theater group for them return # Generate Units - units = unit_group.generate_units(ground_object, unit_type, unit_count) + fixed_pos = FIXED_POS_ARG in unit_group.name + fixed_hdg = FIXED_HDG_ARG in unit_group.name + units = unit_group.generate_units( + ground_object, unit_type, unit_count, fixed_pos, fixed_hdg + ) # Get or create the TheaterGroup ground_group = ground_object.group_by_name(group_name) if ground_group is not None: @@ -304,7 +313,7 @@ class ForceGroup: # Reverse the heading of the unit unit.position.heading = unit.position.heading.opposite # Rotate unit around the center to align the orientation of the group - unit.position.rotate(ground_object.position, rotation) + unit.rotate_position_clockwise(ground_object.position, rotation) @classmethod def _load_all(cls) -> None: diff --git a/game/layout/layout.py b/game/layout/layout.py index e5906ee4..9f674a97 100644 --- a/game/layout/layout.py +++ b/game/layout/layout.py @@ -33,6 +33,10 @@ if TYPE_CHECKING: from game.theater.controlpoint import ControlPoint +FIXED_POS_ARG = "--fix-pos" +FIXED_HDG_ARG = "--fix-hdg" + + class LayoutException(Exception): pass @@ -152,7 +156,12 @@ class TgoLayoutUnitGroup: return len(self.layout_units) def generate_units( - self, go: TheaterGroundObject, unit_type: Type[DcsUnitType], amount: int + self, + go: TheaterGroundObject, + unit_type: Type[DcsUnitType], + amount: int, + fixed_pos: bool, + fixed_hdg: bool, ) -> list[TheaterUnit]: """Generate units of the given unit type and amount for the TgoLayoutGroup""" if amount > len(self.layout_units): @@ -160,7 +169,14 @@ class TgoLayoutUnitGroup: f"{self.name} has incorrect unit_count for {unit_type.id}" ) return [ - TheaterUnit.from_template(i, unit_type, self.layout_units[i], go) + TheaterUnit.from_template( + i, + unit_type, + self.layout_units[i], + go, + fixed_pos, + fixed_hdg, + ) for i in range(amount) ] diff --git a/game/theater/theatergroundobject.py b/game/theater/theatergroundobject.py index b56cd207..d4663cca 100644 --- a/game/theater/theatergroundobject.py +++ b/game/theater/theatergroundobject.py @@ -267,8 +267,8 @@ class TheaterGroundObject(MissionTarget, SidcDescribable, ABC): self.heading = heading # Rotate the whole TGO to match the new heading for unit in self.units: - unit.position.heading += rotation - unit.position.rotate(self.position, rotation) + unit.rotate_heading_clockwise(rotation) + unit.rotate_position_clockwise(self.position, rotation) @property def should_head_to_conflict(self) -> bool: diff --git a/game/theater/theatergroup.py b/game/theater/theatergroup.py index 206112d3..07ea7169 100644 --- a/game/theater/theatergroup.py +++ b/game/theater/theatergroup.py @@ -3,6 +3,7 @@ from __future__ import annotations from dataclasses import dataclass from typing import Any, Optional, TYPE_CHECKING, Type +from dcs import Point from dcs.triggers import TriggerZone from dcs.unittype import ShipType, StaticType, UnitType as DcsUnitType, VehicleType @@ -16,7 +17,7 @@ from game.theater.iadsnetwork.iadsrole import IadsRole from game.utils import Heading, Distance, meters if TYPE_CHECKING: - from game.layout.layout import LayoutUnit + from game.layout.layout import LayoutUnit, FIXED_POS_ARG, FIXED_HDG_ARG from game.sim import GameUpdateEvents from game.theater.theatergroundobject import TheaterGroundObject @@ -35,12 +36,21 @@ class TheaterUnit: position: PointWithHeading # The parent ground object ground_object: TheaterGroundObject + # Should the unit's position remain fixed? + fixed_pos: bool = False + # Should the unit's heading remain fixed? + fixed_hdg: bool = False # State of the unit, dead or alive alive: bool = True @staticmethod def from_template( - id: int, dcs_type: Type[DcsUnitType], t: LayoutUnit, go: TheaterGroundObject + id: int, + dcs_type: Type[DcsUnitType], + t: LayoutUnit, + go: TheaterGroundObject, + fixed_pos: bool, + fixed_hdg: bool, ) -> TheaterUnit: return TheaterUnit( id, @@ -48,6 +58,8 @@ class TheaterUnit: dcs_type, PointWithHeading.from_point(t.position, Heading.from_degrees(t.heading)), go, + fixed_pos or FIXED_POS_ARG in t.name, + fixed_hdg or FIXED_HDG_ARG in t.name, ) @property @@ -132,6 +144,16 @@ class TheaterUnit: unit_range = getattr(self.type, "threat_range", None) return meters(unit_range if unit_range is not None and self.alive else 0) + def rotate_heading_clockwise(self, rotation: Heading) -> None: + if self.fixed_hdg: + return + self.position.heading += rotation + + def rotate_position_clockwise(self, position: Point, rotation: Heading) -> None: + if self.fixed_pos: + return + self.position.rotate(position, rotation) + class SceneryUnit(TheaterUnit): """Special TheaterUnit for handling scenery ground objects"""