mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
fixes to frontline attack; frontline CAP WIP
This commit is contained in:
parent
820820eb92
commit
932bec2f84
15
game/db.py
15
game/db.py
@ -73,6 +73,8 @@ PRICES = {
|
|||||||
An_30M: 13,
|
An_30M: 13,
|
||||||
Yak_40: 13,
|
Yak_40: 13,
|
||||||
S_3B_Tanker: 13,
|
S_3B_Tanker: 13,
|
||||||
|
IL_78M: 13,
|
||||||
|
KC_135: 13,
|
||||||
|
|
||||||
A_50: 8,
|
A_50: 8,
|
||||||
E_3A: 8,
|
E_3A: 8,
|
||||||
@ -167,6 +169,11 @@ UNIT_BY_TASK = {
|
|||||||
C_130,
|
C_130,
|
||||||
],
|
],
|
||||||
|
|
||||||
|
Refueling: [
|
||||||
|
IL_78M,
|
||||||
|
KC_135,
|
||||||
|
],
|
||||||
|
|
||||||
AWACS: [E_3A, A_50, ],
|
AWACS: [E_3A, A_50, ],
|
||||||
|
|
||||||
PinpointStrike: [Armor.MBT_T_90, Armor.MBT_T_80U, Armor.MBT_T_55, Armor.MBT_M1A2_Abrams, Armor.MBT_M60A3_Patton, Armor.ATGM_M1134_Stryker, Armor.APC_BTR_80, ],
|
PinpointStrike: [Armor.MBT_T_90, Armor.MBT_T_80U, Armor.MBT_T_55, Armor.MBT_M1A2_Abrams, Armor.MBT_M60A3_Patton, Armor.ATGM_M1134_Stryker, Armor.APC_BTR_80, ],
|
||||||
@ -251,6 +258,7 @@ UNIT_BY_COUNTRY = {
|
|||||||
L_39ZA,
|
L_39ZA,
|
||||||
|
|
||||||
IL_76MD,
|
IL_76MD,
|
||||||
|
IL_78M,
|
||||||
An_26B,
|
An_26B,
|
||||||
An_30M,
|
An_30M,
|
||||||
Yak_40,
|
Yak_40,
|
||||||
@ -290,6 +298,7 @@ UNIT_BY_COUNTRY = {
|
|||||||
A_10C,
|
A_10C,
|
||||||
AV8BNA,
|
AV8BNA,
|
||||||
|
|
||||||
|
KC_135,
|
||||||
S_3B_Tanker,
|
S_3B_Tanker,
|
||||||
C_130,
|
C_130,
|
||||||
E_3A,
|
E_3A,
|
||||||
@ -450,7 +459,11 @@ def unitdict_split(unit_dict: UnitsDict, count: int):
|
|||||||
|
|
||||||
|
|
||||||
def unitdict_restrict_count(unit_dict: UnitsDict, total_count: int) -> UnitsDict:
|
def unitdict_restrict_count(unit_dict: UnitsDict, total_count: int) -> UnitsDict:
|
||||||
return list(unitdict_split(unit_dict, total_count))[0]
|
groups = list(unitdict_split(unit_dict, total_count))
|
||||||
|
if len(groups) > 0:
|
||||||
|
return groups[0]
|
||||||
|
else:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
def _validate_db():
|
def _validate_db():
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
from .event import *
|
from .event import *
|
||||||
from .frontlineattack import *
|
from .frontlineattack import *
|
||||||
|
from .frontlinepatrol import *
|
||||||
from .intercept import *
|
from .intercept import *
|
||||||
from .baseattack import *
|
from .baseattack import *
|
||||||
from .navalintercept import *
|
from .navalintercept import *
|
||||||
|
|||||||
@ -16,7 +16,7 @@ class BaseAttackEvent(Event):
|
|||||||
STRENGTH_RECOVERY = 0.55
|
STRENGTH_RECOVERY = 0.55
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "Attack from {} to {}".format(self.from_cp, self.to_cp)
|
return "Base attack from {} to {}".format(self.from_cp, self.to_cp)
|
||||||
|
|
||||||
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])
|
||||||
|
|||||||
@ -16,7 +16,7 @@ class FrontlineAttackEvent(Event):
|
|||||||
ATTACKER_AMOUNT_FACTOR = 0.4
|
ATTACKER_AMOUNT_FACTOR = 0.4
|
||||||
ATTACKER_DEFENDER_FACTOR = 0.7
|
ATTACKER_DEFENDER_FACTOR = 0.7
|
||||||
STRENGTH_INFLUENCE = 0.3
|
STRENGTH_INFLUENCE = 0.3
|
||||||
SUCCESS_MIN_TARGETS = 3
|
SUCCESS_TARGETS_HIT_PERCENTAGE = 0.25
|
||||||
|
|
||||||
defenders = None # type: db.ArmorDict
|
defenders = None # type: db.ArmorDict
|
||||||
|
|
||||||
@ -35,9 +35,9 @@ class FrontlineAttackEvent(Event):
|
|||||||
destroyed_targets += count
|
destroyed_targets += count
|
||||||
|
|
||||||
if self.from_cp.captured:
|
if self.from_cp.captured:
|
||||||
return float(destroyed_targets) >= min(self.SUCCESS_MIN_TARGETS, total_targets)
|
return float(destroyed_targets) / total_targets >= self.SUCCESS_TARGETS_HIT_PERCENTAGE
|
||||||
else:
|
else:
|
||||||
return float(destroyed_targets) < min(self.SUCCESS_MIN_TARGETS, total_targets)
|
return float(destroyed_targets) / total_targets < self.SUCCESS_TARGETS_HIT_PERCENTAGE
|
||||||
|
|
||||||
def commit(self, debriefing: Debriefing):
|
def commit(self, debriefing: Debriefing):
|
||||||
super(FrontlineAttackEvent, self).commit(debriefing)
|
super(FrontlineAttackEvent, self).commit(debriefing)
|
||||||
|
|||||||
72
game/event/frontlinepatrol.py
Normal file
72
game/event/frontlinepatrol.py
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import math
|
||||||
|
import random
|
||||||
|
|
||||||
|
from dcs.task import *
|
||||||
|
from dcs.vehicles import AirDefence
|
||||||
|
|
||||||
|
from game import *
|
||||||
|
from game.event import *
|
||||||
|
from game.operation.frontlinepatrol import FrontlinePatrolOperation
|
||||||
|
from userdata.debriefing import Debriefing
|
||||||
|
|
||||||
|
|
||||||
|
class FrontlinePatrolEvent(Event):
|
||||||
|
ESCORT_FACTOR = 0.5
|
||||||
|
STRENGTH_INFLUENCE = 0.3
|
||||||
|
SUCCESS_TARGETS_HIT_PERCENTAGE = 0.6
|
||||||
|
|
||||||
|
cas = None # type: db.PlaneDict
|
||||||
|
escort = None # type: db.PlaneDict
|
||||||
|
|
||||||
|
@property
|
||||||
|
def threat_description(self):
|
||||||
|
return "{} aircraft + ? CAS".format(self.to_cp.base.scramble_count(self.game.settings.multiplier * self.ESCORT_FACTOR, CAP))
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "Frontline CAP from {} at {}".format(self.from_cp, self.to_cp)
|
||||||
|
|
||||||
|
def is_successfull(self, debriefing: Debriefing):
|
||||||
|
total_targets = sum(self.cas.values())
|
||||||
|
destroyed_targets = 0
|
||||||
|
for unit, count in debriefing.destroyed_units[self.defender_name].items():
|
||||||
|
if unit in self.cas:
|
||||||
|
destroyed_targets += count
|
||||||
|
|
||||||
|
if self.from_cp.captured:
|
||||||
|
return float(destroyed_targets) / total_targets >= self.SUCCESS_TARGETS_HIT_PERCENTAGE
|
||||||
|
else:
|
||||||
|
return float(destroyed_targets) / total_targets < self.SUCCESS_TARGETS_HIT_PERCENTAGE
|
||||||
|
|
||||||
|
def commit(self, debriefing: Debriefing):
|
||||||
|
super(FrontlinePatrolEvent, self).commit(debriefing)
|
||||||
|
|
||||||
|
if self.from_cp.captured:
|
||||||
|
if self.is_successfull(debriefing):
|
||||||
|
self.to_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
||||||
|
else:
|
||||||
|
self.to_cp.base.affect_strength(+self.STRENGTH_INFLUENCE)
|
||||||
|
else:
|
||||||
|
if self.is_successfull(debriefing):
|
||||||
|
self.from_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
||||||
|
else:
|
||||||
|
self.to_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
||||||
|
|
||||||
|
def skip(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def player_attacking(self, interceptors: db.PlaneDict, clients: db.PlaneDict):
|
||||||
|
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={},
|
||||||
|
defender_clients=clients,
|
||||||
|
from_cp=self.from_cp,
|
||||||
|
to_cp=self.to_cp)
|
||||||
|
op.setup(cas=self.cas,
|
||||||
|
escort=self.escort,
|
||||||
|
interceptors=interceptors)
|
||||||
|
|
||||||
|
self.operation = op
|
||||||
18
game/game.py
18
game/game.py
@ -5,6 +5,7 @@ import math
|
|||||||
from dcs.task import *
|
from dcs.task import *
|
||||||
from dcs.vehicles import *
|
from dcs.vehicles import *
|
||||||
|
|
||||||
|
from gen.conflictgen import Conflict
|
||||||
from userdata.debriefing import Debriefing
|
from userdata.debriefing import Debriefing
|
||||||
from theater import *
|
from theater import *
|
||||||
|
|
||||||
@ -23,7 +24,7 @@ COMMISION_LIMITS_FACTORS = {
|
|||||||
|
|
||||||
COMMISION_AMOUNTS_SCALE = 1.5
|
COMMISION_AMOUNTS_SCALE = 1.5
|
||||||
COMMISION_AMOUNTS_FACTORS = {
|
COMMISION_AMOUNTS_FACTORS = {
|
||||||
PinpointStrike: 2,
|
PinpointStrike: 6,
|
||||||
CAS: 1,
|
CAS: 1,
|
||||||
CAP: 2,
|
CAP: 2,
|
||||||
AirDefence: 0.3,
|
AirDefence: 0.3,
|
||||||
@ -31,6 +32,7 @@ COMMISION_AMOUNTS_FACTORS = {
|
|||||||
|
|
||||||
PLAYER_INTERCEPT_GLOBAL_PROBABILITY_BASE = 25
|
PLAYER_INTERCEPT_GLOBAL_PROBABILITY_BASE = 25
|
||||||
PLAYER_INTERCEPT_GLOBAL_PROBABILITY_LOG = 2
|
PLAYER_INTERCEPT_GLOBAL_PROBABILITY_LOG = 2
|
||||||
|
PLAYER_BASEATTACK_THRESHOLD = 0.2
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Various events probabilities. First key is player probabilty, second is enemy probability.
|
Various events probabilities. First key is player probabilty, second is enemy probability.
|
||||||
@ -47,8 +49,9 @@ Events:
|
|||||||
"""
|
"""
|
||||||
EVENT_PROBABILITIES = {
|
EVENT_PROBABILITIES = {
|
||||||
BaseAttackEvent: [100, 10],
|
BaseAttackEvent: [100, 10],
|
||||||
InterceptEvent: [25, 10],
|
|
||||||
FrontlineAttackEvent: [100, 0],
|
FrontlineAttackEvent: [100, 0],
|
||||||
|
FrontlinePatrolEvent: [1000, 0],
|
||||||
|
InterceptEvent: [25, 10],
|
||||||
InsurgentAttackEvent: [0, 10],
|
InsurgentAttackEvent: [0, 10],
|
||||||
NavalInterceptEvent: [25, 10],
|
NavalInterceptEvent: [25, 10],
|
||||||
AntiAAStrikeEvent: [25, 10],
|
AntiAAStrikeEvent: [25, 10],
|
||||||
@ -65,7 +68,7 @@ ENEMY_BASE_STRENGTH_RECOVERY = 0.05
|
|||||||
AWACS_BUDGET_COST = 4
|
AWACS_BUDGET_COST = 4
|
||||||
|
|
||||||
# Initial budget value
|
# Initial budget value
|
||||||
PLAYER_BUDGET_INITIAL = 120
|
PLAYER_BUDGET_INITIAL = 170
|
||||||
# Base post-turn bonus value
|
# Base post-turn bonus value
|
||||||
PLAYER_BUDGET_BASE = 10
|
PLAYER_BUDGET_BASE = 10
|
||||||
# Bonus multiplier logarithm base
|
# Bonus multiplier logarithm base
|
||||||
@ -112,11 +115,18 @@ class Game:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
for event_class, (player_probability, enemy_probability) in EVENT_PROBABILITIES.items():
|
for event_class, (player_probability, enemy_probability) in EVENT_PROBABILITIES.items():
|
||||||
|
if event_class == FrontlineAttackEvent or event_class == InfantryTransportEvent or event_class == FrontlinePatrolEvent:
|
||||||
|
if not Conflict.has_frontline_between(player_cp, enemy_cp):
|
||||||
|
continue
|
||||||
|
|
||||||
if self._roll(player_probability, player_cp.base.strength):
|
if 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:
|
||||||
self.events.append(event_class(self.player, self.enemy, player_cp, enemy_cp, self))
|
if event_class == BaseAttackEvent and enemy_cp.base.strength > PLAYER_BASEATTACK_THRESHOLD:
|
||||||
|
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 self._roll(enemy_probability, enemy_cp.base.strength):
|
||||||
if event_class in enemy_generated_types:
|
if event_class in enemy_generated_types:
|
||||||
continue
|
continue
|
||||||
|
|||||||
@ -6,7 +6,7 @@ from gen.aircraft import *
|
|||||||
from gen.aaa import *
|
from gen.aaa import *
|
||||||
from gen.shipgen import *
|
from gen.shipgen import *
|
||||||
from gen.triggergen import *
|
from gen.triggergen import *
|
||||||
from gen.awacsgen import *
|
from gen.airsupportgen import *
|
||||||
from gen.visualgen import *
|
from gen.visualgen import *
|
||||||
from gen.conflictgen import Conflict
|
from gen.conflictgen import Conflict
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@ from gen.aircraft import *
|
|||||||
from gen.aaa import *
|
from gen.aaa import *
|
||||||
from gen.shipgen import *
|
from gen.shipgen import *
|
||||||
from gen.triggergen import *
|
from gen.triggergen import *
|
||||||
from gen.awacsgen import *
|
from gen.airsupportgen import *
|
||||||
from gen.visualgen import *
|
from gen.visualgen import *
|
||||||
|
|
||||||
from .operation import Operation
|
from .operation import Operation
|
||||||
@ -60,7 +60,7 @@ class BaseAttackOperation(Operation):
|
|||||||
self.airgen.generate_defense(self.intercept, clients=self.defender_clients, at=self.defenders_starting_position)
|
self.airgen.generate_defense(self.intercept, clients=self.defender_clients, 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(self.cas, clients=self.attacker_clients, at=self.attackers_starting_position)
|
||||||
self.airgen.generate_strikegroup_escort(self.escort, 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.visualgen.generate_target_smokes(self.to_cp)
|
self.visualgen.generate_target_smokes(self.to_cp)
|
||||||
super(BaseAttackOperation, self).generate()
|
super(BaseAttackOperation, self).generate()
|
||||||
|
|||||||
@ -8,7 +8,7 @@ from gen.aircraft import *
|
|||||||
from gen.aaa import *
|
from gen.aaa import *
|
||||||
from gen.shipgen import *
|
from gen.shipgen import *
|
||||||
from gen.triggergen import *
|
from gen.triggergen import *
|
||||||
from gen.awacsgen import *
|
from gen.airsupportgen import *
|
||||||
from gen.visualgen import *
|
from gen.visualgen import *
|
||||||
from gen.conflictgen import Conflict
|
from gen.conflictgen import Conflict
|
||||||
|
|
||||||
|
|||||||
53
game/operation/frontlinepatrol.py
Normal file
53
game/operation/frontlinepatrol.py
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
from itertools import zip_longest
|
||||||
|
|
||||||
|
from dcs.terrain import Terrain
|
||||||
|
|
||||||
|
from game import db
|
||||||
|
from gen.armor import *
|
||||||
|
from gen.aircraft import *
|
||||||
|
from gen.aaa import *
|
||||||
|
from gen.shipgen import *
|
||||||
|
from gen.triggergen import *
|
||||||
|
from gen.airsupportgen import *
|
||||||
|
from gen.visualgen import *
|
||||||
|
from gen.conflictgen import Conflict
|
||||||
|
|
||||||
|
from .operation import Operation
|
||||||
|
|
||||||
|
|
||||||
|
MAX_DISTANCE_BETWEEN_GROUPS = 12000
|
||||||
|
|
||||||
|
|
||||||
|
class FrontlinePatrolOperation(Operation):
|
||||||
|
cas = None # type: db.PlaneDict
|
||||||
|
escort = None # type: db.PlaneDict
|
||||||
|
interceptors = None # type: db.PlaneDict
|
||||||
|
|
||||||
|
def setup(self, cas: db.PlaneDict, escort: db.PlaneDict, interceptors: db.PlaneDict):
|
||||||
|
self.cas = cas
|
||||||
|
self.escort = escort
|
||||||
|
self.interceptors = interceptors
|
||||||
|
|
||||||
|
def prepare(self, terrain: Terrain, is_quick: bool):
|
||||||
|
super(FrontlinePatrolOperation, self).prepare(terrain, is_quick)
|
||||||
|
self.defenders_starting_position = None
|
||||||
|
|
||||||
|
conflict = Conflict.frontline_cap_conflict(
|
||||||
|
attacker=self.mission.country(self.attacker_name),
|
||||||
|
defender=self.mission.country(self.defender_name),
|
||||||
|
from_cp=self.from_cp,
|
||||||
|
to_cp=self.to_cp,
|
||||||
|
theater=self.game.theater
|
||||||
|
)
|
||||||
|
|
||||||
|
self.initialize(mission=self.mission,
|
||||||
|
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_patrol(self.interceptors, self.defender_clients, self.attackers_starting_position)
|
||||||
|
|
||||||
|
# todo: generate armor
|
||||||
|
|
||||||
|
super(FrontlinePatrolOperation, self).generate()
|
||||||
@ -6,7 +6,7 @@ from gen.aircraft import *
|
|||||||
from gen.aaa import *
|
from gen.aaa import *
|
||||||
from gen.shipgen import *
|
from gen.shipgen import *
|
||||||
from gen.triggergen import *
|
from gen.triggergen import *
|
||||||
from gen.awacsgen import *
|
from gen.airsupportgen import *
|
||||||
from gen.visualgen import *
|
from gen.visualgen import *
|
||||||
from gen.conflictgen import Conflict
|
from gen.conflictgen import Conflict
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@ from gen.aircraft import *
|
|||||||
from gen.aaa import *
|
from gen.aaa import *
|
||||||
from gen.shipgen import *
|
from gen.shipgen import *
|
||||||
from gen.triggergen import *
|
from gen.triggergen import *
|
||||||
from gen.awacsgen import *
|
from gen.airsupportgen import *
|
||||||
from gen.visualgen import *
|
from gen.visualgen import *
|
||||||
from gen.conflictgen import Conflict
|
from gen.conflictgen import Conflict
|
||||||
|
|
||||||
|
|||||||
@ -52,7 +52,7 @@ 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_transport_escort(self.escort, clients=self.defender_clients)
|
self.airgen.generate_defenders_escort(self.escort, clients=self.defender_clients)
|
||||||
|
|
||||||
self.airgen.generate_interception(self.interceptors, clients=self.attacker_clients, at=self.attackers_starting_position)
|
self.airgen.generate_interception(self.interceptors, clients=self.attacker_clients, at=self.attackers_starting_position)
|
||||||
super(InterceptOperation, self).generate()
|
super(InterceptOperation, self).generate()
|
||||||
|
|||||||
@ -18,7 +18,7 @@ class Operation:
|
|||||||
extra_aagen = None # type: ExtraAAConflictGenerator
|
extra_aagen = None # type: ExtraAAConflictGenerator
|
||||||
shipgen = None # type: ShipGenerator
|
shipgen = None # type: ShipGenerator
|
||||||
triggersgen = None # type: TriggersGenerator
|
triggersgen = None # type: TriggersGenerator
|
||||||
awacsgen = None # type: AWACSConflictGenerator
|
awacsgen = None # type: AirSupportConflictGenerator
|
||||||
visualgen = None # type: VisualGenerator
|
visualgen = None # type: VisualGenerator
|
||||||
envgen = None # type: EnvironmentGenerator
|
envgen = None # type: EnvironmentGenerator
|
||||||
|
|
||||||
@ -52,7 +52,7 @@ class Operation:
|
|||||||
self.airgen = AircraftConflictGenerator(mission, conflict, self.game.settings)
|
self.airgen = AircraftConflictGenerator(mission, conflict, self.game.settings)
|
||||||
self.aagen = AAConflictGenerator(mission, conflict)
|
self.aagen = AAConflictGenerator(mission, conflict)
|
||||||
self.shipgen = ShipGenerator(mission, conflict)
|
self.shipgen = ShipGenerator(mission, conflict)
|
||||||
self.awacsgen = AWACSConflictGenerator(mission, conflict, self.game)
|
self.awacsgen = AirSupportConflictGenerator(mission, conflict, self.game)
|
||||||
self.triggersgen = TriggersGenerator(mission, conflict, self.game)
|
self.triggersgen = TriggersGenerator(mission, conflict, self.game)
|
||||||
self.visualgen = VisualGenerator(mission, conflict, self.game)
|
self.visualgen = VisualGenerator(mission, conflict, self.game)
|
||||||
self.envgen = EnviromentGenerator(mission, conflict, self.game)
|
self.envgen = EnviromentGenerator(mission, conflict, self.game)
|
||||||
@ -78,9 +78,7 @@ class Operation:
|
|||||||
|
|
||||||
def generate(self):
|
def generate(self):
|
||||||
self.visualgen.generate()
|
self.visualgen.generate()
|
||||||
|
self.awacsgen.generate(self.is_awacs_enabled)
|
||||||
if self.is_awacs_enabled:
|
|
||||||
self.awacsgen.generate()
|
|
||||||
|
|
||||||
self.extra_aagen.generate()
|
self.extra_aagen.generate()
|
||||||
self.triggersgen.generate(self.is_quick, self.trigger_radius)
|
self.triggersgen.generate(self.is_quick, self.trigger_radius)
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
from .aaa import *
|
from .aaa import *
|
||||||
from .aircraft import *
|
from .aircraft import *
|
||||||
from .armor import *
|
from .armor import *
|
||||||
from .awacsgen import *
|
from .airsupportgen import *
|
||||||
from .conflictgen import *
|
from .conflictgen import *
|
||||||
from .shipgen import *
|
from .shipgen import *
|
||||||
from .visualgen import *
|
from .visualgen import *
|
||||||
|
|||||||
@ -243,13 +243,35 @@ class AircraftConflictGenerator:
|
|||||||
|
|
||||||
waypoint = group.add_waypoint(self.conflict.position, CAS_ALTITUDE, WARM_START_AIRSPEED)
|
waypoint = group.add_waypoint(self.conflict.position, CAS_ALTITUDE, WARM_START_AIRSPEED)
|
||||||
if self.conflict.is_vector:
|
if self.conflict.is_vector:
|
||||||
group.add_waypoint(self.conflict.tail, CAS_ALTITUDE, WARM_START_ALTITUDE)
|
group.add_waypoint(self.conflict.tail, CAS_ALTITUDE, WARM_START_AIRSPEED)
|
||||||
|
|
||||||
group.task = CAS.name
|
group.task = CAS.name
|
||||||
self._setup_group(group, CAS, client_count)
|
self._setup_group(group, CAS, client_count)
|
||||||
self.escort_targets.append((group, group.points.index(waypoint)))
|
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_defenders_cas(self, defenders: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None):
|
||||||
|
assert len(self.escort_targets) == 0
|
||||||
|
|
||||||
|
for flying_type, count, client_count in self._split_to_groups(defenders, clients):
|
||||||
|
group = self._generate_group(
|
||||||
|
name=namegen.next_unit_name(self.conflict.defenders_side, flying_type),
|
||||||
|
side=self.conflict.defenders_side,
|
||||||
|
unit_type=flying_type,
|
||||||
|
count=count,
|
||||||
|
client_count=client_count,
|
||||||
|
at=at and at or self._group_point(self.conflict.air_defenders_location))
|
||||||
|
|
||||||
|
pos = self.conflict.air_defenders_location.point_from_heading(self.conflict.heading-90, CAP_CAS_DISTANCE)
|
||||||
|
waypoint = group.add_waypoint(pos, CAS_ALTITUDE, WARM_START_AIRSPEED)
|
||||||
|
if self.conflict.is_vector:
|
||||||
|
group.add_waypoint(self.conflict.tail, CAS_ALTITUDE, WARM_START_AIRSPEED)
|
||||||
|
|
||||||
|
group.task = CAS.name
|
||||||
|
self._setup_group(group, CAS, client_count)
|
||||||
|
self.escort_targets.append((group, group.points.index(waypoint)))
|
||||||
|
self._rtb_for(group, self.conflict.to_cp, at)
|
||||||
|
|
||||||
def generate_ship_strikegroup(self, attackers: db.PlaneDict, clients: db.PlaneDict, target_groups: typing.Collection[ShipGroup], at: db.StartingPosition = None):
|
def generate_ship_strikegroup(self, attackers: db.PlaneDict, clients: db.PlaneDict, target_groups: typing.Collection[ShipGroup], at: db.StartingPosition = None):
|
||||||
assert len(self.escort_targets) == 0
|
assert len(self.escort_targets) == 0
|
||||||
|
|
||||||
@ -271,7 +293,7 @@ class AircraftConflictGenerator:
|
|||||||
self.escort_targets.append((group, group.points.index(wayp)))
|
self.escort_targets.append((group, group.points.index(wayp)))
|
||||||
self._rtb_for(group, self.conflict.from_cp, at)
|
self._rtb_for(group, self.conflict.from_cp, at)
|
||||||
|
|
||||||
def generate_strikegroup_escort(self, attackers: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None):
|
def generate_attackers_escort(self, attackers: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None):
|
||||||
for g in self._generate_escort(
|
for g in self._generate_escort(
|
||||||
side=self.conflict.attackers_side,
|
side=self.conflict.attackers_side,
|
||||||
units=attackers,
|
units=attackers,
|
||||||
@ -281,7 +303,7 @@ class AircraftConflictGenerator:
|
|||||||
should_orbit=True):
|
should_orbit=True):
|
||||||
self._rtb_for(g, self.conflict.from_cp, at)
|
self._rtb_for(g, self.conflict.from_cp, at)
|
||||||
|
|
||||||
def generate_transport_escort(self, escort: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None):
|
def generate_defenders_escort(self, escort: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None):
|
||||||
for g in self._generate_escort(
|
for g in self._generate_escort(
|
||||||
side=self.conflict.defenders_side,
|
side=self.conflict.defenders_side,
|
||||||
units=escort,
|
units=escort,
|
||||||
@ -308,6 +330,24 @@ class AircraftConflictGenerator:
|
|||||||
self._setup_group(group, CAP, client_count)
|
self._setup_group(group, CAP, client_count)
|
||||||
self._rtb_for(group, self.conflict.to_cp, at)
|
self._rtb_for(group, self.conflict.to_cp, at)
|
||||||
|
|
||||||
|
def generate_patrol(self, patrol: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None):
|
||||||
|
for flying_type, count, client_count in self._split_to_groups(patrol, clients):
|
||||||
|
group = self._generate_group(
|
||||||
|
name=namegen.next_unit_name(self.conflict.attackers_side, flying_type),
|
||||||
|
side=self.conflict.attackers_side,
|
||||||
|
unit_type=flying_type,
|
||||||
|
count=count,
|
||||||
|
client_count=client_count,
|
||||||
|
at=at and at or self._group_point(self.conflict.air_attackers_location))
|
||||||
|
|
||||||
|
waypoint = group.add_waypoint(self.conflict.position, WARM_START_ALTITUDE, WARM_START_AIRSPEED)
|
||||||
|
if self.conflict.is_vector:
|
||||||
|
group.add_waypoint(self.conflict.tail, WARM_START_ALTITUDE, WARM_START_AIRSPEED)
|
||||||
|
|
||||||
|
group.task = CAP.name
|
||||||
|
self._setup_group(group, CAP, client_count)
|
||||||
|
self._rtb_for(group, self.conflict.from_cp, at)
|
||||||
|
|
||||||
def generate_transport(self, transport: db.PlaneDict, destination: Airport):
|
def generate_transport(self, transport: db.PlaneDict, destination: Airport):
|
||||||
assert len(self.escort_targets) == 0
|
assert len(self.escort_targets) == 0
|
||||||
|
|
||||||
|
|||||||
50
gen/airsupportgen.py
Normal file
50
gen/airsupportgen.py
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
from game import db
|
||||||
|
from .conflictgen import *
|
||||||
|
from .naming import *
|
||||||
|
|
||||||
|
from dcs.mission import *
|
||||||
|
from dcs.unitgroup import *
|
||||||
|
from dcs.unittype import *
|
||||||
|
from dcs.task import *
|
||||||
|
from dcs.terrain.terrain import NoParkingSlotError
|
||||||
|
|
||||||
|
TANKER_DISTANCE = 15000
|
||||||
|
TANKER_ALT = 10000
|
||||||
|
|
||||||
|
AWACS_DISTANCE = 150000
|
||||||
|
AWACS_ALT = 10000
|
||||||
|
|
||||||
|
|
||||||
|
class AirSupportConflictGenerator:
|
||||||
|
def __init__(self, mission: Mission, conflict: Conflict, game):
|
||||||
|
self.mission = mission
|
||||||
|
self.conflict = conflict
|
||||||
|
self.game = game
|
||||||
|
|
||||||
|
def generate(self, is_awacs_enabled):
|
||||||
|
tanker_unit = db.find_unittype(Refueling, self.conflict.attackers_side.name)[0]
|
||||||
|
tanker_heading = self.conflict.to_cp.position.heading_between_point(self.conflict.from_cp.position)
|
||||||
|
tanker_position = self.conflict.from_cp.position.point_from_heading(tanker_heading, TANKER_DISTANCE)
|
||||||
|
self.mission.refuel_flight(
|
||||||
|
country=self.mission.country(self.game.player),
|
||||||
|
name=namegen.next_tanker_name(self.mission.country(self.game.player)),
|
||||||
|
airport=None,
|
||||||
|
plane_type=tanker_unit,
|
||||||
|
position=tanker_position,
|
||||||
|
altitude=TANKER_ALT,
|
||||||
|
frequency=140,
|
||||||
|
start_type=StartType.Warm,
|
||||||
|
)
|
||||||
|
|
||||||
|
if is_awacs_enabled:
|
||||||
|
awacs_unit = db.find_unittype(AWACS, self.conflict.attackers_side.name)[0]
|
||||||
|
self.mission.awacs_flight(
|
||||||
|
country=self.mission.country(self.game.player),
|
||||||
|
name=namegen.next_awacs_name(self.mission.country(self.game.player),),
|
||||||
|
plane_type=awacs_unit,
|
||||||
|
altitude=AWACS_ALT,
|
||||||
|
airport=None,
|
||||||
|
position=self.conflict.position.random_point_within(AWACS_DISTANCE, AWACS_DISTANCE),
|
||||||
|
frequency=251,
|
||||||
|
start_type=StartType.Warm,
|
||||||
|
)
|
||||||
@ -1,32 +0,0 @@
|
|||||||
from game import db
|
|
||||||
from .conflictgen import *
|
|
||||||
from .naming import *
|
|
||||||
|
|
||||||
from dcs.mission import *
|
|
||||||
from dcs.unitgroup import *
|
|
||||||
from dcs.unittype import *
|
|
||||||
from dcs.task import *
|
|
||||||
from dcs.terrain.terrain import NoParkingSlotError
|
|
||||||
|
|
||||||
AWACS_DISTANCE = 150000
|
|
||||||
AWACS_ALT = 10000
|
|
||||||
|
|
||||||
|
|
||||||
class AWACSConflictGenerator:
|
|
||||||
def __init__(self, mission: Mission, conflict: Conflict, game):
|
|
||||||
self.mission = mission
|
|
||||||
self.conflict = conflict
|
|
||||||
self.game = game
|
|
||||||
|
|
||||||
def generate(self):
|
|
||||||
plane = db.find_unittype(AWACS, self.conflict.attackers_side.name)[0]
|
|
||||||
|
|
||||||
self.mission.awacs_flight(
|
|
||||||
country=self.mission.country(self.game.player),
|
|
||||||
name=namegen.next_awacs_name(self.mission.country(self.game.player),),
|
|
||||||
plane_type=plane,
|
|
||||||
altitude=AWACS_ALT,
|
|
||||||
airport=None,
|
|
||||||
position=self.conflict.position.random_point_within(AWACS_DISTANCE, AWACS_DISTANCE),
|
|
||||||
frequency=251
|
|
||||||
)
|
|
||||||
@ -20,6 +20,7 @@ AIR_DISTANCE = 40000
|
|||||||
|
|
||||||
CAPTURE_AIR_ATTACKERS_DISTANCE = 25000
|
CAPTURE_AIR_ATTACKERS_DISTANCE = 25000
|
||||||
CAPTURE_AIR_DEFENDERS_DISTANCE = 60000
|
CAPTURE_AIR_DEFENDERS_DISTANCE = 60000
|
||||||
|
CAP_CAS_DISTANCE = 10000
|
||||||
|
|
||||||
GROUND_INTERCEPT_SPREAD = 5000
|
GROUND_INTERCEPT_SPREAD = 5000
|
||||||
GROUND_DISTANCE_FACTOR = 1
|
GROUND_DISTANCE_FACTOR = 1
|
||||||
@ -261,8 +262,11 @@ class Conflict:
|
|||||||
@classmethod
|
@classmethod
|
||||||
def frontline_cap_conflict(cls, attacker: Country, defender: Country, from_cp: ControlPoint, to_cp: ControlPoint, theater: ConflictTheater):
|
def frontline_cap_conflict(cls, attacker: Country, defender: Country, from_cp: ControlPoint, to_cp: ControlPoint, theater: ConflictTheater):
|
||||||
assert cls.has_frontline_between(from_cp, to_cp)
|
assert cls.has_frontline_between(from_cp, to_cp)
|
||||||
|
|
||||||
position, heading, distance = cls.frontline_vector(from_cp, to_cp, theater)
|
position, heading, distance = cls.frontline_vector(from_cp, to_cp, theater)
|
||||||
defenders_distance = random.randint(distance/3, distance)
|
attack_position = position.point_from_heading(heading, randint(0, int(distance)))
|
||||||
|
attackers_position = attack_position.point_from_heading(heading - 90, AIR_DISTANCE)
|
||||||
|
defenders_position = attack_position.point_from_heading(heading + 90, CAP_CAS_DISTANCE)
|
||||||
|
|
||||||
return cls(
|
return cls(
|
||||||
position=position,
|
position=position,
|
||||||
@ -273,10 +277,8 @@ class Conflict:
|
|||||||
to_cp=to_cp,
|
to_cp=to_cp,
|
||||||
attackers_side=attacker,
|
attackers_side=attacker,
|
||||||
defenders_side=defender,
|
defenders_side=defender,
|
||||||
ground_attackers_location=None,
|
air_attackers_location=attackers_position,
|
||||||
ground_defenders_location=None,
|
air_defenders_location=defenders_position,
|
||||||
air_attackers_location=position.point_from_heading(random.randint(*INTERCEPT_ATTACKERS_HEADING) + heading, AIR_DISTANCE),
|
|
||||||
air_defenders_location=position.point_from_heading(heading, max(AIR_DISTANCE, defenders_distance)),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@ -15,6 +15,10 @@ class NameGenerator:
|
|||||||
self.number += 1
|
self.number += 1
|
||||||
return "awacs|{}|{}|0|".format(country.id, self.number)
|
return "awacs|{}|{}|0|".format(country.id, self.number)
|
||||||
|
|
||||||
|
def next_tanker_name(self, country):
|
||||||
|
self.number += 1
|
||||||
|
return "tanker|{}|{}|0|".format(country.id, self.number)
|
||||||
|
|
||||||
def next_carrier_name(self, country):
|
def next_carrier_name(self, country):
|
||||||
self.number += 1
|
self.number += 1
|
||||||
return "carrier|{}|{}|0|".format(country.id, self.number)
|
return "carrier|{}|{}|0|".format(country.id, self.number)
|
||||||
|
|||||||
@ -73,7 +73,7 @@ class TriggersGenerator:
|
|||||||
for country in coalition.countries.values():
|
for country in coalition.countries.values():
|
||||||
if coalition_name == player_coalition:
|
if coalition_name == player_coalition:
|
||||||
for plane_group in country.plane_group + country.helicopter_group:
|
for plane_group in country.plane_group + country.helicopter_group:
|
||||||
if plane_group.task == AWACS.name:
|
if plane_group.task == AWACS.name or plane_group.task == Refueling.name:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
regroup_heading = self.conflict.to_cp.position.heading_between_point(self.conflict.from_cp.position)
|
regroup_heading = self.conflict.to_cp.position.heading_between_point(self.conflict.from_cp.position)
|
||||||
|
|||||||
@ -1,9 +1,22 @@
|
|||||||
|
from dcs.helicopters import helicopter_map
|
||||||
|
|
||||||
from ui.eventresultsmenu import *
|
from ui.eventresultsmenu import *
|
||||||
|
|
||||||
from game import *
|
from game import *
|
||||||
from game.event import *
|
from game.event import *
|
||||||
|
|
||||||
|
|
||||||
|
UNITTYPES_FOR_EVENTS = {
|
||||||
|
FrontlineAttackEvent: CAS,
|
||||||
|
FrontlinePatrolEvent: CAP,
|
||||||
|
InterceptEvent: CAP,
|
||||||
|
InsurgentAttackEvent: CAS,
|
||||||
|
NavalInterceptEvent: CAS,
|
||||||
|
AntiAAStrikeEvent: CAS,
|
||||||
|
InfantryTransportEvent: Embarking,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class EventMenu(Menu):
|
class EventMenu(Menu):
|
||||||
aircraft_scramble_entries = None # type: typing.Dict[PlaneType , Entry]
|
aircraft_scramble_entries = None # type: typing.Dict[PlaneType , Entry]
|
||||||
aircraft_client_entries = None # type: typing.Dict[PlaneType, Entry]
|
aircraft_client_entries = None # type: typing.Dict[PlaneType, Entry]
|
||||||
@ -87,7 +100,14 @@ class EventMenu(Menu):
|
|||||||
Label(self.frame, text="Client slots").grid(row=row, column=3, columnspan=2)
|
Label(self.frame, text="Client slots").grid(row=row, column=3, columnspan=2)
|
||||||
row += 1
|
row += 1
|
||||||
|
|
||||||
|
filter_to = UNITTYPES_FOR_EVENTS[self.event.__class__]
|
||||||
for unit_type, count in self.base.aircraft.items():
|
for unit_type, count in self.base.aircraft.items():
|
||||||
|
if filter_to and db.unit_task(unit_type) != filter_to:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if unit_type in helicopter_map and self.event.__class__ != InsurgentAttackEvent:
|
||||||
|
continue
|
||||||
|
|
||||||
scrable_row(unit_type, count)
|
scrable_row(unit_type, count)
|
||||||
|
|
||||||
if not self.base.total_planes:
|
if not self.base.total_planes:
|
||||||
@ -193,6 +213,9 @@ class EventMenu(Menu):
|
|||||||
elif type(self.event) is FrontlineAttackEvent:
|
elif type(self.event) is FrontlineAttackEvent:
|
||||||
e = self.event # type: FrontlineAttackEvent
|
e = self.event # type: FrontlineAttackEvent
|
||||||
e.player_attacking(armor=scrambled_armor, strikegroup=scrambled_aircraft, clients=scrambled_clients)
|
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)
|
||||||
elif type(self.event) is NavalInterceptEvent:
|
elif type(self.event) is NavalInterceptEvent:
|
||||||
e = self.event # type: NavalInterceptEvent
|
e = self.event # type: NavalInterceptEvent
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user