diff --git a/docs/pylib/auto_link_remapper.py b/docs/pylib/auto_link_remapper.py index e8e37bb06d..0e410a10f2 100644 --- a/docs/pylib/auto_link_remapper.py +++ b/docs/pylib/auto_link_remapper.py @@ -38,18 +38,18 @@ TXT_REMAPS = { } URL_REMAPS = { "Developer-Central": "Components/Components-Overview", - "Tutorials": "Howto/Howto-Overview", - "../Howto/Starting/Directory-Overview": "Gamedir-Overview", - "Howto/Starting/Directory-Overview": "Gamedir-Overview", - "Starting/Directory-Overview": "Gamedir-Overview", + "Tutorials": "Howtos/Howtos-Overview", + "../Howtos/Beginner-Tutorial/Directory-Overview": "Gamedir-Overview", + "Howtos/Beginner-Tutorial/Directory-Overview": "Gamedir-Overview", + "Beginner-Tutorial/Directory-Overview": "Gamedir-Overview", "Directory-Overview": "Gamedir-Overview", "../Setup/Getting-Started": "Setup-Quickstart", "Setup/Getting-Started": "Setup-Quickstart", "Getting-Started": "Setup-Quickstart", - "First-Steps-Coding": "Starting-Part1", - "../Howto/Starting/Adding-Command-Tutorial": "Adding-Commands", - "Howto/Starting/Adding-Command-Tutorial": "Adding-Commands", - "Starting/Adding-Command-Tutorial": "Adding-Commands", + "First-Steps-Coding": "Beginner-Tutorial-Part1", + "../Howtos/Beginner-Tutorial/Adding-Command-Tutorial": "Adding-Commands", + "Howtos/Beginner-Tutorial/Adding-Command-Tutorial": "Adding-Commands", + "Beginner-Tutorial/Adding-Command-Tutorial": "Adding-Commands", "Adding-Command-Tutorial": "Adding-Commands", "CmdSet": "Command-Sets", "Spawner": "Prototypes", @@ -248,26 +248,26 @@ def auto_link_remapper(no_autodoc=False): print(f" ORPHANED DOC: no refs found to {src_url}.md") # write tocfile - with open(_TOC_FILE, "w") as fil: - fil.write("```{toctree}\n") + # with open(_TOC_FILE, "w") as fil: + # fil.write("```{toctree}\n") - if not no_autodoc: - fil.write("- [API root](api/evennia-api.rst)") + # if not no_autodoc: + # fil.write("- [API root](api/evennia-api.rst)") - for ref in sorted(toc_map.values()): + # for ref in sorted(toc_map.values()): - if ref == "toc": - continue + # if ref == "toc": + # continue - # if not "/" in ref: - # ref = "./" + ref + # # if not "/" in ref: + # # ref = "./" + ref - # linkname = ref.replace("-", " ") - fil.write(f"\n{ref}") # - [{linkname}]({ref})") + # # linkname = ref.replace("-", " ") + # fil.write(f"\n{ref}") # - [{linkname}]({ref})") - # we add a self-reference so the toc itself is also a part of a toctree - fil.write("\n```\n\n```{toctree}\n :hidden:\n\ntoc\n```") - print(" -- File toc.md updated.") + # # we add a self-reference so the toc itself is also a part of a toctree + # fil.write("\n```\n\n```{toctree}\n :hidden:\n\ntoc\n```") + # print(" -- File toc.md updated.") print(" -- Auto-Remapper finished.") diff --git a/docs/pylib/contrib_readmes2docs.py b/docs/pylib/contrib_readmes2docs.py index 9c83c8f3b9..aa2886c02e 100644 --- a/docs/pylib/contrib_readmes2docs.py +++ b/docs/pylib/contrib_readmes2docs.py @@ -12,8 +12,11 @@ _DOCS_PATH = pathjoin(_EVENNIA_PATH, "docs") _SOURCE_DIR = pathjoin(_EVENNIA_PATH, "evennia", "contrib") _OUT_DIR = pathjoin(_DOCS_PATH, "source", "Contribs") -_OUT_INDEX_FILE = pathjoin(_OUT_DIR, "Contrib-Overview.md") +_OUT_INDEX_FILE = pathjoin(_OUT_DIR, "Contribs-Overview.md") +_FILE_STRUCTURE = """{header} +{categories} +{footer}""" _CATEGORY_DESCS = { "base_systems": """ @@ -79,19 +82,19 @@ If you want to contribute yourself, see [here](Contributing)! """ -TOCTREE = """ -```{{toctree}} +TOCTREE = """```{{toctree}} +:maxdepth: 1 {listing} -``` - -""" +```""" CATEGORY = """ ## {category} _{category_desc}_ +{toctree} + {blurbs} @@ -168,9 +171,9 @@ def readmes2docs(directory=_SOURCE_DIR): # build the index with blurbs - lines = [HEADER] - filenames = [] + category_sections = [] for category in sorted(categories): + filenames = [] contrib_tups = categories[category] catlines = [] for tup in sorted(contrib_tups, key=lambda tup: tup[0].lower()): @@ -183,22 +186,23 @@ def readmes2docs(directory=_SOURCE_DIR): code_location=tup[4] ) ) - filenames.append(f"Contribs{sep}{tup[3]}") - lines.append( + filenames.append(f"{tup[3]}") + toctree = TOCTREE.format(listing="\n".join(filenames)) + category_sections.append( CATEGORY.format( category=category, category_desc=_CATEGORY_DESCS[category].strip(), - blurbs="\n".join(catlines) + blurbs="\n".join(catlines), + toctree=toctree ) ) - lines.append(TOCTREE.format( - listing="\n ".join(filenames)) + + text = _FILE_STRUCTURE.format( + header=HEADER, + categories="\n".join(category_sections), + footer=INDEX_FOOTER ) - lines.append(INDEX_FOOTER) - - text = "\n".join(lines) - with open(_OUT_INDEX_FILE, 'w') as fil: fil.write(text) diff --git a/docs/pylib/update_dynamic_pages.py b/docs/pylib/update_dynamic_pages.py index 69048a9c9f..e9f84a37d7 100644 --- a/docs/pylib/update_dynamic_pages.py +++ b/docs/pylib/update_dynamic_pages.py @@ -17,7 +17,7 @@ def update_changelog(): """ sourcefile = pathjoin(ROOTDIR, "CHANGELOG.md") - targetfile = pathjoin(DOCSRCDIR, "Setup", "Changelog.md") + targetfile = pathjoin(DOCSRCDIR, "Coding", "Changelog.md") with open(sourcefile) as fil: txt = fil.read() diff --git a/docs/source/Setup/Changelog.md b/docs/source/Coding/Changelog.md similarity index 100% rename from docs/source/Setup/Changelog.md rename to docs/source/Coding/Changelog.md diff --git a/docs/source/Coding/Coding-Introduction.md b/docs/source/Coding/Coding-Introduction.md index 73e8936ee8..b6aca1e59b 100644 --- a/docs/source/Coding/Coding-Introduction.md +++ b/docs/source/Coding/Coding-Introduction.md @@ -7,14 +7,14 @@ Here are some pointers to get you going. ## Start with the tutorial -It's highly recommended that you jump in on the [Starting Tutorial](../Howto/Starting/Part1/Starting-Part1.md). Even if +It's highly recommended that you jump in on the [Starting Tutorial](../Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Part1-Intro.md). Even if you only the beginning or some part of it, it covers much of the things needed to get started. ## Python Evennia is developed using Python. Even if you are more of a designer than a coder, it is wise to learn how to read and understand basic Python code. If you are new to Python, or need a refresher, -take a look at our [Python introduction](../Howto/Starting/Part1/Python-basic-introduction.md). +take a look at our [Python introduction](../Howtos/Beginner-Tutorial/Part1/Python-basic-introduction.md). ## Explore Evennia interactively @@ -74,7 +74,7 @@ After this you can import and access all of the Evennia system, same as with `ev ### More exploration You can complement your exploration by peeking at the sections of the much more detailed -[Evennia Component overview](../Components/Components-Overview.md). The [Tutorials](../Howto/Howto-Overview.md) section also contains a growing collection +[Evennia Component overview](../Components/Components-Overview.md). The [Tutorials](../Howtos/Howtos-Overview.md) section also contains a growing collection of system- or implementation-specific help. ## Use a python syntax checker @@ -91,7 +91,7 @@ using such a checker can be a good start to weed out the simple problems. ## Plan before you code -Before you start coding away at your dream game, take a look at our [Game Planning](../Howto/Starting/Part2/Game-Planning.md) +Before you start coding away at your dream game, take a look at our [Game Planning](../Howtos/Beginner-Tutorial/Part2/Game-Planning.md) page. It might hopefully help you avoid some common pitfalls and time sinks. ## Code in your game folder, not in the evennia/ repository diff --git a/docs/source/Coding/Coding-Overview.md b/docs/source/Coding/Coding-Overview.md index f2a950f155..ff94a89811 100644 --- a/docs/source/Coding/Coding-Overview.md +++ b/docs/source/Coding/Coding-Overview.md @@ -5,26 +5,38 @@ make your game, also if you never coded before. If you are an experienced coder, to you, but some things may still be useful. -## Find your way - -- [Directory-Overview](../Howto/Starting/Part1/Gamedir-Overview.md) -- [Quirks of Evennia](./Quirks.md) - ## Setting up a workflow -- [Setting up PyCharm](./Setting-up-PyCharm.md) -- [Using Version-Control](./Version-Control.md) -- [Updating Evennia sources](./Updating-Your-Game.md) +See also the [Beginner Tutorial](../Howtos/Beginner-Tutorial/Beginner-Tutorial-Intro.md). + +```{toctree} +:maxdepth: 2 + +Version-Control.md +Updating-Your-Game.md + +``` ## Coding away -- [Coding Introduction](./Coding-Introduction.md) -- [Ways to Debug](./Debugging.md) -- [Adding unit-tests](./Unit-Testing.md) -- [Things to remember when importing from evennia](./Flat-API.md) +```{toctree} +:maxdepth: 2 -## Advanced concepts +Coding-Introduction.md +Debugging.md +Unit-Testing.md +Profiling.md +Quirks.md +Changelog.md -- [Continuous Integration](./Continuous-Integration.md) - - [Using Travis](./Using-Travis.md) -- [Profiling](./Profiling.md) +``` + +## Third-party integrations + +```{toctree} +:maxdepth: 2 + +Continuous-Integration.md +Setting-up-PyCharm.md + +``` \ No newline at end of file diff --git a/docs/source/Coding/Continuous-Integration-TeamCity.md b/docs/source/Coding/Continuous-Integration-TeamCity.md new file mode 100644 index 0000000000..59b3391266 --- /dev/null +++ b/docs/source/Coding/Continuous-Integration-TeamCity.md @@ -0,0 +1,198 @@ +# Continuous Integration - TeamCity (linux) + +This sets up a TeamCity build integration environment on Linux. + +## Prerequisites + +- Follow [TeamCity](https://www.jetbrains.com/teamcity/) 's in-depth +[Setup Guide](https://confluence.jetbrains.com/display/TCD8/Installing+and+Configuring+the+TeamCity+Server). +- You need to use [Version Control](./Version-Control.md). + +After meeting the preparation steps for your specific environment, log on to your teamcity interface +at `http://:8111/`. + +Create a new project named "Evennia" and in it construct a new template called `continuous-integration`. + +## A Quick Overview + +_Templates_ are fancy objects in TeamCity that allow an administrator to define build steps that are +shared between one or more build projects. Assigning a VCS Root (Source Control) is unnecessary at +this stage, primarily you'll be worrying about the build steps and your default parameters (both +visible on the tabs to the left.) + +## Template Setup + +In this template, you'll be outlining the steps necessary to build your specific game. (A number of +sample scripts are provided under this section below!) Click Build Steps and prepare your general +flow. For this example, we will be doing a few basic example steps: + +* Transforming the Settings.py file - We do this to update ports or other information that make your production + environment unique from your development environment. +* Making migrations and migrating the game database. +* Publishing the game files. +* Reloading the server. + +For each step we'll being use the "Command Line Runner" (a fancy name for a shell script executor). + +Create a build step with the name: "Transform Configuration" and add the script: + +```bash +#!/bin/bash +# Replaces the game configuration with one +# appropriate for this deployment. + +CONFIG="%system.teamcity.build.checkoutDir%/server/conf/settings.py" +MYCONF="%system.teamcity.build.checkoutDir%/server/conf/my.cnf" + +sed -e 's/TELNET_PORTS = [4000]/TELNET_PORTS = [%game.ports%]/g' "$CONFIG" > "$CONFIG".tmp && mv +"$CONFIG".tmp "$CONFIG" +sed -e 's/WEBSERVER_PORTS = [(4001, 4002)]/WEBSERVER_PORTS = [%game.webports%]/g' "$CONFIG" > +"$CONFIG".tmp && mv "$CONFIG".tmp "$CONFIG" +`````` + +```bash + +# settings.py MySQL DB configuration +echo Configuring Game Database... +echo "" >> "$CONFIG" +echo "######################################################################" >> "$CONFIG" +echo "# MySQL Database Configuration" >> "$CONFIG" +echo "######################################################################" >> "$CONFIG" + +echo "DATABASES = {" >> "$CONFIG" +echo " 'default': {" >> "$CONFIG" +echo " 'ENGINE': 'django.db.backends.mysql'," >> "$CONFIG" +echo " 'OPTIONS': {" >> "$CONFIG" +echo " 'read_default_file': 'server/conf/my.cnf'," >> "$CONFIG" +echo " }," >> "$CONFIG" +echo " }" >> "$CONFIG" +echo "}" >> "$CONFIG" + +# Create the My.CNF file. +echo "[client]" >> "$MYCONF" +echo "database = %mysql.db%" >> "$MYCONF" +echo "user = %mysql.user%" >> "$MYCONF" +echo "password = %mysql.pass%" >> "$MYCONF" +echo "default-character-set = utf8" >> "$MYCONF" + +``` + +If you look at the parameters side of the page after saving this script, you'll notice that some new +parameters have been populated for you. This is because we've included new teamcity configuration +parameters that are populated when the build itself is ran. When creating projects that inherit this +template, we'll be able to fill in or override those parameters for project-specific configuration. + +Go ahead and create another build step called "Make Database Migration" +If you're using Sqlite3 for your game (default database), it's prudent to change working directory on this + step to your game dir. + + ```bash + #!/bin/bash + # Update the DB migration + + LOGDIR="server/logs" + + . %evenv.dir%/bin/activate + + # Check that the logs directory exists. + if [ ! -d "$LOGDIR" ]; then + # Control will enter here if $LOGDIR doesn't exist. + mkdir "$LOGDIR" + fi + + evennia makemigrations + ``` + +Create yet another build step, this time named: "Execute Database Migration": +If you're using Sqlite3 for your game (default database), it's prudent to change working directory on this + step to your game dir. + +```bash +#!/bin/bash +# Apply the database migration. + +LOGDIR="server/logs" + +. %evenv.dir%/bin/activate + +# Check that the logs directory exists. +if [ ! -d "$LOGDIR" ]; then + # Control will enter here if $LOGDIR doesn't exist. + mkdir "$LOGDIR" +fi + +evennia migrate + +``` + +Our next build step is where we actually publish our build. Up until now, all work on game has been +done in a 'work' directory on TeamCity's build agent. From that directory we will now copy our files +to where our game actually exists on the local server. + +Create a new build step called "Publish Build". If you're using SQlite3 on your game, be sure to order this step ABOVE +the Database Migration steps. The build order will matter! + + ```bash + #!/bin/bash + # Publishes the build to the proper build directory. + + DIRECTORY="" + + if [ ! -d "$DIRECTORY" ]; then + # Control will enter here if $DIRECTORY doesn't exist. + mkdir "$DIRECTORY" + fi + + # Copy all the files. + cp -ruv %teamcity.build.checkoutDir%/* "$DIRECTORY" + chmod -R 775 "$DIRECTORY" + + ``` + +Finally the last script will reload our game for us. + +Create a new script called "Reload Game": +The working directory on this build step will be: `%game.dir%` + +```bash +#!/bin/bash +# Apply the database migration. + +LOGDIR="server/logs" +PIDDIR="server/server.pid" + +. %evenv.dir%/bin/activate + +# Check that the logs directory exists. +if [ ! -d "$LOGDIR" ]; then + # Control will enter here if $LOGDIR doesn't exist. + mkdir "$LOGDIR" +fi + +# Check that the server is running. +if [ -d "$PIDDIR" ]; then + # Control will enter here if the game is running. + evennia reload +fi +``` + +Now the template is ready for use! It would be useful this time to revisit the parameters page and +set the evenv parameter to the directory where your virtualenv exists: IE "/srv/mush/evenv". + +### Creating the Project + +Now it's time for the last few steps to set up a CI environment. + +* Return to the Evennia Project overview/administration page. +* Create a new Sub-Project called "Production". This will be the category that holds our actual game. +* Create a new Build Configuration in Production with the name of your MUSH. Base this configuration off of the + continuous-integration template we made earlier. +* In the build configuration, enter VCS roots and create a new VCS root that points to the + branch/version control that you are using. +* Go to the parameters page and fill in the undefined parameters for your specific configuration. +* If you wish for the CI to run every time a commit is made, go to the VCS triggers and add one for + "On Every Commit". + +And you're done! At this point, you can return to the project overview page and queue a new build +for your game. If everything was set up correctly, the build will complete successfully. Additional +build steps could be added or removed at this point, adding some features like Unit Testing or more! \ No newline at end of file diff --git a/docs/source/Coding/Using-Travis.md b/docs/source/Coding/Continuous-Integration-Travis.md similarity index 52% rename from docs/source/Coding/Using-Travis.md rename to docs/source/Coding/Continuous-Integration-Travis.md index f1bf20568a..15c84f9eee 100644 --- a/docs/source/Coding/Using-Travis.md +++ b/docs/source/Coding/Continuous-Integration-Travis.md @@ -1,10 +1,11 @@ -# Using Travis +# Continuous integration with Travis -Evennia uses [Travis CI](https://travis-ci.org/) to check that it's building successfully after every -commit to its Github repository (you can for example see the `build: passing` badge at the top of -Evennia's [Readme file](https://github.com/evennia/evennia)). If your game is open source on Github -you may also use Travis for free. See [the Travis docs](https://docs.travis-ci.com/user/getting- -started/) for how to get started. +[Travis CI](https://travis-ci.org/) is an online service for checking, validating and potentially +deploying code automatically. It can check that every commit is building successfully after every +commit to its Github repository. + +If your game is open source on Github you may use Travis for free. +See [the Travis docs](https://docs.travis-ci.com/user/getting- started/) for how to get started. After logging in you will get to point Travis to your repository on github. One further thing you need to set up yourself is a Travis config file named `.travis.yml` (note the initial period `.`). @@ -15,7 +16,7 @@ scratch and then run validation tests on it. Here is an example: ``` yaml language: python python: - - "2.7" + - "3.10" install: - git clone https://github.com/evennia/evennia.git - cd evennia @@ -23,15 +24,16 @@ install: - cd $TRAVIS_BUILD_DIR script: - evennia migrate - - evennia test evennia - - evennia test + - evennia test --settings settings.py . ``` -This will tell travis how to download Evennia, install it, set up a database and then run the test -suite. +This will tell travis how to download Evennia, install it, set up a database and then run +your own test suite (inside the game dir). Use `evennia test evennia` if you also want to +run the Evennia full test suite. + You need to add this file to git (`git add .travis.yml`) and then commit your changes before Travis will be able to see it. -For properly testing your game you of course also need to write unittests. [We have a page](Unit- -Testing) on how we set those up for Evennia, you should be able to refer to that for making tests -fitting your game. +For properly testing your game you of course also need to write unittests. +The [Unit testing](./Unit-Testing.md) doc page gives some ideas on how to set those up for Evennia. +You should be able to refer to that for making tests fitting your game. diff --git a/docs/source/Coding/Continuous-Integration.md b/docs/source/Coding/Continuous-Integration.md index db9bcc2e65..d13a2dc3cd 100644 --- a/docs/source/Coding/Continuous-Integration.md +++ b/docs/source/Coding/Continuous-Integration.md @@ -1,17 +1,17 @@ # Continuous Integration -One of the advantages of Evennia over traditional MUSH development systems is that Evennia is -capable of integrating into enterprise level integration environments and source control. Because of -this, it can also be the subject of automation for additional convenience, allowing a more -streamlined development environment. +One of the advantages of Evennia over traditional MU* development systems is that Evennia can +integrate into enterprise-level integration environments and source control. -## What is Continuous Integration? +## What is Continuous Integration (CI)? [Continuous Integration (CI)](https://www.thoughtworks.com/continuous-integration) is a development -practice that requires developers to integrate code into a shared repository several times a day. -Each check-in is then verified by an automated build, allowing teams to detect problems early. +practice that requires developers to integrate code into a shared repository. +Each check-in is then verified by an automated build, allowing teams to detect problems early. This +can be set up to safely deploy data to a production server only after tests have passed, for example. For Evennia, continuous integration allows an automated build process to: + * Pull down a latest build from Source Control. * Run migrations on the backing SQL database. * Automate additional unique tasks for that project. @@ -19,204 +19,18 @@ For Evennia, continuous integration allows an automated build process to: * Publish those files to the server directory * Reload the game. -## Preparation -To prepare a CI environment for your `MU*`, it will be necessary to set up some prerequisite -software for your server. +## List of continuous integration tools -Among those you will need: -* A Continuous Integration Environment. - * I recommend [TeamCity](https://www.jetbrains.com/teamcity/) which has an in-depth [Setup -Guide](https://confluence.jetbrains.com/display/TCD8/Installing+and+Configuring+the+TeamCity+Server) -* [Source Control](./Version-Control.md) - * This could be Git or SVN or any other available SC. +There are a lot of tools and services providing CI functionality. Here are a few that people have used +with Evennia: -## Linux TeamCity Setup -For this part of the guide, an example setup will be provided for administrators running a TeamCity -build integration environment on Linux. +```{toctree} +:maxdepth: 1 -After meeting the preparation steps for your specific environment, log on to your teamcity interface -at `http://:8111/`. +Continuous-Integration-Travis.md +Continuous-Integration-TeamCity.md -Create a new project named "Evennia" and in it construct a new template called continuous- -integration. +``` -### A Quick Overview -Templates are fancy objects in TeamCity that allow an administrator to define build steps that are -shared between one or more build projects. Assigning a VCS Root (Source Control) is unnecessary at -this stage, primarily you'll be worrying about the build steps and your default parameters (both -visible on the tabs to the left.) - -### Template Setup - -In this template, you'll be outlining the steps necessary to build your specific game. (A number of -sample scripts are provided under this section below!) Click Build Steps and prepare your general -flow. For this example, we will be doing a few basic example steps: - -* Transforming the Settings.py file - * We do this to update ports or other information that make your production environment unique - from your development environment. -* Making migrations and migrating the game database. -* Publishing the game files. -* Reloading the server. - -For each step we'll being use the "Command Line Runner" (a fancy name for a shell script executor). - -* Create a build step with the name: Transform Configuration -* For the script add: - - ```bash - #!/bin/bash - # Replaces the game configuration with one - # appropriate for this deployment. - - CONFIG="%system.teamcity.build.checkoutDir%/server/conf/settings.py" - MYCONF="%system.teamcity.build.checkoutDir%/server/conf/my.cnf" - - sed -e 's/TELNET_PORTS = [4000]/TELNET_PORTS = [%game.ports%]/g' "$CONFIG" > "$CONFIG".tmp && mv -"$CONFIG".tmp "$CONFIG" - sed -e 's/WEBSERVER_PORTS = [(4001, 4002)]/WEBSERVER_PORTS = [%game.webports%]/g' "$CONFIG" > -"$CONFIG".tmp && mv "$CONFIG".tmp "$CONFIG" - - # settings.py MySQL DB configuration - echo Configuring Game Database... - echo "" >> "$CONFIG" - echo "######################################################################" >> "$CONFIG" - echo "# MySQL Database Configuration" >> "$CONFIG" - echo "######################################################################" >> "$CONFIG" - - echo "DATABASES = {" >> "$CONFIG" - echo " 'default': {" >> "$CONFIG" - echo " 'ENGINE': 'django.db.backends.mysql'," >> "$CONFIG" - echo " 'OPTIONS': {" >> "$CONFIG" - echo " 'read_default_file': 'server/conf/my.cnf'," >> "$CONFIG" - echo " }," >> "$CONFIG" - echo " }" >> "$CONFIG" - echo "}" >> "$CONFIG" - - # Create the My.CNF file. - echo "[client]" >> "$MYCONF" - echo "database = %mysql.db%" >> "$MYCONF" - echo "user = %mysql.user%" >> "$MYCONF" - echo "password = %mysql.pass%" >> "$MYCONF" - echo "default-character-set = utf8" >> "$MYCONF" - ``` - -If you look at the parameters side of the page after saving this script, you'll notice that some new -parameters have been populated for you. This is because we've included new teamcity configuration -parameters that are populated when the build itself is ran. When creating projects that inherit this -template, we'll be able to fill in or override those parameters for project-specific configuration. - -* Go ahead and create another build step called "Make Database Migration" - * If you're using SQLLite on your game, it will be prudent to change working directory on this -step to: %game.dir% -* In this script include: - - ```bash - #!/bin/bash - # Update the DB migration - - LOGDIR="server/logs" - - . %evenv.dir%/bin/activate - - # Check that the logs directory exists. - if [ ! -d "$LOGDIR" ]; then - # Control will enter here if $LOGDIR doesn't exist. - mkdir "$LOGDIR" - fi - - evennia makemigrations - ``` - -* Create yet another build step, this time named: "Execute Database Migration": - * If you're using SQLLite on your game, it will be prudent to change working directory on this -step to: %game.dir% - ```bash - #!/bin/bash - # Apply the database migration. - - LOGDIR="server/logs" - - . %evenv.dir%/bin/activate - - # Check that the logs directory exists. - if [ ! -d "$LOGDIR" ]; then - # Control will enter here if $LOGDIR doesn't exist. - mkdir "$LOGDIR" - fi - - evennia migrate - - ``` - -Our next build step is where we actually publish our build. Up until now, all work on game has been -done in a 'work' directory on TeamCity's build agent. From that directory we will now copy our files -to where our game actually exists on the local server. - -* Create a new build step called "Publish Build": - * If you're using SQLLite on your game, be sure to order this step ABOVE the Database Migration -steps. The build order will matter! - ```bash - #!/bin/bash - # Publishes the build to the proper build directory. - - DIRECTORY="%game.dir%" - - if [ ! -d "$DIRECTORY" ]; then - # Control will enter here if $DIRECTORY doesn't exist. - mkdir "$DIRECTORY" - fi - - # Copy all the files. - cp -ruv %teamcity.build.checkoutDir%/* "$DIRECTORY" - chmod -R 775 "$DIRECTORY" - - ``` - -Finally the last script will reload our game for us. - -* Create a new script called "Reload Game": - * The working directory on this build step will be: %game.dir% - ```bash - #!/bin/bash - # Apply the database migration. - - LOGDIR="server/logs" - PIDDIR="server/server.pid" - - . %evenv.dir%/bin/activate - - # Check that the logs directory exists. - if [ ! -d "$LOGDIR" ]; then - # Control will enter here if $LOGDIR doesn't exist. - mkdir "$LOGDIR" - fi - - # Check that the server is running. - if [ -d "$PIDDIR" ]; then - # Control will enter here if the game is running. - evennia reload - fi - ``` - -Now the template is ready for use! It would be useful this time to revisit the parameters page and -set the evenv parameter to the directory where your virtualenv exists: IE "/srv/mush/evenv". - -### Creating the Project - -Now it's time for the last few steps to set up a CI environment. - -* Return to the Evennia Project overview/administration page. -* Create a new Sub-Project called "Production" - * This will be the category that holds our actual game. -* Create a new Build Configuration in Production with the name of your MUSH. - * Base this configuration off of the continuous-integration template we made earlier. -* In the build configuration, enter VCS roots and create a new VCS root that points to the -branch/version control that you are using. -* Go to the parameters page and fill in the undefined parameters for your specific configuration. -* If you wish for the CI to run every time a commit is made, go to the VCS triggers and add one for -"On Every Commit". - -And you're done! At this point, you can return to the project overview page and queue a new build -for your game. If everything was set up correctly, the build will complete successfully. Additional -build steps could be added or removed at this point, adding some features like Unit Testing or more! \ No newline at end of file +[This is an overview of other tools](https://www.atlassian.com/continuous-delivery/continuous-integration/tools) +(external link). \ No newline at end of file diff --git a/docs/source/Coding/Flat-API.md b/docs/source/Coding/Flat-API.md deleted file mode 100644 index 6e41757c5e..0000000000 --- a/docs/source/Coding/Flat-API.md +++ /dev/null @@ -1,37 +0,0 @@ -# Things to remember about the flat API - -The flat API is a series of 'shortcuts' on the `evennia` main library root (defined in -`evennia/__init__.py`). Its componentas are documented [as part of the auto-documentation](../Evennia-API.md). - -## To remember when importing from `evennia` - -Properties on the root of the `evennia` package are *not* modules in their own right. They are just -shortcut properties stored in the `evennia/__init__.py` module. That means that you cannot use dot- -notation to `import` nested module-names over `evennia`. The rule of thumb is that you cannot use -`import` for more than one level down. Hence you can do - -```python - import evennia - print(evennia.default_cmds.CmdLook) -``` - -or import one level down - -```python - from evennia import default_cmds - print(default_cmds.CmdLook) -``` - -but you *cannot* import two levels down - -```python - from evennia.default_cmds import CmdLook # error! -``` - -This will give you an `ImportError` telling you that the module `default_cmds` cannot be found - -this is becasue `default_cmds` is just a *variable* stored in `evennia.__init__.py`; this cannot be -imported from. If you really want full control over which level of package you import you can always -bypass the root package and import directly from from the real location. For example -`evennia.DefaultObject` is a shortcut to `evennia.objects.objects.DefaultObject`. Using this full -path will have the import mechanism work normally. See `evennia/__init__.py` to see where the -package imports from. \ No newline at end of file diff --git a/docs/source/Coding/Quirks.md b/docs/source/Coding/Quirks.md index f0275289e9..cebf5d3860 100644 --- a/docs/source/Coding/Quirks.md +++ b/docs/source/Coding/Quirks.md @@ -4,7 +4,7 @@ This is a list of various quirks or common stumbling blocks that people often ask about or report when using (or trying to use) Evennia. They are not bugs. -## Forgetting to use @reload to see changes to your typeclasses +## Forgetting to use `reload` to see changes to your typeclasses Firstly: Reloading the server is a safe and usually quick operation which will *not* disconnect any accounts. @@ -104,17 +104,40 @@ can result in very inconsistent and hard-to-diagnose errors. The moral of the story-- it can be dangerous to tinker with magic methods on typeclassed objects. Try to avoid doing so. -## Known upstream bugs +## Things to remember about the flat API -- There is currently (Autumn 2017) a bug in the `zope.interface` installer on some Linux Ubuntu -distributions (notably Ubuntu 16.04 LTS). Zope is a dependency of Twisted. The error manifests in -the server not starting with an error that `zope.interface` is not found even though `pip list` -shows it's installed. The reason is a missing empty `__init__.py` file at the root of the zope -package. If the virtualenv is named "evenv" as suggested in the [Setup Quickstart](../Setup/Installation.md) -instructions, use the following command to fix it: +The flat API is a series of 'shortcuts' on the `evennia` main library root (defined in +`evennia/__init__.py`). Its componentas are documented [as part of the auto-documentation](../Evennia-API.md). - ```shell - touch evenv/local/lib/python2.7/site-packages/zope/__init__.py - ``` +### To remember when importing from `evennia` - This will create the missing file and things should henceforth work correctly. +Properties on the root of the `evennia` package are *not* modules in their own right. They are just +shortcut properties stored in the `evennia/__init__.py` module. That means that you cannot use dot- +notation to `import` nested module-names over `evennia`. The rule of thumb is that you cannot use +`import` for more than one level down. Hence you can do + +```python + import evennia + print(evennia.default_cmds.CmdLook) +``` + +or import one level down + +```python + from evennia import default_cmds + print(default_cmds.CmdLook) +``` + +but you *cannot* import two levels down + +```python + from evennia.default_cmds import CmdLook # error! +``` + +This will give you an `ImportError` telling you that the module `default_cmds` cannot be found - +this is becasue `default_cmds` is just a *variable* stored in `evennia.__init__.py`; this cannot be +imported from. If you really want full control over which level of package you import you can always +bypass the root package and import directly from from the real location. For example +`evennia.DefaultObject` is a shortcut to `evennia.objects.objects.DefaultObject`. Using this full +path will have the import mechanism work normally. See `evennia/__init__.py` to see where the +package imports from. diff --git a/docs/source/Coding/Setting-up-PyCharm.md b/docs/source/Coding/Setting-up-PyCharm.md index cacc71b6be..971aec6618 100644 --- a/docs/source/Coding/Setting-up-PyCharm.md +++ b/docs/source/Coding/Setting-up-PyCharm.md @@ -1,6 +1,4 @@ -# Setting up PyCharm - -# Directions for setting up PyCharm with Evennia +# Setting up PyCharm with Evennia [PyCharm](https://www.jetbrains.com/pycharm/) is a Python developer's IDE from Jetbrains available for Windows, Mac and Linux. It is a commercial product but offer free trials, a scaled-down diff --git a/docs/source/Components/Accounts.md b/docs/source/Components/Accounts.md index 619ab892ba..d2bd11c269 100644 --- a/docs/source/Components/Accounts.md +++ b/docs/source/Components/Accounts.md @@ -10,7 +10,7 @@ Exactly how many Sessions can interact with an Account and its Puppets at once i Evennia's [MULTISESSION_MODE](./Sessions.md#multisession-mode) setting. Apart from storing login information and other account-specific data, the Account object is what is -chatting on [Channels](./Communications.md). It is also a good place to store [Permissions](./Locks.md) to be +chatting on [Channels](./Channels.md). It is also a good place to store [Permissions](./Locks.md) to be consistent between different in-game characters as well as configuration options. The Account object also has its own [CmdSet](./Command-Sets.md), the `AccountCmdSet`. diff --git a/docs/source/Components/Bootstrap-Components-and-Utilities.md b/docs/source/Components/Bootstrap-Components-and-Utilities.md index 4cb46b0e35..69b2a89b9b 100644 --- a/docs/source/Components/Bootstrap-Components-and-Utilities.md +++ b/docs/source/Components/Bootstrap-Components-and-Utilities.md @@ -2,8 +2,8 @@ Bootstrap provides many utilities and components you can use when customizing Evennia's web presence. We'll go over a few examples here that you might find useful. -> Please take a look at either [the basic web tutorial](../Howto/Starting/Part5/Add-a-simple-new-web-page.md) or ->[the web character view tutorial](../Howto/Web-Character-View-Tutorial.md) +> Please take a look at either [the basic web tutorial](../Howtos/Beginner-Tutorial/Part5/Add-a-simple-new-web-page.md) or +>[the web character view tutorial](../Howtos/Web-Character-View-Tutorial.md) > to get a feel for how to add pages to Evennia's website to test these examples. ## General Styling @@ -77,4 +77,4 @@ width of the page - Evennia's base site uses the former. ### Forms [Forms](https://getbootstrap.com/docs/4.0/components/forms/) are highly customizable with Bootstrap. For a more in-depth look at how to use forms and their styles in your own Evennia site, please read -over [the web character gen tutorial.](../Howto/Web-Character-Generation.md) \ No newline at end of file +over [the web character gen tutorial.](../Howtos/Web-Character-Generation.md) \ No newline at end of file diff --git a/docs/source/Components/Command-Sets.md b/docs/source/Components/Command-Sets.md index eef9cf02fd..1f98839bb4 100644 --- a/docs/source/Components/Command-Sets.md +++ b/docs/source/Components/Command-Sets.md @@ -26,7 +26,7 @@ on. The tutorial world included with Evennia showcases a dark room that replaces commands with its own versions because the Character cannot see. If you want a quick start into defining your first commands and using them with command sets, you -can head over to the [Adding Command Tutorial](../Howto/Starting/Part1/Adding-Commands.md) which steps through things +can head over to the [Adding Command Tutorial](../Howtos/Beginner-Tutorial/Part1/Adding-Commands.md) which steps through things without the explanations. ## Defining Command Sets @@ -112,7 +112,7 @@ back even if all other cmdsets fail or are removed. It is always persistent and by `cmdset.delete()`. To remove a default cmdset you must explicitly call `cmdset.remove_default()`. Command sets are often added to an object in its `at_object_creation` method. For more examples of -adding commands, read the [Step by step tutorial](../Howto/Starting/Part1/Adding-Commands.md). Generally you can +adding commands, read the [Step by step tutorial](../Howtos/Beginner-Tutorial/Part1/Adding-Commands.md). Generally you can customize which command sets are added to your objects by using `self.cmdset.add()` or `self.cmdset.add_default()`. @@ -215,7 +215,7 @@ included if `no_objs` option is active in the merge stack. `no_objs` option is active in the merge stack. - The cmdsets of Exits in the location. Merge priority `+101`. Will not be included if `no_exits` *or* `no_objs` option is active in the merge stack. -- The [channel](./Communications.md) cmdset containing commands for posting to all channels the account +- The [channel](./Channels.md) cmdset containing commands for posting to all channels the account or character is currently connected to. Merge priority `+101`. Will not be included if `no_channels` option is active in the merge stack. diff --git a/docs/source/Components/Command-System.md b/docs/source/Components/Command-System.md index bb79f0a16e..db13dbd69b 100644 --- a/docs/source/Components/Command-System.md +++ b/docs/source/Components/Command-System.md @@ -6,4 +6,4 @@ See also: - [Default Commands](./Default-Commands.md) -- [Adding Command Tutorial](../Howto/Starting/Part1/Adding-Commands.md) +- [Adding Command Tutorial](../Howtos/Beginner-Tutorial/Part1/Adding-Commands.md) diff --git a/docs/source/Components/Commands.md b/docs/source/Components/Commands.md index 02c502d392..328144650d 100644 --- a/docs/source/Components/Commands.md +++ b/docs/source/Components/Commands.md @@ -29,7 +29,7 @@ object in various ways. Consider a "Tree" object with a cmdset defining the comm This page goes into full detail about how to use Commands. To fully use them you must also read the page detailing [Command Sets](./Command-Sets.md). There is also a step-by-step -[Adding Command Tutorial](../Howto/Starting/Part1/Adding-Commands.md) that will get you started quickly without the +[Adding Command Tutorial](../Howtos/Beginner-Tutorial/Part1/Adding-Commands.md) that will get you started quickly without the extra explanations. ## Defining Commands @@ -392,7 +392,7 @@ class CmdWait(Command): def func(self): """Command execution.""" - self.msg("Starting to wait ...") + self.msg("Beginner-Tutorial to wait ...") yield 5 self.msg("... This shows after 5 seconds. Waiting ...") yield 2 @@ -484,7 +484,7 @@ display the "Huh?" error message. matches. - User is not allowed to execute the command (`syscmdkeys.CMD_NOPERM`) - Default is to display the "Huh?" error message. -- Channel (`syscmdkeys.CMD_CHANNEL`) - This is a [Channel](./Communications.md) name of a channel you are +- Channel (`syscmdkeys.CMD_CHANNEL`) - This is a [Channel](./Channels.md) name of a channel you are subscribing to - Default is to relay the command's argument to that channel. Such commands are created by the Comm system on the fly depending on your subscriptions. - New session connection (`syscmdkeys.CMD_LOGINSTART`). This command name should be put in the diff --git a/docs/source/Components/Communications.md b/docs/source/Components/Communications.md deleted file mode 100644 index b707ca05ba..0000000000 --- a/docs/source/Components/Communications.md +++ /dev/null @@ -1,8 +0,0 @@ -# Communications - -TODO: Remove this page? - -- [Channels](./Channels.md) - are used for implementing in-game chat rooms. -- [Msg](./Msg.md)-objects are used for storing messages in the database (email-like) - and is a building block for implementing other game systems. It's used by the - `page` command by default. diff --git a/docs/source/Components/Components-Overview.md b/docs/source/Components/Components-Overview.md index 439eacf650..79be8908b3 100644 --- a/docs/source/Components/Components-Overview.md +++ b/docs/source/Components/Components-Overview.md @@ -5,50 +5,82 @@ than, the doc-strings of each component in the [API](../Evennia-API.md). ## Database entites -- [Typeclasses](./Typeclasses.md) - - [Sessions](./Sessions.md) - - [Acccounts](./Accounts.md) - - [Guests](../Concepts/Guest-Logins.md) - - [Objects](./Objects.md) - - [Scripts](./Scripts.md) - - [Channels and Messages](./Communications.md) -- [Attributes](./Attributes.md) -- [Nicks](./Nicks.md) -- [Tags](./Tags.md) -- [Spawner and prototypes](./Prototypes.md) -- [Help entries](./Help-System.md) +```{toctree} +:maxdepth: 2 + +Typeclasses.md +Sessions.md +Accounts.md +Objects.md +Scripts.md +Channels.md +Msg.md +Attributes.md +Nicks.md +Tags.md +Prototypes.md +Help-System.md +Permissions.md + +``` ## Commands -- [Available Default Commands](./Default-Commands.md) -- [Command system](./Command-System.md) - - [Commands](./Commands.md) - - [Command-Sets](./Command-Sets.md) - - [The Connection Screen](./Connection-Screen.md) -- [Batch-Processors](./Batch-Processors.md) - - [Batch-Code-Processor](./Batch-Code-Processor.md) - - [Batch-Command-Processor](./Batch-Command-Processor.md) +```{toctree} +:maxdepth: 2 + +Command-System.md +Commands.md +Command-Sets.md +Default-Commands.md +Connection-Screen.md +Batch-Processors.md +Batch-Code-Processor.md +Batch-Command-Processor.md +``` + ## Utils and tools -- [Misc Utils](./Coding-Utils.md) -- [EvEditor](./EvEditor.md) -- [EvMenu](./EvMenu.md) -- [EvMore](./EvMore.md) -- [MonitorHandler](./MonitorHandler.md) -- [TickerHandler](./TickerHandler.md) -- [Lock system](./Locks.md) -- [FuncParser](./FuncParser.md) +```{toctree} +:maxdepth: 2 + +Coding-Utils.md +EvEditor.md +EvMenu.md +EvMore.md +MonitorHandler.md +TickerHandler.md +Locks.md +FuncParser.md +``` + +## Web components + +```{toctree} +:maxdepth: 2 + +Website.md +Web-API.md +Web-Admin.md +``` ## Server and network -- [Portal](./Portal-And-Server.md) - - [Inputfuncs](./Inputfuncs.md) - - [Outputfuncs](./Outputfuncs.md) - - [Protocols](../Concepts/Custom-Protocols.md) -- [Server](./Server.md) - - [Server conf object](../Setup/Server-Conf.md) -- [Webserver](./Webserver.md) - - [Webclient](./Webclient.md) - - [Bootstrap](./Bootstrap-Components-and-Utilities.md) -- [Signals](./Signals.md) +```{toctree} +:maxdepth: 2 + +Portal-And-Server.md +Inputfuncs.md +Outputfuncs.md +Server.md +Setup/Server-Conf.md +Webserver.md +Webclient.md +Bootstrap-Components-and-Utilities.md +Signals.md +``` + + + + diff --git a/docs/source/Components/EvMenu.md b/docs/source/Components/EvMenu.md index 30433e56da..b283298783 100644 --- a/docs/source/Components/EvMenu.md +++ b/docs/source/Components/EvMenu.md @@ -1115,7 +1115,7 @@ function - for example you can't use other Python keywords like `if` inside the Unless you are dealing with a relatively simple dynamic menu, defining menus with lambda's is probably more work than it's worth: You can create dynamic menus by instead making each node -function more clever. See the [NPC shop tutorial](../Howto/NPC-shop-Tutorial.md) for an example of this. +function more clever. See the [NPC shop tutorial](../Howtos/NPC-shop-Tutorial.md) for an example of this. ## Ask for simple input diff --git a/docs/source/Components/Nicks.md b/docs/source/Components/Nicks.md index eb93bb599c..324583d3ed 100644 --- a/docs/source/Components/Nicks.md +++ b/docs/source/Components/Nicks.md @@ -101,7 +101,7 @@ offers effective error checking, searches and conversion. In a command definition you can reach the nick handler through `self.caller.nicks`. See the `nick` command in `evennia/commands/default/general.py` for more examples. -As a last note, The Evennia [channel](./Communications.md) alias systems are using nicks with the +As a last note, The Evennia [channel](./Channels.md) alias systems are using nicks with the `nick_type="channel"` in order to allow users to create their own custom aliases to channels. # Advanced note diff --git a/docs/source/Components/Tags.md b/docs/source/Components/Tags.md index af9e834898..2234c1c14b 100644 --- a/docs/source/Components/Tags.md +++ b/docs/source/Components/Tags.md @@ -53,7 +53,7 @@ free up the *category* property for any use you desire. ## Adding/Removing Tags You can tag any *typeclassed* object, namely [Objects](./Objects.md), [Accounts](./Accounts.md), -[Scripts](./Scripts.md) and [Channels](./Communications.md). General tags are added by the *Taghandler*. The +[Scripts](./Scripts.md) and [Channels](./Channels.md). General tags are added by the *Taghandler*. The tag handler is accessed as a property `tags` on the relevant entity: ```python diff --git a/docs/source/Components/TickerHandler.md b/docs/source/Components/TickerHandler.md index ad5e88e72c..a5f5ee2039 100644 --- a/docs/source/Components/TickerHandler.md +++ b/docs/source/Components/TickerHandler.md @@ -104,7 +104,7 @@ may store. When testing, you can stop all tickers in the entire game with `tickerhandler.clear()`. You can also view the currently subscribed objects with `tickerhandler.all()`. -See the [Weather Tutorial](../Howto/Weather-Tutorial.md) for an example of using the TickerHandler. +See the [Weather Tutorial](../Howtos/Weather-Tutorial.md) for an example of using the TickerHandler. ### When *not* to use TickerHandler diff --git a/docs/source/Components/Typeclasses.md b/docs/source/Components/Typeclasses.md index 4ef0cd8c6a..6c9c872986 100644 --- a/docs/source/Components/Typeclasses.md +++ b/docs/source/Components/Typeclasses.md @@ -1,7 +1,6 @@ # Typeclasses - -*Typeclasses* form the core of Evennia data storage. It allows Evennia to represent any number of +*Typeclasses* form the core of Evennia's data storage. It allows Evennia to represent any number of different game entities as Python classes, without having to modify the database schema for every new type. @@ -193,7 +192,7 @@ database. Each of the typeclassed entities then extend this list with their own properties. Go to the respective pages for [Objects](./Objects.md), [Scripts](./Scripts.md), [Accounts](./Accounts.md) and -[Channels](./Communications.md) for more info. It's also recommended that you explore the available +[Channels](./Channels.md) for more info. It's also recommended that you explore the available entities using [Evennia's flat API](../Evennia-API.md) to explore which properties and methods they have available. @@ -245,7 +244,7 @@ matches = ScriptDB.objects.filter(db_key__contains="Combat") When querying from the database model parent you don't need to use `filter_family` or `get_family` - you will always query all children on the database model. -# Updating existing typeclass instances +## Updating existing typeclass instances If you already have created instances of Typeclasses, you can modify the *Python code* at any time - due to how Python inheritance works your changes will automatically be applied to all children once @@ -317,7 +316,7 @@ The arguments to this method are described [in the API docs here](github:evennia.typeclasses.models#typedobjectswap_typeclass). -# How typeclasses actually work +## How typeclasses actually work *This is considered an advanced section.* diff --git a/docs/source/Concepts/Async-Process.md b/docs/source/Concepts/Async-Process.md index 6e4b24525a..ad85495d3f 100644 --- a/docs/source/Concepts/Async-Process.md +++ b/docs/source/Concepts/Async-Process.md @@ -139,7 +139,7 @@ sleep. ``` This will delay the execution of the callback for 10 seconds. This function is explored much more in -the [Command Duration Tutorial](../Howto/Command-Duration.md). +the [Command Duration Tutorial](../Howtos/Command-Duration.md). You can also try the following snippet just see how it works: diff --git a/docs/source/Concepts/Colors.md b/docs/source/Concepts/Colors.md index 32b3438c1d..87faffc3fe 100644 --- a/docs/source/Concepts/Colors.md +++ b/docs/source/Concepts/Colors.md @@ -14,7 +14,7 @@ equipment by people who are blind or have otherwise diminished eyesight. So a good rule of thumb is to use colour to enhance your game but don't *rely* on it to display critical information. If you are coding the game, you can add functionality to let users disable -colours as they please, as described [here](../Howto/Manually-Configuring-Color.md). +colours as they please, as described [here](../Howtos/Manually-Configuring-Color.md). To see which colours your client support, use the default `@color` command. This will list all available colours for ANSI and Xterm256 along with the codes you use for them. You can find a list @@ -178,6 +178,6 @@ to activate some features manually. ## More reading -There is an [Understanding Color Tags](../Howto/Understanding-Color-Tags.md) tutorial which expands on the +There is an [Understanding Color Tags](../Howtos/Understanding-Color-Tags.md) tutorial which expands on the use of ANSI color tags and the pitfalls of mixing ANSI and Xterms256 color tags in the same context. diff --git a/docs/source/Concepts/Concepts-Overview.md b/docs/source/Concepts/Concepts-Overview.md index 11da8aed43..a65e995180 100644 --- a/docs/source/Concepts/Concepts-Overview.md +++ b/docs/source/Concepts/Concepts-Overview.md @@ -4,28 +4,59 @@ This documentation cover more over-arching concepts of Evennia, often involving ## General concepts -- [Asynchronous processing](./Async-Process.md) -- [On Soft-Code](./Soft-Code.md) -- [Using MUX as standard for default commands](./Using-MUX-as-a-Standard.md) +```{toctree} +:maxdepth: 2 + +Async-Process.md +Soft-Code.md +Using-MUX-as-a-Standard.md +Messagepath.md +OOB.md + +``` ## Access -- [Multisession modes](./Multisession-modes.md) -- [Permissions](./Building-Permissions.md) -- [Banning](./Banning.md) +```{toctree} +:maxdepth: 2 + +Multisession-modes.md +Building-Permissions.md +Guest-Logins.md +Banning.md + +``` ## Extending the Server -- [Custom Protocols](./Custom-Protocols.md) -- [Bootstrap](./Bootstrap-&-Evennia.md) -- [Creating new models](./New-Models.md) + +```{toctree} +:maxdepth: 2 + +Custom-Protocols.md +Bootstrap-&-Evennia.md +New-Models.md +Zones.md + +``` ## Text processing +```{toctree} +:maxdepth: 2 + +Internationalization.md +Text-Encodings.md +TextTags.md +Change-Messages-Per-Receiver.md +Clickable-Links.md +Colors.md + +``` -- [Change the language of the server](./Internationalization.md) -- [Server text-encoding](./Text-Encodings.md) -- [Text tags](./TextTags.md) -- [Change Messages Per receiver](./Change-Messages-Per-Receiver.md) ## Web features +```{toctree} +:maxdepth: 2 + +Web-Features.md +``` -- [Web features](./Web-Features.md) diff --git a/docs/source/Concepts/Web-Features.md b/docs/source/Concepts/Web-Features.md index b6841e82d3..afbea527c3 100644 --- a/docs/source/Concepts/Web-Features.md +++ b/docs/source/Concepts/Web-Features.md @@ -42,7 +42,7 @@ Example: To override or modify `evennia/web/website/template/website/index.html` add/modify `mygame/web/template_overrides/website/index.html`. The detailed description on how to customize the website is best described in tutorial form. See the -[Web Tutorial](../Howto/Starting/Part5/Web-Tutorial.md) for more information. +[Web Tutorial](../Howtos/Beginner-Tutorial/Part5/Web-Tutorial.md) for more information. ### Overloading Django views diff --git a/docs/source/Contribs/Building-menus.md b/docs/source/Contribs/Building-menus.md deleted file mode 100644 index b98f9241a4..0000000000 --- a/docs/source/Contribs/Building-menus.md +++ /dev/null @@ -1,1233 +0,0 @@ -# Building menus - - -# The building_menu contrib - -This contrib allows you to write custom and easy to use building menus. As the name implies, these -menus are most useful for building things, that is, your builders might appreciate them, although -you can use them for your players as well. - -Building menus are somewhat similar to `EvMenu` although they don't use the same system at all and -are intended to make building easier. They replicate what other engines refer to as "building -editors", which allow to you to build in a menu instead of having to enter a lot of complex -commands. Builders might appreciate this simplicity, and if the code that was used to create them -is simple as well, coders could find this contrib useful. - -## A simple menu - -Before diving in, there are some things to point out: - -- Building menus work on an object. This object will be edited by manipulations in the menu. So -you can create a menu to add/edit a room, an exit, a character and so on. -- Building menus are arranged in layers of choices. A choice gives access to an option or to a sub- -menu. Choices are linked to commands (usually very short). For instance, in the example shown -below, to edit the room key, after opening the building menu, you can type `k`. That will lead you -to the key choice where you can enter a new key for the room. Then you can enter `@` to leave this -choice and go back to the entire menu. (All of this can be changed). -- To open the menu, you will need something like a command. This contrib offers a basic command for -demonstration, but we will override it in this example, using the same code with more flexibility. - -So let's add a very basic example to begin with. - -### A generic editing command - -Let's begin by adding a new command. You could add or edit the following file (there's no trick -here, feel free to organize the code differently): - -```python -# file: commands/building.py -from evennia.contrib.building_menu import BuildingMenu -from commands.command import Command - -class EditCmd(Command): - - """ - Editing command. - - Usage: - @edit [object] - - Open a building menu to edit the specified object. This menu allows to - specific information about this object. - - Examples: - @edit here - @edit self - @edit #142 - - """ - - key = "@edit" - locks = "cmd:id(1) or perm(Builders)" - help_category = "Building" - - def func(self): - if not self.args.strip(): - self.msg("|rYou should provide an argument to this function: the object to edit.|n") - return - - obj = self.caller.search(self.args.strip(), global_search=True) - if not obj: - return - - if obj.typename == "Room": - Menu = RoomBuildingMenu - else: - obj_name = obj.get_display_name(self.caller) - self.msg(f"|rThe object {obj_name} cannot be edited.|n") - return - - menu = Menu(self.caller, obj) - menu.open() -``` - -This command is rather simple in itself: - -1. It has a key `@edit` and a lock to only allow builders to use it. -2. In its `func` method, it begins by checking the arguments, returning an error if no argument is -specified. -3. It then searches for the given argument. We search globally. The `search` method used in this -way will return the found object or `None`. It will also send the error message to the caller if -necessary. -4. Assuming we have found an object, we check the object `typename`. This will be used later when -we want to display several building menus. For the time being, we only handle `Room`. If the -caller specified something else, we'll display an error. -5. Assuming this object is a `Room`, we have defined a `Menu` object containing the class of our -building menu. We build this class (creating an instance), giving it the caller and the object to -edit. -6. We then open the building menu, using the `open` method. - -The end might sound a bit surprising at first glance. But the process is still very simple: we -create an instance of our building menu and call its `open` method. Nothing more. - -> Where is our building menu? - -If you go ahead and add this command and test it, you'll get an error. We haven't defined -`RoomBuildingMenu` yet. - -To add this command, edit `commands/default_cmdsets.py`. Import our command, adding an import line -at the top of the file: - -```python -""" -... -""" - -from evennia import default_cmds - -# The following line is to be added -from commands.building import EditCmd -``` - -And in the class below (`CharacterCmdSet`), add the last line of this code: - -```python -class CharacterCmdSet(default_cmds.CharacterCmdSet): - """ - The `CharacterCmdSet` contains general in-game commands like `look`, - `get`, etc available on in-game Character objects. It is merged with - the `AccountCmdSet` when an Account puppets a Character. - """ - key = "DefaultCharacter" - - def at_cmdset_creation(self): - """ - Populates the cmdset - """ - super().at_cmdset_creation() - # - # any commands you add below will overload the default ones. - # - self.add(EditCmd()) -``` - -### Our first menu - -So far, we can't use our building menu. Our `@edit` command will throw an error. We have to define -the `RoomBuildingMenu` class. Open the `commands/building.py` file and add to the end of the file: - -```python -# ... at the end of commands/building.py -# Our building menu - -class RoomBuildingMenu(BuildingMenu): - - """ - Building menu to edit a room. - - For the time being, we have only one choice: key, to edit the room key. - - """ - - def init(self, room): - self.add_choice("key", "k", attr="key") -``` - -Save these changes, reload your game. You can now use the `@edit` command. Here's what we get -(notice that the commands we enter into the game are prefixed with `> `, though this prefix will -probably not appear in your MUD client): - -``` -> look -Limbo(#2) -Welcome to your new Evennia-based game! Visit https://www.evennia.com if you need -help, want to contribute, report issues or just join the community. -As Account #1 you can create a demo/tutorial area with @batchcommand tutorial_world.build. - -> @edit here -Building menu: Limbo - - [K]ey: Limbo - [Q]uit the menu - -> q -Closing the building menu. - -> @edit here -Building menu: Limbo - - [K]ey: Limbo - [Q]uit the menu - -> k -------------------------------------------------------------------------------- -key for Limbo(#2) - -You can change this value simply by entering it. - -Use @ to go back to the main menu. - -Current value: Limbo - -> A beautiful meadow -------------------------------------------------------------------------------- - -key for A beautiful meadow(#2) - -You can change this value simply by entering it. - -Use @ to go back to the main menu. - -Current value: A beautiful meadow - -> @ -Building menu: A beautiful meadow - - [K]ey: A beautiful meadow - [Q]uit the menu - -> q - -Closing the building menu. - -> look -A beautiful meadow(#2) -Welcome to your new Evennia-based game! Visit https://www.evennia.com if you need -help, want to contribute, report issues or just join the community. -As Account #1 you can create a demo/tutorial area with @batchcommand tutorial_world.build. -``` - -Before diving into the code, let's examine what we have: - -- When we use the `@edit here` command, a building menu for this room appears. -- This menu has two choices: - - Enter `k` to edit the room key. You will go into a choice where you can simply type the key -room key (the way we have done here). You can use `@` to go back to the menu. - - You can use `q` to quit the menu. - -We then check, with the `look` command, that the menu has modified this room key. So by adding a -class, with a method and a single line of code within, we've added a menu with two choices. - -### Code explanation - -Let's examine our code again: - -```python -class RoomBuildingMenu(BuildingMenu): - - """ - Building menu to edit a room. - - For the time being, we have only one choice: key, to edit the room key. - - """ - - def init(self, room): - self.add_choice("key", "k", attr="key") -``` - -- We first create a class inheriting from `BuildingMenu`. This is usually the case when we want to -create a building menu with this contrib. -- In this class, we override the `init` method, which is called when the menu opens. -- In this `init` method, we call `add_choice`. This takes several arguments, but we've defined only -three here: - - The choice name. This is mandatory and will be used by the building menu to know how to -display this choice. - - The command key to access this choice. We've given a simple `"k"`. Menu commands usually are -pretty short (that's part of the reason building menus are appreciated by builders). You can also -specify additional aliases, but we'll see that later. - - We've added a keyword argument, `attr`. This tells the building menu that when we are in this -choice, the text we enter goes into this attribute name. It's called `attr`, but it could be a room -attribute or a typeclass persistent or non-persistent attribute (we'll see other examples as well). - -> We've added the menu choice for `key` here, why is another menu choice defined for `quit`? - -Our building menu creates a choice at the end of our choice list if it's a top-level menu (sub-menus -don't have this feature). You can, however, override it to provide a different "quit" message or to -perform some actions. - -I encourage you to play with this code. As simple as it is, it offers some functionalities already. - -## Customizing building menus - -This somewhat long section explains how to customize building menus. There are different ways -depending on what you would like to achieve. We'll go from specific to more advanced here. - -### Generic choices - -In the previous example, we've used `add_choice`. This is one of three methods you can use to add -choices. The other two are to handle more generic actions: - -- `add_choice_edit`: this is called to add a choice which points to the `EvEditor`. It is used to -edit a description in most cases, although you could edit other things. We'll see an example -shortly. `add_choice_edit` uses most of the `add_choice` keyword arguments we'll see, but usually -we specify only two (sometimes three): - - The choice title as usual. - - The choice key (command key) as usual. - - Optionally, the attribute of the object to edit, with the `attr` keyword argument. By -default, `attr` contains `db.desc`. It means that this persistent data attribute will be edited by -the `EvEditor`. You can change that to whatever you want though. -- `add_choice_quit`: this allows to add a choice to quit the editor. Most advisable! If you don't -do it, the building menu will do it automatically, except if you really tell it not to. Again, you -can specify the title and key of this menu. You can also call a function when this menu closes. - -So here's a more complete example (you can replace your `RoomBuildingMenu` class in -`commands/building.py` to see it): - -```python -class RoomBuildingMenu(BuildingMenu): - - """ - Building menu to edit a room. - """ - - def init(self, room): - self.add_choice("key", "k", attr="key") - self.add_choice_edit("description", "d") - self.add_choice_quit("quit this editor", "q") -``` - -So far, our building menu class is still thin... and yet we already have some interesting feature. -See for yourself the following MUD client output (again, the commands are prefixed with `> ` to -distinguish them): - -``` -> @reload - -> @edit here -Building menu: A beautiful meadow - - [K]ey: A beautiful meadow - [D]escription: - Welcome to your new Evennia-based game! Visit https://www.evennia.com if you need -help, want to contribute, report issues or just join the community. -As Account #1 you can create a demo/tutorial area with @batchcommand tutorial_world.build. - [Q]uit this editor - -> d - -----------Line Editor [editor]---------------------------------------------------- -01| Welcome to your new |wEvennia|n-based game! Visit https://www.evennia.com if you need -02| help, want to contribute, report issues or just join the community. -03| As Account #1 you can create a demo/tutorial area with |w@batchcommand tutorial_world.build|n. - -> :DD - -----------[l:03 w:034 c:0247]------------(:h for help)---------------------------- -Cleared 3 lines from buffer. - -> This is a beautiful meadow. But so beautiful I can't describe it. - -01| This is a beautiful meadow. But so beautiful I can't describe it. - -> :wq -Building menu: A beautiful meadow - - [K]ey: A beautiful meadow - [D]escription: - This is a beautiful meadow. But so beautiful I can't describe it. - [Q]uit this editor - -> q -Closing the building menu. - -> look -A beautiful meadow(#2) -This is a beautiful meadow. But so beautiful I can't describe it. -``` - -So by using the `d` shortcut in our building menu, an `EvEditor` opens. You can use the `EvEditor` -commands (like we did here, `:DD` to remove all, `:wq` to save and quit). When you quit the editor, -the description is saved (here, in `room.db.desc`) and you go back to the building menu. - -Notice that the choice to quit has changed too, which is due to our adding `add_choice_quit`. In -most cases, you will probably not use this method, since the quit menu is added automatically. - -### `add_choice` options - -`add_choice` and the two methods `add_choice_edit` and `add_choice_quit` take a lot of optional -arguments to make customization easier. Some of these options might not apply to `add_choice_edit` -or `add_choice_quit` however. - -Below are the options of `add_choice`, specify them as arguments: - -- The first positional, mandatory argument is the choice title, as we have seen. This will -influence how the choice appears in the menu. -- The second positional, mandatory argument is the command key to access to this menu. It is best -to use keyword arguments for the other arguments. -- The `aliases` keyword argument can contain a list of aliases that can be used to access to this -menu. For instance: `add_choice(..., aliases=['t'])` -- The `attr` keyword argument contains the attribute to edit when this choice is selected. It's a -string, it has to be the name, from the object (specified in the menu constructor) to reach this -attribute. For instance, a `attr` of `"key"` will try to find `obj.key` to read and write the -attribute. You can specify more complex attribute names, for instance, `attr="db.desc"` to set the -`desc` persistent attribute, or `attr="ndb.something"` so use a non-persistent data attribute on the -object. -- The `text` keyword argument is used to change the text that will be displayed when the menu choice -is selected. Menu choices provide a default text that you can change. Since this is a long text, -it's useful to use multi-line strings (see an example below). -- The `glance` keyword argument is used to specify how to display the current information while in -the menu, when the choice hasn't been opened. If you examine the previous examples, you will see -that the current (`key` or `db.desc`) was shown in the menu, next to the command key. This is -useful for seeing at a glance the current value (hence the name). Again, menu choices will provide -a default glance if you don't specify one. -- The `on_enter` keyword argument allows to add a callback to use when the menu choice is opened. -This is more advanced, but sometimes useful. -- The `on_nomatch` keyword argument is called when, once in the menu, the caller enters some text -that doesn't match any command (including the `@` command). By default, this will edit the -specified `attr`. -- The `on_leave` keyword argument allows to specify a callback used when the caller leaves the menu -choice. This can be useful for cleanup as well. - -These are a lot of possibilities, and most of the time you won't need them all. Here is a short -example using some of these arguments (again, replace the `RoomBuildingMenu` class in -`commands/building.py` with the following code to see it working): - -```python -class RoomBuildingMenu(BuildingMenu): - - """ - Building menu to edit a room. - - For the time being, we have only one choice: key, to edit the room key. - - """ - - def init(self, room): - self.add_choice("title", key="t", attr="key", glance="{obj.key}", text=""" - ------------------------------------------------------------------------------- - Editing the title of {{obj.key}}(#{{obj.id}}) - - You can change the title simply by entering it. - Use |y{back}|n to go back to the main menu. - - Current title: |c{{obj.key}}|n - """.format(back="|n or |y".join(self.keys_go_back))) - self.add_choice_edit("description", "d") -``` - -Reload your game and see it in action: - -``` -> @edit here -Building menu: A beautiful meadow - - [T]itle: A beautiful meadow - [D]escription: - This is a beautiful meadow. But so beautiful I can't describe it. - [Q]uit the menu - -> t -------------------------------------------------------------------------------- - -Editing the title of A beautiful meadow(#2) - -You can change the title simply by entering it. -Use @ to go back to the main menu. - -Current title: A beautiful meadow - -> @ - -Building menu: A beautiful meadow - - [T]itle: A beautiful meadow - [D]escription: - This is a beautiful meadow. But so beautiful I can't describe it. - [Q]uit the menu - -> q -Closing the building menu. -``` - -The most surprising part is no doubt the text. We use the multi-line syntax (with `"""`). -Excessive spaces will be removed from the left for each line automatically. We specify some -information between braces... sometimes using double braces. What might be a bit odd: - -- `{back}` is a direct format argument we'll use (see the `.format` specifiers). -- `{{obj...}}` refers to the object being edited. We use two braces, because `.format` will remove them. - -In `glance`, we also use `{obj.key}` to indicate we want to show the room's key. - -### Everything can be a function - -The keyword arguments of `add_choice` are often strings (type `str`). But each of these arguments -can also be a function. This allows for a lot of customization, since we define the callbacks that -will be executed to achieve such and such an operation. - -To demonstrate, we will try to add a new feature. Our building menu for rooms isn't that bad, but -it would be great to be able to edit exits too. So we can add a new menu choice below -description... but how to actually edit exits? Exits are not just an attribute to set: exits are -objects (of type `Exit` by default) which stands between two rooms (object of type `Room`). So how -can we show that? - -First let's add a couple of exits in limbo, so we have something to work with: - -``` -@tunnel n -@tunnel s -``` - -This should create two new rooms, exits leading to them from limbo and back to limbo. - -``` -> look -A beautiful meadow(#2) -This is a beautiful meadow. But so beautiful I can't describe it. -Exits: north(#4) and south(#7) -``` - -We can access room exits with the `exits` property: - -``` -> @py here.exits -[, ] -``` - -So what we need is to display this list in our building menu... and to allow to edit it would be -great. Perhaps even add new exits? - -First of all, let's write a function to display the `glance` on existing exits. Here's the code, -it's explained below: - -```python -class RoomBuildingMenu(BuildingMenu): - - """ - Building menu to edit a room. - - """ - - def init(self, room): - self.add_choice("title", key="t", attr="key", glance="{obj.key}", text=""" - ------------------------------------------------------------------------------- - Editing the title of {{obj.key}}(#{{obj.id}}) - - You can change the title simply by entering it. - Use |y{back}|n to go back to the main menu. - - Current title: |c{{obj.key}}|n - """.format(back="|n or |y".join(self.keys_go_back))) - self.add_choice_edit("description", "d") - self.add_choice("exits", "e", glance=glance_exits, attr="exits") - - -# Menu functions -def glance_exits(room): - """Show the room exits.""" - if room.exits: - glance = "" - for exit in room.exits: - glance += f"\n |y{exit.key}|n" - - return glance - - return "\n |gNo exit yet|n" -``` - -When the building menu opens, it displays each choice to the caller. A choice is displayed with its -title (rendered a bit nicely to show the key as well) and the glance. In the case of the `exits` -choice, the glance is a function, so the building menu calls this function giving it the object -being edited (the room here). The function should return the text to see. - -``` -> @edit here -Building menu: A beautiful meadow - - [T]itle: A beautiful meadow - [D]escription: - This is a beautiful meadow. But so beautiful I can't describe it. - [E]xits: - north - south - [Q]uit the menu - -> q -Closing the editor. -``` - -> How do I know the parameters of the function to give? - -The function you give can accept a lot of different parameters. This allows for a flexible approach -but might seem complicated at first. Basically, your function can accept any parameter, and the -building menu will send only the parameter based on their names. If your function defines an -argument named `caller` for instance (like `def func(caller):` ), then the building menu knows that -the first argument should contain the caller of the building menu. Here are the arguments, you -don't have to specify them (if you do, they need to have the same name): - -- `menu`: if your function defines an argument named `menu`, it will contain the building menu -itself. -- `choice`: if your function defines an argument named `choice`, it will contain the `Choice` object -representing this menu choice. -- `string`: if your function defines an argument named `string`, it will contain the user input to -reach this menu choice. This is not very useful, except on `nomatch` callbacks which we'll see -later. -- `obj`: if your function defines an argument named `obj`, it will contain the building menu edited -object. -- `caller`: if your function defines an argument named `caller`, it will contain the caller of the -building menu. -- Anything else: any other argument will contain the object being edited by the building menu. - -So in our case: - -```python -def glance_exits(room): -``` - -The only argument we need is `room`. It's not present in the list of possible arguments, so the -editing object of the building menu (the room, here) is given. - -> Why is it useful to get the menu or choice object? - -Most of the time, you will not need these arguments. In very rare cases, you will use them to get -specific data (like the default attribute that was set). This tutorial will not elaborate on these -possibilities. Just know that they exist. - -We should also define a text callback, so that we can enter our menu to see the room exits. We'll -see how to edit them in the next section but this is a good opportunity to show a more complete -callback. To see it in action, as usual, replace the class and functions in `commands/building.py`: - -```python -# Our building menu - -class RoomBuildingMenu(BuildingMenu): - - """ - Building menu to edit a room. - - """ - - def init(self, room): - self.add_choice("title", key="t", attr="key", glance="{obj.key}", text=""" - ------------------------------------------------------------------------------- - Editing the title of {{obj.key}}(#{{obj.id}}) - - You can change the title simply by entering it. - Use |y{back}|n to go back to the main menu. - - Current title: |c{{obj.key}}|n - """.format(back="|n or |y".join(self.keys_go_back))) - self.add_choice_edit("description", "d") - self.add_choice("exits", "e", glance=glance_exits, attr="exits", text=text_exits) - - -# Menu functions -def glance_exits(room): - """Show the room exits.""" - if room.exits: - glance = "" - for exit in room.exits: - glance += f"\n |y{exit.key}|n" - - return glance - - return "\n |gNo exit yet|n" - -def text_exits(caller, room): - """Show the room exits in the choice itself.""" - text = "-" * 79 - text += "\n\nRoom exits:" - text += "\n Use |y@c|n to create a new exit." - text += "\n\nExisting exits:" - if room.exits: - for exit in room.exits: - text += f"\n |y@e {exit.key}|n" - if exit.aliases.all(): - text += " (|y{aliases}|n)".format(aliases="|n, |y".join( - alias for alias in exit.aliases.all() - )) - if exit.destination: - text += f" toward {exit.get_display_name(caller)}" - else: - text += "\n\n |gNo exit has yet been defined.|n" - - return text -``` - -Look at the second callback in particular. It takes an additional argument, the caller (remember, -the argument names are important, their order is not relevant). This is useful for displaying -destination of exits accurately. Here is a demonstration of this menu: - -``` -> @edit here -Building menu: A beautiful meadow - - [T]itle: A beautiful meadow - [D]escription: - This is a beautiful meadow. But so beautiful I can't describe it. - [E]xits: - north - south - [Q]uit the menu - -> e -------------------------------------------------------------------------------- - -Room exits: - Use @c to create a new exit. - -Existing exits: - @e north (n) toward north(#4) - @e south (s) toward south(#7) - -> @ -Building menu: A beautiful meadow - - [T]itle: A beautiful meadow - [D]escription: - This is a beautiful meadow. But so beautiful I can't describe it. - [E]xits: - north - south - [Q]uit the menu - -> q -Closing the building menu. -``` - -Using callbacks allows a great flexibility. We'll now see how to handle sub-menus. - -### Sub-menus for complex menus - -A menu is relatively flat: it has a root (where you see all the menu choices) and individual choices -you can go to using the menu choice keys. Once in a choice you can type some input or go back to -the root menu by entering the return command (usually `@`). - -Why shouldn't individual exits have their own menu though? Say, you edit an exit and can change its -key, description or aliases... perhaps even destination? Why ever not? It would make building much -easier! - -The building menu system offers two ways to do that. The first is nested keys: nested keys allow to -go beyond just one menu/choice, to have menus with more layers. Using them is quick but might feel -a bit counter-intuitive at first. Another option is to create a different menu class and redirect -from the first to the second. This option might require more lines but is more explicit and can be -re-used for multiple menus. Adopt one of them depending of your taste. - -#### Nested menu keys - -So far, we've only used menu keys with one letter. We can add more, of course, but menu keys in -their simple shape are just command keys. Press "e" to go to the "exits" choice. - -But menu keys can be nested. Nested keys allow to add choices with sub-menus. For instance, type -"e" to go to the "exits" choice, and then you can type "c" to open a menu to create a new exit, or -"d" to open a menu to delete an exit. The first menu would have the "e.c" key (first e, then c), -the second menu would have key as "e.d". - -That's more advanced and, if the following code doesn't sound very friendly to you, try the next -section which provides a different approach of the same problem. - -So we would like to edit exits. That is, you can type "e" to go into the choice of exits, then -enter `@e` followed by the exit name to edit it... which will open another menu. In this sub-menu -you could change the exit key or description. - -So we have a menu hierarchy similar to that: - -``` -t Change the room title -d Change the room description -e Access the room exits - [exit name] Access the exit name sub-menu - [text] Change the exit key -``` - -Or, if you prefer an example output: - -``` -> look -A beautiful meadow(#2) -This is a beautiful meadow. But so beautiful I can't describe it. -Exits: north(#4) and south(#7) - -> @edit here -Building menu: A beautiful meadow - - [T]itle: A beautiful meadow - [D]escription: - This is a beautiful meadow. But so beautiful I can't describe it. - [E]xits: - north - south - [Q]uit the menu - -> e -------------------------------------------------------------------------------- - -Room exits : - Use @c to create a new exit. - -Existing exits: - @e north (n) toward north(#4) - @e south (s) toward south(#7) - -> @e north -Editing: north -Exit north: -Enter the exit key to change it, or @ to go back. - -New exit key: - -> door - -Exit door: -Enter the exit key to change it, or @ to go back. - -New exit key: - -> @ - -------------------------------------------------------------------------------- - -Room exits : - Use @c to create a new exit. - -Existing exits: - @e door (n) toward door(#4) - @e south (s) toward south(#7) - -> @ -Building menu: A beautiful meadow - - [T]itle: A beautiful meadow - [D]escription: - This is a beautiful meadow. But so beautiful I can't describe it. - [E]xits: - door - south - [Q]uit the menu - -> q -Closing the building menu. -``` - -This needs a bit of code and a bit of explanation. So here we go... the code first, the -explanations next! - -```python -# ... from commands/building.py -# Our building menu - -class RoomBuildingMenu(BuildingMenu): - - """ - Building menu to edit a room. - - For the time being, we have only one choice: key, to edit the room key. - - """ - - def init(self, room): - self.add_choice("title", key="t", attr="key", glance="{obj.key}", text=""" - ------------------------------------------------------------------------------- - Editing the title of {{obj.key}}(#{{obj.id}}) - - You can change the title simply by entering it. - Use |y{back}|n to go back to the main menu. - - Current title: |c{{obj.key}}|n - """.format(back="|n or |y".join(self.keys_go_back))) - self.add_choice_edit("description", "d") - self.add_choice("exits", "e", glance=glance_exits, text=text_exits, on_nomatch=nomatch_exits) - - # Exit sub-menu - self.add_choice("exit", "e.*", text=text_single_exit, on_nomatch=nomatch_single_exit) - - -# Menu functions -def glance_exits(room): - """Show the room exits.""" - if room.exits: - glance = "" - for exit in room.exits: - glance += f"\n |y{exit.key}|n" - - return glance - - return "\n |gNo exit yet|n" - -def text_exits(caller, room): - """Show the room exits in the choice itself.""" - text = "-" * 79 - text += "\n\nRoom exits:" - text += "\n Use |y@c|n to create a new exit." - text += "\n\nExisting exits:" - if room.exits: - for exit in room.exits: - text += f"\n |y@e {exit.key}|n" - if exit.aliases.all(): - text += " (|y{aliases}|n)".format(aliases="|n, |y".join( - alias for alias in exit.aliases.all() - )) - if exit.destination: - text += f" toward {exit.get_display_name(caller)}" - else: - text += "\n\n |gNo exit has yet been defined.|n" - - return text - -def nomatch_exits(menu, caller, room, string): - """ - The user typed something in the list of exits. Maybe an exit name? - """ - string = string[3:] - exit = caller.search(string, candidates=room.exits) - if exit is None: - return - - # Open a sub-menu, using nested keys - caller.msg(f"Editing: {exit.key}") - menu.move(exit) - return False - -# Exit sub-menu -def text_single_exit(menu, caller): - """Show the text to edit single exits.""" - exit = menu.keys[1] - if exit is None: - return "" - - return f""" - Exit {exit.key}: - - Enter the exit key to change it, or |y@|n to go back. - - New exit key: - """ - -def nomatch_single_exit(menu, caller, room, string): - """The user entered something in the exit sub-menu. Replace the exit key.""" - # exit is the second key element: keys should contain ['e', ] - exit = menu.keys[1] - if exit is None: - caller.msg("|rCannot find the exit.|n") - menu.move(back=True) - return False - - exit.key = string - return True -``` - -> That's a lot of code! And we only handle editing the exit key! - -That's why at some point you might want to write a real sub-menu, instead of using simple nested -keys. But you might need both to build pretty menus too! - -1. The first thing new is in our menu class. After creating a `on_nomatch` callback for the exits -menu (that shouldn't be a surprised), we need to add a nested key. We give this menu a key of -`"e.*"`. That's a bit odd! "e" is our key to the exits menu, . is the separator to indicate a -nested menu, and * means anything. So basically, we create a nested menu that is contains within -the exits menu and anything. We'll see what this "anything" is in practice. -2. The `glance_exits` and `text_exits` are basically the same. -3. The `nomatch_exits` is short but interesting. It's called when we enter some text in the "exits" -menu (that is, in the list of exits). We have said that the user should enter `@e` followed by the -exit name to edit it. So in the `nomatch_exits` callbac, we check for that input. If the entered -text begins by `@e`, we try to find the exit in the room. If we do... -4. We call the `menu.move` method. That's where things get a bit complicated with nested menus: we -need to use `menu.move` to change from layer to layer. Here, we are in the choice of exits (the -exits menu, of key "e"). We need to go down one layer to edit an exit. So we call `menu.move` and -give it an exit object. The menu system remembers what position the user is based on the keys she -has entered: when the user opens the menu, there is no key. If she selects the exits choice, the -menu key being "e", the position of the user is `["e"]` (a list with the menu keys). If we call -`menu.move`, whatever we give to this method will be appended to the list of keys, so that the user -position becomes `["e", ]`. -5. In the menu class, we have defined the menu "e.*", meaning "the menu contained in the exits -choice plus anything". The "anything" here is an exit: we have called `menu.move(exit)`, so the -`"e.*"` menu choice is chosen. -6. In this menu, the text is set to a callback. There is also a `on_nomatch` callback that is -called whenever the user enters some text. If so, we change the exit name. - -Using `menu.move` like this is a bit confusing at first. Sometimes it's useful. In this case, if -we want a more complex menu for exits, it makes sense to use a real sub-menu, not nested keys like -this. But sometimes, you will find yourself in a situation where you don't need a full menu to -handle a choice. - -#### Full sub-menu as separate classes - -The best way to handle individual exits is to create two separate classes: - -- One for the room menu. -- One for the individual exit menu. - -The first one will have to redirect on the second. This might be more intuitive and flexible, -depending on what you want to achieve. So let's build two menus: - -```python -# Still in commands/building.py, replace the menu class and functions by... -# Our building menus - -class RoomBuildingMenu(BuildingMenu): - - """ - Building menu to edit a room. - """ - - def init(self, room): - self.add_choice("title", key="t", attr="key", glance="{obj.key}", text=""" - ------------------------------------------------------------------------------- - Editing the title of {{obj.key}}(#{{obj.id}}) - - You can change the title simply by entering it. - Use |y{back}|n to go back to the main menu. - - Current title: |c{{obj.key}}|n - """.format(back="|n or |y".join(self.keys_go_back))) - self.add_choice_edit("description", "d") - self.add_choice("exits", "e", glance=glance_exits, text=text_exits, -on_nomatch=nomatch_exits) - - -# Menu functions -def glance_exits(room): - """Show the room exits.""" - if room.exits: - glance = "" - for exit in room.exits: - glance += f"\n |y{exit.key}|n" - - return glance - - return "\n |gNo exit yet|n" - -def text_exits(caller, room): - """Show the room exits in the choice itself.""" - text = "-" * 79 - text += "\n\nRoom exits:" - text += "\n Use |y@c|n to create a new exit." - text += "\n\nExisting exits:" - if room.exits: - for exit in room.exits: - text += f"\n |y@e {exit.key}|n" - if exit.aliases.all(): - text += " (|y{aliases}|n)".format(aliases="|n, |y".join( - alias for alias in exit.aliases.all() - )) - if exit.destination: - text += f" toward {exit.get_display_name(caller)}" - else: - text += "\n\n |gNo exit has yet been defined.|n" - - return text - -def nomatch_exits(menu, caller, room, string): - """ - The user typed something in the list of exits. Maybe an exit name? - """ - string = string[3:] - exit = caller.search(string, candidates=room.exits) - if exit is None: - return - - # Open a sub-menu, using nested keys - caller.msg(f"Editing: {exit.key}") - menu.open_submenu("commands.building.ExitBuildingMenu", exit, parent_keys=["e"]) - return False - -class ExitBuildingMenu(BuildingMenu): - - """ - Building menu to edit an exit. - - """ - - def init(self, exit): - self.add_choice("key", key="k", attr="key", glance="{obj.key}") - self.add_choice_edit("description", "d") -``` - -The code might be much easier to read. But before detailing it, let's see how it behaves in the -game: - -``` -> @edit here -Building menu: A beautiful meadow - - [T]itle: A beautiful meadow - [D]escription: - This is a beautiful meadow. But so beautiful I can't describe it. - [E]xits: - door - south - [Q]uit the menu - -> e -------------------------------------------------------------------------------- - -Room exits: - Use @c to create a new exit. - -Existing exits: - @e door (n) toward door(#4) - @e south (s) toward south(#7) - -Editing: door - -> @e door -Building menu: door - - [K]ey: door - [D]escription: - None - -> k -------------------------------------------------------------------------------- -key for door(#4) - -You can change this value simply by entering it. - -Use @ to go back to the main menu. - -Current value: door - -> north - -------------------------------------------------------------------------------- -key for north(#4) - -You can change this value simply by entering it. - -Use @ to go back to the main menu. - -Current value: north - -> @ -Building menu: north - - [K]ey: north - [D]escription: - None - -> d -----------Line Editor [editor]---------------------------------------------------- -01| None -----------[l:01 w:001 c:0004]------------(:h for help)---------------------------- - -> :DD -Cleared 1 lines from buffer. - -> This is the northern exit. Cool huh? -01| This is the northern exit. Cool huh? - -> :wq -Building menu: north - [K]ey: north - [D]escription: - This is the northern exit. Cool huh? - -> @ -------------------------------------------------------------------------------- -Room exits: - Use @c to create a new exit. - -Existing exits: - @e north (n) toward north(#4) - @e south (s) toward south(#7) - -> @ -Building menu: A beautiful meadow - - [T]itle: A beautiful meadow - [D]escription: - This is a beautiful meadow. But so beautiful I can't describe it. - [E]xits: - north - south - [Q]uit the menu - -> q -Closing the building menu. - -> look -A beautiful meadow(#2) -This is a beautiful meadow. But so beautiful I can't describe it. -Exits: north(#4) and south(#7) -> @py here.exits[0] ->>> here.exits[0] -north -> @py here.exits[0].db.desc ->>> here.exits[0].db.desc -This is the northern exit. Cool huh? -``` - -Very simply, we created two menus and bridged them together. This needs much less callbacks. There -is only one line in the `nomatch_exits` to add: - -```python - menu.open_submenu("commands.building.ExitBuildingMenu", exit, parent_keys=["e"]) -``` - -We have to call `open_submenu` on the menu object (which opens, as its name implies, a sub menu) -with three arguments: - -- The path of the menu class to create. It's the Python class leading to the menu (notice the -dots). -- The object that will be edited by the menu. Here, it's our exit, so we give it to the sub-menu. -- The keys of the parent to open when the sub-menu closes. Basically, when we're in the root of the -sub-menu and press `@`, we'll open the parent menu, with the parent keys. So we specify `["e"]`, -since the parent menus is the "exits" choice. - -And that's it. The new class will be automatically created. As you can see, we have to create a -`on_nomatch` callback to open the sub-menu, but once opened, it automatically close whenever needed. - -### Generic menu options - -There are some options that can be set on any menu class. These options allow for greater -customization. They are class attributes (see the example below), so just set them in the class -body: - -- `keys_go_back` (default to `["@"]`): the keys to use to go back in the menu hierarchy, from choice -to root menu, from sub-menu to parent-menu. By default, only a `@` is used. You can change this -key for one menu or all of them. You can define multiple return commands if you want. -- `sep_keys` (default `"."`): this is the separator for nested keys. There is no real need to -redefine it except if you really need the dot as a key, and need nested keys in your menu. -- `joker_key` (default to `"*"`): used for nested keys to indicate "any key". Again, you shouldn't -need to change it unless you want to be able to use the @*@ in a command key, and also need nested -keys in your menu. -- `min_shortcut` (default to `1`): although we didn't see it here, one can create a menu choice -without giving it a key. If so, the menu system will try to "guess" the key. This option allows to -change the minimum length of any key for security reasons. - -To set one of them just do so in your menu class(es): - -```python -class RoomBuildingMenu(BuildingMenu): - keys_go_back = ["/"] - min_shortcut = 2 -``` - -## Conclusion - -Building menus mean to save you time and create a rich yet simple interface. But they can be -complicated to learn and require reading the source code to find out how to do such and such a -thing. This documentation, however long, is an attempt at describing this system, but chances are -you'll still have questions about it after reading it, especially if you try to push this system to -a great extent. Do not hesitate to read the documentation of this contrib, it's meant to be -exhaustive but user-friendly. diff --git a/docs/source/Contribs/Contrib-AWSStorage.md b/docs/source/Contribs/Contrib-AWSStorage.md index c6ea74ba63..b5b97b8878 100644 --- a/docs/source/Contribs/Contrib-AWSStorage.md +++ b/docs/source/Contribs/Contrib-AWSStorage.md @@ -29,7 +29,7 @@ of storage space on S3, making the current total cost of running this plugin them to many users, caveat emptor on a total cost of ownership - check AWS's pricing structure. -# Technical details +## Technical details This is a drop-in replacement that operates deeper than all of Evennia's code, so your existing code does not need to change at all to support it. @@ -52,9 +52,9 @@ other contributions or custom code. Simply work how you would normally, Django will handle the rest. -# Installation +## Installation -## Set up AWS account +### Set up AWS account If you don't have an AWS S3 account, you should create one at https://aws.amazon.com/ - documentation for AWS S3 is available at: @@ -161,7 +161,7 @@ checking the source of any image (for instance, the logo). It should read `https://your-bucket-name.s3.amazonaws.com/path/to/file`. If so, the system works and you shouldn't need to do anything else. -# Uninstallation +## Uninstallation If you haven't made changes to your static files (uploaded images, etc), you can simply remove the lines you added to `secret_settings.py`. If you @@ -170,7 +170,7 @@ your files from your S3 bucket and put them in /static/ in the evennia directory. -# License +## License Draws heavily from code provided by django-storages, for which these contributors are authors: @@ -221,7 +221,7 @@ Andrew Perry (Bug fixes in SFTPStorage) The repurposed code from django-storages is released under BSD 3-Clause, same as Evennia, so for detailed licensing, refer to the Evennia license. -# Versioning +## Versioning This is confirmed to work for Django 2 and Django 3. diff --git a/docs/source/Contribs/Contrib-Building-Menu.md b/docs/source/Contribs/Contrib-Building-Menu.md index 7a7318a160..11a8f7409d 100644 --- a/docs/source/Contribs/Contrib-Building-Menu.md +++ b/docs/source/Contribs/Contrib-Building-Menu.md @@ -31,7 +31,7 @@ that will edit any default object, offering to change its key and description. self.add(GenericBuildingCmd()) ``` -## Usage +## Basic Usage The `edit` command will allow you to edit any object. You will need to specify the object name or ID as an argument. For instance: `edit here` @@ -121,9 +121,1225 @@ class CmdEdit(Command): ``` -This is a very short introduction. For more details, see the [online -tutorial](https://github.com/evennia/evennia/wiki/Building-menus) or read the -heavily-documented code of the contrib itself. + +## A simple menu example + +Before diving in, there are some things to point out: + +- Building menus work on an object. This object will be edited by manipulations in the menu. So +you can create a menu to add/edit a room, an exit, a character and so on. +- Building menus are arranged in layers of choices. A choice gives access to an option or to a sub- +menu. Choices are linked to commands (usually very short). For instance, in the example shown +below, to edit the room key, after opening the building menu, you can type `k`. That will lead you +to the key choice where you can enter a new key for the room. Then you can enter `@` to leave this +choice and go back to the entire menu. (All of this can be changed). +- To open the menu, you will need something like a command. This contrib offers a basic command for +demonstration, but we will override it in this example, using the same code with more flexibility. + +So let's add a very basic example to begin with. + +### A generic editing command + +Let's begin by adding a new command. You could add or edit the following file (there's no trick +here, feel free to organize the code differently): + +```python +# file: commands/building.py +from evennia.contrib.building_menu import BuildingMenu +from commands.command import Command + +class EditCmd(Command): + + """ + Editing command. + + Usage: + @edit [object] + + Open a building menu to edit the specified object. This menu allows to + specific information about this object. + + Examples: + @edit here + @edit self + @edit #142 + + """ + + key = "@edit" + locks = "cmd:id(1) or perm(Builders)" + help_category = "Building" + + def func(self): + if not self.args.strip(): + self.msg("|rYou should provide an argument to this function: the object to edit.|n") + return + + obj = self.caller.search(self.args.strip(), global_search=True) + if not obj: + return + + if obj.typename == "Room": + Menu = RoomBuildingMenu + else: + obj_name = obj.get_display_name(self.caller) + self.msg(f"|rThe object {obj_name} cannot be edited.|n") + return + + menu = Menu(self.caller, obj) + menu.open() +``` + +This command is rather simple in itself: + +1. It has a key `@edit` and a lock to only allow builders to use it. +2. In its `func` method, it begins by checking the arguments, returning an error if no argument is +specified. +3. It then searches for the given argument. We search globally. The `search` method used in this +way will return the found object or `None`. It will also send the error message to the caller if +necessary. +4. Assuming we have found an object, we check the object `typename`. This will be used later when +we want to display several building menus. For the time being, we only handle `Room`. If the +caller specified something else, we'll display an error. +5. Assuming this object is a `Room`, we have defined a `Menu` object containing the class of our +building menu. We build this class (creating an instance), giving it the caller and the object to +edit. +6. We then open the building menu, using the `open` method. + +The end might sound a bit surprising at first glance. But the process is still very simple: we +create an instance of our building menu and call its `open` method. Nothing more. + +> Where is our building menu? + +If you go ahead and add this command and test it, you'll get an error. We haven't defined +`RoomBuildingMenu` yet. + +To add this command, edit `commands/default_cmdsets.py`. Import our command, adding an import line +at the top of the file: + +```python +""" +... +""" + +from evennia import default_cmds + +# The following line is to be added +from commands.building import EditCmd +``` + +And in the class below (`CharacterCmdSet`), add the last line of this code: + +```python +class CharacterCmdSet(default_cmds.CharacterCmdSet): + """ + The `CharacterCmdSet` contains general in-game commands like `look`, + `get`, etc available on in-game Character objects. It is merged with + the `AccountCmdSet` when an Account puppets a Character. + """ + key = "DefaultCharacter" + + def at_cmdset_creation(self): + """ + Populates the cmdset + """ + super().at_cmdset_creation() + # + # any commands you add below will overload the default ones. + # + self.add(EditCmd()) +``` + +### Our first menu + +So far, we can't use our building menu. Our `@edit` command will throw an error. We have to define +the `RoomBuildingMenu` class. Open the `commands/building.py` file and add to the end of the file: + +```python +# ... at the end of commands/building.py +# Our building menu + +class RoomBuildingMenu(BuildingMenu): + + """ + Building menu to edit a room. + + For the time being, we have only one choice: key, to edit the room key. + + """ + + def init(self, room): + self.add_choice("key", "k", attr="key") +``` + +Save these changes, reload your game. You can now use the `@edit` command. Here's what we get +(notice that the commands we enter into the game are prefixed with `> `, though this prefix will +probably not appear in your MUD client): + +``` +> look +Limbo(#2) +Welcome to your new Evennia-based game! Visit https://www.evennia.com if you need +help, want to contribute, report issues or just join the community. +As Account #1 you can create a demo/tutorial area with @batchcommand tutorial_world.build. + +> @edit here +Building menu: Limbo + + [K]ey: Limbo + [Q]uit the menu + +> q +Closing the building menu. + +> @edit here +Building menu: Limbo + + [K]ey: Limbo + [Q]uit the menu + +> k +------------------------------------------------------------------------------- +key for Limbo(#2) + +You can change this value simply by entering it. + +Use @ to go back to the main menu. + +Current value: Limbo + +> A beautiful meadow +------------------------------------------------------------------------------- + +key for A beautiful meadow(#2) + +You can change this value simply by entering it. + +Use @ to go back to the main menu. + +Current value: A beautiful meadow + +> @ +Building menu: A beautiful meadow + + [K]ey: A beautiful meadow + [Q]uit the menu + +> q + +Closing the building menu. + +> look +A beautiful meadow(#2) +Welcome to your new Evennia-based game! Visit https://www.evennia.com if you need +help, want to contribute, report issues or just join the community. +As Account #1 you can create a demo/tutorial area with @batchcommand tutorial_world.build. +``` + +Before diving into the code, let's examine what we have: + +- When we use the `@edit here` command, a building menu for this room appears. +- This menu has two choices: + - Enter `k` to edit the room key. You will go into a choice where you can simply type the key +room key (the way we have done here). You can use `@` to go back to the menu. + - You can use `q` to quit the menu. + +We then check, with the `look` command, that the menu has modified this room key. So by adding a +class, with a method and a single line of code within, we've added a menu with two choices. + +### Code explanation + +Let's examine our code again: + +```python +class RoomBuildingMenu(BuildingMenu): + + """ + Building menu to edit a room. + + For the time being, we have only one choice: key, to edit the room key. + + """ + + def init(self, room): + self.add_choice("key", "k", attr="key") +``` + +- We first create a class inheriting from `BuildingMenu`. This is usually the case when we want to +create a building menu with this contrib. +- In this class, we override the `init` method, which is called when the menu opens. +- In this `init` method, we call `add_choice`. This takes several arguments, but we've defined only +three here: + - The choice name. This is mandatory and will be used by the building menu to know how to +display this choice. + - The command key to access this choice. We've given a simple `"k"`. Menu commands usually are +pretty short (that's part of the reason building menus are appreciated by builders). You can also +specify additional aliases, but we'll see that later. + - We've added a keyword argument, `attr`. This tells the building menu that when we are in this +choice, the text we enter goes into this attribute name. It's called `attr`, but it could be a room +attribute or a typeclass persistent or non-persistent attribute (we'll see other examples as well). + +> We've added the menu choice for `key` here, why is another menu choice defined for `quit`? + +Our building menu creates a choice at the end of our choice list if it's a top-level menu (sub-menus +don't have this feature). You can, however, override it to provide a different "quit" message or to +perform some actions. + +I encourage you to play with this code. As simple as it is, it offers some functionalities already. + +## Customizing building menus + +This somewhat long section explains how to customize building menus. There are different ways +depending on what you would like to achieve. We'll go from specific to more advanced here. + +### Generic choices + +In the previous example, we've used `add_choice`. This is one of three methods you can use to add +choices. The other two are to handle more generic actions: + +- `add_choice_edit`: this is called to add a choice which points to the `EvEditor`. It is used to +edit a description in most cases, although you could edit other things. We'll see an example +shortly. `add_choice_edit` uses most of the `add_choice` keyword arguments we'll see, but usually +we specify only two (sometimes three): + - The choice title as usual. + - The choice key (command key) as usual. + - Optionally, the attribute of the object to edit, with the `attr` keyword argument. By +default, `attr` contains `db.desc`. It means that this persistent data attribute will be edited by +the `EvEditor`. You can change that to whatever you want though. +- `add_choice_quit`: this allows to add a choice to quit the editor. Most advisable! If you don't +do it, the building menu will do it automatically, except if you really tell it not to. Again, you +can specify the title and key of this menu. You can also call a function when this menu closes. + +So here's a more complete example (you can replace your `RoomBuildingMenu` class in +`commands/building.py` to see it): + +```python +class RoomBuildingMenu(BuildingMenu): + + """ + Building menu to edit a room. + """ + + def init(self, room): + self.add_choice("key", "k", attr="key") + self.add_choice_edit("description", "d") + self.add_choice_quit("quit this editor", "q") +``` + +So far, our building menu class is still thin... and yet we already have some interesting feature. +See for yourself the following MUD client output (again, the commands are prefixed with `> ` to +distinguish them): + +``` +> @reload + +> @edit here +Building menu: A beautiful meadow + + [K]ey: A beautiful meadow + [D]escription: + Welcome to your new Evennia-based game! Visit https://www.evennia.com if you need +help, want to contribute, report issues or just join the community. +As Account #1 you can create a demo/tutorial area with @batchcommand tutorial_world.build. + [Q]uit this editor + +> d + +----------Line Editor [editor]---------------------------------------------------- +01| Welcome to your new |wEvennia|n-based game! Visit https://www.evennia.com if you need +02| help, want to contribute, report issues or just join the community. +03| As Account #1 you can create a demo/tutorial area with |w@batchcommand tutorial_world.build|n. + +> :DD + +----------[l:03 w:034 c:0247]------------(:h for help)---------------------------- +Cleared 3 lines from buffer. + +> This is a beautiful meadow. But so beautiful I can't describe it. + +01| This is a beautiful meadow. But so beautiful I can't describe it. + +> :wq +Building menu: A beautiful meadow + + [K]ey: A beautiful meadow + [D]escription: + This is a beautiful meadow. But so beautiful I can't describe it. + [Q]uit this editor + +> q +Closing the building menu. + +> look +A beautiful meadow(#2) +This is a beautiful meadow. But so beautiful I can't describe it. +``` + +So by using the `d` shortcut in our building menu, an `EvEditor` opens. You can use the `EvEditor` +commands (like we did here, `:DD` to remove all, `:wq` to save and quit). When you quit the editor, +the description is saved (here, in `room.db.desc`) and you go back to the building menu. + +Notice that the choice to quit has changed too, which is due to our adding `add_choice_quit`. In +most cases, you will probably not use this method, since the quit menu is added automatically. + +### `add_choice` options + +`add_choice` and the two methods `add_choice_edit` and `add_choice_quit` take a lot of optional +arguments to make customization easier. Some of these options might not apply to `add_choice_edit` +or `add_choice_quit` however. + +Below are the options of `add_choice`, specify them as arguments: + +- The first positional, mandatory argument is the choice title, as we have seen. This will +influence how the choice appears in the menu. +- The second positional, mandatory argument is the command key to access to this menu. It is best +to use keyword arguments for the other arguments. +- The `aliases` keyword argument can contain a list of aliases that can be used to access to this +menu. For instance: `add_choice(..., aliases=['t'])` +- The `attr` keyword argument contains the attribute to edit when this choice is selected. It's a +string, it has to be the name, from the object (specified in the menu constructor) to reach this +attribute. For instance, a `attr` of `"key"` will try to find `obj.key` to read and write the +attribute. You can specify more complex attribute names, for instance, `attr="db.desc"` to set the +`desc` persistent attribute, or `attr="ndb.something"` so use a non-persistent data attribute on the +object. +- The `text` keyword argument is used to change the text that will be displayed when the menu choice +is selected. Menu choices provide a default text that you can change. Since this is a long text, +it's useful to use multi-line strings (see an example below). +- The `glance` keyword argument is used to specify how to display the current information while in +the menu, when the choice hasn't been opened. If you examine the previous examples, you will see +that the current (`key` or `db.desc`) was shown in the menu, next to the command key. This is +useful for seeing at a glance the current value (hence the name). Again, menu choices will provide +a default glance if you don't specify one. +- The `on_enter` keyword argument allows to add a callback to use when the menu choice is opened. +This is more advanced, but sometimes useful. +- The `on_nomatch` keyword argument is called when, once in the menu, the caller enters some text +that doesn't match any command (including the `@` command). By default, this will edit the +specified `attr`. +- The `on_leave` keyword argument allows to specify a callback used when the caller leaves the menu +choice. This can be useful for cleanup as well. + +These are a lot of possibilities, and most of the time you won't need them all. Here is a short +example using some of these arguments (again, replace the `RoomBuildingMenu` class in +`commands/building.py` with the following code to see it working): + +```python +class RoomBuildingMenu(BuildingMenu): + + """ + Building menu to edit a room. + + For the time being, we have only one choice: key, to edit the room key. + + """ + + def init(self, room): + self.add_choice("title", key="t", attr="key", glance="{obj.key}", text=""" + ------------------------------------------------------------------------------- + Editing the title of {{obj.key}}(#{{obj.id}}) + + You can change the title simply by entering it. + Use |y{back}|n to go back to the main menu. + + Current title: |c{{obj.key}}|n + """.format(back="|n or |y".join(self.keys_go_back))) + self.add_choice_edit("description", "d") +``` + +Reload your game and see it in action: + +``` +> @edit here +Building menu: A beautiful meadow + + [T]itle: A beautiful meadow + [D]escription: + This is a beautiful meadow. But so beautiful I can't describe it. + [Q]uit the menu + +> t +------------------------------------------------------------------------------- + +Editing the title of A beautiful meadow(#2) + +You can change the title simply by entering it. +Use @ to go back to the main menu. + +Current title: A beautiful meadow + +> @ + +Building menu: A beautiful meadow + + [T]itle: A beautiful meadow + [D]escription: + This is a beautiful meadow. But so beautiful I can't describe it. + [Q]uit the menu + +> q +Closing the building menu. +``` + +The most surprising part is no doubt the text. We use the multi-line syntax (with `"""`). +Excessive spaces will be removed from the left for each line automatically. We specify some +information between braces... sometimes using double braces. What might be a bit odd: + +- `{back}` is a direct format argument we'll use (see the `.format` specifiers). +- `{{obj...}}` refers to the object being edited. We use two braces, because `.format` will remove them. + +In `glance`, we also use `{obj.key}` to indicate we want to show the room's key. + +### Everything can be a function + +The keyword arguments of `add_choice` are often strings (type `str`). But each of these arguments +can also be a function. This allows for a lot of customization, since we define the callbacks that +will be executed to achieve such and such an operation. + +To demonstrate, we will try to add a new feature. Our building menu for rooms isn't that bad, but +it would be great to be able to edit exits too. So we can add a new menu choice below +description... but how to actually edit exits? Exits are not just an attribute to set: exits are +objects (of type `Exit` by default) which stands between two rooms (object of type `Room`). So how +can we show that? + +First let's add a couple of exits in limbo, so we have something to work with: + +``` +@tunnel n +@tunnel s +``` + +This should create two new rooms, exits leading to them from limbo and back to limbo. + +``` +> look +A beautiful meadow(#2) +This is a beautiful meadow. But so beautiful I can't describe it. +Exits: north(#4) and south(#7) +``` + +We can access room exits with the `exits` property: + +``` +> @py here.exits +[, ] +``` + +So what we need is to display this list in our building menu... and to allow to edit it would be +great. Perhaps even add new exits? + +First of all, let's write a function to display the `glance` on existing exits. Here's the code, +it's explained below: + +```python +class RoomBuildingMenu(BuildingMenu): + + """ + Building menu to edit a room. + + """ + + def init(self, room): + self.add_choice("title", key="t", attr="key", glance="{obj.key}", text=""" + ------------------------------------------------------------------------------- + Editing the title of {{obj.key}}(#{{obj.id}}) + + You can change the title simply by entering it. + Use |y{back}|n to go back to the main menu. + + Current title: |c{{obj.key}}|n + """.format(back="|n or |y".join(self.keys_go_back))) + self.add_choice_edit("description", "d") + self.add_choice("exits", "e", glance=glance_exits, attr="exits") + + +# Menu functions +def glance_exits(room): + """Show the room exits.""" + if room.exits: + glance = "" + for exit in room.exits: + glance += f"\n |y{exit.key}|n" + + return glance + + return "\n |gNo exit yet|n" +``` + +When the building menu opens, it displays each choice to the caller. A choice is displayed with its +title (rendered a bit nicely to show the key as well) and the glance. In the case of the `exits` +choice, the glance is a function, so the building menu calls this function giving it the object +being edited (the room here). The function should return the text to see. + +``` +> @edit here +Building menu: A beautiful meadow + + [T]itle: A beautiful meadow + [D]escription: + This is a beautiful meadow. But so beautiful I can't describe it. + [E]xits: + north + south + [Q]uit the menu + +> q +Closing the editor. +``` + +> How do I know the parameters of the function to give? + +The function you give can accept a lot of different parameters. This allows for a flexible approach +but might seem complicated at first. Basically, your function can accept any parameter, and the +building menu will send only the parameter based on their names. If your function defines an +argument named `caller` for instance (like `def func(caller):` ), then the building menu knows that +the first argument should contain the caller of the building menu. Here are the arguments, you +don't have to specify them (if you do, they need to have the same name): + +- `menu`: if your function defines an argument named `menu`, it will contain the building menu +itself. +- `choice`: if your function defines an argument named `choice`, it will contain the `Choice` object +representing this menu choice. +- `string`: if your function defines an argument named `string`, it will contain the user input to +reach this menu choice. This is not very useful, except on `nomatch` callbacks which we'll see +later. +- `obj`: if your function defines an argument named `obj`, it will contain the building menu edited +object. +- `caller`: if your function defines an argument named `caller`, it will contain the caller of the +building menu. +- Anything else: any other argument will contain the object being edited by the building menu. + +So in our case: + +```python +def glance_exits(room): +``` + +The only argument we need is `room`. It's not present in the list of possible arguments, so the +editing object of the building menu (the room, here) is given. + +> Why is it useful to get the menu or choice object? + +Most of the time, you will not need these arguments. In very rare cases, you will use them to get +specific data (like the default attribute that was set). This tutorial will not elaborate on these +possibilities. Just know that they exist. + +We should also define a text callback, so that we can enter our menu to see the room exits. We'll +see how to edit them in the next section but this is a good opportunity to show a more complete +callback. To see it in action, as usual, replace the class and functions in `commands/building.py`: + +```python +# Our building menu + +class RoomBuildingMenu(BuildingMenu): + + """ + Building menu to edit a room. + + """ + + def init(self, room): + self.add_choice("title", key="t", attr="key", glance="{obj.key}", text=""" + ------------------------------------------------------------------------------- + Editing the title of {{obj.key}}(#{{obj.id}}) + + You can change the title simply by entering it. + Use |y{back}|n to go back to the main menu. + + Current title: |c{{obj.key}}|n + """.format(back="|n or |y".join(self.keys_go_back))) + self.add_choice_edit("description", "d") + self.add_choice("exits", "e", glance=glance_exits, attr="exits", text=text_exits) + + +# Menu functions +def glance_exits(room): + """Show the room exits.""" + if room.exits: + glance = "" + for exit in room.exits: + glance += f"\n |y{exit.key}|n" + + return glance + + return "\n |gNo exit yet|n" + +def text_exits(caller, room): + """Show the room exits in the choice itself.""" + text = "-" * 79 + text += "\n\nRoom exits:" + text += "\n Use |y@c|n to create a new exit." + text += "\n\nExisting exits:" + if room.exits: + for exit in room.exits: + text += f"\n |y@e {exit.key}|n" + if exit.aliases.all(): + text += " (|y{aliases}|n)".format(aliases="|n, |y".join( + alias for alias in exit.aliases.all() + )) + if exit.destination: + text += f" toward {exit.get_display_name(caller)}" + else: + text += "\n\n |gNo exit has yet been defined.|n" + + return text +``` + +Look at the second callback in particular. It takes an additional argument, the caller (remember, +the argument names are important, their order is not relevant). This is useful for displaying +destination of exits accurately. Here is a demonstration of this menu: + +``` +> @edit here +Building menu: A beautiful meadow + + [T]itle: A beautiful meadow + [D]escription: + This is a beautiful meadow. But so beautiful I can't describe it. + [E]xits: + north + south + [Q]uit the menu + +> e +------------------------------------------------------------------------------- + +Room exits: + Use @c to create a new exit. + +Existing exits: + @e north (n) toward north(#4) + @e south (s) toward south(#7) + +> @ +Building menu: A beautiful meadow + + [T]itle: A beautiful meadow + [D]escription: + This is a beautiful meadow. But so beautiful I can't describe it. + [E]xits: + north + south + [Q]uit the menu + +> q +Closing the building menu. +``` + +Using callbacks allows a great flexibility. We'll now see how to handle sub-menus. + +### Sub-menus for complex menus + +A menu is relatively flat: it has a root (where you see all the menu choices) and individual choices +you can go to using the menu choice keys. Once in a choice you can type some input or go back to +the root menu by entering the return command (usually `@`). + +Why shouldn't individual exits have their own menu though? Say, you edit an exit and can change its +key, description or aliases... perhaps even destination? Why ever not? It would make building much +easier! + +The building menu system offers two ways to do that. The first is nested keys: nested keys allow to +go beyond just one menu/choice, to have menus with more layers. Using them is quick but might feel +a bit counter-intuitive at first. Another option is to create a different menu class and redirect +from the first to the second. This option might require more lines but is more explicit and can be +re-used for multiple menus. Adopt one of them depending of your taste. + +#### Nested menu keys + +So far, we've only used menu keys with one letter. We can add more, of course, but menu keys in +their simple shape are just command keys. Press "e" to go to the "exits" choice. + +But menu keys can be nested. Nested keys allow to add choices with sub-menus. For instance, type +"e" to go to the "exits" choice, and then you can type "c" to open a menu to create a new exit, or +"d" to open a menu to delete an exit. The first menu would have the "e.c" key (first e, then c), +the second menu would have key as "e.d". + +That's more advanced and, if the following code doesn't sound very friendly to you, try the next +section which provides a different approach of the same problem. + +So we would like to edit exits. That is, you can type "e" to go into the choice of exits, then +enter `@e` followed by the exit name to edit it... which will open another menu. In this sub-menu +you could change the exit key or description. + +So we have a menu hierarchy similar to that: + +``` +t Change the room title +d Change the room description +e Access the room exits + [exit name] Access the exit name sub-menu + [text] Change the exit key +``` + +Or, if you prefer an example output: + +``` +> look +A beautiful meadow(#2) +This is a beautiful meadow. But so beautiful I can't describe it. +Exits: north(#4) and south(#7) + +> @edit here +Building menu: A beautiful meadow + + [T]itle: A beautiful meadow + [D]escription: + This is a beautiful meadow. But so beautiful I can't describe it. + [E]xits: + north + south + [Q]uit the menu + +> e +------------------------------------------------------------------------------- + +Room exits : + Use @c to create a new exit. + +Existing exits: + @e north (n) toward north(#4) + @e south (s) toward south(#7) + +> @e north +Editing: north +Exit north: +Enter the exit key to change it, or @ to go back. + +New exit key: + +> door + +Exit door: +Enter the exit key to change it, or @ to go back. + +New exit key: + +> @ + +------------------------------------------------------------------------------- + +Room exits : + Use @c to create a new exit. + +Existing exits: + @e door (n) toward door(#4) + @e south (s) toward south(#7) + +> @ +Building menu: A beautiful meadow + + [T]itle: A beautiful meadow + [D]escription: + This is a beautiful meadow. But so beautiful I can't describe it. + [E]xits: + door + south + [Q]uit the menu + +> q +Closing the building menu. +``` + +This needs a bit of code and a bit of explanation. So here we go... the code first, the +explanations next! + +```python +# ... from commands/building.py +# Our building menu + +class RoomBuildingMenu(BuildingMenu): + + """ + Building menu to edit a room. + + For the time being, we have only one choice: key, to edit the room key. + + """ + + def init(self, room): + self.add_choice("title", key="t", attr="key", glance="{obj.key}", text=""" + ------------------------------------------------------------------------------- + Editing the title of {{obj.key}}(#{{obj.id}}) + + You can change the title simply by entering it. + Use |y{back}|n to go back to the main menu. + + Current title: |c{{obj.key}}|n + """.format(back="|n or |y".join(self.keys_go_back))) + self.add_choice_edit("description", "d") + self.add_choice("exits", "e", glance=glance_exits, text=text_exits, on_nomatch=nomatch_exits) + + # Exit sub-menu + self.add_choice("exit", "e.*", text=text_single_exit, on_nomatch=nomatch_single_exit) + + +# Menu functions +def glance_exits(room): + """Show the room exits.""" + if room.exits: + glance = "" + for exit in room.exits: + glance += f"\n |y{exit.key}|n" + + return glance + + return "\n |gNo exit yet|n" + +def text_exits(caller, room): + """Show the room exits in the choice itself.""" + text = "-" * 79 + text += "\n\nRoom exits:" + text += "\n Use |y@c|n to create a new exit." + text += "\n\nExisting exits:" + if room.exits: + for exit in room.exits: + text += f"\n |y@e {exit.key}|n" + if exit.aliases.all(): + text += " (|y{aliases}|n)".format(aliases="|n, |y".join( + alias for alias in exit.aliases.all() + )) + if exit.destination: + text += f" toward {exit.get_display_name(caller)}" + else: + text += "\n\n |gNo exit has yet been defined.|n" + + return text + +def nomatch_exits(menu, caller, room, string): + """ + The user typed something in the list of exits. Maybe an exit name? + """ + string = string[3:] + exit = caller.search(string, candidates=room.exits) + if exit is None: + return + + # Open a sub-menu, using nested keys + caller.msg(f"Editing: {exit.key}") + menu.move(exit) + return False + +# Exit sub-menu +def text_single_exit(menu, caller): + """Show the text to edit single exits.""" + exit = menu.keys[1] + if exit is None: + return "" + + return f""" + Exit {exit.key}: + + Enter the exit key to change it, or |y@|n to go back. + + New exit key: + """ + +def nomatch_single_exit(menu, caller, room, string): + """The user entered something in the exit sub-menu. Replace the exit key.""" + # exit is the second key element: keys should contain ['e', ] + exit = menu.keys[1] + if exit is None: + caller.msg("|rCannot find the exit.|n") + menu.move(back=True) + return False + + exit.key = string + return True +``` + +> That's a lot of code! And we only handle editing the exit key! + +That's why at some point you might want to write a real sub-menu, instead of using simple nested +keys. But you might need both to build pretty menus too! + +1. The first thing new is in our menu class. After creating a `on_nomatch` callback for the exits +menu (that shouldn't be a surprised), we need to add a nested key. We give this menu a key of +`"e.*"`. That's a bit odd! "e" is our key to the exits menu, . is the separator to indicate a +nested menu, and * means anything. So basically, we create a nested menu that is contains within +the exits menu and anything. We'll see what this "anything" is in practice. +2. The `glance_exits` and `text_exits` are basically the same. +3. The `nomatch_exits` is short but interesting. It's called when we enter some text in the "exits" +menu (that is, in the list of exits). We have said that the user should enter `@e` followed by the +exit name to edit it. So in the `nomatch_exits` callbac, we check for that input. If the entered +text begins by `@e`, we try to find the exit in the room. If we do... +4. We call the `menu.move` method. That's where things get a bit complicated with nested menus: we +need to use `menu.move` to change from layer to layer. Here, we are in the choice of exits (the +exits menu, of key "e"). We need to go down one layer to edit an exit. So we call `menu.move` and +give it an exit object. The menu system remembers what position the user is based on the keys she +has entered: when the user opens the menu, there is no key. If she selects the exits choice, the +menu key being "e", the position of the user is `["e"]` (a list with the menu keys). If we call +`menu.move`, whatever we give to this method will be appended to the list of keys, so that the user +position becomes `["e", ]`. +5. In the menu class, we have defined the menu `"e.*"`, meaning "the menu contained in the exits +choice plus anything". The "anything" here is an exit: we have called `menu.move(exit)`, so the +`"e.*"` menu choice is chosen. +6. In this menu, the text is set to a callback. There is also a `on_nomatch` callback that is +called whenever the user enters some text. If so, we change the exit name. + +Using `menu.move` like this is a bit confusing at first. Sometimes it's useful. In this case, if +we want a more complex menu for exits, it makes sense to use a real sub-menu, not nested keys like +this. But sometimes, you will find yourself in a situation where you don't need a full menu to +handle a choice. + +## Full sub-menu as separate classes + +The best way to handle individual exits is to create two separate classes: + +- One for the room menu. +- One for the individual exit menu. + +The first one will have to redirect on the second. This might be more intuitive and flexible, +depending on what you want to achieve. So let's build two menus: + +```python +# Still in commands/building.py, replace the menu class and functions by... +# Our building menus + +class RoomBuildingMenu(BuildingMenu): + + """ + Building menu to edit a room. + """ + + def init(self, room): + self.add_choice("title", key="t", attr="key", glance="{obj.key}", text=""" + ------------------------------------------------------------------------------- + Editing the title of {{obj.key}}(#{{obj.id}}) + + You can change the title simply by entering it. + Use |y{back}|n to go back to the main menu. + + Current title: |c{{obj.key}}|n + """.format(back="|n or |y".join(self.keys_go_back))) + self.add_choice_edit("description", "d") + self.add_choice("exits", "e", glance=glance_exits, text=text_exits, +on_nomatch=nomatch_exits) + + +# Menu functions +def glance_exits(room): + """Show the room exits.""" + if room.exits: + glance = "" + for exit in room.exits: + glance += f"\n |y{exit.key}|n" + + return glance + + return "\n |gNo exit yet|n" + +def text_exits(caller, room): + """Show the room exits in the choice itself.""" + text = "-" * 79 + text += "\n\nRoom exits:" + text += "\n Use |y@c|n to create a new exit." + text += "\n\nExisting exits:" + if room.exits: + for exit in room.exits: + text += f"\n |y@e {exit.key}|n" + if exit.aliases.all(): + text += " (|y{aliases}|n)".format(aliases="|n, |y".join( + alias for alias in exit.aliases.all() + )) + if exit.destination: + text += f" toward {exit.get_display_name(caller)}" + else: + text += "\n\n |gNo exit has yet been defined.|n" + + return text + +def nomatch_exits(menu, caller, room, string): + """ + The user typed something in the list of exits. Maybe an exit name? + """ + string = string[3:] + exit = caller.search(string, candidates=room.exits) + if exit is None: + return + + # Open a sub-menu, using nested keys + caller.msg(f"Editing: {exit.key}") + menu.open_submenu("commands.building.ExitBuildingMenu", exit, parent_keys=["e"]) + return False + +class ExitBuildingMenu(BuildingMenu): + + """ + Building menu to edit an exit. + + """ + + def init(self, exit): + self.add_choice("key", key="k", attr="key", glance="{obj.key}") + self.add_choice_edit("description", "d") +``` + +The code might be much easier to read. But before detailing it, let's see how it behaves in the +game: + +``` +> @edit here +Building menu: A beautiful meadow + + [T]itle: A beautiful meadow + [D]escription: + This is a beautiful meadow. But so beautiful I can't describe it. + [E]xits: + door + south + [Q]uit the menu + +> e +------------------------------------------------------------------------------- + +Room exits: + Use @c to create a new exit. + +Existing exits: + @e door (n) toward door(#4) + @e south (s) toward south(#7) + +Editing: door + +> @e door +Building menu: door + + [K]ey: door + [D]escription: + None + +> k +------------------------------------------------------------------------------- +key for door(#4) + +You can change this value simply by entering it. + +Use @ to go back to the main menu. + +Current value: door + +> north + +------------------------------------------------------------------------------- +key for north(#4) + +You can change this value simply by entering it. + +Use @ to go back to the main menu. + +Current value: north + +> @ +Building menu: north + + [K]ey: north + [D]escription: + None + +> d +----------Line Editor [editor]---------------------------------------------------- +01| None +----------[l:01 w:001 c:0004]------------(:h for help)---------------------------- + +> :DD +Cleared 1 lines from buffer. + +> This is the northern exit. Cool huh? +01| This is the northern exit. Cool huh? + +> :wq +Building menu: north + [K]ey: north + [D]escription: + This is the northern exit. Cool huh? + +> @ +------------------------------------------------------------------------------- +Room exits: + Use @c to create a new exit. + +Existing exits: + @e north (n) toward north(#4) + @e south (s) toward south(#7) + +> @ +Building menu: A beautiful meadow + + [T]itle: A beautiful meadow + [D]escription: + This is a beautiful meadow. But so beautiful I can't describe it. + [E]xits: + north + south + [Q]uit the menu + +> q +Closing the building menu. + +> look +A beautiful meadow(#2) +This is a beautiful meadow. But so beautiful I can't describe it. +Exits: north(#4) and south(#7) +> @py here.exits[0] +>>> here.exits[0] +north +> @py here.exits[0].db.desc +>>> here.exits[0].db.desc +This is the northern exit. Cool huh? +``` + +Very simply, we created two menus and bridged them together. This needs much less callbacks. There +is only one line in the `nomatch_exits` to add: + +```python + menu.open_submenu("commands.building.ExitBuildingMenu", exit, parent_keys=["e"]) +``` + +We have to call `open_submenu` on the menu object (which opens, as its name implies, a sub menu) +with three arguments: + +- The path of the menu class to create. It's the Python class leading to the menu (notice the +dots). +- The object that will be edited by the menu. Here, it's our exit, so we give it to the sub-menu. +- The keys of the parent to open when the sub-menu closes. Basically, when we're in the root of the +sub-menu and press `@`, we'll open the parent menu, with the parent keys. So we specify `["e"]`, +since the parent menus is the "exits" choice. + +And that's it. The new class will be automatically created. As you can see, we have to create a +`on_nomatch` callback to open the sub-menu, but once opened, it automatically close whenever needed. + +### Generic menu options + +There are some options that can be set on any menu class. These options allow for greater +customization. They are class attributes (see the example below), so just set them in the class +body: + +- `keys_go_back` (default to `["@"]`): the keys to use to go back in the menu hierarchy, from choice +to root menu, from sub-menu to parent-menu. By default, only a `@` is used. You can change this +key for one menu or all of them. You can define multiple return commands if you want. +- `sep_keys` (default `"."`): this is the separator for nested keys. There is no real need to +redefine it except if you really need the dot as a key, and need nested keys in your menu. +- `joker_key` (default to `"*"`): used for nested keys to indicate "any key". Again, you shouldn't +need to change it unless you want to be able to use the `@*@` in a command key, and also need nested +keys in your menu. +- `min_shortcut` (default to `1`): although we didn't see it here, one can create a menu choice +without giving it a key. If so, the menu system will try to "guess" the key. This option allows to +change the minimum length of any key for security reasons. + +To set one of them just do so in your menu class(es): + +```python +class RoomBuildingMenu(BuildingMenu): + keys_go_back = ["/"] + min_shortcut = 2 +``` + +## Conclusion + +Building menus mean to save you time and create a rich yet simple interface. But they can be +complicated to learn and require reading the source code to find out how to do such and such a +thing. This documentation, however long, is an attempt at describing this system, but chances are +you'll still have questions about it after reading it, especially if you try to push this system to +a great extent. Do not hesitate to read the documentation of this contrib, it's meant to be +exhaustive but user-friendly. ---- diff --git a/docs/source/Contribs/Contrib-Color-Markups.md b/docs/source/Contribs/Contrib-Color-Markups.md index be5a983e05..e56eab0d0f 100644 --- a/docs/source/Contribs/Contrib-Color-Markups.md +++ b/docs/source/Contribs/Contrib-Color-Markups.md @@ -1,9 +1,9 @@ -# Color markups +# Additional Color markups Contrib by Griatch, 2017 Additional color markup styles for Evennia (extending or replacing the default -`|r`, `|234`). Adds support for MUSH-style (`%cr`, `%c123`) and/or legacy-Evennia +`|r`, `|234`). Adds support for MUSH-style (`%cr`, `%c123`) and/or legacy-Evennia (`{r`, `{123`). diff --git a/docs/source/Contribs/Contrib-Cooldowns.md b/docs/source/Contribs/Contrib-Cooldowns.md index 3e17ad926a..ada9765a46 100644 --- a/docs/source/Contribs/Contrib-Cooldowns.md +++ b/docs/source/Contribs/Contrib-Cooldowns.md @@ -3,8 +3,8 @@ Contribution by owllex, 2021 Cooldowns are used to model rate-limited actions, like how often a -character can perform a given action; until a certain time has passed their -command can not be used again. This contrib provides a simple cooldown +character can perform a given action; until a certain time has passed their +command can not be used again. This contrib provides a simple cooldown handler that can be attached to any typeclass. A cooldown is a lightweight persistent asynchronous timer that you can query to see if a certain time has yet passed. @@ -38,7 +38,7 @@ def cooldowns(self): return CooldownHandler(self, db_attribute="cooldowns") ``` -# Example +## Example Assuming you've installed cooldowns on your Character typeclasses, you can use a cooldown to limit how often you can perform a command. The following code diff --git a/docs/source/Contribs/Contrib-Custom-Gametime.md b/docs/source/Contribs/Contrib-Custom-Gametime.md index f927c67f6e..309ea9370b 100644 --- a/docs/source/Contribs/Contrib-Custom-Gametime.md +++ b/docs/source/Contribs/Contrib-Custom-Gametime.md @@ -3,7 +3,7 @@ Contrib by vlgeoff, 2017 - based on Griatch's core original This reimplements the `evennia.utils.gametime` module but with a _custom_ -calendar (unusual number of days per week/month/year etc) for your game world. +calendar (unusual number of days per week/month/year etc) for your game world. Like the original, it allows for scheduling events to happen at given in-game times, but now taking this custom calendar into account. diff --git a/docs/source/Contribs/Contrib-Dice.md b/docs/source/Contribs/Contrib-Dice.md index 14f232b2f6..9e07b53283 100644 --- a/docs/source/Contribs/Contrib-Dice.md +++ b/docs/source/Contribs/Contrib-Dice.md @@ -1,14 +1,14 @@ -# Dice +# Dice roller Contribution by Griatch, 2012 -A dice roller for any number and side of dice. Adds in-game dice rolling -(`roll 2d10 + 1`) as well as conditionals (roll under/over/equal to a target) -and functions for rolling dice in code. Command also supports hidden or secret +A dice roller for any number and side of dice. Adds in-game dice rolling +(`roll 2d10 + 1`) as well as conditionals (roll under/over/equal to a target) +and functions for rolling dice in code. Command also supports hidden or secret rolls for use by a human game master. -# Installation: +## Installation: Add the `CmdDice` command from this module to your character's cmdset @@ -28,7 +28,7 @@ class CharacterCmdSet(default_cmds.CharacterCmdSet): ``` -# Usage: +## Usage: > roll 1d100 + 2 > roll 1d20 @@ -53,7 +53,7 @@ was. Is a hidden roll that does not inform the room it happened. -## Rolling dice from code +### Rolling dice from code To roll dice in code, use the `roll` function from this module: diff --git a/docs/source/Contribs/Contrib-Email-Login.md b/docs/source/Contribs/Contrib-Email-Login.md index 512531c868..716e2d5be2 100644 --- a/docs/source/Contribs/Contrib-Email-Login.md +++ b/docs/source/Contribs/Contrib-Email-Login.md @@ -3,7 +3,7 @@ Contrib by Griatch, 2012 This is a variant of the login system that asks for an email-address -instead of a username to login. Note that it does not verify the email, +instead of a username to login. Note that it does not verify the email, it just uses it as the identifier rather than a username. This used to be the default Evennia login before replacing it with a diff --git a/docs/source/Contribs/Contrib-Evscaperoom.md b/docs/source/Contribs/Contrib-Evscaperoom.md index c0170f440f..acc69a7463 100644 --- a/docs/source/Contribs/Contrib-Evscaperoom.md +++ b/docs/source/Contribs/Contrib-Evscaperoom.md @@ -2,10 +2,10 @@ Contribution by Griatch, 2019 -A full engine for creating multiplayer escape-rooms in Evennia. Allows players to -spawn and join puzzle rooms that track their state independently. Any number of players -can join to solve a room together. This is the engine created for 'EvscapeRoom', which won -the MUD Coders Guild "One Room" Game Jam in April-May, 2019. The contrib has no game +A full engine for creating multiplayer escape-rooms in Evennia. Allows players to +spawn and join puzzle rooms that track their state independently. Any number of players +can join to solve a room together. This is the engine created for 'EvscapeRoom', which won +the MUD Coders Guild "One Room" Game Jam in April-May, 2019. The contrib has no game content but contains the utilities and base classes and an empty example room. The original code for the contest is found at @@ -16,13 +16,13 @@ instead. A copy of the full game can also be played on the Evennia demo server at https://demo.evennia.com - just connect to the server and write `evscaperoom` in the first room to start! -# Introduction +## Introduction Evscaperoom is, as it sounds, an escaperoom in text form. You start locked into a room and have to figure out how to get out. This engine contains everything needed to make a fully-featured puzzle game of this type! -# Installation +## Installation The Evscaperoom is installed by adding the `evscaperoom` command to your character cmdset. When you run that command in-game you're ready to play! @@ -44,7 +44,7 @@ class CharacterCmdSet(...): Reload the server and the `evscaperoom` command will be available. The contrib comes with a small (very small) escape room as an example. -# Making your own evscaperoom +## Making your own evscaperoom To do this, you need to make your own states. First make sure you can play the simple example room installed above. @@ -63,7 +63,7 @@ the following to your `mygame/server/conf/settings.py` file: Reload and the example evscaperoom should still work, but you can now modify and expand it from your game dir! -## Other useful settings +### Other useful settings There are a few other settings that may be useful: @@ -74,7 +74,7 @@ There are a few other settings that may be useful: the room without an argument. The original is found at the top of `evennia/contrib/full_systems/evscaperoom/commands.py`. -# Playing the game +## Playing the game You should start by `look`ing around and at objects. @@ -87,7 +87,7 @@ focus. There is also a full hint system. -# Technical +## Technical When connecting to the game, the user has the option to join an existing room (which may already be in some state of ongoing progress), or may create a fresh @@ -102,7 +102,7 @@ the logic and (in principle) inject new puzzles later. Once no players remain in the room, the room and its state will be wiped. -# Design Philosophy +## Design Philosophy Some basic premises inspired the design of this. diff --git a/docs/source/Contribs/Contrib-Gendersub.md b/docs/source/Contribs/Contrib-Gendersub.md index 8300260416..373593c974 100644 --- a/docs/source/Contribs/Contrib-Gendersub.md +++ b/docs/source/Contribs/Contrib-Gendersub.md @@ -17,10 +17,39 @@ An object can have the following genders: ## Installation Import and add the `SetGender` command to your default cmdset in -`mygame/commands/default_cmdset.py` +`mygame/commands/default_cmdset.py`: + +```python +# mygame/commands/default_cmdsets.py + +# ... + +from evennia.contrib.game_systems.gendersub import SetGender # <--- + +# ... + +class CharacterCmdSet(default_cmds.CharacterCmdSet): + # ... + def at_cmdset_creation(self): + # ... + self.add(SetGender()) # <--- +``` Make your `Character` inherit from `GenderCharacter`. +```python +# mygame/typeclasses/characters.py + +# ... + +from evennia.contrib.game_systems.gendersub import GenderCharacter # <--- + +class Character(GenderCharacter): # <--- + # ... +``` + +Reload the server (`evennia reload` or `reload` from inside the game). + ## Usage diff --git a/docs/source/Contribs/Contrib-Health-Bar.md b/docs/source/Contribs/Contrib-Health-Bar.md index 51f1418491..d49da91ae8 100644 --- a/docs/source/Contribs/Contrib-Health-Bar.md +++ b/docs/source/Contribs/Contrib-Health-Bar.md @@ -3,8 +3,8 @@ Contribution by Tim Ashley Jenkins, 2017 The function provided in this module lets you easily display visual -bars or meters as a colorful bar instead of just a number. A "health bar" -is merely the most obvious use for this, but the bar is highly customizable +bars or meters as a colorful bar instead of just a number. A "health bar" +is merely the most obvious use for this, but the bar is highly customizable and can be used for any sort of appropriate data besides player health. Today's players may be more used to seeing statistics like health, diff --git a/docs/source/Contribs/Contrib-Ingame-Python.md b/docs/source/Contribs/Contrib-Ingame-Python.md index 4cb6a621b6..6deaf769a7 100644 --- a/docs/source/Contribs/Contrib-Ingame-Python.md +++ b/docs/source/Contribs/Contrib-Ingame-Python.md @@ -895,6 +895,15 @@ The in-game Python system will still be accessible (you will have access to the but no event will be called automatically. +```{toctree} +:hidden: + +Contrib-Ingame-Python-Tutorial-Dialogue +Contrib-Ingame-Python-Tutorial-Elevator + +``` + + ---- This document page is generated from `evennia/contrib/base_systems/ingame_python/README.md`. Changes to this diff --git a/docs/source/Contribs/Contrib-Mail.md b/docs/source/Contribs/Contrib-Mail.md index e8e493c93a..591b91ef37 100644 --- a/docs/source/Contribs/Contrib-Mail.md +++ b/docs/source/Contribs/Contrib-Mail.md @@ -4,7 +4,7 @@ Contribution by grungies1138 2016 A simple Brandymail style mail system that uses the `Msg` class from Evennia Core. It has two Commands for either sending mails between Accounts (out of game) -or between Characters (in-game). The two types of mails can be used together or +or between Characters (in-game). The two types of mails can be used together or on their own. - `CmdMail` - this should sit on the Account cmdset and makes the `mail` command @@ -21,27 +21,28 @@ Install one or both of the following (see above): - CmdMail (IC + OOC mail, sent between players) + ```python # mygame/commands/default_cmds.py from evennia.contrib.game_systems import mail # in AccountCmdSet.at_cmdset_creation: self.add(mail.CmdMail()) - + ``` - CmdMailCharacter (optional, IC only mail, sent between characters) + ```python # mygame/commands/default_cmds.py from evennia.contrib.game_systems import mail # in CharacterCmdSet.at_cmdset_creation: self.add(mail.CmdMailCharacter()) - + ``` Once installed, use `help mail` in game for help with the mail command. Use ic/ooc to switch in and out of IC/OOC modes. - ---- This document page is generated from `evennia/contrib/game_systems/mail/README.md`. Changes to this diff --git a/docs/source/Contribs/Contrib-Mapbuilder.md b/docs/source/Contribs/Contrib-Mapbuilder.md index b1cda773f4..a56ce7ff4a 100644 --- a/docs/source/Contribs/Contrib-Mapbuilder.md +++ b/docs/source/Contribs/Contrib-Mapbuilder.md @@ -52,7 +52,7 @@ references to rooms previously created is passed to the build commands. You then call the command in-game using the path to the MAP and MAP_LEGEND vars The path you provide is relative to the evennia or mygame folder. -# Installation +## Installation Use by importing and including the command in your default_cmdsets module. For example: @@ -68,14 +68,14 @@ For example: ``` -# Usage: +## Usage: mapbuilder[/switch] one - execute build instructions once without automatic exit creation. two - execute build instructions twice without automatic exit creation. -# Examples +## Examples mapbuilder world.gamemap.MAP world.maplegend.MAP_LEGEND mapbuilder evennia.contrib.grid.mapbuilder.EXAMPLE1_MAP EXAMPLE1_LEGEND @@ -86,7 +86,7 @@ Below are two examples showcasing the use of automatic exit generation and custom exit generation. Whilst located, and can be used, from this module for convenience The below example code should be in mymap.py in mygame/world. -## Example One +### Example One ```python @@ -190,7 +190,7 @@ EXAMPLE1_LEGEND = { } ``` -## Example Two +### Example Two ```python # @mapbuilder/two evennia.contrib.grid.mapbuilder.EXAMPLE2_MAP EXAMPLE2_LEGEND diff --git a/docs/source/Contribs/Contrib-Unixcommand.md b/docs/source/Contribs/Contrib-Unixcommand.md index d63ba3241d..2909847087 100644 --- a/docs/source/Contribs/Contrib-Unixcommand.md +++ b/docs/source/Contribs/Contrib-Unixcommand.md @@ -1,9 +1,9 @@ -# Unix-like Command style parent +# Unix-like Command style Contribution by Vincent Le Geoff (vlgeoff), 2017 -This module contains a command class with an alternate syntax parser implementing -Unix-style command syntax in-game. This means `--options`, positional arguments +This module contains a command class with an alternate syntax parser implementing +Unix-style command syntax in-game. This means `--options`, positional arguments and stuff like `-n 10`. It might not the best syntax for the average player but can be really useful for builders when they need to have a single command do many things with many options. It uses the `ArgumentParser` from Python's standard diff --git a/docs/source/Contribs/Contrib-Overview.md b/docs/source/Contribs/Contribs-Overview.md similarity index 92% rename from docs/source/Contribs/Contrib-Overview.md rename to docs/source/Contribs/Contribs-Overview.md index b923fc41e9..a80f9d99cb 100644 --- a/docs/source/Contribs/Contrib-Overview.md +++ b/docs/source/Contribs/Contribs-Overview.md @@ -25,6 +25,20 @@ _This category contains systems that are not necessarily tied to a specific in-game mechanic but is useful for the game as a whole. Examples include login systems, new command syntaxes, and build helpers._ +```{toctree} +:maxdepth: 1 + +Contrib-AWSStorage.md +Contrib-Building-Menu.md +Contrib-Color-Markups.md +Contrib-Custom-Gametime.md +Contrib-Email-Login.md +Contrib-Ingame-Python.md +Contrib-Menu-Login.md +Contrib-Mux-Comms-Cmds.md +Contrib-Unixcommand.md +``` + ### Contrib: `awsstorage` @@ -58,7 +72,7 @@ that will edit any default object, offering to change its key and description. _Contrib by Griatch, 2017_ Additional color markup styles for Evennia (extending or replacing the default -`|r`, `|234`). Adds support for MUSH-style (`%cr`, `%c123`) and/or legacy-Evennia +`|r`, `|234`). Adds support for MUSH-style (`%cr`, `%c123`) and/or legacy-Evennia (`{r`, `{123`). [Read the documentation](./Contrib-Color-Markups.md) - [Browse the Code](evennia.contrib.base_systems.color_markups) @@ -70,7 +84,7 @@ Additional color markup styles for Evennia (extending or replacing the default _Contrib by vlgeoff, 2017 - based on Griatch's core original_ This reimplements the `evennia.utils.gametime` module but with a _custom_ -calendar (unusual number of days per week/month/year etc) for your game world. +calendar (unusual number of days per week/month/year etc) for your game world. Like the original, it allows for scheduling events to happen at given in-game times, but now taking this custom calendar into account. @@ -83,7 +97,7 @@ in-game times, but now taking this custom calendar into account. _Contrib by Griatch, 2012_ This is a variant of the login system that asks for an email-address -instead of a username to login. Note that it does not verify the email, +instead of a username to login. Note that it does not verify the email, it just uses it as the identifier rather than a username. [Read the documentation](./Contrib-Email-Login.md) - [Browse the Code](evennia.contrib.base_systems.email_login) @@ -137,8 +151,8 @@ main `channel` command is still called under the hood. _Contribution by Vincent Le Geoff (vlgeoff), 2017_ -This module contains a command class with an alternate syntax parser implementing -Unix-style command syntax in-game. This means `--options`, positional arguments +This module contains a command class with an alternate syntax parser implementing +Unix-style command syntax in-game. This means `--options`, positional arguments and stuff like `-n 10`. It might not the best syntax for the average player but can be really useful for builders when they need to have a single command do many things with many options. It uses the `ArgumentParser` from Python's standard @@ -156,15 +170,21 @@ library under the hood. _This category contains 'complete' game engines that can be used directly to start creating content without no further additions (unless you want to)._ +```{toctree} +:maxdepth: 1 + +Contrib-Evscaperoom.md +``` + ### Contrib: `evscaperoom` _Contribution by Griatch, 2019_ -A full engine for creating multiplayer escape-rooms in Evennia. Allows players to -spawn and join puzzle rooms that track their state independently. Any number of players -can join to solve a room together. This is the engine created for 'EvscapeRoom', which won -the MUD Coders Guild "One Room" Game Jam in April-May, 2019. The contrib has no game +A full engine for creating multiplayer escape-rooms in Evennia. Allows players to +spawn and join puzzle rooms that track their state independently. Any number of players +can join to solve a room together. This is the engine created for 'EvscapeRoom', which won +the MUD Coders Guild "One Room" Game Jam in April-May, 2019. The contrib has no game content but contains the utilities and base classes and an empty example room. [Read the documentation](./Contrib-Evscaperoom.md) - [Browse the Code](evennia.contrib.full_systems.evscaperoom) @@ -181,6 +201,20 @@ crafting, mail, combat and more. Each system is meant to be adopted piecemeal and adopted for your game. This does not include roleplaying-specific systems, those are found in the `rpg` folder._ +```{toctree} +:maxdepth: 1 + +Contrib-Barter.md +Contrib-Clothing.md +Contrib-Cooldowns.md +Contrib-Crafting.md +Contrib-Gendersub.md +Contrib-Mail.md +Contrib-Multidescer.md +Contrib-Puzzles.md +Contrib-Turnbattle.md +``` + ### Contrib: `barter` @@ -214,8 +248,8 @@ look of these clothes are appended to the character's description when worn. _Contribution by owllex, 2021_ Cooldowns are used to model rate-limited actions, like how often a -character can perform a given action; until a certain time has passed their -command can not be used again. This contrib provides a simple cooldown +character can perform a given action; until a certain time has passed their +command can not be used again. This contrib provides a simple cooldown handler that can be attached to any typeclass. A cooldown is a lightweight persistent asynchronous timer that you can query to see if a certain time has yet passed. @@ -255,7 +289,7 @@ _Contribution by grungies1138 2016_ A simple Brandymail style mail system that uses the `Msg` class from Evennia Core. It has two Commands for either sending mails between Accounts (out of game) -or between Characters (in-game). The two types of mails can be used together or +or between Characters (in-game). The two types of mails can be used together or on their own. [Read the documentation](./Contrib-Mail.md) - [Browse the Code](evennia.contrib.game_systems.mail) @@ -314,6 +348,17 @@ the participants until the fight ends. _Systems related to the game world's topology and structure. This has contribs related to rooms, exits and map building._ +```{toctree} +:maxdepth: 1 + +Contrib-Extended-Room.md +Contrib-Mapbuilder.md +Contrib-Simpledoor.md +Contrib-Slow-Exit.md +Contrib-Wilderness.md +Contrib-XYZGrid.md +``` + ### Contrib: `extended_room` @@ -399,14 +444,23 @@ current location (useful for displaying the grid as an in-game, updating map). _These are systems specifically related to roleplaying and rule implementation like character traits, dice rolling and emoting._ +```{toctree} +:maxdepth: 1 + +Contrib-Dice.md +Contrib-Health-Bar.md +Contrib-RPSystem.md +Contrib-Traits.md +``` + ### Contrib: `dice` _Contribution by Griatch, 2012_ -A dice roller for any number and side of dice. Adds in-game dice rolling -(`roll 2d10 + 1`) as well as conditionals (roll under/over/equal to a target) -and functions for rolling dice in code. Command also supports hidden or secret +A dice roller for any number and side of dice. Adds in-game dice rolling +(`roll 2d10 + 1`) as well as conditionals (roll under/over/equal to a target) +and functions for rolling dice in code. Command also supports hidden or secret rolls for use by a human game master. [Read the documentation](./Contrib-Dice.md) - [Browse the Code](evennia.contrib.rpg.dice) @@ -418,8 +472,8 @@ rolls for use by a human game master. _Contribution by Tim Ashley Jenkins, 2017_ The function provided in this module lets you easily display visual -bars or meters as a colorful bar instead of just a number. A "health bar" -is merely the most obvious use for this, but the bar is highly customizable +bars or meters as a colorful bar instead of just a number. A "health bar" +is merely the most obvious use for this, but the bar is highly customizable and can be used for any sort of appropriate data besides player health. [Read the documentation](./Contrib-Health-Bar.md) - [Browse the Code](evennia.contrib.rpg.health_bar) @@ -467,6 +521,17 @@ _Helper resources specifically meant to teach a development concept or to exemplify an Evennia system. Any extra resources tied to documentation tutorials are found here. Also the home of the Tutorial World demo adventure._ +```{toctree} +:maxdepth: 1 + +Contrib-Batchprocessor.md +Contrib-Bodyfunctions.md +Contrib-Mirror.md +Contrib-Red-Button.md +Contrib-Talking-Npc.md +Contrib-Tutorial-World.md +``` + ### Contrib: `batchprocessor` @@ -547,6 +612,15 @@ is a great way to start learning the system. _Miscellaneous, optional tools for manipulating text, auditing connections and more._ +```{toctree} +:maxdepth: 1 + +Contrib-Auditing.md +Contrib-Fieldfill.md +Contrib-Random-String-Generator.md +Contrib-Tree-Select.md +``` + ### Contrib: `auditing` @@ -603,51 +677,6 @@ instance from a multi-line string passed to one function. -```{toctree} - -Contribs/Contrib-AWSStorage.md - Contribs/Contrib-Building-Menu.md - Contribs/Contrib-Color-Markups.md - Contribs/Contrib-Custom-Gametime.md - Contribs/Contrib-Email-Login.md - Contribs/Contrib-Ingame-Python.md - Contribs/Contrib-Menu-Login.md - Contribs/Contrib-Mux-Comms-Cmds.md - Contribs/Contrib-Unixcommand.md - Contribs/Contrib-Evscaperoom.md - Contribs/Contrib-Barter.md - Contribs/Contrib-Clothing.md - Contribs/Contrib-Cooldowns.md - Contribs/Contrib-Crafting.md - Contribs/Contrib-Gendersub.md - Contribs/Contrib-Mail.md - Contribs/Contrib-Multidescer.md - Contribs/Contrib-Puzzles.md - Contribs/Contrib-Turnbattle.md - Contribs/Contrib-Extended-Room.md - Contribs/Contrib-Mapbuilder.md - Contribs/Contrib-Simpledoor.md - Contribs/Contrib-Slow-Exit.md - Contribs/Contrib-Wilderness.md - Contribs/Contrib-XYZGrid.md - Contribs/Contrib-Dice.md - Contribs/Contrib-Health-Bar.md - Contribs/Contrib-RPSystem.md - Contribs/Contrib-Traits.md - Contribs/Contrib-Batchprocessor.md - Contribs/Contrib-Bodyfunctions.md - Contribs/Contrib-Mirror.md - Contribs/Contrib-Red-Button.md - Contribs/Contrib-Talking-Npc.md - Contribs/Contrib-Tutorial-World.md - Contribs/Contrib-Auditing.md - Contribs/Contrib-Fieldfill.md - Contribs/Contrib-Random-String-Generator.md - Contribs/Contrib-Tree-Select.md -``` - - - ---- diff --git a/docs/source/Contributing-Docs.md b/docs/source/Contributing-Docs.md index fea633d96c..49524a358f 100644 --- a/docs/source/Contributing-Docs.md +++ b/docs/source/Contributing-Docs.md @@ -56,19 +56,19 @@ primarily be accessed as link refs (e.g. `Component/Accounts`) the Evennia version on a new branch. -# Editing syntax +## Editing syntax The format used for Evennia's docs is [Markdown][commonmark-help] (Commonmark). While markdown supports a few alternative forms for some of these, we try to stick to the below forms for consistency. -## Italic/Bold +### Italic/Bold We generally use underscores for italics and double-asterisks for bold: - `_Italic text_` - _Italic text_ - `**Bold Text**` - **Bold text** -## Headings +### Headings We use `#` to indicate sections/headings. The more `#` the more of a sub-heading it is (will get smaller and smaller font). @@ -82,7 +82,7 @@ smaller and smaller font). does not prevent it, it will make it impossible to refer to that heading uniquely. The Evennia documentation preparser will detect this and give you an error. -## Lists +### Lists One can create both bullet-point lists and numbered lists: @@ -106,7 +106,7 @@ One can create both bullet-point lists and numbered lists: 2. Numbered point two 3. Numbered point three -## Blockquotes +### Blockquotes A blockquote will create an indented block. It's useful for emphasis and is added by starting one or more lines with `>`. For 'notes' you can also use @@ -120,11 +120,11 @@ an explicit [Note](#note). > Note: This is an important > thing to remember. -## Links +### Links The link syntax is `[linktext](url_or_ref)` - this gives a clickable link [linktext](#links). -### Internal links +#### Internal links Most links will be to other pages of the documentation or to Evennia's API docs. Each document heading can be referenced. The reference always starts with `#`. The heading-name is always @@ -156,7 +156,7 @@ Some more text... > It's fine to not include the `.md` file ending in the reference. The Evennia doc-build process > will correct for this (and also insert any needed relative paths in the reference). -### API links +#### API links The documentation contains auto-generated documentation for all of Evennia's source code. You can direct the reader to the sources by just giving the python-path to the location of the @@ -169,7 +169,7 @@ resource under the `evennia/` repository: Note that you can't refer to files in the `mygame` folder this way. The game folder is generated dynamically and is not part of the api docs. Refer to the parent classes in `evennia` where possible. -### External links +#### External links These are links to resources outside of the documentation. We also provide some convenient shortcuts. @@ -202,7 +202,7 @@ This is a [clickable link][mylink]. This is [another link][1]. This makes the main text a little shorter. -## Tables +### Tables A table is done like this: @@ -224,7 +224,7 @@ As seen, the Markdown syntax can be pretty sloppy (columns don't need to line up include the heading separators and make sure to add the correct number of `|` on every line. -## Verbatim text +### Verbatim text It's common to want to mark something to be displayed verbatim - just as written - without any Markdown parsing. In running text, this is done using backticks (\`), like \`verbatim text\` becomes @@ -330,7 +330,7 @@ evennia/ mygame/ evennia start --log -## MyST directives +### MyST directives Markdown is easy to read and use. But while it does most of what we need, there are some things it's not quite as expressive as it needs to be. For this we use extended [MyST][MyST] syntax. This is @@ -365,7 +365,7 @@ Also the important/warning notes indents like this. ``` -### Important +#### Important This is for particularly important and visible notes. @@ -379,7 +379,7 @@ This is for particularly important and visible notes. This is important because it is! ``` -### Warning +#### Warning A warning block is used to draw attention to particularly dangerous things, or features easy to mess up. @@ -394,7 +394,7 @@ mess up. Be careful about this ... ``` -### Version changes and deprecations +#### Version changes and deprecations These will show up as one-line warnings that suggest an added, changed or deprecated feature beginning with particular version. @@ -425,7 +425,7 @@ feature beginning with particular version. ```{deprecated} 1.0 ``` -### Sidebar +#### Sidebar This will display an informative sidebar that floats to the side of regular content. This is useful for example to remind the reader of some concept relevant to the text. @@ -461,7 +461,7 @@ squeezed to the left of the sidebar), one can embed a plain HTML string in the m
-### A more flexible code block +#### A more flexible code block The regular Markdown Python codeblock is usually enough but for more direct control over the style, one can also use the `{code-block}` directive that takes a set of additional `:options:`: @@ -506,7 +506,7 @@ block through the link that will appear (so it should be unique for a given docu -### eval-rst directive +#### eval-rst directive As a last resort, we can also fall back to writing [ReST][ReST] directives directly: @@ -552,7 +552,7 @@ make us able to express more complex displays than plain Markdown can. For [autodoc-generation][sphinx-autodoc] generation, we use the sphinx-[napoleon][sphinx-napoleon] extension to understand our friendly Google-style docstrings used in classes and functions etc. -# Building the docs locally +## Building the docs locally The sources in `evennia/docs/source/` are built into a documentation using the [Sphinx][sphinx] static generator system. To do this locally you need to use a @@ -713,7 +713,6 @@ After deployment finishes, the updated live documentation will be available at https://evennia.github.io/evennia/latest/. - [sphinx]: https://www.sphinx-doc.org/en/master/ [MyST]: https://myst-parser.readthedocs.io/en/latest/syntax/reference.html [commonmark]: https://spec.commonmark.org/current/ @@ -729,4 +728,4 @@ available at https://evennia.github.io/evennia/latest/. [linkdemo]: #Links [retext]: https://github.com/retext-project/retext [grip]: https://github.com/joeyespo/grip -[pycharm]: https://www.jetbrains.com/pycharm/ +[pycharm]: https://www.jetbrains.com/pycharm/ \ No newline at end of file diff --git a/docs/source/Contributing.md b/docs/source/Contributing.md index 0c2bdee532..0d83bc5c40 100644 --- a/docs/source/Contributing.md +++ b/docs/source/Contributing.md @@ -29,7 +29,7 @@ great help! we don't know about them, we can't fix them! - If you want to help edit the docs directly, [check here](./Contributing-Docs.md) on how to do it. -- If you have knowledge to share, how about writing a new [Tutorial](Howto/Howto-Overview.md)? +- If you have knowledge to share, how about writing a new [Tutorial](Howtos/Howtos-Overview.md)? ## Helping with code @@ -80,7 +80,7 @@ like [Pastebin](https://pastebin.com/) and just supply the link. ### Making an Evennia contrib -Evennia has a [contrib](Contribs/Contrib-Overview.md) directory which contains +Evennia has a [contrib](Contribs/Contribs-Overview.md) directory which contains user-shared code organized by category. You can contribute anything that you think may be useful to another dev, also highly game-specific code. A contrib must always be added via a forked respository. @@ -118,7 +118,7 @@ must always be added via a forked respository. it easier to access them (this may vary though). The `README.md` will be parsed and converted into a document linked from - [the contrib overview page](Contribs/Contrib-Overview.md). It should follow + [the contrib overview page](Contribs/Contribs-Overview.md). It should follow the following structure: ```markdown diff --git a/docs/source/Evennia-API.md b/docs/source/Evennia-API.md index 4cb829e8df..abe914ee6a 100644 --- a/docs/source/Evennia-API.md +++ b/docs/source/Evennia-API.md @@ -24,7 +24,7 @@ The flat API is defined in `__init__.py` [viewable here](github:evennia/__init__ ### Main config -- [evennia.settings_default](github:evennia/settings_default.py) - all settings (modify/override in `mygame/server/settings.py`) +- [evennia.settings_default](Settings-Default) - all settings (modify/override in `mygame/server/settings.py`) ### Search functions @@ -98,3 +98,9 @@ The flat API is defined in `__init__.py` [viewable here](github:evennia/__init__ - [evennia.contrib](https://github.com/evennia/evennia/blob/master/evennia/contrib/) - game-specific contributions and plugins ([docs](https://github.com/evennia/evennia/blob/master/evennia/contrib/README.md)) + +```{toctree} +:hidden: +api/evennia-api.md + +``` \ No newline at end of file diff --git a/docs/source/Evennia-Introduction.md b/docs/source/Evennia-Introduction.md index 76d02a5acf..3e8ab813cf 100644 --- a/docs/source/Evennia-Introduction.md +++ b/docs/source/Evennia-Introduction.md @@ -26,7 +26,7 @@ Evennia is *fully persistent*, that means things you drop on the ground somewher there a dozen server reboots later. Through Django we support a large variety of different database systems (a database is created for you automatically if you use the defaults). -We also include a growing list of *optional* [contribs](Contribs/Contrib-Overview.md) you can use for your game +We also include a growing list of *optional* [contribs](Contribs/Contribs-Overview.md) you can use for your game would you want something to build from. Using the full power of Python throughout the server offers some distinct advantages. All your @@ -49,7 +49,7 @@ connect to the demo via your telnet client you can do so at `demo.evennia.com`, Once you installed Evennia yourself it comes with its own tutorial - this shows off some of the possibilities _and_ gives you a small single-player quest to play. The tutorial takes only one -single in-game command to install as explained [here](Howto/Starting/Part1/Tutorial-World.md). +single in-game command to install as explained [here](Howtos/Beginner-Tutorial/Part1/Tutorial-World.md). ## What you need to know to work with Evennia @@ -71,8 +71,8 @@ Evennia's source code is extensively documented and is [viewable online](https://github.com/evennia/evennia). We also have a comprehensive [online manual](https://evennia.com/docs) with lots of examples. But while Python is considered a very easy programming language to get into, you do have a learning curve to climb if -you are new to programming. Evennia's [Starting-tutorial](Howto/Starting/Part1/Starting-Part1.md) has a [basic introduction -to Python](Howto/Starting/Part1/Python-basic-introduction.md) but you should probably also sit down +you are new to programming. Evennia's [Starting-tutorial](Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Part1-Intro.md) has a [basic introduction +to Python](Howtos/Beginner-Tutorial/Part1/Python-basic-introduction.md) but you should probably also sit down with a full Python beginner's tutorial at some point (there are plenty of them on the web if you look around). See also our [link page](./Links.md) for some reading suggestions. To efficiently code your dream game in @@ -111,7 +111,7 @@ presence (a website and a mud web client) to play around with ... ### Where to from here? From here you can continue browsing the [online documentation](./index.md) to -find more info about Evennia. Or you can jump into the [Tutorials](Howto/Howto-Overview.md) and get your hands +find more info about Evennia. Or you can jump into the [Tutorials](Howtos/Howtos-Overview.md) and get your hands dirty with code right away. You can also read the lead developer's [dev blog](https://evennia.blogspot.com/) for many tidbits and snippets about Evennia's development and structure. @@ -124,9 +124,9 @@ chat](https://webchat.freenode.net/?channels=evennia&uio=MT1mYWxzZSY5PXRydWUmMTE on IRC. This allows you to chat directly with other developers new and old as well as with the devs of Evennia itself. This chat is logged (you can find links on https://www.evennia.com) and can also be searched from the same place for discussion topics you are interested in. -2. Read the [Game Planning](Howto/Starting/Part2/Game-Planning.md) wiki page. It gives some ideas for your work flow and the +2. Read the [Game Planning](Howtos/Beginner-Tutorial/Part2/Game-Planning.md) wiki page. It gives some ideas for your work flow and the state of mind you should aim for - including cutting down the scope of your game for its first release. -3. Do the [Tutorial for basic MUSH-like game](Howto/Starting/Part3/Tutorial-for-basic-MUSH-like-game.md) carefully from +3. Do the [Tutorial for basic MUSH-like game](Howtos/Tutorial-for-basic-MUSH-like-game.md) carefully from beginning to end and try to understand what does what. Even if you are not interested in a MUSH for your own game, you will end up with a small (very small) game that you can build or learn from. diff --git a/docs/source/Glossary.md b/docs/source/Glossary.md index b53008d649..304733dd4f 100644 --- a/docs/source/Glossary.md +++ b/docs/source/Glossary.md @@ -100,7 +100,7 @@ There is usually no need to know the details of Django's database handling in or it will handle most of the complexity for you under the hood using what we call [typeclasses](./Glossary.md#typeclass). But should you need the power of Django you can always get it. Most commonly people want to use "raw" Django when doing more advanced/custom database queries than -offered by Evennia's [default search functions](Howto/Starting/Part1/Searching-Things.md). One will then need +offered by Evennia's [default search functions](Howtos/Beginner-Tutorial/Part1/Searching-Things.md). One will then need to read about Django's _querysets_. Querysets are Python method calls on a special form that lets you build complex queries. They get converted into optimized SQL queries under the hood, suitable for your current database. [Here is our tutorial/explanation of Django queries](Tutorial-Searching- @@ -129,7 +129,7 @@ core. Better make it a contrib. ## _contrib_ -Game-specific code and examples are distributed in evennia's [contribs/](Contribs/Contrib-Overview.md) folder. +Game-specific code and examples are distributed in evennia's [contribs/](Contribs/Contribs-Overview.md) folder. This is game-specific, optional code created by the Evennia community. ## _field_ diff --git a/docs/source/Howto/Default-Exit-Errors.md b/docs/source/Howto/Default-Exit-Errors.md deleted file mode 100644 index 81ddf7b6b6..0000000000 --- a/docs/source/Howto/Default-Exit-Errors.md +++ /dev/null @@ -1,122 +0,0 @@ -# Default Exit Errors - - -Evennia allows for exits to have any name. The command "kitchen" is a valid exit name as well as -"jump out the window" or "north". An exit actually consists of two parts: an [Exit Object](../Components/Objects.md) -and an [Exit Command](../Components/Commands.md) stored on said exit object. The command has the same key and aliases -as the object, which is why you can see the exit in the room and just write its name to traverse it. - -If you try to enter the name of a non-existing exit, it is thus the same as trying a non-exising -command; Evennia doesn't care about the difference: - - > jump out the window - Command 'jump out the window' is not available. Type "help" for help. - -Many games don't need this type of freedom however. They define only the cardinal directions as -valid exit names (Evennia's `@tunnel` command also offers this functionality). In this case, the -error starts to look less logical: - - > west - Command 'west' is not available. Maybe you meant "@set" or "@reset"? - -Since we for our particular game *know* that west is an exit direction, it would be better if the -error message just told us that we couldn't go there. - -## Adding default error commands - -To solve this you need to be aware of how to [write and add new commands](Starting/Part1/Adding-Commands.md). -What you need to do is to create new commands for all directions you want to support in your game. -In this example all we'll do is echo an error message, but you could certainly consider more -advanced uses. You add these commands to the default command set. Here is an example of such a set -of commands: - -```python -# for example in a file mygame/commands/movecommands.py - -from evennia import default_cmds - -class CmdExitError(default_cmds.MuxCommand): - "Parent class for all exit-errors." - locks = "cmd:all()" - arg_regex = r"\s|$" - auto_help = False - def func(self): - "returns the error" - self.caller.msg(f"You cannot move {self.key}.") - -class CmdExitErrorNorth(CmdExitError): - key = "north" - aliases = ["n"] - -class CmdExitErrorEast(CmdExitError): - key = "east" - aliases = ["e"] - -class CmdExitErrorSouth(CmdExitError): - key = "south" - aliases = ["s"] - -class CmdExitErrorWest(CmdExitError): - key = "west" - aliases = ["w"] -``` - -Make sure to add the directional commands (not their parent) to the `CharacterCmdSet` class in -`mygame/commands/default_cmdsets.py`: - -```python -# in mygame/commands/default_cmdsets.py - -from commands import movecommands - -# [...] -class CharacterCmdSet(default_cmds.CharacterCmdSet): - # [...] - def at_cmdset_creation(self): - # [...] - self.add(movecommands.CmdExitErrorNorth()) - self.add(movecommands.CmdExitErrorEast()) - self.add(movecommands.CmdExitErrorSouth()) - self.add(movecommands.CmdExitErrorWest()) -``` - -After a `@reload` these commands (assuming you don't get any errors - check your log) will be -loaded. What happens henceforth is that if you are in a room with an Exitobject (let's say it's -"north"), the proper Exit-command will overload your error command (also named "north"). But if you -enter an direction without having a matching exit for it, you will fallback to your default error -commands: - - > east - You cannot move east. - -Further expansions by the exit system (including manipulating the way the Exit command itself is -created) can be done by modifying the [Exit typeclass](../Components/Typeclasses.md) directly. - -## Additional Comments - -So why didn't we create a single error command above? Something like this: - -```python - class CmdExitError(default_cmds.MuxCommand): - "Handles all exit-errors." - key = "error_cmd" - aliases = ["north", "n", - "east", "e", - "south", "s", - "west", "w"] - #[...] -``` -The anwer is that this would *not* work and understanding why is important in order to not be -confused when working with commands and command sets. - -The reason it doesn't work is because Evennia's [command system](../Components/Commands.md) compares commands *both* -by `key` and by `aliases`. If *either* of those match, the two commands are considered *identical* -as far as cmdset merging system is concerned. - -So the above example would work fine as long as there were no Exits at all in the room. But what -happens when we enter a room with an exit "north"? The Exit's cmdset is merged onto the default one, -and since there is an alias match, the system determines our `CmdExitError` to be identical. It is -thus overloaded by the Exit command (which also correctly defaults to a higher priority). The result -is that you can go through the north exit normally but none of the error messages for the other -directions are available since the single error command was completely overloaded by the single -matching "north" exit-command. \ No newline at end of file diff --git a/docs/source/Howto/Howto-Overview.md b/docs/source/Howto/Howto-Overview.md deleted file mode 100644 index a944ca0b78..0000000000 --- a/docs/source/Howto/Howto-Overview.md +++ /dev/null @@ -1,105 +0,0 @@ -# Tutorials and Howto's - -The documents in this section aims to teach how to use Evennia in a tutorial or -a step-by-step way. They often give hints on about solving a problem or implementing -a particular feature or concept. They will often refer to the -[components](../Components/Components-Overview.md) or [concepts](../Concepts/Concepts-Overview.md) -docs for those that want to dive deeper. - -## The Starting Tutorial - -Recommended starting point! This will take you from absolute beginner to making -a small, but full, game with Evennia. Even if you have a very different game style -in mind for your own game, this will give you a good start. - -### Part 1: What we have - -1. [Introduction & Overview](Starting/Part1/Starting-Part1.md) -1. [Building stuff](Starting/Part1/Building-Quickstart.md) -1. [The Tutorial World](Starting/Part1/Tutorial-World.md) -1. [Python basics](Starting/Part1/Python-basic-introduction.md) -1. [Game dir overview](Starting/Part1/Gamedir-Overview.md) -1. [Python classes and objects](Starting/Part1/Python-classes-and-objects.md) -1. [Accessing the Evennia library](Starting/Part1/Evennia-Library-Overview.md) -1. [Typeclasses - Persistent objects](Starting/Part1/Learning-Typeclasses.md) -1. [Making our first own commands](Starting/Part1/Adding-Commands.md) -1. [Parsing and replacing default Commands](Starting/Part1/More-on-Commands.md) -1. [Creating things](Starting/Part1/Creating-Things.md) -1. [Searching for things](Starting/Part1/Searching-Things.md) -1. [Advanced searching with Django queries](Starting/Part1/Django-queries.md) - -### Part 2: What we want - -1. [Introduction & Overview](Starting/Part2/Starting-Part2.md) -1. [On planning a game](Starting/Part2/Game-Planning.md) -1. [Planning to use some useful Contribs](Starting/Part2/Planning-Some-Useful-Contribs.md) - -### Part3: How we get there - -1. [Introduction & Overview](Starting/Part3/Starting-Part3.md) -1. [Making a custom Character](Starting/Part3/Implementing-a-game-rule-system.md) -1. [Character generation](../Unimplemented.md) -1. [Resolving skills and challenges](../Unimplemented.md) -1. [NPCs and mobiles](./Coordinates.md) -1. [Quests and Zones](../Unimplemented.md) -1. [A Combat system](../Unimplemented.md) - -### Part 4: Using what we created - -1. [Introduction & Overview](Starting/Part4/Starting-Part4.md) -1. [Building the tech demo](../Unimplemented.md) -1. [Creating a game world](../Unimplemented.md) - -### Part 5: Showing the world - -1. [Introduction & Overview](Starting/Part5/Starting-Part5.md) -1. [Add a web page](Starting/Part5/Add-a-simple-new-web-page.md) -1. [More on adding web features](Starting/Part5/Web-Tutorial.md) -1. [Taking your game online](../Unimplemented.md) -1. [Next steps](../Unimplemented.md) - - -## FAQs - -- [Coding FAQ](./Coding-FAQ.md) - -## Howto's - -- [Giving Exits a default error](./Default-Exit-Errors.md) -- [Add a command prompt](./Command-Prompt.md) -- [Don't allow spamming commands](./Command-Cooldown.md) -- [Commands that take time](./Command-Duration.md) -- [Configuring color](./Manually-Configuring-Color.md) -- [Tweet game stats](./Tutorial-Tweeting-Game-Stats.md) - -## Mobs and NPCs - -- [NPCs that listen to you](./Tutorial-NPCs-listening.md) -- [Mobs that attack you](./Tutorial-Aggressive-NPCs.md) -- [Shopkeepers](./NPC-shop-Tutorial.md) - -## Vehicles - -- [Building a mech](./Building-a-mech-tutorial.md) -- [Building a train](./Tutorial-Vehicles.md) - -## Systems - -- [Understanding In-game time](./Gametime-Tutorial.md) -- [Understanding the Help system](./Help-System-Tutorial.md) -- [Adding mass to objects](./Mass-and-weight-for-objects.md) -- [Add weather](./Weather-Tutorial.md) - -## Web-related tutorials - -- [Add a wiki](./Add-a-wiki-on-your-website.md) -- [A web-based character generation](./Web-Character-Generation.md) -- [View Character on website](./Web-Character-View-Tutorial.md) - -## Deep-dives - -- [Parsing command inputs](./Parsing-commands-tutorial.md) -- [Understanding color-tags](./Understanding-Color-Tags.md) -- [Play paper&pen RPGs online with Evennia](./Evennia-for-roleplaying-sessions.md) -- [Evennia for Diku Users](./Evennia-for-Diku-Users.md) -- [Evennia for MUSH-Users](./Evennia-for-MUSH-Users.md) diff --git a/docs/source/Howto/Starting/Part1/Starting-Part1.md b/docs/source/Howto/Starting/Part1/Starting-Part1.md deleted file mode 100644 index 4d434091c8..0000000000 --- a/docs/source/Howto/Starting/Part1/Starting-Part1.md +++ /dev/null @@ -1,131 +0,0 @@ -# Starting Tutorial (Part 1) - -```{eval-rst} -.. sidebar:: Tutorial Parts - - **Part 1: What we have** - A tour of Evennia and how to use the tools, including an introduction to Python. - Part 2: `What we want <../Part2/Starting-Part2.html>`_ - Planning our tutorial game and what to think about when planning your own in the future. - Part 3: `How we get there <../Part3/Starting-Part3.html>`_ - Getting down to the meat of extending Evennia to make our game - Part 4: `Using what we created <../Part4/Starting-Part4.html>`_ - Building a tech-demo and world content to go with our code - Part 5: `Showing the world <../Part5/Starting-Part5.html>`_ - Taking our new game online and let players try it out - -``` - -Welcome to Evennia! This multi-part Tutorial will help you get off the ground. It consists -of five parts, each with several lessons. You can pick what seems interesting, but if you -follow through to the end you will have created a little online game of your own to play -and share with others! - -## Lessons of Part 1 - "What we have" - -1. Introduction (you are here) -1. [Building stuff](./Building-Quickstart.md) -1. [The Tutorial World](./Tutorial-World.md) -1. [Python basics](./Python-basic-introduction.md) -1. [Game dir overview](./Gamedir-Overview.md) -1. [Python classes and objects](./Python-classes-and-objects.md) -1. [Accessing the Evennia library](./Evennia-Library-Overview.md) -1. [Typeclasses and Persistent objects](./Learning-Typeclasses.md) -1. [Making first own Commands](./Adding-Commands.md) -1. [Parsing and replacing default Commands](./More-on-Commands.md) -1. [Creating things](./Creating-Things.md) -1. [Searching for things](./Searching-Things.md) -1. [Advanced searching with Django queries](./Django-queries.md) - -In this first part we'll focus on what we get out of the box in Evennia - we'll get used to the tools, -and how to find things we are looking for. We will also dive into some of things you'll -need to know to fully utilize the system, including giving you a brief rundown of Python concepts. If you are -an experienced Python programmer, some sections may feel a bit basic, but you will at least not have seen -these concepts in the context of Evennia before. - -## Things you will need - -### A Command line - -First of all, you need to know how to find your Terminal/Console in your OS. The Evennia server can be controlled -from in-game, but you _will_ need to use the command-line to get anywhere. Here are some starters: - -- [Django-girls' Intro to the Command line for different OS:es](https://tutorial.djangogirls.org/en/intro_to_command_line/) - -> Note that we only use forward-slashes `/` to show file system paths in this documentation. Windows users need -> to convert this to back-slashes `\` in their heads. - -### A MUD client - -You might already have a MUD-client you prefer. Check out the [grid of supported clients](../../../Setup/Client-Support-Grid.md) for aid. -If telnet's not your thing, you can also just use Evennia's web client in your browser. - -> In this documentation we often use 'MUD' and 'MU' or 'MU*' interchangeably - as labels to represent all the historically different forms of text-based multiplayer game-styles, - like MUD, MUX, MUSH, MUCK, MOO and others. Evennia can be used to create all those game-styles - and more. - -### An Editor -You need a text-editor to edit Python source files. Most everything that can edit and output raw -text works (so not Word). - -- [Here's a blog post summing up some of the alternatives](https://www.elegantthemes.com/blog/resources/best-code-editors) - these -things don't change much from year to year. Popular choices for Python are PyCharm, VSCode, Atom, Sublime Text and Notepad++. - Evennia is to a very large degree coded in VIM, but that's not suitable for beginners. - -> Hint: When setting up your editor, make sure that pressing TAB inserts _4 spaces_ rather than a Tab-character. Since -> Python is whitespace-aware, this will make your life a lot easier. - - -### Set up a game dir for the tutorial - -Next you should make sure you have [installed Evennia](../../../Setup/Installation.md). If you followed the instructions -you will already have created a game-dir. You could use that for this tutorial or you may want to do the -tutorial in its own, isolated game dir; it's up to you. - -- If you want a new gamedir for the tutorial game and already have Evennia running with another gamedir, -first enter that gamedir and run - - evennia stop - -> If you want to run two parallel servers, that'd be fine too, but one would have to use -> different ports from the defaults, or there'd be a clash. We will go into changing settings later. -- Now go to where you want to create your tutorial-game. We will always refer to it as `mygame` so - it may be convenient if you do too: - - evennia --init mygame - cd mygame - evennia migrate - evennia start --log - - Add your superuser name and password at the prompt (email is optional). Make sure you can - go to `localhost:4000` in your MUD client or to [http://localhost:4001](http://localhost:4001) - in your web browser (Mac users: Try `127.0.0.1` instead of `localhost` if you have trouble). - - The above `--log` flag will have Evennia output all its logs to the terminal. This will block - the terminal from other input. To leave the log-view, press `Ctrl-C` (`Cmd-C` on Mac). To see - the log again just run - - evennia --log - - You should now be good to go! - - -```{toctree} -:hidden: - -Building-Quickstart -Tutorial-World-Introduction -Python-basic-introduction -Gamedir-Overview -Python-classes-and-objects -Evennia-Library-Overview -Learning-Typeclasses -Adding-Commands -More-on-Commands -Creating-Things -Searching-Things -Django-queries -../Part2/Starting-Part2 - -``` diff --git a/docs/source/Howto/Starting/Part2/Starting-Part2.md b/docs/source/Howto/Starting/Part2/Starting-Part2.md deleted file mode 100644 index f31330ef24..0000000000 --- a/docs/source/Howto/Starting/Part2/Starting-Part2.md +++ /dev/null @@ -1,41 +0,0 @@ -# Evennia Starting Tutorial (Part 2) - -```{eval-rst} -.. sidebar:: Tutorial Parts - - Part 1: `What we have <../Part1/Starting-Part1.html>`_ - A tour of Evennia and how to use the tools, including an introduction to Python. - **Part 2: What we want** - Planning our tutorial game and what to think about when planning your own in the future. - Part 3: `How we get there <../Part3/Starting-Part3.html>`_ - Getting down to the meat of extending Evennia to make our game - Part 4: `Using what we created <../Part4/Starting-Part4.html>`_ - Building a tech-demo and world content to go with our code - Part 5: `Showing the world <../Part5/Starting-Part5.html>`_ - Taking our new game online and let players try it out -``` - -## Lessons for Part 2 - -In Part two of the Starting tutorial we'll step back and plan out the kind of tutorial -game we want to make. This is a more 'theoretical' part where we won't do any hands-on -programming. - -1. Introduction & Overview (you are here) -1. [Where do I begin](./Planning-Where-Do-I-Begin.md) -1. [On planning a game](./Game-Planning.md) -1. [Planning to use some useful Contribs](./Planning-Some-Useful-Contribs.md) - -In the process we'll go through the common questions of "where to start" -and "what to think about" when creating a multiplayer online text game. - - -```{toctree} -:hidden: - -Planning-Where-Do-I-Begin -Game-Planning -Planning-Some-Useful-Contribs -../Part3/Starting-Part3 - -``` diff --git a/docs/source/Howto/Add-a-wiki-on-your-website.md b/docs/source/Howtos/Add-a-wiki-on-your-website.md similarity index 98% rename from docs/source/Howto/Add-a-wiki-on-your-website.md rename to docs/source/Howtos/Add-a-wiki-on-your-website.md index b9d7c75169..47e680137e 100644 --- a/docs/source/Howto/Add-a-wiki-on-your-website.md +++ b/docs/source/Howtos/Add-a-wiki-on-your-website.md @@ -2,7 +2,7 @@ **Before doing this tutorial you will probably want to read the intro in -[Basic Web tutorial](Starting/Part5/Web-Tutorial.md).** Reading the three first parts of the +[Basic Web tutorial](Beginner-Tutorial/Part5/Web-Tutorial.md).** Reading the three first parts of the [Django tutorial](https://docs.djangoproject.com/en/1.9/intro/tutorial01/) might help as well. This tutorial will provide a step-by-step process to installing a wiki on your website. diff --git a/docs/source/Contribs/Arxcode-Installation.md b/docs/source/Howtos/Arxcode-Installation.md similarity index 99% rename from docs/source/Contribs/Arxcode-Installation.md rename to docs/source/Howtos/Arxcode-Installation.md index 3d6cbe66a7..24ec39c62c 100644 --- a/docs/source/Contribs/Arxcode-Installation.md +++ b/docs/source/Howtos/Arxcode-Installation.md @@ -54,7 +54,7 @@ A new folder `myarx` should appear next to the ones you already had. You could r something else if you want. `cd` into `myarx`. If you wonder about the structure of the game dir, you can -[read more about it here](../Howto/Starting/Part1/Gamedir-Overview.md). +[read more about it here](Beginner-Tutorial/Part1/Gamedir-Overview.md). ### Clean up settings diff --git a/docs/source/Howtos/Beginner-Tutorial/Beginner-Tutorial-Intro.md b/docs/source/Howtos/Beginner-Tutorial/Beginner-Tutorial-Intro.md new file mode 100644 index 0000000000..3cd7a5ea70 --- /dev/null +++ b/docs/source/Howtos/Beginner-Tutorial/Beginner-Tutorial-Intro.md @@ -0,0 +1,116 @@ +# Beginner Tutorial + +```{eval-rst} +.. sidebar:: Tutorial Parts + + **Introduction** + Getting set up. + Part 1: `What we have `_ + A tour of Evennia and how to use the tools, including an introduction to Python. + Part 2: `What we want `_ + Planning our tutorial game and what to think about when planning your own in the future. + Part 3: `How we get there `_ + Getting down to the meat of extending Evennia to make our game + Part 4: `Using what we created `_ + Building a tech-demo and world content to go with our code + Part 5: `Showing the world `_ + Taking our new game online and let players try it out + +``` +Welcome to Evennia! This multi-part Beginner Tutorial will help you get off the ground. It consists +of five parts, each with several lessons. You can pick what seems interesting, but if you +follow through to the end you will have created a little online game of your own to play +and share with others! + +Use the menu on the right to get the index of each tutorial-part. Use the [next](Part1/Beginner-Tutorial-Part1-Intro.md) +and [previous](../Howtos-Overview.md) links to step from lesson to lesson. + +## Things you need + +- A Command line +- A MUD client (or web browser) +- A text-editor/IDE +- Evennia installed and a game-dir initialized + +### A Command line + +You need to know how to find your Terminal/Console in your OS. The Evennia server can be controlled +from in-game, but you _will_ need to use the command-line to get anywhere. Here are some starters: + +- [Django-girls' Intro to the Command line for different OS:es](https://tutorial.djangogirls.org/en/intro_to_command_line/) + +Note that we usually only show forward-slashes `/` for file system paths. Windows users should mentally convert this to +back-slashes `\` instead. + +### A MUD client + +You might already have a MUD-client you prefer. Check out the [grid of supported clients](../../Setup/Client-Support-Grid.md) for aid. +If telnet's not your thing, you can also just use Evennia's web client in your browser. + +> In this documentation we often use the terms 'MUD', 'MU' or 'MU*' interchangeably +to represent all the historically different forms of text-based multiplayer game-styles, +like MUD, MUX, MUSH, MUCK, MOO and others. Evennia can be used to create all those game-styles +and more. + +### An Editor +You need a text-editor to edit Python source files. Most everything that can edit and output raw +text works (so not Word). + +- [Here's a blog post summing up some of the alternatives](https://www.elegantthemes.com/blog/resources/best-code-editors) - these + things don't change much from year to year. Popular choices for Python are PyCharm, VSCode, Atom, Sublime Text and Notepad++. + Evennia is to a very large degree coded in VIM, but that's not suitable for beginners. + +> Hint: When setting up your editor, make sure that pressing TAB inserts _4 spaces_ rather than a Tab-character. Since +> Python is whitespace-aware, this will make your life a lot easier. + + +### Set up a game dir for the tutorial + +Next you should make sure you have [installed Evennia](../../Setup/Installation.md). If you followed the instructions +you will already have created a game-dir. You could use that for this tutorial or you may want to do the +tutorial in its own, isolated game dir; it's up to you. + +- If you want a new gamedir for the tutorial game and already have Evennia running with another gamedir, + first enter that gamedir and run + + evennia stop + +> If you want to run two parallel servers, that'd be fine too, but one would have to use +> different ports from the defaults, or there'd be a clash. We will go into changing settings later. +- Now go to where you want to create your tutorial-game. We will always refer to it as `mygame` so + it may be convenient if you do too: + + evennia --init mygame + cd mygame + evennia migrate + evennia start --log + + Add your superuser name and password at the prompt (email is optional). Make sure you can + go to `localhost:4000` in your MUD client or to [http://localhost:4001](http://localhost:4001) + in your web browser (Mac users: Try `127.0.0.1` instead of `localhost` if you have trouble). + + The above `--log` flag will have Evennia output all its logs to the terminal. This will block + the terminal from other input. To leave the log-view, press `Ctrl-C` (`Cmd-C` on Mac). To see + the log again just run + + evennia --log + +You should now be good to go on to [the first part of the tutorial](Part1/Beginner-Tutorial-Part1-Intro.md). +Good luck! + +
+ +Click here to expand a list of all Beginner-Tutorial sections (all parts). + + +```{toctree} + +Part1/Beginner-Tutorial-Part1-Intro +Part2/Beginner-Tutorial-Part2-Intro +Part3/Beginner-Tutorial-Part3-Intro +Part4/Beginner-Tutorial-Part4-Intro +Part5/Beginner-Tutorial-Part5-Intro + +``` + +
\ No newline at end of file diff --git a/docs/source/Howto/Starting/Part1/Adding-Commands.md b/docs/source/Howtos/Beginner-Tutorial/Part1/Adding-Commands.md similarity index 99% rename from docs/source/Howto/Starting/Part1/Adding-Commands.md rename to docs/source/Howtos/Beginner-Tutorial/Part1/Adding-Commands.md index 1701208210..dbd7c88d3b 100644 --- a/docs/source/Howto/Starting/Part1/Adding-Commands.md +++ b/docs/source/Howtos/Beginner-Tutorial/Part1/Adding-Commands.md @@ -1,4 +1,4 @@ -# Our own commands +# Adding custom commands In this lesson we'll learn how to create our own Evennia _Commands_. If you are new to Python you'll also learn some more basics about how to manipulate strings and get information out of Evennia. diff --git a/docs/source/Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Part1-Intro.md b/docs/source/Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Part1-Intro.md new file mode 100644 index 0000000000..483b35d92b --- /dev/null +++ b/docs/source/Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Part1-Intro.md @@ -0,0 +1,66 @@ +# Part 1: What we have + +```{eval-rst} +.. sidebar:: Beginner Tutorial Parts + + `Introduction <../Beginner-Tutorial-Intro.html>`_ + Getting set up. + **Part 1: What we have** + A tour of Evennia and how to use the tools, including an introduction to Python. + Part 2: `What we want <../Part2/Beginner-Tutorial-Part2-Intro.html>`_ + Planning our tutorial game and what to think about when planning your own in the future. + Part 3: `How we get there <../Part3/Beginner-Tutorial-Part3-Intro.html>`_ + Getting down to the meat of extending Evennia to make our game + Part 4: `Using what we created <../Part4/Beginner-Tutorial-Part4-Intro.html>`_ + Building a tech-demo and world content to go with our code + Part 5: `Showing the world <../Part5/Beginner-Tutorial-Part5-Intro.html>`_ + Taking our new game online and let players try it out + +``` + +In this first part we'll focus on what we get out of the box in Evennia - we'll get used to the tools, +and how to find things we are looking for. We will also dive into some of things you'll +need to know to fully utilize the system, including giving you a brief rundown of Python concepts. If you are +an experienced Python programmer, some sections may feel a bit basic, but you will at least not have seen +these concepts in the context of Evennia before. + +## Lessons + +```{toctree} +:maxdepth: 1 +:numbered: + +Building-Quickstart +Tutorial-World +Python-basic-introduction +Gamedir-Overview +Python-classes-and-objects +Evennia-Library-Overview +Learning-Typeclasses +Adding-Commands +More-on-Commands +Creating-Things +Searching-Things +Django-queries + +``` + +## Table of Contents + +```{toctree} +:maxdepth: 2 + +Building-Quickstart +Tutorial-World +Python-basic-introduction +Gamedir-Overview +Python-classes-and-objects +Evennia-Library-Overview +Learning-Typeclasses +Adding-Commands +More-on-Commands +Creating-Things +Searching-Things +Django-queries + +``` diff --git a/docs/source/Howto/Starting/Part1/Building-Quickstart.md b/docs/source/Howtos/Beginner-Tutorial/Part1/Building-Quickstart.md similarity index 97% rename from docs/source/Howto/Starting/Part1/Building-Quickstart.md rename to docs/source/Howtos/Beginner-Tutorial/Part1/Building-Quickstart.md index 000bc7d3d6..3407ece825 100644 --- a/docs/source/Howto/Starting/Part1/Building-Quickstart.md +++ b/docs/source/Howtos/Beginner-Tutorial/Part1/Building-Quickstart.md @@ -1,4 +1,4 @@ -# Using the game and building stuff +# Using commands and building stuff In this lesson we will test out what we can do in-game out-of-the-box. Evennia ships with [around 90 default commands](../../../Components/Default-Commands.md), and while you can override those as you please, @@ -82,10 +82,9 @@ This created a new 'box' (of the default object type) in your inventory. Use the name box = very large box;box;very;crate ```{warning} MUD clients and semi-colon - - Some traditional MUD clients use the semi-colon `;` to separate client inputs. If so, - the above line will give an error. You need to change your client to use another command-separator - or to put it in 'verbatim' mode. If you still have trouble, use the Evennia web client instead. +Some traditional MUD clients use the semi-colon `;` to separate client inputs. If so, +the above line will give an error. You need to change your client to use another command-separator +or to put it in 'verbatim' mode. If you still have trouble, use the Evennia web client instead. ``` @@ -309,4 +308,4 @@ You will now find your new `History` entry in the `help` list and read your help ## Adding a World After this brief introduction to building and using in-game commands you may be ready to see a more fleshed-out -example. Evennia comes with a tutorial world for you to explore. We will try that out in the next section. +example. Evennia comes with a tutorial world for you to explore. We will try that out in the next lesson. diff --git a/docs/source/Howto/Starting/Part1/Creating-Things.md b/docs/source/Howtos/Beginner-Tutorial/Part1/Creating-Things.md similarity index 99% rename from docs/source/Howto/Starting/Part1/Creating-Things.md rename to docs/source/Howtos/Beginner-Tutorial/Part1/Creating-Things.md index 8e55296e8f..f8a1260724 100644 --- a/docs/source/Howto/Starting/Part1/Creating-Things.md +++ b/docs/source/Howtos/Beginner-Tutorial/Part1/Creating-Things.md @@ -1,6 +1,5 @@ # Creating things - We have already created some things - dragons for example. There are many different things to create in Evennia though. In the last lesson we learned about typeclasses, the way to make objects persistent in the database. diff --git a/docs/source/Howto/Starting/Part1/Django-queries.md b/docs/source/Howtos/Beginner-Tutorial/Part1/Django-queries.md similarity index 99% rename from docs/source/Howto/Starting/Part1/Django-queries.md rename to docs/source/Howtos/Beginner-Tutorial/Part1/Django-queries.md index 9d5586496a..4378aedccd 100644 --- a/docs/source/Howto/Starting/Part1/Django-queries.md +++ b/docs/source/Howtos/Beginner-Tutorial/Part1/Django-queries.md @@ -1,4 +1,4 @@ -# Django Database queries +# Advanced searching - Django Database queries ```{important} More advanced lesson! diff --git a/docs/source/Howto/Starting/Part1/Evennia-Library-Overview.md b/docs/source/Howtos/Beginner-Tutorial/Part1/Evennia-Library-Overview.md similarity index 96% rename from docs/source/Howto/Starting/Part1/Evennia-Library-Overview.md rename to docs/source/Howtos/Beginner-Tutorial/Part1/Evennia-Library-Overview.md index 3a2dd11252..0122a8bf64 100644 --- a/docs/source/Howto/Starting/Part1/Evennia-Library-Overview.md +++ b/docs/source/Howtos/Beginner-Tutorial/Part1/Evennia-Library-Overview.md @@ -51,11 +51,11 @@ This the the structure of the Evennia library: - evennia - [`__init__.py`](../../../Evennia-API.md#shortcuts) - The "flat API" of Evennia resides here. - - [`settings_default.py`](../../../Setup/Server-Conf.md#settings-file) - Root settings of Evennia. Copy settings + - [`settings_default.py`](../../../Setup/Settings.md#settings-file) - Root settings of Evennia. Copy settings from here to `mygame/server/settings.py` file. - [`commands/`](../../../Components/Commands.md) - The command parser and handler. - `default/` - The [default commands](../../../Components/Default-Commands.md) and cmdsets. - - [`comms/`](../../../Components/Communications.md) - Systems for communicating in-game. + - [`comms/`](../../../Components/Channels.md) - Systems for communicating in-game. - `contrib/` - Optional plugins too game-specific for core Evennia. - `game_template/` - Copied to become the "game directory" when using `evennia --init`. - [`help/`](../../../Components/Help-System.md) - Handles the storage and creation of help entries. diff --git a/docs/source/Howto/Starting/Part1/Gamedir-Overview.md b/docs/source/Howtos/Beginner-Tutorial/Part1/Gamedir-Overview.md similarity index 100% rename from docs/source/Howto/Starting/Part1/Gamedir-Overview.md rename to docs/source/Howtos/Beginner-Tutorial/Part1/Gamedir-Overview.md diff --git a/docs/source/Howto/Starting/Part1/Learning-Typeclasses.md b/docs/source/Howtos/Beginner-Tutorial/Part1/Learning-Typeclasses.md similarity index 99% rename from docs/source/Howto/Starting/Part1/Learning-Typeclasses.md rename to docs/source/Howtos/Beginner-Tutorial/Part1/Learning-Typeclasses.md index ef2320010f..ec48e49845 100644 --- a/docs/source/Howto/Starting/Part1/Learning-Typeclasses.md +++ b/docs/source/Howtos/Beginner-Tutorial/Part1/Learning-Typeclasses.md @@ -1,4 +1,4 @@ -# Persistent objects and typeclasses +# Making objects persistent Now that we have learned a little about how to find things in the Evennia library, let's use it. diff --git a/docs/source/Howto/Starting/Part1/More-on-Commands.md b/docs/source/Howtos/Beginner-Tutorial/Part1/More-on-Commands.md similarity index 99% rename from docs/source/Howto/Starting/Part1/More-on-Commands.md rename to docs/source/Howtos/Beginner-Tutorial/Part1/More-on-Commands.md index 6997d5993c..92b8f00f4b 100644 --- a/docs/source/Howto/Starting/Part1/More-on-Commands.md +++ b/docs/source/Howtos/Beginner-Tutorial/Part1/More-on-Commands.md @@ -1,4 +1,4 @@ -# More about Commands +# Parsing Command input In this lesson we learn some basics about parsing the input of Commands. We will also learn how to add, modify and extend Evennia's default commands. diff --git a/docs/source/Howto/Starting/Part1/Python-basic-introduction.md b/docs/source/Howtos/Beginner-Tutorial/Part1/Python-basic-introduction.md similarity index 91% rename from docs/source/Howto/Starting/Part1/Python-basic-introduction.md rename to docs/source/Howtos/Beginner-Tutorial/Part1/Python-basic-introduction.md index f2718cd252..ff504769de 100644 --- a/docs/source/Howto/Starting/Part1/Python-basic-introduction.md +++ b/docs/source/Howtos/Beginner-Tutorial/Part1/Python-basic-introduction.md @@ -1,4 +1,4 @@ -# Starting to code Evennia +# Intro to using Python with Evennia Time to dip our toe into some coding! Evennia is written and extended in [Python](https://python.org), which is a mature and professional programming language that is very fast to work with. @@ -16,7 +16,6 @@ superuser powers back: unquell - ## Evennia Hello world The `py` Command (or `!`, which is an alias) allows you as a superuser to execute raw Python from in- @@ -27,8 +26,8 @@ game. This is useful for quick testing. From the game's input line, enter the fo ```{sidebar} Command input - The line with `>` indicates input to enter in-game, while the lines below are the - expected return from that input. +The line with `>` indicates input to enter in-game, while the lines below are the +expected return from that input. ``` You will see @@ -65,6 +64,8 @@ A string multiplied with a number will repeat that string as many times: > py print("A" + "a" * 5 + "rgh!") Aaaaaargh! +### .format() + While combining different strings is useful, even more powerful is the ability to modify the contents of the string in-place. There are several ways to do this in Python and we'll show two of them here. The first is to use the `.format` _method_ of the string: @@ -114,11 +115,10 @@ To separate two Python instructions on the same line, you use the semi-colon, `; ```{warning} MUD clients and semi-colon - Some MUD clients use the semi-colon `;` to split client-inputs - into separate sends. If so, the above will give an error. Most clients allow you to - run in 'verbatim' mode or to remap to use some other separator than `;`. If you still have - trouble, just use the Evennia web client for now. In real Python code you'll pretty much never use - the semi-colon. +Some MUD clients use the semi-colon `;` to split client-inputs +into separate sends. If so, the above will give an error. Most clients allow you to +run in 'verbatim' mode or to remap to use some other separator than `;`. If you still have +trouble, use the Evennia web client. ``` What happened here was that we _assigned_ the string `"awesome sauce"` to a _variable_ we chose @@ -129,12 +129,14 @@ instead. Here's the stat-example again, moving the stats to variables (here we just set them, but in a real game they may be changed over time, or modified by circumstance): - > py stren, dex, intel = 13, 14, 8 ; print("STR: {}, DEX: {dex}, INT: {}".format(stren, dex, intel)) + > py stren, dext, intel = 13, 14, 8 ; print("STR: {}, DEX: {}, INT: {}".format(stren, dext, intel)) STR: 13, DEX: 14, INT: 8 The point is that even if the values of the stats change, the print() statement would not change - it just keeps pretty-printing whatever is given to it. +### f-strings + Using `.format()` is convenient (and there is a [lot more](https://www.w3schools.com/python/ref_string_format.asp) you can do with it). But the _f-string_ can be even more convenient. An f-string looks like a normal string ... except there is an `f` front of it, like this: @@ -149,12 +151,14 @@ An f-string on its own is just like any other string. But let's redo the example We could just insert that `a` variable directly into the f-string using `{a}`. Fewer parentheses to remember and arguable easier to read as well. - > py stren, dex, intel = 13, 14, 8 ; print(f"STR: {stren}, DEX: {dex}, INT: {intel}") + > py stren, dext, intel = 13, 14, 8 ; print(f"STR: {stren}, DEX: {dext}, INT: {intel}") STR: 13, DEX: 14, INT: 8 We will be exploring more complex string concepts when we get to creating Commands and need to parse and understand player input. +### Colored text + Python itself knows nothing about colored text, this is an Evennia thing. Evennia supports the standard color schemes of traditional MUDs. @@ -163,7 +167,7 @@ standard color schemes of traditional MUDs. Adding that `|r` at the start will turn our output bright red. `|R` will make it dark red. `|n` gives the normal text color. You can also use RGB (Red-Green-Blue) values from 0-5 (Xterm256 colors): - > py print("|043This is a blue-green color.|[530|003 This is dark blue text on orange background.") + > py print("|043This is a blue-green color.|[530|003 Now dark blue text on orange background.") > If you don't see the expected color, your client or terminal may not support Xterm256 (or color at all). Use the Evennia webclient. @@ -194,10 +198,9 @@ print("Hello World!") ```{sidebar} Python module - This is a text file with the `.py` file ending. A module - contains Python source code and from within Python one can - access its contents by importing it via its python-path. - +This is a text file with the `.py` file ending. A module +contains Python source code and from within Python one can +access its contents by importing it via its python-path. ``` Don't forget to _save_ the file. We just created our first Python _module_! @@ -358,10 +361,10 @@ NameError: name 'me' is not defined ```{sidebar} Errors in the logs - In regular use, tracebacks will often appear in the log rather than - in the game. Use `evennia --log` to view the log in the terminal. Make - sure to scroll back if you expect an error and don't see it. Use - `Ctrl-C` (or `Cmd-C` on Mac) to exit the log-view. +In regular use, tracebacks will often appear in the log rather than +in the game. Use `evennia --log` to view the log in the terminal. Make +sure to scroll back if you expect an error and don't see it. Use +`Ctrl-C` (or `Cmd-C` on Mac) to exit the log-view. ``` @@ -434,9 +437,9 @@ On the game command-line, let's create a mirror: ```{sidebar} Creating objects - The `create` command was first used to create boxes in the - `Building Stuff `_ tutorial. Note how it - uses a "python-path" to describe where to load the mirror's code from. +The `create` command was first used to create boxes in the +`Building Stuff `_ tutorial. Note how it +uses a "python-path" to describe where to load the mirror's code from. ``` A mirror should appear in your location. @@ -469,10 +472,10 @@ as the `me` object is. If it can't find anything you'll see an error. ```{sidebar} Function returns - Whereas a function like `print` only prints its arguments, it's very common - for functions/methods to `return` a result of some kind. Think of the function - as a machine - you put something in and out comes a result you can use. In the case - of `me.search`, it will perform a database search and spit out the object it finds. +Whereas a function like `print` only prints its arguments, it's very common +for functions/methods to `return` a result of some kind. Think of the function +as a machine - you put something in and out comes a result you can use. In the case +of `me.search`, it will perform a database search and spit out the object it finds. ``` > py me.search("dummy") @@ -527,10 +530,10 @@ the `>>>`). For brevity in this tutorual we'll turn the echo off. First exit `py ```{sidebar} interactive py - - Start with `py`. - - Use `py/noecho` if you don't want your input to be echoed for every line. - - All your inputs will now be interpreted as Python code. - - Exit with `quit()`. +- Start with `py`. +- Use `py/noecho` if you don't want your input to be echoed for every line. +- All your inputs will now be interpreted as Python code. +- Exit with `quit()`. ``` We can now enter multi-line Python code: @@ -633,13 +636,13 @@ As for the normal python interpreter, use `Ctrl-D`/`Cmd-D` or `quit()` to exit i ```{important} Persistent code - Common for both `py` and `python`/`ipython` is that the code you write is not persistent - it will - be gone after you shut down the interpreter (but ipython will remember your input history). For making long-lasting - Python code, we need to save it in a Python module, like we did for `world/test.py`. +Common for both `py` and `python`/`ipython` is that the code you write is not persistent - it will +be gone after you shut down the interpreter (but ipython will remember your input history). For making long-lasting +Python code, we need to save it in a Python module, like we did for `world/test.py`. ``` -# Conclusions +## Conclusions This covers quite a lot of basic Python usage. We printed and formatted strings, defined our own first function, fixed an error and even searched and talked to a mirror! Being able to access @@ -647,5 +650,4 @@ python inside and outside of the game is an important skill for testing and debu practice you will be writing most your code in Python modules. To that end we also created a first new Python module in the `mygame/` game dir, then imported and used it. -Now let's look at the rest of the stuff you've got going on inside that `mygame/` folder ... - +Now let's look at the rest of the stuff you've got going on inside that `mygame/` folder ... \ No newline at end of file diff --git a/docs/source/Howto/Starting/Part1/Python-classes-and-objects.md b/docs/source/Howtos/Beginner-Tutorial/Part1/Python-classes-and-objects.md similarity index 99% rename from docs/source/Howto/Starting/Part1/Python-classes-and-objects.md rename to docs/source/Howtos/Beginner-Tutorial/Part1/Python-classes-and-objects.md index 8803d6fc8c..55e21357e7 100644 --- a/docs/source/Howto/Starting/Part1/Python-classes-and-objects.md +++ b/docs/source/Howtos/Beginner-Tutorial/Part1/Python-classes-and-objects.md @@ -1,4 +1,4 @@ -# Python Classes and objects +# Introduction to Python classes and objects We have now learned how to run some simple Python code from inside (and outside) your game server. We have also taken a look at what our game dir looks and what is where. Now we'll start to use it. diff --git a/docs/source/Howto/Starting/Part1/Searching-Things.md b/docs/source/Howtos/Beginner-Tutorial/Part1/Searching-Things.md similarity index 100% rename from docs/source/Howto/Starting/Part1/Searching-Things.md rename to docs/source/Howtos/Beginner-Tutorial/Part1/Searching-Things.md diff --git a/docs/source/Howto/Starting/Part1/Tutorial-World.md b/docs/source/Howtos/Beginner-Tutorial/Part1/Tutorial-World.md similarity index 71% rename from docs/source/Howto/Starting/Part1/Tutorial-World.md rename to docs/source/Howtos/Beginner-Tutorial/Part1/Tutorial-World.md index d406766bd5..a4a2ed209f 100644 --- a/docs/source/Howto/Starting/Part1/Tutorial-World.md +++ b/docs/source/Howtos/Beginner-Tutorial/Part1/Tutorial-World.md @@ -11,15 +11,23 @@ Stand in the Limbo room and install it with What this does is to run the build script [evennia/contrib/tutorial_world/build.ev](github:evennia/contrib/tutorial_world/build.ev). This is pretty much just a list of build-commands executed in sequence by the `batchcommand` command. -Wait for the building to complete and don't run it twice. A new exit should have appeared named _Tutorial_. +Wait for the building to complete and don't run it twice. + +> After having run the batchcommand, the `intro` command also becomes available in Limbo. Try it out to +> for in-game help and to get an example of [EvMenu](../../../Components/EvMenu.md), Evennia's in-built +> menu generation system! The game consists of a single-player quest and has some 20 rooms that you can explore as you seek -to discover the whereabouts of a mythical weapon. Make sure you don't play as superuser: +to discover the whereabouts of a mythical weapon. - quell +A new exit should have appeared named _Tutorial_. Enter by writing `tutorial`. -Enter the new exit by writing `tutorial`. Enjoy! If you succeed you will eventually -end up back in Limbo. +You will automatically `quell` when you enter (and `unquell` when you leave), so you can play the way it was intended. +Both if you are triumphant or if you use the `give up` command you will eventually end up back in Limbo. + +```{important} +Only LOSERS and QUITTERS use the `give up` command. +``` ## Gameplay @@ -34,26 +42,27 @@ this is a chance to adventure that you cannot turn down!* face you stand where the moor meets the sea along a high, rocky coast ...* --- -### Hints: -- Look at everything. While a demo, this is not necessarily trivial, depending on your experience with -text-based adventure games. Just remember that everything can be solved or bypassed. -- Some things cannot be damaged by mortal weapons. In that case it's OK to run away. Expect - to be chased though. +### Gameplay hints + +- Use the command `tutorial` to get code insight behind the scenes of every room. +- Look at everything. While a demo, the Tutorial World is not necessarily trivial to solve - it depends +on your experience with text-based adventure games. Just remember that everything can be solved or bypassed. - Some objects are interactive in more than one way. Use the normal `help` command to get a feel for which commands are available at any given time. -- Use the command `tutorial` to get insight behind the scenes of the game. - In order to fight, you need to first find some type of weapon. - *slash* is a normal attack - *stab* launches an attack that makes more damage but has a lower chance to hit. - *defend* will lower the chance to taking damage on your enemy's next attack. +- Some things _cannot_ be hurt by mundane weapons. In that case it's OK to run away. Expect + to be chased though. - Being defeated is a part of the experience. You can't actually die, but getting knocked out means being left in the dark ... ## Once you are done (or had enough) Afterwards you'll either have conquered the old ruin and returned in glory and triumph ... or -you returned limping and whimpering from the challenge through `telport limbo`. +you returned limping and whimpering from the challenge by using the `give up` command. Either way you should now be back in Limbo, able to reflect on the experience. Some features exemplified by the tutorial world: @@ -74,17 +83,16 @@ Some features exemplified by the tutorial world: ```{sidebar} Extra Credit - If you have previous programming experience (or after you have gone - through this Starter tutorial) it may be instructive to dig a little deeper into the Tutorial-world - code to learn how it achieves what it does. The code is heavily documented. - You can find all the code in `evennia/contrib/tutorial_world <../../api/evennia.contrib.tutorial_world.html>`_, - the build-script is `here `_. +If you have previous programming experience (or after you have gone +through this Starter tutorial) it may be instructive to dig a little deeper into the Tutorial-world +code to learn how it achieves what it does. The code is heavily documented. +You can find all the code in [evennia/contrib/tutorials/tutorial_world](evennia.contrib.tutorials.tutorial_world). +The build-script is [here](github:evennia/contrib/tutorials/tutorial_world/build.ev). - When reading and learning from the code, however, keep in mind that *Tutorial World* was created with a very - specific goal in mind: to install easily and to not permanently modify the rest of the server. It therefore - goes to some length to use only temporary solutions and to clean up after itself. This is not something - you will usually need to worry about when making your own game. +When reading the code, remember that the Tutorial World was designed to install easily and to not permanently modify +the rest of the game. It therefore makes sure to only use temporary solutions and to clean up after itself. This is +not something you will often need to worry about when making your own game. ``` Quite a lot of stuff crammed in such a small area! diff --git a/docs/source/Howtos/Beginner-Tutorial/Part2/Beginner-Tutorial-Part2-Intro.md b/docs/source/Howtos/Beginner-Tutorial/Part2/Beginner-Tutorial-Part2-Intro.md new file mode 100644 index 0000000000..ddb06b2e8f --- /dev/null +++ b/docs/source/Howtos/Beginner-Tutorial/Part2/Beginner-Tutorial-Part2-Intro.md @@ -0,0 +1,46 @@ +# Part 2: What we want + +```{eval-rst} +.. sidebar:: Beginner Tutorial Parts + + `Introduction <../Beginner-Tutorial-Intro.html>`_ + Getting set up. + Part 1: `What we have <../Part1/Beginner-Tutorial-Part1-Intro.html>`_ + A tour of Evennia and how to use the tools, including an introduction to Python. + **Part 2: What we want** + Planning our tutorial game and what to think about when planning your own in the future. + Part 3: `How we get there <../Part3/Beginner-Tutorial-Part3-Intro.html>`_ + Getting down to the meat of extending Evennia to make our game + Part 4: `Using what we created <../Part4/Beginner-Tutorial-Part4-Intro.html>`_ + Building a tech-demo and world content to go with our code + Part 5: `Showing the world <../Part5/Beginner-Tutorial-Part5-Intro.html>`_ + Taking our new game online and let players try it out +``` + +In Part two of the Beginner Tutorial we'll take a step back and plan out the kind of tutorial +game we want to make. This is a more 'theoretical' part where we won't do any hands-on +programming. + +In the process we'll go through the common questions of "where to start" +and "what to think about" when creating a multiplayer online text game. + +## Lessons + +```{toctree} +:maxdepth: 1 + +Planning-Where-Do-I-Begin.md +Game-Planning.md +Planning-Some-Useful-Contribs.md +Planning-The-Tutorial-Game.md +``` + +## Table of Contents + +```{toctree} + +Planning-Where-Do-I-Begin.md +Game-Planning.md +Planning-Some-Useful-Contribs.md +Planning-The-Tutorial-Game.md +``` diff --git a/docs/source/Howto/Starting/Part2/Game-Planning.md b/docs/source/Howtos/Beginner-Tutorial/Part2/Game-Planning.md similarity index 100% rename from docs/source/Howto/Starting/Part2/Game-Planning.md rename to docs/source/Howtos/Beginner-Tutorial/Part2/Game-Planning.md diff --git a/docs/source/Howto/Starting/Part2/Planning-Some-Useful-Contribs.md b/docs/source/Howtos/Beginner-Tutorial/Part2/Planning-Some-Useful-Contribs.md similarity index 98% rename from docs/source/Howto/Starting/Part2/Planning-Some-Useful-Contribs.md rename to docs/source/Howtos/Beginner-Tutorial/Part2/Planning-Some-Useful-Contribs.md index edbc89a5fd..d8f78d01bc 100644 --- a/docs/source/Howto/Starting/Part2/Planning-Some-Useful-Contribs.md +++ b/docs/source/Howtos/Beginner-Tutorial/Part2/Planning-Some-Useful-Contribs.md @@ -8,7 +8,7 @@ That said, Evennia _does_ offer some more game-opinionated _optional_ stuff. The and is an ever-growing treasure trove of code snippets, concepts and even full systems you can pick and choose from to use, tweak or take inspiration from when you make your game. -The [Contrib overview](../../../Contribs/Contrib-Overview.md) page gives the full list of the current roster of contributions. On +The [Contrib overview](../../../Contribs/Contribs-Overview.md) page gives the full list of the current roster of contributions. On this page we will review a few contribs we will make use of for our game. We will do the actual installation of them when we start coding in the next part of this tutorial series. While we will introduce them here, you are wise to read their doc-strings yourself for the details. diff --git a/docs/source/Howto/Starting/Part2/Planning-The-Tutorial-Game.md b/docs/source/Howtos/Beginner-Tutorial/Part2/Planning-The-Tutorial-Game.md similarity index 100% rename from docs/source/Howto/Starting/Part2/Planning-The-Tutorial-Game.md rename to docs/source/Howtos/Beginner-Tutorial/Part2/Planning-The-Tutorial-Game.md diff --git a/docs/source/Howto/Starting/Part2/Planning-Where-Do-I-Begin.md b/docs/source/Howtos/Beginner-Tutorial/Part2/Planning-Where-Do-I-Begin.md similarity index 100% rename from docs/source/Howto/Starting/Part2/Planning-Where-Do-I-Begin.md rename to docs/source/Howtos/Beginner-Tutorial/Part2/Planning-Where-Do-I-Begin.md diff --git a/docs/source/Howto/Starting/Part3/A-Sittable-Object.md b/docs/source/Howtos/Beginner-Tutorial/Part3/A-Sittable-Object.md similarity index 100% rename from docs/source/Howto/Starting/Part3/A-Sittable-Object.md rename to docs/source/Howtos/Beginner-Tutorial/Part3/A-Sittable-Object.md diff --git a/docs/source/Howto/Starting/Part3/Starting-Part3.md b/docs/source/Howtos/Beginner-Tutorial/Part3/Beginner-Tutorial-Part3-Intro.md similarity index 60% rename from docs/source/Howto/Starting/Part3/Starting-Part3.md rename to docs/source/Howtos/Beginner-Tutorial/Part3/Beginner-Tutorial-Part3-Intro.md index a92c601603..9e22e70e2d 100644 --- a/docs/source/Howto/Starting/Part3/Starting-Part3.md +++ b/docs/source/Howtos/Beginner-Tutorial/Part3/Beginner-Tutorial-Part3-Intro.md @@ -1,25 +1,43 @@ -# Evennia Starting Tutorial (Part 3) +# Part 3: How we get there ```{eval-rst} +.. sidebar:: Beginner Tutorial Parts -sidebar:: Tutorial Parts - - Part 1: `What we have <../Part1/Starting-Part1.html>`_ + `Introduction <../Beginner-Tutorial-Intro.html>`_ + Getting set up. + Part 1: `What we have <../Part1/Beginner-Tutorial-Part1-Intro.html>`_ A tour of Evennia and how to use the tools, including an introduction to Python. - Part 2: `What we want <../Part2/Starting-Part2.html>`_ + Part 2: `What we want <../Part2/Beginner-Tutorial-Part2-Intro.html>`_ Planning our tutorial game and what to think about when planning your own in the future. **Part 3: How we get there** Getting down to the meat of extending Evennia to make our game - Part 4: `Using what we created <../Part4/Starting-Part4.html>`_ + Part 4: `Using what we created <../Part4/Beginner-Tutorial-Part4-Intro.html>`_ Building a tech-demo and world content to go with our code - Part 5: `Showing the world <../Part5/Starting-Part5.html>`_ + Part 5: `Showing the world <../Part5/Beginner-Tutorial-Part5-Intro.html>`_ Taking our new game online and let players try it out ``` -In part three of the Evennia Starting tutorial we will go through the creation of several key parts -of our tutorial game _EvAdventure_. As we go, we will test each part and create a simple "tech demo" to -show off all the moving parts. -1. Introduction & Overview (you are here) +In part three of the Evennia Beginner tutorial we will go through the creation of several key parts of our tutorial +game _EvAdventure_. This is a pretty big part with plenty of examples. + +If you followed the previous parts of this tutorial you will have some notions about Python and where to find +and make use of things in Evennia. We also have a good idea of the type of game we want. +Even if this is not the game-style you are interested in, following along will give you a lot of experience +with using Evennia. This be of much use when doing your own thing later. + + +## Lessons + +_TODO_ + +```{toctree} +:maxdepth: 1 + +Implementing-a-game-rule-system +Turn-based-Combat-System +A-Sittable-Object + +``` 1. [Changing settings](../../../Unimplemented.md) 1. [Applying contribs](../../../Unimplemented.md) 1. [Creating a rule module](../../../Unimplemented.md) @@ -31,17 +49,15 @@ show off all the moving parts. 1. [Questing and rewards](../../../Unimplemented.md) 1. [Overview of Tech demo](../../../Unimplemented.md) -If you followed the previous parts of this tutorial you will have some notions about Python and where to find -and make use of things in Evennia. We also have a good idea of the type of game we want. -Even if this is not the game-style you are interested in, following along will give you a lot of experience -with using Evennia. This be of much use when doing your own thing later. + +## Table of Contents _TODO_ +```{toctree} +:maxdepth: 1 -```{toctree} -:hidden: - -../../../Unimplemented - +Implementing-a-game-rule-system +Turn-Based-Combat-System +A-Sittable-Object ``` diff --git a/docs/source/Howto/Starting/Part3/Implementing-a-game-rule-system.md b/docs/source/Howtos/Beginner-Tutorial/Part3/Implementing-a-game-rule-system.md similarity index 100% rename from docs/source/Howto/Starting/Part3/Implementing-a-game-rule-system.md rename to docs/source/Howtos/Beginner-Tutorial/Part3/Implementing-a-game-rule-system.md diff --git a/docs/source/Howto/Starting/Part3/Turn-based-Combat-System.md b/docs/source/Howtos/Beginner-Tutorial/Part3/Turn-based-Combat-System.md similarity index 100% rename from docs/source/Howto/Starting/Part3/Turn-based-Combat-System.md rename to docs/source/Howtos/Beginner-Tutorial/Part3/Turn-based-Combat-System.md diff --git a/docs/source/Howto/Starting/Part4/Starting-Part4.md b/docs/source/Howtos/Beginner-Tutorial/Part4/Beginner-Tutorial-Part4-Intro.md similarity index 60% rename from docs/source/Howto/Starting/Part4/Starting-Part4.md rename to docs/source/Howtos/Beginner-Tutorial/Part4/Beginner-Tutorial-Part4-Intro.md index 0a105a09ed..1190c4f118 100644 --- a/docs/source/Howto/Starting/Part4/Starting-Part4.md +++ b/docs/source/Howtos/Beginner-Tutorial/Part4/Beginner-Tutorial-Part4-Intro.md @@ -1,17 +1,19 @@ -# Evennia Starting Tutorial (Part 4) +# Part 4: Using what we created ```{eval-rst} -sidebar:: Tutorial Parts +..sidebar:: Beginner Tutorial Parts - Part 1: `What we have <../Part1/Starting-Part1.html>`_ + `Introduction <../Beginner-Tutorial-Intro.html>`_ + Getting set up. + Part 1: `What we have <../Part1/Beginner-Tutorial-Part1-Intro.html>`_ A tour of Evennia and how to use the tools, including an introduction to Python. - Part 2: `What we want <../Part2/Starting-Part2.html>`_ + Part 2: `What we want <../Part2/Beginner-Tutorial-Part2-Intro.html>`_ Planning our tutorial game and what to think about when planning your own in the future. - Part 3: `How we get there <../Part3/Starting-Part3.html>`_ + Part 3: `How we get there <../Part3/Beginner-Tutorial-Part3-Intro.html>`_ Getting down to the meat of extending Evennia to make our game to make a tech-demo **Part 4: Using what we created** Using the tech-demo and world content to go with our code - Part 5: `Showing the world <../Part5/Starting-Part5.html>`_ + Part 5: `Showing the world <../Part5/Beginner-Tutorial-Part5-Intro.html>`_ Taking our new game online and let players try it out ``` @@ -21,4 +23,20 @@ point - we need to actually make a world. In part four we will expand our tech demo into a more full-fledged (if small) game by use of batchcommand and batchcode processors. +## Lessons + _TODO_ + +```{toctree} +:maxdepth: 1 + +``` + + +## Table of Contents + +_TODO_ + +```{toctree} + +``` diff --git a/docs/source/Howto/Starting/Part5/Add-a-simple-new-web-page.md b/docs/source/Howtos/Beginner-Tutorial/Part5/Add-a-simple-new-web-page.md similarity index 100% rename from docs/source/Howto/Starting/Part5/Add-a-simple-new-web-page.md rename to docs/source/Howtos/Beginner-Tutorial/Part5/Add-a-simple-new-web-page.md diff --git a/docs/source/Howto/Starting/Part5/Starting-Part5.md b/docs/source/Howtos/Beginner-Tutorial/Part5/Beginner-Tutorial-Part5-Intro.md similarity index 53% rename from docs/source/Howto/Starting/Part5/Starting-Part5.md rename to docs/source/Howtos/Beginner-Tutorial/Part5/Beginner-Tutorial-Part5-Intro.md index 4703710859..09d2936c05 100644 --- a/docs/source/Howto/Starting/Part5/Starting-Part5.md +++ b/docs/source/Howtos/Beginner-Tutorial/Part5/Beginner-Tutorial-Part5-Intro.md @@ -1,15 +1,17 @@ -# Evennia Starting Tutorial (part 5) +# Part 5: Showing the world ```{eval-rst} -.. sidebar:: Tutorial Parts +.. sidebar:: Beginner Tutorial Parts - Part 1: `What we have <../Part1/Starting-Part1.html>`_ + `Introduction <../Beginner-Tutorial-Intro.html>`_ + Getting set up. + Part 1: `What we have <../Part1/Beginner-Tutorial-Part1-Intro.html>`_ A tour of Evennia and how to use the tools, including an introduction to Python. - Part 2: `What we want <../Part2/Starting-Part2.html>`_ + Part 2: `What we want <../Part2/Beginner-Tutorial-Part2-Intro.html>`_ Planning our tutorial game and what to think about when planning your own in the future. - Part 3: `How we get there <../Part3/Starting-Part3.html>`_ + Part 3: `How we get there <../Part3/Beginner-Tutorial-Part3-Intro.html>`_ Getting down to the meat of extending Evennia to make our game - Part 4: `Using what we created <../Part4/Starting-Part4.html>`_ + Part 4: `Using what we created <../Part4/Beginner-Tutorial-Part4-Intro.html>`_ Building a tech-demo and world content to go with our code **Part 5: Showing the world** Taking our new game online and let players try it out @@ -19,4 +21,26 @@ You have a working game! In part five we will look at the web-components of Even to fit your game. We will also look at hosting your game and if you feel up to it we'll also go through how to bring your game online so you can invite your first players. +## Lessons + _TODO_ + +```{toctree} +:maxdepth: 1 + +Add-a-simple-new-web-page.md +Web-Tutorial.md + +``` + + +## Table of Contents + +_TODO_ + +```{toctree} + +Add-a-simple-new-web-page.md +Web-Tutorial.md + +``` diff --git a/docs/source/Howto/Starting/Part5/Web-Tutorial.md b/docs/source/Howtos/Beginner-Tutorial/Part5/Web-Tutorial.md similarity index 100% rename from docs/source/Howto/Starting/Part5/Web-Tutorial.md rename to docs/source/Howtos/Beginner-Tutorial/Part5/Web-Tutorial.md diff --git a/docs/source/Howto/Building-a-mech-tutorial.md b/docs/source/Howtos/Building-a-mech-tutorial.md similarity index 100% rename from docs/source/Howto/Building-a-mech-tutorial.md rename to docs/source/Howtos/Building-a-mech-tutorial.md diff --git a/docs/source/Howto/Coding-FAQ.md b/docs/source/Howtos/Coding-FAQ.md similarity index 98% rename from docs/source/Howto/Coding-FAQ.md rename to docs/source/Howtos/Coding-FAQ.md index d38f689a7a..80f376f562 100644 --- a/docs/source/Howto/Coding-FAQ.md +++ b/docs/source/Howtos/Coding-FAQ.md @@ -28,7 +28,7 @@ Character [Command Set](../Components/Command-Sets.md)? **A:** Go to `mygame/commands/default_cmdsets.py`. Find the `CharacterCmdSet` class. It has one method named `at_cmdset_creation`. At the end of that method, add the following line: -`self.remove(default_cmds.CmdGet())`. See the [Adding Commands Tutorial](Starting/Part1/Adding-Commands.md) +`self.remove(default_cmds.CmdGet())`. See the [Adding Commands Tutorial](Beginner-Tutorial/Part1/Adding-Commands.md) for more info. ## Preventing character from moving based on a condition @@ -156,7 +156,7 @@ class CmdWerewolf(Command): def func(self): # ... ``` -Add this to the [default cmdset as usual](Starting/Part1/Adding-Commands.md). The `is_full_moon` [lock +Add this to the [default cmdset as usual](Beginner-Tutorial/Part1/Adding-Commands.md). The `is_full_moon` [lock function](../Components/Locks.md#lock-functions) does not yet exist. We must create that: ```python diff --git a/docs/source/Howto/Command-Cooldown.md b/docs/source/Howtos/Command-Cooldown.md similarity index 100% rename from docs/source/Howto/Command-Cooldown.md rename to docs/source/Howtos/Command-Cooldown.md diff --git a/docs/source/Howto/Command-Duration.md b/docs/source/Howtos/Command-Duration.md similarity index 100% rename from docs/source/Howto/Command-Duration.md rename to docs/source/Howtos/Command-Duration.md diff --git a/docs/source/Howto/Command-Prompt.md b/docs/source/Howtos/Command-Prompt.md similarity index 100% rename from docs/source/Howto/Command-Prompt.md rename to docs/source/Howtos/Command-Prompt.md diff --git a/docs/source/Howto/Coordinates.md b/docs/source/Howtos/Coordinates.md similarity index 100% rename from docs/source/Howto/Coordinates.md rename to docs/source/Howtos/Coordinates.md diff --git a/docs/source/Howtos/Default-Exit-Errors.md b/docs/source/Howtos/Default-Exit-Errors.md new file mode 100644 index 0000000000..d1e4045e73 --- /dev/null +++ b/docs/source/Howtos/Default-Exit-Errors.md @@ -0,0 +1,130 @@ +# Default Exit Errors + +Evennia allows for exits to have any name. The command "kitchen" is a valid exit name as well as "jump out the window" +or "north". An exit actually consists of two parts: an [Exit Object](../Components/Objects.md) and +an [Exit Command](../Components/Commands.md) stored on said exit object. The command has the same key and aliases as the +exit-object, which is why you can see the exit in the room and just write its name to traverse it. + +So if you try to enter the name of a non-existing exit, Evennia treats is the same way as if you were trying to +use a non-existing command: + + > jump out the window + Command 'jump out the window' is not available. Type "help" for help. + +Many games don't need this type of freedom however. They define only the cardinal directions as valid exit names ( +Evennia's `tunnel` command also offers this functionality). In this case, the error starts to look less logical: + + > west + Command 'west' is not available. Maybe you meant "set" or "reset"? + +Since we for our particular game *know* that west is an exit direction, it would be better if the error message just +told us that we couldn't go there. + + > west + You cannot move west. + + +## Adding default error commands + +The way to do this is to give Evennia an _alternative_ Command to use when no Exit-Command is found +in the room. See [Adding Commands](Beginner-Tutorial/Part1/Adding-Commands.md) for more info about the +process of adding new Commands to Evennia. + +In this example all we'll do is echo an error message. + +```python +# for example in a file mygame/commands/movecommands.py + +from evennia import default_cmds, CmdSet + +class CmdExitError(default_cmds.MuxCommand): + """Parent class for all exit-errors.""" + locks = "cmd:all()" + arg_regex = r"\s|$" + auto_help = False + def func(self): + """Returns error based on key""" + self.caller.msg(f"You cannot move {self.key}.") + +class CmdExitErrorNorth(CmdExitError): + key = "north" + aliases = ["n"] + +class CmdExitErrorEast(CmdExitError): + key = "east" + aliases = ["e"] + +class CmdExitErrorSouth(CmdExitError): + key = "south" + aliases = ["s"] + +class CmdExitErrorWest(CmdExitError): + key = "west" + aliases = ["w"] + +# you could add each command on its own to the default cmdset, +# but putting them all in a cmdset here allows you to +# just add this and makes it easier to expand with more +# exit-errors in the future + +class MovementFailCmdSet(CmdSet): + def at_cmdset_creation(self): + self.add(CmdExitErrorNorth()) + self.add(CmdExitErrorEast()) + self.add(CmdExitErrorWest()) + self.add(CmdExitErrorSouth()) +``` + +We pack our commands in a new little cmdset; if we add this to our +`CharacterCmdSet`, we can just add more errors to `MovementFailCmdSet` +later without having to change code in two places. + +```python +# in mygame/commands/default_cmdsets.py + +from commands import movecommands + +# [...] +class CharacterCmdSet(default_cmds.CharacterCmdSet): + # [...] + def at_cmdset_creation(self): + # [...] + # this adds all the commands at once + self.add(movecommands.MovementFailCmdSet) +``` + +`reload` the server. What happens henceforth is that if you are in a room with an Exitobject (let's say it's "north"), +the proper Exit-command will _overload_ your error command (also named "north"). But if you enter a direction without +having a matching exit for it, you will fall back to your default error commands: + + > east + You cannot move east. + +Further expansions by the exit system (including manipulating the way the Exit command itself is created) can be done by +modifying the [Exit typeclass](../Components/Typeclasses.md) directly. + +## Why not a single command? + +So why didn't we create a single error command above? Something like this: + +```python +class CmdExitError(default_cmds.MuxCommand): + "Handles all exit-errors." + key = "error_cmd" + aliases = ["north", "n", + "east", "e", + "south", "s", + "west", "w"] + #[...] +``` + +The reason is that this would *not* work. Understanding why is important. + +Evennia's [command system](../Components/Commands.md) compares commands by key and/or aliases. If _any_ key or alias +match, the two commands are considered _identical_. When the cmdsets merge, priority will then decide which of these +'identical' commandss replace which. + +So the above example would work fine as long as there were _no Exits at all_ in the room. But when we enter +a room with an exit "north", its Exit-command (which has a higher priority) will override the single `CmdExitError` +with its alias 'north'. So the `CmdExitError` will be gone and while "north" will work, we'll again get the normal +"Command not recognized" error for the other directions. \ No newline at end of file diff --git a/docs/source/Howto/Dynamic-In-Game-Map.md b/docs/source/Howtos/Dynamic-In-Game-Map.md similarity index 100% rename from docs/source/Howto/Dynamic-In-Game-Map.md rename to docs/source/Howtos/Dynamic-In-Game-Map.md diff --git a/docs/source/Howto/Evennia-for-Diku-Users.md b/docs/source/Howtos/Evennia-for-Diku-Users.md similarity index 100% rename from docs/source/Howto/Evennia-for-Diku-Users.md rename to docs/source/Howtos/Evennia-for-Diku-Users.md diff --git a/docs/source/Howto/Evennia-for-MUSH-Users.md b/docs/source/Howtos/Evennia-for-MUSH-Users.md similarity index 97% rename from docs/source/Howto/Evennia-for-MUSH-Users.md rename to docs/source/Howtos/Evennia-for-MUSH-Users.md index 752047ecb4..006e6934b7 100644 --- a/docs/source/Howto/Evennia-for-MUSH-Users.md +++ b/docs/source/Howtos/Evennia-for-MUSH-Users.md @@ -203,7 +203,7 @@ developer changing the underlying Python code. ## Next steps If you are a *Developer* and are interested in making a more MUSH-like Evennia game, a good start is -to look into the Evennia [Tutorial for a first MUSH-like game](Starting/Part3/Tutorial-for-basic-MUSH-like-game.md). +to look into the Evennia [Tutorial for a first MUSH-like game](./Tutorial-for-basic-MUSH-like-game.md). That steps through building a simple little game from scratch and helps to acquaint you with the various corners of Evennia. There is also the [Tutorial for running roleplaying sessions](Evennia- for-roleplaying-sessions) that can be of interest. @@ -211,8 +211,8 @@ for-roleplaying-sessions) that can be of interest. An important aspect of making things more familiar for *Players* is adding new and tweaking existing commands. How this is done is covered by the [Tutorial on adding new commands](Adding-Command- Tutorial). You may also find it useful to shop through the `evennia/contrib/` folder. The -[Tutorial world](Starting/Part1/Tutorial-World.md) is a small single-player quest you can try (it’s not very MUSH- -like but it does show many Evennia concepts in action). Beyond that there are [many more tutorials](./Howto-Overview.md) +[Tutorial world](Beginner-Tutorial/Part1/Tutorial-World.md) is a small single-player quest you can try (it’s not very MUSH- +like but it does show many Evennia concepts in action). Beyond that there are [many more tutorials](./Howtos-Overview.md) to try out. If you feel you want a more visual overview you can also look at [Evennia in pictures](https://evennia.blogspot.se/2016/05/evennia-in-pictures.html). diff --git a/docs/source/Howto/Evennia-for-roleplaying-sessions.md b/docs/source/Howtos/Evennia-for-roleplaying-sessions.md similarity index 99% rename from docs/source/Howto/Evennia-for-roleplaying-sessions.md rename to docs/source/Howtos/Evennia-for-roleplaying-sessions.md index 7e68968cf3..0bda191636 100644 --- a/docs/source/Howto/Evennia-for-roleplaying-sessions.md +++ b/docs/source/Howtos/Evennia-for-roleplaying-sessions.md @@ -31,7 +31,7 @@ instructions. Initialize a new game directory with `evennia init `. In this tutorial we assume your game dir is simply named `mygame`. You can use the default database and keep all other settings to default for now. Familiarize yourself with the `mygame` folder before continuing. You might want to browse the -[First Steps Coding](Starting/Part1/Starting-Part1.md) tutorial, just to see roughly where things are modified. +[First Steps Coding](Beginner-Tutorial/Part1/Beginner-Tutorial-Part1-Intro.md) tutorial, just to see roughly where things are modified. ## The Game Master role @@ -686,7 +686,7 @@ implemented. ## Rooms Evennia comes with rooms out of the box, so no extra work needed. A GM will automatically have all -needed building commands available. A fuller go-through is found in the [Building tutorial](Starting/Part1/Building-Quickstart.md). +needed building commands available. A fuller go-through is found in the [Building tutorial](Beginner-Tutorial/Part1/Building-Quickstart.md). Here are some useful highlights: * `@dig roomname;alias = exit_there;alias, exit_back;alias` - this is the basic command for digging diff --git a/docs/source/Howto/Gametime-Tutorial.md b/docs/source/Howtos/Gametime-Tutorial.md similarity index 100% rename from docs/source/Howto/Gametime-Tutorial.md rename to docs/source/Howtos/Gametime-Tutorial.md diff --git a/docs/source/Howto/Help-System-Tutorial.md b/docs/source/Howtos/Help-System-Tutorial.md similarity index 100% rename from docs/source/Howto/Help-System-Tutorial.md rename to docs/source/Howtos/Help-System-Tutorial.md diff --git a/docs/source/Howtos/Howtos-Overview.md b/docs/source/Howtos/Howtos-Overview.md new file mode 100644 index 0000000000..27fc8ec7ad --- /dev/null +++ b/docs/source/Howtos/Howtos-Overview.md @@ -0,0 +1,91 @@ +# Tutorials and Howto's + +The documents in this section aims to teach how to use Evennia in a tutorial or +a step-by-step way. They often give hints on about solving a problem or implementing +a particular feature or concept. They will often refer to the +[components](../Components/Components-Overview.md) or [concepts](../Concepts/Concepts-Overview.md) +docs for those that want to dive deeper. + +## Beginner Tutorial + +Recommended starting point! This will take you from absolute beginner to making +a small, but full, game with Evennia. Even if you have a very different game style +in mind for your own game, this will give you a good start. + +```{toctree} +:maxdepth: 1 + +./Beginner-Tutorial/Beginner-Tutorial-Intro + +``` + +## Howto's + +```{toctree} +:maxdepth: 1 + +Coding-FAQ.md +Command-Prompt.md +Command-Cooldown.md +Command-Duration.md +Default-Exit-Errors.md +Manually-Configuring-Color.md +Tutorial-Tweeting-Game-Stats.md + +``` +## Mobs and NPCs + +```{toctree} +:maxdepth: 1 + +Tutorial-NPCs-listening.md +Tutorial-Aggressive-NPCs.md +NPC-shop-Tutorial.md +``` + +## Vehicles + +```{toctree} +:maxdepth: 1 + +Building-a-mech-tutorial.md +Tutorial-Vehicles.md +``` + +## Systems +```{toctree} +:maxdepth: 1 + +Gametime-Tutorial.md +Help-System-Tutorial.md +Mass-and-weight-for-objects.md +Weather-Tutorial.md +Coordinates.md +Dynamic-In-Game-Map.md +Static-In-Game-Map.md +Arxcode-Installation.md + +``` + +## Web-related tutorials + +```{toctree} +:maxdepth: 1 + +Add-a-wiki-on-your-website.md +Web-Character-Generation.md +Web-Character-View-Tutorial.md + +``` +## Deep-dives + +```{toctree} +:maxdepth: 1 + +Parsing-commands-tutorial.md +Understanding-Color-Tags.md +Evennia-for-roleplaying-sessions.md +Evennia-for-Diku-Users.md +Evennia-for-MUSH-Users.md +Tutorial-for-basic-MUSH-like-game.md +``` \ No newline at end of file diff --git a/docs/source/Howto/Manually-Configuring-Color.md b/docs/source/Howtos/Manually-Configuring-Color.md similarity index 100% rename from docs/source/Howto/Manually-Configuring-Color.md rename to docs/source/Howtos/Manually-Configuring-Color.md diff --git a/docs/source/Howto/Mass-and-weight-for-objects.md b/docs/source/Howtos/Mass-and-weight-for-objects.md similarity index 100% rename from docs/source/Howto/Mass-and-weight-for-objects.md rename to docs/source/Howtos/Mass-and-weight-for-objects.md diff --git a/docs/source/Howto/NPC-shop-Tutorial.md b/docs/source/Howtos/NPC-shop-Tutorial.md similarity index 100% rename from docs/source/Howto/NPC-shop-Tutorial.md rename to docs/source/Howtos/NPC-shop-Tutorial.md diff --git a/docs/source/Howto/Parsing-commands-tutorial.md b/docs/source/Howtos/Parsing-commands-tutorial.md similarity index 99% rename from docs/source/Howto/Parsing-commands-tutorial.md rename to docs/source/Howtos/Parsing-commands-tutorial.md index 33545b9849..8e3638a12b 100644 --- a/docs/source/Howto/Parsing-commands-tutorial.md +++ b/docs/source/Howtos/Parsing-commands-tutorial.md @@ -2,7 +2,7 @@ This tutorial will elaborate on the many ways one can parse command arguments. The first step after -[adding a command](Starting/Part1/Adding-Commands.md) usually is to parse its arguments. There are lots of +[adding a command](Beginner-Tutorial/Part1/Adding-Commands.md) usually is to parse its arguments. There are lots of ways to do it, but some are indeed better than others and this tutorial will try to present them. If you're a Python beginner, this tutorial might help you a lot. If you're already familiar with @@ -652,7 +652,7 @@ about... what is this `"book"`? To get an object from a string, we perform an Evennia search. Evennia provides a `search` method on all typeclassed objects (you will most likely use the one on characters or accounts). This method -supports a very wide array of arguments and has [its own tutorial](Starting/Part1/Searching-Things.md). +supports a very wide array of arguments and has [its own tutorial](Beginner-Tutorial/Part1/Searching-Things.md). Some examples of useful cases follow: ### Local searches diff --git a/docs/source/Howto/Static-In-Game-Map.md b/docs/source/Howtos/Static-In-Game-Map.md similarity index 98% rename from docs/source/Howto/Static-In-Game-Map.md rename to docs/source/Howtos/Static-In-Game-Map.md index 60645bf66e..ce229b4699 100644 --- a/docs/source/Howto/Static-In-Game-Map.md +++ b/docs/source/Howtos/Static-In-Game-Map.md @@ -84,7 +84,7 @@ In this section we will try to create an actual "map" object that an account can at. Evennia offers a range of [default commands](../Components/Default-Commands.md) for -[creating objects and rooms in-game](Starting/Part1/Building-Quickstart.md). While readily accessible, these commands are made to do very +[creating objects and rooms in-game](Beginner-Tutorial/Part1/Building-Quickstart.md). While readily accessible, these commands are made to do very specific, restricted things and will thus not offer as much flexibility to experiment (for an advanced exception see [the FuncParser](../Components/FuncParser.md)). Additionally, entering long descriptions and properties over and over in the game client can become tedious; especially when @@ -413,4 +413,4 @@ easily new game defining features can be added to Evennia. You can easily build from this tutorial by expanding the map and creating more rooms to explore. Why not add more features to your game by trying other tutorials: [Add weather to your world](Weather- Tutorial), [fill your world with NPC's](./Tutorial-Aggressive-NPCs.md) or -[implement a combat system](Starting/Part3/Turn-based-Combat-System.md). +[implement a combat system](Beginner-Tutorial/Part3/Turn-based-Combat-System.md). diff --git a/docs/source/Howto/Tutorial-Aggressive-NPCs.md b/docs/source/Howtos/Tutorial-Aggressive-NPCs.md similarity index 97% rename from docs/source/Howto/Tutorial-Aggressive-NPCs.md rename to docs/source/Howtos/Tutorial-Aggressive-NPCs.md index 26abe4e34b..9f9dc12c83 100644 --- a/docs/source/Howto/Tutorial-Aggressive-NPCs.md +++ b/docs/source/Howtos/Tutorial-Aggressive-NPCs.md @@ -10,7 +10,7 @@ highly inefficient (most of the time its check would fail). Instead we handle th using a couple of existing object hooks to inform the NPC that a Character has entered. It is assumed that you already know how to create custom room and character typeclasses, please see -the [Basic Game tutorial](Starting/Part3/Tutorial-for-basic-MUSH-like-game.md) if you haven't already done this. +the [Basic Game tutorial](./Tutorial-for-basic-MUSH-like-game.md) if you haven't already done this. What we will need is the following: diff --git a/docs/source/Howto/Tutorial-NPCs-listening.md b/docs/source/Howtos/Tutorial-NPCs-listening.md similarity index 97% rename from docs/source/Howto/Tutorial-NPCs-listening.md rename to docs/source/Howtos/Tutorial-NPCs-listening.md index 724427afae..f658b8a4d3 100644 --- a/docs/source/Howto/Tutorial-NPCs-listening.md +++ b/docs/source/Howtos/Tutorial-NPCs-listening.md @@ -6,7 +6,7 @@ their location. In this example the NPC parrots what is said, but any actions co this way. It is assumed that you already know how to create custom room and character typeclasses, please see -the [Basic Game tutorial](Starting/Part3/Tutorial-for-basic-MUSH-like-game.md) if you haven't already done this. +the [Basic Game tutorial](./Tutorial-for-basic-MUSH-like-game.md) if you haven't already done this. What we will need is simply a new NPC typeclass that can react when someone speaks. diff --git a/docs/source/Howto/Tutorial-Tweeting-Game-Stats.md b/docs/source/Howtos/Tutorial-Tweeting-Game-Stats.md similarity index 100% rename from docs/source/Howto/Tutorial-Tweeting-Game-Stats.md rename to docs/source/Howtos/Tutorial-Tweeting-Game-Stats.md diff --git a/docs/source/Howto/Tutorial-Vehicles.md b/docs/source/Howtos/Tutorial-Vehicles.md similarity index 100% rename from docs/source/Howto/Tutorial-Vehicles.md rename to docs/source/Howtos/Tutorial-Vehicles.md diff --git a/docs/source/Howto/Starting/Part3/Tutorial-for-basic-MUSH-like-game.md b/docs/source/Howtos/Tutorial-for-basic-MUSH-like-game.md similarity index 94% rename from docs/source/Howto/Starting/Part3/Tutorial-for-basic-MUSH-like-game.md rename to docs/source/Howtos/Tutorial-for-basic-MUSH-like-game.md index f57c6ac330..b2b46c406a 100644 --- a/docs/source/Howto/Starting/Part3/Tutorial-for-basic-MUSH-like-game.md +++ b/docs/source/Howtos/Tutorial-for-basic-MUSH-like-game.md @@ -7,7 +7,7 @@ focused on free form storytelling. Even if you are not interested in MUSH:es, th first game-type to try since it's not so code heavy. You will be able to use the same principles for building other types of games. -The tutorial starts from scratch. If you did the [First Steps Coding](../Part1/Starting-Part1.md) tutorial +The tutorial starts from scratch. If you did the [First Steps Coding](Beginner-Tutorial/Part1/Beginner-Tutorial-Part1-Intro.md) tutorial already you should have some ideas about how to do some of the steps already. The following are the (very simplistic and cut-down) features we will implement (this was taken from @@ -61,7 +61,7 @@ class Character(DefaultCharacter): self.db.combat_score = 1 ``` -We defined two new [Attributes](../../../Components/Attributes.md) `power` and `combat_score` and set them to default +We defined two new [Attributes](../Components/Attributes.md) `power` and `combat_score` and set them to default values. Make sure to `@reload` the server if you had it already running (you need to reload every time you update your python code, don't worry, no accounts will be disconnected by the reload). @@ -94,8 +94,8 @@ check it. Using this method however will make it easy to add more functionality What we need are the following: -- One character generation [Command](../../../Components/Commands.md) to set the "Power" on the `Character`. -- A chargen [CmdSet](../../../Components/Command-Sets.md) to hold this command. Lets call it `ChargenCmdset`. +- One character generation [Command](../Components/Commands.md) to set the "Power" on the `Character`. +- A chargen [CmdSet](../Components/Command-Sets.md) to hold this command. Lets call it `ChargenCmdset`. - A custom `ChargenRoom` type that makes this set of commands available to players in such rooms. - One such room to test things in. @@ -104,7 +104,7 @@ What we need are the following: For this tutorial we will add all our new commands to `mygame/commands/command.py` but you could split your commands into multiple module if you prefered. -For this tutorial character generation will only consist of one [Command](../../../Components/Commands.md) to set the +For this tutorial character generation will only consist of one [Command](../Components/Commands.md) to set the Character s "power" stat. It will be called on the following MUSH-like form: +setpower 4 @@ -156,7 +156,7 @@ This is a pretty straightforward command. We do some error checking, then set th We use a `help_category` of "mush" for all our commands, just so they are easy to find and separate in the help list. -Save the file. We will now add it to a new [CmdSet](../../../Components/Command-Sets.md) so it can be accessed (in a full +Save the file. We will now add it to a new [CmdSet](../Components/Command-Sets.md) so it can be accessed (in a full chargen system you would of course have more than one command here). Open `mygame/commands/default_cmdsets.py` and import your `command.py` module at the top. We also @@ -210,7 +210,7 @@ class ChargenRoom(Room): ``` Note how new rooms created with this typeclass will always start with `ChargenCmdset` on themselves. Don't forget the `persistent=True` keyword or you will lose the cmdset after a server reload. For -more information about [Command Sets](../../../Components/Command-Sets.md) and [Commands](../../../Components/Commands.md), see the respective +more information about [Command Sets](../Components/Command-Sets.md) and [Commands](../Components/Commands.md), see the respective links. ### Testing chargen @@ -242,7 +242,7 @@ between fixes. Don't continue until the creation seems to have worked okay. This should bring you to the chargen room. Being in there you should now have the `+setpower` command available, so test it out. When you leave (via the `finish` exit), the command will go away and trying `+setpower` should now give you a command-not-found error. Use `ex me` (as a privileged -user) to check so the `Power` [Attribute](../../../Components/Attributes.md) has been set correctly. +user) to check so the `Power` [Attribute](../Components/Attributes.md) has been set correctly. If things are not working, make sure your typeclasses and commands are free of bugs and that you have entered the paths to the various command sets and commands correctly. Check the logs or command @@ -397,7 +397,7 @@ There are a few ways to define the NPC class. We could in theory create a custom and put a custom NPC-specific cmdset on all NPCs. This cmdset could hold all manipulation commands. Since we expect NPC manipulation to be a common occurrence among the user base however, we will instead put all relevant NPC commands in the default command set and limit eventual access with -[Permissions and Locks](../../../Components/Permissions.md). +[Permissions and Locks](../Components/Permissions.md). ### Creating an NPC with +createNPC @@ -454,13 +454,13 @@ class CmdCreateNPC(Command): ), exclude=caller) ``` Here we define a `+createnpc` (`+createNPC` works too) that is callable by everyone *not* having the -`nonpcs` "[permission](../../../Components/Permissions.md)" (in Evennia, a "permission" can just as well be used to +`nonpcs` "[permission](../Components/Permissions.md)" (in Evennia, a "permission" can just as well be used to block access, it depends on the lock we define). We create the NPC object in the caller's current location, using our custom `Character` typeclass to do so. We set an extra lock condition on the NPC, which we will use to check who may edit the NPC later -- we allow the creator to do so, and anyone with the Builders permission (or higher). See -[Locks](../../../Components/Locks.md) for more information about the lock system. +[Locks](../Components/Locks.md) for more information about the lock system. Note that we just give the object default permissions (by not specifying the `permissions` keyword to the `create_object()` call). In some games one might want to give the NPC the same permissions @@ -475,7 +475,7 @@ Since we re-used our custom character typeclass, our new NPC already has a *Powe defaults to 1. How do we change this? There are a few ways we can do this. The easiest is to remember that the `power` attribute is just a -simple [Attribute](../../../Components/Attributes.md) stored on the NPC object. So as a Builder or Admin we could set this +simple [Attribute](../Components/Attributes.md) stored on the NPC object. So as a Builder or Admin we could set this right away with the default `@set` command: @set mynpc/power = 6 @@ -660,6 +660,6 @@ The simple "Power" game mechanic should be easily expandable to something more f useful, same is true for the combat score principle. The `+attack` could be made to target a specific player (or npc) and automatically compare their relevant attributes to determine a result. -To continue from here, you can take a look at the [Tutorial World](../Part1/Tutorial-World.md). For -more specific ideas, see the [other tutorials and hints](../../Howto-Overview.md) as well -as the [Evennia Component overview](../../../Components/Components-Overview.md). +To continue from here, you can take a look at the [Tutorial World](Beginner-Tutorial/Part1/Tutorial-World.md). For +more specific ideas, see the [other tutorials and hints](./Howtos-Overview.md) as well +as the [Evennia Component overview](../Components/Components-Overview.md). diff --git a/docs/source/Howto/Understanding-Color-Tags.md b/docs/source/Howtos/Understanding-Color-Tags.md similarity index 100% rename from docs/source/Howto/Understanding-Color-Tags.md rename to docs/source/Howtos/Understanding-Color-Tags.md diff --git a/docs/source/Howto/Weather-Tutorial.md b/docs/source/Howtos/Weather-Tutorial.md similarity index 100% rename from docs/source/Howto/Weather-Tutorial.md rename to docs/source/Howtos/Weather-Tutorial.md diff --git a/docs/source/Howto/Web-Character-Generation.md b/docs/source/Howtos/Web-Character-Generation.md similarity index 100% rename from docs/source/Howto/Web-Character-Generation.md rename to docs/source/Howtos/Web-Character-Generation.md diff --git a/docs/source/Howto/Web-Character-View-Tutorial.md b/docs/source/Howtos/Web-Character-View-Tutorial.md similarity index 100% rename from docs/source/Howto/Web-Character-View-Tutorial.md rename to docs/source/Howtos/Web-Character-View-Tutorial.md diff --git a/docs/source/Licensing.md b/docs/source/Licensing.md index 40ebd78067..911925394d 100644 --- a/docs/source/Licensing.md +++ b/docs/source/Licensing.md @@ -1,4 +1,4 @@ -# Licensing +# Licensing Q&A Evennia is licensed under the very friendly [BSD](https://en.wikipedia.org/wiki/BSD_license) diff --git a/docs/source/Setup/How-to-connect-Evennia-to-Twitter.md b/docs/source/Setup/How-to-connect-Evennia-to-Twitter.md index 2c278a8068..8111c8c89b 100644 --- a/docs/source/Setup/How-to-connect-Evennia-to-Twitter.md +++ b/docs/source/Setup/How-to-connect-Evennia-to-Twitter.md @@ -30,7 +30,7 @@ pip install python-twitter Evennia doesn't have a `tweet` command out of the box so you need to write your own little [Command](../Components/Commands.md) in order to tweet. If you are unsure about how commands work and how to add -them, it can be an idea to go through the [Adding a Command Tutorial](../Howto/Starting/Part1/Adding-Commands.md) +them, it can be an idea to go through the [Adding a Command Tutorial](../Howtos/Beginner-Tutorial/Part1/Adding-Commands.md) before continuing. You can create the command in a separate command module (something like `mygame/commands/tweet.py`) @@ -106,5 +106,5 @@ This shows only a basic tweet setup, other things to do could be: * Echo your tweets to an in-game channel Rather than using an explicit command you can set up a Script to send automatic tweets, for example -to post updated game stats. See the [Tweeting Game Stats tutorial](../Howto/Tutorial-Tweeting-Game-Stats.md) for +to post updated game stats. See the [Tweeting Game Stats tutorial](../Howtos/Tutorial-Tweeting-Game-Stats.md) for help. \ No newline at end of file diff --git a/docs/source/Setup/IRC.md b/docs/source/Setup/IRC.md index b82939a34d..37bdb98de3 100644 --- a/docs/source/Setup/IRC.md +++ b/docs/source/Setup/IRC.md @@ -1,13 +1,8 @@ # IRC - -_Disambiguation: This page is related to using IRC inside an Evennia game. To join the official -Evennia IRC chat, connect to irc.freenode.net and join #evennia. Alternatively, you can [join our -Discord](https://discord.gg/NecFePw), which is mirrored to IRC._ - [IRC (Internet Relay Chat)](https://en.wikipedia.org/wiki/Internet_Relay_Chat) is a long standing chat protocol used by many open-source projects for communicating in real time. By connecting one of -Evennia's [Channels](../Components/Communications.md) to an IRC channel you can communicate also with people not on +Evennia's [Channels](../Components/Channels.md) to an IRC channel you can communicate also with people not on an mud themselves. You can also use IRC if you are only running your Evennia MUD locally on your computer (your game doesn't need to be open to the public)! All you need is an internet connection. For IRC operation you also need [twisted.words](https://twistedmatrix.com/trac/wiki/TwistedWords). diff --git a/docs/source/Setup/Installation-Docker.md b/docs/source/Setup/Installation-Docker.md index ca44d7e5e6..5ba1597427 100644 --- a/docs/source/Setup/Installation-Docker.md +++ b/docs/source/Setup/Installation-Docker.md @@ -1,4 +1,4 @@ -# Running Evennia in Docker +# Installing with Docker Evennia releases [docker images](https://hub.docker.com/r/evennia/evennia/) which makes running an Evennia-based game in a Docker container easy. diff --git a/docs/source/Setup/Installation-Upgrade.md b/docs/source/Setup/Installation-Upgrade.md index 5f4eb1cabd..348378a989 100644 --- a/docs/source/Setup/Installation-Upgrade.md +++ b/docs/source/Setup/Installation-Upgrade.md @@ -39,4 +39,4 @@ changes to your code before it will start with Evennia 1.0. Some important point - The `evennia/contrib/` folder changed structure - there are now categorized sub-folders, so you have to update your imports. - Any `web` changes need to be moved back from your backup into the new structure of `web/` manually. -- See the [Evennia 1.0 Changelog](./Changelog.md) for all changes. \ No newline at end of file +- See the [Evennia 1.0 Changelog](../Coding/Changelog.md) for all changes. \ No newline at end of file diff --git a/docs/source/Setup/Installation.md b/docs/source/Setup/Installation.md index d29c06bf97..33146eaec2 100644 --- a/docs/source/Setup/Installation.md +++ b/docs/source/Setup/Installation.md @@ -96,15 +96,25 @@ To exit the log tailing, enter `Ctrl-C` (`Cmd-C` for Mac). This will not affect The server configuration file is `mygame/server/settings.py`. It's empty by default. Copy and change only the settings you want from the [default settings file](./Settings-Default.md). +## Register with the Evennia Game Index (optional) + +You can optionally let the world know that you are working on a new Evennia-based game by +registering your server with the _Evennia game index_. You don't have to be +open for players to do this - you just mark your game as closed and "pre-alpha". + + evennia connections + +See [here](./Evennia-Game-Index.md) for more instructions and please [check out the index](http:games.evennia.com) +beforehand to make sure you don't pick a game name that is already taken - be nice! ## The Next steps You are good to go! -Evennia comes with a small [Tutorial World](../Howto/Starting/Part1/Tutorial-World.md) to experiment and learn from. After logging +Evennia comes with a small [Tutorial World](../Howtos/Beginner-Tutorial/Part1/Tutorial-World.md) to experiment and learn from. After logging in, you can create it by running batchcommand tutorial_world.build -Next, why not head into the [Starting Tutorial](../Howto/Starting/Part1/Starting-Part1.md) +Next, why not head into the [Starting Tutorial](../Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Part1-Intro.md) to learn how to start making your new game! \ No newline at end of file diff --git a/docs/source/Setup/Online-Setup.md b/docs/source/Setup/Online-Setup.md index 6107365717..cc2f9c304e 100644 --- a/docs/source/Setup/Online-Setup.md +++ b/docs/source/Setup/Online-Setup.md @@ -1,6 +1,5 @@ # Online Setup - Evennia development can be made without any Internet connection beyond fetching updates. At some point however, you are likely to want to make your game visible online, either as part opening it to the public or to allow other developers or beta testers access to it. @@ -18,6 +17,7 @@ remote hosting later in this document. Out of the box, Evennia uses three ports for outward communication. If your computer has a firewall, these should be open for in/out communication (and only these, other ports used by Evennia are internal to your computer only). + - `4000`, telnet, for traditional mud clients - `4001`, HTTP for the website) - `4002`, websocket, for the web client @@ -66,7 +66,7 @@ web services you are running through this router though. You can connect Evennia to the Internet without any changes to your settings. The default settings are easy to use but are not necessarily the safest. You can customize your online presence in your -[settings file](./Server-Conf.md#settings-file). To have Evennia recognize changed port settings you have +[settings file](./Settings.md#settings-file). To have Evennia recognize changed port settings you have to do a full `evennia reboot` to also restart the Portal and not just the Server component. Below is an example of a simple set of settings, mostly using the defaults. Evennia will require diff --git a/docs/source/Setup/Server-Conf.md b/docs/source/Setup/Settings.md similarity index 84% rename from docs/source/Setup/Server-Conf.md rename to docs/source/Setup/Settings.md index 8c3265ca6c..01f476c022 100644 --- a/docs/source/Setup/Server-Conf.md +++ b/docs/source/Setup/Settings.md @@ -1,19 +1,18 @@ -# Server Conf - +# Game Settings and Configuration direcotry Evennia runs out of the box without any changes to its settings. But there are several important ways to customize the server and expand it with your own plugins. +All game-specific settings are located in the `mygame/server/conf/` directory. + ## Settings file The "Settings" file referenced throughout the documentation is the file -`mygame/server/conf/settings.py`. This is automatically created on the first run of `evennia --init` -(see the [Setup Quickstart](./Installation.md) page). +`mygame/server/conf/settings.py`. -Your new `settings.py` is relatively bare out of the box. Evennia's core settings file is actually -[evennia/settings_default.py](https://github.com/evennia/evennia/blob/master/evennia/settings_default.py) -and is considerably more extensive (it is also heavily documented so you should refer to this file -directly for the available settings). +Your new `settings.py` is relatively bare out of the box. Evennia's core settings file is +the [Settings-Default file](./Settings-Default.md) and is considerably more extensive. It is also +heavily documented and up-to-date, so you should refer to this file directly for the available settings. Since `mygame/server/conf/settings.py` is a normal Python module, it simply imports `evennia/settings_default.py` into itself at the top. @@ -46,9 +45,9 @@ Each setting appears as a property on the imported `settings` object. You can a possible options with `evennia.settings_full` (this also includes advanced Django defaults that are not touched in default Evennia). -> It should be pointed out that when importing `settings` into your code like this, it will be *read +> When importing `settings` into your code like this, it will be *read only*. You *cannot* edit your settings from your code! The only way to change an Evennia setting is -to edit `mygame/server/conf/settings.py` directly. You also generally need to restart the server +to edit `mygame/server/conf/settings.py` directly. You will also need to restart the server (possibly also the Portal) before a changed setting becomes available. ## Other files in the `server/conf` directory @@ -94,11 +93,4 @@ by modifying things further down the line (on the command parse level) than here - *at_search.py* - this allows for replacing the way Evennia handles search results. It allows to change how errors are echoed and how multi-matches are resolved and reported (like how the default understands that "2-ball" should match the second "ball" object if there are two of them in the -room). - -## ServerConf - -There is a special database model called `ServerConf` that stores server internal data and settings -such as current account count (for interfacing with the webserver), startup status and many other -things. It's rarely of use outside the server core itself but may be good to -know about if you are an Evennia developer. \ No newline at end of file +room). \ No newline at end of file diff --git a/docs/source/Setup/Setup-Overview.md b/docs/source/Setup/Setup-Overview.md index 148ae74214..eed92376a1 100644 --- a/docs/source/Setup/Setup-Overview.md +++ b/docs/source/Setup/Setup-Overview.md @@ -1,35 +1,48 @@ # Server Setup and Life -This documentation covers how to setup and maintain the server, from first install to opening your game to the public. +This documentation covers how to setup and maintain the server, +from first install to opening your game to the public. ## Installation & running -- [Installation & Setup quick-start](./Installation.md) - one page to quickly get you going -- [Extended Install instructions](./Installation-Git.md) - if you have trouble or want to contribute to Evennia itself -- [Running through Docker](./Installation-Docker.md) - alternative install method, useful for quick deployment on remote servers -- [Installing Evennia on Android](./Installation-Android.md) - for those craving a mobile life -- [Controlling the server](./Start-Stop-Reload.md) - an extended view on how to start/stop/update the server +```{toctree} +:maxdepth: 2 -## Installing custom game dirs - -- [Installing Arxcode](../Contribs/Arxcode-Installation.md) - a custom gamedir based on the popular Evennia game [Arx](https://play.arxgame.org/) +Installation +Installation-Git +Installation-Docker +Installation-Troubleshooting +Installation-Android +Installation-Upgrade +Installation-Non-Interactive +Start-Stop-Reload +``` ## Configuring -- [The settings file](./Settings-Default.md) - how and where to change the main settings of the server -- [Change database engine](./Choosing-An-SQL-Server.md) - if you want to use something other than SQLite3 -- [Evennia game index](./Evennia-Game-Index.md) - register your upcoming game with the index to start the hype going +```{toctree} +:maxdepth: 2 +Settings +Settings-Default +Choosing-An-SQL-Server +Evennia-Game-Index +IRC +Grapevine +RSS +How-to-connect-Evennia-to-Twitter +Client-Support-Grid -- [Chat on IRC](./IRC.md) - how to link your game's channels to an external [IRC](https://en.wikipedia.org/wiki/Internet_Relay_Chat) channel -- [Chat on Grapevine](./Grapevine.md) - how to link your game's channels the [Grapevine](https://grapevine.haus/) mud network/chat -- [Messages to RSS](./RSS.md) - have your game notify people through RSS -- [Messages to Twitter](./How-to-connect-Evennia-to-Twitter.md) - have Evennia send messages to [Twitter](https://twitter.com/) (requires some coding) +``` ## Going public -- [Notes about security](./Security.md) - some things to think about to stay safe(r) - - [Using HAProxy](./HAProxy-Config.md) - putting a proxy in front of the game server for security - - [Using Apache as a webserver](./Apache-Config.md) - use Apache instead of Evennia's webserver (limited support) -- [Taking your server online](./Online-Setup.md) - decide on where to host and configure your game for production -- [Client support grid](./Client-Support-Grid.md) - clients known to work (or not) with Evennia +```{toctree} +:maxdepth: 2 + +Online-Setup +Security +HAProxy-Config +Apache-Config + +``` \ No newline at end of file diff --git a/docs/source/_static/nature.css b/docs/source/_static/nature.css index c4fbe2c591..ee6c86b042 100644 --- a/docs/source/_static/nature.css +++ b/docs/source/_static/nature.css @@ -185,6 +185,7 @@ div.body h6 { div.body h1 { margin-top: 20px solid #fff; + font-size: 230%; } div.body h2 { font-size: 150%; @@ -236,6 +237,9 @@ div.note { text-indent: -2.9em; padding-left: 3.5em; } +div.note > p { + text-indent: 0em; +} div.seealso { background-color: #ffc; @@ -254,11 +258,19 @@ div.warning { padding-left: 5.2em; } +div.warning > p { + text-indent: 0em; +} + div.important { text-indent: -5.5em; padding-left: 6.1em; } +div.important > p { + text-indent: 0em; +} + p.admonition-title { display: inline; } diff --git a/docs/source/index.md b/docs/source/index.md index c9430d5754..11eba37116 100644 --- a/docs/source/index.md +++ b/docs/source/index.md @@ -1,14 +1,11 @@ ```{warning} - This is the **WIP** documentation of the - development branch of Evennia (v1.0-dev). The text is based on the - original Evennia `wiki `_ - but it's being refactored heavily. There are known conversion issues - and missing links. This will slowly be ironed out as this is developed. + This is the **WIP** documentation of the development branch of Evennia (v1.0-dev). - New things will be added to this version only, but for now you are best - off using v0.9.5 of the docs, or the original wiki. You have been warned. + Unless you are beta-testing the new version, you are likely best + off using v0.9.5 of the docs (switch to it in the bottom left) + or the original github wiki. You have been warned. ``` # Evennia Documentation @@ -17,44 +14,60 @@ This is the manual of [Evennia](https://www.evennia.com), the open source Python `MU*` creation system. - [Evennia Introduction](./Evennia-Introduction.md) -- [Install & Setup Quickstart](Setup/Installation.md) -- [Starting tutorial](Howto/Starting/Part1/Starting-Part1.md) +- [Installation](Setup/Installation.md) +- [Beginner Tutorial](Howtos/Beginner-Tutorial/Beginner-Tutorial-Intro.md) - [How to contribute and get help](./Contributing.md) ## Main sections - [Server Setup, Maintenance and Life](Setup/Setup-Overview.md) - how to run, maintain and release -- [Tutorials and Howto's](Howto/Howto-Overview.md) - projects and hints for reaching particular effects and goals +- [Tutorials and Howto's](Howtos/Howtos-Overview.md) - projects and hints for reaching particular effects and goals ---- + - [Core components](Components/Components-Overview.md) - the core building blocks of Evennia - [Concepts](Concepts/Concepts-Overview.md) - larger-scale concepts and features ---- + - [API](./Evennia-API.md) - the full API-reference, generated from source - [Default Commands](Components/Default-Commands.md) - list of game commands included out of the box - [Coding](Coding/Coding-Overview.md) - coding and development hints and resources -- [Contributions](Contribs/Contrib-Overview.md) - game-specific tools and code added by the community +- [Contribs](Contribs/Contribs-Overview.md) - game-specific tools and code added by the community ---- - [Links](./Links.md) - useful links -- [Table of Contents](./toc.md) - an alphabetical listing of all regular documentation pages +- [How to contribute to these docs](./Contributing-Docs.md) - if you want to help out -Want to help improve the docs? See the page on [Contributing to the docs](./Contributing-Docs.md)! +## All Sections + +
+ + Click here to expand the full list of Documentation sections. + + +```{toctree} +:maxdepth: 3 + +Evennia-Introduction +Setup/Setup-Overview +Howtos/Howtos-Overview +Components/Components-Overview +Concepts/Concepts-Overview +Coding/Coding-Overview +Contribs/Contribs-Overview +Contributing +Contributing-Docs +Licensing +Links + +``` +
```{toctree} :hidden: -Evennia-Introduction -Setup/Setup-Quickstart.md -Howto/Starting/Part1/Starting-Part1.md -Contributing.md -Setup/Setup-Overview.md -Howto/Howto-Overview.md -Components/Components-Overview.md -Concepts/Concepts-Overview.md -Evennia-API.md -Components/Default-Commands.md -Coding/Coding-Overview.md -Contribs/Contrib-Overview.md -Links.md +Glossary +Evennia-API +Licensing +Unimplemented ``` diff --git a/docs/source/toc.md b/docs/source/toc.md deleted file mode 100644 index 42795a0e6c..0000000000 --- a/docs/source/toc.md +++ /dev/null @@ -1,558 +0,0 @@ -```{toctree} -- [API root](api/evennia-api.rst) -Coding/Coding-Introduction -Coding/Coding-Overview -Coding/Continuous-Integration -Coding/Debugging -Coding/Flat-API -Coding/Profiling -Coding/Quirks -Coding/Setting-up-PyCharm -Coding/Unit-Testing -Coding/Updating-Your-Game -Coding/Using-Travis -Coding/Version-Control -Components/Accounts -Components/Attributes -Components/Batch-Code-Processor -Components/Batch-Command-Processor -Components/Batch-Processors -Components/Bootstrap-Components-and-Utilities -Components/Channels -Components/Coding-Utils -Components/Command-Sets -Components/Command-System -Components/Commands -Components/Communications -Components/Components-Overview -Components/Connection-Screen -Components/Default-Commands -Components/EvEditor -Components/EvMenu -Components/EvMore -Components/FuncParser -Components/Help-System -Components/Inputfuncs -Components/Locks -Components/MonitorHandler -Components/Msg -Components/Nicks -Components/Objects -Components/Outputfuncs -Components/Permissions -Components/Portal-And-Server -Components/Prototypes -Components/Scripts -Components/Server -Components/Sessions -Components/Signals -Components/Tags -Components/TickerHandler -Components/Typeclasses -Components/Web-API -Components/Web-Admin -Components/Webclient -Components/Webserver -Components/Website -Concepts/Async-Process -Concepts/Banning -Concepts/Bootstrap-&-Evennia -Concepts/Building-Permissions -Concepts/Change-Messages-Per-Receiver -Concepts/Clickable-Links -Concepts/Colors -Concepts/Concepts-Overview -Concepts/Custom-Protocols -Concepts/Guest-Logins -Concepts/Internationalization -Concepts/Messagepath -Concepts/Multisession-modes -Concepts/New-Models -Concepts/OOB -Concepts/Soft-Code -Concepts/Text-Encodings -Concepts/TextTags -Concepts/Using-MUX-as-a-Standard -Concepts/Web-Features -Concepts/Zones -Contribs/Arxcode-Installation -Contribs/Building-menus -Contribs/Contrib-AWSStorage -Contribs/Contrib-Auditing -Contribs/Contrib-Barter -Contribs/Contrib-Batchprocessor -Contribs/Contrib-Bodyfunctions -Contribs/Contrib-Building-Menu -Contribs/Contrib-Clothing -Contribs/Contrib-Color-Markups -Contribs/Contrib-Cooldowns -Contribs/Contrib-Crafting -Contribs/Contrib-Custom-Gametime -Contribs/Contrib-Dice -Contribs/Contrib-Email-Login -Contribs/Contrib-Evscaperoom -Contribs/Contrib-Extended-Room -Contribs/Contrib-Fieldfill -Contribs/Contrib-Gendersub -Contribs/Contrib-Health-Bar -Contribs/Contrib-Ingame-Python -Contribs/Contrib-Ingame-Python-Tutorial-Dialogue -Contribs/Contrib-Ingame-Python-Tutorial-Elevator -Contribs/Contrib-Mail -Contribs/Contrib-Mapbuilder -Contribs/Contrib-Menu-Login -Contribs/Contrib-Mirror -Contribs/Contrib-Multidescer -Contribs/Contrib-Mux-Comms-Cmds -Contribs/Contrib-Overview -Contribs/Contrib-Puzzles -Contribs/Contrib-RPSystem -Contribs/Contrib-Random-String-Generator -Contribs/Contrib-Red-Button -Contribs/Contrib-Simpledoor -Contribs/Contrib-Slow-Exit -Contribs/Contrib-Talking-Npc -Contribs/Contrib-Traits -Contribs/Contrib-Tree-Select -Contribs/Contrib-Turnbattle -Contribs/Contrib-Tutorial-World -Contribs/Contrib-Unixcommand -Contribs/Contrib-Wilderness -Contribs/Contrib-XYZGrid -Contributing -Contributing-Docs -Evennia-API -Evennia-Introduction -Glossary -Howto/Add-a-wiki-on-your-website -Howto/Building-a-mech-tutorial -Howto/Coding-FAQ -Howto/Command-Cooldown -Howto/Command-Duration -Howto/Command-Prompt -Howto/Coordinates -Howto/Default-Exit-Errors -Howto/Dynamic-In-Game-Map -Howto/Evennia-for-Diku-Users -Howto/Evennia-for-MUSH-Users -Howto/Evennia-for-roleplaying-sessions -Howto/Gametime-Tutorial -Howto/Help-System-Tutorial -Howto/Howto-Overview -Howto/Manually-Configuring-Color -Howto/Mass-and-weight-for-objects -Howto/NPC-shop-Tutorial -Howto/Parsing-commands-tutorial -Howto/Starting/Part1/Adding-Commands -Howto/Starting/Part1/Building-Quickstart -Howto/Starting/Part1/Creating-Things -Howto/Starting/Part1/Django-queries -Howto/Starting/Part1/Evennia-Library-Overview -Howto/Starting/Part1/Gamedir-Overview -Howto/Starting/Part1/Learning-Typeclasses -Howto/Starting/Part1/More-on-Commands -Howto/Starting/Part1/Python-basic-introduction -Howto/Starting/Part1/Python-classes-and-objects -Howto/Starting/Part1/Searching-Things -Howto/Starting/Part1/Starting-Part1 -Howto/Starting/Part1/Tutorial-World -Howto/Starting/Part2/Game-Planning -Howto/Starting/Part2/Planning-Some-Useful-Contribs -Howto/Starting/Part2/Planning-The-Tutorial-Game -Howto/Starting/Part2/Planning-Where-Do-I-Begin -Howto/Starting/Part2/Starting-Part2 -Howto/Starting/Part3/A-Sittable-Object -Howto/Starting/Part3/Implementing-a-game-rule-system -Howto/Starting/Part3/Starting-Part3 -Howto/Starting/Part3/Turn-based-Combat-System -Howto/Starting/Part3/Tutorial-for-basic-MUSH-like-game -Howto/Starting/Part4/Starting-Part4 -Howto/Starting/Part5/Add-a-simple-new-web-page -Howto/Starting/Part5/Starting-Part5 -Howto/Starting/Part5/Web-Tutorial -Howto/Static-In-Game-Map -Howto/Tutorial-Aggressive-NPCs -Howto/Tutorial-NPCs-listening -Howto/Tutorial-Tweeting-Game-Stats -Howto/Tutorial-Vehicles -Howto/Understanding-Color-Tags -Howto/Weather-Tutorial -Howto/Web-Character-Generation -Howto/Web-Character-View-Tutorial -Licensing -Links -Setup/Apache-Config -Setup/Changelog -Setup/Choosing-An-SQL-Server -Setup/Client-Support-Grid -Setup/Evennia-Game-Index -Setup/Grapevine -Setup/HAProxy-Config -Setup/How-to-connect-Evennia-to-Twitter -Setup/IRC -Setup/Installation -Setup/Installation-Android -Setup/Installation-Docker -Setup/Installation-Git -Setup/Installation-Non-Interactive -Setup/Installation-Troubleshooting -Setup/Installation-Upgrade -Setup/Online-Setup -Setup/RSS -Setup/Security -Setup/Server-Conf -Setup/Settings-Default -Setup/Setup-Overview -Setup/Start-Stop-Reload -Unimplemented -api/evennia -api/evennia-api -api/evennia.accounts -api/evennia.accounts.accounts -api/evennia.accounts.bots -api/evennia.accounts.manager -api/evennia.accounts.models -api/evennia.commands -api/evennia.commands.cmdhandler -api/evennia.commands.cmdparser -api/evennia.commands.cmdset -api/evennia.commands.cmdsethandler -api/evennia.commands.command -api/evennia.commands.default -api/evennia.commands.default.account -api/evennia.commands.default.admin -api/evennia.commands.default.batchprocess -api/evennia.commands.default.building -api/evennia.commands.default.cmdset_account -api/evennia.commands.default.cmdset_character -api/evennia.commands.default.cmdset_session -api/evennia.commands.default.cmdset_unloggedin -api/evennia.commands.default.comms -api/evennia.commands.default.general -api/evennia.commands.default.help -api/evennia.commands.default.muxcommand -api/evennia.commands.default.syscommands -api/evennia.commands.default.system -api/evennia.commands.default.tests -api/evennia.commands.default.unloggedin -api/evennia.comms -api/evennia.comms.comms -api/evennia.comms.managers -api/evennia.comms.models -api/evennia.contrib -api/evennia.contrib.base_systems -api/evennia.contrib.base_systems.awsstorage -api/evennia.contrib.base_systems.awsstorage.aws_s3_cdn -api/evennia.contrib.base_systems.awsstorage.tests -api/evennia.contrib.base_systems.building_menu -api/evennia.contrib.base_systems.building_menu.building_menu -api/evennia.contrib.base_systems.building_menu.tests -api/evennia.contrib.base_systems.color_markups -api/evennia.contrib.base_systems.color_markups.color_markups -api/evennia.contrib.base_systems.color_markups.tests -api/evennia.contrib.base_systems.custom_gametime -api/evennia.contrib.base_systems.custom_gametime.custom_gametime -api/evennia.contrib.base_systems.custom_gametime.tests -api/evennia.contrib.base_systems.email_login -api/evennia.contrib.base_systems.email_login.connection_screens -api/evennia.contrib.base_systems.email_login.email_login -api/evennia.contrib.base_systems.email_login.tests -api/evennia.contrib.base_systems.ingame_python -api/evennia.contrib.base_systems.ingame_python.callbackhandler -api/evennia.contrib.base_systems.ingame_python.commands -api/evennia.contrib.base_systems.ingame_python.eventfuncs -api/evennia.contrib.base_systems.ingame_python.scripts -api/evennia.contrib.base_systems.ingame_python.tests -api/evennia.contrib.base_systems.ingame_python.typeclasses -api/evennia.contrib.base_systems.ingame_python.utils -api/evennia.contrib.base_systems.menu_login -api/evennia.contrib.base_systems.menu_login.connection_screens -api/evennia.contrib.base_systems.menu_login.menu_login -api/evennia.contrib.base_systems.menu_login.tests -api/evennia.contrib.base_systems.mux_comms_cmds -api/evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds -api/evennia.contrib.base_systems.mux_comms_cmds.tests -api/evennia.contrib.base_systems.unixcommand -api/evennia.contrib.base_systems.unixcommand.tests -api/evennia.contrib.base_systems.unixcommand.unixcommand -api/evennia.contrib.full_systems -api/evennia.contrib.full_systems.evscaperoom -api/evennia.contrib.full_systems.evscaperoom.commands -api/evennia.contrib.full_systems.evscaperoom.menu -api/evennia.contrib.full_systems.evscaperoom.objects -api/evennia.contrib.full_systems.evscaperoom.room -api/evennia.contrib.full_systems.evscaperoom.scripts -api/evennia.contrib.full_systems.evscaperoom.state -api/evennia.contrib.full_systems.evscaperoom.tests -api/evennia.contrib.full_systems.evscaperoom.utils -api/evennia.contrib.game_systems -api/evennia.contrib.game_systems.barter -api/evennia.contrib.game_systems.barter.barter -api/evennia.contrib.game_systems.barter.tests -api/evennia.contrib.game_systems.clothing -api/evennia.contrib.game_systems.clothing.clothing -api/evennia.contrib.game_systems.clothing.tests -api/evennia.contrib.game_systems.cooldowns -api/evennia.contrib.game_systems.cooldowns.cooldowns -api/evennia.contrib.game_systems.cooldowns.tests -api/evennia.contrib.game_systems.crafting -api/evennia.contrib.game_systems.crafting.crafting -api/evennia.contrib.game_systems.crafting.example_recipes -api/evennia.contrib.game_systems.crafting.tests -api/evennia.contrib.game_systems.gendersub -api/evennia.contrib.game_systems.gendersub.gendersub -api/evennia.contrib.game_systems.gendersub.tests -api/evennia.contrib.game_systems.mail -api/evennia.contrib.game_systems.mail.mail -api/evennia.contrib.game_systems.mail.tests -api/evennia.contrib.game_systems.multidescer -api/evennia.contrib.game_systems.multidescer.multidescer -api/evennia.contrib.game_systems.multidescer.tests -api/evennia.contrib.game_systems.puzzles -api/evennia.contrib.game_systems.puzzles.puzzles -api/evennia.contrib.game_systems.puzzles.tests -api/evennia.contrib.game_systems.turnbattle -api/evennia.contrib.game_systems.turnbattle.tb_basic -api/evennia.contrib.game_systems.turnbattle.tb_equip -api/evennia.contrib.game_systems.turnbattle.tb_items -api/evennia.contrib.game_systems.turnbattle.tb_magic -api/evennia.contrib.game_systems.turnbattle.tb_range -api/evennia.contrib.game_systems.turnbattle.tests -api/evennia.contrib.grid -api/evennia.contrib.grid.extended_room -api/evennia.contrib.grid.extended_room.extended_room -api/evennia.contrib.grid.extended_room.tests -api/evennia.contrib.grid.mapbuilder -api/evennia.contrib.grid.mapbuilder.mapbuilder -api/evennia.contrib.grid.mapbuilder.tests -api/evennia.contrib.grid.simpledoor -api/evennia.contrib.grid.simpledoor.simpledoor -api/evennia.contrib.grid.simpledoor.tests -api/evennia.contrib.grid.slow_exit -api/evennia.contrib.grid.slow_exit.slow_exit -api/evennia.contrib.grid.slow_exit.tests -api/evennia.contrib.grid.wilderness -api/evennia.contrib.grid.wilderness.tests -api/evennia.contrib.grid.wilderness.wilderness -api/evennia.contrib.grid.xyzgrid -api/evennia.contrib.grid.xyzgrid.commands -api/evennia.contrib.grid.xyzgrid.example -api/evennia.contrib.grid.xyzgrid.launchcmd -api/evennia.contrib.grid.xyzgrid.prototypes -api/evennia.contrib.grid.xyzgrid.tests -api/evennia.contrib.grid.xyzgrid.utils -api/evennia.contrib.grid.xyzgrid.xymap -api/evennia.contrib.grid.xyzgrid.xymap_legend -api/evennia.contrib.grid.xyzgrid.xyzgrid -api/evennia.contrib.grid.xyzgrid.xyzroom -api/evennia.contrib.rpg -api/evennia.contrib.rpg.dice -api/evennia.contrib.rpg.dice.dice -api/evennia.contrib.rpg.dice.tests -api/evennia.contrib.rpg.health_bar -api/evennia.contrib.rpg.health_bar.health_bar -api/evennia.contrib.rpg.health_bar.tests -api/evennia.contrib.rpg.rpsystem -api/evennia.contrib.rpg.rpsystem.rplanguage -api/evennia.contrib.rpg.rpsystem.rpsystem -api/evennia.contrib.rpg.rpsystem.tests -api/evennia.contrib.rpg.traits -api/evennia.contrib.rpg.traits.tests -api/evennia.contrib.rpg.traits.traits -api/evennia.contrib.tutorials -api/evennia.contrib.tutorials.batchprocessor -api/evennia.contrib.tutorials.batchprocessor.example_batch_code -api/evennia.contrib.tutorials.bodyfunctions -api/evennia.contrib.tutorials.bodyfunctions.bodyfunctions -api/evennia.contrib.tutorials.bodyfunctions.tests -api/evennia.contrib.tutorials.mirror -api/evennia.contrib.tutorials.mirror.mirror -api/evennia.contrib.tutorials.red_button -api/evennia.contrib.tutorials.red_button.red_button -api/evennia.contrib.tutorials.talking_npc -api/evennia.contrib.tutorials.talking_npc.talking_npc -api/evennia.contrib.tutorials.talking_npc.tests -api/evennia.contrib.tutorials.tutorial_world -api/evennia.contrib.tutorials.tutorial_world.intro_menu -api/evennia.contrib.tutorials.tutorial_world.mob -api/evennia.contrib.tutorials.tutorial_world.objects -api/evennia.contrib.tutorials.tutorial_world.rooms -api/evennia.contrib.tutorials.tutorial_world.tests -api/evennia.contrib.utils -api/evennia.contrib.utils.auditing -api/evennia.contrib.utils.auditing.outputs -api/evennia.contrib.utils.auditing.server -api/evennia.contrib.utils.auditing.tests -api/evennia.contrib.utils.fieldfill -api/evennia.contrib.utils.fieldfill.fieldfill -api/evennia.contrib.utils.random_string_generator -api/evennia.contrib.utils.random_string_generator.random_string_generator -api/evennia.contrib.utils.random_string_generator.tests -api/evennia.contrib.utils.tree_select -api/evennia.contrib.utils.tree_select.tests -api/evennia.contrib.utils.tree_select.tree_select -api/evennia.help -api/evennia.help.filehelp -api/evennia.help.manager -api/evennia.help.models -api/evennia.help.utils -api/evennia.locks -api/evennia.locks.lockfuncs -api/evennia.locks.lockhandler -api/evennia.objects -api/evennia.objects.manager -api/evennia.objects.models -api/evennia.objects.objects -api/evennia.prototypes -api/evennia.prototypes.menus -api/evennia.prototypes.protfuncs -api/evennia.prototypes.prototypes -api/evennia.prototypes.spawner -api/evennia.scripts -api/evennia.scripts.manager -api/evennia.scripts.models -api/evennia.scripts.monitorhandler -api/evennia.scripts.scripthandler -api/evennia.scripts.scripts -api/evennia.scripts.taskhandler -api/evennia.scripts.tickerhandler -api/evennia.server -api/evennia.server.amp_client -api/evennia.server.connection_wizard -api/evennia.server.deprecations -api/evennia.server.evennia_launcher -api/evennia.server.game_index_client -api/evennia.server.game_index_client.client -api/evennia.server.game_index_client.service -api/evennia.server.initial_setup -api/evennia.server.inputfuncs -api/evennia.server.manager -api/evennia.server.models -api/evennia.server.portal -api/evennia.server.portal.amp -api/evennia.server.portal.amp_server -api/evennia.server.portal.grapevine -api/evennia.server.portal.irc -api/evennia.server.portal.mccp -api/evennia.server.portal.mssp -api/evennia.server.portal.mxp -api/evennia.server.portal.naws -api/evennia.server.portal.portal -api/evennia.server.portal.portalsessionhandler -api/evennia.server.portal.rss -api/evennia.server.portal.ssh -api/evennia.server.portal.ssl -api/evennia.server.portal.suppress_ga -api/evennia.server.portal.telnet -api/evennia.server.portal.telnet_oob -api/evennia.server.portal.telnet_ssl -api/evennia.server.portal.tests -api/evennia.server.portal.ttype -api/evennia.server.portal.webclient -api/evennia.server.portal.webclient_ajax -api/evennia.server.profiling -api/evennia.server.profiling.dummyrunner -api/evennia.server.profiling.dummyrunner_settings -api/evennia.server.profiling.memplot -api/evennia.server.profiling.settings_mixin -api/evennia.server.profiling.test_queries -api/evennia.server.profiling.tests -api/evennia.server.profiling.timetrace -api/evennia.server.server -api/evennia.server.serversession -api/evennia.server.session -api/evennia.server.sessionhandler -api/evennia.server.signals -api/evennia.server.throttle -api/evennia.server.validators -api/evennia.server.webserver -api/evennia.settings_default -api/evennia.typeclasses -api/evennia.typeclasses.attributes -api/evennia.typeclasses.managers -api/evennia.typeclasses.models -api/evennia.typeclasses.tags -api/evennia.utils -api/evennia.utils.ansi -api/evennia.utils.batchprocessors -api/evennia.utils.containers -api/evennia.utils.create -api/evennia.utils.dbserialize -api/evennia.utils.eveditor -api/evennia.utils.evform -api/evennia.utils.evmenu -api/evennia.utils.evmore -api/evennia.utils.evtable -api/evennia.utils.funcparser -api/evennia.utils.gametime -api/evennia.utils.idmapper -api/evennia.utils.idmapper.manager -api/evennia.utils.idmapper.models -api/evennia.utils.idmapper.tests -api/evennia.utils.logger -api/evennia.utils.optionclasses -api/evennia.utils.optionhandler -api/evennia.utils.picklefield -api/evennia.utils.search -api/evennia.utils.test_resources -api/evennia.utils.text2html -api/evennia.utils.utils -api/evennia.utils.validatorfuncs -api/evennia.utils.verb_conjugation -api/evennia.utils.verb_conjugation.conjugate -api/evennia.utils.verb_conjugation.pronouns -api/evennia.utils.verb_conjugation.tests -api/evennia.web -api/evennia.web.admin -api/evennia.web.admin.accounts -api/evennia.web.admin.attributes -api/evennia.web.admin.comms -api/evennia.web.admin.frontpage -api/evennia.web.admin.help -api/evennia.web.admin.objects -api/evennia.web.admin.scripts -api/evennia.web.admin.server -api/evennia.web.admin.tags -api/evennia.web.admin.urls -api/evennia.web.admin.utils -api/evennia.web.api -api/evennia.web.api.filters -api/evennia.web.api.permissions -api/evennia.web.api.root -api/evennia.web.api.serializers -api/evennia.web.api.tests -api/evennia.web.api.urls -api/evennia.web.api.views -api/evennia.web.templatetags -api/evennia.web.templatetags.addclass -api/evennia.web.urls -api/evennia.web.utils -api/evennia.web.utils.adminsite -api/evennia.web.utils.backends -api/evennia.web.utils.general_context -api/evennia.web.utils.middleware -api/evennia.web.utils.tests -api/evennia.web.webclient -api/evennia.web.webclient.urls -api/evennia.web.webclient.views -api/evennia.web.website -api/evennia.web.website.forms -api/evennia.web.website.tests -api/evennia.web.website.urls -api/evennia.web.website.views -api/evennia.web.website.views.accounts -api/evennia.web.website.views.channels -api/evennia.web.website.views.characters -api/evennia.web.website.views.errors -api/evennia.web.website.views.help -api/evennia.web.website.views.index -api/evennia.web.website.views.mixins -api/evennia.web.website.views.objects -index -``` - -```{toctree} - :hidden: - -toc -``` \ No newline at end of file diff --git a/evennia/commands/default/comms.py b/evennia/commands/default/comms.py index 2ecf0d827d..ee4138a80c 100644 --- a/evennia/commands/default/comms.py +++ b/evennia/commands/default/comms.py @@ -1578,7 +1578,7 @@ class CmdIRC2Chan(COMMAND_DEFAULT_CLASS): irc_port=irc_port, irc_ssl=irc_ssl, ) - self.msg("Connection created. Starting IRC bot.") + self.msg("Connection created. Beginner-Tutorial IRC bot.") class CmdIRCStatus(COMMAND_DEFAULT_CLASS): diff --git a/evennia/commands/default/system.py b/evennia/commands/default/system.py index 8eae534042..a97f6bed6a 100644 --- a/evennia/commands/default/system.py +++ b/evennia/commands/default/system.py @@ -622,7 +622,7 @@ class CmdService(COMMAND_DEFAULT_CLASS): if service.running: caller.msg("That service is already running.") return - caller.msg(f"Starting service '{self.args}' ...") + caller.msg(f"Beginner-Tutorial service '{self.args}' ...") try: service.startService() except Exception as err: diff --git a/evennia/contrib/base_systems/awsstorage/README.md b/evennia/contrib/base_systems/awsstorage/README.md index 2654d1eea5..b88dc585e9 100644 --- a/evennia/contrib/base_systems/awsstorage/README.md +++ b/evennia/contrib/base_systems/awsstorage/README.md @@ -29,7 +29,7 @@ of storage space on S3, making the current total cost of running this plugin them to many users, caveat emptor on a total cost of ownership - check AWS's pricing structure. -# Technical details +## Technical details This is a drop-in replacement that operates deeper than all of Evennia's code, so your existing code does not need to change at all to support it. @@ -52,9 +52,9 @@ other contributions or custom code. Simply work how you would normally, Django will handle the rest. -# Installation +## Installation -## Set up AWS account +### Set up AWS account If you don't have an AWS S3 account, you should create one at https://aws.amazon.com/ - documentation for AWS S3 is available at: @@ -161,7 +161,7 @@ checking the source of any image (for instance, the logo). It should read `https://your-bucket-name.s3.amazonaws.com/path/to/file`. If so, the system works and you shouldn't need to do anything else. -# Uninstallation +## Uninstallation If you haven't made changes to your static files (uploaded images, etc), you can simply remove the lines you added to `secret_settings.py`. If you @@ -170,7 +170,7 @@ your files from your S3 bucket and put them in /static/ in the evennia directory. -# License +## License Draws heavily from code provided by django-storages, for which these contributors are authors: @@ -221,6 +221,6 @@ Andrew Perry (Bug fixes in SFTPStorage) The repurposed code from django-storages is released under BSD 3-Clause, same as Evennia, so for detailed licensing, refer to the Evennia license. -# Versioning +## Versioning This is confirmed to work for Django 2 and Django 3. diff --git a/evennia/contrib/base_systems/building_menu/README.md b/evennia/contrib/base_systems/building_menu/README.md index 54ec657d82..c6f18733f9 100644 --- a/evennia/contrib/base_systems/building_menu/README.md +++ b/evennia/contrib/base_systems/building_menu/README.md @@ -31,7 +31,7 @@ that will edit any default object, offering to change its key and description. self.add(GenericBuildingCmd()) ``` -## Usage +## Basic Usage The `edit` command will allow you to edit any object. You will need to specify the object name or ID as an argument. For instance: `edit here` @@ -121,6 +121,1222 @@ class CmdEdit(Command): ``` -This is a very short introduction. For more details, see the [online -tutorial](https://github.com/evennia/evennia/wiki/Building-menus) or read the -heavily-documented code of the contrib itself. + +## A simple menu example + +Before diving in, there are some things to point out: + +- Building menus work on an object. This object will be edited by manipulations in the menu. So +you can create a menu to add/edit a room, an exit, a character and so on. +- Building menus are arranged in layers of choices. A choice gives access to an option or to a sub- +menu. Choices are linked to commands (usually very short). For instance, in the example shown +below, to edit the room key, after opening the building menu, you can type `k`. That will lead you +to the key choice where you can enter a new key for the room. Then you can enter `@` to leave this +choice and go back to the entire menu. (All of this can be changed). +- To open the menu, you will need something like a command. This contrib offers a basic command for +demonstration, but we will override it in this example, using the same code with more flexibility. + +So let's add a very basic example to begin with. + +### A generic editing command + +Let's begin by adding a new command. You could add or edit the following file (there's no trick +here, feel free to organize the code differently): + +```python +# file: commands/building.py +from evennia.contrib.building_menu import BuildingMenu +from commands.command import Command + +class EditCmd(Command): + + """ + Editing command. + + Usage: + @edit [object] + + Open a building menu to edit the specified object. This menu allows to + specific information about this object. + + Examples: + @edit here + @edit self + @edit #142 + + """ + + key = "@edit" + locks = "cmd:id(1) or perm(Builders)" + help_category = "Building" + + def func(self): + if not self.args.strip(): + self.msg("|rYou should provide an argument to this function: the object to edit.|n") + return + + obj = self.caller.search(self.args.strip(), global_search=True) + if not obj: + return + + if obj.typename == "Room": + Menu = RoomBuildingMenu + else: + obj_name = obj.get_display_name(self.caller) + self.msg(f"|rThe object {obj_name} cannot be edited.|n") + return + + menu = Menu(self.caller, obj) + menu.open() +``` + +This command is rather simple in itself: + +1. It has a key `@edit` and a lock to only allow builders to use it. +2. In its `func` method, it begins by checking the arguments, returning an error if no argument is +specified. +3. It then searches for the given argument. We search globally. The `search` method used in this +way will return the found object or `None`. It will also send the error message to the caller if +necessary. +4. Assuming we have found an object, we check the object `typename`. This will be used later when +we want to display several building menus. For the time being, we only handle `Room`. If the +caller specified something else, we'll display an error. +5. Assuming this object is a `Room`, we have defined a `Menu` object containing the class of our +building menu. We build this class (creating an instance), giving it the caller and the object to +edit. +6. We then open the building menu, using the `open` method. + +The end might sound a bit surprising at first glance. But the process is still very simple: we +create an instance of our building menu and call its `open` method. Nothing more. + +> Where is our building menu? + +If you go ahead and add this command and test it, you'll get an error. We haven't defined +`RoomBuildingMenu` yet. + +To add this command, edit `commands/default_cmdsets.py`. Import our command, adding an import line +at the top of the file: + +```python +""" +... +""" + +from evennia import default_cmds + +# The following line is to be added +from commands.building import EditCmd +``` + +And in the class below (`CharacterCmdSet`), add the last line of this code: + +```python +class CharacterCmdSet(default_cmds.CharacterCmdSet): + """ + The `CharacterCmdSet` contains general in-game commands like `look`, + `get`, etc available on in-game Character objects. It is merged with + the `AccountCmdSet` when an Account puppets a Character. + """ + key = "DefaultCharacter" + + def at_cmdset_creation(self): + """ + Populates the cmdset + """ + super().at_cmdset_creation() + # + # any commands you add below will overload the default ones. + # + self.add(EditCmd()) +``` + +### Our first menu + +So far, we can't use our building menu. Our `@edit` command will throw an error. We have to define +the `RoomBuildingMenu` class. Open the `commands/building.py` file and add to the end of the file: + +```python +# ... at the end of commands/building.py +# Our building menu + +class RoomBuildingMenu(BuildingMenu): + + """ + Building menu to edit a room. + + For the time being, we have only one choice: key, to edit the room key. + + """ + + def init(self, room): + self.add_choice("key", "k", attr="key") +``` + +Save these changes, reload your game. You can now use the `@edit` command. Here's what we get +(notice that the commands we enter into the game are prefixed with `> `, though this prefix will +probably not appear in your MUD client): + +``` +> look +Limbo(#2) +Welcome to your new Evennia-based game! Visit https://www.evennia.com if you need +help, want to contribute, report issues or just join the community. +As Account #1 you can create a demo/tutorial area with @batchcommand tutorial_world.build. + +> @edit here +Building menu: Limbo + + [K]ey: Limbo + [Q]uit the menu + +> q +Closing the building menu. + +> @edit here +Building menu: Limbo + + [K]ey: Limbo + [Q]uit the menu + +> k +------------------------------------------------------------------------------- +key for Limbo(#2) + +You can change this value simply by entering it. + +Use @ to go back to the main menu. + +Current value: Limbo + +> A beautiful meadow +------------------------------------------------------------------------------- + +key for A beautiful meadow(#2) + +You can change this value simply by entering it. + +Use @ to go back to the main menu. + +Current value: A beautiful meadow + +> @ +Building menu: A beautiful meadow + + [K]ey: A beautiful meadow + [Q]uit the menu + +> q + +Closing the building menu. + +> look +A beautiful meadow(#2) +Welcome to your new Evennia-based game! Visit https://www.evennia.com if you need +help, want to contribute, report issues or just join the community. +As Account #1 you can create a demo/tutorial area with @batchcommand tutorial_world.build. +``` + +Before diving into the code, let's examine what we have: + +- When we use the `@edit here` command, a building menu for this room appears. +- This menu has two choices: + - Enter `k` to edit the room key. You will go into a choice where you can simply type the key +room key (the way we have done here). You can use `@` to go back to the menu. + - You can use `q` to quit the menu. + +We then check, with the `look` command, that the menu has modified this room key. So by adding a +class, with a method and a single line of code within, we've added a menu with two choices. + +### Code explanation + +Let's examine our code again: + +```python +class RoomBuildingMenu(BuildingMenu): + + """ + Building menu to edit a room. + + For the time being, we have only one choice: key, to edit the room key. + + """ + + def init(self, room): + self.add_choice("key", "k", attr="key") +``` + +- We first create a class inheriting from `BuildingMenu`. This is usually the case when we want to +create a building menu with this contrib. +- In this class, we override the `init` method, which is called when the menu opens. +- In this `init` method, we call `add_choice`. This takes several arguments, but we've defined only +three here: + - The choice name. This is mandatory and will be used by the building menu to know how to +display this choice. + - The command key to access this choice. We've given a simple `"k"`. Menu commands usually are +pretty short (that's part of the reason building menus are appreciated by builders). You can also +specify additional aliases, but we'll see that later. + - We've added a keyword argument, `attr`. This tells the building menu that when we are in this +choice, the text we enter goes into this attribute name. It's called `attr`, but it could be a room +attribute or a typeclass persistent or non-persistent attribute (we'll see other examples as well). + +> We've added the menu choice for `key` here, why is another menu choice defined for `quit`? + +Our building menu creates a choice at the end of our choice list if it's a top-level menu (sub-menus +don't have this feature). You can, however, override it to provide a different "quit" message or to +perform some actions. + +I encourage you to play with this code. As simple as it is, it offers some functionalities already. + +## Customizing building menus + +This somewhat long section explains how to customize building menus. There are different ways +depending on what you would like to achieve. We'll go from specific to more advanced here. + +### Generic choices + +In the previous example, we've used `add_choice`. This is one of three methods you can use to add +choices. The other two are to handle more generic actions: + +- `add_choice_edit`: this is called to add a choice which points to the `EvEditor`. It is used to +edit a description in most cases, although you could edit other things. We'll see an example +shortly. `add_choice_edit` uses most of the `add_choice` keyword arguments we'll see, but usually +we specify only two (sometimes three): + - The choice title as usual. + - The choice key (command key) as usual. + - Optionally, the attribute of the object to edit, with the `attr` keyword argument. By +default, `attr` contains `db.desc`. It means that this persistent data attribute will be edited by +the `EvEditor`. You can change that to whatever you want though. +- `add_choice_quit`: this allows to add a choice to quit the editor. Most advisable! If you don't +do it, the building menu will do it automatically, except if you really tell it not to. Again, you +can specify the title and key of this menu. You can also call a function when this menu closes. + +So here's a more complete example (you can replace your `RoomBuildingMenu` class in +`commands/building.py` to see it): + +```python +class RoomBuildingMenu(BuildingMenu): + + """ + Building menu to edit a room. + """ + + def init(self, room): + self.add_choice("key", "k", attr="key") + self.add_choice_edit("description", "d") + self.add_choice_quit("quit this editor", "q") +``` + +So far, our building menu class is still thin... and yet we already have some interesting feature. +See for yourself the following MUD client output (again, the commands are prefixed with `> ` to +distinguish them): + +``` +> @reload + +> @edit here +Building menu: A beautiful meadow + + [K]ey: A beautiful meadow + [D]escription: + Welcome to your new Evennia-based game! Visit https://www.evennia.com if you need +help, want to contribute, report issues or just join the community. +As Account #1 you can create a demo/tutorial area with @batchcommand tutorial_world.build. + [Q]uit this editor + +> d + +----------Line Editor [editor]---------------------------------------------------- +01| Welcome to your new |wEvennia|n-based game! Visit https://www.evennia.com if you need +02| help, want to contribute, report issues or just join the community. +03| As Account #1 you can create a demo/tutorial area with |w@batchcommand tutorial_world.build|n. + +> :DD + +----------[l:03 w:034 c:0247]------------(:h for help)---------------------------- +Cleared 3 lines from buffer. + +> This is a beautiful meadow. But so beautiful I can't describe it. + +01| This is a beautiful meadow. But so beautiful I can't describe it. + +> :wq +Building menu: A beautiful meadow + + [K]ey: A beautiful meadow + [D]escription: + This is a beautiful meadow. But so beautiful I can't describe it. + [Q]uit this editor + +> q +Closing the building menu. + +> look +A beautiful meadow(#2) +This is a beautiful meadow. But so beautiful I can't describe it. +``` + +So by using the `d` shortcut in our building menu, an `EvEditor` opens. You can use the `EvEditor` +commands (like we did here, `:DD` to remove all, `:wq` to save and quit). When you quit the editor, +the description is saved (here, in `room.db.desc`) and you go back to the building menu. + +Notice that the choice to quit has changed too, which is due to our adding `add_choice_quit`. In +most cases, you will probably not use this method, since the quit menu is added automatically. + +### `add_choice` options + +`add_choice` and the two methods `add_choice_edit` and `add_choice_quit` take a lot of optional +arguments to make customization easier. Some of these options might not apply to `add_choice_edit` +or `add_choice_quit` however. + +Below are the options of `add_choice`, specify them as arguments: + +- The first positional, mandatory argument is the choice title, as we have seen. This will +influence how the choice appears in the menu. +- The second positional, mandatory argument is the command key to access to this menu. It is best +to use keyword arguments for the other arguments. +- The `aliases` keyword argument can contain a list of aliases that can be used to access to this +menu. For instance: `add_choice(..., aliases=['t'])` +- The `attr` keyword argument contains the attribute to edit when this choice is selected. It's a +string, it has to be the name, from the object (specified in the menu constructor) to reach this +attribute. For instance, a `attr` of `"key"` will try to find `obj.key` to read and write the +attribute. You can specify more complex attribute names, for instance, `attr="db.desc"` to set the +`desc` persistent attribute, or `attr="ndb.something"` so use a non-persistent data attribute on the +object. +- The `text` keyword argument is used to change the text that will be displayed when the menu choice +is selected. Menu choices provide a default text that you can change. Since this is a long text, +it's useful to use multi-line strings (see an example below). +- The `glance` keyword argument is used to specify how to display the current information while in +the menu, when the choice hasn't been opened. If you examine the previous examples, you will see +that the current (`key` or `db.desc`) was shown in the menu, next to the command key. This is +useful for seeing at a glance the current value (hence the name). Again, menu choices will provide +a default glance if you don't specify one. +- The `on_enter` keyword argument allows to add a callback to use when the menu choice is opened. +This is more advanced, but sometimes useful. +- The `on_nomatch` keyword argument is called when, once in the menu, the caller enters some text +that doesn't match any command (including the `@` command). By default, this will edit the +specified `attr`. +- The `on_leave` keyword argument allows to specify a callback used when the caller leaves the menu +choice. This can be useful for cleanup as well. + +These are a lot of possibilities, and most of the time you won't need them all. Here is a short +example using some of these arguments (again, replace the `RoomBuildingMenu` class in +`commands/building.py` with the following code to see it working): + +```python +class RoomBuildingMenu(BuildingMenu): + + """ + Building menu to edit a room. + + For the time being, we have only one choice: key, to edit the room key. + + """ + + def init(self, room): + self.add_choice("title", key="t", attr="key", glance="{obj.key}", text=""" + ------------------------------------------------------------------------------- + Editing the title of {{obj.key}}(#{{obj.id}}) + + You can change the title simply by entering it. + Use |y{back}|n to go back to the main menu. + + Current title: |c{{obj.key}}|n + """.format(back="|n or |y".join(self.keys_go_back))) + self.add_choice_edit("description", "d") +``` + +Reload your game and see it in action: + +``` +> @edit here +Building menu: A beautiful meadow + + [T]itle: A beautiful meadow + [D]escription: + This is a beautiful meadow. But so beautiful I can't describe it. + [Q]uit the menu + +> t +------------------------------------------------------------------------------- + +Editing the title of A beautiful meadow(#2) + +You can change the title simply by entering it. +Use @ to go back to the main menu. + +Current title: A beautiful meadow + +> @ + +Building menu: A beautiful meadow + + [T]itle: A beautiful meadow + [D]escription: + This is a beautiful meadow. But so beautiful I can't describe it. + [Q]uit the menu + +> q +Closing the building menu. +``` + +The most surprising part is no doubt the text. We use the multi-line syntax (with `"""`). +Excessive spaces will be removed from the left for each line automatically. We specify some +information between braces... sometimes using double braces. What might be a bit odd: + +- `{back}` is a direct format argument we'll use (see the `.format` specifiers). +- `{{obj...}}` refers to the object being edited. We use two braces, because `.format` will remove them. + +In `glance`, we also use `{obj.key}` to indicate we want to show the room's key. + +### Everything can be a function + +The keyword arguments of `add_choice` are often strings (type `str`). But each of these arguments +can also be a function. This allows for a lot of customization, since we define the callbacks that +will be executed to achieve such and such an operation. + +To demonstrate, we will try to add a new feature. Our building menu for rooms isn't that bad, but +it would be great to be able to edit exits too. So we can add a new menu choice below +description... but how to actually edit exits? Exits are not just an attribute to set: exits are +objects (of type `Exit` by default) which stands between two rooms (object of type `Room`). So how +can we show that? + +First let's add a couple of exits in limbo, so we have something to work with: + +``` +@tunnel n +@tunnel s +``` + +This should create two new rooms, exits leading to them from limbo and back to limbo. + +``` +> look +A beautiful meadow(#2) +This is a beautiful meadow. But so beautiful I can't describe it. +Exits: north(#4) and south(#7) +``` + +We can access room exits with the `exits` property: + +``` +> @py here.exits +[, ] +``` + +So what we need is to display this list in our building menu... and to allow to edit it would be +great. Perhaps even add new exits? + +First of all, let's write a function to display the `glance` on existing exits. Here's the code, +it's explained below: + +```python +class RoomBuildingMenu(BuildingMenu): + + """ + Building menu to edit a room. + + """ + + def init(self, room): + self.add_choice("title", key="t", attr="key", glance="{obj.key}", text=""" + ------------------------------------------------------------------------------- + Editing the title of {{obj.key}}(#{{obj.id}}) + + You can change the title simply by entering it. + Use |y{back}|n to go back to the main menu. + + Current title: |c{{obj.key}}|n + """.format(back="|n or |y".join(self.keys_go_back))) + self.add_choice_edit("description", "d") + self.add_choice("exits", "e", glance=glance_exits, attr="exits") + + +# Menu functions +def glance_exits(room): + """Show the room exits.""" + if room.exits: + glance = "" + for exit in room.exits: + glance += f"\n |y{exit.key}|n" + + return glance + + return "\n |gNo exit yet|n" +``` + +When the building menu opens, it displays each choice to the caller. A choice is displayed with its +title (rendered a bit nicely to show the key as well) and the glance. In the case of the `exits` +choice, the glance is a function, so the building menu calls this function giving it the object +being edited (the room here). The function should return the text to see. + +``` +> @edit here +Building menu: A beautiful meadow + + [T]itle: A beautiful meadow + [D]escription: + This is a beautiful meadow. But so beautiful I can't describe it. + [E]xits: + north + south + [Q]uit the menu + +> q +Closing the editor. +``` + +> How do I know the parameters of the function to give? + +The function you give can accept a lot of different parameters. This allows for a flexible approach +but might seem complicated at first. Basically, your function can accept any parameter, and the +building menu will send only the parameter based on their names. If your function defines an +argument named `caller` for instance (like `def func(caller):` ), then the building menu knows that +the first argument should contain the caller of the building menu. Here are the arguments, you +don't have to specify them (if you do, they need to have the same name): + +- `menu`: if your function defines an argument named `menu`, it will contain the building menu +itself. +- `choice`: if your function defines an argument named `choice`, it will contain the `Choice` object +representing this menu choice. +- `string`: if your function defines an argument named `string`, it will contain the user input to +reach this menu choice. This is not very useful, except on `nomatch` callbacks which we'll see +later. +- `obj`: if your function defines an argument named `obj`, it will contain the building menu edited +object. +- `caller`: if your function defines an argument named `caller`, it will contain the caller of the +building menu. +- Anything else: any other argument will contain the object being edited by the building menu. + +So in our case: + +```python +def glance_exits(room): +``` + +The only argument we need is `room`. It's not present in the list of possible arguments, so the +editing object of the building menu (the room, here) is given. + +> Why is it useful to get the menu or choice object? + +Most of the time, you will not need these arguments. In very rare cases, you will use them to get +specific data (like the default attribute that was set). This tutorial will not elaborate on these +possibilities. Just know that they exist. + +We should also define a text callback, so that we can enter our menu to see the room exits. We'll +see how to edit them in the next section but this is a good opportunity to show a more complete +callback. To see it in action, as usual, replace the class and functions in `commands/building.py`: + +```python +# Our building menu + +class RoomBuildingMenu(BuildingMenu): + + """ + Building menu to edit a room. + + """ + + def init(self, room): + self.add_choice("title", key="t", attr="key", glance="{obj.key}", text=""" + ------------------------------------------------------------------------------- + Editing the title of {{obj.key}}(#{{obj.id}}) + + You can change the title simply by entering it. + Use |y{back}|n to go back to the main menu. + + Current title: |c{{obj.key}}|n + """.format(back="|n or |y".join(self.keys_go_back))) + self.add_choice_edit("description", "d") + self.add_choice("exits", "e", glance=glance_exits, attr="exits", text=text_exits) + + +# Menu functions +def glance_exits(room): + """Show the room exits.""" + if room.exits: + glance = "" + for exit in room.exits: + glance += f"\n |y{exit.key}|n" + + return glance + + return "\n |gNo exit yet|n" + +def text_exits(caller, room): + """Show the room exits in the choice itself.""" + text = "-" * 79 + text += "\n\nRoom exits:" + text += "\n Use |y@c|n to create a new exit." + text += "\n\nExisting exits:" + if room.exits: + for exit in room.exits: + text += f"\n |y@e {exit.key}|n" + if exit.aliases.all(): + text += " (|y{aliases}|n)".format(aliases="|n, |y".join( + alias for alias in exit.aliases.all() + )) + if exit.destination: + text += f" toward {exit.get_display_name(caller)}" + else: + text += "\n\n |gNo exit has yet been defined.|n" + + return text +``` + +Look at the second callback in particular. It takes an additional argument, the caller (remember, +the argument names are important, their order is not relevant). This is useful for displaying +destination of exits accurately. Here is a demonstration of this menu: + +``` +> @edit here +Building menu: A beautiful meadow + + [T]itle: A beautiful meadow + [D]escription: + This is a beautiful meadow. But so beautiful I can't describe it. + [E]xits: + north + south + [Q]uit the menu + +> e +------------------------------------------------------------------------------- + +Room exits: + Use @c to create a new exit. + +Existing exits: + @e north (n) toward north(#4) + @e south (s) toward south(#7) + +> @ +Building menu: A beautiful meadow + + [T]itle: A beautiful meadow + [D]escription: + This is a beautiful meadow. But so beautiful I can't describe it. + [E]xits: + north + south + [Q]uit the menu + +> q +Closing the building menu. +``` + +Using callbacks allows a great flexibility. We'll now see how to handle sub-menus. + +### Sub-menus for complex menus + +A menu is relatively flat: it has a root (where you see all the menu choices) and individual choices +you can go to using the menu choice keys. Once in a choice you can type some input or go back to +the root menu by entering the return command (usually `@`). + +Why shouldn't individual exits have their own menu though? Say, you edit an exit and can change its +key, description or aliases... perhaps even destination? Why ever not? It would make building much +easier! + +The building menu system offers two ways to do that. The first is nested keys: nested keys allow to +go beyond just one menu/choice, to have menus with more layers. Using them is quick but might feel +a bit counter-intuitive at first. Another option is to create a different menu class and redirect +from the first to the second. This option might require more lines but is more explicit and can be +re-used for multiple menus. Adopt one of them depending of your taste. + +#### Nested menu keys + +So far, we've only used menu keys with one letter. We can add more, of course, but menu keys in +their simple shape are just command keys. Press "e" to go to the "exits" choice. + +But menu keys can be nested. Nested keys allow to add choices with sub-menus. For instance, type +"e" to go to the "exits" choice, and then you can type "c" to open a menu to create a new exit, or +"d" to open a menu to delete an exit. The first menu would have the "e.c" key (first e, then c), +the second menu would have key as "e.d". + +That's more advanced and, if the following code doesn't sound very friendly to you, try the next +section which provides a different approach of the same problem. + +So we would like to edit exits. That is, you can type "e" to go into the choice of exits, then +enter `@e` followed by the exit name to edit it... which will open another menu. In this sub-menu +you could change the exit key or description. + +So we have a menu hierarchy similar to that: + +``` +t Change the room title +d Change the room description +e Access the room exits + [exit name] Access the exit name sub-menu + [text] Change the exit key +``` + +Or, if you prefer an example output: + +``` +> look +A beautiful meadow(#2) +This is a beautiful meadow. But so beautiful I can't describe it. +Exits: north(#4) and south(#7) + +> @edit here +Building menu: A beautiful meadow + + [T]itle: A beautiful meadow + [D]escription: + This is a beautiful meadow. But so beautiful I can't describe it. + [E]xits: + north + south + [Q]uit the menu + +> e +------------------------------------------------------------------------------- + +Room exits : + Use @c to create a new exit. + +Existing exits: + @e north (n) toward north(#4) + @e south (s) toward south(#7) + +> @e north +Editing: north +Exit north: +Enter the exit key to change it, or @ to go back. + +New exit key: + +> door + +Exit door: +Enter the exit key to change it, or @ to go back. + +New exit key: + +> @ + +------------------------------------------------------------------------------- + +Room exits : + Use @c to create a new exit. + +Existing exits: + @e door (n) toward door(#4) + @e south (s) toward south(#7) + +> @ +Building menu: A beautiful meadow + + [T]itle: A beautiful meadow + [D]escription: + This is a beautiful meadow. But so beautiful I can't describe it. + [E]xits: + door + south + [Q]uit the menu + +> q +Closing the building menu. +``` + +This needs a bit of code and a bit of explanation. So here we go... the code first, the +explanations next! + +```python +# ... from commands/building.py +# Our building menu + +class RoomBuildingMenu(BuildingMenu): + + """ + Building menu to edit a room. + + For the time being, we have only one choice: key, to edit the room key. + + """ + + def init(self, room): + self.add_choice("title", key="t", attr="key", glance="{obj.key}", text=""" + ------------------------------------------------------------------------------- + Editing the title of {{obj.key}}(#{{obj.id}}) + + You can change the title simply by entering it. + Use |y{back}|n to go back to the main menu. + + Current title: |c{{obj.key}}|n + """.format(back="|n or |y".join(self.keys_go_back))) + self.add_choice_edit("description", "d") + self.add_choice("exits", "e", glance=glance_exits, text=text_exits, on_nomatch=nomatch_exits) + + # Exit sub-menu + self.add_choice("exit", "e.*", text=text_single_exit, on_nomatch=nomatch_single_exit) + + +# Menu functions +def glance_exits(room): + """Show the room exits.""" + if room.exits: + glance = "" + for exit in room.exits: + glance += f"\n |y{exit.key}|n" + + return glance + + return "\n |gNo exit yet|n" + +def text_exits(caller, room): + """Show the room exits in the choice itself.""" + text = "-" * 79 + text += "\n\nRoom exits:" + text += "\n Use |y@c|n to create a new exit." + text += "\n\nExisting exits:" + if room.exits: + for exit in room.exits: + text += f"\n |y@e {exit.key}|n" + if exit.aliases.all(): + text += " (|y{aliases}|n)".format(aliases="|n, |y".join( + alias for alias in exit.aliases.all() + )) + if exit.destination: + text += f" toward {exit.get_display_name(caller)}" + else: + text += "\n\n |gNo exit has yet been defined.|n" + + return text + +def nomatch_exits(menu, caller, room, string): + """ + The user typed something in the list of exits. Maybe an exit name? + """ + string = string[3:] + exit = caller.search(string, candidates=room.exits) + if exit is None: + return + + # Open a sub-menu, using nested keys + caller.msg(f"Editing: {exit.key}") + menu.move(exit) + return False + +# Exit sub-menu +def text_single_exit(menu, caller): + """Show the text to edit single exits.""" + exit = menu.keys[1] + if exit is None: + return "" + + return f""" + Exit {exit.key}: + + Enter the exit key to change it, or |y@|n to go back. + + New exit key: + """ + +def nomatch_single_exit(menu, caller, room, string): + """The user entered something in the exit sub-menu. Replace the exit key.""" + # exit is the second key element: keys should contain ['e', ] + exit = menu.keys[1] + if exit is None: + caller.msg("|rCannot find the exit.|n") + menu.move(back=True) + return False + + exit.key = string + return True +``` + +> That's a lot of code! And we only handle editing the exit key! + +That's why at some point you might want to write a real sub-menu, instead of using simple nested +keys. But you might need both to build pretty menus too! + +1. The first thing new is in our menu class. After creating a `on_nomatch` callback for the exits +menu (that shouldn't be a surprised), we need to add a nested key. We give this menu a key of +`"e.*"`. That's a bit odd! "e" is our key to the exits menu, . is the separator to indicate a +nested menu, and * means anything. So basically, we create a nested menu that is contains within +the exits menu and anything. We'll see what this "anything" is in practice. +2. The `glance_exits` and `text_exits` are basically the same. +3. The `nomatch_exits` is short but interesting. It's called when we enter some text in the "exits" +menu (that is, in the list of exits). We have said that the user should enter `@e` followed by the +exit name to edit it. So in the `nomatch_exits` callbac, we check for that input. If the entered +text begins by `@e`, we try to find the exit in the room. If we do... +4. We call the `menu.move` method. That's where things get a bit complicated with nested menus: we +need to use `menu.move` to change from layer to layer. Here, we are in the choice of exits (the +exits menu, of key "e"). We need to go down one layer to edit an exit. So we call `menu.move` and +give it an exit object. The menu system remembers what position the user is based on the keys she +has entered: when the user opens the menu, there is no key. If she selects the exits choice, the +menu key being "e", the position of the user is `["e"]` (a list with the menu keys). If we call +`menu.move`, whatever we give to this method will be appended to the list of keys, so that the user +position becomes `["e", ]`. +5. In the menu class, we have defined the menu `"e.*"`, meaning "the menu contained in the exits +choice plus anything". The "anything" here is an exit: we have called `menu.move(exit)`, so the +`"e.*"` menu choice is chosen. +6. In this menu, the text is set to a callback. There is also a `on_nomatch` callback that is +called whenever the user enters some text. If so, we change the exit name. + +Using `menu.move` like this is a bit confusing at first. Sometimes it's useful. In this case, if +we want a more complex menu for exits, it makes sense to use a real sub-menu, not nested keys like +this. But sometimes, you will find yourself in a situation where you don't need a full menu to +handle a choice. + +## Full sub-menu as separate classes + +The best way to handle individual exits is to create two separate classes: + +- One for the room menu. +- One for the individual exit menu. + +The first one will have to redirect on the second. This might be more intuitive and flexible, +depending on what you want to achieve. So let's build two menus: + +```python +# Still in commands/building.py, replace the menu class and functions by... +# Our building menus + +class RoomBuildingMenu(BuildingMenu): + + """ + Building menu to edit a room. + """ + + def init(self, room): + self.add_choice("title", key="t", attr="key", glance="{obj.key}", text=""" + ------------------------------------------------------------------------------- + Editing the title of {{obj.key}}(#{{obj.id}}) + + You can change the title simply by entering it. + Use |y{back}|n to go back to the main menu. + + Current title: |c{{obj.key}}|n + """.format(back="|n or |y".join(self.keys_go_back))) + self.add_choice_edit("description", "d") + self.add_choice("exits", "e", glance=glance_exits, text=text_exits, +on_nomatch=nomatch_exits) + + +# Menu functions +def glance_exits(room): + """Show the room exits.""" + if room.exits: + glance = "" + for exit in room.exits: + glance += f"\n |y{exit.key}|n" + + return glance + + return "\n |gNo exit yet|n" + +def text_exits(caller, room): + """Show the room exits in the choice itself.""" + text = "-" * 79 + text += "\n\nRoom exits:" + text += "\n Use |y@c|n to create a new exit." + text += "\n\nExisting exits:" + if room.exits: + for exit in room.exits: + text += f"\n |y@e {exit.key}|n" + if exit.aliases.all(): + text += " (|y{aliases}|n)".format(aliases="|n, |y".join( + alias for alias in exit.aliases.all() + )) + if exit.destination: + text += f" toward {exit.get_display_name(caller)}" + else: + text += "\n\n |gNo exit has yet been defined.|n" + + return text + +def nomatch_exits(menu, caller, room, string): + """ + The user typed something in the list of exits. Maybe an exit name? + """ + string = string[3:] + exit = caller.search(string, candidates=room.exits) + if exit is None: + return + + # Open a sub-menu, using nested keys + caller.msg(f"Editing: {exit.key}") + menu.open_submenu("commands.building.ExitBuildingMenu", exit, parent_keys=["e"]) + return False + +class ExitBuildingMenu(BuildingMenu): + + """ + Building menu to edit an exit. + + """ + + def init(self, exit): + self.add_choice("key", key="k", attr="key", glance="{obj.key}") + self.add_choice_edit("description", "d") +``` + +The code might be much easier to read. But before detailing it, let's see how it behaves in the +game: + +``` +> @edit here +Building menu: A beautiful meadow + + [T]itle: A beautiful meadow + [D]escription: + This is a beautiful meadow. But so beautiful I can't describe it. + [E]xits: + door + south + [Q]uit the menu + +> e +------------------------------------------------------------------------------- + +Room exits: + Use @c to create a new exit. + +Existing exits: + @e door (n) toward door(#4) + @e south (s) toward south(#7) + +Editing: door + +> @e door +Building menu: door + + [K]ey: door + [D]escription: + None + +> k +------------------------------------------------------------------------------- +key for door(#4) + +You can change this value simply by entering it. + +Use @ to go back to the main menu. + +Current value: door + +> north + +------------------------------------------------------------------------------- +key for north(#4) + +You can change this value simply by entering it. + +Use @ to go back to the main menu. + +Current value: north + +> @ +Building menu: north + + [K]ey: north + [D]escription: + None + +> d +----------Line Editor [editor]---------------------------------------------------- +01| None +----------[l:01 w:001 c:0004]------------(:h for help)---------------------------- + +> :DD +Cleared 1 lines from buffer. + +> This is the northern exit. Cool huh? +01| This is the northern exit. Cool huh? + +> :wq +Building menu: north + [K]ey: north + [D]escription: + This is the northern exit. Cool huh? + +> @ +------------------------------------------------------------------------------- +Room exits: + Use @c to create a new exit. + +Existing exits: + @e north (n) toward north(#4) + @e south (s) toward south(#7) + +> @ +Building menu: A beautiful meadow + + [T]itle: A beautiful meadow + [D]escription: + This is a beautiful meadow. But so beautiful I can't describe it. + [E]xits: + north + south + [Q]uit the menu + +> q +Closing the building menu. + +> look +A beautiful meadow(#2) +This is a beautiful meadow. But so beautiful I can't describe it. +Exits: north(#4) and south(#7) +> @py here.exits[0] +>>> here.exits[0] +north +> @py here.exits[0].db.desc +>>> here.exits[0].db.desc +This is the northern exit. Cool huh? +``` + +Very simply, we created two menus and bridged them together. This needs much less callbacks. There +is only one line in the `nomatch_exits` to add: + +```python + menu.open_submenu("commands.building.ExitBuildingMenu", exit, parent_keys=["e"]) +``` + +We have to call `open_submenu` on the menu object (which opens, as its name implies, a sub menu) +with three arguments: + +- The path of the menu class to create. It's the Python class leading to the menu (notice the +dots). +- The object that will be edited by the menu. Here, it's our exit, so we give it to the sub-menu. +- The keys of the parent to open when the sub-menu closes. Basically, when we're in the root of the +sub-menu and press `@`, we'll open the parent menu, with the parent keys. So we specify `["e"]`, +since the parent menus is the "exits" choice. + +And that's it. The new class will be automatically created. As you can see, we have to create a +`on_nomatch` callback to open the sub-menu, but once opened, it automatically close whenever needed. + +### Generic menu options + +There are some options that can be set on any menu class. These options allow for greater +customization. They are class attributes (see the example below), so just set them in the class +body: + +- `keys_go_back` (default to `["@"]`): the keys to use to go back in the menu hierarchy, from choice +to root menu, from sub-menu to parent-menu. By default, only a `@` is used. You can change this +key for one menu or all of them. You can define multiple return commands if you want. +- `sep_keys` (default `"."`): this is the separator for nested keys. There is no real need to +redefine it except if you really need the dot as a key, and need nested keys in your menu. +- `joker_key` (default to `"*"`): used for nested keys to indicate "any key". Again, you shouldn't +need to change it unless you want to be able to use the `@*@` in a command key, and also need nested +keys in your menu. +- `min_shortcut` (default to `1`): although we didn't see it here, one can create a menu choice +without giving it a key. If so, the menu system will try to "guess" the key. This option allows to +change the minimum length of any key for security reasons. + +To set one of them just do so in your menu class(es): + +```python +class RoomBuildingMenu(BuildingMenu): + keys_go_back = ["/"] + min_shortcut = 2 +``` + +## Conclusion + +Building menus mean to save you time and create a rich yet simple interface. But they can be +complicated to learn and require reading the source code to find out how to do such and such a +thing. This documentation, however long, is an attempt at describing this system, but chances are +you'll still have questions about it after reading it, especially if you try to push this system to +a great extent. Do not hesitate to read the documentation of this contrib, it's meant to be +exhaustive but user-friendly. diff --git a/evennia/contrib/base_systems/color_markups/README.md b/evennia/contrib/base_systems/color_markups/README.md index c21c8ce865..5d92b1d021 100644 --- a/evennia/contrib/base_systems/color_markups/README.md +++ b/evennia/contrib/base_systems/color_markups/README.md @@ -1,9 +1,9 @@ -# Color markups +# Additional Color markups Contrib by Griatch, 2017 Additional color markup styles for Evennia (extending or replacing the default -`|r`, `|234`). Adds support for MUSH-style (`%cr`, `%c123`) and/or legacy-Evennia +`|r`, `|234`). Adds support for MUSH-style (`%cr`, `%c123`) and/or legacy-Evennia (`{r`, `{123`). diff --git a/evennia/contrib/base_systems/custom_gametime/README.md b/evennia/contrib/base_systems/custom_gametime/README.md index 335efe40a5..505ae3fd5c 100644 --- a/evennia/contrib/base_systems/custom_gametime/README.md +++ b/evennia/contrib/base_systems/custom_gametime/README.md @@ -3,7 +3,7 @@ Contrib by vlgeoff, 2017 - based on Griatch's core original This reimplements the `evennia.utils.gametime` module but with a _custom_ -calendar (unusual number of days per week/month/year etc) for your game world. +calendar (unusual number of days per week/month/year etc) for your game world. Like the original, it allows for scheduling events to happen at given in-game times, but now taking this custom calendar into account. diff --git a/evennia/contrib/base_systems/email_login/README.md b/evennia/contrib/base_systems/email_login/README.md index e60446961c..bdbd0a1cfa 100644 --- a/evennia/contrib/base_systems/email_login/README.md +++ b/evennia/contrib/base_systems/email_login/README.md @@ -3,7 +3,7 @@ Contrib by Griatch, 2012 This is a variant of the login system that asks for an email-address -instead of a username to login. Note that it does not verify the email, +instead of a username to login. Note that it does not verify the email, it just uses it as the identifier rather than a username. This used to be the default Evennia login before replacing it with a diff --git a/evennia/contrib/base_systems/ingame_python/README.md b/evennia/contrib/base_systems/ingame_python/README.md index fbaef0a0d7..115d387c93 100644 --- a/evennia/contrib/base_systems/ingame_python/README.md +++ b/evennia/contrib/base_systems/ingame_python/README.md @@ -893,3 +893,12 @@ EVENTS_DISABLED = True The in-game Python system will still be accessible (you will have access to the `call` command, to debug), but no event will be called automatically. + + +```{toctree} +:hidden: + +Contrib-Ingame-Python-Tutorial-Dialogue +Contrib-Ingame-Python-Tutorial-Elevator + +``` diff --git a/evennia/contrib/base_systems/unixcommand/README.md b/evennia/contrib/base_systems/unixcommand/README.md index 8f62e8ef75..895ae8d75c 100644 --- a/evennia/contrib/base_systems/unixcommand/README.md +++ b/evennia/contrib/base_systems/unixcommand/README.md @@ -1,9 +1,9 @@ -# Unix-like Command style parent +# Unix-like Command style Contribution by Vincent Le Geoff (vlgeoff), 2017 -This module contains a command class with an alternate syntax parser implementing -Unix-style command syntax in-game. This means `--options`, positional arguments +This module contains a command class with an alternate syntax parser implementing +Unix-style command syntax in-game. This means `--options`, positional arguments and stuff like `-n 10`. It might not the best syntax for the average player but can be really useful for builders when they need to have a single command do many things with many options. It uses the `ArgumentParser` from Python's standard diff --git a/evennia/contrib/full_systems/evscaperoom/README.md b/evennia/contrib/full_systems/evscaperoom/README.md index 048e636f5d..088753107c 100644 --- a/evennia/contrib/full_systems/evscaperoom/README.md +++ b/evennia/contrib/full_systems/evscaperoom/README.md @@ -2,10 +2,10 @@ Contribution by Griatch, 2019 -A full engine for creating multiplayer escape-rooms in Evennia. Allows players to -spawn and join puzzle rooms that track their state independently. Any number of players -can join to solve a room together. This is the engine created for 'EvscapeRoom', which won -the MUD Coders Guild "One Room" Game Jam in April-May, 2019. The contrib has no game +A full engine for creating multiplayer escape-rooms in Evennia. Allows players to +spawn and join puzzle rooms that track their state independently. Any number of players +can join to solve a room together. This is the engine created for 'EvscapeRoom', which won +the MUD Coders Guild "One Room" Game Jam in April-May, 2019. The contrib has no game content but contains the utilities and base classes and an empty example room. The original code for the contest is found at @@ -16,13 +16,13 @@ instead. A copy of the full game can also be played on the Evennia demo server at https://demo.evennia.com - just connect to the server and write `evscaperoom` in the first room to start! -# Introduction +## Introduction Evscaperoom is, as it sounds, an escaperoom in text form. You start locked into a room and have to figure out how to get out. This engine contains everything needed to make a fully-featured puzzle game of this type! -# Installation +## Installation The Evscaperoom is installed by adding the `evscaperoom` command to your character cmdset. When you run that command in-game you're ready to play! @@ -44,7 +44,7 @@ class CharacterCmdSet(...): Reload the server and the `evscaperoom` command will be available. The contrib comes with a small (very small) escape room as an example. -# Making your own evscaperoom +## Making your own evscaperoom To do this, you need to make your own states. First make sure you can play the simple example room installed above. @@ -63,7 +63,7 @@ the following to your `mygame/server/conf/settings.py` file: Reload and the example evscaperoom should still work, but you can now modify and expand it from your game dir! -## Other useful settings +### Other useful settings There are a few other settings that may be useful: @@ -74,7 +74,7 @@ There are a few other settings that may be useful: the room without an argument. The original is found at the top of `evennia/contrib/full_systems/evscaperoom/commands.py`. -# Playing the game +## Playing the game You should start by `look`ing around and at objects. @@ -87,7 +87,7 @@ focus. There is also a full hint system. -# Technical +## Technical When connecting to the game, the user has the option to join an existing room (which may already be in some state of ongoing progress), or may create a fresh @@ -102,7 +102,7 @@ the logic and (in principle) inject new puzzles later. Once no players remain in the room, the room and its state will be wiped. -# Design Philosophy +## Design Philosophy Some basic premises inspired the design of this. diff --git a/evennia/contrib/game_systems/cooldowns/README.md b/evennia/contrib/game_systems/cooldowns/README.md index de425eebab..e1ffadb291 100644 --- a/evennia/contrib/game_systems/cooldowns/README.md +++ b/evennia/contrib/game_systems/cooldowns/README.md @@ -3,8 +3,8 @@ Contribution by owllex, 2021 Cooldowns are used to model rate-limited actions, like how often a -character can perform a given action; until a certain time has passed their -command can not be used again. This contrib provides a simple cooldown +character can perform a given action; until a certain time has passed their +command can not be used again. This contrib provides a simple cooldown handler that can be attached to any typeclass. A cooldown is a lightweight persistent asynchronous timer that you can query to see if a certain time has yet passed. @@ -38,7 +38,7 @@ def cooldowns(self): return CooldownHandler(self, db_attribute="cooldowns") ``` -# Example +## Example Assuming you've installed cooldowns on your Character typeclasses, you can use a cooldown to limit how often you can perform a command. The following code diff --git a/evennia/contrib/game_systems/mail/README.md b/evennia/contrib/game_systems/mail/README.md index 1686e7fb76..6b5c46659a 100644 --- a/evennia/contrib/game_systems/mail/README.md +++ b/evennia/contrib/game_systems/mail/README.md @@ -4,7 +4,7 @@ Contribution by grungies1138 2016 A simple Brandymail style mail system that uses the `Msg` class from Evennia Core. It has two Commands for either sending mails between Accounts (out of game) -or between Characters (in-game). The two types of mails can be used together or +or between Characters (in-game). The two types of mails can be used together or on their own. - `CmdMail` - this should sit on the Account cmdset and makes the `mail` command @@ -21,22 +21,23 @@ Install one or both of the following (see above): - CmdMail (IC + OOC mail, sent between players) + ```python # mygame/commands/default_cmds.py from evennia.contrib.game_systems import mail # in AccountCmdSet.at_cmdset_creation: self.add(mail.CmdMail()) - + ``` - CmdMailCharacter (optional, IC only mail, sent between characters) + ```python # mygame/commands/default_cmds.py from evennia.contrib.game_systems import mail # in CharacterCmdSet.at_cmdset_creation: self.add(mail.CmdMailCharacter()) - + ``` Once installed, use `help mail` in game for help with the mail command. Use ic/ooc to switch in and out of IC/OOC modes. - diff --git a/evennia/contrib/grid/mapbuilder/README.md b/evennia/contrib/grid/mapbuilder/README.md index 05a8719316..33d69e69ff 100644 --- a/evennia/contrib/grid/mapbuilder/README.md +++ b/evennia/contrib/grid/mapbuilder/README.md @@ -52,7 +52,7 @@ references to rooms previously created is passed to the build commands. You then call the command in-game using the path to the MAP and MAP_LEGEND vars The path you provide is relative to the evennia or mygame folder. -# Installation +## Installation Use by importing and including the command in your default_cmdsets module. For example: @@ -68,14 +68,14 @@ For example: ``` -# Usage: +## Usage: mapbuilder[/switch] one - execute build instructions once without automatic exit creation. two - execute build instructions twice without automatic exit creation. -# Examples +## Examples mapbuilder world.gamemap.MAP world.maplegend.MAP_LEGEND mapbuilder evennia.contrib.grid.mapbuilder.EXAMPLE1_MAP EXAMPLE1_LEGEND @@ -86,7 +86,7 @@ Below are two examples showcasing the use of automatic exit generation and custom exit generation. Whilst located, and can be used, from this module for convenience The below example code should be in mymap.py in mygame/world. -## Example One +### Example One ```python @@ -190,7 +190,7 @@ EXAMPLE1_LEGEND = { } ``` -## Example Two +### Example Two ```python # @mapbuilder/two evennia.contrib.grid.mapbuilder.EXAMPLE2_MAP EXAMPLE2_LEGEND diff --git a/evennia/contrib/grid/xyzgrid/launchcmd.py b/evennia/contrib/grid/xyzgrid/launchcmd.py index 98876865d8..2a5a4df92f 100644 --- a/evennia/contrib/grid/xyzgrid/launchcmd.py +++ b/evennia/contrib/grid/xyzgrid/launchcmd.py @@ -315,7 +315,7 @@ def _option_spawn(*suboptions): print("Aborted.") return - print("Starting spawn ...") + print("Beginner-Tutorial spawn ...") grid.spawn(xyz=(x, y, z)) print("... spawn complete!\nIt's recommended to reload the server to refresh caches if this " "modified an existing grid.") diff --git a/evennia/contrib/grid/xyzgrid/xymap_legend.py b/evennia/contrib/grid/xyzgrid/xymap_legend.py index bf4e0496ec..2912e02998 100644 --- a/evennia/contrib/grid/xyzgrid/xymap_legend.py +++ b/evennia/contrib/grid/xyzgrid/xymap_legend.py @@ -1128,7 +1128,7 @@ class BasicMapNode(MapNode): class InterruptMapNode(MapNode): """A point of interest node/room. Pathfinder will ignore but auto-stepper will - stop here if passing through. Starting from here is fine.""" + stop here if passing through. Beginner-Tutorial from here is fine.""" symbol = "I" display_symbol = "#" interrupt_path = True diff --git a/evennia/contrib/rpg/dice/README.md b/evennia/contrib/rpg/dice/README.md index a03a991fdd..db20407341 100644 --- a/evennia/contrib/rpg/dice/README.md +++ b/evennia/contrib/rpg/dice/README.md @@ -1,14 +1,14 @@ -# Dice +# Dice roller Contribution by Griatch, 2012 -A dice roller for any number and side of dice. Adds in-game dice rolling -(`roll 2d10 + 1`) as well as conditionals (roll under/over/equal to a target) -and functions for rolling dice in code. Command also supports hidden or secret +A dice roller for any number and side of dice. Adds in-game dice rolling +(`roll 2d10 + 1`) as well as conditionals (roll under/over/equal to a target) +and functions for rolling dice in code. Command also supports hidden or secret rolls for use by a human game master. -# Installation: +## Installation: Add the `CmdDice` command from this module to your character's cmdset @@ -28,7 +28,7 @@ class CharacterCmdSet(default_cmds.CharacterCmdSet): ``` -# Usage: +## Usage: > roll 1d100 + 2 > roll 1d20 @@ -53,7 +53,7 @@ was. Is a hidden roll that does not inform the room it happened. -## Rolling dice from code +### Rolling dice from code To roll dice in code, use the `roll` function from this module: diff --git a/evennia/contrib/rpg/health_bar/README.md b/evennia/contrib/rpg/health_bar/README.md index 50dcb3bb1a..5fe4600fc6 100644 --- a/evennia/contrib/rpg/health_bar/README.md +++ b/evennia/contrib/rpg/health_bar/README.md @@ -3,8 +3,8 @@ Contribution by Tim Ashley Jenkins, 2017 The function provided in this module lets you easily display visual -bars or meters as a colorful bar instead of just a number. A "health bar" -is merely the most obvious use for this, but the bar is highly customizable +bars or meters as a colorful bar instead of just a number. A "health bar" +is merely the most obvious use for this, but the bar is highly customizable and can be used for any sort of appropriate data besides player health. Today's players may be more used to seeing statistics like health, diff --git a/evennia/contrib/tutorials/tutorial_world/intro_menu.py b/evennia/contrib/tutorials/tutorial_world/intro_menu.py index 445df03640..3bfdf52f72 100644 --- a/evennia/contrib/tutorials/tutorial_world/intro_menu.py +++ b/evennia/contrib/tutorials/tutorial_world/intro_menu.py @@ -697,12 +697,12 @@ Evennia you are wise to take a look at the |wEvennia documentation|n at - The tutorial-world may or may not be your cup of tea, but it does show off several |wuseful tools|n of Evennia. You may want to check out how it works: - |yhttps://www.evennia.com/docs/latest/Howto/Starting/Part1/Tutorial-World|n + |yhttps://www.evennia.com/docs/latest/Howtos/Beginner-Tutorial/Part1/Tutorial-World|n - You can then continue looking through the |wTutorials|n and pick one that fits your level of understanding. - |yhttps://www.evennia.com/docs/latest/Howto/Howto-Overview|n + |yhttps://www.evennia.com/docs/latest/Howtos/Howtos-Overview|n - Make sure to |wjoin our forum|n and connect to our |wsupport chat|n! The Evennia community is very active and friendly and no question is too simple. diff --git a/evennia/server/evennia_launcher.py b/evennia/server/evennia_launcher.py index 76cf5571ed..84d3df38f3 100644 --- a/evennia/server/evennia_launcher.py +++ b/evennia/server/evennia_launcher.py @@ -889,7 +889,7 @@ def reload_evennia(sprofiler=False, reset=False): send_instruction(SSTART, server_cmd) def _portal_not_running(fail): - print("Evennia not running. Starting up ...") + print("Evennia not running. Beginner-Tutorial up ...") start_evennia() collectstatic() @@ -962,7 +962,7 @@ def reboot_evennia(pprofiler=False, sprofiler=False): wait_for_status(False, None, _portal_stopped) def _portal_not_running(fail): - print("Evennia not running. Starting up ...") + print("Evennia not running. Beginner-Tutorial up ...") start_evennia() collectstatic() @@ -988,7 +988,7 @@ def start_server_interactive(): def _iserver(): _, server_twistd_cmd = _get_twistd_cmdline(False, False) server_twistd_cmd.append("--nodaemon") - print("Starting Server in interactive mode (stop with Ctrl-C)...") + print("Beginner-Tutorial Server in interactive mode (stop with Ctrl-C)...") try: Popen(server_twistd_cmd, env=getenv(), stderr=STDOUT).wait() except KeyboardInterrupt: @@ -1026,7 +1026,7 @@ def start_portal_interactive(): else: Popen(server_twistd_cmd, env=getenv(), bufsize=-1) - print("Starting Portal in interactive mode (stop with Ctrl-C)...") + print("Beginner-Tutorial Portal in interactive mode (stop with Ctrl-C)...") try: Popen(portal_twistd_cmd, env=getenv(), stderr=STDOUT).wait() except KeyboardInterrupt: diff --git a/evennia/utils/evmenu.py b/evennia/utils/evmenu.py index 4aaedb8e35..0081e70148 100644 --- a/evennia/utils/evmenu.py +++ b/evennia/utils/evmenu.py @@ -220,7 +220,7 @@ callable must be a module-global function on the form ## options - # Starting the option-line with > + # Beginner-Tutorial the option-line with > # allows to perform different actions depending on # what is inserted.