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:
parent
3be4370b2f
commit
68161fd025
4 changed files with 186 additions and 0 deletions
7
content/things/chest.toml
Normal file
7
content/things/chest.toml
Normal 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
7
content/things/sack.toml
Normal 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"]
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
149
tests/test_container_templates.py
Normal file
149
tests/test_container_templates.py
Normal 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
|
||||||
Loading…
Reference in a new issue