mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
WIP: display events on the map; start events from adjacent CPs
This commit is contained in:
@@ -28,7 +28,7 @@ class BaseAttackEvent(Event):
|
||||
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])
|
||||
attackers_success = alive_attackers >= alive_defenders
|
||||
if self.from_cp.captured:
|
||||
if self.departure_cp.captured:
|
||||
return attackers_success
|
||||
else:
|
||||
return not attackers_success
|
||||
@@ -36,14 +36,14 @@ class BaseAttackEvent(Event):
|
||||
def commit(self, debriefing: Debriefing):
|
||||
super(BaseAttackEvent, self).commit(debriefing)
|
||||
if self.is_successfull(debriefing):
|
||||
if self.from_cp.captured:
|
||||
if self.departure_cp.captured:
|
||||
self.to_cp.captured = True
|
||||
self.to_cp.ground_objects = []
|
||||
self.to_cp.base.filter_units(db.UNIT_BY_COUNTRY[self.attacker_name])
|
||||
|
||||
self.to_cp.base.affect_strength(+self.STRENGTH_RECOVERY)
|
||||
else:
|
||||
if not self.from_cp.captured:
|
||||
if not self.departure_cp.captured:
|
||||
self.to_cp.captured = False
|
||||
self.to_cp.base.affect_strength(+self.STRENGTH_RECOVERY)
|
||||
|
||||
@@ -54,14 +54,14 @@ class BaseAttackEvent(Event):
|
||||
def player_defending(self, flights: db.TaskForceDict):
|
||||
assert CAP in flights and len(flights) == 1, "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
|
||||
cas = self.departure_cp.base.scramble_cas(self.game.settings.multiplier)
|
||||
escort = self.departure_cp.base.scramble_sweep(self.game.settings.multiplier)
|
||||
attackers = self.departure_cp.base.armor
|
||||
|
||||
op = BaseAttackOperation(game=self.game,
|
||||
attacker_name=self.attacker_name,
|
||||
defender_name=self.defender_name,
|
||||
from_cp=self.from_cp,
|
||||
from_cp=self.departure_cp,
|
||||
to_cp=self.to_cp)
|
||||
|
||||
op.setup(cas=assigned_units_from(cas),
|
||||
@@ -79,7 +79,7 @@ class BaseAttackEvent(Event):
|
||||
op = BaseAttackOperation(game=self.game,
|
||||
attacker_name=self.attacker_name,
|
||||
defender_name=self.defender_name,
|
||||
from_cp=self.from_cp,
|
||||
from_cp=self.departure_cp,
|
||||
to_cp=self.to_cp)
|
||||
|
||||
defenders = self.to_cp.base.scramble_sweep(self.game.settings.multiplier)
|
||||
|
||||
@@ -22,18 +22,26 @@ class Event:
|
||||
informational = False
|
||||
is_awacs_enabled = False
|
||||
ca_slots = 0
|
||||
|
||||
game = None # type: Game
|
||||
location = None # type: Point
|
||||
from_cp = None # type: ControlPoint
|
||||
departure_cp = None # type: ControlPoint
|
||||
to_cp = None # type: ControlPoint
|
||||
|
||||
operation = None # type: Operation
|
||||
difficulty = 1 # type: int
|
||||
game = None # type: Game
|
||||
environment_settings = None # type: EnvironmentSettings
|
||||
BONUS_BASE = 5
|
||||
|
||||
def __init__(self, attacker_name: str, defender_name: str, from_cp: ControlPoint, to_cp: ControlPoint, game):
|
||||
def __init__(self, game, from_cp: ControlPoint, target_cp: ControlPoint, location: Point, attacker_name: str, defender_name: str):
|
||||
self.game = game
|
||||
self.departure_cp = None
|
||||
self.from_cp = from_cp
|
||||
self.to_cp = target_cp
|
||||
self.location = location
|
||||
self.attacker_name = attacker_name
|
||||
self.defender_name = defender_name
|
||||
self.to_cp = to_cp
|
||||
self.from_cp = from_cp
|
||||
self.game = game
|
||||
|
||||
@property
|
||||
def is_player_attacking(self) -> bool:
|
||||
@@ -44,7 +52,7 @@ class Event:
|
||||
if self.attacker_name == self.game.player:
|
||||
return self.to_cp
|
||||
else:
|
||||
return self.from_cp
|
||||
return self.departure_cp
|
||||
|
||||
@property
|
||||
def threat_description(self) -> str:
|
||||
@@ -67,11 +75,17 @@ class Event:
|
||||
def is_successfull(self, debriefing: Debriefing) -> bool:
|
||||
return self.operation.is_successfull(debriefing)
|
||||
|
||||
def player_attacking(self, flights: db.TaskForceDict):
|
||||
assert False
|
||||
def player_attacking(self, cp: ControlPoint, flights: db.TaskForceDict):
|
||||
if self.is_player_attacking:
|
||||
self.departure_cp = cp
|
||||
else:
|
||||
self.to_cp = cp
|
||||
|
||||
def player_defending(self, flights: db.TaskForceDict):
|
||||
assert False
|
||||
def player_defending(self, cp: ControlPoint, flights: db.TaskForceDict):
|
||||
if self.is_player_attacking:
|
||||
self.departure_cp = cp
|
||||
else:
|
||||
self.to_cp = cp
|
||||
|
||||
def generate(self):
|
||||
self.operation.is_awacs_enabled = self.is_awacs_enabled
|
||||
@@ -93,7 +107,7 @@ class Event:
|
||||
def commit(self, debriefing: Debriefing):
|
||||
for country, losses in debriefing.destroyed_units.items():
|
||||
if country == self.attacker_name:
|
||||
cp = self.from_cp
|
||||
cp = self.departure_cp
|
||||
else:
|
||||
cp = self.to_cp
|
||||
|
||||
@@ -122,11 +136,12 @@ class UnitsDeliveryEvent(Event):
|
||||
units = None # type: typing.Dict[UnitType, int]
|
||||
|
||||
def __init__(self, attacker_name: str, defender_name: str, from_cp: ControlPoint, to_cp: ControlPoint, game):
|
||||
super(UnitsDeliveryEvent, self).__init__(attacker_name=attacker_name,
|
||||
defender_name=defender_name,
|
||||
super(UnitsDeliveryEvent, self).__init__(game=game,
|
||||
location=to_cp.position,
|
||||
from_cp=from_cp,
|
||||
to_cp=to_cp,
|
||||
game=game)
|
||||
target_cp=to_cp,
|
||||
attacker_name=attacker_name,
|
||||
defender_name=defender_name)
|
||||
|
||||
self.units = {}
|
||||
|
||||
|
||||
@@ -11,8 +11,6 @@ class FrontlineAttackEvent(Event):
|
||||
STRENGTH_INFLUENCE = 0.3
|
||||
SUCCESS_FACTOR = 1.5
|
||||
|
||||
defenders = None # type: db.ArmorDict
|
||||
|
||||
@property
|
||||
def threat_description(self):
|
||||
return "{} vehicles".format(self.to_cp.base.assemble_count())
|
||||
@@ -20,9 +18,9 @@ class FrontlineAttackEvent(Event):
|
||||
@property
|
||||
def tasks(self) -> typing.Collection[typing.Type[Task]]:
|
||||
if self.is_player_attacking:
|
||||
return [CAS, PinpointStrike]
|
||||
return [CAS]
|
||||
else:
|
||||
return [CAP, PinpointStrike]
|
||||
return [CAP]
|
||||
|
||||
def flight_name(self, for_task: typing.Type[Task]) -> str:
|
||||
if for_task == CAS:
|
||||
@@ -63,9 +61,8 @@ class FrontlineAttackEvent(Event):
|
||||
self.to_cp.base.affect_strength(-0.1)
|
||||
|
||||
def player_attacking(self, flights: db.TaskForceDict):
|
||||
assert CAS in flights and PinpointStrike in flights and len(flights) == 2, "Invalid flights"
|
||||
assert CAS in flights and len(flights) == 1, "Invalid flights"
|
||||
|
||||
self.defenders = self.to_cp.base.assemble_attack()
|
||||
|
||||
op = FrontlineAttackOperation(game=self.game,
|
||||
attacker_name=self.attacker_name,
|
||||
@@ -73,9 +70,10 @@ class FrontlineAttackEvent(Event):
|
||||
from_cp=self.from_cp,
|
||||
to_cp=self.to_cp)
|
||||
|
||||
armor = unitdict_from(flights[PinpointStrike])
|
||||
op.setup(target=self.defenders,
|
||||
attackers=db.unitdict_restrict_count(armor, sum(self.defenders.values())),
|
||||
defenders = self.to_cp.base.assemble_attack()
|
||||
attackers = db.unitdict_restrict_count(self.from_cp.base.assemble_attack(), sum(defenders.values()))
|
||||
op.setup(target=defenders,
|
||||
attackers=attackers,
|
||||
strikegroup=flights[CAS])
|
||||
|
||||
self.operation = op
|
||||
|
||||
@@ -17,7 +17,7 @@ class FrontlinePatrolEvent(Event):
|
||||
|
||||
@property
|
||||
def tasks(self):
|
||||
return [CAP, PinpointStrike]
|
||||
return [CAP]
|
||||
|
||||
def flight_name(self, for_task: typing.Type[Task]) -> str:
|
||||
if for_task == CAP:
|
||||
@@ -55,7 +55,7 @@ class FrontlinePatrolEvent(Event):
|
||||
pass
|
||||
|
||||
def player_attacking(self, flights: db.TaskForceDict):
|
||||
assert CAP in flights and PinpointStrike in flights and len(flights) == 2, "Invalid flights"
|
||||
assert CAP in flights and len(flights) == 1, "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)
|
||||
@@ -67,10 +67,11 @@ class FrontlinePatrolEvent(Event):
|
||||
to_cp=self.to_cp)
|
||||
|
||||
defenders = self.to_cp.base.assemble_attack()
|
||||
attackers = db.unitdict_restrict_count(self.from_cp.base.assemble_attack(), sum(defenders.values()))
|
||||
op.setup(cas=assigned_units_from(self.cas),
|
||||
escort=assigned_units_from(self.escort),
|
||||
interceptors=flights[CAP],
|
||||
armor_attackers=db.unitdict_restrict_count(db.unitdict_from(flights[PinpointStrike]), sum(defenders.values())),
|
||||
armor_attackers=attackers,
|
||||
armor_defenders=defenders)
|
||||
|
||||
self.operation = op
|
||||
|
||||
@@ -35,7 +35,7 @@ class InfantryTransportEvent(Event):
|
||||
if self.is_successfull(debriefing):
|
||||
self.to_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
||||
else:
|
||||
self.from_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
||||
self.departure_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
||||
|
||||
def player_attacking(self, flights: db.TaskForceDict):
|
||||
assert Embarking in flights and len(flights) == 1, "Invalid flights"
|
||||
@@ -44,7 +44,7 @@ class InfantryTransportEvent(Event):
|
||||
game=self.game,
|
||||
attacker_name=self.attacker_name,
|
||||
defender_name=self.defender_name,
|
||||
from_cp=self.from_cp,
|
||||
from_cp=self.departure_cp,
|
||||
to_cp=self.to_cp
|
||||
)
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ class InsurgentAttackEvent(Event):
|
||||
killed_units = sum([v for k, v in debriefing.destroyed_units[self.attacker_name].items() if db.unit_task(k) == PinpointStrike])
|
||||
all_units = sum(self.targets.values())
|
||||
attackers_success = (float(killed_units) / (all_units + 0.01)) > self.SUCCESS_FACTOR
|
||||
if self.from_cp.captured:
|
||||
if self.departure_cp.captured:
|
||||
return attackers_success
|
||||
else:
|
||||
return not attackers_success
|
||||
@@ -56,7 +56,7 @@ class InsurgentAttackEvent(Event):
|
||||
op = InsurgentAttackOperation(game=self.game,
|
||||
attacker_name=self.attacker_name,
|
||||
defender_name=self.defender_name,
|
||||
from_cp=self.from_cp,
|
||||
from_cp=self.departure_cp,
|
||||
to_cp=self.to_cp)
|
||||
op.setup(target=self.targets,
|
||||
strikegroup=flights[CAS])
|
||||
|
||||
@@ -25,7 +25,7 @@ class InterceptEvent(Event):
|
||||
return "Escort flight"
|
||||
|
||||
def _enemy_scramble_multiplier(self) -> float:
|
||||
is_global = self.from_cp.is_global or self.to_cp.is_global
|
||||
is_global = self.departure_cp.is_global or self.to_cp.is_global
|
||||
return self.game.settings.multiplier * is_global and 0.5 or 1
|
||||
|
||||
@property
|
||||
@@ -34,7 +34,7 @@ class InterceptEvent(Event):
|
||||
|
||||
def is_successfull(self, debriefing: Debriefing):
|
||||
units_destroyed = debriefing.destroyed_units[self.defender_name].get(self.transport_unit, 0)
|
||||
if self.from_cp.captured:
|
||||
if self.departure_cp.captured:
|
||||
return units_destroyed > 0
|
||||
else:
|
||||
return units_destroyed == 0
|
||||
@@ -47,11 +47,11 @@ class InterceptEvent(Event):
|
||||
for _, cp in self.game.theater.conflicts(True):
|
||||
cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
||||
else:
|
||||
self.from_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
||||
self.departure_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
||||
else:
|
||||
# enemy attacking
|
||||
if self.is_successfull(debriefing):
|
||||
self.from_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
||||
self.departure_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
||||
else:
|
||||
self.to_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
||||
|
||||
@@ -71,7 +71,7 @@ class InterceptEvent(Event):
|
||||
op = InterceptOperation(game=self.game,
|
||||
attacker_name=self.attacker_name,
|
||||
defender_name=self.defender_name,
|
||||
from_cp=self.from_cp,
|
||||
from_cp=self.departure_cp,
|
||||
to_cp=self.to_cp)
|
||||
|
||||
op.setup(escort=assigned_units_from(escort),
|
||||
@@ -84,7 +84,7 @@ class InterceptEvent(Event):
|
||||
def player_defending(self, flights: db.TaskForceDict):
|
||||
assert CAP in flights and len(flights) == 1, "Invalid flights"
|
||||
|
||||
interceptors = self.from_cp.base.scramble_interceptors(self.game.settings.multiplier)
|
||||
interceptors = self.departure_cp.base.scramble_interceptors(self.game.settings.multiplier)
|
||||
|
||||
self.transport_unit = random.choice(db.find_unittype(Transport, self.defender_name))
|
||||
assert self.transport_unit is not None
|
||||
@@ -92,7 +92,7 @@ class InterceptEvent(Event):
|
||||
op = InterceptOperation(game=self.game,
|
||||
attacker_name=self.attacker_name,
|
||||
defender_name=self.defender_name,
|
||||
from_cp=self.from_cp,
|
||||
from_cp=self.departure_cp,
|
||||
to_cp=self.to_cp)
|
||||
|
||||
op.setup(escort=flights[CAP],
|
||||
|
||||
@@ -33,8 +33,8 @@ class NavalInterceptEvent(Event):
|
||||
@property
|
||||
def threat_description(self):
|
||||
s = "{} ship(s)".format(self._targets_count())
|
||||
if not self.from_cp.captured:
|
||||
s += ", {} aircraft".format(self.from_cp.base.scramble_count(self.game.settings.multiplier))
|
||||
if not self.departure_cp.captured:
|
||||
s += ", {} aircraft".format(self.departure_cp.base.scramble_count(self.game.settings.multiplier))
|
||||
return s
|
||||
|
||||
def is_successfull(self, debriefing: Debriefing):
|
||||
@@ -44,7 +44,7 @@ class NavalInterceptEvent(Event):
|
||||
if unit in self.targets:
|
||||
destroyed_targets += count
|
||||
|
||||
if self.from_cp.captured:
|
||||
if self.departure_cp.captured:
|
||||
return math.ceil(float(destroyed_targets) / total_targets) > self.SUCCESS_RATE
|
||||
else:
|
||||
return math.ceil(float(destroyed_targets) / total_targets) < self.SUCCESS_RATE
|
||||
@@ -56,11 +56,11 @@ class NavalInterceptEvent(Event):
|
||||
if self.is_successfull(debriefing):
|
||||
self.to_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
||||
else:
|
||||
self.from_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
||||
self.departure_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
||||
else:
|
||||
# enemy attacking
|
||||
if self.is_successfull(debriefing):
|
||||
self.from_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
||||
self.departure_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
||||
else:
|
||||
self.to_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
||||
|
||||
@@ -79,7 +79,7 @@ class NavalInterceptEvent(Event):
|
||||
self.game,
|
||||
attacker_name=self.attacker_name,
|
||||
defender_name=self.defender_name,
|
||||
from_cp=self.from_cp,
|
||||
from_cp=self.departure_cp,
|
||||
to_cp=self.to_cp
|
||||
)
|
||||
|
||||
@@ -100,11 +100,11 @@ class NavalInterceptEvent(Event):
|
||||
self.game,
|
||||
attacker_name=self.attacker_name,
|
||||
defender_name=self.defender_name,
|
||||
from_cp=self.from_cp,
|
||||
from_cp=self.departure_cp,
|
||||
to_cp=self.to_cp
|
||||
)
|
||||
|
||||
strikegroup = self.from_cp.base.scramble_cas(self.game.settings.multiplier)
|
||||
strikegroup = self.departure_cp.base.scramble_cas(self.game.settings.multiplier)
|
||||
op.setup(strikegroup=assigned_units_from(strikegroup),
|
||||
interceptors=flights[CAP],
|
||||
targets=self.targets)
|
||||
|
||||
@@ -49,7 +49,7 @@ class StrikeEvent(Event):
|
||||
self.game,
|
||||
attacker_name=self.attacker_name,
|
||||
defender_name=self.defender_name,
|
||||
from_cp=self.from_cp,
|
||||
from_cp=self.departure_cp,
|
||||
to_cp=self.to_cp
|
||||
)
|
||||
|
||||
|
||||
13
game/game.py
13
game/game.py
@@ -129,7 +129,7 @@ class Game:
|
||||
# skip strikes in case of no targets
|
||||
return
|
||||
|
||||
self.events.append(event_class(self.player, self.enemy, player_cp, enemy_cp, self))
|
||||
self.events.append(event_class(self, player_cp, enemy_cp, enemy_cp.position, self.player, self.enemy))
|
||||
|
||||
def _generate_enemy_event(self, event_class, player_cp, enemy_cp):
|
||||
if event_class in [type(x) for x in self.events if not self.is_player_attack(x)]:
|
||||
@@ -169,7 +169,7 @@ class Game:
|
||||
# skip base attack if strength is too high
|
||||
return
|
||||
|
||||
self.events.append(event_class(self.enemy, self.player, enemy_cp, player_cp, self))
|
||||
self.events.append(event_class(self, enemy_cp, player_cp, player_cp.position, self.enemy, self.player))
|
||||
|
||||
def _generate_events(self):
|
||||
for player_cp, enemy_cp in self.theater.conflicts(True):
|
||||
@@ -269,7 +269,12 @@ class Game:
|
||||
def pass_turn(self, no_action=False, ignored_cps: typing.Collection[ControlPoint]=None):
|
||||
logging.info("Pass turn")
|
||||
for event in self.events:
|
||||
event.skip()
|
||||
if self.settings.version == "dev":
|
||||
# don't damage player CPs in by skipping in dev mode
|
||||
if isinstance(event, UnitsDeliveryEvent):
|
||||
event.skip()
|
||||
else:
|
||||
event.skip()
|
||||
|
||||
if not no_action:
|
||||
self._budget_player()
|
||||
@@ -286,5 +291,5 @@ class Game:
|
||||
|
||||
self.events = [] # type: typing.List[Event]
|
||||
self._generate_events()
|
||||
self._generate_globalinterceptions()
|
||||
#self._generate_globalinterceptions()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user