dont limit aircraft to predefined role; better scrambling screen

This commit is contained in:
Vasyl Horbachenko 2018-09-09 20:21:07 +03:00
parent 4ba1dd87e8
commit a918914431
25 changed files with 332 additions and 320 deletions

View File

@ -1,4 +1,5 @@
import typing import typing
import enum
from dcs.vehicles import * from dcs.vehicles import *
from dcs.unitgroup import * from dcs.unitgroup import *

View File

@ -1,13 +1,16 @@
import typing
import math import math
import random import random
from dcs.task import * from dcs.task import *
from dcs.unittype import UnitType
from game import db from game import db
from game.operation.baseattack import BaseAttackOperation from game.operation.baseattack import BaseAttackOperation
from userdata.debriefing import Debriefing from userdata.debriefing import Debriefing
from .event import Event from .event import *
from ..operation.operation import flight_dict_from
class BaseAttackEvent(Event): class BaseAttackEvent(Event):
@ -18,6 +21,18 @@ class BaseAttackEvent(Event):
def __str__(self): def __str__(self):
return "Base attack" return "Base attack"
@property
def tasks(self):
return [CAP, CAS, PinpointStrike]
def flight_name(self, for_task: typing.Type[Task]) -> str:
if for_task == CAP:
return "Escort flight"
elif for_task == CAS:
return "CAS flight"
elif for_task == PinpointStrike:
return "Ground attack"
def is_successfull(self, debriefing: Debriefing): def is_successfull(self, debriefing: Debriefing):
alive_attackers = sum([v for k, v in debriefing.alive_units[self.attacker_name].items() if db.unit_task(k) == PinpointStrike]) alive_attackers = sum([v for k, v in debriefing.alive_units[self.attacker_name].items() if db.unit_task(k) == PinpointStrike])
alive_defenders = sum([v for k, v in debriefing.alive_units[self.defender_name].items() if db.unit_task(k) == PinpointStrike]) alive_defenders = sum([v for k, v in debriefing.alive_units[self.defender_name].items() if db.unit_task(k) == PinpointStrike])
@ -45,7 +60,9 @@ 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, interceptors: db.PlaneDict, clients: db.PlaneDict): def player_defending(self, flights: ScrambledFlightsDict):
assert len(flights) == 1 and flights[CAP], "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)
escort = self.from_cp.base.scramble_sweep(self.game.settings.multiplier) escort = self.from_cp.base.scramble_sweep(self.game.settings.multiplier)
attackers = self.from_cp.base.armor attackers = self.from_cp.base.armor
@ -53,36 +70,34 @@ class BaseAttackEvent(Event):
op = BaseAttackOperation(game=self.game, op = BaseAttackOperation(game=self.game,
attacker_name=self.attacker_name, attacker_name=self.attacker_name,
defender_name=self.defender_name, defender_name=self.defender_name,
attacker_clients={},
defender_clients=clients,
from_cp=self.from_cp, from_cp=self.from_cp,
to_cp=self.to_cp) to_cp=self.to_cp)
op.setup(cas=cas, op.setup(cas=flight_dict_from(cas),
escort=escort, escort=flight_dict_from(escort),
intercept=flights[CAP],
attack=attackers, attack=attackers,
intercept=interceptors,
defense=self.to_cp.base.armor, defense=self.to_cp.base.armor,
aa=self.to_cp.base.aa) aa=self.to_cp.base.aa)
self.operation = op self.operation = op
def player_attacking(self, cas: db.PlaneDict, escort: db.PlaneDict, armor: db.ArmorDict, clients: db.PlaneDict): def player_attacking(self, flights: ScrambledFlightsDict):
assert flights[CAP] and flights[CAS] and flights[PinpointStrike] and len(flights) == 3, "Invalid flights"
op = BaseAttackOperation(game=self.game, op = BaseAttackOperation(game=self.game,
attacker_name=self.attacker_name, attacker_name=self.attacker_name,
defender_name=self.defender_name, defender_name=self.defender_name,
attacker_clients=clients,
defender_clients={},
from_cp=self.from_cp, from_cp=self.from_cp,
to_cp=self.to_cp) to_cp=self.to_cp)
defenders = self.to_cp.base.scramble_sweep(self.game.settings.multiplier) defenders = self.to_cp.base.scramble_sweep(self.game.settings.multiplier)
defenders.update(self.to_cp.base.scramble_cas(self.game.settings.multiplier)) defenders.update(self.to_cp.base.scramble_cas(self.game.settings.multiplier))
op.setup(cas=cas, op.setup(cas=flights[CAS],
escort=escort, escort=flights[CAP],
attack=armor, attack=flights[PinpointStrike],
intercept=defenders, intercept=flight_dict_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

@ -1,16 +1,22 @@
import typing
import logging import logging
from dcs.unittype import UnitType
from dcs.task import Task
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 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
@ -44,12 +50,25 @@ class Event:
def threat_description(self) -> str: def threat_description(self) -> str:
return "" return ""
def flight_name(self, for_task: typing.Type[Task]) -> str:
return "Flight"
@property
def tasks(self) -> typing.Collection[Task]:
return []
def bonus(self) -> int: def bonus(self) -> int:
return int(math.log(self.to_cp.importance + 1, DIFFICULTY_LOG_BASE) * self.BONUS_BASE) return int(math.log(self.to_cp.importance + 1, DIFFICULTY_LOG_BASE) * self.BONUS_BASE)
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):
pass
def player_defending(self, flights: ScrambledFlightsDict):
pass
def generate(self): def generate(self):
self.operation.is_awacs_enabled = self.is_awacs_enabled self.operation.is_awacs_enabled = self.is_awacs_enabled

View File

@ -24,6 +24,21 @@ class FrontlineAttackEvent(Event):
def threat_description(self): def threat_description(self):
return "{} vehicles".format(self.to_cp.base.assemble_count()) return "{} vehicles".format(self.to_cp.base.assemble_count())
@property
def tasks(self) -> typing.Collection[typing.Type[Task]]:
if self.is_player_attacking:
return [CAS, PinpointStrike]
else:
return [CAP, PinpointStrike]
def flight_name(self, for_task: typing.Type[Task]) -> str:
if for_task == CAS:
return "CAS flight"
elif for_task == CAP:
return "CAP flight"
elif for_task == PinpointStrike:
return "Ground attack"
def __str__(self): def __str__(self):
return "Frontline attack" return "Frontline attack"
@ -54,20 +69,21 @@ 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, armor: db.ArmorDict, strikegroup: db.PlaneDict, clients: db.PlaneDict): def player_attacking(self, flights: ScrambledFlightsDict):
assert flights[CAS] and flights[PinpointStrike] and len(flights) == 2, "Invalid flights"
self.defenders = self.to_cp.base.assemble_attack() self.defenders = self.to_cp.base.assemble_attack()
op = FrontlineAttackOperation(game=self.game, op = FrontlineAttackOperation(game=self.game,
attacker_name=self.attacker_name, attacker_name=self.attacker_name,
defender_name=self.defender_name, defender_name=self.defender_name,
attacker_clients=clients,
defender_clients={},
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])
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=strikegroup) strikegroup=flights[CAS])
self.operation = op self.operation = op

View File

@ -22,6 +22,16 @@ class FrontlinePatrolEvent(Event):
def threat_description(self): def threat_description(self):
return "{} aircraft + ? CAS".format(self.to_cp.base.scramble_count(self.game.settings.multiplier * self.ESCORT_FACTOR, CAP)) return "{} aircraft + ? CAS".format(self.to_cp.base.scramble_count(self.game.settings.multiplier * self.ESCORT_FACTOR, CAP))
@property
def tasks(self):
return [CAP, PinpointStrike]
def flight_name(self, for_task: typing.Type[Task]) -> str:
if for_task == CAP:
return "CAP flight"
elif for_task == PinpointStrike:
return "Ground attack"
def __str__(self): def __str__(self):
return "Frontline CAP" return "Frontline CAP"
@ -65,23 +75,23 @@ class FrontlinePatrolEvent(Event):
def skip(self): def skip(self):
pass pass
def player_attacking(self, interceptors: db.PlaneDict, clients: db.PlaneDict, armor: db.ArmorDict): def player_attacking(self, flights: ScrambledFlightsDict):
assert flights[CAP] and flights[PinpointStrike] 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)
self.escort = self.to_cp.base.scramble_sweep(self.game.settings.multiplier * self.ESCORT_FACTOR) self.escort = self.to_cp.base.scramble_sweep(self.game.settings.multiplier * self.ESCORT_FACTOR)
op = FrontlinePatrolOperation(game=self.game, op = FrontlinePatrolOperation(game=self.game,
attacker_name=self.attacker_name, attacker_name=self.attacker_name,
defender_name=self.defender_name, defender_name=self.defender_name,
attacker_clients=clients,
defender_clients={},
from_cp=self.from_cp, from_cp=self.from_cp,
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=self.cas, op.setup(cas=flight_dict_from(self.cas),
escort=self.escort, escort=flight_dict_from(self.escort),
interceptors=interceptors, interceptors=flights[CAP],
armor_attackers=db.unitdict_restrict_count(armor, sum(defenders.values())), armor_attackers=db.unitdict_restrict_count(dict_from_flight(flights[PinpointStrike]), sum(defenders.values())),
armor_defenders=defenders) armor_defenders=defenders)
self.operation = op self.operation = op

View File

@ -9,7 +9,7 @@ from game.operation.infantrytransport import InfantryTransportOperation
from theater.conflicttheater import * from theater.conflicttheater import *
from userdata.debriefing import Debriefing from userdata.debriefing import Debriefing
from .event import Event from .event import *
class InfantryTransportEvent(Event): class InfantryTransportEvent(Event):
@ -18,6 +18,14 @@ class InfantryTransportEvent(Event):
def __str__(self): def __str__(self):
return "Frontline transport troops" return "Frontline transport troops"
@property
def tasks(self):
return [Embarking]
def flight_name(self, for_task: typing.Type[Task]) -> str:
if for_task == Embarking:
return "Transport flight"
def is_successfull(self, debriefing: Debriefing): def is_successfull(self, debriefing: Debriefing):
return True return True
@ -29,19 +37,19 @@ 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, transport: db.HeliDict, clients: db.HeliDict): def player_attacking(self, flights: ScrambledFlightsDict):
assert flights[Embarking] and len(flights) == 1, "Invalid flights"
op = InfantryTransportOperation( op = InfantryTransportOperation(
game=self.game, game=self.game,
attacker_name=self.attacker_name, attacker_name=self.attacker_name,
defender_name=self.defender_name, defender_name=self.defender_name,
attacker_clients=clients,
defender_clients={},
from_cp=self.from_cp, from_cp=self.from_cp,
to_cp=self.to_cp to_cp=self.to_cp
) )
air_defense = db.find_unittype(AirDefence, self.defender_name)[0] air_defense = db.find_unittype(AirDefence, self.defender_name)[0]
op.setup(transport=transport, op.setup(transport=flights[Embarking],
aa={air_defense: 2}) aa={air_defense: 2})
self.operation = op self.operation = op

View File

@ -18,6 +18,14 @@ class InsurgentAttackEvent(Event):
def threat_description(self): def threat_description(self):
return "" return ""
@property
def tasks(self):
return [CAS]
def flight_name(self, for_task: typing.Type[Task]) -> str:
if for_task == CAS:
return "Ground intercept flight"
def __str__(self): def __str__(self):
return "Destroy insurgents" return "Destroy insurgents"
@ -30,7 +38,9 @@ class InsurgentAttackEvent(Event):
else: else:
return not attackers_success return not attackers_success
def player_defending(self, strikegroup: db.PlaneDict, clients: db.PlaneDict): def player_defending(self, flights: ScrambledFlightsDict):
assert flights[CAS] and len(flights) == 1, "Invalid flights"
suitable_unittypes = db.find_unittype(Reconnaissance, self.attacker_name) suitable_unittypes = db.find_unittype(Reconnaissance, self.attacker_name)
random.shuffle(suitable_unittypes) random.shuffle(suitable_unittypes)
unittypes = suitable_unittypes[:self.TARGET_VARIETY] unittypes = suitable_unittypes[:self.TARGET_VARIETY]
@ -40,12 +50,10 @@ class InsurgentAttackEvent(Event):
op = InsurgentAttackOperation(game=self.game, op = InsurgentAttackOperation(game=self.game,
attacker_name=self.attacker_name, attacker_name=self.attacker_name,
defender_name=self.defender_name, defender_name=self.defender_name,
attacker_clients={},
defender_clients=clients,
from_cp=self.from_cp, from_cp=self.from_cp,
to_cp=self.to_cp) to_cp=self.to_cp)
op.setup(target=self.targets, op.setup(target=self.targets,
strikegroup=strikegroup) strikegroup=flights[CAS])
self.operation = op self.operation = op

View File

@ -9,7 +9,7 @@ from game.operation.intercept import InterceptOperation
from theater.conflicttheater import * from theater.conflicttheater import *
from userdata.debriefing import Debriefing from userdata.debriefing import Debriefing
from .event import Event from .event import *
class InterceptEvent(Event): class InterceptEvent(Event):
@ -22,6 +22,17 @@ class InterceptEvent(Event):
def __str__(self): def __str__(self):
return "Air Intercept" return "Air Intercept"
@property
def tasks(self):
return [CAP]
def flight_name(self, for_task: typing.Type[Task]) -> str:
if for_task == CAP:
if self.is_player_attacking:
return "Intercept flight"
else:
return "Escort flight"
def _enemy_scramble_multiplier(self) -> float: def _enemy_scramble_multiplier(self) -> float:
is_global = self.from_cp.is_global or self.to_cp.is_global is_global = self.from_cp.is_global or self.to_cp.is_global
return self.game.settings.multiplier * is_global and 0.5 or 1 return self.game.settings.multiplier * is_global and 0.5 or 1
@ -57,7 +68,9 @@ 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, interceptors: db.PlaneDict, clients: db.PlaneDict): def player_attacking(self, flights: ScrambledFlightsDict):
assert flights[CAP] 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())
self.transport_unit = random.choice(db.find_unittype(Transport, self.defender_name)) self.transport_unit = random.choice(db.find_unittype(Transport, self.defender_name))
@ -67,20 +80,17 @@ class InterceptEvent(Event):
op = InterceptOperation(game=self.game, op = InterceptOperation(game=self.game,
attacker_name=self.attacker_name, attacker_name=self.attacker_name,
defender_name=self.defender_name, defender_name=self.defender_name,
attacker_clients=clients,
defender_clients={},
from_cp=self.from_cp, from_cp=self.from_cp,
to_cp=self.to_cp) to_cp=self.to_cp)
op.setup(escort=escort, op.setup(escort=flight_dict_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=interceptors) interceptors=flights[CAP])
self.operation = op self.operation = op
def player_defending(self, escort: db.PlaneDict, clients: db.PlaneDict): def player_defending(self, flights: ScrambledFlightsDict):
# TODO: even not quick mission is too quick
interceptors = self.from_cp.base.scramble_interceptors(self.game.settings.multiplier) interceptors = self.from_cp.base.scramble_interceptors(self.game.settings.multiplier)
self.transport_unit = random.choice(db.find_unittype(Transport, self.defender_name)) self.transport_unit = random.choice(db.find_unittype(Transport, self.defender_name))
@ -89,14 +99,12 @@ class InterceptEvent(Event):
op = InterceptOperation(game=self.game, op = InterceptOperation(game=self.game,
attacker_name=self.attacker_name, attacker_name=self.attacker_name,
defender_name=self.defender_name, defender_name=self.defender_name,
attacker_clients={},
defender_clients=clients,
from_cp=self.from_cp, from_cp=self.from_cp,
to_cp=self.to_cp) to_cp=self.to_cp)
op.setup(escort=escort, op.setup(escort=flights[CAP],
transport={self.transport_unit: 1}, transport={self.transport_unit: 1},
interceptors=interceptors, interceptors=flight_dict_from(interceptors),
airdefense={}) airdefense={})
self.operation = op self.operation = op

View File

@ -9,7 +9,7 @@ from game import db
from game.operation.navalintercept import NavalInterceptionOperation from game.operation.navalintercept import NavalInterceptionOperation
from userdata.debriefing import Debriefing from userdata.debriefing import Debriefing
from .event import Event from .event import *
class NavalInterceptEvent(Event): class NavalInterceptEvent(Event):
@ -26,6 +26,19 @@ class NavalInterceptEvent(Event):
def __str__(self) -> str: def __str__(self) -> str:
return "Naval intercept" return "Naval intercept"
@property
def tasks(self):
if self.is_player_attacking:
return [CAS]
else:
return [CAP]
def flight_name(self, for_task: typing.Type[Task]) -> str:
if for_task == CAS:
return "Naval intercept flight"
elif for_task == CAP:
return "CAP flight"
@property @property
def threat_description(self): def threat_description(self):
s = "{} ship(s)".format(self._targets_count()) s = "{} ship(s)".format(self._targets_count())
@ -64,7 +77,9 @@ 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, strikegroup: db.PlaneDict, clients: db.PlaneDict): def player_attacking(self, flights: ScrambledFlightsDict):
assert flights[CAS] and len(flights) == 1, "Invalid flights"
self.targets = { self.targets = {
random.choice(db.find_unittype(CargoTransportation, self.defender_name)): self._targets_count(), random.choice(db.find_unittype(CargoTransportation, self.defender_name)): self._targets_count(),
} }
@ -73,19 +88,19 @@ class NavalInterceptEvent(Event):
self.game, self.game,
attacker_name=self.attacker_name, attacker_name=self.attacker_name,
defender_name=self.defender_name, defender_name=self.defender_name,
attacker_clients=clients,
defender_clients={},
from_cp=self.from_cp, from_cp=self.from_cp,
to_cp=self.to_cp to_cp=self.to_cp
) )
op.setup(strikegroup=strikegroup, op.setup(strikegroup=flights[CAS],
interceptors={}, interceptors={},
targets=self.targets) targets=self.targets)
self.operation = op self.operation = op
def player_defending(self, interceptors: db.PlaneDict, clients: db.PlaneDict): def player_defending(self, flights: ScrambledFlightsDict):
assert flights[CAP] and len(flights) == 1, "Invalid flights"
self.targets = { self.targets = {
random.choice(db.find_unittype(CargoTransportation, self.defender_name)): self._targets_count(), random.choice(db.find_unittype(CargoTransportation, self.defender_name)): self._targets_count(),
} }
@ -94,15 +109,13 @@ class NavalInterceptEvent(Event):
self.game, self.game,
attacker_name=self.attacker_name, attacker_name=self.attacker_name,
defender_name=self.defender_name, defender_name=self.defender_name,
attacker_clients={},
defender_clients=clients,
from_cp=self.from_cp, from_cp=self.from_cp,
to_cp=self.to_cp to_cp=self.to_cp
) )
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=strikegroup, op.setup(strikegroup=flight_dict_from(strikegroup),
interceptors=interceptors, interceptors=flights[CAP],
targets=self.targets) targets=self.targets)
self.operation = op self.operation = op

View File

@ -9,7 +9,7 @@ from game.operation.strike import StrikeOperation
from theater.conflicttheater import * from theater.conflicttheater import *
from userdata.debriefing import Debriefing from userdata.debriefing import Debriefing
from .event import Event from .event import *
class StrikeEvent(Event): class StrikeEvent(Event):
@ -22,25 +22,40 @@ class StrikeEvent(Event):
def is_successfull(self, debriefing: Debriefing): def is_successfull(self, debriefing: Debriefing):
return True return True
@property
def tasks(self):
if self.is_player_attacking:
return [CAP, CAS]
else:
return [CAP]
def flight_name(self, for_task: typing.Type[Task]) -> str:
if for_task == CAP:
if self.is_player_attacking:
return "Escort flight"
else:
return "CAP flight"
elif for_task == CAS:
return "Strike flight"
def commit(self, debriefing: Debriefing): def commit(self, debriefing: Debriefing):
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, strikegroup: db.PlaneDict, escort: db.PlaneDict, clients: db.PlaneDict): def player_attacking(self, flights: ScrambledFlightsDict):
assert flights[CAP] and flights[CAS] and len(flights) == 2, "Invalid flights"
op = StrikeOperation( op = StrikeOperation(
self.game, self.game,
attacker_name=self.attacker_name, attacker_name=self.attacker_name,
defender_name=self.defender_name, defender_name=self.defender_name,
attacker_clients=clients,
defender_clients={},
from_cp=self.from_cp, from_cp=self.from_cp,
to_cp=self.to_cp to_cp=self.to_cp
) )
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=strikegroup, escort=flights[CAP],
escort=escort, interceptors=flight_dict_from(interceptors))
interceptors=interceptors)
self.operation = op self.operation = op

View File

@ -120,7 +120,7 @@ class Game:
if not Conflict.has_frontline_between(player_cp, enemy_cp): if not Conflict.has_frontline_between(player_cp, enemy_cp):
continue continue
if self._roll(player_probability, player_cp.base.strength): if player_probability == 100 or self._roll(player_probability, player_cp.base.strength):
if event_class == NavalInterceptEvent and enemy_cp.radials == LAND: if event_class == NavalInterceptEvent and enemy_cp.radials == LAND:
pass pass
else: else:
@ -131,7 +131,7 @@ class Game:
pass pass
else: else:
self.events.append(event_class(self.player, self.enemy, player_cp, enemy_cp, self)) self.events.append(event_class(self.player, self.enemy, player_cp, enemy_cp, self))
elif self._roll(enemy_probability, enemy_cp.base.strength): elif enemy_probability == 100 or self._roll(enemy_probability, enemy_cp.base.strength):
if event_class in enemy_generated_types: if event_class in enemy_generated_types:
continue continue

View File

@ -9,13 +9,13 @@ from gen.triggergen import *
from gen.airsupportgen import * from gen.airsupportgen import *
from gen.visualgen import * from gen.visualgen import *
from .operation import Operation from .operation import *
class BaseAttackOperation(Operation): class BaseAttackOperation(Operation):
cas = None # type: db.PlaneDict cas = None # type: FlightDict
escort = None # type: db.PlaneDict escort = None # type: FlightDict
intercept = None # type: db.PlaneDict intercept = None # type: FlightDict
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 +23,10 @@ class BaseAttackOperation(Operation):
trigger_radius = TRIGGER_RADIUS_SMALL trigger_radius = TRIGGER_RADIUS_SMALL
def setup(self, def setup(self,
cas: db.PlaneDict, cas: FlightDict,
escort: db.PlaneDict, escort: FlightDict,
attack: db.ArmorDict, attack: FlightDict,
intercept: db.PlaneDict, intercept: FlightDict,
defense: db.ArmorDict, defense: db.ArmorDict,
aa: db.AirDefenseDict): aa: db.AirDefenseDict):
self.cas = cas self.cas = cas
@ -57,10 +57,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(self.intercept, clients=self.defender_clients, at=self.defenders_starting_position) self.airgen.generate_defense(*flight_arguments(self.intercept), at=self.defenders_starting_position)
self.airgen.generate_cas_strikegroup(self.cas, clients=self.attacker_clients, at=self.attackers_starting_position) self.airgen.generate_cas_strikegroup(*flight_arguments(self.cas), at=self.attackers_starting_position)
self.airgen.generate_attackers_escort(self.escort, clients=self.attacker_clients, at=self.attackers_starting_position) self.airgen.generate_attackers_escort(*flight_arguments(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

@ -12,21 +12,21 @@ from gen.airsupportgen import *
from gen.visualgen import * from gen.visualgen import *
from gen.conflictgen import Conflict from gen.conflictgen import Conflict
from .operation import Operation from .operation import *
MAX_DISTANCE_BETWEEN_GROUPS = 12000 MAX_DISTANCE_BETWEEN_GROUPS = 12000
class FrontlineAttackOperation(Operation): class FrontlineAttackOperation(Operation):
strikegroup = None # type: FlightDict
attackers = None # type: db.ArmorDict attackers = None # type: db.ArmorDict
strikegroup = None # type: db.PlaneDict
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: db.PlaneDict): strikegroup: FlightDict):
self.strikegroup = strikegroup self.strikegroup = strikegroup
self.target = target self.target = target
self.attackers = attackers self.attackers = attackers
@ -50,7 +50,7 @@ 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(self.strikegroup, clients=self.attacker_clients, at=self.attackers_starting_position) self.airgen.generate_cas_strikegroup(*flight_arguments(self.strikegroup), at=self.attackers_starting_position)
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

@ -12,21 +12,26 @@ from gen.airsupportgen import *
from gen.visualgen import * from gen.visualgen import *
from gen.conflictgen import Conflict from gen.conflictgen import Conflict
from .operation import Operation from .operation import *
MAX_DISTANCE_BETWEEN_GROUPS = 12000 MAX_DISTANCE_BETWEEN_GROUPS = 12000
class FrontlinePatrolOperation(Operation): class FrontlinePatrolOperation(Operation):
cas = None # type: db.PlaneDict cas = None # type: FlightDict
escort = None # type: db.PlaneDict escort = None # type: FlightDict
interceptors = None # type: db.PlaneDict interceptors = None # type: FlightDict
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, cas: db.PlaneDict, escort: db.PlaneDict, interceptors: db.PlaneDict, armor_attackers: db.ArmorDict, armor_defenders: db.ArmorDict): def setup(self,
cas: FlightDict,
escort: FlightDict,
interceptors: FlightDict,
armor_attackers: db.ArmorDict,
armor_defenders: db.ArmorDict):
self.cas = cas self.cas = cas
self.escort = escort self.escort = escort
self.interceptors = interceptors self.interceptors = interceptors
@ -50,9 +55,9 @@ class FrontlinePatrolOperation(Operation):
conflict=conflict) conflict=conflict)
def generate(self): def generate(self):
self.airgen.generate_defenders_cas(self.cas, {}, self.defenders_starting_position) self.airgen.generate_defenders_cas(*flight_arguments(self.cas), at=self.defenders_starting_position)
self.airgen.generate_defenders_escort(self.escort, {}, self.defenders_starting_position) self.airgen.generate_defenders_escort(*flight_arguments(self.escort), at=self.defenders_starting_position)
self.airgen.generate_migcap(self.interceptors, self.attacker_clients, self.attackers_starting_position) self.airgen.generate_migcap(*flight_arguments(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

@ -10,14 +10,14 @@ from gen.airsupportgen import *
from gen.visualgen import * from gen.visualgen import *
from gen.conflictgen import Conflict from gen.conflictgen import Conflict
from .operation import Operation from .operation import *
class InfantryTransportOperation(Operation): class InfantryTransportOperation(Operation):
transport = None # type: db.HeliDict transport = None # type: FlightDict
aa = None # type: db.AirDefenseDict aa = None # type: db.AirDefenseDict
def setup(self, transport: db.HeliDict, aa: db.AirDefenseDict): def setup(self, transport: FlightDict, aa: db.AirDefenseDict):
self.transport = transport self.transport = transport
self.aa = aa self.aa = aa
@ -36,11 +36,7 @@ class InfantryTransportOperation(Operation):
conflict=conflict) conflict=conflict)
def generate(self): def generate(self):
self.airgen.generate_passenger_transport( self.airgen.generate_passenger_transport(*flight_arguments(self.transport), at=self.attackers_starting_position)
helis=self.transport,
clients=self.attacker_clients,
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

@ -10,16 +10,16 @@ from gen.airsupportgen import *
from gen.visualgen import * from gen.visualgen import *
from gen.conflictgen import Conflict from gen.conflictgen import Conflict
from .operation import Operation from .operation import *
class InsurgentAttackOperation(Operation): class InsurgentAttackOperation(Operation):
strikegroup = None # type: db.PlaneDict strikegroup = None # type: FlightDict
target = None # type: db.ArmorDict target = None # type: db.ArmorDict
def setup(self, def setup(self,
target: db.ArmorDict, target: db.ArmorDict,
strikegroup: db.PlaneDict): strikegroup: FlightDict):
self.strikegroup = strikegroup self.strikegroup = strikegroup
self.target = target self.target = target
@ -38,7 +38,7 @@ class InsurgentAttackOperation(Operation):
conflict=conflict) conflict=conflict)
def generate(self): def generate(self):
self.airgen.generate_defense(self.strikegroup, self.defender_clients, self.defenders_starting_position) self.airgen.generate_defense(*flight_arguments(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,22 @@
from dcs.terrain import Terrain from dcs.terrain import Terrain
from gen import * from gen import *
from .operation import Operation from .operation import *
class InterceptOperation(Operation): class InterceptOperation(Operation):
escort = None # type: db.PlaneDict escort = None # type: FlightDict
transport = None # type: db.PlaneDict transport = None # type: db.PlaneDict
interceptors = None # type: db.PlaneDict interceptors = None # type: FlightDict
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: db.PlaneDict, escort: FlightDict,
transport: db.PlaneDict, transport: db.PlaneDict,
airdefense: db.AirDefenseDict, airdefense: db.AirDefenseDict,
interceptors: db.PlaneDict): interceptors: FlightDict):
self.escort = escort self.escort = escort
self.transport = transport self.transport = transport
self.airdefense = airdefense self.airdefense = airdefense
@ -52,9 +52,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(self.escort, clients=self.defender_clients) self.airgen.generate_defenders_escort(*flight_arguments(self.escort), at=self.defenders_starting_position)
self.airgen.generate_interception(self.interceptors, clients=self.attacker_clients, at=self.attackers_starting_position) self.airgen.generate_interception(*flight_arguments(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,18 @@
from dcs.terrain import Terrain from dcs.terrain import Terrain
from gen import * from gen import *
from .operation import Operation from .operation import *
class NavalInterceptionOperation(Operation): class NavalInterceptionOperation(Operation):
strikegroup = None # type: db.PlaneDict strikegroup = None # type: FlightDict
interceptors = None # type: db.PlaneDict interceptors = None # type: FlightDict
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: db.PlaneDict, strikegroup: FlightDict,
interceptors: db.PlaneDict, interceptors: FlightDict,
targets: db.ShipDict): targets: db.ShipDict):
self.strikegroup = strikegroup self.strikegroup = strikegroup
self.interceptors = interceptors self.interceptors = interceptors
@ -37,16 +37,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(
attackers=self.strikegroup, *flight_arguments(self.strikegroup),
clients=self.attacker_clients,
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(
defenders=self.interceptors, *flight_arguments(self.interceptors),
clients=self.defender_clients,
at=self.defenders_starting_position at=self.defenders_starting_position
) )

View File

@ -1,11 +1,27 @@
from dcs.terrain import Terrain 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 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
@ -33,15 +49,11 @@ class Operation:
game, game,
attacker_name: str, attacker_name: str,
defender_name: str, defender_name: str,
attacker_clients: db.PlaneDict,
defender_clients: db.PlaneDict,
from_cp: ControlPoint, from_cp: ControlPoint,
to_cp: ControlPoint = None): to_cp: ControlPoint = None):
self.game = game self.game = game
self.attacker_name = attacker_name self.attacker_name = attacker_name
self.defender_name = defender_name self.defender_name = defender_name
self.attacker_clients = attacker_clients
self.defender_clients = defender_clients
self.from_cp = from_cp self.from_cp = from_cp
self.to_cp = to_cp self.to_cp = to_cp
self.is_quick = False self.is_quick = False

View File

@ -10,18 +10,18 @@ from gen.airsupportgen import *
from gen.visualgen import * from gen.visualgen import *
from gen.conflictgen import Conflict from gen.conflictgen import Conflict
from .operation import Operation from .operation import *
class StrikeOperation(Operation): class StrikeOperation(Operation):
strikegroup = None # type: db.PlaneDict strikegroup = None # type: FlightDict
escort = None # type: db.PlaneDict escort = None # type: FlightDict
interceptors = None # type: db.PlaneDict interceptors = None # type: FlightDict
def setup(self, def setup(self,
strikegroup: db.PlaneDict, strikegroup: FlightDict,
escort: db.PlaneDict, escort: FlightDict,
interceptors: db.PlaneDict): interceptors: FlightDict):
self.strikegroup = strikegroup self.strikegroup = strikegroup
self.escort = escort self.escort = escort
self.interceptors = interceptors self.interceptors = interceptors
@ -49,10 +49,10 @@ class StrikeOperation(Operation):
category_counters = {} # type: typing.Dict[str, int] category_counters = {} # type: typing.Dict[str, int]
processed_groups = [] processed_groups = []
for object in self.to_cp.ground_objects: for object in self.to_cp.ground_objects:
if object.group_id in processed_groups: if object.group_identifier in processed_groups:
continue continue
processed_groups.append(object.group_id) processed_groups.append(object.group_identifier)
category_counters[object.category] = category_counters.get(object.category, 0) + 1 category_counters[object.category] = category_counters.get(object.category, 0) + 1
markpoint_name = "{}{}".format(object.name_abbrev, category_counters[object.category]) markpoint_name = "{}{}".format(object.name_abbrev, category_counters[object.category])
@ -61,18 +61,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(strikegroup=self.strikegroup, self.airgen.generate_ground_attack_strikegroup(*flight_arguments(self.strikegroup),
targets=targets, targets=targets,
clients=self.attacker_clients,
at=self.attackers_starting_position) at=self.attackers_starting_position)
self.airgen.generate_attackers_escort(self.escort, self.airgen.generate_attackers_escort(*flight_arguments(self.escort), at=self.attackers_starting_position)
clients=self.attacker_clients,
at=self.attackers_starting_position)
self.airgen.generate_barcap(patrol=self.interceptors, self.airgen.generate_barcap(*flight_arguments(self.interceptors), at=self.defenders_starting_position)
clients={},
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

@ -2,7 +2,7 @@
class Settings: class Settings:
player_skill = "Good" player_skill = "Good"
enemy_skill = "Average" enemy_skill = "Average"
only_player_takeoff = False only_player_takeoff = True
night_disabled = False night_disabled = False
multiplier = 1 multiplier = 1
sams = True sams = True

View File

@ -265,7 +265,7 @@ class AircraftConflictGenerator:
self.escort_targets.append((group, group.points.index(waypoint))) 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, targets: typing.List[typing.Tuple[str, Point]], clients: db.PlaneDict, 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):
assert len(self.escort_targets) == 0 assert 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):

5
gen/heli.py Normal file
View File

@ -0,0 +1,5 @@
from .aircraft import *
class HelicopterConflictGenerator(AircraftConflictGenerator):
pass

View File

@ -41,6 +41,10 @@ class TheaterGroundObject:
def string_identifier(self): def string_identifier(self):
return "{}|{}|{}|{}".format(self.category, self.cp_id, self.group_id, self.object_id) return "{}|{}|{}|{}".format(self.category, self.cp_id, self.group_id, self.object_id)
@property
def group_identifier(self) -> str:
return "{}|{}".format(self.category, self.group_id)
@property @property
def name_abbrev(self) -> str: def name_abbrev(self) -> str:
return ABBREV_NAME[self.category] return ABBREV_NAME[self.category]

View File

@ -7,27 +7,9 @@ from game.event import *
from .styles import STYLES, RED from .styles import STYLES, RED
UNITTYPES_FOR_EVENTS = {
FrontlineAttackEvent: [[CAS, PinpointStrike], [CAP]],
FrontlinePatrolEvent: [[CAP, PinpointStrike], [CAP]],
BaseAttackEvent: [[CAP, CAS, PinpointStrike], [CAP, CAS, PinpointStrike]],
StrikeEvent: [[CAP, CAS], [CAP]],
InterceptEvent: [[CAP], [CAP]],
InsurgentAttackEvent: [[CAS], [CAP]],
NavalInterceptEvent: [[CAS], [CAP]],
InfantryTransportEvent: [[Embarking], [CAP]],
}
AI_BAN_FOR_EVENTS = {
InfantryTransportEvent: [Embarking],
StrikeEvent: [CAS],
}
class EventMenu(Menu): class EventMenu(Menu):
aircraft_scramble_entries = None # type: typing.Dict[PlaneType , Entry] scramble_entries = None # type: typing.Dict[typing.Type[Task], typing.Dict[typing.Type[UnitType], typing.Tuple[Entry, Entry]]]
aircraft_client_entries = None # type: typing.Dict[PlaneType, Entry]
armor_scramble_entries = None # type: typing.Dict[VehicleType, Entry]
error_label = None # type: Label error_label = None # type: Label
awacs = None # type: IntVar awacs = None # type: IntVar
@ -35,9 +17,7 @@ class EventMenu(Menu):
super(EventMenu, self).__init__(window, parent, game) super(EventMenu, self).__init__(window, parent, game)
self.event = event self.event = event
self.aircraft_scramble_entries = {} self.scramble_entries = {k: {} for k in self.event.tasks}
self.armor_scramble_entries = {}
self.aircraft_client_entries = {}
if self.event.attacker_name == self.game.player: if self.event.attacker_name == self.game.player:
self.base = self.event.from_cp.base self.base = self.event.from_cp.base
@ -68,32 +48,24 @@ class EventMenu(Menu):
return new_label return new_label
def scrable_row(unit_type, unit_count): def scrable_row(task_type, unit_type, unit_count, client_slots: bool):
nonlocal row nonlocal row
Label(self.frame, text="{} ({})".format(db.unit_type_name(unit_type), unit_count), **STYLES["widget"]).grid(row=row, sticky=W) Label(self.frame, text="{} ({})".format(db.unit_type_name(unit_type), unit_count), **STYLES["widget"]).grid(row=row, sticky=W)
scramble_entry = Entry(self.frame, width=2) scramble_entry = Entry(self.frame, width=2)
scramble_entry.grid(column=1, row=row, sticky=E, padx=5) scramble_entry.grid(column=1, row=row, sticky=E, padx=5)
scramble_entry.insert(0, "0") scramble_entry.insert(0, "0")
self.aircraft_scramble_entries[unit_type] = scramble_entry Button(self.frame, text="+", command=self.scramble_half(task_type, unit_type), **STYLES["btn-primary"]).grid(column=2, row=row)
Button(self.frame, text="+", command=self.scramble_half(True, unit_type), **STYLES["btn-primary"]).grid(column=2, row=row)
if client_slots:
client_entry = Entry(self.frame, width=2) client_entry = Entry(self.frame, width=2)
client_entry.grid(column=3, row=row, sticky=E, padx=5) client_entry.grid(column=3, row=row, sticky=E, padx=5)
client_entry.insert(0, "0") client_entry.insert(0, "0")
self.aircraft_client_entries[unit_type] = client_entry Button(self.frame, text="+", command=self.client_one(task_type, unit_type), **STYLES["btn-primary"]).grid(column=4, row=row)
Button(self.frame, text="+", command=self.client_one(unit_type), **STYLES["btn-primary"]).grid(column=4, row=row) else:
client_entry = None
row += 1 self.scramble_entries[task_type][unit_type] = scramble_entry, client_entry
def scramble_armor_row(unit_type, unit_count):
nonlocal row
Label(self.frame, text="{} ({})".format(db.unit_type_name(unit_type), unit_count), **STYLES["widget"]).grid(row=row, sticky=W)
scramble_entry = Entry(self.frame, width=2)
scramble_entry.insert(0, "0")
scramble_entry.grid(column=1, row=row, sticky=E, padx=5)
self.armor_scramble_entries[unit_type] = scramble_entry
Button(self.frame, text="+", command=self.scramble_half(False, unit_type),**STYLES["btn-primary"]).grid(column=2, row=row)
row += 1 row += 1
@ -108,84 +80,53 @@ class EventMenu(Menu):
Label(self.frame, text="{}. {}".format(self.event, threat_descr), **STYLES["mission-preview"]).grid(row=row, column=0, columnspan=5, sticky=S+EW, padx=5, pady=5) Label(self.frame, text="{}. {}".format(self.event, threat_descr), **STYLES["mission-preview"]).grid(row=row, column=0, columnspan=5, sticky=S+EW, padx=5, pady=5)
row += 1 row += 1
header("Aircraft :")
if self.base.aircraft:
Label(self.frame, text="Amount", **STYLES["widget"]).grid(row=row, column=1, columnspan=2) Label(self.frame, text="Amount", **STYLES["widget"]).grid(row=row, column=1, columnspan=2)
Label(self.frame, text="Client slots", **STYLES["widget"]).grid(row=row, column=3, columnspan=2) Label(self.frame, text="Client slots", **STYLES["widget"]).grid(row=row, column=3, columnspan=2)
row += 1 row += 1
filter_attackers_index = 0 if self.game.is_player_attack(self.event) else 1 for flight_task in self.event.tasks:
filter_to = UNITTYPES_FOR_EVENTS[self.event.__class__][filter_attackers_index] header("{}:".format(self.event.flight_name(flight_task)))
for unit_type, count in self.base.aircraft.items(): if flight_task == PinpointStrike:
if filter_to and db.unit_task(unit_type) not in filter_to: if not self.base.armor:
continue label("No units")
for t, c in self.base.armor.items():
scrable_row(flight_task, t, c, client_slots=False)
else:
if not self.base.aircraft:
label("No units")
for t, c in self.base.aircraft.items():
scrable_row(flight_task, t, c, client_slots=True)
if unit_type in helicopter_map and self.event.__class__ != InsurgentAttackEvent: header("Support:")
continue
scrable_row(unit_type, count)
if not self.base.total_planes:
label("None", sticky=W)
header("Armor :")
armor_counter = 0
for unit_type, count in self.base.armor.items():
if filter_to and db.unit_task(unit_type) not in filter_to:
continue
scramble_armor_row(unit_type, count)
armor_counter += 1
if not self.base.total_armor or armor_counter == 0:
label("None", sticky=W)
header("Support :")
# Options # Options
awacs_enabled = self.game.budget >= AWACS_BUDGET_COST and NORMAL or DISABLED awacs_enabled = self.game.budget >= AWACS_BUDGET_COST and NORMAL or DISABLED
Checkbutton(self.frame, var=self.awacs, state=awacs_enabled, **STYLES["radiobutton"]).grid(row=row, column=0, sticky=E) Checkbutton(self.frame, var=self.awacs, state=awacs_enabled, **STYLES["radiobutton"]).grid(row=row, column=0, sticky=E)
Label(self.frame, text="AWACS ({}m)".format(AWACS_BUDGET_COST), **STYLES["widget"]).grid(row=row, column=3, sticky=W, padx=5, pady=5) Label(self.frame, text="AWACS ({}m)".format(AWACS_BUDGET_COST), **STYLES["widget"]).grid(row=row, column=3, sticky=W, padx=5, pady=5)
row += 1 row += 1
header("Ready ?") header("Ready?")
self.error_label = label("") self.error_label = label("")
self.error_label["fg"] = RED self.error_label["fg"] = RED
Button(self.frame, text="Commit", command=self.start, **STYLES["btn-primary"]).grid(column=0, row=row, sticky=E, padx=5, pady=(10,10)) Button(self.frame, text="Commit", command=self.start, **STYLES["btn-primary"]).grid(column=0, row=row, sticky=E, padx=5, pady=(10,10))
Button(self.frame, text="Back", command=self.dismiss, **STYLES["btn-warning"]).grid(column=3, row=row, sticky=E, padx=5, pady=(10,10)) Button(self.frame, text="Back", command=self.dismiss, **STYLES["btn-warning"]).grid(column=3, row=row, sticky=E, padx=5, pady=(10,10))
row += 1 row += 1
def _scrambled_aircraft_count(self, unit_type: UnitType) -> int: def scramble_half(self, task: typing.Type[UnitType], unit_type: UnitType) -> typing.Callable:
value = self.aircraft_scramble_entries[unit_type].get()
if value and int(value) > 0:
return min(int(value), self.base.aircraft[unit_type])
return 0
def _scrambled_armor_count(self, unit_type: UnitType) -> int:
value = self.armor_scramble_entries[unit_type].get()
if value and int(value) > 0:
return min(int(value), self.base.armor[unit_type])
return 0
def scramble_half(self, aircraft: bool, unit_type: UnitType) -> typing.Callable:
def action(): def action():
entry = None # type: Entry entry = self.scramble_entries[task][unit_type][0] # type: Entry
total_count = 0 value = entry.get()
if aircraft:
entry = self.aircraft_scramble_entries[unit_type]
total_count = self.base.aircraft[unit_type]
else:
entry = self.armor_scramble_entries[unit_type]
total_count = self.base.armor[unit_type]
existing_count = int(entry.get()) total_units = self.base.total_units_of_type(unit_type)
amount = int(value and value or "0")
entry.delete(0, END) entry.delete(0, END)
entry.insert(0, "{}".format(int(existing_count + math.ceil(total_count/2)))) entry.insert(0, str(amount + int(math.ceil(total_units/2))))
return action return action
def client_one(self, unit_type: UnitType) -> typing.Callable: def client_one(self, task: typing.Type[Task], unit_type: UnitType) -> typing.Callable:
def action(): def action():
entry = self.aircraft_client_entries[unit_type] # type: Entry entry = self.scramble_entries[task][unit_type][1] # type: Entry
value = entry.get() value = entry.get()
amount = int(value and value or "0") amount = int(value and value or "0")
entry.delete(0, END) entry.delete(0, END)
@ -199,94 +140,37 @@ class EventMenu(Menu):
else: else:
self.event.is_awacs_enabled = False self.event.is_awacs_enabled = False
scrambled_aircraft = {} flights = {k: {} for k in self.event.tasks} # type: ScrambledFlightsDict
scrambled_sweep = {} total_counts_scrambled = {} # type: typing.Dict[typing.Type[UnitType], int]
scrambled_cas = {}
for unit_type, field in self.aircraft_scramble_entries.items():
amount = self._scrambled_aircraft_count(unit_type)
if amount > 0:
task = db.unit_task(unit_type)
scrambled_aircraft[unit_type] = amount def dampen_count(unit_type: typing.Type[UnitType], count: int) -> int:
if task == CAS: nonlocal total_counts_scrambled
scrambled_cas[unit_type] = amount total_count = self.base.total_units_of_type(unit_type)
elif task == CAP:
scrambled_sweep[unit_type] = amount
scrambled_clients = {} total_scrambled = total_counts_scrambled.get(unit_type, 0)
for unit_type, field in self.aircraft_client_entries.items(): dampened_value = count if count + total_scrambled < total_count else total_count - total_scrambled
value = field.get() total_counts_scrambled[unit_type] = total_counts_scrambled.get(unit_type, 0) + dampened_value
if value and int(value) > 0: return dampened_value
amount = int(value)
scrambled_clients[unit_type] = amount
scrambled_armor = {} for task_type, dict in self.scramble_entries.items():
for unit_type, field in self.armor_scramble_entries.items(): for unit_type, (count_entry, clients_entry) in dict.items():
amount = self._scrambled_armor_count(unit_type) try:
if amount > 0: count = int(count_entry.get())
scrambled_armor[unit_type] = amount except:
count = 0
if type(self.event) in AI_BAN_FOR_EVENTS: try:
banned_tasks_for_ai = AI_BAN_FOR_EVENTS[type(self.event)] clients_count = int(clients_entry and clients_entry.get() or 0)
for task in banned_tasks_for_ai: except:
scrambled_slots = [1 for x in scrambled_aircraft if db.unit_task(x) == task] clients_count = 0
scrambled_client_slots = [1 for x in scrambled_clients if db.unit_task(x) == task]
if scrambled_slots != scrambled_client_slots: flights[task_type][unit_type] = dampen_count(unit_type, count), clients_count
self.error_label["text"] = "AI slots of task {} are not supported for this operation".format(task.name)
return
if type(self.event) is BaseAttackEvent:
e = self.event # type: BaseAttackEvent
if self.game.is_player_attack(self.event):
e.player_attacking(cas=scrambled_cas,
escort=scrambled_sweep,
armor=scrambled_armor,
clients=scrambled_clients)
else:
e.player_defending(interceptors=scrambled_aircraft,
clients=scrambled_clients)
elif type(self.event) is InterceptEvent:
e = self.event # type: InterceptEvent
if self.game.is_player_attack(self.event):
e.player_attacking(interceptors=scrambled_aircraft,
clients=scrambled_clients)
else:
e.player_defending(escort=scrambled_aircraft,
clients=scrambled_clients)
elif type(self.event) is FrontlineAttackEvent:
e = self.event # type: FrontlineAttackEvent
e.player_attacking(armor=scrambled_armor, strikegroup=scrambled_aircraft, clients=scrambled_clients)
elif type(self.event) is FrontlinePatrolEvent:
e = self.event # type: FrontlinePatrolEvent
e.player_attacking(interceptors=scrambled_aircraft, clients=scrambled_clients, armor=scrambled_armor)
elif type(self.event) is NavalInterceptEvent:
e = self.event # type: NavalInterceptEvent
if self.game.is_player_attack(self.event): if self.game.is_player_attack(self.event):
e.player_attacking(strikegroup=scrambled_aircraft, clients=scrambled_clients) self.event.player_attacking(flights)
else: else:
e.player_defending(interceptors=scrambled_aircraft, clients=scrambled_clients) self.event.player_defending(flights)
elif type(self.event) is InsurgentAttackEvent:
e = self.event # type: InsurgentAttackEvent
if self.game.is_player_attack(self.event):
assert False
else:
e.player_defending(strikegroup=scrambled_aircraft, clients=scrambled_clients)
elif type(self.event) is InfantryTransportEvent:
e = self.event # type: InfantryTransportEvent
if self.game.is_player_attack(self.event):
e.player_attacking(transport=scrambled_aircraft, clients=scrambled_clients)
else:
assert False
elif type(self.event) is StrikeEvent:
e = self.event # type: StrikeEvent
if self.game.is_player_attack(self.event):
e.player_attacking(strikegroup=scrambled_cas,
escort=scrambled_sweep,
clients=scrambled_clients)
else:
assert False
self.game.initiate_event(self.event) self.game.initiate_event(self.event)
EventResultsMenu(self.window, self.parent, self.game, self.event).display() EventResultsMenu(self.window, self.parent, self.game, self.event).display()