mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
This feature allows you to cancel the sales of aircraft or ground vehicles if needed. Upon clicking the minus button, a count of sold units will be appended to the unit count. This count responds to both further presses of the minus button, and also to presses of the plus button. No further units will be requested for the next turn until all sold units have been re-bought. I've tested a bunch of different scenarios with this: - Selling and rebuying a unit - the budget increases and decreases as expected. - Selling one unit, buying a unit worth the new player budget, and then trying to rebuy the old unit - the old unit cannot be rebought until the budget has been freed up for it. - Closing the base window and re-opening it - the sold unit count is retained. - Ending the turn - the sold unit count is reset back to 0 as expected. Contributes to Khopa/dcs_liberation#365
165 lines
5.0 KiB
Python
165 lines
5.0 KiB
Python
import random
|
|
from enum import Enum
|
|
from typing import Dict, List
|
|
|
|
from dcs.unittype import VehicleType
|
|
|
|
from game.theater import ControlPoint
|
|
from gen.ground_forces.ai_ground_planner_db import *
|
|
from gen.ground_forces.combat_stance import CombatStance
|
|
|
|
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
|
|
|
|
|
|
DISTANCE_FROM_FRONTLINE = {
|
|
CombatGroupRole.TANK: (2200, 3200),
|
|
CombatGroupRole.APC: (7500, 8500),
|
|
CombatGroupRole.IFV: (2700, 3700),
|
|
CombatGroupRole.ARTILLERY: (16000, 18000),
|
|
CombatGroupRole.SHORAD: (12000, 13000),
|
|
CombatGroupRole.LOGI: (18000, 20000),
|
|
CombatGroupRole.INFANTRY: (2800, 3300),
|
|
CombatGroupRole.ATGM: (5200, 6200),
|
|
}
|
|
|
|
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):
|
|
self.units: List[VehicleType] = []
|
|
self.role = role
|
|
self.assigned_enemy_cp = None
|
|
self.start_position = None
|
|
|
|
def __str__(self):
|
|
s = ""
|
|
s += "ROLE : " + str(self.role) + "\n"
|
|
if len(self.units) > 0:
|
|
s += "UNITS " + self.units[0].name + " * " + str(len(self.units))
|
|
return s
|
|
|
|
|
|
class GroundPlanner:
|
|
|
|
def __init__(self, cp:ControlPoint, game):
|
|
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.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):
|
|
|
|
if hasattr(self.cp, 'stance'):
|
|
group_size_choice = GROUP_SIZES_BY_COMBAT_STANCE[self.cp.stance]
|
|
else:
|
|
self.cp.stance = CombatStance.DEFENSIVE
|
|
group_size_choice = GROUP_SIZES_BY_COMBAT_STANCE[CombatStance.DEFENSIVE]
|
|
|
|
# Create combat groups and assign them randomly to each enemy CP
|
|
for key in self.cp.base.armor.keys():
|
|
|
|
role = None
|
|
collection = None
|
|
if key in TYPE_TANKS:
|
|
collection = self.tank_groups
|
|
role = CombatGroupRole.TANK
|
|
elif key in TYPE_APC:
|
|
collection = self.apc_group
|
|
role = CombatGroupRole.APC
|
|
elif key in TYPE_ARTILLERY:
|
|
collection = self.art_group
|
|
role = CombatGroupRole.ARTILLERY
|
|
elif key in TYPE_IFV:
|
|
collection = self.ifv_group
|
|
role = CombatGroupRole.IFV
|
|
elif key in TYPE_LOGI:
|
|
collection = self.logi_groups
|
|
role = CombatGroupRole.LOGI
|
|
elif key in TYPE_ATGM:
|
|
collection = self.atgm_group
|
|
role = CombatGroupRole.ATGM
|
|
elif key in TYPE_SHORAD:
|
|
collection = self.shorad_groups
|
|
role = CombatGroupRole.SHORAD
|
|
else:
|
|
print("Warning unit type not handled by ground generator")
|
|
print(key)
|
|
continue
|
|
|
|
self.cp.base.sold_units[key] = 0
|
|
available = self.cp.base.armor[key]
|
|
while available > 0:
|
|
|
|
if role == CombatGroupRole.SHORAD:
|
|
n = 1
|
|
else:
|
|
n = random.choice(group_size_choice)
|
|
if n > available:
|
|
if available >= 2:
|
|
n = 2
|
|
else:
|
|
n = 1
|
|
available -= n
|
|
|
|
group = CombatGroup(role)
|
|
if len(self.connected_enemy_cp) > 0:
|
|
enemy_cp = random.choice(self.connected_enemy_cp).id
|
|
self.units_per_cp[enemy_cp].append(group)
|
|
group.assigned_enemy_cp = enemy_cp
|
|
else:
|
|
self.reserve.append(group)
|
|
group.assigned_enemy_cp = "__reserve__"
|
|
|
|
for i in range(n):
|
|
group.units.append(key)
|
|
collection.append(group)
|
|
|
|
print("------------------")
|
|
print("Ground Planner : ")
|
|
print(self.cp.name)
|
|
print("------------------")
|
|
for key in self.units_per_cp.keys():
|
|
print("For : #" + str(key))
|
|
for group in self.units_per_cp[key]:
|
|
print(str(group))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|