def go_to(self, location):
"""Relocate the element to a specific location."""
current = self.get("location")
- if current and current in universe.contents[current].contents:
+ if current and self.key in universe.contents[current].contents:
del universe.contents[current].contents[self.key]
if location in universe.contents: self.set("location", location)
universe.contents[location].contents[self.key] = self
def go_home(self):
"""Relocate the element to its default location."""
self.go_to(self.get("default_location"))
+ self.echo_to_location("You suddenly realize that " + self.get("name") + " is here.")
def move_direction(self, direction):
"""Relocate the element in a specified direction."""
+ self.echo_to_location(self.get("name") + " exits " + universe.categories["internal"]["directions"].getdict(direction)["exit"] + ".")
+ self.send("You exit " + universe.categories["internal"]["directions"].getdict(direction)["exit"] + ".")
self.go_to(universe.contents[self.get("location")].link_neighbor(direction))
+ self.echo_to_location(self.get("name") + " arrives from " + universe.categories["internal"]["directions"].getdict(direction)["enter"] + ".")
def look_at(self, key):
"""Show an element to another element."""
if self.owner:
portals = {}
if match("""^location:-?\d+,-?\d+,-?\d+$""", self.key):
coordinates = [(int(x)) for x in self.key.split(":")[1].split(",")]
- offsets = {
- "down": (0,0,-1),
- "east": (1,0,0),
- "north": (0,1,0),
- "south": (0,-1,0),
- "up": (0,0,1),
- "west": (-1,0,0)
- }
+ directions = universe.categories["internal"]["directions"]
+ offsets = dict([(x, directions.getdict(x)["vector"]) for x in directions.facets()])
for portal in self.getlist("gridlinks"):
adjacent = map(lambda c,o: c+o, coordinates, offsets[portal])
neighbor = "location:" + ",".join([(str(x)) for x in adjacent])
self.output_queue = []
self.partial_input = ""
self.echoing = True
+ self.received_newline = True
self.terminator = IAC+GA
self.negotiation_pause = 0
self.avatar = None
"output_queue",
"partial_input",
"echoing",
+ "received_newline",
"terminator",
"negotiation_pause",
"avatar",
"""Remove a user from the list of connected users."""
universe.userlist.remove(self)
- def send(self, output, eol="$(eol)", raw=False, flush=False, add_prompt=True):
+ def send(self, output, eol="$(eol)", raw=False, flush=False, add_prompt=True, just_prompt=False):
"""Send arbitrary text to a connected user."""
# unless raw mode is on, clean it up all nice and pretty
# start with a newline, append the message, then end
# with the optional eol string passed to this function
# and the ansi escape to return to normal text
- output = "$(eol)" + output + eol + chr(27) + "[0m"
+ if not just_prompt: output = "$(eol)$(eol)" + output
+ output += eol + chr(27) + "[0m"
# tack on a prompt if active
- if self.state == "active" and add_prompt: output += "$(eol)> "
+ if self.state == "active":
+ if not just_prompt: output += "$(eol)"
+ if add_prompt: output += "> "
# find and replace macros in the output
output = replace_macros(self, output)
def flush(self):
"""Try to send the last item in the queue and remove it."""
if self.output_queue:
+ if self.received_newline:
+ self.received_newline = False
+ if self.output_queue[0].startswith("\r\n"):
+ self.output_queue[0] = self.output_queue[0][2:]
try:
self.connection.send(self.output_queue[0])
del self.output_queue[0]
if self.avatar:
current = self.avatar.get("location")
self.avatar.set("default_location", current)
+ self.avatar.echo_to_location("You suddenly wonder where " + self.avatar.get("name") + " went.")
del universe.contents[current].contents[self.avatar.key]
self.avatar.remove_facet("location")
self.avatar.owner = None
elif value.find(":") > 0: return eval("{" + value + "}")
else: return { value: None }
-def broadcast(message):
+def broadcast(message, add_prompt=True):
"""Send a message to all connected users."""
- for each_user in universe.userlist: each_user.send("$(eol)" + message)
+ for each_user in universe.userlist: each_user.send("$(eol)" + message, add_prompt=add_prompt)
def log(message):
"""Log a message."""
# the time in posix log timestamp format
timestamp = asctime()[4:19]
+ file_name = universe.categories["internal"]["logging"].get("file")
+ if file_name:
+ file_descriptor = file(file_name, "a")
+ file_descriptor.write(timestamp + " " + message + "\n")
+ file_descriptor.flush()
+ file_descriptor.close()
+
# send the timestamp and message to standard output
- print(timestamp + " " + message)
+ if universe.categories["internal"]["logging"].getboolean("stdout"):
+ print(timestamp + " " + message)
# send the message to the system log
- openlog("mudpy", LOG_PID, LOG_INFO | LOG_DAEMON)
- syslog(message)
- closelog()
+ syslog_name = universe.categories["internal"]["logging"].get("syslog")
+ if syslog_name:
+ openlog(syslog_name, LOG_PID, LOG_INFO | LOG_DAEMON)
+ syslog(message)
+ closelog()
def wrap_ansi_text(text, width):
"""Wrap text with arbitrary width while ignoring ANSI colors."""
user.menu_seen = False
# if the user's client echo is off, send a blank line for aesthetics
- if not user.echoing: user.send("", "")
+ if user.echoing: user.received_newline = True
def generic_menu_handler(user):
"""A generic menu choice handler."""
# get the next waiting line of input
input_data = user.input_queue.pop(0)
- # split out the command (first word) and parameters (everything else)
- if input_data.find(" ") > 0:
- command_name, parameters = input_data.split(" ", 1)
- else:
- command_name = input_data
- parameters = ""
+ # is there input?
+ if input_data:
- # lowercase the command
- command_name = command_name.lower()
+ # split out the command (first word) and parameters (everything else)
+ if input_data.find(" ") > 0:
+ command_name, parameters = input_data.split(" ", 1)
+ else:
+ command_name = input_data
+ parameters = ""
- # the command matches a command word for which we have data
- if command_name in universe.categories["command"]:
- command = universe.categories["command"][command_name]
- else: command = None
+ # lowercase the command
+ command_name = command_name.lower()
- # if it's allowed, do it
- if user.can_run(command): exec(command.get("action"))
+ # the command matches a command word for which we have data
+ if command_name in universe.categories["command"]:
+ command = universe.categories["command"][command_name]
+ else: command = None
+
+ # if it's allowed, do it
+ if user.can_run(command): exec(command.get("action"))
- # otherwise, give an error
- elif command_name: command_error(user, input_data)
+ # otherwise, give an error
+ elif command_name: command_error(user, input_data)
+ # if no input, just idle back with a prompt
+ else: user.send("", just_prompt=True)
+
def command_halt(user, parameters):
"""Halt the world."""
else: message = "User " + user.account.get("name") + " halted the world."
# let everyone know
- broadcast(message)
+ broadcast(message, add_prompt=False)
log(message)
# set a flag to terminate the world
user.avatar.move_direction(parameters)
else: user.send("You cannot go that way.")
+def command_look(user, parameters):
+ """Look around."""
+ if parameters: user.send("You look at or in anything yet.")
+ else: user.avatar.look_at(user.avatar.get("location"))
+
def command_say(user, parameters):
"""Speak to others in the same room."""