mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
dont limit aircraft to predefined role; better scrambling screen
This commit is contained in:
parent
4ba1dd87e8
commit
a918914431
@ -1,4 +1,5 @@
|
||||
import typing
|
||||
import enum
|
||||
|
||||
from dcs.vehicles import *
|
||||
from dcs.unitgroup import *
|
||||
|
||||
@ -1,13 +1,16 @@
|
||||
import typing
|
||||
import math
|
||||
import random
|
||||
|
||||
from dcs.task import *
|
||||
from dcs.unittype import UnitType
|
||||
|
||||
from game import db
|
||||
from game.operation.baseattack import BaseAttackOperation
|
||||
from userdata.debriefing import Debriefing
|
||||
|
||||
from .event import Event
|
||||
from .event import *
|
||||
from ..operation.operation import flight_dict_from
|
||||
|
||||
|
||||
class BaseAttackEvent(Event):
|
||||
@ -18,6 +21,18 @@ class BaseAttackEvent(Event):
|
||||
def __str__(self):
|
||||
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):
|
||||
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])
|
||||
@ -45,7 +60,9 @@ class BaseAttackEvent(Event):
|
||||
if not self.is_player_attacking and self.to_cp.captured:
|
||||
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)
|
||||
escort = self.from_cp.base.scramble_sweep(self.game.settings.multiplier)
|
||||
attackers = self.from_cp.base.armor
|
||||
@ -53,36 +70,34 @@ class BaseAttackEvent(Event):
|
||||
op = BaseAttackOperation(game=self.game,
|
||||
attacker_name=self.attacker_name,
|
||||
defender_name=self.defender_name,
|
||||
attacker_clients={},
|
||||
defender_clients=clients,
|
||||
from_cp=self.from_cp,
|
||||
to_cp=self.to_cp)
|
||||
|
||||
op.setup(cas=cas,
|
||||
escort=escort,
|
||||
op.setup(cas=flight_dict_from(cas),
|
||||
escort=flight_dict_from(escort),
|
||||
intercept=flights[CAP],
|
||||
attack=attackers,
|
||||
intercept=interceptors,
|
||||
defense=self.to_cp.base.armor,
|
||||
aa=self.to_cp.base.aa)
|
||||
|
||||
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,
|
||||
attacker_name=self.attacker_name,
|
||||
defender_name=self.defender_name,
|
||||
attacker_clients=clients,
|
||||
defender_clients={},
|
||||
from_cp=self.from_cp,
|
||||
to_cp=self.to_cp)
|
||||
|
||||
defenders = self.to_cp.base.scramble_sweep(self.game.settings.multiplier)
|
||||
defenders.update(self.to_cp.base.scramble_cas(self.game.settings.multiplier))
|
||||
|
||||
op.setup(cas=cas,
|
||||
escort=escort,
|
||||
attack=armor,
|
||||
intercept=defenders,
|
||||
op.setup(cas=flights[CAS],
|
||||
escort=flights[CAP],
|
||||
attack=flights[PinpointStrike],
|
||||
intercept=flight_dict_from(defenders),
|
||||
defense=self.to_cp.base.armor,
|
||||
aa=self.to_cp.base.assemble_aa())
|
||||
|
||||
|
||||
@ -1,16 +1,22 @@
|
||||
import typing
|
||||
import logging
|
||||
|
||||
from dcs.unittype import UnitType
|
||||
from dcs.task import Task
|
||||
from dcs.unittype import UnitType
|
||||
|
||||
from game import *
|
||||
from theater import *
|
||||
from gen.environmentgen import EnvironmentSettings
|
||||
from game.operation.operation import flight_dict_from, dict_from_flight
|
||||
|
||||
from userdata.debriefing import Debriefing
|
||||
from userdata import persistency
|
||||
|
||||
DIFFICULTY_LOG_BASE = 1.1
|
||||
|
||||
ScrambledFlightsDict = typing.Dict[typing.Type[Task], typing.Dict[typing.Type[UnitType], typing.Tuple[int, int]]]
|
||||
|
||||
|
||||
class Event:
|
||||
silent = False
|
||||
@ -44,12 +50,25 @@ class Event:
|
||||
def threat_description(self) -> str:
|
||||
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:
|
||||
return int(math.log(self.to_cp.importance + 1, DIFFICULTY_LOG_BASE) * self.BONUS_BASE)
|
||||
|
||||
def is_successfull(self, debriefing: Debriefing) -> bool:
|
||||
return self.operation.is_successfull(debriefing)
|
||||
|
||||
def player_attacking(self, flights: ScrambledFlightsDict):
|
||||
pass
|
||||
|
||||
def player_defending(self, flights: ScrambledFlightsDict):
|
||||
pass
|
||||
|
||||
def generate(self):
|
||||
self.operation.is_awacs_enabled = self.is_awacs_enabled
|
||||
|
||||
|
||||
@ -24,6 +24,21 @@ class FrontlineAttackEvent(Event):
|
||||
def threat_description(self):
|
||||
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):
|
||||
return "Frontline attack"
|
||||
|
||||
@ -54,20 +69,21 @@ class FrontlineAttackEvent(Event):
|
||||
if self.to_cp.captured:
|
||||
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()
|
||||
|
||||
op = FrontlineAttackOperation(game=self.game,
|
||||
attacker_name=self.attacker_name,
|
||||
defender_name=self.defender_name,
|
||||
attacker_clients=clients,
|
||||
defender_clients={},
|
||||
from_cp=self.from_cp,
|
||||
to_cp=self.to_cp)
|
||||
|
||||
armor = dict_from_flight(flights[PinpointStrike])
|
||||
op.setup(target=self.defenders,
|
||||
attackers=db.unitdict_restrict_count(armor, sum(self.defenders.values())),
|
||||
strikegroup=strikegroup)
|
||||
strikegroup=flights[CAS])
|
||||
|
||||
self.operation = op
|
||||
|
||||
|
||||
@ -22,6 +22,16 @@ class FrontlinePatrolEvent(Event):
|
||||
def threat_description(self):
|
||||
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):
|
||||
return "Frontline CAP"
|
||||
|
||||
@ -65,23 +75,23 @@ class FrontlinePatrolEvent(Event):
|
||||
def skip(self):
|
||||
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.escort = self.to_cp.base.scramble_sweep(self.game.settings.multiplier * self.ESCORT_FACTOR)
|
||||
|
||||
op = FrontlinePatrolOperation(game=self.game,
|
||||
attacker_name=self.attacker_name,
|
||||
defender_name=self.defender_name,
|
||||
attacker_clients=clients,
|
||||
defender_clients={},
|
||||
from_cp=self.from_cp,
|
||||
to_cp=self.to_cp)
|
||||
|
||||
defenders = self.to_cp.base.assemble_attack()
|
||||
op.setup(cas=self.cas,
|
||||
escort=self.escort,
|
||||
interceptors=interceptors,
|
||||
armor_attackers=db.unitdict_restrict_count(armor, sum(defenders.values())),
|
||||
op.setup(cas=flight_dict_from(self.cas),
|
||||
escort=flight_dict_from(self.escort),
|
||||
interceptors=flights[CAP],
|
||||
armor_attackers=db.unitdict_restrict_count(dict_from_flight(flights[PinpointStrike]), sum(defenders.values())),
|
||||
armor_defenders=defenders)
|
||||
|
||||
self.operation = op
|
||||
|
||||
@ -9,7 +9,7 @@ from game.operation.infantrytransport import InfantryTransportOperation
|
||||
from theater.conflicttheater import *
|
||||
from userdata.debriefing import Debriefing
|
||||
|
||||
from .event import Event
|
||||
from .event import *
|
||||
|
||||
|
||||
class InfantryTransportEvent(Event):
|
||||
@ -18,6 +18,14 @@ class InfantryTransportEvent(Event):
|
||||
def __str__(self):
|
||||
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):
|
||||
return True
|
||||
|
||||
@ -29,19 +37,19 @@ class InfantryTransportEvent(Event):
|
||||
else:
|
||||
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(
|
||||
game=self.game,
|
||||
attacker_name=self.attacker_name,
|
||||
defender_name=self.defender_name,
|
||||
attacker_clients=clients,
|
||||
defender_clients={},
|
||||
from_cp=self.from_cp,
|
||||
to_cp=self.to_cp
|
||||
)
|
||||
|
||||
air_defense = db.find_unittype(AirDefence, self.defender_name)[0]
|
||||
op.setup(transport=transport,
|
||||
op.setup(transport=flights[Embarking],
|
||||
aa={air_defense: 2})
|
||||
|
||||
self.operation = op
|
||||
|
||||
@ -18,6 +18,14 @@ class InsurgentAttackEvent(Event):
|
||||
def threat_description(self):
|
||||
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):
|
||||
return "Destroy insurgents"
|
||||
|
||||
@ -30,7 +38,9 @@ class InsurgentAttackEvent(Event):
|
||||
else:
|
||||
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)
|
||||
random.shuffle(suitable_unittypes)
|
||||
unittypes = suitable_unittypes[:self.TARGET_VARIETY]
|
||||
@ -40,12 +50,10 @@ class InsurgentAttackEvent(Event):
|
||||
op = InsurgentAttackOperation(game=self.game,
|
||||
attacker_name=self.attacker_name,
|
||||
defender_name=self.defender_name,
|
||||
attacker_clients={},
|
||||
defender_clients=clients,
|
||||
from_cp=self.from_cp,
|
||||
to_cp=self.to_cp)
|
||||
op.setup(target=self.targets,
|
||||
strikegroup=strikegroup)
|
||||
strikegroup=flights[CAS])
|
||||
|
||||
self.operation = op
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ from game.operation.intercept import InterceptOperation
|
||||
from theater.conflicttheater import *
|
||||
from userdata.debriefing import Debriefing
|
||||
|
||||
from .event import Event
|
||||
from .event import *
|
||||
|
||||
|
||||
class InterceptEvent(Event):
|
||||
@ -22,6 +22,17 @@ class InterceptEvent(Event):
|
||||
def __str__(self):
|
||||
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:
|
||||
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
|
||||
@ -57,7 +68,9 @@ class InterceptEvent(Event):
|
||||
if self.to_cp.captured:
|
||||
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())
|
||||
|
||||
self.transport_unit = random.choice(db.find_unittype(Transport, self.defender_name))
|
||||
@ -67,20 +80,17 @@ class InterceptEvent(Event):
|
||||
op = InterceptOperation(game=self.game,
|
||||
attacker_name=self.attacker_name,
|
||||
defender_name=self.defender_name,
|
||||
attacker_clients=clients,
|
||||
defender_clients={},
|
||||
from_cp=self.from_cp,
|
||||
to_cp=self.to_cp)
|
||||
|
||||
op.setup(escort=escort,
|
||||
op.setup(escort=flight_dict_from(escort),
|
||||
transport={self.transport_unit: 1},
|
||||
airdefense={airdefense_unit: self.AIRDEFENSE_COUNT},
|
||||
interceptors=interceptors)
|
||||
interceptors=flights[CAP])
|
||||
|
||||
self.operation = op
|
||||
|
||||
def player_defending(self, escort: db.PlaneDict, clients: db.PlaneDict):
|
||||
# TODO: even not quick mission is too quick
|
||||
def player_defending(self, flights: ScrambledFlightsDict):
|
||||
interceptors = self.from_cp.base.scramble_interceptors(self.game.settings.multiplier)
|
||||
|
||||
self.transport_unit = random.choice(db.find_unittype(Transport, self.defender_name))
|
||||
@ -89,14 +99,12 @@ class InterceptEvent(Event):
|
||||
op = InterceptOperation(game=self.game,
|
||||
attacker_name=self.attacker_name,
|
||||
defender_name=self.defender_name,
|
||||
attacker_clients={},
|
||||
defender_clients=clients,
|
||||
from_cp=self.from_cp,
|
||||
to_cp=self.to_cp)
|
||||
|
||||
op.setup(escort=escort,
|
||||
op.setup(escort=flights[CAP],
|
||||
transport={self.transport_unit: 1},
|
||||
interceptors=interceptors,
|
||||
interceptors=flight_dict_from(interceptors),
|
||||
airdefense={})
|
||||
|
||||
self.operation = op
|
||||
|
||||
@ -9,7 +9,7 @@ from game import db
|
||||
from game.operation.navalintercept import NavalInterceptionOperation
|
||||
from userdata.debriefing import Debriefing
|
||||
|
||||
from .event import Event
|
||||
from .event import *
|
||||
|
||||
|
||||
class NavalInterceptEvent(Event):
|
||||
@ -26,6 +26,19 @@ class NavalInterceptEvent(Event):
|
||||
def __str__(self) -> str:
|
||||
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
|
||||
def threat_description(self):
|
||||
s = "{} ship(s)".format(self._targets_count())
|
||||
@ -64,7 +77,9 @@ class NavalInterceptEvent(Event):
|
||||
if self.to_cp.captured:
|
||||
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 = {
|
||||
random.choice(db.find_unittype(CargoTransportation, self.defender_name)): self._targets_count(),
|
||||
}
|
||||
@ -73,19 +88,19 @@ class NavalInterceptEvent(Event):
|
||||
self.game,
|
||||
attacker_name=self.attacker_name,
|
||||
defender_name=self.defender_name,
|
||||
attacker_clients=clients,
|
||||
defender_clients={},
|
||||
from_cp=self.from_cp,
|
||||
to_cp=self.to_cp
|
||||
)
|
||||
|
||||
op.setup(strikegroup=strikegroup,
|
||||
op.setup(strikegroup=flights[CAS],
|
||||
interceptors={},
|
||||
targets=self.targets)
|
||||
|
||||
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 = {
|
||||
random.choice(db.find_unittype(CargoTransportation, self.defender_name)): self._targets_count(),
|
||||
}
|
||||
@ -94,15 +109,13 @@ class NavalInterceptEvent(Event):
|
||||
self.game,
|
||||
attacker_name=self.attacker_name,
|
||||
defender_name=self.defender_name,
|
||||
attacker_clients={},
|
||||
defender_clients=clients,
|
||||
from_cp=self.from_cp,
|
||||
to_cp=self.to_cp
|
||||
)
|
||||
|
||||
strikegroup = self.from_cp.base.scramble_cas(self.game.settings.multiplier)
|
||||
op.setup(strikegroup=strikegroup,
|
||||
interceptors=interceptors,
|
||||
op.setup(strikegroup=flight_dict_from(strikegroup),
|
||||
interceptors=flights[CAP],
|
||||
targets=self.targets)
|
||||
|
||||
self.operation = op
|
||||
|
||||
@ -9,7 +9,7 @@ from game.operation.strike import StrikeOperation
|
||||
from theater.conflicttheater import *
|
||||
from userdata.debriefing import Debriefing
|
||||
|
||||
from .event import Event
|
||||
from .event import *
|
||||
|
||||
|
||||
class StrikeEvent(Event):
|
||||
@ -22,25 +22,40 @@ class StrikeEvent(Event):
|
||||
def is_successfull(self, debriefing: Debriefing):
|
||||
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):
|
||||
super(StrikeEvent, self).commit(debriefing)
|
||||
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(
|
||||
self.game,
|
||||
attacker_name=self.attacker_name,
|
||||
defender_name=self.defender_name,
|
||||
attacker_clients=clients,
|
||||
defender_clients={},
|
||||
from_cp=self.from_cp,
|
||||
to_cp=self.to_cp
|
||||
)
|
||||
|
||||
interceptors = self.to_cp.base.scramble_interceptors(self.game.settings.multiplier)
|
||||
|
||||
op.setup(strikegroup=strikegroup,
|
||||
escort=escort,
|
||||
interceptors=interceptors)
|
||||
op.setup(strikegroup=flights[CAS],
|
||||
escort=flights[CAP],
|
||||
interceptors=flight_dict_from(interceptors))
|
||||
|
||||
self.operation = op
|
||||
|
||||
@ -120,7 +120,7 @@ class Game:
|
||||
if not Conflict.has_frontline_between(player_cp, enemy_cp):
|
||||
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:
|
||||
pass
|
||||
else:
|
||||
@ -131,7 +131,7 @@ class Game:
|
||||
pass
|
||||
else:
|
||||
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:
|
||||
continue
|
||||
|
||||
|
||||
@ -9,13 +9,13 @@ from gen.triggergen import *
|
||||
from gen.airsupportgen import *
|
||||
from gen.visualgen import *
|
||||
|
||||
from .operation import Operation
|
||||
from .operation import *
|
||||
|
||||
|
||||
class BaseAttackOperation(Operation):
|
||||
cas = None # type: db.PlaneDict
|
||||
escort = None # type: db.PlaneDict
|
||||
intercept = None # type: db.PlaneDict
|
||||
cas = None # type: FlightDict
|
||||
escort = None # type: FlightDict
|
||||
intercept = None # type: FlightDict
|
||||
attack = None # type: db.ArmorDict
|
||||
defense = None # type: db.ArmorDict
|
||||
aa = None # type: db.AirDefenseDict
|
||||
@ -23,10 +23,10 @@ class BaseAttackOperation(Operation):
|
||||
trigger_radius = TRIGGER_RADIUS_SMALL
|
||||
|
||||
def setup(self,
|
||||
cas: db.PlaneDict,
|
||||
escort: db.PlaneDict,
|
||||
attack: db.ArmorDict,
|
||||
intercept: db.PlaneDict,
|
||||
cas: FlightDict,
|
||||
escort: FlightDict,
|
||||
attack: FlightDict,
|
||||
intercept: FlightDict,
|
||||
defense: db.ArmorDict,
|
||||
aa: db.AirDefenseDict):
|
||||
self.cas = cas
|
||||
@ -57,10 +57,10 @@ class BaseAttackOperation(Operation):
|
||||
self.armorgen.generate(self.attack, self.defense)
|
||||
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_attackers_escort(self.escort, 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(*flight_arguments(self.escort), at=self.attackers_starting_position)
|
||||
|
||||
self.visualgen.generate_target_smokes(self.to_cp)
|
||||
|
||||
|
||||
@ -12,21 +12,21 @@ from gen.airsupportgen import *
|
||||
from gen.visualgen import *
|
||||
from gen.conflictgen import Conflict
|
||||
|
||||
from .operation import Operation
|
||||
from .operation import *
|
||||
|
||||
|
||||
MAX_DISTANCE_BETWEEN_GROUPS = 12000
|
||||
|
||||
|
||||
class FrontlineAttackOperation(Operation):
|
||||
strikegroup = None # type: FlightDict
|
||||
attackers = None # type: db.ArmorDict
|
||||
strikegroup = None # type: db.PlaneDict
|
||||
target = None # type: db.ArmorDict
|
||||
|
||||
def setup(self,
|
||||
target: db.ArmorDict,
|
||||
attackers: db.ArmorDict,
|
||||
strikegroup: db.PlaneDict):
|
||||
strikegroup: FlightDict):
|
||||
self.strikegroup = strikegroup
|
||||
self.target = target
|
||||
self.attackers = attackers
|
||||
@ -50,7 +50,7 @@ class FrontlineAttackOperation(Operation):
|
||||
|
||||
def generate(self):
|
||||
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.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."
|
||||
|
||||
@ -12,21 +12,26 @@ from gen.airsupportgen import *
|
||||
from gen.visualgen import *
|
||||
from gen.conflictgen import Conflict
|
||||
|
||||
from .operation import Operation
|
||||
from .operation import *
|
||||
|
||||
|
||||
MAX_DISTANCE_BETWEEN_GROUPS = 12000
|
||||
|
||||
|
||||
class FrontlinePatrolOperation(Operation):
|
||||
cas = None # type: db.PlaneDict
|
||||
escort = None # type: db.PlaneDict
|
||||
interceptors = None # type: db.PlaneDict
|
||||
cas = None # type: FlightDict
|
||||
escort = None # type: FlightDict
|
||||
interceptors = None # type: FlightDict
|
||||
|
||||
armor_attackers = 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.escort = escort
|
||||
self.interceptors = interceptors
|
||||
@ -50,9 +55,9 @@ class FrontlinePatrolOperation(Operation):
|
||||
conflict=conflict)
|
||||
|
||||
def generate(self):
|
||||
self.airgen.generate_defenders_cas(self.cas, {}, self.defenders_starting_position)
|
||||
self.airgen.generate_defenders_escort(self.escort, {}, self.defenders_starting_position)
|
||||
self.airgen.generate_migcap(self.interceptors, self.attacker_clients, self.attackers_starting_position)
|
||||
self.airgen.generate_defenders_cas(*flight_arguments(self.cas), at=self.defenders_starting_position)
|
||||
self.airgen.generate_defenders_escort(*flight_arguments(self.escort), at=self.defenders_starting_position)
|
||||
self.airgen.generate_migcap(*flight_arguments(self.interceptors), at=self.attackers_starting_position)
|
||||
|
||||
self.armorgen.generate_vec(self.armor_attackers, self.armor_defenders)
|
||||
|
||||
|
||||
@ -10,14 +10,14 @@ from gen.airsupportgen import *
|
||||
from gen.visualgen import *
|
||||
from gen.conflictgen import Conflict
|
||||
|
||||
from .operation import Operation
|
||||
from .operation import *
|
||||
|
||||
|
||||
class InfantryTransportOperation(Operation):
|
||||
transport = None # type: db.HeliDict
|
||||
transport = None # type: FlightDict
|
||||
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.aa = aa
|
||||
|
||||
@ -36,11 +36,7 @@ class InfantryTransportOperation(Operation):
|
||||
conflict=conflict)
|
||||
|
||||
def generate(self):
|
||||
self.airgen.generate_passenger_transport(
|
||||
helis=self.transport,
|
||||
clients=self.attacker_clients,
|
||||
at=self.attackers_starting_position
|
||||
)
|
||||
self.airgen.generate_passenger_transport(*flight_arguments(self.transport), at=self.attackers_starting_position)
|
||||
|
||||
self.armorgen.generate_passengers(count=6)
|
||||
self.aagen.generate_at_defenders_location(self.aa)
|
||||
|
||||
@ -10,16 +10,16 @@ from gen.airsupportgen import *
|
||||
from gen.visualgen import *
|
||||
from gen.conflictgen import Conflict
|
||||
|
||||
from .operation import Operation
|
||||
from .operation import *
|
||||
|
||||
|
||||
class InsurgentAttackOperation(Operation):
|
||||
strikegroup = None # type: db.PlaneDict
|
||||
strikegroup = None # type: FlightDict
|
||||
target = None # type: db.ArmorDict
|
||||
|
||||
def setup(self,
|
||||
target: db.ArmorDict,
|
||||
strikegroup: db.PlaneDict):
|
||||
strikegroup: FlightDict):
|
||||
self.strikegroup = strikegroup
|
||||
self.target = target
|
||||
|
||||
@ -38,7 +38,7 @@ class InsurgentAttackOperation(Operation):
|
||||
conflict=conflict)
|
||||
|
||||
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.briefinggen.title = "Destroy insurgents"
|
||||
|
||||
@ -1,22 +1,22 @@
|
||||
from dcs.terrain import Terrain
|
||||
|
||||
from gen import *
|
||||
from .operation import Operation
|
||||
from .operation import *
|
||||
|
||||
|
||||
class InterceptOperation(Operation):
|
||||
escort = None # type: db.PlaneDict
|
||||
escort = None # type: FlightDict
|
||||
transport = None # type: db.PlaneDict
|
||||
interceptors = None # type: db.PlaneDict
|
||||
interceptors = None # type: FlightDict
|
||||
airdefense = None # type: db.AirDefenseDict
|
||||
|
||||
trigger_radius = TRIGGER_RADIUS_LARGE
|
||||
|
||||
def setup(self,
|
||||
escort: db.PlaneDict,
|
||||
escort: FlightDict,
|
||||
transport: db.PlaneDict,
|
||||
airdefense: db.AirDefenseDict,
|
||||
interceptors: db.PlaneDict):
|
||||
interceptors: FlightDict):
|
||||
self.escort = escort
|
||||
self.transport = transport
|
||||
self.airdefense = airdefense
|
||||
@ -52,9 +52,9 @@ class InterceptOperation(Operation):
|
||||
self.attackers_starting_position = ship
|
||||
|
||||
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.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"
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
from dcs.terrain import Terrain
|
||||
|
||||
from gen import *
|
||||
from .operation import Operation
|
||||
from .operation import *
|
||||
|
||||
|
||||
class NavalInterceptionOperation(Operation):
|
||||
strikegroup = None # type: db.PlaneDict
|
||||
interceptors = None # type: db.PlaneDict
|
||||
strikegroup = None # type: FlightDict
|
||||
interceptors = None # type: FlightDict
|
||||
targets = None # type: db.ShipDict
|
||||
trigger_radius = TRIGGER_RADIUS_LARGE
|
||||
|
||||
def setup(self,
|
||||
strikegroup: db.PlaneDict,
|
||||
interceptors: db.PlaneDict,
|
||||
strikegroup: FlightDict,
|
||||
interceptors: FlightDict,
|
||||
targets: db.ShipDict):
|
||||
self.strikegroup = strikegroup
|
||||
self.interceptors = interceptors
|
||||
@ -37,16 +37,14 @@ class NavalInterceptionOperation(Operation):
|
||||
target_groups = self.shipgen.generate_cargo(units=self.targets)
|
||||
|
||||
self.airgen.generate_ship_strikegroup(
|
||||
attackers=self.strikegroup,
|
||||
clients=self.attacker_clients,
|
||||
*flight_arguments(self.strikegroup),
|
||||
target_groups=target_groups,
|
||||
at=self.attackers_starting_position
|
||||
)
|
||||
|
||||
if self.interceptors:
|
||||
self.airgen.generate_defense(
|
||||
defenders=self.interceptors,
|
||||
clients=self.defender_clients,
|
||||
*flight_arguments(self.interceptors),
|
||||
at=self.defenders_starting_position
|
||||
)
|
||||
|
||||
|
||||
@ -1,11 +1,27 @@
|
||||
from dcs.terrain import Terrain
|
||||
import typing
|
||||
|
||||
from dcs.lua.parse import loads
|
||||
from dcs.unittype import UnitType
|
||||
|
||||
from userdata.debriefing import *
|
||||
|
||||
from theater import *
|
||||
from gen import *
|
||||
|
||||
FlightDict = typing.Dict[typing.Type[UnitType], typing.Tuple[int, int]]
|
||||
|
||||
|
||||
def flight_arguments(fd: FlightDict) -> typing.Tuple[db.PlaneDict, db.PlaneDict]:
|
||||
return {k: v1 for k, (v1, v2) in fd.items()}, {k: v2 for k, (v1, v2) in fd.items()},
|
||||
|
||||
|
||||
def flight_dict_from(d: db.PlaneDict) -> FlightDict:
|
||||
return {k: (v, 0) for k, v in d.items()}
|
||||
|
||||
|
||||
def dict_from_flight(fd: FlightDict) -> db.Dict:
|
||||
return {k: v1 for k, (v1, v2) in fd.items()}
|
||||
|
||||
|
||||
class Operation:
|
||||
attackers_starting_position = None # type: db.StartingPosition
|
||||
@ -33,15 +49,11 @@ class Operation:
|
||||
game,
|
||||
attacker_name: str,
|
||||
defender_name: str,
|
||||
attacker_clients: db.PlaneDict,
|
||||
defender_clients: db.PlaneDict,
|
||||
from_cp: ControlPoint,
|
||||
to_cp: ControlPoint = None):
|
||||
self.game = game
|
||||
self.attacker_name = attacker_name
|
||||
self.defender_name = defender_name
|
||||
self.attacker_clients = attacker_clients
|
||||
self.defender_clients = defender_clients
|
||||
self.from_cp = from_cp
|
||||
self.to_cp = to_cp
|
||||
self.is_quick = False
|
||||
|
||||
@ -10,18 +10,18 @@ from gen.airsupportgen import *
|
||||
from gen.visualgen import *
|
||||
from gen.conflictgen import Conflict
|
||||
|
||||
from .operation import Operation
|
||||
from .operation import *
|
||||
|
||||
|
||||
class StrikeOperation(Operation):
|
||||
strikegroup = None # type: db.PlaneDict
|
||||
escort = None # type: db.PlaneDict
|
||||
interceptors = None # type: db.PlaneDict
|
||||
strikegroup = None # type: FlightDict
|
||||
escort = None # type: FlightDict
|
||||
interceptors = None # type: FlightDict
|
||||
|
||||
def setup(self,
|
||||
strikegroup: db.PlaneDict,
|
||||
escort: db.PlaneDict,
|
||||
interceptors: db.PlaneDict):
|
||||
strikegroup: FlightDict,
|
||||
escort: FlightDict,
|
||||
interceptors: FlightDict):
|
||||
self.strikegroup = strikegroup
|
||||
self.escort = escort
|
||||
self.interceptors = interceptors
|
||||
@ -49,10 +49,10 @@ class StrikeOperation(Operation):
|
||||
category_counters = {} # type: typing.Dict[str, int]
|
||||
processed_groups = []
|
||||
for object in self.to_cp.ground_objects:
|
||||
if object.group_id in processed_groups:
|
||||
if object.group_identifier in processed_groups:
|
||||
continue
|
||||
|
||||
processed_groups.append(object.group_id)
|
||||
processed_groups.append(object.group_identifier)
|
||||
|
||||
category_counters[object.category] = category_counters.get(object.category, 0) + 1
|
||||
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]))
|
||||
|
||||
self.airgen.generate_ground_attack_strikegroup(strikegroup=self.strikegroup,
|
||||
self.airgen.generate_ground_attack_strikegroup(*flight_arguments(self.strikegroup),
|
||||
targets=targets,
|
||||
clients=self.attacker_clients,
|
||||
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.airgen.generate_barcap(patrol=self.interceptors,
|
||||
clients={},
|
||||
at=self.defenders_starting_position)
|
||||
self.airgen.generate_barcap(*flight_arguments(self.interceptors), at=self.defenders_starting_position)
|
||||
|
||||
self.briefinggen.title = "Strike"
|
||||
self.briefinggen.description = "Destroy infrastructure assets and military supplies in the region. Each building destroyed will lower targets strength."
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
class Settings:
|
||||
player_skill = "Good"
|
||||
enemy_skill = "Average"
|
||||
only_player_takeoff = False
|
||||
only_player_takeoff = True
|
||||
night_disabled = False
|
||||
multiplier = 1
|
||||
sams = True
|
||||
|
||||
@ -265,7 +265,7 @@ class AircraftConflictGenerator:
|
||||
self.escort_targets.append((group, group.points.index(waypoint)))
|
||||
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
|
||||
|
||||
for flying_type, count, client_count in self._split_to_groups(strikegroup, clients):
|
||||
|
||||
5
gen/heli.py
Normal file
5
gen/heli.py
Normal file
@ -0,0 +1,5 @@
|
||||
from .aircraft import *
|
||||
|
||||
|
||||
class HelicopterConflictGenerator(AircraftConflictGenerator):
|
||||
pass
|
||||
@ -41,6 +41,10 @@ class TheaterGroundObject:
|
||||
def string_identifier(self):
|
||||
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
|
||||
def name_abbrev(self) -> str:
|
||||
return ABBREV_NAME[self.category]
|
||||
|
||||
242
ui/eventmenu.py
242
ui/eventmenu.py
@ -7,27 +7,9 @@ from game.event import *
|
||||
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):
|
||||
aircraft_scramble_entries = None # type: typing.Dict[PlaneType , Entry]
|
||||
aircraft_client_entries = None # type: typing.Dict[PlaneType, Entry]
|
||||
armor_scramble_entries = None # type: typing.Dict[VehicleType, Entry]
|
||||
scramble_entries = None # type: typing.Dict[typing.Type[Task], typing.Dict[typing.Type[UnitType], typing.Tuple[Entry, Entry]]]
|
||||
|
||||
error_label = None # type: Label
|
||||
awacs = None # type: IntVar
|
||||
|
||||
@ -35,9 +17,7 @@ class EventMenu(Menu):
|
||||
super(EventMenu, self).__init__(window, parent, game)
|
||||
|
||||
self.event = event
|
||||
self.aircraft_scramble_entries = {}
|
||||
self.armor_scramble_entries = {}
|
||||
self.aircraft_client_entries = {}
|
||||
self.scramble_entries = {k: {} for k in self.event.tasks}
|
||||
|
||||
if self.event.attacker_name == self.game.player:
|
||||
self.base = self.event.from_cp.base
|
||||
@ -68,32 +48,24 @@ class EventMenu(Menu):
|
||||
|
||||
return new_label
|
||||
|
||||
def scrable_row(unit_type, unit_count):
|
||||
def scrable_row(task_type, unit_type, unit_count, client_slots: bool):
|
||||
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.grid(column=1, row=row, sticky=E, padx=5)
|
||||
scramble_entry.insert(0, "0")
|
||||
self.aircraft_scramble_entries[unit_type] = scramble_entry
|
||||
Button(self.frame, text="+", command=self.scramble_half(True, unit_type), **STYLES["btn-primary"]).grid(column=2, row=row)
|
||||
Button(self.frame, text="+", command=self.scramble_half(task_type, unit_type), **STYLES["btn-primary"]).grid(column=2, row=row)
|
||||
|
||||
client_entry = Entry(self.frame, width=2)
|
||||
client_entry.grid(column=3, row=row, sticky=E, padx=5)
|
||||
client_entry.insert(0, "0")
|
||||
self.aircraft_client_entries[unit_type] = client_entry
|
||||
Button(self.frame, text="+", command=self.client_one(unit_type), **STYLES["btn-primary"]).grid(column=4, row=row)
|
||||
if client_slots:
|
||||
client_entry = Entry(self.frame, width=2)
|
||||
client_entry.grid(column=3, row=row, sticky=E, padx=5)
|
||||
client_entry.insert(0, "0")
|
||||
Button(self.frame, text="+", command=self.client_one(task_type, unit_type), **STYLES["btn-primary"]).grid(column=4, row=row)
|
||||
else:
|
||||
client_entry = None
|
||||
|
||||
row += 1
|
||||
|
||||
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)
|
||||
self.scramble_entries[task_type][unit_type] = scramble_entry, client_entry
|
||||
|
||||
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)
|
||||
row += 1
|
||||
|
||||
header("Aircraft :")
|
||||
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)
|
||||
row += 1
|
||||
|
||||
if self.base.aircraft:
|
||||
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)
|
||||
row += 1
|
||||
for flight_task in self.event.tasks:
|
||||
header("{}:".format(self.event.flight_name(flight_task)))
|
||||
if flight_task == PinpointStrike:
|
||||
if not self.base.armor:
|
||||
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)
|
||||
|
||||
filter_attackers_index = 0 if self.game.is_player_attack(self.event) else 1
|
||||
filter_to = UNITTYPES_FOR_EVENTS[self.event.__class__][filter_attackers_index]
|
||||
for unit_type, count in self.base.aircraft.items():
|
||||
if filter_to and db.unit_task(unit_type) not in filter_to:
|
||||
continue
|
||||
|
||||
if unit_type in helicopter_map and self.event.__class__ != InsurgentAttackEvent:
|
||||
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 :")
|
||||
header("Support:")
|
||||
# Options
|
||||
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)
|
||||
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
|
||||
|
||||
header("Ready ?")
|
||||
header("Ready?")
|
||||
self.error_label = label("")
|
||||
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="Back", command=self.dismiss, **STYLES["btn-warning"]).grid(column=3, row=row, sticky=E, padx=5, pady=(10,10))
|
||||
row += 1
|
||||
|
||||
def _scrambled_aircraft_count(self, unit_type: UnitType) -> int:
|
||||
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 scramble_half(self, task: typing.Type[UnitType], unit_type: UnitType) -> typing.Callable:
|
||||
def action():
|
||||
entry = None # type: Entry
|
||||
total_count = 0
|
||||
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]
|
||||
entry = self.scramble_entries[task][unit_type][0] # type: Entry
|
||||
value = entry.get()
|
||||
|
||||
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.insert(0, "{}".format(int(existing_count + math.ceil(total_count/2))))
|
||||
entry.insert(0, str(amount + int(math.ceil(total_units/2))))
|
||||
|
||||
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():
|
||||
entry = self.aircraft_client_entries[unit_type] # type: Entry
|
||||
entry = self.scramble_entries[task][unit_type][1] # type: Entry
|
||||
value = entry.get()
|
||||
amount = int(value and value or "0")
|
||||
entry.delete(0, END)
|
||||
@ -199,94 +140,37 @@ class EventMenu(Menu):
|
||||
else:
|
||||
self.event.is_awacs_enabled = False
|
||||
|
||||
scrambled_aircraft = {}
|
||||
scrambled_sweep = {}
|
||||
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)
|
||||
flights = {k: {} for k in self.event.tasks} # type: ScrambledFlightsDict
|
||||
total_counts_scrambled = {} # type: typing.Dict[typing.Type[UnitType], int]
|
||||
|
||||
scrambled_aircraft[unit_type] = amount
|
||||
if task == CAS:
|
||||
scrambled_cas[unit_type] = amount
|
||||
elif task == CAP:
|
||||
scrambled_sweep[unit_type] = amount
|
||||
def dampen_count(unit_type: typing.Type[UnitType], count: int) -> int:
|
||||
nonlocal total_counts_scrambled
|
||||
total_count = self.base.total_units_of_type(unit_type)
|
||||
|
||||
scrambled_clients = {}
|
||||
for unit_type, field in self.aircraft_client_entries.items():
|
||||
value = field.get()
|
||||
if value and int(value) > 0:
|
||||
amount = int(value)
|
||||
scrambled_clients[unit_type] = amount
|
||||
total_scrambled = total_counts_scrambled.get(unit_type, 0)
|
||||
dampened_value = count if count + total_scrambled < total_count else total_count - total_scrambled
|
||||
total_counts_scrambled[unit_type] = total_counts_scrambled.get(unit_type, 0) + dampened_value
|
||||
return dampened_value
|
||||
|
||||
scrambled_armor = {}
|
||||
for unit_type, field in self.armor_scramble_entries.items():
|
||||
amount = self._scrambled_armor_count(unit_type)
|
||||
if amount > 0:
|
||||
scrambled_armor[unit_type] = amount
|
||||
for task_type, dict in self.scramble_entries.items():
|
||||
for unit_type, (count_entry, clients_entry) in dict.items():
|
||||
try:
|
||||
count = int(count_entry.get())
|
||||
except:
|
||||
count = 0
|
||||
|
||||
if type(self.event) in AI_BAN_FOR_EVENTS:
|
||||
banned_tasks_for_ai = AI_BAN_FOR_EVENTS[type(self.event)]
|
||||
for task in banned_tasks_for_ai:
|
||||
scrambled_slots = [1 for x in scrambled_aircraft if db.unit_task(x) == task]
|
||||
scrambled_client_slots = [1 for x in scrambled_clients if db.unit_task(x) == task]
|
||||
try:
|
||||
clients_count = int(clients_entry and clients_entry.get() or 0)
|
||||
except:
|
||||
clients_count = 0
|
||||
|
||||
if scrambled_slots != scrambled_client_slots:
|
||||
self.error_label["text"] = "AI slots of task {} are not supported for this operation".format(task.name)
|
||||
return
|
||||
flights[task_type][unit_type] = dampen_count(unit_type, count), clients_count
|
||||
|
||||
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):
|
||||
e.player_attacking(strikegroup=scrambled_aircraft, clients=scrambled_clients)
|
||||
else:
|
||||
e.player_defending(interceptors=scrambled_aircraft, clients=scrambled_clients)
|
||||
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
|
||||
if self.game.is_player_attack(self.event):
|
||||
self.event.player_attacking(flights)
|
||||
else:
|
||||
self.event.player_defending(flights)
|
||||
|
||||
self.game.initiate_event(self.event)
|
||||
EventResultsMenu(self.window, self.parent, self.game, self.event).display()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user