def __init__( self, name: str, background: BaseTexture, pass_map: PassMap, triggers: List[Trigger], player_position: Vector, scripts: Mapping[str, Callable[[], None]], path: Path, save_point: Optional[Object], ): self.name = name self.background = background self.pass_map = pass_map self.trigger_event_watchers = [ TriggerEventWatcher(trigger) for trigger in triggers ] self.player = Player(player_position) self.scripts = scripts self.path = path self.objects: WalList[Object] = WalList([]) self.named_objects: Dict[str, Object] = {} self.state: dict = {} self.sprites: WalList[BaseSprite] = WalList([]) self.save_point = save_point if save_point is not None: self.add_object(save_point) self._update_callbacks: WalList[Callable[[float], None]] = WalList([]) get_event_manager().subscribe('key:confirm', Subscriber(self.on_interact))
def finalize(self): get_event_manager().subscribe( 'end_of_cycle', Subscriber(lambda *args: get_game().overworld.unfreeze()), ) self.kill() self.on_finish_callback()
def hide(self, on_finish: Callable): self.spawn( RoomTransitionFadeIn( self.game.screen.get_size()).start_animation()) get_event_manager().subscribe( 'room_exit_animation_finished', Subscriber(lambda event_id, arg: on_finish()), )
async def _run_wrapper(self): try: await self.run() except BulletSpawner.TerminateCoroutine: pass except StopIteration: pass get_event_manager().raise_event('attack_finished')
def update(self, time_delta): delta = Vector(self.moving_x, self.moving_y) * (self.speed * time_delta) self.move(delta) if self._is_walking() and self._should_stop(): assert self._stop_event is not None get_event_manager().raise_event(self._stop_event, None) self._stop_event = None
def on_confirm(self, event, arg): del event, arg if not self.is_alive(): return if self.pages[self.page_index].has_animation_finished(): self.next() get_event_manager().subscribe('key:confirm', Subscriber(self.on_confirm))
def handler(event, arg): del event, arg nonlocal counter counter += 1 if counter == num_awaitables: get_event_manager().raise_event(all_finished_event) else: get_event_manager().subscribe(one_finished_event, Subscriber(handler))
def _on_interact_somewhere(self, *args): del args if not self.is_alive(): return if not get_game().overworld.is_frozen(): player = get_game().overworld.room.player if self.get_hitbox_with_position().colliderect( player.get_extended_hitbox()): self.on_interact() get_event_manager().subscribe('key:confirm', Subscriber(self._on_interact_somewhere))
def update(self, time_delta: float): # Handle events that occured since last check self.process_events() # Run scheduled callbacks get_pending_callback_queue().update() # Delegate the main update logic to the current game mode self.current_game_mode.update(time_delta) # Finalize the update cycle get_event_manager().raise_event('end_of_cycle', None, silent=True)
def load_room(self, room_name: str): logger.debug('Loading room {}', room_name) self._room_ready = False self.freeze() self.spawn( RoomTransitionFadeIn( self.game.screen.get_size()).start_animation()) get_event_manager().subscribe( 'room_exit_animation_finished', Subscriber( lambda event_id, arg: self._run_room_loading_logic(room_name)), )
async def run(self): if not DEBUG_SKIP: await display_text( load_text('fight/pre-lyceum/itt_test_cariel_tutorial')) menu = self.get_main_menu() while True: choice = await menu.choose() action = await self.get_action_for_choice(choice) if action is not None: await action() break get_event_manager().raise_event('fight_finished')
def on_interact(self, *args): del args if get_game().overworld.room is not self: return if not get_game().overworld.is_frozen(): affected_rect = get_game( ).overworld.room.player.get_extended_hitbox() for watcher in self.trigger_event_watchers: if affected_rect.colliderect(watcher.trigger.rect): watcher.pass_event(Event('interact')) get_event_manager().subscribe('key:confirm', Subscriber(self.on_interact))
def __init__( self, pos: Vector, texture: Optional[BaseTexture] = None, is_passable: bool = False, hitbox: Optional[pg.Rect] = None, ): super().__init__(pos) self.texture = texture self.is_passable = is_passable self.hitbox = hitbox if hitbox is not None else generate_hitbox(20, 20) get_event_manager().subscribe('key:confirm', Subscriber(self._on_interact_somewhere)) self.on_interact: Callable[[], Any] = lambda: None
async def run(self): await display_text(self.get_battle_entry_text()) while True: menu = self.get_main_menu() choice = await self.choose_from_menu_tree(menu) action = await self.get_action_for_choice(choice) await action() if self.has_battle_finished(): break await self.process_enemy_attack() if self.has_battle_finished(): break await self.on_finish() get_event_manager().raise_event('fight_finished')
def _run_room_loading_logic(self, room_name: str, player_pos: Optional[Vector] = None): if self._room_loaded: prev_room_name = self.room.name self.room.kill() else: prev_room_name = 'default' self.room = load_room( Path('.') / 'assets' / 'rooms' / room_name, prev_room_name, player_pos, ) self._room_screen = pg.Surface(self.room.get_size()) self.spawn( RoomTransitionFadeOut( self.game.screen.get_size()).start_animation()) subscriber = Subscriber( lambda event_id, arg: self._finalize_room_loading()) get_event_manager().subscribe('room_enter_animation_finished', subscriber)
async def walk(self, delta: Vector): assert self._target is None self._target = self.pos + delta direction = delta.normalized() self.set_moving(direction.x, direction.y) self._stop_event = get_event_manager().unique_id() await wait_for_event(self._stop_event) self.set_moving(0, 0) self.pos = self._target self._target = None
def process_events(self): for event in pg.event.get(): if event.type == pg.QUIT: raise GameExited() if event.type == pg.KEYDOWN: # Process all keys get_event_manager().raise_event('key:any', event) # Process special keys if event.key in (pg.K_z, pg.K_RETURN): get_event_manager().raise_event('key:confirm', event) if event.key in (pg.K_x, pg.K_LSHIFT, pg.K_RSHIFT): get_event_manager().raise_event('key:cancel', event) if event.key in (pg.K_c, pg.K_LCTRL, pg.K_RCTRL): get_event_manager().raise_event('key:menu', event)
async def gather(*awaitables): # XXX: This code is fascinatingly awful, but it serves for a good purpose, # allowing awaiting multiple coroutines at the same time one_finished_event = get_event_manager().unique_id() all_finished_event = get_event_manager().unique_id() counter = 0 num_awaitables = len(awaitables) def handler(event, arg): del event, arg nonlocal counter counter += 1 if counter == num_awaitables: get_event_manager().raise_event(all_finished_event) else: get_event_manager().subscribe(one_finished_event, Subscriber(handler)) get_event_manager().subscribe(one_finished_event, Subscriber(handler)) for aw in awaitables: # WARNING: this code is potentially dangerous, since `aw`, which is changed # by the outer loop, is captured by the inner function. In this very case, # however, everything is fine, because that function is called immediately # and is then discarded. # # TODO: refactor this code to make it more robust and to silence Pylint's # cell-var-from-import warning async def await_and_notify(*args, **kwargs): del args, kwargs await aw get_event_manager().raise_event(one_finished_event) SimpleScript(await_and_notify)() await wait_for_event(all_finished_event)
async def await_and_notify(*args, **kwargs): del args, kwargs await aw get_event_manager().raise_event(one_finished_event)
def initialize(self): get_game().overworld.freeze() get_event_manager().subscribe('key:confirm', Subscriber(self.on_confirm)) get_event_manager().subscribe('key:cancel', Subscriber(self.on_cancel)) self.next()
def make_callback(): event_id = get_event_manager().unique_id() callback = lambda *args, **kwargs: get_event_manager().raise_event(event_id, None) return event_id, callback
async def display_text(text): get_game().current_game_mode.spawn(text) event_id = get_event_manager().unique_id() text.on_finish_callback = lambda: get_event_manager().raise_event(event_id, None) text.initialize() await wait_for_event(event_id)
def wait_for_any_event(): script = get_game().current_script get_event_manager().subscribe_to_any_event(Subscriber(lambda event, arg: script((event, arg)))) return (yield)
def wait_for_event(event_id): script = get_game().current_script get_event_manager().subscribe(event_id, Subscriber(lambda event, arg: script((event, arg)))) return (yield)
def notify_after(delay: float, event_id: EventId, argument: Any = None): get_pending_callback_queue().fire_after( delay, lambda *args: get_event_manager().raise_event(event_id, argument), )
def set_timeout(self, new_timeout: float): self._timeout_event = get_event_manager().unique_id() notify_after(new_timeout, self._timeout_event)
def on_kill(self): get_event_manager().raise_event('hit_animation_finished')
def on_cancel(self, event, arg): del event, arg if not self.is_alive(): return self.pages[self.page_index].try_force_finish() get_event_manager().subscribe('key:cancel', Subscriber(self.on_cancel))