mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Settings doctrine page + streamlining (#156)
* Added a separate Doctrine page in settings with the following new options: - Minimum number of aircraft for autoplanner to plan OCA packages against - Airbase threat range (nmi) - TARCAP threat buffer distance (nmi) - AEW&C threat buffer distance (nmi) - Theater tanker threat buffer distance (nmi) Implemented handling for the OPFOR autoplanner aggressiveness in objectivefinder.py vulnerable_control_points(). * * Added three new options in Settings: - Autoplanner plans refueling flights for Strike packages - Autoplanner plans refueling flights for OCA packages - Autoplanner plans refueling flights for DEAD packages Fixed a bug in faction.py where F-16Ds were not correctly removed from the faction when the F-16I/F-16D mod was not selected. * Renamed Maximum frontline length -> Maximum frontline width.
This commit is contained in:
@@ -48,7 +48,9 @@ class Builder(IBuilder[AewcFlightPlan, PatrollingLayout]):
|
||||
orbit_heading = heading_to_threat_boundary
|
||||
|
||||
# Station 80nm outside the threat zone.
|
||||
threat_buffer = nautical_miles(80)
|
||||
threat_buffer = nautical_miles(
|
||||
self.flight.coalition.game.settings.aewc_threat_buffer_min_distance
|
||||
)
|
||||
if self.threat_zones.threatened(location.position):
|
||||
orbit_distance = distance_to_threat + threat_buffer
|
||||
else:
|
||||
|
||||
@@ -60,7 +60,9 @@ class CapBuilder(IBuilder[FlightPlanT, LayoutT], ABC):
|
||||
# distance from the nearest enemy airbase, but since they are by
|
||||
# definition in enemy territory they can't avoid the threat zone
|
||||
# without being useless.
|
||||
min_distance_from_enemy = nautical_miles(20)
|
||||
min_distance_from_enemy = nautical_miles(
|
||||
self.coalition.game.settings.tarcap_threat_buffer_min_distance
|
||||
)
|
||||
distance_to_airfield = meters(
|
||||
closest_airfield.position.distance_to_point(
|
||||
self.package.target.position
|
||||
|
||||
@@ -53,7 +53,7 @@ class CasFlightPlan(PatrollingFlightPlan[CasLayout], UiZoneDisplay):
|
||||
|
||||
@property
|
||||
def engagement_distance(self) -> Distance:
|
||||
max_length = self.flight.coalition.game.settings.max_frontline_length * 1000
|
||||
max_length = self.flight.coalition.game.settings.max_frontline_width * 1000
|
||||
return meters(max_length) / 2
|
||||
|
||||
@property
|
||||
|
||||
@@ -36,7 +36,9 @@ class Builder(IBuilder[TheaterRefuelingFlightPlan, PatrollingLayout]):
|
||||
orbit_heading = heading_to_threat_boundary
|
||||
|
||||
# Station 70nm outside the threat zone.
|
||||
threat_buffer = nautical_miles(70)
|
||||
threat_buffer = nautical_miles(
|
||||
self.flight.coalition.game.settings.tanker_threat_buffer_min_distance
|
||||
)
|
||||
if self.threat_zones.threatened(location.position):
|
||||
orbit_distance = distance_to_threat + threat_buffer
|
||||
else:
|
||||
|
||||
@@ -3,6 +3,7 @@ from __future__ import annotations
|
||||
import math
|
||||
import operator
|
||||
from collections.abc import Iterable, Iterator
|
||||
from random import randint
|
||||
from typing import TYPE_CHECKING, TypeVar
|
||||
|
||||
from game.ato.closestairfields import ClosestAirfields, ObjectiveDistanceCache
|
||||
@@ -33,10 +34,6 @@ MissionTargetType = TypeVar("MissionTargetType", bound=MissionTarget)
|
||||
class ObjectiveFinder:
|
||||
"""Identifies potential objectives for the mission planner."""
|
||||
|
||||
# TODO: Merge into doctrine.
|
||||
AIRFIELD_THREAT_RANGE = nautical_miles(150)
|
||||
SAM_THREAT_RANGE = nautical_miles(100)
|
||||
|
||||
def __init__(self, game: Game, is_player: bool) -> None:
|
||||
self.game = game
|
||||
self.is_player = is_player
|
||||
@@ -151,9 +148,18 @@ class ObjectiveFinder:
|
||||
# Off-map spawn locations don't need protection.
|
||||
continue
|
||||
airfields_in_proximity = self.closest_airfields_to(cp)
|
||||
airbase_threat_range = self.game.settings.airbase_threat_range
|
||||
if (
|
||||
not self.is_player
|
||||
and randint(1, 100)
|
||||
> self.game.settings.opfor_autoplanner_aggressiveness
|
||||
):
|
||||
# Chance that the airfield threat range will be evaluated as zero,
|
||||
# causing the OPFOR autoplanner to plan offensively
|
||||
airbase_threat_range = 0
|
||||
airfields_in_threat_range = (
|
||||
airfields_in_proximity.operational_airfields_within(
|
||||
self.AIRFIELD_THREAT_RANGE
|
||||
nautical_miles(airbase_threat_range)
|
||||
)
|
||||
)
|
||||
for airfield in airfields_in_threat_range:
|
||||
|
||||
@@ -44,3 +44,5 @@ class PlanDead(PackagePlanningTask[IadsGroundObject]):
|
||||
self.propose_flight(FlightType.SEAD, 2)
|
||||
self.propose_flight(FlightType.SEAD_ESCORT, 2, EscortType.Sead)
|
||||
self.propose_flight(FlightType.ESCORT, 2, EscortType.AirToAir)
|
||||
if self.target.control_point.coalition.game.settings.autoplan_tankers_for_dead:
|
||||
self.propose_flight(FlightType.REFUELING, 1)
|
||||
|
||||
@@ -29,3 +29,5 @@ class PlanOcaStrike(PackagePlanningTask[ControlPoint]):
|
||||
if self.aircraft_cold_start:
|
||||
self.propose_flight(FlightType.OCA_AIRCRAFT, 2)
|
||||
self.propose_common_escorts()
|
||||
if self.target.coalition.game.settings.autoplan_tankers_for_oca:
|
||||
self.propose_flight(FlightType.REFUELING, 1)
|
||||
|
||||
@@ -24,3 +24,5 @@ class PlanStrike(PackagePlanningTask[TheaterGroundObject]):
|
||||
tgt_count = self.target.alive_unit_count
|
||||
self.propose_flight(FlightType.STRIKE, min(4, (tgt_count // 2) + 1))
|
||||
self.propose_common_escorts()
|
||||
if self.target.coalition.game.settings.autoplan_tankers_for_strike:
|
||||
self.propose_flight(FlightType.REFUELING, 1)
|
||||
|
||||
@@ -173,7 +173,11 @@ class TheaterState(WorldState["TheaterState"]):
|
||||
cp: BattlePositions.for_control_point(cp)
|
||||
for cp in ordered_capturable_points
|
||||
},
|
||||
oca_targets=list(finder.oca_targets(min_aircraft=20)),
|
||||
oca_targets=list(
|
||||
finder.oca_targets(
|
||||
min_aircraft=game.settings.oca_target_autoplanner_min_aircraft_count
|
||||
)
|
||||
),
|
||||
strike_targets=list(finder.strike_targets()),
|
||||
enemy_barcaps=list(game.theater.control_points_for(not player)),
|
||||
threat_zones=game.threat_zone_for(not player),
|
||||
|
||||
@@ -330,10 +330,10 @@ class Faction:
|
||||
self.remove_aircraft("F-15D")
|
||||
if not mod_settings.f_16_idf:
|
||||
self.remove_aircraft("F-16I")
|
||||
self.remove_aircraft("F_16D_52")
|
||||
self.remove_aircraft("F_16D_50")
|
||||
self.remove_aircraft("F_16D_50_NS")
|
||||
self.remove_aircraft("F_16D_52_NS")
|
||||
self.remove_aircraft("F-16D_52")
|
||||
self.remove_aircraft("F-16D_50")
|
||||
self.remove_aircraft("F-16D_50_NS")
|
||||
self.remove_aircraft("F-16D_52_NS")
|
||||
self.remove_aircraft("F-16D_Barak_30")
|
||||
self.remove_aircraft("F-16D_Barak_40")
|
||||
else:
|
||||
|
||||
@@ -64,7 +64,7 @@ class FrontLineConflictDescription:
|
||||
attack_heading = frontline.blue_forward_heading
|
||||
position = cls.find_ground_position(
|
||||
frontline.position,
|
||||
settings.max_frontline_length * 1000,
|
||||
settings.max_frontline_width * 1000,
|
||||
attack_heading.right,
|
||||
theater,
|
||||
)
|
||||
@@ -82,13 +82,13 @@ class FrontLineConflictDescription:
|
||||
right_heading = heading.right
|
||||
left_position = cls.extend_ground_position(
|
||||
center_position,
|
||||
int(settings.max_frontline_length * 1000 / 2),
|
||||
int(settings.max_frontline_width * 1000 / 2),
|
||||
left_heading,
|
||||
theater,
|
||||
)
|
||||
right_position = cls.extend_ground_position(
|
||||
center_position,
|
||||
int(settings.max_frontline_length * 1000 / 2),
|
||||
int(settings.max_frontline_width * 1000 / 2),
|
||||
right_heading,
|
||||
theater,
|
||||
)
|
||||
|
||||
@@ -46,6 +46,9 @@ PILOTS_AND_SQUADRONS_SECTION = "Pilots and Squadrons"
|
||||
HQ_AUTOMATION_SECTION = "HQ Automation"
|
||||
FLIGHT_PLANNER_AUTOMATION = "Flight Planner Automation"
|
||||
|
||||
CAMPAIGN_DOCTRINE_PAGE = "Campaign Doctrine"
|
||||
DOCTRINE_DISTANCES_SECTION = "Doctrine distances"
|
||||
|
||||
MISSION_GENERATOR_PAGE = "Mission Generator"
|
||||
|
||||
GAMEPLAY_SECTION = "Gameplay"
|
||||
@@ -194,6 +197,109 @@ class Settings:
|
||||
"assigned to their primary task."
|
||||
),
|
||||
)
|
||||
autoplan_tankers_for_strike: bool = boolean_option(
|
||||
"Autoplanner plans refueling flights for Strike packages",
|
||||
page=CAMPAIGN_DOCTRINE_PAGE,
|
||||
section=GENERAL_SECTION,
|
||||
default=True,
|
||||
invert=False,
|
||||
detail=(
|
||||
"If checked, the autoplanner will include tankers in Strike packages, "
|
||||
"provided the faction has access to them."
|
||||
),
|
||||
)
|
||||
autoplan_tankers_for_oca: bool = boolean_option(
|
||||
"Autoplanner plans refueling flights for OCA packages",
|
||||
page=CAMPAIGN_DOCTRINE_PAGE,
|
||||
section=GENERAL_SECTION,
|
||||
default=True,
|
||||
invert=False,
|
||||
detail=(
|
||||
"If checked, the autoplanner will include tankers in OCA packages, "
|
||||
"provided the faction has access to them."
|
||||
),
|
||||
)
|
||||
autoplan_tankers_for_dead: bool = boolean_option(
|
||||
"Autoplanner plans refueling flights for DEAD packages",
|
||||
page=CAMPAIGN_DOCTRINE_PAGE,
|
||||
section=GENERAL_SECTION,
|
||||
default=True,
|
||||
invert=False,
|
||||
detail=(
|
||||
"If checked, the autoplanner will include tankers in DEAD packages, "
|
||||
"provided the faction has access to them."
|
||||
),
|
||||
)
|
||||
oca_target_autoplanner_min_aircraft_count: int = bounded_int_option(
|
||||
"Minimum number of aircraft (at vulnerable airfields) for autoplanner to plan OCA packages against",
|
||||
page=CAMPAIGN_DOCTRINE_PAGE,
|
||||
section=GENERAL_SECTION,
|
||||
default=20,
|
||||
min=0,
|
||||
max=100,
|
||||
detail=(
|
||||
"How many aircraft there has to be at an airfield for "
|
||||
"the autoplanner to plan an OCA strike against it."
|
||||
),
|
||||
)
|
||||
opfor_autoplanner_aggressiveness: int = bounded_int_option(
|
||||
"OPFOR autoplanner aggressiveness (%)",
|
||||
page=CAMPAIGN_DOCTRINE_PAGE,
|
||||
section=GENERAL_SECTION,
|
||||
default=20,
|
||||
min=0,
|
||||
max=100,
|
||||
detail=(
|
||||
"Chance (larger number -> higher chance) that the OPFOR AI "
|
||||
"autoplanner will take risks and plan flights against targets "
|
||||
"within threatened airspace."
|
||||
),
|
||||
)
|
||||
airbase_threat_range: int = bounded_int_option(
|
||||
"Airbase threat range (nmi)",
|
||||
page=CAMPAIGN_DOCTRINE_PAGE,
|
||||
section=DOCTRINE_DISTANCES_SECTION,
|
||||
default=100,
|
||||
min=0,
|
||||
max=300,
|
||||
detail=(
|
||||
"Will impact both defensive (BARCAP) and offensive flights. Also has a performance impact,"
|
||||
"lower threat range generally means less BARCAPs are planned."
|
||||
),
|
||||
)
|
||||
tarcap_threat_buffer_min_distance: int = bounded_int_option(
|
||||
"TARCAP threat buffer distance (nmi)",
|
||||
page=CAMPAIGN_DOCTRINE_PAGE,
|
||||
section=DOCTRINE_DISTANCES_SECTION,
|
||||
default=20,
|
||||
min=0,
|
||||
max=100,
|
||||
detail=("How close to known threats will the TARCAP racetrack extend."),
|
||||
)
|
||||
aewc_threat_buffer_min_distance: int = bounded_int_option(
|
||||
"AEW&C threat buffer distance (nmi)",
|
||||
page=CAMPAIGN_DOCTRINE_PAGE,
|
||||
section=DOCTRINE_DISTANCES_SECTION,
|
||||
default=80,
|
||||
min=0,
|
||||
max=300,
|
||||
detail=(
|
||||
"How far, at minimum, will AEW&C racetracks be planned"
|
||||
"to known threat zones."
|
||||
),
|
||||
)
|
||||
tanker_threat_buffer_min_distance: int = bounded_int_option(
|
||||
"Theater tanker threat buffer distance (nmi)",
|
||||
page=CAMPAIGN_DOCTRINE_PAGE,
|
||||
section=DOCTRINE_DISTANCES_SECTION,
|
||||
default=70,
|
||||
min=0,
|
||||
max=300,
|
||||
detail=(
|
||||
"How far, at minimum, will theater tanker racetracks be "
|
||||
"planned to known threat zones."
|
||||
),
|
||||
)
|
||||
# Pilots and Squadrons
|
||||
ai_pilot_levelling: bool = boolean_option(
|
||||
"Allow AI pilot leveling",
|
||||
@@ -496,27 +602,14 @@ class Settings:
|
||||
max=150,
|
||||
)
|
||||
# Mission specific
|
||||
max_frontline_length: int = bounded_int_option(
|
||||
"Maximum frontline length (km)",
|
||||
max_frontline_width: int = bounded_int_option(
|
||||
"Maximum frontline width (km)",
|
||||
page=MISSION_GENERATOR_PAGE,
|
||||
section=GAMEPLAY_SECTION,
|
||||
default=80,
|
||||
min=1,
|
||||
max=100,
|
||||
)
|
||||
opfor_autoplanner_aggressiveness: int = bounded_int_option(
|
||||
"OPFOR autoplanner aggressiveness (%)",
|
||||
page=MISSION_GENERATOR_PAGE,
|
||||
section=GAMEPLAY_SECTION,
|
||||
default=20,
|
||||
min=0,
|
||||
max=100,
|
||||
detail=(
|
||||
"Chance (larger number -> higher chance) that the OPFOR AI "
|
||||
"autoplanner will take risks and plan flights against targets "
|
||||
"within threatened airspace."
|
||||
),
|
||||
)
|
||||
game_masters_count: int = bounded_int_option(
|
||||
"Number of game masters",
|
||||
page=MISSION_GENERATOR_PAGE,
|
||||
|
||||
@@ -172,7 +172,7 @@ VERSION = _build_version_string()
|
||||
#: * Support for scenery objectives defined by quad zones.
|
||||
#: * Campaign designers can now define almost all settings:
|
||||
#: `settings:`
|
||||
#: ` max_frontline_length: 25` (in km)
|
||||
#: ` max_frontline_width: 25` (in km)
|
||||
#: ` perf_culling_distance: 35` (in km)
|
||||
#:
|
||||
#: Version 10.6
|
||||
|
||||
Reference in New Issue
Block a user