Add container support to thing template loader

Extended ThingTemplate with optional container fields (capacity, closed, locked).
When a template includes capacity, spawn_thing now creates a Container instead
of a regular Thing.

Added two example container templates:
- chest.toml: non-portable, capacity 5, starts closed
- sack.toml: portable, capacity 3, starts open
This commit is contained in:
Jared Miller 2026-02-11 20:43:09 -05:00
parent 3be4370b2f
commit 68161fd025
Signed by: shmup
GPG key ID: 22B5C6D66A38B06C
4 changed files with 186 additions and 0 deletions

View file

@ -0,0 +1,7 @@
name = "chest"
description = "a sturdy wooden chest with iron bindings"
portable = false
capacity = 5
closed = true
locked = false
aliases = ["box"]

7
content/things/sack.toml Normal file
View file

@ -0,0 +1,7 @@
name = "sack"
description = "a rough cloth sack with drawstring closure"
portable = true
capacity = 3
closed = false
locked = false
aliases = ["bag"]

View file

@ -4,6 +4,7 @@ import tomllib
from dataclasses import dataclass, field from dataclasses import dataclass, field
from pathlib import Path from pathlib import Path
from mudlib.container import Container
from mudlib.object import Object from mudlib.object import Object
from mudlib.thing import Thing from mudlib.thing import Thing
@ -16,6 +17,10 @@ class ThingTemplate:
description: str description: str
portable: bool = True portable: bool = True
aliases: list[str] = field(default_factory=list) 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 # Module-level registry
@ -31,6 +36,9 @@ def load_thing_template(path: Path) -> ThingTemplate:
description=data["description"], description=data["description"],
portable=data.get("portable", True), portable=data.get("portable", True),
aliases=data.get("aliases", []), 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, y: int | None = None,
) -> Thing: ) -> Thing:
"""Create a Thing instance from a template at the given location.""" """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( return Thing(
name=template.name, name=template.name,
description=template.description, description=template.description,

View file

@ -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