2010-08-29 18:46:58 +00:00
|
|
|
"""
|
2012-03-30 23:47:22 +02:00
|
|
|
This is the basis of the typeclass system.
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
The idea is have the object as a normal class with the
|
|
|
|
|
database-connection tied to itself through a property.
|
|
|
|
|
|
|
|
|
|
The instances of all the different object types are all tied to their
|
|
|
|
|
own database object stored in the 'dbobj' property. All attribute
|
|
|
|
|
get/set operations are channeled transparently to the database object
|
|
|
|
|
as desired. You should normally never have to worry about the database
|
|
|
|
|
abstraction, just do everything on the TypeClass object.
|
|
|
|
|
|
|
|
|
|
That an object is controlled by a player/user is just defined by its
|
|
|
|
|
'user' property being set. This means a user may switch which object
|
|
|
|
|
they control by simply linking to a new object's user property.
|
|
|
|
|
"""
|
2010-09-04 09:47:38 +00:00
|
|
|
|
2012-10-14 19:29:56 +02:00
|
|
|
from django.conf import settings
|
2010-08-29 18:46:58 +00:00
|
|
|
from src.typeclasses.typeclass import TypeClass
|
2011-04-30 21:09:19 +00:00
|
|
|
from src.commands import cmdset, command
|
2013-01-09 19:43:46 +01:00
|
|
|
|
2012-03-31 15:09:22 +02:00
|
|
|
__all__ = ("Object", "Character", "Room", "Exit")
|
2010-08-29 18:46:58 +00:00
|
|
|
|
2012-08-02 17:03:26 +02:00
|
|
|
_GA = object.__getattribute__
|
|
|
|
|
_SA = object.__setattr__
|
|
|
|
|
_DA = object.__delattr__
|
|
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
#
|
2012-03-30 23:47:22 +02:00
|
|
|
# Base class to inherit from.
|
2010-08-29 18:46:58 +00:00
|
|
|
#
|
|
|
|
|
|
|
|
|
|
class Object(TypeClass):
|
|
|
|
|
"""
|
2012-03-31 15:09:22 +02:00
|
|
|
This is the base class for all in-game objects. Inherit from this
|
|
|
|
|
to create different types of objects in the game.
|
2012-03-30 23:47:22 +02:00
|
|
|
"""
|
2012-03-31 15:09:22 +02:00
|
|
|
# __init__ is only defined here in order to present docstring to API.
|
2012-03-24 23:02:45 +01:00
|
|
|
def __init__(self, dbobj):
|
|
|
|
|
"""
|
2013-06-30 14:13:01 +02:00
|
|
|
This is the root typeclass object, representing all entities
|
|
|
|
|
that have an actual presence in-game. Objects generally have a
|
|
|
|
|
location. They can also be manipulated and looked at. Most
|
|
|
|
|
game entities you define should inherit from Object at some distance.
|
|
|
|
|
Evennia defines some important subclasses of Object by default, namely
|
|
|
|
|
Characters, Exits and Rooms (see the bottom of this module).
|
|
|
|
|
|
|
|
|
|
Note that all new Objects and their subclasses *must* always be
|
2012-05-02 00:39:56 +02:00
|
|
|
created using the ev.create_object() function. This is so the
|
|
|
|
|
typeclass system can be correctly initiated behind the scenes.
|
2012-03-24 23:02:45 +01:00
|
|
|
|
|
|
|
|
|
2012-03-30 23:47:22 +02:00
|
|
|
Object Typeclass API:
|
2012-03-24 23:02:45 +01:00
|
|
|
|
2012-05-02 00:39:56 +02:00
|
|
|
* Available properties (only available on *initiated* typeclass objects)
|
2012-03-24 23:02:45 +01:00
|
|
|
|
2012-03-30 23:47:22 +02:00
|
|
|
key (string) - name of object
|
2013-06-30 14:13:01 +02:00
|
|
|
name (string) - same as key
|
2012-03-24 23:02:45 +01:00
|
|
|
aliases (list of strings) - aliases to the object. Will be saved to database as AliasDB entries but returned as strings.
|
|
|
|
|
dbref (int, read-only) - unique #id-number. Also "id" can be used.
|
|
|
|
|
dbobj (Object, read-only) - link to database model. dbobj.typeclass points back to this class
|
|
|
|
|
typeclass (Object, read-only) - this links back to this class as an identified only. Use self.swap_typeclass() to switch.
|
|
|
|
|
date_created (string) - time stamp of object creation
|
2012-03-30 23:47:22 +02:00
|
|
|
permissions (list of strings) - list of permission strings
|
2012-03-24 23:02:45 +01:00
|
|
|
|
2013-04-09 22:22:17 +02:00
|
|
|
player (Player) - controlling player (if any, only set together with sessid below)
|
|
|
|
|
sessid (int, read-only) - session id (if any, only set together with player above)
|
2012-03-24 23:02:45 +01:00
|
|
|
location (Object) - current location. Is None if this is a room
|
|
|
|
|
home (Object) - safety start-location
|
|
|
|
|
sessions (list of Sessions, read-only) - returns all sessions connected to this object
|
|
|
|
|
has_player (bool, read-only)- will only return *connected* players
|
|
|
|
|
contents (list of Objects, read-only) - returns all objects inside this object (including exits)
|
|
|
|
|
exits (list of Objects, read-only) - returns all exits from this object, if any
|
2012-03-30 23:47:22 +02:00
|
|
|
destination (Object) - only set if this object is an exit.
|
2012-03-24 23:02:45 +01:00
|
|
|
is_superuser (bool, read-only) - True/False if this user is a superuser
|
|
|
|
|
|
2012-03-30 23:47:22 +02:00
|
|
|
* Handlers available
|
2012-03-24 23:02:45 +01:00
|
|
|
|
|
|
|
|
locks - lock-handler: use locks.add() to add new lock strings
|
|
|
|
|
db - attribute-handler: store/retrieve database attributes on this self.db.myattr=val, val=self.db.myattr
|
2012-03-30 23:47:22 +02:00
|
|
|
ndb - non-persistent attribute handler: same as db but does not create a database entry when storing data
|
2012-03-24 23:02:45 +01:00
|
|
|
scripts - script-handler. Add new scripts to object with scripts.add()
|
|
|
|
|
cmdset - cmdset-handler. Use cmdset.add() to add new cmdsets to object
|
|
|
|
|
nicks - nick-handler. New nicks with nicks.add().
|
|
|
|
|
|
2012-03-30 23:47:22 +02:00
|
|
|
* Helper methods (see src.objects.objects.py for full headers)
|
2012-03-24 23:02:45 +01:00
|
|
|
|
2012-12-08 14:09:42 +01:00
|
|
|
search(ostring, global_search=False, global_dbref=False, attribute_name=None,
|
|
|
|
|
use_nicks=False, location=None, ignore_errors=False, player=False)
|
2012-03-24 23:02:45 +01:00
|
|
|
execute_cmd(raw_string)
|
|
|
|
|
msg(message, from_obj=None, data=None)
|
|
|
|
|
msg_contents(message, exclude=None, from_obj=None, data=None)
|
2012-10-23 22:31:51 +02:00
|
|
|
move_to(destination, quiet=False, emit_to_obj=None, use_destination=True, to_none=False)
|
2012-03-24 23:02:45 +01:00
|
|
|
copy(new_key=None)
|
|
|
|
|
delete()
|
|
|
|
|
is_typeclass(typeclass, exact=False)
|
|
|
|
|
swap_typeclass(new_typeclass, clean_attributes=False, no_default=True)
|
|
|
|
|
access(accessing_obj, access_type='read', default=False)
|
|
|
|
|
check_permstring(permstring)
|
|
|
|
|
|
|
|
|
|
* Hook methods
|
|
|
|
|
|
|
|
|
|
basetype_setup() - only called once, used for behind-the-scenes setup. Normally not modified.
|
|
|
|
|
basetype_posthook_setup() - customization in basetype, after the object has been created; Normally not modified.
|
|
|
|
|
|
2012-03-30 23:47:22 +02:00
|
|
|
at_object_creation() - only called once, when object is first created. Object customizations go here.
|
2012-03-24 23:02:45 +01:00
|
|
|
at_object_delete() - called just before deleting an object. If returning False, deletion is aborted. Note that all objects
|
2012-03-30 23:47:22 +02:00
|
|
|
inside a deleted object are automatically moved to their <home>, they don't need to be removed here.
|
2012-03-24 23:02:45 +01:00
|
|
|
|
2012-03-30 23:47:22 +02:00
|
|
|
at_init() - called whenever typeclass is cached from memory, at least once every server restart/reload
|
2013-04-06 21:36:52 +02:00
|
|
|
at_cmdset_get() - this is called just before the command handler requests a cmdset from this objecth
|
|
|
|
|
at_pre_puppet(player)- (player-controlled objects only) called just before puppeting
|
|
|
|
|
at_post_puppet() - (player-controlled objects only) called just after completing connection player<->object
|
|
|
|
|
at_pre_unpuppet() - (player-controlled objects only) called just before un-puppeting
|
|
|
|
|
at_post_unpuppet(player) - (player-controlled objects only) called just after disconnecting player<->object link
|
2012-03-24 23:02:45 +01:00
|
|
|
at_server_reload() - called before server is reloaded
|
|
|
|
|
at_server_shutdown() - called just before server is fully shut down
|
|
|
|
|
|
|
|
|
|
at_before_move(destination) - called just before moving object to the destination. If returns False, move is cancelled.
|
|
|
|
|
announce_move_from(destination) - called in old location, just before move, if obj.move_to() has quiet=False
|
|
|
|
|
announce_move_to(source_location) - called in new location, just after move, if obj.move_to() has quiet=False
|
|
|
|
|
at_after_move(source_location) - always called after a move has been successfully performed.
|
|
|
|
|
at_object_leave(obj, target_location) - called when an object leaves this object in any fashion
|
|
|
|
|
at_object_receive(obj, source_location) - called when this object receives another object
|
|
|
|
|
|
|
|
|
|
at_before_traverse(traversing_object) - (exit-objects only) called just before an object traverses this object
|
2012-03-30 23:47:22 +02:00
|
|
|
at_after_traverse(traversing_object, source_location) - (exit-objects only) called just after a traversal has happened.
|
2012-03-24 23:02:45 +01:00
|
|
|
at_failed_traverse(traversing_object) - (exit-objects only) called if traversal fails and property err_traverse is not defined.
|
|
|
|
|
|
2012-03-30 23:47:22 +02:00
|
|
|
at_msg_receive(self, msg, from_obj=None, data=None) - called when a message (via self.msg()) is sent to this obj.
|
2012-03-24 23:02:45 +01:00
|
|
|
If returns false, aborts send.
|
2012-03-30 23:47:22 +02:00
|
|
|
at_msg_send(self, msg, to_obj=None, data=None) - called when this objects sends a message to someone via self.msg().
|
2012-03-24 23:02:45 +01:00
|
|
|
|
|
|
|
|
return_appearance(looker) - describes this object. Used by "look" command by default
|
2012-03-30 23:47:22 +02:00
|
|
|
at_desc(looker=None) - called by 'look' whenever the appearance is requested.
|
2012-03-24 23:02:45 +01:00
|
|
|
at_get(getter) - called after object has been picked up. Does not stop pickup.
|
|
|
|
|
at_drop(dropper) - called when this object has been dropped.
|
|
|
|
|
at_say(speaker, message) - by default, called if an object inside this object speaks
|
2012-03-30 23:47:22 +02:00
|
|
|
|
2012-03-24 23:02:45 +01:00
|
|
|
"""
|
|
|
|
|
super(Object, self).__init__(dbobj)
|
|
|
|
|
|
2012-03-24 18:25:32 +01:00
|
|
|
## methods inherited from the database object (overload them here)
|
|
|
|
|
|
|
|
|
|
def search(self, ostring,
|
|
|
|
|
global_search=False,
|
2012-03-30 23:47:22 +02:00
|
|
|
use_nicks=False,
|
2013-05-11 23:22:02 +02:00
|
|
|
typeclass=None,
|
2012-03-24 18:25:32 +01:00
|
|
|
location=None,
|
2013-05-11 23:22:02 +02:00
|
|
|
attribute_name=None,
|
|
|
|
|
quiet=False,
|
|
|
|
|
exact=False):
|
2012-03-24 18:25:32 +01:00
|
|
|
"""
|
2013-05-11 23:22:02 +02:00
|
|
|
Returns the typeclass of an Object matching a search string/condition
|
|
|
|
|
|
2012-03-24 18:25:32 +01:00
|
|
|
Perform a standard object search in the database, handling
|
2013-05-11 23:22:02 +02:00
|
|
|
multiple results and lack thereof gracefully. By default, only
|
|
|
|
|
objects in self's current location or inventory is searched.
|
|
|
|
|
Note: to find Players, use eg. ev.player_search.
|
|
|
|
|
|
|
|
|
|
Inputs:
|
|
|
|
|
|
|
|
|
|
ostring (str): Primary search criterion. Will be matched against object.key (with object.aliases second)
|
|
|
|
|
unless the keyword attribute_name specifies otherwise. Special strings:
|
|
|
|
|
#<num> - search by unique dbref. This is always a global search.
|
|
|
|
|
me,self - self-reference to this object
|
|
|
|
|
<num>-<string> - can be used to differentiate between multiple same-named matches
|
|
|
|
|
global_search (bool): Search all objects globally. This is overruled by "location" keyword.
|
|
|
|
|
use_nicks (bool): Use nickname-replace (nicktype "object") on the search string
|
|
|
|
|
typeclass (str or Typeclass): Limit search only to Objects with this typeclass. May be a list of typeclasses
|
|
|
|
|
for a broader search.
|
|
|
|
|
location (Object): Specify a location to search, if different from the self's given location
|
|
|
|
|
plus its contents. This can also be a list of locations.
|
|
|
|
|
attribute_name (str): Use this named Attribute to match ostring against, instead of object.key.
|
|
|
|
|
quiet (bool) - don't display default error messages - return multiple matches as a list and
|
|
|
|
|
no matches as None. If not set (default), will echo error messages and return None.
|
|
|
|
|
exact (bool) - if unset (default) - prefers to match to beginning of string rather than not matching
|
|
|
|
|
at all. If set, requires exact mathing of entire string.
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
|
|
|
|
quiet=False (default):
|
|
|
|
|
no match or multimatch:
|
|
|
|
|
auto-echoes errors to self.msg, then returns None
|
|
|
|
|
(results are handled by modules set by settings.SEARCH_AT_RESULT
|
|
|
|
|
and settings.SEARCH_AT_MULTIMATCH_INPUT)
|
|
|
|
|
match:
|
|
|
|
|
a unique object match
|
|
|
|
|
quiet=True:
|
|
|
|
|
no match or multimatch:
|
|
|
|
|
returns None or list of multi-matches
|
|
|
|
|
match:
|
|
|
|
|
a unique object match
|
|
|
|
|
|
2012-03-24 18:25:32 +01:00
|
|
|
"""
|
2012-03-30 23:47:22 +02:00
|
|
|
return self.dbobj.search(ostring,
|
2013-05-11 23:22:02 +02:00
|
|
|
global_search=global_search,
|
|
|
|
|
use_nicks=use_nicks,
|
|
|
|
|
typeclass=typeclass,
|
|
|
|
|
location=location,
|
|
|
|
|
attribute_name=attribute_name,
|
|
|
|
|
quiet=quiet,
|
|
|
|
|
exact=quiet)
|
2012-03-30 23:47:22 +02:00
|
|
|
|
2013-02-03 17:00:46 +01:00
|
|
|
def execute_cmd(self, raw_string, sessid=None):
|
2012-03-24 18:25:32 +01:00
|
|
|
"""
|
|
|
|
|
Do something as this object. This command transparently
|
|
|
|
|
lets its typeclass execute the command. Evennia also calls
|
|
|
|
|
this method whenever the player sends a command on the command line.
|
|
|
|
|
|
2012-03-30 23:47:22 +02:00
|
|
|
Argument:
|
2012-03-24 18:25:32 +01:00
|
|
|
raw_string (string) - raw command input
|
2013-02-03 17:00:46 +01:00
|
|
|
sessid (int) - id of session executing the command. This sets the sessid property on the command.
|
2012-03-24 18:25:32 +01:00
|
|
|
|
|
|
|
|
Returns Deferred - this is an asynchronous Twisted object that will
|
|
|
|
|
not fire until the command has actually finished executing. To overload
|
2012-03-30 23:47:22 +02:00
|
|
|
this one needs to attach callback functions to it, with addCallback(function).
|
2012-03-24 18:25:32 +01:00
|
|
|
This function will be called with an eventual return value from the command
|
2012-03-30 23:47:22 +02:00
|
|
|
execution.
|
2012-03-24 18:25:32 +01:00
|
|
|
|
|
|
|
|
This return is not used at all by Evennia by default, but might be useful
|
2012-03-30 23:47:22 +02:00
|
|
|
for coders intending to implement some sort of nested command structure.
|
|
|
|
|
"""
|
2013-02-03 17:00:46 +01:00
|
|
|
return self.dbobj.execute_cmd(raw_string, sessid=sessid)
|
2012-03-24 18:25:32 +01:00
|
|
|
|
2013-02-17 20:21:23 +01:00
|
|
|
def msg(self, message, from_obj=None, data=None, sessid=0):
|
2012-03-24 18:25:32 +01:00
|
|
|
"""
|
|
|
|
|
Emits something to any sessions attached to the object.
|
2012-03-30 23:47:22 +02:00
|
|
|
|
2012-03-24 18:25:32 +01:00
|
|
|
message (str): The message to send
|
|
|
|
|
from_obj (obj): object that is sending.
|
|
|
|
|
data (object): an optional data object that may or may not
|
2012-03-30 23:47:22 +02:00
|
|
|
be used by the protocol.
|
2013-02-17 20:21:23 +01:00
|
|
|
sessid: optional session target. If sessid=0, the session will
|
|
|
|
|
default to self.sessid or from_obj.sessid.
|
2012-03-24 18:25:32 +01:00
|
|
|
"""
|
2013-02-17 20:21:23 +01:00
|
|
|
self.dbobj.msg(message, from_obj=from_obj, data=data, sessid=0)
|
2012-03-24 18:25:32 +01:00
|
|
|
|
|
|
|
|
def msg_contents(self, message, exclude=None, from_obj=None, data=None):
|
|
|
|
|
"""
|
|
|
|
|
Emits something to all objects inside an object.
|
|
|
|
|
|
|
|
|
|
exclude is a list of objects not to send to. See self.msg() for more info.
|
|
|
|
|
"""
|
|
|
|
|
self.dbobj.msg_contents(message, exclude=exclude, from_obj=from_obj, data=data)
|
|
|
|
|
|
|
|
|
|
def move_to(self, destination, quiet=False,
|
2012-10-23 22:31:51 +02:00
|
|
|
emit_to_obj=None, use_destination=True, to_none=False):
|
2012-03-24 18:25:32 +01:00
|
|
|
"""
|
|
|
|
|
Moves this object to a new location. Note that if <destination> is an
|
|
|
|
|
exit object (i.e. it has "destination"!=None), the move_to will
|
|
|
|
|
happen to this destination and -not- into the exit object itself, unless
|
|
|
|
|
use_destination=False. Note that no lock checks are done by this function,
|
2012-03-30 23:47:22 +02:00
|
|
|
such things are assumed to have been handled before calling move_to.
|
|
|
|
|
|
2012-03-24 18:25:32 +01:00
|
|
|
destination: (Object) Reference to the object to move to. This
|
|
|
|
|
can also be an exit object, in which case the destination
|
2012-03-30 23:47:22 +02:00
|
|
|
property is used as destination.
|
2012-03-24 18:25:32 +01:00
|
|
|
quiet: (bool) If true, don't emit left/arrived messages.
|
|
|
|
|
emit_to_obj: (Object) object to receive error messages
|
|
|
|
|
use_destination (bool): Default is for objects to use the "destination" property
|
|
|
|
|
of destinations as the target to move to. Turning off this
|
2012-03-30 23:47:22 +02:00
|
|
|
keyword allows objects to move "inside" exit objects.
|
2012-10-23 22:31:51 +02:00
|
|
|
to_none - allow destination to be None. Note that no hooks are run when moving
|
|
|
|
|
to a None location. If you want to run hooks, run them manually.
|
2012-03-24 18:25:32 +01:00
|
|
|
Returns True/False depending on if there were problems with the move. This method
|
2012-03-30 23:47:22 +02:00
|
|
|
may also return various error messages to the emit_to_obj.
|
2012-03-24 18:25:32 +01:00
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
return self.dbobj.move_to(destination, quiet=quiet,
|
|
|
|
|
emit_to_obj=emit_to_obj, use_destination=use_destination)
|
2012-03-30 23:47:22 +02:00
|
|
|
|
2012-03-24 18:25:32 +01:00
|
|
|
def copy(self, new_key=None):
|
2012-03-30 23:47:22 +02:00
|
|
|
"""
|
2012-03-24 18:25:32 +01:00
|
|
|
Makes an identical copy of this object. If you want to customize the copy by
|
|
|
|
|
changing some settings, use ObjectDB.object.copy_object() directly.
|
|
|
|
|
|
|
|
|
|
new_key (string) - new key/name of copied object. If new_key is not specified, the copy will be named
|
2012-03-30 23:47:22 +02:00
|
|
|
<old_key>_copy by default.
|
|
|
|
|
Returns: Object (copy of this one)
|
2012-03-24 18:25:32 +01:00
|
|
|
"""
|
|
|
|
|
return self.dbobj.copy(new_key=new_key)
|
2012-03-30 23:47:22 +02:00
|
|
|
|
|
|
|
|
def delete(self):
|
2012-03-24 18:25:32 +01:00
|
|
|
"""
|
2012-03-30 23:47:22 +02:00
|
|
|
Deletes this object.
|
2012-03-24 18:25:32 +01:00
|
|
|
Before deletion, this method makes sure to move all contained
|
|
|
|
|
objects to their respective home locations, as well as clean
|
|
|
|
|
up all exits to/from the object.
|
|
|
|
|
|
|
|
|
|
Returns: boolean True if deletion succeded, False if there
|
|
|
|
|
were errors during deletion or deletion otherwise
|
2012-03-30 23:47:22 +02:00
|
|
|
failed.
|
2012-03-24 18:25:32 +01:00
|
|
|
"""
|
|
|
|
|
return self.dbobj.delete()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# methods inherited from the typeclass system
|
|
|
|
|
|
|
|
|
|
def is_typeclass(self, typeclass, exact=False):
|
|
|
|
|
"""
|
|
|
|
|
Returns true if this object has this type
|
|
|
|
|
OR has a typeclass which is an subclass of
|
|
|
|
|
the given typeclass.
|
2012-03-30 23:47:22 +02:00
|
|
|
|
2012-03-24 18:25:32 +01:00
|
|
|
typeclass - can be a class object or the
|
2012-03-30 23:47:22 +02:00
|
|
|
python path to such an object to match against.
|
|
|
|
|
|
2012-03-24 18:25:32 +01:00
|
|
|
exact - returns true only if the object's
|
|
|
|
|
type is exactly this typeclass, ignoring
|
|
|
|
|
parents.
|
|
|
|
|
|
2012-03-30 23:47:22 +02:00
|
|
|
Returns: Boolean
|
|
|
|
|
"""
|
2012-03-24 18:25:32 +01:00
|
|
|
return self.dbobj.is_typeclass(typeclass, exact=exact)
|
|
|
|
|
|
|
|
|
|
def swap_typeclass(self, new_typeclass, clean_attributes=False, no_default=True):
|
|
|
|
|
"""
|
|
|
|
|
This performs an in-situ swap of the typeclass. This means
|
|
|
|
|
that in-game, this object will suddenly be something else.
|
|
|
|
|
Player will not be affected. To 'move' a player to a different
|
2012-03-30 23:47:22 +02:00
|
|
|
object entirely (while retaining this object's type), use
|
2012-03-24 18:25:32 +01:00
|
|
|
self.player.swap_object().
|
|
|
|
|
|
2012-03-30 23:47:22 +02:00
|
|
|
Note that this might be an error prone operation if the
|
2012-03-24 18:25:32 +01:00
|
|
|
old/new typeclass was heavily customized - your code
|
2012-03-30 23:47:22 +02:00
|
|
|
might expect one and not the other, so be careful to
|
2012-03-24 18:25:32 +01:00
|
|
|
bug test your code if using this feature! Often its easiest
|
|
|
|
|
to create a new object and just swap the player over to
|
2012-03-30 23:47:22 +02:00
|
|
|
that one instead.
|
2012-03-24 18:25:32 +01:00
|
|
|
|
2012-03-30 23:47:22 +02:00
|
|
|
Arguments:
|
|
|
|
|
new_typeclass (path/classobj) - type to switch to
|
2012-03-24 18:25:32 +01:00
|
|
|
clean_attributes (bool/list) - will delete all attributes
|
|
|
|
|
stored on this object (but not any
|
|
|
|
|
of the database fields such as name or
|
|
|
|
|
location). You can't get attributes back,
|
|
|
|
|
but this is often the safest bet to make
|
|
|
|
|
sure nothing in the new typeclass clashes
|
|
|
|
|
with the old one. If you supply a list,
|
|
|
|
|
only those named attributes will be cleared.
|
|
|
|
|
no_default - if this is active, the swapper will not allow for
|
|
|
|
|
swapping to a default typeclass in case the given
|
|
|
|
|
one fails for some reason. Instead the old one
|
2012-03-30 23:47:22 +02:00
|
|
|
will be preserved.
|
|
|
|
|
Returns:
|
2012-03-24 18:25:32 +01:00
|
|
|
boolean True/False depending on if the swap worked or not.
|
2012-03-30 23:47:22 +02:00
|
|
|
|
2012-03-24 18:25:32 +01:00
|
|
|
|
|
|
|
|
"""
|
2012-04-21 16:15:37 +02:00
|
|
|
return self.dbobj.swap_typeclass(new_typeclass, clean_attributes=clean_attributes, no_default=no_default)
|
2012-03-24 18:25:32 +01:00
|
|
|
|
|
|
|
|
def access(self, accessing_obj, access_type='read', default=False):
|
|
|
|
|
"""
|
|
|
|
|
Determines if another object has permission to access this object in whatever way.
|
|
|
|
|
|
|
|
|
|
accessing_obj (Object)- object trying to access this one
|
|
|
|
|
access_type (string) - type of access sought
|
|
|
|
|
default (bool) - what to return if no lock of access_type was found
|
2012-10-28 14:07:18 +01:00
|
|
|
|
|
|
|
|
This function will call at_access_success or at_access_failure depending on the
|
|
|
|
|
outcome of the access check.
|
|
|
|
|
|
2012-03-30 23:47:22 +02:00
|
|
|
"""
|
2012-10-28 14:07:18 +01:00
|
|
|
if self.dbobj.access(accessing_obj, access_type=access_type, default=default):
|
|
|
|
|
self.at_access_success(accessing_obj, access_type)
|
|
|
|
|
return True
|
|
|
|
|
else:
|
|
|
|
|
self.at_access_failure(accessing_obj, access_type)
|
|
|
|
|
return False
|
2012-03-24 18:25:32 +01:00
|
|
|
|
|
|
|
|
def check_permstring(self, permstring):
|
|
|
|
|
"""
|
|
|
|
|
This explicitly checks the given string against this object's
|
|
|
|
|
'permissions' property without involving any locks.
|
2012-03-30 23:47:22 +02:00
|
|
|
|
2012-03-24 18:25:32 +01:00
|
|
|
permstring (string) - permission string that need to match a permission on the object.
|
|
|
|
|
(example: 'Builders')
|
|
|
|
|
"""
|
|
|
|
|
return self.dbobj.check_permstring(permstring)
|
|
|
|
|
|
|
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
def __eq__(self, other):
|
|
|
|
|
"""
|
2012-03-20 22:29:37 +01:00
|
|
|
Checks for equality against an id string or another object or user.
|
|
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
This has be located at this level, having it in the
|
|
|
|
|
parent doesn't work.
|
|
|
|
|
"""
|
2012-04-26 17:47:25 +02:00
|
|
|
try:
|
2012-12-08 17:11:22 +01:00
|
|
|
return _GA(_GA(self, "dbobj"),"dbid") == _GA(_GA(other,"dbobj"),"dbid")
|
2012-04-26 17:47:25 +02:00
|
|
|
except AttributeError:
|
|
|
|
|
# compare players instead
|
2012-03-20 22:29:37 +01:00
|
|
|
try:
|
2012-12-08 17:11:22 +01:00
|
|
|
return _GA(_GA(_GA(self, "dbobj"),"player"),"uid") == _GA(_GA(other, "player"),"uid")
|
2012-03-20 22:29:37 +01:00
|
|
|
except AttributeError:
|
2012-04-26 17:47:25 +02:00
|
|
|
return False
|
2010-08-29 18:46:58 +00:00
|
|
|
|
2012-03-24 18:25:32 +01:00
|
|
|
## hooks called by the game engine
|
|
|
|
|
|
2012-03-30 23:47:22 +02:00
|
|
|
|
2011-03-17 21:43:18 +00:00
|
|
|
def basetype_setup(self):
|
|
|
|
|
"""
|
|
|
|
|
This sets up the default properties of an Object,
|
|
|
|
|
just before the more general at_object_creation.
|
2011-04-23 11:54:08 +00:00
|
|
|
|
2012-10-20 09:33:40 +02:00
|
|
|
You normally don't need to change this unless you change some fundamental
|
|
|
|
|
things like names of permission groups.
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
2011-03-15 16:08:32 +00:00
|
|
|
# the default security setup fallback for a generic
|
|
|
|
|
# object. Overload in child for a custom setup. Also creation
|
2011-03-17 21:43:18 +00:00
|
|
|
# commands may set this (create an item and you should be its
|
|
|
|
|
# controller, for example)
|
|
|
|
|
|
2011-03-15 16:08:32 +00:00
|
|
|
dbref = self.dbobj.dbref
|
2012-09-17 15:31:50 +02:00
|
|
|
self.locks.add(";".join(["control:perm(Immortals)", # edit locks/permissions, delete
|
|
|
|
|
"examine:perm(Builders)", # examine properties
|
|
|
|
|
"view:all()", # look at object (visibility)
|
|
|
|
|
"edit:perm(Wizards)", # edit properties/attributes
|
|
|
|
|
"delete:perm(Wizards)", # delete object
|
|
|
|
|
"get:all()", # pick up object
|
|
|
|
|
"call:true()", # allow to call commands on this object
|
2013-05-12 19:53:19 +02:00
|
|
|
"tell:perm(Wizards)", # allow emits to this object
|
2012-09-17 15:31:50 +02:00
|
|
|
"puppet:id(%s) or perm(Immortals) or pperm(Immortals)" % dbref])) # restricts puppeting of this object
|
2011-03-17 21:43:18 +00:00
|
|
|
|
2011-08-11 21:16:35 +00:00
|
|
|
def basetype_posthook_setup(self):
|
|
|
|
|
"""
|
|
|
|
|
Called once, after basetype_setup and at_object_creation. This should generally not be overloaded unless
|
|
|
|
|
you are redefining how a room/exit/object works. It allows for basetype-like setup
|
|
|
|
|
after the object is created. An example of this is EXITs, who need to know keys, aliases, locks
|
|
|
|
|
etc to set up their exit-cmdsets.
|
|
|
|
|
"""
|
|
|
|
|
pass
|
|
|
|
|
|
2012-03-24 18:25:32 +01:00
|
|
|
def at_object_creation(self):
|
2011-09-03 10:22:19 +00:00
|
|
|
"""
|
2012-03-24 18:25:32 +01:00
|
|
|
Called once, when this object is first created.
|
2012-03-30 23:47:22 +02:00
|
|
|
"""
|
2011-09-03 10:22:19 +00:00
|
|
|
pass
|
|
|
|
|
|
2012-03-30 23:47:22 +02:00
|
|
|
|
2012-03-24 18:25:32 +01:00
|
|
|
def at_object_delete(self):
|
2011-09-03 10:22:19 +00:00
|
|
|
"""
|
2012-03-24 18:25:32 +01:00
|
|
|
Called just before the database object is
|
|
|
|
|
permanently delete()d from the database. If
|
2012-03-30 23:47:22 +02:00
|
|
|
this method returns False, deletion is aborted.
|
2011-09-03 10:22:19 +00:00
|
|
|
"""
|
2012-03-24 18:25:32 +01:00
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def at_init(self):
|
2012-03-30 23:47:22 +02:00
|
|
|
"""
|
2012-03-24 18:25:32 +01:00
|
|
|
This is always called whenever this object is initiated --
|
|
|
|
|
that is, whenever it its typeclass is cached from memory. This
|
|
|
|
|
happens on-demand first time the object is used or activated
|
|
|
|
|
in some way after being created but also after each server
|
|
|
|
|
restart or reload.
|
|
|
|
|
"""
|
2012-03-30 23:47:22 +02:00
|
|
|
pass
|
2011-09-03 10:22:19 +00:00
|
|
|
|
2011-08-11 21:16:35 +00:00
|
|
|
def at_cmdset_get(self):
|
|
|
|
|
"""
|
|
|
|
|
Called just before cmdsets on this object are requested by the
|
|
|
|
|
command handler. If changes need to be done on the fly to the cmdset
|
|
|
|
|
before passing them on to the cmdhandler, this is the place to do it.
|
|
|
|
|
This is called also if the object currently have no cmdsets.
|
|
|
|
|
"""
|
|
|
|
|
pass
|
|
|
|
|
|
2013-04-06 21:36:52 +02:00
|
|
|
def at_pre_puppet(self, player):
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
2013-04-06 21:36:52 +02:00
|
|
|
Called just before a Player connects to this object
|
|
|
|
|
to puppet it.
|
|
|
|
|
|
|
|
|
|
player - connecting player object
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
|
|
|
|
pass
|
2013-04-06 21:36:52 +02:00
|
|
|
|
|
|
|
|
def at_post_puppet(self):
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
2013-04-06 21:36:52 +02:00
|
|
|
Called just after puppeting has been completed and
|
|
|
|
|
all Player<->Object links have been established.
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
|
|
|
|
pass
|
2013-04-06 21:36:52 +02:00
|
|
|
|
|
|
|
|
def at_pre_unpuppet(self):
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
2013-04-06 21:36:52 +02:00
|
|
|
Called just before beginning to un-connect a puppeting
|
|
|
|
|
from this Player.
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
|
|
|
|
pass
|
|
|
|
|
|
2013-04-06 21:36:52 +02:00
|
|
|
def at_post_unpuppet(self, player):
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
2013-04-06 21:36:52 +02:00
|
|
|
Called just after the Player successfully disconnected
|
|
|
|
|
from this object, severing all connections.
|
|
|
|
|
|
|
|
|
|
player - the player object that just disconnected from
|
|
|
|
|
this object.
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
|
|
|
|
pass
|
|
|
|
|
|
2012-03-24 18:25:32 +01:00
|
|
|
def at_server_reload(self):
|
|
|
|
|
"""
|
2012-03-30 23:47:22 +02:00
|
|
|
This hook is called whenever the server is shutting down for restart/reboot.
|
2012-03-24 18:25:32 +01:00
|
|
|
If you want to, for example, save non-persistent properties across a restart,
|
2012-03-30 23:47:22 +02:00
|
|
|
this is the place to do it.
|
2012-03-24 18:25:32 +01:00
|
|
|
"""
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
def at_server_shutdown(self):
|
|
|
|
|
"""
|
2012-03-30 23:47:22 +02:00
|
|
|
This hook is called whenever the server is shutting down fully (i.e. not for
|
|
|
|
|
a restart).
|
2012-03-24 18:25:32 +01:00
|
|
|
"""
|
|
|
|
|
pass
|
|
|
|
|
|
2012-10-28 14:07:18 +01:00
|
|
|
def at_access_success(self, accessing_obj, access_type):
|
|
|
|
|
"""
|
|
|
|
|
This hook is called whenever accessing_obj succeed a lock check of type access_type
|
|
|
|
|
on this object, for whatever reason. The return value of this hook is not used,
|
|
|
|
|
the lock will still pass regardless of what this hook does (use lockstring/funcs to tweak
|
|
|
|
|
the lock result).
|
|
|
|
|
"""
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
def at_access_failure(self, accessing_obj, access_type):
|
|
|
|
|
"""
|
|
|
|
|
This hook is called whenever accessing_obj fails a lock check of type access_type
|
|
|
|
|
on this object, for whatever reason. The return value of this hook is not used, the
|
|
|
|
|
lock will still fail regardless of what this hook does (use lockstring/funcs to tweak the
|
|
|
|
|
lock result).
|
|
|
|
|
"""
|
|
|
|
|
pass
|
2012-03-24 18:25:32 +01:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
# hooks called when moving the object
|
|
|
|
|
|
|
|
|
|
def at_before_move(self, destination):
|
|
|
|
|
"""
|
|
|
|
|
Called just before starting to move
|
2012-03-30 23:47:22 +02:00
|
|
|
this object to destination.
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
destination - the object we are moving to
|
|
|
|
|
|
|
|
|
|
If this method returns False/None, the move
|
2012-03-30 23:47:22 +02:00
|
|
|
is cancelled before it is even started.
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
|
|
|
|
#return has_perm(self, destination, "can_move")
|
2012-03-30 23:47:22 +02:00
|
|
|
return True
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
def announce_move_from(self, destination):
|
|
|
|
|
"""
|
|
|
|
|
Called if the move is to be announced. This is
|
|
|
|
|
called while we are still standing in the old
|
2012-03-30 23:47:22 +02:00
|
|
|
location.
|
2010-08-29 18:46:58 +00:00
|
|
|
|
2012-03-30 23:47:22 +02:00
|
|
|
destination - the place we are going to.
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
|
|
|
|
if not self.location:
|
2012-03-30 23:47:22 +02:00
|
|
|
return
|
|
|
|
|
name = self.name
|
2010-08-29 18:46:58 +00:00
|
|
|
loc_name = ""
|
2012-03-30 23:47:22 +02:00
|
|
|
loc_name = self.location.name
|
2010-08-29 18:46:58 +00:00
|
|
|
dest_name = destination.name
|
|
|
|
|
string = "%s is leaving %s, heading for %s."
|
2011-04-08 23:10:04 +00:00
|
|
|
self.location.msg_contents(string % (name, loc_name, dest_name), exclude=self)
|
2012-03-30 23:47:22 +02:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
def announce_move_to(self, source_location):
|
|
|
|
|
"""
|
|
|
|
|
Called after the move if the move was not quiet. At this
|
2012-03-30 23:47:22 +02:00
|
|
|
point we are standing in the new location.
|
2010-08-29 18:46:58 +00:00
|
|
|
|
2012-03-30 23:47:22 +02:00
|
|
|
source_location - the place we came from
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
|
|
|
|
|
2012-03-30 23:47:22 +02:00
|
|
|
name = self.name
|
2010-08-29 18:46:58 +00:00
|
|
|
if not source_location and self.location.has_player:
|
|
|
|
|
# This was created from nowhere and added to a player's
|
|
|
|
|
# inventory; it's probably the result of a create command.
|
|
|
|
|
string = "You now have %s in your possession." % name
|
2011-04-08 23:10:04 +00:00
|
|
|
self.location.msg(string)
|
2012-03-30 23:47:22 +02:00
|
|
|
return
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
src_name = "nowhere"
|
|
|
|
|
loc_name = self.location.name
|
|
|
|
|
if source_location:
|
|
|
|
|
src_name = source_location.name
|
2012-03-30 23:47:22 +02:00
|
|
|
string = "%s arrives to %s from %s."
|
2011-04-08 23:10:04 +00:00
|
|
|
self.location.msg_contents(string % (name, loc_name, src_name), exclude=self)
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def at_after_move(self, source_location):
|
|
|
|
|
"""
|
2012-03-30 23:47:22 +02:00
|
|
|
Called after move has completed, regardless of quiet mode or not.
|
2010-08-29 18:46:58 +00:00
|
|
|
Allows changes to the object due to the location it is now in.
|
|
|
|
|
|
2012-03-30 23:47:22 +02:00
|
|
|
source_location - where we came from
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def at_object_leave(self, moved_obj, target_location):
|
|
|
|
|
"""
|
|
|
|
|
Called just before an object leaves from inside this object
|
|
|
|
|
|
|
|
|
|
moved_obj - the object leaving
|
|
|
|
|
target_location - where the object is going.
|
|
|
|
|
"""
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
def at_object_receive(self, moved_obj, source_location):
|
|
|
|
|
"""
|
2012-03-30 23:47:22 +02:00
|
|
|
Called after an object has been moved into this object.
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
moved_obj - the object moved into this one
|
2012-03-30 23:47:22 +02:00
|
|
|
source_location - where moved_object came from.
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
|
|
|
|
pass
|
2011-04-24 11:26:51 +00:00
|
|
|
|
|
|
|
|
def at_before_traverse(self, traversing_object):
|
|
|
|
|
"""
|
2012-03-30 23:47:22 +02:00
|
|
|
Called just before an object uses this object to
|
2011-04-24 11:26:51 +00:00
|
|
|
traverse to another object (i.e. this object is a type of Exit)
|
2012-03-30 23:47:22 +02:00
|
|
|
|
2011-04-24 11:26:51 +00:00
|
|
|
The target location should normally be available as self.destination.
|
|
|
|
|
"""
|
|
|
|
|
pass
|
|
|
|
|
|
2012-10-14 13:11:13 +02:00
|
|
|
def at_traverse(self, traversing_object, target_location):
|
|
|
|
|
"""
|
|
|
|
|
This hook is responsible for handling the actual traversal, normally
|
|
|
|
|
by calling traversing_object.move_to(target_location). It is normally
|
|
|
|
|
only implemented by Exit objects. If it returns False (usually because move_to
|
|
|
|
|
returned False), at_after_traverse below should not be called and
|
|
|
|
|
instead at_failed_traverse should be called.
|
|
|
|
|
"""
|
|
|
|
|
pass
|
|
|
|
|
|
2011-04-24 11:26:51 +00:00
|
|
|
def at_after_traverse(self, traversing_object, source_location):
|
|
|
|
|
"""
|
2012-03-30 23:47:22 +02:00
|
|
|
Called just after an object successfully used this object to
|
2011-04-24 11:26:51 +00:00
|
|
|
traverse to another object (i.e. this object is a type of Exit)
|
2012-03-30 23:47:22 +02:00
|
|
|
|
2011-04-24 11:26:51 +00:00
|
|
|
The target location should normally be available as self.destination.
|
|
|
|
|
"""
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
def at_failed_traverse(self, traversing_object):
|
|
|
|
|
"""
|
2012-03-30 23:47:22 +02:00
|
|
|
This is called if an object fails to traverse this object for some
|
2011-04-24 11:26:51 +00:00
|
|
|
reason. It will not be called if the attribute err_traverse is defined,
|
2012-03-30 23:47:22 +02:00
|
|
|
that attribute will then be echoed back instead.
|
2011-04-24 11:26:51 +00:00
|
|
|
"""
|
2012-03-30 23:47:22 +02:00
|
|
|
pass
|
2010-08-29 18:46:58 +00:00
|
|
|
|
2012-03-24 18:25:32 +01:00
|
|
|
def at_msg_receive(self, msg, from_obj=None, data=None):
|
|
|
|
|
"""
|
2012-03-30 23:47:22 +02:00
|
|
|
This hook is called whenever someone
|
2012-03-24 18:25:32 +01:00
|
|
|
sends a message to this object.
|
|
|
|
|
|
|
|
|
|
Note that from_obj may be None if the sender did
|
|
|
|
|
not include itself as an argument to the obj.msg()
|
2012-03-30 23:47:22 +02:00
|
|
|
call - so you have to check for this. .
|
|
|
|
|
|
2012-03-24 18:25:32 +01:00
|
|
|
Consider this a pre-processing method before
|
2012-03-30 23:47:22 +02:00
|
|
|
msg is passed on to the user sesssion. If this
|
|
|
|
|
method returns False, the msg will not be
|
2012-03-24 18:25:32 +01:00
|
|
|
passed on.
|
2012-10-28 14:07:18 +01:00
|
|
|
Input:
|
|
|
|
|
msg = the message received
|
|
|
|
|
from_obj = the one sending the message
|
|
|
|
|
Output:
|
|
|
|
|
boolean True/False
|
2012-03-24 18:25:32 +01:00
|
|
|
"""
|
2012-03-30 23:47:22 +02:00
|
|
|
return True
|
2012-03-24 18:25:32 +01:00
|
|
|
|
|
|
|
|
def at_msg_send(self, msg, to_obj=None, data=None):
|
|
|
|
|
"""
|
|
|
|
|
This is a hook that is called when /this/ object
|
|
|
|
|
sends a message to another object with obj.msg()
|
2012-03-30 23:47:22 +02:00
|
|
|
while also specifying that it is the one sending.
|
|
|
|
|
|
2012-03-24 18:25:32 +01:00
|
|
|
Note that this method is executed on the object
|
|
|
|
|
passed along with the msg() function (i.e. using
|
|
|
|
|
obj.msg(msg, caller) will then launch caller.at_msg())
|
2012-03-30 23:47:22 +02:00
|
|
|
and if no object was passed, it will never be called.
|
2012-03-24 18:25:32 +01:00
|
|
|
"""
|
|
|
|
|
pass
|
|
|
|
|
|
2012-03-30 23:47:22 +02:00
|
|
|
|
|
|
|
|
# hooks called by the default cmdset.
|
|
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
def return_appearance(self, pobject):
|
|
|
|
|
"""
|
|
|
|
|
This is a convenient hook for a 'look'
|
2012-03-30 23:47:22 +02:00
|
|
|
command to call.
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
|
|
|
|
if not pobject:
|
2012-03-30 23:47:22 +02:00
|
|
|
return
|
2012-09-20 00:47:28 +02:00
|
|
|
# get and identify all objects
|
|
|
|
|
visible = (con for con in self.contents if con != pobject and con.access(pobject, "view"))
|
|
|
|
|
exits, users, things = [], [], []
|
|
|
|
|
for con in visible:
|
|
|
|
|
key = con.key
|
|
|
|
|
if con.destination:
|
|
|
|
|
exits.append(key)
|
|
|
|
|
elif con.has_player:
|
|
|
|
|
users.append("{c%s{n" % key)
|
|
|
|
|
else:
|
|
|
|
|
things.append(key)
|
|
|
|
|
# get description, build string
|
|
|
|
|
string = "{c%s{n" % self.key
|
|
|
|
|
desc = self.db.desc
|
2010-08-29 18:46:58 +00:00
|
|
|
if desc:
|
2011-04-21 16:45:18 +00:00
|
|
|
string += "\n %s" % desc
|
2010-08-29 18:46:58 +00:00
|
|
|
if exits:
|
|
|
|
|
string += "\n{wExits:{n " + ", ".join(exits)
|
|
|
|
|
if users or things:
|
2012-09-20 00:47:28 +02:00
|
|
|
string += "\n{wYou see:{n " + ", ".join(users + things)
|
2010-08-29 18:46:58 +00:00
|
|
|
return string
|
|
|
|
|
|
|
|
|
|
def at_desc(self, looker=None):
|
|
|
|
|
"""
|
|
|
|
|
This is called whenever someone looks
|
|
|
|
|
at this object. Looker is the looking
|
2012-03-30 23:47:22 +02:00
|
|
|
object.
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
def at_get(self, getter):
|
|
|
|
|
"""
|
|
|
|
|
Called when this object has been picked up. Obs-
|
|
|
|
|
this method cannot stop the pickup - use permissions
|
|
|
|
|
for that!
|
|
|
|
|
|
|
|
|
|
getter - the object getting this object.
|
|
|
|
|
"""
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
def at_drop(self, dropper):
|
|
|
|
|
"""
|
|
|
|
|
Called when this object has been dropped.
|
|
|
|
|
|
|
|
|
|
dropper - the object which just dropped this object.
|
|
|
|
|
"""
|
|
|
|
|
pass
|
|
|
|
|
def at_say(self, speaker, message):
|
|
|
|
|
"""
|
|
|
|
|
Called on this object if an object inside this object speaks.
|
2012-03-30 23:47:22 +02:00
|
|
|
The string returned from this method is the final form
|
|
|
|
|
of the speech. Obs - you don't have to add things like
|
2010-08-29 18:46:58 +00:00
|
|
|
'you say: ' or similar, that is handled by the say command.
|
|
|
|
|
|
|
|
|
|
speaker - the object speaking
|
|
|
|
|
message - the words spoken.
|
|
|
|
|
"""
|
|
|
|
|
return message
|
|
|
|
|
|
|
|
|
|
#
|
2013-06-30 14:13:01 +02:00
|
|
|
# Base Character object
|
2010-08-29 18:46:58 +00:00
|
|
|
#
|
|
|
|
|
|
|
|
|
|
class Character(Object):
|
|
|
|
|
"""
|
|
|
|
|
This is just like the Object except it implements its own
|
|
|
|
|
version of the at_object_creation to set up the script
|
|
|
|
|
that adds the default cmdset to the object.
|
2012-03-30 23:47:22 +02:00
|
|
|
"""
|
2011-03-17 21:43:18 +00:00
|
|
|
|
|
|
|
|
def basetype_setup(self):
|
|
|
|
|
"""
|
|
|
|
|
Setup character-specific security
|
2011-04-23 11:54:08 +00:00
|
|
|
|
2012-10-20 09:33:40 +02:00
|
|
|
You should normally not need to overload this, but if you do, make
|
|
|
|
|
sure to reproduce at least the two last commands in this method (unless
|
|
|
|
|
you want to fundamentally change how a Character object works).
|
|
|
|
|
|
2011-03-17 21:43:18 +00:00
|
|
|
"""
|
|
|
|
|
super(Character, self).basetype_setup()
|
2012-09-17 15:31:50 +02:00
|
|
|
self.locks.add(";".join(["get:false()", # noone can pick up the character
|
|
|
|
|
"call:false()"])) # no commands can be called on character from outside
|
2011-03-17 21:43:18 +00:00
|
|
|
# add the default cmdset
|
2013-04-12 13:01:20 +02:00
|
|
|
self.cmdset.add_default(settings.CMDSET_CHARACTER, permanent=True)
|
2011-03-17 21:43:18 +00:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
def at_object_creation(self):
|
|
|
|
|
"""
|
|
|
|
|
All this does (for now) is to add the default cmdset. Since
|
|
|
|
|
the script is permanently stored to this object (the permanent
|
|
|
|
|
keyword creates a script to do this), we should never need to
|
|
|
|
|
do this again for as long as this object exists.
|
2012-03-30 23:47:22 +02:00
|
|
|
"""
|
|
|
|
|
pass
|
2011-09-03 10:22:19 +00:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
def at_after_move(self, source_location):
|
|
|
|
|
"Default is to look around after a move."
|
|
|
|
|
self.execute_cmd('look')
|
2011-11-06 23:55:24 +01:00
|
|
|
|
2013-04-06 21:36:52 +02:00
|
|
|
def at_pre_puppet(self, player):
|
2011-11-06 23:55:24 +01:00
|
|
|
"""
|
2013-04-06 21:36:52 +02:00
|
|
|
This recovers the character again after having been "stoved away" at the unpuppet
|
2011-11-06 23:55:24 +01:00
|
|
|
"""
|
|
|
|
|
if self.db.prelogout_location:
|
2012-03-30 23:47:22 +02:00
|
|
|
# try to recover
|
|
|
|
|
self.location = self.db.prelogout_location
|
2011-11-06 23:55:24 +01:00
|
|
|
if self.location == None:
|
|
|
|
|
# make sure location is never None (home should always exist)
|
|
|
|
|
self.location = self.home
|
2013-04-20 16:14:12 +02:00
|
|
|
if self.location:
|
|
|
|
|
# save location again to be sure
|
|
|
|
|
self.db.prelogout_location = self.location
|
|
|
|
|
self.location.msg_contents("%s has entered the game." % self.name, exclude=[self])
|
|
|
|
|
self.location.at_object_receive(self, self.location)
|
|
|
|
|
else:
|
|
|
|
|
player.msg("{r%s has no location and no home is set.{n" % self)
|
2013-04-06 21:36:52 +02:00
|
|
|
|
2013-04-18 09:13:31 +02:00
|
|
|
def at_post_puppet(self):
|
|
|
|
|
"""
|
|
|
|
|
Called just after puppeting has completed.
|
|
|
|
|
"""
|
|
|
|
|
self.msg("\nYou become {c%s{n.\n" % self.name)
|
|
|
|
|
self.execute_cmd("look")
|
|
|
|
|
if self.location:
|
|
|
|
|
self.location.msg_contents("%s has entered the game." % self.name, exclude=[self])
|
|
|
|
|
|
2013-04-06 21:36:52 +02:00
|
|
|
def at_post_unpuppet(self, player):
|
|
|
|
|
"""
|
|
|
|
|
We stove away the character when the player goes ooc/logs off, otherwise the character object will
|
|
|
|
|
remain in the room also after the player logged off ("headless", so to say).
|
|
|
|
|
"""
|
|
|
|
|
if self.location: # have to check, in case of multiple connections closing
|
|
|
|
|
self.location.msg_contents("%s has left the game." % self.name, exclude=[self])
|
|
|
|
|
self.db.prelogout_location = self.location
|
|
|
|
|
self.location = None
|
|
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
#
|
2012-03-30 23:47:22 +02:00
|
|
|
# Base Room object
|
2010-08-29 18:46:58 +00:00
|
|
|
#
|
|
|
|
|
|
|
|
|
|
class Room(Object):
|
|
|
|
|
"""
|
2013-06-30 14:13:01 +02:00
|
|
|
This is the base room object. It's just like any Object except its
|
|
|
|
|
location is None.
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
2011-03-17 21:43:18 +00:00
|
|
|
def basetype_setup(self):
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
|
|
|
|
Simple setup, shown as an example
|
|
|
|
|
(since default is None anyway)
|
|
|
|
|
"""
|
2011-03-20 13:24:07 +00:00
|
|
|
|
|
|
|
|
super(Room, self).basetype_setup()
|
2012-09-17 15:31:50 +02:00
|
|
|
self.locks.add(";".join(["get:false()",
|
|
|
|
|
"puppet:false()"])) # would be weird to puppet a room ...
|
2012-03-30 23:47:22 +02:00
|
|
|
self.location = None
|
2010-08-29 18:46:58 +00:00
|
|
|
|
2011-04-30 21:09:19 +00:00
|
|
|
#
|
2013-06-30 14:13:01 +02:00
|
|
|
# Base Exit object
|
2011-04-30 21:09:19 +00:00
|
|
|
#
|
|
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
class Exit(Object):
|
|
|
|
|
"""
|
2013-06-30 14:13:01 +02:00
|
|
|
This is the base exit object - it connects a location to another.
|
|
|
|
|
This is done by the exit assigning a "command" on itself with the
|
|
|
|
|
same name as the exit object (to do this we need to remember to
|
|
|
|
|
re-create the command when the object is cached since it must be
|
2011-05-01 18:04:15 +00:00
|
|
|
created dynamically depending on what the exit is called). This
|
2013-06-30 14:13:01 +02:00
|
|
|
command (which has a high priority) will thus allow us to traverse
|
|
|
|
|
exits simply by giving the exit-object's name on its own.
|
2012-03-30 23:47:22 +02:00
|
|
|
"""
|
|
|
|
|
|
2011-05-01 18:04:15 +00:00
|
|
|
# Helper classes and methods to implement the Exit. These need not
|
|
|
|
|
# be overloaded unless one want to change the foundation for how
|
2012-03-30 23:47:22 +02:00
|
|
|
# Exits work. See the end of the class for hook methods to overload.
|
2011-05-01 18:04:15 +00:00
|
|
|
|
|
|
|
|
def create_exit_cmdset(self, exidbobj):
|
|
|
|
|
"""
|
|
|
|
|
Helper function for creating an exit command set + command.
|
|
|
|
|
|
2011-08-11 21:16:35 +00:00
|
|
|
The command of this cmdset has the same name as the Exit object
|
|
|
|
|
and allows the exit to react when the player enter the exit's name,
|
2012-03-30 23:47:22 +02:00
|
|
|
triggering the movement between rooms.
|
|
|
|
|
|
2011-08-11 21:16:35 +00:00
|
|
|
Note that exitdbobj is an ObjectDB instance. This is necessary
|
|
|
|
|
for handling reloads and avoid tracebacks if this is called while
|
|
|
|
|
the typeclass system is rebooting.
|
|
|
|
|
"""
|
2011-05-01 18:04:15 +00:00
|
|
|
class ExitCommand(command.Command):
|
|
|
|
|
"""
|
|
|
|
|
This is a command that simply cause the caller
|
2012-03-30 23:47:22 +02:00
|
|
|
to traverse the object it is attached to.
|
2011-05-01 18:04:15 +00:00
|
|
|
"""
|
2012-03-30 23:47:22 +02:00
|
|
|
locks = "cmd:all()" # should always be set to this.
|
2011-05-01 18:04:15 +00:00
|
|
|
obj = None
|
2012-02-27 20:56:01 +01:00
|
|
|
arg_regex=r"\s.*?|$"
|
2012-06-20 21:16:34 +02:00
|
|
|
is_exit = True # this helps cmdhandler disable exits in cmdsets with no_exits=True.
|
2011-05-01 18:04:15 +00:00
|
|
|
|
|
|
|
|
def func(self):
|
|
|
|
|
"Default exit traverse if no syscommand is defined."
|
|
|
|
|
|
|
|
|
|
if self.obj.access(self.caller, 'traverse'):
|
2012-03-30 23:47:22 +02:00
|
|
|
# we may traverse the exit.
|
2012-10-14 13:11:13 +02:00
|
|
|
self.obj.at_traverse(self.caller, self.obj.destination)
|
2011-05-01 18:04:15 +00:00
|
|
|
else:
|
2012-10-14 13:11:13 +02:00
|
|
|
# exit is locked
|
2011-05-01 18:04:15 +00:00
|
|
|
if self.obj.db.err_traverse:
|
|
|
|
|
# if exit has a better error message, let's use it.
|
|
|
|
|
self.caller.msg(self.obj.db.err_traverse)
|
|
|
|
|
else:
|
|
|
|
|
# No shorthand error message. Call hook.
|
|
|
|
|
self.obj.at_failed_traverse(self.caller)
|
|
|
|
|
|
|
|
|
|
# create an exit command.
|
|
|
|
|
cmd = ExitCommand()
|
|
|
|
|
cmd.key = exidbobj.db_key.strip().lower()
|
2012-03-30 23:47:22 +02:00
|
|
|
cmd.obj = exidbobj
|
2011-05-01 18:04:15 +00:00
|
|
|
cmd.aliases = exidbobj.aliases
|
2011-06-26 22:03:09 +00:00
|
|
|
cmd.locks = str(exidbobj.locks)
|
2011-05-01 18:04:15 +00:00
|
|
|
cmd.destination = exidbobj.db_destination
|
2012-10-14 16:37:36 +02:00
|
|
|
cmd.auto_help = False
|
2011-05-01 18:04:15 +00:00
|
|
|
# create a cmdset
|
|
|
|
|
exit_cmdset = cmdset.CmdSet(None)
|
|
|
|
|
exit_cmdset.key = '_exitset'
|
|
|
|
|
exit_cmdset.priority = 9
|
2012-03-30 23:47:22 +02:00
|
|
|
exit_cmdset.duplicates = True
|
|
|
|
|
# add command to cmdset
|
|
|
|
|
exit_cmdset.add(cmd)
|
2011-05-01 18:04:15 +00:00
|
|
|
return exit_cmdset
|
|
|
|
|
|
2012-03-30 23:47:22 +02:00
|
|
|
# Command hooks
|
2011-03-17 21:43:18 +00:00
|
|
|
def basetype_setup(self):
|
|
|
|
|
"""
|
|
|
|
|
Setup exit-security
|
2011-04-23 11:54:08 +00:00
|
|
|
|
2012-10-20 09:33:40 +02:00
|
|
|
You should normally not need to overload this - if you do make sure you
|
|
|
|
|
include all the functionality in this method.
|
2011-03-17 21:43:18 +00:00
|
|
|
"""
|
|
|
|
|
super(Exit, self).basetype_setup()
|
2011-04-30 21:09:19 +00:00
|
|
|
|
2011-05-01 18:04:15 +00:00
|
|
|
# setting default locks (overload these in at_object_creation()
|
2012-09-17 15:31:50 +02:00
|
|
|
self.locks.add(";".join(["puppet:false()", # would be weird to puppet an exit ...
|
|
|
|
|
"traverse:all()", # who can pass through exit by default
|
|
|
|
|
"get:false()"])) # noone can pick up the exit
|
2012-03-30 23:47:22 +02:00
|
|
|
|
2011-09-03 10:22:19 +00:00
|
|
|
# an exit should have a destination (this is replaced at creation time)
|
2011-08-11 21:16:35 +00:00
|
|
|
if self.dbobj.location:
|
2012-03-30 23:47:22 +02:00
|
|
|
self.destination = self.dbobj.location
|
2011-08-11 21:16:35 +00:00
|
|
|
|
|
|
|
|
def at_cmdset_get(self):
|
|
|
|
|
"""
|
2012-03-30 23:47:22 +02:00
|
|
|
Called when the cmdset is requested from this object, just before the cmdset is
|
2011-08-11 21:16:35 +00:00
|
|
|
actually extracted. If no Exit-cmdset is cached, create it now.
|
2012-03-30 23:47:22 +02:00
|
|
|
"""
|
2011-08-11 21:16:35 +00:00
|
|
|
|
|
|
|
|
if self.ndb.exit_reset or not self.cmdset.has_cmdset("_exitset", must_be_default=True):
|
|
|
|
|
# we are resetting, or no exit-cmdset was set. Create one dynamically.
|
2012-03-30 23:47:22 +02:00
|
|
|
self.cmdset.add_default(self.create_exit_cmdset(self.dbobj), permanent=False)
|
|
|
|
|
self.ndb.exit_reset = False
|
2011-05-01 18:04:15 +00:00
|
|
|
|
2012-03-30 23:47:22 +02:00
|
|
|
# this and other hooks are what usually can be modified safely.
|
2011-05-01 18:04:15 +00:00
|
|
|
|
|
|
|
|
def at_object_creation(self):
|
|
|
|
|
"Called once, when object is first created (after basetype_setup)."
|
2012-03-30 23:47:22 +02:00
|
|
|
pass
|
2011-04-24 11:26:51 +00:00
|
|
|
|
2012-10-14 13:11:13 +02:00
|
|
|
def at_traverse(self, traversing_object, target_location):
|
|
|
|
|
"""
|
|
|
|
|
This implements the actual traversal. The traverse lock has already been
|
|
|
|
|
checked (in the Exit command) at this point.
|
|
|
|
|
"""
|
|
|
|
|
source_location = traversing_object.location
|
|
|
|
|
if traversing_object.move_to(target_location):
|
|
|
|
|
self.at_after_traverse(traversing_object, source_location)
|
|
|
|
|
else:
|
|
|
|
|
if self.db.err_traverse:
|
|
|
|
|
# if exit has a better error message, let's use it.
|
|
|
|
|
self.caller.msg(self.db.err_traverse)
|
|
|
|
|
else:
|
|
|
|
|
# No shorthand error message. Call hook.
|
|
|
|
|
self.at_failed_traverse(traversing_object)
|
|
|
|
|
|
|
|
|
|
def at_after_traverse(self, traversing_object, source_location):
|
|
|
|
|
"""
|
|
|
|
|
Called after a successful traverse.
|
|
|
|
|
"""
|
|
|
|
|
pass
|
|
|
|
|
|
2011-04-24 11:26:51 +00:00
|
|
|
def at_failed_traverse(self, traversing_object):
|
|
|
|
|
"""
|
2012-03-30 23:47:22 +02:00
|
|
|
This is called if an object fails to traverse this object for some
|
2011-04-24 11:26:51 +00:00
|
|
|
reason. It will not be called if the attribute "err_traverse" is defined,
|
2012-03-30 23:47:22 +02:00
|
|
|
that attribute will then be echoed back instead as a convenient shortcut.
|
2011-05-01 18:04:15 +00:00
|
|
|
|
2012-03-30 23:47:22 +02:00
|
|
|
(See also hooks at_before_traverse and at_after_traverse).
|
2011-04-24 11:26:51 +00:00
|
|
|
"""
|
2011-05-01 18:04:15 +00:00
|
|
|
traversing_object.msg("You cannot go there.")
|