317 lines
9 KiB
Python
317 lines
9 KiB
Python
"""
|
|
Protfuncs are function-strings embedded in a prototype and allows for a builder to create a
|
|
prototype with custom logics without having access to Python. The Protfunc is parsed using the
|
|
inlinefunc parser but is fired at the moment the spawning happens, using the creating object's
|
|
session as input.
|
|
|
|
In the prototype dict, the protfunc is specified as a string inside the prototype, e.g.:
|
|
|
|
{ ...
|
|
|
|
"key": "$funcname(arg1, arg2, ...)"
|
|
|
|
... }
|
|
|
|
and multiple functions can be nested (no keyword args are supported). The result will be used as the
|
|
value for that prototype key for that individual spawn.
|
|
|
|
Available protfuncs are callables in one of the modules of `settings.PROT_FUNC_MODULES`. They
|
|
are specified as functions
|
|
|
|
def funcname (*args, **kwargs)
|
|
|
|
where *args are the arguments given in the prototype, and **kwargs are inserted by Evennia:
|
|
|
|
- session (Session): The Session of the entity spawning using this prototype.
|
|
- prototype (dict): The dict this protfunc is a part of.
|
|
- current_key (str): The active key this value belongs to in the prototype.
|
|
- testing (bool): This is set if this function is called as part of the prototype validation; if
|
|
set, the protfunc should take care not to perform any persistent actions, such as operate on
|
|
objects or add things to the database.
|
|
|
|
Any traceback raised by this function will be handled at the time of spawning and abort the spawn
|
|
before any object is created/updated. It must otherwise return the value to store for the specified
|
|
prototype key (this value must be possible to serialize in an Attribute).
|
|
|
|
"""
|
|
|
|
from ast import literal_eval
|
|
from random import randint as base_randint, random as base_random
|
|
|
|
from evennia.utils import search
|
|
from evennia.utils.utils import justify as base_justify, is_iter, to_str
|
|
|
|
_PROTLIB = None
|
|
|
|
|
|
# default protfuncs
|
|
|
|
def random(*args, **kwargs):
|
|
"""
|
|
Usage: $random()
|
|
Returns a random value in the interval [0, 1)
|
|
|
|
"""
|
|
return base_random()
|
|
|
|
|
|
def randint(*args, **kwargs):
|
|
"""
|
|
Usage: $randint(start, end)
|
|
Returns random integer in interval [start, end]
|
|
|
|
"""
|
|
if len(args) != 2:
|
|
raise TypeError("$randint needs two arguments - start and end.")
|
|
start, end = int(args[0]), int(args[1])
|
|
return base_randint(start, end)
|
|
|
|
|
|
def left_justify(*args, **kwargs):
|
|
"""
|
|
Usage: $left_justify(<text>)
|
|
Returns <text> left-justified.
|
|
|
|
"""
|
|
if args:
|
|
return base_justify(args[0], align='l')
|
|
return ""
|
|
|
|
|
|
def right_justify(*args, **kwargs):
|
|
"""
|
|
Usage: $right_justify(<text>)
|
|
Returns <text> right-justified across screen width.
|
|
|
|
"""
|
|
if args:
|
|
return base_justify(args[0], align='r')
|
|
return ""
|
|
|
|
|
|
def center_justify(*args, **kwargs):
|
|
|
|
"""
|
|
Usage: $center_justify(<text>)
|
|
Returns <text> centered in screen width.
|
|
|
|
"""
|
|
if args:
|
|
return base_justify(args[0], align='c')
|
|
return ""
|
|
|
|
|
|
def full_justify(*args, **kwargs):
|
|
|
|
"""
|
|
Usage: $full_justify(<text>)
|
|
Returns <text> filling up screen width by adding extra space.
|
|
|
|
"""
|
|
if args:
|
|
return base_justify(args[0], align='f')
|
|
return ""
|
|
|
|
|
|
def protkey(*args, **kwargs):
|
|
"""
|
|
Usage: $protkey(<key>)
|
|
Returns the value of another key in this prototoype. Will raise an error if
|
|
the key is not found in this prototype.
|
|
|
|
"""
|
|
if args:
|
|
prototype = kwargs['prototype']
|
|
return prototype[args[0].strip()]
|
|
|
|
|
|
def add(*args, **kwargs):
|
|
"""
|
|
Usage: $add(val1, val2)
|
|
Returns the result of val1 + val2. Values must be
|
|
valid simple Python structures possible to add,
|
|
such as numbers, lists etc.
|
|
|
|
"""
|
|
if len(args) > 1:
|
|
val1, val2 = args[0], args[1]
|
|
# try to convert to python structures, otherwise, keep as strings
|
|
try:
|
|
val1 = literal_eval(val1.strip())
|
|
except Exception:
|
|
pass
|
|
try:
|
|
val2 = literal_eval(val2.strip())
|
|
except Exception:
|
|
pass
|
|
return val1 + val2
|
|
raise ValueError("$add requires two arguments.")
|
|
|
|
|
|
def sub(*args, **kwargs):
|
|
"""
|
|
Usage: $del(val1, val2)
|
|
Returns the value of val1 - val2. Values must be
|
|
valid simple Python structures possible to
|
|
subtract.
|
|
|
|
"""
|
|
if len(args) > 1:
|
|
val1, val2 = args[0], args[1]
|
|
# try to convert to python structures, otherwise, keep as strings
|
|
try:
|
|
val1 = literal_eval(val1.strip())
|
|
except Exception:
|
|
pass
|
|
try:
|
|
val2 = literal_eval(val2.strip())
|
|
except Exception:
|
|
pass
|
|
return val1 - val2
|
|
raise ValueError("$sub requires two arguments.")
|
|
|
|
|
|
def mult(*args, **kwargs):
|
|
"""
|
|
Usage: $mul(val1, val2)
|
|
Returns the value of val1 * val2. The values must be
|
|
valid simple Python structures possible to
|
|
multiply, like strings and/or numbers.
|
|
|
|
"""
|
|
if len(args) > 1:
|
|
val1, val2 = args[0], args[1]
|
|
# try to convert to python structures, otherwise, keep as strings
|
|
try:
|
|
val1 = literal_eval(val1.strip())
|
|
except Exception:
|
|
pass
|
|
try:
|
|
val2 = literal_eval(val2.strip())
|
|
except Exception:
|
|
pass
|
|
return val1 * val2
|
|
raise ValueError("$mul requires two arguments.")
|
|
|
|
|
|
def div(*args, **kwargs):
|
|
"""
|
|
Usage: $div(val1, val2)
|
|
Returns the value of val1 / val2. Values must be numbers and
|
|
the result is always a float.
|
|
|
|
"""
|
|
if len(args) > 1:
|
|
val1, val2 = args[0], args[1]
|
|
# try to convert to python structures, otherwise, keep as strings
|
|
try:
|
|
val1 = literal_eval(val1.strip())
|
|
except Exception:
|
|
pass
|
|
try:
|
|
val2 = literal_eval(val2.strip())
|
|
except Exception:
|
|
pass
|
|
return val1 / float(val2)
|
|
raise ValueError("$mult requires two arguments.")
|
|
|
|
|
|
def toint(*args, **kwargs):
|
|
"""
|
|
Usage: $toint(<number>)
|
|
Returns <number> as an integer.
|
|
"""
|
|
if args:
|
|
val = args[0]
|
|
try:
|
|
return int(literal_eval(val.strip()))
|
|
except ValueError:
|
|
return val
|
|
raise ValueError("$toint requires one argument.")
|
|
|
|
|
|
def eval(*args, **kwargs):
|
|
"""
|
|
Usage $eval(<expression>)
|
|
Returns evaluation of a simple Python expression. The string may *only* consist of the following
|
|
Python literal structures: strings, numbers, tuples, lists, dicts, booleans,
|
|
and None. The strings can also contain #dbrefs. Escape embedded protfuncs as $$protfunc(..)
|
|
- those will then be evaluated *after* $eval.
|
|
|
|
"""
|
|
global _PROTLIB
|
|
if not _PROTLIB:
|
|
from evennia.prototypes import prototypes as _PROTLIB
|
|
|
|
string = ",".join(args)
|
|
struct = literal_eval(string)
|
|
|
|
if isinstance(struct, basestring):
|
|
# we must shield the string, otherwise it will be merged as a string and future
|
|
# literal_evas will pick up e.g. '2' as something that should be converted to a number
|
|
struct = '"{}"'.format(struct)
|
|
|
|
# convert any #dbrefs to objects (also in nested structures)
|
|
struct = _PROTLIB.value_to_obj_or_any(struct)
|
|
|
|
return struct
|
|
|
|
|
|
def _obj_search(*args, **kwargs):
|
|
"Helper function to search for an object"
|
|
|
|
query = "".join(args)
|
|
session = kwargs.get("session", None)
|
|
return_list = kwargs.pop("return_list", False)
|
|
account = None
|
|
|
|
if session:
|
|
account = session.account
|
|
|
|
targets = search.search_object(query)
|
|
|
|
if return_list:
|
|
retlist = []
|
|
if account:
|
|
for target in targets:
|
|
if target.access(account, target, 'control'):
|
|
retlist.append(target)
|
|
else:
|
|
retlist = targets
|
|
return retlist
|
|
else:
|
|
# single-match
|
|
if not targets:
|
|
raise ValueError("$obj: Query '{}' gave no matches.".format(query))
|
|
if len(targets) > 1:
|
|
raise ValueError("$obj: Query '{query}' gave {nmatches} matches. Limit your "
|
|
"query or use $objlist instead.".format(
|
|
query=query, nmatches=len(targets)))
|
|
target = targets[0]
|
|
if account:
|
|
if not target.access(account, target, 'control'):
|
|
raise ValueError("$obj: Obj {target}(#{dbref} cannot be added - "
|
|
"Account {account} does not have 'control' access.".format(
|
|
target=target.key, dbref=target.id, account=account))
|
|
return target
|
|
|
|
|
|
def obj(*args, **kwargs):
|
|
"""
|
|
Usage $obj(<query>)
|
|
Returns one Object searched globally by key, alias or #dbref. Error if more than one.
|
|
|
|
"""
|
|
obj = _obj_search(return_list=False, *args, **kwargs)
|
|
if obj:
|
|
return "#{}".format(obj.id)
|
|
return "".join(args)
|
|
|
|
|
|
def objlist(*args, **kwargs):
|
|
"""
|
|
Usage $objlist(<query>)
|
|
Returns list with one or more Objects searched globally by key, alias or #dbref.
|
|
|
|
"""
|
|
return ["#{}".format(obj.id) for obj in _obj_search(return_list=True, *args, **kwargs)]
|