Rework killed map_objects recognition

- removed the map_object_id from the TGO
- add a new TriggerRule with the MapObjectIsDead Condition which adds the map object to the killed_map_objects array in the state.json
- Use the trigger_zone_name as the unique identifier used for the unit_map to recognize the kill
This commit is contained in:
RndName 2021-12-31 17:10:23 +01:00
parent ffd8152b36
commit e070d5bf0d
No known key found for this signature in database
GPG Key ID: 5EF516FD9537F7C0
6 changed files with 40 additions and 18 deletions

View File

@ -12,6 +12,7 @@ Saves from 5.0.0 are compatible with 5.1.0
## Fixes ## Fixes
* **[Campaign]** Fixed some minor issues in campaigns which generated error messages in the log. * **[Campaign]** Fixed some minor issues in campaigns which generated error messages in the log.
* **[Campaign]** Changed the way how map object / scenery kills where tracked. This fixes issues with kill recognition after map updates from ED which change the object ids and therefore prevent correct kill recognition.
* **[Mission Generation]** Fixed incorrect radio specification for the AN/ARC-222. * **[Mission Generation]** Fixed incorrect radio specification for the AN/ARC-222.
* **[Mission Generation]** Fixed mission scripting error when using a dedicated server. * **[Mission Generation]** Fixed mission scripting error when using a dedicated server.
* **[Mission Generation]** Fixed an issue where empty convoys lead to an index error when a point capture made a pending transfer of units not completable anymore. * **[Mission Generation]** Fixed an issue where empty convoys lead to an index error when a point capture made a pending transfer of units not completable anymore.

View File

@ -104,6 +104,9 @@ class StateData:
#: Names of vehicle (and ship) units that were killed during the mission. #: Names of vehicle (and ship) units that were killed during the mission.
killed_ground_units: List[str] killed_ground_units: List[str]
#: Names of map objects that were killed during the mission.
killed_map_objects: list[str]
#: List of descriptions of destroyed statics. Format of each element is a mapping of #: List of descriptions of destroyed statics. Format of each element is a mapping of
#: the coordinate type ("x", "y", "z", "type", "orientation") to the value. #: the coordinate type ("x", "y", "z", "type", "orientation") to the value.
destroyed_statics: List[dict[str, Union[float, str]]] destroyed_statics: List[dict[str, Union[float, str]]]
@ -122,6 +125,7 @@ class StateData:
# Also normalize dead map objects (which are ints) to strings. The unit map # Also normalize dead map objects (which are ints) to strings. The unit map
# only stores strings. # only stores strings.
killed_ground_units=list({str(u) for u in data["killed_ground_units"]}), killed_ground_units=list({str(u) for u in data["killed_ground_units"]}),
killed_map_objects=data["killed_map_objects"],
destroyed_statics=data["destroyed_objects_positions"], destroyed_statics=data["destroyed_objects_positions"],
base_capture_events=data["base_capture_events"], base_capture_events=data["base_capture_events"],
) )
@ -323,6 +327,16 @@ class Debriefing:
losses.enemy_airlifts.append(airlift_unit) losses.enemy_airlifts.append(airlift_unit)
continue continue
# Find killed map objects and mark them as loss
for map_object in self.state_data.killed_map_objects:
building = self.unit_map.building_or_fortification(map_object)
if building is not None:
if building.ground_object.control_point.captured:
losses.player_buildings.append(building)
else:
losses.enemy_buildings.append(building)
continue
return losses return losses
def base_capture_events(self) -> List[BaseCaptureEvent]: def base_capture_events(self) -> List[BaseCaptureEvent]:

View File

@ -316,16 +316,6 @@ class SceneryGroundObject(BuildingGroundObject):
is_fob_structure=False, is_fob_structure=False,
) )
self.zone = zone self.zone = zone
try:
# In the default TriggerZone using "assign as..." in the DCS Mission Editor,
# property three has the scenery's object ID as its value.
self.map_object_id = self.zone.properties[3]["value"]
except (IndexError, KeyError):
logging.exception(
"Invalid TriggerZone for Scenery definition. The third property must "
"be the map object ID."
)
raise
class FactoryGroundObject(BuildingGroundObject): class FactoryGroundObject(BuildingGroundObject):

View File

@ -217,7 +217,7 @@ class UnitMap:
self.buildings[name] = Building(ground_object) self.buildings[name] = Building(ground_object)
def add_scenery(self, ground_object: SceneryGroundObject) -> None: def add_scenery(self, ground_object: SceneryGroundObject) -> None:
name = str(ground_object.map_object_id) name = str(ground_object.zone.name)
if name in self.buildings: if name in self.buildings:
raise RuntimeError( raise RuntimeError(
f"Duplicate TGO unit: {name}. TriggerZone name: " f"Duplicate TGO unit: {name}. TriggerZone name: "

View File

@ -24,7 +24,8 @@ from typing import (
) )
from dcs import Mission, Point, unitgroup from dcs import Mission, Point, unitgroup
from dcs.action import SceneryDestructionZone from dcs.action import SceneryDestructionZone, DoScript
from dcs.condition import MapObjectIsDead
from dcs.country import Country from dcs.country import Country
from dcs.point import StaticPoint from dcs.point import StaticPoint
from dcs.statics import Fortification, fortification_map, warehouse_map from dcs.statics import Fortification, fortification_map, warehouse_map
@ -35,7 +36,8 @@ from dcs.task import (
OptAlarmState, OptAlarmState,
FireAtPoint, FireAtPoint,
) )
from dcs.triggers import TriggerStart, TriggerZone from dcs.translation import String
from dcs.triggers import TriggerStart, TriggerZone, Event, TriggerOnce
from dcs.unit import Ship, Unit, Vehicle, InvisibleFARP from dcs.unit import Ship, Unit, Vehicle, InvisibleFARP
from dcs.unitgroup import ShipGroup, StaticGroup, VehicleGroup from dcs.unitgroup import ShipGroup, StaticGroup, VehicleGroup
from dcs.unittype import StaticType, ShipType, VehicleType from dcs.unittype import StaticType, ShipType, VehicleType
@ -297,7 +299,9 @@ class SceneryGenerator(BuildingSiteGenerator):
# this trigger rule is applied. Otherwise you can kill a # this trigger rule is applied. Otherwise you can kill a
# structure twice. # structure twice.
if self.ground_object.is_dead: if self.ground_object.is_dead:
self.generate_dead_trigger_rule(trigger_zone) self.generate_destruction_trigger_rule(trigger_zone)
else:
self.generate_on_dead_trigger_rule(trigger_zone)
# Tell Liberation to manage this groundobjectsgen as part of the campaign. # Tell Liberation to manage this groundobjectsgen as part of the campaign.
self.register_scenery() self.register_scenery()
@ -325,7 +329,7 @@ class SceneryGenerator(BuildingSiteGenerator):
zone.properties, zone.properties,
) )
def generate_dead_trigger_rule(self, trigger_zone: TriggerZone) -> None: def generate_destruction_trigger_rule(self, trigger_zone: TriggerZone) -> None:
# Add destruction zone trigger # Add destruction zone trigger
t = TriggerStart(comment="Destruction") t = TriggerStart(comment="Destruction")
t.actions.append( t.actions.append(
@ -333,6 +337,17 @@ class SceneryGenerator(BuildingSiteGenerator):
) )
self.m.triggerrules.triggers.append(t) self.m.triggerrules.triggers.append(t)
def generate_on_dead_trigger_rule(self, trigger_zone: TriggerZone) -> None:
# Add a TriggerRule with the MapObjectIsDead condition to recognize killed
# map objects and add them to the state.json with a DoScript
t = TriggerOnce(Event.NoEvent, f"MapObjectIsDead Trigger {trigger_zone.id}")
t.add_condition(MapObjectIsDead(trigger_zone.id))
script_string = String(
f'killed_map_objects[#killed_map_objects + 1] = "{trigger_zone.name}"'
)
t.actions.append(DoScript(script_string))
self.m.triggerrules.triggers.append(t)
def register_scenery(self) -> None: def register_scenery(self) -> None:
scenery = self.ground_object scenery = self.ground_object
assert isinstance(scenery, SceneryGroundObject) assert isinstance(scenery, SceneryGroundObject)

View File

@ -4,10 +4,11 @@ local WRITESTATE_SCHEDULE_IN_SECONDS = 60
logger = mist.Logger:new("DCSLiberation", "info") logger = mist.Logger:new("DCSLiberation", "info")
logger:info("Check that json.lua is loaded : json = "..tostring(json)) logger:info("Check that json.lua is loaded : json = "..tostring(json))
killed_aircrafts = {} killed_aircrafts = {} -- killed aircraft will be added via S_EVENT_CRASH event
killed_ground_units = {} killed_ground_units = {} -- killed units will be added via S_EVENT_DEAD event
base_capture_events = {} base_capture_events = {}
destroyed_objects_positions = {} destroyed_objects_positions = {} -- will be added via S_EVENT_DEAD event
killed_map_objects = {} -- killed map objects will be added via TriggerRules
mission_ended = false mission_ended = false
local function ends_with(str, ending) local function ends_with(str, ending)
@ -35,6 +36,7 @@ function write_state()
["base_capture_events"] = base_capture_events, ["base_capture_events"] = base_capture_events,
["mission_ended"] = mission_ended, ["mission_ended"] = mission_ended,
["destroyed_objects_positions"] = destroyed_objects_positions, ["destroyed_objects_positions"] = destroyed_objects_positions,
["killed_map_objects"] = killed_map_objects,
} }
if not json then if not json then
local message = string.format("Unable to save DCS Liberation state to %s, JSON library is not loaded !", _debriefing_file_location) local message = string.format("Unable to save DCS Liberation state to %s, JSON library is not loaded !", _debriefing_file_location)