mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
Fix range for ai flight planner so they are more likely to plan CAS flights (It's up to the player to setup flight on the runway or in flight)
255 lines
9.2 KiB
Python
255 lines
9.2 KiB
Python
import typing
|
|
import logging
|
|
|
|
from dcs.action import Coalition
|
|
from dcs.unittype import UnitType
|
|
from dcs.task import *
|
|
from dcs.vehicles import AirDefence
|
|
from dcs.unittype import UnitType
|
|
|
|
from game import *
|
|
from theater import *
|
|
from gen.environmentgen import EnvironmentSettings
|
|
from gen.conflictgen import Conflict
|
|
from game.db import assigned_units_from, unitdict_from
|
|
|
|
from userdata.debriefing import Debriefing
|
|
from userdata import persistency
|
|
|
|
import game.db as db
|
|
|
|
DIFFICULTY_LOG_BASE = 1.1
|
|
EVENT_DEPARTURE_MAX_DISTANCE = 340000
|
|
|
|
|
|
class Event:
|
|
silent = False
|
|
informational = False
|
|
is_awacs_enabled = False
|
|
ca_slots = 0
|
|
|
|
game = None # type: Game
|
|
location = None # type: Point
|
|
from_cp = None # type: ControlPoint
|
|
departure_cp = None # type: ControlPoint
|
|
to_cp = None # type: ControlPoint
|
|
|
|
operation = None # type: Operation
|
|
difficulty = 1 # type: int
|
|
environment_settings = None # type: EnvironmentSettings
|
|
BONUS_BASE = 5
|
|
|
|
def __init__(self, game, from_cp: ControlPoint, target_cp: ControlPoint, location: Point, attacker_name: str, defender_name: str):
|
|
self.game = game
|
|
self.departure_cp = None
|
|
self.from_cp = from_cp
|
|
self.to_cp = target_cp
|
|
self.location = location
|
|
self.attacker_name = attacker_name
|
|
self.defender_name = defender_name
|
|
|
|
@property
|
|
def is_player_attacking(self) -> bool:
|
|
return self.attacker_name == self.game.player_name
|
|
|
|
@property
|
|
def enemy_cp(self) -> ControlPoint:
|
|
if self.attacker_name == self.game.player_name:
|
|
return self.to_cp
|
|
else:
|
|
return self.departure_cp
|
|
|
|
@property
|
|
def threat_description(self) -> str:
|
|
return ""
|
|
|
|
def flight_name(self, for_task: typing.Type[typing.Type[Task]]) -> str:
|
|
return "Flight"
|
|
|
|
@property
|
|
def tasks(self) -> typing.Collection[typing.Type[Task]]:
|
|
return []
|
|
|
|
@property
|
|
def ai_banned_tasks(self) -> typing.Collection[typing.Type[Task]]:
|
|
return []
|
|
|
|
@property
|
|
def player_banned_tasks(self) -> typing.Collection[typing.Type[Task]]:
|
|
return []
|
|
|
|
@property
|
|
def global_cp_available(self) -> bool:
|
|
return False
|
|
|
|
def is_departure_available_from(self, cp: ControlPoint) -> bool:
|
|
if not cp.captured:
|
|
return False
|
|
|
|
if self.location.distance_to_point(cp.position) > EVENT_DEPARTURE_MAX_DISTANCE:
|
|
return False
|
|
|
|
if cp.is_global and not self.global_cp_available:
|
|
return False
|
|
|
|
return True
|
|
|
|
def bonus(self) -> int:
|
|
return int(math.log(self.to_cp.importance + 1, DIFFICULTY_LOG_BASE) * self.BONUS_BASE)
|
|
|
|
def is_successfull(self, debriefing: Debriefing) -> bool:
|
|
return self.operation.is_successfull(debriefing)
|
|
|
|
def player_attacking(self, cp: ControlPoint, flights: db.TaskForceDict):
|
|
if self.is_player_attacking:
|
|
self.departure_cp = cp
|
|
else:
|
|
self.to_cp = cp
|
|
|
|
def player_defending(self, cp: ControlPoint, flights: db.TaskForceDict):
|
|
if self.is_player_attacking:
|
|
self.departure_cp = cp
|
|
else:
|
|
self.to_cp = cp
|
|
|
|
def generate(self):
|
|
self.operation.is_awacs_enabled = self.is_awacs_enabled
|
|
self.operation.ca_slots = self.ca_slots
|
|
|
|
self.operation.prepare(self.game.theater.terrain, is_quick=False)
|
|
self.operation.generate()
|
|
self.operation.current_mission.save(persistency.mission_path_for("liberation_nextturn.miz"))
|
|
self.environment_settings = self.operation.environment_settings
|
|
|
|
def generate_quick(self):
|
|
pass
|
|
# TODO : This is not needed anymore. The player can start mission in flight from the flight planner if he want it to be quick.
|
|
# TODO : remove this method
|
|
#self.operation.is_awacs_enabled = self.is_awacs_enabled
|
|
#self.operation.environment_settings = self.environment_settings
|
|
#
|
|
#self.operation.prepare(self.game.theater.terrain, is_quick=True)
|
|
#self.operation.generate()
|
|
#self.operation.current_mission.save(persistency.mission_path_for("liberation_nextturn_quick.miz"))
|
|
|
|
def commit(self, debriefing: Debriefing):
|
|
|
|
logging.info("Commiting mission results")
|
|
|
|
# ------------------------------
|
|
# Destroyed aircrafts
|
|
cp_map = {cp.id: cp for cp in self.game.theater.controlpoints}
|
|
for destroyed_aircraft in debriefing.killed_aircrafts:
|
|
try:
|
|
cpid = int(destroyed_aircraft.split("|")[3])
|
|
type = db.unit_type_from_name(destroyed_aircraft.split("|")[4])
|
|
if cpid in cp_map.keys():
|
|
cp = cp_map[cpid]
|
|
if type in cp.base.aircraft.keys():
|
|
logging.info("Aircraft destroyed : " + str(type))
|
|
cp.base.aircraft[type] = max(0, cp.base.aircraft[type]-1)
|
|
except Exception as e:
|
|
print(e)
|
|
|
|
# ------------------------------
|
|
# Destroyed ground units
|
|
cp_map = {cp.id: cp for cp in self.game.theater.controlpoints}
|
|
for killed_ground_unit in debriefing.killed_ground_units:
|
|
try:
|
|
cpid = int(killed_ground_unit.split("|")[3])
|
|
type = db.unit_type_from_name(killed_ground_unit.split("|")[4])
|
|
if cpid in cp_map.keys():
|
|
cp = cp_map[cpid]
|
|
if type in cp.base.armor.keys():
|
|
logging.info("Ground unit destroyed : " + str(type))
|
|
cp.base.armor[type] = max(0, cp.base.armor[type] - 1)
|
|
except Exception as e:
|
|
print(e)
|
|
|
|
# ------------------------------
|
|
# Static ground objects
|
|
for destroyed_ground_unit_name in debriefing.killed_ground_units:
|
|
for cp in self.game.theater.controlpoints:
|
|
if not cp.ground_objects:
|
|
continue
|
|
|
|
# -- Static ground objects
|
|
for i, ground_object in enumerate(cp.ground_objects):
|
|
if ground_object.is_dead:
|
|
continue
|
|
|
|
if ground_object.matches_string_identifier(destroyed_ground_unit_name):
|
|
logging.info("cp {} killing ground object {}".format(cp, ground_object.string_identifier))
|
|
cp.ground_objects[i].is_dead = True
|
|
|
|
# -- AA Site groups
|
|
for i, ground_object in enumerate(cp.ground_objects):
|
|
if ground_object.dcs_identifier in ["AA", "CARRIER"]:
|
|
for g in ground_object.groups:
|
|
for u in g.units:
|
|
if u.name == destroyed_ground_unit_name:
|
|
g.units.remove(u)
|
|
ucount = sum([len(g.units) for g in ground_object.groups])
|
|
if ucount == 0:
|
|
ground_object.is_dead = True
|
|
|
|
# ------------------------------
|
|
# Captured bases
|
|
|
|
if self.game.player_country in db.BLUEFOR_FACTIONS:
|
|
coalition = 2 # Value in DCS mission event for BLUE
|
|
else:
|
|
coalition = 1 # Value in DCS mission event for RED
|
|
|
|
for captured in debriefing.base_capture_events:
|
|
try:
|
|
id = int(captured.split("||")[0])
|
|
new_owner_coalition = int(captured.split("||")[1])
|
|
|
|
for cp in self.game.theater.controlpoints:
|
|
if cp.id == id:
|
|
if cp.captured and new_owner_coalition != coalition:
|
|
cp.captured = False
|
|
cp.base.aircraft = {}
|
|
cp.base.armor = {}
|
|
cp.base.aa = {}
|
|
for g in cp.ground_objects:
|
|
g.groups = []
|
|
elif not(cp.captured) and new_owner_coalition == coalition:
|
|
cp.captured = True
|
|
cp.base.aircraft = {}
|
|
cp.base.armor = {}
|
|
cp.base.aa = {}
|
|
for g in cp.ground_objects:
|
|
g.groups = []
|
|
except Exception as e:
|
|
print(e)
|
|
|
|
def skip(self):
|
|
pass
|
|
|
|
|
|
class UnitsDeliveryEvent(Event):
|
|
informational = True
|
|
units = None # type: typing.Dict[UnitType, int]
|
|
|
|
def __init__(self, attacker_name: str, defender_name: str, from_cp: ControlPoint, to_cp: ControlPoint, game):
|
|
super(UnitsDeliveryEvent, self).__init__(game=game,
|
|
location=to_cp.position,
|
|
from_cp=from_cp,
|
|
target_cp=to_cp,
|
|
attacker_name=attacker_name,
|
|
defender_name=defender_name)
|
|
|
|
self.units = {}
|
|
|
|
def __str__(self):
|
|
return "Pending delivery to {}".format(self.to_cp)
|
|
|
|
def deliver(self, units: typing.Dict[UnitType, int]):
|
|
for k, v in units.items():
|
|
self.units[k] = self.units.get(k, 0) + v
|
|
|
|
def skip(self):
|
|
self.to_cp.base.commision_units(self.units)
|