mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Merge branch 'dev' into pr/204
This commit is contained in:
@@ -57,6 +57,8 @@ class AircraftBehavior:
|
||||
self.configure_refueling(group, flight)
|
||||
elif self.task in [FlightType.CAS, FlightType.BAI]:
|
||||
self.configure_cas(group, flight)
|
||||
elif self.task == FlightType.ARMED_RECON:
|
||||
self.configure_armed_recon(group, flight)
|
||||
elif self.task == FlightType.DEAD:
|
||||
self.configure_dead(group, flight)
|
||||
elif self.task in [FlightType.SEAD, FlightType.SEAD_SWEEP]:
|
||||
@@ -183,6 +185,17 @@ class AircraftBehavior:
|
||||
restrict_jettison=True,
|
||||
)
|
||||
|
||||
def configure_armed_recon(self, group: FlyingGroup[Any], flight: Flight) -> None:
|
||||
self.configure_task(flight, group, CAS, [AFAC, AntishipStrike])
|
||||
self.configure_behavior(
|
||||
flight,
|
||||
group,
|
||||
react_on_threat=OptReactOnThreat.Values.EvadeFire,
|
||||
roe=OptROE.Values.OpenFire,
|
||||
rtb_winchester=OptRTBOnOutOfAmmo.Values.All,
|
||||
restrict_jettison=True,
|
||||
)
|
||||
|
||||
def configure_dead(self, group: FlyingGroup[Any], flight: Flight) -> None:
|
||||
# Only CAS and SEAD are capable of the Attack Group task. SEAD is arguably more
|
||||
# appropriate but it has an extremely limited list of capable aircraft, whereas
|
||||
@@ -379,23 +392,35 @@ class AircraftBehavior:
|
||||
|
||||
if preferred_task in flight.unit_type.dcs_unit_type.tasks:
|
||||
group.task = preferred_task.name
|
||||
elif fallback_tasks:
|
||||
return
|
||||
if fallback_tasks:
|
||||
for task in fallback_tasks:
|
||||
if task in flight.unit_type.dcs_unit_type.tasks:
|
||||
group.task = task.name
|
||||
return
|
||||
elif flight.unit_type.dcs_unit_type.task_default and preferred_task == Nothing:
|
||||
if flight.unit_type.dcs_unit_type.task_default and preferred_task == Nothing:
|
||||
group.task = flight.unit_type.dcs_unit_type.task_default.name
|
||||
logging.warning(
|
||||
f"{ac_type} is not capable of 'Nothing', using default task '{group.task}'"
|
||||
)
|
||||
else:
|
||||
fallback_part = (
|
||||
f" nor any of the following fall-back tasks: {[task.name for task in fallback_tasks]}"
|
||||
if fallback_tasks
|
||||
else ""
|
||||
return
|
||||
if flight.roster.members and flight.roster.members[0].is_player:
|
||||
group.task = (
|
||||
flight.unit_type.dcs_unit_type.task_default.name
|
||||
if flight.unit_type.dcs_unit_type.task_default
|
||||
else group.task # even if this is incompatible, if it's a client we don't really care...
|
||||
)
|
||||
raise RuntimeError(
|
||||
f"{ac_type} is neither capable of {preferred_task.name}"
|
||||
f"{fallback_part}. Can't generate {flight.flight_type} flight."
|
||||
logging.warning(
|
||||
f"Client override: {ac_type} is not capable of '{preferred_task}', using default task '{group.task}'"
|
||||
)
|
||||
return
|
||||
|
||||
fallback_part = (
|
||||
f" nor any of the following fall-back tasks: {[task.name for task in fallback_tasks]}"
|
||||
if fallback_tasks
|
||||
else ""
|
||||
)
|
||||
raise RuntimeError(
|
||||
f"{ac_type} is neither capable of {preferred_task.name}"
|
||||
f"{fallback_part}. Can't generate {flight.flight_type} flight."
|
||||
)
|
||||
|
||||
@@ -497,21 +497,20 @@ class FlightGroupSpawner:
|
||||
) -> Optional[FlyingGroup[Any]]:
|
||||
is_airbase = False
|
||||
is_roadbase = False
|
||||
ground_spawn = None
|
||||
|
||||
try:
|
||||
if is_large:
|
||||
if len(self.ground_spawns_large[cp]) > 0:
|
||||
ground_spawn = self.ground_spawns_large[cp].pop()
|
||||
is_airbase = True
|
||||
else:
|
||||
if len(self.ground_spawns_roadbase[cp]) > 0:
|
||||
ground_spawn = self.ground_spawns_roadbase[cp].pop()
|
||||
is_roadbase = True
|
||||
if len(self.ground_spawns[cp]) > 0:
|
||||
ground_spawn = self.ground_spawns[cp].pop()
|
||||
is_airbase = True
|
||||
except IndexError as ex:
|
||||
logging.warning("Not enough ground spawn slots available at " + str(ex))
|
||||
if not is_large and len(self.ground_spawns_roadbase[cp]) > 0:
|
||||
ground_spawn = self.ground_spawns_roadbase[cp].pop()
|
||||
is_roadbase = True
|
||||
elif not is_large and len(self.ground_spawns[cp]) > 0:
|
||||
ground_spawn = self.ground_spawns[cp].pop()
|
||||
is_airbase = True
|
||||
elif len(self.ground_spawns_large[cp]) > 0:
|
||||
ground_spawn = self.ground_spawns_large[cp].pop()
|
||||
is_airbase = True
|
||||
|
||||
if ground_spawn is None:
|
||||
logging.warning("Not enough ground spawn slots available at " + cp.name)
|
||||
return None
|
||||
|
||||
group = self._generate_at_group(name, ground_spawn[0])
|
||||
@@ -581,14 +580,12 @@ class FlightGroupSpawner:
|
||||
for i in range(self.flight.count - 1):
|
||||
try:
|
||||
terrain = cp.coalition.game.theater.terrain
|
||||
if is_large:
|
||||
if len(self.ground_spawns_large[cp]) > 0:
|
||||
ground_spawn = self.ground_spawns_large[cp].pop()
|
||||
else:
|
||||
if len(self.ground_spawns_roadbase[cp]) > 0:
|
||||
ground_spawn = self.ground_spawns_roadbase[cp].pop()
|
||||
else:
|
||||
ground_spawn = self.ground_spawns[cp].pop()
|
||||
if not is_large and len(self.ground_spawns_roadbase[cp]) > 0:
|
||||
ground_spawn = self.ground_spawns_roadbase[cp].pop()
|
||||
elif not is_large and len(self.ground_spawns[cp]) > 0:
|
||||
ground_spawn = self.ground_spawns[cp].pop()
|
||||
elif len(self.ground_spawns_large[cp]) > 0:
|
||||
ground_spawn = self.ground_spawns_large[cp].pop()
|
||||
group.units[1 + i].position = Point(
|
||||
ground_spawn[0].x, ground_spawn[0].y, terrain=terrain
|
||||
)
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
from dcs.point import MovingPoint
|
||||
from dcs.task import (
|
||||
OptECMUsing,
|
||||
ControlledTask,
|
||||
Targets,
|
||||
EngageTargetsInZone,
|
||||
)
|
||||
|
||||
from game.utils import nautical_miles
|
||||
from .pydcswaypointbuilder import PydcsWaypointBuilder
|
||||
|
||||
|
||||
class ArmedReconIngressBuilder(PydcsWaypointBuilder):
|
||||
def add_tasks(self, waypoint: MovingPoint) -> None:
|
||||
self.register_special_ingress_points()
|
||||
# Preemptively use ECM to better avoid getting swatted.
|
||||
ecm_option = OptECMUsing(value=OptECMUsing.Values.UseIfDetectedLockByRadar)
|
||||
waypoint.tasks.append(ecm_option)
|
||||
|
||||
waypoint.add_task(
|
||||
ControlledTask(
|
||||
EngageTargetsInZone(
|
||||
position=self.flight.flight_plan.tot_waypoint.position,
|
||||
radius=int(
|
||||
nautical_miles(
|
||||
self.flight.coalition.game.settings.armed_recon_engagement_range_distance
|
||||
).meters
|
||||
),
|
||||
targets=[
|
||||
Targets.All.GroundUnits,
|
||||
Targets.All.Air.Helicopters,
|
||||
],
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -17,7 +17,7 @@ class HoldPointBuilder(PydcsWaypointBuilder):
|
||||
loiter = ControlledTask(
|
||||
OrbitAction(
|
||||
altitude=waypoint.alt,
|
||||
speed=speed.meters_per_second,
|
||||
speed=speed.kph,
|
||||
pattern=OrbitAction.OrbitPattern.Circle,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -8,7 +8,6 @@ from dcs.task import (
|
||||
OptECMUsing,
|
||||
OptFormation,
|
||||
Targets,
|
||||
OptROE,
|
||||
SetUnlimitedFuelCommand,
|
||||
)
|
||||
|
||||
@@ -94,12 +93,6 @@ class JoinPointBuilder(PydcsWaypointBuilder):
|
||||
max_dist: float = 30.0,
|
||||
vertical_spacing: float = 2000.0,
|
||||
) -> None:
|
||||
if self.flight.is_helo:
|
||||
# Make helicopters a bit more aggressive
|
||||
waypoint.tasks.append(OptROE(value=OptROE.Values.OpenFireWeaponFree))
|
||||
else:
|
||||
waypoint.tasks.append(OptROE(value=OptROE.Values.OpenFire))
|
||||
|
||||
rx = (random.random() + 0.1) * 333
|
||||
ry = feet(vertical_spacing).meters
|
||||
rz = (random.random() + 0.1) * 166 * random.choice([-1, 1])
|
||||
|
||||
@@ -3,7 +3,7 @@ import logging
|
||||
from dcs.point import MovingPoint
|
||||
from dcs.task import EngageTargetsInZone, Targets
|
||||
|
||||
from game.theater import Airfield
|
||||
from game.theater import Airfield, Fob
|
||||
from game.utils import nautical_miles
|
||||
from .pydcswaypointbuilder import PydcsWaypointBuilder
|
||||
|
||||
@@ -12,7 +12,7 @@ class OcaAircraftIngressBuilder(PydcsWaypointBuilder):
|
||||
def add_tasks(self, waypoint: MovingPoint) -> None:
|
||||
target = self.package.target
|
||||
self.register_special_ingress_points()
|
||||
if not isinstance(target, Airfield):
|
||||
if not (isinstance(target, Airfield) or isinstance(target, Fob)):
|
||||
logging.error(
|
||||
"Unexpected target type for OCA Strike mission: %s",
|
||||
target.__class__.__name__,
|
||||
|
||||
@@ -2,9 +2,8 @@ from dcs.point import MovingPoint
|
||||
from dcs.task import (
|
||||
OptECMUsing,
|
||||
ControlledTask,
|
||||
EngageTargets,
|
||||
Targets,
|
||||
OptROE,
|
||||
EngageTargetsInZone,
|
||||
)
|
||||
|
||||
from game.utils import nautical_miles
|
||||
@@ -14,16 +13,15 @@ from .pydcswaypointbuilder import PydcsWaypointBuilder
|
||||
class SeadSweepIngressBuilder(PydcsWaypointBuilder):
|
||||
def add_tasks(self, waypoint: MovingPoint) -> None:
|
||||
self.register_special_ingress_points()
|
||||
waypoint.tasks.append(OptROE(value=OptROE.Values.OpenFireWeaponFree))
|
||||
# Preemptively use ECM to better avoid getting swatted.
|
||||
ecm_option = OptECMUsing(value=OptECMUsing.Values.UseIfDetectedLockByRadar)
|
||||
waypoint.tasks.append(ecm_option)
|
||||
|
||||
waypoint.add_task(
|
||||
ControlledTask(
|
||||
EngageTargets(
|
||||
# TODO: From doctrine.
|
||||
max_distance=int(
|
||||
EngageTargetsInZone(
|
||||
position=self.flight.flight_plan.tot_waypoint.position,
|
||||
radius=int(
|
||||
nautical_miles(
|
||||
self.flight.coalition.game.settings.sead_sweep_engagement_range_distance
|
||||
).meters
|
||||
|
||||
@@ -22,6 +22,7 @@ from game.settings import Settings
|
||||
from game.utils import pairwise
|
||||
from .airassaultingress import AirAssaultIngressBuilder
|
||||
from .antishipingress import AntiShipIngressBuilder
|
||||
from .armedreconingress import ArmedReconIngressBuilder
|
||||
from .baiingress import BaiIngressBuilder
|
||||
from .casingress import CasIngressBuilder
|
||||
from .deadingress import DeadIngressBuilder
|
||||
@@ -136,6 +137,7 @@ class WaypointGenerator:
|
||||
FlightWaypointType.DROPOFF_ZONE: LandingZoneBuilder,
|
||||
FlightWaypointType.INGRESS_AIR_ASSAULT: AirAssaultIngressBuilder,
|
||||
FlightWaypointType.INGRESS_ANTI_SHIP: AntiShipIngressBuilder,
|
||||
FlightWaypointType.INGRESS_ARMED_RECON: ArmedReconIngressBuilder,
|
||||
FlightWaypointType.INGRESS_BAI: BaiIngressBuilder,
|
||||
FlightWaypointType.INGRESS_CAS: CasIngressBuilder,
|
||||
FlightWaypointType.INGRESS_DEAD: DeadIngressBuilder,
|
||||
@@ -203,7 +205,10 @@ class WaypointGenerator:
|
||||
not self.flight.state.in_flight
|
||||
and self.flight.state.spawn_type is not StartType.RUNWAY
|
||||
and self.flight.departure.is_fleet
|
||||
and not self.flight.client_count
|
||||
and not (
|
||||
self.flight.client_count
|
||||
and self.flight.coalition.game.settings.player_flights_sixpack
|
||||
)
|
||||
):
|
||||
# https://github.com/dcs-liberation/dcs_liberation/issues/1309
|
||||
# Without a delay, AI aircraft will be spawned on the sixpack, which other
|
||||
|
||||
Reference in New Issue
Block a user