From 4ce7480df8c9fb1f2032308868c376029ef8e130 Mon Sep 17 00:00:00 2001 From: Vasiliy Horbachenko Date: Thu, 12 Jul 2018 05:12:01 +0300 Subject: [PATCH] debriefing based on events, not world state WIP --- .idea/modules.xml | 1 + game/db.py | 11 ++++ gen/aaa.py | 6 +-- gen/aircraft.py | 14 +++--- gen/armor.py | 4 +- gen/conflictgen.py | 6 +-- gen/naming.py | 36 +++---------- gen/visualgen.py | 2 +- ui/eventresultsmenu.py | 6 +-- userdata/debriefing.py | 111 +++++++++++++++++------------------------ 10 files changed, 83 insertions(+), 114 deletions(-) diff --git a/.idea/modules.xml b/.idea/modules.xml index c32a91ea..b52058de 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -3,6 +3,7 @@ + \ No newline at end of file diff --git a/game/db.py b/game/db.py index 91105b95..47cc07da 100644 --- a/game/db.py +++ b/game/db.py @@ -400,6 +400,17 @@ def unit_type_name(unit_type) -> str: 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: if task == AirDefence: return "AirDefence" diff --git a/gen/aaa.py b/gen/aaa.py index 84dbf83c..0fbc88f9 100644 --- a/gen/aaa.py +++ b/gen/aaa.py @@ -21,7 +21,7 @@ class AAConflictGenerator: for _ in range(count): self.m.vehicle_group( 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, position=self.conflict.ground_defenders_location.random_point_within(100, 100), group_size=1) @@ -34,7 +34,7 @@ class AAConflictGenerator: self.m.vehicle_group( country=self.conflict.defenders_side, - name=namegen.next_ground_group_name(), + name=namegen.next_unit_name(self.conflict.defenders_side, type), _type=type, position=p, group_size=1) @@ -66,7 +66,7 @@ class ExtraAAConflictGenerator: self.mission.vehicle_group( country=self.mission.country(country_name), - name=namegen.next_ground_group_name(), + name=namegen.next_basedefense_name(), _type=db.EXTRA_AA[country_name], position=position, group_size=2 diff --git a/gen/aircraft.py b/gen/aircraft.py index 93fb53e7..b7e410f6 100644 --- a/gen/aircraft.py +++ b/gen/aircraft.py @@ -188,7 +188,7 @@ class AircraftConflictGenerator: groups = [] for flying_type, count, client_count in self._split_to_groups(units, clients): group = self._generate_group( - name=namegen.next_escort_group_name(), + name=namegen.next_unit_name(side, flying_type), side=side, unit_type=flying_type, count=count, @@ -225,7 +225,7 @@ class AircraftConflictGenerator: for flying_type, count, client_count in self._split_to_groups(attackers, clients): 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, unit_type=flying_type, count=count, @@ -243,7 +243,7 @@ class AircraftConflictGenerator: for flying_type, count, client_count in self._split_to_groups(attackers, clients): 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, unit_type=flying_type, count=count, @@ -282,7 +282,7 @@ class AircraftConflictGenerator: 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): 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, unit_type=flying_type, count=count, @@ -301,7 +301,7 @@ class AircraftConflictGenerator: for flying_type, count, client_count in self._split_to_groups(transport): 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, unit_type=flying_type, count=count, @@ -317,7 +317,7 @@ class AircraftConflictGenerator: 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): 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, unit_type=flying_type, count=count, @@ -338,7 +338,7 @@ class AircraftConflictGenerator: 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): 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, unit_type=heli_type, count=count, diff --git a/gen/armor.py b/gen/armor.py index 5142649b..d75e9268 100644 --- a/gen/armor.py +++ b/gen/armor.py @@ -29,7 +29,7 @@ class ArmorConflictGenerator: for c in range(count): group = self.m.vehicle_group( side, - namegen.next_armor_group_name(), + namegen.next_unit_name(side, unit), unit, position=self._group_point(at), group_size=1, @@ -57,7 +57,7 @@ class ArmorConflictGenerator: self.m.vehicle_group( 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, position=self.conflict.ground_attackers_location, group_size=count diff --git a/gen/conflictgen.py b/gen/conflictgen.py index 80c8f700..f45d6f9b 100644 --- a/gen/conflictgen.py +++ b/gen/conflictgen.py @@ -95,7 +95,7 @@ class Conflict: self.air_defenders_location = air_defenders_location @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) heading = to_cp.position.heading_between_point(from_cp.position) return to_cp.position.point_from_heading(heading, distance) @@ -187,7 +187,7 @@ class Conflict: @classmethod 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) - 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) if not position: heading = to_cp.find_radial(to_cp.position.heading_between_point(from_cp.position)) @@ -257,7 +257,7 @@ class Conflict: @classmethod 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) 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) diff --git a/gen/naming.py b/gen/naming.py index 17126ca1..10f57275 100644 --- a/gen/naming.py +++ b/gen/naming.py @@ -1,37 +1,15 @@ +from game import db + + class NameGenerator: number = 0 - def next_armor_group_name(self): + def next_unit_name(self, country, unit_type): 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): - self.number += 1 - 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) + def next_basedefense_name(self): + return "basedefense_aa" namegen = NameGenerator() diff --git a/gen/visualgen.py b/gen/visualgen.py index 380bfda0..ff16672a 100644 --- a/gen/visualgen.py +++ b/gen/visualgen.py @@ -99,7 +99,7 @@ class VisualGenerator: def _generate_frontline_smokes(self): for from_cp, to_cp in self.game.theater.conflicts(): 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) for offset in range(0, FRONT_SMOKE_LENGTH, FRONT_SMOKE_SPACING): diff --git a/ui/eventresultsmenu.py b/ui/eventresultsmenu.py index b5624b99..4a53d5a0 100644 --- a/ui/eventresultsmenu.py +++ b/ui/eventresultsmenu.py @@ -65,9 +65,9 @@ class EventResultsMenu(Menu): def process_debriefing(self, debriefing: Debriefing): self.debriefing = debriefing - debriefing.calculate_destroyed_units(mission=self.event.operation.mission, - player_name=self.game.player, - enemy_name=self.game.enemy) + debriefing.calculate_alive_units(mission=self.event.operation.mission, + player_name=self.game.player, + enemy_name=self.game.enemy) self.game.finish_event(event=self.event, debriefing=debriefing) self.game.pass_turn(ignored_cps=[self.event.to_cp, ]) diff --git a/userdata/debriefing.py b/userdata/debriefing.py index 0cdadcb5..af299f76 100644 --- a/userdata/debriefing.py +++ b/userdata/debriefing.py @@ -20,49 +20,29 @@ from .persistency import base_path 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: - def __init__(self, alive_units): + def __init__(self, dead_units): 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 - 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, - }, - } + self._dead_units = dead_units @classmethod def parse(cls, path: str): @@ -70,30 +50,35 @@ class Debriefing: table_string = f.read() try: table = parse.loads(table_string) - except: - table = cls.parse_mp_debrief(table_string) - units = table.get("debriefing", {}).get("world_state", {}) - alive_units = {} + except Exception as e: + table = parse_mutliplayer_debriefing(table_string) - for unit in units.values(): - unit_type_name = unit["type"] # type: str - country_id = int(unit["country"]) + events = table.get("debriefing", {}).get("events", {}) + dead_units = {} - if type(unit_type_name) == str: - unit_type = vehicle_map.get(unit_type_name, plane_map.get(unit_type_name, ship_map.get(unit_type_name, None))) + for event in events: + 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: continue + except Exception as e: + continue - if unit_type in db.EXTRA_AA.values(): - continue + if country_id not in dead_units: + dead_units[country_id] = {} - country_dict = alive_units.get(country_id, {}) - country_dict[unit_type] = country_dict.get(unit_type, 0) + 1 - alive_units[country_id] = country_dict + if unit_type not in dead_units[country_id]: + dead_units[country_id][unit_type] = 0 - 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]: result = {} for group in groups: @@ -113,12 +98,6 @@ class Debriefing: 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) enemy = mission.country(enemy_name) @@ -126,13 +105,13 @@ class Debriefing: enemy_units = count_groups(enemy.plane_group + enemy.vehicle_group + enemy.ship_group) self.destroyed_units = { - player.name: calculate_losses(player_units, self.alive_units.get(player.id, {})), - enemy.name: calculate_losses(enemy_units, self.alive_units.get(enemy.id, {})), + player.name: self._dead_units[player.id], + enemy.name: self._dead_units[enemy.id], } self.alive_units = { - player.name: self.alive_units.get(player.id, {}), - enemy.name: self.alive_units.get(enemy.id, {}), + player.name: {k: v - self._dead_units[player.id].get(k, 0) for k, v in player_units.items()}, + enemy.name: {k: v - self._dead_units[enemy.id].get(k, 0) for k, v in enemy_units.items()}, }