Compare commits

..

4 Commits

Author SHA1 Message Date
Vasyl Horbachenko
12853feec3 updated version check 2018-09-11 03:35:52 +03:00
Vasyl Horbachenko
d31876b65e FARP spawn for helis on frontline cas; updated ground object placements 2018-09-11 03:12:33 +03:00
Vasyl Horbachenko
ca521e7e51 FARPs for heli flights WIP 2018-09-10 23:12:04 +03:00
Vasyl Horbachenko
f21c515d5c convert resource files to gif 2018-09-10 21:46:34 +03:00
37 changed files with 232 additions and 278 deletions

View File

@@ -1,5 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import os import os
import re
import sys import sys
import dcs import dcs
import logging import logging
@@ -33,13 +34,19 @@ def proceed_to_main_menu(game: Game):
def is_version_compatible(save_version): def is_version_compatible(save_version):
current_version = VERSION_STRING.split(".") current_version_components = re.split(r"[\._]", VERSION_STRING)
save_version = save_version.split(".") save_version_components = re.split(r"[\._]", save_version)
if "--ignore-save" in sys.argv: if "--ignore-save" in sys.argv:
return False return False
if current_version[:2] == save_version[:2]: if current_version_components == save_version_components:
return True
if save_version == "1.4_rc1":
return False
if current_version_components[:2] == save_version_components[:2]:
return True return True
return False return False
@@ -80,9 +87,10 @@ try:
new_game_menu = ui.newgamemenu.NewGameMenu(w, start_new_game) new_game_menu = ui.newgamemenu.NewGameMenu(w, start_new_game)
new_game_menu.display() new_game_menu.display()
else: else:
game.settings.version = VERSION_STRING
proceed_to_main_menu(game) proceed_to_main_menu(game)
except Exception as e: except Exception as e:
print(e) logging.exception(e)
ui.corruptedsavemenu.CorruptedSaveMenu(w).display() ui.corruptedsavemenu.CorruptedSaveMenu(w).display()
w.run() w.run()

View File

@@ -358,7 +358,8 @@ PLANE_PAYLOAD_OVERRIDES = {
}, },
Ka_50: { Ka_50: {
"*": "12x9A4172, 40xS-8", CAS: "12x9A4172, 40xS-8",
GroundAttack: "12x9A4172, 40xS-8",
}, },
M_2000C: { M_2000C: {
@@ -366,7 +367,7 @@ PLANE_PAYLOAD_OVERRIDES = {
}, },
MiG_21Bis: { MiG_21Bis: {
"*": "Patrol, medium range", CAP: "Patrol, medium range",
} }
} }
@@ -392,7 +393,11 @@ HeliDict = typing.Dict[HelicopterType, int]
ArmorDict = typing.Dict[VehicleType, int] ArmorDict = typing.Dict[VehicleType, int]
ShipDict = typing.Dict[ShipType, int] ShipDict = typing.Dict[ShipType, int]
AirDefenseDict = typing.Dict[AirDefence, 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: def unit_task(unit: UnitType) -> Task:
@@ -471,6 +476,39 @@ def unitdict_restrict_count(unit_dict: UnitsDict, total_count: int) -> UnitsDict
return {} 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 assignedunits_split_to_count(dict: AssignedUnitsDict, count: int):
buffer_dict = {}
for unit_type, (unit_count, client_count) in dict.items():
for _ in range(unit_count):
new_count, new_client_count = buffer_dict.get(unit_type, (0, 0))
new_count += 1
if client_count > 0:
new_client_count += 1
client_count -= 1
buffer_dict[unit_type] = new_count, new_client_count
if new_count >= count:
yield buffer_dict
buffer_dict = {}
if len(buffer_dict):
yield buffer_dict
def unitdict_from(fd: AssignedUnitsDict) -> Dict:
return {k: v1 for k, (v1, v2) in fd.items()}
def _validate_db(): def _validate_db():
# check unit by task uniquity # check unit by task uniquity
total_set = set() total_set = set()

View File

@@ -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 game.operation.baseattack import BaseAttackOperation
from userdata.debriefing import Debriefing
from .event import * from .event import *
from ..operation.operation import flight_dict_from from game.db import assigned_units_from
class BaseAttackEvent(Event): class BaseAttackEvent(Event):
@@ -60,7 +51,7 @@ class BaseAttackEvent(Event):
if not self.is_player_attacking and self.to_cp.captured: if not self.is_player_attacking and self.to_cp.captured:
self.to_cp.captured = False 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" assert CAP in flights and len(flights) == 1, "Invalid scrambled flights"
cas = self.from_cp.base.scramble_cas(self.game.settings.multiplier) cas = self.from_cp.base.scramble_cas(self.game.settings.multiplier)
@@ -73,8 +64,8 @@ class BaseAttackEvent(Event):
from_cp=self.from_cp, from_cp=self.from_cp,
to_cp=self.to_cp) to_cp=self.to_cp)
op.setup(cas=flight_dict_from(cas), op.setup(cas=assigned_units_from(cas),
escort=flight_dict_from(escort), escort=assigned_units_from(escort),
intercept=flights[CAP], intercept=flights[CAP],
attack=attackers, attack=attackers,
defense=self.to_cp.base.armor, defense=self.to_cp.base.armor,
@@ -82,7 +73,7 @@ class BaseAttackEvent(Event):
self.operation = op 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" assert CAP in flights and CAS in flights and PinpointStrike in flights and len(flights) == 3, "Invalid flights"
op = BaseAttackOperation(game=self.game, op = BaseAttackOperation(game=self.game,
@@ -97,7 +88,7 @@ class BaseAttackEvent(Event):
op.setup(cas=flights[CAS], op.setup(cas=flights[CAS],
escort=flights[CAP], escort=flights[CAP],
attack=flights[PinpointStrike], attack=flights[PinpointStrike],
intercept=flight_dict_from(defenders), intercept=assigned_units_from(defenders),
defense=self.to_cp.base.armor, defense=self.to_cp.base.armor,
aa=self.to_cp.base.assemble_aa()) aa=self.to_cp.base.assemble_aa())

View File

@@ -2,21 +2,19 @@ import typing
import logging import logging
from dcs.unittype import UnitType from dcs.unittype import UnitType
from dcs.task import Task from dcs.task import *
from dcs.unittype import UnitType from dcs.unittype import UnitType
from game import * from game import *
from theater import * from theater import *
from gen.environmentgen import EnvironmentSettings 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.debriefing import Debriefing
from userdata import persistency from userdata import persistency
DIFFICULTY_LOG_BASE = 1.1 DIFFICULTY_LOG_BASE = 1.1
ScrambledFlightsDict = typing.Dict[typing.Type[Task], typing.Dict[typing.Type[UnitType], typing.Tuple[int, int]]]
class Event: class Event:
silent = False silent = False
@@ -67,10 +65,10 @@ class Event:
def is_successfull(self, debriefing: Debriefing) -> bool: def is_successfull(self, debriefing: Debriefing) -> bool:
return self.operation.is_successfull(debriefing) return self.operation.is_successfull(debriefing)
def player_attacking(self, flights: ScrambledFlightsDict): def player_attacking(self, flights: db.TaskForceDict):
assert False assert False
def player_defending(self, flights: ScrambledFlightsDict): def player_defending(self, flights: db.TaskForceDict):
assert False assert False
def generate(self): def generate(self):

View File

@@ -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.event import *
from game.operation.frontlineattack import FrontlineAttackOperation from game.operation.frontlineattack import FrontlineAttackOperation
from userdata.debriefing import Debriefing from userdata.debriefing import Debriefing
@@ -69,7 +62,7 @@ class FrontlineAttackEvent(Event):
if self.to_cp.captured: if self.to_cp.captured:
self.to_cp.base.affect_strength(-0.1) 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" assert CAS in flights and PinpointStrike in flights and len(flights) == 2, "Invalid flights"
self.defenders = self.to_cp.base.assemble_attack() self.defenders = self.to_cp.base.assemble_attack()
@@ -80,7 +73,7 @@ class FrontlineAttackEvent(Event):
from_cp=self.from_cp, from_cp=self.from_cp,
to_cp=self.to_cp) to_cp=self.to_cp)
armor = dict_from_flight(flights[PinpointStrike]) armor = unitdict_from(flights[PinpointStrike])
op.setup(target=self.defenders, op.setup(target=self.defenders,
attackers=db.unitdict_restrict_count(armor, sum(self.defenders.values())), attackers=db.unitdict_restrict_count(armor, sum(self.defenders.values())),
strikegroup=flights[CAS]) strikegroup=flights[CAS])

View File

@@ -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.event import *
from game.operation.frontlinepatrol import FrontlinePatrolOperation from game.operation.frontlinepatrol import FrontlinePatrolOperation
from userdata.debriefing import Debriefing from userdata.debriefing import Debriefing
@@ -61,7 +54,7 @@ class FrontlinePatrolEvent(Event):
def skip(self): def skip(self):
pass 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" 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) self.cas = self.to_cp.base.scramble_cas(self.game.settings.multiplier)
@@ -74,8 +67,8 @@ class FrontlinePatrolEvent(Event):
to_cp=self.to_cp) to_cp=self.to_cp)
defenders = self.to_cp.base.assemble_attack() defenders = self.to_cp.base.assemble_attack()
op.setup(cas=flight_dict_from(self.cas), op.setup(cas=assigned_units_from(self.cas),
escort=flight_dict_from(self.escort), escort=assigned_units_from(self.escort),
interceptors=flights[CAP], interceptors=flights[CAP],
armor_attackers=db.unitdict_restrict_count(dict_from_flight(flights[PinpointStrike]), sum(defenders.values())), armor_attackers=db.unitdict_restrict_count(dict_from_flight(flights[PinpointStrike]), sum(defenders.values())),
armor_defenders=defenders) armor_defenders=defenders)

View File

@@ -37,7 +37,7 @@ class InfantryTransportEvent(Event):
else: else:
self.from_cp.base.affect_strength(-self.STRENGTH_INFLUENCE) 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" assert Embarking in flights and len(flights) == 1, "Invalid flights"
op = InfantryTransportOperation( op = InfantryTransportOperation(

View File

@@ -40,7 +40,7 @@ class InsurgentAttackEvent(Event):
else: else:
return not attackers_success 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" assert CAS in flights and len(flights) == 1, "Invalid flights"
suitable_unittypes = db.find_unittype(Reconnaissance, self.attacker_name) suitable_unittypes = db.find_unittype(Reconnaissance, self.attacker_name)

View File

@@ -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 game.operation.intercept import InterceptOperation
from theater.conflicttheater import *
from userdata.debriefing import Debriefing
from .event import * from .event import *
@@ -68,7 +59,7 @@ class InterceptEvent(Event):
if self.to_cp.captured: if self.to_cp.captured:
self.to_cp.base.affect_strength(-self.STRENGTH_INFLUENCE) 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" assert CAP in flights and len(flights) == 1, "Invalid flights"
escort = self.to_cp.base.scramble_sweep(self._enemy_scramble_multiplier()) escort = self.to_cp.base.scramble_sweep(self._enemy_scramble_multiplier())
@@ -83,14 +74,14 @@ class InterceptEvent(Event):
from_cp=self.from_cp, from_cp=self.from_cp,
to_cp=self.to_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}, transport={self.transport_unit: 1},
airdefense={airdefense_unit: self.AIRDEFENSE_COUNT}, airdefense={airdefense_unit: self.AIRDEFENSE_COUNT},
interceptors=flights[CAP]) interceptors=flights[CAP])
self.operation = op 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" assert CAP in flights and len(flights) == 1, "Invalid flights"
interceptors = self.from_cp.base.scramble_interceptors(self.game.settings.multiplier) interceptors = self.from_cp.base.scramble_interceptors(self.game.settings.multiplier)
@@ -106,7 +97,7 @@ class InterceptEvent(Event):
op.setup(escort=flights[CAP], op.setup(escort=flights[CAP],
transport={self.transport_unit: 1}, transport={self.transport_unit: 1},
interceptors=flight_dict_from(interceptors), interceptors=assigned_units_from(interceptors),
airdefense={}) airdefense={})
self.operation = op self.operation = op

View File

@@ -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 game.operation.navalintercept import NavalInterceptionOperation
from userdata.debriefing import Debriefing
from .event import * from .event import *
@@ -19,7 +10,7 @@ class NavalInterceptEvent(Event):
targets = None # type: db.ShipDict targets = None # type: db.ShipDict
def _targets_count(self) -> int: 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 factor = (self.to_cp.importance - IMPORTANCE_LOW) * 10
return max(int(factor), 1) return max(int(factor), 1)
@@ -77,7 +68,7 @@ class NavalInterceptEvent(Event):
if self.to_cp.captured: if self.to_cp.captured:
self.to_cp.base.affect_strength(-self.STRENGTH_INFLUENCE) 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" assert CAS in flights and len(flights) == 1, "Invalid flights"
self.targets = { self.targets = {
@@ -98,7 +89,7 @@ class NavalInterceptEvent(Event):
self.operation = op 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" assert CAP in flights and len(flights) == 1, "Invalid flights"
self.targets = { self.targets = {
@@ -114,7 +105,7 @@ class NavalInterceptEvent(Event):
) )
strikegroup = self.from_cp.base.scramble_cas(self.game.settings.multiplier) 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], interceptors=flights[CAP],
targets=self.targets) targets=self.targets)

View File

@@ -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 game.operation.strike import StrikeOperation
from theater.conflicttheater import *
from userdata.debriefing import Debriefing
from .event import * from .event import *
@@ -50,7 +41,7 @@ class StrikeEvent(Event):
super(StrikeEvent, self).commit(debriefing) super(StrikeEvent, self).commit(debriefing)
self.to_cp.base.affect_strength(-self.SINGLE_OBJECT_STRENGTH_INFLUENCE * len(debriefing.destroyed_objects)) 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" assert CAP in flights and CAS in flights and len(flights) == 2, "Invalid flights"
op = StrikeOperation( op = StrikeOperation(
@@ -64,6 +55,6 @@ class StrikeEvent(Event):
interceptors = self.to_cp.base.scramble_interceptors(self.game.settings.multiplier) interceptors = self.to_cp.base.scramble_interceptors(self.game.settings.multiplier)
op.setup(strikegroup=flights[CAS], op.setup(strikegroup=flights[CAS],
escort=flights[CAP], escort=flights[CAP],
interceptors=flight_dict_from(interceptors)) interceptors=assigned_units_from(interceptors))
self.operation = op self.operation = op

View File

@@ -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.triggergen import *
from gen.airsupportgen import *
from gen.visualgen import *
from .operation import * from .operation import *
class BaseAttackOperation(Operation): class BaseAttackOperation(Operation):
cas = None # type: FlightDict cas = None # type: db.AssignedUnitsDict
escort = None # type: FlightDict escort = None # type: db.AssignedUnitsDict
intercept = None # type: FlightDict intercept = None # type: db.AssignedUnitsDict
attack = None # type: db.ArmorDict attack = None # type: db.ArmorDict
defense = None # type: db.ArmorDict defense = None # type: db.ArmorDict
aa = None # type: db.AirDefenseDict aa = None # type: db.AirDefenseDict
@@ -23,10 +16,10 @@ class BaseAttackOperation(Operation):
trigger_radius = TRIGGER_RADIUS_SMALL trigger_radius = TRIGGER_RADIUS_SMALL
def setup(self, def setup(self,
cas: FlightDict, cas: db.AssignedUnitsDict,
escort: FlightDict, escort: db.AssignedUnitsDict,
attack: FlightDict, attack: db.AssignedUnitsDict,
intercept: FlightDict, intercept: db.AssignedUnitsDict,
defense: db.ArmorDict, defense: db.ArmorDict,
aa: db.AirDefenseDict): aa: db.AirDefenseDict):
self.cas = cas self.cas = cas
@@ -57,10 +50,10 @@ class BaseAttackOperation(Operation):
self.armorgen.generate(self.attack, self.defense) self.armorgen.generate(self.attack, self.defense)
self.aagen.generate(self.aa) 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_cas_strikegroup(*assigned_units_split(self.cas), 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.visualgen.generate_target_smokes(self.to_cp) self.visualgen.generate_target_smokes(self.to_cp)

View File

@@ -1,16 +1,4 @@
from itertools import zip_longest from game.db import assigned_units_split
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 .operation import * from .operation import *
@@ -19,14 +7,14 @@ MAX_DISTANCE_BETWEEN_GROUPS = 12000
class FrontlineAttackOperation(Operation): class FrontlineAttackOperation(Operation):
strikegroup = None # type: FlightDict strikegroup = None # type: db.AssignedUnitsDict
attackers = None # type: db.ArmorDict attackers = None # type: db.ArmorDict
target = None # type: db.ArmorDict target = None # type: db.ArmorDict
def setup(self, def setup(self,
target: db.ArmorDict, target: db.ArmorDict,
attackers: db.ArmorDict, attackers: db.ArmorDict,
strikegroup: FlightDict): strikegroup: db.AssignedUnitsDict):
self.strikegroup = strikegroup self.strikegroup = strikegroup
self.target = target self.target = target
self.attackers = attackers self.attackers = attackers
@@ -50,7 +38,16 @@ class FrontlineAttackOperation(Operation):
def generate(self): def generate(self):
self.armorgen.generate_vec(self.attackers, self.target) 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.values()}
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.values()}
if heli_flights:
self.briefinggen.append_frequency("FARP", "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), at=farp, escort=False)
self.briefinggen.title = "Frontline CAS" 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." 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."

View File

@@ -1,16 +1,4 @@
from itertools import zip_longest from game.db import assigned_units_split
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 .operation import * from .operation import *
@@ -19,17 +7,17 @@ MAX_DISTANCE_BETWEEN_GROUPS = 12000
class FrontlinePatrolOperation(Operation): class FrontlinePatrolOperation(Operation):
cas = None # type: FlightDict cas = None # type: db.AssignedUnitsDict
escort = None # type: FlightDict escort = None # type: db.AssignedUnitsDict
interceptors = None # type: FlightDict interceptors = None # type: db.AssignedUnitsDict
armor_attackers = None # type: db.ArmorDict armor_attackers = None # type: db.ArmorDict
armor_defenders = None # type: db.ArmorDict armor_defenders = None # type: db.ArmorDict
def setup(self, def setup(self,
cas: FlightDict, cas: db.AssignedUnitsDict,
escort: FlightDict, escort: db.AssignedUnitsDict,
interceptors: FlightDict, interceptors: db.AssignedUnitsDict,
armor_attackers: db.ArmorDict, armor_attackers: db.ArmorDict,
armor_defenders: db.ArmorDict): armor_defenders: db.ArmorDict):
self.cas = cas self.cas = cas
@@ -55,9 +43,9 @@ class FrontlinePatrolOperation(Operation):
conflict=conflict) conflict=conflict)
def generate(self): def generate(self):
self.airgen.generate_defenders_cas(*flight_arguments(self.cas), at=self.defenders_starting_position) self.airgen.generate_defenders_cas(*assigned_units_split(self.cas), at=self.defenders_starting_position)
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_migcap(*flight_arguments(self.interceptors), at=self.attackers_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) self.armorgen.generate_vec(self.armor_attackers, self.armor_defenders)

View File

@@ -1,23 +1,13 @@
from dcs.terrain import Terrain from game.db import assigned_units_split
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 .operation import * from .operation import *
class InfantryTransportOperation(Operation): class InfantryTransportOperation(Operation):
transport = None # type: FlightDict transport = None # type: db.AssignedUnitsDict
aa = None # type: db.AirDefenseDict 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.transport = transport
self.aa = aa self.aa = aa
@@ -36,7 +26,7 @@ class InfantryTransportOperation(Operation):
conflict=conflict) conflict=conflict)
def generate(self): 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.armorgen.generate_passengers(count=6)
self.aagen.generate_at_defenders_location(self.aa) self.aagen.generate_at_defenders_location(self.aa)

View File

@@ -1,25 +1,15 @@
from dcs.terrain import Terrain from game.db import assigned_units_split
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 .operation import * from .operation import *
class InsurgentAttackOperation(Operation): class InsurgentAttackOperation(Operation):
strikegroup = None # type: FlightDict strikegroup = None # type: db.AssignedUnitsDict
target = None # type: db.ArmorDict target = None # type: db.ArmorDict
def setup(self, def setup(self,
target: db.ArmorDict, target: db.ArmorDict,
strikegroup: FlightDict): strikegroup: db.AssignedUnitsDict):
self.strikegroup = strikegroup self.strikegroup = strikegroup
self.target = target self.target = target
@@ -38,7 +28,7 @@ class InsurgentAttackOperation(Operation):
conflict=conflict) conflict=conflict)
def generate(self): 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.armorgen.generate(self.target, {})
self.briefinggen.title = "Destroy insurgents" self.briefinggen.title = "Destroy insurgents"

View File

@@ -1,22 +1,21 @@
from dcs.terrain import Terrain from game.db import assigned_units_split
from gen import *
from .operation import * from .operation import *
class InterceptOperation(Operation): class InterceptOperation(Operation):
escort = None # type: FlightDict escort = None # type: db.AssignedUnitsDict
transport = None # type: db.PlaneDict transport = None # type: db.PlaneDict
interceptors = None # type: FlightDict interceptors = None # type: db.AssignedUnitsDict
airdefense = None # type: db.AirDefenseDict airdefense = None # type: db.AirDefenseDict
trigger_radius = TRIGGER_RADIUS_LARGE trigger_radius = TRIGGER_RADIUS_LARGE
def setup(self, def setup(self,
escort: FlightDict, escort: db.AssignedUnitsDict,
transport: db.PlaneDict, transport: db.PlaneDict,
airdefense: db.AirDefenseDict, airdefense: db.AirDefenseDict,
interceptors: FlightDict): interceptors: db.AssignedUnitsDict):
self.escort = escort self.escort = escort
self.transport = transport self.transport = transport
self.airdefense = airdefense self.airdefense = airdefense
@@ -52,9 +51,9 @@ class InterceptOperation(Operation):
self.attackers_starting_position = ship self.attackers_starting_position = ship
self.airgen.generate_transport(self.transport, self.to_cp.at) 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.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" 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"

View File

@@ -1,18 +1,17 @@
from dcs.terrain import Terrain from game.db import assigned_units_split
from gen import *
from .operation import * from .operation import *
class NavalInterceptionOperation(Operation): class NavalInterceptionOperation(Operation):
strikegroup = None # type: FlightDict strikegroup = None # type: db.AssignedUnitsDict
interceptors = None # type: FlightDict interceptors = None # type: db.AssignedUnitsDict
targets = None # type: db.ShipDict targets = None # type: db.ShipDict
trigger_radius = TRIGGER_RADIUS_LARGE trigger_radius = TRIGGER_RADIUS_LARGE
def setup(self, def setup(self,
strikegroup: FlightDict, strikegroup: db.AssignedUnitsDict,
interceptors: FlightDict, interceptors: db.AssignedUnitsDict,
targets: db.ShipDict): targets: db.ShipDict):
self.strikegroup = strikegroup self.strikegroup = strikegroup
self.interceptors = interceptors self.interceptors = interceptors
@@ -37,14 +36,14 @@ class NavalInterceptionOperation(Operation):
target_groups = self.shipgen.generate_cargo(units=self.targets) target_groups = self.shipgen.generate_cargo(units=self.targets)
self.airgen.generate_ship_strikegroup( self.airgen.generate_ship_strikegroup(
*flight_arguments(self.strikegroup), *assigned_units_split(self.strikegroup),
target_groups=target_groups, target_groups=target_groups,
at=self.attackers_starting_position at=self.attackers_starting_position
) )
if self.interceptors: if self.interceptors:
self.airgen.generate_defense( self.airgen.generate_defense(
*flight_arguments(self.interceptors), *assigned_units_split(self.interceptors),
at=self.defenders_starting_position at=self.defenders_starting_position
) )

View File

@@ -1,31 +1,14 @@
import typing
from dcs.lua.parse import loads from dcs.lua.parse import loads
from dcs.unittype import UnitType
from userdata.debriefing import * from userdata.debriefing import *
from theater import *
from gen 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: class Operation:
attackers_starting_position = None # type: db.StartingPosition attackers_starting_position = None # type: db.StartingPosition
defenders_starting_position = None # type: db.StartingPosition defenders_starting_position = None # type: db.StartingPosition
mission = None # type: dcs.Mission mission = None # type: dcs.Mission
conflict = None # type: Conflict conflict = None # type: Conflict
armorgen = None # type: ArmorConflictGenerator armorgen = None # type: ArmorConflictGenerator

View File

@@ -1,27 +1,17 @@
from dcs.terrain import Terrain from game.db import assigned_units_split
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 .operation import * from .operation import *
class StrikeOperation(Operation): class StrikeOperation(Operation):
strikegroup = None # type: FlightDict strikegroup = None # type: db.AssignedUnitsDict
escort = None # type: FlightDict escort = None # type: db.AssignedUnitsDict
interceptors = None # type: FlightDict interceptors = None # type: db.AssignedUnitsDict
def setup(self, def setup(self,
strikegroup: FlightDict, strikegroup: db.AssignedUnitsDict,
escort: FlightDict, escort: db.AssignedUnitsDict,
interceptors: FlightDict): interceptors: db.AssignedUnitsDict):
self.strikegroup = strikegroup self.strikegroup = strikegroup
self.escort = escort self.escort = escort
self.interceptors = interceptors self.interceptors = interceptors
@@ -61,13 +51,13 @@ class StrikeOperation(Operation):
targets.sort(key=lambda x: self.from_cp.position.distance_to_point(x[1])) 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, targets=targets,
at=self.attackers_starting_position) 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.title = "Strike"
self.briefinggen.description = "Destroy infrastructure assets and military supplies in the region. Each building destroyed will lower targets strength." self.briefinggen.description = "Destroy infrastructure assets and military supplies in the region. Each building destroyed will lower targets strength."

View File

@@ -5,6 +5,7 @@ from dcs.mission import *
DISTANCE_FACTOR = 0.5, 1 DISTANCE_FACTOR = 0.5, 1
EXTRA_AA_MIN_DISTANCE = 35000 EXTRA_AA_MIN_DISTANCE = 35000
EXTRA_AA_MAX_DISTANCE = 150000
EXTRA_AA_POSITION_FROM_CP = 550 EXTRA_AA_POSITION_FROM_CP = 550
@@ -58,7 +59,9 @@ class ExtraAAConflictGenerator:
if cp.position.distance_to_point(self.conflict.from_cp.position) < EXTRA_AA_MIN_DISTANCE: if cp.position.distance_to_point(self.conflict.from_cp.position) < EXTRA_AA_MIN_DISTANCE:
continue continue
print("generated extra aa for {}".format(cp)) if cp.position.distance_to_point(self.conflict.position) > EXTRA_AA_MAX_DISTANCE:
continue
country_name = cp.captured and self.player_name or self.enemy_name country_name = cp.captured and self.player_name or self.enemy_name
position = cp.position.point_from_heading(0, EXTRA_AA_POSITION_FROM_CP) position = cp.position.point_from_heading(0, EXTRA_AA_POSITION_FROM_CP)

View File

@@ -42,7 +42,7 @@ GROUP_VERTICAL_OFFSET = 300
class AircraftConflictGenerator: 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 vertical_offset = None # type: int
def __init__(self, mission: Mission, conflict: Conflict, settings: Settings): def __init__(self, mission: Mission, conflict: Conflict, settings: Settings):
@@ -77,7 +77,7 @@ class AircraftConflictGenerator:
count -= group_size count -= group_size
client_count -= client_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 did_load_loadout = False
unit_type = group.units[0].unit_type unit_type = group.units[0].unit_type
if unit_type in db.PLANE_PAYLOAD_OVERRIDES: if unit_type in db.PLANE_PAYLOAD_OVERRIDES:
@@ -112,6 +112,7 @@ class AircraftConflictGenerator:
group.units[idx].set_client() group.units[idx].set_client()
group.points[0].tasks.append(OptReactOnThreat(OptReactOnThreat.Values.EvadeFire)) group.points[0].tasks.append(OptReactOnThreat(OptReactOnThreat.Values.EvadeFire))
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: def _generate_at_airport(self, name: str, side: Country, unit_type: FlyingType, count: int, client_count: int, airport: Airport = None) -> FlyingGroup:
assert count > 0 assert count > 0
@@ -155,11 +156,11 @@ class AircraftConflictGenerator:
start_type=self._start_type(), start_type=self._start_type(),
group_size=count) group_size=count)
def _generate_at_carrier(self, name: str, side: Country, unit_type: FlyingType, count: int, client_count: int, at: ShipGroup) -> FlyingGroup: def _generate_at_group(self, name: str, side: Country, unit_type: FlyingType, count: int, client_count: int, at: typing.Union[ShipGroup, StaticGroup]) -> FlyingGroup:
assert count > 0 assert count > 0
assert unit is not None assert unit is not None
logging.info("airgen: {} for {} at carrier {}".format(unit_type, side.id, at)) logging.info("airgen: {} for {} at unit {}".format(unit_type, side.id, at))
return self.m.flight_group_from_unit( return self.m.flight_group_from_unit(
country=side, country=side,
name=name, name=name,
@@ -172,10 +173,10 @@ class AircraftConflictGenerator:
def _generate_group(self, name: str, side: Country, unit_type: FlyingType, count: int, client_count: int, at: db.StartingPosition): def _generate_group(self, name: str, side: Country, unit_type: FlyingType, count: int, client_count: int, at: db.StartingPosition):
if isinstance(at, Point): if isinstance(at, Point):
return self._generate_inflight(name, side, unit_type, count, client_count, at) return self._generate_inflight(name, side, unit_type, count, client_count, at)
elif isinstance(at, ShipGroup): elif isinstance(at, Group):
takeoff_ban = unit_type in db.CARRIER_TAKEOFF_BAN takeoff_ban = unit_type in db.CARRIER_TAKEOFF_BAN
if not takeoff_ban: if not takeoff_ban:
return self._generate_at_carrier(name, side, unit_type, count, client_count, at) return self._generate_at_group(name, side, unit_type, count, client_count, at)
else: else:
return self._generate_inflight(name, side, unit_type, count, client_count, at.position) return self._generate_inflight(name, side, unit_type, count, client_count, at.position)
elif issubclass(at, Airport): elif issubclass(at, Airport):
@@ -192,14 +193,16 @@ class AircraftConflictGenerator:
assert False assert False
def _rtb_for(self, group: FlyingGroup, cp: ControlPoint, at: db.StartingPosition = None): def _rtb_for(self, group: FlyingGroup, cp: ControlPoint, at: db.StartingPosition = None):
group.add_waypoint(cp.position, RTB_ALTITUDE) if not at:
at = cp.at
if isinstance(cp.at, Point): if isinstance(at, Point):
pass group.add_waypoint(at, RTB_ALTITUDE)
elif isinstance(cp.at, ShipGroup): elif isinstance(at, Group):
pass group.add_waypoint(at.position, RTB_ALTITUDE)
elif issubclass(cp.at, Airport): elif issubclass(at, Airport):
group.land_at(cp.at) group.add_waypoint(at.position, RTB_ALTITUDE)
group.land_at(at)
def _at_position(self, at) -> Point: def _at_position(self, at) -> Point:
if isinstance(at, Point): if isinstance(at, Point):
@@ -243,8 +246,8 @@ class AircraftConflictGenerator:
groups.append(group) groups.append(group)
return groups return groups
def generate_cas_strikegroup(self, attackers: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None): def generate_cas_strikegroup(self, attackers: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None, escort=True):
assert len(self.escort_targets) == 0 assert not escort or len(self.escort_targets) == 0
for flying_type, count, client_count in self._split_to_groups(attackers, clients): for flying_type, count, client_count in self._split_to_groups(attackers, clients):
group = self._generate_group( group = self._generate_group(
@@ -261,11 +264,12 @@ class AircraftConflictGenerator:
group.task = CAS.name group.task = CAS.name
self._setup_group(group, CAS, client_count) self._setup_group(group, CAS, client_count)
self.escort_targets.append((group, group.points.index(waypoint))) if escort:
self.escort_targets.append((group, group.points.index(waypoint)))
self._rtb_for(group, self.conflict.from_cp, at) self._rtb_for(group, self.conflict.from_cp, at)
def generate_ground_attack_strikegroup(self, strikegroup: db.PlaneDict, clients: db.PlaneDict, targets: typing.List[typing.Tuple[str, Point]], at: db.StartingPosition = None): def generate_ground_attack_strikegroup(self, strikegroup: db.PlaneDict, clients: db.PlaneDict, targets: typing.List[typing.Tuple[str, Point]], at: db.StartingPosition = None, escort=True):
assert len(self.escort_targets) == 0 assert not escort or len(self.escort_targets) == 0
for flying_type, count, client_count in self._split_to_groups(strikegroup, clients): for flying_type, count, client_count in self._split_to_groups(strikegroup, clients):
group = self._generate_group( group = self._generate_group(
@@ -285,11 +289,12 @@ class AircraftConflictGenerator:
group.task = GroundAttack.name group.task = GroundAttack.name
self._setup_group(group, GroundAttack, client_count) self._setup_group(group, GroundAttack, client_count)
self.escort_targets.append((group, group.points.index(escort_until_waypoint))) if escort:
self.escort_targets.append((group, group.points.index(escort_until_waypoint)))
self._rtb_for(group, self.conflict.from_cp, at) self._rtb_for(group, self.conflict.from_cp, at)
def generate_defenders_cas(self, defenders: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None): def generate_defenders_cas(self, defenders: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None, escort=True):
assert len(self.escort_targets) == 0 assert not escort or len(self.escort_targets) == 0
for flying_type, count, client_count in self._split_to_groups(defenders, clients): for flying_type, count, client_count in self._split_to_groups(defenders, clients):
group = self._generate_group( group = self._generate_group(
@@ -310,11 +315,12 @@ class AircraftConflictGenerator:
group.task = CAS.name group.task = CAS.name
self._setup_group(group, CAS, client_count) self._setup_group(group, CAS, client_count)
self.escort_targets.append((group, group.points.index(waypoint))) if escort:
self.escort_targets.append((group, group.points.index(waypoint)))
self._rtb_for(group, self.conflict.to_cp, at) self._rtb_for(group, self.conflict.to_cp, at)
def generate_ship_strikegroup(self, attackers: db.PlaneDict, clients: db.PlaneDict, target_groups: typing.Collection[ShipGroup], at: db.StartingPosition = None): def generate_ship_strikegroup(self, attackers: db.PlaneDict, clients: db.PlaneDict, target_groups: typing.Collection[ShipGroup], at: db.StartingPosition = None, escort=True):
assert len(self.escort_targets) == 0 assert not escort or len(self.escort_targets) == 0
for flying_type, count, client_count in self._split_to_groups(attackers, clients): for flying_type, count, client_count in self._split_to_groups(attackers, clients):
group = self._generate_group( group = self._generate_group(
@@ -331,7 +337,8 @@ class AircraftConflictGenerator:
group.task = AntishipStrike.name group.task = AntishipStrike.name
self._setup_group(group, AntishipStrike, client_count) self._setup_group(group, AntishipStrike, client_count)
self.escort_targets.append((group, group.points.index(wayp))) if escort:
self.escort_targets.append((group, group.points.index(wayp)))
self._rtb_for(group, self.conflict.from_cp, at) self._rtb_for(group, self.conflict.from_cp, at)
def generate_attackers_escort(self, attackers: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None): def generate_attackers_escort(self, attackers: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None):
@@ -413,8 +420,8 @@ class AircraftConflictGenerator:
self._setup_group(group, CAP, client_count) self._setup_group(group, CAP, client_count)
self._rtb_for(group, self.conflict.to_cp, at) self._rtb_for(group, self.conflict.to_cp, at)
def generate_transport(self, transport: db.PlaneDict, destination: Airport): def generate_transport(self, transport: db.PlaneDict, destination: Airport, escort=True):
assert len(self.escort_targets) == 0 assert not escort or len(self.escort_targets) == 0
for flying_type, count, client_count in self._split_to_groups(transport): for flying_type, count, client_count in self._split_to_groups(transport):
group = self._generate_group( group = self._generate_group(
@@ -426,8 +433,8 @@ class AircraftConflictGenerator:
at=self._group_point(self.conflict.air_defenders_location)) at=self._group_point(self.conflict.air_defenders_location))
waypoint = group.add_waypoint(destination.position.random_point_within(0, 0), TRANSPORT_LANDING_ALT) waypoint = group.add_waypoint(destination.position.random_point_within(0, 0), TRANSPORT_LANDING_ALT)
self.escort_targets.append((group, group.points.index(waypoint))) if escort:
self.escort_targets.append((group, group.points.index(waypoint)))
group.task = Transport.name group.task = Transport.name
group.land_at(destination) group.land_at(destination)

View File

@@ -142,6 +142,9 @@ class Conflict:
y = lerp * dy + self.tail.y y = lerp * dy + self.tail.y
return Point(x, 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 @classmethod
def has_frontline_between(cls, from_cp: ControlPoint, to_cp: ControlPoint) -> bool: def has_frontline_between(cls, from_cp: ControlPoint, to_cp: ControlPoint) -> bool:
return from_cp.has_frontline and to_cp.has_frontline return from_cp.has_frontline and to_cp.has_frontline
@@ -190,7 +193,7 @@ class Conflict:
return pos return pos
@classmethod @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 pos = initial
for _ in range(0, int(max_distance), 500): for _ in range(0, int(max_distance), 500):
if theater.is_on_land(pos): if theater.is_on_land(pos):

View File

@@ -7,6 +7,8 @@ from .naming import *
from dcs.mission import * from dcs.mission import *
from dcs.statics import * from dcs.statics import *
FARP_FRONTLINE_DISTANCE = 10000
CATEGORY_MAPPING = { CATEGORY_MAPPING = {
"power": [Fortification.Workshop_A], "power": [Fortification.Workshop_A],
@@ -20,11 +22,27 @@ CATEGORY_MAPPING = {
class GroundObjectsGenerator: class GroundObjectsGenerator:
FARP_CAPACITY = 4
def __init__(self, mission: Mission, conflict: Conflict, game): def __init__(self, mission: Mission, conflict: Conflict, game):
self.m = mission self.m = mission
self.conflict = conflict self.conflict = conflict
self.game = game self.game = game
def generate_farps(self, number_of_units=1) -> typing.Collection[StaticGroup]:
assert self.conflict.is_vector, "FARP could be generated only on frontline conflicts!"
for i, _ in enumerate(range(0, number_of_units, self.FARP_CAPACITY)):
heading = self.conflict.heading - 90
position = self.conflict.find_ground_position(self.conflict.center.point_from_heading(heading, FARP_FRONTLINE_DISTANCE), heading)
position = position.point_from_heading(0, i * 275)
yield self.m.farp(
country=self.m.country(self.game.player),
name="FARP",
position=position,
)
def generate(self): def generate(self):
side = self.m.country(self.game.enemy) side = self.m.country(self.game.enemy)

View File

@@ -72,32 +72,35 @@ class TriggersGenerator:
for coalition_name, coalition in self.mission.coalition.items(): for coalition_name, coalition in self.mission.coalition.items():
for country in coalition.countries.values(): for country in coalition.countries.values():
if coalition_name == player_coalition: if coalition_name == player_coalition:
for plane_group in country.plane_group + country.helicopter_group: for group in country.plane_group + country.helicopter_group:
if plane_group.task == AWACS.name or plane_group.task == Refueling.name: if group.task == AWACS.name or group.task == Refueling.name:
continue
if player_cp.position.distance_to_point(group.position) > PUSH_TRIGGER_SIZE * 3:
continue continue
regroup_heading = self.conflict.to_cp.position.heading_between_point(player_cp.position) regroup_heading = self.conflict.to_cp.position.heading_between_point(player_cp.position)
pos1 = plane_group.position.point_from_heading(regroup_heading, REGROUP_ZONE_DISTANCE) pos1 = group.position.point_from_heading(regroup_heading, REGROUP_ZONE_DISTANCE)
pos2 = plane_group.position.point_from_heading(regroup_heading, REGROUP_ZONE_DISTANCE+5000) pos2 = group.position.point_from_heading(regroup_heading, REGROUP_ZONE_DISTANCE+5000)
w1 = plane_group.add_waypoint(pos1, REGROUP_ALT) w1 = group.add_waypoint(pos1, REGROUP_ALT)
w2 = plane_group.add_waypoint(pos2, REGROUP_ALT) w2 = group.add_waypoint(pos2, REGROUP_ALT)
plane_group.points.remove(w1) group.points.remove(w1)
plane_group.points.remove(w2) group.points.remove(w2)
plane_group.points.insert(1, w2) group.points.insert(1, w2)
plane_group.points.insert(1, w1) group.points.insert(1, w1)
w1.tasks.append(Silence(True)) w1.tasks.append(Silence(True))
switch_waypoint_task = ControlledTask(SwitchWaypoint(from_waypoint=3, to_waypoint=2)) switch_waypoint_task = ControlledTask(SwitchWaypoint(from_waypoint=3, to_waypoint=2))
switch_waypoint_task.start_if_user_flag(1, False) switch_waypoint_task.start_if_user_flag(1, False)
w2.tasks.append(switch_waypoint_task) w2.tasks.append(switch_waypoint_task)
plane_group.points[3].tasks.append(Silence(False)) group.points[3].tasks.append(Silence(False))
plane_group.add_trigger_action(SwitchWaypoint(to_waypoint=4)) group.add_trigger_action(SwitchWaypoint(to_waypoint=4))
push_by_trigger.append(plane_group) push_by_trigger.append(group)
push_trigger_zone = self.mission.triggers.add_triggerzone(player_cp.position, PUSH_TRIGGER_SIZE, name="Push zone") push_trigger_zone = self.mission.triggers.add_triggerzone(player_cp.position, PUSH_TRIGGER_SIZE, name="Push zone")
push_trigger = TriggerOnce(Event.NoEvent, "Push trigger") push_trigger = TriggerOnce(Event.NoEvent, "Push trigger")

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 852 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

BIN
resources/ui/terrain_pg.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -140,7 +140,7 @@ class EventMenu(Menu):
else: else:
self.event.is_awacs_enabled = False 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] units_scramble_counts = {} # type: typing.Dict[typing.Type[UnitType], int]
tasks_scramble_counts = {} # type: typing.Dict[typing.Type[Task], int] tasks_scramble_counts = {} # type: typing.Dict[typing.Type[Task], int]
tasks_clients_counts = {} # type: typing.Dict[typing.Type[Task], int] tasks_clients_counts = {} # type: typing.Dict[typing.Type[Task], int]

View File

@@ -86,17 +86,17 @@ class NewGameMenu(Menu):
Radiobutton(terrain, variable=self.selected_terrain, value=0, **STYLES["radiobutton"]) \ Radiobutton(terrain, variable=self.selected_terrain, value=0, **STYLES["radiobutton"]) \
.grid(row=0, column=0, sticky=W) .grid(row=0, column=0, sticky=W)
Label(terrain, text="Caucasus", **STYLES["widget"]).grid(row=0, column=1, sticky=W) Label(terrain, text="Caucasus", **STYLES["widget"]).grid(row=0, column=1, sticky=W)
self.create_label_image(terrain, "terrain_caucasus.png").grid(row=0, column=2, padx=5) self.create_label_image(terrain, "terrain_caucasus.gif").grid(row=0, column=2, padx=5)
Radiobutton(terrain, variable=self.selected_terrain, value=1, **STYLES["radiobutton"]) \ Radiobutton(terrain, variable=self.selected_terrain, value=1, **STYLES["radiobutton"]) \
.grid(row=1, column=0, sticky=W) .grid(row=1, column=0, sticky=W)
Label(terrain, text="Nevada", **STYLES["widget"]).grid(row=1, column=1, sticky=W) Label(terrain, text="Nevada", **STYLES["widget"]).grid(row=1, column=1, sticky=W)
self.create_label_image(terrain, "terrain_nevada.png").grid(row=1, column=2, padx=5) self.create_label_image(terrain, "terrain_nevada.gif").grid(row=1, column=2, padx=5)
Radiobutton(terrain, variable=self.selected_terrain, value=2, **STYLES["radiobutton"]) \ Radiobutton(terrain, variable=self.selected_terrain, value=2, **STYLES["radiobutton"]) \
.grid(row=2, column=0, sticky=W) .grid(row=2, column=0, sticky=W)
Label(terrain, text="Persian Gulf", **STYLES["widget"]).grid(row=2, column=1, sticky=W) Label(terrain, text="Persian Gulf", **STYLES["widget"]).grid(row=2, column=1, sticky=W)
self.create_label_image(terrain, "terrain_pg.png").grid(row=2, column=2, padx=5) 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"]) \ 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) .grid(row=3, column=0, columnspan=3, sticky=W)

View File

@@ -44,11 +44,8 @@ def restore_game():
if not _save_file_exists(): if not _save_file_exists():
return None return None
try: with open(_save_file(), "rb") as f:
with open(_save_file(), "rb") as f: return pickle.load(f)
return pickle.load(f)
except Exception as e:
raise e
def save_game(game) -> bool: def save_game(game) -> bool: