Intra-chapter refactoring
This commit is contained in:
parent
8e9f088c35
commit
f947338c2d
@ -6,14 +6,12 @@ import numpy as np # type: ignore
|
||||
import tcod
|
||||
|
||||
from actions import Action, MeleeAction, MovementAction, WaitAction
|
||||
from components.base_component import BaseComponent
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from entity import Actor
|
||||
|
||||
|
||||
class BaseAI(Action, BaseComponent):
|
||||
entity: Actor
|
||||
class BaseAI(Action):
|
||||
|
||||
def get_path_to(self, dest_x: int, dest_y: int) -> List[Tuple[int, int]]:
|
||||
"""Compute and return a path to the target position.
|
||||
|
@ -5,11 +5,16 @@ from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from engine import Engine
|
||||
from entity import Entity
|
||||
from game_map import GameMap
|
||||
|
||||
|
||||
class BaseComponent:
|
||||
entity: Entity # Owning entity instance
|
||||
parent: Entity # Owning entity instance
|
||||
|
||||
@property
|
||||
def gamemap(self) -> GameMap:
|
||||
return self.parent.gamemap
|
||||
|
||||
@property
|
||||
def engine(self) -> Engine:
|
||||
return self.entity.gamemap.engine
|
||||
return self.gamemap.engine
|
||||
|
@ -12,7 +12,7 @@ if TYPE_CHECKING:
|
||||
|
||||
|
||||
class Fighter(BaseComponent):
|
||||
entity: Actor
|
||||
parent: Actor
|
||||
|
||||
def __init__(self, hp: int, defense: int, power: int):
|
||||
self.max_hp = hp
|
||||
@ -27,23 +27,23 @@ class Fighter(BaseComponent):
|
||||
@hp.setter
|
||||
def hp(self, value: int) -> None:
|
||||
self._hp = max(0, min(value, self.max_hp))
|
||||
if self._hp == 0 and self.entity.ai:
|
||||
if self._hp == 0 and self.parent.ai:
|
||||
self.die()
|
||||
|
||||
def die(self) -> None:
|
||||
if self.engine.player is self.entity:
|
||||
if self.engine.player is self.parent:
|
||||
death_message = "You died!"
|
||||
death_message_color = color.player_die
|
||||
self.engine.event_handler = GameOverEventHandler(self.engine)
|
||||
else:
|
||||
death_message = f"{self.entity.name} is dead!"
|
||||
death_message = f"{self.parent.name} is dead!"
|
||||
death_message_color = color.enemy_die
|
||||
|
||||
self.entity.char = "%"
|
||||
self.entity.color = (191, 0, 0)
|
||||
self.entity.blocks_movement = False
|
||||
self.entity.ai = None
|
||||
self.entity.name = f"remains of {self.entity.name}"
|
||||
self.entity.render_order = RenderOrder.CORPSE
|
||||
self.parent.char = "%"
|
||||
self.parent.color = (191, 0, 0)
|
||||
self.parent.blocks_movement = False
|
||||
self.parent.ai = None
|
||||
self.parent.name = f"remains of {self.parent.name}"
|
||||
self.parent.render_order = RenderOrder.CORPSE
|
||||
|
||||
self.engine.message_log.add_message(death_message, death_message_color)
|
||||
|
25
entity.py
25
entity.py
@ -18,11 +18,11 @@ class Entity:
|
||||
A generic object to represent players, enemies, items, etc.
|
||||
"""
|
||||
|
||||
gamemap: GameMap
|
||||
parent: GameMap
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
gamemap: Optional[GameMap] = None,
|
||||
parent: Optional[GameMap] = None,
|
||||
x: int = 0,
|
||||
y: int = 0,
|
||||
char: str = "?",
|
||||
@ -38,17 +38,21 @@ class Entity:
|
||||
self.name = name
|
||||
self.blocks_movement = blocks_movement
|
||||
self.render_order = render_order
|
||||
if gamemap:
|
||||
if parent:
|
||||
# If gamemap isn't provided now, it will be later.
|
||||
self.gamemap = gamemap
|
||||
gamemap.entities.add(self)
|
||||
self.parent = parent
|
||||
parent.entities.add(self)
|
||||
|
||||
@property
|
||||
def gamemap(self) -> GameMap:
|
||||
return self.parent.gamemap
|
||||
|
||||
def spawn(self: T, gamemap: GameMap, x: int, y: int) -> T:
|
||||
"""Spawn a copy of this instance at the given location."""
|
||||
clone = copy.deepcopy(self)
|
||||
clone.x = x
|
||||
clone.y = y
|
||||
clone.gamemap = gamemap
|
||||
clone.parent = gamemap
|
||||
gamemap.entities.add(clone)
|
||||
return clone
|
||||
|
||||
@ -57,10 +61,11 @@ class Entity:
|
||||
self.x = x
|
||||
self.y = y
|
||||
if gamemap:
|
||||
if hasattr(self, "gamemap"): # Possibly uninitialized
|
||||
self.gamemap.entities.remove(self)
|
||||
if hasattr(self, "parent"): # Possibly uninitialized
|
||||
if self.parent is self.gamemap:
|
||||
self.gamemap.entities.remove(self)
|
||||
|
||||
self.gamemap = gamemap
|
||||
self.parent = gamemap
|
||||
gamemap.entities.add(self)
|
||||
|
||||
def move(self, dx: int, dy: int):
|
||||
@ -94,7 +99,7 @@ class Actor(Entity):
|
||||
self.ai: Optional[BaseAI] = ai_cls(self)
|
||||
|
||||
self.fighter = fighter
|
||||
self.fighter.entity = self
|
||||
self.fighter.parent = self
|
||||
|
||||
@property
|
||||
def is_alive(self) -> bool:
|
||||
|
@ -37,6 +37,10 @@ class GameMap:
|
||||
order="F"
|
||||
) # Tiles the player has seen before
|
||||
|
||||
@property
|
||||
def gamemap(self) -> GameMap:
|
||||
return self
|
||||
|
||||
@property
|
||||
def actors(self) -> Iterator[Actor]:
|
||||
"""Iterate over this map's living actors."""
|
||||
|
@ -1,4 +1,4 @@
|
||||
from typing import List, Reversible, Tuple
|
||||
from typing import Iterable, List, Reversible, Tuple
|
||||
import textwrap
|
||||
|
||||
import tcod
|
||||
@ -57,7 +57,18 @@ class MessageLog:
|
||||
self.render_messages(console, x, y, width, height, self.messages)
|
||||
|
||||
@staticmethod
|
||||
def wrap(string: str, width: int) -> Iterable[str]:
|
||||
"""Return a wrapped text message."""
|
||||
for line in string.splitlines(): # Handle newlines in messages.
|
||||
yield from textwrap.wrap(
|
||||
line,
|
||||
width,
|
||||
expand_tabs=True
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def render_messages(
|
||||
cls,
|
||||
console: tcod.Console,
|
||||
x: int,
|
||||
y: int,
|
||||
@ -72,7 +83,7 @@ class MessageLog:
|
||||
y_offset = height - 1
|
||||
|
||||
for message in reversed(messages):
|
||||
for line in reversed(textwrap.wrap(message.full_text, width)):
|
||||
for line in reversed(list(cls.wrap(message.full_text, width))):
|
||||
console.print(x=x, y=y + y_offset, string=line, fg=message.fg)
|
||||
y_offset -= 1
|
||||
if y_offset < 0:
|
||||
|
Loading…
Reference in New Issue
Block a user