1
0

Refactor movement to allow diagonal movement, add basic attack logs

This commit is contained in:
Timothy Warren 2022-01-10 13:47:10 -05:00
parent be433a9449
commit 018dbe35b8
4 changed files with 66 additions and 19 deletions

View File

@ -4,11 +4,11 @@ from typing import Optional, Tuple, TYPE_CHECKING, overload
if TYPE_CHECKING: if TYPE_CHECKING:
from engine import Engine from engine import Engine
from entity import Entity from entity import Actor, Entity
class Action: class Action:
def __init__(self, entity: Entity) -> None: def __init__(self, entity: Actor) -> None:
super().__init__() super().__init__()
self.entity = entity self.entity = entity
@ -40,7 +40,7 @@ class WaitAction(Action):
class ActionWithDirection(Action): class ActionWithDirection(Action):
def __init__(self, entity, dx: int, dy: int): def __init__(self, entity: Actor, dx: int, dy: int):
super().__init__(entity) super().__init__(entity)
self.dx = dx self.dx = dx
@ -56,14 +56,26 @@ class ActionWithDirection(Action):
"""Return the blocking entity at this action's destination.""" """Return the blocking entity at this action's destination."""
return self.engine.game_map.get_blocking_entity_at_location(*self.dest_xy) return self.engine.game_map.get_blocking_entity_at_location(*self.dest_xy)
@property
def target_actor(self) -> Optional[Actor]:
"""Return the actor at this action's destination."""
return self.engine.game_map.get_actor_at_location(*self.dest_xy)
class MeleeAction(ActionWithDirection): class MeleeAction(ActionWithDirection):
def perform(self) -> None: def perform(self) -> None:
target = self.blocking_entity target = self.target_actor
if not target: if not target:
return # No entity to attack. return # No entity to attack.
print(f"You kick the {target.name}, much to its annoyance!") damage = self.entity.fighter.power - target.fighter.defense
attack_desc = f"{self.entity.name.capitalize()} attacks {target.name}"
if damage > 0:
print(f"{attack_desc} for {damage} hit points.")
target.fighter.hp -= damage
else:
print(f"{attack_desc} but does no damage.")
class MovementAction(ActionWithDirection): class MovementAction(ActionWithDirection):
@ -82,7 +94,7 @@ class MovementAction(ActionWithDirection):
class BumpAction(ActionWithDirection): class BumpAction(ActionWithDirection):
def perform(self) -> None: def perform(self) -> None:
if self.blocking_entity: if self.target_actor:
return MeleeAction(self.entity, self.dx, self.dy).perform() return MeleeAction(self.entity, self.dx, self.dy).perform()
else: else:
return MovementAction(self.entity, self.dx, self.dy).perform() return MovementAction(self.entity, self.dx, self.dy).perform()

View File

@ -33,7 +33,7 @@ class BaseAI(Action, BaseComponent):
cost[entity.x, entity.y] += 10 cost[entity.x, entity.y] += 10
# Create a graph from the cost array and pass that graph to a new pathfinder. # Create a graph from the cost array and pass that graph to a new pathfinder.
graph = tcod.path.SimpleGraph(cost, cardinal=2, diagonal=3) graph = tcod.path.SimpleGraph(cost=cost, cardinal=2, diagonal=3)
pathfinder = tcod.path.Pathfinder(graph) pathfinder = tcod.path.Pathfinder(graph)
pathfinder.add_root((self.entity.x, self.entity.y)) # Start position pathfinder.add_root((self.entity.x, self.entity.y)) # Start position
@ -69,7 +69,7 @@ class HostileEnemy(BaseAI):
return MovementAction( return MovementAction(
self.entity, self.entity,
dest_x - self.entity.x, dest_x - self.entity.x,
dest_y - self.entity.y dest_y - self.entity.y,
).perform() ).perform()
return WaitAction(self.entity).perform() return WaitAction(self.entity).perform()

View File

@ -86,7 +86,7 @@ class Actor(Entity):
blocks_movement=True blocks_movement=True
) )
self.ai = Optional[BaseAI] = ai_cls(self) self.ai: Optional[BaseAI] = ai_cls(self)
self.fighter = fighter self.fighter = fighter
self.fighter.entity = self self.fighter.entity = self

View File

@ -4,11 +4,49 @@ from typing import Optional, TYPE_CHECKING
import tcod.event import tcod.event
from actions import Action, EscapeAction, BumpAction from actions import Action, BumpAction, EscapeAction, WaitAction
if TYPE_CHECKING: if TYPE_CHECKING:
from engine import Engine from engine import Engine
MOVE_KEYS = {
# Arrow keys
tcod.event.K_UP: (0, -1),
tcod.event.K_DOWN: (0, 1),
tcod.event.K_LEFT: (-1, 0),
tcod.event.K_RIGHT: (1, 0),
tcod.event.K_HOME: (-1, -1),
tcod.event.K_END: (-1, 1),
tcod.event.K_PAGEUP: (1, -1),
tcod.event.K_PAGEDOWN: (1, 1),
# Numpad keys
tcod.event.K_KP_1: (-1, 1),
tcod.event.K_KP_2: (0, 1),
tcod.event.K_KP_3: (1, 1),
tcod.event.K_KP_4: (-1, 0),
tcod.event.K_KP_6: (1, 0),
tcod.event.K_KP_7: (-1, -1),
tcod.event.K_KP_8: (0, -1),
tcod.event.K_KP_9: (1, -1),
# Vi keys
tcod.event.K_h: (-1, 0),
tcod.event.K_j: (0, 1),
tcod.event.K_k: (0, -1),
tcod.event.K_l: (1, 0),
tcod.event.K_y: (-1, -1),
tcod.event.K_u: (1, -1),
tcod.event.K_b: (-1, 1),
tcod.event.K_n: (1, 1),
}
WAIT_KEYS = {
tcod.event.K_PERIOD,
tcod.event.K_KP_5,
tcod.event.K_CLEAR,
}
class EventHandler(tcod.event.EventDispatch[Action]): class EventHandler(tcod.event.EventDispatch[Action]):
def __init__(self, engine: Engine): def __init__(self, engine: Engine):
@ -33,14 +71,11 @@ class EventHandler(tcod.event.EventDispatch[Action]):
player = self.engine.player player = self.engine.player
if key == tcod.event.K_UP: if key in MOVE_KEYS:
action = BumpAction(player, dx=0, dy=-1) dx, dy = MOVE_KEYS[key]
elif key == tcod.event.K_DOWN: action = BumpAction(player, dx, dy)
action = BumpAction(player, dx=0, dy=1) elif key in WAIT_KEYS:
elif key == tcod.event.K_LEFT: action = WaitAction(player)
action = BumpAction(player, dx=-1, dy=0)
elif key == tcod.event.K_RIGHT:
action = BumpAction(player, dx=1, dy=0)
elif key == tcod.event.K_ESCAPE: elif key == tcod.event.K_ESCAPE:
action = EscapeAction(player) action = EscapeAction(player)