mirror of
https://github.com/evennia/evennia.git
synced 2026-03-20 14:56:30 +01:00
Show flattened current values in menu
This commit is contained in:
parent
405293729f
commit
e09576812f
2 changed files with 59 additions and 119 deletions
|
|
@ -42,6 +42,17 @@ def _get_menu_prototype(caller):
|
|||
return prototype
|
||||
|
||||
|
||||
def _get_flat_menu_prototype(caller, refresh=False):
|
||||
"""Return prototype where parent values are included"""
|
||||
flat_prototype = None
|
||||
if not refresh and hasattr(caller.ndb._menutree, "olc_flat_prototype"):
|
||||
flat_prototype = caller.ndb._menutree.olc_flat_prototype
|
||||
if not flat_prototype:
|
||||
prot = _get_menu_prototype(caller)
|
||||
caller.ndb._menutree.olc_flat_prototype = flat_prototype = spawner.flatten_prototype(prot)
|
||||
return flat_prototype
|
||||
|
||||
|
||||
def _set_menu_prototype(caller, prototype):
|
||||
"""Set the prototype with existing one"""
|
||||
caller.ndb._menutree.olc_prototype = prototype
|
||||
|
|
@ -230,6 +241,19 @@ def _format_lockfuncs():
|
|||
docs=utils.justify(lockfunc.__doc__.strip(), align='l', indent=10).strip()))
|
||||
|
||||
|
||||
def _get_current_value(caller, keyname, formatter=str):
|
||||
"Return current value, marking if value comes from parent or set in this prototype"
|
||||
prot = _get_menu_prototype(caller)
|
||||
if keyname in prot:
|
||||
# value in current prot
|
||||
return "Current {}: {}".format(keyname, formatter(prot[keyname]))
|
||||
flat_prot = _get_flat_menu_prototype(caller)
|
||||
if keyname in flat_prot:
|
||||
# value in flattened prot
|
||||
return "Current {} (|binherited|n): {}".format(keyname, formatter(flat_prot[keyname]))
|
||||
return "[No {} set]".format(keyname)
|
||||
|
||||
|
||||
# Menu nodes ------------------------------
|
||||
|
||||
|
||||
|
|
@ -363,12 +387,13 @@ def _check_prototype_key(caller, key):
|
|||
|
||||
|
||||
def node_prototype_key(caller):
|
||||
prototype = _get_menu_prototype(caller)
|
||||
|
||||
text = """
|
||||
The |cPrototype-Key|n uniquely identifies the prototype and is |wmandatory|n. It is used to
|
||||
find and use the prototype to spawn new entities. It is not case sensitive.
|
||||
|
||||
{current}"""
|
||||
{current}""".format(current=_get_current_value(caller, "prototype_key"))
|
||||
|
||||
helptext = """
|
||||
The prototype-key is not itself used when spawnng the new object, but is only used for
|
||||
managing, storing and loading the prototype. It must be globally unique, so existing keys
|
||||
|
|
@ -376,12 +401,6 @@ def node_prototype_key(caller):
|
|||
prototype will be loaded.
|
||||
"""
|
||||
|
||||
old_key = prototype.get('prototype_key', None)
|
||||
if old_key:
|
||||
text = text.format(current="Currently set to '|w{key}|n'".format(key=old_key))
|
||||
else:
|
||||
text = text.format(current="Currently |runset|n (required).")
|
||||
|
||||
options = _wizard_options("prototype_key", "index", "prototype_parent")
|
||||
options.append({"key": "_default",
|
||||
"goto": _check_prototype_key})
|
||||
|
|
@ -502,9 +521,6 @@ def _typeclass_select(caller, typeclass):
|
|||
|
||||
@list_node(_all_typeclasses, _typeclass_select)
|
||||
def node_typeclass(caller):
|
||||
prototype = _get_menu_prototype(caller)
|
||||
typeclass = prototype.get("typeclass")
|
||||
|
||||
text = """
|
||||
The |cTypeclass|n defines what 'type' of object this is - the actual working code to use.
|
||||
|
||||
|
|
@ -512,7 +528,8 @@ def node_typeclass(caller):
|
|||
one of the prototype's |cparents|n.
|
||||
|
||||
{current}
|
||||
"""
|
||||
""".format(current=_get_current_value(caller, "typeclass"))
|
||||
|
||||
helptext = """
|
||||
A |nTypeclass|n is specified by the actual python-path to the class definition in the
|
||||
Evennia code structure.
|
||||
|
|
@ -521,14 +538,6 @@ def node_typeclass(caller):
|
|||
effects or expects certain values depend greatly on the code in play.
|
||||
"""
|
||||
|
||||
if typeclass:
|
||||
text = text.format(
|
||||
current="Current typeclass is |y{typeclass}|n.".format(typeclass=typeclass))
|
||||
else:
|
||||
text = text.format(
|
||||
current="Using default typeclass {typeclass}.".format(
|
||||
typeclass=settings.BASE_OBJECT_TYPECLASS))
|
||||
|
||||
text = (text, helptext)
|
||||
|
||||
options = _wizard_options("typeclass", "prototype_parent", "key", color="|W")
|
||||
|
|
@ -541,14 +550,12 @@ def node_typeclass(caller):
|
|||
|
||||
|
||||
def node_key(caller):
|
||||
prototype = _get_menu_prototype(caller)
|
||||
key = prototype.get("key")
|
||||
|
||||
text = """
|
||||
The |cKey|n is the given name of the object to spawn. This will retain the given case.
|
||||
|
||||
{current}
|
||||
"""
|
||||
""".format(current=_get_current_value(caller, "key"))
|
||||
|
||||
helptext = """
|
||||
The key should often not be identical for every spawned object. Using a randomising
|
||||
$protfunc can be used, for example |c$choice(Alan, Tom, John)|n will give one of the three
|
||||
|
|
@ -558,11 +565,6 @@ def node_key(caller):
|
|||
{pfuncs}
|
||||
""".format(pfuncs=_format_protfuncs())
|
||||
|
||||
if key:
|
||||
text = text.format(current="Current key is '{key}'.".format(key=key))
|
||||
else:
|
||||
text = text.format(current="The key is currently unset.")
|
||||
|
||||
text = (text, helptext)
|
||||
|
||||
options = _wizard_options("key", "typeclass", "aliases")
|
||||
|
|
@ -578,8 +580,6 @@ def node_key(caller):
|
|||
|
||||
|
||||
def node_aliases(caller):
|
||||
prototype = _get_menu_prototype(caller)
|
||||
aliases = prototype.get("aliases")
|
||||
|
||||
text = """
|
||||
|cAliases|n are alternative ways to address an object, next to its |cKey|n. Aliases are not
|
||||
|
|
@ -588,7 +588,8 @@ def node_aliases(caller):
|
|||
Add multiple aliases separating with commas.
|
||||
|
||||
{current}
|
||||
"""
|
||||
""".format(current=_get_current_value(caller, "aliases"))
|
||||
|
||||
helptext = """
|
||||
Aliases are fixed alternative identifiers and are stored with the new object.
|
||||
|
||||
|
|
@ -597,11 +598,6 @@ def node_aliases(caller):
|
|||
{pfuncs}
|
||||
""".format(pfuncs=_format_protfuncs())
|
||||
|
||||
if aliases:
|
||||
text = text.format(current="Current aliases are '|c{aliases}|n'.".format(aliases=aliases))
|
||||
else:
|
||||
text = text.format(current="No aliases are set.")
|
||||
|
||||
text = (text, helptext)
|
||||
|
||||
options = _wizard_options("aliases", "key", "attrs")
|
||||
|
|
@ -703,8 +699,6 @@ def _examine_attr(caller, selection):
|
|||
|
||||
@list_node(_caller_attrs)
|
||||
def node_attrs(caller):
|
||||
prot = _get_menu_prototype(caller)
|
||||
attrs = prot.get("attrs")
|
||||
|
||||
text = """
|
||||
|cAttributes|n are custom properties of the object. Enter attributes on one of these forms:
|
||||
|
|
@ -717,7 +711,8 @@ def node_attrs(caller):
|
|||
(attrname;;lockstring=value). Attribute values can have embedded $protfuncs.
|
||||
|
||||
{current}
|
||||
"""
|
||||
""".format(current=_get_current_value(caller, "attrs"))
|
||||
|
||||
helptext = """
|
||||
Most commonly, Attributes don't need any categories or locks. If using locks, the lock-types
|
||||
'attredit', 'attrread' are used to limiting editing and viewing of the Attribute. Putting
|
||||
|
|
@ -729,12 +724,6 @@ def node_attrs(caller):
|
|||
{pfuncs}
|
||||
""".format(pfuncs=_format_protfuncs())
|
||||
|
||||
if attrs:
|
||||
text = text.format(current="Current attrs {attrs}.".format(
|
||||
attrs=attrs))
|
||||
else:
|
||||
text = text.format(current="No attrs are set.")
|
||||
|
||||
text = (text, helptext)
|
||||
|
||||
options = _wizard_options("attrs", "aliases", "tags")
|
||||
|
|
@ -835,7 +824,10 @@ def node_tags(caller):
|
|||
tagname
|
||||
tagname;category
|
||||
tagname;category;data
|
||||
"""
|
||||
|
||||
{current}
|
||||
""".format(current=_get_current_value(caller, 'tags'))
|
||||
|
||||
helptext = """
|
||||
Tags are shared between all objects with that tag. So the 'data' field (which is not
|
||||
commonly used) can only hold eventual info about the Tag itself, not about the individual
|
||||
|
|
@ -855,8 +847,6 @@ def node_tags(caller):
|
|||
|
||||
|
||||
def node_locks(caller):
|
||||
prototype = _get_menu_prototype(caller)
|
||||
locks = prototype.get("locks")
|
||||
|
||||
text = """
|
||||
The |cLock string|n defines limitations for accessing various properties of the object once
|
||||
|
|
@ -868,7 +858,8 @@ def node_locks(caller):
|
|||
Separate multiple lockstrings by semicolons (;).
|
||||
|
||||
{current}
|
||||
"""
|
||||
""".format(current=_get_current_value(caller, 'locks'))
|
||||
|
||||
helptext = """
|
||||
Here is an example of a lock string constisting of two locks:
|
||||
|
||||
|
|
@ -884,11 +875,6 @@ def node_locks(caller):
|
|||
{lfuncs}
|
||||
""".format(lfuncs=_format_lockfuncs())
|
||||
|
||||
if locks:
|
||||
text = text.format(current="Current locks are '|y{locks}|n'.".format(locks=locks))
|
||||
else:
|
||||
text = text.format(current="No locks are set.")
|
||||
|
||||
text = (text, helptext)
|
||||
|
||||
options = _wizard_options("locks", "tags", "permissions")
|
||||
|
|
@ -904,15 +890,14 @@ def node_locks(caller):
|
|||
|
||||
|
||||
def node_permissions(caller):
|
||||
prototype = _get_menu_prototype(caller)
|
||||
permissions = prototype.get("permissions")
|
||||
|
||||
text = """
|
||||
|cPermissions|n are simple strings used to grant access to this object. A permission is used
|
||||
when a |clock|n is checked that contains the |wperm|n or |wpperm|n lock functions.
|
||||
|
||||
{current}
|
||||
"""
|
||||
""".format(current=_get_current_value(caller, "permissions"))
|
||||
|
||||
helptext = """
|
||||
Any string can act as a permission as long as a lock is set to look for it. Depending on the
|
||||
lock, having a permission could even be negative (i.e. the lock is only passed if you
|
||||
|
|
@ -925,12 +910,6 @@ def node_permissions(caller):
|
|||
having the |cpermission|n "Builder" or higher.
|
||||
""".format(settings.PERMISSION_HIERARCHY)
|
||||
|
||||
if permissions:
|
||||
text = text.format(current="Current permissions are {permissions}.".format(
|
||||
permissions=permissions))
|
||||
else:
|
||||
text = text.format(current="No permissions are set.")
|
||||
|
||||
text = (text, helptext)
|
||||
|
||||
options = _wizard_options("permissions", "destination", "location")
|
||||
|
|
@ -946,15 +925,14 @@ def node_permissions(caller):
|
|||
|
||||
|
||||
def node_location(caller):
|
||||
prototype = _get_menu_prototype(caller)
|
||||
location = prototype.get("location")
|
||||
|
||||
text = """
|
||||
The |cLocation|n of this object in the world. If not given, the object will spawn
|
||||
in the inventory of |c{caller}|n instead.
|
||||
|
||||
{current}
|
||||
""".format(caller=caller.key)
|
||||
""".format(caller=caller.key, current=_get_current_value(caller, "location"))
|
||||
|
||||
helptext = """
|
||||
You get the most control by not specifying the location - you can then teleport the spawned
|
||||
objects as needed later. Setting the location may be useful for quickly populating a given
|
||||
|
|
@ -964,11 +942,6 @@ def node_location(caller):
|
|||
{pfuncs}
|
||||
""".format(pfuncs=_format_protfuncs)
|
||||
|
||||
if location:
|
||||
text = text.format(current="Current location is {location}.".format(location=location))
|
||||
else:
|
||||
text = text.format(current="Default location is {}'s inventory.".format(caller))
|
||||
|
||||
text = (text, helptext)
|
||||
|
||||
options = _wizard_options("location", "permissions", "home")
|
||||
|
|
@ -984,8 +957,6 @@ def node_location(caller):
|
|||
|
||||
|
||||
def node_home(caller):
|
||||
prototype = _get_menu_prototype(caller)
|
||||
home = prototype.get("home")
|
||||
|
||||
text = """
|
||||
The |cHome|n location of an object is often only used as a backup - this is where the object
|
||||
|
|
@ -993,7 +964,7 @@ def node_home(caller):
|
|||
home for characters to quickly move back to. If unset, the global home default will be used.
|
||||
|
||||
{current}
|
||||
"""
|
||||
""".format(current=_get_current_value(caller, "home"))
|
||||
helptext = """
|
||||
The location can be specified as as #dbref but can also be explicitly searched for using
|
||||
$obj(name).
|
||||
|
|
@ -1001,12 +972,6 @@ def node_home(caller):
|
|||
The home location is often not used except as a backup. It should never be unset.
|
||||
"""
|
||||
|
||||
if home:
|
||||
text = text.format(current="Current home location is {home}.".format(home=home))
|
||||
else:
|
||||
text = text.format(
|
||||
current="Default home location ({home}) used.".format(home=settings.DEFAULT_HOME))
|
||||
|
||||
text = (text, helptext)
|
||||
|
||||
options = _wizard_options("home", "aliases", "destination")
|
||||
|
|
@ -1022,25 +987,19 @@ def node_home(caller):
|
|||
|
||||
|
||||
def node_destination(caller):
|
||||
prototype = _get_menu_prototype(caller)
|
||||
dest = prototype.get("dest")
|
||||
|
||||
text = """
|
||||
The object's |cDestination|n is usually only set for Exit-like objects and designates where
|
||||
the exit 'leads to'. It's usually unset for all other types of objects.
|
||||
|
||||
{current}
|
||||
"""
|
||||
""".format(current=_get_current_node(caller, "destination"))
|
||||
|
||||
helptext = """
|
||||
The destination can be given as a #dbref but can also be explicitly searched for using
|
||||
$obj(name).
|
||||
"""
|
||||
|
||||
if dest:
|
||||
text = text.format(current="Current destination is {dest}.".format(dest=dest))
|
||||
else:
|
||||
text = text.format("No destination is set (default).")
|
||||
|
||||
text = (text, helptext)
|
||||
|
||||
options = _wizard_options("destination", "home", "prototype_desc")
|
||||
|
|
@ -1057,24 +1016,17 @@ def node_destination(caller):
|
|||
|
||||
def node_prototype_desc(caller):
|
||||
|
||||
prototype = _get_menu_prototype(caller)
|
||||
desc = prototype.get("prototype_desc", None)
|
||||
|
||||
text = """
|
||||
The |cPrototype-Description|n optionally briefly describes the prototype when it's viewed in
|
||||
listings.
|
||||
|
||||
{current}
|
||||
"""
|
||||
""".format(current=_get_current_value(caller, "prototype_desc"))
|
||||
|
||||
helptext = """
|
||||
Giving a brief description helps you and others to locate the prototype for use later.
|
||||
"""
|
||||
|
||||
if desc:
|
||||
text = text.format(current="The current meta desc is:\n\"|w{desc}|n\"".format(desc=desc))
|
||||
else:
|
||||
text = text.format(current="Prototype-Description is currently unset.")
|
||||
|
||||
text = (text, helptext)
|
||||
|
||||
options = _wizard_options("prototype_desc", "prototype_key", "prototype_tags")
|
||||
|
|
@ -1091,26 +1043,19 @@ def node_prototype_desc(caller):
|
|||
|
||||
|
||||
def node_prototype_tags(caller):
|
||||
prototype = _get_menu_prototype(caller)
|
||||
|
||||
text = """
|
||||
|cPrototype-Tags|n can be used to classify and find prototypes in listings Tag names are not
|
||||
case-sensitive and can have not have a custom category. Separate multiple tags by commas.
|
||||
|
||||
{current}
|
||||
"""
|
||||
""".format(current=_get_current_value(caller, "prototype_tags"))
|
||||
helptext = """
|
||||
Using prototype-tags is a good way to organize and group large numbers of prototypes by
|
||||
genre, type etc. Under the hood, prototypes' tags will all be stored with the category
|
||||
'{tagmetacategory}'.
|
||||
""".format(tagmetacategory=protlib._PROTOTYPE_TAG_META_CATEGORY)
|
||||
|
||||
tags = prototype.get('prototype_tags', [])
|
||||
|
||||
if tags:
|
||||
text = text.format(current="The current tags are:\n|w{tags}|n".format(tags=tags))
|
||||
else:
|
||||
text = text.format(current="No tags are currently set.")
|
||||
|
||||
text = (text, helptext)
|
||||
|
||||
options = _wizard_options("prototype_tags", "prototype_desc", "prototype_locks")
|
||||
|
|
@ -1127,8 +1072,6 @@ def node_prototype_tags(caller):
|
|||
|
||||
|
||||
def node_prototype_locks(caller):
|
||||
prototype = _get_menu_prototype(caller)
|
||||
locks = prototype.get('prototype_locks', '')
|
||||
|
||||
text = """
|
||||
|cPrototype-Locks|n are used to limit access to this prototype when someone else is trying
|
||||
|
|
@ -1142,19 +1085,14 @@ def node_prototype_locks(caller):
|
|||
If unsure, leave as default.
|
||||
|
||||
{current}
|
||||
"""
|
||||
""".format(current=_get_current_value(caller, "prototype_locks"))
|
||||
|
||||
helptext = """
|
||||
Prototype locks can be used when there are different tiers of builders or for developers to
|
||||
produce 'base prototypes' only meant for builders to inherit and expand on rather than
|
||||
change.
|
||||
"""
|
||||
|
||||
if locks:
|
||||
text = text.format(current="Current lock is |w'{lockstring}'|n".format(lockstring=locks))
|
||||
else:
|
||||
text = text.format(
|
||||
current="Default lock set: |w'spawn:all(); edit:id({dbref}) or perm(Admin)'|n".format(dbref=caller.id))
|
||||
|
||||
text = (text, helptext)
|
||||
|
||||
options = _wizard_options("prototype_locks", "prototype_tags", "index")
|
||||
|
|
|
|||
|
|
@ -173,9 +173,11 @@ def flatten_prototype(prototype):
|
|||
flattened (dict): The final, flattened prototype.
|
||||
|
||||
"""
|
||||
protparents = {prot['prototype_key'].lower(): prot for prot in protlib.search_prototype()}
|
||||
protlib.validate_prototype(prototype, None, protparents, is_prototype_base=True)
|
||||
return _get_prototype(prototype, {}, protparents)
|
||||
if prototype:
|
||||
protparents = {prot['prototype_key'].lower(): prot for prot in protlib.search_prototype()}
|
||||
protlib.validate_prototype(prototype, None, protparents, is_prototype_base=True)
|
||||
return _get_prototype(prototype, {}, protparents)
|
||||
return {}
|
||||
|
||||
|
||||
# obj-related prototype functions
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue