Let the TheaterCommander manage front line stance.

This improves the AI behavior by choosing the stances non-randomly:

* Breakthrough will be used if the base is expected to be capturable and
  the coalition outnumbers the enemy by 20%.
* Elimination will be used if the coalition has at least as many units
  as the enemy.
* Defensive will be used if the coalition has at least half as many
  units as the enemy.
* Retreat will be used if the coalition is significantly outnumbers.

This also exposes the option to the player.
This commit is contained in:
Dan Albert
2021-07-12 20:31:38 -07:00
parent 575aca5886
commit 0a416ab758
35 changed files with 361 additions and 57 deletions

View File

@@ -86,43 +86,19 @@ class GroundConflictGenerator:
player_planned_combat_groups: List[CombatGroup],
enemy_planned_combat_groups: List[CombatGroup],
player_stance: CombatStance,
enemy_stance: CombatStance,
unit_map: UnitMap,
) -> None:
self.mission = mission
self.conflict = conflict
self.enemy_planned_combat_groups = enemy_planned_combat_groups
self.player_planned_combat_groups = player_planned_combat_groups
self.player_stance = CombatStance(player_stance)
self.enemy_stance = self._enemy_stance()
self.player_stance = player_stance
self.enemy_stance = enemy_stance
self.game = game
self.unit_map = unit_map
self.jtacs: List[JtacInfo] = []
def _enemy_stance(self) -> CombatStance:
"""Picks the enemy stance according to the number of planned groups on the frontline for each side"""
if len(self.enemy_planned_combat_groups) > len(
self.player_planned_combat_groups
):
return random.choice(
[
CombatStance.AGGRESSIVE,
CombatStance.AGGRESSIVE,
CombatStance.AGGRESSIVE,
CombatStance.ELIMINATION,
CombatStance.BREAKTHROUGH,
]
)
else:
return random.choice(
[
CombatStance.DEFENSIVE,
CombatStance.DEFENSIVE,
CombatStance.DEFENSIVE,
CombatStance.AMBUSH,
CombatStance.AGGRESSIVE,
]
)
def generate(self) -> None:
position = Conflict.frontline_position(
self.conflict.front_line, self.game.theater

View File

@@ -247,14 +247,9 @@ class CoalitionMissionPlanner:
"""
return self.game.air_wing_for(self.is_player).can_auto_plan(mission_type)
def plan_missions(self) -> None:
def fulfill_missions(self) -> None:
"""Identifies and plans mission for the turn."""
player = "Blue" if self.is_player else "Red"
with logged_duration(f"{player} mission identification and fulfillment"):
with MultiEventTracer() as tracer:
commander = TheaterCommander(self.game, self.is_player)
commander.plan_missions(self, tracer)
with logged_duration(f"{player} mission scheduling"):
self.stagger_missions()