mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Improve AI strike targeting.
We were setting up all the correct *target* waypoints but the AI doesn't use the target waypoints; they use the targets property of the ingress waypoint. This meant that the flight plan looked correct in the UI and was correct for players but the tasks were set up incorrectly for the AI because building TGOs are aggravatingly multiple TGOs with the same name in the implementation. Mission targets now enumerate their own strike targets so that this mistake is harder to make in the future. This won't be perfect, the AI is still not able to parallelize tasks and since buildings aren't groups they can only attack one structure at a time, but they'll now at least switch to the next target after hitting the first one. As a bonus, stop bombing the dead buildings. Fixes https://github.com/dcs-liberation/dcs_liberation/issues/235 Fixes https://github.com/dcs-liberation/dcs_liberation/issues/244
This commit is contained in:
parent
04ebe4c68a
commit
2a77f57aa4
@ -10,6 +10,7 @@ Saves from 2.5 are not compatible with 3.0.
|
||||
* **[Campaign AI]** Every 30 minutes the AI will plan a CAP, so players can customize their mission better.
|
||||
* **[Campaign AI]** AI now considers Ju-88s for CAS, strike, and DEAD missions.
|
||||
* **[Campaign AI]** Fix purchase of aircraft by priority (the faction's list was being used as the priority list rather than the game's).
|
||||
* **[Flight Planner]** AI strike flight plans now include the correct target actions for building groups.
|
||||
* **[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.
|
||||
* **[UI]** DCS loadouts are now selectable in the loadout setup menu.
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
from __future__ import annotations
|
||||
from game.scenery_group import SceneryGroup
|
||||
|
||||
import heapq
|
||||
import itertools
|
||||
@ -9,7 +8,7 @@ from abc import ABC, abstractmethod
|
||||
from dataclasses import dataclass, field
|
||||
from enum import Enum
|
||||
from functools import total_ordering
|
||||
from typing import Any, Dict, Iterator, List, Optional, Set, TYPE_CHECKING, Type
|
||||
from typing import Any, Dict, Iterator, List, Optional, Set, TYPE_CHECKING, Type, Union
|
||||
|
||||
from dcs.mapping import Point
|
||||
from dcs.ships import (
|
||||
@ -19,10 +18,12 @@ from dcs.ships import (
|
||||
Type_071_Amphibious_Transport_Dock,
|
||||
)
|
||||
from dcs.terrain.terrain import Airport, ParkingSlot
|
||||
from dcs.unit import Unit
|
||||
from dcs.unittype import FlyingType
|
||||
|
||||
from game import db
|
||||
from game.point_with_heading import PointWithHeading
|
||||
from game.scenery_group import SceneryGroup
|
||||
from gen.flights.closestairfields import ObjectiveDistanceCache
|
||||
from gen.ground_forces.ai_ground_planner_db import TYPE_SHORAD
|
||||
from gen.ground_forces.combat_stance import CombatStance
|
||||
@ -781,6 +782,10 @@ class ControlPoint(MissionTarget, ABC):
|
||||
|
||||
return self.captured != other.captured
|
||||
|
||||
@property
|
||||
def strike_targets(self) -> List[Union[MissionTarget, Unit]]:
|
||||
return []
|
||||
|
||||
|
||||
class Airfield(ControlPoint):
|
||||
def __init__(
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Iterator, TYPE_CHECKING
|
||||
from typing import Iterator, TYPE_CHECKING, List, Union
|
||||
|
||||
from dcs.mapping import Point
|
||||
from dcs.unit import Unit
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from gen.flights.flight import FlightType
|
||||
@ -42,3 +43,7 @@ class MissionTarget:
|
||||
# TODO: FlightType.EWAR,
|
||||
# TODO: FlightType.RECON,
|
||||
]
|
||||
|
||||
@property
|
||||
def strike_targets(self) -> List[Union[MissionTarget, Unit]]:
|
||||
raise NotImplementedError
|
||||
|
||||
@ -2,7 +2,7 @@ from __future__ import annotations
|
||||
|
||||
import itertools
|
||||
import logging
|
||||
from typing import Iterator, List, TYPE_CHECKING
|
||||
from typing import Iterator, List, TYPE_CHECKING, Union
|
||||
|
||||
from dcs.mapping import Point
|
||||
from dcs.triggers import TriggerZone
|
||||
@ -185,6 +185,10 @@ class TheaterGroundObject(MissionTarget):
|
||||
"""True if this TGO is the group for the control point itself (CVs and FOBs)."""
|
||||
return False
|
||||
|
||||
@property
|
||||
def strike_targets(self) -> List[Union[MissionTarget, Unit]]:
|
||||
return self.units
|
||||
|
||||
|
||||
class BuildingGroundObject(TheaterGroundObject):
|
||||
def __init__(
|
||||
@ -233,6 +237,15 @@ class BuildingGroundObject(TheaterGroundObject):
|
||||
def kill(self) -> None:
|
||||
self._dead = True
|
||||
|
||||
def iter_building_group(self) -> Iterator[TheaterGroundObject]:
|
||||
for tgo in self.control_point.ground_objects:
|
||||
if tgo.obj_name == self.obj_name and not tgo.is_dead:
|
||||
yield tgo
|
||||
|
||||
@property
|
||||
def strike_targets(self) -> List[Union[MissionTarget, Unit]]:
|
||||
return list(self.iter_building_group())
|
||||
|
||||
|
||||
class SceneryGroundObject(BuildingGroundObject):
|
||||
def __init__(
|
||||
|
||||
@ -5,7 +5,7 @@ import random
|
||||
from dataclasses import dataclass
|
||||
from datetime import timedelta
|
||||
from functools import cached_property
|
||||
from typing import Dict, List, Optional, TYPE_CHECKING, Type, Union
|
||||
from typing import Dict, List, Optional, TYPE_CHECKING, Type, Union, Iterable
|
||||
|
||||
from dcs import helicopters
|
||||
from dcs.action import AITaskPush, ActivateGroup
|
||||
@ -70,6 +70,7 @@ from dcs.task import (
|
||||
)
|
||||
from dcs.terrain.terrain import Airport, NoParkingSlotError
|
||||
from dcs.triggers import Event, TriggerOnce, TriggerRule
|
||||
from dcs.unit import Unit
|
||||
from dcs.unitgroup import FlyingGroup, ShipGroup, StaticGroup
|
||||
from dcs.unittype import FlyingType, UnitType
|
||||
|
||||
@ -85,6 +86,7 @@ from game.theater.controlpoint import (
|
||||
NavalControlPoint,
|
||||
OffMapSpawn,
|
||||
)
|
||||
from game.theater.missiontarget import MissionTarget
|
||||
from game.theater.theatergroundobject import TheaterGroundObject
|
||||
from game.transfers import MultiGroupTransport
|
||||
from game.unitmap import UnitMap
|
||||
@ -1629,7 +1631,9 @@ class PydcsWaypointBuilder:
|
||||
else:
|
||||
return False
|
||||
|
||||
def register_special_waypoints(self, targets) -> None:
|
||||
def register_special_waypoints(
|
||||
self, targets: Iterable[Union[MissionTarget, Unit]]
|
||||
) -> None:
|
||||
"""Create special target waypoints for various aircraft"""
|
||||
for i, t in enumerate(targets):
|
||||
if self.group.units[0].unit_type == JF_17 and i < 4:
|
||||
@ -1850,29 +1854,16 @@ class StrikeIngressBuilder(PydcsWaypointBuilder):
|
||||
def build_strike(self) -> MovingPoint:
|
||||
waypoint = super().build()
|
||||
for target in self.waypoint.targets:
|
||||
bombing = Bombing(target.position)
|
||||
# If there is only one target, drop all ordnance in one pass.
|
||||
if len(self.waypoint.targets) == 1:
|
||||
bombing.params["expend"] = "All"
|
||||
bombing.params["weaponType"] = WeaponType.Auto.value
|
||||
bombing.params["groupAttack"] = True
|
||||
waypoint.tasks.append(bombing)
|
||||
|
||||
targets = [target]
|
||||
# If the target type is a group of units,
|
||||
# then target each unit in the group with a Bombing task on their position
|
||||
# (It is not perfect, we should have an engage Group task instead,
|
||||
# but we don't have the group ref in the model there)
|
||||
# TODO : for building group, engage all the buildings as well
|
||||
if isinstance(target, TheaterGroundObject):
|
||||
if len(target.units) > 0:
|
||||
targets = target.units
|
||||
|
||||
for t in targets:
|
||||
bombing = Bombing(t.position)
|
||||
# If there is only one target, drop all ordnance in one pass
|
||||
if len(self.waypoint.targets) == 1 and len(targets) == 1:
|
||||
bombing.params["expend"] = "All"
|
||||
bombing.params["weaponType"] = WeaponType.Auto.value
|
||||
bombing.params["groupAttack"] = True
|
||||
waypoint.tasks.append(bombing)
|
||||
print(bombing)
|
||||
|
||||
# Register special waypoints
|
||||
self.register_special_waypoints(targets)
|
||||
# Register special waypoints
|
||||
self.register_special_waypoints(self.waypoint.targets)
|
||||
return waypoint
|
||||
|
||||
|
||||
|
||||
@ -2,10 +2,11 @@ from __future__ import annotations
|
||||
|
||||
from datetime import timedelta
|
||||
from enum import Enum
|
||||
from typing import List, Optional, TYPE_CHECKING, Type
|
||||
from typing import List, Optional, TYPE_CHECKING, Type, Union
|
||||
|
||||
from dcs.mapping import Point
|
||||
from dcs.point import MovingPoint, PointAction
|
||||
from dcs.unit import Unit
|
||||
from dcs.unittype import FlyingType
|
||||
|
||||
from game import db
|
||||
@ -107,7 +108,7 @@ class FlightWaypoint:
|
||||
# Only used in the waypoint list in the flight edit page. No sense
|
||||
# having three names. A short and long form is enough.
|
||||
self.description = ""
|
||||
self.targets: List[MissionTarget] = []
|
||||
self.targets: List[Union[MissionTarget, Unit]] = []
|
||||
self.obj_name = ""
|
||||
self.pretty_name = ""
|
||||
self.only_for_player = False
|
||||
|
||||
@ -202,8 +202,7 @@ class WaypointBuilder:
|
||||
waypoint.pretty_name = "INGRESS on " + objective.name
|
||||
waypoint.description = "INGRESS on " + objective.name
|
||||
waypoint.name = "INGRESS"
|
||||
# TODO: This seems wrong, but it's what was there before.
|
||||
waypoint.targets.append(objective)
|
||||
waypoint.targets = objective.strike_targets
|
||||
return waypoint
|
||||
|
||||
def egress(self, position: Point, target: MissionTarget) -> FlightWaypoint:
|
||||
|
||||
@ -26,7 +26,7 @@ import datetime
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Optional, TYPE_CHECKING, Tuple
|
||||
from typing import Dict, List, Optional, TYPE_CHECKING, Tuple, Iterator
|
||||
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
from dcs.mission import Mission
|
||||
@ -38,7 +38,7 @@ from game.utils import meters
|
||||
from .aircraft import AIRCRAFT_DATA, FlightData
|
||||
from .airsupportgen import AwacsInfo, TankerInfo
|
||||
from .briefinggen import CommInfo, JtacInfo, MissionInfoGenerator
|
||||
from .flights.flight import FlightWaypoint, FlightWaypointType
|
||||
from .flights.flight import FlightWaypoint, FlightWaypointType, FlightType
|
||||
from .radios import RadioFrequency
|
||||
from .runways import RunwayData
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user