diff --git a/game/gamesrc/world/__init__.py b/game/gamesrc/world/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/game/gamesrc/world/connection_screens.py b/game/gamesrc/world/connection_screens.py new file mode 100644 index 0000000000..2c86a43505 --- /dev/null +++ b/game/gamesrc/world/connection_screens.py @@ -0,0 +1,28 @@ +# +# This module holds textual connection screen definitions. All global +# string variables (only) in this module are read by Evennia and +# assumed to define a Connection screen. +# +# The names of the string variables doesn't matter (except they +# shouldn't start with _), but each should hold a string defining a +# connection screen - as seen when first connecting to the game +# (before having logged in). If there are more than one string +# variable defined, a random one is picked. +# +# After adding new connection screens to this module you must +# either reboot or reload the server to make them available. +# + +from src.utils import utils + +DEFAULT_SCREEN = \ +"""{b=============================================================={n + Welcome to {gEvennia{n, version %s! + + If you have an existing account, connect to it by typing: + {wconnect {n + If you need to create an account, type (without the <>'s): + {wcreate \"\" {n + + Enter {whelp{n for more info. {wlook{n will re-load this screen. +{b=============================================================={n""" % utils.get_evennia_version() diff --git a/game/gamesrc/world/examples/__init__.py b/game/gamesrc/world/examples/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/commands/default/unloggedin.py b/src/commands/default/unloggedin.py index 9e261982f3..9131163790 100644 --- a/src/commands/default/unloggedin.py +++ b/src/commands/default/unloggedin.py @@ -2,18 +2,19 @@ Commands that are available from the connect screen. """ import traceback -#from django.contrib.auth.models import User from django.conf import settings from django.contrib.auth.models import User from src.server import sessionhandler from src.players.models import PlayerDB from src.objects.models import ObjectDB -from src.config.models import ConfigValue, ConnectScreen +from src.config.models import ConfigValue from src.comms.models import Channel from src.utils import create, logger, utils, ansi from src.commands.default.muxcommand import MuxCommand +CONNECTION_SCREEN_MODULE = settings.CONNECTION_SCREEN_MODULE + class CmdConnect(MuxCommand): """ Connect to the game. @@ -252,8 +253,8 @@ class CmdUnconnectedLook(MuxCommand): def func(self): "Show the connect screen." try: - screen = ConnectScreen.objects.get_random_connect_screen() - string = ansi.parse_ansi(screen.text) + screen = utils.string_from_module(CONNECTION_SCREEN_MODULE) + string = ansi.parse_ansi(screen) self.caller.msg(string) except Exception, e: self.caller.msg(e) @@ -272,35 +273,30 @@ class CmdUnconnectedHelp(MuxCommand): "Shows help" string = \ - """Welcome to Evennia! - -Commands available at this point: - create - create a new account - connect - login with an existing account - look - re-show the connect screen - help - this help - quit - leave + """ +You are not yet logged into the game. Commands available at this point: + {wcreate, connect, look, help, quit{n To login to the system, you need to do one of the following: -1) If you have no previous account, you need to use the 'create' +{w1){n If you have no previous account, you need to use the 'create' command like this: - > create "Anna the Barbarian" anna@myemail.com c67jHL8p + {wcreate "Anna the Barbarian" anna@myemail.com c67jHL8p{n It's always a good idea (not only here, but everywhere on the net) to not use a regular word for your password. Make it longer than 3 characters (ideally 6 or more) and mix numbers and capitalization into it. -2) If you have an account already, either because you just created - one in 1) above or you are returning, use the 'connect' command: +{w2){n If you have an account already, either because you just created + one in {w1){n above or you are returning, use the 'connect' command: - > connect anna@myemail.com c67jHL8p + {wconnect anna@myemail.com c67jHL8p{n - This should log you in. Run 'help' again once you're logged in + This should log you in. Run {whelp{n again once you're logged in to get more aid. Hope you enjoy your stay! -You can use the 'look' command if you want to see the connect screen again. +You can use the {wlook{n command if you want to see the connect screen again. """ self.caller.msg(string) diff --git a/src/config/manager.py b/src/config/manager.py index 8236eed40f..5495a38436 100644 --- a/src/config/manager.py +++ b/src/config/manager.py @@ -65,27 +65,3 @@ class ConfigValueManager(models.Manager): self.set_configvalue(db_key, db_value) else: return self.get_configvalue(db_key, default=default) - - -class ConnectScreenManager(models.Manager): - """ - This handles the random initial login screen system. - """ - def get_random_connect_screen(self): - """ - Returns a random active connect screen. - """ - try: - return self.filter(db_is_active=True).order_by('?')[0] - except IndexError: - ConnectScreen = ContentType.objects.get(app_label="config", - model="connectscreen").model_class() - text = "This is a placeholder connect screen. " - text += "Remind your admin to edit it." - new_screen = ConnectScreen(db_key='Default', - db_text=text, - db_is_active=True) - new_screen.save() - return new_screen - - diff --git a/src/config/migrations/0002_auto__del_connectscreen.py b/src/config/migrations/0002_auto__del_connectscreen.py new file mode 100644 index 0000000000..2bb9e11312 --- /dev/null +++ b/src/config/migrations/0002_auto__del_connectscreen.py @@ -0,0 +1,35 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models +from src.utils import utils + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Deleting model 'ConnectScreen' + db.delete_table('config_connectscreen') + + def backwards(self, orm): + + # Adding model 'ConnectScreen' + db.create_table('config_connectscreen', ( + ('db_key', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)), + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('db_is_active', self.gf('django.db.models.fields.BooleanField')(default=True)), + ('db_text', self.gf('django.db.models.fields.TextField')()), + )) + db.send_create_signal('config', ['ConnectScreen']) + + + models = { + 'config.configvalue': { + 'Meta': {'object_name': 'ConfigValue'}, + 'db_key': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'db_value': ('django.db.models.fields.TextField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + } + } + + complete_apps = ['config'] diff --git a/src/config/models.py b/src/config/models.py index 6372005d38..a69350c895 100755 --- a/src/config/models.py +++ b/src/config/models.py @@ -9,7 +9,6 @@ ConnectScreen model - cycling connect screens from django.db import models from src.utils.idmapper.models import SharedMemoryModel from src.config.manager import ConfigValueManager -from src.config.manager import ConnectScreenManager #------------------------------------------------------------ # @@ -93,99 +92,3 @@ class ConfigValue(SharedMemoryModel): def __unicode__(self): return "%s" % self.key - -#------------------------------------------------------------ -## ConnectScreen -# -#------------------------------------------------------------ - -class ConnectScreen(SharedMemoryModel): - """ - Stores connect screens. The admins may have only one or multiple, which - will cycle randomly. - - Properties on ConnectScreen: - key - optional identifier - text - the text to show - is_active - if the screen is in rotation - - """ - - # - # ConnectScreen database model setup - # - # These database fields are all set using their corresponding properties, - # named same as the field, but withtout the db_* prefix. - # - - # optional identifier - db_key = models.CharField(max_length=255, blank=True) - # connect screen text (ansi may be used) - db_text = models.TextField() - # if this screen should be used in rotation - db_is_active = models.BooleanField(default=True) - - # Database manager - objects = ConnectScreenManager() - - # Wrapper properties to easily set database fields. These are - # @property decorators that allows to access these fields using - # normal python operations (without having to remember to save() - # etc). So e.g. a property 'attr' has a get/set/del decorator - # defined that allows the user to do self.attr = value, - # value = self.attr and del self.attr respectively (where self - # is the object in question). - - # key property (wraps db_key) - #@property - def key_get(self): - "Getter. Allows for value = self.key" - return self.db_key - #@key.setter - def key_set(self, value): - "Setter. Allows for self.key = value" - self.db_key = value - self.save() - #@key.deleter - def key_del(self): - "Deleter. Allows for del self.key. Deletes entry." - self.delete() - key = property(key_get, key_set, key_del) - - # text property (wraps db_text) - #@property - def text_get(self): - "Getter. Allows for value = self.text" - return self.db_text - #@text.setter - def text_set(self, value): - "Setter. Allows for self.text = value" - self.db_text = value - self.save() - #@text.deleter - def text_del(self): - "Deleter. Allows for del self.text." - raise Exception("You can't delete the text of the connect screen!") - text = property(text_get, text_set, text_del) - - # is_active property (wraps db_is_active) - #@property - def is_active_get(self): - "Getter. Allows for value = self.is_active" - return self.db_is_active - #@is_active.setter - def is_active_set(self, value): - "Setter. Allows for self.is_active = value" - self.db_is_active = value - self.save() - #@is_active.deleter - def is_active_del(self): - "Deleter. Allows for del self.is_active." - self.db_is_active = False - self.save() - is_active = property(is_active_get, is_active_set, is_active_del) - - class Meta: - "Define Django meta options" - verbose_name = "Connect Screen" - verbose_name_plural = "Connect Screens" diff --git a/src/server/initial_setup.py b/src/server/initial_setup.py index b6d68388c2..597c3b89ed 100644 --- a/src/server/initial_setup.py +++ b/src/server/initial_setup.py @@ -21,23 +21,6 @@ def create_config_values(): ConfigValue.objects.conf("site_name", settings.SERVERNAME) ConfigValue.objects.conf("idle_timeout", settings.IDLE_TIMEOUT) -def create_connect_screens(): - """ - Creates the default connect screen(s). - """ - - print " Creating startup screen(s) ..." - - text = "{b=================================================================={n" - text += "\r\n Welcome to {wEvennia{n! Please type one of the following to begin:\r\n" - text += "\r\n If you have an existing account, connect to it by typing:\r\n " - text += "{wconnect {n\r\n If you need to create an account, " - text += "type (without the <>'s):\r\n " - text += "{wcreate \"\" {n\r\n" - text += "\r\n Enter {whelp{n for more info. {wlook{n will re-show this screen.\r\n" - text += "{b=================================================================={n\r\n" - ConnectScreen(db_key="Default", db_text=text, db_is_active=True).save() - def get_god_user(): """ Returns the initially created 'god' User object. @@ -203,7 +186,6 @@ def handle_setup(last_step): # setting up the list of functions to run setup_queue = [ create_config_values, - create_connect_screens, create_objects, create_channels, create_system_scripts, diff --git a/src/server/telnet.py b/src/server/telnet.py index bd44b39b07..6ee2ffadca 100644 --- a/src/server/telnet.py +++ b/src/server/telnet.py @@ -79,16 +79,11 @@ class TelnetProtocol(StatefulTelnetProtocol, session.Session): def at_connect(self): """ - Show the banner screen. Grab from the 'connect_screen' - config directive. If more than one connect screen is - defined in the ConnectScreen attribute, it will be - random which screen is used. + Show the banner screen. """ self.telnet_markup = True - # show screen - screen = ConnectScreen.objects.get_random_connect_screen() - string = ansi.parse_ansi(screen.text) - self.at_data_out(string) + # show connection screen + self.execute_cmd('look') def at_login(self, player): """ diff --git a/src/server/webclient.py b/src/server/webclient.py index 920bf6820b..9ed367c74d 100644 --- a/src/server/webclient.py +++ b/src/server/webclient.py @@ -221,15 +221,10 @@ class WebClientSession(session.Session): def at_connect(self): """ - Show the banner screen. Grab from the 'connect_screen' - config directive. If more than one connect screen is - defined in the ConnectScreen attribute, it will be - random which screen is used. + Show the banner screen. """ # show screen - screen = ConnectScreen.objects.get_random_connect_screen() - #string = parse_html(screen.text) - self.at_data_out(screen.text) + self.execute_cmd('look') def at_login(self, player): """ diff --git a/src/settings_default.py b/src/settings_default.py index 57055ff5d5..63429f02f3 100644 --- a/src/settings_default.py +++ b/src/settings_default.py @@ -96,7 +96,10 @@ IDLE_COMMAND = "idle" # Add sets for languages/regions your players are likely to use. # (see http://en.wikipedia.org/wiki/Character_encoding) ENCODINGS = ["utf-8", "latin-1", "ISO-8859-1"] - +# The module holding text strings for the connection screen. +# This module should contain one ore more variables +# with strings defining the look of the screen. +CONNECTION_SCREEN_MODULE = "game.gamesrc.world.connection_screens" ################################################### # Evennia Database config diff --git a/src/utils/utils.py b/src/utils/utils.py index aa938f3a47..8d69922bc2 100644 --- a/src/utils/utils.py +++ b/src/utils/utils.py @@ -7,6 +7,7 @@ be of use when designing your own game. import os, sys, imp import textwrap import datetime +import random from twisted.internet import threads from django.conf import settings from src.utils import ansi @@ -479,6 +480,7 @@ def mod_import(mod_path): result = imp.find_module(modname, [path]) except ImportError: log_trace("Could not find module '%s' (%s.py) at path '%s'" % (modname, modname, path)) + return try: mod = imp.load_module(modname, *result) except ImportError: @@ -487,3 +489,24 @@ def mod_import(mod_path): # we have to close the file handle manually result[0].close() return mod + +def string_from_module(modpath, variable=None): + """ + This obtains a string from a given module python path. + The variable must be global within that module - that is, defined in + the outermost scope of the module. The value of the + variable will be returned. If not found (or if it's not a string), + None is returned. + + This is useful primarily for storing various game strings + in a module and extract them by name or randomly. + """ + mod = __import__(modpath, fromlist=[None]) + if variable: + return mod.__dict__.get(variable, None) + else: + mvars = [val for key, val in mod.__dict__.items() + if not key.startswith('_') and isinstance(val, basestring)] + if not mvars: + return None + return mvars[random.randint(0, len(mvars)-1)]