Refactor event handling
This commit is contained in:
parent
a1e6125c34
commit
e82d2e5b49
3
color.py
3
color.py
@ -20,3 +20,6 @@ health_recovered = (0x0, 0xFF, 0x0)
|
|||||||
bar_text = white
|
bar_text = white
|
||||||
bar_filled = (0x0, 0x60, 0x0)
|
bar_filled = (0x0, 0x60, 0x0)
|
||||||
bar_empty = (0x40, 0x10, 0x10)
|
bar_empty = (0x40, 0x10, 0x10)
|
||||||
|
|
||||||
|
menu_title = (255, 255, 63)
|
||||||
|
menu_text = white
|
||||||
|
@ -8,7 +8,11 @@ import components.ai
|
|||||||
import components.inventory
|
import components.inventory
|
||||||
from components.base_component import BaseComponent
|
from components.base_component import BaseComponent
|
||||||
from exceptions import Impossible
|
from exceptions import Impossible
|
||||||
from input_handlers import AreaRangedAttackHandler, SingleRangedAttackHandler
|
from input_handlers import (
|
||||||
|
ActionOrHandler,
|
||||||
|
AreaRangedAttackHandler,
|
||||||
|
SingleRangedAttackHandler
|
||||||
|
)
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from entity import Actor, Item
|
from entity import Actor, Item
|
||||||
@ -17,7 +21,7 @@ if TYPE_CHECKING:
|
|||||||
class Consumable(BaseComponent):
|
class Consumable(BaseComponent):
|
||||||
parent: Item
|
parent: Item
|
||||||
|
|
||||||
def get_action(self, consumer: Actor) -> Optional[actions.Action]:
|
def get_action(self, consumer: Actor) -> Optional[ActionOrHandler]:
|
||||||
"""Try to return the action for this item."""
|
"""Try to return the action for this item."""
|
||||||
return actions.ItemAction(consumer, self.parent)
|
return actions.ItemAction(consumer, self.parent)
|
||||||
|
|
||||||
@ -40,18 +44,17 @@ class ConfusionConsumable(Consumable):
|
|||||||
def __init__(self, number_of_turns: int):
|
def __init__(self, number_of_turns: int):
|
||||||
self.number_of_turns = number_of_turns
|
self.number_of_turns = number_of_turns
|
||||||
|
|
||||||
def get_action(self, consumer: Actor) -> Optional[actions.Action]:
|
def get_action(self, consumer: Actor) -> SingleRangedAttackHandler:
|
||||||
self.engine.message_log.add_message(
|
self.engine.message_log.add_message(
|
||||||
"Select a target location.",
|
"Select a target location.",
|
||||||
color.needs_target
|
color.needs_target
|
||||||
)
|
)
|
||||||
self.engine.event_handler = SingleRangedAttackHandler(
|
|
||||||
|
return SingleRangedAttackHandler(
|
||||||
self.engine,
|
self.engine,
|
||||||
callback=lambda xy: actions.ItemAction(consumer, self.parent, xy),
|
callback=lambda xy: actions.ItemAction(consumer, self.parent, xy),
|
||||||
)
|
)
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def activate(self, action: actions.ItemAction) -> None:
|
def activate(self, action: actions.ItemAction) -> None:
|
||||||
consumer = action.entity
|
consumer = action.entity
|
||||||
target = action.target_actor
|
target = action.target_actor
|
||||||
@ -99,19 +102,18 @@ class FireballDamageConsumable(Consumable):
|
|||||||
self.damage = damage
|
self.damage = damage
|
||||||
self.radius = radius
|
self.radius = radius
|
||||||
|
|
||||||
def get_action(self, consumer: Actor) -> Optional[actions.Action]:
|
def get_action(self, consumer: Actor) -> AreaRangedAttackHandler:
|
||||||
self.engine.message_log.add_message(
|
self.engine.message_log.add_message(
|
||||||
"Select a target location.",
|
"Select a target location.",
|
||||||
color.needs_target
|
color.needs_target
|
||||||
)
|
)
|
||||||
self.engine.event_handler = AreaRangedAttackHandler(
|
|
||||||
|
return AreaRangedAttackHandler(
|
||||||
self.engine,
|
self.engine,
|
||||||
self.radius,
|
self.radius,
|
||||||
lambda xy: actions.ItemAction(consumer, self.parent, xy),
|
lambda xy: actions.ItemAction(consumer, self.parent, xy),
|
||||||
)
|
)
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def activate(self, action: actions.ItemAction) -> None:
|
def activate(self, action: actions.ItemAction) -> None:
|
||||||
target_xy = action.target_xy
|
target_xy = action.target_xy
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@ from typing import TYPE_CHECKING
|
|||||||
|
|
||||||
import color
|
import color
|
||||||
from components.base_component import BaseComponent
|
from components.base_component import BaseComponent
|
||||||
from input_handlers import GameOverEventHandler
|
|
||||||
from render_order import RenderOrder
|
from render_order import RenderOrder
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@ -34,7 +33,6 @@ class Fighter(BaseComponent):
|
|||||||
if self.engine.player is self.parent:
|
if self.engine.player is self.parent:
|
||||||
death_message = "You died!"
|
death_message = "You died!"
|
||||||
death_message_color = color.player_die
|
death_message_color = color.player_die
|
||||||
self.engine.event_handler = GameOverEventHandler(self.engine)
|
|
||||||
else:
|
else:
|
||||||
death_message = f"{self.parent.name} is dead!"
|
death_message = f"{self.parent.name} is dead!"
|
||||||
death_message_color = color.enemy_die
|
death_message_color = color.enemy_die
|
||||||
|
@ -2,12 +2,10 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from tcod.context import Context
|
|
||||||
from tcod.console import Console
|
from tcod.console import Console
|
||||||
from tcod.map import compute_fov
|
from tcod.map import compute_fov
|
||||||
|
|
||||||
import exceptions
|
import exceptions
|
||||||
from input_handlers import MainGameEventHandler
|
|
||||||
from message_log import MessageLog
|
from message_log import MessageLog
|
||||||
from render_functions import render_bar, render_names_at_mouse_location
|
from render_functions import render_bar, render_names_at_mouse_location
|
||||||
|
|
||||||
@ -20,7 +18,6 @@ class Engine:
|
|||||||
game_map: GameMap
|
game_map: GameMap
|
||||||
|
|
||||||
def __init__(self, player: Actor):
|
def __init__(self, player: Actor):
|
||||||
self.event_handler: EventHandler = MainGameEventHandler(self)
|
|
||||||
self.message_log = MessageLog()
|
self.message_log = MessageLog()
|
||||||
self.mouse_location = (0, 0)
|
self.mouse_location = (0, 0)
|
||||||
self.player = player
|
self.player = player
|
||||||
|
@ -2,4 +2,8 @@ class Impossible(Exception):
|
|||||||
"""Exception raised when an action is impossible to be performed.
|
"""Exception raised when an action is impossible to be performed.
|
||||||
|
|
||||||
The reason is given as the exception message.
|
The reason is given as the exception message.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class QuitWithoutSaving(SystemExit):
|
||||||
|
"""Can be raised to exit the game without automatically saving."""
|
@ -1,6 +1,6 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import overload, Callable, Optional, Tuple, TYPE_CHECKING
|
from typing import overload, Callable, Optional, Tuple, TYPE_CHECKING, Union
|
||||||
|
|
||||||
import tcod.event
|
import tcod.event
|
||||||
|
|
||||||
@ -61,13 +61,50 @@ CONFIRM_KEYS = {
|
|||||||
tcod.event.K_KP_ENTER,
|
tcod.event.K_KP_ENTER,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ActionOrHandler = Union[Action, "BaseEventHandler"]
|
||||||
|
"""
|
||||||
|
An event handler return value which can trigger an action or switch active handlers.
|
||||||
|
|
||||||
class EventHandler(tcod.event.EventDispatch[Action]):
|
If a handler is returned than it will become the active handler for future events.
|
||||||
|
if an action is returned it will be attempted and if it's valid then
|
||||||
|
MainGameEventHandler will become the active handler.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class BaseEventHandler(tcod.event.EventDispatch[ActionOrHandler]):
|
||||||
|
def handle_events(self, event: tcod.event.Event) -> BaseEventHandler:
|
||||||
|
"""Handle an event and return the next active event handler."""
|
||||||
|
state = self.dispatch(event)
|
||||||
|
if isinstance(state, BaseEventHandler):
|
||||||
|
return state
|
||||||
|
assert not isinstance(state, Action), f"{self!r} can not handle actions."
|
||||||
|
|
||||||
|
return self
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def on_render(self, console: tcod.Console) -> None:
|
||||||
|
"""Must be implemented"""
|
||||||
|
|
||||||
|
def ev_quit(self, event: tcod.event.Quit) -> Optional[Action]:
|
||||||
|
raise SystemExit()
|
||||||
|
|
||||||
|
|
||||||
|
class EventHandler(BaseEventHandler):
|
||||||
def __init__(self, engine: Engine):
|
def __init__(self, engine: Engine):
|
||||||
self.engine = engine
|
self.engine = engine
|
||||||
|
|
||||||
def handle_events(self, event: tcod.event.Event) -> None:
|
def handle_events(self, event: tcod.event.Event) -> BaseEventHandler:
|
||||||
self.handle_action(self.dispatch(event))
|
"""Handle events for input handlers with an engine."""
|
||||||
|
action_or_state = self.dispatch(event)
|
||||||
|
if isinstance(action_or_state, BaseEventHandler):
|
||||||
|
return action_or_state
|
||||||
|
if self.handle_action(action_or_state):
|
||||||
|
# A valid action was performed.
|
||||||
|
if not self.engine.player.is_alive:
|
||||||
|
# The player was killed sometime during or after the action.
|
||||||
|
return GameOverEventHandler(self.engine)
|
||||||
|
return MainGameEventHandler(self.engine) # Return to the main handler.
|
||||||
|
return self
|
||||||
|
|
||||||
def handle_action(self, action: Optional[Action]) -> bool:
|
def handle_action(self, action: Optional[Action]) -> bool:
|
||||||
"""Handle actions returned from event methods.
|
"""Handle actions returned from event methods.
|
||||||
@ -93,9 +130,6 @@ class EventHandler(tcod.event.EventDispatch[Action]):
|
|||||||
if self.engine.game_map.in_bounds(event.tile.x, event.tile.y):
|
if self.engine.game_map.in_bounds(event.tile.x, event.tile.y):
|
||||||
self.engine.mouse_location = event.tile.x, event.tile.y
|
self.engine.mouse_location = event.tile.x, event.tile.y
|
||||||
|
|
||||||
def ev_quit(self, event: tcod.event.Quit) -> Optional[Action]:
|
|
||||||
raise SystemExit()
|
|
||||||
|
|
||||||
def on_render(self, console: tcod.Console) -> None:
|
def on_render(self, console: tcod.Console) -> None:
|
||||||
self.engine.render(console)
|
self.engine.render(console)
|
||||||
|
|
||||||
@ -103,16 +137,7 @@ class EventHandler(tcod.event.EventDispatch[Action]):
|
|||||||
class AskUserEventHandler(EventHandler):
|
class AskUserEventHandler(EventHandler):
|
||||||
"""Handles user input for actions which require special input."""
|
"""Handles user input for actions which require special input."""
|
||||||
|
|
||||||
def handle_action(self, action: Optional[Action]) -> bool:
|
def ev_keydown(self, event: tcod.event.KeyDown) -> Optional[ActionOrHandler]:
|
||||||
"""Return to the main event handler when a valid action was performed."""
|
|
||||||
if super().handle_action(action):
|
|
||||||
self.engine.event_handler = MainGameEventHandler(self.engine)
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
def ev_keydown(self, event: tcod.event.KeyDown) -> Optional[Action]:
|
|
||||||
"""By default any key exits this input handler."""
|
"""By default any key exits this input handler."""
|
||||||
# Ignore modifier keys.
|
# Ignore modifier keys.
|
||||||
if event.sym in {
|
if event.sym in {
|
||||||
@ -127,18 +152,16 @@ class AskUserEventHandler(EventHandler):
|
|||||||
|
|
||||||
return self.on_exit()
|
return self.on_exit()
|
||||||
|
|
||||||
def ev_mousebuttondown(self, event: tcod.event.MouseButtonDown) -> Optional[Action]:
|
def ev_mousebuttondown(self, event: tcod.event.MouseButtonDown) -> Optional[ActionOrHandler]:
|
||||||
"""By default any mouse click exits this input handler."""
|
"""By default any mouse click exits this input handler."""
|
||||||
return self.on_exit()
|
return self.on_exit()
|
||||||
|
|
||||||
def on_exit(self) -> Optional[Action]:
|
def on_exit(self) -> Optional[ActionOrHandler]:
|
||||||
"""Called when the user is trying to exit or cancel an action.
|
"""Called when the user is trying to exit or cancel an action.
|
||||||
|
|
||||||
By default this returns to the main event handler.
|
By default this returns to the main event handler.
|
||||||
"""
|
"""
|
||||||
self.engine.event_handler = MainGameEventHandler(self.engine)
|
return MainGameEventHandler(self.engine)
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
class InventoryEventHandler(AskUserEventHandler):
|
class InventoryEventHandler(AskUserEventHandler):
|
||||||
@ -189,7 +212,7 @@ class InventoryEventHandler(AskUserEventHandler):
|
|||||||
else:
|
else:
|
||||||
console.print(x + 1, y + 1, "(Empty)")
|
console.print(x + 1, y + 1, "(Empty)")
|
||||||
|
|
||||||
def ev_keydown(self, event: tcod.event.KeyDown) -> Optional[Action]:
|
def ev_keydown(self, event: tcod.event.KeyDown) -> Optional[ActionOrHandler]:
|
||||||
player = self.engine.player
|
player = self.engine.player
|
||||||
key = event.sym
|
key = event.sym
|
||||||
index = key - tcod.event.K_a
|
index = key - tcod.event.K_a
|
||||||
@ -206,7 +229,7 @@ class InventoryEventHandler(AskUserEventHandler):
|
|||||||
return super().ev_keydown(event)
|
return super().ev_keydown(event)
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def on_item_selected(self, item: Item) -> Optional[Action]:
|
def on_item_selected(self, item: Item) -> Optional[ActionOrHandler]:
|
||||||
"""Called when the user selects a valid item."""
|
"""Called when the user selects a valid item."""
|
||||||
|
|
||||||
|
|
||||||
@ -215,7 +238,7 @@ class InventoryActivateHandler(InventoryEventHandler):
|
|||||||
|
|
||||||
TITLE = "Select an item to use"
|
TITLE = "Select an item to use"
|
||||||
|
|
||||||
def on_item_selected(self, item: Item) -> Optional[Action]:
|
def on_item_selected(self, item: Item) -> Optional[ActionOrHandler]:
|
||||||
"""Return the action for the selected item."""
|
"""Return the action for the selected item."""
|
||||||
return item.consumable.get_action(self.engine.player)
|
return item.consumable.get_action(self.engine.player)
|
||||||
|
|
||||||
@ -225,7 +248,7 @@ class InventoryDropHandler(InventoryEventHandler):
|
|||||||
|
|
||||||
TITLE = "Select an item to drop"
|
TITLE = "Select an item to drop"
|
||||||
|
|
||||||
def on_item_selected(self, item: Item) -> Optional[Action]:
|
def on_item_selected(self, item: Item) -> Optional[ActionOrHandler]:
|
||||||
"""Drop this item."""
|
"""Drop this item."""
|
||||||
return actions.DropItem(self.engine.player, item)
|
return actions.DropItem(self.engine.player, item)
|
||||||
|
|
||||||
@ -246,7 +269,7 @@ class SelectIndexHandler(AskUserEventHandler):
|
|||||||
console.tiles_rgb["bg"][x, y] = color.white
|
console.tiles_rgb["bg"][x, y] = color.white
|
||||||
console.tiles_rgb["fg"][x, y] = color.black
|
console.tiles_rgb["fg"][x, y] = color.black
|
||||||
|
|
||||||
def ev_keydown(self, event: tcod.event.KeyDown) -> Optional[Action]:
|
def ev_keydown(self, event: tcod.event.KeyDown) -> Optional[ActionOrHandler]:
|
||||||
"""Check for key movement or confirmation keys."""
|
"""Check for key movement or confirmation keys."""
|
||||||
key = event.sym
|
key = event.sym
|
||||||
if key in MOVE_KEYS:
|
if key in MOVE_KEYS:
|
||||||
@ -273,7 +296,7 @@ class SelectIndexHandler(AskUserEventHandler):
|
|||||||
|
|
||||||
return super().ev_keydown(event)
|
return super().ev_keydown(event)
|
||||||
|
|
||||||
def ev_mousebuttondown(self, event: tcod.event.MouseButtonDown) -> Optional[Action]:
|
def ev_mousebuttondown(self, event: tcod.event.MouseButtonDown) -> Optional[ActionOrHandler]:
|
||||||
"""Left click confirms a selection."""
|
"""Left click confirms a selection."""
|
||||||
if self.engine.game_map.in_bounds(*event.tile):
|
if self.engine.game_map.in_bounds(*event.tile):
|
||||||
if event.button == 1:
|
if event.button == 1:
|
||||||
@ -282,16 +305,16 @@ class SelectIndexHandler(AskUserEventHandler):
|
|||||||
return super().ev_mousebuttondown(event)
|
return super().ev_mousebuttondown(event)
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def on_index_selected(self, x: int, y: int) -> Optional[Action]:
|
def on_index_selected(self, x: int, y: int) -> Optional[ActionOrHandler]:
|
||||||
"""Called when an index is selected."""
|
"""Called when an index is selected."""
|
||||||
|
|
||||||
|
|
||||||
class LookHandler(SelectIndexHandler):
|
class LookHandler(SelectIndexHandler):
|
||||||
"""Lets the player look around using the keyboard."""
|
"""Lets the player look around using the keyboard."""
|
||||||
|
|
||||||
def on_index_selected(self, x: int, y: int) -> None:
|
def on_index_selected(self, x: int, y: int) -> MainGameEventHandler:
|
||||||
"""Return to main handler."""
|
"""Return to main handler."""
|
||||||
self.engine.event_handler = MainGameEventHandler(self.engine)
|
return MainGameEventHandler(self.engine)
|
||||||
|
|
||||||
|
|
||||||
class SingleRangedAttackHandler(SelectIndexHandler):
|
class SingleRangedAttackHandler(SelectIndexHandler):
|
||||||
@ -300,13 +323,13 @@ class SingleRangedAttackHandler(SelectIndexHandler):
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
engine: Engine,
|
engine: Engine,
|
||||||
callback: Callable[[Tuple[int, int]], Optional[Action]]
|
callback: Callable[[Tuple[int, int]], Optional[ActionOrHandler]]
|
||||||
):
|
):
|
||||||
super().__init__(engine)
|
super().__init__(engine)
|
||||||
|
|
||||||
self.callback = callback
|
self.callback = callback
|
||||||
|
|
||||||
def on_index_selected(self, x: int, y: int) -> Optional[Action]:
|
def on_index_selected(self, x: int, y: int) -> Optional[ActionOrHandler]:
|
||||||
return self.callback((x, y))
|
return self.callback((x, y))
|
||||||
|
|
||||||
|
|
||||||
@ -320,7 +343,7 @@ class AreaRangedAttackHandler(SelectIndexHandler):
|
|||||||
self,
|
self,
|
||||||
engine: Engine,
|
engine: Engine,
|
||||||
radius: int,
|
radius: int,
|
||||||
callback: Callable[[Tuple[int, int]], Optional[Action]]
|
callback: Callable[[Tuple[int, int]], Optional[ActionOrHandler]]
|
||||||
):
|
):
|
||||||
super().__init__(engine)
|
super().__init__(engine)
|
||||||
|
|
||||||
@ -343,12 +366,12 @@ class AreaRangedAttackHandler(SelectIndexHandler):
|
|||||||
clear=False,
|
clear=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
def on_index_selected(self, x: int, y: int) -> Optional[Action]:
|
def on_index_selected(self, x: int, y: int) -> Optional[ActionOrHandler]:
|
||||||
return self.callback((x, y))
|
return self.callback((x, y))
|
||||||
|
|
||||||
|
|
||||||
class MainGameEventHandler(EventHandler):
|
class MainGameEventHandler(EventHandler):
|
||||||
def ev_keydown(self, event: tcod.event.KeyDown) -> Optional[Action]:
|
def ev_keydown(self, event: tcod.event.KeyDown) -> Optional[ActionOrHandler]:
|
||||||
action: Optional[Action] = None
|
action: Optional[Action] = None
|
||||||
|
|
||||||
key = event.sym
|
key = event.sym
|
||||||
@ -365,17 +388,17 @@ class MainGameEventHandler(EventHandler):
|
|||||||
raise SystemExit()
|
raise SystemExit()
|
||||||
|
|
||||||
elif key == tcod.event.K_v:
|
elif key == tcod.event.K_v:
|
||||||
self.engine.event_handler = HistoryViewer(self.engine)
|
return HistoryViewer(self.engine)
|
||||||
|
|
||||||
elif key == tcod.event.K_g:
|
elif key == tcod.event.K_g:
|
||||||
action = PickupAction(player)
|
action = PickupAction(player)
|
||||||
|
|
||||||
elif key == tcod.event.K_i:
|
elif key == tcod.event.K_i:
|
||||||
self.engine.event_handler = InventoryActivateHandler(self.engine)
|
return InventoryActivateHandler(self.engine)
|
||||||
elif key == tcod.event.K_d:
|
elif key == tcod.event.K_d:
|
||||||
self.engine.event_handler = InventoryDropHandler(self.engine)
|
return InventoryDropHandler(self.engine)
|
||||||
elif key == tcod.event.K_SLASH:
|
elif key == tcod.event.K_SLASH:
|
||||||
self.engine.event_handler = LookHandler(self.engine)
|
return LookHandler(self.engine)
|
||||||
|
|
||||||
# No valid key was pressed
|
# No valid key was pressed
|
||||||
return action
|
return action
|
||||||
@ -430,7 +453,7 @@ class HistoryViewer(EventHandler):
|
|||||||
)
|
)
|
||||||
log_console.blit(console, 3, 3)
|
log_console.blit(console, 3, 3)
|
||||||
|
|
||||||
def ev_keydown(self, event: tcod.event.KeyDown) -> None:
|
def ev_keydown(self, event: tcod.event.KeyDown) -> Optional[MainGameEventHandler]:
|
||||||
# Fancy conditional movement to make it feel right.
|
# Fancy conditional movement to make it feel right.
|
||||||
if event.sym in CURSOR_Y_KEYS:
|
if event.sym in CURSOR_Y_KEYS:
|
||||||
adjust = CURSOR_Y_KEYS[event.sym]
|
adjust = CURSOR_Y_KEYS[event.sym]
|
||||||
@ -448,4 +471,6 @@ class HistoryViewer(EventHandler):
|
|||||||
elif event.sym == tcod.event.K_END:
|
elif event.sym == tcod.event.K_END:
|
||||||
self.cursor = self.log_length - 1 # Move directly to the last message.
|
self.cursor = self.log_length - 1 # Move directly to the last message.
|
||||||
else: # Any other key moves back to the main game state.
|
else: # Any other key moves back to the main game state.
|
||||||
self.engine.event_handler = MainGameEventHandler(self.engine)
|
return MainGameEventHandler(self.engine)
|
||||||
|
|
||||||
|
return None
|
||||||
|
38
main.py
38
main.py
@ -7,6 +7,8 @@ import tcod
|
|||||||
import color
|
import color
|
||||||
from engine import Engine
|
from engine import Engine
|
||||||
import entity_factories
|
import entity_factories
|
||||||
|
import exceptions
|
||||||
|
import input_handlers
|
||||||
from procgen import generate_dungeon
|
from procgen import generate_dungeon
|
||||||
|
|
||||||
|
|
||||||
@ -52,6 +54,8 @@ def main() -> None:
|
|||||||
color.welcome_text
|
color.welcome_text
|
||||||
)
|
)
|
||||||
|
|
||||||
|
handler: input_handlers.BaseEventHandler = input_handlers.MainGameEventHandler(engine)
|
||||||
|
|
||||||
with tcod.context.new_terminal(
|
with tcod.context.new_terminal(
|
||||||
screen_width,
|
screen_width,
|
||||||
screen_height,
|
screen_height,
|
||||||
@ -60,19 +64,29 @@ def main() -> None:
|
|||||||
vsync=True,
|
vsync=True,
|
||||||
) as context:
|
) as context:
|
||||||
root_console = tcod.Console(screen_width, screen_height, order="F")
|
root_console = tcod.Console(screen_width, screen_height, order="F")
|
||||||
while True:
|
try:
|
||||||
root_console.clear()
|
while True:
|
||||||
engine.event_handler.on_render(console=root_console)
|
root_console.clear()
|
||||||
context.present(root_console)
|
engine.event_handler.on_render(console=root_console)
|
||||||
|
context.present(root_console)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
for event in tcod.event.wait():
|
for event in tcod.event.wait():
|
||||||
context.convert_event(event)
|
context.convert_event(event)
|
||||||
engine.event_handler.handle_events(event)
|
engine.event_handler.handle_events(event)
|
||||||
except Exception: # Handle exceptions in game.
|
except Exception: # Handle exceptions in game.
|
||||||
traceback.print_exc() # Print error to stderr.
|
traceback.print_exc() # Print error to stderr.
|
||||||
# Then print the error to the message log.
|
# Then print the error to the message log.
|
||||||
engine.message_log.add_message(traceback.format_exc(), color.error)
|
engine.message_log.add_message(traceback.format_exc(), color.error)
|
||||||
|
|
||||||
|
except exceptions.QuitWithoutSaving:
|
||||||
|
raise
|
||||||
|
except SystemExit: # Save and quit.
|
||||||
|
# TODO: Add the save function here
|
||||||
|
raise
|
||||||
|
except BaseException: # Save on any other unexpected exception.
|
||||||
|
# TODO: Add the save function here
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
Loading…
Reference in New Issue
Block a user