debriefing based on events, not world state WIP

This commit is contained in:
Vasiliy Horbachenko 2018-07-12 05:12:01 +03:00
parent d2aede593b
commit 4ce7480df8
10 changed files with 83 additions and 114 deletions

1
.idea/modules.xml generated
View File

@ -3,6 +3,7 @@
<component name="ProjectModuleManager"> <component name="ProjectModuleManager">
<modules> <modules>
<module fileurl="file://$PROJECT_DIR$/.idea/dcs_pmcliberation.iml" filepath="$PROJECT_DIR$/.idea/dcs_pmcliberation.iml" /> <module fileurl="file://$PROJECT_DIR$/.idea/dcs_pmcliberation.iml" filepath="$PROJECT_DIR$/.idea/dcs_pmcliberation.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/dcs_pmcliberation.iml" filepath="$PROJECT_DIR$/.idea/dcs_pmcliberation.iml" />
</modules> </modules>
</component> </component>
</project> </project>

View File

@ -400,6 +400,17 @@ def unit_type_name(unit_type) -> str:
return unit_type.id and unit_type.id or unit_type.name return unit_type.id and unit_type.id or unit_type.name
def unit_type_from_name(name: str) -> UnitType:
if name in vehicle_map:
return vehicle_map[name]
elif name in plane_map:
return plane_map[name]
elif name in ship_map:
return ship_map[name]
else:
return None
def task_name(task) -> str: def task_name(task) -> str:
if task == AirDefence: if task == AirDefence:
return "AirDefence" return "AirDefence"

View File

@ -21,7 +21,7 @@ class AAConflictGenerator:
for _ in range(count): for _ in range(count):
self.m.vehicle_group( self.m.vehicle_group(
country=self.conflict.defenders_side, country=self.conflict.defenders_side,
name=namegen.next_ground_group_name(), name=namegen.next_unit_name(self.conflict.defenders_side, unit_type),
_type=unit_type, _type=unit_type,
position=self.conflict.ground_defenders_location.random_point_within(100, 100), position=self.conflict.ground_defenders_location.random_point_within(100, 100),
group_size=1) group_size=1)
@ -34,7 +34,7 @@ class AAConflictGenerator:
self.m.vehicle_group( self.m.vehicle_group(
country=self.conflict.defenders_side, country=self.conflict.defenders_side,
name=namegen.next_ground_group_name(), name=namegen.next_unit_name(self.conflict.defenders_side, type),
_type=type, _type=type,
position=p, position=p,
group_size=1) group_size=1)
@ -66,7 +66,7 @@ class ExtraAAConflictGenerator:
self.mission.vehicle_group( self.mission.vehicle_group(
country=self.mission.country(country_name), country=self.mission.country(country_name),
name=namegen.next_ground_group_name(), name=namegen.next_basedefense_name(),
_type=db.EXTRA_AA[country_name], _type=db.EXTRA_AA[country_name],
position=position, position=position,
group_size=2 group_size=2

View File

@ -188,7 +188,7 @@ class AircraftConflictGenerator:
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_escort_group_name(), name=namegen.next_unit_name(side, flying_type),
side=side, side=side,
unit_type=flying_type, unit_type=flying_type,
count=count, count=count,
@ -225,7 +225,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_cas_group_name(), name=namegen.next_unit_name(self.conflict.attackers_side, flying_type),
side=self.conflict.attackers_side, side=self.conflict.attackers_side,
unit_type=flying_type, unit_type=flying_type,
count=count, count=count,
@ -243,7 +243,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_cas_group_name(), name=namegen.next_unit_name(self.conflict.attackers_side, flying_type),
side=self.conflict.attackers_side, side=self.conflict.attackers_side,
unit_type=flying_type, unit_type=flying_type,
count=count, count=count,
@ -282,7 +282,7 @@ class AircraftConflictGenerator:
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_intercept_group_name(), name=namegen.next_unit_name(self.conflict.defenders_side, flying_type),
side=self.conflict.defenders_side, side=self.conflict.defenders_side,
unit_type=flying_type, unit_type=flying_type,
count=count, count=count,
@ -301,7 +301,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_transport_group_name(), name=namegen.next_unit_name(self.conflict.defenders_side, flying_type),
side=self.conflict.defenders_side, side=self.conflict.defenders_side,
unit_type=flying_type, unit_type=flying_type,
count=count, count=count,
@ -317,7 +317,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_intercept_group_name(), name=namegen.next_unit_name(self.conflict.attackers_side, flying_type),
side=self.conflict.attackers_side, side=self.conflict.attackers_side,
unit_type=flying_type, unit_type=flying_type,
count=count, count=count,
@ -338,7 +338,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_transport_group_name(), name=namegen.next_unit_name(self.conflict.attackers_side, heli_type),
side=self.conflict.attackers_side, side=self.conflict.attackers_side,
unit_type=heli_type, unit_type=heli_type,
count=count, count=count,

View File

@ -29,7 +29,7 @@ class ArmorConflictGenerator:
for c in range(count): for c in range(count):
group = self.m.vehicle_group( group = self.m.vehicle_group(
side, side,
namegen.next_armor_group_name(), namegen.next_unit_name(side, unit),
unit, unit,
position=self._group_point(at), position=self._group_point(at),
group_size=1, group_size=1,
@ -57,7 +57,7 @@ class ArmorConflictGenerator:
self.m.vehicle_group( self.m.vehicle_group(
country=self.conflict.attackers_side, country=self.conflict.attackers_side,
name=namegen.next_passenger_group_name(), name=namegen.next_unit_name(self.conflict.attackers_side, unit_type),
_type=unit_type, _type=unit_type,
position=self.conflict.ground_attackers_location, position=self.conflict.ground_attackers_location,
group_size=count group_size=count

View File

@ -95,7 +95,7 @@ class Conflict:
self.air_defenders_location = air_defenders_location self.air_defenders_location = air_defenders_location
@classmethod @classmethod
def _frontline_position(cls, from_cp: ControlPoint, to_cp: ControlPoint): def frontline_position(cls, from_cp: ControlPoint, to_cp: ControlPoint):
distance = max(from_cp.position.distance_to_point(to_cp.position) * FRONT_SMOKE_DISTANCE_FACTOR * to_cp.base.strength, FRONT_SMOKE_MIN_DISTANCE) distance = max(from_cp.position.distance_to_point(to_cp.position) * FRONT_SMOKE_DISTANCE_FACTOR * to_cp.base.strength, FRONT_SMOKE_MIN_DISTANCE)
heading = to_cp.position.heading_between_point(from_cp.position) heading = to_cp.position.heading_between_point(from_cp.position)
return to_cp.position.point_from_heading(heading, distance) return to_cp.position.point_from_heading(heading, distance)
@ -187,7 +187,7 @@ class Conflict:
@classmethod @classmethod
def ground_intercept_conflict(cls, attacker: Country, defender: Country, from_cp: ControlPoint, to_cp: ControlPoint, theater: ConflictTheater): def ground_intercept_conflict(cls, attacker: Country, defender: Country, from_cp: ControlPoint, to_cp: ControlPoint, theater: ConflictTheater):
heading = to_cp.position.heading_between_point(from_cp.position) heading = to_cp.position.heading_between_point(from_cp.position)
initial_location = cls._frontline_position(from_cp, to_cp).random_point_within(GROUND_INTERCEPT_SPREAD) initial_location = cls.frontline_position(from_cp, to_cp).random_point_within(GROUND_INTERCEPT_SPREAD)
position = Conflict._find_ground_location(initial_location, GROUND_INTERCEPT_SPREAD, heading, theater) position = Conflict._find_ground_location(initial_location, GROUND_INTERCEPT_SPREAD, heading, theater)
if not position: if not position:
heading = to_cp.find_radial(to_cp.position.heading_between_point(from_cp.position)) heading = to_cp.find_radial(to_cp.position.heading_between_point(from_cp.position))
@ -257,7 +257,7 @@ class Conflict:
@classmethod @classmethod
def transport_conflict(cls, attacker: Country, defender: Country, from_cp: ControlPoint, to_cp: ControlPoint, theater: ConflictTheater): def transport_conflict(cls, attacker: Country, defender: Country, from_cp: ControlPoint, to_cp: ControlPoint, theater: ConflictTheater):
frontline_position = cls._frontline_position(from_cp, to_cp) frontline_position = cls.frontline_position(from_cp, to_cp)
heading = to_cp.position.heading_between_point(from_cp.position) heading = to_cp.position.heading_between_point(from_cp.position)
initial_dest = frontline_position.point_from_heading(heading, TRANSPORT_FRONTLINE_DIST) initial_dest = frontline_position.point_from_heading(heading, TRANSPORT_FRONTLINE_DIST)
dest = cls._find_ground_location(initial_dest, from_cp.position.distance_to_point(to_cp.position) / 3, heading, theater) dest = cls._find_ground_location(initial_dest, from_cp.position.distance_to_point(to_cp.position) / 3, heading, theater)

View File

@ -1,37 +1,15 @@
from game import db
class NameGenerator: class NameGenerator:
number = 0 number = 0
def next_armor_group_name(self): def next_unit_name(self, country, unit_type):
self.number += 1 self.number += 1
return "Armor Unit {}".format(self.number) return "{}|{}|{}".format(country.id, self.number, db.unit_type_name(unit_type))
def next_cas_group_name(self): def next_basedefense_name(self):
self.number += 1 return "basedefense_aa"
return "CAS Unit {}".format(self.number)
def next_escort_group_name(self):
self.number += 1
return "Escort Unit {}".format(self.number)
def next_intercept_group_name(self):
self.number += 1
return "Intercept Unit {}".format(self.number)
def next_ground_group_name(self):
self.number += 1
return "AA Unit {}".format(self.number)
def next_transport_group_name(self):
self.number += 1
return "Transport Unit {}".format(self.number)
def next_awacs_group_name(self):
self.number += 1
return "AWACS Unit {}".format(self.number)
def next_passenger_group_name(self):
self.number += 1
return "Infantry Unit {}".format(self.number)
namegen = NameGenerator() namegen = NameGenerator()

View File

@ -99,7 +99,7 @@ class VisualGenerator:
def _generate_frontline_smokes(self): def _generate_frontline_smokes(self):
for from_cp, to_cp in self.game.theater.conflicts(): for from_cp, to_cp in self.game.theater.conflicts():
heading = to_cp.position.heading_between_point(from_cp.position) heading = to_cp.position.heading_between_point(from_cp.position)
point = Conflict._frontline_position(from_cp, to_cp) point = Conflict.frontline_position(from_cp, to_cp)
plane_start = point.point_from_heading(turn_heading(heading, 90), FRONT_SMOKE_LENGTH / 2) plane_start = point.point_from_heading(turn_heading(heading, 90), FRONT_SMOKE_LENGTH / 2)
for offset in range(0, FRONT_SMOKE_LENGTH, FRONT_SMOKE_SPACING): for offset in range(0, FRONT_SMOKE_LENGTH, FRONT_SMOKE_SPACING):

View File

@ -65,9 +65,9 @@ class EventResultsMenu(Menu):
def process_debriefing(self, debriefing: Debriefing): def process_debriefing(self, debriefing: Debriefing):
self.debriefing = debriefing self.debriefing = debriefing
debriefing.calculate_destroyed_units(mission=self.event.operation.mission, debriefing.calculate_alive_units(mission=self.event.operation.mission,
player_name=self.game.player, player_name=self.game.player,
enemy_name=self.game.enemy) enemy_name=self.game.enemy)
self.game.finish_event(event=self.event, debriefing=debriefing) self.game.finish_event(event=self.event, debriefing=debriefing)
self.game.pass_turn(ignored_cps=[self.event.to_cp, ]) self.game.pass_turn(ignored_cps=[self.event.to_cp, ])

View File

@ -20,49 +20,29 @@ from .persistency import base_path
DEBRIEFING_LOG_EXTENSION = "log" DEBRIEFING_LOG_EXTENSION = "log"
def parse_mutliplayer_debriefing(contents: str):
result = []
for line in [x.strip() for x in contents.splitlines()]:
key = None
if line.startswith("initiator"):
key = "initiator"
result.append({})
if line.startswith("type"):
key = "type"
else:
continue
value = re.findall(r"=\s*\"(.*?)\",", line)[0]
result[-1][key] = value
return {"debriefing": {"events": result}}
class Debriefing: class Debriefing:
def __init__(self, alive_units): def __init__(self, dead_units):
self.destroyed_units = {} # type: typing.Dict[str, typing.Dict[UnitType, int]] self.destroyed_units = {} # type: typing.Dict[str, typing.Dict[UnitType, int]]
self.alive_units = alive_units # type: typing.Dict[str, typing.Dict[UnitType, int]] self.alive_units = {} # type: typing.Dict[str, typing.Dict[UnitType, int]]
@classmethod self._dead_units = dead_units
def parse_mp_debrief(cls, string: str):
# TODO: actually write a parser
result = {}
append = False
country = None
unit_type = None
for line in string.split("\n"):
line = line.strip()
if not append:
if line == "world_state =":
append = True
continue
if append:
if line.startswith("country"):
country = re.findall(r"country\s*=\s*(\d+),", line)[0]
if line.startswith("type"):
unit_type = re.findall(r"type\s*=\s*\"(.*?)\",", line)[0]
if country and unit_type:
result[len(result)+1] = {
"country": int(country),
"type": unit_type,
}
country = unit_type = None
if line.strip() == "} -- end of world_state":
break
return {
"debriefing": {
"world_state": result,
},
}
@classmethod @classmethod
def parse(cls, path: str): def parse(cls, path: str):
@ -70,30 +50,35 @@ class Debriefing:
table_string = f.read() table_string = f.read()
try: try:
table = parse.loads(table_string) table = parse.loads(table_string)
except: except Exception as e:
table = cls.parse_mp_debrief(table_string) table = parse_mutliplayer_debriefing(table_string)
units = table.get("debriefing", {}).get("world_state", {})
alive_units = {}
for unit in units.values(): events = table.get("debriefing", {}).get("events", {})
unit_type_name = unit["type"] # type: str dead_units = {}
country_id = int(unit["country"])
if type(unit_type_name) == str: for event in events:
unit_type = vehicle_map.get(unit_type_name, plane_map.get(unit_type_name, ship_map.get(unit_type_name, None))) if event["type"] != "crashed" and event["type"] != "dead":
continue
try:
components = event["initiator"].split("|")
country_id, group_id, unit_type = int(components[0]), int(components[1]), db.unit_type_from_name(components[2])
if unit_type is None: if unit_type is None:
continue continue
except Exception as e:
continue
if unit_type in db.EXTRA_AA.values(): if country_id not in dead_units:
continue dead_units[country_id] = {}
country_dict = alive_units.get(country_id, {}) if unit_type not in dead_units[country_id]:
country_dict[unit_type] = country_dict.get(unit_type, 0) + 1 dead_units[country_id][unit_type] = 0
alive_units[country_id] = country_dict
return Debriefing(alive_units) dead_units[country_id][unit_type] += 1
def calculate_destroyed_units(self, mission: Mission, player_name: str, enemy_name: str): return Debriefing(dead_units)
def calculate_units(self, mission: Mission, player_name: str, enemy_name: str):
def count_groups(groups: typing.List[UnitType]) -> typing.Dict[UnitType, int]: def count_groups(groups: typing.List[UnitType]) -> typing.Dict[UnitType, int]:
result = {} result = {}
for group in groups: for group in groups:
@ -113,12 +98,6 @@ class Debriefing:
return result return result
def calculate_losses(all_units: typing.Dict[UnitType, int], alive_units: typing.Dict[str, int]) -> typing.Dict[UnitType, int]:
result = {}
for t, count in all_units.items():
result[t] = max(count - alive_units.get(t, 0), 0)
return result
player = mission.country(player_name) player = mission.country(player_name)
enemy = mission.country(enemy_name) enemy = mission.country(enemy_name)
@ -126,13 +105,13 @@ class Debriefing:
enemy_units = count_groups(enemy.plane_group + enemy.vehicle_group + enemy.ship_group) enemy_units = count_groups(enemy.plane_group + enemy.vehicle_group + enemy.ship_group)
self.destroyed_units = { self.destroyed_units = {
player.name: calculate_losses(player_units, self.alive_units.get(player.id, {})), player.name: self._dead_units[player.id],
enemy.name: calculate_losses(enemy_units, self.alive_units.get(enemy.id, {})), enemy.name: self._dead_units[enemy.id],
} }
self.alive_units = { self.alive_units = {
player.name: self.alive_units.get(player.id, {}), player.name: {k: v - self._dead_units[player.id].get(k, 0) for k, v in player_units.items()},
enemy.name: self.alive_units.get(enemy.id, {}), enemy.name: {k: v - self._dead_units[enemy.id].get(k, 0) for k, v in enemy_units.items()},
} }