From 9b92b595c4da140aa846f02f08db7ab52352ca23 Mon Sep 17 00:00:00 2001 From: Griatch Date: Sat, 18 Dec 2021 21:48:08 +0100 Subject: [PATCH] Complete reshuffling of contribs. Not moved tests --- evennia/contrib/tests.py | 1 - .../tutorials/batchprocessor/README.md | 35 ++++ .../tutorials/batchprocessor/__init__.py | 4 + .../example_batch_cmds.ev | 0 .../example_batch_code.py | 0 .../contrib/tutorials/bodyfunctions/README.md | 16 ++ .../tutorials/bodyfunctions/__init__.py | 6 + .../bodyfunctions.py | 7 +- .../{tutorial_examples => mirror}/mirror.py | 0 .../contrib/tutorials/red_button/README.md | 34 ++++ .../contrib/tutorials/red_button/__init__.py | 6 + .../red_button.py | 7 +- .../contrib/tutorials/talking_npc/README.md | 21 +++ .../{tutorial_examples => }/tests.py | 0 .../tutorials/tutorial_examples/__init__.py | 0 .../tutorials/tutorial_world/README.md | 29 ++-- .../tutorials/tutorial_world/__init__.py | 6 +- .../contrib/tutorials/tutorial_world/build.ev | 8 +- evennia/contrib/utils/fieldfill/README.md | 157 +++++++++++++++++ evennia/contrib/utils/fieldfill/__init__.py | 7 + .../utils/{ => fieldfill}/fieldfill.py | 4 +- .../utils/random_string_generator/README.md | 52 ++++++ .../utils/random_string_generator/__init__.py | 6 + .../random_string_generator.py | 7 +- evennia/contrib/utils/tree_select/README.md | 161 ++++++++++++++++++ evennia/contrib/utils/tree_select/__init__.py | 6 + .../utils/{ => tree_select}/tree_select.py | 1 + 27 files changed, 552 insertions(+), 29 deletions(-) create mode 100644 evennia/contrib/tutorials/batchprocessor/README.md create mode 100644 evennia/contrib/tutorials/batchprocessor/__init__.py rename evennia/contrib/tutorials/{tutorial_examples => batchprocessor}/example_batch_cmds.ev (100%) rename evennia/contrib/tutorials/{tutorial_examples => batchprocessor}/example_batch_code.py (100%) create mode 100644 evennia/contrib/tutorials/bodyfunctions/README.md create mode 100644 evennia/contrib/tutorials/bodyfunctions/__init__.py rename evennia/contrib/tutorials/{tutorial_examples => bodyfunctions}/bodyfunctions.py (95%) rename evennia/contrib/tutorials/{tutorial_examples => mirror}/mirror.py (100%) create mode 100644 evennia/contrib/tutorials/red_button/README.md create mode 100644 evennia/contrib/tutorials/red_button/__init__.py rename evennia/contrib/tutorials/{tutorial_examples => red_button}/red_button.py (99%) create mode 100644 evennia/contrib/tutorials/talking_npc/README.md rename evennia/contrib/tutorials/{tutorial_examples => }/tests.py (100%) delete mode 100644 evennia/contrib/tutorials/tutorial_examples/__init__.py create mode 100644 evennia/contrib/utils/fieldfill/README.md create mode 100644 evennia/contrib/utils/fieldfill/__init__.py rename evennia/contrib/utils/{ => fieldfill}/fieldfill.py (99%) create mode 100644 evennia/contrib/utils/random_string_generator/README.md create mode 100644 evennia/contrib/utils/random_string_generator/__init__.py rename evennia/contrib/utils/{ => random_string_generator}/random_string_generator.py (97%) create mode 100644 evennia/contrib/utils/tree_select/README.md create mode 100644 evennia/contrib/utils/tree_select/__init__.py rename evennia/contrib/utils/{ => tree_select}/tree_select.py (99%) diff --git a/evennia/contrib/tests.py b/evennia/contrib/tests.py index 3b31c04c58..561d10831b 100644 --- a/evennia/contrib/tests.py +++ b/evennia/contrib/tests.py @@ -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 diff --git a/evennia/contrib/tutorials/batchprocessor/README.md b/evennia/contrib/tutorials/batchprocessor/README.md new file mode 100644 index 0000000000..fa8c91d4b6 --- /dev/null +++ b/evennia/contrib/tutorials/batchprocessor/README.md @@ -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). diff --git a/evennia/contrib/tutorials/batchprocessor/__init__.py b/evennia/contrib/tutorials/batchprocessor/__init__.py new file mode 100644 index 0000000000..cf53f16d34 --- /dev/null +++ b/evennia/contrib/tutorials/batchprocessor/__init__.py @@ -0,0 +1,4 @@ +""" +Batch processing examples - Griatch 2012 + +""" diff --git a/evennia/contrib/tutorials/tutorial_examples/example_batch_cmds.ev b/evennia/contrib/tutorials/batchprocessor/example_batch_cmds.ev similarity index 100% rename from evennia/contrib/tutorials/tutorial_examples/example_batch_cmds.ev rename to evennia/contrib/tutorials/batchprocessor/example_batch_cmds.ev diff --git a/evennia/contrib/tutorials/tutorial_examples/example_batch_code.py b/evennia/contrib/tutorials/batchprocessor/example_batch_code.py similarity index 100% rename from evennia/contrib/tutorials/tutorial_examples/example_batch_code.py rename to evennia/contrib/tutorials/batchprocessor/example_batch_code.py diff --git a/evennia/contrib/tutorials/bodyfunctions/README.md b/evennia/contrib/tutorials/bodyfunctions/README.md new file mode 100644 index 0000000000..6eecbd1c72 --- /dev/null +++ b/evennia/contrib/tutorials/bodyfunctions/README.md @@ -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). diff --git a/evennia/contrib/tutorials/bodyfunctions/__init__.py b/evennia/contrib/tutorials/bodyfunctions/__init__.py new file mode 100644 index 0000000000..fd5ab86a88 --- /dev/null +++ b/evennia/contrib/tutorials/bodyfunctions/__init__.py @@ -0,0 +1,6 @@ +""" +Bodyfunctions example script - Griatch, 2012 + +""" + +from .bodyfunctions import BodyFunctions # noqa diff --git a/evennia/contrib/tutorials/tutorial_examples/bodyfunctions.py b/evennia/contrib/tutorials/bodyfunctions/bodyfunctions.py similarity index 95% rename from evennia/contrib/tutorials/tutorial_examples/bodyfunctions.py rename to evennia/contrib/tutorials/bodyfunctions/bodyfunctions.py index 0cb0dd6b4a..177aa669e1 100644 --- a/evennia/contrib/tutorials/tutorial_examples/bodyfunctions.py +++ b/evennia/contrib/tutorials/bodyfunctions/bodyfunctions.py @@ -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): diff --git a/evennia/contrib/tutorials/tutorial_examples/mirror.py b/evennia/contrib/tutorials/mirror/mirror.py similarity index 100% rename from evennia/contrib/tutorials/tutorial_examples/mirror.py rename to evennia/contrib/tutorials/mirror/mirror.py diff --git a/evennia/contrib/tutorials/red_button/README.md b/evennia/contrib/tutorials/red_button/README.md new file mode 100644 index 0000000000..c419845309 --- /dev/null +++ b/evennia/contrib/tutorials/red_button/README.md @@ -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. + diff --git a/evennia/contrib/tutorials/red_button/__init__.py b/evennia/contrib/tutorials/red_button/__init__.py new file mode 100644 index 0000000000..4b9852d882 --- /dev/null +++ b/evennia/contrib/tutorials/red_button/__init__.py @@ -0,0 +1,6 @@ +""" +Tutorial Red Button Object - Griatch 2011 + +""" + +from .red_button import RedButton # noqa diff --git a/evennia/contrib/tutorials/tutorial_examples/red_button.py b/evennia/contrib/tutorials/red_button/red_button.py similarity index 99% rename from evennia/contrib/tutorials/tutorial_examples/red_button.py rename to evennia/contrib/tutorials/red_button/red_button.py index ab4a36d2fc..0e3484ab3d 100644 --- a/evennia/contrib/tutorials/tutorial_examples/red_button.py +++ b/evennia/contrib/tutorials/red_button/red_button.py @@ -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. diff --git a/evennia/contrib/tutorials/talking_npc/README.md b/evennia/contrib/tutorials/talking_npc/README.md new file mode 100644 index 0000000000..d08b404cef --- /dev/null +++ b/evennia/contrib/tutorials/talking_npc/README.md @@ -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. diff --git a/evennia/contrib/tutorials/tutorial_examples/tests.py b/evennia/contrib/tutorials/tests.py similarity index 100% rename from evennia/contrib/tutorials/tutorial_examples/tests.py rename to evennia/contrib/tutorials/tests.py diff --git a/evennia/contrib/tutorials/tutorial_examples/__init__.py b/evennia/contrib/tutorials/tutorial_examples/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/evennia/contrib/tutorials/tutorial_world/README.md b/evennia/contrib/tutorials/tutorial_world/README.md index 62768401f2..7259f3a156 100644 --- a/evennia/contrib/tutorials/tutorial_world/README.md +++ b/evennia/contrib/tutorials/tutorial_world/README.md @@ -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 ? diff --git a/evennia/contrib/tutorials/tutorial_world/__init__.py b/evennia/contrib/tutorials/tutorial_world/__init__.py index 45bded2779..0d106e1049 100644 --- a/evennia/contrib/tutorials/tutorial_world/__init__.py +++ b/evennia/contrib/tutorials/tutorial_world/__init__.py @@ -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 diff --git a/evennia/contrib/tutorials/tutorial_world/build.ev b/evennia/contrib/tutorials/tutorial_world/build.ev index dd43a88c2a..6875f421ca 100644 --- a/evennia/contrib/tutorials/tutorial_world/build.ev +++ b/evennia/contrib/tutorials/tutorial_world/build.ev @@ -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 diff --git a/evennia/contrib/utils/fieldfill/README.md b/evennia/contrib/utils/fieldfill/README.md new file mode 100644 index 0000000000..33ce33549d --- /dev/null +++ b/evennia/contrib/utils/fieldfill/README.md @@ -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 = , 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. diff --git a/evennia/contrib/utils/fieldfill/__init__.py b/evennia/contrib/utils/fieldfill/__init__.py new file mode 100644 index 0000000000..d4f50ce113 --- /dev/null +++ b/evennia/contrib/utils/fieldfill/__init__.py @@ -0,0 +1,7 @@ +""" +FieldFill contrib - Tim Ashley Jenkins 2018 + +""" + +from .fieldfill import FieldEvMenu # noqa +from .fieldfill import CmdTestMenu # noqa diff --git a/evennia/contrib/utils/fieldfill.py b/evennia/contrib/utils/fieldfill/fieldfill.py similarity index 99% rename from evennia/contrib/utils/fieldfill.py rename to evennia/contrib/utils/fieldfill/fieldfill.py index e2a5970ffe..269940040a 100644 --- a/evennia/contrib/utils/fieldfill.py +++ b/evennia/contrib/utils/fieldfill/fieldfill.py @@ -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) diff --git a/evennia/contrib/utils/random_string_generator/README.md b/evennia/contrib/utils/random_string_generator/README.md new file mode 100644 index 0000000000..410a512c74 --- /dev/null +++ b/evennia/contrib/utils/random_string_generator/README.md @@ -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. diff --git a/evennia/contrib/utils/random_string_generator/__init__.py b/evennia/contrib/utils/random_string_generator/__init__.py new file mode 100644 index 0000000000..07f92e9b82 --- /dev/null +++ b/evennia/contrib/utils/random_string_generator/__init__.py @@ -0,0 +1,6 @@ +""" +Pseudo-random generator - vlgeoff 2017 + +""" + +from .random_string_generator import RandomStringGenerator # noqa diff --git a/evennia/contrib/utils/random_string_generator.py b/evennia/contrib/utils/random_string_generator/random_string_generator.py similarity index 97% rename from evennia/contrib/utils/random_string_generator.py rename to evennia/contrib/utils/random_string_generator/random_string_generator.py index bedb0ed3b6..c3fd7d3df2 100644 --- a/evennia/contrib/utils/random_string_generator.py +++ b/evennia/contrib/utils/random_string_generator/random_string_generator.py @@ -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 "".format( + return "".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 diff --git a/evennia/contrib/utils/tree_select/README.md b/evennia/contrib/utils/tree_select/README.md new file mode 100644 index 0000000000..59f84cb020 --- /dev/null +++ b/evennia/contrib/utils/tree_select/README.md @@ -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. diff --git a/evennia/contrib/utils/tree_select/__init__.py b/evennia/contrib/utils/tree_select/__init__.py new file mode 100644 index 0000000000..e1fee4c564 --- /dev/null +++ b/evennia/contrib/utils/tree_select/__init__.py @@ -0,0 +1,6 @@ +""" +Menu selection tree - Tim Ashley Jenkins 2017 + +""" + +from .tree_select import init_tree_selection # noqa diff --git a/evennia/contrib/utils/tree_select.py b/evennia/contrib/utils/tree_select/tree_select.py similarity index 99% rename from evennia/contrib/utils/tree_select.py rename to evennia/contrib/utils/tree_select/tree_select.py index bdc600c8e4..e958a471e3 100644 --- a/evennia/contrib/utils/tree_select.py +++ b/evennia/contrib/utils/tree_select/tree_select.py @@ -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