Limit front line size with ammo depots.

This limit is determined by the number of buildings that belong to Ammo
Depots at the front line's connected Control Point. The limit increases
for every surviving building at ammo depot objectives.

There is a lower limit to the number of units that will spawn, so that
if there are no surviving ammo depot buildings at a control point, there
will still be some ground conflict.
This commit is contained in:
SnappyComebacks 2021-05-26 18:37:43 -06:00 committed by Dan Albert
parent 077ca19912
commit 95b0b851a5
7 changed files with 73 additions and 4 deletions

View File

@ -3,7 +3,6 @@ import dcs
DEFAULT_AVAILABLE_BUILDINGS = [
"fuel",
"ammo",
"comms",
"oil",
"ware",

View File

@ -262,10 +262,19 @@ class ProcurementAi:
# Prefer to buy front line units at active front lines that are not
# already overloaded.
for cp in self.owned_points:
total_ground_units_allocated_to_this_control_point = (
self.total_ground_units_allocated_to(cp)
)
if not cp.has_ground_unit_source(self.game):
continue
if self.total_ground_units_allocated_to(cp) >= 50:
if (
total_ground_units_allocated_to_this_control_point >= 50
or total_ground_units_allocated_to_this_control_point
>= cp.frontline_unit_count_limit
):
# Control point is already sufficiently defended.
continue
for connected in cp.connected_points:

View File

@ -22,7 +22,7 @@ from dcs.ships import (
DDG_Arleigh_Burke_IIa,
LHA_1_Tarawa,
)
from dcs.statics import Fortification
from dcs.statics import Fortification, Warehouse
from dcs.terrain import (
caucasus,
nevada,
@ -128,6 +128,8 @@ class MizCampaignLoader:
FACTORY_UNIT_TYPE = Fortification.Workshop_A.id
AMMUNITION_DEPOT_UNIT_TYPE = Warehouse.Ammunition_depot.id
REQUIRED_STRIKE_TARGET_UNIT_TYPE = Fortification.Tech_combine.id
BASE_DEFENSE_RADIUS = nautical_miles(2)
@ -320,6 +322,12 @@ class MizCampaignLoader:
if group.units[0].type in self.FACTORY_UNIT_TYPE:
yield group
@property
def ammunition_depots(self) -> Iterator[StaticGroup]:
for group in itertools.chain(self.blue.static_group, self.red.static_group):
if group.units[0].type in self.AMMUNITION_DEPOT_UNIT_TYPE:
yield group
@property
def required_strike_targets(self) -> Iterator[StaticGroup]:
for group in itertools.chain(self.blue.static_group, self.red.static_group):
@ -559,6 +567,12 @@ class MizCampaignLoader:
PointWithHeading.from_point(group.position, group.units[0].heading)
)
for group in self.ammunition_depots:
closest, distance = self.objective_info(group)
closest.preset_locations.ammunition_depots.append(
PointWithHeading.from_point(group.position, group.units[0].heading)
)
for group in self.required_strike_targets:
closest, distance = self.objective_info(group)
closest.preset_locations.required_strike_locations.append(

View File

@ -59,6 +59,9 @@ if TYPE_CHECKING:
from game import Game
from gen.flights.flight import FlightType
FREE_FRONTLINE_UNIT_SUPPLY: int = 15
AMMO_DEPOT_FRONTLINE_UNIT_CONTRIBUTION: int = 12
class ControlPointType(Enum):
#: An airbase with slots for everything.
@ -161,6 +164,9 @@ class PresetLocations:
#: Locations of factories for producing ground units. These will always be spawned.
factories: List[PointWithHeading] = field(default_factory=list)
#: Locations of ammo depots for controlling number of units on the front line at a control point.
ammunition_depots: List[PointWithHeading] = field(default_factory=list)
#: Locations of stationary armor groups. These will always be spawned.
armor_groups: List[PointWithHeading] = field(default_factory=list)
@ -783,6 +789,20 @@ class ControlPoint(MissionTarget, ABC):
return self.captured != other.captured
@property
def frontline_unit_count_limit(self) -> int:
tally_connected_ammo_depots = 0
for cp_objective in self.connected_objectives:
if cp_objective.category == "ammo" and not cp_objective.is_dead:
tally_connected_ammo_depots += 1
return (
FREE_FRONTLINE_UNIT_SUPPLY
+ tally_connected_ammo_depots * AMMO_DEPOT_FRONTLINE_UNIT_CONTRIBUTION
)
@property
def strike_targets(self) -> List[Union[MissionTarget, Unit]]:
return []

View File

@ -471,6 +471,7 @@ class AirbaseGroundObjectGenerator(ControlPointGroundObjectGenerator):
self.generate_strike_targets()
self.generate_offshore_strike_targets()
self.generate_factories()
self.generate_ammunition_depots()
if self.faction.missiles:
self.generate_missile_sites()
@ -629,6 +630,10 @@ class AirbaseGroundObjectGenerator(ControlPointGroundObjectGenerator):
self.control_point.connected_objectives.append(g)
def generate_ammunition_depots(self) -> None:
for position in self.control_point.preset_locations.ammunition_depots:
self.generate_strike_target_at(category="ammo", position=position)
def generate_factories(self) -> None:
"""Generates the factories that are required by the campaign."""
for position in self.control_point.preset_locations.factories:
@ -828,6 +833,7 @@ class FobGroundObjectGenerator(AirbaseGroundObjectGenerator):
FobDefenseGenerator(self.game, self.control_point).generate()
self.generate_armor_groups()
self.generate_factories()
self.generate_ammunition_depots()
self.generate_required_aa()
self.generate_required_ewr()
self.generate_scenery_sites()

View File

@ -73,4 +73,12 @@ VERSION = _build_version_string()
#: * AAA_8_8cm_Flak_18,
#: * SPAAA_Vulcan_M163,
#: * SPAAA_ZSU_23_4_Shilka_Gun_Dish,
CAMPAIGN_FORMAT_VERSION = (4, 2)
#:
#: Version 5.0
#: * Ammunition Depots objective locations are now predetermined using the "Ammunition Depot"
#: Warehouse object, and through trigger zone based scenery objects.
#: * The number of alive Ammunition Depot objective buildings connected to a control point
#: directly influences how many ground units can be supported on the front line.
#: * The number of supported ground units at any control point is artificially capped at 50,
#: even if the number of alive Ammunition Depot objectives can support more.
CAMPAIGN_FORMAT_VERSION = (5, 0)

View File

@ -80,6 +80,10 @@ class GroundPlanner:
def plan_groundwar(self):
ground_unit_limit = self.cp.frontline_unit_count_limit
remaining_available_frontline_units = ground_unit_limit
if hasattr(self.cp, "stance"):
group_size_choice = GROUP_SIZES_BY_COMBAT_STANCE[self.cp.stance]
else:
@ -118,6 +122,12 @@ class GroundPlanner:
continue
available = self.cp.base.armor[key]
if available > remaining_available_frontline_units:
available = remaining_available_frontline_units
remaining_available_frontline_units -= available
while available > 0:
if role == CombatGroupRole.SHORAD:
@ -144,6 +154,9 @@ class GroundPlanner:
group.units.append(key)
collection.append(group)
if remaining_available_frontline_units == 0:
break
print("------------------")
print("Ground Planner : ")
print(self.cp.name)