mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
debriefing based on events, not world state WIP
This commit is contained in:
parent
d2aede593b
commit
4ce7480df8
1
.idea/modules.xml
generated
1
.idea/modules.xml
generated
@ -3,6 +3,7 @@
|
||||
<component name="ProjectModuleManager">
|
||||
<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" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
11
game/db.py
11
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"
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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):
|
||||
|
||||
@ -65,7 +65,7 @@ class EventResultsMenu(Menu):
|
||||
|
||||
def process_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,
|
||||
enemy_name=self.game.enemy)
|
||||
|
||||
|
||||
@ -20,49 +20,29 @@ from .persistency import base_path
|
||||
DEBRIEFING_LOG_EXTENSION = "log"
|
||||
|
||||
|
||||
class Debriefing:
|
||||
def __init__(self, alive_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]]
|
||||
def parse_mutliplayer_debriefing(contents: str):
|
||||
result = []
|
||||
|
||||
@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]
|
||||
for line in [x.strip() for x in contents.splitlines()]:
|
||||
key = None
|
||||
if line.startswith("initiator"):
|
||||
key = "initiator"
|
||||
result.append({})
|
||||
if line.startswith("type"):
|
||||
unit_type = re.findall(r"type\s*=\s*\"(.*?)\",", line)[0]
|
||||
key = "type"
|
||||
else:
|
||||
continue
|
||||
value = re.findall(r"=\s*\"(.*?)\",", line)[0]
|
||||
result[-1][key] = value
|
||||
return {"debriefing": {"events": result}}
|
||||
|
||||
if country and unit_type:
|
||||
result[len(result)+1] = {
|
||||
"country": int(country),
|
||||
"type": unit_type,
|
||||
}
|
||||
|
||||
country = unit_type = None
|
||||
class Debriefing:
|
||||
def __init__(self, dead_units):
|
||||
self.destroyed_units = {} # type: typing.Dict[str, typing.Dict[UnitType, int]]
|
||||
self.alive_units = {} # type: typing.Dict[str, typing.Dict[UnitType, int]]
|
||||
|
||||
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
|
||||
|
||||
if unit_type in db.EXTRA_AA.values():
|
||||
except Exception as e:
|
||||
continue
|
||||
|
||||
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 country_id not in dead_units:
|
||||
dead_units[country_id] = {}
|
||||
|
||||
return Debriefing(alive_units)
|
||||
if unit_type not in dead_units[country_id]:
|
||||
dead_units[country_id][unit_type] = 0
|
||||
|
||||
def calculate_destroyed_units(self, mission: Mission, player_name: str, enemy_name: str):
|
||||
dead_units[country_id][unit_type] += 1
|
||||
|
||||
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()},
|
||||
}
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user