read_only = yes
[command:create]
-action = command_create(user, parameters)
+action = command_create(actor, parameters)
administrative = yes
description = Create a new element in the universe.
help = Ways to create an element:$(eol)$(eol) create actor:fred$(eol) create other:garply foo/bar/baz
[command:delete]
-action = command_delete(user, parameters)
+action = command_delete(actor, parameters)
administrative = yes
description = Delete an existing facet from an element.
help = You can delete any facet of an element as follows:$(eol)$(eol) delete location:boardroom terrain
[command:destroy]
-action = command_destroy(user, parameters)
+action = command_destroy(actor, parameters)
administrative = yes
description = Destroy an existing element in the universe.
help = You can destroy any element in the universe as follows:$(eol)$(eol) destroy prop:dagger
[command:halt]
-action = command_halt(user, parameters)
+action = command_halt(actor, parameters)
administrative = yes
description = Shut down the world.
help = This will save all active accounts, disconnect all clients and stop the entire program.
[command:help]
-action = command_help(user, parameters)
+action = command_help(actor, parameters)
description = List commands or get help on one.
help = This will list all comand words available to you along with a brief description or, alternatively, give you detailed information on one command.
[command:look]
-action = command_look(user, parameters)
+action = command_look(actor, parameters)
description = Look around.
help = With the look command, you can see where you are.
[command:move]
-action = command_move(user, parameters)
+action = command_move(actor, parameters)
description = Move in a specific direction.
help = You move in a direction by entering:$(eol) move north
[command:quit]
-action = command_quit(user)
+action = command_quit(actor)
description = Leave Example.
help = This will save your account and disconnect your client connection.
[command:reload]
-action = command_reload(user)
+action = command_reload(actor)
administrative = yes
description = Reload code modules and data.
help = This will reload all python code modules, reload configuration files and re-read data files.
[command:say]
-action = command_say(user, parameters)
+action = command_say(actor, parameters)
description = State something out loud.
help = This allows you to speak to other characters within the same room. If you end your sentence with specific punctuation, the aparent speech action (ask, exclaim, et cetera) will be adapted accordingly. It will also add punctuation and capitalize your message where needed.
[command:set]
-action = command_set(user, parameters)
+action = command_set(actor, parameters)
administrative = yes
description = Set a facet of an element.
help = Invoke it like this:$(eol)$(eol) set actor:dominique description You see nothing special.
[command:show]
-action = command_show(user, parameters)
+action = command_show(actor, parameters)
administrative = yes
description = Show element data.
-help = Here are the possible incantations:$(eol)$(eol) show categories$(eol) show category actor$(eol) show element location:1:2:3:4$(eol) show files$(eol) show log 20$(eol) show result user.avatar.get("name")$(eol) show time
+help = Here are the possible incantations:$(eol)$(eol) show categories$(eol) show category actor$(eol) show element location:1:2:3:4$(eol) show files$(eol) show log 20$(eol) show result avatar.get("name")$(eol) show time
class Element:
"""An element of the universe."""
- def __init__(self, key, universe, filename=""):
+ def __init__(self, key, universe, filename=None):
"""Set up a new element."""
# not owned by a user by default (used for avatars)
# no contents in here by default
self.contents = {}
+ # an event queue for the element
+ self.events = {}
+
# keep track of our key name
self.key = key
def destroy(self):
"""Remove an element from the universe and destroy it."""
- log("Destroying: " + self.key + ".", 2)
self.origin.data.remove_section(self.key)
del universe.categories[self.category][self.subkey]
del universe.contents[self.key]
newlist = self.getlist(facet)
newlist.append(value)
self.set(facet, newlist)
+
+ def new_event(self, action, when=None):
+ """Create, attach and enqueue an event element."""
+
+ # if when isn't specified, that means now
+ if not when: when = universe.get_time()
+
+ # events are elements themselves
+ event = Element("event:" + self.key + ":" + counter)
+
def send(self, message, eol="$(eol)"):
"""Convenience method to pass messages to an owner."""
if self.owner: self.owner.send(message, eol)
+
+ def can_run(self, command):
+ """Check if the user can run this command object."""
+
+ # has to be in the commands category
+ if command not in universe.categories["command"].values(): result = False
+
+ # avatars of administrators can run any command
+ elif self.owner and self.owner.account.getboolean("administrator"): result = True
+
+ # everyone can run non-administrative commands
+ elif not command.getboolean("administrative"): result = True
+
+ # otherwise the command cannot be run by this actor
+ else: result = False
+
+ # pass back the result
+ return result
+
def go_to(self, location):
"""Relocate the element to a specific location."""
current = self.get("location")
file_descriptor.flush()
file_descriptor.close()
+ # unset the modified flag
+ self.modified = False
+
class Universe:
"""The universe."""
def __init__(self, filename=""):
self.default_origins = {}
self.files = {}
self.private_files = []
- self.loglist = []
+ self.loglines = {}
+ self.pending_events_long = {}
+ self.pending_events_short = {}
self.userlist = []
self.terminate_world = False
self.reload_modules = False
# note that we're now ready for user connections
log("Waiting for connection(s)...")
+ def get_time(self):
+ """Convenience method to get the elapsed time counter."""
+ return self.categories["internal"]["counters"].getint("elapsed")
+
class User:
"""This is a connected user."""
# replace the input with our cleaned-up text
self.partial_input = text
- def can_run(self, command):
- """Check if the user can run this command object."""
-
- # has to be in the commands category
- if command not in universe.categories["command"].values(): result = False
-
- # administrators can run any command
- elif self.account.getboolean("administrator"): result = True
-
- # everyone can run non-administrative commands
- elif not command.getboolean("administrative"): result = True
-
- # otherwise the command cannot be run by this user
- else: result = False
-
- # pass back the result
- return result
-
def new_avatar(self):
"""Instantiate a new, unconfigured avatar for this user."""
counter = 0
# add to the recent log list
for line in lines:
- while 0 < len(universe.loglist) >= max_log_lines: del universe.loglist[0]
- universe.loglist.append(timestamp + " " + line)
+ while 0 < len(universe.loglines) >= max_log_lines: del universe.loglines[0]
+ universe.loglines.append((level, timestamp + " " + line))
+
+def get_loglines(level, start, stop=0):
+ """Return a specific range of loglines filtered by level."""
+
+ # begin with a blank message
+ message = ""
+
+ # filter the log lines
+ loglines = filter(lambda x,y: x>=level, universe.loglines)
+
+ # we need this in several places
+ count = len(loglines)
+
+ # don't proceed if there are no lines
+ if count:
+
+ # can't start before the begining or at the end
+ if start > count: start = count
+ if start < 1: start = 1
+
+ # can't stop before we start
+ if stop >= start: stop = start - 1
+
+ # some preamble
+ message += "There are " + str(len(universe.loglist))
+ message += " log lines in memory and " + str(count)
+ message += " at or above level " + str(level) + "."
+ message += " The lines from " + str(stop)
+ message += " to " + str(start) + " are:$(eol)$(eol)"
+
+ # add the text from the selected lines
+ for line in loglines[-start:-stop]:
+ message += " " + line[1] + "$(eol)"
+
+ # pass it back
+ return message
def wrap_ansi_text(text, width):
"""Wrap text with arbitrary width while ignoring ANSI colors."""
else: command = None
# if it's allowed, do it
- if user.can_run(command): exec(command.get("action"))
+ if user.avatar.can_run(command): exec(command.get("action"))
# otherwise, give an error
- elif command_name: command_error(user, input_data)
+ elif command_name: command_error(user.avatar, input_data)
# if no input, just idle back with a prompt
else: user.send("", just_prompt=True)
-def command_halt(user, parameters):
+def command_halt(actor, parameters):
"""Halt the world."""
+ if actor.owner:
- # see if there's a message or use a generic one
- if parameters: message = "Halting: " + parameters
- else: message = "User " + user.account.get("name") + " halted the world."
+ # see if there's a message or use a generic one
+ if parameters: message = "Halting: " + parameters
+ else: message = "User " + actor.owner.account.get("name") + " halted the world."
- # let everyone know
- broadcast(message, add_prompt=False)
- log(message, 8)
+ # let everyone know
+ broadcast(message, add_prompt=False)
+ log(message, 8)
- # set a flag to terminate the world
- universe.terminate_world = True
+ # set a flag to terminate the world
+ universe.terminate_world = True
-def command_reload(user):
+def command_reload(actor):
"""Reload all code modules, configs and data."""
+ if actor.owner:
- # let the user know and log
- user.send("Reloading all code modules, configs and data.")
- log("User " + user.account.get("name") + " reloaded the world.", 8)
+ # let the user know and log
+ actor.send("Reloading all code modules, configs and data.")
+ log("User " + actor.owner.account.get("name") + " reloaded the world.", 8)
- # set a flag to reload
- universe.reload_modules = True
+ # set a flag to reload
+ universe.reload_modules = True
-def command_quit(user):
+def command_quit(actor):
"""Leave the world and go back to the main menu."""
- user.deactivate_avatar()
- user.state = "main_utility"
+ if actor.owner:
+ actor.owner.deactivate_avatar()
+ actor.owner.state = "main_utility"
-def command_help(user, parameters):
+def command_help(actor, parameters):
"""List available commands and provide help for commands."""
# did the user ask for help on a specific command word?
- if parameters:
+ if parameters and actor.owner:
# is the command word one for which we have data?
if parameters in universe.categories["command"]:
else: command = None
# only for allowed commands
- if user.can_run(command):
+ if actor.can_run(command):
# add a description if provided
description = command.get("description")
sorted_commands.sort()
for item in sorted_commands:
command = universe.categories["command"][item]
- if user.can_run(command):
+ if actor.can_run(command):
description = command.get("description")
if not description:
description = "(no short description provided)"
output += "$(eol)Enter \"help COMMAND\" for help on a command named \"COMMAND\"."
# send the accumulated output to the user
- user.send(output)
+ actor.send(output)
-def command_move(user, parameters):
+def command_move(actor, parameters):
"""Move the avatar in a given direction."""
- if parameters in universe.contents[user.avatar.get("location")].portals():
- user.avatar.move_direction(parameters)
- else: user.send("You cannot go that way.")
+ if parameters in universe.contents[actor.get("location")].portals():
+ actor.move_direction(parameters)
+ else: actor.send("You cannot go that way.")
-def command_look(user, parameters):
+def command_look(actor, parameters):
"""Look around."""
- if parameters: user.send("You can't look at or in anything yet.")
- else: user.avatar.look_at(user.avatar.get("location"))
+ if parameters: actor.send("You can't look at or in anything yet.")
+ else: actor.look_at(actor.get("location"))
-def command_say(user, parameters):
+def command_say(actor, parameters):
"""Speak to others in the same room."""
# check for replacement macros
- if replace_macros(user, parameters, True) != parameters:
- user.send("You cannot speak $_(replacement macros).")
+ if replace_macros(actor.owner, parameters, True) != parameters:
+ actor.send("You cannot speak $_(replacement macros).")
# the user entered a message
elif parameters:
message = message.replace(" " + word + " ", " " + word.capitalize() + " ")
# tell the room
- user.avatar.echo_to_location(user.avatar.get("name") + " " + action + "s, \"" + message + "\"")
- user.send("You " + action + ", \"" + message + "\"")
+ actor.echo_to_location(actor.get("name") + " " + action + "s, \"" + message + "\"")
+ actor.send("You " + action + ", \"" + message + "\"")
# there was no message
else:
- user.send("What do you want to say?")
+ actor.send("What do you want to say?")
-def command_show(user, parameters):
+def command_show(actor, parameters):
"""Show program data."""
message = ""
if parameters.find(" ") < 1:
elif arguments[0] == "log":
if match("^\d+$", arguments[1]) and int(arguments[1]) > 0:
linecount = int(arguments[1])
- if linecount > len(universe.loglist): linecount = len(universe.loglist)
+ if linecount > len(universe.loglines): linecount = len(universe.loglist)
message = "There are " + str(len(universe.loglist)) + " log lines in memory."
message += " The most recent " + str(linecount) + " lines are:$(eol)$(eol)"
for line in universe.loglist[-linecount:]:
if not message:
if parameters: message = "I don't know what \"" + parameters + "\" is."
else: message = "What do you want to show?"
- user.send(message)
+ actor.send(message)
-def command_create(user, parameters):
+def command_create(actor, parameters):
"""Create an element if it does not exist."""
if not parameters: message = "You must at least specify an element to create."
+ elif not actor.owner: message = ""
else:
arguments = parameters.split()
if len(arguments) == 1: arguments.append("")
if element in universe.contents: message = "The \"" + element + "\" element already exists."
else:
message = "You create \"" + element + "\" within the universe."
- logline = user.account.get("name") + " created an element: " + element
+ logline = actor.owner.account.get("name") + " created an element: " + element
if filename:
logline += " in file " + filename
if filename not in universe.files:
Element(element, universe, filename)
log(logline, 6)
elif len(arguments) > 2: message = "You can only specify an element and a filename."
- user.send(message)
+ actor.send(message)
-def command_destroy(user, parameters):
+def command_destroy(actor, parameters):
"""Destroy an element if it exists."""
- if not parameters: message = "You must specify an element to destroy."
- else:
- if parameters not in universe.contents: message = "The \"" + parameters + "\" element does not exist."
+ if actor.owner:
+ if not parameters: message = "You must specify an element to destroy."
else:
- universe.contents[parameters].destroy()
- message = "You destroy \"" + parameters + "\" within the universe."
- log(user.account.get("name") + " destroyed an element: " + parameters, 6)
- user.send(message)
+ if parameters not in universe.contents: message = "The \"" + parameters + "\" element does not exist."
+ else:
+ universe.contents[parameters].destroy()
+ message = "You destroy \"" + parameters + "\" within the universe."
+ log(actor.owner.account.get("name") + " destroyed an element: " + parameters, 6)
+ actor.send(message)
-def command_set(user, parameters):
+def command_set(actor, parameters):
"""Set a facet of an element."""
if not parameters: message = "You must specify an element, a facet and a value."
else:
else:
universe.contents[element].set(facet, value)
message = "You have successfully (re)set the \"" + facet + "\" facet of element \"" + element + "\". Try \"show element " + element + "\" for verification."
- user.send(message)
+ actor.send(message)
-def command_delete(user, parameters):
+def command_delete(actor, parameters):
"""Delete a facet from an element."""
if not parameters: message = "You must specify an element and a facet."
else:
else:
universe.contents[element].remove_facet(facet)
message = "You have successfully deleted the \"" + facet + "\" facet of element \"" + element + "\". Try \"show element " + element + "\" for verification."
- user.send(message)
+ actor.send(message)
-def command_error(user, input_data):
+def command_error(actor, input_data):
"""Generic error for an unrecognized command word."""
# 90% of the time use a generic error
message = "Arglebargle, glop-glyf!?!"
# send the error message
- user.send(message)
+ actor.send(message)
# if there is no universe, create an empty one
if not "universe" in locals(): universe = Universe()