211 lines
6.5 KiB
Python
211 lines
6.5 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, players
|
|
from mudlib.store import account_exists, load_player_data, set_admin
|
|
from mudlib.things import spawn_thing, thing_templates
|
|
from mudlib.zone import Zone
|
|
from mudlib.zones import get_zone, register_zone, zone_registry
|
|
|
|
# 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")
|
|
|
|
|
|
async def cmd_promote(player: Player, args: str) -> None:
|
|
"""Grant admin status to a player."""
|
|
target_name = args.strip()
|
|
if not target_name:
|
|
await player.send("Usage: @promote <player_name>\r\n")
|
|
return
|
|
|
|
if not account_exists(target_name):
|
|
await player.send(f"Account '{target_name}' not found.\r\n")
|
|
return
|
|
|
|
# Check current status via live player or DB
|
|
data = load_player_data(target_name)
|
|
if data and data.get("is_admin"):
|
|
await player.send(f"{target_name} is already an admin.\r\n")
|
|
return
|
|
|
|
set_admin(target_name, True)
|
|
|
|
# Update live player if online
|
|
target = next(
|
|
(p for p in players.values() if p.name.lower() == target_name.lower()),
|
|
None,
|
|
)
|
|
if target is not None:
|
|
target.is_admin = True
|
|
await target.send("You have been granted admin status.\r\n")
|
|
|
|
await player.send(f"{target_name} is now an admin.\r\n")
|
|
|
|
|
|
async def cmd_demote(player: Player, args: str) -> None:
|
|
"""Revoke admin status from a player."""
|
|
target_name = args.strip()
|
|
if not target_name:
|
|
await player.send("Usage: @demote <player_name>\r\n")
|
|
return
|
|
|
|
if target_name.lower() == player.name.lower():
|
|
await player.send("You can't demote yourself.\r\n")
|
|
return
|
|
|
|
if not account_exists(target_name):
|
|
await player.send(f"Account '{target_name}' not found.\r\n")
|
|
return
|
|
|
|
data = load_player_data(target_name)
|
|
if data and not data.get("is_admin"):
|
|
await player.send(f"{target_name} is not an admin.\r\n")
|
|
return
|
|
|
|
set_admin(target_name, False)
|
|
|
|
# Update live player if online
|
|
target = next(
|
|
(p for p in players.values() if p.name.lower() == target_name.lower()),
|
|
None,
|
|
)
|
|
if target is not None:
|
|
target.is_admin = False
|
|
await target.send("Your admin status has been revoked.\r\n")
|
|
|
|
await player.send(f"{target_name} is no longer an admin.\r\n")
|
|
|
|
|
|
async def cmd_zones(player: Player, args: str) -> None:
|
|
"""List all registered zones."""
|
|
if not zone_registry:
|
|
await player.send("No zones registered.\r\n")
|
|
return
|
|
|
|
await player.send("zones:\r\n")
|
|
current_zone_name = (
|
|
player.location.name if isinstance(player.location, Zone) else None
|
|
)
|
|
|
|
for name in sorted(zone_registry.keys()):
|
|
zone = zone_registry[name]
|
|
dimensions = f"{zone.width}x{zone.height}"
|
|
marker = " [here]" if name == current_zone_name else ""
|
|
await player.send(f" {name:<15} {dimensions:>6}{marker}\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"))
|
|
register(
|
|
CommandDefinition("@promote", cmd_promote, admin=True, help="Grant admin status")
|
|
)
|
|
register(
|
|
CommandDefinition("@demote", cmd_demote, admin=True, help="Revoke admin status")
|
|
)
|
|
register(CommandDefinition("@zones", cmd_zones, admin=True, help="List all zones"))
|