Remove QuitAction and ActionWithActor!

Move quit event handling to the interface and flatten the Action class
hierarchy. There are no longer any actions that don't take an Actor. This has
the happy side effect of resolving some pylint errors too. :)
This commit is contained in:
Eryn Wells 2023-03-11 01:09:53 -08:00
parent 02ed3d1e4a
commit 327cc90b2e
6 changed files with 24 additions and 43 deletions

View file

@ -12,6 +12,10 @@ if TYPE_CHECKING:
class Action: class Action:
'''An action with no specific actor''' '''An action with no specific actor'''
def __init__(self, actor: Actor):
super().__init__()
self.actor = actor
# pylint: disable=unused-argument # pylint: disable=unused-argument
def perform(self, engine: 'Engine') -> ActionResult: def perform(self, engine: 'Engine') -> ActionResult:
'''Perform this action. '''Perform this action.
@ -42,17 +46,3 @@ class Action:
def __repr__(self): def __repr__(self):
return f'{self.__class__.__name__}()' return f'{self.__class__.__name__}()'
class ActionWithActor(Action):
'''An action that assigned to an actor'''
def __init__(self, actor: Actor):
super().__init__()
self.actor = actor
def __str__(self) -> str:
return f'{self.__class__.__name__} for {self.actor!s}'
def __repr__(self):
return f'{self.__class__.__name__}({self.actor!r})'

View file

@ -11,7 +11,6 @@ Action : Base class of all actions
BumpAction BumpAction
WalkAction WalkAction
MeleeAction MeleeAction
ExitAction
WaitAction WaitAction
''' '''
@ -22,21 +21,14 @@ from .. import items
from .. import log from .. import log
from ..geometry import Vector from ..geometry import Vector
from ..object import Actor, Item from ..object import Actor, Item
from .action import Action, ActionWithActor from .action import Action
from .result import ActionResult from .result import ActionResult
if TYPE_CHECKING: if TYPE_CHECKING:
from ..engine import Engine from ..engine import Engine
class ExitAction(Action): class MoveAction(Action):
'''Exit the game.'''
def perform(self, engine: 'Engine') -> ActionResult:
raise SystemExit()
class MoveAction(ActionWithActor):
'''An abstract Action that requires a direction to complete.''' '''An abstract Action that requires a direction to complete.'''
def __init__(self, actor: Actor, direction: Vector): def __init__(self, actor: Actor, direction: Vector):
@ -157,7 +149,7 @@ class MeleeAction(MoveAction):
return self.success() return self.success()
class WaitAction(ActionWithActor): class WaitAction(Action):
'''Wait a turn''' '''Wait a turn'''
def perform(self, engine: 'Engine') -> ActionResult: def perform(self, engine: 'Engine') -> ActionResult:
@ -174,7 +166,7 @@ class WaitAction(ActionWithActor):
return self.success() return self.success()
class DieAction(ActionWithActor): class DieAction(Action):
'''Kill an Actor''' '''Kill an Actor'''
def perform(self, engine: 'Engine') -> ActionResult: def perform(self, engine: 'Engine') -> ActionResult:
@ -193,7 +185,7 @@ class DieAction(ActionWithActor):
return self.success() return self.success()
class DropItemAction(ActionWithActor): class DropItemAction(Action):
'''Drop an item''' '''Drop an item'''
def __init__(self, actor: 'Actor', item: 'Item'): def __init__(self, actor: 'Actor', item: 'Item'):
@ -205,7 +197,7 @@ class DropItemAction(ActionWithActor):
return self.success() return self.success()
class HealAction(ActionWithActor): class HealAction(Action):
'''Heal a target actor some number of hit points''' '''Heal a target actor some number of hit points'''
def __init__(self, actor: 'Actor', hit_points_to_recover: int): def __init__(self, actor: 'Actor', hit_points_to_recover: int):

View file

@ -7,7 +7,7 @@ import numpy as np
import tcod import tcod
from . import log from . import log
from .actions.action import ActionWithActor from .actions.action import Action
from .actions.game import BumpAction, WaitAction from .actions.game import BumpAction, WaitAction
from .components import Component from .components import Component
from .geometry import Direction, Point from .geometry import Direction, Point
@ -26,7 +26,7 @@ class AI(Component):
super().__init__() super().__init__()
self.entity = entity self.entity = entity
def act(self, engine: 'Engine') -> Optional[ActionWithActor]: def act(self, engine: 'Engine') -> Optional[Action]:
'''Produce an action to perform''' '''Produce an action to perform'''
raise NotImplementedError() raise NotImplementedError()
@ -38,7 +38,7 @@ class HostileEnemy(AI):
beeline for her. beeline for her.
''' '''
def act(self, engine: 'Engine') -> Optional[ActionWithActor]: def act(self, engine: 'Engine') -> Optional[Action]:
visible_tiles = tcod.map.compute_fov( visible_tiles = tcod.map.compute_fov(
engine.map.tiles['transparent'], engine.map.tiles['transparent'],
pov=tuple(self.entity.position), pov=tuple(self.entity.position),

View file

@ -9,7 +9,7 @@ import tcod
from . import log from . import log
from . import monsters from . import monsters
from .actions.action import Action, ActionWithActor from .actions.action import Action
from .actions.result import ActionResult from .actions.result import ActionResult
from .ai import HostileEnemy from .ai import HostileEnemy
from .configuration import Configuration from .configuration import Configuration
@ -110,7 +110,7 @@ class Engine:
def process_input_action(self, action: Action): def process_input_action(self, action: Action):
'''Process an Action from player input''' '''Process an Action from player input'''
if not isinstance(action, ActionWithActor): if not isinstance(action, Action):
action.perform(self) action.perform(self)
return return
@ -159,7 +159,7 @@ class Engine:
if action: if action:
self._perform_action_until_done(action) self._perform_action_until_done(action)
def _perform_action_until_done(self, action: ActionWithActor) -> ActionResult: def _perform_action_until_done(self, action: Action) -> ActionResult:
'''Perform the given action and any alternate follow-up actions until the action chain is done.''' '''Perform the given action and any alternate follow-up actions until the action chain is done.'''
result = action.perform(self) result = action.perform(self)
@ -184,7 +184,7 @@ class Engine:
if log.ACTIONS_TREE.isEnabledFor(log.INFO) and self.map.visible[tuple(action.actor.position)]: if log.ACTIONS_TREE.isEnabledFor(log.INFO) and self.map.visible[tuple(action.actor.position)]:
if result.alternate: if result.alternate:
alternate_string = f'{result.alternate.__class__.__name__}[{result.alternate.actor.symbol}]' alternate_string = f'{result.alternate.__class__.__name__}[{result.alternate.actor}]'
else: else:
alternate_string = str(result.alternate) alternate_string = str(result.alternate)
log.ACTIONS_TREE.info( log.ACTIONS_TREE.info(

View file

@ -6,7 +6,7 @@ import tcod
import tcod.event as tev import tcod.event as tev
from .actions.action import Action from .actions.action import Action
from .actions.game import BumpAction, ExitAction, WaitAction from .actions.game import BumpAction, WaitAction
from .geometry import Direction from .geometry import Direction
if TYPE_CHECKING: if TYPE_CHECKING:
@ -51,9 +51,6 @@ class EngineEventHandler(tev.EventDispatch[Action]):
return action return action
def ev_quit(self, event: tcod.event.Quit) -> Optional[Action]:
return ExitAction()
class GameOverEventHandler(tev.EventDispatch[Action]): class GameOverEventHandler(tev.EventDispatch[Action]):
'''When the game is over (the hero dies, the player quits, etc), this event handler takes over.''' '''When the game is over (the hero dies, the player quits, etc), this event handler takes over.'''
@ -61,6 +58,3 @@ class GameOverEventHandler(tev.EventDispatch[Action]):
def __init__(self, engine: 'Engine'): def __init__(self, engine: 'Engine'):
super().__init__() super().__init__()
self.engine = engine self.engine = engine
def ev_quit(self, event: tev.Quit) -> Optional[Action]:
return ExitAction()

View file

@ -2,7 +2,7 @@
'''Defines event handling mechanisms.''' '''Defines event handling mechanisms.'''
from typing import TYPE_CHECKING from typing import NoReturn, TYPE_CHECKING
from tcod import event as tev from tcod import event as tev
@ -42,6 +42,11 @@ class InterfaceEventHandler(tev.EventDispatch[bool]):
def ev_mousebuttonup(self, event: tev.MouseButtonUp) -> bool: def ev_mousebuttonup(self, event: tev.MouseButtonUp) -> bool:
return self._handle_event(event) return self._handle_event(event)
def ev_quit(self, event: tev.Quit) -> NoReturn:
# TODO: Maybe show a "do you want to quit?" alert?
# TODO: Probably inform the engine that we're shutting down.
raise SystemExit()
def _handle_event(self, event: tev.Event) -> bool: def _handle_event(self, event: tev.Event) -> bool:
for handler in self._handlers: for handler in self._handlers:
if handler and handler.dispatch(event): if handler and handler.dispatch(event):