mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
This PR allows campaign creators to incorporate map objects (referred to as Scenery in the code) into their Liberation campaign. Map objects are defined using white trigger zones created by right clicking on scenery and clicking `assign as...`. Objective groups are defined by creating a blue TriggerZone surrounding the centers of the white trigger zones. The type of objective is determined by the campaign creator, assigning the value of the first property of the blue TriggerZone with the objective type. Map objects maintain their visually dead state by assigning a `Mission Start` `Scenery Object Dead` trigger to the trigger zone. It is important for the Liberation generated TriggerZone to be as small as possible so that no other scenery is marked dead by DCS. TriggerZones are hidden during gameplay (DCS behavior. I don't know if it's possible to turn that off.) TriggerZones are visible in the mission editor and mission planner however. If a player is using an older plane, it is important for them to remember where the target is. In the mission planner, the trigger zones' will be blue or red depending on which faction the map objects belong to. Inherent Resolve campaign has been modified to integrate scenery objects. ### **Limitations:** - Objective definitions (Any Blue TriggerZones) in campaign definition cannot overlap. - Map object deaths in `state.json` is tracking integers. You won't know what died until debriefing. - No images for the various buildings. In theory it can be done, but an unreasonable amount of work. - Every blue trigger zone must have a unique name. (If you let DCS auto increment the names this is not a concern. - No output to screen when scenery object is dead. You can see the building drawn as dead in the F10 map though. ### **Pictures:** An objective:  How the objective looks once in the mission planner/editor. This objective belongs to the enemy faction: 
90 lines
3.2 KiB
Python
90 lines
3.2 KiB
Python
from __future__ import annotations
|
|
from game.theater.theatergroundobject import NAME_BY_CATEGORY
|
|
from dcs.triggers import TriggerZone
|
|
|
|
from typing import Iterable, List
|
|
|
|
|
|
class SceneryGroupError(RuntimeError):
|
|
"""Error for when there are insufficient conditions to create a SceneryGroup."""
|
|
|
|
pass
|
|
|
|
|
|
class SceneryGroup:
|
|
"""Store information about a scenery objective."""
|
|
|
|
def __init__(
|
|
self, zone_def: TriggerZone, zones: Iterable[TriggerZone], category: str
|
|
) -> None:
|
|
|
|
self.zone_def = zone_def
|
|
self.zones = zones
|
|
self.position = zone_def.position
|
|
self.category = category
|
|
|
|
@staticmethod
|
|
def from_trigger_zones(trigger_zones: Iterable[TriggerZone]) -> List[SceneryGroup]:
|
|
"""Define scenery objectives based on their encompassing blue/red circle."""
|
|
zone_definitions = []
|
|
white_zones = []
|
|
|
|
scenery_groups = []
|
|
|
|
# Aggregate trigger zones into different groups based on color.
|
|
for zone in trigger_zones:
|
|
if SceneryGroup.is_blue(zone):
|
|
zone_definitions.append(zone)
|
|
if SceneryGroup.is_white(zone):
|
|
white_zones.append(zone)
|
|
|
|
# For each objective definition.
|
|
for zone_def in zone_definitions:
|
|
|
|
zone_def_radius = zone_def.radius
|
|
zone_def_position = zone_def.position
|
|
zone_def_name = zone_def.name
|
|
|
|
if len(zone_def.properties) == 0:
|
|
raise SceneryGroupError(
|
|
"Undefined SceneryGroup category in TriggerZone: " + zone_def_name
|
|
)
|
|
|
|
# Arbitrary campaign design requirement: First property must define the category.
|
|
zone_def_category = zone_def.properties[1].get("value").lower()
|
|
|
|
valid_white_zones = []
|
|
|
|
for zone in list(white_zones):
|
|
if zone.position.distance_to_point(zone_def_position) < zone_def_radius:
|
|
valid_white_zones.append(zone)
|
|
white_zones.remove(zone)
|
|
|
|
if len(valid_white_zones) > 0 and zone_def_category in NAME_BY_CATEGORY:
|
|
scenery_groups.append(
|
|
SceneryGroup(zone_def, valid_white_zones, zone_def_category)
|
|
)
|
|
elif len(valid_white_zones) == 0:
|
|
raise SceneryGroupError(
|
|
"No white triggerzones found in: " + zone_def_name
|
|
)
|
|
elif zone_def_category not in NAME_BY_CATEGORY:
|
|
raise SceneryGroupError(
|
|
"Incorrect TriggerZone category definition for: "
|
|
+ zone_def_name
|
|
+ " in campaign definition. TriggerZone category: "
|
|
+ zone_def_category
|
|
)
|
|
|
|
return scenery_groups
|
|
|
|
@staticmethod
|
|
def is_blue(zone: TriggerZone) -> bool:
|
|
# Blue in RGB is [0 Red], [0 Green], [1 Blue]. Ignore the fourth position: Transparency.
|
|
return zone.color[1] == 0 and zone.color[2] == 0 and zone.color[3] == 1
|
|
|
|
@staticmethod
|
|
def is_white(zone: TriggerZone) -> bool:
|
|
# White in RGB is [1 Red], [1 Green], [1 Blue]. Ignore the fourth position: Transparency.
|
|
return zone.color[1] == 1 and zone.color[2] == 1 and zone.color[3] == 1
|