diff --git a/evennia/trunk/TODO b/evennia/trunk/TODO index 29d7893b98..2a0bb19511 100644 --- a/evennia/trunk/TODO +++ b/evennia/trunk/TODO @@ -1,2 +1,18 @@ -Add any things that need work here: +TODO List +--------- +The TODO list has all of the things currently needing attention the most in it. +If you are feeling ambitious, tackle as much as you can and send patches +to the project site or via email to gtaylor@clemson.edu. + +High Priority Tasks +------------------- +* Pretty much all of the commands need some kind of required permission(s). + Right now, pretty much everyone has access to everything. Django has + a built-in permissions system, it should be trivial to use it for + the purpose. +* Figure out how to handle our scripting support. + +Medium Priority Tasks +--------------------- * We're going to need a delayed event queue in addition to the scheduler. + For example: I want player X to perform this action in Y seconds. diff --git a/evennia/trunk/apps/helpsys/__init__.py b/evennia/trunk/apps/helpsys/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/evennia/trunk/apps/helpsys/models.py b/evennia/trunk/apps/helpsys/models.py new file mode 100644 index 0000000000..edd82306f6 --- /dev/null +++ b/evennia/trunk/apps/helpsys/models.py @@ -0,0 +1,32 @@ +from django.db import models +import ansi + +# Create your models here. +class HelpEntry(models.Model): + """ + A generic help entry. + """ + topicname = models.CharField(maxlength=255) + entrytext = models.TextField(blank=True, null=True) + staff_only = models.BooleanField(default=0) + + def __str__(self): + return "%3d. %s" % (self.id, self.topicname) + + def get_topicname(self): + """ + Returns the topic's name. + """ + try: + return self.topicname + except: + return None + + def get_entrytext_ingame(self): + """ + Gets the entry text for in-game viewing. + """ + try: + return ansi.parse_ansi(self.entrytext) + except: + return None diff --git a/evennia/trunk/apps/helpsys/views.py b/evennia/trunk/apps/helpsys/views.py new file mode 100644 index 0000000000..60f00ef0ef --- /dev/null +++ b/evennia/trunk/apps/helpsys/views.py @@ -0,0 +1 @@ +# Create your views here. diff --git a/evennia/trunk/apps/objects/models.py b/evennia/trunk/apps/objects/models.py index d22174559d..b3dbdde871 100755 --- a/evennia/trunk/apps/objects/models.py +++ b/evennia/trunk/apps/objects/models.py @@ -68,6 +68,23 @@ class Object(models.Model): message: (str) The message to send """ + # We won't allow emitting to objects... yet. + if not self.is_player(): + return False + + session = session_mgr.session_from_object(self) + if session: + session.msg(ansi.parse_ansi(message)) + else: + return False + + def emit_to_contents(self, message): + """ + Emits something to all objects inside an object. + """ + contents = self.get_contents() + for obj in contents: + obj.emit_to(message) def is_staff(self): """ @@ -118,13 +135,6 @@ class Object(models.Model): pobject.name = new_name pobject.save() - def set_description(self, new_desc): - """ - Rename an object. - """ - self.description = ansi.parse_ansi(new_desc) - self.save() - def get_name(self, fullname=False): """ Returns an object's name. @@ -143,12 +153,28 @@ class Object(models.Model): else: return ansi.parse_ansi(self.ansi_name.split(';')[0]) - def get_description(self): + def set_description(self, new_desc): + """ + Rename an object. + """ + self.description = new_desc + self.save() + + def get_description(self, no_parsing=False, wrap_width=False): """ Returns an object's ANSI'd description. """ try: - return ansi.parse_ansi(self.description) + if no_parsing: + retval = self.description + else: + retval = ansi.parse_ansi(self.description) + + if wrap_width: + # TODO: Broken for some reason? Returning None. + return functions_general.word_wrap(retval, width=wrap_width) + else: + return retval except: return None @@ -319,6 +345,18 @@ class Object(models.Model): self.flags = ' '.join(flags) self.save() + def is_connected_plr(self): + """ + Is this object a connected player? + """ + if self.is_player(): + if session_mgr.session_from_object(self): + return True + else: + return False + else: + return False + def get_owner(self): """ Returns an object's owner. @@ -375,11 +413,16 @@ class Object(models.Model): else: return False - def get_contents(self): + def get_contents(self, filter_type=None): """ Returns the contents of an object. + + filter_type: (int) An object type number to filter by. """ - return list(Object.objects.filter(location__id=self.id).exclude(type__gt=4)) + if filter_type: + return list(Object.objects.filter(location__id=self.id).filter(type=filter_type)) + else: + return list(Object.objects.filter(location__id=self.id).exclude(type__gt=4)) def get_zone(self): """ diff --git a/evennia/trunk/cmdhandler.py b/evennia/trunk/cmdhandler.py index 747410492d..0a21d00616 100755 --- a/evennia/trunk/cmdhandler.py +++ b/evennia/trunk/cmdhandler.py @@ -1,6 +1,7 @@ import commands_staff import commands_general import commands_unloggedin +import functions_db """ This is the command processing module. It is instanced once in the main @@ -13,6 +14,13 @@ class UnknownCommand(Exception): Throw this when a user enters an an invalid command. """ +def match_exits(pobject, searchstr): + """ + See if we can find an input match to exits. + """ + exits = pobject.get_location().get_contents(filter_type=4) + return functions_db.list_search_object_namestr(exits, searchstr) + def handle(cdat): """ Use the spliced (list) uinput variable to retrieve the correct @@ -60,8 +68,22 @@ def handle(cdat): if callable(cmd): cdat['uinput'] = parsed_input cmd(cdat) - else: - raise UnknownCommand + return + + pobject = session.get_pobject() + exit_matches = match_exits(pobject, ' '.join(parsed_input['splitted'])) + if exit_matches: + exit = exit_matches[0] + if exit.get_home(): + cdat['uinput'] = parsed_input + pobject.move_to(exit.get_home()) + commands_general.cmd_look(cdat) + else: + session.msg("That exit leads to nowhere.") + return + + # If we reach this point, we haven't matched anything. + raise UnknownCommand except UnknownCommand: session.msg("Unknown command.") diff --git a/evennia/trunk/commands_general.py b/evennia/trunk/commands_general.py index b95a2146a5..6d869260b8 100644 --- a/evennia/trunk/commands_general.py +++ b/evennia/trunk/commands_general.py @@ -2,10 +2,10 @@ import settings import time import functions_general import functions_db +import functions_help import global_defines import session_mgr -from ansi import * - +import ansi """ Generic command module. Pretty much every command should go here for now. @@ -55,7 +55,7 @@ def cmd_look(cdat): retval = "%s%s(#%i%s)\r\n%s" % ( target_obj.get_ansiname(), - ansi["normal"], + ansi.ansi["normal"], target_obj.id, target_obj.flag_string(), target_obj.get_description(), @@ -68,7 +68,7 @@ def cmd_look(cdat): for obj in target_obj.get_contents(): if obj.is_player(): - if obj != pobject: + if obj != pobject and obj.is_connected_plr(): con_players.append(obj) elif obj.is_exit(): con_exits.append(obj) @@ -76,15 +76,15 @@ def cmd_look(cdat): con_things.append(obj) if con_players: - session.msg("%sPlayers:%s" % (ansi["hilite"], ansi["normal"],)) + session.msg("%sPlayers:%s" % (ansi.ansi["hilite"], ansi.ansi["normal"],)) for player in con_players: session.msg('%s' %(player,)) if con_things: - session.msg("%sContents:%s" % (ansi["hilite"], ansi["normal"],)) + session.msg("%sContents:%s" % (ansi.ansi["hilite"], ansi.ansi["normal"],)) for thing in con_things: session.msg('%s' %(thing,)) if con_exits: - session.msg("%sExits:%s" % (ansi["hilite"], ansi["normal"],)) + session.msg("%sExits:%s" % (ansi.ansi["hilite"], ansi.ansi["normal"],)) for exit in con_exits: session.msg('%s' %(exit,)) @@ -111,19 +111,19 @@ def cmd_examine(cdat): return else: target_obj = results[0] - - session.msg("%s%s(#%i%s)" % ( + session.msg("%s%s(#%i%s)\r\n%s" % ( target_obj.get_ansiname(fullname=True), - ansi["normal"], + ansi.ansi["normal"], target_obj.id, target_obj.flag_string(), + target_obj.get_description(no_parsing=True), )) session.msg("Type: %s Flags: %s" % (target_obj.get_type(), target_obj.get_flags())) session.msg("Owner: %s " % (target_obj.get_owner(),)) session.msg("Zone: %s" % (target_obj.get_zone(),)) for attribute in target_obj.get_all_attributes(): - session.msg("%s%s%s: %s" % (ansi["hilite"], attribute.name, ansi["normal"], attribute.value)) + session.msg("%s%s%s: %s" % (ansi.ansi["hilite"], attribute.name, ansi.ansi["normal"], attribute.value)) con_players = [] con_things = [] @@ -145,7 +145,7 @@ def cmd_examine(cdat): session.msg('%s' %(thing,)) if con_exits: - session.msg("%sExits:%s" % (ansi["hilite"], ansi["normal"],)) + session.msg("%sExits:%s" % (ansi.ansi["hilite"], ansi.ansi["normal"],)) for exit in con_exits: session.msg('%s' %(exit,)) @@ -214,13 +214,41 @@ def cmd_say(cdat): session.msg(retval) +def cmd_help(cdat): + """ + Help system commands. + """ + session = cdat['session'] + pobject = session.get_pobject() + topicstr = ' '.join(cdat['uinput']['splitted'][1:]) + + if len(topicstr) == 0: + topicstr = "Help Index" + elif len(topicstr) < 2 and not topicstr.isdigit(): + session.msg("Your search query is too short. It must be at least three letters long.") + return + + topics = functions_help.find_topicmatch(topicstr, pobject) + + if len(topics) == 0: + session.msg("No matching topics found, please refine your search.") + elif len(topics) > 1: + session.msg("More than one match found:") + for result in topics: + session.msg(" %s" % (result,)) + session.msg("You may type 'help <#>' to see any of these topics.") + else: + topic = topics[0] + session.msg("\r\n%s%s%s" % (ansi.ansi["hilite"], topic.get_topicname(), ansi.ansi["normal"])) + session.msg(topic.get_entrytext_ingame()) + def cmd_version(cdat): """ Version info command. """ session = cdat['session'] retval = "-"*50 +"\n\r" - retval += "Evennia %s\n\r" % (settings.EVENNIA_VERSION,) + retval += "Evennia %s\n\r" % (global_defines.EVENNIA_VERSION,) retval += "-"*50 session.msg(retval) diff --git a/evennia/trunk/commands_staff.py b/evennia/trunk/commands_staff.py index 13f1ee7e93..5c182622d1 100644 --- a/evennia/trunk/commands_staff.py +++ b/evennia/trunk/commands_staff.py @@ -132,7 +132,6 @@ def cmd_dig(cdat): """ session = cdat['session'] pobject = session.get_pobject() - server = session.server uinput= cdat['uinput']['splitted'] roomname = ' '.join(uinput[1:]) @@ -145,6 +144,20 @@ def cmd_dig(cdat): session.msg("You create a new room: %s" % (new_object,)) +def cmd_emit(cdat): + """ + Emits something to your location. + """ + session = cdat['session'] + pobject = session.get_pobject() + uinput= cdat['uinput']['splitted'] + message = ' '.join(uinput[1:]) + + if message == '': + session.msg("Emit what?") + else: + pobject.get_location().emit_to_contents(message) + def cmd_create(cdat): """ Creates a new object of type 'THING'. diff --git a/evennia/trunk/functions_db.py b/evennia/trunk/functions_db.py index 2ba7faa3c5..f9b64ee0e3 100644 --- a/evennia/trunk/functions_db.py +++ b/evennia/trunk/functions_db.py @@ -4,7 +4,10 @@ from django.contrib.auth.models import User from apps.objects.models import Object from apps.config.models import ConfigValue import global_defines - +import gameconf +""" +Common database functions. +""" def get_server_config(configname): """ Returns a server config value. @@ -169,7 +172,7 @@ def create_user(cdat, uname, email, password): """ session = cdat['session'] server = cdat['server'] - start_room = int(server.get_configvalue('player_dbnum_start')) + start_room = int(gameconf.get_configvalue('player_dbnum_start')) start_room_obj = get_object_from_dbref(start_room) # The user's entry in the User table must match up to an object @@ -197,4 +200,4 @@ def create_user(cdat, uname, email, password): # Activate the player's session and set them loose. session.login(user) print 'Registration: %s' % (session,) - session.push("Welcome to %s, %s.\n\r" % (server.get_configvalue('site_name'), session.get_pobject().get_name(),)) + session.push("Welcome to %s, %s.\n\r" % (gameconf.get_configvalue('site_name'), session.get_pobject().get_name(),)) diff --git a/evennia/trunk/functions_help.py b/evennia/trunk/functions_help.py new file mode 100644 index 0000000000..eef3ffccfa --- /dev/null +++ b/evennia/trunk/functions_help.py @@ -0,0 +1,18 @@ +from apps.helpsys.models import HelpEntry +""" +Help system functions. +""" +def find_topicmatch(topicstr, pobject): + """ + Searches for matching topics based on player's input. + """ + if topicstr.isdigit(): + return HelpEntry.objects.filter(id=topicstr) + else: + return HelpEntry.objects.filter(topicname__istartswith=topicstr) + +def find_topicsuggestions(topicstr, pobject): + """ + Do a fuzzier "contains" match. + """ + return HelpEntry.objects.filter(topicname__icontains=topicstr) diff --git a/evennia/trunk/global_defines.py b/evennia/trunk/global_defines.py index 4fd49390d5..3470beb8cd 100644 --- a/evennia/trunk/global_defines.py +++ b/evennia/trunk/global_defines.py @@ -21,3 +21,6 @@ NOSET_FLAGS = ["CONNECTED"] # These attribute names can't be modified by players. NOSET_ATTRIBS = ["MONEY"] + +# Server version number. +EVENNIA_VERSION = 'Pre-Alpha' diff --git a/evennia/trunk/settings.py b/evennia/trunk/settings.py index 77cdf5f547..b54f489d29 100755 --- a/evennia/trunk/settings.py +++ b/evennia/trunk/settings.py @@ -9,10 +9,10 @@ ADMINS = ( MANAGERS = ADMINS -DATABASE_ENGINE = 'sqlite3' # 'postgresql', 'mysql', 'sqlite3' or 'ado_mssql'. -DATABASE_NAME = 'evennia.sql' # Or path to database file if using sqlite3. -DATABASE_USER = 'evennia' # Not used with sqlite3. -DATABASE_PASSWORD = 'CvAPpy:FFRTmTMHf' # Not used with sqlite3. +DATABASE_ENGINE = 'sqlite3' # 'postgresql', 'mysql', 'sqlite3' or 'ado_mssql'. +DATABASE_NAME = 'evennia.sql' # Or path to database file if using sqlite3. +DATABASE_USER = '' # Not used with sqlite3. +DATABASE_PASSWORD = '' # Not used with sqlite3. DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3. DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3. @@ -76,10 +76,5 @@ INSTALLED_APPS = ( 'django.contrib.admin', 'evennia.apps.config', 'evennia.apps.objects', -# 'django.contrib.sites', + 'evennia.apps.helpsys', ) - -# -## Evennia Config -# -EVENNIA_VERSION = 'Pre-Alpha 0.0'