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:
'''An action with no specific actor'''
def __init__(self, actor: Actor):
super().__init__()
self.actor = actor
# pylint: disable=unused-argument
def perform(self, engine: 'Engine') -> ActionResult:
'''Perform this action.
@ -42,17 +46,3 @@ class Action:
def __repr__(self):
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
WalkAction
MeleeAction
ExitAction
WaitAction
'''
@ -22,21 +21,14 @@ from .. import items
from .. import log
from ..geometry import Vector
from ..object import Actor, Item
from .action import Action, ActionWithActor
from .action import Action
from .result import ActionResult
if TYPE_CHECKING:
from ..engine import Engine
class ExitAction(Action):
'''Exit the game.'''
def perform(self, engine: 'Engine') -> ActionResult:
raise SystemExit()
class MoveAction(ActionWithActor):
class MoveAction(Action):
'''An abstract Action that requires a direction to complete.'''
def __init__(self, actor: Actor, direction: Vector):
@ -157,7 +149,7 @@ class MeleeAction(MoveAction):
return self.success()
class WaitAction(ActionWithActor):
class WaitAction(Action):
'''Wait a turn'''
def perform(self, engine: 'Engine') -> ActionResult:
@ -174,7 +166,7 @@ class WaitAction(ActionWithActor):
return self.success()
class DieAction(ActionWithActor):
class DieAction(Action):
'''Kill an Actor'''
def perform(self, engine: 'Engine') -> ActionResult:
@ -193,7 +185,7 @@ class DieAction(ActionWithActor):
return self.success()
class DropItemAction(ActionWithActor):
class DropItemAction(Action):
'''Drop an item'''
def __init__(self, actor: 'Actor', item: 'Item'):
@ -205,7 +197,7 @@ class DropItemAction(ActionWithActor):
return self.success()
class HealAction(ActionWithActor):
class HealAction(Action):
'''Heal a target actor some number of hit points'''
def __init__(self, actor: 'Actor', hit_points_to_recover: int):

View file

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

View file

@ -9,7 +9,7 @@ import tcod
from . import log
from . import monsters
from .actions.action import Action, ActionWithActor
from .actions.action import Action
from .actions.result import ActionResult
from .ai import HostileEnemy
from .configuration import Configuration
@ -110,7 +110,7 @@ class Engine:
def process_input_action(self, action: Action):
'''Process an Action from player input'''
if not isinstance(action, ActionWithActor):
if not isinstance(action, Action):
action.perform(self)
return
@ -159,7 +159,7 @@ class Engine:
if 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.'''
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 result.alternate:
alternate_string = f'{result.alternate.__class__.__name__}[{result.alternate.actor.symbol}]'
alternate_string = f'{result.alternate.__class__.__name__}[{result.alternate.actor}]'
else:
alternate_string = str(result.alternate)
log.ACTIONS_TREE.info(

View file

@ -6,7 +6,7 @@ import tcod
import tcod.event as tev
from .actions.action import Action
from .actions.game import BumpAction, ExitAction, WaitAction
from .actions.game import BumpAction, WaitAction
from .geometry import Direction
if TYPE_CHECKING:
@ -51,9 +51,6 @@ class EngineEventHandler(tev.EventDispatch[Action]):
return action
def ev_quit(self, event: tcod.event.Quit) -> Optional[Action]:
return ExitAction()
class GameOverEventHandler(tev.EventDispatch[Action]):
'''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'):
super().__init__()
self.engine = engine
def ev_quit(self, event: tev.Quit) -> Optional[Action]:
return ExitAction()

View file

@ -2,7 +2,7 @@
'''Defines event handling mechanisms.'''
from typing import TYPE_CHECKING
from typing import NoReturn, TYPE_CHECKING
from tcod import event as tev
@ -42,6 +42,11 @@ class InterfaceEventHandler(tev.EventDispatch[bool]):
def ev_mousebuttonup(self, event: tev.MouseButtonUp) -> bool:
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:
for handler in self._handlers:
if handler and handler.dispatch(event):