mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Prioritize ammo depots when appropriate.
The AI will now prioritize targeting ammo depots if the current deployable enemy forces outnumber the friendly cap by 50% or more.
This commit is contained in:
@@ -4,10 +4,13 @@ from dataclasses import dataclass
|
||||
from game.commander.tasks.compound.destroyenemygroundunits import (
|
||||
DestroyEnemyGroundUnits,
|
||||
)
|
||||
from game.commander.tasks.compound.reduceenemyfrontlinecapacity import (
|
||||
ReduceEnemyFrontLineCapacity,
|
||||
)
|
||||
from game.commander.tasks.primitive.breakthroughattack import BreakthroughAttack
|
||||
from game.commander.theaterstate import TheaterState
|
||||
from game.htn import CompoundTask, Method
|
||||
from game.theater import FrontLine
|
||||
from game.theater import FrontLine, ControlPoint
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -17,3 +20,32 @@ class CaptureBase(CompoundTask[TheaterState]):
|
||||
def each_valid_method(self, state: TheaterState) -> Iterator[Method[TheaterState]]:
|
||||
yield [BreakthroughAttack(self.front_line, state.context.coalition.player)]
|
||||
yield [DestroyEnemyGroundUnits(self.front_line)]
|
||||
if self.worth_destroying_ammo_depots(state):
|
||||
yield [ReduceEnemyFrontLineCapacity(self.enemy_cp(state))]
|
||||
|
||||
def enemy_cp(self, state: TheaterState) -> ControlPoint:
|
||||
return self.front_line.control_point_hostile_to(state.context.coalition.player)
|
||||
|
||||
def units_deployable(self, state: TheaterState, player: bool) -> int:
|
||||
cp = self.front_line.control_point_friendly_to(player)
|
||||
ammo_depots = list(state.ammo_dumps_at(cp))
|
||||
return cp.deployable_front_line_units_with(len(ammo_depots))
|
||||
|
||||
def unit_cap(self, state: TheaterState, player: bool) -> int:
|
||||
cp = self.front_line.control_point_friendly_to(player)
|
||||
ammo_depots = list(state.ammo_dumps_at(cp))
|
||||
return cp.front_line_capacity_with(len(ammo_depots))
|
||||
|
||||
def enemy_has_ammo_dumps(self, state: TheaterState) -> bool:
|
||||
return bool(state.ammo_dumps_at(self.enemy_cp(state)))
|
||||
|
||||
def worth_destroying_ammo_depots(self, state: TheaterState) -> bool:
|
||||
if not self.enemy_has_ammo_dumps(state):
|
||||
return False
|
||||
|
||||
friendly_cap = self.unit_cap(state, state.context.coalition.player)
|
||||
enemy_deployable = self.units_deployable(state, state.context.coalition.player)
|
||||
|
||||
# If the enemy can currently deploy 50% more units than we possibly could, it's
|
||||
# worth killing an ammo depot.
|
||||
return enemy_deployable / friendly_cap > 1.5
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
from collections import Iterator
|
||||
from dataclasses import dataclass
|
||||
|
||||
from game.commander.tasks.primitive.aggressiveattack import AggressiveAttack
|
||||
from game.commander.tasks.primitive.cas import PlanCas
|
||||
from game.commander.tasks.primitive.eliminationattack import EliminationAttack
|
||||
from game.commander.tasks.primitive.strike import PlanStrike
|
||||
from game.commander.theaterstate import TheaterState
|
||||
from game.htn import CompoundTask, Method
|
||||
from game.theater import FrontLine
|
||||
from game.theater import ControlPoint
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class DestroyEnemyGroundUnits(CompoundTask[TheaterState]):
|
||||
front_line: FrontLine
|
||||
class ReduceEnemyFrontLineCapacity(CompoundTask[TheaterState]):
|
||||
control_point: ControlPoint
|
||||
|
||||
def each_valid_method(self, state: TheaterState) -> Iterator[Method[TheaterState]]:
|
||||
yield [EliminationAttack(self.front_line, state.context.coalition.player)]
|
||||
yield [AggressiveAttack(self.front_line, state.context.coalition.player)]
|
||||
yield [PlanCas(self.front_line)]
|
||||
for ammo_dump in state.ammo_dumps_at(self.control_point):
|
||||
yield [PlanStrike(ammo_dump)]
|
||||
|
||||
@@ -3,6 +3,7 @@ from __future__ import annotations
|
||||
import dataclasses
|
||||
import itertools
|
||||
import math
|
||||
from collections import Iterator
|
||||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING, Any, Union, Optional
|
||||
|
||||
@@ -18,6 +19,7 @@ from game.theater.theatergroundobject import (
|
||||
NavalGroundObject,
|
||||
IadsGroundObject,
|
||||
VehicleGroupGroundObject,
|
||||
BuildingGroundObject,
|
||||
)
|
||||
from game.threatzones import ThreatZones
|
||||
from gen.ground_forces.combat_stance import CombatStance
|
||||
@@ -88,6 +90,15 @@ class TheaterState(WorldState["TheaterState"]):
|
||||
def eliminate_garrison(self, target: VehicleGroupGroundObject) -> None:
|
||||
self.enemy_garrisons[target.control_point].eliminate(target)
|
||||
|
||||
def ammo_dumps_at(
|
||||
self, control_point: ControlPoint
|
||||
) -> Iterator[BuildingGroundObject]:
|
||||
for target in self.strike_targets:
|
||||
if target.control_point != control_point:
|
||||
continue
|
||||
if target.is_ammo_depot:
|
||||
yield target
|
||||
|
||||
def clone(self) -> TheaterState:
|
||||
# Do not use copy.deepcopy. Copying every TGO, control point, etc is absurdly
|
||||
# expensive.
|
||||
|
||||
Reference in New Issue
Block a user