mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
Finish moving gen into game.
This commit is contained in:
0
game/ground_forces/__init__.py
Normal file
0
game/ground_forces/__init__.py
Normal file
162
game/ground_forces/ai_ground_planner.py
Normal file
162
game/ground_forces/ai_ground_planner.py
Normal file
@@ -0,0 +1,162 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import random
|
||||
from enum import Enum
|
||||
from typing import Dict, List, TYPE_CHECKING
|
||||
|
||||
from game.data.units import UnitClass
|
||||
from game.dcs.groundunittype import GroundUnitType
|
||||
from .combat_stance import CombatStance
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game import Game
|
||||
from game.theater import ControlPoint
|
||||
|
||||
MAX_COMBAT_GROUP_PER_CP = 10
|
||||
|
||||
|
||||
class CombatGroupRole(Enum):
|
||||
TANK = 1
|
||||
APC = 2
|
||||
IFV = 3
|
||||
ARTILLERY = 4
|
||||
SHORAD = 5
|
||||
LOGI = 6
|
||||
INFANTRY = 7
|
||||
ATGM = 8
|
||||
RECON = 9
|
||||
|
||||
|
||||
DISTANCE_FROM_FRONTLINE = {
|
||||
CombatGroupRole.TANK: (2200, 3200),
|
||||
CombatGroupRole.APC: (2700, 3700),
|
||||
CombatGroupRole.IFV: (2700, 3700),
|
||||
CombatGroupRole.ARTILLERY: (16000, 18000),
|
||||
CombatGroupRole.SHORAD: (5000, 8000),
|
||||
CombatGroupRole.LOGI: (18000, 20000),
|
||||
CombatGroupRole.INFANTRY: (2800, 3300),
|
||||
CombatGroupRole.ATGM: (5200, 6200),
|
||||
CombatGroupRole.RECON: (2000, 3000),
|
||||
}
|
||||
|
||||
GROUP_SIZES_BY_COMBAT_STANCE = {
|
||||
CombatStance.DEFENSIVE: [2, 4, 6],
|
||||
CombatStance.AGGRESSIVE: [2, 4, 6],
|
||||
CombatStance.RETREAT: [2, 4, 6, 8],
|
||||
CombatStance.BREAKTHROUGH: [4, 6, 6, 8],
|
||||
CombatStance.ELIMINATION: [2, 4, 4, 4, 6],
|
||||
CombatStance.AMBUSH: [1, 1, 2, 2, 2, 2, 4],
|
||||
}
|
||||
|
||||
|
||||
class CombatGroup:
|
||||
def __init__(
|
||||
self, role: CombatGroupRole, unit_type: GroundUnitType, size: int
|
||||
) -> None:
|
||||
self.unit_type = unit_type
|
||||
self.size = size
|
||||
self.role = role
|
||||
self.start_position = None
|
||||
|
||||
def __str__(self) -> str:
|
||||
s = f"ROLE : {self.role}\n"
|
||||
if self.size:
|
||||
s += f"UNITS {self.unit_type} * {self.size}"
|
||||
return s
|
||||
|
||||
|
||||
class GroundPlanner:
|
||||
def __init__(self, cp: ControlPoint, game: Game) -> None:
|
||||
self.cp = cp
|
||||
self.game = game
|
||||
self.connected_enemy_cp = [
|
||||
cp for cp in self.cp.connected_points if cp.captured != self.cp.captured
|
||||
]
|
||||
self.tank_groups: List[CombatGroup] = []
|
||||
self.apc_group: List[CombatGroup] = []
|
||||
self.ifv_group: List[CombatGroup] = []
|
||||
self.art_group: List[CombatGroup] = []
|
||||
self.atgm_group: List[CombatGroup] = []
|
||||
self.logi_groups: List[CombatGroup] = []
|
||||
self.shorad_groups: List[CombatGroup] = []
|
||||
self.recon_groups: List[CombatGroup] = []
|
||||
|
||||
self.units_per_cp: Dict[int, List[CombatGroup]] = {}
|
||||
for cp in self.connected_enemy_cp:
|
||||
self.units_per_cp[cp.id] = []
|
||||
self.reserve: List[CombatGroup] = []
|
||||
|
||||
def plan_groundwar(self) -> None:
|
||||
|
||||
ground_unit_limit = self.cp.frontline_unit_count_limit
|
||||
|
||||
remaining_available_frontline_units = ground_unit_limit
|
||||
|
||||
# TODO: Fix to handle the per-front stances.
|
||||
# https://github.com/dcs-liberation/dcs_liberation/issues/1417
|
||||
group_size_choice = GROUP_SIZES_BY_COMBAT_STANCE[CombatStance.DEFENSIVE]
|
||||
|
||||
# Create combat groups and assign them randomly to each enemy CP
|
||||
for unit_type in self.cp.base.armor:
|
||||
unit_class = unit_type.unit_class
|
||||
if unit_class is UnitClass.TANK:
|
||||
collection = self.tank_groups
|
||||
role = CombatGroupRole.TANK
|
||||
elif unit_class is UnitClass.APC:
|
||||
collection = self.apc_group
|
||||
role = CombatGroupRole.APC
|
||||
elif unit_class is UnitClass.ARTILLERY:
|
||||
collection = self.art_group
|
||||
role = CombatGroupRole.ARTILLERY
|
||||
elif unit_class is UnitClass.IFV:
|
||||
collection = self.ifv_group
|
||||
role = CombatGroupRole.IFV
|
||||
elif unit_class is UnitClass.LOGISTICS:
|
||||
collection = self.logi_groups
|
||||
role = CombatGroupRole.LOGI
|
||||
elif unit_class is UnitClass.ATGM:
|
||||
collection = self.atgm_group
|
||||
role = CombatGroupRole.ATGM
|
||||
elif unit_class is UnitClass.SHORAD:
|
||||
collection = self.shorad_groups
|
||||
role = CombatGroupRole.SHORAD
|
||||
elif unit_class is UnitClass.RECON:
|
||||
collection = self.recon_groups
|
||||
role = CombatGroupRole.RECON
|
||||
else:
|
||||
logging.warning(
|
||||
f"Unused front line vehicle at base {unit_type}: unknown unit class"
|
||||
)
|
||||
continue
|
||||
|
||||
available = self.cp.base.armor[unit_type]
|
||||
|
||||
if available > remaining_available_frontline_units:
|
||||
available = remaining_available_frontline_units
|
||||
|
||||
remaining_available_frontline_units -= available
|
||||
|
||||
while available > 0:
|
||||
|
||||
if role == CombatGroupRole.SHORAD:
|
||||
count = 1
|
||||
else:
|
||||
count = random.choice(group_size_choice)
|
||||
if count > available:
|
||||
if available >= 2:
|
||||
count = 2
|
||||
else:
|
||||
count = 1
|
||||
available -= count
|
||||
|
||||
group = CombatGroup(role, unit_type, count)
|
||||
if len(self.connected_enemy_cp) > 0:
|
||||
enemy_cp = random.choice(self.connected_enemy_cp).id
|
||||
self.units_per_cp[enemy_cp].append(group)
|
||||
else:
|
||||
self.reserve.append(group)
|
||||
collection.append(group)
|
||||
|
||||
if remaining_available_frontline_units == 0:
|
||||
break
|
||||
12
game/ground_forces/combat_stance.py
Normal file
12
game/ground_forces/combat_stance.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class CombatStance(Enum):
|
||||
DEFENSIVE = 0 # Unit will adopt defensive stance with medium group of units
|
||||
AGGRESSIVE = (
|
||||
1 # Unit will attempt to make progress with medium sized group of units
|
||||
)
|
||||
RETREAT = 2 # Unit will retreat
|
||||
BREAKTHROUGH = 3 # Unit will attempt a breakthrough, rushing forward very aggresively with big group of armored units, and even less armored units will move aggresively
|
||||
ELIMINATION = 4 # Unit will progress aggresively toward anemy units, attempting to eliminate the ennemy force
|
||||
AMBUSH = 5 # Units will adopt a defensive stance a bit different from 'DEFENSIVE', ATGM & INFANTRY with RPG will be located on frontline with the armored units. (The groups of units will be smaller)
|
||||
Reference in New Issue
Block a user