diff --git a/changelog.md b/changelog.md index e46f2529..9f36ec2e 100644 --- a/changelog.md +++ b/changelog.md @@ -8,6 +8,7 @@ Saves from 5.x are not compatible with 6.0. * **[Campaign]** Add option to manually add and remove squadrons and different aircraft type in the new game wizard / air wing configuration dialog. * **[Mission Generation]** Added an option to fast-forward mission generation until the point of first contact (WIP). * **[Mission Generation]** Add Option to enforce the Easy Communication setting for the mission +* **[Mission Generation]** Added performance option to not cull IADS when culling would effect how mission is played at target area. * **[Flight Planning]** Added preset formations for different flight types at hold, join, ingress, and split waypoints. Air to Air flights will tend toward line-abreast and spread-four formations. Air to ground flights will tend towards trail formation. * **[Flight Planning]** Added the ability to plan tankers for recovery on package flights. AI does not plan. * **[Flight Planning]** Air to Ground flights now have ECM enabled on lock at the join point, and SEAD/DEAD also have ECM enabled on detection and lock at ingress. diff --git a/game/game.py b/game/game.py index 270542cf..93520b8a 100644 --- a/game/game.py +++ b/game/game.py @@ -6,7 +6,7 @@ import math from collections.abc import Iterator from datetime import date, datetime, timedelta from enum import Enum -from typing import Any, List, TYPE_CHECKING, Type, Union, cast +from typing import Any, List, TYPE_CHECKING, Type, TypeVar, Union, cast from dcs.countries import Switzerland, USAFAggressors, UnitedNationsPeacekeepers from dcs.country import Country @@ -17,6 +17,7 @@ from faker import Faker from game.models.game_stats import GameStats from game.plugins import LuaPluginManager +from game.utils import Distance from gen import naming from gen.flights.closestairfields import ObjectiveDistanceCache from gen.ground_forces.ai_ground_planner import GroundPlanner @@ -30,13 +31,15 @@ from .profiling import logged_duration from .settings import Settings from .theater import ConflictTheater from .theater.bullseye import Bullseye +from .theater.theatergroundobject import ( + EwrGroundObject, + SamGroundObject, + TheaterGroundObject, +) from .theater.transitnetwork import TransitNetwork, TransitNetworkBuilder from .weather import Conditions, TimeOfDay if TYPE_CHECKING: - from game.missiongenerator.frontlineconflictdescription import ( - FrontLineConflictDescription, - ) from .ato.airtaaskingorder import AirTaskingOrder from .navmesh import NavMesh from .squadrons import AirWing @@ -493,6 +496,30 @@ class Game: return False return True + def iads_considerate_culling(self, tgo: TheaterGroundObject[Any]) -> bool: + if not self.settings.perf_do_not_cull_threatening_iads: + return self.position_culled(tgo.position) + else: + if self.settings.perf_culling: + if isinstance(tgo, EwrGroundObject): + max_detection_range = tgo.max_detection_range().meters + for z in self.__culling_zones: + seperation = z.distance_to_point(tgo.position) + # Don't cull EWR if in detection range. + if seperation < max_detection_range: + return False + if isinstance(tgo, SamGroundObject): + max_threat_range = tgo.max_threat_range().meters + for z in self.__culling_zones: + seperation = z.distance_to_point(tgo.position) + # Create a 12nm buffer around nearby SAMs. + respect_bubble = ( + max_threat_range + Distance.from_nautical_miles(12).meters + ) + if seperation < respect_bubble: + return False + return self.position_culled(tgo.position) + def get_culling_zones(self) -> list[Point]: """ Check culling points diff --git a/game/missiongenerator/tgogenerator.py b/game/missiongenerator/tgogenerator.py index cd54ae34..2f35a087 100644 --- a/game/missiongenerator/tgogenerator.py +++ b/game/missiongenerator/tgogenerator.py @@ -95,7 +95,7 @@ class GenericGroundObjectGenerator(Generic[TgoT]): @property def culled(self) -> bool: - return self.game.position_culled(self.ground_object.position) + return self.game.iads_considerate_culling(self.ground_object) def generate(self) -> None: if self.culled: diff --git a/game/settings/settings.py b/game/settings/settings.py index f33e665e..2fba3762 100644 --- a/game/settings/settings.py +++ b/game/settings/settings.py @@ -450,6 +450,12 @@ class Settings: max=10000, causes_expensive_game_update=True, ) + perf_do_not_cull_threatening_iads: bool = boolean_option( + "Do not cull threatening IADS", + page=MISSION_GENERATOR_PAGE, + section=PERFORMANCE_SECTION, + default=True, + ) perf_do_not_cull_carrier: bool = boolean_option( "Do not cull carrier's surroundings", page=MISSION_GENERATOR_PAGE,