Compare commits

..

4 commits

3 changed files with 39 additions and 12 deletions

View file

@ -3,6 +3,7 @@
from typing import Any
from mudlib.commands import CommandDefinition, register
from mudlib.entity import Entity
from mudlib.player import Player, players
# World instance will be injected by the server
@ -69,8 +70,7 @@ async def move_player(player: Player, dx: int, dy: int, direction_name: str) ->
# Check if the target is passable
if not world.is_passable(target_x, target_y):
player.writer.write("You can't go that way.\r\n")
await player.writer.drain()
await player.send("You can't go that way.\r\n")
return
# Send departure message to players in the old area
@ -94,11 +94,11 @@ async def move_player(player: Player, dx: int, dy: int, direction_name: str) ->
await cmd_look(player, "")
async def send_nearby_message(player: Player, x: int, y: int, message: str) -> None:
"""Send a message to all players near a location, excluding the player.
async def send_nearby_message(entity: Entity, x: int, y: int, message: str) -> None:
"""Send a message to all players near a location, excluding the entity.
Args:
player: The player who triggered the message (excluded from receiving it)
entity: The entity who triggered the message (excluded from receiving it)
x: X coordinate of the location
y: Y coordinate of the location
message: The message to send
@ -107,7 +107,7 @@ async def send_nearby_message(player: Player, x: int, y: int, message: str) -> N
viewport_range = 10
for other in players.values():
if other.name == player.name:
if other.name == entity.name:
continue
# Check if other player is within viewport range (wrapping)
@ -116,8 +116,7 @@ async def send_nearby_message(player: Player, x: int, y: int, message: str) -> N
dx_dist = min(dx_dist, world.width - dx_dist)
dy_dist = min(dy_dist, world.height - dy_dist)
if dx_dist <= viewport_range and dy_dist <= viewport_range:
other.writer.write(message)
await other.writer.drain()
await other.send(message)
# Define individual movement command handlers

24
src/mudlib/entity.py Normal file
View file

@ -0,0 +1,24 @@
"""Base entity class for characters in the world."""
from dataclasses import dataclass
@dataclass
class Entity:
"""Base class for anything with position and identity in the world."""
name: str
x: int
y: int
async def send(self, message: str) -> None:
"""Send a message to this entity. Base implementation is a no-op."""
pass
@dataclass
class Mob(Entity):
"""Represents a non-player character (NPC) in the world."""
description: str = ""
alive: bool = True

View file

@ -3,14 +3,13 @@
from dataclasses import dataclass, field
from typing import Any
from mudlib.entity import Entity
@dataclass
class Player:
class Player(Entity):
"""Represents a connected player."""
name: str
x: int # position in world
y: int
writer: Any # telnetlib3 TelnetWriter for sending output
reader: Any # telnetlib3 TelnetReader for reading input
flying: bool = False
@ -21,6 +20,11 @@ class Player:
"""Current mode is the top of the stack."""
return self.mode_stack[-1]
async def send(self, message: str) -> None:
"""Send a message to the player via their telnet writer."""
self.writer.write(message)
await self.writer.drain()
# Global registry of connected players
players: dict[str, Player] = {}