going-rogue/erynrl/events.py
Eryn Wells 356e205f2c Implement viewport tracking for the MapWindow
As the player moves the hero, the MapWindow will try to keep the
hero in the middle of the view.
2023-02-12 19:47:27 -08:00

115 lines
3.7 KiB
Python

# Eryn Wells <eryn@erynwells.me>
'''Defines event handling mechanisms.'''
from typing import Optional, TYPE_CHECKING
import tcod
from . import log
from .actions.action import Action
from .actions.game import ExitAction, RegenerateRoomsAction, BumpAction, WaitAction
from .geometry import Direction, Point
if TYPE_CHECKING:
from .engine import Engine
class EventHandler(tcod.event.EventDispatch[Action]):
'''Abstract event handler class'''
def __init__(self, engine: 'Engine'):
super().__init__()
self.engine = engine
def handle_events(self, context: tcod.context.Context):
'''Wait for events and handle them.'''
for event in tcod.event.wait():
context.convert_event(event)
self.handle_event(event)
def handle_event(self, event: tcod.event.Event):
'''
Handle an event by transforming it into an Action and processing it until it is completed. If the Action
succeeds, also process actions from other Entities.
Parameters
----------
event : tcod.event.Event
The event to handle
'''
action = self.dispatch(event)
# Unhandled event. Ignore it.
if not action:
log.EVENTS.debug('Unhandled event: %s', event)
return
self.engine.process_input_action(action)
def ev_quit(self, event: tcod.event.Quit) -> Optional[Action]:
return ExitAction()
class MainGameEventHandler(EventHandler):
'''
Handler of `tcod` events for the main game.
Receives input from the player and dispatches actions to the game engine to interat with the hero and other objects
in the game.
'''
def ev_keydown(self, event: tcod.event.KeyDown) -> Optional[Action]:
action: Optional[Action] = None
hero = self.engine.hero
is_shift_pressed = bool(event.mod & tcod.event.Modifier.SHIFT)
sym = event.sym
match sym:
case tcod.event.KeySym.b:
action = BumpAction(hero, Direction.SouthWest)
case tcod.event.KeySym.h:
action = BumpAction(hero, Direction.West)
case tcod.event.KeySym.j:
action = BumpAction(hero, Direction.South)
case tcod.event.KeySym.k:
action = BumpAction(hero, Direction.North)
case tcod.event.KeySym.l:
action = BumpAction(hero, Direction.East)
case tcod.event.KeySym.n:
action = BumpAction(hero, Direction.SouthEast)
case tcod.event.KeySym.u:
action = BumpAction(hero, Direction.NorthEast)
case tcod.event.KeySym.y:
action = BumpAction(hero, Direction.NorthWest)
case tcod.event.KeySym.ESCAPE:
action = ExitAction()
case tcod.event.KeySym.SPACE:
action = RegenerateRoomsAction()
case tcod.event.KeySym.PERIOD:
if not is_shift_pressed:
action = WaitAction(hero)
return action
def ev_mousemotion(self, event: tcod.event.MouseMotion) -> Optional[Action]:
mouse_point = Point(event.tile.x, event.tile.y)
if not self.engine.map.tile_is_in_bounds(mouse_point):
mouse_point = None
self.engine.update_mouse_point(mouse_point)
class GameOverEventHandler(EventHandler):
'''When the game is over (the hero dies, the player quits, etc), this event handler takes over.'''
def ev_keydown(self, event: tcod.event.KeyDown) -> Optional[Action]:
action: Optional[Action] = None
sym = event.sym
match sym:
case tcod.event.KeySym.ESCAPE:
action = ExitAction()
return action