def func(self): "implements the command." caller = self.caller if not self.args: caller.msg("Get what?") return #print "general/get:", caller, caller.location, self.args, caller.location.contents parsed = self.args.split(" ") if len(parsed) == 3 and parsed[1] == "from": target = caller.search(parsed[2]) if target != None: if utils.inherits_from(target, "game.gamesrc.objects.container.Container") == False: if target == caller: obj = caller.search(parsed[0], location=target) if obj == None: return else: caller.msg("You already have that.") elif utils.inherits_from(target, "game.gamesrc.objects.kc.Character"): caller.msg("You can't steal from others!") elif target == caller.location: caller.msg("Isn't that a bit overcomplicated?") else: caller.msg("It's not possible to take something out of that.") return elif utils.inherits_from(target, "game.gamesrc.objects.container.Container") == True: if target.db.con_closed: caller.msg("You have to open the %s first." % target.name) return obj = caller.search(parsed[0], location=target) else: obj = caller.search(parsed[0], location=caller.location) if not obj: return if caller == obj: caller.msg("You can't get yourself.") return #print obj, obj.location, caller, caller==obj.location if caller == obj.location: caller.msg("You already have that.") return if not obj.access(caller, 'get'): if obj.db.get_err_msg: caller.msg(obj.db.get_err_msg) else: caller.msg("You can't get that.") return obj.move_to(caller, quiet=True) if len(parsed) == 3 and parsed[1] == "from" and not target == caller.location: caller.msg("You get the %s from the %s." % (obj.name, target.name)) caller.location.msg_contents("%s gets the %s from the %s." % (caller.name, obj.name, target.name), exclude=caller) else: caller.msg("You pick up the %s." % obj.name) caller.location.msg_contents("%s picks up the %s." % (caller.name, obj.name), exclude=caller) # calling hook method obj.at_get(caller)
def display_mail(self, message): """ Display a mail message. """ senders = ', '.join([ sender.name for sender in message.senders if utils.inherits_from(sender.typeclass, settings.BASE_CHARACTER_TYPECLASS) ]) receivers = ', '.join([ receiver.name for receiver in message.receivers if utils.inherits_from(receiver.typeclass, settings.BASE_CHARACTER_TYPECLASS) ]) self.caller.msg('--------Mail from %s to %s.' % (senders, receivers)) self.caller.msg('Sent on: %s' % message.date_sent) self.caller.msg('Subject: %s\n' % message.header) self.caller.msg(message.message) self.caller.msg('\nDone.')
def parse(self): """ We run the parent parser as usual, then fix the result """ super(MuxPlayerCommand, self).parse() if utils.inherits_from(self.caller, "src.objects.objects.Object"): # caller is an Object/Character self.character = self.caller self.caller = self.caller.player elif utils.inherits_from(self.caller, "src.players.players.Player"): # caller was already a Player self.character = self.caller.get_puppet(self.sessid) else: self.character = None
def func(self): "Implement function" caller = self.caller if utils.inherits_from(caller, "src.objects.objects.Object"): caller = self.caller.player if not caller.character: string = "You are already OOC." caller.msg(string) return caller.db.last_puppet = caller.character # save location as if we were disconnecting from the game entirely. if caller.character.location: caller.character.location.msg_contents("%s has left the game." % caller.character.key, exclude=[caller.character]) caller.character.db.prelogout_location = caller.character.location caller.character.location = None # disconnect caller.character.player = None caller.character = None caller.msg("\n{GYou go OOC.{n\n") caller.execute_cmd("look")
def is_lit(self): """ Checks for a lightsource on all characters in the room. """ return any([any([True for obj in char.contents if utils.inherits_from(obj, "game.gamesrc.objects.world.items.LightSource") and obj.is_active]) for char in self.contents if char.has_player])
def add(self, cmd): """ Add a command, a list of commands or a cmdset to this cmdset. Note that if cmd already exists in set, it will replace the old one (no priority checking etc at this point; this is often used to overload default commands). If cmd is another cmdset class or -instance, the commands of that command set is added to this one, as if they were part of the original cmdset definition. No merging or priority checks are made, rather later added commands will simply replace existing ones to make a unique set. """ if inherits_from(cmd, "src.commands.cmdset.CmdSet"): # cmd is a command set so merge all commands in that set # to this one. We raise a visible error if we created # an infinite loop (adding cmdset to itself somehow) try: cmd = self._instantiate(cmd) except RuntimeError: string = "Adding cmdset %(cmd)s to %(class)s lead to an " string += "infinite loop. When adding a cmdset to another, " string += "make sure they are not themself cyclically added to " string += "the new cmdset somewhere in the chain." raise RuntimeError( _(string) % { "cmd": cmd, "class": self.__class__ }) cmds = cmd.commands elif is_iter(cmd): cmds = [self._instantiate(c) for c in cmd] else: cmds = [self._instantiate(cmd)] commands = self.commands system_commands = self.system_commands for cmd in cmds: # add all commands if not hasattr(cmd, 'obj'): cmd.obj = self.cmdsetobj try: ic = commands.index(cmd) commands[ic] = cmd # replace except ValueError: commands.append(cmd) # extra run to make sure to avoid doublets self.commands = list(set(commands)) #print "In cmdset.add(cmd):", self.key, cmd # add system_command to separate list as well, # for quick look-up if cmd.key.startswith("__"): try: ic = system_commands.index(cmd) system_commands[ic] = cmd # replace except ValueError: system_commands.append(cmd)
def parse(self): "overload parts of parse" # run parent super(CommCommand, self).parse() # fix obj->player if utils.inherits_from(self.caller, "src.objects.objects.Object"): # an object. Convert it to its player. self.caller = self.caller.player
def __player_set(self, player): "Setter. Allows for self.player = value" if inherits_from(player, TypeClass): player = player.dbobj set_field_cache(self, "player", player) # we must set this here or superusers won't be able to # bypass lockchecks unless they start the game connected # to the character in question. self.locks.cache_lock_bypass(self)
def display_mail(self, message): """ Display a mail message. """ senders = ', '.join([ sender.name for sender in message.senders if utils.inherits_from( sender.typeclass, settings.BASE_CHARACTER_TYPECLASS) ]) receivers = ', '.join([ receiver.name for receiver in message.receivers if utils.inherits_from( receiver.typeclass, settings.BASE_CHARACTER_TYPECLASS) ]) self.caller.msg('--------Mail from %s to %s.' % (senders, receivers)) self.caller.msg('Sent on: %s' % message.date_sent) self.caller.msg('Subject: %s\n' % message.header) self.caller.msg(message.message) self.caller.msg('\nDone.')
def add(self, cmd): """ Add a command, a list of commands or a cmdset to this cmdset. Note that if cmd already exists in set, it will replace the old one (no priority checking etc at this point; this is often used to overload default commands). If cmd is another cmdset class or -instance, the commands of that command set is added to this one, as if they were part of the original cmdset definition. No merging or priority checks are made, rather later added commands will simply replace existing ones to make a unique set. """ if inherits_from(cmd, "src.commands.cmdset.CmdSet"): # cmd is a command set so merge all commands in that set # to this one. We raise a visible error if we created # an infinite loop (adding cmdset to itself somehow) try: cmd = self._instantiate(cmd) except RuntimeError: string = "Adding cmdset %(cmd)s to %(class)s lead to an " string += "infinite loop. When adding a cmdset to another, " string += "make sure they are not themself cyclically added to " string += "the new cmdset somewhere in the chain." raise RuntimeError(_(string) % {"cmd": cmd, "class": self.__class__}) cmds = cmd.commands elif is_iter(cmd): cmds = [self._instantiate(c) for c in cmd] else: cmds = [self._instantiate(cmd)] commands = self.commands system_commands = self.system_commands for cmd in cmds: # add all commands if not hasattr(cmd, 'obj'): cmd.obj = self.cmdsetobj try: ic = commands.index(cmd) commands[ic] = cmd # replace except ValueError: commands.append(cmd) # extra run to make sure to avoid doublets self.commands = list(set(commands)) #print "In cmdset.add(cmd):", self.key, cmd # add system_command to separate list as well, # for quick look-up if cmd.key.startswith("__"): try: ic = system_commands.index(cmd) system_commands[ic] = cmd # replace except ValueError: system_commands.append(cmd)
def func(self): "Implement put" caller = self.caller if not self.args: caller.msg("Put what in where?") return parsed = self.args.split(" ") if len(parsed) == 3 and parsed[1] == "in": target = caller.search(parsed[2]) if target != None: if utils.inherits_from(target, "game.gamesrc.objects.container.Container") == False: if utils.inherits_from(target, "game.gamesrc.objects.kc.Character"): caller.msg("Why don't you try giving it to them?") elif target == caller.location: caller.msg("Why don't you just drop it?") else: caller.msg("It's not possible to put something in that.") return elif utils.inherits_from(target, "game.gamesrc.objects.container.Container") == True: if target.db.con_closed: caller.msg("You have to open the %s first." % target.name) return to_put = caller.search(parsed[0]) if target == to_put: caller.msg("You can't do that.") return else: return if not (to_put and target): return if target == caller: caller.msg("You keep the %s to yourself." % to_put.key) return if not to_put.location == caller: caller.msg("You are not holding the %s." % to_put.key) return # give object to_put.location = target caller.msg("You put the %s in the %s." % (to_put.key, target.key)) caller.location.msg_contents("%s puts the %s in the %s." % (caller.key, to_put.key, target.key), exclude=caller)
def func(self): "implement the ooc look command" if MULTISESSION_MODE < 2: # only one character allowed string = "You are out-of-character (OOC).\nUse {w@ic{n to get back into the game." self.msg(string) return if utils.inherits_from(self.caller, "src.objects.objects.Object"): # An object of some type is calling. Use default look instead. super(CmdOOCLook, self).func() elif self.args: self.look_target() else: self.no_look_target()
def parse(self): """ We run the parent parser as usual, then fix the result """ super(MuxCommandOOC, self).parse() if utils.inherits_from(self.caller, "src.objects.objects.Object"): # caller is an Object/Character self.character = self.caller self.caller = self.caller.player elif hasattr(self.caller, "character"): # caller was already a Player self.character = self.caller.character else: self.character = None
def add(self, cmdset, emit_to_obj=None, permanent=False): """ Add a cmdset to the handler, on top of the old ones. Default is to not make this permanent, i.e. the set will not survive a server reset. cmdset - can be a cmdset object or the python path to such an object. emit_to_obj - an object to receive error messages. permanent - this cmdset will remain across a server reboot Note: An interesting feature of this method is if you were to send it an *already instantiated cmdset* (i.e. not a class), the current cmdsethandler's obj attribute will then *not* be transferred over to this already instantiated set (this is because it might be used elsewhere and can cause strange effects). This means you could in principle have the handler launch command sets tied to a *different* object than the handler. Not sure when this would be useful, but it's a 'quirk' that has to be documented. """ if not (isinstance(cmdset, basestring) or utils.inherits_from(cmdset, CmdSet)): raise Exception( _("Only CmdSets can be added to the cmdsethandler!")) if callable(cmdset): cmdset = cmdset(self.obj) elif isinstance(cmdset, basestring): # this is (maybe) a python path. Try to import from cache. cmdset = self._import_cmdset(cmdset) if cmdset and cmdset.key != '_CMDSET_ERROR': if permanent and cmdset.key != '_CMDSET_ERROR': # store the path permanently cmdset.permanent = True storage = self.obj.cmdset_storage if not storage: storage = ["", cmdset.path] else: storage.append(cmdset.path) self.obj.cmdset_storage = storage else: cmdset.permanent = False self.cmdset_stack.append(cmdset) self.update()
def add(self, cmdset, emit_to_obj=None, permanent=False): """ Add a cmdset to the handler, on top of the old ones. Default is to not make this permanent, i.e. the set will not survive a server reset. cmdset - can be a cmdset object or the python path to such an object. emit_to_obj - an object to receive error messages. permanent - this cmdset will remain across a server reboot Note: An interesting feature of this method is if you were to send it an *already instantiated cmdset* (i.e. not a class), the current cmdsethandler's obj attribute will then *not* be transferred over to this already instantiated set (this is because it might be used elsewhere and can cause strange effects). This means you could in principle have the handler launch command sets tied to a *different* object than the handler. Not sure when this would be useful, but it's a 'quirk' that has to be documented. """ if not (isinstance(cmdset, basestring) or utils.inherits_from(cmdset, CmdSet)): raise Exception(_("Only CmdSets can be added to the cmdsethandler!")) if callable(cmdset): cmdset = cmdset(self.obj) elif isinstance(cmdset, basestring): # this is (maybe) a python path. Try to import from cache. cmdset = self._import_cmdset(cmdset) if cmdset and cmdset.key != '_CMDSET_ERROR': if permanent and cmdset.key != '_CMDSET_ERROR': # store the path permanently cmdset.permanent = True storage = self.obj.cmdset_storage if not storage: storage = ["", cmdset.path] else: storage.append(cmdset.path) self.obj.cmdset_storage = storage else: cmdset.permanent = False self.cmdset_stack.append(cmdset) self.update()
def add_default(self, cmdset, emit_to_obj=None, permanent=True): """ Add a new default cmdset. If an old default existed, it is replaced. If permanent is set, the set will survive a reboot. cmdset - can be a cmdset object or the python path to an instance of such an object. emit_to_obj - an object to receive error messages. permanent - save cmdset across reboots See also the notes for self.add(), which applies here too. """ if callable(cmdset): if not utils.inherits_from(cmdset, CmdSet): raise Exception( _("Only CmdSets can be added to the cmdsethandler!")) cmdset = cmdset(self.obj) elif isinstance(cmdset, basestring): # this is (maybe) a python path. Try to import from cache. cmdset = self._import_cmdset(cmdset) if cmdset and cmdset.key != '_CMDSET_ERROR': if self.cmdset_stack: self.cmdset_stack[0] = cmdset self.mergetype_stack[0] = cmdset.mergetype else: self.cmdset_stack = [cmdset] self.mergetype_stack = [cmdset.mergetype] if permanent and cmdset.key != '_CMDSET_ERROR': cmdset.permanent = True storage = self.obj.cmdset_storage if storage: storage[0] = cmdset.path else: storage = [cmdset.path] self.obj.cmdset_storage = storage else: cmdset.permanent = False self.update()
def add_default(self, cmdset, emit_to_obj=None, permanent=True): """ Add a new default cmdset. If an old default existed, it is replaced. If permanent is set, the set will survive a reboot. cmdset - can be a cmdset object or the python path to an instance of such an object. emit_to_obj - an object to receive error messages. permanent - save cmdset across reboots See also the notes for self.add(), which applies here too. """ if callable(cmdset): if not utils.inherits_from(cmdset, CmdSet): raise Exception(_("Only CmdSets can be added to the cmdsethandler!")) cmdset = cmdset(self.obj) elif isinstance(cmdset, basestring): # this is (maybe) a python path. Try to import from cache. cmdset = self._import_cmdset(cmdset) if cmdset and cmdset.key != '_CMDSET_ERROR': if self.cmdset_stack: self.cmdset_stack[0] = cmdset self.mergetype_stack[0] = cmdset.mergetype else: self.cmdset_stack = [cmdset] self.mergetype_stack = [cmdset.mergetype] if permanent and cmdset.key != '_CMDSET_ERROR': cmdset.permanent = True storage = self.obj.cmdset_storage if storage: storage[0] = cmdset.path else: storage = [cmdset.path] self.obj.cmdset_storage = storage else: cmdset.permanent = False self.update()
def create_player(key, email, password, typeclass=None, is_superuser=False, locks=None, permissions=None, report_to=None): """ This creates a new player. key - the player's name. This should be unique. email - email on valid [email protected] form. password - password in cleartext is_superuser - wether or not this player is to be a superuser locks - lockstring permission - list of permissions report_to - an object with a msg() method to report errors to. If not given, errors will be logged. Will return the Player-typeclass or None/raise Exception if the Typeclass given failed to load. Concerning is_superuser: Usually only the server admin should need to be superuser, all other access levels can be handled with more fine-grained permissions or groups. A superuser bypasses all lock checking operations and is thus not suitable for play-testing the game. """ global _PlayerDB, _Player if not _PlayerDB: from src.players.models import PlayerDB as _PlayerDB if not _Player: from src.players.player import Player as _Player if not email: email = "*****@*****.**" if _PlayerDB.objects.filter(username__iexact=key): raise ValueError("A Player with the name '%s' already exists." % key) # this handles a given dbref-relocate to a player. report_to = handle_dbref(report_to, _PlayerDB) try: # create the correct Player object if is_superuser: new_db_player = _PlayerDB.objects.create_superuser( key, email, password) else: new_db_player = _PlayerDB.objects.create_user(key, email, password) if not typeclass: typeclass = settings.BASE_PLAYER_TYPECLASS elif isinstance(typeclass, _PlayerDB): # this is an PlayerDB instance, extract its typeclass path typeclass = typeclass.typeclass.path elif isinstance(typeclass, _Player) or utils.inherits_from( typeclass, _Player): # this is Player object typeclass, extract its path typeclass = typeclass.path # assign the typeclass typeclass = utils.to_unicode(typeclass) new_db_player.typeclass_path = typeclass # this will either load the typeclass or the default one new_player = new_db_player.typeclass if not _GA(new_db_player, "is_typeclass")(typeclass, exact=True): # this will fail if we gave a typeclass as input # and it still gave us a default SharedMemoryModel.delete(new_db_player) if report_to: _GA(report_to, "msg")("Error creating %s (%s):\n%s" % (new_db_player.key, typeclass, _GA(new_db_player, "typeclass_last_errmsg"))) return None else: raise Exception(_GA(new_db_player, "typeclass_last_errmsg")) new_player.basetype_setup() # setup the basic locks and cmdset # call hook method (may override default permissions) new_player.at_player_creation() # custom given arguments potentially overrides the hook if permissions: new_player.permissions.add(permissions) elif not new_player.permissions: new_player.permissions.add(settings.PERMISSION_PLAYER_DEFAULT) if locks: new_player.locks.add(locks) return new_player except Exception: # a failure in creating the player; we try to clean # up as much as we can logger.log_trace() try: new_player.delete() except Exception: pass try: del new_player except Exception: pass raise
def create_object(typeclass, key=None, location=None, home=None, player=None, permissions=None, locks=None, aliases=None, destination=None, report_to=None): """ Create a new in-game object. Any game object is a combination of a database object that stores data persistently to the database, and a typeclass, which on-the-fly 'decorates' the database object into whataver different type of object it is supposed to be in the game. See src.objects.managers for methods to manipulate existing objects in the database. src.objects.objects holds the base typeclasses and src.objects.models hold the database model. report_to is an optional object for reporting errors to in string form. If report_to is not set, errors will be raised as en Exception containing the error message. If set, this method will return None upon errors. """ global _Object, _ObjectDB if not _Object: from src.objects.objects import Object as _Object if not _ObjectDB: from src.objects.models import ObjectDB as _ObjectDB if not typeclass: typeclass = settings.BASE_OBJECT_TYPECLASS elif isinstance(typeclass, _ObjectDB): # this is already an objectdb instance, extract its typeclass typeclass = typeclass.typeclass.path elif isinstance(typeclass, _Object) or utils.inherits_from(typeclass, _Object): # this is already an object typeclass, extract its path typeclass = typeclass.path # create new database object new_db_object = _ObjectDB() # assign the typeclass typeclass = utils.to_unicode(typeclass) new_db_object.typeclass_path = typeclass # the name/key is often set later in the typeclass. This # is set here as a failsafe. if key: new_db_object.key = key else: new_db_object.key = "#%i" % new_db_object.dbid # this will either load the typeclass or the default one new_object = new_db_object.typeclass if not _GA(new_object, "is_typeclass")(typeclass, exact=True): # this will fail if we gave a typeclass as input and it still gave us a default SharedMemoryModel.delete(new_db_object) if report_to: _GA(report_to, "msg")("Error creating %s (%s):\n%s" % (new_db_object.key, typeclass, _GA(new_db_object, "typeclass_last_errmsg"))) return None else: raise Exception(_GA(new_db_object, "typeclass_last_errmsg")) # from now on we can use the typeclass object # as if it was the database object. if player: # link a player and the object together new_object.player = player player.obj = new_object new_object.destination = destination # call the hook method. This is where all at_creation # customization happens as the typeclass stores custom # things on its database object. new_object.basetype_setup() # setup the basics of Exits, Characters etc. new_object.at_object_creation() # custom-given perms/locks overwrite hooks if permissions: new_object.permissions = permissions if locks: new_object.locks.add(locks) if aliases: new_object.aliases = aliases # perform a move_to in order to display eventual messages. if home: new_object.home = home else: new_object.home = settings.CHARACTER_DEFAULT_HOME if location: new_object.move_to(location, quiet=True) else: # rooms would have location=None. new_object.location = None # post-hook setup (mainly used by Exits) new_object.basetype_posthook_setup() new_object.save() return new_object
def create_script(typeclass, key=None, obj=None, player=None, locks=None, interval=None, start_delay=None, repeats=None, persistent=None, autostart=True, report_to=None): """ Create a new script. All scripts are a combination of a database object that communicates with the database, and an typeclass that 'decorates' the database object into being different types of scripts. It's behaviour is similar to the game objects except scripts has a time component and are more limited in scope. Argument 'typeclass' can be either an actual typeclass object or a python path to such an object. Only set key here if you want a unique name for this particular script (set it in config to give same key to all scripts of the same type). Set obj to tie this script to a particular object. See src.scripts.manager for methods to manipulate existing scripts in the database. report_to is an obtional object to receive error messages. If report_to is not set, an Exception with the error will be raised. If set, this method will return None upon errors. """ global _Script, _ScriptDB if not _Script: from src.scripts.scripts import Script as _Script if not _ScriptDB: from src.scripts.models import ScriptDB as _ScriptDB if not typeclass: typeclass = settings.BASE_SCRIPT_TYPECLASS elif isinstance(typeclass, _ScriptDB): # this is already an scriptdb instance, extract its typeclass typeclass = typeclass.typeclass.path elif isinstance(typeclass, _Script) or utils.inherits_from( typeclass, _Script): # this is already an object typeclass, extract its path typeclass = typeclass.path # create new database script new_db_script = _ScriptDB() # assign the typeclass typeclass = utils.to_unicode(typeclass) new_db_script.typeclass_path = typeclass # the name/key is often set later in the typeclass. This # is set here as a failsafe. if key: new_db_script.key = key else: new_db_script.key = "#%i" % new_db_script.id # this will either load the typeclass or the default one new_script = new_db_script.typeclass if not _GA(new_db_script, "is_typeclass")(typeclass, exact=True): # this will fail if we gave a typeclass as input and it still # gave us a default SharedMemoryModel.delete(new_db_script) if report_to: _GA(report_to, "msg")("Error creating %s (%s): %s" % (new_db_script.key, typeclass, _GA(new_db_script, "typeclass_last_errmsg"))) return None else: raise Exception(_GA(new_db_script, "typeclass_last_errmsg")) if obj: new_script.obj = obj if player: new_script.player = player # call the hook method. This is where all at_creation # customization happens as the typeclass stores custom # things on its database object. new_script.at_script_creation() # custom-given variables override the hook if key: new_script.key = key if locks: new_script.locks.add(locks) if interval is not None: new_script.interval = interval if start_delay is not None: new_script.start_delay = start_delay if repeats is not None: new_script.repeats = repeats if persistent is not None: new_script.persistent = persistent # a new created script should usually be started. if autostart: new_script.start() new_db_script.save() return new_script
def func(self): "Do checks and create account" session = self.caller args = self.args.strip() # extract quoted parts parts = [part.strip() for part in re.split(r"\"|\'", args) if part.strip()] if len(parts) == 1: # this was (hopefully) due to no quotes being found parts = parts[0].split(None, 1) if len(parts) != 2: string = "\n Usage (without <>): create <name> <password>" string += "\nIf <name> or <password> contains spaces, enclose it in quotes." session.msg(string) return playername, password = parts # Drop the player name to lowercase playername = playername.lower() # sanity checks if re.search('[^a-zA-Z0-9._-]', playername) or not (3 <= len(playername) <= 20): session.msg('{RPlayer names must be between 3 and 20 characters, and only contain english letters, numbers, dot (.), underscore (_), or dash(-)') return # Verify this player doesn't already exist if PlayerDB.objects.filter(user__username__iexact=playername) or User.objects.filter(username__iexact=playername): # player already exists (we also ignore capitalization here) session.msg("Sorry, there is already a player with the name '%s'." % playername) return # Verify that this player name does not match an existing character name for existing_object in search_object(playername, attribute_name='key'): if utils.inherits_from(existing_object, "src.objects.objects.Character"): session.msg("Sorry, there is already a character with the name '%s'." % playername) return # Security check the password if not re.findall('^[\w. @+-]+$', password) or not (3 < len(password)): string = "\n\r Password should be longer than 3 characers. Letters, spaces, digits and @\.\+\-\_ only." string += "\nFor best security, make it longer than 8 characters. You can also use a phrase of" string += "\nmany words if you enclose the password in quotes." session.msg(string) return # everything's ok. Create the new player account. try: default_home = ObjectDB.objects.get_id(settings.CHARACTER_DEFAULT_HOME) typeclass = settings.BASE_CHARACTER_TYPECLASS permissions = settings.PERMISSION_PLAYER_DEFAULT try: new_player = create.create_player(playername, None, password, permissions=permissions) except Exception, e: session.msg("There was an error creating the default Player/Character:\n%s\n If this problem persists, contact an admin." % e) return # This needs to be called so the engine knows this player is logging in for the first time. # (so it knows to call the right hooks during login later) utils.init_new_player(new_player) # join the new player to the public channel pchanneldef = settings.CHANNEL_PUBLIC if pchanneldef: pchannel = Channel.objects.get_channel(pchanneldef[0]) if not pchannel.connect_to(new_player): string = "New player '%s' could not connect to public channel!" % new_player.key logger.log_errmsg(string) # tell the caller everything went well. string = "A new account '%s' was created. Welcome!" if " " in playername: string += "\n\nYou can now log in with the command 'connect \"%s\" <your password>'." else: string += "\n\nYou can now log with the command 'connect %s <your password>'." session.msg(string % (playername, playername))
def create_player(name, email, password, user=None, typeclass=None, is_superuser=False, locks=None, permissions=None, create_character=True, character_typeclass=None, character_location=None, character_home=None, player_dbobj=None, report_to=None): """ This creates a new player, handling the creation of the User object and its associated Player object. If player_dbobj is given, this player object is used instead of creating a new one. This is called by the admin interface since it needs to create the player object in order to relate it automatically to the user. If create_character is True, a game player object with the same name as the User/Player will also be created. Its typeclass and base properties can also be given. Returns the new game character, or the Player obj if no character is created. For more info about the typeclass argument, see create_objects() above. Note: if user is supplied, it will NOT be modified (args name, email, passw and is_superuser will be ignored). Change those properties directly on the User instead. If no permissions are given (None), the default permission group as defined in settings.PERMISSION_PLAYER_DEFAULT will be assigned. If permissions are given, no automatic assignment will occur. Concerning is_superuser: A superuser should have access to everything in the game and on the server/web interface. The very first user created in the database is always a superuser (that's using django's own creation, not this one). Usually only the server admin should need to be superuser, all other access levels can be handled with more fine-grained permissions or groups. Since superuser overrules all permissions, we don't set any in this case. """ # The system should already have checked so the name/email # isn't already registered, and that the password is ok before # getting here. global _PlayerDB, _Player if not _PlayerDB: from src.players.models import PlayerDB as _PlayerDB if not _Player: from src.players.player import Player as _Player if not email: email = "*****@*****.**" if user: new_user = user email = user.email else: if is_superuser: new_user = User.objects.create_superuser(name, email, password) else: new_user = User.objects.create_user(name, email, password) try: if not typeclass: typeclass = settings.BASE_PLAYER_TYPECLASS elif isinstance(typeclass, _PlayerDB): # this is already an objectdb instance, extract its typeclass typeclass = typeclass.typeclass.path elif isinstance(typeclass, _Player) or utils.inherits_from(typeclass, _Player): # this is already an object typeclass, extract its path typeclass = typeclass.path if player_dbobj: try: _GA(player_dbobj, "dbobj") new_db_player = player_dbobj.dbobj except AttributeError: new_db_player = player_dbobj # use the typeclass from this object typeclass = new_db_player.typeclass_path else: new_db_player = _PlayerDB(db_key=name, user=new_user) new_db_player.save() # assign the typeclass typeclass = utils.to_unicode(typeclass) new_db_player.typeclass_path = typeclass # this will either load the typeclass or the default one new_player = new_db_player.typeclass if not _GA(new_db_player, "is_typeclass")(typeclass, exact=True): # this will fail if we gave a typeclass as input and it still gave us a default SharedMemoryModel.delete(new_db_player) if report_to: _GA(report_to, "msg")("Error creating %s (%s):\n%s" % (new_db_player.key, typeclass, _GA(new_db_player, "typeclass_last_errmsg"))) return None else: raise Exception(_GA(new_db_player, "typeclass_last_errmsg")) new_player.basetype_setup() # setup the basic locks and cmdset # call hook method (may override default permissions) new_player.at_player_creation() # custom given arguments potentially overrides the hook if permissions: new_player.permissions = permissions elif not new_player.permissions: new_player.permissions = settings.PERMISSION_PLAYER_DEFAULT if locks: new_player.locks.add(locks) # create *in-game* 'player' object if create_character: if not character_typeclass: character_typeclass = settings.BASE_CHARACTER_TYPECLASS # creating the object automatically links the player # and object together by player.obj <-> obj.player new_character = create_object(character_typeclass, key=name, location=character_location, home=character_location, permissions=permissions, player=new_player, report_to=report_to) return new_character return new_player except Exception, e: # a failure in creating the character if not user: # in there was a failure we clean up everything we can logger.log_trace() try: new_user.delete() except Exception: pass try: new_player.delete() except Exception: pass try: del new_character except Exception: pass raise e
def create_object(typeclass=None, key=None, location=None, home=None, permissions=None, locks=None, aliases=None, destination=None, report_to=None, nohome=False): """ Create a new in-game object. Any game object is a combination of a database object that stores data persistently to the database, and a typeclass, which on-the-fly 'decorates' the database object into whataver different type of object it is supposed to be in the game. See src.objects.managers for methods to manipulate existing objects in the database. src.objects.objects holds the base typeclasses and src.objects.models hold the database model. report_to is an optional object for reporting errors to in string form. If report_to is not set, errors will be raised as en Exception containing the error message. If set, this method will return None upon errors. nohome - this allows the creation of objects without a default home location; this only used when creating the default location itself or during unittests """ global _Object, _ObjectDB if not _Object: from src.objects.objects import Object as _Object if not _ObjectDB: from src.objects.models import ObjectDB as _ObjectDB # input validation if not typeclass: typeclass = settings.BASE_OBJECT_TYPECLASS elif isinstance(typeclass, _ObjectDB): # this is already an objectdb instance, extract its typeclass typeclass = typeclass.typeclass.path elif isinstance(typeclass, _Object) or utils.inherits_from(typeclass, _Object): # this is already an object typeclass, extract its path typeclass = typeclass.path typeclass = utils.to_unicode(typeclass) # Setup input for the create command location = handle_dbref(location, _ObjectDB) destination = handle_dbref(destination, _ObjectDB) home = handle_dbref(home, _ObjectDB) if not home: try: home = handle_dbref(settings.DEFAULT_HOME, _ObjectDB) if not nohome else None except _ObjectDB.DoesNotExist: raise _ObjectDB.DoesNotExist("settings.DEFAULT_HOME (= '%s') does not exist, or the setting is malformed." % settings.DEFAULT_HOME) # create new database object all in one go new_db_object = _ObjectDB(db_key=key, db_location=location, db_destination=destination, db_home=home, db_typeclass_path=typeclass) if not key: # the object should always have a key, so if not set we give a default new_db_object.key = "#%i" % new_db_object.dbid # this will either load the typeclass or the default one (will also save object) new_object = new_db_object.typeclass if not _GA(new_object, "is_typeclass")(typeclass, exact=True): # this will fail if we gave a typeclass as input and it still # gave us a default try: SharedMemoryModel.delete(new_db_object) except AssertionError: # this happens if object was never created pass if report_to: report_to = handle_dbref(report_to, _ObjectDB) _GA(report_to, "msg")("Error creating %s (%s).\n%s" % (new_db_object.key, typeclass, _GA(new_db_object, "typeclass_last_errmsg"))) return None else: raise Exception(_GA(new_db_object, "typeclass_last_errmsg")) # from now on we can use the typeclass object # as if it was the database object. # call the hook methods. This is where all at_creation # customization happens as the typeclass stores custom # things on its database object. # note - this may override input keys, locations etc! new_object.basetype_setup() # setup the basics of Exits, Characters etc. new_object.at_object_creation() # we want the input to override that set in the hooks, so # we re-apply those if needed if new_object.key != key: new_object.key = key if new_object.location != location: new_object.location = location if new_object.home != home: new_object.home = home if new_object.destination != destination: new_object.destination = destination # custom-given perms/locks do overwrite hooks if permissions: new_object.permissions.add(permissions) if locks: new_object.locks.add(locks) if aliases: new_object.aliases.add(aliases) # trigger relevant move_to hooks in order to display messages. if location: location.at_object_receive(new_object, None) new_object.at_after_move(None) # post-hook setup (mainly used by Exits) new_object.basetype_posthook_setup() return new_object
def create_object(typeclass=None, key=None, location=None, home=None, permissions=None, locks=None, aliases=None, destination=None, report_to=None, nohome=False): """ Create a new in-game object. Any game object is a combination of a database object that stores data persistently to the database, and a typeclass, which on-the-fly 'decorates' the database object into whataver different type of object it is supposed to be in the game. See src.objects.managers for methods to manipulate existing objects in the database. src.objects.objects holds the base typeclasses and src.objects.models hold the database model. report_to is an optional object for reporting errors to in string form. If report_to is not set, errors will be raised as en Exception containing the error message. If set, this method will return None upon errors. nohome - this allows the creation of objects without a default home location; this only used when creating default location itself or during unittests """ global _Object, _ObjectDB if not _Object: from src.objects.objects import Object as _Object if not _ObjectDB: from src.objects.models import ObjectDB as _ObjectDB # input validation if not typeclass: typeclass = settings.BASE_OBJECT_TYPECLASS elif isinstance(typeclass, _ObjectDB): # this is already an objectdb instance, extract its typeclass typeclass = typeclass.typeclass.path elif isinstance(typeclass, _Object) or utils.inherits_from( typeclass, _Object): # this is already an object typeclass, extract its path typeclass = typeclass.path # handle eventual #dbref input location = handle_dbref(location, _ObjectDB) home = handle_dbref(home, _ObjectDB) destination = handle_dbref(destination, _ObjectDB) report_to = handle_dbref(report_to, _ObjectDB) # create new database object new_db_object = _ObjectDB() # assign the typeclass typeclass = utils.to_unicode(typeclass) new_db_object.typeclass_path = typeclass # the name/key is often set later in the typeclass. This # is set here as a failsafe. if key: new_db_object.key = key else: new_db_object.key = "#%i" % new_db_object.dbid # this will either load the typeclass or the default one new_object = new_db_object.typeclass if not _GA(new_object, "is_typeclass")(typeclass, exact=True): # this will fail if we gave a typeclass as input and it still # gave us a default SharedMemoryModel.delete(new_db_object) if report_to: _GA(report_to, "msg")("Error creating %s (%s):\n%s" % (new_db_object.key, typeclass, _GA(new_db_object, "typeclass_last_errmsg"))) return None else: raise Exception(_GA(new_db_object, "typeclass_last_errmsg")) # from now on we can use the typeclass object # as if it was the database object. new_object.destination = destination # call the hook method. This is where all at_creation # customization happens as the typeclass stores custom # things on its database object. new_object.basetype_setup() # setup the basics of Exits, Characters etc. new_object.at_object_creation() # custom-given perms/locks overwrite hooks if permissions: new_object.permissions.add(permissions) if locks: new_object.locks.add(locks) if aliases: new_object.aliases.add(aliases) if home: new_object.home = home else: # we shouldn't need to handle dbref here (home handler should fix it), but some have # reported issues here (issue 446). try: new_object.home = handle_dbref(settings.DEFAULT_HOME, _ObjectDB) if not nohome else None except _ObjectDB.DoesNotExist: raise _ObjectDB.DoesNotExist( "settings.DEFAULT_HOME (= '%s') does not exist, or the setting is malformed." % settings.DEFAULT_HOME) # perform a move_to in order to display eventual messages. if location: new_object.move_to(location, quiet=True) else: # rooms would have location=None. new_object.location = None # post-hook setup (mainly used by Exits) new_object.basetype_posthook_setup() new_object.save() return new_object
def character_set(self, character): "Setter. Allows for self.character = value" if inherits_from(character, TypeClass): character = character.dbobj set_field_cache(self, "obj", character)
def func(self): """ Implements the ooc look command We use an attribute _character_dbrefs on the player in order to figure out which characters are "theirs". A drawback of this is that only the CmdCharacterCreate command adds this attribute, and thus e.g. player #1 will not be listed (although it will work). Existence in this list does not depend on puppeting rights though, that is checked by the @ic command directly. """ # making sure caller is really a player self.character = None if utils.inherits_from(self.caller, "src.objects.objects.Object"): # An object of some type is calling. Convert to player. #print self.caller, self.caller.__class__ self.character = self.caller if hasattr(self.caller, "player"): self.caller = self.caller.player if not self.character: # ooc mode, we are players avail_chars = self.caller.db._character_dbrefs if self.args: # Maybe the caller wants to look at a character if not avail_chars: self.caller.msg("You have no characters to look at. Why not create one?") return objs = ObjectDB.objects.get_objs_with_key_and_typeclass(self.args.strip(), CHARACTER_TYPECLASS) objs = [obj for obj in objs if obj.id in avail_chars] if not objs: self.caller.msg("You cannot see this Character.") return self.caller.msg(objs[0].return_appearance(self.caller)) return # not inspecting a character. Show the OOC info. charobjs = [] charnames = [] if self.caller.db._character_dbrefs: dbrefs = self.caller.db._character_dbrefs charobjs = [ObjectDB.objects.get_id(dbref) for dbref in dbrefs] charnames = [charobj.key for charobj in charobjs if charobj] if charnames: charlist = "The following Character(s) are available:\n\n" charlist += "\n\r".join(["{w %s{n" % charname for charname in charnames]) charlist += "\n\n Use {w@ic <character name>{n to switch to that Character." else: charlist = "You have no Characters." string = \ """ You, %s, are an {wOOC ghost{n without form. The world is hidden from you and besides chatting on channels your options are limited. You need to have a Character in order to interact with the world. %s Use {wcreate <name>{n to create a new character and {whelp{n for a list of available commands.""" % (self.caller.key, charlist) self.caller.msg(string) else: # not ooc mode - leave back to normal look self.caller = self.character # we have to put this back for normal look to work. super(CmdOOCLook, self).func()
def create_object(typeclass=None, key=None, location=None, home=None, permissions=None, locks=None, aliases=None, destination=None, report_to=None, nohome=False): """ Create a new in-game object. Any game object is a combination of a database object that stores data persistently to the database, and a typeclass, which on-the-fly 'decorates' the database object into whataver different type of object it is supposed to be in the game. See src.objects.managers for methods to manipulate existing objects in the database. src.objects.objects holds the base typeclasses and src.objects.models hold the database model. report_to is an optional object for reporting errors to in string form. If report_to is not set, errors will be raised as en Exception containing the error message. If set, this method will return None upon errors. nohome - this allows the creation of objects without a default home location; this only used when creating the default location itself or during unittests """ global _Object, _ObjectDB if not _Object: from src.objects.objects import Object as _Object if not _ObjectDB: from src.objects.models import ObjectDB as _ObjectDB # input validation if not typeclass: typeclass = settings.BASE_OBJECT_TYPECLASS elif isinstance(typeclass, _ObjectDB): # this is already an objectdb instance, extract its typeclass typeclass = typeclass.typeclass.path elif isinstance(typeclass, _Object) or utils.inherits_from( typeclass, _Object): # this is already an object typeclass, extract its path typeclass = typeclass.path typeclass = utils.to_unicode(typeclass) # Setup input for the create command location = handle_dbref(location, _ObjectDB) destination = handle_dbref(destination, _ObjectDB) home = handle_dbref(home, _ObjectDB) if not home: try: home = handle_dbref(settings.DEFAULT_HOME, _ObjectDB) if not nohome else None except _ObjectDB.DoesNotExist: raise _ObjectDB.DoesNotExist( "settings.DEFAULT_HOME (= '%s') does not exist, or the setting is malformed." % settings.DEFAULT_HOME) # create new database object all in one go new_db_object = _ObjectDB(db_key=key, db_location=location, db_destination=destination, db_home=home, db_typeclass_path=typeclass) if not key: # the object should always have a key, so if not set we give a default new_db_object.key = "#%i" % new_db_object.dbid # this will either load the typeclass or the default one (will also save object) new_object = new_db_object.typeclass if not _GA(new_object, "is_typeclass")(typeclass, exact=True): # this will fail if we gave a typeclass as input and it still # gave us a default try: SharedMemoryModel.delete(new_db_object) except AssertionError: # this happens if object was never created pass if report_to: report_to = handle_dbref(report_to, _ObjectDB) _GA(report_to, "msg")("Error creating %s (%s).\n%s" % (new_db_object.key, typeclass, _GA(new_db_object, "typeclass_last_errmsg"))) return None else: raise Exception(_GA(new_db_object, "typeclass_last_errmsg")) # from now on we can use the typeclass object # as if it was the database object. # call the hook methods. This is where all at_creation # customization happens as the typeclass stores custom # things on its database object. # note - this may override input keys, locations etc! new_object.basetype_setup() # setup the basics of Exits, Characters etc. new_object.at_object_creation() # we want the input to override that set in the hooks, so # we re-apply those if needed if new_object.key != key: new_object.key = key if new_object.location != location: new_object.location = location if new_object.home != home: new_object.home = home if new_object.destination != destination: new_object.destination = destination # custom-given perms/locks do overwrite hooks if permissions: new_object.permissions.add(permissions) if locks: new_object.locks.add(locks) if aliases: new_object.aliases.add(aliases) # trigger relevant move_to hooks in order to display messages. if location: new_object.at_object_receive(new_object, None) new_object.at_after_move(new_object) # post-hook setup (mainly used by Exits) new_object.basetype_posthook_setup() return new_object
def func(self): """ Tries to create the Character object. We also put an attribute on ourselves to remember it. """ # making sure caller is really a player self.character = None if utils.inherits_from(self.caller, "src.objects.objects.Object"): # An object of some type is calling. Convert to player. #print self.caller, self.caller.__class__ self.character = self.caller if hasattr(self.caller, "player"): self.caller = self.caller.player if not self.args: self.caller.msg("Usage: create <character name>") return charname = self.args.strip() split_charname = charname.split(' ') if len(split_charname) > 2: self.caller.msg("Character name must be in the following format: Firstname Surname. Or: Firstname.") return old_char = ObjectDB.objects.get_objs_with_key_and_typeclass(charname, CHARACTER_TYPECLASS) if old_char: self.caller.msg("Character {c%s{n already exists." % charname) return # create the character new_character = create.create_object(CHARACTER_TYPECLASS, key=charname) if not new_character: self.caller.msg("{rThe Character couldn't be created. This is a bug. Please contact an admin.") return # make sure to lock the character to only be puppeted by this player new_character.locks.add("puppet:id(%i) or pid(%i) or perm(Immortals) or pperm(Immortals)" % (new_character.id, self.caller.id)) # save dbref avail_chars = self.caller.db._character_dbrefs if avail_chars: avail_chars.append(new_character.id) else: avail_chars = [new_character.id] self.caller.db._character_dbrefs = avail_chars self.caller.msg("{gThe Character {c%s{g was successfully created!" % charname) if self.caller.swap_character(new_character): attributes = new_character.db.attributes nodes = [] copy_dir = '/var/mud/evennia/game/gamesrc/copy/' for option in ['race', 'deity', 'alignment', 'gender', 'weapon skills', 'armor skills']: if 'race' in option: for race in ['bardok', 'erelania', 'the unknowns', 'earthen', 'gerdling']: confirm_node = MenuNode("confirm-%s" % race, links=['deity'], linktexts=['Choose your deity.'], code="self.caller.set_race('%s')" % race) nodes.append(confirm_node) if 'bardok' in race: text = copyreader.read_file("%s/races/bardok_desc.txt" % copy_dir) race_node = MenuNode("%s" % race, text=text, links=['confirm-bardok', 'race'], linktexts=['Confirm Race Selection', 'Back to Races']) elif 'erelania' in race: text = copyreader.read_file("%s/races/erelania_desc.txt" % copy_dir) race_node = MenuNode("%s" % race, text=text, links=['confirm-erelania', 'race'], linktexts=['Confirm Race Selection', 'Back to Races']) elif 'gerdling' in race: text = copyreader.read_file("%s/races/gerdling_desc.txt" % copy_dir) race_node = MenuNode("%s" % race, text=text, links=['confirm-gerdling', 'race'], linktexts=['Confirm Race Selection', 'Back to Races']) elif 'earthen' in race: text = copyreader.read_file("%s/races/earthen_desc.txt" % copy_dir) race_node = MenuNode("%s" % race, text=text, links=['confirm-earthen', 'race'], linktexts=['Confirm Race Selection', 'Back to Races']) nodes.append(race_node) text = copyreader.read_file("%s/races/races_desc.txt" % copy_dir) root_race_node = MenuNode("%s" % option, text=text, links=['bardok', 'erelania', 'gerdling', 'earthen'], linktexts=['The Bardok', 'The Erelania', 'The Gerdling', 'The Earthen']) nodes.append(root_race_node) elif 'deity' in option: deities = ['ankarith', 'slyth', 'green warden', 'kaylynne'] for deity in deities: confirm_node = MenuNode('confirm-%s' % deity, links=['gender'], linktexts=['Choose your gender.'], code="self.caller.set_deity('%s')" % deity) nodes.append(confirm_node) if 'karith' in deity: text = copyreader.read_file("%s/deities/ankarith_desc.txt" % copy_dir) deity_node = MenuNode("%s" % deity, text=text, links=['confirm-ankarith', 'deity'], linktexts=['Confirm Deity Selection', 'Back to Deities']) #self.obj.msg("links: %s, linktexts: %s" % (deity_node.links, deity_node.linktexts)) elif 'slyth' in deity: text = copyreader.read_file("%s/deities/slyth_desc.txt" % copy_dir) deity_node = MenuNode("%s" % deity, text=text, links=['confirm-slyth', 'deity'], linktexts=['Confirm Deity Selection', 'Back to Deities']) elif 'green warden' in deity: text = copyreader.read_file("%s/deities/greenwarden_desc.txt" % copy_dir) deity_node = MenuNode("%s" % deity, text=text, links=['confirm-green warden', 'deity'], linktexts=['Confirm Deity Selection', 'Back to Deities']) elif 'kaylynne' in deity: text = copyreader.read_file("%s/deities/kaylynne_desc.txt" % copy_dir) deity_node = MenuNode("%s" % deity, text=text, links=['confirm-kaylynne', 'deity'], linktexts=['Confirm Deity Selection', 'Back to Deities']) nodes.append(deity_node) deity_node_text = copyreader.read_file("%s/deities/deities_desc.txt" % copy_dir) root_deity_node = MenuNode("deity", text=deity_node_text, links=['ankarith', 'slyth', 'green warden', 'kaylynne'], linktexts=['An\'Karith', 'Slyth of the Glade', 'The Green Warden', 'Kaylynne']) nodes.append(root_deity_node) elif 'gender' in option: confirm_male = MenuNode("confirm-gender-male", links=['weapons'], linktexts=['Choose which weapon to specialize in.'], code="self.caller.set_gender('male')") confirm_female = MenuNode("confirm-gender-female", links=['weapons'], linktexts=['Choose which weapon to specialize in.'], code="self.caller.set_gender('female')") nodes.append(confirm_male) nodes.append(confirm_female) text = """ --{rGender Selection{n-- Please select which gender you would like to be: """ gender_node = MenuNode("gender", text=text, links=['confirm-gender-male', 'confirm-gender-female'], linktexts=['Male', 'Female']) nodes.append(gender_node) elif 'weapon skills' in option: confirm_blades = MenuNode("confirm-blades", links=['armor'], linktexts=['Choose Armor Specialization .'], code="self.caller.set_weapon_skill('blades')") confirm_heavy = MenuNode("confirm-heavy", links=['armor'], linktexts=['Choose Armor Specialization'], code="self.caller.set_weapon_skill('heavy')") confirm_bludgeon = MenuNode("confirm-bludgeon", links=['armor'], linktexts=['Choose Armor Specialization.'], code="self.caller.set_weapon_skill('bludgeon')") nodes.append(confirm_blades) nodes.append(confirm_heavy) nodes.append(confirm_bludgeon) text = """ --{rWeapon Type Selection{n-- Please select which weapon type you would like to specialize in: {GTypes:{n {cBludgeoning{n - Weapons that bash and smash. (Maces, hammers, staves). {cBladed{n - Weapons that slash and cut. (Swords, daggers, axes). {cHeavy{n - Large, often two handed weaponry. (Bastard sword, Great Axe, Polearm). Using weaponry you are not skilled in will result is an increased chance of scoring only glancing blows on a target (damage / 2). You may also take large and more consistent balance reduction. """ weapons_node = MenuNode("weapons", links=['confirm-bludgeon', 'confirm-blades', 'confirm-heavy'], linktexts=['Bludgeoning Weapons', 'Bladed Weapons', 'Heavy Weapons'], text=text) nodes.append(weapons_node) elif 'armor skills' in option: confirm_light = MenuNode("confirm-lightarmor", links=['END'], linktexts=['Begin Your Journey!'], code="self.caller.set_armor_skill('light')") confirm_medium = MenuNode("confirm-mediumarmor", links=['END'], linktexts=['Begin Your Journey!'], code="self.caller.set_armor_skill('medium')") confirm_heavy = MenuNode("confirm-heavyarmor", links=['END'], linktexts=['Begin Your Journey!'], code="self.caller.set_armor_skill('heavy')") nodes.append(confirm_light) nodes.append(confirm_medium) nodes.append(confirm_heavy) text = """ --{rArmor Specilization{n-- Please select which armory type you would like to specialize in: {GTypes:{n {cLight{n - Lightweight, mobile armors. (leather, cloth). {cMedium{n - Moderate weight, semi-mobile armor. (scalemail, ring mail, chainmail). {cHeavy{n - Heavy weight, hard to move in armor. (plate and half plate) Using armor you are not specialized in, will result in large balance loss which in turn will result in stat loss and most likely death. """ armor_node = MenuNode("armor", links=['confirm-lightarmor', 'confirm-mediumarmor', 'confirm-heavyarmor'], linktexts=['Light Armor', 'Medium Armor', 'Heavy Armor'], text=text) nodes.append(armor_node) """ elif 'alignment' in option: confirm_good = MenuNode("confirm-good", links=['END'], linktexts=['Begin your journey.'], text="{rYou begin your journey down the path of light.{n", code="self.caller.set_alignment('good')") confirm_evil = MenuNode("confirm-evil", links=['END'], linktexts=['Begin your journey.'], text="{rYou begin your journey down the path of darkness.{n", code="self.caller.set_alignment('evil')") nodes.append(confirm_good) nodes.append(confirm_evil) text = --{rAlignment Selection{n-- Which path to do you desire to walk? alignment_node = MenuNode("alignment", text=text, links=['confirm-evil', 'confirm-good', 'START'], linktexts=['Path of Darkness', 'Path of Light', 'Back to Customization']) nodes.append(alignment_node) """ start_node = MenuNode("START", text="{bWelcome to Avaloria. Please proceed through the menu to customize your character.{n", links=['race' ], linktexts=['Choose your race.']) nodes.append(start_node) endnode = MenuNode("END", links=[], linktexts=[], code="self.caller.post_creation()") nodes.append(endnode) # node_string = ' '.join([node.key for node in nodes]) # self.obj.msg("{mDEBUG: nodes: %s{n" % node_string) menutree = MenuTree(caller=self.caller.character, nodes=nodes, exec_end=None) flags = new_character.db.flags flags['in_menu'] = True self.caller.db.flags = flags menutree.start()
def perm(accessing_obj, accessed_obj, *args, **kwargs): """ The basic permission-checker. Ignores case. Usage: perm(<permission>) where <permission> is the permission accessing_obj must have in order to pass the lock. If the given permission is part of settings.PERMISSION_HIERARCHY, permission is also granted to all ranks higher up in the hierarchy. If accessing_object is an Object controlled by a Player, the permissions of the Player is used unless the Attribute _quell is set to True on the Object. In this case however, the LOWEST hieararcy-permission of the Player/Object-pair will be used (this is order to avoid Players potentially escalating their own permissions by use of a higher-level Object) """ # this allows the perm_above lockfunc to make use of this function too gtmode = kwargs.pop("_greater_than", False) try: perm = args[0].lower() perms_object = [p.lower() for p in accessing_obj.permissions.all()] except (AttributeError, IndexError): return False if utils.inherits_from(accessing_obj, "src.objects.objects.Object") and accessing_obj.player: player = accessing_obj.player perms_player = [p.lower() for p in player.permissions.all()] is_quell = player.attributes.get("_quell") if perm in _PERMISSION_HIERARCHY: # check hierarchy without allowing escalation obj->player hpos_target = _PERMISSION_HIERARCHY.index(perm) hpos_player = [hpos for hpos, hperm in enumerate(_PERMISSION_HIERARCHY) if hperm in perms_player] hpos_player = hpos_player and hpos_player[-1] or -1 if is_quell: hpos_object = [hpos for hpos, hperm in enumerate(_PERMISSION_HIERARCHY) if hperm in perms_object] hpos_object = hpos_object and hpos_object[-1] or -1 if gtmode: return hpos_target < min(hpos_player, hpos_object) else: return hpos_target <= min(hpos_player, hpos_object) elif gtmode: return gtmode and hpos_target < hpos_player else: return hpos_target <= hpos_player elif not is_quell and perm in perms_player: # if we get here, check player perms first, otherwise # continue as normal return True if perm in perms_object: # simplest case - we have direct match return True if perm in _PERMISSION_HIERARCHY: # check if we have a higher hierarchy position hpos_target = _PERMISSION_HIERARCHY.index(perm) return any(1 for hpos, hperm in enumerate(_PERMISSION_HIERARCHY) if hperm in perms_object and hpos_target < hpos) return False
def _to_player(accessing_obj): "Helper function. Makes sure an accessing object is a player object" if utils.inherits_from(accessing_obj, "src.objects.objects.Object"): # an object. Convert to player. accessing_obj = accessing_obj.player return accessing_obj
def __player_set(self, player): "Setter. Allows for self.player = value" if inherits_from(player, TypeClass): player = player.dbobj set_field_cache(self, "player", player)
def create_player(key, email, password, typeclass=None, is_superuser=False, locks=None, permissions=None, report_to=None): """ This creates a new player. key - the player's name. This should be unique. email - email on valid [email protected] form. password - password in cleartext is_superuser - wether or not this player is to be a superuser locks - lockstring permission - list of permissions report_to - an object with a msg() method to report errors to. If not given, errors will be logged. Will return the Player-typeclass or None/raise Exception if the Typeclass given failed to load. Concerning is_superuser: Usually only the server admin should need to be superuser, all other access levels can be handled with more fine-grained permissions or groups. A superuser bypasses all lock checking operations and is thus not suitable for play-testing the game. """ global _PlayerDB, _Player if not _PlayerDB: from src.players.models import PlayerDB as _PlayerDB if not _Player: from src.players.player import Player as _Player if not email: email = "*****@*****.**" if _PlayerDB.objects.filter(username__iexact=key): raise ValueError("A Player with the name '%s' already exists." % key) # this handles a given dbref-relocate to a player. report_to = handle_dbref(report_to, _PlayerDB) try: # create the correct Player object if is_superuser: new_db_player = _PlayerDB.objects.create_superuser(key, email, password) else: new_db_player = _PlayerDB.objects.create_user(key, email, password) if not typeclass: typeclass = settings.BASE_PLAYER_TYPECLASS elif isinstance(typeclass, _PlayerDB): # this is an PlayerDB instance, extract its typeclass path typeclass = typeclass.typeclass.path elif isinstance(typeclass, _Player) or utils.inherits_from(typeclass, _Player): # this is Player object typeclass, extract its path typeclass = typeclass.path # assign the typeclass typeclass = utils.to_unicode(typeclass) new_db_player.typeclass_path = typeclass # this will either load the typeclass or the default one new_player = new_db_player.typeclass if not _GA(new_db_player, "is_typeclass")(typeclass, exact=True): # this will fail if we gave a typeclass as input # and it still gave us a default SharedMemoryModel.delete(new_db_player) if report_to: _GA(report_to, "msg")("Error creating %s (%s):\n%s" % (new_db_player.key, typeclass, _GA(new_db_player, "typeclass_last_errmsg"))) return None else: raise Exception(_GA(new_db_player, "typeclass_last_errmsg")) new_player.basetype_setup() # setup the basic locks and cmdset # call hook method (may override default permissions) new_player.at_player_creation() # custom given arguments potentially overrides the hook if permissions: new_player.permissions.add(permissions) elif not new_player.permissions: new_player.permissions.add(settings.PERMISSION_PLAYER_DEFAULT) if locks: new_player.locks.add(locks) return new_player except Exception: # a failure in creating the player; we try to clean # up as much as we can logger.log_trace() try: new_player.delete() except Exception: pass try: del new_player except Exception: pass raise
def create_script(typeclass, key=None, obj=None, player=None, locks=None, interval=None, start_delay=None, repeats=None, persistent=None, autostart=True, report_to=None): """ Create a new script. All scripts are a combination of a database object that communicates with the database, and an typeclass that 'decorates' the database object into being different types of scripts. It's behaviour is similar to the game objects except scripts has a time component and are more limited in scope. Argument 'typeclass' can be either an actual typeclass object or a python path to such an object. Only set key here if you want a unique name for this particular script (set it in config to give same key to all scripts of the same type). Set obj to tie this script to a particular object. See src.scripts.manager for methods to manipulate existing scripts in the database. report_to is an obtional object to receive error messages. If report_to is not set, an Exception with the error will be raised. If set, this method will return None upon errors. """ global _Script, _ScriptDB if not _Script: from src.scripts.scripts import Script as _Script if not _ScriptDB: from src.scripts.models import ScriptDB as _ScriptDB if not typeclass: typeclass = settings.BASE_SCRIPT_TYPECLASS elif isinstance(typeclass, _ScriptDB): # this is already an scriptdb instance, extract its typeclass typeclass = typeclass.typeclass.path elif isinstance(typeclass, _Script) or utils.inherits_from(typeclass, _Script): # this is already an object typeclass, extract its path typeclass = typeclass.path # create new database script new_db_script = _ScriptDB() # assign the typeclass typeclass = utils.to_unicode(typeclass) new_db_script.typeclass_path = typeclass # the name/key is often set later in the typeclass. This # is set here as a failsafe. if key: new_db_script.key = key else: new_db_script.key = "#%i" % new_db_script.id # this will either load the typeclass or the default one new_script = new_db_script.typeclass if not _GA(new_db_script, "is_typeclass")(typeclass, exact=True): # this will fail if we gave a typeclass as input and it still # gave us a default SharedMemoryModel.delete(new_db_script) if report_to: _GA(report_to, "msg")("Error creating %s (%s): %s" % (new_db_script.key, typeclass, _GA(new_db_script, "typeclass_last_errmsg"))) return None else: raise Exception(_GA(new_db_script, "typeclass_last_errmsg")) if obj: new_script.obj = obj if player: new_script.player = player # call the hook method. This is where all at_creation # customization happens as the typeclass stores custom # things on its database object. new_script.at_script_creation() # custom-given variables override the hook if key: new_script.key = key if locks: new_script.locks.add(locks) if interval is not None: new_script.interval = interval if start_delay is not None: new_script.start_delay = start_delay if repeats is not None: new_script.repeats = repeats if persistent is not None: new_script.persistent = persistent # a new created script should usually be started. if autostart: new_script.start() new_db_script.save() return new_script
def func(self): """ Tries to create the Character object. We also put an attribute on ourselves to remember it. """ # making sure caller is really a player self.character = None if utils.inherits_from(self.caller, "src.objects.objects.Object"): # An object of some type is calling. Convert to player. #print self.caller, self.caller.__class__ self.character = self.caller if hasattr(self.caller, "player"): self.caller = self.caller.player if not self.args: self.caller.msg("Usage: create <character name>") return charname = self.args.strip() old_char = ObjectDB.objects.get_objs_with_key_and_typeclass(charname, CHARACTER_TYPECLASS) if old_char: self.caller.msg("Character {c%s{n already exists." % charname) return # create the character new_character = create.create_object(CHARACTER_TYPECLASS, key=charname) if not new_character: self.caller.msg("{rThe Character couldn't be created. This is a bug. Please contact an admin.") return # make sure to lock the character to only be puppeted by this player new_character.locks.add("puppet:id(%i) or pid(%i) or perm(Immortals) or pperm(Immortals)" % (new_character.id, self.caller.id)) # save dbref avail_chars = self.caller.db._character_dbrefs if avail_chars: avail_chars.append(new_character.id) else: avail_chars = [new_character.id] self.caller.db._character_dbrefs = avail_chars self.caller.msg("{gThe Character {c%s{g was successfully created!" % charname) self.caller = new_character attributes = new_character.db.attributes nodes = [] copy_dir = '/var/mud/evennia/game/gamesrc/copy/' for option in ['race', 'deity', 'alignment', 'gender']: if 'race' in option: for race in ['bardok', 'erelania', 'the unknowns', 'earthen', 'gerdling']: confirm_node = MenuNode("confirm-%s" % race, links=['deity'], linktexts=['Choose your deity.'], code="self.caller.set_race('%s')" % race) nodes.append(confirm_node) if 'bardok' in race: text = copyreader.read_file("%s/races/bardok_desc.txt" % copy_dir) race_node = MenuNode("%s" % race, text=text, links=['confirm-bardok', 'race'], linktexts=['Confirm Race Selection', 'Back to Races']) elif 'erelania' in race: text = copyreader.read_file("%s/races/erelania_desc.txt" % copy_dir) race_node = MenuNode("%s" % race, text=text, links=['confirm-erelania', 'race'], linktexts=['Confirm Race Selection', 'Back to Races']) elif 'gerdling' in race: text = copyreader.read_file("%s/races/gerdling_desc.txt" % copy_dir) race_node = MenuNode("%s" % race, text=text, links=['confirm-gerdling', 'race'], linktexts=['Confirm Race Selection', 'Back to Races']) elif 'earthen' in race: text = copyreader.read_file("%s/races/earthen_desc.txt" % copy_dir) race_node = MenuNode("%s" % race, text=text, links=['confirm-earthen', 'race'], linktexts=['Confirm Race Selection', 'Back to Races']) nodes.append(race_node) text = copyreader.read_file("%s/races/races_desc.txt" % copy_dir) root_race_node = MenuNode("%s" % option, text=text, links=['bardok', 'erelania', 'gerdling', 'earthen'], linktexts=['The Bardok', 'The Erelania', 'The Gerdling', 'The Earthen']) nodes.append(root_race_node) elif 'deity' in option: deities = ['ankarith', 'slyth', 'green warden', 'kaylynne'] for deity in deities: confirm_node = MenuNode('confirm-%s' % deity, links=['gender'], linktexts=['Choose your gender.'], code="self.caller.set_deity('%s')" % deity) nodes.append(confirm_node) if 'karith' in deity: text = copyreader.read_file("%s/deities/ankarith_desc.txt" % copy_dir) deity_node = MenuNode("%s" % deity, text=text, links=['confirm-ankarith', 'deity'], linktexts=['Confirm Deity Selection', 'Back to Deities']) #self.obj.msg("links: %s, linktexts: %s" % (deity_node.links, deity_node.linktexts)) elif 'slyth' in deity: text = copyreader.read_file("%s/deities/slyth_desc.txt" % copy_dir) deity_node = MenuNode("%s" % deity, text=text, links=['confirm-slyth', 'deity'], linktexts=['Confirm Deity Selection', 'Back to Deities']) elif 'green warden' in deity: text = copyreader.read_file("%s/deities/greenwarden_desc.txt" % copy_dir) deity_node = MenuNode("%s" % deity, text=text, links=['confirm-green warden', 'deity'], linktexts=['Confirm Deity Selection', 'Back to Deities']) elif 'kaylynne' in deity: text = copyreader.read_file("%s/deities/kaylynne_desc.txt" % copy_dir) deity_node = MenuNode("%s" % deity, text=text, links=['confirm-kaylynne', 'deity'], linktexts=['Confirm Deity Selection', 'Back to Deities']) nodes.append(deity_node) deity_node_text = copyreader.read_file("%s/deities/deities_desc.txt" % copy_dir) root_deity_node = MenuNode("deity", text=deity_node_text, links=['ankarith', 'slyth', 'green warden', 'kaylynne'], linktexts=['An\'Karith', 'Slyth of the Glade', 'The Green Warden', 'Kaylynne']) nodes.append(root_deity_node) elif 'gender' in option: confirm_male = MenuNode("confirm-gender-male", links=['alignment'], linktexts=['Choose the path you walk.'], code="self.caller.set_gender('male')") confirm_female = MenuNode("confirm-gender-female", links=['alignment'], linktexts=['Choose the path you walk.'], code="self.caller.set_gender('female')") nodes.append(confirm_male) nodes.append(confirm_female) text = """ --{rGender Selection{n-- Please select which gender you would like to be: """ gender_node = MenuNode("gender", text=text, links=['confirm-gender-male', 'confirm-gender-female'], linktexts=['Male', 'Female']) nodes.append(gender_node) elif 'alignment' in option: confirm_good = MenuNode("confirm-good", text="{rYou begin your journey down the path of light.{n", code="self.caller.set_alignment('good')") confirm_evil = MenuNode("confirm-evil", text="{rYou begin your journey down the path of darkness.{n", code="self.caller.set_alignment('evil')") nodes.append(confirm_good) nodes.append(confirm_evil) text = """ --{rAlignment Selection{n-- Which path to do you desire to walk? """ alignment_node = MenuNode("alignment", text=text, links=['confirm-evil', 'confirm-good', 'START'], linktexts=['Path of Darkness', 'Path of Light', 'Back to Customization']) nodes.append(alignment_node) start_node = MenuNode("START", text="{bWelcome to Avaloria. Please proceed through the menu to customize your character.{n", links=['race' ], linktexts=['Choose your race.']) nodes.append(start_node) node_string = ' '.join([node.key for node in nodes]) self.obj.msg("{mDEBUG: nodes: %s{n" % node_string) menutree = MenuTree(caller=self.obj, nodes=nodes) menutree.start()
def create_object(typeclass=None, key=None, location=None, home=None, permissions=None, locks=None, aliases=None, destination=None, report_to=None, nohome=False): """ Create a new in-game object. Any game object is a combination of a database object that stores data persistently to the database, and a typeclass, which on-the-fly 'decorates' the database object into whataver different type of object it is supposed to be in the game. See src.objects.managers for methods to manipulate existing objects in the database. src.objects.objects holds the base typeclasses and src.objects.models hold the database model. report_to is an optional object for reporting errors to in string form. If report_to is not set, errors will be raised as en Exception containing the error message. If set, this method will return None upon errors. nohome - this allows the creation of objects without a default home location; this only used when creating default location itself or during unittests """ global _Object, _ObjectDB if not _Object: from src.objects.objects import Object as _Object if not _ObjectDB: from src.objects.models import ObjectDB as _ObjectDB # input validation if not typeclass: typeclass = settings.BASE_OBJECT_TYPECLASS elif isinstance(typeclass, _ObjectDB): # this is already an objectdb instance, extract its typeclass typeclass = typeclass.typeclass.path elif isinstance(typeclass, _Object) or utils.inherits_from(typeclass, _Object): # this is already an object typeclass, extract its path typeclass = typeclass.path # handle eventual #dbref input location = handle_dbref(location, _ObjectDB) home = handle_dbref(home, _ObjectDB) destination = handle_dbref(destination, _ObjectDB) report_to = handle_dbref(report_to, _ObjectDB) # create new database object new_db_object = _ObjectDB() # assign the typeclass typeclass = utils.to_unicode(typeclass) new_db_object.typeclass_path = typeclass # the name/key is often set later in the typeclass. This # is set here as a failsafe. if key: new_db_object.key = key else: new_db_object.key = "#%i" % new_db_object.dbid # this will either load the typeclass or the default one new_object = new_db_object.typeclass if not _GA(new_object, "is_typeclass")(typeclass, exact=True): # this will fail if we gave a typeclass as input and it still # gave us a default SharedMemoryModel.delete(new_db_object) if report_to: _GA(report_to, "msg")("Error creating %s (%s):\n%s" % (new_db_object.key, typeclass, _GA(new_db_object, "typeclass_last_errmsg"))) return None else: raise Exception(_GA(new_db_object, "typeclass_last_errmsg")) # from now on we can use the typeclass object # as if it was the database object. new_object.destination = destination # call the hook method. This is where all at_creation # customization happens as the typeclass stores custom # things on its database object. new_object.basetype_setup() # setup the basics of Exits, Characters etc. new_object.at_object_creation() # custom-given perms/locks overwrite hooks if permissions: new_object.permissions.add(permissions) if locks: new_object.locks.add(locks) if aliases: new_object.aliases.add(aliases) if home: new_object.home = home else: # we shouldn't need to handle dbref here (home handler should fix it), but some have # reported issues here (issue 446). try: new_object.home = handle_dbref(settings.DEFAULT_HOME, _ObjectDB) if not nohome else None except _ObjectDB.DoesNotExist: raise _ObjectDB.DoesNotExist("settings.DEFAULT_HOME (= '%s') does not exist, or the setting is malformed." % settings.DEFAULT_HOME) # perform a move_to in order to display eventual messages. if location: new_object.move_to(location, quiet=True) else: # rooms would have location=None. new_object.location = None # post-hook setup (mainly used by Exits) new_object.basetype_posthook_setup() new_object.save() return new_object
class Mail(default_cmds.MuxCommand): """ Send and receive messages. To check your messages: mail To check message number 3, type: mail 3 To send a message to someone named Thaddius: mail Thaddius=Hello there, Thaddius! To delete message number 4, type: mail/delete 4 To delete all of your messages, type: mail/delete/all """ key = "mail" aliases = [] locks = "cmd:all()" help_category = "General" def list_mail(self): """ List mail to the calling user. """ mail = self.caller.db.mail MESSAGE = 0 TIMESTAMP = 1 READ = 2 try: messages = [ item for item in mail if item[TIMESTAMP] <= item[MESSAGE].date_sent ] # Let's clean up mail storage for this user while we're at it. self.caller.db.mail = messages except TypeError: messages = [] header = '--------Mailbox for %s' % self.caller.name self.caller.msg(header) count = 1 for message in messages: if message[READ]: read = '' else: read = '{w*' self.caller.msg('%s%s. From %s: %s{n' % (read, count, message[MESSAGE].senders[0], message[MESSAGE].header)) count += 1 self.caller.msg('-' * len(header)) def mail_check(self): messages = self.caller.db.mail if not messages: if not self.args.lower() == 'quiet': self.caller.msg(ALERT % "You have no new messages.") return count = 0 READ = 2 for message in messages: if not message[READ]: count += 1 if not count and not self.args.lower() == 'quiet': self.caller.msg(ALERT % "You have no new messages.") else: self.caller.msg( ALERT % "You have %s new message(s). Check them with: mail" % count) def display_mail(self, message): """ Display a mail message. """ senders = ', '.join([ sender.name for sender in message.senders if utils.inherits_from( sender.typeclass, settings.BASE_CHARACTER_TYPECLASS) ]) receivers = ', '.join([ receiver.name for receiver in message.receivers if utils.inherits_from( receiver.typeclass, settings.BASE_CHARACTER_TYPECLASS) ]) self.caller.msg('--------Mail from %s to %s.' % (senders, receivers)) self.caller.msg('Sent on: %s' % message.date_sent) self.caller.msg('Subject: %s\n' % message.header) self.caller.msg(message.message) self.caller.msg('\nDone.') def delete_handler(self): """ Delete a specified message. """ MESSAGE = 0 TIMESTAMP = 1 if 'all' in self.switches: try: messages = [ item for item in self.caller.db.mail if item[TIMESTAMP] <= item[MESSAGE].date_sent ] for message in messages: message[MESSAGE].delete() except TypeError, AttributeError: pass self.caller.db.mail = [] self.caller.msg(ALERT % "All mail deleted.") return try: choice = int(self.args) - 1 except ValueError: self.caller.msg("'%s' is not a valid message number." % self.args) return try: message = self.caller.mail[choice][MESSAGE] except (TypeError, IndexError): self.caller.msg("The message number %s does not exist." % self.args) return self.caller.msg( 'Deleted message from %s to %s entitled "%s".' % (', '.join([ target.name for target in message.senders if utils.inherits_from( target.typeclass, settings.BASE_CHARACTER_TYPECLASS) ]), ', '.join([ target.name for target in message.receivers if utils.inherits_from( target.typeclass, settings.BASE_CHARACTER_TYPECLASS) ]), message.header)) Mail(self.caller.mail[choice]).delete()