379 lines
8.8 KiB
Python
379 lines
8.8 KiB
Python
"""Tests for zone loading from TOML files."""
|
|
|
|
import pathlib
|
|
import tempfile
|
|
|
|
from mudlib.portal import Portal
|
|
from mudlib.zones import load_zone, load_zones
|
|
|
|
|
|
def test_load_zone():
|
|
"""Load a zone from TOML file."""
|
|
# Create a temporary TOML file
|
|
with tempfile.NamedTemporaryFile(mode="w", suffix=".toml", delete=False) as f:
|
|
f.write("""
|
|
name = "test_zone"
|
|
description = "a test zone"
|
|
width = 4
|
|
height = 3
|
|
toroidal = false
|
|
|
|
[terrain]
|
|
rows = [
|
|
"####",
|
|
"#..#",
|
|
"####",
|
|
]
|
|
|
|
[terrain.impassable]
|
|
tiles = ["#"]
|
|
""")
|
|
temp_path = pathlib.Path(f.name)
|
|
|
|
try:
|
|
zone = load_zone(temp_path)
|
|
|
|
assert zone.name == "test_zone"
|
|
assert zone.width == 4
|
|
assert zone.height == 3
|
|
assert zone.toroidal is False
|
|
assert len(zone.terrain) == 3
|
|
assert zone.terrain[0] == ["#", "#", "#", "#"]
|
|
assert zone.terrain[1] == ["#", ".", ".", "#"]
|
|
assert zone.terrain[2] == ["#", "#", "#", "#"]
|
|
assert zone.impassable == {"#"}
|
|
finally:
|
|
temp_path.unlink()
|
|
|
|
|
|
def test_load_zone_toroidal():
|
|
"""Load a toroidal zone."""
|
|
with tempfile.NamedTemporaryFile(mode="w", suffix=".toml", delete=False) as f:
|
|
f.write("""
|
|
name = "toroidal_zone"
|
|
description = "a toroidal test zone"
|
|
width = 3
|
|
height = 2
|
|
toroidal = true
|
|
|
|
[terrain]
|
|
rows = [
|
|
"...",
|
|
"...",
|
|
]
|
|
""")
|
|
temp_path = pathlib.Path(f.name)
|
|
|
|
try:
|
|
zone = load_zone(temp_path)
|
|
|
|
assert zone.toroidal is True
|
|
# Default impassable set from Zone class
|
|
assert zone.impassable == {"^", "~"}
|
|
finally:
|
|
temp_path.unlink()
|
|
|
|
|
|
def test_load_zones_from_directory():
|
|
"""Load all zones from a directory."""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
tmpdir_path = pathlib.Path(tmpdir)
|
|
|
|
# Create two zone files
|
|
zone1_path = tmpdir_path / "zone1.toml"
|
|
zone1_path.write_text("""
|
|
name = "zone1"
|
|
description = "first zone"
|
|
width = 2
|
|
height = 2
|
|
toroidal = false
|
|
|
|
[terrain]
|
|
rows = [
|
|
"..",
|
|
"..",
|
|
]
|
|
""")
|
|
|
|
zone2_path = tmpdir_path / "zone2.toml"
|
|
zone2_path.write_text("""
|
|
name = "zone2"
|
|
description = "second zone"
|
|
width = 3
|
|
height = 3
|
|
toroidal = true
|
|
|
|
[terrain]
|
|
rows = [
|
|
"###",
|
|
"#.#",
|
|
"###",
|
|
]
|
|
""")
|
|
|
|
# Create a non-TOML file that should be ignored
|
|
(tmpdir_path / "readme.txt").write_text("not a zone file")
|
|
|
|
zones = load_zones(tmpdir_path)
|
|
|
|
assert len(zones) == 2
|
|
assert "zone1" in zones
|
|
assert "zone2" in zones
|
|
assert zones["zone1"].name == "zone1"
|
|
assert zones["zone2"].name == "zone2"
|
|
|
|
|
|
def test_load_tavern_zone():
|
|
"""Load the actual tavern zone file."""
|
|
# This tests the real tavern.toml file in content/zones/
|
|
project_root = pathlib.Path(__file__).resolve().parents[1]
|
|
tavern_path = project_root / "content" / "zones" / "tavern.toml"
|
|
|
|
zone = load_zone(tavern_path)
|
|
|
|
assert zone.name == "tavern"
|
|
assert zone.width == 8
|
|
assert zone.height == 6
|
|
assert zone.toroidal is False
|
|
assert zone.spawn_x == 1
|
|
assert zone.spawn_y == 1
|
|
assert len(zone.terrain) == 6
|
|
assert zone.terrain[0] == ["#", "#", "#", "#", "#", "#", "#", "#"]
|
|
assert zone.terrain[5] == ["#", "#", "#", "#", ".", "#", "#", "#"]
|
|
assert zone.impassable == {"#"}
|
|
# Check that interior is passable
|
|
assert zone.is_passable(1, 1)
|
|
assert zone.is_passable(4, 3)
|
|
# Check that walls are impassable
|
|
assert not zone.is_passable(0, 0)
|
|
assert not zone.is_passable(7, 0)
|
|
|
|
|
|
def test_load_zone_with_spawn_point():
|
|
"""Load a zone with spawn_x and spawn_y defined."""
|
|
with tempfile.NamedTemporaryFile(mode="w", suffix=".toml", delete=False) as f:
|
|
f.write("""
|
|
name = "spawn_zone"
|
|
description = "a zone with spawn point"
|
|
width = 10
|
|
height = 10
|
|
spawn_x = 5
|
|
spawn_y = 7
|
|
|
|
[terrain]
|
|
rows = [
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
]
|
|
""")
|
|
temp_path = pathlib.Path(f.name)
|
|
|
|
try:
|
|
zone = load_zone(temp_path)
|
|
|
|
assert zone.spawn_x == 5
|
|
assert zone.spawn_y == 7
|
|
finally:
|
|
temp_path.unlink()
|
|
|
|
|
|
def test_load_zone_default_spawn_point():
|
|
"""Load a zone without spawn point defined defaults to (0, 0)."""
|
|
with tempfile.NamedTemporaryFile(mode="w", suffix=".toml", delete=False) as f:
|
|
f.write("""
|
|
name = "default_spawn"
|
|
description = "a zone without spawn point"
|
|
width = 5
|
|
height = 5
|
|
|
|
[terrain]
|
|
rows = [
|
|
".....",
|
|
".....",
|
|
".....",
|
|
".....",
|
|
".....",
|
|
]
|
|
""")
|
|
temp_path = pathlib.Path(f.name)
|
|
|
|
try:
|
|
zone = load_zone(temp_path)
|
|
|
|
assert zone.spawn_x == 0
|
|
assert zone.spawn_y == 0
|
|
finally:
|
|
temp_path.unlink()
|
|
|
|
|
|
def test_load_zone_with_portals():
|
|
"""Load a zone with portals defined."""
|
|
with tempfile.NamedTemporaryFile(mode="w", suffix=".toml", delete=False) as f:
|
|
f.write("""
|
|
name = "portal_zone"
|
|
description = "a zone with portals"
|
|
width = 10
|
|
height = 10
|
|
|
|
[terrain]
|
|
rows = [
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
"..........",
|
|
]
|
|
|
|
[[portals]]
|
|
x = 5
|
|
y = 3
|
|
target = "tavern:1,1"
|
|
label = "tavern door"
|
|
|
|
[[portals]]
|
|
x = 2
|
|
y = 7
|
|
target = "forest:10,5"
|
|
label = "forest path"
|
|
""")
|
|
temp_path = pathlib.Path(f.name)
|
|
|
|
try:
|
|
zone = load_zone(temp_path)
|
|
|
|
# Find portals in zone contents
|
|
portals = [obj for obj in zone._contents if isinstance(obj, Portal)]
|
|
assert len(portals) == 2
|
|
|
|
# Check first portal (tavern door at 5,3)
|
|
tavern_portal = [p for p in portals if p.name == "tavern door"][0]
|
|
assert tavern_portal.x == 5
|
|
assert tavern_portal.y == 3
|
|
assert tavern_portal.target_zone == "tavern"
|
|
assert tavern_portal.target_x == 1
|
|
assert tavern_portal.target_y == 1
|
|
assert tavern_portal.location == zone
|
|
|
|
# Check second portal (forest path at 2,7)
|
|
forest_portal = [p for p in portals if p.name == "forest path"][0]
|
|
assert forest_portal.x == 2
|
|
assert forest_portal.y == 7
|
|
assert forest_portal.target_zone == "forest"
|
|
assert forest_portal.target_x == 10
|
|
assert forest_portal.target_y == 5
|
|
assert forest_portal.location == zone
|
|
|
|
# Verify portals are at correct coordinates
|
|
contents_at_5_3 = zone.contents_at(5, 3)
|
|
assert tavern_portal in contents_at_5_3
|
|
|
|
contents_at_2_7 = zone.contents_at(2, 7)
|
|
assert forest_portal in contents_at_2_7
|
|
finally:
|
|
temp_path.unlink()
|
|
|
|
|
|
def test_load_zone_without_portals():
|
|
"""Load a zone without portals section works fine."""
|
|
with tempfile.NamedTemporaryFile(mode="w", suffix=".toml", delete=False) as f:
|
|
f.write("""
|
|
name = "no_portals"
|
|
description = "a zone without portals"
|
|
width = 3
|
|
height = 3
|
|
|
|
[terrain]
|
|
rows = [
|
|
"...",
|
|
"...",
|
|
"...",
|
|
]
|
|
""")
|
|
temp_path = pathlib.Path(f.name)
|
|
|
|
try:
|
|
zone = load_zone(temp_path)
|
|
|
|
# Should have no portals
|
|
portals = [obj for obj in zone._contents if isinstance(obj, Portal)]
|
|
assert len(portals) == 0
|
|
finally:
|
|
temp_path.unlink()
|
|
|
|
|
|
def test_load_zone_portal_with_aliases():
|
|
"""Portal can have optional aliases field in TOML."""
|
|
with tempfile.NamedTemporaryFile(mode="w", suffix=".toml", delete=False) as f:
|
|
f.write("""
|
|
name = "alias_zone"
|
|
description = "a zone with aliased portal"
|
|
width = 5
|
|
height = 5
|
|
|
|
[terrain]
|
|
rows = [
|
|
".....",
|
|
".....",
|
|
".....",
|
|
".....",
|
|
".....",
|
|
]
|
|
|
|
[[portals]]
|
|
x = 2
|
|
y = 2
|
|
target = "elsewhere:0,0"
|
|
label = "mysterious gateway"
|
|
aliases = ["gateway", "gate", "portal"]
|
|
""")
|
|
temp_path = pathlib.Path(f.name)
|
|
|
|
try:
|
|
zone = load_zone(temp_path)
|
|
|
|
portals = [obj for obj in zone._contents if isinstance(obj, Portal)]
|
|
assert len(portals) == 1
|
|
|
|
portal = portals[0]
|
|
assert portal.name == "mysterious gateway"
|
|
assert portal.aliases == ["gateway", "gate", "portal"]
|
|
finally:
|
|
temp_path.unlink()
|
|
|
|
|
|
def test_tavern_has_portal_to_hub():
|
|
"""Tavern zone has a portal at the door leading to hub zone."""
|
|
project_root = pathlib.Path(__file__).resolve().parents[1]
|
|
tavern_path = project_root / "content" / "zones" / "tavern.toml"
|
|
|
|
zone = load_zone(tavern_path)
|
|
|
|
# Find portals in zone
|
|
portals = [obj for obj in zone._contents if isinstance(obj, Portal)]
|
|
assert len(portals) == 1
|
|
|
|
# Check portal is at the door (4, 5) and leads to hub
|
|
portal = portals[0]
|
|
assert portal.name == "the tavern door"
|
|
assert portal.x == 4
|
|
assert portal.y == 5
|
|
assert portal.target_zone == "hub"
|
|
assert portal.target_x == 14
|
|
assert portal.target_y == 7
|
|
|
|
# Verify portal is accessible at door coordinates
|
|
contents_at_door = zone.contents_at(4, 5)
|
|
assert portal in contents_at_door
|