Empty gun for AI missions that do not need a gun.

There is no "all but gun" RTB winchester option, so air to ground
missions with mixed weapon types will insist on using all of their
bullets after running out of missiles and bombs. Take away their bullets
so they don't strafe a Tor.

Exceptions are made for player flights and for airframes where the gun
is essential like the A-10 or warbirds.
This commit is contained in:
Dan Albert 2021-05-22 16:14:20 -07:00
parent a789f58068
commit 69299d395c
3 changed files with 80 additions and 5 deletions

View File

@ -14,6 +14,7 @@ Saves from 2.5 are not compatible with 3.0.
* **[Flight Planner]** AI strike flight plans now include the correct target actions for building groups.
* **[Flight Planner]** Flight plans now include bullseye waypoints.
* **[Flight Planner]** Differentiated SEAD and SEAD escort. SEAD is tasked with suppressing the package target, SEAD escort is tasked with protecting the package from all SAMs along its route.
* **[Payloads]** AI flights for most air to ground mission types (CAS excluded) will have their guns emptied to prevent strafing fully armed and operational battle stations. Gun-reliant airframes like A-10s and warbirds will keep their bullets.
* **[Kneeboard]** ATC table overflow alleviated by wrapping long airfield names and splitting ATC frequency and channel into separate rows.
* **[UI]** Added new web based map UI. This is mostly functional but many of the old display options are a WIP. Revert to the old map with --old-map.
* **[UI]** Campaigns generated for an older or newer version of the game will now be marked as incompatible. They can still be played, but bugs may be present.

View File

@ -1603,3 +1603,39 @@ F_16C_50.Liveries = DefaultLiveries
P_51D_30_NA.Liveries = DefaultLiveries
Ju_88A4.Liveries = DefaultLiveries
B_17G.Liveries = DefaultLiveries
# List of airframes that rely on their gun as a primary weapon. We confiscate bullets
# from most AI air-to-ground missions since they aren't smart enough to RTB when they're
# out of everything other than bullets (DCS does not have an all-but-gun winchester
# option) and we don't want to be attacking fully functional Tors with a Vulcan.
#
# These airframes are the exceptions. They probably should be using their gun regardless
# of the mission type.
GUN_RELIANT_AIRFRAMES: List[Type[FlyingType]] = [
AH_1W,
AH_64A,
AH_64D,
A_10A,
A_10C,
A_10C_2,
A_20G,
Bf_109K_4,
FW_190A8,
FW_190D9,
F_86F_Sabre,
Ju_88A4,
Ka_50,
MiG_15bis,
MiG_19P,
Mi_24V,
Mi_28N,
P_47D_30,
P_47D_30bl1,
P_47D_40,
P_51D,
P_51D_30_NA,
SpitfireLFMkIX,
SpitfireLFMkIXCW,
Su_25,
Su_25T,
]

View File

@ -62,7 +62,6 @@ from dcs.task import (
OptRestrictJettison,
OrbitAction,
RunwayAttack,
SEAD,
StartCommand,
Targets,
Transport,
@ -78,6 +77,7 @@ from dcs.unittype import FlyingType, UnitType
from game import db
from game.data.cap_capabilities_db import GUNFIGHTERS
from game.data.weapons import Pylon
from game.db import GUN_RELIANT_AIRFRAMES
from game.factions.faction import Faction
from game.settings import Settings
from game.theater.controlpoint import (
@ -1155,12 +1155,23 @@ class AircraftConflictGenerator:
raise RuntimeError(f"No reduced fuel case for type {unit_type}")
@staticmethod
def flight_always_keeps_gun(flight: Flight) -> bool:
# Never take bullets from players. They're smart enough to know when to use it
# and when to RTB.
if flight.client_count > 0:
return True
return flight.unit_type in GUN_RELIANT_AIRFRAMES
def configure_behavior(
self,
flight: Flight,
group: FlyingGroup,
react_on_threat: Optional[OptReactOnThreat.Values] = None,
roe: Optional[OptROE.Values] = None,
rtb_winchester: Optional[OptRTBOnOutOfAmmo.Values] = None,
restrict_jettison: Optional[bool] = None,
mission_uses_gun: bool = True,
) -> None:
group.points[0].tasks.clear()
if react_on_threat is not None:
@ -1172,6 +1183,17 @@ class AircraftConflictGenerator:
if rtb_winchester is not None:
group.points[0].tasks.append(OptRTBOnOutOfAmmo(rtb_winchester))
# Confiscate the bullets of AI missions that do not rely on the gun. There is no
# "all but gun" RTB winchester option, so air to ground missions with mixed
# weapon types will insist on using all of their bullets after running out of
# missiles and bombs. Take away their bullets so they don't strafe a Tor.
#
# Exceptions are made for player flights and for airframes where the gun is
# essential like the A-10 or warbirds.
if not mission_uses_gun and not self.flight_always_keeps_gun(flight):
for unit in group.units:
unit.gun = 0
group.points[0].tasks.append(OptRTBOnBingoFuel(True))
# Do not restrict afterburner.
# https://forums.eagle.ru/forum/english/digital-combat-simulator/dcs-world-2-5/bugs-and-problems-ai/ai-ad/7121294-ai-stuck-at-high-aoa-after-making-sharp-turn-if-afterburner-is-restricted
@ -1197,7 +1219,7 @@ class AircraftConflictGenerator:
else:
ammo_type = OptRTBOnOutOfAmmo.Values.Cannon
self.configure_behavior(group, rtb_winchester=ammo_type)
self.configure_behavior(flight, group, rtb_winchester=ammo_type)
def configure_sweep(
self,
@ -1214,7 +1236,7 @@ class AircraftConflictGenerator:
else:
ammo_type = OptRTBOnOutOfAmmo.Values.Cannon
self.configure_behavior(group, rtb_winchester=ammo_type)
self.configure_behavior(flight, group, rtb_winchester=ammo_type)
def configure_cas(
self,
@ -1226,6 +1248,7 @@ class AircraftConflictGenerator:
group.task = CAS.name
self._setup_group(group, package, flight, dynamic_runways)
self.configure_behavior(
flight,
group,
react_on_threat=OptReactOnThreat.Values.EvadeFire,
roe=OptROE.Values.OpenFire,
@ -1249,11 +1272,13 @@ class AircraftConflictGenerator:
group.task = CAS.name
self._setup_group(group, package, flight, dynamic_runways)
self.configure_behavior(
flight,
group,
react_on_threat=OptReactOnThreat.Values.EvadeFire,
roe=OptROE.Values.OpenFire,
rtb_winchester=OptRTBOnOutOfAmmo.Values.All,
restrict_jettison=True,
mission_uses_gun=False,
)
def configure_sead(
@ -1269,6 +1294,7 @@ class AircraftConflictGenerator:
group.task = CAS.name
self._setup_group(group, package, flight, dynamic_runways)
self.configure_behavior(
flight,
group,
react_on_threat=OptReactOnThreat.Values.EvadeFire,
roe=OptROE.Values.OpenFire,
@ -1276,6 +1302,7 @@ class AircraftConflictGenerator:
# weapons for SEAD).
rtb_winchester=OptRTBOnOutOfAmmo.Values.ASM,
restrict_jettison=True,
mission_uses_gun=False,
)
def configure_strike(
@ -1288,10 +1315,12 @@ class AircraftConflictGenerator:
group.task = GroundAttack.name
self._setup_group(group, package, flight, dynamic_runways)
self.configure_behavior(
flight,
group,
react_on_threat=OptReactOnThreat.Values.EvadeFire,
roe=OptROE.Values.OpenFire,
restrict_jettison=True,
mission_uses_gun=False,
)
def configure_anti_ship(
@ -1304,10 +1333,12 @@ class AircraftConflictGenerator:
group.task = AntishipStrike.name
self._setup_group(group, package, flight, dynamic_runways)
self.configure_behavior(
flight,
group,
react_on_threat=OptReactOnThreat.Values.EvadeFire,
roe=OptROE.Values.OpenFire,
restrict_jettison=True,
mission_uses_gun=False,
)
def configure_runway_attack(
@ -1320,10 +1351,12 @@ class AircraftConflictGenerator:
group.task = RunwayAttack.name
self._setup_group(group, package, flight, dynamic_runways)
self.configure_behavior(
flight,
group,
react_on_threat=OptReactOnThreat.Values.EvadeFire,
roe=OptROE.Values.OpenFire,
restrict_jettison=True,
mission_uses_gun=False,
)
def configure_oca_strike(
@ -1336,6 +1369,7 @@ class AircraftConflictGenerator:
group.task = CAS.name
self._setup_group(group, package, flight, dynamic_runways)
self.configure_behavior(
flight,
group,
react_on_threat=OptReactOnThreat.Values.EvadeFire,
roe=OptROE.Values.OpenFire,
@ -1361,6 +1395,7 @@ class AircraftConflictGenerator:
# Awacs task action
self.configure_behavior(
flight,
group,
react_on_threat=OptReactOnThreat.Values.EvadeFire,
roe=OptROE.Values.WeaponHold,
@ -1382,7 +1417,7 @@ class AircraftConflictGenerator:
group.task = CAP.name
self._setup_group(group, package, flight, dynamic_runways)
self.configure_behavior(
group, roe=OptROE.Values.OpenFire, restrict_jettison=True
flight, group, roe=OptROE.Values.OpenFire, restrict_jettison=True
)
def configure_sead_escort(
@ -1398,12 +1433,14 @@ class AircraftConflictGenerator:
group.task = CAS.name
self._setup_group(group, package, flight, dynamic_runways)
self.configure_behavior(
flight,
group,
roe=OptROE.Values.OpenFire,
# ASM includes ARMs and TALDs (among other things, but those are the useful
# weapons for SEAD).
rtb_winchester=OptRTBOnOutOfAmmo.Values.ASM,
restrict_jettison=True,
mission_uses_gun=False,
)
def configure_transport(
@ -1416,6 +1453,7 @@ class AircraftConflictGenerator:
group.task = Transport.name
self._setup_group(group, package, flight, dynamic_runways)
self.configure_behavior(
flight,
group,
react_on_threat=OptReactOnThreat.Values.EvadeFire,
roe=OptROE.Values.WeaponHold,
@ -1424,7 +1462,7 @@ class AircraftConflictGenerator:
def configure_unknown_task(self, group: FlyingGroup, flight: Flight) -> None:
logging.error(f"Unhandled flight type: {flight.flight_type}")
self.configure_behavior(group)
self.configure_behavior(flight, group)
def setup_flight_group(
self,