* data/universe/rooms: Added a few example locations.
* lib/commands: Collapsed this directory into a single file.
* lib/muff/muffcmds.py, lib/muff/muffmisc.py, lib/muff/muffvars.py:
Replaced some risky try/except constructs with if/then/else
clauses.
* lib/muff/muffcmds.py (command_show): Added files and universe
parameter options.
* lib/muff/muffmisc.py (getlong, repr_long, setlong): Folded into
getint and friends.
* lib/muff/muffvars.py (save): Finished migrating into the
muffuniv.Universe.save method.
(variable_data): Moved to muffuniv.Universe.internals dict.
-[halt]
+[command:quit]
+action = command_quit(user, command, parameters)
+description = Leave Example.
+help = This will save your account and disconnect your client connection.
+
+[command:halt]
+action = command_halt(user, command, parameters)
description = Shut down the world.
help = This will save all active accounts, disconnect all clients and stop the entire program.
-[help]
+[command:help]
+action = command_help(user, command, 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.
-[quit]
-description = Leave Example.
-help = This will save your account and disconnect your client connection.
+[command:time]
+action = command_time(user, command, parameters)
+description = Show the current world time in elapsed increments.
+help = This will show the current world time in elapsed increments.
+
+[command:show]
+action = command_show(user, command, parameters)
+description = Show program data.
+help = For now, this is used to show things like "universe" and "avatars".
-[reload]
+[command:reload]
+action = command_reload(user, command, parameters)
description = Reload code modules and data.
help = This will reload all python code modules, reload configuration files and re-read data files.
-[say]
+[command:say]
+action = command_say(user, command, 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.
-[show]
-description = Show program data.
-help = For now, this is used to show things like "universe" and "avatars".
-
-[time]
-description = Show the current world time in elapsed increments.
-help = This will show the current world time in elapsed increments.
-
[include]
actors = actors
+avatars = avatars
rooms = rooms
-[room:0,0,0,0]
-
[room:1,0,0,0]
+[room:0,0,0,0]
+
[room:-1,0,0,0]
+++ /dev/null
-[index]
-files = active
-
+[include]
+universe = universe/index
+
for module in muff.__all__:
exec("import " + module)
-# does the files:commands setting exist yet?
-try:
- if muffconf.get("files", "commands"): pass
-
-# if not, reload the muffconf module
-except AttributeError:
- reload(muffconf)
-
-# now we can safely nab the command path setting and build a list of data files
-command_path = muffconf.get("files", "commands")
-command_files_index = ConfigParser.SafeConfigParser()
-command_files_index.read(command_path + "/index")
-command_files = []
-for each_file in command_files_index.get("index", "files").split():
- command_files.append(command_path + "/" + each_file)
-
-# read the command data files
-command_data = ConfigParser.SafeConfigParser()
-command_data.read(command_files)
-
-# this creates a list of commands mentioned in the data files
-command_list = command_data.sections()
-
def handle_user_input(user):
"""The main handler, branches to a state-specific handler."""
# check to make sure the state is expected, then call that handler
- try:
+ if "handler_" + user.state in globals():
exec("handler_" + user.state + "(user)")
- except NameError:
+ else:
generic_menu_handler(user)
# since we got input, flag that the menu/prompt needs to be redisplayed
"""A generic menu choice handler."""
# get a lower-case representation of the next line of input
- choice = user.input_queue.pop(0)
- if choice: choice = choice.lower()
+ if user.input_queue:
+ choice = user.input_queue.pop(0)
+ if choice: choice = choice.lower()
+ else: choice = ""
# run any script related to this choice
exec(muffmenu.get_choice_action(user, choice))
command = command.lower()
# the command matches a command word for which we have data
- if command in command_list: exec("command_" + command + "(user, command, parameters)")
+ if command in muffuniv.universe.commands.keys():
+ exec(muffuniv.universe.commands[command].get("action"))
# no data matching the entered command word
elif command: command_error(user, command, parameters)
def command_time(user, command="", parameters=""):
"""Show the current world time in elapsed increments."""
- user.send(muffmisc.repr_long(muffmisc.getlong(muffvars.variable_data,
- "time", "elapsed")) + " increments elapsed since the world was created.")
+ user.send(muffuniv.universe.internals["counters"].get("elapsed") + " increments elapsed since the world was created.")
def command_help(user, command="", parameters=""):
"""List available commands and provide help for commands."""
if parameters:
# is the command word one for which we have data?
- if parameters in command_list:
+ if parameters in muffuniv.universe.commands.keys():
# add a description if provided
- try:
- description = command_data.get(parameters, "description")
- except:
+ description = muffuniv.universe.commands[parameters].get("description")
+ if not description:
description = "(no short description provided)"
- output = "$(grn)" + parameters + "$(nrm) - " + command_data.get(parameters, "description") + "$(eol)$(eol)"
+ output = "$(grn)" + parameters + "$(nrm) - " + description + "$(eol)$(eol)"
# add the help text if provided
- try:
- help_text = command_data.get(parameters, "help")
- except:
+ help_text = muffuniv.universe.commands[parameters].get("help")
+ if not help_text:
help_text = "No help is provided for this command."
output += help_text
# give a sorted list of commands with descriptions if provided
output = "These are the commands available to you:$(eol)$(eol)"
- sorted_commands = command_list
+ sorted_commands = muffuniv.universe.commands.keys()
sorted_commands.sort()
for item in sorted_commands:
- try:
- description = command_data.get(item, "description")
- except:
+ description = muffuniv.universe.commands[item].get("description")
+ if not description:
description = "(no short description provided)"
- output += " $(grn)" + item + "$(nrm) - " + command_data.get(item, "description") + "$(eol)"
+ output += " $(grn)" + item + "$(nrm) - " + description + "$(eol)"
output += "$(eol)Enter \"help COMMAND\" for help on a command named \"COMMAND\"."
# send the accumulated output to the user
def command_show(user, command="", parameters=""):
"""Show program data."""
- if parameters == "universe":
- message = "These are the current elements in the universe:$(eol)"
- keys = muffuniv.universe.contents.keys()
- keys.sort()
- for key in keys: message += "$(eol) $(grn)" + key + "$(nrm)"
- elif parameters == "avatars":
+ if parameters == "avatars":
message = "These are the avatars managed by your account:$(eol)"
avatars = user.list_avatar_names()
avatars.sort()
for avatar in avatars: message += "$(eol) $(grn)" + avatar + "$(nrm)"
+ elif parameters == "files":
+ message = "These are the current files containing the universe:$(eol)"
+ keys = muffuniv.universe.files.keys()
+ keys.sort()
+ for key in keys: message += "$(eol) $(grn)" + key + "$(nrm)"
+ elif parameters == "universe":
+ message = "These are the current elements in the universe:$(eol)"
+ keys = muffuniv.universe.contents.keys()
+ keys.sort()
+ for key in keys: message += "$(eol) $(grn)" + key + "$(nrm)"
elif parameters: message = "I don't know what \"" + parameters + "\" is."
else: message = "What do you want to show?"
user.send(message)
def set(section, option, value):
"""Convenienve function to set miscellaneous configuration data."""
- return muffmisc.setlong(config_data, section, option, value)
+ return config_data.get(section, option, repr(value))
muffmisc.on_pulse()
# the loop has terminated, so save persistent data
- muffvars.save()
muffuniv.universe.save()
# log a final message
# used by several functions for random calls
import random
-# used to match the 'L' at the end of a long int in repr_long
-import re
-
# random_name uses string.strip
import string
# strip any leading quotemark, capitalize and return the name
return string.strip(name, "'").capitalize()
-def repr_long(value):
- string_value = repr(value)
- if re.match('\d*L$', string_value): return string_value.strip("L")
- else: return string_value
-
-def getlong(config, section, option):
- try:
- return int(config.get(section, option).strip("L"))
- except ConfigParser.NoSectionError:
- config.add_section(section)
- return getlong(config, section, option)
- except ConfigParser.NoOptionError:
- setlong(config, section, option, 0)
- return getlong(config, section, option)
-
-def setlong(config, section, option, value):
- return config.set(section, option, repr_long(value))
-
def replace_macros(user, text, is_input=False):
+ """Replaces macros in text output."""
while True:
macro_start = string.find(text, "$(")
if macro_start == -1: break
"""Check for a factor of the current increment count."""
if type(frequency) is str:
frequency = muffconf.getint("time", frequency)
- return not getlong(muffvars.variable_data, "time", "elapsed") % frequency
+ return not muffuniv.universe.internals["counters"].getint("elapsed") % frequency
def on_pulse():
"""The things which should happen on each pulse, aside from reloads."""
# periodically save everything
if check_time("frequency_save"):
- muffvars.save()
for user in muffvars.userlist: user.save()
muffuniv.universe.save()
time.sleep(muffconf.getfloat("time", "increment"))
# increment the elapsed increment counter
- setlong(muffvars.variable_data, "time", "elapsed",
- getlong(muffvars.variable_data, "time", "elapsed") + 1)
+ muffuniv.universe.internals["counters"].set("elapsed", muffuniv.universe.internals["counters"].getint("elapsed") + 1)
def reload_data():
"""Reload data into new persistent objects."""
def __init__(self, key, origin, universe):
"""Default values for the in-memory element variables."""
self.key = key
+ if not origin.startswith(os.sep):
+ origin = os.getcwd() + os.sep + origin
self.origin = origin
universe.contents[key] = self
+ if key.find(":"):
+ category = key.split(":", 1)
+ if category[0] in universe.categories:
+ exec("universe." + category[0] + "s[category[1]] = self")
+ if not origin in universe.files.keys():
+ DataFile(origin, universe)
if not universe.files[origin].data.has_section(key):
universe.files[origin].data.add_section(key)
def facets(self):
return universe.files[self.origin].data.get(self.key, facet)
except:
return None
+ def getint(self, facet):
+ """Convenience method to coerce return values as type int."""
+ value = self.get(facet)
+ if not value: value = 0
+ elif type(value) is str: value = value.rstrip("L")
+ return int(value)
def set(self, facet, value):
"""Set values."""
if facet in universe.files[self.origin].data.options(self.key):
- universe.files[self.origin].data.set(self.key, facet, value)
+ universe.files[self.origin].data.set(self.key, facet, repr(value))
else: self.facet = value
def rec(self, facet, value):
"""Add initial values to the record."""
class Universe:
"""The universe."""
def __init__(self):
- filename = muffconf.get("files", "data")
- if not filename.startswith(os.sep): filename = os.getcwd() + os.sep + filename
self.contents = {}
self.files = {}
- DataFile(filename, self)
+ self.categories = [ "account", "actor", "command", "internal", "item", "menu", "room" ]
+ for item in self.categories: exec("self." + item + "s = {}")
+ for item in [ "avatars", "commands", "internals", "universe" ]:
+ filename = muffconf.get("files", item)
+ if not filename.startswith(os.sep): filename = os.getcwd() + os.sep + filename
+ DataFile(filename, self)
def save(self):
for key in self.files.keys(): self.files[key].save()
# reload the muffconf module if the files:data setting does not exist
try:
- if muffconf.get("files", "data"): pass
+ if muffconf.has_section("files"): pass
except AttributeError:
reload(muffconf)
def new_avatar(self):
"""Instantiate a new, unconfigured avatar for this user."""
try:
- counter = muffvars.variable_data.getint("counters", "next_actor")
+ counter = muffuniv.universe.internals["counters"].getint("next_actor")
except:
muffmisc.log("get next_actor failed")
counter = 1
while muffuniv.element_exists("actor:" + repr(counter)): counter += 1
- muffvars.variable_data.set("counters", "next_actor", counter + 1)
- self.avatar = muffuniv.Element("actor:" + repr(counter))
+ muffuniv.universe.internals["counters"].set("next_actor", counter + 1)
+ self.avatar = muffuniv.Element("actor:" + repr(counter), muffconf.get("files", "avatars"), muffuniv.universe)
try:
avatars = self.record.get("account", "avatars").split()
except:
for module in muff.__all__:
exec("import " + module)
-# does the files:variable setting exist yet?
-try:
- if muffconf.get("files", "variable"): pass
-
-# if not, reload the muffconf module
-except AttributeError:
- reload(muffconf)
-
-# now we can safely load persistent variables from file
-variable_file = muffconf.get("files", "variable")
-variable_data = ConfigParser.SafeConfigParser()
-variable_data.read(variable_file)
-
# if there is no userlist, create an empty one
try:
if userlist: pass
"$(red)": chr(27) + "[31m"
}
-def save():
- """Function to save persistent variables to a file."""
-
- # try to open the variable file
- try:
- file_descriptor = file(variable_file, "w")
-
- # failing that, make the directory in which it resides first
- except IOError:
- os.makedirs(os.sep.join(variable_file.split(os.sep)[:-1]))
- file_descriptor = file(variable_file, "w")
-
- # now write the data and close out the file
- variable_data.write(file_descriptor)
- file_descriptor.flush()
- file_descriptor.close()
-
[files]
accounts = ./lib/accounts
-commands = ./lib/commands
+avatars = data/avatars
+commands = data/commands
+internals = data/internals
menus = ./lib/menus
modules = ./lib
-variable = ./lib/save/variable
-data = lib/index
+universe = data/universe/index
[general]
password_tries = 3