mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
Fix several cases of wrongly using broken runways.
The usual symptom here was the game breaking when a carrier is destroyed. The carrier would no longer be operational but missions would be assigned there that could not generate flight plans.
This commit is contained in:
parent
f6909d2f98
commit
355e6e1d15
@ -46,6 +46,7 @@ Saves from 2.5 are not compatible with 3.0.
|
|||||||
* **[Campaign]** Fixed bug where offshore strike locations were being used to spawn ship objectives.
|
* **[Campaign]** Fixed bug where offshore strike locations were being used to spawn ship objectives.
|
||||||
* **[Flight Planner]** AI strike flight plans now include the correct target actions for building groups.
|
* **[Flight Planner]** AI strike flight plans now include the correct target actions for building groups.
|
||||||
* **[Flight Planner]** AI BAI/DEAD/SEAD flights now have tasks to attack all groups at the target location, not just the primary group (for multi-group SAM sites).
|
* **[Flight Planner]** AI BAI/DEAD/SEAD flights now have tasks to attack all groups at the target location, not just the primary group (for multi-group SAM sites).
|
||||||
|
* **[Flight Planner]** Fixed some contexts where damaged runways would be used. Destroying a carrier will no longer break the game.
|
||||||
|
|
||||||
# 2.5.1
|
# 2.5.1
|
||||||
|
|
||||||
|
|||||||
@ -258,11 +258,9 @@ class ProcurementAi:
|
|||||||
) -> Iterator[ControlPoint]:
|
) -> Iterator[ControlPoint]:
|
||||||
distance_cache = ObjectiveDistanceCache.get_closest_airfields(request.near)
|
distance_cache = ObjectiveDistanceCache.get_closest_airfields(request.near)
|
||||||
threatened = []
|
threatened = []
|
||||||
for cp in distance_cache.airfields_within(request.range):
|
for cp in distance_cache.operational_airfields_within(request.range):
|
||||||
if not cp.is_friendly(self.is_player):
|
if not cp.is_friendly(self.is_player):
|
||||||
continue
|
continue
|
||||||
if not cp.runway_is_operational():
|
|
||||||
continue
|
|
||||||
if cp.unclaimed_parking(self.game) < request.number:
|
if cp.unclaimed_parking(self.game) < request.number:
|
||||||
continue
|
continue
|
||||||
if self.threat_zones.threatened(cp.position):
|
if self.threat_zones.threatened(cp.position):
|
||||||
|
|||||||
@ -517,7 +517,7 @@ class ControlPoint(MissionTarget, ABC):
|
|||||||
max_retreat_distance = nautical_miles(200)
|
max_retreat_distance = nautical_miles(200)
|
||||||
# Skip the first airbase because that's the airbase we're retreating
|
# Skip the first airbase because that's the airbase we're retreating
|
||||||
# from.
|
# from.
|
||||||
airfields = list(closest.airfields_within(max_retreat_distance))[1:]
|
airfields = list(closest.operational_airfields_within(max_retreat_distance))[1:]
|
||||||
for airbase in airfields:
|
for airbase in airfields:
|
||||||
if not airbase.can_operate(airframe):
|
if not airbase.can_operate(airframe):
|
||||||
continue
|
continue
|
||||||
|
|||||||
@ -124,7 +124,7 @@ class ThreatZones:
|
|||||||
cls, location: ControlPoint, max_distance: Distance
|
cls, location: ControlPoint, max_distance: Distance
|
||||||
) -> Optional[ControlPoint]:
|
) -> Optional[ControlPoint]:
|
||||||
airfields = ObjectiveDistanceCache.get_closest_airfields(location)
|
airfields = ObjectiveDistanceCache.get_closest_airfields(location)
|
||||||
for airfield in airfields.airfields_within(max_distance):
|
for airfield in airfields.all_airfields_within(max_distance):
|
||||||
if airfield.captured != location.captured:
|
if airfield.captured != location.captured:
|
||||||
return airfield
|
return airfield
|
||||||
return None
|
return None
|
||||||
|
|||||||
@ -162,7 +162,7 @@ class AircraftAllocator:
|
|||||||
self, flight: ProposedFlight, task: FlightType
|
self, flight: ProposedFlight, task: FlightType
|
||||||
) -> Optional[Tuple[ControlPoint, Squadron]]:
|
) -> Optional[Tuple[ControlPoint, Squadron]]:
|
||||||
types = aircraft_for_task(task)
|
types = aircraft_for_task(task)
|
||||||
airfields_in_range = self.closest_airfields.airfields_within(
|
airfields_in_range = self.closest_airfields.operational_airfields_within(
|
||||||
flight.max_distance
|
flight.max_distance
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -258,7 +258,9 @@ class PackageBuilder:
|
|||||||
self, aircraft: Type[FlyingType], arrival: ControlPoint
|
self, aircraft: Type[FlyingType], arrival: ControlPoint
|
||||||
) -> Optional[ControlPoint]:
|
) -> Optional[ControlPoint]:
|
||||||
divert_limit = nautical_miles(150)
|
divert_limit = nautical_miles(150)
|
||||||
for airfield in self.closest_airfields.airfields_within(divert_limit):
|
for airfield in self.closest_airfields.operational_airfields_within(
|
||||||
|
divert_limit
|
||||||
|
):
|
||||||
if airfield.captured != self.is_player:
|
if airfield.captured != self.is_player:
|
||||||
continue
|
continue
|
||||||
if airfield == arrival:
|
if airfield == arrival:
|
||||||
@ -467,8 +469,10 @@ class ObjectiveFinder:
|
|||||||
# Off-map spawn locations don't need protection.
|
# Off-map spawn locations don't need protection.
|
||||||
continue
|
continue
|
||||||
airfields_in_proximity = self.closest_airfields_to(cp)
|
airfields_in_proximity = self.closest_airfields_to(cp)
|
||||||
airfields_in_threat_range = airfields_in_proximity.airfields_within(
|
airfields_in_threat_range = (
|
||||||
self.AIRFIELD_THREAT_RANGE
|
airfields_in_proximity.operational_airfields_within(
|
||||||
|
self.AIRFIELD_THREAT_RANGE
|
||||||
|
)
|
||||||
)
|
)
|
||||||
for airfield in airfields_in_threat_range:
|
for airfield in airfields_in_threat_range:
|
||||||
if not airfield.is_friendly(self.is_player):
|
if not airfield.is_friendly(self.is_player):
|
||||||
|
|||||||
@ -27,17 +27,35 @@ class ClosestAirfields:
|
|||||||
def operational_airfields(self) -> Iterator[ControlPoint]:
|
def operational_airfields(self) -> Iterator[ControlPoint]:
|
||||||
return (c for c in self.closest_airfields if c.runway_is_operational())
|
return (c for c in self.closest_airfields if c.runway_is_operational())
|
||||||
|
|
||||||
def airfields_within(self, distance: Distance) -> Iterator[ControlPoint]:
|
def _airfields_within(
|
||||||
|
self, distance: Distance, operational: bool
|
||||||
|
) -> Iterator[ControlPoint]:
|
||||||
|
airfields = (
|
||||||
|
self.operational_airfields if operational else self.closest_airfields
|
||||||
|
)
|
||||||
|
for cp in airfields:
|
||||||
|
if cp.distance_to(self.target) < distance.meters:
|
||||||
|
yield cp
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
def operational_airfields_within(
|
||||||
|
self, distance: Distance
|
||||||
|
) -> Iterator[ControlPoint]:
|
||||||
"""Iterates over all airfields within the given range of the target.
|
"""Iterates over all airfields within the given range of the target.
|
||||||
|
|
||||||
Note that this iterates over *all* airfields, not just friendly
|
Note that this iterates over *all* airfields, not just friendly
|
||||||
airfields.
|
airfields.
|
||||||
"""
|
"""
|
||||||
for cp in self.closest_airfields:
|
return self._airfields_within(distance, operational=True)
|
||||||
if cp.distance_to(self.target) < distance.meters:
|
|
||||||
yield cp
|
def all_airfields_within(self, distance: Distance) -> Iterator[ControlPoint]:
|
||||||
else:
|
"""Iterates over all airfields within the given range of the target.
|
||||||
break
|
|
||||||
|
Note that this iterates over *all* airfields, not just friendly
|
||||||
|
airfields.
|
||||||
|
"""
|
||||||
|
return self._airfields_within(distance, operational=False)
|
||||||
|
|
||||||
|
|
||||||
class ObjectiveDistanceCache:
|
class ObjectiveDistanceCache:
|
||||||
|
|||||||
@ -1807,7 +1807,7 @@ class FlightPlanBuilder:
|
|||||||
# We'll always have a package, but if this is being planned via the UI
|
# We'll always have a package, but if this is being planned via the UI
|
||||||
# it could be the first flight in the package.
|
# it could be the first flight in the package.
|
||||||
if not self.package.flights:
|
if not self.package.flights:
|
||||||
raise RuntimeError(
|
raise PlanningError(
|
||||||
"Cannot determine source airfield for package with no flights"
|
"Cannot determine source airfield for package with no flights"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1819,4 +1819,4 @@ class FlightPlanBuilder:
|
|||||||
for flight in self.package.flights:
|
for flight in self.package.flights:
|
||||||
if flight.departure == airfield:
|
if flight.departure == airfield:
|
||||||
return airfield
|
return airfield
|
||||||
raise RuntimeError("Could not find any airfield assigned to this package")
|
raise PlanningError("Could not find any airfield assigned to this package")
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user