mirror of
https://github.com/evennia/evennia.git
synced 2026-03-28 02:36:32 +01:00
Fixed all links
This commit is contained in:
parent
d4f1733bc7
commit
26f8ba3f71
175 changed files with 11972 additions and 4443 deletions
|
|
@ -25,9 +25,26 @@ This is an example of a menu *node*. Think of a node as a point where the menu s
|
|||
and waits for user to give some input. By jumping to different nodes depending on the input, a menu
|
||||
is constructed.
|
||||
|
||||
To create the menu, EvMenu uses normal Python functions, one per node. It will load all those
|
||||
## Ways to create the menu
|
||||
|
||||
### node functions
|
||||
|
||||
The native way to define an EvMenu is to define Python functions, one per node. It will load all
|
||||
those
|
||||
functions/nodes either from a module or by being passed a dictionary mapping the node's names to
|
||||
said functions, like `{"nodename": <function>, ...}`
|
||||
said functions, like `{"nodename": <function>, ...}`. Since you are dealing with raw code, this is
|
||||
by
|
||||
far the most powerful way - for example you could have dynamic nodes that change content depending
|
||||
on game context, time and what you picked before.
|
||||
|
||||
### menu templating
|
||||
|
||||
For a simpler menu you often don't need the full flexibility you get from defining each node as a
|
||||
Python function. For that, there is the _EvMenu templating_ language. This allows you to define the
|
||||
menu
|
||||
in a more human-readable string with a simple format. This is then parsed to produce the
|
||||
`{"nodename": <function>, ...}` mapping for you, for the EvMenu to use normally. The templating
|
||||
language is described in the [Menu templating section](./EvMenu#Evmenu-templating-language).
|
||||
|
||||
|
||||
## Launching the menu
|
||||
|
|
@ -46,12 +63,38 @@ class CmdTestMenu(Command):
|
|||
|
||||
def func(self):
|
||||
|
||||
EvMenu(caller, "world.mymenu")
|
||||
EvMenu(caller, "world.mymenu")
|
||||
|
||||
```
|
||||
|
||||
When running this command, the menu will start using the menu nodes loaded from
|
||||
`mygame/world/mymenu.py`. See next section on how to define menu nodes.
|
||||
`mygame/world/mymenu.py` and use this to build the menu-tree - each function name becomes
|
||||
the name of a node in the tree. See next section on how to define menu nodes.
|
||||
|
||||
Alternatively, you could pass the menu-tree to EvMenu directly:
|
||||
|
||||
```python
|
||||
|
||||
menutree = {"start": nodestartfunc,
|
||||
"node1": nodefunc1,
|
||||
"node2": nodefunc2,, ...}
|
||||
EvMenu(caller, menutree)
|
||||
|
||||
```
|
||||
This menutree can also be generated from an *EvMenu template*
|
||||
|
||||
```python
|
||||
from evennia.utils.evmenu import parse_menu_template
|
||||
|
||||
menutree = parse_menu_template(caller, template_string, goto_callables)
|
||||
EvMenu(caller, menutree)
|
||||
```
|
||||
|
||||
The `template_string` and `goto_callables` are described in [Template language
|
||||
section](EvMenu#Evmenu-templating-language).
|
||||
|
||||
|
||||
## The EvMenu class
|
||||
|
||||
The `EvMenu` has the following optional callsign:
|
||||
|
||||
|
|
@ -73,26 +116,34 @@ EvMenu(caller, menu_data,
|
|||
new [CmdSet](./Command-Sets) assigned to it, for handling the menu.
|
||||
- `menu_data` (str, module or dict): is a module or python path to a module where the global-level
|
||||
functions will each be considered to be a menu node. Their names in the module will be the names
|
||||
by which they are referred to in the module. Importantly, function names starting with an underscore
|
||||
`_` will be ignored by the loader. Alternatively, this can be a direct mapping `{"nodename":function, ...}`.
|
||||
by which they are referred to in the module. Importantly, function names starting with an
|
||||
underscore
|
||||
`_` will be ignored by the loader. Alternatively, this can be a direct mapping
|
||||
`{"nodename":function, ...}`.
|
||||
- `startnode` (str): is the name of the menu-node to start the menu at. Changing this means that
|
||||
you can jump into a menu tree at different positions depending on circumstance and thus possibly
|
||||
re-use menu entries.
|
||||
- `cmdset_mergetype` (str): This is usually one of "Replace" or "Union" (see [CmdSets](./Command-Sets).
|
||||
- `cmdset_mergetype` (str): This is usually one of "Replace" or "Union" (see [CmdSets](Command-
|
||||
Sets).
|
||||
The first means that the menu is exclusive - the user has no access to any other commands while
|
||||
in the menu. The Union mergetype means the menu co-exists with previous commands (and may overload
|
||||
in the menu. The Union mergetype means the menu co-exists with previous commands (and may
|
||||
overload
|
||||
them, so be careful as to what to name your menu entries in this case).
|
||||
- `cmdset_priority` (int): The priority with which to merge in the menu cmdset. This allows for
|
||||
advanced usage.
|
||||
- `auto_quit`, `auto_look`, `auto_help` (bool): If either of these are `True`, the menu
|
||||
automatically makes a `quit`, `look` or `help` command available to the user. The main reason why
|
||||
you'd want to turn this off is if you want to use the aliases "q", "l" or "h" for something in your
|
||||
menu. Nevertheless, at least `quit` is highly recommend - if `False`, the menu *must* itself supply
|
||||
an "exit node" (a node without any options), or the user will be stuck in the menu until the server
|
||||
you'd want to turn this off is if you want to use the aliases "q", "l" or "h" for something in
|
||||
your
|
||||
menu. Nevertheless, at least `quit` is highly recommend - if `False`, the menu *must* itself
|
||||
supply
|
||||
an "exit node" (a node without any options), or the user will be stuck in the menu until the
|
||||
server
|
||||
reloads (or eternally if the menu is `persistent`)!
|
||||
- `cmd_on_exit` (str): This command string will be executed right *after* the menu has closed down.
|
||||
From experience, it's useful to trigger a "look" command to make sure the user is aware of the
|
||||
change of state; but any command can be used. If set to `None`, no command will be triggered after
|
||||
change of state; but any command can be used. If set to `None`, no command will be triggered
|
||||
after
|
||||
exiting the menu.
|
||||
- `persistent` (bool) - if `True`, the menu will survive a reload (so the user will not be kicked
|
||||
out by the reload - make sure they can exit on their own!)
|
||||
|
|
@ -134,7 +185,8 @@ def menunodename3(caller, raw_string, **kwargs):
|
|||
|
||||
```
|
||||
|
||||
> While all of the above forms are okay, it's recommended to stick to the third and last form since it
|
||||
> While all of the above forms are okay, it's recommended to stick to the third and last form since
|
||||
it
|
||||
> gives the most flexibility. The previous forms are mainly there for backwards compatibility with
|
||||
> existing menus from a time when EvMenu was less able.
|
||||
|
||||
|
|
@ -173,11 +225,13 @@ help text is not given, the menu will give a generic error message when using `h
|
|||
|
||||
#### options
|
||||
|
||||
The `options` list describe all the choices available to the user when viewing this node. If `options` is
|
||||
The `options` list describe all the choices available to the user when viewing this node. If
|
||||
`options` is
|
||||
returned as `None`, it means that this node is an *Exit node* - any text is displayed and then the
|
||||
menu immediately exits, running the `exit_cmd` if given.
|
||||
|
||||
Otherwise, `options` should be a list (or tuple) of dictionaries, one for each option. If only one option is
|
||||
Otherwise, `options` should be a list (or tuple) of dictionaries, one for each option. If only one
|
||||
option is
|
||||
available, a single dictionary can also be returned. This is how it could look:
|
||||
|
||||
|
||||
|
|
@ -187,10 +241,10 @@ def node_test(caller, raw_string, **kwargs):
|
|||
text = "A goblin attacks you!"
|
||||
|
||||
options = (
|
||||
{"key": ("Attack", "a", "att"),
|
||||
{"key": ("Attack", "a", "att"),
|
||||
"desc": "Strike the enemy with all your might",
|
||||
"goto": "node_attack"},
|
||||
{"key": ("Defend", "d", "def"),
|
||||
{"key": ("Defend", "d", "def"),
|
||||
"desc": "Hold back and defend yourself",
|
||||
"goto": (_defend, {"str": 10, "enemyname": "Goblin"})})
|
||||
|
||||
|
|
@ -212,7 +266,8 @@ Defend: Hold back and defend yourself
|
|||
|
||||
##### option-key 'key'
|
||||
|
||||
The option's `key` is what the user should enter in order to choose that option. If given as a tuple, the
|
||||
The option's `key` is what the user should enter in order to choose that option. If given as a
|
||||
tuple, the
|
||||
first string of that tuple will be what is shown on-screen while the rest are aliases for picking
|
||||
that option. In the above example, the user could enter "Attack" (or "attack", it's not
|
||||
case-sensitive), "a" or "att" in order to attack the goblin. Aliasing is useful for adding custom
|
||||
|
|
@ -284,11 +339,11 @@ def node_select(caller, raw_string, **kwargs):
|
|||
"help - they all do different things ...")
|
||||
|
||||
options = ({"desc": "Option one",
|
||||
"goto": "node_one"},
|
||||
{"desc": "Option two",
|
||||
"goto": _action_two},
|
||||
{"desc": "Option three",
|
||||
"goto": (_action_three, {"key": 1, "key2": 2})}
|
||||
"goto": "node_one"},
|
||||
{"desc": "Option two",
|
||||
"goto": _action_two},
|
||||
{"desc": "Option three",
|
||||
"goto": (_action_three, {"key": 1, "key2": 2})}
|
||||
)
|
||||
|
||||
return text, options
|
||||
|
|
@ -306,7 +361,8 @@ function as
|
|||
Here, `raw_string` is always the input the user entered to make that choice and `kwargs` are the
|
||||
same as those `kwargs` that already entered the *current* node (they are passed on).
|
||||
|
||||
Alternatively the `goto` could point to a "goto-callable". Such callables are usually defined in the same
|
||||
Alternatively the `goto` could point to a "goto-callable". Such callables are usually defined in the
|
||||
same
|
||||
module as the menu nodes and given names starting with `_` (to avoid being parsed as nodes
|
||||
themselves). These callables will be called the same as a node function - `callable(caller,
|
||||
raw_string, **kwargs)`, where `raw_string` is what the user entered on this node and `**kwargs` is
|
||||
|
|
@ -318,7 +374,8 @@ kwargs passed into it depending on which option was actually chosen.
|
|||
|
||||
The "goto callable" must either return a string `"nodename"` or a tuple `("nodename", mykwargs)`.
|
||||
This will lead to the next node being called as either `nodename(caller, raw_string, **kwargs)` or
|
||||
`nodename(caller, raw_string, **mykwargs)` - so this allows changing (or replacing) the options going
|
||||
`nodename(caller, raw_string, **mykwargs)` - so this allows changing (or replacing) the options
|
||||
going
|
||||
into the next node depending on what option was chosen.
|
||||
|
||||
There is one important case - if the goto-callable returns `None` for a `nodename`, *the current
|
||||
|
|
@ -412,21 +469,293 @@ class MyEvMenu(EvMenu):
|
|||
See `evennia/utils/evmenu.py` for the details of their default implementations.
|
||||
|
||||
|
||||
|
||||
## Evmenu templating language
|
||||
|
||||
The EvMenu is very powerful and flexible. But often your menu is simple enough to
|
||||
not require the full power of EvMenu. For this you can use the Evmenu templating language.
|
||||
|
||||
This is how the templating is used:
|
||||
|
||||
```python
|
||||
from evennia.utils.evmenu import parse_menu_template, EvMenu
|
||||
|
||||
template_string = "(will be described below)"
|
||||
# this could be empty if you don't need to access any callables
|
||||
# in your template
|
||||
goto_callables = {"mycallable1": function, ...}
|
||||
|
||||
# generate the menutree
|
||||
menutree = parse_menu_template(caller, template_string, goto_callables)
|
||||
# a normal EvMenu call
|
||||
EvMenu(caller, menutree, ...)
|
||||
|
||||
```
|
||||
|
||||
... So the `parse_menu_template` is just another way to generate the `menutree` dict needed by
|
||||
EvMenu - after this EvMenu works normally.
|
||||
|
||||
The good thing with this two-step procedude is that you can mix- and match - if you wanted
|
||||
you could insert a normal, fully flexible function-based node-function in the `menutree` before
|
||||
passing
|
||||
the whole thing into `EvMenu` and get the best of both worlds. It also makes it
|
||||
easy to substitute base EvMenu with a child class that changes the menu display.
|
||||
|
||||
... But if you really don't need any such customization, you can also apply the template in one step
|
||||
using
|
||||
the `template2menu` helper:
|
||||
|
||||
|
||||
```python
|
||||
from evennia.utils.evmenu import template2menu
|
||||
|
||||
template_string = "(will be described below)"
|
||||
goto_callables = {"mycallable1": function, ...}
|
||||
|
||||
template2menu(caller, template_string, goto_callables, startnode="start", ...)
|
||||
|
||||
```
|
||||
In addition to the template-related arguments, `template2menu` takes all the same `**kwargs`
|
||||
as `EvMenu` and will parse the template and start the menu for you in one go.
|
||||
|
||||
### The templating string
|
||||
|
||||
The template is a normal string with a very simple format. Each node begins
|
||||
with a marker `## Node <name of node>`, follwowed by a `## Options` separator (the `Node` and
|
||||
`Options` are
|
||||
case-insensitive).
|
||||
|
||||
```python
|
||||
template_string = """
|
||||
|
||||
## NODE start
|
||||
|
||||
<text for the node>
|
||||
|
||||
## OPTIONS
|
||||
|
||||
# this is a comment. Only line-comments are allowed.
|
||||
|
||||
key;alias;alias: description -> goto_str_or_callable
|
||||
key;alias;alias: goto_str_or_callable
|
||||
>pattern: goto_str_or_callable
|
||||
|
||||
"""
|
||||
```
|
||||
|
||||
- The text after `## NODE` defines the name of the node. This must be unique within the
|
||||
menu because this is what you use for `goto` statements. The name could have spaces.
|
||||
- The area between `## NODE` and `## OPTIONS` contains the text of the node. It can have
|
||||
normal formatting and will retain intentation.
|
||||
- The `## OPTIONS` section, until the next `## NODE` or the end of the string,
|
||||
holds the options, one per line.
|
||||
- Option-indenting is ignored but can be useful for readability.
|
||||
- The options-section can also have line-comments, marked by starting the line with `#`.
|
||||
- A node without a following `## OPTIONS` section indicates an end node, and reaching
|
||||
it will print the text and immediately exit the menu (same as for regular EvMenu).
|
||||
|
||||
### Templating options format
|
||||
|
||||
The normal, full syntax is:
|
||||
|
||||
key;alias;alias: description -> goto_str_or_callable
|
||||
|
||||
An example would be
|
||||
|
||||
next;n: Go to node Two -> node2
|
||||
|
||||
In the menu, this will become an option
|
||||
|
||||
next: Go to node Two
|
||||
|
||||
where you can enter `next` or `n` to go to the menu node named `node2`.
|
||||
|
||||
To skip the description, just add the goto without the `->`:
|
||||
|
||||
next;n: node2
|
||||
|
||||
This will create a menu option without any description:
|
||||
|
||||
next
|
||||
|
||||
A special key is `>`. This acts as a _pattern matcher_. Between `>` and the `:` one
|
||||
can fit an optional _pattern_. This
|
||||
pattern will first be parsed with [glob-style
|
||||
parsing](https://docs.python.org/2/library/fnmatch.html) and then
|
||||
with [regex](https://docs.python.org/3/library/re.html#module-re), and only if
|
||||
the player's input matches either will the option be chosen. An input-matching
|
||||
option cannot have a description.
|
||||
|
||||
```
|
||||
# this matches the empty string (just pressing return)
|
||||
>: node2
|
||||
|
||||
# this matches input starting with 'test' (regex match)
|
||||
> ^test.+?: testnode
|
||||
|
||||
# this matches any number input (regex match)
|
||||
> [0-9]+?: countnode
|
||||
|
||||
# this matches everything not covered by previous options
|
||||
# (glob-matching, space is stripped without quotes)
|
||||
> *: node3
|
||||
```
|
||||
|
||||
You can have multiple pattern-matchers for a node but remember that options are
|
||||
checked in the order they are listed. So make sure to put your pattern-matchers
|
||||
in decending order of generality; if you have a 'catch-all' pattern,
|
||||
it should be put last or those behind it will never be tried.
|
||||
|
||||
```
|
||||
next;n: node2
|
||||
back;b: node1
|
||||
>: node2
|
||||
```
|
||||
|
||||
The above would give you the option to write next/back but you can also just press return to move on
|
||||
to the next node.
|
||||
|
||||
### Templating goto-callables
|
||||
|
||||
Instead of giving the name of a node to go to, you can also give the name
|
||||
of a _goto_callable_, which in turn returns the name of the node to go to. You
|
||||
tell the template it's a callable by simply adding `()` at the end.
|
||||
|
||||
next: Go to node 2 -> goto_node2()
|
||||
|
||||
You can also add keyword arguments:
|
||||
|
||||
back: myfunction(from=foo)
|
||||
|
||||
> Note: ONLY keyword-arguments are supported! Trying to pass a positional
|
||||
> argument will lead to an error.
|
||||
|
||||
The contents of the kwargs-values will be evaluated by `literal_eval` so
|
||||
you don't need to add quotes to strings _unless they have spaces in them_. Numbers
|
||||
will be converted correctly, but more complex input structures (like lists or dicts) will
|
||||
_not_ - if you want more complex input you should use a full function-based EvMenu
|
||||
node instead.
|
||||
|
||||
The goto-callable is defined just like any Evmenu goto-func. You must always
|
||||
use the full form (including `**kwargs`):
|
||||
|
||||
```python
|
||||
def mygotocallable(caller, raw_string, **kwargs):
|
||||
# ...
|
||||
return "nodename_to_goto"
|
||||
|
||||
```
|
||||
|
||||
Return `None` to re-run the current node. Any keyword arguments you specify in
|
||||
your template will be passed to your goto-callable in `**kwargs`. Unlike in
|
||||
regular EvMenu nodes you _can't_ return kwargs to pass it between nodes and other dynamic
|
||||
tricks.
|
||||
|
||||
All goto-callables you use in your menu-template must be added to the
|
||||
`goto_callable` mapping that you pass to `parse_menu_template` or
|
||||
`template2menu`.
|
||||
|
||||
### Templating example to show all possible options:
|
||||
|
||||
|
||||
```python
|
||||
|
||||
template_string = """
|
||||
|
||||
## NODE start
|
||||
|
||||
This is the text of the start node.
|
||||
Both ## NODE, ## node or ## Node works. The node-name can have
|
||||
spaces.
|
||||
|
||||
The text area can have multiple lines, line breaks etc.
|
||||
|
||||
## OPTIONS
|
||||
|
||||
# here starts the option-defition
|
||||
# comments are only allowed from beginning of line.
|
||||
# Indenting is not necessary, but good for readability
|
||||
|
||||
1: Option number 1 -> node1
|
||||
2: Option number 2 -> node2
|
||||
next: This steps next -> go_back()
|
||||
# the -> can be ignored if there is no desc
|
||||
back: go_back(from_node=start)
|
||||
abort: abort
|
||||
|
||||
# ----------------------------------- this is ignored
|
||||
|
||||
## NODE node1
|
||||
|
||||
Text for Node1. Enter a message!
|
||||
<return> to go back.
|
||||
|
||||
## options
|
||||
|
||||
# Starting the option-line with >
|
||||
# allows to perform different actions depending on
|
||||
# what is inserted.
|
||||
|
||||
# this catches everything starting with foo
|
||||
> foo*: handle_foo_message()
|
||||
|
||||
# regex are also allowed (this catches number inputs)
|
||||
> [0-9]+?: handle_numbers()
|
||||
|
||||
# this catches the empty return
|
||||
>: start
|
||||
|
||||
# this catches everything else
|
||||
> *: handle_message(from_node=node1)
|
||||
|
||||
# -----------------------------------------
|
||||
|
||||
## NODE node2
|
||||
|
||||
Text for Node2. Just go back.
|
||||
|
||||
## options
|
||||
|
||||
>: start
|
||||
|
||||
# node abort
|
||||
|
||||
This exits the menu since there is no `## options` section.
|
||||
|
||||
|
||||
"""
|
||||
|
||||
# we assume the callables are defined earlier
|
||||
goto_callables = {"go_back": go_back_func,
|
||||
"handle_foo_message": handle_message,
|
||||
"handle_numbers": my_number_handler,
|
||||
"handle_message": handle_message2}
|
||||
|
||||
# boom - a menu
|
||||
template2menu(caller, template_string, goto_callables)
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Examples:
|
||||
|
||||
- **[Simple branching menu](./EvMenu#example-simple-branching-menu)** - choose from options
|
||||
- **[Dynamic goto](./EvMenu#example-dynamic-goto)** - jumping to different nodes based on response
|
||||
- **[Set caller properties](./EvMenu#example-set-caller-properties)** - a menu that changes things
|
||||
- **[Getting arbitrary input](./EvMenu#example-get-arbitrary-input)** - entering text
|
||||
- **[Storing data between nodes](./EvMenu#example-storing-data-between-nodes)** - keeping states and information while in the menu
|
||||
- **[Repeating the same node](./EvMenu#example-repeating-the-same-node)** - validating within the node before moving to the next
|
||||
- **[Full Menu](./EvMenu#example-full-menu):** a complete example
|
||||
- **[Yes/No prompt](./EvMenu#example-yesno-prompt)** - entering text with limited possible responses (this is *not* using EvMenu but the conceptually similar yet technically unrelated `get_input` helper function accessed as `evennia.utils.evmenu.get_input`).
|
||||
- **[Storing data between nodes](./EvMenu#example-storing-data-between-nodes)** - keeping states and
|
||||
information while in the menu
|
||||
- **[Repeating the same node](./EvMenu#example-repeating-the-same-node)** - validating within the node
|
||||
before moving to the next
|
||||
- **[Yes/No prompt](./EvMenu#example-yesno-prompt)** - entering text with limited possible responses
|
||||
(this is *not* using EvMenu but the conceptually similar yet technically unrelated `get_input`
|
||||
helper function accessed as `evennia.utils.evmenu.get_input`).
|
||||
|
||||
|
||||
### Example: Simple branching menu
|
||||
|
||||
Below is an example of a simple branching menu node leading to different other nodes depending on choice:
|
||||
Below is an example of a simple branching menu node leading to different other nodes depending on
|
||||
choice:
|
||||
|
||||
```python
|
||||
# in mygame/world/mychargen.py
|
||||
|
|
@ -520,11 +849,11 @@ def node_background(caller):
|
|||
options = ({"key": "death",
|
||||
"desc": "A violent death in the family",
|
||||
"goto": (_set_attribute, {"attr": ("experienced_violence", True),
|
||||
"next_node": "node_violent_background"})},
|
||||
"next_node": "node_violent_background"})},
|
||||
{"key": "betrayal",
|
||||
"desc": "The betrayal of a trusted grown-up",
|
||||
"goto": (_set_attribute, {"attr": ("experienced_betrayal", True),
|
||||
"next_node": "node_betrayal_background"})})
|
||||
"next_node": "node_betrayal_background"})})
|
||||
return text, options
|
||||
```
|
||||
|
||||
|
|
@ -564,8 +893,8 @@ def _set_name(caller, raw_string, **kwargs):
|
|||
caller.msg("Set name to {}.".format(prev_entry))
|
||||
return "node_background"
|
||||
else:
|
||||
caller.msg("Aborted.")
|
||||
return "node_exit"
|
||||
caller.msg("Aborted.")
|
||||
return "node_exit"
|
||||
else:
|
||||
# re-run old node, but pass in the name given
|
||||
return None, {"prev_entry": inp}
|
||||
|
|
@ -577,9 +906,9 @@ def enter_name(caller, raw_string, **kwargs):
|
|||
prev_entry = kwargs.get("prev_entry")
|
||||
|
||||
if prev_entry:
|
||||
text = "Current name: {}.\nEnter another name or <return> to accept."
|
||||
text = "Current name: {}.\nEnter another name or <return> to accept."
|
||||
else:
|
||||
text = "Enter your character's name or <return> to abort."
|
||||
text = "Enter your character's name or <return> to abort."
|
||||
|
||||
options = {"key": "_default",
|
||||
"goto": (_set_name, {"prev_entry": prev_entry})}
|
||||
|
|
@ -643,7 +972,7 @@ def node_view_sheet(caller):
|
|||
|
||||
options = ({"key": "Accept",
|
||||
"goto": "finish_chargen"},
|
||||
{"key": "Decline",
|
||||
{"key": "Decline",
|
||||
"goto": "start_over"})
|
||||
|
||||
return text, options
|
||||
|
|
@ -656,7 +985,8 @@ all nodes. At the end we look at it and, if we accept the character the menu wil
|
|||
result to permanent storage and exit.
|
||||
|
||||
> One point to remember though is that storage on `caller.ndb._menutree` is not persistent across
|
||||
> `@reloads`. If you are using a persistent menu (using `EvMenu(..., persistent=True)` you should use
|
||||
> `@reloads`. If you are using a persistent menu (using `EvMenu(..., persistent=True)` you should
|
||||
use
|
||||
> `caller.db` to store in-menu data like this as well. You must then yourself make sure to clean it
|
||||
> when the user exits the menu.
|
||||
|
||||
|
|
@ -673,12 +1003,12 @@ node is ok. A common example is a login menu:
|
|||
def _check_username(caller, raw_string, **kwargs):
|
||||
# we assume lookup_username() exists
|
||||
if not lookup_username(raw_string):
|
||||
# re-run current node by returning `None`
|
||||
caller.msg("|rUsername not found. Try again.")
|
||||
return None
|
||||
# re-run current node by returning `None`
|
||||
caller.msg("|rUsername not found. Try again.")
|
||||
return None
|
||||
else:
|
||||
# username ok - continue to next node
|
||||
return "node_password"
|
||||
# username ok - continue to next node
|
||||
return "node_password"
|
||||
|
||||
|
||||
def node_username(caller):
|
||||
|
|
@ -692,19 +1022,19 @@ def _check_password(caller, raw_string, **kwargs):
|
|||
|
||||
nattempts = kwargs.get("nattempts", 0)
|
||||
if nattempts > 3:
|
||||
caller.msg("Too many failed attempts. Logging out")
|
||||
return "node_abort"
|
||||
caller.msg("Too many failed attempts. Logging out")
|
||||
return "node_abort"
|
||||
elif not validate_password(raw_string):
|
||||
caller.msg("Password error. Try again.")
|
||||
return None, {"nattempts", nattempts + 1}
|
||||
return None, {"nattempts", nattempts + 1}
|
||||
else:
|
||||
# password accepted
|
||||
return "node_login"
|
||||
# password accepted
|
||||
return "node_login"
|
||||
|
||||
def node_password(caller, raw_string, **kwargs):
|
||||
text = "Enter your password."
|
||||
options = {"key": "_default",
|
||||
"goto": _check_password}
|
||||
"goto": _check_password}
|
||||
return text, options
|
||||
|
||||
```
|
||||
|
|
@ -885,7 +1215,7 @@ Normally, the `get_input` function quits after any input, but as seen in the exa
|
|||
return True from the callback to repeat the prompt until you pass whatever check you want.
|
||||
|
||||
> Note: You *cannot* link consecutive questions by putting a new `get_input` call inside the
|
||||
> callback If you want that you should use an EvMenu instead (see the [Repeating the same
|
||||
> callback. If you want that you should use an EvMenu instead (see the [Repeating the same
|
||||
> node](EvMenu#example-repeating-the-same-node) example above). Otherwise you can either peek at the
|
||||
> implementation of `get_input` and implement your own mechanism (it's just using cmdset nesting) or
|
||||
> you can look at [this extension suggested on the mailing
|
||||
|
|
@ -947,14 +1277,15 @@ _options(caller):
|
|||
|
||||
_select(caller, menuchoice, available_choices):
|
||||
# analyze choice
|
||||
return "next_node"
|
||||
return node_matching_the_choice
|
||||
|
||||
@list_node(options, select=_select, pagesize=10)
|
||||
@list_node(_options, select=_select, pagesize=10)
|
||||
def node_mylist(caller, raw_string, **kwargs):
|
||||
...
|
||||
|
||||
return text, options
|
||||
|
||||
# the decorator auto-creates the options; any options
|
||||
# returned here would be appended to the auto-options
|
||||
return node_text, {}
|
||||
```
|
||||
|
||||
The `options` argument to `list_node` is either a list, a generator or a callable returning a list
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue