WIP: display events on the map; start events from adjacent CPs

This commit is contained in:
Vasyl Horbachenko
2018-11-04 02:38:14 +02:00
parent 97be483624
commit 8f85101cec
16 changed files with 221 additions and 137 deletions

View File

@@ -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)

View File

@@ -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 = {}

View File

@@ -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

View File

@@ -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

View File

@@ -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
)

View File

@@ -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])

View File

@@ -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],

View File

@@ -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)

View File

@@ -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
)

View File

@@ -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()