Start adding menu OLC mechanic for spawner.
The EvMenu behaves strangely; going from desc->tags by setting the description means that the back-option no longer works, giving an error that the desc-node is not defined ...
This commit is contained in:
parent
641ea746a5
commit
2d791252e3
3 changed files with 227 additions and 7 deletions
|
|
@ -15,7 +15,7 @@ from evennia.utils.eveditor import EvEditor
|
||||||
from evennia.utils.evmore import EvMore
|
from evennia.utils.evmore import EvMore
|
||||||
from evennia.utils.spawner import (spawn, search_prototype, list_prototypes,
|
from evennia.utils.spawner import (spawn, search_prototype, list_prototypes,
|
||||||
save_db_prototype, build_metaproto, validate_prototype,
|
save_db_prototype, build_metaproto, validate_prototype,
|
||||||
delete_db_prototype, PermissionError)
|
delete_db_prototype, PermissionError, start_olc)
|
||||||
from evennia.utils.ansi import raw
|
from evennia.utils.ansi import raw
|
||||||
|
|
||||||
COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
|
COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
|
||||||
|
|
@ -2806,7 +2806,8 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
|
||||||
@spawn/show [<key>]
|
@spawn/show [<key>]
|
||||||
|
|
||||||
@spawn/save <key>[;desc[;tag,tag[,...][;lockstring]]] = <prototype_dict>
|
@spawn/save <key>[;desc[;tag,tag[,...][;lockstring]]] = <prototype_dict>
|
||||||
@spawn/menu
|
@spawn/menu [<key>]
|
||||||
|
@olc - equivalent to @spawn/menu
|
||||||
|
|
||||||
Switches:
|
Switches:
|
||||||
noloc - allow location to be None if not specified explicitly. Otherwise,
|
noloc - allow location to be None if not specified explicitly. Otherwise,
|
||||||
|
|
@ -2816,7 +2817,7 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
|
||||||
show, examine - inspect prototype by key. If not given, acts like list.
|
show, examine - inspect prototype by key. If not given, acts like list.
|
||||||
save - save a prototype to the database. It will be listable by /list.
|
save - save a prototype to the database. It will be listable by /list.
|
||||||
delete - remove a prototype from database, if allowed to.
|
delete - remove a prototype from database, if allowed to.
|
||||||
menu - manipulate prototype in a menu interface.
|
menu, olc - create/manipulate prototype in a menu interface.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
@spawn GOBLIN
|
@spawn GOBLIN
|
||||||
|
|
@ -2844,7 +2845,8 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
key = "@spawn"
|
key = "@spawn"
|
||||||
switch_options = ("noloc", "search", "list", "show", "save", "delete", "menu")
|
aliases = ["@olc"]
|
||||||
|
switch_options = ("noloc", "search", "list", "show", "save", "delete", "menu", "olc")
|
||||||
locks = "cmd:perm(spawn) or perm(Builder)"
|
locks = "cmd:perm(spawn) or perm(Builder)"
|
||||||
help_category = "Building"
|
help_category = "Building"
|
||||||
|
|
||||||
|
|
@ -2904,6 +2906,22 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
|
||||||
|
|
||||||
caller = self.caller
|
caller = self.caller
|
||||||
|
|
||||||
|
if self.cmdstring == "olc" or 'menu' in self.switches or 'olc' in self.switches:
|
||||||
|
# OLC menu mode
|
||||||
|
metaprot = None
|
||||||
|
if self.lhs:
|
||||||
|
key = self.lhs
|
||||||
|
metaprot = search_prototype(key=key, return_meta=True)
|
||||||
|
if len(metaprot) > 1:
|
||||||
|
caller.msg("More than one match for {}:\n{}".format(
|
||||||
|
key, "\n".join(mproto.key for mproto in metaprot)))
|
||||||
|
return
|
||||||
|
elif metaprot:
|
||||||
|
# one match
|
||||||
|
metaprot = metaprot[0]
|
||||||
|
start_olc(caller, self.session, metaprot)
|
||||||
|
return
|
||||||
|
|
||||||
if 'search' in self.switches:
|
if 'search' in self.switches:
|
||||||
# query for a key match
|
# query for a key match
|
||||||
if not self.args:
|
if not self.args:
|
||||||
|
|
|
||||||
|
|
@ -945,9 +945,11 @@ class EvMenu(object):
|
||||||
node (str): The formatted node to display.
|
node (str): The formatted node to display.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
screen_width = self._session.protocol_flags.get("SCREENWIDTH", {0: 78})[0]
|
||||||
|
|
||||||
nodetext_width_max = max(m_len(line) for line in nodetext.split("\n"))
|
nodetext_width_max = max(m_len(line) for line in nodetext.split("\n"))
|
||||||
options_width_max = max(m_len(line) for line in optionstext.split("\n"))
|
options_width_max = max(m_len(line) for line in optionstext.split("\n"))
|
||||||
total_width = max(options_width_max, nodetext_width_max)
|
total_width = min(screen_width, max(options_width_max, nodetext_width_max))
|
||||||
separator1 = "_" * total_width + "\n\n" if nodetext_width_max else ""
|
separator1 = "_" * total_width + "\n\n" if nodetext_width_max else ""
|
||||||
separator2 = "\n" + "_" * total_width + "\n\n" if total_width else ""
|
separator2 = "\n" + "_" * total_width + "\n\n" if total_width else ""
|
||||||
return separator1 + "|n" + nodetext + "|n" + separator2 + "|n" + optionstext
|
return separator1 + "|n" + nodetext + "|n" + separator2 + "|n" + optionstext
|
||||||
|
|
|
||||||
|
|
@ -109,17 +109,19 @@ from django.conf import settings
|
||||||
from random import randint
|
from random import randint
|
||||||
import evennia
|
import evennia
|
||||||
from evennia.objects.models import ObjectDB
|
from evennia.objects.models import ObjectDB
|
||||||
from evennia.utils.utils import make_iter, all_from_module, dbid_to_obj, is_iter
|
from evennia.utils.utils import make_iter, all_from_module, dbid_to_obj, is_iter, crop
|
||||||
|
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from evennia.scripts.scripts import DefaultScript
|
from evennia.scripts.scripts import DefaultScript
|
||||||
from evennia.utils.create import create_script
|
from evennia.utils.create import create_script
|
||||||
from evennia.utils.evtable import EvTable
|
from evennia.utils.evtable import EvTable
|
||||||
|
from evennia.utils.evmenu import EvMenu
|
||||||
|
|
||||||
|
|
||||||
_CREATE_OBJECT_KWARGS = ("key", "location", "home", "destination")
|
_CREATE_OBJECT_KWARGS = ("key", "location", "home", "destination")
|
||||||
_MODULE_PROTOTYPES = {}
|
_MODULE_PROTOTYPES = {}
|
||||||
_MODULE_PROTOTYPE_MODULES = {}
|
_MODULE_PROTOTYPE_MODULES = {}
|
||||||
|
_MENU_CROP_WIDTH = 15
|
||||||
|
|
||||||
|
|
||||||
class PermissionError(RuntimeError):
|
class PermissionError(RuntimeError):
|
||||||
|
|
@ -156,7 +158,7 @@ class DbPrototype(DefaultScript):
|
||||||
self.desc = "A prototype"
|
self.desc = "A prototype"
|
||||||
|
|
||||||
|
|
||||||
def build_metaproto(key, desc, locks, tags, prototype):
|
def build_metaproto(key='', desc='', locks='', tags=None, prototype=None):
|
||||||
"""
|
"""
|
||||||
Create a metaproto from combinant parts.
|
Create a metaproto from combinant parts.
|
||||||
|
|
||||||
|
|
@ -657,6 +659,204 @@ def spawn(*prototypes, **kwargs):
|
||||||
return _batch_create_object(*objsparams)
|
return _batch_create_object(*objsparams)
|
||||||
|
|
||||||
|
|
||||||
|
# prototype design menu nodes
|
||||||
|
|
||||||
|
def _get_menu_metaprot(caller):
|
||||||
|
if hasattr(caller.ndb._menutree, "olc_metaprot"):
|
||||||
|
return caller.ndb._menutree.olc_metaprot
|
||||||
|
else:
|
||||||
|
metaproto = build_metaproto(None, '', [], [], None)
|
||||||
|
caller.ndb._menutree.olc_metaprot = metaproto
|
||||||
|
caller.ndb._menutree.olc_new = True
|
||||||
|
return metaproto
|
||||||
|
|
||||||
|
|
||||||
|
def _set_menu_metaprot(caller, field, value):
|
||||||
|
metaprot = _get_menu_metaprot(caller)
|
||||||
|
kwargs = dict(metaprot.__dict__)
|
||||||
|
kwargs[field] = value
|
||||||
|
caller.ndb._menutree.olc_metaprot = build_metaproto(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def node_index(caller):
|
||||||
|
metaprot = _get_menu_metaprot(caller)
|
||||||
|
key = "|g{}|n".format(
|
||||||
|
crop(metaprot.key, _MENU_CROP_WIDTH)) if metaprot.key else "|rundefined, required|n"
|
||||||
|
desc = "|g{}|n".format(
|
||||||
|
crop(metaprot.desc, _MENU_CROP_WIDTH)) if metaprot.desc else "''"
|
||||||
|
tags = "|g{}|n".format(
|
||||||
|
crop(", ".join(metaprot.tags), _MENU_CROP_WIDTH)) if metaprot.tags else []
|
||||||
|
locks = "|g{}|n".format(
|
||||||
|
crop(", ".join(metaprot.locks), _MENU_CROP_WIDTH)) if metaprot.tags else []
|
||||||
|
prot = "|gdefined|n" if metaprot.prototype else "|rundefined, required|n"
|
||||||
|
|
||||||
|
text = ("|c --- Prototype wizard --- |n\n"
|
||||||
|
"(make choice; q to abort, h for help)")
|
||||||
|
options = (
|
||||||
|
{"desc": "Key ({})".format(key), "goto": "node_key"},
|
||||||
|
{"desc": "Description ({})".format(desc), "goto": "node_desc"},
|
||||||
|
{"desc": "Tags ({})".format(tags), "goto": "node_tags"},
|
||||||
|
{"desc": "Locks ({})".format(locks), "goto": "node_locks"},
|
||||||
|
{"desc": "Prototype ({})".format(prot), "goto": "node_prototype_index"})
|
||||||
|
return text, options
|
||||||
|
|
||||||
|
|
||||||
|
def _node_check_key(caller, key):
|
||||||
|
old_metaprot = search_prototype(key)
|
||||||
|
olc_new = caller.ndb._menutree.olc_new
|
||||||
|
key = key.strip().lower()
|
||||||
|
if old_metaprot:
|
||||||
|
# we are starting a new prototype that matches an existing
|
||||||
|
if not caller.locks.check_lockstring(caller, old_metaprot.locks, access_type='edit'):
|
||||||
|
# return to the node_key to try another key
|
||||||
|
caller.msg("Prototype '{key}' already exists and you don't "
|
||||||
|
"have permission to edit it.".format(key=key))
|
||||||
|
return "node_key"
|
||||||
|
elif olc_new:
|
||||||
|
# we are selecting an existing prototype to edit. Reset to index.
|
||||||
|
del caller.ndb._menutree.olc_new
|
||||||
|
caller.ndb._menutree.olc_metaprot = old_metaprot
|
||||||
|
caller.msg("Prototype already exists. Reloading.")
|
||||||
|
return "node_index"
|
||||||
|
|
||||||
|
# continue on
|
||||||
|
_set_menu_metaprot(caller, 'key', key)
|
||||||
|
caller.msg("Key '{key}' was set.".format(key=key))
|
||||||
|
return "node_desc"
|
||||||
|
|
||||||
|
|
||||||
|
def node_key(caller):
|
||||||
|
metaprot = _get_menu_metaprot(caller)
|
||||||
|
text = ["The |ckey|n must be unique and is used to find and use "
|
||||||
|
"the prototype to spawn new entities. It is not case sensitive."]
|
||||||
|
old_key = metaprot.key
|
||||||
|
if old_key:
|
||||||
|
text.append("Current key is '|y{key}|n'".format(key=old_key))
|
||||||
|
else:
|
||||||
|
text.append("The key is currently unset.")
|
||||||
|
text.append("Enter text or make choice (q for quit, h for help)")
|
||||||
|
text = "\n".join(text)
|
||||||
|
options = ({"desc": "forward (desc)",
|
||||||
|
"goto": "node_desc"},
|
||||||
|
{"desc": "back (index)",
|
||||||
|
"goto": "node_index"},
|
||||||
|
{"key": "_default",
|
||||||
|
"desc": "enter a key",
|
||||||
|
"goto": _node_check_key})
|
||||||
|
return text, options
|
||||||
|
|
||||||
|
|
||||||
|
def _node_check_desc(caller, desc):
|
||||||
|
desc = desc.strip()
|
||||||
|
_set_menu_metaprot(caller, 'desc', desc)
|
||||||
|
caller.msg("Description was set to '{desc}'.".format(desc=desc))
|
||||||
|
return "node_tags"
|
||||||
|
|
||||||
|
|
||||||
|
def node_desc(caller):
|
||||||
|
metaprot = _get_menu_metaprot(caller)
|
||||||
|
text = ["|cDescribe|n briefly the prototype for viewing in listings."]
|
||||||
|
desc = metaprot.desc
|
||||||
|
|
||||||
|
if desc:
|
||||||
|
text.append("The current desc is:\n\"|y{desc}|n\"".format(desc))
|
||||||
|
else:
|
||||||
|
text.append("Description is currently unset.")
|
||||||
|
text = "\n".join(text)
|
||||||
|
options = ({"desc": "forward (tags)",
|
||||||
|
"goto": "node_tags"},
|
||||||
|
{"desc": "back (key)",
|
||||||
|
"goto": "node_key"},
|
||||||
|
{"key": "_default",
|
||||||
|
"desc": "enter a description",
|
||||||
|
"goto": _node_check_desc})
|
||||||
|
|
||||||
|
return text, options
|
||||||
|
|
||||||
|
|
||||||
|
def _node_check_tags(caller, tags):
|
||||||
|
tags = [part.strip().lower() for part in tags.split(",")]
|
||||||
|
_set_menu_metaprot(caller, 'tags', tags)
|
||||||
|
caller.msg("Tags {tags} were set".format(tags=tags))
|
||||||
|
return "node_locks"
|
||||||
|
|
||||||
|
|
||||||
|
def node_tags(caller):
|
||||||
|
metaprot = _get_menu_metaprot(caller)
|
||||||
|
text = ["|cTags|n can be used to find prototypes. They are case-insitive. "
|
||||||
|
"Separate multiple by tags by commas."]
|
||||||
|
tags = metaprot.tags
|
||||||
|
|
||||||
|
if tags:
|
||||||
|
text.append("The current tags are:\n|y{tags}|n".format(tags))
|
||||||
|
else:
|
||||||
|
text.append("No tags are currently set.")
|
||||||
|
text = "\n".join(text)
|
||||||
|
options = ({"desc": "forward (locks)",
|
||||||
|
"goto": "node_locks"},
|
||||||
|
{"desc": "back (desc)",
|
||||||
|
"goto": "node_desc"},
|
||||||
|
{"key": "_default",
|
||||||
|
"desc": "enter tags separated by commas",
|
||||||
|
"goto": _node_check_tags})
|
||||||
|
return text, options
|
||||||
|
|
||||||
|
|
||||||
|
def _node_check_locks(caller, lockstring):
|
||||||
|
# TODO - have a way to validate lock string here
|
||||||
|
_set_menu_metaprot(caller, 'locks', lockstring)
|
||||||
|
caller.msg("Set lockstring '{lockstring}'.".format(lockstring=lockstring))
|
||||||
|
return "node_prototype_index"
|
||||||
|
|
||||||
|
|
||||||
|
def node_locks(caller):
|
||||||
|
metaprot = _get_menu_metaprot(caller)
|
||||||
|
text = ["Set |ylocks|n on the prototype. There are two valid lock types: "
|
||||||
|
"'edit' (who can edit the prototype) and 'use' (who can apply the prototype)\n"
|
||||||
|
"(If you are unsure, leave as default.)"]
|
||||||
|
locks = metaprot.locks
|
||||||
|
if locks:
|
||||||
|
text.append("Current lock is |y'{lockstring}'|n".format(lockstring=locks))
|
||||||
|
else:
|
||||||
|
text.append("Lock unset - if not changed the default lockstring will be set as\n"
|
||||||
|
" |y'use:all(); edit:id({dbref}) or perm(Admin)'|n".format(dbref=caller.id))
|
||||||
|
text = "\n".join(text)
|
||||||
|
options = ({"desc": "forward (prototype)",
|
||||||
|
"goto": "node_prototype_index"},
|
||||||
|
{"desc": "back (tags)",
|
||||||
|
"goto": "node_tags"},
|
||||||
|
{"key": "_default",
|
||||||
|
"desc": "enter lockstring",
|
||||||
|
"goto": _node_check_locks})
|
||||||
|
|
||||||
|
return text, options
|
||||||
|
|
||||||
|
|
||||||
|
def node_prototype_index(caller):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def start_olc(caller, session=None, metaproto=None):
|
||||||
|
"""
|
||||||
|
Start menu-driven olc system for prototypes.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
caller (Object or Account): The entity starting the menu.
|
||||||
|
session (Session, optional): The individual session to get data.
|
||||||
|
metaproto (MetaProto, optional): Given when editing an existing
|
||||||
|
prototype rather than creating a new one.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
menudata = {"node_index": node_index,
|
||||||
|
"node_key": node_key,
|
||||||
|
"node_desc": node_desc,
|
||||||
|
"node_tags": node_tags,
|
||||||
|
"node_locks": node_locks,
|
||||||
|
"node_prototype_index": node_prototype_index}
|
||||||
|
EvMenu(caller, menudata, startnode='node_index', session=session, olc_metaproto=metaproto)
|
||||||
|
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue