mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
New automatic de-briefing system implemented
This commit is contained in:
parent
4365db0fae
commit
3f5f4f4bb1
@ -2,6 +2,7 @@ import typing
|
|||||||
import enum
|
import enum
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
from dcs.countries import get_by_id, country_dict
|
||||||
from dcs.vehicles import *
|
from dcs.vehicles import *
|
||||||
from dcs.ships import *
|
from dcs.ships import *
|
||||||
from dcs.planes import *
|
from dcs.planes import *
|
||||||
@ -836,6 +837,13 @@ def unitdict_from(fd: AssignedUnitsDict) -> Dict:
|
|||||||
return {k: v1 for k, (v1, v2) in fd.items()}
|
return {k: v1 for k, (v1, v2) in fd.items()}
|
||||||
|
|
||||||
|
|
||||||
|
def country_id_from_name(name):
|
||||||
|
for k,v in country_dict.items():
|
||||||
|
if v.name == name:
|
||||||
|
return k
|
||||||
|
return -1
|
||||||
|
|
||||||
|
|
||||||
def _validate_db():
|
def _validate_db():
|
||||||
# check unit by task uniquity
|
# check unit by task uniquity
|
||||||
total_set = set()
|
total_set = set()
|
||||||
|
|||||||
@ -130,44 +130,65 @@ class Event:
|
|||||||
|
|
||||||
def commit(self, debriefing: Debriefing):
|
def commit(self, debriefing: Debriefing):
|
||||||
|
|
||||||
for destroyed_unit_name in debriefing.dead_units_name:
|
logging.info("Commiting mission results")
|
||||||
|
|
||||||
for cp in self.game.theater.controlpoints:
|
# ------------------------------
|
||||||
|
# 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)
|
||||||
|
|
||||||
for i, ground_object in enumerate(cp.ground_objects):
|
# ------------------------------
|
||||||
if ground_object.dcs_identifier == "AA":
|
# Destroyed ground units
|
||||||
for g in ground_object.groups:
|
cp_map = {cp.id: cp for cp in self.game.theater.controlpoints}
|
||||||
for u in g.units:
|
for killed_ground_unit in debriefing.killed_ground_units:
|
||||||
if u.name == destroyed_unit_name:
|
try:
|
||||||
g.units.remove(u)
|
cpid = int(killed_ground_unit.split("|")[3])
|
||||||
ucount = sum([len(g.units) for g in ground_object.groups])
|
type = db.unit_type_from_name(killed_ground_unit.split("|")[4])
|
||||||
print(ucount)
|
if cpid in cp_map.keys():
|
||||||
if ucount == 0:
|
cp = cp_map[cpid]
|
||||||
print("SET DEAD")
|
if type in cp.base.armor.keys():
|
||||||
ground_object.is_dead = True
|
logging.info("Ground unit destroyed : " + str(type))
|
||||||
|
cp.base.armor[type] = max(0, cp.base.armor[type] - 1)
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
|
||||||
for country, losses in debriefing.destroyed_units.items():
|
# ------------------------------
|
||||||
if country == self.attacker_name:
|
# Static ground objects
|
||||||
cp = self.departure_cp
|
for destroyed_ground_unit_name in debriefing.killed_ground_units:
|
||||||
else:
|
|
||||||
cp = self.to_cp
|
|
||||||
|
|
||||||
logging.info("base {} commit losses {}".format(cp.base, losses))
|
|
||||||
cp.base.commit_losses(losses)
|
|
||||||
|
|
||||||
for object_identifier in debriefing.destroyed_objects:
|
|
||||||
for cp in self.game.theater.controlpoints:
|
for cp in self.game.theater.controlpoints:
|
||||||
if not cp.ground_objects:
|
if not cp.ground_objects:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# -- Static ground objects
|
||||||
for i, ground_object in enumerate(cp.ground_objects):
|
for i, ground_object in enumerate(cp.ground_objects):
|
||||||
if ground_object.is_dead:
|
if ground_object.is_dead:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if ground_object.matches_string_identifier(object_identifier):
|
if ground_object.matches_string_identifier(destroyed_ground_unit_name):
|
||||||
logging.info("cp {} killing ground object {}".format(cp, ground_object.string_identifier))
|
logging.info("cp {} killing ground object {}".format(cp, ground_object.string_identifier))
|
||||||
cp.ground_objects[i].is_dead = True
|
cp.ground_objects[i].is_dead = True
|
||||||
|
|
||||||
|
# -- AA Site groups
|
||||||
|
for i, ground_object in enumerate(cp.ground_objects):
|
||||||
|
if ground_object.dcs_identifier == "AA":
|
||||||
|
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
|
||||||
|
|
||||||
def skip(self):
|
def skip(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@ -46,10 +46,12 @@ class FrontlineAttackEvent(Event):
|
|||||||
attacker_country = self.game.enemy_country
|
attacker_country = self.game.enemy_country
|
||||||
defender_country = self.game.player_country
|
defender_country = self.game.player_country
|
||||||
|
|
||||||
alive_attackers = sum([v for k, v in debriefing.alive_units.get(attacker_country, {}).items() if db.unit_task(k) == PinpointStrike])
|
# TODO : Rework
|
||||||
alive_defenders = sum([v for k, v in debriefing.alive_units.get(defender_country, {}).items() if db.unit_task(k) == PinpointStrike])
|
#alive_attackers = sum([v for k, v in debriefing.alive_units.get(attacker_country, {}).items() if db.unit_task(k) == PinpointStrike])
|
||||||
|
#alive_defenders = sum([v for k, v in debriefing.alive_units.get(defender_country, {}).items() if db.unit_task(k) == PinpointStrike])
|
||||||
|
#attackers_success = (float(alive_attackers) / (alive_defenders + 0.01)) > self.SUCCESS_FACTOR
|
||||||
|
attackers_success = True
|
||||||
|
|
||||||
attackers_success = (float(alive_attackers) / (alive_defenders + 0.01)) > self.SUCCESS_FACTOR
|
|
||||||
if self.from_cp.captured:
|
if self.from_cp.captured:
|
||||||
return attackers_success
|
return attackers_success
|
||||||
else:
|
else:
|
||||||
|
|||||||
@ -50,7 +50,6 @@ class BaseAttackOperation(Operation):
|
|||||||
|
|
||||||
def generate(self):
|
def generate(self):
|
||||||
self.armorgen.generate(self.attack, self.defense)
|
self.armorgen.generate(self.attack, self.defense)
|
||||||
self.aagen.generate(self.aa)
|
|
||||||
|
|
||||||
self.airgen.generate_defense(*assigned_units_split(self.intercept), at=self.defenders_starting_position)
|
self.airgen.generate_defense(*assigned_units_split(self.intercept), at=self.defenders_starting_position)
|
||||||
|
|
||||||
|
|||||||
@ -31,7 +31,6 @@ class InfantryTransportOperation(Operation):
|
|||||||
self.airgen.generate_passenger_transport(*assigned_units_split(self.transport), at=self.attackers_starting_position)
|
self.airgen.generate_passenger_transport(*assigned_units_split(self.transport), at=self.attackers_starting_position)
|
||||||
|
|
||||||
self.armorgen.generate_passengers(count=6)
|
self.armorgen.generate_passengers(count=6)
|
||||||
self.aagen.generate_at_defenders_location(self.aa)
|
|
||||||
|
|
||||||
self.visualgen.generate_transportation_marker(self.conflict.ground_attackers_location)
|
self.visualgen.generate_transportation_marker(self.conflict.ground_attackers_location)
|
||||||
self.visualgen.generate_transportation_destination(self.conflict.position)
|
self.visualgen.generate_transportation_destination(self.conflict.position)
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
from dcs.lua.parse import loads
|
from dcs.lua.parse import loads
|
||||||
|
|
||||||
from userdata.debriefing import *
|
|
||||||
|
|
||||||
from gen import *
|
from gen import *
|
||||||
|
from userdata.debriefing import *
|
||||||
|
|
||||||
TANKER_CALLSIGNS = ["Texaco", "Arco", "Shell"]
|
TANKER_CALLSIGNS = ["Texaco", "Arco", "Shell"]
|
||||||
|
|
||||||
@ -17,7 +16,6 @@ class Operation:
|
|||||||
conflict = None # type: Conflict
|
conflict = None # type: Conflict
|
||||||
armorgen = None # type: ArmorConflictGenerator
|
armorgen = None # type: ArmorConflictGenerator
|
||||||
airgen = None # type: AircraftConflictGenerator
|
airgen = None # type: AircraftConflictGenerator
|
||||||
aagen = None # type: AAConflictGenerator
|
|
||||||
extra_aagen = None # type: ExtraAAConflictGenerator
|
extra_aagen = None # type: ExtraAAConflictGenerator
|
||||||
shipgen = None # type: ShipGenerator
|
shipgen = None # type: ShipGenerator
|
||||||
triggersgen = None # type: TriggersGenerator
|
triggersgen = None # type: TriggersGenerator
|
||||||
@ -67,7 +65,6 @@ class Operation:
|
|||||||
self.conflict = conflict
|
self.conflict = conflict
|
||||||
self.armorgen = ArmorConflictGenerator(mission, conflict)
|
self.armorgen = ArmorConflictGenerator(mission, conflict)
|
||||||
self.airgen = AircraftConflictGenerator(mission, conflict, self.game.settings)
|
self.airgen = AircraftConflictGenerator(mission, conflict, self.game.settings)
|
||||||
self.aagen = AAConflictGenerator(mission, conflict)
|
|
||||||
self.shipgen = ShipGenerator(mission, conflict)
|
self.shipgen = ShipGenerator(mission, conflict)
|
||||||
self.airsupportgen = AirSupportConflictGenerator(mission, conflict, self.game)
|
self.airsupportgen = AirSupportConflictGenerator(mission, conflict, self.game)
|
||||||
self.triggersgen = TriggersGenerator(mission, conflict, self.game)
|
self.triggersgen = TriggersGenerator(mission, conflict, self.game)
|
||||||
@ -85,8 +82,6 @@ class Operation:
|
|||||||
with open("resources/default_options.lua", "r") as f:
|
with open("resources/default_options.lua", "r") as f:
|
||||||
options_dict = loads(f.read())["options"]
|
options_dict = loads(f.read())["options"]
|
||||||
|
|
||||||
dcs.Mission.aaa_vehicle_group = aaa.aaa_vehicle_group
|
|
||||||
|
|
||||||
self.current_mission = dcs.Mission(terrain)
|
self.current_mission = dcs.Mission(terrain)
|
||||||
|
|
||||||
if is_quick:
|
if is_quick:
|
||||||
@ -200,7 +195,10 @@ class Operation:
|
|||||||
load_dcs_libe = TriggerStart(comment="Load DCS Liberation Script")
|
load_dcs_libe = TriggerStart(comment="Load DCS Liberation Script")
|
||||||
with open(os.path.abspath("./resources/scripts/dcs_liberation.lua")) as f:
|
with open(os.path.abspath("./resources/scripts/dcs_liberation.lua")) as f:
|
||||||
script = f.read()
|
script = f.read()
|
||||||
script = script.replace("{{json_file_abs_location}}", "'"+os.path.abspath("./resources/scripts/json.lua"+"'"))
|
json_location = "[["+os.path.abspath("resources\\scripts\\json.lua")+"]]"
|
||||||
|
state_location = "[[" + os.path.abspath("state.json") + "]]"
|
||||||
|
script = script.replace("{{json_file_abs_location}}", json_location)
|
||||||
|
script = script.replace("{{debriefing_file_location}}", state_location)
|
||||||
load_dcs_libe.add_action(DoScript(String(script)))
|
load_dcs_libe.add_action(DoScript(String(script)))
|
||||||
self.current_mission.triggerrules.triggers.append(load_dcs_libe)
|
self.current_mission.triggerrules.triggers.append(load_dcs_libe)
|
||||||
|
|
||||||
|
|||||||
433
gen/aaa.py
433
gen/aaa.py
@ -1,441 +1,17 @@
|
|||||||
import random
|
|
||||||
import math
|
|
||||||
from .conflictgen import *
|
from .conflictgen import *
|
||||||
from .naming import *
|
from .naming import *
|
||||||
|
|
||||||
from dcs.mission import *
|
from dcs.mission import *
|
||||||
|
from dcs.mission import *
|
||||||
|
|
||||||
|
from .conflictgen import *
|
||||||
|
from .naming import *
|
||||||
|
|
||||||
DISTANCE_FACTOR = 0.5, 1
|
DISTANCE_FACTOR = 0.5, 1
|
||||||
EXTRA_AA_MIN_DISTANCE = 50000
|
EXTRA_AA_MIN_DISTANCE = 50000
|
||||||
EXTRA_AA_MAX_DISTANCE = 150000
|
EXTRA_AA_MAX_DISTANCE = 150000
|
||||||
EXTRA_AA_POSITION_FROM_CP = 550
|
EXTRA_AA_POSITION_FROM_CP = 550
|
||||||
|
|
||||||
|
|
||||||
def num_sam_dead(sam_type, destroyed_count):
|
|
||||||
"""
|
|
||||||
Given a type and count of SAM units, determine if enough units were destroyed to warrant the
|
|
||||||
loss of a site
|
|
||||||
:param sam_type:
|
|
||||||
inidivudal unit name in SAM site which was destroyed
|
|
||||||
:param destroyed_count:
|
|
||||||
count of that unit type which was destroyed *in the sortie*
|
|
||||||
:return:
|
|
||||||
INT: number of sites lost
|
|
||||||
"""
|
|
||||||
sam_threshold = {
|
|
||||||
AirDefence.SAM_SR_P_19: 1,
|
|
||||||
AirDefence.SAM_SA_3_S_125_TR_SNR: 1,
|
|
||||||
AirDefence.SAM_SA_6_Kub_STR_9S91: 1,
|
|
||||||
AirDefence.SAM_SA_10_S_300PS_SR_5N66M: 1,
|
|
||||||
AirDefence.SAM_SA_10_S_300PS_TR_30N6: 1,
|
|
||||||
AirDefence.SAM_SA_10_S_300PS_CP_54K6: 1,
|
|
||||||
AirDefence.SAM_SA_10_S_300PS_SR_64H6E: 1,
|
|
||||||
AirDefence.SAM_SA_3_S_125_LN_5P73: 4,
|
|
||||||
AirDefence.SAM_SA_6_Kub_LN_2P25: 6,
|
|
||||||
AirDefence.SAM_SA_10_S_300PS_LN_5P85C: 8,
|
|
||||||
AirDefence.SAM_SA_2_LN_SM_90:4,
|
|
||||||
AirDefence.SAM_SA_2_TR_SNR_75_Fan_Song: 1,
|
|
||||||
AirDefence.SAM_Hawk_PCP: 1,
|
|
||||||
AirDefence.SAM_Hawk_LN_M192: 4,
|
|
||||||
AirDefence.SAM_Hawk_SR_AN_MPQ_50: 1,
|
|
||||||
AirDefence.SAM_Hawk_TR_AN_MPQ_46: 1
|
|
||||||
}
|
|
||||||
|
|
||||||
return int(destroyed_count / sam_threshold[sam_type])
|
|
||||||
|
|
||||||
|
|
||||||
def determine_positions(position, heading, num_units, launcher_distance, coverage=90):
|
|
||||||
"""
|
|
||||||
Given a position on the map, array a group of units in a circle a uniform distance from the unit
|
|
||||||
:param position:
|
|
||||||
position of the center unit
|
|
||||||
:param heading:
|
|
||||||
the direction the units should be arranged toward if coverage is not 360
|
|
||||||
:param num_units:
|
|
||||||
number of units to play on the circle
|
|
||||||
:param launcher_distance:
|
|
||||||
distance the units should be from the center unit
|
|
||||||
:param coverage:
|
|
||||||
0-360
|
|
||||||
:return:
|
|
||||||
list of tuples representing each unit location
|
|
||||||
[(pos_x, pos_y, heading), ...]
|
|
||||||
"""
|
|
||||||
if coverage == 360:
|
|
||||||
# one of the positions is shared :'(
|
|
||||||
outer_offset = coverage / num_units
|
|
||||||
else:
|
|
||||||
outer_offset = coverage / (num_units - 1)
|
|
||||||
|
|
||||||
positions = []
|
|
||||||
|
|
||||||
if num_units % 2 == 0:
|
|
||||||
current_offset = heading - ((coverage / (num_units - 1)) / 2)
|
|
||||||
else:
|
|
||||||
current_offset = heading
|
|
||||||
current_offset -= outer_offset * (math.ceil(num_units / 2) - 1)
|
|
||||||
for x in range(1, num_units + 1):
|
|
||||||
positions.append((
|
|
||||||
position.x + launcher_distance * math.cos(math.radians(current_offset)),
|
|
||||||
position.y + launcher_distance * math.sin(math.radians(current_offset)),
|
|
||||||
current_offset,
|
|
||||||
))
|
|
||||||
current_offset += outer_offset
|
|
||||||
return positions
|
|
||||||
|
|
||||||
|
|
||||||
def aaa_vehicle_group(self, country, name, _type: unittype.VehicleType, position: mapping.Point,
|
|
||||||
heading=0, group_size=1,
|
|
||||||
formation=unitgroup.VehicleGroup.Formation.Line,
|
|
||||||
move_formation: PointAction=PointAction.OffRoad):
|
|
||||||
"""
|
|
||||||
Override the default vehicle group so that our group can contain a mix of units (which is required for advanced
|
|
||||||
SAM sites)
|
|
||||||
For further docstrings, see the built-in function
|
|
||||||
"""
|
|
||||||
vg = unitgroup.VehicleGroup(self.next_group_id(), self.string(name))
|
|
||||||
|
|
||||||
for i in range(1, group_size + 1):
|
|
||||||
heading = randint(0, 359)
|
|
||||||
if _type == AirDefence.SAM_SA_3_S_125_LN_5P73:
|
|
||||||
# 4 launchers (180 degrees all facing the same direction), 1 SR, 1 TR
|
|
||||||
num_launchers = 4
|
|
||||||
# search radar
|
|
||||||
v = self.vehicle(
|
|
||||||
name + " Unit #{nr}-sr".format(nr=i),
|
|
||||||
AirDefence.SAM_SR_P_19,
|
|
||||||
)
|
|
||||||
v.position.x = position.x
|
|
||||||
v.position.y = position.y + (i - 1) * 20
|
|
||||||
v.heading = heading
|
|
||||||
vg.add_unit(v)
|
|
||||||
# track radar
|
|
||||||
v = self.vehicle(
|
|
||||||
name + " Unit #{nr}-tr".format(nr=i),
|
|
||||||
AirDefence.SAM_SA_3_S_125_TR_SNR,
|
|
||||||
)
|
|
||||||
|
|
||||||
center_x = position.x + randint(20, 40)
|
|
||||||
center_y = position.y + (i - 1) * 20
|
|
||||||
|
|
||||||
v.position.x = center_x
|
|
||||||
v.position.y = center_y
|
|
||||||
v.heading = heading
|
|
||||||
vg.add_unit(v)
|
|
||||||
plop_positions = determine_positions(
|
|
||||||
position,
|
|
||||||
heading,
|
|
||||||
num_launchers,
|
|
||||||
launcher_distance=100,
|
|
||||||
coverage=180,
|
|
||||||
)
|
|
||||||
for x in range(0, num_launchers):
|
|
||||||
v = self.vehicle(
|
|
||||||
name + " Unit #{nr}-{x}".format(nr=i, x=x),
|
|
||||||
AirDefence.SAM_SA_3_S_125_LN_5P73,
|
|
||||||
)
|
|
||||||
|
|
||||||
v.position.x = plop_positions[x][0]
|
|
||||||
v.position.y = plop_positions[x][1]
|
|
||||||
v.heading = plop_positions[x][2]
|
|
||||||
vg.add_unit(v)
|
|
||||||
|
|
||||||
elif _type == AirDefence.SAM_SA_6_Kub_LN_2P25:
|
|
||||||
# 6 launchers (360 degree coverage)
|
|
||||||
# 1 S/TR
|
|
||||||
# search/track radar
|
|
||||||
num_launchers = 6
|
|
||||||
v = self.vehicle(
|
|
||||||
name + " Unit #{nr}-str".format(nr=i),
|
|
||||||
AirDefence.SAM_SA_6_Kub_STR_9S91,
|
|
||||||
)
|
|
||||||
v.position.x = position.x
|
|
||||||
v.position.y = position.y + (i - 1) * 20
|
|
||||||
v.heading = heading
|
|
||||||
vg.add_unit(v)
|
|
||||||
|
|
||||||
plop_positions = determine_positions(
|
|
||||||
position,
|
|
||||||
heading,
|
|
||||||
num_launchers,
|
|
||||||
launcher_distance=100,
|
|
||||||
coverage=360,
|
|
||||||
)
|
|
||||||
for x in range(0, num_launchers):
|
|
||||||
v = self.vehicle(
|
|
||||||
name + " Unit #{nr}-{x}".format(nr=i, x=x),
|
|
||||||
AirDefence.SAM_SA_6_Kub_LN_2P25,
|
|
||||||
)
|
|
||||||
|
|
||||||
v.position.x = plop_positions[x][0]
|
|
||||||
v.position.y = plop_positions[x][1]
|
|
||||||
v.heading = plop_positions[x][2]
|
|
||||||
vg.add_unit(v)
|
|
||||||
elif _type == AirDefence.SAM_SA_10_S_300PS_LN_5P85C:
|
|
||||||
# 8 launchers - 4 directions, two in each direction
|
|
||||||
# 1 SR (offset)
|
|
||||||
# 1 TR (center)
|
|
||||||
# search radar
|
|
||||||
num_launchers = 8
|
|
||||||
v = self.vehicle(
|
|
||||||
name + " Unit #{nr}-sr".format(nr=i),
|
|
||||||
AirDefence.SAM_SA_10_S_300PS_SR_5N66M,
|
|
||||||
)
|
|
||||||
v.position.x = position.x
|
|
||||||
v.position.y = position.y + (i - 1) * 20
|
|
||||||
v.heading = heading
|
|
||||||
vg.add_unit(v)
|
|
||||||
# track radar
|
|
||||||
v = self.vehicle(
|
|
||||||
name + " Unit #{nr}-tr".format(nr=i),
|
|
||||||
AirDefence.SAM_SA_10_S_300PS_TR_30N6,
|
|
||||||
)
|
|
||||||
|
|
||||||
center_x = position.x + randint(20, 40)
|
|
||||||
center_y = position.y + (i - 1) * 20
|
|
||||||
|
|
||||||
v.position.x = center_x
|
|
||||||
v.position.y = center_y
|
|
||||||
v.heading = heading
|
|
||||||
vg.add_unit(v)
|
|
||||||
|
|
||||||
# command center
|
|
||||||
v = self.vehicle(
|
|
||||||
name + " Unit #{nr}-c".format(nr=i),
|
|
||||||
AirDefence.SAM_SA_10_S_300PS_CP_54K6,
|
|
||||||
)
|
|
||||||
|
|
||||||
center_x = position.x + randint(40, 60)
|
|
||||||
center_y = position.y + (i - 1) * 20
|
|
||||||
|
|
||||||
v.position.x = center_x
|
|
||||||
v.position.y = center_y
|
|
||||||
v.heading = heading
|
|
||||||
vg.add_unit(v)
|
|
||||||
|
|
||||||
plop_positions = determine_positions(
|
|
||||||
position,
|
|
||||||
heading,
|
|
||||||
num_launchers,
|
|
||||||
launcher_distance=150,
|
|
||||||
coverage=360,
|
|
||||||
)
|
|
||||||
for x in range(0, num_launchers):
|
|
||||||
v = self.vehicle(
|
|
||||||
name + " Unit #{nr}-{x}".format(nr=i, x=x),
|
|
||||||
AirDefence.SAM_SA_10_S_300PS_LN_5P85C,
|
|
||||||
)
|
|
||||||
|
|
||||||
v.position.x = plop_positions[x][0]
|
|
||||||
v.position.y = plop_positions[x][1]
|
|
||||||
v.heading = plop_positions[x][2]
|
|
||||||
vg.add_unit(v)
|
|
||||||
|
|
||||||
elif _type == AirDefence.SAM_SA_10_S_300PS_CP_54K6:
|
|
||||||
# 8 launchers - 4 directions, two in each direction
|
|
||||||
# 1 SR (offset)
|
|
||||||
# 1 TR (center)
|
|
||||||
# search radar
|
|
||||||
num_launchers = 8
|
|
||||||
v = self.vehicle(
|
|
||||||
name + " Unit #{nr}-sr".format(nr=i),
|
|
||||||
AirDefence.SAM_SA_10_S_300PS_SR_64H6E,
|
|
||||||
)
|
|
||||||
v.position.x = position.x
|
|
||||||
v.position.y = position.y + (i - 1) * 20
|
|
||||||
v.heading = heading
|
|
||||||
vg.add_unit(v)
|
|
||||||
# track radar
|
|
||||||
v = self.vehicle(
|
|
||||||
name + " Unit #{nr}-tr".format(nr=i),
|
|
||||||
AirDefence.SAM_SA_10_S_300PS_TR_30N6,
|
|
||||||
)
|
|
||||||
|
|
||||||
center_x = position.x + randint(20, 40)
|
|
||||||
center_y = position.y + (i - 1) * 20
|
|
||||||
|
|
||||||
v.position.x = center_x
|
|
||||||
v.position.y = center_y
|
|
||||||
v.heading = heading
|
|
||||||
vg.add_unit(v)
|
|
||||||
|
|
||||||
# command center
|
|
||||||
v = self.vehicle(
|
|
||||||
name + " Unit #{nr}-c".format(nr=i),
|
|
||||||
AirDefence.SAM_SA_10_S_300PS_CP_54K6,
|
|
||||||
)
|
|
||||||
|
|
||||||
center_x = position.x + randint(40, 60)
|
|
||||||
center_y = position.y + (i - 1) * 20
|
|
||||||
|
|
||||||
v.position.x = center_x
|
|
||||||
v.position.y = center_y
|
|
||||||
v.heading = heading
|
|
||||||
vg.add_unit(v)
|
|
||||||
|
|
||||||
plop_positions = determine_positions(
|
|
||||||
position,
|
|
||||||
heading,
|
|
||||||
num_units=num_launchers,
|
|
||||||
launcher_distance=150,
|
|
||||||
coverage=360,
|
|
||||||
)
|
|
||||||
for x in range(0, num_launchers):
|
|
||||||
v = self.vehicle(
|
|
||||||
name + " Unit #{nr}-{x}".format(nr=i, x=x),
|
|
||||||
AirDefence.SAM_SA_10_S_300PS_LN_5P85D,
|
|
||||||
)
|
|
||||||
|
|
||||||
v.position.x = plop_positions[x][0]
|
|
||||||
v.position.y = plop_positions[x][1]
|
|
||||||
v.heading = plop_positions[x][2]
|
|
||||||
vg.add_unit(v)
|
|
||||||
elif _type == AirDefence.SAM_Hawk_PCP:
|
|
||||||
# 4 launchers (180 degrees all facing the same direction), 1 SR, 1 TR, 1 PCP
|
|
||||||
num_launchers = 4
|
|
||||||
|
|
||||||
# search radar
|
|
||||||
v = self.vehicle(
|
|
||||||
name + " Unit #{nr}-sr".format(nr=i),
|
|
||||||
AirDefence.SAM_Hawk_SR_AN_MPQ_50,
|
|
||||||
)
|
|
||||||
v.position.x = position.x
|
|
||||||
v.position.y = position.y + (i - 1) * 20
|
|
||||||
v.heading = heading
|
|
||||||
vg.add_unit(v)
|
|
||||||
|
|
||||||
|
|
||||||
# track radar
|
|
||||||
v = self.vehicle(
|
|
||||||
name + " Unit #{nr}-tr".format(nr=i),
|
|
||||||
AirDefence.SAM_Hawk_TR_AN_MPQ_46,
|
|
||||||
)
|
|
||||||
center_x = position.x + randint(20, 40)
|
|
||||||
center_y = position.y + (i - 1) * 20
|
|
||||||
v.position.x = center_x
|
|
||||||
v.position.y = center_y
|
|
||||||
v.heading = heading
|
|
||||||
vg.add_unit(v)
|
|
||||||
|
|
||||||
# PCP
|
|
||||||
v = self.vehicle(
|
|
||||||
name + " Unit #{nr}-pcp".format(nr=i),
|
|
||||||
AirDefence.SAM_Hawk_PCP,
|
|
||||||
)
|
|
||||||
|
|
||||||
center_x = position.x + randint(60, 80)
|
|
||||||
center_y = position.y + 20
|
|
||||||
v.position.x = center_x
|
|
||||||
v.position.y = center_y
|
|
||||||
v.heading = heading
|
|
||||||
vg.add_unit(v)
|
|
||||||
|
|
||||||
plop_positions = determine_positions(
|
|
||||||
position,
|
|
||||||
heading,
|
|
||||||
num_launchers,
|
|
||||||
launcher_distance=100,
|
|
||||||
coverage=180,
|
|
||||||
)
|
|
||||||
for x in range(0, num_launchers):
|
|
||||||
v = self.vehicle(
|
|
||||||
name + " Unit #{nr}-{x}".format(nr=i, x=x),
|
|
||||||
AirDefence.SAM_Hawk_LN_M192,
|
|
||||||
)
|
|
||||||
|
|
||||||
v.position.x = plop_positions[x][0]
|
|
||||||
v.position.y = plop_positions[x][1]
|
|
||||||
v.heading = plop_positions[x][2]
|
|
||||||
vg.add_unit(v)
|
|
||||||
elif _type == AirDefence.SAM_SA_2_LN_SM_90:
|
|
||||||
# 4 launchers (180 degrees all facing the same direction), 1 SR, 1 TR
|
|
||||||
num_launchers = 4
|
|
||||||
|
|
||||||
# search radar
|
|
||||||
v = self.vehicle(
|
|
||||||
name + " Unit #{nr}-sr".format(nr=i),
|
|
||||||
AirDefence.SAM_SR_P_19,
|
|
||||||
)
|
|
||||||
v.position.x = position.x
|
|
||||||
v.position.y = position.y + (i - 1) * 20
|
|
||||||
v.heading = heading
|
|
||||||
vg.add_unit(v)
|
|
||||||
|
|
||||||
|
|
||||||
# track radar
|
|
||||||
v = self.vehicle(
|
|
||||||
name + " Unit #{nr}-tr".format(nr=i),
|
|
||||||
AirDefence.SAM_SA_2_TR_SNR_75_Fan_Song,
|
|
||||||
)
|
|
||||||
center_x = position.x + randint(20, 40)
|
|
||||||
center_y = position.y + (i - 1) * 20
|
|
||||||
v.position.x = center_x
|
|
||||||
v.position.y = center_y
|
|
||||||
v.heading = heading
|
|
||||||
vg.add_unit(v)
|
|
||||||
|
|
||||||
plop_positions = determine_positions(
|
|
||||||
position,
|
|
||||||
heading,
|
|
||||||
num_launchers,
|
|
||||||
launcher_distance=100,
|
|
||||||
coverage=180,
|
|
||||||
)
|
|
||||||
for x in range(0, num_launchers):
|
|
||||||
v = self.vehicle(
|
|
||||||
name + " Unit #{nr}-{x}".format(nr=i, x=x),
|
|
||||||
AirDefence.SAM_SA_2_LN_SM_90,
|
|
||||||
)
|
|
||||||
|
|
||||||
v.position.x = plop_positions[x][0]
|
|
||||||
v.position.y = plop_positions[x][1]
|
|
||||||
v.heading = plop_positions[x][2]
|
|
||||||
vg.add_unit(v)
|
|
||||||
else:
|
|
||||||
v = self.vehicle(name + " Unit #{nr}-sam".format(nr=i), _type)
|
|
||||||
v.position.x = position.x
|
|
||||||
v.position.y = position.y + (i - 1) * 20
|
|
||||||
v.heading = heading
|
|
||||||
vg.add_unit(v)
|
|
||||||
|
|
||||||
wp = vg.add_waypoint(vg.units[0].position, move_formation, 0)
|
|
||||||
wp.ETA_locked = True
|
|
||||||
if _type.eplrs:
|
|
||||||
wp.tasks.append(task.EPLRS(self.next_eplrs("vehicle")))
|
|
||||||
|
|
||||||
country.add_vehicle_group(vg)
|
|
||||||
return vg
|
|
||||||
|
|
||||||
|
|
||||||
class AAConflictGenerator:
|
|
||||||
def __init__(self, mission: Mission, conflict: Conflict):
|
|
||||||
self.m = mission
|
|
||||||
self.conflict = conflict
|
|
||||||
|
|
||||||
def generate_at_defenders_location(self, units: db.AirDefenseDict):
|
|
||||||
for unit_type, count in units.items():
|
|
||||||
for _ in range(count):
|
|
||||||
self.m.vehicle_group(
|
|
||||||
country=self.conflict.defenders_country,
|
|
||||||
name=namegen.next_unit_name(self.conflict.defenders_country, unit_type),
|
|
||||||
_type=unit_type,
|
|
||||||
position=self.conflict.ground_defenders_location.random_point_within(100, 100),
|
|
||||||
group_size=1)
|
|
||||||
|
|
||||||
def generate(self, units: db.AirDefenseDict):
|
|
||||||
for type, count in units.items():
|
|
||||||
for _, radial in zip(range(count), self.conflict.radials):
|
|
||||||
distance = randint(self.conflict.size * DISTANCE_FACTOR[0] + 9000, self.conflict.size * DISTANCE_FACTOR[1] + 14000)
|
|
||||||
p = self.conflict.position.point_from_heading(random.choice(self.conflict.radials), distance)
|
|
||||||
|
|
||||||
self.m.aaa_vehicle_group(
|
|
||||||
country=self.conflict.defenders_country,
|
|
||||||
name=namegen.next_unit_name(self.conflict.defenders_country, type),
|
|
||||||
_type=type,
|
|
||||||
position=p,
|
|
||||||
group_size=1)
|
|
||||||
|
|
||||||
|
|
||||||
class ExtraAAConflictGenerator:
|
class ExtraAAConflictGenerator:
|
||||||
def __init__(self, mission: Mission, conflict: Conflict, game, player_country: Country, enemy_country: Country):
|
def __init__(self, mission: Mission, conflict: Conflict, game, player_country: Country, enemy_country: Country):
|
||||||
self.mission = mission
|
self.mission = mission
|
||||||
@ -445,7 +21,6 @@ class ExtraAAConflictGenerator:
|
|||||||
self.enemy_country = enemy_country
|
self.enemy_country = enemy_country
|
||||||
|
|
||||||
def generate(self):
|
def generate(self):
|
||||||
from theater.conflicttheater import ControlPoint
|
|
||||||
|
|
||||||
for cp in self.game.theater.controlpoints:
|
for cp in self.game.theater.controlpoints:
|
||||||
if cp.is_global:
|
if cp.is_global:
|
||||||
|
|||||||
@ -242,11 +242,11 @@ class AircraftConflictGenerator:
|
|||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
def _generate_escort(self, side: Country, units: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition, is_quick=False, should_orbit=False):
|
def _generate_escort(self, side: Country, units: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition, cp, is_quick=False, should_orbit=False):
|
||||||
groups = []
|
groups = []
|
||||||
for flying_type, count, client_count in self._split_to_groups(units, clients):
|
for flying_type, count, client_count in self._split_to_groups(units, clients):
|
||||||
group = self._generate_group(
|
group = self._generate_group(
|
||||||
name=namegen.next_unit_name(side, flying_type),
|
name=namegen.next_unit_name(side, cp.id, flying_type),
|
||||||
side=side,
|
side=side,
|
||||||
unit_type=flying_type,
|
unit_type=flying_type,
|
||||||
count=count,
|
count=count,
|
||||||
@ -279,7 +279,7 @@ class AircraftConflictGenerator:
|
|||||||
|
|
||||||
for flying_type, count, client_count in self._split_to_groups(attackers, clients):
|
for flying_type, count, client_count in self._split_to_groups(attackers, clients):
|
||||||
group = self._generate_group(
|
group = self._generate_group(
|
||||||
name=namegen.next_unit_name(self.conflict.attackers_country, flying_type),
|
name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type),
|
||||||
side=self.conflict.attackers_country,
|
side=self.conflict.attackers_country,
|
||||||
unit_type=flying_type,
|
unit_type=flying_type,
|
||||||
count=count,
|
count=count,
|
||||||
@ -313,7 +313,7 @@ class AircraftConflictGenerator:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
group = self._generate_at_airport(
|
group = self._generate_at_airport(
|
||||||
name=namegen.next_unit_name(country, type),
|
name=namegen.next_unit_name(country, cp.id, type),
|
||||||
side=country,
|
side=country,
|
||||||
unit_type=type,
|
unit_type=type,
|
||||||
count=number,
|
count=number,
|
||||||
@ -322,7 +322,7 @@ class AircraftConflictGenerator:
|
|||||||
start_type=StartType.Runway)
|
start_type=StartType.Runway)
|
||||||
except Exception:
|
except Exception:
|
||||||
group = self._generate_group(
|
group = self._generate_group(
|
||||||
name=namegen.next_unit_name(country, type),
|
name=namegen.next_unit_name(country, cp.id, type),
|
||||||
side=country,
|
side=country,
|
||||||
unit_type=type,
|
unit_type=type,
|
||||||
count=number,
|
count=number,
|
||||||
@ -360,7 +360,7 @@ class AircraftConflictGenerator:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
group = self._generate_at_airport(
|
group = self._generate_at_airport(
|
||||||
name=namegen.next_unit_name(country, type),
|
name=namegen.next_unit_name(country, cp.id, type),
|
||||||
side=country,
|
side=country,
|
||||||
unit_type=type,
|
unit_type=type,
|
||||||
count=number,
|
count=number,
|
||||||
@ -369,7 +369,7 @@ class AircraftConflictGenerator:
|
|||||||
start_type=StartType.Runway)
|
start_type=StartType.Runway)
|
||||||
except Exception:
|
except Exception:
|
||||||
group = self._generate_group(
|
group = self._generate_group(
|
||||||
name=namegen.next_unit_name(country, type),
|
name=namegen.next_unit_name(country, cp.id, type),
|
||||||
side=country,
|
side=country,
|
||||||
unit_type=type,
|
unit_type=type,
|
||||||
count=number,
|
count=number,
|
||||||
@ -413,7 +413,7 @@ class AircraftConflictGenerator:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
group = self._generate_at_airport(
|
group = self._generate_at_airport(
|
||||||
name=namegen.next_unit_name(country, type),
|
name=namegen.next_unit_name(country, cp.id, type),
|
||||||
side=country,
|
side=country,
|
||||||
unit_type=type,
|
unit_type=type,
|
||||||
count=number,
|
count=number,
|
||||||
@ -422,7 +422,7 @@ class AircraftConflictGenerator:
|
|||||||
start_type=StartType.Runway)
|
start_type=StartType.Runway)
|
||||||
except Exception:
|
except Exception:
|
||||||
group = self._generate_group(
|
group = self._generate_group(
|
||||||
name=namegen.next_unit_name(country, type),
|
name=namegen.next_unit_name(country, cp.id, type),
|
||||||
side=country,
|
side=country,
|
||||||
unit_type=type,
|
unit_type=type,
|
||||||
count=number,
|
count=number,
|
||||||
@ -450,7 +450,7 @@ class AircraftConflictGenerator:
|
|||||||
|
|
||||||
for flying_type, count, client_count in self._split_to_groups(strikegroup, clients):
|
for flying_type, count, client_count in self._split_to_groups(strikegroup, clients):
|
||||||
group = self._generate_group(
|
group = self._generate_group(
|
||||||
name=namegen.next_unit_name(self.conflict.attackers_country, flying_type),
|
name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type),
|
||||||
side=self.conflict.attackers_country,
|
side=self.conflict.attackers_country,
|
||||||
unit_type=flying_type,
|
unit_type=flying_type,
|
||||||
count=count,
|
count=count,
|
||||||
@ -476,7 +476,7 @@ class AircraftConflictGenerator:
|
|||||||
|
|
||||||
for flying_type, count, client_count in self._split_to_groups(strikegroup, clients):
|
for flying_type, count, client_count in self._split_to_groups(strikegroup, clients):
|
||||||
group = self._generate_group(
|
group = self._generate_group(
|
||||||
name=namegen.next_unit_name(self.conflict.attackers_country, flying_type),
|
name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type),
|
||||||
side=self.conflict.attackers_country,
|
side=self.conflict.attackers_country,
|
||||||
unit_type=flying_type,
|
unit_type=flying_type,
|
||||||
count=count,
|
count=count,
|
||||||
@ -502,7 +502,7 @@ class AircraftConflictGenerator:
|
|||||||
|
|
||||||
for flying_type, count, client_count in self._split_to_groups(defenders, clients):
|
for flying_type, count, client_count in self._split_to_groups(defenders, clients):
|
||||||
group = self._generate_group(
|
group = self._generate_group(
|
||||||
name=namegen.next_unit_name(self.conflict.attackers_country, flying_type),
|
name=namegen.next_unit_name(self.conflict.defenders_country, self.conflict.to_cp.id, flying_type),
|
||||||
side=self.conflict.defenders_country,
|
side=self.conflict.defenders_country,
|
||||||
unit_type=flying_type,
|
unit_type=flying_type,
|
||||||
count=count,
|
count=count,
|
||||||
@ -528,7 +528,7 @@ class AircraftConflictGenerator:
|
|||||||
|
|
||||||
for flying_type, count, client_count in self._split_to_groups(attackers, clients):
|
for flying_type, count, client_count in self._split_to_groups(attackers, clients):
|
||||||
group = self._generate_group(
|
group = self._generate_group(
|
||||||
name=namegen.next_unit_name(self.conflict.attackers_country, flying_type),
|
name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type),
|
||||||
side=self.conflict.attackers_country,
|
side=self.conflict.attackers_country,
|
||||||
unit_type=flying_type,
|
unit_type=flying_type,
|
||||||
count=count,
|
count=count,
|
||||||
@ -552,6 +552,7 @@ class AircraftConflictGenerator:
|
|||||||
clients=clients,
|
clients=clients,
|
||||||
at=at and at or self._group_point(self.conflict.air_attackers_location),
|
at=at and at or self._group_point(self.conflict.air_attackers_location),
|
||||||
is_quick=at is None,
|
is_quick=at is None,
|
||||||
|
cp=self.conflict.from_cp,
|
||||||
should_orbit=True):
|
should_orbit=True):
|
||||||
self._rtb_for(g, self.conflict.from_cp, at)
|
self._rtb_for(g, self.conflict.from_cp, at)
|
||||||
|
|
||||||
@ -562,13 +563,14 @@ class AircraftConflictGenerator:
|
|||||||
clients=clients,
|
clients=clients,
|
||||||
at=at and at or self._group_point(self.conflict.air_defenders_location),
|
at=at and at or self._group_point(self.conflict.air_defenders_location),
|
||||||
is_quick=at is None,
|
is_quick=at is None,
|
||||||
|
cp=self.conflict.to_cp,
|
||||||
should_orbit=False):
|
should_orbit=False):
|
||||||
self._rtb_for(g, self.conflict.to_cp, at)
|
self._rtb_for(g, self.conflict.to_cp, at)
|
||||||
|
|
||||||
def generate_defense(self, defenders: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None):
|
def generate_defense(self, defenders: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None):
|
||||||
for flying_type, count, client_count in self._split_to_groups(defenders, clients):
|
for flying_type, count, client_count in self._split_to_groups(defenders, clients):
|
||||||
group = self._generate_group(
|
group = self._generate_group(
|
||||||
name=namegen.next_unit_name(self.conflict.attackers_country, flying_type),
|
name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.to_cp.id, flying_type),
|
||||||
side=self.conflict.defenders_country,
|
side=self.conflict.defenders_country,
|
||||||
unit_type=flying_type,
|
unit_type=flying_type,
|
||||||
count=count,
|
count=count,
|
||||||
@ -585,7 +587,7 @@ class AircraftConflictGenerator:
|
|||||||
def generate_migcap(self, patrol: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None):
|
def generate_migcap(self, patrol: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None):
|
||||||
for flying_type, count, client_count in self._split_to_groups(patrol, clients):
|
for flying_type, count, client_count in self._split_to_groups(patrol, clients):
|
||||||
group = self._generate_group(
|
group = self._generate_group(
|
||||||
name=namegen.next_unit_name(self.conflict.attackers_country, flying_type),
|
name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type),
|
||||||
side=self.conflict.attackers_country,
|
side=self.conflict.attackers_country,
|
||||||
unit_type=flying_type,
|
unit_type=flying_type,
|
||||||
count=count,
|
count=count,
|
||||||
@ -603,7 +605,7 @@ class AircraftConflictGenerator:
|
|||||||
def generate_barcap(self, patrol: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None):
|
def generate_barcap(self, patrol: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None):
|
||||||
for flying_type, count, client_count in self._split_to_groups(patrol, clients):
|
for flying_type, count, client_count in self._split_to_groups(patrol, clients):
|
||||||
group = self._generate_group(
|
group = self._generate_group(
|
||||||
name=namegen.next_unit_name(self.conflict.attackers_country, flying_type),
|
name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type),
|
||||||
side=self.conflict.defenders_country,
|
side=self.conflict.defenders_country,
|
||||||
unit_type=flying_type,
|
unit_type=flying_type,
|
||||||
count=count,
|
count=count,
|
||||||
@ -629,7 +631,7 @@ class AircraftConflictGenerator:
|
|||||||
|
|
||||||
for flying_type, count, client_count in self._split_to_groups(transport):
|
for flying_type, count, client_count in self._split_to_groups(transport):
|
||||||
group = self._generate_group(
|
group = self._generate_group(
|
||||||
name=namegen.next_unit_name(self.conflict.attackers_country, flying_type),
|
name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type),
|
||||||
side=self.conflict.defenders_country,
|
side=self.conflict.defenders_country,
|
||||||
unit_type=flying_type,
|
unit_type=flying_type,
|
||||||
count=count,
|
count=count,
|
||||||
@ -647,7 +649,7 @@ class AircraftConflictGenerator:
|
|||||||
def generate_interception(self, interceptors: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None):
|
def generate_interception(self, interceptors: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None):
|
||||||
for flying_type, count, client_count in self._split_to_groups(interceptors, clients):
|
for flying_type, count, client_count in self._split_to_groups(interceptors, clients):
|
||||||
group = self._generate_group(
|
group = self._generate_group(
|
||||||
name=namegen.next_unit_name(self.conflict.attackers_country, flying_type),
|
name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type),
|
||||||
side=self.conflict.attackers_country,
|
side=self.conflict.attackers_country,
|
||||||
unit_type=flying_type,
|
unit_type=flying_type,
|
||||||
count=count,
|
count=count,
|
||||||
@ -669,7 +671,7 @@ class AircraftConflictGenerator:
|
|||||||
def generate_passenger_transport(self, helis: db.HeliDict, clients: db.HeliDict, at: db.StartingPosition):
|
def generate_passenger_transport(self, helis: db.HeliDict, clients: db.HeliDict, at: db.StartingPosition):
|
||||||
for heli_type, count, client_count in self._split_to_groups(helis, clients):
|
for heli_type, count, client_count in self._split_to_groups(helis, clients):
|
||||||
group = self._generate_group(
|
group = self._generate_group(
|
||||||
name=namegen.next_unit_name(self.conflict.attackers_country, heli_type),
|
name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, heli_type),
|
||||||
side=self.conflict.attackers_country,
|
side=self.conflict.attackers_country,
|
||||||
unit_type=heli_type,
|
unit_type=heli_type,
|
||||||
count=count,
|
count=count,
|
||||||
|
|||||||
@ -37,11 +37,17 @@ class ArmorConflictGenerator:
|
|||||||
return point.random_point_within(distance, self.conflict.size * SPREAD_DISTANCE_SIZE_FACTOR)
|
return point.random_point_within(distance, self.conflict.size * SPREAD_DISTANCE_SIZE_FACTOR)
|
||||||
|
|
||||||
def _generate_group(self, side: Country, unit: VehicleType, count: int, at: Point, to: Point = None, move_formation: PointAction = PointAction.OffRoad):
|
def _generate_group(self, side: Country, unit: VehicleType, count: int, at: Point, to: Point = None, move_formation: PointAction = PointAction.OffRoad):
|
||||||
|
|
||||||
|
if side == self.conflict.attackers_country:
|
||||||
|
cp = self.conflict.from_cp
|
||||||
|
else:
|
||||||
|
cp = self.conflict.to_cp
|
||||||
|
|
||||||
for c in range(count):
|
for c in range(count):
|
||||||
logging.info("armorgen: {} for {}".format(unit, side.id))
|
logging.info("armorgen: {} for {}".format(unit, side.id))
|
||||||
group = self.m.vehicle_group(
|
group = self.m.vehicle_group(
|
||||||
side,
|
side,
|
||||||
namegen.next_unit_name(side, unit),
|
namegen.next_unit_name(side, cp.id, unit),
|
||||||
unit,
|
unit,
|
||||||
position=self._group_point(at),
|
position=self._group_point(at),
|
||||||
group_size=1,
|
group_size=1,
|
||||||
|
|||||||
@ -4,9 +4,9 @@ from game import db
|
|||||||
class NameGenerator:
|
class NameGenerator:
|
||||||
number = 0
|
number = 0
|
||||||
|
|
||||||
def next_unit_name(self, country, unit_type):
|
def next_unit_name(self, country, parent_base_id, unit_type):
|
||||||
self.number += 1
|
self.number += 1
|
||||||
return "unit|{}|{}|{}|".format(country.id, self.number, db.unit_type_name(unit_type))
|
return "unit|{}|{}|{}|{}|".format(country.id, self.number, parent_base_id, db.unit_type_name(unit_type))
|
||||||
|
|
||||||
def next_basedefense_name(self):
|
def next_basedefense_name(self):
|
||||||
return "basedefense_aa|0|0|"
|
return "basedefense_aa|0|0|"
|
||||||
|
|||||||
@ -47,12 +47,6 @@ if __name__ == "__main__":
|
|||||||
copyfile("./resources/scripts/MissionScripting.lua", installation.get_dcs_install_directory() + os.path.sep + "Scripts/MissionScripting.lua")
|
copyfile("./resources/scripts/MissionScripting.lua", installation.get_dcs_install_directory() + os.path.sep + "Scripts/MissionScripting.lua")
|
||||||
app.processEvents()
|
app.processEvents()
|
||||||
|
|
||||||
# Create DCS Liberation script folder
|
|
||||||
script_dir = installation.get_dcs_saved_games_directory() + os.sep + "Scripts" + os.sep + "DCSLiberation"
|
|
||||||
if not os.path.exists(script_dir):
|
|
||||||
os.makedirs(script_dir)
|
|
||||||
copyfile("./resources/scripts/json.lua", script_dir + os.path.sep + "json.lua")
|
|
||||||
|
|
||||||
# Apply CSS (need works)
|
# Apply CSS (need works)
|
||||||
app.setStyleSheet(css)
|
app.setStyleSheet(css)
|
||||||
GameUpdateSignal()
|
GameUpdateSignal()
|
||||||
|
|||||||
11
qt_ui/widgets/QDebriefingInformation.py
Normal file
11
qt_ui/widgets/QDebriefingInformation.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
from PySide2.QtWidgets import QFrame
|
||||||
|
|
||||||
|
|
||||||
|
class QDebriefingInformation(QFrame):
|
||||||
|
"""
|
||||||
|
UI component to display debreifing informations
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(QDebriefingInformation, self).__init__()
|
||||||
|
self.init_ui()
|
||||||
@ -19,9 +19,6 @@ class QDebriefingWindow(QDialog):
|
|||||||
self.gameEvent = gameEvent
|
self.gameEvent = gameEvent
|
||||||
self.debriefing = debriefing
|
self.debriefing = debriefing
|
||||||
|
|
||||||
self.player_losses = debriefing.destroyed_units.get(self.game.player_country, {})
|
|
||||||
self.enemy_losses = debriefing.destroyed_units.get(self.game.enemy_country, {})
|
|
||||||
|
|
||||||
self.initUI()
|
self.initUI()
|
||||||
|
|
||||||
def initUI(self):
|
def initUI(self):
|
||||||
@ -44,7 +41,12 @@ class QDebriefingWindow(QDialog):
|
|||||||
lostUnits.setLayout(lostUnitsLayout)
|
lostUnits.setLayout(lostUnitsLayout)
|
||||||
|
|
||||||
row = 0
|
row = 0
|
||||||
for unit_type, count in self.player_losses.items():
|
for unit_type, count in self.debriefing.player_dead_aircraft_dict.items():
|
||||||
|
lostUnitsLayout.addWidget(QLabel(db.unit_type_name(unit_type)), row, 0)
|
||||||
|
lostUnitsLayout.addWidget(QLabel("{}".format(count)), row, 1)
|
||||||
|
row += 1
|
||||||
|
|
||||||
|
for unit_type, count in self.debriefing.player_dead_units_dict.items():
|
||||||
lostUnitsLayout.addWidget(QLabel(db.unit_type_name(unit_type)), row, 0)
|
lostUnitsLayout.addWidget(QLabel(db.unit_type_name(unit_type)), row, 0)
|
||||||
lostUnitsLayout.addWidget(QLabel("{}".format(count)), row, 1)
|
lostUnitsLayout.addWidget(QLabel("{}".format(count)), row, 1)
|
||||||
row += 1
|
row += 1
|
||||||
@ -56,13 +58,20 @@ class QDebriefingWindow(QDialog):
|
|||||||
enemylostUnitsLayout = QGridLayout()
|
enemylostUnitsLayout = QGridLayout()
|
||||||
enemylostUnits.setLayout(enemylostUnitsLayout)
|
enemylostUnits.setLayout(enemylostUnitsLayout)
|
||||||
|
|
||||||
row = 0
|
#row = 0
|
||||||
if self.debriefing.destroyed_objects:
|
#if self.debriefing.destroyed_objects:
|
||||||
enemylostUnitsLayout.addWidget(QLabel("Ground assets"), row, 0)
|
# enemylostUnitsLayout.addWidget(QLabel("Ground assets"), row, 0)
|
||||||
enemylostUnitsLayout.addWidget(QLabel("{}".format(len(self.debriefing.destroyed_objects))), row, 1)
|
# enemylostUnitsLayout.addWidget(QLabel("{}".format(len(self.debriefing.destroyed_objects))), row, 1)
|
||||||
|
# row += 1
|
||||||
|
|
||||||
|
for unit_type, count in self.debriefing.enemy_dead_aircraft_dict.items():
|
||||||
|
if count == 0:
|
||||||
|
continue
|
||||||
|
enemylostUnitsLayout.addWidget(QLabel(db.unit_type_name(unit_type)), row, 0)
|
||||||
|
enemylostUnitsLayout.addWidget(QLabel("{}".format(count)), row, 1)
|
||||||
row += 1
|
row += 1
|
||||||
|
|
||||||
for unit_type, count in self.enemy_losses.items():
|
for unit_type, count in self.debriefing.enemy_dead_units_dict.items():
|
||||||
if count == 0:
|
if count == 0:
|
||||||
continue
|
continue
|
||||||
enemylostUnitsLayout.addWidget(QLabel(db.unit_type_name(unit_type)), row, 0)
|
enemylostUnitsLayout.addWidget(QLabel(db.unit_type_name(unit_type)), row, 0)
|
||||||
|
|||||||
@ -1,14 +1,32 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from PySide2 import QtCore
|
from PySide2 import QtCore
|
||||||
|
from PySide2.QtCore import QObject, Signal
|
||||||
from PySide2.QtGui import QMovie, QIcon
|
from PySide2.QtGui import QMovie, QIcon
|
||||||
from PySide2.QtWidgets import QLabel, QDialog, QVBoxLayout
|
from PySide2.QtWidgets import QLabel, QDialog, QVBoxLayout, QGroupBox, QGridLayout, QPushButton
|
||||||
|
|
||||||
from game.game import Event, Game
|
from game.game import Event, Game
|
||||||
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
|
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
|
||||||
from userdata.debriefing import wait_for_debriefing, Debriefing
|
from userdata.debriefing import wait_for_debriefing, Debriefing
|
||||||
from userdata.persistency import base_path
|
from userdata.persistency import base_path
|
||||||
|
|
||||||
|
class DebriefingFileWrittenSignal(QObject):
|
||||||
|
|
||||||
|
instance = None
|
||||||
|
debriefingReceived = Signal(Debriefing)
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(DebriefingFileWrittenSignal, self).__init__()
|
||||||
|
DebriefingFileWrittenSignal.instance = self
|
||||||
|
|
||||||
|
def sendDebriefing(self, debriefing: Debriefing):
|
||||||
|
self.debriefingReceived.emit(debriefing)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_instance():
|
||||||
|
return DebriefingFileWrittenSignal.instance
|
||||||
|
|
||||||
|
DebriefingFileWrittenSignal()
|
||||||
|
|
||||||
class QWaitingForMissionResultWindow(QDialog):
|
class QWaitingForMissionResultWindow(QDialog):
|
||||||
|
|
||||||
@ -22,34 +40,67 @@ class QWaitingForMissionResultWindow(QDialog):
|
|||||||
self.setWindowIcon(QIcon("./resources/icon.png"))
|
self.setWindowIcon(QIcon("./resources/icon.png"))
|
||||||
|
|
||||||
self.initUi()
|
self.initUi()
|
||||||
wait_for_debriefing(lambda debriefing: self.process_debriefing(debriefing))
|
DebriefingFileWrittenSignal.get_instance().debriefingReceived.connect(self.updateLayout)
|
||||||
|
wait_for_debriefing(lambda debriefing: self.on_debriefing_udpate(debriefing), self.game)
|
||||||
|
|
||||||
def initUi(self):
|
def initUi(self):
|
||||||
self.layout = QVBoxLayout()
|
self.layout = QGridLayout()
|
||||||
self.layout.addWidget(QLabel("<b>You are clear for takeoff !</b>"))
|
self.gridLayout = QGridLayout()
|
||||||
self.layout.addWidget(QLabel("In DCS open and play the mission : "))
|
self.gridLayout.addWidget(QLabel("<b>You are clear for takeoff !</b>"),0,0)
|
||||||
self.layout.addWidget(QLabel("<i>liberation_nextturn</i>"))
|
self.gridLayout.addWidget(QLabel("In DCS open and start playing the mission : "),1,0)
|
||||||
self.layout.addWidget(QLabel("or"))
|
self.gridLayout.addWidget(QLabel("<i>liberation_nextturn</i>"),2,0)
|
||||||
self.layout.addWidget(QLabel("<i>liberation_nextturn_quick</i>"))
|
self.gridLayout.addWidget(QLabel("or"),3,0)
|
||||||
self.layout.addWidget(QLabel("<b>Then save the debriefing to the folder :</b>"))
|
self.gridLayout.addWidget(QLabel("<i>liberation_nextturn_quick</i>"),4,0)
|
||||||
self.layout.addWidget(QLabel(self.debriefing_directory_location()))
|
|
||||||
|
|
||||||
progress = QLabel("")
|
progress = QLabel("")
|
||||||
progress.setAlignment(QtCore.Qt.AlignCenter)
|
progress.setAlignment(QtCore.Qt.AlignCenter)
|
||||||
progressBar = QMovie("./resources/ui/loader.gif")
|
progressBar = QMovie("./resources/ui/loader.gif")
|
||||||
progress.setMovie(progressBar)
|
progress.setMovie(progressBar)
|
||||||
self.layout.addWidget(progress)
|
self.gridLayout.addWidget(progress,5,0)
|
||||||
progressBar.start()
|
progressBar.start()
|
||||||
|
self.layout.addLayout(self.gridLayout,0,0)
|
||||||
self.setLayout(self.layout)
|
self.setLayout(self.layout)
|
||||||
|
|
||||||
|
def updateLayout(self, debriefing):
|
||||||
|
updateBox = QGroupBox("Mission status")
|
||||||
|
updateLayout = QGridLayout()
|
||||||
|
updateBox.setLayout(updateLayout)
|
||||||
|
|
||||||
|
updateLayout.addWidget(QLabel("<b>Aircrafts destroyed</b>"), 0, 0)
|
||||||
|
updateLayout.addWidget(QLabel(str(len(debriefing.killed_aircrafts))), 0, 1)
|
||||||
|
|
||||||
|
updateLayout.addWidget(QLabel("<b>Ground units destroyed</b>"), 1, 0)
|
||||||
|
updateLayout.addWidget(QLabel(str(len(debriefing.killed_ground_units))), 1, 1)
|
||||||
|
|
||||||
|
updateLayout.addWidget(QLabel("<b>Weapons fired</b>"), 2, 0)
|
||||||
|
updateLayout.addWidget(QLabel(str(len(debriefing.weapons_fired))), 2, 1)
|
||||||
|
|
||||||
|
updateLayout.addWidget(QLabel("<b>Base Capture Events</b>"), 3, 0)
|
||||||
|
updateLayout.addWidget(QLabel(str(len(debriefing.base_capture_events))), 3, 1)
|
||||||
|
|
||||||
|
# Clear previous content of the window
|
||||||
|
for i in reversed(range(self.gridLayout.count())):
|
||||||
|
self.gridLayout.itemAt(i).widget().setParent(None)
|
||||||
|
|
||||||
|
# Set new window content
|
||||||
|
self.gridLayout.addWidget(updateBox, 0, 0)
|
||||||
|
|
||||||
|
if not debriefing.mission_ended:
|
||||||
|
self.gridLayout.addWidget(QLabel("<b>Mission is being played</b>"), 1, 0)
|
||||||
|
else:
|
||||||
|
#self.gridLayout.addWidget(QLabel("<b>Mission is over !</b>"), 1, 0)
|
||||||
|
proceed = QPushButton("Accept results")
|
||||||
|
proceed.setProperty("style", "btn-primary")
|
||||||
|
proceed.clicked.connect(lambda: self.process_debriefing(debriefing))
|
||||||
|
self.gridLayout.addWidget(proceed, 1, 0)
|
||||||
|
|
||||||
|
def on_debriefing_udpate(self, debriefing):
|
||||||
|
print("On Debriefing update")
|
||||||
|
print(debriefing)
|
||||||
|
DebriefingFileWrittenSignal.get_instance().sendDebriefing(debriefing)
|
||||||
|
wait_for_debriefing(lambda debriefing: self.on_debriefing_udpate(debriefing), self.game)
|
||||||
|
|
||||||
def process_debriefing(self, debriefing: Debriefing):
|
def process_debriefing(self, debriefing: Debriefing):
|
||||||
|
|
||||||
debriefing.calculate_units(regular_mission=self.gameEvent.operation.regular_mission,
|
|
||||||
quick_mission=self.gameEvent.operation.quick_mission,
|
|
||||||
player_country=self.game.player_country,
|
|
||||||
enemy_country=self.game.enemy_country)
|
|
||||||
|
|
||||||
self.game.finish_event(event=self.gameEvent, debriefing=debriefing)
|
self.game.finish_event(event=self.gameEvent, debriefing=debriefing)
|
||||||
self.game.pass_turn(ignored_cps=[self.gameEvent.to_cp, ])
|
self.game.pass_turn(ignored_cps=[self.gameEvent.to_cp, ])
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,15 @@
|
|||||||
local jsonlib = lfs.writedir() .. "Scripts\\DCSLiberation\\json.lua"
|
local jsonlib = {{json_file_abs_location}}
|
||||||
json = loadfile(jsonlib)()
|
json = loadfile(jsonlib)()
|
||||||
|
|
||||||
killed_aircrafts = {};
|
logger = mist.Logger:new("DCSLiberation", "info")
|
||||||
killed_ground_units = {};
|
|
||||||
|
debriefing_file_location = {{debriefing_file_location}}
|
||||||
|
|
||||||
|
killed_aircrafts = {}
|
||||||
|
killed_ground_units = {}
|
||||||
weapons_fired = {}
|
weapons_fired = {}
|
||||||
|
base_capture_events = {}
|
||||||
|
mission_ended = false
|
||||||
|
|
||||||
local function messageAll(message)
|
local function messageAll(message)
|
||||||
local msg = {}
|
local msg = {}
|
||||||
@ -14,23 +20,24 @@ local function messageAll(message)
|
|||||||
end
|
end
|
||||||
|
|
||||||
write_state = function()
|
write_state = function()
|
||||||
log("Writing DCS Liberation State...")
|
messageAll("Writing DCS Liberation State...")
|
||||||
local stateFile = lfs.writedir()..[[Scripts\DCSLiberation\state.json]]
|
local fp = io.open(debriefing_file_location, 'w')
|
||||||
local fp = io.open(stateFile, 'w')
|
|
||||||
local game_state = {
|
local game_state = {
|
||||||
["killed_aircrafts"] = killed_aircrafts,
|
["killed_aircrafts"] = killed_aircrafts,
|
||||||
["killed_ground_units"] = killed_ground_units,
|
["killed_ground_units"] = killed_ground_units,
|
||||||
["weapons_fired"] = weapons_fired,
|
["weapons_fired"] = weapons_fired,
|
||||||
|
["base_capture_events"] = base_capture_events,
|
||||||
|
["mission_ended"] = mission_ended,
|
||||||
}
|
}
|
||||||
fp:write(json:encode(game_state))
|
fp:write(json:encode(game_state))
|
||||||
fp:close()
|
fp:close()
|
||||||
log("Done writing DCS Liberation state.")
|
messageAll("Done writing DCS Liberation state.")
|
||||||
end
|
end
|
||||||
|
|
||||||
mist.scheduleFunction(write_state, {}, timer.getTime() + 10, 60, timer.getTime() + 3600)
|
mist.scheduleFunction(write_state, {}, timer.getTime() + 10, 60, timer.getTime() + 3600)
|
||||||
|
|
||||||
activeWeapons = {}
|
activeWeapons = {}
|
||||||
local function onCrash(event)
|
local function onEvent(event)
|
||||||
if event.id == world.event.S_EVENT_CRASH and event.initiator then
|
if event.id == world.event.S_EVENT_CRASH and event.initiator then
|
||||||
messageAll("Crash :" .. event.initiator.getName(event.initiator))
|
messageAll("Crash :" .. event.initiator.getName(event.initiator))
|
||||||
killed_aircrafts[#killed_aircrafts + 1] = event.initiator.getName(event.initiator)
|
killed_aircrafts[#killed_aircrafts + 1] = event.initiator.getName(event.initiator)
|
||||||
@ -43,8 +50,16 @@ local function onCrash(event)
|
|||||||
if event.id == world.event.S_EVENT_SHOT and event.weapon then
|
if event.id == world.event.S_EVENT_SHOT and event.weapon then
|
||||||
weapons_fired[#weapons_fired + 1] = event.weapon.getTypeName(event.weapon)
|
weapons_fired[#weapons_fired + 1] = event.weapon.getTypeName(event.weapon)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if event.id == world.event.S_EVENT_BASE_CAPTURED and event.place then
|
||||||
|
base_capture_events[#base_capture_events + 1] = event.place.getName(event.place) .. "||" .. event.place.getCoalition(event.place)
|
||||||
|
end
|
||||||
|
|
||||||
|
if event.id == world.event.S_EVENT_MISSION_END then
|
||||||
|
mission_ended = true
|
||||||
|
write_state()
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
mist.addEventHandler(onEvent)
|
||||||
|
|
||||||
mist.addEventHandler(onCrash)
|
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
@ -14,188 +15,97 @@ from .persistency import base_path
|
|||||||
|
|
||||||
DEBRIEFING_LOG_EXTENSION = "log"
|
DEBRIEFING_LOG_EXTENSION = "log"
|
||||||
|
|
||||||
|
class DebriefingDeadUnitInfo:
|
||||||
|
country_id = -1
|
||||||
|
player_unit = False
|
||||||
|
type = None
|
||||||
|
|
||||||
def parse_mutliplayer_debriefing(contents: str):
|
def __init__(self, country_id, player_unit , type):
|
||||||
result = {}
|
self.country_id = country_id
|
||||||
element = None
|
self.player_unit = player_unit
|
||||||
|
self.type = type
|
||||||
in_events = False
|
|
||||||
|
|
||||||
for line in [x.strip() for x in contents.splitlines()]:
|
|
||||||
if line.startswith("events ="):
|
|
||||||
in_events = True
|
|
||||||
elif line.startswith("} -- end of events"):
|
|
||||||
in_events = False
|
|
||||||
|
|
||||||
if not in_events:
|
|
||||||
continue
|
|
||||||
|
|
||||||
key = None
|
|
||||||
if line.startswith("initiator\t"):
|
|
||||||
key = "initiator"
|
|
||||||
if element is None:
|
|
||||||
element = {}
|
|
||||||
elif line.startswith("initiatorMissionID\t"):
|
|
||||||
key = "initiatorMissionID"
|
|
||||||
if element is None:
|
|
||||||
element = {}
|
|
||||||
elif line.startswith("type\t"):
|
|
||||||
key = "type"
|
|
||||||
if element is None:
|
|
||||||
element = {}
|
|
||||||
elif line.startswith("}, -- end of ["):
|
|
||||||
result[len(result)] = element
|
|
||||||
element = None
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
continue
|
|
||||||
|
|
||||||
value = re.findall(r"=\s*\"(.*?)\",", line)[0]
|
|
||||||
element[key] = value
|
|
||||||
|
|
||||||
return {"debriefing": {"events": result}}
|
|
||||||
|
|
||||||
|
|
||||||
class Debriefing:
|
class Debriefing:
|
||||||
def __init__(self, dead_units, dead_units_name, trigger_state):
|
def __init__(self, state_data, game):
|
||||||
self.destroyed_units = {} # type: typing.Dict[str, typing.Dict[UnitType, int]]
|
self.base_capture_events = state_data["base_capture_events"]
|
||||||
self.alive_units = {} # type: typing.Dict[str, typing.Dict[UnitType, int]]
|
self.killed_aircrafts = state_data["killed_aircrafts"]
|
||||||
self.destroyed_objects = [] # type: typing.List[str]
|
self.killed_ground_units = state_data["killed_ground_units"]
|
||||||
|
self.weapons_fired = state_data["weapons_fired"]
|
||||||
|
self.mission_ended = state_data["mission_ended"]
|
||||||
|
|
||||||
self._trigger_state = trigger_state
|
self.player_country_id = db.country_id_from_name(game.player_country)
|
||||||
self._dead_units = dead_units
|
self.enemy_country_id = db.country_id_from_name(game.enemy_country)
|
||||||
self.dead_units_name = dead_units_name
|
|
||||||
|
|
||||||
@classmethod
|
self.dead_aircraft = []
|
||||||
def parse(cls, path: str):
|
self.dead_units = []
|
||||||
dead_units = []
|
|
||||||
dead_units_name = []
|
|
||||||
|
|
||||||
def append_dead_object(object_mission_id_str, object_name):
|
for aircraft in self.killed_aircrafts:
|
||||||
nonlocal dead_units
|
|
||||||
object_mission_id = int(object_mission_id_str)
|
|
||||||
if object_mission_id in dead_units:
|
|
||||||
logging.error("debriefing: failed to append_dead_object {}: already exists!".format(object_mission_id))
|
|
||||||
return
|
|
||||||
|
|
||||||
dead_units.append(object_mission_id)
|
|
||||||
dead_units_name.append(object_name)
|
|
||||||
|
|
||||||
def parse_dead_object(event):
|
|
||||||
print(event)
|
|
||||||
try:
|
try:
|
||||||
append_dead_object(event["initiatorMissionID"], event["initiator"])
|
country = int(aircraft.split("|")[1])
|
||||||
|
type = db.unit_type_from_name(aircraft.split("|")[4])
|
||||||
|
player_unit = (country == self.player_country_id)
|
||||||
|
aircraft = DebriefingDeadUnitInfo(country, player_unit, type)
|
||||||
|
self.dead_aircraft.append(aircraft)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(e)
|
print(e)
|
||||||
|
|
||||||
with open(path, "r") as f:
|
for unit in self.killed_ground_units:
|
||||||
table_string = f.read()
|
|
||||||
try:
|
try:
|
||||||
table = parse.loads(table_string)
|
country = int(unit.split("|")[1])
|
||||||
|
type = db.unit_type_from_name(unit.split("|")[4])
|
||||||
|
player_unit = (country == self.player_country_id)
|
||||||
|
unit = DebriefingDeadUnitInfo(country, player_unit, type)
|
||||||
|
self.dead_units.append(unit)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
table = parse_mutliplayer_debriefing(table_string)
|
print(e)
|
||||||
|
|
||||||
events = table.get("debriefing", {}).get("events", {})
|
self.player_dead_aircraft = [a for a in self.dead_aircraft if a.country_id == self.player_country_id]
|
||||||
for event in events.values():
|
self.enemy_dead_aircraft = [a for a in self.dead_aircraft if a.country_id == self.enemy_country_id]
|
||||||
event_type = event.get("type", None)
|
self.player_dead_units = [a for a in self.dead_units if a.country_id == self.player_country_id]
|
||||||
if event_type in ["crash", "dead"]:
|
self.enemy_dead_units = [a for a in self.dead_units if a.country_id == self.enemy_country_id]
|
||||||
parse_dead_object(event)
|
|
||||||
|
|
||||||
trigger_state = table.get("debriefing", {}).get("triggers_state", {})
|
self.player_dead_aircraft_dict = {}
|
||||||
|
for a in self.player_dead_aircraft:
|
||||||
|
if a.type in self.player_dead_aircraft_dict.keys():
|
||||||
|
self.player_dead_aircraft_dict[a.type] = self.player_dead_aircraft_dict[a.type] + 1
|
||||||
|
else:
|
||||||
|
self.player_dead_aircraft_dict[a.type] = 1
|
||||||
|
|
||||||
return Debriefing(dead_units, dead_units_name, trigger_state)
|
self.enemy_dead_aircraft_dict = {}
|
||||||
|
for a in self.enemy_dead_aircraft:
|
||||||
|
if a.type in self.enemy_dead_aircraft_dict.keys():
|
||||||
|
self.enemy_dead_aircraft_dict[a.type] = self.enemy_dead_aircraft_dict[a.type] + 1
|
||||||
|
else:
|
||||||
|
self.enemy_dead_aircraft_dict[a.type] = 1
|
||||||
|
|
||||||
def calculate_units(self, regular_mission: Mission, quick_mission: Mission, player_country: str, enemy_country: str):
|
self.player_dead_units_dict = {}
|
||||||
def count_groups(groups: typing.List[UnitType]) -> typing.Dict[UnitType, int]:
|
for a in self.player_dead_units:
|
||||||
result = {}
|
if a.type in self.player_dead_units_dict.keys():
|
||||||
for group in groups:
|
self.player_dead_units_dict[a.type] = self.player_dead_units_dict[a.type] + 1
|
||||||
for unit in group.units:
|
else:
|
||||||
unit_type = db.unit_type_of(unit)
|
self.player_dead_units_dict[a.type] = 1
|
||||||
if unit_type in db.EXTRA_AA.values():
|
|
||||||
continue
|
|
||||||
|
|
||||||
result[unit_type] = result.get(unit_type, 0) + 1
|
self.enemy_dead_units_dict = {}
|
||||||
|
for a in self.enemy_dead_units:
|
||||||
|
if a.type in self.enemy_dead_units_dict.keys():
|
||||||
|
self.enemy_dead_units_dict[a.type] = self.enemy_dead_units_dict[a.type] + 1
|
||||||
|
else:
|
||||||
|
self.enemy_dead_units_dict[a.type] = 1
|
||||||
|
|
||||||
return result
|
def _poll_new_debriefing_log(callback: typing.Callable, game):
|
||||||
|
if os.path.isfile("state.json"):
|
||||||
mission = regular_mission if len(self._trigger_state) else quick_mission
|
last_modified = os.path.getmtime("state.json")
|
||||||
|
else:
|
||||||
player = mission.country(player_country)
|
last_modified = 0
|
||||||
enemy = mission.country(enemy_country)
|
while True:
|
||||||
|
if os.path.isfile("state.json") and os.path.getmtime("state.json") > last_modified:
|
||||||
player_units = count_groups(player.plane_group + player.vehicle_group + player.ship_group)
|
with open("state.json", "r") as json_file:
|
||||||
enemy_units = count_groups(enemy.plane_group + enemy.vehicle_group + enemy.ship_group)
|
json_data = json.load(json_file) #Debriefing.parse(os.path.join(debriefing_directory_location(), file))
|
||||||
|
debriefing = Debriefing(json_data, game)
|
||||||
self.destroyed_units = {
|
|
||||||
player.name: {},
|
|
||||||
enemy.name: {},
|
|
||||||
}
|
|
||||||
|
|
||||||
all_groups = {
|
|
||||||
player.name: player.plane_group + player.helicopter_group + player.vehicle_group + player.ship_group,
|
|
||||||
enemy.name: enemy.plane_group + enemy.helicopter_group + enemy.vehicle_group + enemy.ship_group,
|
|
||||||
}
|
|
||||||
|
|
||||||
static_groups = enemy.static_group
|
|
||||||
|
|
||||||
for country_name, country_groups in all_groups.items():
|
|
||||||
for group in country_groups:
|
|
||||||
for unit in group.units:
|
|
||||||
if unit.id in self._dead_units:
|
|
||||||
unit_type = db.unit_type_of(unit)
|
|
||||||
logging.info("debriefing: found dead unit {} ({}, {}) for country {}".format(str(unit.name), unit.id, unit_type, country_name))
|
|
||||||
|
|
||||||
assert country_name
|
|
||||||
assert unit_type
|
|
||||||
self.destroyed_units[country_name][unit_type] = self.destroyed_units[country_name].get(unit_type, 0) + 1
|
|
||||||
self._dead_units.remove(unit.id)
|
|
||||||
|
|
||||||
for group in static_groups:
|
|
||||||
identifier = group.units[0].id
|
|
||||||
if identifier in self._dead_units:
|
|
||||||
logging.info("debriefing: found dead static {} ({})".format(str(group.name), identifier))
|
|
||||||
|
|
||||||
assert str(group.name)
|
|
||||||
self.destroyed_objects.append(str(group.name))
|
|
||||||
self._dead_units.remove(identifier)
|
|
||||||
|
|
||||||
logging.info("debriefing: unsatistied ids: {}".format(self._dead_units))
|
|
||||||
|
|
||||||
self.alive_units = {
|
|
||||||
player.name: {k: v - self.destroyed_units[player.name].get(k, 0) for k, v in player_units.items()},
|
|
||||||
enemy.name: {k: v - self.destroyed_units[enemy.name].get(k, 0) for k, v in enemy_units.items()},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def debriefing_directory_location() -> str:
|
|
||||||
return os.path.join(base_path(), "liberation_debriefings")
|
|
||||||
|
|
||||||
|
|
||||||
def _logfiles_snapshot() -> typing.Dict[str, float]:
|
|
||||||
result = {}
|
|
||||||
for file in os.listdir(debriefing_directory_location()):
|
|
||||||
fullpath = os.path.join(debriefing_directory_location(), file)
|
|
||||||
result[file] = os.path.getmtime(fullpath)
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def _poll_new_debriefing_log(snapshot: typing.Dict[str, float], callback: typing.Callable):
|
|
||||||
should_run = True
|
|
||||||
while should_run:
|
|
||||||
for file, timestamp in _logfiles_snapshot().items():
|
|
||||||
if file not in snapshot or timestamp != snapshot[file]:
|
|
||||||
debriefing = Debriefing.parse(os.path.join(debriefing_directory_location(), file))
|
|
||||||
callback(debriefing)
|
callback(debriefing)
|
||||||
should_run = False
|
break
|
||||||
break
|
time.sleep(5)
|
||||||
|
|
||||||
time.sleep(3)
|
def wait_for_debriefing(callback: typing.Callable, game):
|
||||||
|
threading.Thread(target=_poll_new_debriefing_log, args=[callback, game]).start()
|
||||||
|
|
||||||
def wait_for_debriefing(callback: typing.Callable):
|
|
||||||
if not os.path.exists(debriefing_directory_location()):
|
|
||||||
os.mkdir(debriefing_directory_location())
|
|
||||||
|
|
||||||
threading.Thread(target=_poll_new_debriefing_log, args=(_logfiles_snapshot(), callback)).start()
|
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,8 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
|
from dcs import installation
|
||||||
|
|
||||||
_user_folder = None # type: str
|
_user_folder = None # type: str
|
||||||
|
|
||||||
|
|
||||||
@ -17,6 +19,7 @@ def base_path() -> str:
|
|||||||
global _user_folder
|
global _user_folder
|
||||||
assert _user_folder
|
assert _user_folder
|
||||||
|
|
||||||
|
return installation.get_dcs_saved_games_directory()
|
||||||
openbeta_path = os.path.join(_user_folder, "DCS.openbeta")
|
openbeta_path = os.path.join(_user_folder, "DCS.openbeta")
|
||||||
if "--force-stable-DCS" not in sys.argv and os.path.exists(openbeta_path):
|
if "--force-stable-DCS" not in sys.argv and os.path.exists(openbeta_path):
|
||||||
return openbeta_path
|
return openbeta_path
|
||||||
|
|||||||
10
userdata/state.py
Normal file
10
userdata/state.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
class RunningMissionState:
|
||||||
|
|
||||||
|
killed_aircrafts = []
|
||||||
|
killed_ground_units = []
|
||||||
|
weapons_fired = []
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
Loading…
x
Reference in New Issue
Block a user