Complete reshuffling of contribs. Not moved tests

This commit is contained in:
Griatch 2021-12-18 21:48:08 +01:00
parent 9efaea9e35
commit 9b92b595c4
27 changed files with 552 additions and 29 deletions

View file

@ -7,7 +7,6 @@ Testing suite for contrib folder
import time
import datetime
from anything import Anything
from django.test import override_settings
from evennia.commands.default.tests import CommandTest
from evennia.utils.test_resources import EvenniaTest, mockdelay, mockdeferLater
from mock import Mock, patch

View file

@ -0,0 +1,35 @@
# Batch processor examples
Contibution - Griatch 2012
The batch processor is used for generating in-game content from one or more
static files. Files can be stored with version control and then 'applied'
to the game to create content.
There are two batch processor types:
- Batch-cmd processor: A list of `#`-separated Evennia commands being executed
in sequence, such as `create`, `dig`, `north` etc. When running a script
of this type (filename ending with `.ev`), the caller of the script will be
the one performing the script's actions.
- Batch-code processor: A full Python script (filename ending with `.py` that
executes Evennia api calls to build, such as `evennia.create_object` or
`evennia.search_object` etc. It can be divided up into comment-separated
chunks so one can execute only parts of the script at a time (in this way it's
a little different than a normal Python file).
## Usage
To test the two example batch files, you need `Developer` or `superuser`
permissions, be logged into the game and run of
> batchcommand/interactive tutorials.batchprocessor.example_batch_cmds
> batchcode/interactive tutorials.batchprocessor.example_batch_code
The `/interactive` drops you in interactive mode so you can follow along what
the scripts do. Skip it to build it all at once.
Both commands produce the same results - they create a red-button object,
a table and a chair. If you run either with the `/debug` switch, the objects will
be deleted afterwards (for quick tests of syntax that you don't want to spam new
objects, for example).

View file

@ -0,0 +1,4 @@
"""
Batch processing examples - Griatch 2012
"""

View file

@ -0,0 +1,16 @@
# Script example
Griatch - 2012
Example script for testing. This adds a simple timer that has your
character make observations and notices at irregular intervals.
To test, use (in game)
> script me = contrib.tutorials.bodyfunctions.BodyFunctions
## Notes
Use `scripts me` to see the script running on you. Note that even though
the timer ticks down to 0, you will _not_ see an echo every tick (it's
random if an echo is given on a tick or not).

View file

@ -0,0 +1,6 @@
"""
Bodyfunctions example script - Griatch, 2012
"""
from .bodyfunctions import BodyFunctions # noqa

View file

@ -1,9 +1,13 @@
"""
Script example
Griatch - 2012
Example script for testing. This adds a simple timer that has your
character make observations and notices at irregular intervals.
To test, use
@script me = tutorial_examples.bodyfunctions.BodyFunctions
script me = tutorial_examples.bodyfunctions.BodyFunctions
The script will only send messages to the object it is stored on, so
make sure to put it on yourself or you won't see any messages!
@ -16,6 +20,7 @@ from evennia import DefaultScript
class BodyFunctions(DefaultScript):
"""
This class defines the script itself
"""
def at_script_creation(self):

View file

@ -0,0 +1,34 @@
# Red Button example
Griatch - 2011
This is a more advanced example object with its own functionality (commands)
on it.
Create the button with
create/drop button:tutorials.red_button.RedButton
Note that you must drop the button before you can see its messages! It's
imperative that you press the red button. You know you want to.
Use `del button` to destroy/stop the button when you are done playing.
## Technical
The button's functionality is controlled by CmdSets that gets added and removed
depending on the 'state' the button is in.
- Lid-closed state: In this state the button is covered by a glass cover and
trying to 'push' it will fail. You can 'nudge', 'smash' or 'open' the lid.
- Lid-open state: In this state the lid is open but will close again after a
certain time. Using 'push' now will press the button and trigger the
Blind-state.
- Blind-state: In this mode you are blinded by a bright flash. This will affect
your normal commands like 'look' and help until the blindness wears off after
a certain time.
Timers are handled by persistent delays on the button. These are examples of
`evennia.utils.utils.delay` calls that wait a certain time before calling a
method - such as when closing the lid and un-blinding a character.

View file

@ -0,0 +1,6 @@
"""
Tutorial Red Button Object - Griatch 2011
"""
from .red_button import RedButton # noqa

View file

@ -1,4 +1,7 @@
"""
Red Button
Griatch - 2011
This is a more advanced example object. It combines functions from
script.examples as well as commands.examples to make an interactive
@ -6,14 +9,14 @@ button typeclass.
Create this button with
create/drop red_button.RedButton
create/drop tutorials.red_button.RedButton
Note that you must drop the button before you can see its messages!
## Technical
The button's functionality is controlled by CmdSets that gets added and removed
depending on the 'state' the button is in.
depending on the 'state' the button is in.
- Lid-closed state: In this state the button is covered by a glass cover and trying
to 'push' it will fail. You can 'nudge', 'smash' or 'open' the lid.

View file

@ -0,0 +1,21 @@
# Talkative NPC example
Contribution - Griatch 2011, grungies1138, 2016
This is a static NPC object capable of holding a simple menu-driven
conversation. It's just meant as an example.
## Installation
Create the NPC by creating an object of typeclass `contrib.tutorials.talking_npc.TalkingNPC`,
For example:
create/drop John : contrib.tutorials.talking_npc.TalkingNPC
Use `talk` in the same room as the NPC to start a conversation.
If there are many talkative npcs in the same room you will get to choose which
one's talk command to call (Evennia handles this automatically).
This use of EvMenu is very simplistic; See EvMenu for a lot more complex
possibilities.

View file

@ -1,4 +1,3 @@
# Evennia Tutorial World
Griatch 2011, 2015
@ -10,30 +9,33 @@ herein are designed to show off features of the engine, not to be a
very challenging (nor long) gaming experience. As such it's of course
only skimming the surface of what is possible.
The tutorial world also includes a game tutor menu example, exemplifying
Evmenu.
## Install
## Installation
Log in as superuser (#1), then run
@batchcommand tutorial_world.build
batchcommand tutorials.tutorial_world.build
Wait a little while for building to complete and don't run the command
again. This should build the world and connect it to Limbo.
again even if it's slow. This builds the world and connect it to Limbo
and creates a new exit `tutorial`.
If you are a superuser (User `#1`), use the `@quell` command to play
the tutorial as intended.
If you are a superuser (User `#1`), use the `quell` command to play
the tutorial as intended.
## Comments
The tutorial world is intended for your playing around with the engine.
It will help you learn how to accomplish some more advanced effects
and might give some good ideas along the way.
The tutorial world is intended to be explored and analyzed. It will help you
learn how to accomplish some more advanced effects and might give some good
ideas along the way.
It's suggested you play it through (as a normal user, NOT as
Superuser!) and explore it a bit, then come back here and start
looking into the (heavily documented) build/source code to find out
how things tick - that's the "tutorial" in Tutorial world after all.
It's suggested you play it through (as a normal user, NOT as Superuser!) and
explore it a bit, then come back here and start looking into the (heavily
documented) build/source code to find out how things tick - that's the
"tutorial" in Tutorial world after all.
Please report bugs in the tutorial to the Evennia issue tracker.
@ -50,6 +52,7 @@ tutorial game**
## Tutorial World Room map
?

View file

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
"""
This package holds the demo game of Evennia.
Tutorial world - Griatch, 2011, 2015
"""
from . import mob, objects, rooms
from . import mob, objects, rooms # noqa

View file

@ -16,7 +16,7 @@
# To load this file, place yourself in Limbo (room #2) and load the
# file as user #1 with
#
# @batchcommand contrib.tutorial_world.build
# batchcommand contrib.tutorials.tutorial_world.build
#
# If you give the /interactive switch you can step through the
# build process command for command.
@ -285,7 +285,7 @@ start
#
@set sign/tutorial_info =
This is a readable object, of the Typeclass
evennia.contrib.tutorial_world.objects.TutorialReadable. The sign has a cmdset
evennia.contrib.tutorials.tutorial_world.objects.TutorialReadable. The sign has a cmdset
defined on itself, containing only one command, namely 'read'. This
command is what allows you to 'read sign'. Doing so returns the
contents of the Attribute 'readable_sign', containing the information
@ -488,7 +488,7 @@ north
#
bridge
#
# Set up properties on bridge room (see contrib.tutorial_world.rooms.BridgeRoom)
# Set up properties on bridge room (see contrib.tutorials.tutorial_world.rooms.BridgeRoom)
#
# connect west edge to cliff
#
@ -1363,7 +1363,7 @@ The prize you have been looking for!
what can be done with Evennia. The tutorial focuses more on showing
various techniques than to supply any sort of novel storytelling or
gaming challenge. The full README and source code for the tutorial
world can be found under |wcontrib/tutorial_world|g.
world can be found under |wcontrib/tutorials/tutorial_world|g.
If you went through the tutorial quest once, it can be interesting to

View file

@ -0,0 +1,157 @@
# Easy fillable form
Contrib - Tim Ashley Jenkins 2018
This module contains a function that calls an easily customizable EvMenu - this
menu presents the player with a fillable form, with fields that can be filled
out in any order. Each field's value can be verified, with the function
allowing easy checks for text and integer input, minimum and maximum values /
character lengths, or can even be verified by a custom function. Once the form
is submitted, the form's data is submitted as a dictionary to any callable of
your choice.
The function that initializes the fillable form menu is fairly simple, and
includes the caller, the template for the form, and the callback(caller, result)
to which the form data will be sent to upon submission.
init_fill_field(formtemplate, caller, formcallback)
Form templates are defined as a list of dictionaries - each dictionary
represents a field in the form, and contains the data for the field's name and
behavior. For example, this basic form template will allow a player to fill out
a brief character profile:
PROFILE_TEMPLATE = [
{"fieldname":"Name", "fieldtype":"text"},
{"fieldname":"Age", "fieldtype":"number"},
{"fieldname":"History", "fieldtype":"text"},
]
This will present the player with an EvMenu showing this basic form:
```
Name:
Age:
History:
```
While in this menu, the player can assign a new value to any field with the
syntax <field> = <new value>, like so:
```
> name = Ashley
Field 'Name' set to: Ashley
```
Typing 'look' by itself will show the form and its current values.
```
> look
Name: Ashley
Age:
History:
```
Number fields require an integer input, and will reject any text that can't
be converted into an integer.
```
> age = youthful
Field 'Age' requires a number.
> age = 31
Field 'Age' set to: 31
```
Form data is presented as an EvTable, so text of any length will wrap cleanly.
```
> history = EVERY MORNING I WAKE UP AND OPEN PALM SLAM[...]
Field 'History' set to: EVERY MORNING I WAKE UP AND[...]
> look
Name: Ashley
Age: 31
History: EVERY MORNING I WAKE UP AND OPEN PALM SLAM A VHS INTO THE SLOT.
IT'S CHRONICLES OF RIDDICK AND RIGHT THEN AND THERE I START DOING
THE MOVES ALONGSIDE WITH THE MAIN CHARACTER, RIDDICK. I DO EVERY
MOVE AND I DO EVERY MOVE HARD.
```
When the player types 'submit' (or your specified submit command), the menu
quits and the form's data is passed to your specified function as a dictionary,
like so:
formdata = {"Name":"Ashley", "Age":31, "History":"EVERY MORNING I[...]"}
You can do whatever you like with this data in your function - forms can be used
to set data on a character, to help builders create objects, or for players to
craft items or perform other complicated actions with many variables involved.
The data that your form will accept can also be specified in your form template -
let's say, for example, that you won't accept ages under 18 or over 100. You can
do this by specifying "min" and "max" values in your field's dictionary:
```
PROFILE_TEMPLATE = [
{"fieldname":"Name", "fieldtype":"text"},
{"fieldname":"Age", "fieldtype":"number", "min":18, "max":100},
{"fieldname":"History", "fieldtype":"text"}
]
```
Now if the player tries to enter a value out of range, the form will not acept the
given value.
```
> age = 10
Field 'Age' reqiures a minimum value of 18.
> age = 900
Field 'Age' has a maximum value of 100.
```
Setting 'min' and 'max' for a text field will instead act as a minimum or
maximum character length for the player's input.
There are lots of ways to present the form to the player - fields can have default
values or show a custom message in place of a blank value, and player input can be
verified by a custom function, allowing for a great deal of flexibility. There
is also an option for 'bool' fields, which accept only a True / False input and
can be customized to represent the choice to the player however you like (E.G.
Yes/No, On/Off, Enabled/Disabled, etc.)
This module contains a simple example form that demonstrates all of the included
functionality - a command that allows a player to compose a message to another
online character and have it send after a custom delay. You can test it by
importing this module in your game's `default_cmdsets.py` module and adding
CmdTestMenu to your default character's command set.
## FIELD TEMPLATE KEYS:
### Required:
```
fieldname (str): Name of the field, as presented to the player.
fieldtype (str): Type of value required: 'text', 'number', or 'bool'.
```
### Optional:
- max (int): Maximum character length (if text) or value (if number).
- min (int): Minimum charater length (if text) or value (if number).
- truestr (str): String for a 'True' value in a bool field.
(E.G. 'On', 'Enabled', 'Yes')
- falsestr (str): String for a 'False' value in a bool field.
(E.G. 'Off', 'Disabled', 'No')
- default (str): Initial value (blank if not given).
- blankmsg (str): Message to show in place of value when field is blank.
- cantclear (bool): Field can't be cleared if True.
- required (bool): If True, form cannot be submitted while field is blank.
- verifyfunc (callable): Name of a callable used to verify input - takes
(caller, value) as arguments. If the function returns True,
the player's input is considered valid - if it returns False,
the input is rejected. Any other value returned will act as
the field's new value, replacing the player's input. This
allows for values that aren't strings or integers (such as
object dbrefs). For boolean fields, return '0' or '1' to set
the field to False or True.

View file

@ -0,0 +1,7 @@
"""
FieldFill contrib - Tim Ashley Jenkins 2018
"""
from .fieldfill import FieldEvMenu # noqa
from .fieldfill import CmdTestMenu # noqa

View file

@ -12,8 +12,8 @@ is submitted, the form's data is submitted as a dictionary to any callable of
your choice.
The function that initializes the fillable form menu is fairly simple, and
includes the caller, the template for the form, and the callback(caller, result) to which the form
data will be sent to upon submission.
includes the caller, the template for the form, and the callback(caller, result)
to which the form data will be sent to upon submission.
init_fill_field(formtemplate, caller, formcallback)

View file

@ -0,0 +1,52 @@
# Pseudo-random generator and registry
Contribution - Vincent Le Goff 2017
This contrib can be used to generate pseudo-random strings of information
with specific criteria. You could, for instance, use it to generate
phone numbers, license plate numbers, validation codes, non-sensivite
passwords and so on. The strings generated by the generator will be
stored and won't be available again in order to avoid repetition.
Here's a very simple example:
```python
from evennia.contrib.random_string_generator import RandomStringGenerator
# Create a generator for phone numbers
phone_generator = RandomStringGenerator("phone number", r"555-[0-9]{3}-[0-9]{4}")
# Generate a phone number (555-XXX-XXXX with X as numbers)
number = phone_generator.get()
# `number` will contain something like: "555-981-2207"
# If you call `phone_generator.get`, it won't give the same anymore.phone_generator.all()
# Will return a list of all currently-used phone numbers
phone_generator.remove("555-981-2207")
# The number can be generated again
```
## Importing
1. Import the `RandomStringGenerator` class from the contrib.
2. Create an instance of this class taking two arguments:
- The name of the gemerator (like "phone number", "license plate"...).
- The regular expression representing the expected results.
3. Use the generator's `all`, `get` and `remove` methods as shown above.
To understand how to read and create regular expressions, you can refer to
[the documentation on the re module](https://docs.python.org/2/library/re.html).
Some examples of regular expressions you could use:
- `r"555-\d{3}-\d{4}"`: 555, a dash, 3 digits, another dash, 4 digits.
- `r"[0-9]{3}[A-Z][0-9]{3}"`: 3 digits, a capital letter, 3 digits.
- `r"[A-Za-z0-9]{8,15}"`: between 8 and 15 letters and digits.
- ...
Behind the scenes, a script is created to store the generated information
for a single generator. The `RandomStringGenerator` object will also
read the regular expression you give to it to see what information is
required (letters, digits, a more restricted class, simple characters...)...
More complex regular expressions (with branches for instance) might not be
available.

View file

@ -0,0 +1,6 @@
"""
Pseudo-random generator - vlgeoff 2017
"""
from .random_string_generator import RandomStringGenerator # noqa

View file

@ -98,7 +98,7 @@ class RandomStringGeneratorScript(DefaultScript):
self.db.generated = {}
class RandomStringGenerator(object):
class RandomStringGenerator:
"""
A generator class to generate pseudo-random strings with a rule.
@ -156,7 +156,7 @@ class RandomStringGenerator(object):
self._find_elements(regex)
def __repr__(self):
return "<evennia.contrib.random_string_generator.RandomStringGenerator for {}>".format(
return "<evennia.contrib.tutorials.random_string_generator.RandomStringGenerator for {}>".format(
self.name
)
@ -168,7 +168,8 @@ class RandomStringGenerator(object):
try:
script = ScriptDB.objects.get(db_key="generator_script")
except ScriptDB.DoesNotExist:
script = create_script("contrib.random_string_generator.RandomStringGeneratorScript")
script = create_script(
"contrib.tutorials.random_string_generator.RandomStringGeneratorScript")
type(self).script = script
return script

View file

@ -0,0 +1,161 @@
# Easy menu selection tree
Contrib - Tim Ashley Jenkins 2017
This module allows you to create and initialize an entire branching EvMenu
instance with nothing but a multi-line string passed to one function.
EvMenu is incredibly powerful and flexible, but using it for simple menus
can often be fairly cumbersome - a simple menu that can branch into five
categories would require six nodes, each with options represented as a list
of dictionaries.
This module provides a function, `init_tree_selection`, which acts as a frontend
for EvMenu, dynamically sourcing the options from a multi-line string you
provide. For example, if you define a string as such:
TEST_MENU = '''Foo
Bar
Baz
Qux'''
And then use `TEST_MENU` as the 'treestr' source when you call
`init_tree_selection` on a player:
init_tree_selection(TEST_MENU, caller, callback)
The player will be presented with an EvMenu, like so:
___________________________
Make your selection:
___________________________
Foo
Bar
Baz
Qux
Making a selection will pass the selection's key to the specified callback as a
string along with the caller, as well as the index of the selection (the line
number on the source string) along with the source string for the tree itself.
In addition to specifying selections on the menu, you can also specify
categories. Categories are indicated by putting options below it preceded with
a '-' character. If a selection is a category, then choosing it will bring up a
new menu node, prompting the player to select between those options, or to go
back to the previous menu. In addition, categories are marked by default with a
'[+]' at the end of their key. Both this marker and the option to go back can be
disabled.
Categories can be nested in other categories as well - just go another '-'
deeper. You can do this as many times as you like. There's no hard limit to the
number of categories you can go down.
For example, let's add some more options to our menu, turning 'Bar' into a
category.
TEST_MENU = '''Foo
Bar
-You've got to know
--When to hold em
--When to fold em
--When to walk away
Baz
Qux'''
Now when we call the menu, we can see that 'Bar' has become a category instead of a
selectable option.
_______________________________
Make your selection:
_______________________________
Foo
Bar [+]
Baz
Qux
Note the [+] next to 'Bar'. If we select 'Bar', it'll show us the option listed
under it.
________________________________________________________________
Bar
________________________________________________________________
You've got to know [+]
<< Go Back: Return to the previous menu.
Just the one option, which is a category itself, and the option to go back,
which will take us back to the previous menu. Let's select 'You've got to know'.
________________________________________________________________
You've got to know
________________________________________________________________
When to hold em
When to fold em
When to walk away
<< Go Back: Return to the previous menu.
Now we see the three options listed under it, too. We can select one of them or
use 'Go Back' to return to the 'Bar' menu we were just at before. It's very
simple to make a branching tree of selections!
One last thing - you can set the descriptions for the various options simply by
adding a ':' character followed by the description to the option's line. For
example, let's add a description to 'Baz' in our menu:
TEST_MENU = '''Foo
Bar
-You've got to know
--When to hold em
--When to fold em
--When to walk away
Baz: Look at this one: the best option.
Qux'''
Now we see that the Baz option has a description attached that's separate from its key:
_______________________________________________________________
Make your selection:
_______________________________________________________________
Foo
Bar [+]
Baz: Look at this one: the best option.
Qux
Once the player makes a selection - let's say, 'Foo' - the menu will terminate
and call your specified callback with the selection, like so:
callback(caller, TEST_MENU, 0, "Foo")
The index of the selection is given along with a string containing the
selection's key. That way, if you have two selections in the menu with the same
key, you can still differentiate between them.
And that's all there is to it! For simple branching-tree selections, using this
system is much easier than manually creating EvMenu nodes. It also makes
generating menus with dynamic options much easier - since the source of the menu
tree is just a string, you could easily generate that string procedurally before
passing it to the `init_tree_selection` function. For example, if a player casts
a spell or does an attack without specifying a target, instead of giving them an
error, you could present them with a list of valid targets to select by
generating a multi-line string of targets and passing it to
`init_tree_selection`, with the callable performing the maneuver once a
selection is made.
This selection system only works for simple branching trees - doing anything
really complicated like jumping between categories or prompting for arbitrary
input would still require a full EvMenu implementation. For simple selections,
however, I'm sure you will find using this function to be much easier!
Included in this module is a sample menu and function which will let a player
change the color of their name - feel free to mess with it to get a feel for how
this system works by importing this module in your game's `default_cmdsets.py`
module and adding `CmdNameColor` to your default character's command set.

View file

@ -0,0 +1,6 @@
"""
Menu selection tree - Tim Ashley Jenkins 2017
"""
from .tree_select import init_tree_selection # noqa

View file

@ -155,6 +155,7 @@ Included in this module is a sample menu and function which will let a player ch
of their name - feel free to mess with it to get a feel for how this system works by importing
this module in your game's default_cmdsets.py module and adding CmdNameColor to your default
character's command set.
"""
from evennia.utils import evmenu