mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
frontline attack ops
This commit is contained in:
committed by
Vasyl Horbachenko
parent
6f5835a2b8
commit
820820eb92
@@ -448,6 +448,11 @@ def unitdict_split(unit_dict: UnitsDict, count: int):
|
||||
if len(buffer_dict):
|
||||
yield buffer_dict
|
||||
|
||||
|
||||
def unitdict_restrict_count(unit_dict: UnitsDict, total_count: int) -> UnitsDict:
|
||||
return list(unitdict_split(unit_dict, total_count))[0]
|
||||
|
||||
|
||||
def _validate_db():
|
||||
# check unit by task uniquity
|
||||
total_set = set()
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
from .event import *
|
||||
from .frontlinecas import *
|
||||
from .frontlineattack import *
|
||||
from .intercept import *
|
||||
from .capture import *
|
||||
from .baseattack import *
|
||||
from .navalintercept import *
|
||||
from .antiaastrike import *
|
||||
from .groundattack import *
|
||||
from .insurgentattack import *
|
||||
from .infantrytransport import *
|
||||
|
||||
@@ -4,13 +4,13 @@ import random
|
||||
from dcs.task import *
|
||||
|
||||
from game import db
|
||||
from game.operation.capture import CaptureOperation
|
||||
from game.operation.baseattack import BaseAttackOperation
|
||||
from userdata.debriefing import Debriefing
|
||||
|
||||
from .event import Event
|
||||
|
||||
|
||||
class CaptureEvent(Event):
|
||||
class BaseAttackEvent(Event):
|
||||
silent = True
|
||||
BONUS_BASE = 15
|
||||
STRENGTH_RECOVERY = 0.55
|
||||
@@ -28,7 +28,7 @@ class CaptureEvent(Event):
|
||||
return not attackers_success
|
||||
|
||||
def commit(self, debriefing: Debriefing):
|
||||
super(CaptureEvent, self).commit(debriefing)
|
||||
super(BaseAttackEvent, self).commit(debriefing)
|
||||
if self.is_successfull(debriefing):
|
||||
if self.from_cp.captured:
|
||||
self.to_cp.captured = True
|
||||
@@ -49,13 +49,13 @@ class CaptureEvent(Event):
|
||||
escort = self.from_cp.base.scramble_sweep(self.game.settings.multiplier)
|
||||
attackers = self.from_cp.base.armor
|
||||
|
||||
op = CaptureOperation(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 = 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,
|
||||
@@ -67,13 +67,13 @@ class CaptureEvent(Event):
|
||||
self.operation = op
|
||||
|
||||
def player_attacking(self, cas: db.PlaneDict, escort: db.PlaneDict, armor: db.ArmorDict, clients: db.PlaneDict):
|
||||
op = CaptureOperation(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 = 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))
|
||||
76
game/event/frontlineattack.py
Normal file
76
game/event/frontlineattack.py
Normal file
@@ -0,0 +1,76 @@
|
||||
import math
|
||||
import random
|
||||
|
||||
from dcs.task import *
|
||||
from dcs.vehicles import AirDefence
|
||||
|
||||
from game import *
|
||||
from game.event import *
|
||||
from game.operation.frontlineattack import FrontlineAttackOperation
|
||||
from userdata.debriefing import Debriefing
|
||||
|
||||
|
||||
class FrontlineAttackEvent(Event):
|
||||
TARGET_VARIETY = 2
|
||||
TARGET_AMOUNT_FACTOR = 0.5
|
||||
ATTACKER_AMOUNT_FACTOR = 0.4
|
||||
ATTACKER_DEFENDER_FACTOR = 0.7
|
||||
STRENGTH_INFLUENCE = 0.3
|
||||
SUCCESS_MIN_TARGETS = 3
|
||||
|
||||
defenders = None # type: db.ArmorDict
|
||||
|
||||
@property
|
||||
def threat_description(self):
|
||||
return "{} vehicles".format(self.to_cp.base.assemble_count())
|
||||
|
||||
def __str__(self):
|
||||
return "Frontline attack from {} at {}".format(self.from_cp, self.to_cp)
|
||||
|
||||
def is_successfull(self, debriefing: Debriefing):
|
||||
total_targets = sum(self.defenders.values())
|
||||
destroyed_targets = 0
|
||||
for unit, count in debriefing.destroyed_units[self.defender_name].items():
|
||||
if unit in self.defenders:
|
||||
destroyed_targets += count
|
||||
|
||||
if self.from_cp.captured:
|
||||
return float(destroyed_targets) >= min(self.SUCCESS_MIN_TARGETS, total_targets)
|
||||
else:
|
||||
return float(destroyed_targets) < min(self.SUCCESS_MIN_TARGETS, total_targets)
|
||||
|
||||
def commit(self, debriefing: Debriefing):
|
||||
super(FrontlineAttackEvent, 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):
|
||||
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):
|
||||
self.defenders = self.to_cp.base.assemble_cap()
|
||||
|
||||
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)
|
||||
|
||||
op.setup(target=self.defenders,
|
||||
attackers=db.unitdict_restrict_count(armor, sum(self.defenders.values())),
|
||||
strikegroup=strikegroup)
|
||||
|
||||
self.operation = op
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
import math
|
||||
import random
|
||||
|
||||
from dcs.task import *
|
||||
from dcs.vehicles import AirDefence
|
||||
|
||||
from game import *
|
||||
from game.event import *
|
||||
from game.operation.frontlinecas import FrontlineCASOperation
|
||||
from userdata.debriefing import Debriefing
|
||||
|
||||
|
||||
class FrontlineCASEvent(Event):
|
||||
TARGET_VARIETY = 2
|
||||
TARGET_AMOUNT_FACTOR = 0.5
|
||||
ATTACKER_AMOUNT_FACTOR = 0.4
|
||||
STRENGTH_INFLUENCE = 0.3
|
||||
SUCCESS_MIN_TARGETS = 3
|
||||
|
||||
targets = None # type: db.ArmorDict
|
||||
|
||||
@property
|
||||
def threat_description(self):
|
||||
if not self.game.is_player_attack(self):
|
||||
return "{} aicraft".format(self.from_cp.base.scramble_count(self.game.settings.multiplier, CAS))
|
||||
else:
|
||||
return super(FrontlineCASEvent, self).threat_description
|
||||
|
||||
def __str__(self):
|
||||
return "Frontline CAS from {} at {}".format(self.from_cp, self.to_cp)
|
||||
|
||||
def is_successfull(self, debriefing: Debriefing):
|
||||
total_targets = sum(self.targets.values())
|
||||
destroyed_targets = 0
|
||||
for unit, count in debriefing.destroyed_units[self.defender_name].items():
|
||||
if unit in self.targets:
|
||||
destroyed_targets += count
|
||||
|
||||
if self.from_cp.captured:
|
||||
return float(destroyed_targets) >= min(self.SUCCESS_MIN_TARGETS, total_targets)
|
||||
else:
|
||||
return float(destroyed_targets) < min(self.SUCCESS_MIN_TARGETS, total_targets)
|
||||
|
||||
def commit(self, debriefing: Debriefing):
|
||||
super(FrontlineCASEvent, 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):
|
||||
if self.to_cp.captured:
|
||||
self.to_cp.base.affect_strength(-0.1)
|
||||
|
||||
def player_attacking(self, strikegroup: db.PlaneDict, clients: db.PlaneDict):
|
||||
suitable_armor_targets = db.find_unittype(PinpointStrike, self.defender_name)
|
||||
random.shuffle(suitable_armor_targets)
|
||||
|
||||
target_types = suitable_armor_targets[:self.TARGET_VARIETY]
|
||||
typecount = max(math.floor(self.to_cp.base.assemble_count() * self.TARGET_AMOUNT_FACTOR), 1)
|
||||
self.targets = {unittype: typecount for unittype in target_types}
|
||||
|
||||
defense_aa_unit = random.choice(self.game.commision_unit_types(self.to_cp, AirDefence))
|
||||
self.targets[defense_aa_unit] = 1
|
||||
|
||||
suitable_armor_attackers = db.find_unittype(PinpointStrike, self.attacker_name)
|
||||
random.shuffle(suitable_armor_attackers)
|
||||
attacker_types = suitable_armor_attackers[:self.TARGET_VARIETY]
|
||||
typecount = max(math.floor(self.from_cp.base.assemble_count() * self.ATTACKER_AMOUNT_FACTOR), 1)
|
||||
attackers = {unittype: typecount for unittype in attacker_types}
|
||||
|
||||
op = FrontlineCASOperation(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(target=self.targets,
|
||||
attackers=attackers,
|
||||
strikegroup=strikegroup)
|
||||
|
||||
self.operation = op
|
||||
|
||||
@@ -5,11 +5,11 @@ from dcs.task import *
|
||||
|
||||
from game import *
|
||||
from game.event import *
|
||||
from game.event.frontlinecas import FrontlineCASEvent
|
||||
from game.operation.groundattack import GroundAttackOperation
|
||||
from game.event.frontlineattack import FrontlineAttackEvent
|
||||
from game.operation.insurgentattack import InsurgentAttackOperation
|
||||
|
||||
|
||||
class GroundAttackEvent(FrontlineCASEvent):
|
||||
class InsurgentAttackEvent(FrontlineAttackEvent):
|
||||
def __str__(self):
|
||||
return "Destroy insurgents at {}".format(self.to_cp)
|
||||
|
||||
@@ -24,13 +24,13 @@ class GroundAttackEvent(FrontlineCASEvent):
|
||||
typecount = max(math.floor(self.difficulty * self.TARGET_AMOUNT_FACTOR), 1)
|
||||
self.targets = {unittype: typecount for unittype in unittypes}
|
||||
|
||||
op = GroundAttackOperation(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 = 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)
|
||||
|
||||
10
game/game.py
10
game/game.py
@@ -39,17 +39,17 @@ For the enemy events, only 1 event of each type could be generated for a turn.
|
||||
Events:
|
||||
* CaptureEvent - capture base
|
||||
* InterceptEvent - air intercept
|
||||
* FrontlineCASEvent - frontline CAS
|
||||
* FrontlineAttack - frontline attack
|
||||
* GroundAttackEvent - destroy insurgents
|
||||
* NavalInterceptEvent - naval intercept
|
||||
* AntiAAStrikeEvent - anti-AA strike
|
||||
* InfantryTransportEvent - helicopter infantry transport
|
||||
"""
|
||||
EVENT_PROBABILITIES = {
|
||||
CaptureEvent: [100, 10],
|
||||
BaseAttackEvent: [100, 10],
|
||||
InterceptEvent: [25, 10],
|
||||
FrontlineCASEvent: [250, 0],
|
||||
GroundAttackEvent: [0, 10],
|
||||
FrontlineAttackEvent: [100, 0],
|
||||
InsurgentAttackEvent: [0, 10],
|
||||
NavalInterceptEvent: [25, 10],
|
||||
AntiAAStrikeEvent: [25, 10],
|
||||
InfantryTransportEvent: [25, 0],
|
||||
@@ -130,7 +130,7 @@ class Game:
|
||||
if event_class == NavalInterceptEvent:
|
||||
if player_cp.radials == LAND:
|
||||
continue
|
||||
elif event_class == CaptureEvent:
|
||||
elif event_class == BaseAttackEvent:
|
||||
if enemy_cap_generated:
|
||||
continue
|
||||
if enemy_cp.base.total_armor == 0:
|
||||
|
||||
@@ -12,7 +12,7 @@ from gen.visualgen import *
|
||||
from .operation import Operation
|
||||
|
||||
|
||||
class CaptureOperation(Operation):
|
||||
class BaseAttackOperation(Operation):
|
||||
cas = None # type: db.PlaneDict
|
||||
escort = None # type: db.PlaneDict
|
||||
intercept = None # type: db.PlaneDict
|
||||
@@ -37,7 +37,7 @@ class CaptureOperation(Operation):
|
||||
self.aa = aa
|
||||
|
||||
def prepare(self, terrain: dcs.terrain.Terrain, is_quick: bool):
|
||||
super(CaptureOperation, self).prepare(terrain, is_quick)
|
||||
super(BaseAttackOperation, self).prepare(terrain, is_quick)
|
||||
|
||||
self.defenders_starting_position = None
|
||||
if self.game.player == self.defender_name:
|
||||
@@ -63,5 +63,5 @@ class CaptureOperation(Operation):
|
||||
self.airgen.generate_strikegroup_escort(self.escort, clients=self.attacker_clients, at=self.attackers_starting_position)
|
||||
|
||||
self.visualgen.generate_target_smokes(self.to_cp)
|
||||
super(CaptureOperation, self).generate()
|
||||
super(BaseAttackOperation, self).generate()
|
||||
|
||||
@@ -18,7 +18,7 @@ from .operation import Operation
|
||||
MAX_DISTANCE_BETWEEN_GROUPS = 12000
|
||||
|
||||
|
||||
class FrontlineCASOperation(Operation):
|
||||
class FrontlineAttackOperation(Operation):
|
||||
attackers = None # type: db.ArmorDict
|
||||
strikegroup = None # type: db.PlaneDict
|
||||
target = None # type: db.ArmorDict
|
||||
@@ -32,7 +32,7 @@ class FrontlineCASOperation(Operation):
|
||||
self.attackers = attackers
|
||||
|
||||
def prepare(self, terrain: Terrain, is_quick: bool):
|
||||
super(FrontlineCASOperation, self).prepare(terrain, is_quick)
|
||||
super(FrontlineAttackOperation, self).prepare(terrain, is_quick)
|
||||
if self.defender_name == self.game.player:
|
||||
self.attackers_starting_position = None
|
||||
self.defenders_starting_position = None
|
||||
@@ -51,4 +51,4 @@ class FrontlineCASOperation(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)
|
||||
super(FrontlineCASOperation, self).generate()
|
||||
super(FrontlineAttackOperation, self).generate()
|
||||
@@ -13,7 +13,7 @@ from gen.conflictgen import Conflict
|
||||
from .operation import Operation
|
||||
|
||||
|
||||
class GroundAttackOperation(Operation):
|
||||
class InsurgentAttackOperation(Operation):
|
||||
strikegroup = None # type: db.PlaneDict
|
||||
target = None # type: db.ArmorDict
|
||||
|
||||
@@ -24,7 +24,7 @@ class GroundAttackOperation(Operation):
|
||||
self.target = target
|
||||
|
||||
def prepare(self, terrain: Terrain, is_quick: bool):
|
||||
super(GroundAttackOperation, self).prepare(terrain, is_quick)
|
||||
super(InsurgentAttackOperation, self).prepare(terrain, is_quick)
|
||||
|
||||
conflict = Conflict.ground_attack_conflict(
|
||||
attacker=self.mission.country(self.attacker_name),
|
||||
@@ -41,4 +41,4 @@ class GroundAttackOperation(Operation):
|
||||
self.airgen.generate_defense(self.strikegroup, self.defender_clients, self.defenders_starting_position)
|
||||
self.armorgen.generate(self.target, {})
|
||||
|
||||
super(GroundAttackOperation, self).generate()
|
||||
super(InsurgentAttackOperation, self).generate()
|
||||
Reference in New Issue
Block a user