Introduce weighted distribution for random 2/3/4-ships

This commit is contained in:
Raffson 2023-02-26 14:03:22 +01:00
parent f2cebc82cc
commit ae379bd8f5
No known key found for this signature in database
GPG Key ID: B0402B2C9B764D99
12 changed files with 77 additions and 8 deletions

View File

@ -27,6 +27,7 @@
* **[Campaign Design]** Ability to define designated CTLD zones for Control Points (Airbases & FOBs/FARPs) * **[Campaign Design]** Ability to define designated CTLD zones for Control Points (Airbases & FOBs/FARPs)
* **[Campaign Design]** Ability to define preset groups for specific TGOs, given the preset group is accessible for the faction and the task matches. * **[Campaign Design]** Ability to define preset groups for specific TGOs, given the preset group is accessible for the faction and the task matches.
* **[Campaign Management]** Additional options for automated budget management. * **[Campaign Management]** Additional options for automated budget management.
* **[Campaign Management]** New options to allow more control of randomized flight sizes (applicable for BARCAP/CAS/OCA/ANTI-SHIP).
## Fixes ## Fixes
* **[UI]** Removed deprecated options * **[UI]** Removed deprecated options

View File

@ -183,3 +183,12 @@ class PackagePlanningTask(TheaterCommanderTask, Generic[MissionTargetT]):
if iads_threat not in state.threatening_air_defenses: if iads_threat not in state.threatening_air_defenses:
state.threatening_air_defenses.append(iads_threat) state.threatening_air_defenses.append(iads_threat)
return not threatened return not threatened
def get_flight_size(self) -> int:
settings = self.target.coalition.game.settings
weights = [
settings.fpa_2ship_weight,
settings.fpa_3ship_weight,
settings.fpa_4ship_weight,
]
return random.choices([2, 3, 4], weights, k=1)[0]

View File

@ -23,5 +23,6 @@ class PlanAntiShip(PackagePlanningTask[NavalGroundObject]):
state.eliminate_ship(self.target) state.eliminate_ship(self.target)
def propose_flights(self) -> None: def propose_flights(self) -> None:
self.propose_flight(FlightType.ANTISHIP, randint(2, 4)) size = self.get_flight_size()
self.propose_flight(FlightType.ANTISHIP, size)
self.propose_flight(FlightType.ESCORT, 2, EscortType.AirToAir) self.propose_flight(FlightType.ESCORT, 2, EscortType.AirToAir)

View File

@ -22,5 +22,6 @@ class PlanAntiShipping(PackagePlanningTask[CargoShip]):
state.enemy_shipping.remove(self.target) state.enemy_shipping.remove(self.target)
def propose_flights(self) -> None: def propose_flights(self) -> None:
self.propose_flight(FlightType.ANTISHIP, randint(2, 4)) size = self.get_flight_size()
self.propose_flight(FlightType.ANTISHIP, size)
self.propose_common_escorts() self.propose_common_escorts()

View File

@ -1,5 +1,6 @@
from __future__ import annotations from __future__ import annotations
import random
from dataclasses import dataclass from dataclasses import dataclass
from random import randint from random import randint
@ -22,7 +23,8 @@ class PlanBarcap(PackagePlanningTask[ControlPoint]):
state.barcaps_needed[self.target] -= 1 state.barcaps_needed[self.target] -= 1
def propose_flights(self) -> None: def propose_flights(self) -> None:
self.propose_flight(FlightType.BARCAP, randint(2, 4)) size = self.get_flight_size()
self.propose_flight(FlightType.BARCAP, size)
@property @property
def purchase_multiplier(self) -> int: def purchase_multiplier(self) -> int:

View File

@ -30,5 +30,6 @@ class PlanCas(PackagePlanningTask[FrontLine]):
state.vulnerable_front_lines.remove(self.target) state.vulnerable_front_lines.remove(self.target)
def propose_flights(self) -> None: def propose_flights(self) -> None:
self.propose_flight(FlightType.CAS, randint(2, 4)) size = self.get_flight_size()
self.propose_flight(FlightType.CAS, size)
self.propose_flight(FlightType.TARCAP, 2) self.propose_flight(FlightType.TARCAP, 2)

View File

@ -24,7 +24,8 @@ class PlanOcaStrike(PackagePlanningTask[ControlPoint]):
state.oca_targets.remove(self.target) state.oca_targets.remove(self.target)
def propose_flights(self) -> None: def propose_flights(self) -> None:
self.propose_flight(FlightType.OCA_RUNWAY, randint(2, 4)) size = self.get_flight_size()
self.propose_flight(FlightType.OCA_RUNWAY, size)
if self.aircraft_cold_start: if self.aircraft_cold_start:
self.propose_flight(FlightType.OCA_AIRCRAFT, 2) self.propose_flight(FlightType.OCA_AIRCRAFT, 2)
self.propose_common_escorts() self.propose_common_escorts()

View File

@ -36,6 +36,7 @@ CAMPAIGN_MANAGEMENT_PAGE = "Campaign Management"
GENERAL_SECTION = "General" GENERAL_SECTION = "General"
PILOTS_AND_SQUADRONS_SECTION = "Pilots and Squadrons" PILOTS_AND_SQUADRONS_SECTION = "Pilots and Squadrons"
HQ_AUTOMATION_SECTION = "HQ Automation" HQ_AUTOMATION_SECTION = "HQ Automation"
FLIGHT_PLANNER_AUTOMATION = "Flight Planner Automation"
MISSION_GENERATOR_PAGE = "Mission Generator" MISSION_GENERATOR_PAGE = "Mission Generator"
@ -310,6 +311,41 @@ class Settings:
), ),
) )
# Flight Planner Automation
#: The weight used for 2-ships.
fpa_2ship_weight: int = bounded_int_option(
"2-ship weight factor (WF2)",
CAMPAIGN_MANAGEMENT_PAGE,
FLIGHT_PLANNER_AUTOMATION,
default=50,
min=0,
max=100,
detail=(
"Used as a distribution to randomize 2/3/4-ships for BARCAP, CAS, OCA & ANTI-SHIP flights. "
"The weight W_i is calculated according to the following formula: 

"
"W_i = WF_i / (WF2 + WF3 + WF4)"
),
)
#: The weight used for 3-ships.
fpa_3ship_weight: int = bounded_int_option(
"3-ship weight factor (WF3)",
CAMPAIGN_MANAGEMENT_PAGE,
FLIGHT_PLANNER_AUTOMATION,
default=35,
min=0,
max=100,
detail="See 2-ship weight factor (WF2)",
)
fpa_4ship_weight: int = bounded_int_option(
"4-ship weight factor (WF4)",
CAMPAIGN_MANAGEMENT_PAGE,
FLIGHT_PLANNER_AUTOMATION,
default=15,
min=0,
max=100,
detail="See 2-ship weight factor (WF2)",
)
# Mission Generator # Mission Generator
# Gameplay # Gameplay
fast_forward_to_first_contact: bool = boolean_option( fast_forward_to_first_contact: bool = boolean_option(

View File

@ -12,7 +12,7 @@ from ..utils import Heading, pairwise
if TYPE_CHECKING: if TYPE_CHECKING:
from game.ato import FlightType from game.ato import FlightType
from .controlpoint import ControlPoint from .controlpoint import ControlPoint, Coalition
FRONTLINE_MIN_CP_DISTANCE = 5000 FRONTLINE_MIN_CP_DISTANCE = 5000
@ -121,6 +121,10 @@ class FrontLine(MissionTarget):
"""Returns a tuple of the two control points.""" """Returns a tuple of the two control points."""
return self.blue_cp, self.red_cp return self.blue_cp, self.red_cp
@property
def coalition(self) -> Coalition:
return self.blue_cp.coalition
@property @property
def route_length(self) -> float: def route_length(self) -> float:
"""The total distance of all segments""" """The total distance of all segments"""

View File

@ -6,7 +6,7 @@ from dcs.mapping import Point
if TYPE_CHECKING: if TYPE_CHECKING:
from game.ato.flighttype import FlightType from game.ato.flighttype import FlightType
from game.theater import TheaterUnit from game.theater import TheaterUnit, Coalition
class MissionTarget: class MissionTarget:
@ -47,3 +47,7 @@ class MissionTarget:
@property @property
def strike_targets(self) -> list[TheaterUnit]: def strike_targets(self) -> list[TheaterUnit]:
return [] return []
@property
def coalition(self) -> Coalition:
raise NotImplementedError

View File

@ -27,7 +27,7 @@ if TYPE_CHECKING:
from game.ato.flighttype import FlightType from game.ato.flighttype import FlightType
from game.threatzones import ThreatPoly from game.threatzones import ThreatPoly
from .theatergroup import TheaterUnit, TheaterGroup from .theatergroup import TheaterUnit, TheaterGroup
from .controlpoint import ControlPoint from .controlpoint import ControlPoint, Coalition
NAME_BY_CATEGORY = { NAME_BY_CATEGORY = {
@ -275,6 +275,10 @@ class TheaterGroundObject(MissionTarget, SidcDescribable, ABC):
def is_iads(self) -> bool: def is_iads(self) -> bool:
return False return False
@property
def coalition(self) -> Coalition:
return self.control_point.coalition
class BuildingGroundObject(TheaterGroundObject): class BuildingGroundObject(TheaterGroundObject):
def __init__( def __init__(

View File

@ -59,6 +59,7 @@ from game.utils import meters, nautical_miles
if TYPE_CHECKING: if TYPE_CHECKING:
from game import Game from game import Game
from game.squadrons import Squadron from game.squadrons import Squadron
from game.theater import Coalition
class Transport: class Transport:
@ -432,6 +433,10 @@ class MultiGroupTransport(MissionTarget, Transport):
def description(self) -> str: def description(self) -> str:
raise NotImplementedError raise NotImplementedError
@property
def coalition(self) -> Coalition:
return self.origin.coalition
class Convoy(MultiGroupTransport): class Convoy(MultiGroupTransport):
def __init__(self, origin: ControlPoint, destination: ControlPoint) -> None: def __init__(self, origin: ControlPoint, destination: ControlPoint) -> None: