Show flattened current values in menu

This commit is contained in:
Griatch 2018-07-25 14:11:44 +02:00
parent 405293729f
commit e09576812f
2 changed files with 59 additions and 119 deletions

View file

@ -42,6 +42,17 @@ def _get_menu_prototype(caller):
return prototype 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): def _set_menu_prototype(caller, prototype):
"""Set the prototype with existing one""" """Set the prototype with existing one"""
caller.ndb._menutree.olc_prototype = prototype caller.ndb._menutree.olc_prototype = prototype
@ -230,6 +241,19 @@ def _format_lockfuncs():
docs=utils.justify(lockfunc.__doc__.strip(), align='l', indent=10).strip())) 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 ------------------------------ # Menu nodes ------------------------------
@ -363,12 +387,13 @@ def _check_prototype_key(caller, key):
def node_prototype_key(caller): def node_prototype_key(caller):
prototype = _get_menu_prototype(caller)
text = """ text = """
The |cPrototype-Key|n uniquely identifies the prototype and is |wmandatory|n. It is used to 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. 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 = """ helptext = """
The prototype-key is not itself used when spawnng the new object, but is only used for 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 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. 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 = _wizard_options("prototype_key", "index", "prototype_parent")
options.append({"key": "_default", options.append({"key": "_default",
"goto": _check_prototype_key}) "goto": _check_prototype_key})
@ -502,9 +521,6 @@ def _typeclass_select(caller, typeclass):
@list_node(_all_typeclasses, _typeclass_select) @list_node(_all_typeclasses, _typeclass_select)
def node_typeclass(caller): def node_typeclass(caller):
prototype = _get_menu_prototype(caller)
typeclass = prototype.get("typeclass")
text = """ text = """
The |cTypeclass|n defines what 'type' of object this is - the actual working code to use. 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. one of the prototype's |cparents|n.
{current} {current}
""" """.format(current=_get_current_value(caller, "typeclass"))
helptext = """ helptext = """
A |nTypeclass|n is specified by the actual python-path to the class definition in the A |nTypeclass|n is specified by the actual python-path to the class definition in the
Evennia code structure. Evennia code structure.
@ -521,14 +538,6 @@ def node_typeclass(caller):
effects or expects certain values depend greatly on the code in play. 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) text = (text, helptext)
options = _wizard_options("typeclass", "prototype_parent", "key", color="|W") options = _wizard_options("typeclass", "prototype_parent", "key", color="|W")
@ -541,14 +550,12 @@ def node_typeclass(caller):
def node_key(caller): def node_key(caller):
prototype = _get_menu_prototype(caller)
key = prototype.get("key")
text = """ text = """
The |cKey|n is the given name of the object to spawn. This will retain the given case. The |cKey|n is the given name of the object to spawn. This will retain the given case.
{current} {current}
""" """.format(current=_get_current_value(caller, "key"))
helptext = """ helptext = """
The key should often not be identical for every spawned object. Using a randomising 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 $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} {pfuncs}
""".format(pfuncs=_format_protfuncs()) """.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) text = (text, helptext)
options = _wizard_options("key", "typeclass", "aliases") options = _wizard_options("key", "typeclass", "aliases")
@ -578,8 +580,6 @@ def node_key(caller):
def node_aliases(caller): def node_aliases(caller):
prototype = _get_menu_prototype(caller)
aliases = prototype.get("aliases")
text = """ text = """
|cAliases|n are alternative ways to address an object, next to its |cKey|n. Aliases are not |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. Add multiple aliases separating with commas.
{current} {current}
""" """.format(current=_get_current_value(caller, "aliases"))
helptext = """ helptext = """
Aliases are fixed alternative identifiers and are stored with the new object. Aliases are fixed alternative identifiers and are stored with the new object.
@ -597,11 +598,6 @@ def node_aliases(caller):
{pfuncs} {pfuncs}
""".format(pfuncs=_format_protfuncs()) """.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) text = (text, helptext)
options = _wizard_options("aliases", "key", "attrs") options = _wizard_options("aliases", "key", "attrs")
@ -703,8 +699,6 @@ def _examine_attr(caller, selection):
@list_node(_caller_attrs) @list_node(_caller_attrs)
def node_attrs(caller): def node_attrs(caller):
prot = _get_menu_prototype(caller)
attrs = prot.get("attrs")
text = """ text = """
|cAttributes|n are custom properties of the object. Enter attributes on one of these forms: |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. (attrname;;lockstring=value). Attribute values can have embedded $protfuncs.
{current} {current}
""" """.format(current=_get_current_value(caller, "attrs"))
helptext = """ helptext = """
Most commonly, Attributes don't need any categories or locks. If using locks, the lock-types 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 'attredit', 'attrread' are used to limiting editing and viewing of the Attribute. Putting
@ -729,12 +724,6 @@ def node_attrs(caller):
{pfuncs} {pfuncs}
""".format(pfuncs=_format_protfuncs()) """.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) text = (text, helptext)
options = _wizard_options("attrs", "aliases", "tags") options = _wizard_options("attrs", "aliases", "tags")
@ -835,7 +824,10 @@ def node_tags(caller):
tagname tagname
tagname;category tagname;category
tagname;category;data tagname;category;data
"""
{current}
""".format(current=_get_current_value(caller, 'tags'))
helptext = """ helptext = """
Tags are shared between all objects with that tag. So the 'data' field (which is not 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 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): def node_locks(caller):
prototype = _get_menu_prototype(caller)
locks = prototype.get("locks")
text = """ text = """
The |cLock string|n defines limitations for accessing various properties of the object once 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 (;). Separate multiple lockstrings by semicolons (;).
{current} {current}
""" """.format(current=_get_current_value(caller, 'locks'))
helptext = """ helptext = """
Here is an example of a lock string constisting of two locks: Here is an example of a lock string constisting of two locks:
@ -884,11 +875,6 @@ def node_locks(caller):
{lfuncs} {lfuncs}
""".format(lfuncs=_format_lockfuncs()) """.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) text = (text, helptext)
options = _wizard_options("locks", "tags", "permissions") options = _wizard_options("locks", "tags", "permissions")
@ -904,15 +890,14 @@ def node_locks(caller):
def node_permissions(caller): def node_permissions(caller):
prototype = _get_menu_prototype(caller)
permissions = prototype.get("permissions")
text = """ text = """
|cPermissions|n are simple strings used to grant access to this object. A permission is used |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. when a |clock|n is checked that contains the |wperm|n or |wpperm|n lock functions.
{current} {current}
""" """.format(current=_get_current_value(caller, "permissions"))
helptext = """ helptext = """
Any string can act as a permission as long as a lock is set to look for it. Depending on the 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 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. having the |cpermission|n "Builder" or higher.
""".format(settings.PERMISSION_HIERARCHY) """.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) text = (text, helptext)
options = _wizard_options("permissions", "destination", "location") options = _wizard_options("permissions", "destination", "location")
@ -946,15 +925,14 @@ def node_permissions(caller):
def node_location(caller): def node_location(caller):
prototype = _get_menu_prototype(caller)
location = prototype.get("location")
text = """ text = """
The |cLocation|n of this object in the world. If not given, the object will spawn The |cLocation|n of this object in the world. If not given, the object will spawn
in the inventory of |c{caller}|n instead. in the inventory of |c{caller}|n instead.
{current} {current}
""".format(caller=caller.key) """.format(caller=caller.key, current=_get_current_value(caller, "location"))
helptext = """ helptext = """
You get the most control by not specifying the location - you can then teleport the spawned 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 objects as needed later. Setting the location may be useful for quickly populating a given
@ -964,11 +942,6 @@ def node_location(caller):
{pfuncs} {pfuncs}
""".format(pfuncs=_format_protfuncs) """.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) text = (text, helptext)
options = _wizard_options("location", "permissions", "home") options = _wizard_options("location", "permissions", "home")
@ -984,8 +957,6 @@ def node_location(caller):
def node_home(caller): def node_home(caller):
prototype = _get_menu_prototype(caller)
home = prototype.get("home")
text = """ text = """
The |cHome|n location of an object is often only used as a backup - this is where the object 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. home for characters to quickly move back to. If unset, the global home default will be used.
{current} {current}
""" """.format(current=_get_current_value(caller, "home"))
helptext = """ helptext = """
The location can be specified as as #dbref but can also be explicitly searched for using The location can be specified as as #dbref but can also be explicitly searched for using
$obj(name). $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. 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) text = (text, helptext)
options = _wizard_options("home", "aliases", "destination") options = _wizard_options("home", "aliases", "destination")
@ -1022,25 +987,19 @@ def node_home(caller):
def node_destination(caller): def node_destination(caller):
prototype = _get_menu_prototype(caller)
dest = prototype.get("dest")
text = """ text = """
The object's |cDestination|n is usually only set for Exit-like objects and designates where 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. the exit 'leads to'. It's usually unset for all other types of objects.
{current} {current}
""" """.format(current=_get_current_node(caller, "destination"))
helptext = """ helptext = """
The destination can be given as a #dbref but can also be explicitly searched for using The destination can be given as a #dbref but can also be explicitly searched for using
$obj(name). $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) text = (text, helptext)
options = _wizard_options("destination", "home", "prototype_desc") options = _wizard_options("destination", "home", "prototype_desc")
@ -1057,24 +1016,17 @@ def node_destination(caller):
def node_prototype_desc(caller): def node_prototype_desc(caller):
prototype = _get_menu_prototype(caller)
desc = prototype.get("prototype_desc", None)
text = """ text = """
The |cPrototype-Description|n optionally briefly describes the prototype when it's viewed in The |cPrototype-Description|n optionally briefly describes the prototype when it's viewed in
listings. listings.
{current} {current}
""" """.format(current=_get_current_value(caller, "prototype_desc"))
helptext = """ helptext = """
Giving a brief description helps you and others to locate the prototype for use later. 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) text = (text, helptext)
options = _wizard_options("prototype_desc", "prototype_key", "prototype_tags") options = _wizard_options("prototype_desc", "prototype_key", "prototype_tags")
@ -1091,26 +1043,19 @@ def node_prototype_desc(caller):
def node_prototype_tags(caller): def node_prototype_tags(caller):
prototype = _get_menu_prototype(caller)
text = """ text = """
|cPrototype-Tags|n can be used to classify and find prototypes in listings Tag names are not |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. case-sensitive and can have not have a custom category. Separate multiple tags by commas.
{current} {current}
""" """.format(current=_get_current_value(caller, "prototype_tags"))
helptext = """ helptext = """
Using prototype-tags is a good way to organize and group large numbers of prototypes by 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 genre, type etc. Under the hood, prototypes' tags will all be stored with the category
'{tagmetacategory}'. '{tagmetacategory}'.
""".format(tagmetacategory=protlib._PROTOTYPE_TAG_META_CATEGORY) """.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) text = (text, helptext)
options = _wizard_options("prototype_tags", "prototype_desc", "prototype_locks") options = _wizard_options("prototype_tags", "prototype_desc", "prototype_locks")
@ -1127,8 +1072,6 @@ def node_prototype_tags(caller):
def node_prototype_locks(caller): def node_prototype_locks(caller):
prototype = _get_menu_prototype(caller)
locks = prototype.get('prototype_locks', '')
text = """ text = """
|cPrototype-Locks|n are used to limit access to this prototype when someone else is trying |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. If unsure, leave as default.
{current} {current}
""" """.format(current=_get_current_value(caller, "prototype_locks"))
helptext = """ helptext = """
Prototype locks can be used when there are different tiers of builders or for developers to 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 produce 'base prototypes' only meant for builders to inherit and expand on rather than
change. 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) text = (text, helptext)
options = _wizard_options("prototype_locks", "prototype_tags", "index") options = _wizard_options("prototype_locks", "prototype_tags", "index")

View file

@ -173,9 +173,11 @@ def flatten_prototype(prototype):
flattened (dict): The final, flattened prototype. flattened (dict): The final, flattened prototype.
""" """
if prototype:
protparents = {prot['prototype_key'].lower(): prot for prot in protlib.search_prototype()} protparents = {prot['prototype_key'].lower(): prot for prot in protlib.search_prototype()}
protlib.validate_prototype(prototype, None, protparents, is_prototype_base=True) protlib.validate_prototype(prototype, None, protparents, is_prototype_base=True)
return _get_prototype(prototype, {}, protparents) return _get_prototype(prototype, {}, protparents)
return {}
# obj-related prototype functions # obj-related prototype functions