mirror of
https://github.com/evennia/evennia.git
synced 2026-03-29 03:57:17 +02:00
Add example diagram to Evmenu doc
This commit is contained in:
parent
edf2bbf3c9
commit
70eb2a3e37
1 changed files with 82 additions and 73 deletions
|
|
@ -278,33 +278,24 @@ it
|
|||
|
||||
### Return values from the node
|
||||
|
||||
Each function must return two variables, `text` and `options`.
|
||||
Each node function must return two variables, `text` and `options`.
|
||||
|
||||
|
||||
#### text
|
||||
|
||||
The `text` variable is a string or tuple. This text is what will be displayed when the user reaches
|
||||
this node. If this is a tuple, then the first element of the tuple will be considered the displayed
|
||||
text and the second the help-text to display when the user enters the `help` command on this node.
|
||||
|
||||
The `text` variable is a string or tuple. This text is what will be displayed when the user reaches this node. If this is a tuple, then the first element of the tuple will be considered the displayed text and the second the help-text to display when the user enters the `help` command on this node.
|
||||
```python
|
||||
text = ("This is the text to display", "This is the help text for this node")
|
||||
```
|
||||
|
||||
Returning a `None` text is allowed and simply leads to a node with no text and only options. If the
|
||||
help text is not given, the menu will give a generic error message when using `help`.
|
||||
Returning a `None` text is allowed and simply leads to a node with no text and only options. If the help text is not given, the menu will give a generic error message when using `help`.
|
||||
|
||||
|
||||
#### options
|
||||
|
||||
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.
|
||||
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
|
||||
available, a single dictionary can also be returned. This is how it could look:
|
||||
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:
|
||||
|
||||
|
||||
```python
|
||||
|
|
@ -338,14 +329,7 @@ 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
|
||||
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
|
||||
coloring to the choice. The first element of the aliasing tuple should then be the colored version,
|
||||
followed by a version without color - since otherwise the user would have to enter the color codes
|
||||
to select that choice.
|
||||
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 coloring to the choice. The first element of the aliasing tuple should then be the colored version, followed by a version without color - since otherwise the user would have to enter the color codes to select that choice.
|
||||
|
||||
Note that the `key` is *optional*. If no key is given, it will instead automatically be replaced
|
||||
with a running number starting from `1`. If removing the `key` part of each option, the resulting
|
||||
|
|
@ -361,12 +345,9 @@ ________________________________
|
|||
|
||||
```
|
||||
|
||||
Whether you want to use a key or rely on numbers is mostly
|
||||
a matter of style and the type of menu.
|
||||
Whether you want to use a key or rely on numbers is mostly a matter of style and the type of menu.
|
||||
|
||||
EvMenu accepts one important special `key` given only as `"_default"`. This key is used when a user
|
||||
enters something that does not match any other fixed keys. It is particularly useful for getting
|
||||
user input:
|
||||
EvMenu accepts one important special `key` given only as `"_default"`. This key is used when a user enters something that does not match any other fixed keys. It is particularly useful for getting user input:
|
||||
|
||||
```python
|
||||
def node_readuser(caller, raw_string, **kwargs):
|
||||
|
|
@ -385,15 +366,12 @@ A `"_default"` option does not show up in the menu, so the above will just be a
|
|||
|
||||
#### option-key 'desc'
|
||||
|
||||
This simply contains the description as to what happens when selecting the menu option. For
|
||||
`"_default"` options or if the `key` is already long or descriptive, it is not strictly needed. But
|
||||
usually it's better to keep the `key` short and put more detail in `desc`.
|
||||
This simply contains the description as to what happens when selecting the menu option. For `"_default"` options or if the `key` is already long or descriptive, it is not strictly needed. But usually it's better to keep the `key` short and put more detail in `desc`.
|
||||
|
||||
|
||||
#### option-key 'goto'
|
||||
|
||||
This is the operational part of the option and fires only when the user chooses said option. Here
|
||||
are three ways to write it
|
||||
This is the operational part of the option and fires only when the user chooses said option. Here are three ways to write it
|
||||
|
||||
```python
|
||||
|
||||
|
|
@ -422,63 +400,33 @@ def node_select(caller, raw_string, **kwargs):
|
|||
|
||||
```
|
||||
|
||||
As seen above, `goto` could just be pointing to a single `nodename` string - the name of the node to
|
||||
go to. When given like this, EvMenu will look for a node named like this and call its associated
|
||||
function as
|
||||
As seen above, `goto` could just be pointing to a single `nodename` string - the name of the node to go to. When given like this, EvMenu will look for a node named like this and call its associated function as
|
||||
|
||||
```python
|
||||
nodename(caller, raw_string, **kwargs)
|
||||
```
|
||||
|
||||
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).
|
||||
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
|
||||
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
|
||||
forwarded from the node's own input.
|
||||
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 forwarded from the node's own input.
|
||||
|
||||
The `goto` option key could also point to a tuple `(callable, kwargs)` - this allows for customizing
|
||||
the kwargs passed into the goto-callable, for example you could use the same callable but change the
|
||||
kwargs passed into it depending on which option was actually chosen.
|
||||
The `goto` option key could also point to a tuple `(callable, kwargs)` - this allows for customizing the kwargs passed into the goto-callable, for example you could use the same callable but change the 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
|
||||
into the next node depending on what option was 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 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
|
||||
node will run again*, possibly with different kwargs. This makes it very easy to re-use a node over
|
||||
and over, for example allowing different options to update some text form being passed and
|
||||
manipulated for every iteration.
|
||||
|
||||
|
||||
> The EvMenu also supports the `exec` option key. This allows for running a callable *before* the
|
||||
> goto-callable. This functionality comes from a time before goto could be a callable and is
|
||||
> *deprecated* as of Evennia 0.8. Use `goto` for all functionality where you'd before use `exec`.
|
||||
There is one important case - if the goto-callable returns `None` for a `nodename`, *the current node will run again*, possibly with different kwargs. This makes it very easy to re-use a node over and over, for example allowing different options to update some text form being passed and manipulated for every iteration.
|
||||
|
||||
|
||||
### Temporary storage
|
||||
|
||||
When the menu starts, the EvMenu instance is stored on the caller as `caller.ndb._evmenu`. Through
|
||||
this object you can in principle reach the menu's internal state if you know what you are doing.
|
||||
This is also a good place to store temporary, more global variables that may be cumbersome to keep
|
||||
passing from node to node via the `**kwargs`. The `_evmnenu` will be deleted automatically when the
|
||||
menu closes, meaning you don't need to worry about cleaning anything up.
|
||||
When the menu starts, the EvMenu instance is stored on the caller as `caller.ndb._evmenu`. Through this object you can in principle reach the menu's internal state if you know what you are doing. This is also a good place to store temporary, more global variables that may be cumbersome to keep passing from node to node via the `**kwargs`. The `_evmnenu` will be deleted automatically when the menu closes, meaning you don't need to worry about cleaning anything up.
|
||||
|
||||
If you want *permanent* state storage, it's instead better to use an Attribute on `caller`. Remember
|
||||
that this will remain after the menu closes though, so you need to handle any needed cleanup
|
||||
yourself.
|
||||
If you want *permanent* state storage, it's instead better to use an Attribute on `caller`. Remember that this will remain after the menu closes though, so you need to handle any needed cleanup yourself.
|
||||
|
||||
|
||||
### Customizing Menu formatting
|
||||
|
||||
The `EvMenu` display of nodes, options etc are controlled by a series of formatting methods on the
|
||||
`EvMenu` class. To customize these, simply create a new child class of `EvMenu` and override as
|
||||
needed. Here is an example:
|
||||
The `EvMenu` display of nodes, options etc are controlled by a series of formatting methods on the `EvMenu` class. To customize these, simply create a new child class of `EvMenu` and override as needed. Here is an example:
|
||||
|
||||
```python
|
||||
from evennia.utils.evmenu import EvMenu
|
||||
|
|
@ -542,8 +490,7 @@ See `evennia/utils/evmenu.py` for the details of their default implementations.
|
|||
|
||||
## EvMenu templating language
|
||||
|
||||
In evmenu.py are two helper functions `parse_menu_template` and `template2menu`
|
||||
that is used to parse a _menu template_ string into an EvMenu:
|
||||
In evmenu.py are two helper functions `parse_menu_template` and `template2menu` that is used to parse a _menu template_ string into an EvMenu:
|
||||
|
||||
evmenu.template2menu(caller, menu_template, goto_callables)
|
||||
|
||||
|
|
@ -875,6 +822,68 @@ auto-created by the `list_node` decorator.
|
|||
|
||||
## Example Menus
|
||||
|
||||
Here is a diagram to help visualize the flow of data from node to node, including goto-callables in-between:
|
||||
|
||||
```
|
||||
┌─
|
||||
│ def nodeA(caller, raw_string, **kwargs):
|
||||
│ text = "Choose how to operate on 2 and 3."
|
||||
│ options = (
|
||||
│ {
|
||||
│ "key": "A",
|
||||
│ "desc": "Multiply 2 with 3",
|
||||
│ "goto": (_callback, {"type": "mult", "a": 2, "b": 3})
|
||||
│ }, ───────────────────┬────────────
|
||||
│ { │
|
||||
│ "key": "B", └───────────────┐
|
||||
│ "desc": "Add 2 and 3", │
|
||||
Node A│ "goto": (_callback, {"type": "add", "a": 2, "b": 3}) │
|
||||
│ }, ─────────────────┬───────────── │
|
||||
│ { │ │
|
||||
│ "key": "C", │ │
|
||||
│ "desc": "Show the value 5", │ │
|
||||
│ "goto": ("node_B", {"c": 5}) │ │
|
||||
│ } ───────┐ │ │
|
||||
│ ) └──────────┼─────────────────┼───┐
|
||||
│ return text, options │ │ │
|
||||
└─ ┌──────────┘ │ │
|
||||
│ │ │
|
||||
│ ┌──────────────────────────┘ │
|
||||
┌─ ▼ ▼ │
|
||||
│ def _callback(caller, raw_string, **kwargs): │
|
||||
│ if kwargs["type"] == "mult": │
|
||||
│ return "node_B", {"c": kwargs["a"] * kwargs["b"]} │
|
||||
Goto- │ ───────────────┬──────────────── │
|
||||
callable│ │ │
|
||||
│ └───────────────────┐ │
|
||||
│ │ │
|
||||
│ elif kwargs["type"] == "add": │ │
|
||||
│ return "node_B", {"c": kwargs["a"] + kwargs["b"]} │ │
|
||||
└─ ────────┬─────────────────────── │ │
|
||||
│ │ │
|
||||
│ ┌────────────────────────┼──────────┘
|
||||
│ │ │
|
||||
│ │ ┌──────────────────────┘
|
||||
┌─ ▼ ▼ ▼
|
||||
│ def nodeB(caller, raw_string, **kwargs):
|
||||
Node B│ text = "Result of operation: " + kwargs["c"]
|
||||
│ return text, {}
|
||||
└─
|
||||
|
||||
┌─
|
||||
Menu │ EvMenu(caller, {"node_A": nodeA, "node_B": nodeB}, startnode="node_A")
|
||||
Start│
|
||||
└─
|
||||
```
|
||||
|
||||
Above we create a very simple/stupid menu (in the `EvMenu` call at the end) where we map the node identifier `"node_A"` to the Python function `nodeA` and `"node_B"` to the function `nodeB`.
|
||||
|
||||
We start the menu in `"node_A"` where we get three options A, B and C. Options A and B will route via a a goto-callable `_callback` that either multiples or adds the numbers 2 and 3 together before continuing to `"node_B"`. Option C routes directly to `"node_B"`, passing the number 5.
|
||||
|
||||
In every step, we pass a dict which becomes the ingoing `**kwargs` in the next step. If we didn't pass anything (it's optional), the next step's `**kwargs` would just be empty.
|
||||
|
||||
More examples:
|
||||
|
||||
- **[Simple branching menu](./EvMenu.md#example-simple-branching-menu)** - choose from options
|
||||
- **[Dynamic goto](./EvMenu.md#example-dynamic-goto)** - jumping to different nodes based on response
|
||||
- **[Set caller properties](./EvMenu.md#example-set-caller-properties)** - a menu that changes things
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue