mud/src/mudlib/commands/build.py

120 lines
3.6 KiB
Python

"""Builder commands for world editing."""
from pathlib import Path
from mudlib.commands import CommandDefinition, register
from mudlib.export import export_zone_to_file
from mudlib.player import Player
from mudlib.things import spawn_thing, thing_templates
from mudlib.zone import Zone
from mudlib.zones import get_zone, register_zone
# Content directory, set during server startup
_content_dir: Path | None = None
def set_content_dir(path: Path) -> None:
"""Set the content directory for saving zones."""
global _content_dir
_content_dir = path
async def cmd_goto(player: Player, args: str) -> None:
"""Teleport to a named zone's spawn point."""
zone_name = args.strip()
if not zone_name:
await player.send("Usage: @goto <zone_name>\r\n")
return
target = get_zone(zone_name)
if target is None:
await player.send(f"Zone '{zone_name}' not found.\r\n")
return
player.move_to(target, x=target.spawn_x, y=target.spawn_y)
await player.send(f"Teleported to {zone_name}.\r\n")
from mudlib.commands.look import cmd_look
await cmd_look(player, "")
async def cmd_dig(player: Player, args: str) -> None:
"""Create a new blank zone and teleport there."""
parts = args.strip().split()
if len(parts) != 3:
await player.send("Usage: @dig <name> <width> <height>\r\n")
return
name = parts[0]
try:
width = int(parts[1])
height = int(parts[2])
except ValueError:
await player.send("Width and height must be numbers.\r\n")
return
if width < 1 or height < 1:
await player.send("Zone dimensions must be at least 1x1.\r\n")
return
if get_zone(name) is not None:
await player.send(f"Zone '{name}' already exists.\r\n")
return
terrain = [["." for _ in range(width)] for _ in range(height)]
zone = Zone(
name=name,
width=width,
height=height,
terrain=terrain,
toroidal=False,
)
register_zone(name, zone)
player.move_to(zone, x=0, y=0)
await player.send(f"Created zone '{name}' ({width}x{height}).\r\n")
from mudlib.commands.look import cmd_look
await cmd_look(player, "")
async def cmd_save(player: Player, args: str) -> None:
"""Save the current zone to its TOML file."""
zone = player.location
if not isinstance(zone, Zone):
await player.send("You're not in a zone.\r\n")
return
if _content_dir is None:
await player.send("Content directory not configured.\r\n")
return
zones_dir = _content_dir / "zones"
zones_dir.mkdir(parents=True, exist_ok=True)
path = zones_dir / f"{zone.name}.toml"
export_zone_to_file(zone, path)
await player.send(f"Zone '{zone.name}' saved to {path.name}.\r\n")
async def cmd_place(player: Player, args: str) -> None:
"""Place a thing from templates at the player's position."""
thing_name = args.strip()
if not thing_name:
await player.send("Usage: @place <thing_name>\r\n")
return
template = thing_templates.get(thing_name)
if template is None:
await player.send(f"Thing template '{thing_name}' not found.\r\n")
return
spawn_thing(template, player.location, x=player.x, y=player.y)
await player.send(f"Placed {thing_name} at ({player.x}, {player.y}).\r\n")
register(CommandDefinition("@goto", cmd_goto, admin=True, help="Teleport to a zone"))
register(CommandDefinition("@dig", cmd_dig, admin=True, help="Create a new zone"))
register(CommandDefinition("@save", cmd_save, admin=True, help="Save current zone"))
register(CommandDefinition("@place", cmd_place, admin=True, help="Place a thing"))