Let map objects be Strike targets.

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:
![CampaignCreation](https://user-images.githubusercontent.com/74509817/117526797-c294af00-af84-11eb-9fb7-3940db64c5d8.png)

How the objective looks once in the mission planner/editor.  This objective belongs to the enemy faction:
![MissionPlanner](https://user-images.githubusercontent.com/74509817/117526819-ece66c80-af84-11eb-9db0-64000dedcf89.png)
This commit is contained in:
SnappyComebacks
2021-05-14 18:18:03 -06:00
committed by GitHub
parent 9a9872812f
commit bb1a066ff7
11 changed files with 265 additions and 5 deletions

View File

@@ -12,6 +12,7 @@ import random
from typing import Dict, Iterator, Optional, TYPE_CHECKING, Type, List
from dcs import Mission, Point, unitgroup
from dcs.action import SceneryDestructionZone
from dcs.country import Country
from dcs.point import StaticPoint
from dcs.statics import Fortification, fortification_map, warehouse_map, Warehouse
@@ -22,6 +23,7 @@ from dcs.task import (
OptAlarmState,
FireAtPoint,
)
from dcs.triggers import TriggerStart, TriggerZone
from dcs.unit import Ship, Unit, Vehicle, SingleHeliPad, Static
from dcs.unitgroup import Group, ShipGroup, StaticGroup, VehicleGroup
from dcs.unittype import StaticType, UnitType
@@ -39,9 +41,10 @@ from game.theater.theatergroundobject import (
LhaGroundObject,
ShipGroundObject,
MissileSiteGroundObject,
SceneryGroundObject,
)
from game.unitmap import UnitMap
from game.utils import knots, mps
from game.utils import feet, knots, mps
from .radios import RadioFrequency, RadioRegistry
from .runways import RunwayData
from .tacan import TacanBand, TacanChannel, TacanRegistry
@@ -259,6 +262,58 @@ class FactoryGenerator(BuildingSiteGenerator):
self.generate_static(Fortification.Workshop_A)
class SceneryGenerator(BuildingSiteGenerator):
def generate(self) -> None:
assert isinstance(self.ground_object, SceneryGroundObject)
trigger_zone = self.generate_trigger_zone(self.ground_object)
# DCS only visually shows a scenery object is dead when
# this trigger rule is applied. Otherwise you can kill a
# structure twice.
if self.ground_object.is_dead:
self.generate_dead_trigger_rule(trigger_zone)
# Tell Liberation to manage this groundobjectsgen as part of the campaign.
self.register_scenery()
def generate_trigger_zone(self, scenery: SceneryGroundObject) -> TriggerZone:
zone = scenery.zone
# Align the trigger zones to the faction color on the DCS briefing/F10 map.
if scenery.is_friendly(to_player=True):
color = {1: 0.2, 2: 0.7, 3: 1, 4: 0.15}
else:
color = {1: 1, 2: 0.2, 3: 0.2, 4: 0.15}
# Create the smallest valid size trigger zone (16 feet) so that risk of overlap is minimized.
# As long as the triggerzone is over the scenery object, we're ok.
smallest_valid_radius = feet(16).meters
return self.m.triggers.add_triggerzone(
zone.position,
smallest_valid_radius,
zone.hidden,
zone.name,
color,
zone.properties,
)
def generate_dead_trigger_rule(self, trigger_zone: TriggerZone) -> None:
# Add destruction zone trigger
t = TriggerStart(comment="Destruction")
t.actions.append(
SceneryDestructionZone(destruction_level=100, zone=trigger_zone.id)
)
self.m.triggerrules.triggers.append(t)
def register_scenery(self) -> None:
scenery = self.ground_object
assert isinstance(scenery, SceneryGroundObject)
self.unit_map.add_scenery(scenery)
class GenericCarrierGenerator(GenericGroundObjectGenerator):
"""Base type for carrier group generation.
@@ -576,6 +631,10 @@ class GroundObjectsGenerator:
generator = FactoryGenerator(
ground_object, country, self.game, self.m, self.unit_map
)
elif isinstance(ground_object, SceneryGroundObject):
generator = SceneryGenerator(
ground_object, country, self.game, self.m, self.unit_map
)
elif isinstance(ground_object, BuildingGroundObject):
generator = BuildingSiteGenerator(
ground_object, country, self.game, self.m, self.unit_map