from typing import Optional import tcod from actions import BaseAction, QuitAction, BumpAction, WaitAction from engine import Engine #input options MOVE_KEYS = { #arrow keys tcod.event.KeySym.UP: (0, -1), tcod.event.KeySym.DOWN: (0, 1), tcod.event.KeySym.LEFT: (-1, 0), tcod.event.KeySym.RIGHT: (1, 0), tcod.event.KeySym.HOME: (-1, -1), tcod.event.KeySym.END: (-1, 1), tcod.event.KeySym.PAGEUP: (1, -1), tcod.event.KeySym.PAGEDOWN: (1, 1), #numpad keys tcod.event.KeySym.KP_1: (-1, 1), tcod.event.KeySym.KP_2: (0, 1), tcod.event.KeySym.KP_3: (1, 1), tcod.event.KeySym.KP_4: (-1, 0), tcod.event.KeySym.KP_6: (1, 0), tcod.event.KeySym.KP_7: (-1, -1), tcod.event.KeySym.KP_8: (0, -1), tcod.event.KeySym.KP_9: (1, -1), #vi key mapping tcod.event.KeySym.h: (-1, 0), tcod.event.KeySym.j: (0, 1), tcod.event.KeySym.k: (0, -1), tcod.event.KeySym.l: (1, 0), tcod.event.KeySym.y: (-1, -1), tcod.event.KeySym.u: (1, -1), tcod.event.KeySym.b: (-1, 1), tcod.event.KeySym.n: (1, 1), } WAIT_KEYS = { tcod.event.KeySym.PERIOD, tcod.event.KeySym.KP_5, tcod.event.KeySym.CLEAR, } CURSOR_SCROLL_KEYS = { tcod.event.KeySym.UP: -1, tcod.event.KeySym.DOWN: 1, tcod.event.KeySym.PAGEUP: -10, tcod.event.KeySym.PAGEDOWN: 10, tcod.event.KeySym.KP_2: 1, tcod.event.KeySym.KP_8: -1, } #event handler is one part of the engine class EventHandler(tcod.event.EventDispatch[BaseAction]): def __init__(self, engine: Engine): super().__init__() self.engine = engine def render(self, console: tcod.console.Console) -> None: pass #no-op #callbacks def ev_quit(self, event: tcod.event.Quit) -> Optional[BaseAction]: return QuitAction() def handle_events(self, context: tcod.context.Context) -> bool: result = False for event in tcod.event.wait(): context.convert_event(event) action = self.dispatch(event) if action is None: continue result |= action.apply() #entity references the engine return result class InGameHandler(EventHandler): def ev_keydown(self, event: tcod.event.KeyDown) -> Optional[BaseAction]: key = event.sym #SDL stuff, neat. player = self.engine.player #player input if key == tcod.event.KeySym.ESCAPE: return QuitAction() if key in MOVE_KEYS: xdir, ydir = MOVE_KEYS[key] return BumpAction(player, xdir = xdir, ydir = ydir) if key in WAIT_KEYS: return WaitAction(player) if key == tcod.event.KeySym.v: self.engine.event_handler = LogHistoryViewer(self.engine) def ev_mousemotion(self, event: tcod.event.MouseMotion) -> None: if self.engine.floor_map.in_bounds(event.tile.x, event.tile.y): self.engine.mouse_location = event.tile.x, event.tile.y class GameOverHandler(EventHandler): def ev_keydown(self, event: tcod.event.KeyDown) -> Optional[BaseAction]: key = event.sym #SDL stuff, neat. #player input if key == tcod.event.KeySym.ESCAPE: return QuitAction() return None class LogHistoryViewer(EventHandler): def __init__(self, engine: Engine): super().__init__(engine) self.log_length = len(engine.message_log.messages) self.cursor = self.log_length - 1 def render(self, console: tcod.console.Console) -> None: super().render(console) log_console = tcod.console.Console(console.width - 6, console.height - 6) #custom... log_console.draw_frame(0, 0, log_console.width, log_console.height) log_console.print_box( 0, 0, log_console.width, 1, "Message History", alignment=tcod.constants.CENTER ) self.engine.message_log.render_messages( log_console, 1, 1, log_console.width - 2, log_console.height - 2, self.engine.message_log.messages[:self.cursor + 1] ) log_console.blit(console, 3, 3) #into the middle def ev_keydown(self, event: tcod.event.KeyDown) -> Optional[BaseAction]: if event.sym in CURSOR_SCROLL_KEYS: adjust = CURSOR_SCROLL_KEYS[event.sym] if adjust < 0 and self.cursor == 0: pass #do nothing elif adjust > 0 and self.cursor == self.log_length - 1: pass #do nothing else: self.cursor = max(0, min(self.log_length - 1, self.cursor + adjust)) #TODO: nicer scroll down elif event.sym == tcod.event.KeySym.HOME: self.cursor = 0 elif event.sym == tcod.event.KeySym.END: self.cursor = self.log_length - 1 else: #return to the game self.engine.event_handler = InGameHandler(self.engine)