diff --git a/contrib/README b/contrib/README index 57bed43196..5983b6111f 100644 --- a/contrib/README +++ b/contrib/README @@ -47,7 +47,3 @@ things you want from here into game/gamesrc and change them there. Evennia's ooc mode. Works well with the menu login contrib and is intended as a starting point for building a more full-featured character creation system. - -* Evlang (Griatch 2012) - A heavily restricted version of Python for use - as a "softcode" language by Players in-game. Contains a complete - system with examples of objects and commands for coding. diff --git a/src/commands/default/building.py b/src/commands/default/building.py index 837864ffff..0bcda6900a 100644 --- a/src/commands/default/building.py +++ b/src/commands/default/building.py @@ -1353,6 +1353,7 @@ class CmdTypeclass(MuxCommand): @typclass[/switch] [= ] @type '' @parent '' + @swap - this is a shorthand for using /force/reset flags. Switch: reset - clean out *all* the attributes on the object - @@ -1407,6 +1408,10 @@ class CmdTypeclass(MuxCommand): caller.msg(string) return + if self.cmdstring == "@swap": + self.switches.append("force") + self.switches.append("reset") + # we have an =, a typeclass was supplied. typeclass = self.rhs @@ -1414,7 +1419,7 @@ class CmdTypeclass(MuxCommand): caller.msg("You are not allowed to do that.") return - if not hasattr(obj, 'swap_typeclass') or not hasattr(obj, 'typeclass'): + if not hasattr(obj, 'swap_typeclass'): caller.msg("This object cannot have a type at all!") return @@ -1424,25 +1429,23 @@ class CmdTypeclass(MuxCommand): else: reset = "reset" in self.switches old_typeclass_path = obj.typeclass_path - ok = obj.swap_typeclass(typeclass, clean_attributes=reset) - if ok: - if is_same: - string = "%s updated its existing typeclass (%s).\n" % (obj.name, obj.path) - else: - string = "%s changed typeclass from %s to %s.\n" % (obj.name, - old_typeclass_path, - obj.typeclass_path) - string += "Creation hooks were run." - if reset: - string += " All old attributes where deleted before the swap." - else: - string += " Note that the typeclassed object could have ended up with a mixture of old" - string += "\nand new attributes. Use /reset to remove old attributes if you don't want this." + + # we let this raise exception if needed + obj.swap_typeclass(typeclass, clean_attributes=reset) + + if is_same: + string = "%s updated its existing typeclass (%s).\n" % (obj.name, obj.path) else: - string = obj.typeclass_last_errmsg - string += "\nCould not swap '%s' (%s) to typeclass '%s'." % (obj.name, - old_typeclass_path, - typeclass) + string = "%s changed typeclass from %s to %s.\n" % (obj.name, + old_typeclass_path, + obj.typeclass_path) + string += "Creation hooks were run." + if reset: + string += " All old attributes where deleted before the swap." + else: + string += " Note that the typeclassed object could have ended up with a mixture of old" + string += "\nand new attributes. Use /reset to remove old attributes if you don't want this." + caller.msg(string) diff --git a/src/commands/default/muxcommand.py b/src/commands/default/muxcommand.py index 965189d2a9..b41a6d1d17 100644 --- a/src/commands/default/muxcommand.py +++ b/src/commands/default/muxcommand.py @@ -183,11 +183,11 @@ class MuxPlayerCommand(MuxCommand): """ super(MuxPlayerCommand, self).parse() - if utils.inherits_from(self.caller, "src.objects.objects.Object"): + if utils.inherits_from(self.caller, "src.objects.objects.DefaultObject"): # caller is an Object/Character self.character = self.caller self.caller = self.caller.player - elif utils.inherits_from(self.caller, "src.players.players.Player"): + elif utils.inherits_from(self.caller, "src.players.players.DefaultPlayer"): # caller was already a Player self.character = self.caller.get_puppet(self.sessid) else: diff --git a/src/commands/default/tests.py b/src/commands/default/tests.py index 75336cdf01..c22d2418f8 100644 --- a/src/commands/default/tests.py +++ b/src/commands/default/tests.py @@ -159,7 +159,7 @@ class TestGeneral(CommandTest): self.call(general.CmdLook(), "here", "Room1\n room_desc") self.call(general.CmdHome(), "", "You are already home") self.call(general.CmdInventory(), "", "You are not carrying anything.") - self.call(general.CmdPose(), "looks around", "Char1 looks around") + self.call(general.CmdPose(), "looks around", "") # TODO-check this self.call(general.CmdHome(), "", "You are already home") self.call(general.CmdNick(), "testalias = testaliasedstring1", "Nick set:") self.call(general.CmdNick(), "/player testalias = testaliasedstring2", "Nick set:") @@ -251,8 +251,8 @@ class TestBuilding(CommandTest): self.call(building.CmdUnLink(), "TestExit1", "Former exit TestExit1 no longer links anywhere.") self.call(building.CmdSetHome(), "Obj6 = Room6b", "Obj6's home location was changed from Room6") self.call(building.CmdListCmdSets(), "", ":") - self.call(building.CmdTypeclass(), "Obj6 = src.objects.objects.Exit", - "Obj6 changed typeclass from src.commands.default.tests.TestObjectClass to src.objects.objects.Exit") + self.call(building.CmdTypeclass(), "Obj6 = src.objects.objects.DefaultExit", + "Obj6 changed typeclass from src.commands.default.tests.TestObjectClass to src.objects.objects.DefaultExit") self.call(building.CmdLock(), "Obj6 = test:perm(Immortals)", "Added lock 'test:perm(Immortals)' to Obj6.") self.call(building.CmdFind(), "TestRoom1", "One Match") self.call(building.CmdScript(), "Obj6 = src.scripts.scripts.Script", "Script src.scripts.scripts.Script successfully added") @@ -271,11 +271,11 @@ class TestComms(CommandTest): self.call(comms.CmdAllCom(), "", "Available channels (use comlist,addcom and delcom to manage") self.call(comms.CmdClock(), "testchan=send:all()", "Lock(s) applied. Current locks on testchan:") self.call(comms.CmdCdesc(), "testchan = Test Channel", "Description of channel 'testchan' set to 'Test Channel'.") - self.call(comms.CmdCemit(), "testchan = Test Message", "[testchan] Test Message|Sent to channel testchan: Test Message") + self.call(comms.CmdCemit(), "testchan = Test Message", "Sent to channel testchan: Test Message") self.call(comms.CmdCWho(), "testchan", "Channel subscriptions\ntestchan:\n TestPlayer7") self.call(comms.CmdPage(), "TestPlayer7b = Test", "TestPlayer7b is offline. They will see your message if they list their pages later.|You paged TestPlayer7b with: 'Test'.") self.call(comms.CmdCBoot(), "", "Usage: @cboot[/quiet] = [:reason]") # noone else connected to boot - self.call(comms.CmdCdestroy(), "testchan" ,"[testchan] TestPlayer7: testchan is being destroyed. Make sure to change your aliases.|Channel 'testchan' was destroyed.") + self.call(comms.CmdCdestroy(), "testchan" ,"Channel 'testchan' was destroyed.") from src.commands.default import batchprocess diff --git a/src/comms/comms.py b/src/comms/comms.py index f6e7da869d..1b59fdba9f 100644 --- a/src/comms/comms.py +++ b/src/comms/comms.py @@ -257,7 +257,6 @@ class Channel(ChannelDB): """ # get all players connected to this channel and send to them for player in self.db_subscriptions.all(): - player = player try: # note our addition of the from_channel keyword here. This could be checked # by a custom player.msg() to treat channel-receives differently. diff --git a/src/comms/managers.py b/src/comms/managers.py index fe00a81854..b4dd8a3741 100644 --- a/src/comms/managers.py +++ b/src/comms/managers.py @@ -53,25 +53,20 @@ def identify_object(inp): from src.objects.models import ObjectDB as _ObjectDB if not _ChannelDB: from src.comms.models import ChannelDB as _ChannelDB + if not inp: return inp, None - # try to identify the type - try: - obj = _GA(inp, "dbobj") # this works for all typeclassed entities - except AttributeError: - obj = inp - typ = type(obj) - if typ == _PlayerDB: - return obj, "player" - elif typ == _ObjectDB: - return obj, "object" - elif typ == _ChannelDB: - return obj, "channel" - elif dbref(obj): - return dbref(obj), "dbref" - elif typ == basestring: - return obj, "string" - return obj, None # Something else + if isinstance(inp, basestring): + return inp, "string" + elif inp.is_typeclass(_PlayerDB, exact=False): + return inp, "player" + elif inp.is_typeclass(_ObjectDB, exact=False): + return inp, "object" + elif inp.is_typeclass(_ChannelDB, exact=False): + return inp, "channel" + elif dbref(inp): + return dbref(inp), "dbref" + return inp, None # something else def to_object(inp, objtype='player'): @@ -300,7 +295,7 @@ class ChannelDBManager(TypedObjectManager): """ Return all channels a given player is subscribed to """ - return player.player.subscription_set.all() + return player.subscription_set.all() @returns_typeclass_list def channel_search(self, ostring, exact=True): diff --git a/src/objects/objects.py b/src/objects/objects.py index 60bdd6b943..651256adcd 100644 --- a/src/objects/objects.py +++ b/src/objects/objects.py @@ -279,11 +279,11 @@ class DefaultObject(ObjectDB): """ return any(self.sessions) - #@property - #def is_superuser(self): - # "Check if user has a player, and if so, if it is a superuser." - # return self.db_player and self.db_player.is_superuser \ - # and not self.db_player.attributes.get("_quell") + @property + def is_superuser(self): + "Check if user has a player, and if so, if it is a superuser." + return self.db_player and self.db_player.is_superuser \ + and not self.db_player.attributes.get("_quell") def contents_get(self, exclude=None): """ diff --git a/src/tests/test_scripts_models.py b/src/tests/test_scripts_models.py index 43f7ca27a9..75b500dc01 100644 --- a/src/tests/test_scripts_models.py +++ b/src/tests/test_scripts_models.py @@ -1,9 +1,5 @@ -try: - # this is an optimized version only available in later Django versions - from django.utils.unittest import TestCase -except ImportError: - # if the first fails, we use the old version - from django.test import TestCase +# this is an optimized version only available in later Django versions +from django.utils.unittest import TestCase from src.scripts.models import ScriptDB, ObjectDoesNotExist from src.utils.create import create_script diff --git a/src/typeclasses/models.py b/src/typeclasses/models.py index 8f2ebe23a8..b092dd2ce0 100644 --- a/src/typeclasses/models.py +++ b/src/typeclasses/models.py @@ -299,6 +299,30 @@ class TypedObject(SharedMemoryModel): # Object manipulation methods # + def is_typeclass(self, typeclass, exact=True): + """ + Returns true if this object has this type OR has a typeclass + which is an subclass of the given typeclass. This operates on + the actually loaded typeclass (this is important since a + failing typeclass may instead have its default currently + loaded) typeclass - can be a class object or the python path + to such an object to match against. + + typeclass - a class or the full python path to the class + exact - returns true only + if the object's type is exactly this typeclass, ignoring + parents. + """ + if not isinstance(typeclass, basestring): + typeclass = typeclass.path + + if exact: + return typeclass == self.path + else: + # check parent chain + selfpath = self.path + return any(cls for cls in self.__class__.mro() if cls.path == selfpath) + def swap_typeclass(self, new_typeclass, clean_attributes=False, run_start_hooks=True, no_default=True): """