2010-08-29 18:46:58 +00:00
|
|
|
"""
|
|
|
|
|
Scripts are entities that perform some sort of action, either only
|
|
|
|
|
once or repeatedly. They can be directly linked to a particular
|
|
|
|
|
Evennia Object or be stand-alonw (in the latter case it is considered
|
|
|
|
|
a 'global' script). Scripts can indicate both actions related to the
|
|
|
|
|
game world as well as pure behind-the-scenes events and
|
|
|
|
|
effects. Everything that has a time component in the game (i.e. is not
|
|
|
|
|
hard-coded at startup or directly created/controlled by players) is
|
|
|
|
|
handled by Scripts.
|
|
|
|
|
|
|
|
|
|
Scripts have to check for themselves that they should be applied at a
|
|
|
|
|
particular moment of time; this is handled by the is_valid() hook.
|
|
|
|
|
Scripts can also implement at_start and at_end hooks for preparing and
|
2012-03-31 13:06:29 +02:00
|
|
|
cleaning whatever effect they have had on the game object.
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
Common examples of uses of Scripts:
|
|
|
|
|
- load the default cmdset to the player object's cmdhandler
|
|
|
|
|
when logging in.
|
|
|
|
|
- switch to a different state, such as entering a text editor,
|
|
|
|
|
start combat or enter a dark room.
|
|
|
|
|
- Weather patterns in-game
|
|
|
|
|
- merge a new cmdset with the default one for changing which
|
2012-03-31 13:06:29 +02:00
|
|
|
commands are available at a particular time
|
|
|
|
|
- give the player/object a time-limited bonus/effect
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
from django.conf import settings
|
|
|
|
|
from django.db import models
|
2014-02-27 10:08:56 +01:00
|
|
|
from django.core.exceptions import ObjectDoesNotExist
|
|
|
|
|
from src.typeclasses.models import TypedObject, TagHandler, AttributeHandler
|
2010-08-29 18:46:58 +00:00
|
|
|
from src.scripts.manager import ScriptManager
|
2014-02-27 10:08:56 +01:00
|
|
|
from src.utils.utils import dbref, to_str
|
2010-08-29 18:46:58 +00:00
|
|
|
|
2013-07-08 18:13:21 +02:00
|
|
|
__all__ = ("ScriptDB",)
|
2014-02-27 10:08:56 +01:00
|
|
|
_GA = object.__getattribute__
|
2013-07-12 20:21:52 +02:00
|
|
|
_SA = object.__setattr__
|
2012-03-31 15:09:22 +02:00
|
|
|
|
2012-03-31 13:06:29 +02:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
#------------------------------------------------------------
|
|
|
|
|
#
|
|
|
|
|
# ScriptDB
|
|
|
|
|
#
|
|
|
|
|
#------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
class ScriptDB(TypedObject):
|
|
|
|
|
"""
|
2012-03-31 13:06:29 +02:00
|
|
|
The Script database representation.
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
The TypedObject supplies the following (inherited) properties:
|
|
|
|
|
key - main name
|
|
|
|
|
name - alias for key
|
|
|
|
|
typeclass_path - the path to the decorating typeclass
|
|
|
|
|
typeclass - auto-linked typeclass
|
|
|
|
|
date_created - time stamp of object creation
|
2012-03-31 13:06:29 +02:00
|
|
|
permissions - perm strings
|
|
|
|
|
dbref - #id of object
|
2010-08-29 18:46:58 +00:00
|
|
|
db - persistent attribute storage
|
2012-03-31 13:06:29 +02:00
|
|
|
ndb - non-persistent attribute storage
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
The ScriptDB adds the following properties:
|
|
|
|
|
desc - optional description of script
|
|
|
|
|
obj - the object the script is linked to, if any
|
2014-02-23 22:59:08 +01:00
|
|
|
player - the player the script is linked to (exclusive with obj)
|
2010-08-29 18:46:58 +00:00
|
|
|
interval - how often script should run
|
|
|
|
|
start_delay - if the script should start repeating right away
|
|
|
|
|
repeats - how many times the script should repeat
|
|
|
|
|
persistent - if script should survive a server reboot
|
2012-03-31 13:06:29 +02:00
|
|
|
is_active - bool if script is currently running
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
2012-03-31 13:06:29 +02:00
|
|
|
#
|
2010-08-29 18:46:58 +00:00
|
|
|
# ScriptDB Database Model setup
|
|
|
|
|
#
|
|
|
|
|
# These databse fields are all set using their corresponding properties,
|
|
|
|
|
# named same as the field, but withtou the db_* prefix.
|
|
|
|
|
|
2012-03-31 13:06:29 +02:00
|
|
|
# inherited fields (from TypedObject):
|
2010-08-29 18:46:58 +00:00
|
|
|
# db_key, db_typeclass_path, db_date_created, db_permissions
|
2012-03-31 13:06:29 +02:00
|
|
|
|
|
|
|
|
# optional description.
|
2011-10-02 01:21:03 +02:00
|
|
|
db_desc = models.CharField('desc', max_length=255, blank=True)
|
2010-08-29 18:46:58 +00:00
|
|
|
# A reference to the database object affected by this Script, if any.
|
2011-10-02 01:21:03 +02:00
|
|
|
db_obj = models.ForeignKey("objects.ObjectDB", null=True, blank=True, verbose_name='scripted object',
|
|
|
|
|
help_text='the object to store this script on, if not a global script.')
|
2014-02-23 22:59:08 +01:00
|
|
|
db_player = models.ForeignKey("players.PlayerDB", null=True, blank=True, verbose_name="scripted player",
|
|
|
|
|
help_text='the player to store this script on (should not be set if obj is set)')
|
2010-10-31 08:34:38 +00:00
|
|
|
# how often to run Script (secs). -1 means there is no timer
|
2011-10-02 01:21:03 +02:00
|
|
|
db_interval = models.IntegerField('interval', default=-1, help_text='how often to repeat script, in seconds. -1 means off.')
|
2010-08-29 18:46:58 +00:00
|
|
|
# start script right away or wait interval seconds first
|
2011-10-02 01:21:03 +02:00
|
|
|
db_start_delay = models.BooleanField('start delay', default=False, help_text='pause interval seconds before starting.')
|
2010-08-29 18:46:58 +00:00
|
|
|
# how many times this script is to be repeated, if interval!=0.
|
2011-10-02 01:21:03 +02:00
|
|
|
db_repeats = models.IntegerField('number of repeats', default=0, help_text='0 means off.')
|
2010-08-29 18:46:58 +00:00
|
|
|
# defines if this script should survive a reboot or not
|
2011-10-02 01:21:03 +02:00
|
|
|
db_persistent = models.BooleanField('survive server reboot', default=False)
|
2010-08-29 18:46:58 +00:00
|
|
|
# defines if this script has already been started in this session
|
2011-10-02 01:21:03 +02:00
|
|
|
db_is_active = models.BooleanField('script active', default=False)
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
# Database manager
|
|
|
|
|
objects = ScriptManager()
|
2012-03-31 13:06:29 +02:00
|
|
|
|
2013-07-11 15:59:03 +02:00
|
|
|
# caches for quick lookups
|
|
|
|
|
_typeclass_paths = settings.SCRIPT_TYPECLASS_PATHS
|
|
|
|
|
_default_typeclass_path = settings.BASE_SCRIPT_TYPECLASS or "src.scripts.scripts.DoNothing"
|
|
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
class Meta:
|
|
|
|
|
"Define Django meta options"
|
|
|
|
|
verbose_name = "Script"
|
|
|
|
|
|
2013-07-12 14:44:49 +02:00
|
|
|
def __init__(self, *args, **kwargs):
|
2013-07-12 15:57:46 +02:00
|
|
|
super(ScriptDB, self).__init__(*args, **kwargs)
|
2013-08-24 21:23:43 +02:00
|
|
|
_SA(self, "attributes", AttributeHandler(self))
|
2014-02-16 15:22:43 +01:00
|
|
|
_SA(self, "tags", TagHandler(self))
|
|
|
|
|
#_SA(self, "aliases", AliasHandler(self))
|
2013-07-12 14:44:49 +02:00
|
|
|
|
2014-02-27 10:08:56 +01:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
#
|
|
|
|
|
#
|
|
|
|
|
# ScriptDB class properties
|
|
|
|
|
#
|
|
|
|
|
#
|
|
|
|
|
|
2014-02-27 10:08:56 +01:00
|
|
|
# obj property
|
|
|
|
|
def __get_obj(self):
|
|
|
|
|
"""
|
|
|
|
|
property wrapper that homogenizes access to either
|
|
|
|
|
the db_player or db_obj field, using the same obj
|
|
|
|
|
property name
|
|
|
|
|
"""
|
|
|
|
|
if self.db_player:
|
|
|
|
|
return _GA(self, "db_player")
|
|
|
|
|
return _GA(self, "db_obj")
|
|
|
|
|
|
|
|
|
|
def __set_obj(self, value):
|
|
|
|
|
"""
|
|
|
|
|
Set player or obj to their right database field. If
|
|
|
|
|
a dbref is given, assume ObjectDB.
|
|
|
|
|
"""
|
|
|
|
|
try:
|
|
|
|
|
value = _GA(value, "dbobj")
|
|
|
|
|
except AttributeError:
|
|
|
|
|
pass
|
|
|
|
|
if isinstance(value, (basestring, int)):
|
|
|
|
|
from src.objects.models import ObjectDB
|
|
|
|
|
value = to_str(value, force_string=True)
|
|
|
|
|
if (value.isdigit() or value.startswith("#")):
|
|
|
|
|
dbid = dbref(value, reqhash=False)
|
|
|
|
|
if dbid:
|
|
|
|
|
try:
|
|
|
|
|
value = ObjectDB.objects.get(id=dbid)
|
|
|
|
|
except ObjectDoesNotExist:
|
|
|
|
|
# maybe it is just a name that happens to look like a dbid
|
|
|
|
|
pass
|
|
|
|
|
if value.__class__.__name__ == "PlayerDB":
|
|
|
|
|
fname = "db_player"
|
|
|
|
|
_SA(self, fname, value)
|
|
|
|
|
else:
|
|
|
|
|
fname = "db_obj"
|
|
|
|
|
_SA(self, fname, value)
|
|
|
|
|
# saving the field
|
|
|
|
|
_GA(self, "save")(update_fields=[fname])
|
|
|
|
|
obj = property(__get_obj, __set_obj)
|
2014-04-06 12:43:59 +02:00
|
|
|
object = property(__get_obj, __set_obj)
|
2014-02-27 10:08:56 +01:00
|
|
|
|
2011-08-06 18:15:04 +00:00
|
|
|
|
|
|
|
|
def at_typeclass_error(self):
|
|
|
|
|
"""
|
2012-03-31 13:06:29 +02:00
|
|
|
If this is called, it means the typeclass has a critical
|
2011-08-06 18:15:04 +00:00
|
|
|
error and cannot even be loaded. We don't allow a script
|
|
|
|
|
to be created under those circumstances. Already created,
|
|
|
|
|
permanent scripts are set to already be active so they
|
|
|
|
|
won't get activated now (next reboot the bug might be fixed)
|
|
|
|
|
"""
|
|
|
|
|
# By setting is_active=True, we trick the script not to run "again".
|
2012-03-31 13:06:29 +02:00
|
|
|
self.is_active = True
|
2011-08-06 18:15:04 +00:00
|
|
|
return super(ScriptDB, self).at_typeclass_error()
|
2011-09-03 10:22:19 +00:00
|
|
|
|
|
|
|
|
delete_iter = 0
|
|
|
|
|
def delete(self):
|
2014-02-27 10:08:56 +01:00
|
|
|
"Delete script"
|
2011-09-03 10:22:19 +00:00
|
|
|
if self.delete_iter > 0:
|
2012-03-31 13:06:29 +02:00
|
|
|
return
|
2011-09-03 10:22:19 +00:00
|
|
|
self.delete_iter += 1
|
|
|
|
|
super(ScriptDB, self).delete()
|