def _generate_capture_triggers(self, player_coalition: str, enemy_coalition: str) -> None: """Creates a pair of triggers for each control point of `cls.capture_zone_types`. One for the initial capture of a control point, and one if it is recaptured. Directly appends to the global `base_capture_events` var declared by `dcs_libaration.lua` """ for cp in self.game.theater.controlpoints: if isinstance(cp, self.capture_zone_types): if cp.captured: attacking_coalition = enemy_coalition attack_coalition_int = 1 # 1 is the Event int for Red defending_coalition = player_coalition defend_coalition_int = 2 # 2 is the Event int for Blue else: attacking_coalition = player_coalition attack_coalition_int = 2 defending_coalition = enemy_coalition defend_coalition_int = 1 trigger_zone = self.mission.triggers.add_triggerzone( cp.position, radius=3000, hidden=False, name="CAPTURE") flag = self.get_capture_zone_flag() capture_trigger = TriggerCondition(Event.NoEvent, "Capture Trigger") capture_trigger.add_condition( AllOfCoalitionOutsideZone(defending_coalition, trigger_zone.id)) capture_trigger.add_condition( PartOfCoalitionInZone(attacking_coalition, trigger_zone.id, unit_type="GROUND")) capture_trigger.add_condition(FlagIsFalse(flag=flag)) script_string = String( f'base_capture_events[#base_capture_events + 1] = "{cp.id}||{attack_coalition_int}||{cp.full_name}"' ) capture_trigger.add_action(DoScript(script_string)) capture_trigger.add_action(SetFlag(flag=flag)) self.mission.triggerrules.triggers.append(capture_trigger) recapture_trigger = TriggerCondition(Event.NoEvent, "Capture Trigger") recapture_trigger.add_condition( AllOfCoalitionOutsideZone(attacking_coalition, trigger_zone.id)) recapture_trigger.add_condition( PartOfCoalitionInZone(defending_coalition, trigger_zone.id, unit_type="GROUND")) recapture_trigger.add_condition(FlagIsTrue(flag=flag)) script_string = String( f'base_capture_events[#base_capture_events + 1] = "{cp.id}||{defend_coalition_int}||{cp.full_name}"' ) recapture_trigger.add_action(DoScript(script_string)) recapture_trigger.add_action(ClearFlag(flag=flag)) self.mission.triggerrules.triggers.append(recapture_trigger)
def __init__(self, _id, name=None, type=""): self.type = type self.position = mapping.Point(0, 0) self.heading = 0 self.id = _id self.skill = Skill.Average # type: Skill self.name = name if name else String()
def _gen_markers(self) -> None: """ Generate markers on F10 map for each existing objective """ if self.game.settings.generate_marks: mark_trigger = TriggerOnce(Event.NoEvent, "Marks generator") mark_trigger.add_condition(TimeAfter(1)) v = 10 for cp in self.game.theater.controlpoints: seen = set() for ground_object in cp.ground_objects: if ground_object.obj_name in seen: continue seen.add(ground_object.obj_name) for location in ground_object.mark_locations: zone = self.mission.triggers.add_triggerzone( location, radius=10, hidden=True, name="MARK") if cp.captured: name = ground_object.obj_name + " [ALLY]" else: name = ground_object.obj_name + " [ENEMY]" mark_trigger.add_action( MarkToAll(v, zone.id, String(name))) v += 1 self.mission.triggerrules.triggers.append(mark_trigger)
def __init__(self): self.alt = 0 self.type = "" self.name = String() self.position = mapping.Point(0, 0) self.speed = 0 self.formation_template = "" self.action = PointAction.None_ # type: PointAction
def __init__(self, _id: int, name=None): if not isinstance(_id, int): raise TypeError("id must be an integer") self.id = _id self.hidden = False self.units = [] # type: List[Unit] self.points = [] # type: List[Union[StaticPoint, MovingPoint]] self.name = name if name else String()
def add_waypoint(self, pos: mapping.Point, altitude, speed=600, name: String=None) -> MovingPoint: mp = MovingPoint() mp.type = "Turning Point" mp.action = PointAction.TurningPoint mp.name = name if name else String() mp.position = mapping.Point(pos.x, pos.y) mp.alt = altitude mp.speed = speed / 3.6 mp.ETA_locked = False mp.properties = PointProperties() self.add_point(mp) return mp
def test_create_mission_with_part_of_coalition_zone_trigger(self): m = dcs.mission.Mission(terrain=dcs.terrain.Caucasus()) usa = m.country("USA") trigger_zone = m.triggers.add_triggerzone(m.terrain.batumi().position.point_from_heading(90, 15000), radius=5000, hidden=False, name="TRIGGER_ZONE") trigger = dcs.triggers.TriggerOnce(dcs.triggers.Event.NoEvent, "Detection of blue aircraft") trigger.add_condition(dcs.condition.PartOfCoalitionInZone("blue", trigger_zone.id, "AIRPLANE")) trigger.add_action(dcs.action.MessageToAll(text=String("Blue aircraft detected in trigger zone !"))) m.triggerrules.triggers.append(trigger) trigger_zone_2 = m.triggers.add_triggerzone(m.terrain.batumi().position, radius=5000, hidden=False, name="BATUMI_ZONE") trigger_outside = dcs.triggers.TriggerOnce(dcs.triggers.Event.NoEvent, "No blue in batumi zone") trigger_outside.add_condition(dcs.condition.PartOfCoalitionOutsideZone("blue", trigger_zone_2.id, "AIRPLANE")) trigger_outside.add_action(dcs.action.MessageToAll( text=String("Blue aircraft are not in batumi zone anymore!"))) m.triggerrules.triggers.append(trigger_outside) f15 = m.flight_group_inflight(usa, "F15", dcs.planes.F_15C, m.terrain.batumi().position, 1000) f15.add_waypoint(trigger_zone.position, 500) m.save('missions/mission_with_part_of_coalition_zone_trigger.miz') # Test load mission m2 = dcs.mission.Mission() self.assertEqual(0, len(m2.load_file('missions/mission_with_part_of_coalition_zone_trigger.miz'))) self.assertEqual(m2.triggerrules.triggers[0].rules[0].unitType, "AIRPLANE") self.assertEqual(m2.triggerrules.triggers[0].rules[0].zone, trigger_zone.id) self.assertEqual(m2.triggerrules.triggers[0].rules[0].coalitionlist, "blue") self.assertEqual(m2.triggerrules.triggers[1].rules[0].unitType, "AIRPLANE") self.assertEqual(m2.triggerrules.triggers[1].rules[0].zone, trigger_zone_2.id) self.assertEqual(m2.triggerrules.triggers[1].rules[0].coalitionlist, "blue")
def modify(self, group_id, old_wp, new_wp): group = self.campaign.lookup_group(group_id) if group is None: raise ValueError(f"no group found with id {group_id}") converted_old_wp = _convert_point(self.campaign.mission.terrain, old_wp) old_wp_index = [ u_index for u_index, u in enumerate(group.points) if self._is_same_point(u.position, converted_old_wp) ] if old_wp_index: wp = group.points[old_wp_index[0]] wp.alt = new_wp['alt'] wp.type = new_wp['type'] wpt_key = "DictKey_WptName_" # incorrect_wp_name: Workaround for DCS Liberation as it will give the same key # for all ingress WPs e.g. "INGERSS" instead of "DictKey_WptName_XYZ" incorrect_wp_name = wp.name is not None and not wp.name.id.startswith( wpt_key) if wp.name is None or wp.name.translation is None or not isinstance(wp.name, String) \ or incorrect_wp_name: logging.debug("Creating new WP name String.") wp.name = String(self._get_next_wp_key(), self.campaign.mission.translation) wp.name.set(new_wp['name']) wp.position = _convert_point(self.campaign.mission.terrain, new_wp['position']) wp.speed = new_wp['speed'] wp.action = PointAction[new_wp['action']] if isinstance(wp, MovingPoint): wp.alt_type = new_wp['alt_type'] logging.info(f"Waypoint {old_wp_index} modified") else: logging.warning("Failed to modify waypoint") return group
def generate_lua( cls, airgen: AircraftConflictGenerator, airsupportgen: AirSupportConflictGenerator, jtacs: List[JtacInfo], ) -> None: # TODO: Refactor this luaData = { "AircraftCarriers": {}, "Tankers": {}, "AWACs": {}, "JTACs": {}, "TargetPoints": {}, "RedAA": {}, "BlueAA": {}, } # type: ignore for i, tanker in enumerate(airsupportgen.air_support.tankers): luaData["Tankers"][i] = { "dcsGroupName": tanker.group_name, "callsign": tanker.callsign, "variant": tanker.variant, "radio": tanker.freq.mhz, "tacan": str(tanker.tacan.number) + tanker.tacan.band.name, } for i, awacs in enumerate(airsupportgen.air_support.awacs): luaData["AWACs"][i] = { "dcsGroupName": awacs.group_name, "callsign": awacs.callsign, "radio": awacs.freq.mhz, } for i, jtac in enumerate(jtacs): luaData["JTACs"][i] = { "dcsGroupName": jtac.group_name, "callsign": jtac.callsign, "zone": jtac.region, "dcsUnit": jtac.unit_name, "laserCode": jtac.code, } flight_count = 0 for flight in airgen.flights: if flight.friendly and flight.flight_type in [ FlightType.ANTISHIP, FlightType.DEAD, FlightType.SEAD, FlightType.STRIKE, ]: flightType = str(flight.flight_type) flightTarget = flight.package.target if flightTarget: flightTargetName = None flightTargetType = None if isinstance(flightTarget, TheaterGroundObject): flightTargetName = flightTarget.obj_name flightTargetType = (flightType + f" TGT ({flightTarget.category})") elif hasattr(flightTarget, "name"): flightTargetName = flightTarget.name flightTargetType = flightType + " TGT (Airbase)" luaData["TargetPoints"][flight_count] = { "name": flightTargetName, "type": flightTargetType, "position": { "x": flightTarget.position.x, "y": flightTarget.position.y, }, } flight_count += 1 for cp in cls.game.theater.controlpoints: for ground_object in cp.ground_objects: if ground_object.might_have_aa and not ground_object.is_dead: for g in ground_object.groups: threat_range = ground_object.threat_range(g) if not threat_range: continue faction = "BlueAA" if cp.captured else "RedAA" luaData[faction][g.name] = { "name": ground_object.name, "range": threat_range.meters, "position": { "x": ground_object.position.x, "y": ground_object.position.y, }, } # set a LUA table with data from Liberation that we want to set # at the moment it contains Liberation's install path, and an overridable definition for the JTACAutoLase function # later, we'll add data about the units and points having been generated, in order to facilitate the configuration of the plugin lua scripts state_location = "[[" + os.path.abspath(".") + "]]" lua = (""" -- setting configuration table env.info("DCSLiberation|: setting configuration table") -- all data in this table is overridable. dcsLiberation = {} -- the base location for state.json; if non-existent, it'll be replaced with LIBERATION_EXPORT_DIR, TEMP, or DCS working directory dcsLiberation.installPath=""" + state_location + """ """) # Process the tankers lua += """ -- list the tankers generated by Liberation dcsLiberation.Tankers = { """ for key in luaData["Tankers"]: data = luaData["Tankers"][key] dcsGroupName = data["dcsGroupName"] callsign = data["callsign"] variant = data["variant"] tacan = data["tacan"] radio = data["radio"] lua += f" {{dcsGroupName='{dcsGroupName}', callsign='{callsign}', variant='{variant}', tacan='{tacan}', radio='{radio}' }}, \n" # lua += f" {{name='{dcsGroupName}', description='{callsign} ({variant})', information='Tacan:{tacan} Radio:{radio}' }}, \n" lua += "}" # Process the AWACSes lua += """ -- list the AWACs generated by Liberation dcsLiberation.AWACs = { """ for key in luaData["AWACs"]: data = luaData["AWACs"][key] dcsGroupName = data["dcsGroupName"] callsign = data["callsign"] radio = data["radio"] lua += f" {{dcsGroupName='{dcsGroupName}', callsign='{callsign}', radio='{radio}' }}, \n" # lua += f" {{name='{dcsGroupName}', description='{callsign} (AWACS)', information='Radio:{radio}' }}, \n" lua += "}" # Process the JTACs lua += """ -- list the JTACs generated by Liberation dcsLiberation.JTACs = { """ for key in luaData["JTACs"]: data = luaData["JTACs"][key] dcsGroupName = data["dcsGroupName"] callsign = data["callsign"] zone = data["zone"] laserCode = data["laserCode"] dcsUnit = data["dcsUnit"] lua += f" {{dcsGroupName='{dcsGroupName}', callsign='{callsign}', zone={repr(zone)}, laserCode='{laserCode}', dcsUnit='{dcsUnit}' }}, \n" lua += "}" # Process the Target Points lua += """ -- list the target points generated by Liberation dcsLiberation.TargetPoints = { """ for key in luaData["TargetPoints"]: data = luaData["TargetPoints"][key] name = data["name"] pointType = data["type"] positionX = data["position"]["x"] positionY = data["position"]["y"] lua += f" {{name='{name}', pointType='{pointType}', positionX='{positionX}', positionY='{positionY}' }}, \n" # lua += f" {{name='{pointType} {name}', point{{x={positionX}, z={positionY} }} }}, \n" lua += "}" lua += """ -- list the airbases generated by Liberation -- dcsLiberation.Airbases = {} -- list the aircraft carriers generated by Liberation -- dcsLiberation.Carriers = {} -- list the Red AA generated by Liberation dcsLiberation.RedAA = { """ for key in luaData["RedAA"]: data = luaData["RedAA"][key] name = data["name"] radius = data["range"] positionX = data["position"]["x"] positionY = data["position"]["y"] lua += f" {{dcsGroupName='{key}', name='{name}', range='{radius}', positionX='{positionX}', positionY='{positionY}' }}, \n" lua += "}" lua += """ -- list the Blue AA generated by Liberation dcsLiberation.BlueAA = { """ for key in luaData["BlueAA"]: data = luaData["BlueAA"][key] name = data["name"] radius = data["range"] positionX = data["position"]["x"] positionY = data["position"]["y"] lua += f" {{dcsGroupName='{key}', name='{name}', range='{radius}', positionX='{positionX}', positionY='{positionY}' }}, \n" lua += "}" lua += """ """ trigger = TriggerStart(comment="Set DCS Liberation data") trigger.add_action(DoScript(String(lua))) Operation.current_mission.triggerrules.triggers.append(trigger)
def inject_lua_trigger(cls, contents: str, comment: str) -> None: trigger = TriggerStart(comment=comment) trigger.add_action(DoScript(String(contents))) cls.current_mission.triggerrules.triggers.append(trigger)
def generate(self): radio_registry = RadioRegistry() tacan_registry = TacanRegistry() # Dedup beacon/radio frequencies, since some maps have some frequencies # used multiple times. beacons = load_beacons_for_terrain(self.game.theater.terrain.name) unique_map_frequencies: Set[RadioFrequency] = set() for beacon in beacons: unique_map_frequencies.add(beacon.frequency) if beacon.is_tacan: if beacon.channel is None: logging.error( f"TACAN beacon has no channel: {beacon.callsign}") else: tacan_registry.reserve(beacon.tacan_channel) for airfield, data in AIRFIELD_DATA.items(): if data.theater == self.game.theater.terrain.name: unique_map_frequencies.add(data.atc.hf) unique_map_frequencies.add(data.atc.vhf_fm) unique_map_frequencies.add(data.atc.vhf_am) unique_map_frequencies.add(data.atc.uhf) # No need to reserve ILS or TACAN because those are in the # beacon list. for frequency in unique_map_frequencies: radio_registry.reserve(frequency) # Set mission time and weather conditions. EnvironmentGenerator(self.current_mission, self.game.conditions).generate() # Generate ground object first groundobjectgen = GroundObjectsGenerator(self.current_mission, self.conflict, self.game, radio_registry, tacan_registry) groundobjectgen.generate() # Generate destroyed units for d in self.game.get_destroyed_units(): try: utype = db.unit_type_from_name(d["type"]) except KeyError: continue pos = Point(d["x"], d["z"]) if utype is not None and not self.game.position_culled( pos) and self.game.settings.perf_destroyed_units: self.current_mission.static_group( country=self.current_mission.country( self.game.player_country), name="", _type=utype, hidden=True, position=pos, heading=d["orientation"], dead=True, ) # Air Support (Tanker & Awacs) airsupportgen = AirSupportConflictGenerator(self.current_mission, self.conflict, self.game, radio_registry, tacan_registry) airsupportgen.generate(self.is_awacs_enabled) # Generate Activity on the map airgen = AircraftConflictGenerator(self.current_mission, self.conflict, self.game.settings, self.game, radio_registry) airgen.generate_flights( self.current_mission.country(self.game.player_country), self.game.blue_ato, groundobjectgen.runways) airgen.generate_flights( self.current_mission.country(self.game.enemy_country), self.game.red_ato, groundobjectgen.runways) # Generate ground units on frontline everywhere jtacs: List[JtacInfo] = [] for front_line in self.game.theater.conflicts(True): player_cp = front_line.control_point_a enemy_cp = front_line.control_point_b conflict = Conflict.frontline_cas_conflict( self.attacker_name, self.defender_name, self.current_mission.country(self.attacker_country), self.current_mission.country(self.defender_country), player_cp, enemy_cp, self.game.theater) # Generate frontline ops player_gp = self.game.ground_planners[player_cp.id].units_per_cp[ enemy_cp.id] enemy_gp = self.game.ground_planners[enemy_cp.id].units_per_cp[ player_cp.id] groundConflictGen = GroundConflictGenerator( self.current_mission, conflict, self.game, player_gp, enemy_gp, player_cp.stances[enemy_cp.id]) groundConflictGen.generate() jtacs.extend(groundConflictGen.jtacs) # Setup combined arms parameters self.current_mission.groundControl.pilot_can_control_vehicles = self.ca_slots > 0 if self.game.player_country in [ country.name for country in self.current_mission.coalition["blue"].countries.values() ]: self.current_mission.groundControl.blue_tactical_commander = self.ca_slots else: self.current_mission.groundControl.red_tactical_commander = self.ca_slots # Triggers triggersgen = TriggersGenerator(self.current_mission, self.conflict, self.game) triggersgen.generate() # Options forcedoptionsgen = ForcedOptionsGenerator(self.current_mission, self.conflict, self.game) forcedoptionsgen.generate() # Generate Visuals Smoke Effects visualgen = VisualGenerator(self.current_mission, self.conflict, self.game) if self.game.settings.perf_smoke_gen: visualgen.generate() luaData = {} luaData["AircraftCarriers"] = {} luaData["Tankers"] = {} luaData["AWACs"] = {} luaData["JTACs"] = {} luaData["TargetPoints"] = {} self.assign_channels_to_flights(airgen.flights, airsupportgen.air_support) for tanker in airsupportgen.air_support.tankers: luaData["Tankers"][tanker.callsign] = { "dcsGroupName": tanker.dcsGroupName, "callsign": tanker.callsign, "variant": tanker.variant, "radio": tanker.freq.mhz, "tacan": str(tanker.tacan.number) + tanker.tacan.band.name } if self.is_awacs_enabled: for awacs in airsupportgen.air_support.awacs: luaData["AWACs"][awacs.callsign] = { "dcsGroupName": awacs.dcsGroupName, "callsign": awacs.callsign, "radio": awacs.freq.mhz } for jtac in jtacs: luaData["JTACs"][jtac.callsign] = { "dcsGroupName": jtac.dcsGroupName, "callsign": jtac.callsign, "zone": jtac.region, "dcsUnit": jtac.unit_name, "laserCode": jtac.code } for flight in airgen.flights: if flight.friendly and flight.flight_type in [ FlightType.ANTISHIP, FlightType.DEAD, FlightType.SEAD, FlightType.STRIKE ]: flightType = flight.flight_type.name flightTarget = flight.package.target if flightTarget: flightTargetName = None flightTargetType = None if hasattr(flightTarget, 'obj_name'): flightTargetName = flightTarget.obj_name flightTargetType = flightType + f" TGT ({flightTarget.category})" elif hasattr(flightTarget, 'name'): flightTargetName = flightTarget.name flightTargetType = flightType + " TGT (Airbase)" luaData["TargetPoints"][flightTargetName] = { "name": flightTargetName, "type": flightTargetType, "position": { "x": flightTarget.position.x, "y": flightTarget.position.y } } # set a LUA table with data from Liberation that we want to set # at the moment it contains Liberation's install path, and an overridable definition for the JTACAutoLase function # later, we'll add data about the units and points having been generated, in order to facilitate the configuration of the plugin lua scripts state_location = "[[" + os.path.abspath(".") + "]]" lua = """ -- setting configuration table env.info("DCSLiberation|: setting configuration table") -- all data in this table is overridable. dcsLiberation = {} -- the base location for state.json; if non-existent, it'll be replaced with LIBERATION_EXPORT_DIR, TEMP, or DCS working directory dcsLiberation.installPath=""" + state_location + """ """ # Process the tankers lua += """ -- list the tankers generated by Liberation dcsLiberation.Tankers = { """ for key in luaData["Tankers"]: data = luaData["Tankers"][key] dcsGroupName = data["dcsGroupName"] callsign = data["callsign"] variant = data["variant"] tacan = data["tacan"] radio = data["radio"] lua += f" {{dcsGroupName='{dcsGroupName}', callsign='{callsign}', variant='{variant}', tacan='{tacan}', radio='{radio}' }}, \n" #lua += f" {{name='{dcsGroupName}', description='{callsign} ({variant})', information='Tacan:{tacan} Radio:{radio}' }}, \n" lua += "}" # Process the AWACSes lua += """ -- list the AWACs generated by Liberation dcsLiberation.AWACs = { """ for key in luaData["AWACs"]: data = luaData["AWACs"][key] dcsGroupName = data["dcsGroupName"] callsign = data["callsign"] radio = data["radio"] lua += f" {{dcsGroupName='{dcsGroupName}', callsign='{callsign}', radio='{radio}' }}, \n" #lua += f" {{name='{dcsGroupName}', description='{callsign} (AWACS)', information='Radio:{radio}' }}, \n" lua += "}" # Process the JTACs lua += """ -- list the JTACs generated by Liberation dcsLiberation.JTACs = { """ for key in luaData["JTACs"]: data = luaData["JTACs"][key] dcsGroupName = data["dcsGroupName"] callsign = data["callsign"] zone = data["zone"] laserCode = data["laserCode"] dcsUnit = data["dcsUnit"] lua += f" {{dcsGroupName='{dcsGroupName}', callsign='{callsign}', zone='{zone}', laserCode='{laserCode}', dcsUnit='{dcsUnit}' }}, \n" #lua += f" {{name='{dcsGroupName}', description='JTAC {callsign} ', information='Laser:{laserCode}', jtac={laserCode} }}, \n" lua += "}" # Process the Target Points lua += """ -- list the target points generated by Liberation dcsLiberation.TargetPoints = { """ for key in luaData["TargetPoints"]: data = luaData["TargetPoints"][key] name = data["name"] pointType = data["type"] positionX = data["position"]["x"] positionY = data["position"]["y"] lua += f" {{name='{name}', pointType='{pointType}', positionX='{positionX}', positionY='{positionY}' }}, \n" #lua += f" {{name='{pointType} {name}', point{{x={positionX}, z={positionY} }} }}, \n" lua += "}" lua += """ -- list the airbases generated by Liberation -- dcsLiberation.Airbases = {} -- list the aircraft carriers generated by Liberation -- dcsLiberation.Carriers = {} -- later, we'll add more data to the table """ trigger = TriggerStart(comment="Set DCS Liberation data") trigger.add_action(DoScript(String(lua))) self.current_mission.triggerrules.triggers.append(trigger) # Inject Plugins Lua Scripts and data for plugin in LuaPluginManager.plugins(): if plugin.enabled: plugin.inject_scripts(self) plugin.inject_configuration(self) self.assign_channels_to_flights(airgen.flights, airsupportgen.air_support) self.notify_info_generators(groundobjectgen, airsupportgen, jtacs, airgen)