diff --git a/content/things/chest.toml b/content/things/chest.toml new file mode 100644 index 0000000..fa0a49e --- /dev/null +++ b/content/things/chest.toml @@ -0,0 +1,7 @@ +name = "chest" +description = "a sturdy wooden chest with iron bindings" +portable = false +capacity = 5 +closed = true +locked = false +aliases = ["box"] diff --git a/content/things/sack.toml b/content/things/sack.toml new file mode 100644 index 0000000..ebbaab3 --- /dev/null +++ b/content/things/sack.toml @@ -0,0 +1,7 @@ +name = "sack" +description = "a rough cloth sack with drawstring closure" +portable = true +capacity = 3 +closed = false +locked = false +aliases = ["bag"] diff --git a/src/mudlib/things.py b/src/mudlib/things.py index 915181a..c9da055 100644 --- a/src/mudlib/things.py +++ b/src/mudlib/things.py @@ -4,6 +4,7 @@ import tomllib from dataclasses import dataclass, field from pathlib import Path +from mudlib.container import Container from mudlib.object import Object from mudlib.thing import Thing @@ -16,6 +17,10 @@ class ThingTemplate: description: str portable: bool = True aliases: list[str] = field(default_factory=list) + # Container fields (presence of capacity indicates a container template) + capacity: int | None = None + closed: bool = False + locked: bool = False # Module-level registry @@ -31,6 +36,9 @@ def load_thing_template(path: Path) -> ThingTemplate: description=data["description"], portable=data.get("portable", True), aliases=data.get("aliases", []), + capacity=data.get("capacity"), + closed=data.get("closed", False), + locked=data.get("locked", False), ) @@ -51,6 +59,21 @@ def spawn_thing( y: int | None = None, ) -> Thing: """Create a Thing instance from a template at the given location.""" + # If template has capacity, spawn a Container instead of a Thing + if template.capacity is not None: + return Container( + name=template.name, + description=template.description, + portable=template.portable, + aliases=list(template.aliases), + capacity=template.capacity, + closed=template.closed, + locked=template.locked, + location=location, + x=x, + y=y, + ) + return Thing( name=template.name, description=template.description, diff --git a/tests/test_container_templates.py b/tests/test_container_templates.py new file mode 100644 index 0000000..8ace16c --- /dev/null +++ b/tests/test_container_templates.py @@ -0,0 +1,149 @@ +"""Tests for container template loading and spawning.""" + +from pathlib import Path +from tempfile import TemporaryDirectory + +from mudlib.container import Container +from mudlib.thing import Thing +from mudlib.things import load_thing_template, spawn_thing +from mudlib.zone import Zone + + +def test_load_container_template_with_capacity(): + """load_thing_template recognizes container templates (has capacity field).""" + with TemporaryDirectory() as tmpdir: + toml_path = Path(tmpdir) / "chest.toml" + toml_path.write_text( + """ +name = "chest" +description = "a wooden chest" +capacity = 5 +""" + ) + template = load_thing_template(toml_path) + assert template.name == "chest" + assert template.description == "a wooden chest" + assert hasattr(template, "capacity") + assert template.capacity == 5 + + +def test_load_container_template_with_closed(): + """load_thing_template handles closed field.""" + with TemporaryDirectory() as tmpdir: + toml_path = Path(tmpdir) / "chest.toml" + toml_path.write_text( + """ +name = "chest" +description = "a wooden chest" +capacity = 5 +closed = true +""" + ) + template = load_thing_template(toml_path) + assert template.closed is True + + +def test_load_container_template_with_locked(): + """load_thing_template handles locked field.""" + with TemporaryDirectory() as tmpdir: + toml_path = Path(tmpdir) / "chest.toml" + toml_path.write_text( + """ +name = "chest" +description = "a wooden chest" +capacity = 5 +closed = true +locked = true +""" + ) + template = load_thing_template(toml_path) + assert template.locked is True + + +def test_load_container_template_defaults(): + """Container template fields have sensible defaults.""" + with TemporaryDirectory() as tmpdir: + toml_path = Path(tmpdir) / "sack.toml" + toml_path.write_text( + """ +name = "sack" +description = "a cloth sack" +capacity = 3 +""" + ) + template = load_thing_template(toml_path) + assert template.capacity == 3 + assert template.closed is False # default: open + assert template.locked is False # default: unlocked + + +def test_spawn_container_from_template(): + """spawn_thing creates a Container when template has capacity.""" + with TemporaryDirectory() as tmpdir: + toml_path = Path(tmpdir) / "chest.toml" + toml_path.write_text( + """ +name = "chest" +description = "a wooden chest" +capacity = 5 +closed = true +""" + ) + template = load_thing_template(toml_path) + terrain = [["." for _ in range(10)] for _ in range(10)] + zone = Zone(name="test", width=10, height=10, terrain=terrain) + + thing = spawn_thing(template, zone, x=5, y=5) + + assert isinstance(thing, Container) + assert thing.name == "chest" + assert thing.description == "a wooden chest" + assert thing.capacity == 5 + assert thing.closed is True + assert thing.location is zone + + +def test_spawn_regular_thing_from_template_without_capacity(): + """spawn_thing creates a regular Thing when template lacks capacity.""" + with TemporaryDirectory() as tmpdir: + toml_path = Path(tmpdir) / "rock.toml" + toml_path.write_text( + """ +name = "rock" +description = "a smooth grey rock" +portable = true +""" + ) + template = load_thing_template(toml_path) + terrain = [["." for _ in range(10)] for _ in range(10)] + zone = Zone(name="test", width=10, height=10, terrain=terrain) + + thing = spawn_thing(template, zone, x=5, y=5) + + assert isinstance(thing, Thing) + assert not isinstance(thing, Container) + assert thing.name == "rock" + assert thing.portable is True + + +def test_spawn_portable_container(): + """spawn_thing creates a portable Container (like a sack).""" + with TemporaryDirectory() as tmpdir: + toml_path = Path(tmpdir) / "sack.toml" + toml_path.write_text( + """ +name = "sack" +description = "a cloth sack" +capacity = 3 +portable = true +""" + ) + template = load_thing_template(toml_path) + terrain = [["." for _ in range(10)] for _ in range(10)] + zone = Zone(name="test", width=10, height=10, terrain=terrain) + + thing = spawn_thing(template, zone, x=5, y=5) + + assert isinstance(thing, Container) + assert thing.portable is True + assert thing.capacity == 3