diff --git a/actions.py b/actions.py index 1522e56..f7978f7 100644 --- a/actions.py +++ b/actions.py @@ -32,6 +32,33 @@ class Action: """ +class PickupAction(Action): + """Pickup an item and add it to the inventory, if there is room for it.""" + + def __init__(self, entity: Actor): + super().__init__(entity) + + def perform(self) -> None: + actor_location_x = self.entity.x + actor_location_y = self.entity.y + inventory = self.entity.inventory + + for item in self.engine.game_map.items: + if actor_location_x == item.x and actor_location_y == item.y: + if len(inventory.items) >= inventory.capacity: + raise exceptions.Impossible("Your inventory is full.") + + self.engine.game_map.entities.remove(item) + item.parent = self.entity.inventory + inventory.items.append(item) + + self.engine.message_log.add_message(f"You picked up the {item.name}!") + + return + + raise exceptions.Impossible("There is nothing here to pick up.") + + class ItemAction(Action): def __init__( self, diff --git a/components/inventory.py b/components/inventory.py new file mode 100644 index 0000000..bcbddac --- /dev/null +++ b/components/inventory.py @@ -0,0 +1,28 @@ +from __future__ import annotations + +from typing import List, TYPE_CHECKING + +from components.base_component import BaseComponent + +if TYPE_CHECKING: + from entity import Actor, Item + + +class Inventory(BaseComponent): + parent: Actor + + def __init__(self, capacity: int): + self.capacity = capacity + self.items: List[Item] = [] + + def drop(self, item: Item) -> None: + """ + Removes an item from the inventory and restores it to the game map, + at the player's current location. + :param item: + :return: + """ + self.items.remove(item) + item.place(self.parent.x, self.parent.y, self.gamemap) + + self.engine.message_log.add_message(f"You dropped the {item.name}.") diff --git a/entity.py b/entity.py index 9d1fdaa..b947d4b 100644 --- a/entity.py +++ b/entity.py @@ -9,6 +9,7 @@ if TYPE_CHECKING: from components.ai import BaseAI from components.consumable import Consumable from components.fighter import Fighter + from components.inventory import Inventory from game_map import GameMap T = TypeVar("T", bound="Entity") @@ -85,7 +86,8 @@ class Actor(Entity): color: Tuple[int, int, int] = (255, 255, 255), name: str = "", ai_cls: Type[BaseAI], - fighter: Fighter + fighter: Fighter, + inventory: Inventory, ): super().__init__( x=x, @@ -102,6 +104,9 @@ class Actor(Entity): self.fighter = fighter self.fighter.parent = self + self.inventory = inventory + self.inventory.parent = self + @property def is_alive(self) -> bool: """Returns True as long as this actor can perform actions.""" diff --git a/entity_factories.py b/entity_factories.py index b172da4..ca8f24f 100644 --- a/entity_factories.py +++ b/entity_factories.py @@ -1,6 +1,7 @@ from components.ai import HostileEnemy from components.consumable import HealingConsumable from components.fighter import Fighter +from components.inventory import Inventory from entity import Actor, Item player = Actor( @@ -9,6 +10,7 @@ player = Actor( name="PLayer", ai_cls=HostileEnemy, fighter=Fighter(hp=30, defense=2, power=5), + inventory=Inventory(capacity=26), ) orc = Actor( @@ -17,13 +19,15 @@ orc = Actor( name="Orc", ai_cls=HostileEnemy, fighter=Fighter(hp=10, defense=0, power=3), + inventory=Inventory(capacity=0) ) troll = Actor( char="T", color=(0, 127, 0), name="Troll", ai_cls=HostileEnemy, - fighter=Fighter(hp=16, defense=1, power=4) + fighter=Fighter(hp=16, defense=1, power=4), + inventory=Inventory(capacity=0) ) health_potion = Item( diff --git a/game_map.py b/game_map.py index dd4b841..ed69b82 100644 --- a/game_map.py +++ b/game_map.py @@ -5,7 +5,7 @@ from typing import Iterable, Iterator, Optional, TYPE_CHECKING import numpy as np # type: ignore from tcod.console import Console -from entity import Actor +from entity import Actor, Item import tile_types if TYPE_CHECKING: @@ -50,6 +50,10 @@ class GameMap: if isinstance(entity, Actor) and entity.is_alive ) + @property + def items(self) -> Iterator[Item]: + yield from (entity for entity in self.entities if isinstance(entity, Item)) + def get_blocking_entity_at_location( self, location_x: int, diff --git a/input_handlers.py b/input_handlers.py index 17859aa..4029a63 100644 --- a/input_handlers.py +++ b/input_handlers.py @@ -8,6 +8,7 @@ from actions import ( Action, BumpAction, EscapeAction, + PickupAction, WaitAction ) import color @@ -109,9 +110,13 @@ class MainGameEventHandler(EventHandler): elif key == tcod.event.K_ESCAPE: action = EscapeAction(player) + elif key == tcod.event.K_v: self.engine.event_handler = HistoryViewer(self.engine) + elif key == tcod.event.K_g: + action = PickupAction(player) + # No valid key was pressed return action