def handle_user_input(self, events: List[Any]) -> Optional[SceneTransition]: transition_to_pause = False events_triggered_from_ui: List[EventTriggeredFromUi] = [] # TODO handle dialog/no dialog more explicitly as states, and delegate more things to them (?) if self.ui_view.has_open_dialog(): self.game_state.game_world.player_entity.set_not_moving() user_actions = get_dialog_actions(events) for action in user_actions: if isinstance(action, ActionChangeDialogOption): npc_type, previous_index, new_index = self.ui_view.change_dialog_option( action.index_delta) self._handle_dialog_change_option(npc_type, previous_index, new_index) if isinstance(action, ActionPressSpaceKey): result = self.ui_view.handle_space_click() if result: npc_in_dialog, option_index = result npc_type = npc_in_dialog.npc_type blur_npc_action(npc_type, option_index, self.game_state, self.ui_view) message = select_npc_action(npc_type, option_index, self.game_engine) if message: self.ui_view.info_message.set_message(message) npc_in_dialog.stun_status.remove_one() # User may have been holding down a key when starting dialog, and then releasing it while in # dialog. It's safer then to treat all keys as released when we exit the dialog. self.user_input_handler.forget_held_down_keys() if isinstance(action, ActionMouseMovement): self.ui_view.handle_mouse_movement_in_dialog( action.mouse_screen_position) # we handle "normal UI" mouse movement here primarily so that you can hover your equipment # while in a dialog. (especially important when buying from an NPC) self.ui_view.handle_mouse_movement( action.mouse_screen_position) if isinstance(action, ActionMouseClicked): result = self.ui_view.handle_mouse_click_in_dialog() if result: npc_type, previous_index, new_index = result self._handle_dialog_change_option( npc_type, previous_index, new_index) else: user_actions = self.user_input_handler.get_actions(events) for action in user_actions: if isinstance(action, ActionToggleRenderDebugging): self.render_hit_and_collision_boxes = not self.render_hit_and_collision_boxes # TODO: Handle this better than accessing a global variable from here pythongame.core.pathfinding.npc_pathfinding.DEBUG_RENDER_PATHFINDING = \ not pythongame.core.pathfinding.npc_pathfinding.DEBUG_RENDER_PATHFINDING elif isinstance(action, ActionTryUseAbility): self.game_engine.try_use_ability(action.ability_type) elif isinstance(action, ActionTryUsePotion): self.game_engine.try_use_consumable(action.slot_number) elif isinstance(action, ActionMoveInDirection): self.game_engine.move_in_direction(action.direction) elif isinstance(action, ActionStopMoving): self.game_engine.stop_moving() elif isinstance(action, ActionPauseGame): transition_to_pause = True elif isinstance(action, ActionMouseMovement): self.ui_view.handle_mouse_movement( action.mouse_screen_position) elif isinstance(action, ActionMouseClicked): events_triggered_from_ui += self.ui_view.handle_mouse_click( ) elif isinstance(action, ActionMouseReleased): events_triggered_from_ui += self.ui_view.handle_mouse_release( ) elif isinstance(action, ActionRightMouseClicked): events_triggered_from_ui += self.ui_view.handle_mouse_right_click( ) elif isinstance(action, ActionPressSpaceKey): ready_entity = self.player_interactions_state.get_entity_to_interact_with( ) if ready_entity is not None: if isinstance(ready_entity, NonPlayerCharacter): ready_entity.world_entity.direction = get_directions_to_position( ready_entity.world_entity, self.game_state.game_world.player_entity. get_center_position())[0] ready_entity.world_entity.set_not_moving() ready_entity.stun_status.add_one() npc_type = ready_entity.npc_type dialog_data = get_dialog_data( npc_type, self.game_state) option_index = self.ui_view.start_dialog_with_npc( ready_entity, dialog_data) play_sound(SoundId.DIALOG) hover_npc_action(npc_type, option_index, self.game_state, self.ui_view) elif isinstance(ready_entity, LootableOnGround): self.game_engine.try_pick_up_loot_from_ground( ready_entity) elif isinstance(ready_entity, Portal): self.game_engine.interact_with_portal(ready_entity) elif isinstance(ready_entity, WarpPoint): self.game_engine.use_warp_point(ready_entity) elif isinstance(ready_entity, Chest): self.game_engine.open_chest(ready_entity) elif isinstance(ready_entity, Shrine): self.game_engine.interact_with_shrine(ready_entity) elif isinstance(ready_entity, DungeonEntrance): has_key = self.game_state.player_state.item_inventory.has_item_in_inventory( plain_item_id(ItemType.PORTAL_KEY)) if has_key: entering_dungeon_scene = self.scene_factory.switching_game_world( self.game_engine, self.character_file, self.total_time_played_on_character, self._create_dungeon_engine_and_behavior) return SceneTransition(entering_dungeon_scene) else: self.ui_view.info_message.set_message( "There is a keyhole on the side!") else: raise Exception("Unhandled entity: " + str(ready_entity)) elif isinstance(action, ActionPressKey): events_triggered_from_ui += self.ui_view.handle_key_press( action.key) # TODO Much noise below around playing sounds. Perhaps game_engine should play the sounds in these cases? for event in events_triggered_from_ui: if isinstance(event, StartDraggingItemOrConsumable): play_sound(SoundId.UI_START_DRAGGING_ITEM) elif isinstance(event, DragItemBetweenInventorySlots): did_switch_succeed = self.game_engine.drag_item_between_inventory_slots( event.from_slot, event.to_slot) if did_switch_succeed: play_sound(SoundId.UI_ITEM_WAS_MOVED) else: play_sound(SoundId.INVALID_ACTION) elif isinstance(event, DropItemOnGround): world_position = _get_mouse_world_pos(self.game_state, event.screen_position) self.game_engine.drop_inventory_item_on_ground( event.from_slot, world_position) play_sound(SoundId.UI_ITEM_WAS_DROPPED_ON_GROUND) elif isinstance(event, DragConsumableBetweenInventorySlots): self.game_engine.drag_consumable_between_inventory_slots( event.from_slot, event.to_slot) play_sound(SoundId.UI_ITEM_WAS_MOVED) elif isinstance(event, DropConsumableOnGround): world_position = _get_mouse_world_pos(self.game_state, event.screen_position) self.game_engine.drop_consumable_on_ground( event.from_slot, world_position) play_sound(SoundId.UI_ITEM_WAS_DROPPED_ON_GROUND) elif isinstance(event, PickTalent): name_of_picked = pick_talent(self.game_state, event.tier_index, event.option_index) if not self.game_state.player_state.has_unpicked_talents(): self.ui_view.close_talent_window() self.ui_view.info_message.set_message("Talent picked: " + name_of_picked) play_sound(SoundId.EVENT_PICKED_TALENT) elif isinstance(event, TrySwitchItemInInventory): did_switch_succeed = self.game_engine.try_switch_item_at_slot( event.slot) if did_switch_succeed: play_sound(SoundId.UI_ITEM_WAS_MOVED) else: play_sound(SoundId.INVALID_ACTION) elif isinstance(event, ToggleSound): toggle_muted() elif isinstance(event, SaveGame): self._save_game() elif isinstance(event, ToggleFullscreen): self.toggle_fullscreen_callback() elif isinstance(event, ToggleWindow): play_sound(SoundId.UI_TOGGLE) else: raise Exception("Unhandled event: " + str(event)) if transition_to_pause: return SceneTransition( PausedScene(self, self.world_view, self.ui_view, self.game_state))
def _handle_dialog_change_option(self, npc_type: NpcType, previous_index: int, new_index: int): play_sound(SoundId.DIALOG) blur_npc_action(npc_type, previous_index, self.game_state, self.ui_view) hover_npc_action(npc_type, new_index, self.game_state, self.ui_view)