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 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]** New options to allow more control of randomized flight sizes (applicable for BARCAP/CAS/OCA/ANTI-SHIP).
## Fixes
* **[UI]** Removed deprecated options

View File

@ -183,3 +183,12 @@ class PackagePlanningTask(TheaterCommanderTask, Generic[MissionTargetT]):
if iads_threat not in state.threatening_air_defenses:
state.threatening_air_defenses.append(iads_threat)
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)
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)

View File

@ -22,5 +22,6 @@ class PlanAntiShipping(PackagePlanningTask[CargoShip]):
state.enemy_shipping.remove(self.target)
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()

View File

@ -1,5 +1,6 @@
from __future__ import annotations
import random
from dataclasses import dataclass
from random import randint
@ -22,7 +23,8 @@ class PlanBarcap(PackagePlanningTask[ControlPoint]):
state.barcaps_needed[self.target] -= 1
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
def purchase_multiplier(self) -> int:

View File

@ -30,5 +30,6 @@ class PlanCas(PackagePlanningTask[FrontLine]):
state.vulnerable_front_lines.remove(self.target)
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)

View File

@ -24,7 +24,8 @@ class PlanOcaStrike(PackagePlanningTask[ControlPoint]):
state.oca_targets.remove(self.target)
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:
self.propose_flight(FlightType.OCA_AIRCRAFT, 2)
self.propose_common_escorts()

View File

@ -36,6 +36,7 @@ CAMPAIGN_MANAGEMENT_PAGE = "Campaign Management"
GENERAL_SECTION = "General"
PILOTS_AND_SQUADRONS_SECTION = "Pilots and Squadrons"
HQ_AUTOMATION_SECTION = "HQ Automation"
FLIGHT_PLANNER_AUTOMATION = "Flight Planner Automation"
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
# Gameplay
fast_forward_to_first_contact: bool = boolean_option(

View File

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

View File

@ -6,7 +6,7 @@ from dcs.mapping import Point
if TYPE_CHECKING:
from game.ato.flighttype import FlightType
from game.theater import TheaterUnit
from game.theater import TheaterUnit, Coalition
class MissionTarget:
@ -47,3 +47,7 @@ class MissionTarget:
@property
def strike_targets(self) -> list[TheaterUnit]:
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.threatzones import ThreatPoly
from .theatergroup import TheaterUnit, TheaterGroup
from .controlpoint import ControlPoint
from .controlpoint import ControlPoint, Coalition
NAME_BY_CATEGORY = {
@ -275,6 +275,10 @@ class TheaterGroundObject(MissionTarget, SidcDescribable, ABC):
def is_iads(self) -> bool:
return False
@property
def coalition(self) -> Coalition:
return self.control_point.coalition
class BuildingGroundObject(TheaterGroundObject):
def __init__(

View File

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