Add BAI missions.

BAI is used for attacking ground vehicles as opposed to buildings like
strike does, and not air defenses like DEAD does. Unlike strike, BAI is
tolerant of moving targets.

Fixes https://github.com/Khopa/dcs_liberation/issues/216
This commit is contained in:
Dan Albert 2020-11-16 21:05:53 -08:00
parent 8bd00bf450
commit 9fb33526a7
6 changed files with 80 additions and 11 deletions

View File

@ -2,6 +2,7 @@
# Features/Improvements
* **[Flight Planner]** Added fighter sweep missions.
* **[Flight Planner]** Added BAI missions.
* **[Flight Planner]** Differentiated BARCAP and TARCAP. TARCAP is now for hostile areas and will arrive before the package.
* **[Modding]** Possible to setup liveries overrides for factions

View File

@ -1279,6 +1279,7 @@ class PydcsWaypointBuilder:
package: Package, flight: Flight,
mission: Mission) -> PydcsWaypointBuilder:
builders = {
FlightWaypointType.INGRESS_BAI: BaiIngressBuilder,
FlightWaypointType.INGRESS_CAS: CasIngressBuilder,
FlightWaypointType.INGRESS_DEAD: DeadIngressBuilder,
FlightWaypointType.INGRESS_SEAD: SeadIngressBuilder,
@ -1339,6 +1340,32 @@ class HoldPointBuilder(PydcsWaypointBuilder):
return waypoint
class BaiIngressBuilder(PydcsWaypointBuilder):
def build(self) -> MovingPoint:
waypoint = super().build()
target_group = self.package.target
if isinstance(target_group, TheaterGroundObject):
# Match search is used due to TheaterGroundObject.name not matching
# the Mission group name because of SkyNet prefixes.
tgroup = self.mission.find_group(target_group.group_name,
search="match")
if tgroup is not None:
task = AttackGroup(tgroup.id, weapon_type=WeaponType.Auto)
task.params["attackQtyLimit"] = False
task.params["directionEnabled"] = False
task.params["altitudeEnabled"] = False
task.params["groupAttack"] = True
waypoint.tasks.append(task)
else:
logging.error("Could not find group for BAI mission %s",
target_group.group_name)
else:
logging.error("Unexpected target type for BAI mission: %s",
target_group.__class__.__name__)
return waypoint
class CasIngressBuilder(PydcsWaypointBuilder):
def build(self) -> MovingPoint:
waypoint = super().build()
@ -1372,14 +1399,16 @@ class DeadIngressBuilder(PydcsWaypointBuilder):
target_group = self.package.target
if isinstance(target_group, TheaterGroundObject):
tgroup = self.mission.find_group(target_group.group_name, search="match") # Match search is used due to TheaterGroundObject.name not matching
if tgroup is not None: # the Mission group name because of SkyNet prefixes.
task = AttackGroup(tgroup.id)
# Match search is used due to TheaterGroundObject.name not matching
# the Mission group name because of SkyNet prefixes.
tgroup = self.mission.find_group(target_group.group_name,
search="match")
if tgroup is not None:
task = AttackGroup(tgroup.id, weapon_type=WeaponType.Guided)
task.params["expend"] = "All"
task.params["attackQtyLimit"] = False
task.params["directionEnabled"] = False
task.params["altitudeEnabled"] = False
task.params["weaponType"] = 268402702 # Guided Weapons
task.params["groupAttack"] = True
waypoint.tasks.append(task)
else:
@ -1394,8 +1423,11 @@ class SeadIngressBuilder(PydcsWaypointBuilder):
target_group = self.package.target
if isinstance(target_group, TheaterGroundObject):
tgroup = self.mission.find_group(target_group.group_name, search="match") # Match search is used due to TheaterGroundObject.name not matching
if tgroup is not None: # the Mission group name because of SkyNet prefixes.
# Match search is used due to TheaterGroundObject.name not matching
# the Mission group name because of SkyNet prefixes.
tgroup = self.mission.find_group(target_group.group_name,
search="match")
if tgroup is not None:
waypoint.add_task(EngageTargetsInZone(
position=tgroup.position,
radius=nm_to_meter(30),

View File

@ -64,6 +64,7 @@ class FlightWaypointType(Enum):
INGRESS_ESCORT = 19
INGRESS_DEAD = 20
INGRESS_SWEEP = 21
INGRESS_BAI = 22
class FlightWaypoint:

View File

@ -629,7 +629,9 @@ class FlightPlanBuilder:
custom_targets: Optional[List[Unit]]) -> FlightPlan:
# TODO: Flesh out mission types.
task = flight.flight_type
if task == FlightType.BARCAP:
if task == FlightType.BAI:
return self.generate_bai(flight)
elif task == FlightType.BARCAP:
return self.generate_barcap(flight)
elif task == FlightType.CAS:
return self.generate_cas(flight)
@ -702,6 +704,23 @@ class FlightPlanBuilder:
return self.strike_flightplan(flight, location, targets)
def generate_bai(self, flight: Flight) -> StrikeFlightPlan:
"""Generates a BAI flight plan.
Args:
flight: The flight to generate the flight plan for.
"""
location = self.package.target
if not isinstance(location, TheaterGroundObject):
raise InvalidObjectiveLocation(flight.flight_type, location)
targets: List[StrikeTarget] = []
for group in location.groups:
targets.append(StrikeTarget(f"{group.id}", group))
return self.strike_flightplan(flight, location, targets)
def generate_barcap(self, flight: Flight) -> BarCapFlightPlan:
"""Generate a BARCAP flight at a given location.
@ -965,7 +984,9 @@ class FlightPlanBuilder:
@staticmethod
def target_waypoint(flight: Flight, builder: WaypointBuilder,
target: StrikeTarget) -> FlightWaypoint:
if flight.flight_type == FlightType.DEAD:
if flight.flight_type == FlightType.BAI:
return builder.bai_group(target)
elif flight.flight_type == FlightType.DEAD:
return builder.dead_point(target)
elif flight.flight_type == FlightType.SEAD:
return builder.sead_point(target)
@ -1068,7 +1089,6 @@ class FlightPlanBuilder:
assert self.package.waypoints is not None
builder = WaypointBuilder(self.game.conditions, flight, self.doctrine,
targets)
# sead_types = {FlightType.DEAD, FlightType.SEAD}
if flight.flight_type is FlightType.SEAD:
ingress = builder.ingress_sead(self.package.waypoints.ingress,
location)
@ -1076,6 +1096,9 @@ class FlightPlanBuilder:
elif flight.flight_type is FlightType.DEAD:
ingress = builder.ingress_dead(self.package.waypoints.ingress,
location)
elif flight.flight_type is FlightType.BAI:
ingress = builder.ingress_bai(self.package.waypoints.ingress,
location)
else:
ingress = builder.ingress_strike(self.package.waypoints.ingress,
location)

View File

@ -5,6 +5,7 @@ from typing import List, Optional, Tuple, Union
from dcs.mapping import Point
from dcs.unit import Unit
from dcs.unitgroup import VehicleGroup
from game.data.doctrine import Doctrine
from game.utils import nm_to_meter
@ -17,7 +18,7 @@ from ..runways import RunwayAssigner
@dataclass(frozen=True)
class StrikeTarget:
name: str
target: Union[TheaterGroundObject, Unit]
target: Union[VehicleGroup, TheaterGroundObject, Unit]
class WaypointBuilder:
@ -169,6 +170,11 @@ class WaypointBuilder:
return self._ingress(FlightWaypointType.INGRESS_ESCORT, position,
objective)
def ingress_bai(self, position: Point,
objective: MissionTarget) -> FlightWaypoint:
return self._ingress(FlightWaypointType.INGRESS_BAI, position,
objective)
def ingress_dead(self, position:Point,
objective: MissionTarget) -> FlightWaypoint:
return self._ingress(FlightWaypointType.INGRESS_DEAD, position,
@ -211,6 +217,9 @@ class WaypointBuilder:
waypoint.name = "EGRESS"
return waypoint
def bai_group(self, target: StrikeTarget) -> FlightWaypoint:
return self._target_point(target, f"ATTACK {target.name}")
def dead_point(self, target: StrikeTarget) -> FlightWaypoint:
return self._target_point(target, f"STRIKE {target.name}")

View File

@ -126,7 +126,10 @@ class TheaterGroundObject(MissionTarget):
# TODO: FlightType.TROOP_TRANSPORT
]
else:
yield FlightType.STRIKE
yield from [
FlightType.STRIKE,
FlightType.BAI,
]
yield from super().mission_types(for_player)