From ca521e7e511640a37765e492c3ab3b567a37070e Mon Sep 17 00:00:00 2001 From: Vasyl Horbachenko Date: Mon, 10 Sep 2018 23:12:04 +0300 Subject: [PATCH] FARPs for heli flights WIP --- game/db.py | 20 ++++++++++++++++-- game/event/baseattack.py | 21 ++++++------------- game/event/event.py | 8 +++----- game/event/frontlineattack.py | 11 ++-------- game/event/frontlinepatrol.py | 13 +++--------- game/event/infantrytransport.py | 2 +- game/event/insurgentattack.py | 2 +- game/event/intercept.py | 17 ++++----------- game/event/navalintercept.py | 17 ++++----------- game/event/strike.py | 13 ++---------- game/operation/baseattack.py | 29 ++++++++++---------------- game/operation/frontlineattack.py | 26 +++++++++-------------- game/operation/frontlinepatrol.py | 32 +++++++++-------------------- game/operation/infantrytransport.py | 18 ++++------------ game/operation/insurgentattack.py | 18 ++++------------ game/operation/intercept.py | 15 +++++++------- game/operation/navalintercept.py | 15 +++++++------- game/operation/operation.py | 19 +---------------- game/operation/strike.py | 30 +++++++++------------------ gen/aircraft.py | 4 ++-- gen/conflictgen.py | 5 ++++- gen/groundobjectsgen.py | 13 ++++++++++++ ui/eventmenu.py | 2 +- 23 files changed, 128 insertions(+), 222 deletions(-) diff --git a/game/db.py b/game/db.py index 392514a1..9d4f714d 100644 --- a/game/db.py +++ b/game/db.py @@ -366,7 +366,7 @@ PLANE_PAYLOAD_OVERRIDES = { }, MiG_21Bis: { - "*": "Patrol, medium range", + CAP: "Patrol, medium range", } } @@ -392,7 +392,11 @@ HeliDict = typing.Dict[HelicopterType, int] ArmorDict = typing.Dict[VehicleType, int] ShipDict = typing.Dict[ShipType, int] AirDefenseDict = typing.Dict[AirDefence, int] -StartingPosition = typing.Optional[typing.Union[ShipGroup, Airport, Point]] + +AssignedUnitsDict = typing.Dict[typing.Type[UnitType], typing.Tuple[int, int]] +TaskForceDict = typing.Dict[typing.Type[Task], AssignedUnitsDict] + +StartingPosition = typing.Optional[typing.Union[ShipGroup, StaticGroup, Airport, Point]] def unit_task(unit: UnitType) -> Task: @@ -471,6 +475,18 @@ def unitdict_restrict_count(unit_dict: UnitsDict, total_count: int) -> UnitsDict return {} +def assigned_units_split(fd: AssignedUnitsDict) -> typing.Tuple[PlaneDict, PlaneDict]: + return {k: v1 for k, (v1, v2) in fd.items()}, {k: v2 for k, (v1, v2) in fd.items()}, + + +def assigned_units_from(d: PlaneDict) -> AssignedUnitsDict: + return {k: (v, 0) for k, v in d.items()} + + +def unitdict_from(fd: AssignedUnitsDict) -> Dict: + return {k: v1 for k, (v1, v2) in fd.items()} + + def _validate_db(): # check unit by task uniquity total_set = set() diff --git a/game/event/baseattack.py b/game/event/baseattack.py index 98b0bd52..e708f5cc 100644 --- a/game/event/baseattack.py +++ b/game/event/baseattack.py @@ -1,16 +1,7 @@ -import typing -import math -import random - -from dcs.task import * -from dcs.unittype import UnitType - -from game import db from game.operation.baseattack import BaseAttackOperation -from userdata.debriefing import Debriefing from .event import * -from ..operation.operation import flight_dict_from +from game.db import assigned_units_from class BaseAttackEvent(Event): @@ -60,7 +51,7 @@ class BaseAttackEvent(Event): if not self.is_player_attacking and self.to_cp.captured: self.to_cp.captured = False - def player_defending(self, flights: ScrambledFlightsDict): + def player_defending(self, flights: db.TaskForceDict): assert CAP in flights and len(flights) == 1, "Invalid scrambled flights" cas = self.from_cp.base.scramble_cas(self.game.settings.multiplier) @@ -73,8 +64,8 @@ class BaseAttackEvent(Event): from_cp=self.from_cp, to_cp=self.to_cp) - op.setup(cas=flight_dict_from(cas), - escort=flight_dict_from(escort), + op.setup(cas=assigned_units_from(cas), + escort=assigned_units_from(escort), intercept=flights[CAP], attack=attackers, defense=self.to_cp.base.armor, @@ -82,7 +73,7 @@ class BaseAttackEvent(Event): self.operation = op - def player_attacking(self, flights: ScrambledFlightsDict): + def player_attacking(self, flights: db.TaskForceDict): assert CAP in flights and CAS in flights and PinpointStrike in flights and len(flights) == 3, "Invalid flights" op = BaseAttackOperation(game=self.game, @@ -97,7 +88,7 @@ class BaseAttackEvent(Event): op.setup(cas=flights[CAS], escort=flights[CAP], attack=flights[PinpointStrike], - intercept=flight_dict_from(defenders), + intercept=assigned_units_from(defenders), defense=self.to_cp.base.armor, aa=self.to_cp.base.assemble_aa()) diff --git a/game/event/event.py b/game/event/event.py index e771a9f7..55439e30 100644 --- a/game/event/event.py +++ b/game/event/event.py @@ -8,15 +8,13 @@ from dcs.unittype import UnitType from game import * from theater import * from gen.environmentgen import EnvironmentSettings -from game.operation.operation import flight_dict_from, dict_from_flight +from game.db import assigned_units_from, unitdict_from from userdata.debriefing import Debriefing from userdata import persistency DIFFICULTY_LOG_BASE = 1.1 -ScrambledFlightsDict = typing.Dict[typing.Type[Task], typing.Dict[typing.Type[UnitType], typing.Tuple[int, int]]] - class Event: silent = False @@ -67,10 +65,10 @@ class Event: def is_successfull(self, debriefing: Debriefing) -> bool: return self.operation.is_successfull(debriefing) - def player_attacking(self, flights: ScrambledFlightsDict): + def player_attacking(self, flights: db.TaskForceDict): assert False - def player_defending(self, flights: ScrambledFlightsDict): + def player_defending(self, flights: db.TaskForceDict): assert False def generate(self): diff --git a/game/event/frontlineattack.py b/game/event/frontlineattack.py index 90e8ec0f..5560c714 100644 --- a/game/event/frontlineattack.py +++ b/game/event/frontlineattack.py @@ -1,10 +1,3 @@ -import math -import random - -from dcs.task import * -from dcs.vehicles import AirDefence - -from game import * from game.event import * from game.operation.frontlineattack import FrontlineAttackOperation from userdata.debriefing import Debriefing @@ -69,7 +62,7 @@ class FrontlineAttackEvent(Event): if self.to_cp.captured: self.to_cp.base.affect_strength(-0.1) - def player_attacking(self, flights: ScrambledFlightsDict): + def player_attacking(self, flights: db.TaskForceDict): assert CAS in flights and PinpointStrike in flights and len(flights) == 2, "Invalid flights" self.defenders = self.to_cp.base.assemble_attack() @@ -80,7 +73,7 @@ class FrontlineAttackEvent(Event): from_cp=self.from_cp, to_cp=self.to_cp) - armor = dict_from_flight(flights[PinpointStrike]) + armor = unitdict_from(flights[PinpointStrike]) op.setup(target=self.defenders, attackers=db.unitdict_restrict_count(armor, sum(self.defenders.values())), strikegroup=flights[CAS]) diff --git a/game/event/frontlinepatrol.py b/game/event/frontlinepatrol.py index 3413dfbc..e2ec1603 100644 --- a/game/event/frontlinepatrol.py +++ b/game/event/frontlinepatrol.py @@ -1,10 +1,3 @@ -import math -import random - -from dcs.task import * -from dcs.vehicles import AirDefence - -from game import * from game.event import * from game.operation.frontlinepatrol import FrontlinePatrolOperation from userdata.debriefing import Debriefing @@ -61,7 +54,7 @@ class FrontlinePatrolEvent(Event): def skip(self): pass - def player_attacking(self, flights: ScrambledFlightsDict): + def player_attacking(self, flights: db.TaskForceDict): assert CAP in flights and PinpointStrike in flights and len(flights) == 2, "Invalid flights" self.cas = self.to_cp.base.scramble_cas(self.game.settings.multiplier) @@ -74,8 +67,8 @@ class FrontlinePatrolEvent(Event): to_cp=self.to_cp) defenders = self.to_cp.base.assemble_attack() - op.setup(cas=flight_dict_from(self.cas), - escort=flight_dict_from(self.escort), + op.setup(cas=assigned_units_from(self.cas), + escort=assigned_units_from(self.escort), interceptors=flights[CAP], armor_attackers=db.unitdict_restrict_count(dict_from_flight(flights[PinpointStrike]), sum(defenders.values())), armor_defenders=defenders) diff --git a/game/event/infantrytransport.py b/game/event/infantrytransport.py index 2086c025..59d85abe 100644 --- a/game/event/infantrytransport.py +++ b/game/event/infantrytransport.py @@ -37,7 +37,7 @@ class InfantryTransportEvent(Event): else: self.from_cp.base.affect_strength(-self.STRENGTH_INFLUENCE) - def player_attacking(self, flights: ScrambledFlightsDict): + def player_attacking(self, flights: db.TaskForceDict): assert Embarking in flights and len(flights) == 1, "Invalid flights" op = InfantryTransportOperation( diff --git a/game/event/insurgentattack.py b/game/event/insurgentattack.py index de4df51b..5a5d3f0a 100644 --- a/game/event/insurgentattack.py +++ b/game/event/insurgentattack.py @@ -40,7 +40,7 @@ class InsurgentAttackEvent(Event): else: return not attackers_success - def player_defending(self, flights: ScrambledFlightsDict): + def player_defending(self, flights: db.TaskForceDict): assert CAS in flights and len(flights) == 1, "Invalid flights" suitable_unittypes = db.find_unittype(Reconnaissance, self.attacker_name) diff --git a/game/event/intercept.py b/game/event/intercept.py index eca702e2..a137d9b2 100644 --- a/game/event/intercept.py +++ b/game/event/intercept.py @@ -1,13 +1,4 @@ -import math -import random - -from dcs.task import * -from dcs.vehicles import * - -from game import db from game.operation.intercept import InterceptOperation -from theater.conflicttheater import * -from userdata.debriefing import Debriefing from .event import * @@ -68,7 +59,7 @@ class InterceptEvent(Event): if self.to_cp.captured: self.to_cp.base.affect_strength(-self.STRENGTH_INFLUENCE) - def player_attacking(self, flights: ScrambledFlightsDict): + def player_attacking(self, flights: db.TaskForceDict): assert CAP in flights and len(flights) == 1, "Invalid flights" escort = self.to_cp.base.scramble_sweep(self._enemy_scramble_multiplier()) @@ -83,14 +74,14 @@ class InterceptEvent(Event): from_cp=self.from_cp, to_cp=self.to_cp) - op.setup(escort=flight_dict_from(escort), + op.setup(escort=assigned_units_from(escort), transport={self.transport_unit: 1}, airdefense={airdefense_unit: self.AIRDEFENSE_COUNT}, interceptors=flights[CAP]) self.operation = op - def player_defending(self, flights: ScrambledFlightsDict): + def player_defending(self, flights: db.TaskForceDict): assert CAP in flights and len(flights) == 1, "Invalid flights" interceptors = self.from_cp.base.scramble_interceptors(self.game.settings.multiplier) @@ -106,7 +97,7 @@ class InterceptEvent(Event): op.setup(escort=flights[CAP], transport={self.transport_unit: 1}, - interceptors=flight_dict_from(interceptors), + interceptors=assigned_units_from(interceptors), airdefense={}) self.operation = op diff --git a/game/event/navalintercept.py b/game/event/navalintercept.py index 0f776197..f1049a2d 100644 --- a/game/event/navalintercept.py +++ b/game/event/navalintercept.py @@ -1,13 +1,4 @@ -import typing -import math -import random - -from dcs.task import * -from dcs.vehicles import * - -from game import db from game.operation.navalintercept import NavalInterceptionOperation -from userdata.debriefing import Debriefing from .event import * @@ -19,7 +10,7 @@ class NavalInterceptEvent(Event): targets = None # type: db.ShipDict def _targets_count(self) -> int: - from gen.conflictgen import IMPORTANCE_LOW, IMPORTANCE_HIGH + from gen.conflictgen import IMPORTANCE_LOW factor = (self.to_cp.importance - IMPORTANCE_LOW) * 10 return max(int(factor), 1) @@ -77,7 +68,7 @@ class NavalInterceptEvent(Event): if self.to_cp.captured: self.to_cp.base.affect_strength(-self.STRENGTH_INFLUENCE) - def player_attacking(self, flights: ScrambledFlightsDict): + def player_attacking(self, flights: db.TaskForceDict): assert CAS in flights and len(flights) == 1, "Invalid flights" self.targets = { @@ -98,7 +89,7 @@ class NavalInterceptEvent(Event): self.operation = op - def player_defending(self, flights: ScrambledFlightsDict): + def player_defending(self, flights: db.TaskForceDict): assert CAP in flights and len(flights) == 1, "Invalid flights" self.targets = { @@ -114,7 +105,7 @@ class NavalInterceptEvent(Event): ) strikegroup = self.from_cp.base.scramble_cas(self.game.settings.multiplier) - op.setup(strikegroup=flight_dict_from(strikegroup), + op.setup(strikegroup=assigned_units_from(strikegroup), interceptors=flights[CAP], targets=self.targets) diff --git a/game/event/strike.py b/game/event/strike.py index 158da7af..5785b7cc 100644 --- a/game/event/strike.py +++ b/game/event/strike.py @@ -1,13 +1,4 @@ -import math -import random - -from dcs.task import * -from dcs.vehicles import * - -from game import db from game.operation.strike import StrikeOperation -from theater.conflicttheater import * -from userdata.debriefing import Debriefing from .event import * @@ -50,7 +41,7 @@ class StrikeEvent(Event): super(StrikeEvent, self).commit(debriefing) self.to_cp.base.affect_strength(-self.SINGLE_OBJECT_STRENGTH_INFLUENCE * len(debriefing.destroyed_objects)) - def player_attacking(self, flights: ScrambledFlightsDict): + def player_attacking(self, flights: db.TaskForceDict): assert CAP in flights and CAS in flights and len(flights) == 2, "Invalid flights" op = StrikeOperation( @@ -64,6 +55,6 @@ class StrikeEvent(Event): interceptors = self.to_cp.base.scramble_interceptors(self.game.settings.multiplier) op.setup(strikegroup=flights[CAS], escort=flights[CAP], - interceptors=flight_dict_from(interceptors)) + interceptors=assigned_units_from(interceptors)) self.operation = op diff --git a/game/operation/baseattack.py b/game/operation/baseattack.py index dcb6d7d9..51d887f8 100644 --- a/game/operation/baseattack.py +++ b/game/operation/baseattack.py @@ -1,21 +1,14 @@ -from game import db +from game.db import assigned_units_split -from gen.conflictgen import Conflict -from gen.armor import * -from gen.aircraft import * -from gen.aaa import * -from gen.shipgen import * from gen.triggergen import * -from gen.airsupportgen import * -from gen.visualgen import * from .operation import * class BaseAttackOperation(Operation): - cas = None # type: FlightDict - escort = None # type: FlightDict - intercept = None # type: FlightDict + cas = None # type: db.AssignedUnitsDict + escort = None # type: db.AssignedUnitsDict + intercept = None # type: db.AssignedUnitsDict attack = None # type: db.ArmorDict defense = None # type: db.ArmorDict aa = None # type: db.AirDefenseDict @@ -23,10 +16,10 @@ class BaseAttackOperation(Operation): trigger_radius = TRIGGER_RADIUS_SMALL def setup(self, - cas: FlightDict, - escort: FlightDict, - attack: FlightDict, - intercept: FlightDict, + cas: db.AssignedUnitsDict, + escort: db.AssignedUnitsDict, + attack: db.AssignedUnitsDict, + intercept: db.AssignedUnitsDict, defense: db.ArmorDict, aa: db.AirDefenseDict): self.cas = cas @@ -57,10 +50,10 @@ class BaseAttackOperation(Operation): self.armorgen.generate(self.attack, self.defense) self.aagen.generate(self.aa) - self.airgen.generate_defense(*flight_arguments(self.intercept), at=self.defenders_starting_position) + self.airgen.generate_defense(*assigned_units_split(self.intercept), at=self.defenders_starting_position) - self.airgen.generate_cas_strikegroup(*flight_arguments(self.cas), at=self.attackers_starting_position) - self.airgen.generate_attackers_escort(*flight_arguments(self.escort), at=self.attackers_starting_position) + self.airgen.generate_cas_strikegroup(*assigned_units_split(self.cas), at=self.attackers_starting_position) + self.airgen.generate_attackers_escort(*assigned_units_split(self.escort), at=self.attackers_starting_position) self.visualgen.generate_target_smokes(self.to_cp) diff --git a/game/operation/frontlineattack.py b/game/operation/frontlineattack.py index 0a2a289b..4b80fa39 100644 --- a/game/operation/frontlineattack.py +++ b/game/operation/frontlineattack.py @@ -1,16 +1,4 @@ -from itertools import zip_longest - -from dcs.terrain import Terrain - -from game import db -from gen.armor import * -from gen.aircraft import * -from gen.aaa import * -from gen.shipgen import * -from gen.triggergen import * -from gen.airsupportgen import * -from gen.visualgen import * -from gen.conflictgen import Conflict +from game.db import assigned_units_split from .operation import * @@ -19,14 +7,14 @@ MAX_DISTANCE_BETWEEN_GROUPS = 12000 class FrontlineAttackOperation(Operation): - strikegroup = None # type: FlightDict + strikegroup = None # type: db.AssignedUnitsDict attackers = None # type: db.ArmorDict target = None # type: db.ArmorDict def setup(self, target: db.ArmorDict, attackers: db.ArmorDict, - strikegroup: FlightDict): + strikegroup: db.AssignedUnitsDict): self.strikegroup = strikegroup self.target = target self.attackers = attackers @@ -50,7 +38,13 @@ class FrontlineAttackOperation(Operation): def generate(self): self.armorgen.generate_vec(self.attackers, self.target) - self.airgen.generate_cas_strikegroup(*flight_arguments(self.strikegroup), at=self.attackers_starting_position) + + planes_flights = {k: v for k, v in self.strikegroup.items() if k in plane_map} + self.airgen.generate_cas_strikegroup(*assigned_units_split(planes_flights), at=self.attackers_starting_position) + + heli_flights = {k: v for k, v in self.strikegroup.items() if k in helicopters.helicopter_map} + if heli_flights: + self.airgen.generate_cas_strikegroup(*assigned_units_split(heli_flights), at=self.groundobjectgen.generate_farp()) self.briefinggen.title = "Frontline CAS" self.briefinggen.description = "Provide CAS for the ground forces attacking enemy lines. Operation will be considered successful if total number of enemy units will be lower than your own by a factor of 1.5 (i.e. with 12 units from both sides, enemy forces need to be reduced to at least 8), meaning that you (and, probably, your wingmans) should concentrate on destroying the enemy units. Target base strength will be lowered as a result. Be advised that your flight will not attack anything until you explicitly tell them so by comms menu." diff --git a/game/operation/frontlinepatrol.py b/game/operation/frontlinepatrol.py index 09f2bb1d..2bad15f6 100644 --- a/game/operation/frontlinepatrol.py +++ b/game/operation/frontlinepatrol.py @@ -1,16 +1,4 @@ -from itertools import zip_longest - -from dcs.terrain import Terrain - -from game import db -from gen.armor import * -from gen.aircraft import * -from gen.aaa import * -from gen.shipgen import * -from gen.triggergen import * -from gen.airsupportgen import * -from gen.visualgen import * -from gen.conflictgen import Conflict +from game.db import assigned_units_split from .operation import * @@ -19,17 +7,17 @@ MAX_DISTANCE_BETWEEN_GROUPS = 12000 class FrontlinePatrolOperation(Operation): - cas = None # type: FlightDict - escort = None # type: FlightDict - interceptors = None # type: FlightDict + cas = None # type: db.AssignedUnitsDict + escort = None # type: db.AssignedUnitsDict + interceptors = None # type: db.AssignedUnitsDict armor_attackers = None # type: db.ArmorDict armor_defenders = None # type: db.ArmorDict def setup(self, - cas: FlightDict, - escort: FlightDict, - interceptors: FlightDict, + cas: db.AssignedUnitsDict, + escort: db.AssignedUnitsDict, + interceptors: db.AssignedUnitsDict, armor_attackers: db.ArmorDict, armor_defenders: db.ArmorDict): self.cas = cas @@ -55,9 +43,9 @@ class FrontlinePatrolOperation(Operation): conflict=conflict) def generate(self): - self.airgen.generate_defenders_cas(*flight_arguments(self.cas), at=self.defenders_starting_position) - self.airgen.generate_defenders_escort(*flight_arguments(self.escort), at=self.defenders_starting_position) - self.airgen.generate_migcap(*flight_arguments(self.interceptors), at=self.attackers_starting_position) + self.airgen.generate_defenders_cas(*assigned_units_split(self.cas), at=self.defenders_starting_position) + self.airgen.generate_defenders_escort(*assigned_units_split(self.escort), at=self.defenders_starting_position) + self.airgen.generate_migcap(*assigned_units_split(self.interceptors), at=self.attackers_starting_position) self.armorgen.generate_vec(self.armor_attackers, self.armor_defenders) diff --git a/game/operation/infantrytransport.py b/game/operation/infantrytransport.py index bdf588b0..d96bd2cd 100644 --- a/game/operation/infantrytransport.py +++ b/game/operation/infantrytransport.py @@ -1,23 +1,13 @@ -from dcs.terrain import Terrain - -from game import db -from gen.armor import * -from gen.aircraft import * -from gen.aaa import * -from gen.shipgen import * -from gen.triggergen import * -from gen.airsupportgen import * -from gen.visualgen import * -from gen.conflictgen import Conflict +from game.db import assigned_units_split from .operation import * class InfantryTransportOperation(Operation): - transport = None # type: FlightDict + transport = None # type: db.AssignedUnitsDict aa = None # type: db.AirDefenseDict - def setup(self, transport: FlightDict, aa: db.AirDefenseDict): + def setup(self, transport: db.AssignedUnitsDict, aa: db.AirDefenseDict): self.transport = transport self.aa = aa @@ -36,7 +26,7 @@ class InfantryTransportOperation(Operation): conflict=conflict) def generate(self): - self.airgen.generate_passenger_transport(*flight_arguments(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.aagen.generate_at_defenders_location(self.aa) diff --git a/game/operation/insurgentattack.py b/game/operation/insurgentattack.py index dc4988eb..410517da 100644 --- a/game/operation/insurgentattack.py +++ b/game/operation/insurgentattack.py @@ -1,25 +1,15 @@ -from dcs.terrain import Terrain - -from game import db -from gen.armor import * -from gen.aircraft import * -from gen.aaa import * -from gen.shipgen import * -from gen.triggergen import * -from gen.airsupportgen import * -from gen.visualgen import * -from gen.conflictgen import Conflict +from game.db import assigned_units_split from .operation import * class InsurgentAttackOperation(Operation): - strikegroup = None # type: FlightDict + strikegroup = None # type: db.AssignedUnitsDict target = None # type: db.ArmorDict def setup(self, target: db.ArmorDict, - strikegroup: FlightDict): + strikegroup: db.AssignedUnitsDict): self.strikegroup = strikegroup self.target = target @@ -38,7 +28,7 @@ class InsurgentAttackOperation(Operation): conflict=conflict) def generate(self): - self.airgen.generate_defense(*flight_arguments(self.strikegroup), at=self.defenders_starting_position) + self.airgen.generate_defense(*assigned_units_split(self.strikegroup), at=self.defenders_starting_position) self.armorgen.generate(self.target, {}) self.briefinggen.title = "Destroy insurgents" diff --git a/game/operation/intercept.py b/game/operation/intercept.py index 9ff5cd02..ba396dbe 100644 --- a/game/operation/intercept.py +++ b/game/operation/intercept.py @@ -1,22 +1,21 @@ -from dcs.terrain import Terrain +from game.db import assigned_units_split -from gen import * from .operation import * class InterceptOperation(Operation): - escort = None # type: FlightDict + escort = None # type: db.AssignedUnitsDict transport = None # type: db.PlaneDict - interceptors = None # type: FlightDict + interceptors = None # type: db.AssignedUnitsDict airdefense = None # type: db.AirDefenseDict trigger_radius = TRIGGER_RADIUS_LARGE def setup(self, - escort: FlightDict, + escort: db.AssignedUnitsDict, transport: db.PlaneDict, airdefense: db.AirDefenseDict, - interceptors: FlightDict): + interceptors: db.AssignedUnitsDict): self.escort = escort self.transport = transport self.airdefense = airdefense @@ -52,9 +51,9 @@ class InterceptOperation(Operation): self.attackers_starting_position = ship self.airgen.generate_transport(self.transport, self.to_cp.at) - self.airgen.generate_defenders_escort(*flight_arguments(self.escort), at=self.defenders_starting_position) + self.airgen.generate_defenders_escort(*assigned_units_split(self.escort), at=self.defenders_starting_position) - self.airgen.generate_interception(*flight_arguments(self.interceptors), at=self.attackers_starting_position) + self.airgen.generate_interception(*assigned_units_split(self.interceptors), at=self.attackers_starting_position) self.briefinggen.title = "Air Intercept" self.briefinggen.description = "Intercept enemy supply transport aircraft. Escort will also be present if there are available planes on the base. Operation will be considered successful if most of the targets are destroyed, lowering targets strength as a result" diff --git a/game/operation/navalintercept.py b/game/operation/navalintercept.py index 6c9e5954..77c5d746 100644 --- a/game/operation/navalintercept.py +++ b/game/operation/navalintercept.py @@ -1,18 +1,17 @@ -from dcs.terrain import Terrain +from game.db import assigned_units_split -from gen import * from .operation import * class NavalInterceptionOperation(Operation): - strikegroup = None # type: FlightDict - interceptors = None # type: FlightDict + strikegroup = None # type: db.AssignedUnitsDict + interceptors = None # type: db.AssignedUnitsDict targets = None # type: db.ShipDict trigger_radius = TRIGGER_RADIUS_LARGE def setup(self, - strikegroup: FlightDict, - interceptors: FlightDict, + strikegroup: db.AssignedUnitsDict, + interceptors: db.AssignedUnitsDict, targets: db.ShipDict): self.strikegroup = strikegroup self.interceptors = interceptors @@ -37,14 +36,14 @@ class NavalInterceptionOperation(Operation): target_groups = self.shipgen.generate_cargo(units=self.targets) self.airgen.generate_ship_strikegroup( - *flight_arguments(self.strikegroup), + *assigned_units_split(self.strikegroup), target_groups=target_groups, at=self.attackers_starting_position ) if self.interceptors: self.airgen.generate_defense( - *flight_arguments(self.interceptors), + *assigned_units_split(self.interceptors), at=self.defenders_starting_position ) diff --git a/game/operation/operation.py b/game/operation/operation.py index 9edb3eae..a87d7e33 100644 --- a/game/operation/operation.py +++ b/game/operation/operation.py @@ -1,31 +1,14 @@ -import typing - from dcs.lua.parse import loads -from dcs.unittype import UnitType from userdata.debriefing import * -from theater import * from gen import * -FlightDict = typing.Dict[typing.Type[UnitType], typing.Tuple[int, int]] - - -def flight_arguments(fd: FlightDict) -> typing.Tuple[db.PlaneDict, db.PlaneDict]: - return {k: v1 for k, (v1, v2) in fd.items()}, {k: v2 for k, (v1, v2) in fd.items()}, - - -def flight_dict_from(d: db.PlaneDict) -> FlightDict: - return {k: (v, 0) for k, v in d.items()} - - -def dict_from_flight(fd: FlightDict) -> db.Dict: - return {k: v1 for k, (v1, v2) in fd.items()} - class Operation: attackers_starting_position = None # type: db.StartingPosition defenders_starting_position = None # type: db.StartingPosition + mission = None # type: dcs.Mission conflict = None # type: Conflict armorgen = None # type: ArmorConflictGenerator diff --git a/game/operation/strike.py b/game/operation/strike.py index 1ee8d940..20391305 100644 --- a/game/operation/strike.py +++ b/game/operation/strike.py @@ -1,27 +1,17 @@ -from dcs.terrain import Terrain - -from game import db -from gen.armor import * -from gen.aircraft import * -from gen.aaa import * -from gen.shipgen import * -from gen.triggergen import * -from gen.airsupportgen import * -from gen.visualgen import * -from gen.conflictgen import Conflict +from game.db import assigned_units_split from .operation import * class StrikeOperation(Operation): - strikegroup = None # type: FlightDict - escort = None # type: FlightDict - interceptors = None # type: FlightDict + strikegroup = None # type: db.AssignedUnitsDict + escort = None # type: db.AssignedUnitsDict + interceptors = None # type: db.AssignedUnitsDict def setup(self, - strikegroup: FlightDict, - escort: FlightDict, - interceptors: FlightDict): + strikegroup: db.AssignedUnitsDict, + escort: db.AssignedUnitsDict, + interceptors: db.AssignedUnitsDict): self.strikegroup = strikegroup self.escort = escort self.interceptors = interceptors @@ -61,13 +51,13 @@ class StrikeOperation(Operation): targets.sort(key=lambda x: self.from_cp.position.distance_to_point(x[1])) - self.airgen.generate_ground_attack_strikegroup(*flight_arguments(self.strikegroup), + self.airgen.generate_ground_attack_strikegroup(*assigned_units_split(self.strikegroup), targets=targets, at=self.attackers_starting_position) - self.airgen.generate_attackers_escort(*flight_arguments(self.escort), at=self.attackers_starting_position) + self.airgen.generate_attackers_escort(*assigned_units_split(self.escort), at=self.attackers_starting_position) - self.airgen.generate_barcap(*flight_arguments(self.interceptors), at=self.defenders_starting_position) + self.airgen.generate_barcap(*assigned_units_split(self.interceptors), at=self.defenders_starting_position) self.briefinggen.title = "Strike" self.briefinggen.description = "Destroy infrastructure assets and military supplies in the region. Each building destroyed will lower targets strength." diff --git a/gen/aircraft.py b/gen/aircraft.py index 457688e5..a2c6cb9c 100644 --- a/gen/aircraft.py +++ b/gen/aircraft.py @@ -42,7 +42,7 @@ GROUP_VERTICAL_OFFSET = 300 class AircraftConflictGenerator: - escort_targets = [] # type: typing.List[typing.Tuple[PlaneGroup, int]] + escort_targets = [] # type: typing.List[typing.Tuple[FlyingGroup, int]] vertical_offset = None # type: int def __init__(self, mission: Mission, conflict: Conflict, settings: Settings): @@ -77,7 +77,7 @@ class AircraftConflictGenerator: count -= group_size client_count -= client_size - def _setup_group(self, group: FlyingGroup, for_task: Task, client_count: int): + def _setup_group(self, group: FlyingGroup, for_task: typing.Type[Task], client_count: int): did_load_loadout = False unit_type = group.units[0].unit_type if unit_type in db.PLANE_PAYLOAD_OVERRIDES: diff --git a/gen/conflictgen.py b/gen/conflictgen.py index a2dc39cb..158e1c94 100644 --- a/gen/conflictgen.py +++ b/gen/conflictgen.py @@ -142,6 +142,9 @@ class Conflict: y = lerp * dy + self.tail.y return Point(x, y) + def find_ground_position(self, at: Point, heading: int, max_distance: int = 40000) -> typing.Optional[Point]: + return Conflict._find_ground_position(at, max_distance, heading, self.theater) + @classmethod def has_frontline_between(cls, from_cp: ControlPoint, to_cp: ControlPoint) -> bool: return from_cp.has_frontline and to_cp.has_frontline @@ -190,7 +193,7 @@ class Conflict: return pos @classmethod - def _find_ground_position(cls, initial: Point, max_distance: int, heading: int, theater: ConflictTheater) -> Point: + def _find_ground_position(cls, initial: Point, max_distance: int, heading: int, theater: ConflictTheater) -> typing.Optional[Point]: pos = initial for _ in range(0, int(max_distance), 500): if theater.is_on_land(pos): diff --git a/gen/groundobjectsgen.py b/gen/groundobjectsgen.py index 558c4c31..33517ab1 100644 --- a/gen/groundobjectsgen.py +++ b/gen/groundobjectsgen.py @@ -7,6 +7,8 @@ from .naming import * from dcs.mission import * from dcs.statics import * +FARP_FRONTLINE_DISTANCE = 10000 + CATEGORY_MAPPING = { "power": [Fortification.Workshop_A], @@ -25,6 +27,17 @@ class GroundObjectsGenerator: self.conflict = conflict self.game = game + def generate_farp(self) -> StaticGroup: + assert self.conflict.is_vector, "FARP could be generated only on frontline conflicts!" + + position = self.conflict.find_ground_position(self.conflict.center.point_from_heading(self.conflict.opposite_heading, FARP_FRONTLINE_DISTANCE)) + return self.m.static_group( + country=self.m.country(self.game.player), + name="", + _type=Fortification.FARP_Command_Post, + position=position + ) + def generate(self): side = self.m.country(self.game.enemy) diff --git a/ui/eventmenu.py b/ui/eventmenu.py index d8d4b027..db76176f 100644 --- a/ui/eventmenu.py +++ b/ui/eventmenu.py @@ -140,7 +140,7 @@ class EventMenu(Menu): else: self.event.is_awacs_enabled = False - flights = {k: {} for k in self.event.tasks} # type: ScrambledFlightsDict + flights = {k: {} for k in self.event.tasks} # type: db.TaskForceDict units_scramble_counts = {} # type: typing.Dict[typing.Type[UnitType], int] tasks_scramble_counts = {} # type: typing.Dict[typing.Type[Task], int] tasks_clients_counts = {} # type: typing.Dict[typing.Type[Task], int]