Start improve OLC menu docs and help texts
This commit is contained in:
parent
a954f9c723
commit
e4016e435e
5 changed files with 203 additions and 29 deletions
|
|
@ -19,6 +19,15 @@
|
||||||
- The spawn command got the /save switch to save the defined prototype and its key.
|
- The spawn command got the /save switch to save the defined prototype and its key.
|
||||||
- The command spawn/menu will now start an OLC (OnLine Creation) menu to load/save/edit/spawn prototypes.
|
- The command spawn/menu will now start an OLC (OnLine Creation) menu to load/save/edit/spawn prototypes.
|
||||||
|
|
||||||
|
### EvMenu
|
||||||
|
|
||||||
|
- Added `EvMenu.helptext_formatter(helptext)` to allow custom formatting of per-node help.
|
||||||
|
- Added `evennia.utils.evmenu.list_node` decorator for turning an EvMenu node into a multi-page listing.
|
||||||
|
- A `goto` option callable returning None (rather than the name of the next node) will now rerun the
|
||||||
|
current node instead of failing.
|
||||||
|
- Better error handling of in-node syntax errors.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Overviews
|
# Overviews
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import json
|
||||||
from random import choice
|
from random import choice
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from evennia.utils.evmenu import EvMenu, list_node
|
from evennia.utils.evmenu import EvMenu, list_node
|
||||||
|
from evennia.utils import evmore
|
||||||
from evennia.utils.ansi import strip_ansi
|
from evennia.utils.ansi import strip_ansi
|
||||||
from evennia.utils import utils
|
from evennia.utils import utils
|
||||||
from evennia.prototypes import prototypes as protlib
|
from evennia.prototypes import prototypes as protlib
|
||||||
|
|
@ -78,7 +79,9 @@ def _format_option_value(prop, required=False, prototype=None, cropper=None):
|
||||||
out = ", ".join(str(pr) for pr in prop)
|
out = ", ".join(str(pr) for pr in prop)
|
||||||
if not out and required:
|
if not out and required:
|
||||||
out = "|rrequired"
|
out = "|rrequired"
|
||||||
return " ({}|n)".format(cropper(out) if cropper else utils.crop(out, _MENU_CROP_WIDTH))
|
if out:
|
||||||
|
return " ({}|n)".format(cropper(out) if cropper else utils.crop(out, _MENU_CROP_WIDTH))
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
def _set_prototype_value(caller, field, value, parse=True):
|
def _set_prototype_value(caller, field, value, parse=True):
|
||||||
|
|
@ -214,31 +217,75 @@ def _validate_prototype(prototype):
|
||||||
return err, text
|
return err, text
|
||||||
|
|
||||||
|
|
||||||
# Menu nodes
|
def _format_protfuncs():
|
||||||
|
out = []
|
||||||
|
sorted_funcs = [(key, func) for key, func in
|
||||||
|
sorted(protlib.PROT_FUNCS.items(), key=lambda tup: tup[0])]
|
||||||
|
for protfunc_name, protfunc in sorted_funcs:
|
||||||
|
out.append("- |c${name}|n - |W{docs}".format(
|
||||||
|
name=protfunc_name,
|
||||||
|
docs=utils.justify(protfunc.__doc__.strip(), align='l', indent=10).strip()))
|
||||||
|
return "\n ".join(out)
|
||||||
|
|
||||||
|
|
||||||
|
# Menu nodes ------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
# main index (start page) node
|
||||||
|
|
||||||
|
|
||||||
def node_index(caller):
|
def node_index(caller):
|
||||||
prototype = _get_menu_prototype(caller)
|
prototype = _get_menu_prototype(caller)
|
||||||
|
|
||||||
text = (
|
text = """
|
||||||
"|c --- Prototype wizard --- |n\n\n"
|
|c --- Prototype wizard --- |n
|
||||||
"Define the |yproperties|n of the prototype. All prototype values can be "
|
|
||||||
"over-ridden at the time of spawning an instance of the prototype, but some are "
|
A |cprototype|n is a 'template' for |wspawning|n an in-game entity. A field of the prototype
|
||||||
"required.\n\n'|wprototype-'-properties|n are not used in the prototype itself but are used "
|
can be hard-coded or scripted using |w$protfuncs|n - for example to randomize the value
|
||||||
"to organize and list prototypes. The 'prototype-key' uniquely identifies the prototype "
|
every time the prototype is used to spawn a new entity.
|
||||||
"and allows you to edit an existing prototype or save a new one for use by you or "
|
|
||||||
"others later.\n\n(make choice; q to abort. If unsure, start from 1.)")
|
The prototype fields named 'prototype_*' are not used to create the entity itself but for
|
||||||
|
organizing the template when saving it for you (and maybe others) to use later.
|
||||||
|
|
||||||
|
Select prototype field to edit. If you are unsure, start from [|w1|n]. At any time you can
|
||||||
|
[|wV|n]alidate that the prototype works correctly and use it to [|wSP|n]awn a new entity. You
|
||||||
|
can also [|wSA|n]ve|n your work or [|wLO|n]oad an existing prototype to use as a base. Use
|
||||||
|
[|wL|n]ook to re-show a menu node. [|wQ|n]uit will always exit the menu and [|wH|n]elp will
|
||||||
|
show context-sensitive help.
|
||||||
|
"""
|
||||||
|
|
||||||
|
helptxt = """
|
||||||
|
|c- prototypes |n
|
||||||
|
|
||||||
|
A prototype is really just a Python dictionary. When spawning, this dictionary is essentially
|
||||||
|
passed into `|wevennia.utils.create.create_object(**prototype)|n` to create a new object. By
|
||||||
|
using different prototypes you can customize instances of objects without having to do code
|
||||||
|
changes to their typeclass (something which requires code access). The classical example is
|
||||||
|
to spawn goblins with different names, looks, equipment and skill, each based on the same
|
||||||
|
`Goblin` typeclass.
|
||||||
|
|
||||||
|
|c- $protfuncs |n
|
||||||
|
|
||||||
|
Prototype-functions (protfuncs) allow for limited scripting within a prototype. These are
|
||||||
|
entered as a string $funcname(arg, arg, ...) and are evaluated |wat the time of spawning|n only.
|
||||||
|
They can also be nested for combined effects.
|
||||||
|
|
||||||
|
{pfuncs}
|
||||||
|
""".format(pfuncs=_format_protfuncs())
|
||||||
|
|
||||||
|
text = (text, helptxt)
|
||||||
|
|
||||||
options = []
|
options = []
|
||||||
options.append(
|
options.append(
|
||||||
{"desc": "|WPrototype-Key|n|n{}".format(
|
{"desc": "|WPrototype-Key|n|n{}".format(
|
||||||
_format_option_value("Key", "prototype_key" not in prototype, prototype, None)),
|
_format_option_value("Key", "prototype_key" not in prototype, prototype, None)),
|
||||||
"goto": "node_prototype_key"})
|
"goto": "node_prototype_key"})
|
||||||
for key in ('Typeclass', 'Prototype_parent', 'Key', 'Aliases', 'Attrs', 'Tags', 'Locks',
|
for key in ('Typeclass', 'Prototype-parent', 'Key', 'Aliases', 'Attrs', 'Tags', 'Locks',
|
||||||
'Permissions', 'Location', 'Home', 'Destination'):
|
'Permissions', 'Location', 'Home', 'Destination'):
|
||||||
required = False
|
required = False
|
||||||
cropper = None
|
cropper = None
|
||||||
if key in ("Prototype-parent", "Typeclass"):
|
if key in ("Prototype-parent", "Typeclass"):
|
||||||
required = "prototype_parent" not in prototype and "typeclass" not in prototype
|
required = ("prototype_parent" not in prototype) and ("typeclass" not in prototype)
|
||||||
if key == 'Typeclass':
|
if key == 'Typeclass':
|
||||||
cropper = _path_cropper
|
cropper = _path_cropper
|
||||||
options.append(
|
options.append(
|
||||||
|
|
@ -256,16 +303,18 @@ def node_index(caller):
|
||||||
options.extend((
|
options.extend((
|
||||||
{"key": ("|wV|Walidate prototype", "validate", "v"),
|
{"key": ("|wV|Walidate prototype", "validate", "v"),
|
||||||
"goto": "node_validate_prototype"},
|
"goto": "node_validate_prototype"},
|
||||||
{"key": ("|wS|Wave prototype", "save", "s"),
|
{"key": ("|wSA|Wve prototype", "save", "sa"),
|
||||||
"goto": "node_prototype_save"},
|
"goto": "node_prototype_save"},
|
||||||
{"key": ("|wSP|Wawn prototype", "spawn", "sp"),
|
{"key": ("|wSP|Wawn prototype", "spawn", "sp"),
|
||||||
"goto": "node_prototype_spawn"},
|
"goto": "node_prototype_spawn"},
|
||||||
{"key": ("|wL|Woad prototype", "load", "l"),
|
{"key": ("|wLO|Wad prototype", "load", "lo"),
|
||||||
"goto": "node_prototype_load"}))
|
"goto": "node_prototype_load"}))
|
||||||
|
|
||||||
return text, options
|
return text, options
|
||||||
|
|
||||||
|
|
||||||
|
# validate prototype (available as option from all nodes)
|
||||||
|
|
||||||
def node_validate_prototype(caller, raw_string, **kwargs):
|
def node_validate_prototype(caller, raw_string, **kwargs):
|
||||||
"""General node to view and validate a protototype"""
|
"""General node to view and validate a protototype"""
|
||||||
prototype = _get_menu_prototype(caller)
|
prototype = _get_menu_prototype(caller)
|
||||||
|
|
@ -273,11 +322,22 @@ def node_validate_prototype(caller, raw_string, **kwargs):
|
||||||
|
|
||||||
_, text = _validate_prototype(prototype)
|
_, text = _validate_prototype(prototype)
|
||||||
|
|
||||||
|
helptext = """
|
||||||
|
The validator checks if the prototype's various values are on the expected form. It also test
|
||||||
|
any $protfuncs.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
text = (text, helptext)
|
||||||
|
|
||||||
options = _wizard_options(None, prev_node, None)
|
options = _wizard_options(None, prev_node, None)
|
||||||
|
|
||||||
return text, options
|
return text, options
|
||||||
|
|
||||||
|
|
||||||
|
# prototype_key node
|
||||||
|
|
||||||
|
|
||||||
def _check_prototype_key(caller, key):
|
def _check_prototype_key(caller, key):
|
||||||
old_prototype = protlib.search_prototype(key)
|
old_prototype = protlib.search_prototype(key)
|
||||||
olc_new = _is_new_prototype(caller)
|
olc_new = _is_new_prototype(caller)
|
||||||
|
|
@ -303,22 +363,36 @@ def _check_prototype_key(caller, key):
|
||||||
|
|
||||||
def node_prototype_key(caller):
|
def node_prototype_key(caller):
|
||||||
prototype = _get_menu_prototype(caller)
|
prototype = _get_menu_prototype(caller)
|
||||||
text = ["The prototype name, or |wMeta-Key|n, uniquely identifies the prototype. "
|
text = """
|
||||||
"It is used to find and use the prototype to spawn new entities. "
|
The |cPrototype-Key|n uniquely identifies the prototype. It must be specified. It is used to
|
||||||
"It is not case sensitive."]
|
find and use the prototype to spawn new entities. It is not case sensitive.
|
||||||
|
|
||||||
|
{current}"""
|
||||||
|
|
||||||
|
helptext = """
|
||||||
|
The prototype-key is not itself used to spawn the new object, but is only used for managing,
|
||||||
|
storing and loading the prototype. It must be globally unique, so existing keys will be
|
||||||
|
checked before a new key is accepted. If an existing key is picked, the existing prototype
|
||||||
|
will be loaded.
|
||||||
|
"""
|
||||||
|
|
||||||
old_key = prototype.get('prototype_key', None)
|
old_key = prototype.get('prototype_key', None)
|
||||||
if old_key:
|
if old_key:
|
||||||
text.append("Current key is '|w{key}|n'".format(key=old_key))
|
text = text.format(current="Currently set to '|w{key}|n'".format(key=old_key))
|
||||||
else:
|
else:
|
||||||
text.append("The key is currently unset.")
|
text = text.format(current="Currently |runset|n (required).")
|
||||||
text.append("Enter text or make a choice (q for quit)")
|
|
||||||
text = "\n\n".join(text)
|
|
||||||
options = _wizard_options("prototype_key", "index", "prototype_parent")
|
options = _wizard_options("prototype_key", "index", "prototype_parent")
|
||||||
options.append({"key": "_default",
|
options.append({"key": "_default",
|
||||||
"goto": _check_prototype_key})
|
"goto": _check_prototype_key})
|
||||||
|
|
||||||
|
text = (text, helptext)
|
||||||
return text, options
|
return text, options
|
||||||
|
|
||||||
|
|
||||||
|
# prototype_parents node
|
||||||
|
|
||||||
|
|
||||||
def _all_prototype_parents(caller):
|
def _all_prototype_parents(caller):
|
||||||
"""Return prototype_key of all available prototypes for listing in menu"""
|
"""Return prototype_key of all available prototypes for listing in menu"""
|
||||||
return [prototype["prototype_key"]
|
return [prototype["prototype_key"]
|
||||||
|
|
@ -368,6 +442,8 @@ def node_prototype_parent(caller):
|
||||||
return text, options
|
return text, options
|
||||||
|
|
||||||
|
|
||||||
|
# typeclasses node
|
||||||
|
|
||||||
def _all_typeclasses(caller):
|
def _all_typeclasses(caller):
|
||||||
"""Get name of available typeclasses."""
|
"""Get name of available typeclasses."""
|
||||||
return list(name for name in
|
return list(name for name in
|
||||||
|
|
@ -423,6 +499,9 @@ def node_typeclass(caller):
|
||||||
return text, options
|
return text, options
|
||||||
|
|
||||||
|
|
||||||
|
# key node
|
||||||
|
|
||||||
|
|
||||||
def node_key(caller):
|
def node_key(caller):
|
||||||
prototype = _get_menu_prototype(caller)
|
prototype = _get_menu_prototype(caller)
|
||||||
key = prototype.get("key")
|
key = prototype.get("key")
|
||||||
|
|
@ -442,6 +521,9 @@ def node_key(caller):
|
||||||
return text, options
|
return text, options
|
||||||
|
|
||||||
|
|
||||||
|
# aliases node
|
||||||
|
|
||||||
|
|
||||||
def node_aliases(caller):
|
def node_aliases(caller):
|
||||||
prototype = _get_menu_prototype(caller)
|
prototype = _get_menu_prototype(caller)
|
||||||
aliases = prototype.get("aliases")
|
aliases = prototype.get("aliases")
|
||||||
|
|
@ -462,6 +544,9 @@ def node_aliases(caller):
|
||||||
return text, options
|
return text, options
|
||||||
|
|
||||||
|
|
||||||
|
# attributes node
|
||||||
|
|
||||||
|
|
||||||
def _caller_attrs(caller):
|
def _caller_attrs(caller):
|
||||||
prototype = _get_menu_prototype(caller)
|
prototype = _get_menu_prototype(caller)
|
||||||
attrs = prototype.get("attrs", [])
|
attrs = prototype.get("attrs", [])
|
||||||
|
|
@ -572,6 +657,9 @@ def node_attrs(caller):
|
||||||
return text, options
|
return text, options
|
||||||
|
|
||||||
|
|
||||||
|
# tags node
|
||||||
|
|
||||||
|
|
||||||
def _caller_tags(caller):
|
def _caller_tags(caller):
|
||||||
prototype = _get_menu_prototype(caller)
|
prototype = _get_menu_prototype(caller)
|
||||||
tags = prototype.get("tags", [])
|
tags = prototype.get("tags", [])
|
||||||
|
|
@ -659,6 +747,9 @@ def node_tags(caller):
|
||||||
return text, options
|
return text, options
|
||||||
|
|
||||||
|
|
||||||
|
# locks node
|
||||||
|
|
||||||
|
|
||||||
def node_locks(caller):
|
def node_locks(caller):
|
||||||
prototype = _get_menu_prototype(caller)
|
prototype = _get_menu_prototype(caller)
|
||||||
locks = prototype.get("locks")
|
locks = prototype.get("locks")
|
||||||
|
|
@ -679,6 +770,9 @@ def node_locks(caller):
|
||||||
return text, options
|
return text, options
|
||||||
|
|
||||||
|
|
||||||
|
# permissions node
|
||||||
|
|
||||||
|
|
||||||
def node_permissions(caller):
|
def node_permissions(caller):
|
||||||
prototype = _get_menu_prototype(caller)
|
prototype = _get_menu_prototype(caller)
|
||||||
permissions = prototype.get("permissions")
|
permissions = prototype.get("permissions")
|
||||||
|
|
@ -699,6 +793,9 @@ def node_permissions(caller):
|
||||||
return text, options
|
return text, options
|
||||||
|
|
||||||
|
|
||||||
|
# location node
|
||||||
|
|
||||||
|
|
||||||
def node_location(caller):
|
def node_location(caller):
|
||||||
prototype = _get_menu_prototype(caller)
|
prototype = _get_menu_prototype(caller)
|
||||||
location = prototype.get("location")
|
location = prototype.get("location")
|
||||||
|
|
@ -718,6 +815,9 @@ def node_location(caller):
|
||||||
return text, options
|
return text, options
|
||||||
|
|
||||||
|
|
||||||
|
# home node
|
||||||
|
|
||||||
|
|
||||||
def node_home(caller):
|
def node_home(caller):
|
||||||
prototype = _get_menu_prototype(caller)
|
prototype = _get_menu_prototype(caller)
|
||||||
home = prototype.get("home")
|
home = prototype.get("home")
|
||||||
|
|
@ -737,6 +837,9 @@ def node_home(caller):
|
||||||
return text, options
|
return text, options
|
||||||
|
|
||||||
|
|
||||||
|
# destination node
|
||||||
|
|
||||||
|
|
||||||
def node_destination(caller):
|
def node_destination(caller):
|
||||||
prototype = _get_menu_prototype(caller)
|
prototype = _get_menu_prototype(caller)
|
||||||
dest = prototype.get("dest")
|
dest = prototype.get("dest")
|
||||||
|
|
@ -756,6 +859,9 @@ def node_destination(caller):
|
||||||
return text, options
|
return text, options
|
||||||
|
|
||||||
|
|
||||||
|
# prototype_desc node
|
||||||
|
|
||||||
|
|
||||||
def node_prototype_desc(caller):
|
def node_prototype_desc(caller):
|
||||||
|
|
||||||
prototype = _get_menu_prototype(caller)
|
prototype = _get_menu_prototype(caller)
|
||||||
|
|
@ -778,6 +884,9 @@ def node_prototype_desc(caller):
|
||||||
return text, options
|
return text, options
|
||||||
|
|
||||||
|
|
||||||
|
# prototype_tags node
|
||||||
|
|
||||||
|
|
||||||
def node_prototype_tags(caller):
|
def node_prototype_tags(caller):
|
||||||
prototype = _get_menu_prototype(caller)
|
prototype = _get_menu_prototype(caller)
|
||||||
text = ["|wPrototype-Tags|n can be used to classify and find prototypes. "
|
text = ["|wPrototype-Tags|n can be used to classify and find prototypes. "
|
||||||
|
|
@ -800,6 +909,9 @@ def node_prototype_tags(caller):
|
||||||
return text, options
|
return text, options
|
||||||
|
|
||||||
|
|
||||||
|
# prototype_locks node
|
||||||
|
|
||||||
|
|
||||||
def node_prototype_locks(caller):
|
def node_prototype_locks(caller):
|
||||||
prototype = _get_menu_prototype(caller)
|
prototype = _get_menu_prototype(caller)
|
||||||
text = ["Set |wPrototype-Locks|n on the prototype. There are two valid lock types: "
|
text = ["Set |wPrototype-Locks|n on the prototype. There are two valid lock types: "
|
||||||
|
|
@ -821,6 +933,9 @@ def node_prototype_locks(caller):
|
||||||
return text, options
|
return text, options
|
||||||
|
|
||||||
|
|
||||||
|
# update existing objects node
|
||||||
|
|
||||||
|
|
||||||
def _update_spawned(caller, **kwargs):
|
def _update_spawned(caller, **kwargs):
|
||||||
"""update existing objects"""
|
"""update existing objects"""
|
||||||
prototype = kwargs['prototype']
|
prototype = kwargs['prototype']
|
||||||
|
|
@ -904,6 +1019,9 @@ def node_update_objects(caller, **kwargs):
|
||||||
return text, options
|
return text, options
|
||||||
|
|
||||||
|
|
||||||
|
# prototype save node
|
||||||
|
|
||||||
|
|
||||||
def node_prototype_save(caller, **kwargs):
|
def node_prototype_save(caller, **kwargs):
|
||||||
"""Save prototype to disk """
|
"""Save prototype to disk """
|
||||||
# these are only set if we selected 'yes' to save on a previous pass
|
# these are only set if we selected 'yes' to save on a previous pass
|
||||||
|
|
@ -972,6 +1090,9 @@ def node_prototype_save(caller, **kwargs):
|
||||||
return "\n".join(text), options
|
return "\n".join(text), options
|
||||||
|
|
||||||
|
|
||||||
|
# spawning node
|
||||||
|
|
||||||
|
|
||||||
def _spawn(caller, **kwargs):
|
def _spawn(caller, **kwargs):
|
||||||
"""Spawn prototype"""
|
"""Spawn prototype"""
|
||||||
prototype = kwargs["prototype"].copy()
|
prototype = kwargs["prototype"].copy()
|
||||||
|
|
@ -1037,6 +1158,9 @@ def node_prototype_spawn(caller, **kwargs):
|
||||||
return text, options
|
return text, options
|
||||||
|
|
||||||
|
|
||||||
|
# prototype load node
|
||||||
|
|
||||||
|
|
||||||
def _prototype_load_select(caller, prototype_key):
|
def _prototype_load_select(caller, prototype_key):
|
||||||
matches = protlib.search_prototype(key=prototype_key)
|
matches = protlib.search_prototype(key=prototype_key)
|
||||||
if matches:
|
if matches:
|
||||||
|
|
@ -1052,12 +1176,15 @@ def _prototype_load_select(caller, prototype_key):
|
||||||
@list_node(_all_prototype_parents, _prototype_load_select)
|
@list_node(_all_prototype_parents, _prototype_load_select)
|
||||||
def node_prototype_load(caller, **kwargs):
|
def node_prototype_load(caller, **kwargs):
|
||||||
text = ["Select a prototype to load. This will replace any currently edited prototype."]
|
text = ["Select a prototype to load. This will replace any currently edited prototype."]
|
||||||
options = _wizard_options("load", "save", "index")
|
options = _wizard_options("prototype_load", "prototype_save", "index")
|
||||||
options.append({"key": "_default",
|
options.append({"key": "_default",
|
||||||
"goto": _prototype_parent_examine})
|
"goto": _prototype_parent_examine})
|
||||||
return "\n".join(text), options
|
return "\n".join(text), options
|
||||||
|
|
||||||
|
|
||||||
|
# EvMenu definition, formatting and access functions
|
||||||
|
|
||||||
|
|
||||||
class OLCMenu(EvMenu):
|
class OLCMenu(EvMenu):
|
||||||
"""
|
"""
|
||||||
A custom EvMenu with a different formatting for the options.
|
A custom EvMenu with a different formatting for the options.
|
||||||
|
|
@ -1086,6 +1213,15 @@ class OLCMenu(EvMenu):
|
||||||
|
|
||||||
return "{}{}{}".format(olc_options, sep, other_options)
|
return "{}{}{}".format(olc_options, sep, other_options)
|
||||||
|
|
||||||
|
def helptext_formatter(self, helptext):
|
||||||
|
"""
|
||||||
|
Show help text
|
||||||
|
"""
|
||||||
|
return "|c --- Help ---|n\n" + helptext
|
||||||
|
|
||||||
|
def display_helptext(self):
|
||||||
|
evmore.msg(self.caller, self.helptext, session=self._session)
|
||||||
|
|
||||||
|
|
||||||
def start_olc(caller, session=None, prototype=None):
|
def start_olc(caller, session=None, prototype=None):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ from evennia.objects.models import ObjectDB
|
||||||
from evennia.utils.create import create_script
|
from evennia.utils.create import create_script
|
||||||
from evennia.utils.utils import (
|
from evennia.utils.utils import (
|
||||||
all_from_module, make_iter, is_iter, dbid_to_obj, callables_from_module,
|
all_from_module, make_iter, is_iter, dbid_to_obj, callables_from_module,
|
||||||
get_all_typeclasses, to_str, dbref)
|
get_all_typeclasses, to_str, dbref, justify)
|
||||||
from evennia.locks.lockhandler import validate_lockstring, check_lockstring
|
from evennia.locks.lockhandler import validate_lockstring, check_lockstring
|
||||||
from evennia.utils import logger
|
from evennia.utils import logger
|
||||||
from evennia.utils import inlinefuncs
|
from evennia.utils import inlinefuncs
|
||||||
|
|
@ -29,7 +29,7 @@ _PROTOTYPE_RESERVED_KEYS = _PROTOTYPE_META_NAMES + (
|
||||||
"permissions", "locks", "exec", "tags", "attrs")
|
"permissions", "locks", "exec", "tags", "attrs")
|
||||||
_PROTOTYPE_TAG_CATEGORY = "from_prototype"
|
_PROTOTYPE_TAG_CATEGORY = "from_prototype"
|
||||||
_PROTOTYPE_TAG_META_CATEGORY = "db_prototype"
|
_PROTOTYPE_TAG_META_CATEGORY = "db_prototype"
|
||||||
_PROT_FUNCS = {}
|
PROT_FUNCS = {}
|
||||||
|
|
||||||
|
|
||||||
_RE_DBREF = re.compile(r"(?<!\$obj\()(#[0-9]+)")
|
_RE_DBREF = re.compile(r"(?<!\$obj\()(#[0-9]+)")
|
||||||
|
|
@ -51,7 +51,7 @@ class ValidationError(RuntimeError):
|
||||||
for mod in settings.PROT_FUNC_MODULES:
|
for mod in settings.PROT_FUNC_MODULES:
|
||||||
try:
|
try:
|
||||||
callables = callables_from_module(mod)
|
callables = callables_from_module(mod)
|
||||||
_PROT_FUNCS.update(callables)
|
PROT_FUNCS.update(callables)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
logger.log_trace()
|
logger.log_trace()
|
||||||
raise
|
raise
|
||||||
|
|
@ -97,7 +97,7 @@ def protfunc_parser(value, available_functions=None, testing=False, stacktrace=F
|
||||||
pass
|
pass
|
||||||
value = to_str(value, force_string=True)
|
value = to_str(value, force_string=True)
|
||||||
|
|
||||||
available_functions = _PROT_FUNCS if available_functions is None else available_functions
|
available_functions = PROT_FUNCS if available_functions is None else available_functions
|
||||||
|
|
||||||
# insert $obj(#dbref) for #dbref
|
# insert $obj(#dbref) for #dbref
|
||||||
value = _RE_DBREF.sub("$obj(\\1)", value)
|
value = _RE_DBREF.sub("$obj(\\1)", value)
|
||||||
|
|
@ -118,6 +118,20 @@ def protfunc_parser(value, available_functions=None, testing=False, stacktrace=F
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def format_available_protfuncs():
|
||||||
|
"""
|
||||||
|
Get all protfuncs in a pretty-formatted form.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
clr (str, optional): What coloration tag to use.
|
||||||
|
"""
|
||||||
|
out = []
|
||||||
|
for protfunc_name, protfunc in PROT_FUNCS.items():
|
||||||
|
out.append("- |c${name}|n - |W{docs}".format(
|
||||||
|
name=protfunc_name, docs=protfunc.__doc__.strip().replace("\n", "")))
|
||||||
|
return justify("\n".join(out), indent=8)
|
||||||
|
|
||||||
|
|
||||||
# helper functions
|
# helper functions
|
||||||
|
|
||||||
def value_to_obj(value, force=True):
|
def value_to_obj(value, force=True):
|
||||||
|
|
|
||||||
|
|
@ -796,7 +796,7 @@ class EvMenu(object):
|
||||||
|
|
||||||
# handle the helptext
|
# handle the helptext
|
||||||
if helptext:
|
if helptext:
|
||||||
self.helptext = helptext
|
self.helptext = self.helptext_formatter(helptext)
|
||||||
elif options:
|
elif options:
|
||||||
self.helptext = _HELP_FULL if self.auto_quit else _HELP_NO_QUIT
|
self.helptext = _HELP_FULL if self.auto_quit else _HELP_NO_QUIT
|
||||||
else:
|
else:
|
||||||
|
|
@ -898,6 +898,19 @@ class EvMenu(object):
|
||||||
"""
|
"""
|
||||||
return dedent(nodetext).strip()
|
return dedent(nodetext).strip()
|
||||||
|
|
||||||
|
def helptext_formatter(self, helptext):
|
||||||
|
"""
|
||||||
|
Format the node's help text
|
||||||
|
|
||||||
|
Args:
|
||||||
|
helptext (str): The unformatted help text for the node.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
helptext (str): The formatted help text.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return dedent(helptext).strip()
|
||||||
|
|
||||||
def options_formatter(self, optionlist):
|
def options_formatter(self, optionlist):
|
||||||
"""
|
"""
|
||||||
Formats the option block.
|
Formats the option block.
|
||||||
|
|
|
||||||
|
|
@ -321,6 +321,7 @@ def parse_inlinefunc(string, strip=False, available_funcs=None, stacktrace=False
|
||||||
# process string on stack
|
# process string on stack
|
||||||
ncallable = 0
|
ncallable = 0
|
||||||
nlparens = 0
|
nlparens = 0
|
||||||
|
nvalid = 0
|
||||||
|
|
||||||
if stacktrace:
|
if stacktrace:
|
||||||
out = "STRING: {} =>".format(string)
|
out = "STRING: {} =>".format(string)
|
||||||
|
|
@ -367,6 +368,7 @@ def parse_inlinefunc(string, strip=False, available_funcs=None, stacktrace=False
|
||||||
try:
|
try:
|
||||||
# try to fetch the matching inlinefunc from storage
|
# try to fetch the matching inlinefunc from storage
|
||||||
stack.append(available_funcs[funcname])
|
stack.append(available_funcs[funcname])
|
||||||
|
nvalid += 1
|
||||||
except KeyError:
|
except KeyError:
|
||||||
stack.append(available_funcs["nomatch"])
|
stack.append(available_funcs["nomatch"])
|
||||||
stack.append(funcname)
|
stack.append(funcname)
|
||||||
|
|
@ -393,9 +395,9 @@ def parse_inlinefunc(string, strip=False, available_funcs=None, stacktrace=False
|
||||||
# this means not all inlinefuncs were complete
|
# this means not all inlinefuncs were complete
|
||||||
return string
|
return string
|
||||||
|
|
||||||
if _STACK_MAXSIZE > 0 and _STACK_MAXSIZE < len(stack):
|
if _STACK_MAXSIZE > 0 and _STACK_MAXSIZE < nvalid:
|
||||||
# if stack is larger than limit, throw away parsing
|
# if stack is larger than limit, throw away parsing
|
||||||
return string + gdict["stackfull"](*args, **kwargs)
|
return string + available_funcs["stackfull"](*args, **kwargs)
|
||||||
elif usecache:
|
elif usecache:
|
||||||
# cache the stack - we do this also if we don't check the cache above
|
# cache the stack - we do this also if we don't check the cache above
|
||||||
_PARSING_CACHE[string] = stack
|
_PARSING_CACHE[string] = stack
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue