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:
MetalStormGhost 2023-07-02 00:54:27 +03:00 committed by GitHub
parent 4b4ec8d9ad
commit 6e37cadb84
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 168 additions and 40 deletions

View File

@ -7,6 +7,17 @@
* **[Campaign Design]** Ability to define SCENERY REMOVE OBJECTS ZONE triggers with the roadbase objects in campaign miz. This might not work reliably in multiplayer due to DCS issues. FARPs can be used to remove scenery objects in multiplayer.
* **[Campaign Management]** Improved squadron retreat logic at longer ranges.
* **[Options]** Ability to load & save your settings.
* **[Options]** 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)
* **[Options]** Improved the option to configure OPFOR autoplanner aggressiveness. The AI might now take even more risks and plan missions against defended targets.
* 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
* **[UI]** Added fuel selector in flight's edit window.
* **[Plugins]** Expose Splash Damage's "game_messages" option and set its default to false.
* **[Mission Generation]** Improved AI SEAD capabilities, allowing for mixed loadouts using Decoys, ARMs & ASMs.
@ -33,13 +44,14 @@
* **[Plugins]** Added "EWR Jammer" plugin (only for humans, may change in the future).
* **[Campaign]** New campaign (Operation Desert Sabre) by Chimiste
* **[Plugins]** Updated CTLD to latest released version
* **[Options]** Renamed Maximum frontline length -> Maximum frontline width.
## Fixes
* **[New Game Wizard]** Settings would not persist when going back to a previous page (obsolete due to overhaul).
* **[Mission Generation]** Unused aircraft are no longer claimed, fixing a bug where these aircraft would no longer be available after aborting the mission.
* **[Mission Generation]** Fixed (potential) bug in helipad assignments at FOBs/FARPs.
* **[Mission Generation]** Fix AI immediately returning to base when forced to air-start due to insufficient parking space.
* **[Modding]** Fixed a bug where F-16Ds were not correctly removed from the faction when the F-16I/F-16D mod was not selected
# Retribution v1.1.1 (hotfix)

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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:

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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),

View File

@ -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:

View File

@ -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,
)

View File

@ -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,

View File

@ -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

View File

@ -77,6 +77,7 @@ def load_icons():
"./resources/ui/misc/" + get_theme_icons() + "/money_icon.png"
)
ICONS["Campaign Management"] = ICONS["Money"]
ICONS["Campaign Doctrine"] = QPixmap("./resources/ui/misc/blue-sam.png")
ICONS["PassTurn"] = QPixmap(
"./resources/ui/misc/" + get_theme_icons() + "/hourglass.png"
)

View File

@ -15,7 +15,7 @@ recommended_player_income_multiplier: 1.0
recommended_enemy_income_multiplier: 1.0
advanced_iads: false
settings:
max_frontline_length: 30
max_frontline_width: 30
player_income_multiplier: 1.5
squadrons:
CVN-74 John Stennis:

View File

@ -15,7 +15,7 @@ recommended_player_income_multiplier: 5.0
recommended_enemy_income_multiplier: 1.0
advanced_iads: false
settings:
max_frontline_length: 30
max_frontline_width: 30
squadrons:
CVN-74 John Stennis:
- primary: BARCAP

View File

@ -15,7 +15,7 @@ recommended_player_income_multiplier: 5.0
recommended_enemy_income_multiplier: 1.0
advanced_iads: false
settings:
max_frontline_length: 30
max_frontline_width: 30
squadrons:
Blue CV-1:
- primary: BARCAP

View File

@ -14,7 +14,7 @@ recommended_enemy_money: 2000
recommended_player_income_multiplier: 5.0
recommended_enemy_income_multiplier: 1.0
settings:
max_frontline_length: 20
max_frontline_width: 20
advanced_iads: true # Campaign has connection_nodes / power_sources / command_centers
iads_config:
#COMMAND

View File

@ -14,7 +14,7 @@ recommended_enemy_money: 2000
recommended_player_income_multiplier: 5.0
recommended_enemy_income_multiplier: 1.0
settings:
max_frontline_length: 30
max_frontline_width: 30
advanced_iads: true # Campaign has connection_nodes / power_sources / command_centers
iads_config:
#REDFOR BASE DEFENSE

View File

@ -15,7 +15,7 @@ recommended_player_income_multiplier: 5.0
recommended_enemy_income_multiplier: 1.0
advanced_iads: false
settings:
max_frontline_length: 30
max_frontline_width: 30
squadrons:
#Bandar Abbas Intl
2: