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:
parent
97be483624
commit
8f85101cec
@ -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_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])
|
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
|
attackers_success = alive_attackers >= alive_defenders
|
||||||
if self.from_cp.captured:
|
if self.departure_cp.captured:
|
||||||
return attackers_success
|
return attackers_success
|
||||||
else:
|
else:
|
||||||
return not attackers_success
|
return not attackers_success
|
||||||
@ -36,14 +36,14 @@ class BaseAttackEvent(Event):
|
|||||||
def commit(self, debriefing: Debriefing):
|
def commit(self, debriefing: Debriefing):
|
||||||
super(BaseAttackEvent, self).commit(debriefing)
|
super(BaseAttackEvent, self).commit(debriefing)
|
||||||
if self.is_successfull(debriefing):
|
if self.is_successfull(debriefing):
|
||||||
if self.from_cp.captured:
|
if self.departure_cp.captured:
|
||||||
self.to_cp.captured = True
|
self.to_cp.captured = True
|
||||||
self.to_cp.ground_objects = []
|
self.to_cp.ground_objects = []
|
||||||
self.to_cp.base.filter_units(db.UNIT_BY_COUNTRY[self.attacker_name])
|
self.to_cp.base.filter_units(db.UNIT_BY_COUNTRY[self.attacker_name])
|
||||||
|
|
||||||
self.to_cp.base.affect_strength(+self.STRENGTH_RECOVERY)
|
self.to_cp.base.affect_strength(+self.STRENGTH_RECOVERY)
|
||||||
else:
|
else:
|
||||||
if not self.from_cp.captured:
|
if not self.departure_cp.captured:
|
||||||
self.to_cp.captured = False
|
self.to_cp.captured = False
|
||||||
self.to_cp.base.affect_strength(+self.STRENGTH_RECOVERY)
|
self.to_cp.base.affect_strength(+self.STRENGTH_RECOVERY)
|
||||||
|
|
||||||
@ -54,14 +54,14 @@ class BaseAttackEvent(Event):
|
|||||||
def player_defending(self, flights: db.TaskForceDict):
|
def player_defending(self, flights: db.TaskForceDict):
|
||||||
assert CAP in flights and len(flights) == 1, "Invalid scrambled flights"
|
assert CAP in flights and len(flights) == 1, "Invalid scrambled flights"
|
||||||
|
|
||||||
cas = self.from_cp.base.scramble_cas(self.game.settings.multiplier)
|
cas = self.departure_cp.base.scramble_cas(self.game.settings.multiplier)
|
||||||
escort = self.from_cp.base.scramble_sweep(self.game.settings.multiplier)
|
escort = self.departure_cp.base.scramble_sweep(self.game.settings.multiplier)
|
||||||
attackers = self.from_cp.base.armor
|
attackers = self.departure_cp.base.armor
|
||||||
|
|
||||||
op = BaseAttackOperation(game=self.game,
|
op = BaseAttackOperation(game=self.game,
|
||||||
attacker_name=self.attacker_name,
|
attacker_name=self.attacker_name,
|
||||||
defender_name=self.defender_name,
|
defender_name=self.defender_name,
|
||||||
from_cp=self.from_cp,
|
from_cp=self.departure_cp,
|
||||||
to_cp=self.to_cp)
|
to_cp=self.to_cp)
|
||||||
|
|
||||||
op.setup(cas=assigned_units_from(cas),
|
op.setup(cas=assigned_units_from(cas),
|
||||||
@ -79,7 +79,7 @@ class BaseAttackEvent(Event):
|
|||||||
op = BaseAttackOperation(game=self.game,
|
op = BaseAttackOperation(game=self.game,
|
||||||
attacker_name=self.attacker_name,
|
attacker_name=self.attacker_name,
|
||||||
defender_name=self.defender_name,
|
defender_name=self.defender_name,
|
||||||
from_cp=self.from_cp,
|
from_cp=self.departure_cp,
|
||||||
to_cp=self.to_cp)
|
to_cp=self.to_cp)
|
||||||
|
|
||||||
defenders = self.to_cp.base.scramble_sweep(self.game.settings.multiplier)
|
defenders = self.to_cp.base.scramble_sweep(self.game.settings.multiplier)
|
||||||
|
|||||||
@ -22,18 +22,26 @@ class Event:
|
|||||||
informational = False
|
informational = False
|
||||||
is_awacs_enabled = False
|
is_awacs_enabled = False
|
||||||
ca_slots = 0
|
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
|
operation = None # type: Operation
|
||||||
difficulty = 1 # type: int
|
difficulty = 1 # type: int
|
||||||
game = None # type: Game
|
|
||||||
environment_settings = None # type: EnvironmentSettings
|
environment_settings = None # type: EnvironmentSettings
|
||||||
BONUS_BASE = 5
|
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.attacker_name = attacker_name
|
||||||
self.defender_name = defender_name
|
self.defender_name = defender_name
|
||||||
self.to_cp = to_cp
|
|
||||||
self.from_cp = from_cp
|
|
||||||
self.game = game
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_player_attacking(self) -> bool:
|
def is_player_attacking(self) -> bool:
|
||||||
@ -44,7 +52,7 @@ class Event:
|
|||||||
if self.attacker_name == self.game.player:
|
if self.attacker_name == self.game.player:
|
||||||
return self.to_cp
|
return self.to_cp
|
||||||
else:
|
else:
|
||||||
return self.from_cp
|
return self.departure_cp
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def threat_description(self) -> str:
|
def threat_description(self) -> str:
|
||||||
@ -67,11 +75,17 @@ class Event:
|
|||||||
def is_successfull(self, debriefing: Debriefing) -> bool:
|
def is_successfull(self, debriefing: Debriefing) -> bool:
|
||||||
return self.operation.is_successfull(debriefing)
|
return self.operation.is_successfull(debriefing)
|
||||||
|
|
||||||
def player_attacking(self, flights: db.TaskForceDict):
|
def player_attacking(self, cp: ControlPoint, flights: db.TaskForceDict):
|
||||||
assert False
|
if self.is_player_attacking:
|
||||||
|
self.departure_cp = cp
|
||||||
|
else:
|
||||||
|
self.to_cp = cp
|
||||||
|
|
||||||
def player_defending(self, flights: db.TaskForceDict):
|
def player_defending(self, cp: ControlPoint, flights: db.TaskForceDict):
|
||||||
assert False
|
if self.is_player_attacking:
|
||||||
|
self.departure_cp = cp
|
||||||
|
else:
|
||||||
|
self.to_cp = cp
|
||||||
|
|
||||||
def generate(self):
|
def generate(self):
|
||||||
self.operation.is_awacs_enabled = self.is_awacs_enabled
|
self.operation.is_awacs_enabled = self.is_awacs_enabled
|
||||||
@ -93,7 +107,7 @@ class Event:
|
|||||||
def commit(self, debriefing: Debriefing):
|
def commit(self, debriefing: Debriefing):
|
||||||
for country, losses in debriefing.destroyed_units.items():
|
for country, losses in debriefing.destroyed_units.items():
|
||||||
if country == self.attacker_name:
|
if country == self.attacker_name:
|
||||||
cp = self.from_cp
|
cp = self.departure_cp
|
||||||
else:
|
else:
|
||||||
cp = self.to_cp
|
cp = self.to_cp
|
||||||
|
|
||||||
@ -122,11 +136,12 @@ class UnitsDeliveryEvent(Event):
|
|||||||
units = None # type: typing.Dict[UnitType, int]
|
units = None # type: typing.Dict[UnitType, int]
|
||||||
|
|
||||||
def __init__(self, attacker_name: str, defender_name: str, from_cp: ControlPoint, to_cp: ControlPoint, game):
|
def __init__(self, attacker_name: str, defender_name: str, from_cp: ControlPoint, to_cp: ControlPoint, game):
|
||||||
super(UnitsDeliveryEvent, self).__init__(attacker_name=attacker_name,
|
super(UnitsDeliveryEvent, self).__init__(game=game,
|
||||||
defender_name=defender_name,
|
location=to_cp.position,
|
||||||
from_cp=from_cp,
|
from_cp=from_cp,
|
||||||
to_cp=to_cp,
|
target_cp=to_cp,
|
||||||
game=game)
|
attacker_name=attacker_name,
|
||||||
|
defender_name=defender_name)
|
||||||
|
|
||||||
self.units = {}
|
self.units = {}
|
||||||
|
|
||||||
|
|||||||
@ -11,8 +11,6 @@ class FrontlineAttackEvent(Event):
|
|||||||
STRENGTH_INFLUENCE = 0.3
|
STRENGTH_INFLUENCE = 0.3
|
||||||
SUCCESS_FACTOR = 1.5
|
SUCCESS_FACTOR = 1.5
|
||||||
|
|
||||||
defenders = None # type: db.ArmorDict
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def threat_description(self):
|
def threat_description(self):
|
||||||
return "{} vehicles".format(self.to_cp.base.assemble_count())
|
return "{} vehicles".format(self.to_cp.base.assemble_count())
|
||||||
@ -20,9 +18,9 @@ class FrontlineAttackEvent(Event):
|
|||||||
@property
|
@property
|
||||||
def tasks(self) -> typing.Collection[typing.Type[Task]]:
|
def tasks(self) -> typing.Collection[typing.Type[Task]]:
|
||||||
if self.is_player_attacking:
|
if self.is_player_attacking:
|
||||||
return [CAS, PinpointStrike]
|
return [CAS]
|
||||||
else:
|
else:
|
||||||
return [CAP, PinpointStrike]
|
return [CAP]
|
||||||
|
|
||||||
def flight_name(self, for_task: typing.Type[Task]) -> str:
|
def flight_name(self, for_task: typing.Type[Task]) -> str:
|
||||||
if for_task == CAS:
|
if for_task == CAS:
|
||||||
@ -63,9 +61,8 @@ class FrontlineAttackEvent(Event):
|
|||||||
self.to_cp.base.affect_strength(-0.1)
|
self.to_cp.base.affect_strength(-0.1)
|
||||||
|
|
||||||
def player_attacking(self, flights: db.TaskForceDict):
|
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,
|
op = FrontlineAttackOperation(game=self.game,
|
||||||
attacker_name=self.attacker_name,
|
attacker_name=self.attacker_name,
|
||||||
@ -73,9 +70,10 @@ class FrontlineAttackEvent(Event):
|
|||||||
from_cp=self.from_cp,
|
from_cp=self.from_cp,
|
||||||
to_cp=self.to_cp)
|
to_cp=self.to_cp)
|
||||||
|
|
||||||
armor = unitdict_from(flights[PinpointStrike])
|
defenders = self.to_cp.base.assemble_attack()
|
||||||
op.setup(target=self.defenders,
|
attackers = db.unitdict_restrict_count(self.from_cp.base.assemble_attack(), sum(defenders.values()))
|
||||||
attackers=db.unitdict_restrict_count(armor, sum(self.defenders.values())),
|
op.setup(target=defenders,
|
||||||
|
attackers=attackers,
|
||||||
strikegroup=flights[CAS])
|
strikegroup=flights[CAS])
|
||||||
|
|
||||||
self.operation = op
|
self.operation = op
|
||||||
|
|||||||
@ -17,7 +17,7 @@ class FrontlinePatrolEvent(Event):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def tasks(self):
|
def tasks(self):
|
||||||
return [CAP, PinpointStrike]
|
return [CAP]
|
||||||
|
|
||||||
def flight_name(self, for_task: typing.Type[Task]) -> str:
|
def flight_name(self, for_task: typing.Type[Task]) -> str:
|
||||||
if for_task == CAP:
|
if for_task == CAP:
|
||||||
@ -55,7 +55,7 @@ class FrontlinePatrolEvent(Event):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def player_attacking(self, flights: db.TaskForceDict):
|
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.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)
|
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)
|
to_cp=self.to_cp)
|
||||||
|
|
||||||
defenders = self.to_cp.base.assemble_attack()
|
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),
|
op.setup(cas=assigned_units_from(self.cas),
|
||||||
escort=assigned_units_from(self.escort),
|
escort=assigned_units_from(self.escort),
|
||||||
interceptors=flights[CAP],
|
interceptors=flights[CAP],
|
||||||
armor_attackers=db.unitdict_restrict_count(db.unitdict_from(flights[PinpointStrike]), sum(defenders.values())),
|
armor_attackers=attackers,
|
||||||
armor_defenders=defenders)
|
armor_defenders=defenders)
|
||||||
|
|
||||||
self.operation = op
|
self.operation = op
|
||||||
|
|||||||
@ -35,7 +35,7 @@ class InfantryTransportEvent(Event):
|
|||||||
if self.is_successfull(debriefing):
|
if self.is_successfull(debriefing):
|
||||||
self.to_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
self.to_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
||||||
else:
|
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):
|
def player_attacking(self, flights: db.TaskForceDict):
|
||||||
assert Embarking in flights and len(flights) == 1, "Invalid flights"
|
assert Embarking in flights and len(flights) == 1, "Invalid flights"
|
||||||
@ -44,7 +44,7 @@ class InfantryTransportEvent(Event):
|
|||||||
game=self.game,
|
game=self.game,
|
||||||
attacker_name=self.attacker_name,
|
attacker_name=self.attacker_name,
|
||||||
defender_name=self.defender_name,
|
defender_name=self.defender_name,
|
||||||
from_cp=self.from_cp,
|
from_cp=self.departure_cp,
|
||||||
to_cp=self.to_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])
|
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())
|
all_units = sum(self.targets.values())
|
||||||
attackers_success = (float(killed_units) / (all_units + 0.01)) > self.SUCCESS_FACTOR
|
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
|
return attackers_success
|
||||||
else:
|
else:
|
||||||
return not attackers_success
|
return not attackers_success
|
||||||
@ -56,7 +56,7 @@ class InsurgentAttackEvent(Event):
|
|||||||
op = InsurgentAttackOperation(game=self.game,
|
op = InsurgentAttackOperation(game=self.game,
|
||||||
attacker_name=self.attacker_name,
|
attacker_name=self.attacker_name,
|
||||||
defender_name=self.defender_name,
|
defender_name=self.defender_name,
|
||||||
from_cp=self.from_cp,
|
from_cp=self.departure_cp,
|
||||||
to_cp=self.to_cp)
|
to_cp=self.to_cp)
|
||||||
op.setup(target=self.targets,
|
op.setup(target=self.targets,
|
||||||
strikegroup=flights[CAS])
|
strikegroup=flights[CAS])
|
||||||
|
|||||||
@ -25,7 +25,7 @@ class InterceptEvent(Event):
|
|||||||
return "Escort flight"
|
return "Escort flight"
|
||||||
|
|
||||||
def _enemy_scramble_multiplier(self) -> float:
|
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
|
return self.game.settings.multiplier * is_global and 0.5 or 1
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -34,7 +34,7 @@ class InterceptEvent(Event):
|
|||||||
|
|
||||||
def is_successfull(self, debriefing: Debriefing):
|
def is_successfull(self, debriefing: Debriefing):
|
||||||
units_destroyed = debriefing.destroyed_units[self.defender_name].get(self.transport_unit, 0)
|
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
|
return units_destroyed > 0
|
||||||
else:
|
else:
|
||||||
return units_destroyed == 0
|
return units_destroyed == 0
|
||||||
@ -47,11 +47,11 @@ class InterceptEvent(Event):
|
|||||||
for _, cp in self.game.theater.conflicts(True):
|
for _, cp in self.game.theater.conflicts(True):
|
||||||
cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
||||||
else:
|
else:
|
||||||
self.from_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
self.departure_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
||||||
else:
|
else:
|
||||||
# enemy attacking
|
# enemy attacking
|
||||||
if self.is_successfull(debriefing):
|
if self.is_successfull(debriefing):
|
||||||
self.from_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
self.departure_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
||||||
else:
|
else:
|
||||||
self.to_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
self.to_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ class InterceptEvent(Event):
|
|||||||
op = InterceptOperation(game=self.game,
|
op = InterceptOperation(game=self.game,
|
||||||
attacker_name=self.attacker_name,
|
attacker_name=self.attacker_name,
|
||||||
defender_name=self.defender_name,
|
defender_name=self.defender_name,
|
||||||
from_cp=self.from_cp,
|
from_cp=self.departure_cp,
|
||||||
to_cp=self.to_cp)
|
to_cp=self.to_cp)
|
||||||
|
|
||||||
op.setup(escort=assigned_units_from(escort),
|
op.setup(escort=assigned_units_from(escort),
|
||||||
@ -84,7 +84,7 @@ class InterceptEvent(Event):
|
|||||||
def player_defending(self, flights: db.TaskForceDict):
|
def player_defending(self, flights: db.TaskForceDict):
|
||||||
assert CAP in flights and len(flights) == 1, "Invalid flights"
|
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))
|
self.transport_unit = random.choice(db.find_unittype(Transport, self.defender_name))
|
||||||
assert self.transport_unit is not None
|
assert self.transport_unit is not None
|
||||||
@ -92,7 +92,7 @@ class InterceptEvent(Event):
|
|||||||
op = InterceptOperation(game=self.game,
|
op = InterceptOperation(game=self.game,
|
||||||
attacker_name=self.attacker_name,
|
attacker_name=self.attacker_name,
|
||||||
defender_name=self.defender_name,
|
defender_name=self.defender_name,
|
||||||
from_cp=self.from_cp,
|
from_cp=self.departure_cp,
|
||||||
to_cp=self.to_cp)
|
to_cp=self.to_cp)
|
||||||
|
|
||||||
op.setup(escort=flights[CAP],
|
op.setup(escort=flights[CAP],
|
||||||
|
|||||||
@ -33,8 +33,8 @@ class NavalInterceptEvent(Event):
|
|||||||
@property
|
@property
|
||||||
def threat_description(self):
|
def threat_description(self):
|
||||||
s = "{} ship(s)".format(self._targets_count())
|
s = "{} ship(s)".format(self._targets_count())
|
||||||
if not self.from_cp.captured:
|
if not self.departure_cp.captured:
|
||||||
s += ", {} aircraft".format(self.from_cp.base.scramble_count(self.game.settings.multiplier))
|
s += ", {} aircraft".format(self.departure_cp.base.scramble_count(self.game.settings.multiplier))
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def is_successfull(self, debriefing: Debriefing):
|
def is_successfull(self, debriefing: Debriefing):
|
||||||
@ -44,7 +44,7 @@ class NavalInterceptEvent(Event):
|
|||||||
if unit in self.targets:
|
if unit in self.targets:
|
||||||
destroyed_targets += count
|
destroyed_targets += count
|
||||||
|
|
||||||
if self.from_cp.captured:
|
if self.departure_cp.captured:
|
||||||
return math.ceil(float(destroyed_targets) / total_targets) > self.SUCCESS_RATE
|
return math.ceil(float(destroyed_targets) / total_targets) > self.SUCCESS_RATE
|
||||||
else:
|
else:
|
||||||
return math.ceil(float(destroyed_targets) / total_targets) < self.SUCCESS_RATE
|
return math.ceil(float(destroyed_targets) / total_targets) < self.SUCCESS_RATE
|
||||||
@ -56,11 +56,11 @@ class NavalInterceptEvent(Event):
|
|||||||
if self.is_successfull(debriefing):
|
if self.is_successfull(debriefing):
|
||||||
self.to_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
self.to_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
||||||
else:
|
else:
|
||||||
self.from_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
self.departure_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
||||||
else:
|
else:
|
||||||
# enemy attacking
|
# enemy attacking
|
||||||
if self.is_successfull(debriefing):
|
if self.is_successfull(debriefing):
|
||||||
self.from_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
self.departure_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
||||||
else:
|
else:
|
||||||
self.to_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
self.to_cp.base.affect_strength(-self.STRENGTH_INFLUENCE)
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ class NavalInterceptEvent(Event):
|
|||||||
self.game,
|
self.game,
|
||||||
attacker_name=self.attacker_name,
|
attacker_name=self.attacker_name,
|
||||||
defender_name=self.defender_name,
|
defender_name=self.defender_name,
|
||||||
from_cp=self.from_cp,
|
from_cp=self.departure_cp,
|
||||||
to_cp=self.to_cp
|
to_cp=self.to_cp
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -100,11 +100,11 @@ class NavalInterceptEvent(Event):
|
|||||||
self.game,
|
self.game,
|
||||||
attacker_name=self.attacker_name,
|
attacker_name=self.attacker_name,
|
||||||
defender_name=self.defender_name,
|
defender_name=self.defender_name,
|
||||||
from_cp=self.from_cp,
|
from_cp=self.departure_cp,
|
||||||
to_cp=self.to_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),
|
op.setup(strikegroup=assigned_units_from(strikegroup),
|
||||||
interceptors=flights[CAP],
|
interceptors=flights[CAP],
|
||||||
targets=self.targets)
|
targets=self.targets)
|
||||||
|
|||||||
@ -49,7 +49,7 @@ class StrikeEvent(Event):
|
|||||||
self.game,
|
self.game,
|
||||||
attacker_name=self.attacker_name,
|
attacker_name=self.attacker_name,
|
||||||
defender_name=self.defender_name,
|
defender_name=self.defender_name,
|
||||||
from_cp=self.from_cp,
|
from_cp=self.departure_cp,
|
||||||
to_cp=self.to_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
|
# skip strikes in case of no targets
|
||||||
return
|
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):
|
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)]:
|
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
|
# skip base attack if strength is too high
|
||||||
return
|
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):
|
def _generate_events(self):
|
||||||
for player_cp, enemy_cp in self.theater.conflicts(True):
|
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):
|
def pass_turn(self, no_action=False, ignored_cps: typing.Collection[ControlPoint]=None):
|
||||||
logging.info("Pass turn")
|
logging.info("Pass turn")
|
||||||
for event in self.events:
|
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:
|
if not no_action:
|
||||||
self._budget_player()
|
self._budget_player()
|
||||||
@ -286,5 +291,5 @@ class Game:
|
|||||||
|
|
||||||
self.events = [] # type: typing.List[Event]
|
self.events = [] # type: typing.List[Event]
|
||||||
self._generate_events()
|
self._generate_events()
|
||||||
self._generate_globalinterceptions()
|
#self._generate_globalinterceptions()
|
||||||
|
|
||||||
|
|||||||
@ -102,9 +102,5 @@ class ConflictTheater:
|
|||||||
for connected_point in [x for x in cp.connected_points if x.captured != from_player]:
|
for connected_point in [x for x in cp.connected_points if x.captured != from_player]:
|
||||||
yield (cp, connected_point)
|
yield (cp, connected_point)
|
||||||
|
|
||||||
for global_cp in [x for x in self.controlpoints if x.is_global and x.captured == from_player]:
|
|
||||||
if global_cp.position.distance_to_point(connected_point.position) < GLOBAL_CP_CONFLICT_DISTANCE_MIN:
|
|
||||||
yield (global_cp, connected_point)
|
|
||||||
|
|
||||||
def enemy_points(self) -> typing.Collection[ControlPoint]:
|
def enemy_points(self) -> typing.Collection[ControlPoint]:
|
||||||
return [point for point in self.controlpoints if not point.captured]
|
return [point for point in self.controlpoints if not point.captured]
|
||||||
|
|||||||
@ -20,7 +20,7 @@ class EventMenu(Menu):
|
|||||||
self.scramble_entries = {k: {} for k in self.event.tasks}
|
self.scramble_entries = {k: {} for k in self.event.tasks}
|
||||||
|
|
||||||
if self.event.attacker_name == self.game.player:
|
if self.event.attacker_name == self.game.player:
|
||||||
self.base = self.event.from_cp.base
|
self.base = self.event.departure_cp.base
|
||||||
else:
|
else:
|
||||||
self.base = self.event.to_cp.base
|
self.base = self.event.to_cp.base
|
||||||
|
|
||||||
@ -195,11 +195,10 @@ class EventMenu(Menu):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if isinstance(self.event, FrontlineAttackEvent) or isinstance(self.event, FrontlinePatrolEvent):
|
if isinstance(self.event, FrontlineAttackEvent) or isinstance(self.event, FrontlinePatrolEvent):
|
||||||
if tasks_scramble_counts.get(PinpointStrike, 0) == 0:
|
if self.base.total_armor == 0:
|
||||||
self.error_label["text"] = "No ground vehicles assigned to attack!"
|
self.error_label["text"] = "No ground vehicles available to attack!"
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
if self.game.is_player_attack(self.event):
|
if self.game.is_player_attack(self.event):
|
||||||
self.event.player_attacking(flights)
|
self.event.player_attacking(flights)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@ -41,6 +41,7 @@ class MainMenu(Menu):
|
|||||||
column = 0
|
column = 0
|
||||||
row = 0
|
row = 0
|
||||||
|
|
||||||
|
"""
|
||||||
def label(text):
|
def label(text):
|
||||||
nonlocal row, body
|
nonlocal row, body
|
||||||
frame = LabelFrame(body, **STYLES["label-frame"])
|
frame = LabelFrame(body, **STYLES["label-frame"])
|
||||||
@ -104,6 +105,7 @@ class MainMenu(Menu):
|
|||||||
label(str(event))
|
label(str(event))
|
||||||
else:
|
else:
|
||||||
event_button(event)
|
event_button(event)
|
||||||
|
"""
|
||||||
|
|
||||||
def pass_turn(self):
|
def pass_turn(self):
|
||||||
self.game.pass_turn(no_action=True)
|
self.game.pass_turn(no_action=True)
|
||||||
@ -113,7 +115,7 @@ class MainMenu(Menu):
|
|||||||
ConfigurationMenu(self.window, self, self.game).display()
|
ConfigurationMenu(self.window, self, self.game).display()
|
||||||
|
|
||||||
def start_event(self, event) -> typing.Callable:
|
def start_event(self, event) -> typing.Callable:
|
||||||
return lambda: EventMenu(self.window, self, self.game, event).display()
|
EventMenu(self.window, self, self.game, event).display()
|
||||||
|
|
||||||
def go_cp(self, cp: ControlPoint):
|
def go_cp(self, cp: ControlPoint):
|
||||||
if not cp.captured:
|
if not cp.captured:
|
||||||
|
|||||||
@ -10,6 +10,9 @@ from ui.styles import STYLES
|
|||||||
from ui.window import *
|
from ui.window import *
|
||||||
|
|
||||||
|
|
||||||
|
EVENT_DEPARTURE_MAX_DISTANCE = 250000
|
||||||
|
|
||||||
|
|
||||||
class OverviewCanvas:
|
class OverviewCanvas:
|
||||||
mainmenu = None # type: ui.mainmenu.MainMenu
|
mainmenu = None # type: ui.mainmenu.MainMenu
|
||||||
|
|
||||||
@ -29,6 +32,8 @@ class OverviewCanvas:
|
|||||||
HEIGHT = 600
|
HEIGHT = 600
|
||||||
|
|
||||||
started = None
|
started = None
|
||||||
|
selected_event_info = None # type: typing.Tuple[Event, typing.Tuple[int, int]]
|
||||||
|
frontline_vector_cache = None # type: typing.Dict[str, typing.Tuple[Point, int, int]]
|
||||||
|
|
||||||
def __init__(self, frame: Frame, parent, game: Game):
|
def __init__(self, frame: Frame, parent, game: Game):
|
||||||
|
|
||||||
@ -47,8 +52,8 @@ class OverviewCanvas:
|
|||||||
self.expanded = True
|
self.expanded = True
|
||||||
|
|
||||||
pygame.font.init()
|
pygame.font.init()
|
||||||
self.font:pygame.font.SysFont = pygame.font.SysFont("arial", 15)
|
self.font: pygame.font.SysFont = pygame.font.SysFont("arial", 15)
|
||||||
self.fontsmall:pygame.font.SysFont = pygame.font.SysFont("arial", 10)
|
self.fontsmall: pygame.font.SysFont = pygame.font.SysFont("arial", 10)
|
||||||
self.icons = {}
|
self.icons = {}
|
||||||
|
|
||||||
# Frontline are too heavy on performance to compute in realtime, so keep them in a cache
|
# Frontline are too heavy on performance to compute in realtime, so keep them in a cache
|
||||||
@ -84,7 +89,6 @@ class OverviewCanvas:
|
|||||||
self.init_sdl_thread()
|
self.init_sdl_thread()
|
||||||
|
|
||||||
def build_map_options_panel(self):
|
def build_map_options_panel(self):
|
||||||
|
|
||||||
def force_redraw():
|
def force_redraw():
|
||||||
if self.screen:
|
if self.screen:
|
||||||
self.redraw_required = True
|
self.redraw_required = True
|
||||||
@ -130,7 +134,6 @@ class OverviewCanvas:
|
|||||||
self.thread.join()
|
self.thread.join()
|
||||||
|
|
||||||
def init_sdl_layer(self):
|
def init_sdl_layer(self):
|
||||||
|
|
||||||
# Setup pygame to run in tk frame
|
# Setup pygame to run in tk frame
|
||||||
os.environ['SDL_WINDOWID'] = str(self.embed.winfo_id())
|
os.environ['SDL_WINDOWID'] = str(self.embed.winfo_id())
|
||||||
if platform.system == "Windows":
|
if platform.system == "Windows":
|
||||||
@ -185,9 +188,7 @@ class OverviewCanvas:
|
|||||||
print("Stopped SDL app")
|
print("Stopped SDL app")
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
#self.parent.window.tk.winfo_ismapped()
|
|
||||||
self.embed.winfo_ismapped()
|
self.embed.winfo_ismapped()
|
||||||
self.embed.winfo_manager()
|
self.embed.winfo_manager()
|
||||||
except:
|
except:
|
||||||
@ -234,7 +235,6 @@ class OverviewCanvas:
|
|||||||
self.zoom = 10
|
self.zoom = 10
|
||||||
|
|
||||||
if self.redraw_required:
|
if self.redraw_required:
|
||||||
|
|
||||||
# Fill
|
# Fill
|
||||||
self.screen.fill(self.BACKGROUND)
|
self.screen.fill(self.BACKGROUND)
|
||||||
self.overlay.fill(pygame.Color(0, 0, 0, 0))
|
self.overlay.fill(pygame.Color(0, 0, 0, 0))
|
||||||
@ -243,7 +243,7 @@ class OverviewCanvas:
|
|||||||
cursor_pos = pygame.mouse.get_pos()
|
cursor_pos = pygame.mouse.get_pos()
|
||||||
cursor_pos = (
|
cursor_pos = (
|
||||||
cursor_pos[0] / self.zoom - self.scroll[0], cursor_pos[1] / self.zoom - self.scroll[1])
|
cursor_pos[0] / self.zoom - self.scroll[0], cursor_pos[1] / self.zoom - self.scroll[1])
|
||||||
self.draw_map(self.surface, self.overlay, cursor_pos, (left_down, right_down))
|
self.draw_map(self.surface, self.overlay, cursor_pos, [left_down, right_down])
|
||||||
|
|
||||||
# Scaling
|
# Scaling
|
||||||
scaled = pygame.transform.scale(self.surface, (
|
scaled = pygame.transform.scale(self.surface, (
|
||||||
@ -255,9 +255,7 @@ class OverviewCanvas:
|
|||||||
|
|
||||||
self.redraw_required = False
|
self.redraw_required = False
|
||||||
|
|
||||||
def draw_map(self, surface: pygame.Surface, overlay: pygame.Surface, mouse_pos: (int, int),
|
def draw_map(self, surface: pygame.Surface, overlay: pygame.Surface, mouse_pos: (int, int), mouse_down: [bool, bool]):
|
||||||
mouse_down: (bool, bool)):
|
|
||||||
|
|
||||||
self.surface.blit(self.map, (0, 0))
|
self.surface.blit(self.map, (0, 0))
|
||||||
|
|
||||||
# Display zoom level on overlay
|
# Display zoom level on overlay
|
||||||
@ -269,8 +267,7 @@ class OverviewCanvas:
|
|||||||
# pygame.draw.rect(surface, (255, 0, 255), (mouse_pos[0], mouse_pos[1], 5, 5), 2)
|
# pygame.draw.rect(surface, (255, 0, 255), (mouse_pos[0], mouse_pos[1], 5, 5), 2)
|
||||||
|
|
||||||
for cp in self.game.theater.controlpoints:
|
for cp in self.game.theater.controlpoints:
|
||||||
|
coords = self._transform_point(cp.position)
|
||||||
coords = self.transform_point(cp.position)
|
|
||||||
|
|
||||||
if self.display_ground_targets.get():
|
if self.display_ground_targets.get():
|
||||||
if cp.captured:
|
if cp.captured:
|
||||||
@ -278,14 +275,13 @@ class OverviewCanvas:
|
|||||||
else:
|
else:
|
||||||
color = self._enemy_color()
|
color = self._enemy_color()
|
||||||
for ground_object in cp.ground_objects:
|
for ground_object in cp.ground_objects:
|
||||||
x, y = self.transform_point(ground_object.position)
|
x, y = self._transform_point(ground_object.position)
|
||||||
pygame.draw.line(surface, color, coords, (x + 8, y + 8), 1)
|
pygame.draw.line(surface, color, coords, (x + 8, y + 8), 1)
|
||||||
self.draw_ground_object(ground_object, surface, color, mouse_pos)
|
self.draw_ground_object(ground_object, surface, color, mouse_pos)
|
||||||
|
|
||||||
if self.display_road.get():
|
if self.display_road.get():
|
||||||
|
|
||||||
for connected_cp in cp.connected_points:
|
for connected_cp in cp.connected_points:
|
||||||
connected_coords = self.transform_point(connected_cp.position)
|
connected_coords = self._transform_point(connected_cp.position)
|
||||||
if connected_cp.captured != cp.captured:
|
if connected_cp.captured != cp.captured:
|
||||||
color = self._enemy_color()
|
color = self._enemy_color()
|
||||||
elif connected_cp.captured and cp.captured:
|
elif connected_cp.captured and cp.captured:
|
||||||
@ -296,15 +292,7 @@ class OverviewCanvas:
|
|||||||
pygame.draw.line(surface, color, coords, connected_coords, 2)
|
pygame.draw.line(surface, color, coords, connected_coords, 2)
|
||||||
|
|
||||||
if cp.captured and not connected_cp.captured and Conflict.has_frontline_between(cp, connected_cp):
|
if cp.captured and not connected_cp.captured and Conflict.has_frontline_between(cp, connected_cp):
|
||||||
|
frontline = self._frontline_vector(cp, connected_cp)
|
||||||
# Cache mechanism to avoid performing frontline vector computation on every frame
|
|
||||||
key = str(cp.id) + "_" + str(connected_cp.id)
|
|
||||||
if key in self.frontline_vector_cache:
|
|
||||||
frontline = self.frontline_vector_cache[key]
|
|
||||||
else:
|
|
||||||
frontline = Conflict.frontline_vector(cp, connected_cp, self.game.theater)
|
|
||||||
self.frontline_vector_cache[key] = frontline
|
|
||||||
|
|
||||||
if not frontline:
|
if not frontline:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@ -314,66 +302,79 @@ class OverviewCanvas:
|
|||||||
frontline_pos = frontline_pos.point_from_heading(heading + 180, 5000)
|
frontline_pos = frontline_pos.point_from_heading(heading + 180, 5000)
|
||||||
distance = 10000
|
distance = 10000
|
||||||
|
|
||||||
start_coords = self.transform_point(frontline_pos, treshold=10)
|
start_coords = self._transform_point(frontline_pos, treshold=10)
|
||||||
end_coords = self.transform_point(frontline_pos.point_from_heading(heading, distance),
|
end_coords = self._transform_point(frontline_pos.point_from_heading(heading, distance),
|
||||||
treshold=60)
|
treshold=60)
|
||||||
|
|
||||||
pygame.draw.line(surface, color, start_coords, end_coords, 4)
|
pygame.draw.line(surface, color, start_coords, end_coords, 4)
|
||||||
|
|
||||||
if self.display_bases.get():
|
if self.display_bases.get():
|
||||||
for cp in self.game.theater.controlpoints:
|
mouse_down = self.draw_bases(mouse_pos, mouse_down)
|
||||||
coords = self.transform_point(cp.position)
|
|
||||||
radius = 12 * math.pow(cp.importance, 1)
|
|
||||||
radius_m = radius * cp.base.strength - 2
|
|
||||||
|
|
||||||
if cp.captured:
|
mouse_down = self.draw_events(self.surface, mouse_pos, mouse_down)
|
||||||
color = self._player_color()
|
|
||||||
|
if mouse_down[0]:
|
||||||
|
self.selected_event_info = None
|
||||||
|
|
||||||
|
def draw_bases(self, mouse_pos, mouse_down):
|
||||||
|
for cp in self.game.theater.controlpoints:
|
||||||
|
coords = self._transform_point(cp.position)
|
||||||
|
radius = 12 * math.pow(cp.importance, 1)
|
||||||
|
radius_m = radius * cp.base.strength - 2
|
||||||
|
|
||||||
|
if cp.captured:
|
||||||
|
color = self._player_color()
|
||||||
|
else:
|
||||||
|
color = self._enemy_color()
|
||||||
|
|
||||||
|
pygame.draw.circle(self.surface, self.BLACK, (int(coords[0]), int(coords[1])), int(radius))
|
||||||
|
pygame.draw.circle(self.surface, color, (int(coords[0]), int(coords[1])), int(radius_m))
|
||||||
|
|
||||||
|
label = self.font.render(cp.name, self.ANTIALIASING, (225, 225, 225), self.BLACK)
|
||||||
|
labelHover = self.font.render(cp.name, self.ANTIALIASING, (255, 255, 255), (128, 186, 128))
|
||||||
|
labelClick = self.font.render(cp.name, self.ANTIALIASING, (255, 255, 255), (122, 122, 255))
|
||||||
|
|
||||||
|
point = coords[0] - label.get_width() / 2 + 1, coords[1] + 1
|
||||||
|
rect = pygame.Rect(*point, label.get_width(), label.get_height())
|
||||||
|
|
||||||
|
if rect.collidepoint(*mouse_pos):
|
||||||
|
if mouse_down[0]:
|
||||||
|
self.surface.blit(labelClick, (coords[0] - label.get_width() / 2 + 1, coords[1] + 1))
|
||||||
|
self._selected_cp(cp)
|
||||||
|
mouse_down[0] = False
|
||||||
else:
|
else:
|
||||||
color = self._enemy_color()
|
self.surface.blit(labelHover, (coords[0] - label.get_width() / 2 + 1, coords[1] + 1))
|
||||||
|
|
||||||
pygame.draw.circle(surface, self.BLACK, (int(coords[0]), int(coords[1])), int(radius))
|
self.draw_base_info(self.overlay, cp, (0, 0))
|
||||||
pygame.draw.circle(surface, color, (int(coords[0]), int(coords[1])), int(radius_m))
|
if self.selected_event_info and cp.captured and self.selected_event_info[0].location.distance_to_point(cp.position) < EVENT_DEPARTURE_MAX_DISTANCE:
|
||||||
|
pygame.draw.line(self.surface, self.WHITE, point, self.selected_event_info[1])
|
||||||
|
|
||||||
label = self.font.render(cp.name, self.ANTIALIASING, (225, 225, 225), self.BLACK)
|
else:
|
||||||
labelHover = self.font.render(cp.name, self.ANTIALIASING, (255, 255, 255), (128, 186, 128))
|
self.surface.blit(label, (coords[0] - label.get_width() / 2 + 1, coords[1] + 1))
|
||||||
labelClick = self.font.render(cp.name, self.ANTIALIASING, (255, 255, 255), (122, 122, 255))
|
|
||||||
|
|
||||||
rect = pygame.Rect(coords[0] - label.get_width() / 2 + 1, coords[1] + 1, label.get_width(),
|
if self.display_forces.get():
|
||||||
label.get_height())
|
units_title = " {} / {} / {} ".format(cp.base.total_planes, cp.base.total_armor, cp.base.total_aa)
|
||||||
|
label2 = self.fontsmall.render(units_title, self.ANTIALIASING, color, (30, 30, 30))
|
||||||
|
self.surface.blit(label2, (coords[0] - label2.get_width() / 2, coords[1] + label.get_height() + 1))
|
||||||
|
|
||||||
if rect.collidepoint(mouse_pos):
|
return mouse_down
|
||||||
if (mouse_down[0]):
|
|
||||||
surface.blit(labelClick, (coords[0] - label.get_width() / 2 + 1, coords[1] + 1))
|
|
||||||
self.parent.go_cp(cp)
|
|
||||||
else:
|
|
||||||
surface.blit(labelHover, (coords[0] - label.get_width() / 2 + 1, coords[1] + 1))
|
|
||||||
|
|
||||||
self.draw_base_info(overlay, cp, (0, 0))
|
def draw_base_info(self, surface: pygame.Surface, control_point: ControlPoint, pos):
|
||||||
|
title = self.font.render(control_point.name, self.ANTIALIASING, self.BLACK, self.GREEN)
|
||||||
else:
|
|
||||||
surface.blit(label, (coords[0] - label.get_width() / 2 + 1, coords[1] + 1))
|
|
||||||
|
|
||||||
if self.display_forces.get():
|
|
||||||
units_title = " {} / {} / {} ".format(cp.base.total_planes, cp.base.total_armor, cp.base.total_aa)
|
|
||||||
label2 = self.fontsmall.render(units_title, self.ANTIALIASING, color, (30, 30, 30))
|
|
||||||
surface.blit(label2, (coords[0] - label2.get_width() / 2, coords[1] + label.get_height() + 1))
|
|
||||||
|
|
||||||
def draw_base_info(self, surface: pygame.Surface, controlPoint: ControlPoint, pos):
|
|
||||||
title = self.font.render(controlPoint.name, self.ANTIALIASING, self.BLACK, self.GREEN)
|
|
||||||
hp = self.font.render("Strength : ", self.ANTIALIASING, (225, 225, 225), self.BLACK)
|
hp = self.font.render("Strength : ", self.ANTIALIASING, (225, 225, 225), self.BLACK)
|
||||||
|
|
||||||
armor_txt = "ARMOR > "
|
armor_txt = "ARMOR > "
|
||||||
for key, value in controlPoint.base.armor.items():
|
for key, value in control_point.base.armor.items():
|
||||||
armor_txt += key.id + " x " + str(value) + " | "
|
armor_txt += key.id + " x " + str(value) + " | "
|
||||||
armor = self.font.render(armor_txt, self.ANTIALIASING, (225, 225, 225), self.BLACK)
|
armor = self.font.render(armor_txt, self.ANTIALIASING, (225, 225, 225), self.BLACK)
|
||||||
|
|
||||||
aircraft_txt = "AIRCRAFT > "
|
aircraft_txt = "AIRCRAFT > "
|
||||||
for key, value in controlPoint.base.aircraft.items():
|
for key, value in control_point.base.aircraft.items():
|
||||||
aircraft_txt += key.id + " x " + str(value) + " | "
|
aircraft_txt += key.id + " x " + str(value) + " | "
|
||||||
aircraft = self.font.render(aircraft_txt, self.ANTIALIASING, (225, 225, 225), self.BLACK)
|
aircraft = self.font.render(aircraft_txt, self.ANTIALIASING, (225, 225, 225), self.BLACK)
|
||||||
|
|
||||||
aa_txt = "AA/SAM > "
|
aa_txt = "AA/SAM > "
|
||||||
for key, value in controlPoint.base.aa.items():
|
for key, value in control_point.base.aa.items():
|
||||||
aa_txt += key.id + " x " + str(value) + " | "
|
aa_txt += key.id + " x " + str(value) + " | "
|
||||||
aa = self.font.render(aa_txt, self.ANTIALIASING, (225, 225, 225), self.BLACK)
|
aa = self.font.render(aa_txt, self.ANTIALIASING, (225, 225, 225), self.BLACK)
|
||||||
|
|
||||||
@ -396,7 +397,7 @@ class OverviewCanvas:
|
|||||||
pygame.draw.rect(surface, self.BRIGHT_RED,
|
pygame.draw.rect(surface, self.BRIGHT_RED,
|
||||||
(pos[0] + hp.get_width() + 5, 4 + pos[1] + lineheight + 5 + 2, 50, lineheight - 4))
|
(pos[0] + hp.get_width() + 5, 4 + pos[1] + lineheight + 5 + 2, 50, lineheight - 4))
|
||||||
pygame.draw.rect(surface, self.BRIGHT_GREEN, (
|
pygame.draw.rect(surface, self.BRIGHT_GREEN, (
|
||||||
pos[0] + hp.get_width() + 5, 4 + pos[1] + lineheight + 5 + 2, 50 * controlPoint.base.strength, lineheight - 4))
|
pos[0] + hp.get_width() + 5, 4 + pos[1] + lineheight + 5 + 2, 50 * control_point.base.strength, lineheight - 4))
|
||||||
|
|
||||||
# Text
|
# Text
|
||||||
surface.blit(armor, (pos[0] + 4, 4 + pos[1] + lineheight * 2 + 10))
|
surface.blit(armor, (pos[0] + 4, 4 + pos[1] + lineheight * 2 + 10))
|
||||||
@ -404,7 +405,7 @@ class OverviewCanvas:
|
|||||||
surface.blit(aa, (pos[0] + 4, 4 + pos[1] + lineheight * 4 + 20))
|
surface.blit(aa, (pos[0] + 4, 4 + pos[1] + lineheight * 4 + 20))
|
||||||
|
|
||||||
def draw_ground_object(self, ground_object: TheaterGroundObject, surface: pygame.Surface, color, mouse_pos):
|
def draw_ground_object(self, ground_object: TheaterGroundObject, surface: pygame.Surface, color, mouse_pos):
|
||||||
x, y = self.transform_point(ground_object.position)
|
x, y = self._transform_point(ground_object.position)
|
||||||
rect = pygame.Rect(x, y, 16, 16)
|
rect = pygame.Rect(x, y, 16, 16)
|
||||||
|
|
||||||
if ground_object.is_dead:
|
if ground_object.is_dead:
|
||||||
@ -423,7 +424,50 @@ class OverviewCanvas:
|
|||||||
lb = self.font.render(str(ground_object), self.ANTIALIASING, color, self.BLACK)
|
lb = self.font.render(str(ground_object), self.ANTIALIASING, color, self.BLACK)
|
||||||
surface.blit(lb, (pos[0] + 18, pos[1]))
|
surface.blit(lb, (pos[0] + 18, pos[1]))
|
||||||
|
|
||||||
def transform_point(self, p: Point, treshold=30) -> (int, int):
|
def draw_events(self, surface: pygame.Surface, mouse_pos, mouse_down):
|
||||||
|
location_point_counters = {}
|
||||||
|
|
||||||
|
def _location_to_point(location: Point) -> typing.Tuple[int, int]:
|
||||||
|
nonlocal location_point_counters
|
||||||
|
key = str(location.x) + str(location.y)
|
||||||
|
|
||||||
|
point = self._transform_point(location)
|
||||||
|
point = point[0], point[1] + location_point_counters.get(key, 0) * 40
|
||||||
|
|
||||||
|
location_point_counters[key] = location_point_counters.get(key, 0) + 1
|
||||||
|
return point
|
||||||
|
|
||||||
|
for event in self.game.events:
|
||||||
|
location = event.location
|
||||||
|
if isinstance(event, FrontlinePatrolEvent) or isinstance(event, FrontlineAttackEvent):
|
||||||
|
location = self._frontline_center(event.from_cp, event.to_cp)
|
||||||
|
|
||||||
|
point = _location_to_point(location)
|
||||||
|
rect = pygame.Rect(*point, 30, 30)
|
||||||
|
pygame.draw.rect(surface, self.BLACK, rect)
|
||||||
|
|
||||||
|
if rect.collidepoint(*mouse_pos) or self.selected_event_info == (event, point):
|
||||||
|
line = self.font.render(str(event), self.ANTIALIASING, self.WHITE, self.BLACK)
|
||||||
|
surface.blit(line, rect.center)
|
||||||
|
|
||||||
|
if rect.collidepoint(*mouse_pos):
|
||||||
|
if mouse_down[0]:
|
||||||
|
self.selected_event_info = event, point
|
||||||
|
mouse_down[0] = False
|
||||||
|
|
||||||
|
return mouse_down
|
||||||
|
|
||||||
|
def _selected_cp(self, cp):
|
||||||
|
if self.selected_event_info:
|
||||||
|
event = self.selected_event_info[0]
|
||||||
|
event.departure_cp = cp
|
||||||
|
|
||||||
|
self.selected_event_info = None
|
||||||
|
self.parent.start_event(event)
|
||||||
|
else:
|
||||||
|
self.parent.go_cp(cp)
|
||||||
|
|
||||||
|
def _transform_point(self, p: Point, treshold=30) -> (int, int):
|
||||||
point_a = list(self.game.theater.reference_points.keys())[0]
|
point_a = list(self.game.theater.reference_points.keys())[0]
|
||||||
point_a_img = self.game.theater.reference_points[point_a]
|
point_a_img = self.game.theater.reference_points[point_a]
|
||||||
|
|
||||||
@ -448,6 +492,23 @@ class OverviewCanvas:
|
|||||||
|
|
||||||
return X > treshold and X or treshold, Y > treshold and Y or treshold
|
return X > treshold and X or treshold, Y > treshold and Y or treshold
|
||||||
|
|
||||||
|
def _frontline_vector(self, from_cp: ControlPoint, to_cp: ControlPoint):
|
||||||
|
# Cache mechanism to avoid performing frontline vector computation on every frame
|
||||||
|
key = str(from_cp.id) + "_" + str(to_cp.id)
|
||||||
|
if key in self.frontline_vector_cache:
|
||||||
|
return self.frontline_vector_cache[key]
|
||||||
|
else:
|
||||||
|
frontline = Conflict.frontline_vector(from_cp, to_cp, self.game.theater)
|
||||||
|
self.frontline_vector_cache[key] = frontline
|
||||||
|
return frontline
|
||||||
|
|
||||||
|
def _frontline_center(self, from_cp: ControlPoint, to_cp: ControlPoint) -> typing.Optional[Point]:
|
||||||
|
frontline_vector = self._frontline_vector(from_cp, to_cp)
|
||||||
|
if frontline_vector:
|
||||||
|
return frontline_vector[0].point_from_heading(frontline_vector[1], frontline_vector[2]/2)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
def _player_color(self):
|
def _player_color(self):
|
||||||
return self.game.player == "USA" and self.BLUE or self.RED
|
return self.game.player == "USA" and self.BLUE or self.RED
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,16 @@
|
|||||||
from tkinter import *
|
from tkinter import *
|
||||||
from tkinter import Menu as TkMenu
|
from tkinter import Menu as TkMenu
|
||||||
from tkinter import messagebox
|
from tkinter import messagebox
|
||||||
|
|
||||||
|
from .styles import BG_COLOR,BG_TITLE_COLOR
|
||||||
from game.game import *
|
from game.game import *
|
||||||
from theater import persiangulf, nevada, caucasus, start_generator
|
from theater import persiangulf, nevada, caucasus, start_generator
|
||||||
from .styles import BG_COLOR,BG_TITLE_COLOR
|
from userdata import logging as logging_module
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import webbrowser
|
import webbrowser
|
||||||
|
|
||||||
|
|
||||||
class Window:
|
class Window:
|
||||||
|
|
||||||
image = None
|
image = None
|
||||||
@ -84,7 +88,6 @@ class Window:
|
|||||||
self.build()
|
self.build()
|
||||||
|
|
||||||
def start_new_game(self, player_name: str, enemy_name: str, terrain: str, sams: bool, midgame: bool, multiplier: float):
|
def start_new_game(self, player_name: str, enemy_name: str, terrain: str, sams: bool, midgame: bool, multiplier: float):
|
||||||
|
|
||||||
if terrain == "persiangulf":
|
if terrain == "persiangulf":
|
||||||
conflicttheater = persiangulf.PersianGulfTheater()
|
conflicttheater = persiangulf.PersianGulfTheater()
|
||||||
elif terrain == "nevada":
|
elif terrain == "nevada":
|
||||||
@ -104,7 +107,7 @@ class Window:
|
|||||||
game.budget = int(game.budget * multiplier)
|
game.budget = int(game.budget * multiplier)
|
||||||
game.settings.multiplier = multiplier
|
game.settings.multiplier = multiplier
|
||||||
game.settings.sams = sams
|
game.settings.sams = sams
|
||||||
game.settings.version = "1.4.0"
|
game.settings.version = logging_module.version_string()
|
||||||
|
|
||||||
if midgame:
|
if midgame:
|
||||||
game.budget = game.budget * 4 * len(list(conflicttheater.conflicts()))
|
game.budget = game.budget * 4 * len(list(conflicttheater.conflicts()))
|
||||||
|
|||||||
@ -35,6 +35,10 @@ def setup_version_string(str):
|
|||||||
_version_string = str
|
_version_string = str
|
||||||
|
|
||||||
|
|
||||||
|
def version_string():
|
||||||
|
return _version_string
|
||||||
|
|
||||||
|
|
||||||
if "--stdout" in sys.argv:
|
if "--stdout" in sys.argv:
|
||||||
logging.basicConfig(stream=sys.stdout, level=logging.INFO)
|
logging.basicConfig(stream=sys.stdout, level=logging.INFO)
|
||||||
else:
|
else:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user