1
0
python-roguelike/entity.py

165 lines
4.3 KiB
Python
Raw Normal View History

2022-01-07 15:52:53 -05:00
from __future__ import annotations
import copy
2022-01-13 14:56:38 -05:00
import math
from typing import Optional, Tuple, Type, TypeVar, TYPE_CHECKING, Union
2022-01-07 15:52:53 -05:00
2022-01-10 14:09:31 -05:00
from render_order import RenderOrder
2022-01-07 15:52:53 -05:00
if TYPE_CHECKING:
2022-01-10 13:21:17 -05:00
from components.ai import BaseAI
from components.consumable import Consumable
from components.equipment import Equipment
from components.equippable import Equippable
2022-01-10 13:21:17 -05:00
from components.fighter import Fighter
from components.inventory import Inventory
2022-01-25 15:51:59 -05:00
from components.level import Level
2022-01-07 15:52:53 -05:00
from game_map import GameMap
T = TypeVar("T", bound="Entity")
2022-01-06 11:19:56 -05:00
class Entity:
"""
A generic object to represent players, enemies, items, etc.
"""
2022-01-07 15:52:53 -05:00
parent: Union[GameMap, Inventory]
2022-01-07 15:52:53 -05:00
def __init__(
2022-02-08 10:00:28 -05:00
self,
parent: Optional[GameMap] = None,
x: int = 0,
y: int = 0,
char: str = "?",
color: Tuple[int, int, int] = (255, 255, 255),
name: str = "<Unnamed>",
blocks_movement: bool = False,
render_order: RenderOrder = RenderOrder.CORPSE,
2022-01-07 15:52:53 -05:00
):
2022-01-06 11:19:56 -05:00
self.x = x
self.y = y
self.char = char
self.color = color
2022-01-07 15:52:53 -05:00
self.name = name
self.blocks_movement = blocks_movement
2022-01-10 14:09:31 -05:00
self.render_order = render_order
2022-01-12 13:45:52 -05:00
if parent:
# If gamemap isn't provided now, it will be later.
2022-01-12 13:45:52 -05:00
self.parent = parent
parent.entities.add(self)
@property
def gamemap(self) -> GameMap:
return self.parent.gamemap
2022-01-07 15:52:53 -05:00
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
2022-01-12 13:45:52 -05:00
clone.parent = gamemap
2022-01-07 15:52:53 -05:00
gamemap.entities.add(clone)
return clone
2022-01-06 11:19:56 -05:00
def place(self, x: int, y: int, gamemap: Optional[GameMap] = None) -> None:
"""Place this entity at a new location. Handles moving across GameMaps."""
self.x = x
self.y = y
if gamemap:
2022-01-12 13:45:52 -05:00
if hasattr(self, "parent"): # Possibly uninitialized
if self.parent is self.gamemap:
self.gamemap.entities.remove(self)
2022-01-12 13:45:52 -05:00
self.parent = gamemap
gamemap.entities.add(self)
2022-01-13 14:56:38 -05:00
def distance(self, x: int, y: int) -> float:
"""
Return the distance between the current entity and the given (x,y) coordinate.
"""
return math.sqrt((x - self.x) ** 2 + (y - self.y) ** 2)
2022-01-06 11:19:56 -05:00
def move(self, dx: int, dy: int):
# Move the entity by a given amount
self.x += dx
self.y += dy
2022-01-10 13:21:17 -05:00
class Actor(Entity):
def __init__(
2022-02-08 10:00:28 -05:00
self,
*,
x: int = 0,
y: int = 0,
char: str = "?",
color: Tuple[int, int, int] = (255, 255, 255),
name: str = "<Unamed>",
ai_cls: Type[BaseAI],
equipment: Equipment,
2022-02-08 10:00:28 -05:00
fighter: Fighter,
inventory: Inventory,
level: Level,
2022-01-10 13:21:17 -05:00
):
super().__init__(
x=x,
y=y,
char=char,
color=color,
name=name,
2022-01-10 14:10:21 -05:00
blocks_movement=True,
render_order=RenderOrder.ACTOR,
2022-01-10 13:21:17 -05:00
)
self.ai: Optional[BaseAI] = ai_cls(self)
2022-01-10 13:21:17 -05:00
self.equipment: Equipment = equipment
self.equipment.parent = self
2022-01-10 13:21:17 -05:00
self.fighter = fighter
2022-01-12 13:45:52 -05:00
self.fighter.parent = self
2022-01-10 13:21:17 -05:00
self.inventory = inventory
self.inventory.parent = self
2022-01-25 15:51:59 -05:00
self.level = level
self.level.parent = self
2022-01-10 13:21:17 -05:00
@property
def is_alive(self) -> bool:
"""Returns True as long as this actor can perform actions."""
return bool(self.ai)
class Item(Entity):
def __init__(
2022-02-08 10:00:28 -05:00
self,
*,
x: int = 0,
y: int = 0,
char: str = "?",
color: Tuple[int, int, int] = (255, 255, 255),
name: str = "<Unamed>",
consumable: Optional[Consumable] = None,
equippable: Optional[Equippable] = None,
):
super().__init__(
x=x,
y=y,
char=char,
color=color,
name=name,
blocks_movement=False,
render_order=RenderOrder.ITEM,
)
self.consumable = consumable
if self.consumable:
self.consumable.parent = self
self.equippable = equippable
if self.equippable:
self.equippable.parent = self