mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e9d7ee51f3 | ||
|
|
9053408e13 | ||
|
|
8f4094ee98 | ||
|
|
933e064079 | ||
|
|
274e08dd8b | ||
|
|
05c968edc2 | ||
|
|
270820de0b | ||
|
|
e049a97bec | ||
|
|
e2306ba0f3 | ||
|
|
6d0f488672 | ||
|
|
8df4607e50 | ||
|
|
49f2c00d76 | ||
|
|
d284305323 | ||
|
|
c32ac8577c | ||
|
|
0d5530f5ea | ||
|
|
a528249062 |
29
README.md
29
README.md
@@ -1,8 +1,29 @@
|
||||
[DCS World](https://www.digitalcombatsimulator.com/en/products/world/) single-player liberation dynamic campaign.
|
||||

|
||||
|
||||
[Installation instructions/Manual](https://github.com/shdwp/dcs_liberation/wiki)
|
||||
|
||||
Inspired by *ARMA Liberation* mission.
|
||||
[DCS World](https://www.digitalcombatsimulator.com/en/products/world/) single-player dynamic campaign.
|
||||
|
||||
Uses [pydcs](http://github.com/pydcs/dcs) for mission generation.
|
||||
|
||||
## Installation
|
||||
1. Download and install **Python 3.6.0** package from https://www.python.org/downloads/release/python-360/ (look at the bottom under *Files*; any option will do if it matches your architecture) with default set of options (you need to have *Install launcher for all users (recommended)* checked)
|
||||
1. Download archived release (https://github.com/shdwp/dcs_liberation/releases; **not source code zip**, file should be named **dcs_liberation_xx.zip**)
|
||||
1. Unzip the archive somewhere. Path does not matter. **Application will not work** if you start it without extracting
|
||||
1. Run **start.bat**
|
||||
1. If **"Windows protected your PC"** popup appears on your computer (windows blocks any application unknown to it), you can click on **"More info"** and **"Run anyway"**
|
||||
|
||||
## Tutorials
|
||||
* [Manual](https://github.com/shdwp/dcs_liberation/wiki/Manual)
|
||||
|
||||
You should start with the manual, it covers everything you need to know before playing the campaign.
|
||||
|
||||
* [Troubleshooting](https://github.com/shdwp/dcs_liberation/wiki/Troubleshooting)
|
||||
|
||||
You could also briefly check the troubleshooting page to get familiar with the known issues that you could probably fix by yourself.
|
||||
|
||||
* [Modding tutorial](https://github.com/shdwp/dcs_liberation/wiki/Modding-tutorial)
|
||||
|
||||
Modding tutorial will cover how to change default loadouts, configure which planes are present in the campaign (or add new altogether) and more. Check this out if you find that something is not going for your liking, there could be a tutorial for changing that. Although be aware that it would require changing source files and could easily result in non functioning application.
|
||||
|
||||
* [Development guide](https://github.com/shdwp/dcs_liberation/wiki/Development-guide)
|
||||
|
||||
If you want to contribute to the project, this will give you a brief overview and on how to actually run it from source files.
|
||||
|
||||
@@ -43,7 +43,7 @@ def is_version_compatible(save_version):
|
||||
if current_version_components == save_version_components:
|
||||
return True
|
||||
|
||||
if save_version in ["1.4_rc1", "1.4_rc2", "1.4_rc3"]:
|
||||
if save_version in ["1.4_rc1", "1.4_rc2", "1.4_rc3", "1.4_rc4", "1.4_rc5", "1.4_rc6"]:
|
||||
return False
|
||||
|
||||
if current_version_components[:2] == save_version_components[:2]:
|
||||
|
||||
61
game/db.py
61
game/db.py
@@ -2,12 +2,14 @@ import typing
|
||||
import enum
|
||||
|
||||
from dcs.vehicles import *
|
||||
from dcs.unitgroup import *
|
||||
from dcs.ships import *
|
||||
from dcs.planes import *
|
||||
from dcs.helicopters import *
|
||||
|
||||
from dcs.task import *
|
||||
from dcs.unit import *
|
||||
from dcs.unittype import *
|
||||
from dcs.unitgroup import *
|
||||
|
||||
"""
|
||||
---------- BEGINNING OF CONFIGURATION SECTION
|
||||
@@ -39,10 +41,10 @@ PRICES = {
|
||||
# fighter
|
||||
C_101CC: 8,
|
||||
MiG_23MLD: 18,
|
||||
Su_27: 24,
|
||||
Su_33: 25,
|
||||
MiG_29A: 24,
|
||||
MiG_29S: 26,
|
||||
Su_27: 20,
|
||||
Su_33: 22,
|
||||
MiG_29A: 23,
|
||||
MiG_29S: 25,
|
||||
|
||||
F_5E_3: 6,
|
||||
MiG_15bis: 5,
|
||||
@@ -52,7 +54,7 @@ PRICES = {
|
||||
AV8BNA: 13,
|
||||
M_2000C: 13,
|
||||
FA_18C_hornet: 18,
|
||||
F_15C: 24,
|
||||
F_15C: 20,
|
||||
|
||||
# bomber
|
||||
Su_25: 15,
|
||||
@@ -65,7 +67,8 @@ PRICES = {
|
||||
|
||||
# heli
|
||||
Ka_50: 13,
|
||||
UH_1H: 5,
|
||||
SA342M: 8,
|
||||
UH_1H: 4,
|
||||
Mi_8MT: 5,
|
||||
|
||||
# special
|
||||
@@ -76,7 +79,6 @@ PRICES = {
|
||||
S_3B_Tanker: 13,
|
||||
IL_78M: 13,
|
||||
KC_135: 13,
|
||||
KC130: 13,
|
||||
|
||||
A_50: 8,
|
||||
E_3A: 8,
|
||||
@@ -110,9 +112,10 @@ PRICES = {
|
||||
# ship
|
||||
CV_1143_5_Admiral_Kuznetsov: 100,
|
||||
CVN_74_John_C__Stennis: 100,
|
||||
LHA_1_Tarawa: 50,
|
||||
|
||||
LHA_1_Tarawa: 30,
|
||||
Bulk_cargo_ship_Yakushev: 10,
|
||||
Armed_speedboat: 10,
|
||||
Dry_cargo_ship_Ivanov: 10,
|
||||
Tanker_Elnya_160: 10,
|
||||
}
|
||||
@@ -158,6 +161,7 @@ UNIT_BY_TASK = {
|
||||
Su_25T,
|
||||
Su_34,
|
||||
Ka_50,
|
||||
SA342M,
|
||||
],
|
||||
|
||||
Transport: [
|
||||
@@ -166,14 +170,13 @@ UNIT_BY_TASK = {
|
||||
An_30M,
|
||||
Yak_40,
|
||||
|
||||
S_3B_Tanker,
|
||||
C_130,
|
||||
],
|
||||
|
||||
Refueling: [
|
||||
IL_78M,
|
||||
KC_135,
|
||||
KC130,
|
||||
S_3B_Tanker,
|
||||
],
|
||||
|
||||
AWACS: [E_3A, A_50, ],
|
||||
@@ -198,8 +201,8 @@ UNIT_BY_TASK = {
|
||||
Nothing: [Infantry.Infantry_M4, Infantry.Soldier_AK, ],
|
||||
Embarking: [UH_1H, Mi_8MT, ],
|
||||
|
||||
Carriage: [CVN_74_John_C__Stennis, CV_1143_5_Admiral_Kuznetsov, ],
|
||||
CargoTransportation: [Dry_cargo_ship_Ivanov, Bulk_cargo_ship_Yakushev, Tanker_Elnya_160, LHA_1_Tarawa],
|
||||
Carriage: [CVN_74_John_C__Stennis, LHA_1_Tarawa, CV_1143_5_Admiral_Kuznetsov, ],
|
||||
CargoTransportation: [Dry_cargo_ship_Ivanov, Bulk_cargo_ship_Yakushev, Tanker_Elnya_160, Armed_speedboat, ],
|
||||
}
|
||||
|
||||
"""
|
||||
@@ -265,6 +268,7 @@ UNIT_BY_COUNTRY = {
|
||||
A_50,
|
||||
|
||||
Ka_50,
|
||||
SA342M,
|
||||
UH_1H,
|
||||
Mi_8MT,
|
||||
|
||||
@@ -299,12 +303,12 @@ UNIT_BY_COUNTRY = {
|
||||
AV8BNA,
|
||||
|
||||
KC_135,
|
||||
KC130,
|
||||
S_3B_Tanker,
|
||||
C_130,
|
||||
E_3A,
|
||||
|
||||
Ka_50,
|
||||
SA342M,
|
||||
UH_1H,
|
||||
Mi_8MT,
|
||||
|
||||
@@ -319,9 +323,19 @@ UNIT_BY_COUNTRY = {
|
||||
|
||||
CVN_74_John_C__Stennis,
|
||||
LHA_1_Tarawa,
|
||||
Armed_speedboat,
|
||||
],
|
||||
}
|
||||
|
||||
CARRIER_TYPE_BY_PLANE = {
|
||||
FA_18C_hornet: CVN_74_John_C__Stennis,
|
||||
Ka_50: LHA_1_Tarawa,
|
||||
SA342M: LHA_1_Tarawa,
|
||||
UH_1H: LHA_1_Tarawa,
|
||||
Mi_8MT: LHA_1_Tarawa,
|
||||
AV8BNA: LHA_1_Tarawa,
|
||||
}
|
||||
|
||||
"""
|
||||
Aircraft payload overrides. Usually default loadout for the task is loaded during the mission generation.
|
||||
Syntax goes as follows:
|
||||
@@ -341,6 +355,8 @@ Payload will be used for operation of following type, "*" category will be used
|
||||
PLANE_PAYLOAD_OVERRIDES = {
|
||||
FA_18C_hornet: {
|
||||
CAP: "AIM-120*4,AIM-9*2,AIM-7*2,Fuel",
|
||||
PinpointStrike: "MK-82*8,AIM-9*2,AIM-7,FLIR Pod,Fuel",
|
||||
AntishipStrike: "MK-82*8,AIM-9*2,AIM-7,FLIR Pod,Fuel",
|
||||
},
|
||||
|
||||
Su_25T: {
|
||||
@@ -435,6 +451,15 @@ def unit_type_from_name(name: str) -> UnitType:
|
||||
return None
|
||||
|
||||
|
||||
def unit_type_of(unit: Unit) -> UnitType:
|
||||
if isinstance(unit, Vehicle):
|
||||
return vehicle_map[unit.type]
|
||||
elif isinstance(unit, Ship):
|
||||
return ship_map[unit.type]
|
||||
else:
|
||||
return unit.unit_type
|
||||
|
||||
|
||||
def task_name(task) -> str:
|
||||
if task == AirDefence:
|
||||
return "AirDefence"
|
||||
@@ -460,6 +485,14 @@ def unitdict_append(unit_dict: UnitsDict, unit_type: UnitType, count: int):
|
||||
unit_dict[unit_type] = unit_dict.get(unit_type, 0) + 1
|
||||
|
||||
|
||||
def unitdict_merge(a: UnitsDict, b: UnitsDict) -> UnitsDict:
|
||||
b = b.copy()
|
||||
for k, v in a.items():
|
||||
b[k] = b.get(k, 0) + v
|
||||
|
||||
return b
|
||||
|
||||
|
||||
def unitdict_split(unit_dict: UnitsDict, count: int):
|
||||
buffer_dict = {}
|
||||
for unit_type, unit_count in unit_dict.items():
|
||||
|
||||
@@ -79,7 +79,7 @@ class Event:
|
||||
|
||||
self.operation.prepare(self.game.theater.terrain, is_quick=False)
|
||||
self.operation.generate()
|
||||
self.operation.mission.save(persistency.mission_path_for("liberation_nextturn.miz"))
|
||||
self.operation.current_mission.save(persistency.mission_path_for("liberation_nextturn.miz"))
|
||||
self.environment_settings = self.operation.environment_settings
|
||||
|
||||
def generate_quick(self):
|
||||
@@ -88,7 +88,7 @@ class Event:
|
||||
|
||||
self.operation.prepare(self.game.theater.terrain, is_quick=True)
|
||||
self.operation.generate()
|
||||
self.operation.mission.save(persistency.mission_path_for("liberation_nextturn_quick.miz"))
|
||||
self.operation.current_mission.save(persistency.mission_path_for("liberation_nextturn_quick.miz"))
|
||||
|
||||
def commit(self, debriefing: Debriefing):
|
||||
for country, losses in debriefing.destroyed_units.items():
|
||||
|
||||
@@ -15,6 +15,7 @@ class InsurgentAttackEvent(Event):
|
||||
SUCCESS_FACTOR = 0.7
|
||||
TARGET_VARIETY = 2
|
||||
TARGET_AMOUNT_FACTOR = 0.5
|
||||
STRENGTH_INFLUENCE = 0.1
|
||||
|
||||
@property
|
||||
def threat_description(self):
|
||||
@@ -31,6 +32,9 @@ class InsurgentAttackEvent(Event):
|
||||
def __str__(self):
|
||||
return "Destroy insurgents"
|
||||
|
||||
def skip(self):
|
||||
self.to_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
||||
|
||||
def is_successfull(self, debriefing: Debriefing):
|
||||
killed_units = sum([v for k, v in debriefing.destroyed_units[self.attacker_name].items() if db.unit_task(k) == PinpointStrike])
|
||||
all_units = sum(self.targets.values())
|
||||
|
||||
@@ -11,7 +11,7 @@ class NavalInterceptEvent(Event):
|
||||
|
||||
def _targets_count(self) -> int:
|
||||
from gen.conflictgen import IMPORTANCE_LOW
|
||||
factor = (self.to_cp.importance - IMPORTANCE_LOW) * 10
|
||||
factor = (self.to_cp.importance - IMPORTANCE_LOW + 0.1) * 20
|
||||
return max(int(factor), 1)
|
||||
|
||||
def __str__(self) -> str:
|
||||
|
||||
10
game/game.py
10
game/game.py
@@ -58,14 +58,14 @@ EVENT_PROBABILITIES = {
|
||||
InfantryTransportEvent: [25, 0],
|
||||
|
||||
# events conditionally present; for both enemy and player
|
||||
BaseAttackEvent: [100, 5],
|
||||
BaseAttackEvent: [100, 9],
|
||||
|
||||
# events randomly present; for both enemy and player
|
||||
InterceptEvent: [25, 5],
|
||||
NavalInterceptEvent: [25, 5],
|
||||
InterceptEvent: [25, 9],
|
||||
NavalInterceptEvent: [25, 9],
|
||||
|
||||
# events randomly present; only for the enemy
|
||||
InsurgentAttackEvent: [0, 4],
|
||||
InsurgentAttackEvent: [0, 6],
|
||||
}
|
||||
|
||||
# amount of strength player bases recover for the turn
|
||||
@@ -80,7 +80,7 @@ AWACS_BUDGET_COST = 4
|
||||
# Initial budget value
|
||||
PLAYER_BUDGET_INITIAL = 170
|
||||
# Base post-turn bonus value
|
||||
PLAYER_BUDGET_BASE = 17
|
||||
PLAYER_BUDGET_BASE = 14
|
||||
# Bonus multiplier logarithm base
|
||||
PLAYER_BUDGET_IMPORTANCE_LOG = 2
|
||||
|
||||
|
||||
@@ -37,13 +37,13 @@ class BaseAttackOperation(Operation):
|
||||
self.attackers_starting_position = None
|
||||
|
||||
conflict = Conflict.capture_conflict(
|
||||
attacker=self.mission.country(self.attacker_name),
|
||||
defender=self.mission.country(self.defender_name),
|
||||
attacker=self.current_mission.country(self.attacker_name),
|
||||
defender=self.current_mission.country(self.defender_name),
|
||||
from_cp=self.from_cp,
|
||||
to_cp=self.to_cp,
|
||||
theater=self.game.theater
|
||||
)
|
||||
self.initialize(mission=self.mission,
|
||||
self.initialize(mission=self.current_mission,
|
||||
conflict=conflict)
|
||||
|
||||
def generate(self):
|
||||
|
||||
@@ -26,14 +26,14 @@ class FrontlineAttackOperation(Operation):
|
||||
self.defenders_starting_position = None
|
||||
|
||||
conflict = Conflict.frontline_cas_conflict(
|
||||
attacker=self.mission.country(self.attacker_name),
|
||||
defender=self.mission.country(self.defender_name),
|
||||
attacker=self.current_mission.country(self.attacker_name),
|
||||
defender=self.current_mission.country(self.defender_name),
|
||||
from_cp=self.from_cp,
|
||||
to_cp=self.to_cp,
|
||||
theater=self.game.theater
|
||||
)
|
||||
|
||||
self.initialize(mission=self.mission,
|
||||
self.initialize(mission=self.current_mission,
|
||||
conflict=conflict)
|
||||
|
||||
def generate(self):
|
||||
@@ -44,7 +44,7 @@ class FrontlineAttackOperation(Operation):
|
||||
|
||||
heli_flights = {k: v for k, v in self.strikegroup.items() if k in helicopters.helicopter_map.values()}
|
||||
if heli_flights:
|
||||
self.briefinggen.append_frequency("FARP", "127.5 MHz AM")
|
||||
self.briefinggen.append_frequency("FARP + Heli flights", "127.5 MHz AM")
|
||||
for farp, dict in zip(self.groundobjectgen.generate_farps(sum([x[0] for x in heli_flights.values()])),
|
||||
db.assignedunits_split_to_count(heli_flights, self.groundobjectgen.FARP_CAPACITY)):
|
||||
self.airgen.generate_cas_strikegroup(*assigned_units_split(dict),
|
||||
|
||||
@@ -32,14 +32,14 @@ class FrontlinePatrolOperation(Operation):
|
||||
self.defenders_starting_position = None
|
||||
|
||||
conflict = Conflict.frontline_cap_conflict(
|
||||
attacker=self.mission.country(self.attacker_name),
|
||||
defender=self.mission.country(self.defender_name),
|
||||
attacker=self.current_mission.country(self.attacker_name),
|
||||
defender=self.current_mission.country(self.defender_name),
|
||||
from_cp=self.from_cp,
|
||||
to_cp=self.to_cp,
|
||||
theater=self.game.theater
|
||||
)
|
||||
|
||||
self.initialize(mission=self.mission,
|
||||
self.initialize(mission=self.current_mission,
|
||||
conflict=conflict)
|
||||
|
||||
def generate(self):
|
||||
|
||||
@@ -15,14 +15,14 @@ class InfantryTransportOperation(Operation):
|
||||
super(InfantryTransportOperation, self).prepare(terrain, is_quick)
|
||||
|
||||
conflict = Conflict.transport_conflict(
|
||||
attacker=self.mission.country(self.attacker_name),
|
||||
defender=self.mission.country(self.defender_name),
|
||||
attacker=self.current_mission.country(self.attacker_name),
|
||||
defender=self.current_mission.country(self.defender_name),
|
||||
from_cp=self.from_cp,
|
||||
to_cp=self.to_cp,
|
||||
theater=self.game.theater
|
||||
)
|
||||
|
||||
self.initialize(mission=self.mission,
|
||||
self.initialize(mission=self.current_mission,
|
||||
conflict=conflict)
|
||||
|
||||
def generate(self):
|
||||
|
||||
@@ -17,14 +17,14 @@ class InsurgentAttackOperation(Operation):
|
||||
super(InsurgentAttackOperation, self).prepare(terrain, is_quick)
|
||||
|
||||
conflict = Conflict.ground_attack_conflict(
|
||||
attacker=self.mission.country(self.attacker_name),
|
||||
defender=self.mission.country(self.defender_name),
|
||||
attacker=self.current_mission.country(self.attacker_name),
|
||||
defender=self.current_mission.country(self.defender_name),
|
||||
from_cp=self.from_cp,
|
||||
to_cp=self.to_cp,
|
||||
theater=self.game.theater
|
||||
)
|
||||
|
||||
self.initialize(mission=self.mission,
|
||||
self.initialize(mission=self.current_mission,
|
||||
conflict=conflict)
|
||||
|
||||
def generate(self):
|
||||
|
||||
@@ -28,27 +28,18 @@ class InterceptOperation(Operation):
|
||||
self.attackers_starting_position = None
|
||||
|
||||
conflict = Conflict.intercept_conflict(
|
||||
attacker=self.mission.country(self.attacker_name),
|
||||
defender=self.mission.country(self.defender_name),
|
||||
attacker=self.current_mission.country(self.attacker_name),
|
||||
defender=self.current_mission.country(self.defender_name),
|
||||
from_cp=self.from_cp,
|
||||
to_cp=self.to_cp,
|
||||
theater=self.game.theater
|
||||
)
|
||||
|
||||
self.initialize(mission=self.mission,
|
||||
self.initialize(mission=self.current_mission,
|
||||
conflict=conflict)
|
||||
|
||||
def generate(self):
|
||||
for global_cp in self.game.theater.controlpoints:
|
||||
if not global_cp.is_global:
|
||||
continue
|
||||
|
||||
ship = self.shipgen.generate_carrier(type=db.find_unittype(Carriage, self.game.player)[0],
|
||||
country=self.game.player,
|
||||
at=global_cp.at)
|
||||
|
||||
if global_cp == self.from_cp and not self.is_quick:
|
||||
self.attackers_starting_position = ship
|
||||
self.prepare_carriers(db.unitdict_from(self.interceptors))
|
||||
|
||||
self.airgen.generate_transport(self.transport, self.to_cp.at)
|
||||
self.airgen.generate_defenders_escort(*assigned_units_split(self.escort), at=self.defenders_starting_position)
|
||||
|
||||
@@ -23,16 +23,18 @@ class NavalInterceptionOperation(Operation):
|
||||
self.attackers_starting_position = None
|
||||
|
||||
conflict = Conflict.naval_intercept_conflict(
|
||||
attacker=self.mission.country(self.attacker_name),
|
||||
defender=self.mission.country(self.defender_name),
|
||||
attacker=self.current_mission.country(self.attacker_name),
|
||||
defender=self.current_mission.country(self.defender_name),
|
||||
from_cp=self.from_cp,
|
||||
to_cp=self.to_cp,
|
||||
theater=self.game.theater
|
||||
)
|
||||
|
||||
self.initialize(self.mission, conflict)
|
||||
self.initialize(self.current_mission, conflict)
|
||||
|
||||
def generate(self):
|
||||
self.prepare_carriers(db.unitdict_from(self.strikegroup))
|
||||
|
||||
target_groups = self.shipgen.generate_cargo(units=self.targets)
|
||||
|
||||
self.airgen.generate_ship_strikegroup(
|
||||
|
||||
@@ -11,7 +11,9 @@ class Operation:
|
||||
attackers_starting_position = None # type: db.StartingPosition
|
||||
defenders_starting_position = None # type: db.StartingPosition
|
||||
|
||||
mission = None # type: dcs.Mission
|
||||
current_mission = None # type: dcs.Mission
|
||||
regular_mission = None # type: dcs.Mission
|
||||
quick_mission = None # type: dcs.Mission
|
||||
conflict = None # type: Conflict
|
||||
armorgen = None # type: ArmorConflictGenerator
|
||||
airgen = None # type: AircraftConflictGenerator
|
||||
@@ -51,7 +53,7 @@ class Operation:
|
||||
return True
|
||||
|
||||
def initialize(self, mission: Mission, conflict: Conflict):
|
||||
self.mission = mission
|
||||
self.current_mission = mission
|
||||
self.conflict = conflict
|
||||
self.armorgen = ArmorConflictGenerator(mission, conflict)
|
||||
self.airgen = AircraftConflictGenerator(mission, conflict, self.game.settings)
|
||||
@@ -72,8 +74,13 @@ class Operation:
|
||||
with open("resources/default_options.lua", "r") as f:
|
||||
options_dict = loads(f.read())["options"]
|
||||
|
||||
self.mission = dcs.Mission(terrain)
|
||||
self.mission.options.load_from_dict(options_dict)
|
||||
self.current_mission = dcs.Mission(terrain)
|
||||
if is_quick:
|
||||
self.quick_mission = self.current_mission
|
||||
else:
|
||||
self.regular_mission = self.current_mission
|
||||
|
||||
self.current_mission.options.load_from_dict(options_dict)
|
||||
self.is_quick = is_quick
|
||||
|
||||
if is_quick:
|
||||
@@ -83,6 +90,18 @@ class Operation:
|
||||
self.attackers_starting_position = self.from_cp.at
|
||||
self.defenders_starting_position = self.to_cp.at
|
||||
|
||||
def prepare_carriers(self, for_units: db.UnitsDict):
|
||||
for global_cp in self.game.theater.controlpoints:
|
||||
if not global_cp.is_global:
|
||||
continue
|
||||
|
||||
ship = self.shipgen.generate_carrier(for_units=[t for t, c in for_units.items() if c > 0],
|
||||
country=self.game.player,
|
||||
at=global_cp.at)
|
||||
|
||||
if global_cp == self.from_cp and not self.is_quick:
|
||||
self.attackers_starting_position = ship
|
||||
|
||||
def generate(self):
|
||||
self.visualgen.generate()
|
||||
|
||||
@@ -95,11 +114,11 @@ class Operation:
|
||||
self.briefinggen.append_frequency("AWACS", "133 MHz AM")
|
||||
|
||||
# combined arms
|
||||
self.mission.groundControl.pilot_can_control_vehicles = self.ca_slots > 0
|
||||
if self.game.player in [country.name for country in self.mission.coalition["blue"].countries.values()]:
|
||||
self.mission.groundControl.blue_tactical_commander = self.ca_slots
|
||||
self.current_mission.groundControl.pilot_can_control_vehicles = self.ca_slots > 0
|
||||
if self.game.player in [country.name for country in self.current_mission.coalition["blue"].countries.values()]:
|
||||
self.current_mission.groundControl.blue_tactical_commander = self.ca_slots
|
||||
else:
|
||||
self.mission.groundControl.red_tactical_commander = self.ca_slots
|
||||
self.current_mission.groundControl.red_tactical_commander = self.ca_slots
|
||||
|
||||
# ground infrastructure
|
||||
self.groundobjectgen.generate()
|
||||
|
||||
@@ -8,6 +8,8 @@ class StrikeOperation(Operation):
|
||||
escort = None # type: db.AssignedUnitsDict
|
||||
interceptors = None # type: db.AssignedUnitsDict
|
||||
|
||||
trigger_radius = TRIGGER_RADIUS_ALL_MAP
|
||||
|
||||
def setup(self,
|
||||
strikegroup: db.AssignedUnitsDict,
|
||||
escort: db.AssignedUnitsDict,
|
||||
@@ -24,27 +26,18 @@ class StrikeOperation(Operation):
|
||||
self.attackers_starting_position = None
|
||||
|
||||
conflict = Conflict.strike_conflict(
|
||||
attacker=self.mission.country(self.attacker_name),
|
||||
defender=self.mission.country(self.defender_name),
|
||||
attacker=self.current_mission.country(self.attacker_name),
|
||||
defender=self.current_mission.country(self.defender_name),
|
||||
from_cp=self.from_cp,
|
||||
to_cp=self.to_cp,
|
||||
theater=self.game.theater
|
||||
)
|
||||
|
||||
self.initialize(mission=self.mission,
|
||||
self.initialize(mission=self.current_mission,
|
||||
conflict=conflict)
|
||||
|
||||
def generate(self):
|
||||
for global_cp in self.game.theater.controlpoints:
|
||||
if not global_cp.is_global:
|
||||
continue
|
||||
|
||||
ship = self.shipgen.generate_carrier(type=db.find_unittype(Carriage, self.game.player)[0],
|
||||
country=self.game.player,
|
||||
at=global_cp.at)
|
||||
|
||||
if global_cp == self.from_cp and not self.is_quick:
|
||||
self.attackers_starting_position = ship
|
||||
self.prepare_carriers(db.unitdict_merge(db.unitdict_from(self.strikegroup), db.unitdict_from(self.escort)))
|
||||
|
||||
targets = [] # type: typing.List[typing.Tuple[str, str, Point]]
|
||||
category_counters = {} # type: typing.Dict[str, int]
|
||||
|
||||
@@ -5,6 +5,7 @@ class Settings:
|
||||
enemy_vehicle_skill = "Average"
|
||||
only_player_takeoff = True
|
||||
night_disabled = False
|
||||
|
||||
multiplier = 1
|
||||
sams = True
|
||||
cold_start = False
|
||||
|
||||
@@ -112,7 +112,12 @@ class AircraftConflictGenerator:
|
||||
group.units[idx].set_client()
|
||||
|
||||
group.points[0].tasks.append(OptReactOnThreat(OptReactOnThreat.Values.EvadeFire))
|
||||
group.set_frequency(251.0)
|
||||
|
||||
if unit_type in helicopters.helicopter_map.values():
|
||||
print(unit_type)
|
||||
group.set_frequency(127.5)
|
||||
else:
|
||||
group.set_frequency(251.0)
|
||||
|
||||
def _generate_at_airport(self, name: str, side: Country, unit_type: FlyingType, count: int, client_count: int, airport: Airport = None) -> FlyingGroup:
|
||||
assert count > 0
|
||||
|
||||
@@ -9,11 +9,11 @@ from dcs.task import *
|
||||
from dcs.terrain.terrain import NoParkingSlotError
|
||||
|
||||
TANKER_DISTANCE = 15000
|
||||
TANKER_ALT = 6000
|
||||
TANKER_ALT = 4572
|
||||
TANKER_HEADING_OFFSET = 45
|
||||
|
||||
AWACS_DISTANCE = 150000
|
||||
AWACS_ALT = 15000
|
||||
AWACS_ALT = 13000
|
||||
|
||||
|
||||
class AirSupportConflictGenerator:
|
||||
|
||||
10
gen/armor.py
10
gen/armor.py
@@ -20,6 +20,8 @@ FRONTLINE_CAS_FIGHTS_COUNT = 4, 8
|
||||
FRONTLINE_CAS_GROUP_MIN = 1, 2
|
||||
FRONTLINE_CAS_PADDING = 12000
|
||||
|
||||
FIGHT_DISTANCE = 1500
|
||||
|
||||
|
||||
class ArmorConflictGenerator:
|
||||
def __init__(self, mission: Mission, conflict: Conflict):
|
||||
@@ -56,8 +58,8 @@ class ArmorConflictGenerator:
|
||||
|
||||
def _generate_fight_at(self, attackers: db.ArmorDict, defenders: db.ArmorDict, position: Point):
|
||||
if attackers:
|
||||
attack_pos = position.point_from_heading(self.conflict.heading - 90, 8000)
|
||||
attack_dest = position.point_from_heading(self.conflict.heading + 90, 25000)
|
||||
attack_pos = position.point_from_heading(self.conflict.heading - 90, FIGHT_DISTANCE)
|
||||
attack_dest = position.point_from_heading(self.conflict.heading + 90, FIGHT_DISTANCE * 2)
|
||||
for type, count in attackers.items():
|
||||
self._generate_group(
|
||||
side=self.conflict.attackers_side,
|
||||
@@ -68,8 +70,8 @@ class ArmorConflictGenerator:
|
||||
)
|
||||
|
||||
if defenders:
|
||||
def_pos = position.point_from_heading(self.conflict.heading + 90, 4000)
|
||||
def_dest = position.point_from_heading(self.conflict.heading - 90, 25000)
|
||||
def_pos = position.point_from_heading(self.conflict.heading + 90, FIGHT_DISTANCE)
|
||||
def_dest = position.point_from_heading(self.conflict.heading - 90, FIGHT_DISTANCE * 2)
|
||||
for type, count in defenders.items():
|
||||
self._generate_group(
|
||||
side=self.conflict.defenders_side,
|
||||
|
||||
@@ -21,6 +21,10 @@ WEATHER_CLOUD_DENSITY = 1, 8
|
||||
WEATHER_CLOUD_THICKNESS = 100, 400
|
||||
WEATHER_CLOUD_BASE_MIN = 1600
|
||||
|
||||
WEATHER_FOG_CHANCE = 20
|
||||
WEATHER_FOG_VISIBILITY = 2500, 5000
|
||||
WEATHER_FOG_THICKNESS = 100, 500
|
||||
|
||||
RANDOM_TIME = {
|
||||
"night": 5,
|
||||
"dusk": 30,
|
||||
@@ -29,11 +33,10 @@ RANDOM_TIME = {
|
||||
}
|
||||
|
||||
RANDOM_WEATHER = {
|
||||
1: 0, # heavy rain
|
||||
2: 5, # rain
|
||||
3: 15, # dynamic
|
||||
4: 40, # clear
|
||||
5: 100, # random
|
||||
1: 0, # thunderstorm
|
||||
2: 20, # rain
|
||||
3: 80, # clouds
|
||||
4: 100, # clear
|
||||
}
|
||||
|
||||
|
||||
@@ -68,6 +71,29 @@ class EnviromentGenerator:
|
||||
|
||||
self.mission.start_time = start_time
|
||||
|
||||
def _generate_wind(self, wind_speed, wind_direction=None):
|
||||
# wind
|
||||
if not wind_direction:
|
||||
wind_direction = random.randint(0, 360)
|
||||
|
||||
self.mission.weather.wind_at_ground = Wind(wind_direction, wind_speed)
|
||||
self.mission.weather.wind_at_2000 = Wind(wind_direction, wind_speed * 2)
|
||||
self.mission.weather.wind_at_8000 = Wind(wind_direction, wind_speed * 3)
|
||||
|
||||
def _generate_base_weather(self):
|
||||
# clouds
|
||||
self.mission.weather.clouds_base = random.randint(*WEATHER_CLOUD_BASE)
|
||||
self.mission.weather.clouds_density = random.randint(*WEATHER_CLOUD_DENSITY)
|
||||
self.mission.weather.clouds_thickness = random.randint(*WEATHER_CLOUD_THICKNESS)
|
||||
|
||||
# wind
|
||||
self._generate_wind(random.randint(0, 4))
|
||||
|
||||
# fog
|
||||
if random.randint(0, 100) < WEATHER_FOG_CHANCE:
|
||||
self.mission.weather.fog_visibility = random.randint(*WEATHER_FOG_VISIBILITY)
|
||||
self.mission.weather.fog_thickness = random.randint(*WEATHER_FOG_THICKNESS)
|
||||
|
||||
def _gen_random_weather(self):
|
||||
weather_type = None
|
||||
for k, v in RANDOM_WEATHER.items():
|
||||
@@ -77,32 +103,33 @@ class EnviromentGenerator:
|
||||
|
||||
logging.info("generated weather {}".format(weather_type))
|
||||
if weather_type == 1:
|
||||
self.mission.weather.heavy_rain()
|
||||
elif weather_type == 2:
|
||||
self.mission.weather.heavy_rain()
|
||||
self.mission.weather.enable_fog = False
|
||||
elif weather_type == 3:
|
||||
self.mission.weather.random(self.mission.start_time, self.conflict.theater.terrain)
|
||||
elif weather_type == 4:
|
||||
pass
|
||||
elif weather_type == 5:
|
||||
self.mission.weather.clouds_base = random.randint(*WEATHER_CLOUD_BASE)
|
||||
self.mission.weather.clouds_density = random.randint(*WEATHER_CLOUD_DENSITY)
|
||||
self.mission.weather.clouds_thickness = random.randint(*WEATHER_CLOUD_THICKNESS)
|
||||
# thunderstorm
|
||||
self._generate_base_weather()
|
||||
self._generate_wind(random.randint(8, 12))
|
||||
|
||||
wind_direction = random.randint(0, 360)
|
||||
wind_speed = random.randint(0, 4)
|
||||
self.mission.weather.wind_at_ground = Wind(wind_direction, wind_speed)
|
||||
self.mission.weather.wind_at_2000 = Wind(wind_direction, wind_speed * 2)
|
||||
self.mission.weather.wind_at_8000 = Wind(wind_direction, wind_speed * 3)
|
||||
self.mission.weather.clouds_density = random.randint(9, 10)
|
||||
self.mission.weather.clouds_iprecptns = Weather.Preceptions.Thunderstorm
|
||||
elif weather_type == 2:
|
||||
# rain
|
||||
self._generate_base_weather()
|
||||
self.mission.weather.clouds_density = random.randint(5, 8)
|
||||
self.mission.weather.clouds_iprecptns = Weather.Preceptions.Rain
|
||||
|
||||
self._generate_wind(random.randint(4, 8))
|
||||
elif weather_type == 3:
|
||||
# clouds
|
||||
self._generate_base_weather()
|
||||
elif weather_type == 4:
|
||||
# clear
|
||||
pass
|
||||
|
||||
if self.mission.weather.clouds_density > 0:
|
||||
# sometimes clouds are randomized way too low and need to be fixed
|
||||
self.mission.weather.clouds_base = max(self.mission.weather.clouds_base, WEATHER_CLOUD_BASE_MIN)
|
||||
|
||||
if self.mission.weather.wind_at_ground == 0:
|
||||
if self.mission.weather.wind_at_ground.speed == 0:
|
||||
# frontline smokes look silly w/o any wind
|
||||
self.mission.weather.wind_at_ground = random.randint(1, 2)
|
||||
self._generate_wind(1)
|
||||
|
||||
def generate(self) -> EnvironmentSettings:
|
||||
self._gen_random_time()
|
||||
|
||||
@@ -28,6 +28,9 @@ class GroundObjectsGenerator:
|
||||
heading -= 90
|
||||
|
||||
position = self.conflict.find_ground_position(center.point_from_heading(heading, FARP_FRONTLINE_DISTANCE), heading)
|
||||
if not position:
|
||||
return
|
||||
|
||||
for i, _ in enumerate(range(0, number_of_units, self.FARP_CAPACITY)):
|
||||
position = position.point_from_heading(0, i * 275)
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
from .aircraft import *
|
||||
|
||||
|
||||
class HelicopterConflictGenerator(AircraftConflictGenerator):
|
||||
pass
|
||||
@@ -16,7 +16,13 @@ class ShipGenerator:
|
||||
self.m = mission
|
||||
self.conflict = conflict
|
||||
|
||||
def generate_carrier(self, type: ShipType, country: str, at: Point) -> ShipGroup:
|
||||
def generate_carrier(self, for_units: typing.Collection[UnitType], country: str, at: Point) -> ShipGroup:
|
||||
type = db.find_unittype(Carriage, country)[0]
|
||||
for unit_type in for_units:
|
||||
if unit_type in db.CARRIER_TYPE_BY_PLANE:
|
||||
type = db.CARRIER_TYPE_BY_PLANE[unit_type]
|
||||
break
|
||||
|
||||
group = self.m.ship_group(
|
||||
country=self.m.country(country),
|
||||
name=namegen.next_carrier_name(self.m.country(country)),
|
||||
|
||||
@@ -16,7 +16,7 @@ from gen.airsupportgen import AirSupportConflictGenerator
|
||||
from gen import *
|
||||
|
||||
PUSH_TRIGGER_SIZE = 3000
|
||||
PUSH_TRIGGER_ACTIVATION_AGL = 100
|
||||
PUSH_TRIGGER_ACTIVATION_AGL = 25
|
||||
|
||||
REGROUP_ZONE_DISTANCE = 12000
|
||||
REGROUP_ALT = 5000
|
||||
@@ -25,9 +25,10 @@ TRIGGER_WAYPOINT_OFFSET = 2
|
||||
TRIGGER_MIN_DISTANCE_FROM_START = 10000
|
||||
TRIGGER_RADIUS_MINIMUM = 20000
|
||||
|
||||
TRIGGER_RADIUS_SMALL = 30000
|
||||
TRIGGER_RADIUS_SMALL = 50000
|
||||
TRIGGER_RADIUS_MEDIUM = 100000
|
||||
TRIGGER_RADIUS_LARGE = 150000
|
||||
TRIGGER_RADIUS_ALL_MAP = 3000000
|
||||
|
||||
|
||||
class Silence(Option):
|
||||
@@ -53,14 +54,16 @@ class TriggersGenerator:
|
||||
vehicle_group.late_activation = True
|
||||
activate_by_trigger.append(vehicle_group)
|
||||
|
||||
"""
|
||||
conflict_distance = player_cp.position.distance_to_point(self.conflict.position)
|
||||
minimum_radius = max(conflict_distance - TRIGGER_MIN_DISTANCE_FROM_START, TRIGGER_RADIUS_MINIMUM)
|
||||
if minimum_radius < 0:
|
||||
minimum_radius = 0
|
||||
|
||||
result_radius = min(minimum_radius, radius)
|
||||
"""
|
||||
|
||||
activation_trigger_zone = self.mission.triggers.add_triggerzone(self.conflict.position, result_radius, name="Activation zone")
|
||||
activation_trigger_zone = self.mission.triggers.add_triggerzone(self.conflict.position, radius, name="Activation zone")
|
||||
activation_trigger = TriggerOnce(Event.NoEvent, "Activation trigger")
|
||||
activation_trigger.add_condition(PartOfCoalitionInZone(player_coalition, activation_trigger_zone.id))
|
||||
activation_trigger.add_condition(FlagIsTrue())
|
||||
|
||||
@@ -10,9 +10,9 @@ from dcs.task import *
|
||||
from game import db
|
||||
|
||||
STRENGTH_AA_ASSEMBLE_MIN = 0.2
|
||||
PLANES_SCRAMBLE_MIN_BASE = 4
|
||||
PLANES_SCRAMBLE_MIN_BASE = 2
|
||||
PLANES_SCRAMBLE_MAX_BASE = 8
|
||||
PLANES_SCRAMBLE_FACTOR = 0.6
|
||||
PLANES_SCRAMBLE_FACTOR = 0.3
|
||||
|
||||
BASE_MAX_STRENGTH = 1
|
||||
BASE_MIN_STRENGTH = 0
|
||||
|
||||
@@ -33,7 +33,6 @@ class CaucasusTheater(ConflictTheater):
|
||||
gelendzhik = ControlPoint.from_airport(caucasus.Gelendzhik, COAST_DR_E, SIZE_BIG, 1.1)
|
||||
maykop = ControlPoint.from_airport(caucasus.Maykop_Khanskaya, LAND, SIZE_LARGE, IMPORTANCE_HIGH)
|
||||
krasnodar = ControlPoint.from_airport(caucasus.Krasnodar_Center, LAND, SIZE_LARGE, IMPORTANCE_HIGH)
|
||||
novorossiysk = ControlPoint.from_airport(caucasus.Novorossiysk, COAST_DR_E, SIZE_BIG, 1.2)
|
||||
krymsk = ControlPoint.from_airport(caucasus.Krymsk, LAND, SIZE_LARGE, 1.2)
|
||||
anapa = ControlPoint.from_airport(caucasus.Anapa_Vityazevo, LAND, SIZE_LARGE, IMPORTANCE_HIGH)
|
||||
|
||||
|
||||
@@ -72,8 +72,8 @@ class PersianGulfTheater(ConflictTheater):
|
||||
self.add_controlpoint(self.havadarya, connected_to=[self.lar, self.qeshm, self.bandar_abbas])
|
||||
self.add_controlpoint(self.bandar_abbas, connected_to=[self.havadarya])
|
||||
|
||||
self.add_controlpoint(self.east_carrier)
|
||||
self.add_controlpoint(self.west_carrier)
|
||||
self.add_controlpoint(self.east_carrier)
|
||||
|
||||
self.west_carrier.captured = True
|
||||
self.east_carrier.captured = True
|
||||
|
||||
@@ -2,6 +2,7 @@ import math
|
||||
import pickle
|
||||
import random
|
||||
import typing
|
||||
import logging
|
||||
|
||||
from theater.base import *
|
||||
from theater.conflicttheater import *
|
||||
@@ -72,8 +73,8 @@ def generate_groundobjects(theater: ConflictTheater):
|
||||
|
||||
group_id = 0
|
||||
for cp in theater.enemy_points():
|
||||
for _ in range(0, random.randrange(3, 6)):
|
||||
available_categories = list(tpls) + ["aa", "aa", "aa"]
|
||||
for _ in range(0, random.randrange(2, 4)):
|
||||
available_categories = list(tpls) + ["aa", "aa"]
|
||||
tpl_category = random.choice(available_categories)
|
||||
|
||||
tpl = random.choice(list(tpls[tpl_category].values()))
|
||||
@@ -84,14 +85,17 @@ def generate_groundobjects(theater: ConflictTheater):
|
||||
print("Couldn't find point for {}".format(cp))
|
||||
continue
|
||||
|
||||
dist = point.distance_to_point(cp.position)
|
||||
"""
|
||||
dist = point.distance_to_point(cp.position) - 15000
|
||||
for another_cp in theater.enemy_points():
|
||||
if another_cp.position.distance_to_point(point) < dist:
|
||||
cp = another_cp
|
||||
"""
|
||||
|
||||
group_id += 1
|
||||
object_id = 0
|
||||
|
||||
logging.info("generated {} for {}".format(tpl_category, cp))
|
||||
for object in tpl:
|
||||
object_id += 1
|
||||
|
||||
|
||||
@@ -194,6 +194,12 @@ class EventMenu(Menu):
|
||||
self.error_label["text"] = "Need at least one player in flight {}".format(self.event.flight_name(task))
|
||||
return
|
||||
|
||||
if isinstance(self.event, FrontlineAttackEvent) or isinstance(self.event, FrontlinePatrolEvent):
|
||||
if tasks_scramble_counts.get(PinpointStrike, 0) == 0:
|
||||
self.error_label["text"] = "No ground vehicles assigned to attack!"
|
||||
return
|
||||
|
||||
|
||||
if self.game.is_player_attack(self.event):
|
||||
self.event.player_attacking(flights)
|
||||
else:
|
||||
|
||||
@@ -54,6 +54,7 @@ class EventResultsMenu(Menu):
|
||||
pg.start(10)
|
||||
row += 1
|
||||
|
||||
"""
|
||||
Label(self.frame, text="Cheat operation results: ", **STYLES["strong"]).grid(column=0, row=row,
|
||||
columnspan=2, sticky=NSEW,
|
||||
pady=5)
|
||||
@@ -69,6 +70,7 @@ class EventResultsMenu(Menu):
|
||||
Button(self.frame, text="some player losses", command=self.simulate_result(0.8, 0),
|
||||
**STYLES["btn-warning"]).grid(column=1, row=row, padx=5, pady=5)
|
||||
row += 1
|
||||
"""
|
||||
|
||||
else:
|
||||
row = 0
|
||||
@@ -99,12 +101,14 @@ class EventResultsMenu(Menu):
|
||||
Label(self.frame, text="{}".format(count), **STYLES["widget"]).grid(column=1, row=row)
|
||||
row += 1
|
||||
|
||||
Button(self.frame, text="Okay", command=self.dismiss, **STYLES["btn-primary"]).grid(columnspan=1, row=row);
|
||||
Button(self.frame, text="Okay", command=self.dismiss, **STYLES["btn-primary"]).grid(columnspan=1, row=row)
|
||||
row += 1
|
||||
|
||||
def process_debriefing(self, debriefing: Debriefing):
|
||||
self.debriefing = debriefing
|
||||
debriefing.calculate_units(mission=self.event.operation.mission,
|
||||
|
||||
debriefing.calculate_units(regular_mission=self.event.operation.regular_mission,
|
||||
quick_mission=self.event.operation.quick_mission,
|
||||
player_name=self.game.player,
|
||||
enemy_name=self.game.enemy)
|
||||
|
||||
|
||||
@@ -98,9 +98,6 @@ class NewGameMenu(Menu):
|
||||
Label(terrain, text="Persian Gulf", **STYLES["widget"]).grid(row=2, column=1, sticky=W)
|
||||
self.create_label_image(terrain, "terrain_pg.gif").grid(row=2, column=2, padx=5)
|
||||
|
||||
Label(terrain, text="Currently strike missions are only\navailable for a number of airports only in Caucasus", **STYLES["widget"]) \
|
||||
.grid(row=3, column=0, columnspan=3, sticky=W)
|
||||
|
||||
# Misc Options
|
||||
options = LabelFrame(body, text="Misc Options", **STYLES["label-frame"])
|
||||
options.grid(row=0, column=2, sticky=NE, padx=5)
|
||||
|
||||
@@ -60,11 +60,12 @@ def parse_mutliplayer_debriefing(contents: str):
|
||||
|
||||
|
||||
class Debriefing:
|
||||
def __init__(self, dead_units):
|
||||
def __init__(self, dead_units, trigger_state):
|
||||
self.destroyed_units = {} # type: typing.Dict[str, typing.Dict[UnitType, int]]
|
||||
self.alive_units = {} # type: typing.Dict[str, typing.Dict[UnitType, int]]
|
||||
self.destroyed_objects = [] # type: typing.List[str]
|
||||
|
||||
self._trigger_state = trigger_state
|
||||
self._dead_units = dead_units
|
||||
|
||||
@classmethod
|
||||
@@ -99,29 +100,16 @@ class Debriefing:
|
||||
if event_type in ["crash", "dead"]:
|
||||
parse_dead_object(event)
|
||||
|
||||
"""
|
||||
initiator_components = event["initiator"].split("|")
|
||||
trigger_state = table.get("debriefing", {}).get("triggers_state", {})
|
||||
|
||||
if initiator_components[0] in CATEGORY_MAP:
|
||||
parse_dead_object(event)
|
||||
else:
|
||||
parse_dead_unit(event)
|
||||
"""
|
||||
return Debriefing(dead_units, trigger_state)
|
||||
|
||||
return Debriefing(dead_units)
|
||||
|
||||
def calculate_units(self, mission: Mission, player_name: str, enemy_name: str):
|
||||
def calculate_units(self, regular_mission: Mission, quick_mission: Mission, player_name: str, enemy_name: str):
|
||||
def count_groups(groups: typing.List[UnitType]) -> typing.Dict[UnitType, int]:
|
||||
result = {}
|
||||
for group in groups:
|
||||
for unit in group.units:
|
||||
if isinstance(unit, Vehicle):
|
||||
unit_type = vehicle_map[unit.type]
|
||||
elif isinstance(unit, Ship):
|
||||
unit_type = ship_map[unit.type]
|
||||
else:
|
||||
unit_type = unit.unit_type
|
||||
|
||||
unit_type = db.unit_type_of(unit)
|
||||
if unit_type in db.EXTRA_AA.values():
|
||||
continue
|
||||
|
||||
@@ -129,6 +117,8 @@ class Debriefing:
|
||||
|
||||
return result
|
||||
|
||||
mission = regular_mission if len(self._trigger_state) else quick_mission
|
||||
|
||||
player = mission.country(player_name)
|
||||
enemy = mission.country(enemy_name)
|
||||
|
||||
@@ -151,15 +141,20 @@ class Debriefing:
|
||||
for group in country_groups:
|
||||
for unit in group.units:
|
||||
if unit.id in self._dead_units:
|
||||
logging.info("debriefing: found dead unit {} ({})".format(str(unit.name), unit.id))
|
||||
unit_klass = db.unit_type_from_name(unit.type)
|
||||
self.destroyed_units[country_name][unit_klass] = self.destroyed_units[country_name].get(unit_klass, 0) + 1
|
||||
unit_type = db.unit_type_of(unit)
|
||||
logging.info("debriefing: found dead unit {} ({}, {})".format(str(unit.name), unit.id, unit_type))
|
||||
|
||||
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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user