Skip to content

Storage rework rework #39

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 22 commits into from
Jun 13, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion data/worlds/chaosdorf/areas/cave.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name = "Cave"
name = "cave"
description = "a comfy room with sofas and a tv"

[[contents]]
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name = "confeerence room"
name = "confererence room"
description = "a room with a giant tv, a conference table, and a window."

[[contents]]
8 changes: 4 additions & 4 deletions data/worlds/chaosdorf/areas/floor.toml
Original file line number Diff line number Diff line change
@@ -10,19 +10,19 @@ obvious = true
[[contents]]
kind = "gateway"
name = "everyones toilet door"
target = "everyones-toilet"
target = "everyones toilet"
obvious = true

[[contents]]
kind = "gateway"
name = "flinta toilet door"
target = "flinta-toilet"
target = "flinta toilet"
obvious = true

[[contents]]
kind = "gateway"
name = "premium toilet door"
target = "premium-toilet"
target = "premium toilet"
obvious = true

[[contents]]
@@ -34,7 +34,7 @@ obvious = true
[[contents]]
kind = "gateway"
name = "conference room door"
target = "conference-room"
target = "conference room"
obvious = true

[[contents]]
2 changes: 1 addition & 1 deletion data/worlds/chaosdorf/areas/lounge.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name = "Lounge"
name = "lounge"
description = "a place to eat and socialize"

[[contents]]
4 changes: 2 additions & 2 deletions data/worlds/chaosdorf/world.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "Chaosdorf"
name = "chaosdorf"
language = "en"
areas = ["cave", "lounge", "kitchen", "hackcenter", "floor", "elab", "conference-room", "everyones-toilet", "flinta-toilet", "premium-toilet", "wetlab"]
areas = ["cave", "lounge", "kitchen", "hackcenter", "floor", "elab", "conference room", "everyones toilet", "flinta toilet", "premium toilet", "wetlab"]
spawn = "cave"
intro_text = """
You awake confused from a deep sleep.
2 changes: 2 additions & 0 deletions data/worlds/test/areas/test_area.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
name = "test area"
description = "an area could be a dungeon, a room, a castle"
3 changes: 3 additions & 0 deletions data/worlds/test/characters/Enemy/test_enemy.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name = "test enemy"
description = "an enemy is a character which will attack the player"
health = 100
3 changes: 3 additions & 0 deletions data/worlds/test/characters/Player/test_player.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name = "test player"
description = "the playable character"
health = 100
3 changes: 3 additions & 0 deletions data/worlds/test/characters/test_character.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name = "test character"
description = "a character is a person in the world"
health = 100
3 changes: 3 additions & 0 deletions data/worlds/test/containers/test_container.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name = "test container"
description = "a container is an item which has an inventory"
capacity = 10
3 changes: 3 additions & 0 deletions data/worlds/test/entities/test_entity.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name = "test entity"
description = "an entity is an abstract thing"
obvious = true
4 changes: 4 additions & 0 deletions data/worlds/test/gateways/test_gateway.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
name = "test gateway"
description = "a gateway is a portal to another area"
target = "test area"
locked = false
3 changes: 3 additions & 0 deletions data/worlds/test/inventories/test_inventory.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name = "test inventory"
description = "an inventory can contain items"
capacity = 10
7 changes: 7 additions & 0 deletions data/worlds/test/items/Armour/test_armour.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
name = "test armour"
description = "armour is an item which can be worn by the player"
obvious = true
moveable = true
carryable = true
armour_type = "head"
defense = 10
4 changes: 4 additions & 0 deletions data/worlds/test/items/Key/test_key.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
name = "test key"
description = "a key is an item which can be used by the player to open doors"
obvious = true
key_id = "dungeon key 1"
3 changes: 3 additions & 0 deletions data/worlds/test/items/Weapon/test_weapon.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name = "test weapon"
description = "a weapon is an item which can be used by the player to damage his enemies"
damage = 10
5 changes: 5 additions & 0 deletions data/worlds/test/items/test_item.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
name = "test item"
description = "an item is a entity in the world, which the player can interact with"
obvious = true
moveable = true
carryable = true
4 changes: 4 additions & 0 deletions data/worlds/test/world.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
name = "test"
language = "en"
areas = ["test area"]
spawn = "test area"
15 changes: 14 additions & 1 deletion src/fantasy_forge/area.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,33 @@
"""An Area is a place in the world, containing NPCs, Items and connections to other areas."""

from __future__ import annotations

import logging
from pathlib import Path
from typing import TYPE_CHECKING, Any, Iterator, Self

import toml

from fantasy_forge.entity import Entity

logger = logging.getLogger(__name__)


class Area(Entity):
"""An Area is a place in the world, containing NPCs, Items and connections to other areas."""

__important_attributes__ = ("name",)
contents: dict[str, Entity]

def __init__(self: Self, messages: Messages, config_dict: dict[str, Any]):
"""
config_dict contents

inherited from Entity
'name' (str): name of the entity
'description' (str): description of the entity (default: "")
'obvious'(bool): whether the entity will be spotted immediately (default: False)
"""
super().__init__(messages, config_dict)
self.contents: dict = {}

24 changes: 24 additions & 0 deletions src/fantasy_forge/armour.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
"""Armour class

An Armour is an item which can be worn by Characters and grants protection.
"""

from __future__ import annotations

from typing import TYPE_CHECKING, Self
@@ -13,16 +18,35 @@


class Armour(Item):
"""An Armour object."""

armour_type: str
defense: int

__important_attributes__ = ("name", "armour_type", "defense")
__attributes__ = {**Item.__attributes__, "armour_type": str, "defense": int}

def __init__(self, messages: Messages, config_dict):
"""
config_dict contents
'armour_type' (str): armour slot ("head", "torso", "legs", "feet")
'defense' (int): defense points gained by armour

inherited from Item:
'moveable' (bool): can the item be moved by the player (default: True)
'carryable' (bool): can the item be put in the inventory by the player (default: True)

inherited from Entity
'name' (str): name of the entity
'description' (str): description of the entity (default: "")
'obvious'(bool): whether the entity will be spotted immediately (default: False)
"""
# set armour type
a_type: str = config_dict.pop("armour_type")
assert a_type in ARMOUR_TYPES
self.armour_type = a_type
self.defense = config_dict.pop("defense")

super().__init__(messages, config_dict)

def to_dict(self: Self) -> dict:
19 changes: 19 additions & 0 deletions src/fantasy_forge/character.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
"""Character class

A character is a living entity, which can interact with other entities or characters.
"""

from __future__ import annotations

from typing import TYPE_CHECKING, Any, Self
@@ -26,20 +31,32 @@ class Character(Entity):
"""A character in the world."""

__important_attributes__ = ("name", "health", "alive")
__attributes__ = {**Entity.__attributes__, "health": int, "alive": bool}

health: int
inventory: Inventory
main_hand: Weapon | None
_alive: bool

def __init__(self: Self, messages: Messages, config_dict: dict[str, Any]) -> None:
"""
config_dict contents
'health' (int): health points

inherited from Entity:
'name' (str): name of the entity
'description' (str): description of the entity (default: "")
'obvious'(bool): whether the entity will be spotted immediately (default: False)
"""

self.health = config_dict.pop("health")
self.inventory = Inventory(messages, BASE_INVENTORY_CAPACITY)
self.main_hand = None
super().__init__(messages, config_dict)

@property
def alive(self: Self) -> bool:
"""Return True if the character is alive."""
self._alive = self.health > 0
return self._alive

@@ -58,6 +75,7 @@ def attack(self: Self, target: Character) -> None:
)

def on_attack(self: Self, weapon: Weapon):
"""Handles an incoming attack."""
self.health -= weapon.damage

def _on_death(self: Self, player: Player):
@@ -80,6 +98,7 @@ def _on_death(self: Self, player: Player):
for loot_item in self.inventory:
player.area.contents[loot_item.name] = loot_item
player.seen_entities[loot_item.name] = loot_item

self.messages.to(
[player],
"attack-drop-single",
42 changes: 34 additions & 8 deletions src/fantasy_forge/container.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,40 @@
"""Container class

A container is an item in the world which holds an inventory.
"""

from typing import Any, Self

from fantasy_forge.entity import Entity
from fantasy_forge.inventory import Inventory
from fantasy_forge.world import World
from fantasy_forge.item import Item


class Container(Inventory, Item):
"""Container object."""

__important_attributes__ = (*Item.__important_attributes__, "capacity")
__attributes__ = {**Inventory.__attributes__, **Item.__attributes__}

def __init__(
self: Self, config_dict: dict[str, Any], l10n: FluentLocalization
) -> None:
"""
config_dict contents
inherited from Inventory
'capacity' (int): maximum capacity of the inventory

inherited from Item
'moveable' (bool): can the item be moved by the player (default: True)
'carryable' (bool): can the item be put in the inventory by the player (default: True)

inherited from Entity
'name' (str): name of the entity
'description' (str): description of the entity (default: "")
'obvious'(bool): whether the entity will be spotted immediately (default: False)
"""
Inventory.__init__(self, config_dict, l10n)
Item.__init__(self, config_dict, l10n)

class Container(Entity, Inventory):
__important_attributes__ = ("name", "capacity")

def __init__(self: Self, world: World, config_dict: dict[str, Any]):
capacity: int = config_dict.get("capacity", 10)
Entity.__init__(world, capacity)
Inventory.__init__(world, config_dict)
if TYPE_CHECKING:
from fluent.runtime import FluentLocalization
22 changes: 20 additions & 2 deletions src/fantasy_forge/enemy.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
from typing import Any, Self
"""Enemy class

An enemy is a hostile character which will attack the player on contact.
"""

from fantasy_forge.character import Character, bare_hands
from fantasy_forge.item import Item
@@ -7,11 +10,26 @@

class Enemy(Character):
"""An enemy is a person which will fight back."""

def __init__(self: Self, messages: Messages, config_dict: dict[str, Any]):
"""
config_dict contents
'loot' (list[Item]): items dropped after death

inherited from Character
'health' (int): health points

inherited from Entity:
'name' (str): name of the entity
'description' (str): description of the entity (default: "")
'obvious'(bool): whether the entity will be spotted immediately (default: False)
"""
super().__init__(messages, config_dict)
for item_dict in config_dict.get("loot", []):
self.inventory.add(Item(messages, item_dict))

def __str__(self: Self) -> str:
return self.name


if TYPE_CHECKING:
from fluent.runtime import FluentLocalization
19 changes: 17 additions & 2 deletions src/fantasy_forge/entity.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,42 @@
"""Entity class

An entity is an abstract object in the world.
Each entity is identifiable by its name.
"""

from __future__ import annotations

from typing import TYPE_CHECKING, Any, Self


class Entity:
"""An Entity is an abstract object in the world."""
"""An Entity object"""

__important_attributes__ = ("name",)
__attributes__: dict[str, type] = {"name": str, "description": str, "obvious": bool}

messages: Messages
name: str
description: str
obvious: bool # obvious entities are seen when entering the room
l10n: FluentLocalization

def __init__(
self: Self,
messages: Messages,
config_dict: dict[str, Any],
) -> None:
"""
config_dict contents
'name' (str): name of the entity
'description' (str): description of the entity (default: "")
'obvious'(bool): whether the entity will be spotted immediately (default: False)
"""
self.messages = messages
self.name = config_dict.pop("name")
self.description = config_dict.pop("description", "")
self.obvious = config_dict.pop("obvious", False)

def on_look(self: Self, actor: Player):
actor.shell.stdout.write(self.description + "\n")

@@ -48,6 +62,7 @@ def __str__(self: Self) -> str:
return self.name

def to_dict(self: Self) -> dict:
"""Returns entity attributes as a dictionary."""
entity_dict: dict = {"name": self.name, "description": self.description}
return entity_dict

Loading