From 86c930be7a7cde3a3d6ec701f57bde1d041cce0a Mon Sep 17 00:00:00 2001 From: Griatch Date: Wed, 23 Jun 2021 18:58:26 +0200 Subject: [PATCH] Updated HTML docs --- docs/0.9.5/.buildinfo | 2 +- ...-voice-operated-elevator-using-events.html | 1 - docs/0.9.5/API-refactoring.html | 1 - docs/0.9.5/Accounts.html | 1 - docs/0.9.5/Add-a-simple-new-web-page.html | 1 - docs/0.9.5/Add-a-wiki-on-your-website.html | 1 - docs/0.9.5/Adding-Command-Tutorial.html | 1 - .../Adding-Object-Typeclass-Tutorial.html | 1 - docs/0.9.5/Administrative-Docs.html | 1 - docs/0.9.5/Apache-Config.html | 1 - docs/0.9.5/Arxcode-installing-help.html | 1 - docs/0.9.5/Async-Process.html | 1 - docs/0.9.5/Attributes.html | 1 - docs/0.9.5/Banning.html | 1 - docs/0.9.5/Batch-Code-Processor.html | 1 - docs/0.9.5/Batch-Command-Processor.html | 1 - docs/0.9.5/Batch-Processors.html | 1 - docs/0.9.5/Bootstrap-&-Evennia.html | 1 - .../Bootstrap-Components-and-Utilities.html | 1 - docs/0.9.5/Builder-Docs.html | 1 - docs/0.9.5/Building-Permissions.html | 1 - docs/0.9.5/Building-Quickstart.html | 1 - docs/0.9.5/Building-a-mech-tutorial.html | 1 - docs/0.9.5/Building-menus.html | 1 - docs/0.9.5/Choosing-An-SQL-Server.html | 1 - docs/0.9.5/Client-Support-Grid.html | 1 - docs/0.9.5/Coding-FAQ.html | 1 - docs/0.9.5/Coding-Introduction.html | 1 - docs/0.9.5/Coding-Utils.html | 1 - docs/0.9.5/Command-Cooldown.html | 1 - docs/0.9.5/Command-Duration.html | 1 - docs/0.9.5/Command-Prompt.html | 1 - docs/0.9.5/Command-Sets.html | 1 - docs/0.9.5/Command-System.html | 1 - docs/0.9.5/Commands.html | 1 - docs/0.9.5/Communications.html | 1 - docs/0.9.5/Connection-Screen.html | 1 - docs/0.9.5/Continuous-Integration.html | 1 - docs/0.9.5/Contributing-Docs.html | 1 - docs/0.9.5/Contributing.html | 1 - docs/0.9.5/Coordinates.html | 1 - docs/0.9.5/Custom-Protocols.html | 1 - docs/0.9.5/Customize-channels.html | 1 - docs/0.9.5/Debugging.html | 1 - docs/0.9.5/Default-Command-Help.html | 1 - docs/0.9.5/Default-Exit-Errors.html | 1 - docs/0.9.5/Developer-Central.html | 1 - docs/0.9.5/Dialogues-in-events.html | 1 - docs/0.9.5/Directory-Overview.html | 1 - docs/0.9.5/Docs-refactoring.html | 1 - docs/0.9.5/Dynamic-In-Game-Map.html | 1 - docs/0.9.5/EvEditor.html | 1 - docs/0.9.5/EvMenu.html | 1 - docs/0.9.5/EvMore.html | 1 - docs/0.9.5/Evennia-API.html | 1 - docs/0.9.5/Evennia-Game-Index.html | 1 - docs/0.9.5/Evennia-Introduction.html | 1 - docs/0.9.5/Evennia-for-Diku-Users.html | 1 - docs/0.9.5/Evennia-for-MUSH-Users.html | 1 - .../Evennia-for-roleplaying-sessions.html | 1 - docs/0.9.5/Execute-Python-Code.html | 1 - docs/0.9.5/First-Steps-Coding.html | 1 - docs/0.9.5/Game-Planning.html | 1 - docs/0.9.5/Gametime-Tutorial.html | 1 - docs/0.9.5/Getting-Started.html | 1 - docs/0.9.5/Glossary.html | 1 - docs/0.9.5/Grapevine.html | 1 - docs/0.9.5/Guest-Logins.html | 1 - docs/0.9.5/HAProxy-Config.html | 1 - docs/0.9.5/Help-System-Tutorial.html | 1 - docs/0.9.5/Help-System.html | 1 - docs/0.9.5/How-To-Get-And-Give-Help.html | 1 - .../How-to-connect-Evennia-to-Twitter.html | 1 - docs/0.9.5/IRC.html | 1 - .../Implementing-a-game-rule-system.html | 1 - docs/0.9.5/Inputfuncs.html | 1 - docs/0.9.5/Installing-on-Android.html | 1 - docs/0.9.5/Internationalization.html | 1 - ...Learn-Python-for-Evennia-The-Hard-Way.html | 1 - docs/0.9.5/Licensing.html | 1 - docs/0.9.5/Links.html | 1 - docs/0.9.5/Locks.html | 1 - docs/0.9.5/Manually-Configuring-Color.html | 1 - docs/0.9.5/Mass-and-weight-for-objects.html | 1 - docs/0.9.5/Messagepath.html | 1 - docs/0.9.5/MonitorHandler.html | 1 - docs/0.9.5/NPC-shop-Tutorial.html | 1 - docs/0.9.5/New-Models.html | 1 - docs/0.9.5/Nicks.html | 1 - docs/0.9.5/OOB.html | 1 - docs/0.9.5/Objects.html | 1 - docs/0.9.5/Online-Setup.html | 1 - ...-arguments,-theory-and-best-practices.html | 1 - docs/0.9.5/Portal-And-Server.html | 1 - docs/0.9.5/Profiling.html | 1 - docs/0.9.5/Python-3.html | 1 - docs/0.9.5/Python-basic-introduction.html | 1 - .../0.9.5/Python-basic-tutorial-part-two.html | 1 - docs/0.9.5/Quirks.html | 1 - docs/0.9.5/RSS.html | 1 - docs/0.9.5/Roadmap.html | 1 - docs/0.9.5/Running-Evennia-in-Docker.html | 1 - docs/0.9.5/Screenshot.html | 1 - docs/0.9.5/Scripts.html | 1 - docs/0.9.5/Security.html | 1 - docs/0.9.5/Server-Conf.html | 1 - docs/0.9.5/Sessions.html | 1 - docs/0.9.5/Setting-up-PyCharm.html | 1 - docs/0.9.5/Signals.html | 1 - docs/0.9.5/Soft-Code.html | 1 - docs/0.9.5/Spawner-and-Prototypes.html | 1 - docs/0.9.5/Start-Stop-Reload.html | 1 - docs/0.9.5/Static-In-Game-Map.html | 1 - docs/0.9.5/Tags.html | 1 - docs/0.9.5/Text-Encodings.html | 1 - docs/0.9.5/TextTags.html | 1 - docs/0.9.5/TickerHandler.html | 1 - docs/0.9.5/Turn-based-Combat-System.html | 1 - docs/0.9.5/Tutorial-Aggressive-NPCs.html | 1 - docs/0.9.5/Tutorial-NPCs-listening.html | 1 - .../0.9.5/Tutorial-Searching-For-Objects.html | 1 - docs/0.9.5/Tutorial-Tweeting-Game-Stats.html | 1 - docs/0.9.5/Tutorial-Vehicles.html | 1 - docs/0.9.5/Tutorial-World-Introduction.html | 1 - .../Tutorial-for-basic-MUSH-like-game.html | 1 - docs/0.9.5/Tutorials.html | 1 - docs/0.9.5/Typeclasses.html | 1 - docs/0.9.5/Understanding-Color-Tags.html | 1 - docs/0.9.5/Unit-Testing.html | 1 - docs/0.9.5/Updating-Your-Game.html | 1 - docs/0.9.5/Using-MUX-as-a-Standard.html | 1 - docs/0.9.5/Using-Travis.html | 1 - docs/0.9.5/Version-Control.html | 1 - docs/0.9.5/Weather-Tutorial.html | 1 - docs/0.9.5/Web-Character-Generation.html | 1 - docs/0.9.5/Web-Character-View-Tutorial.html | 1 - docs/0.9.5/Web-Features.html | 1 - docs/0.9.5/Web-Tutorial.html | 1 - docs/0.9.5/Webclient-brainstorm.html | 1 - docs/0.9.5/Webclient.html | 1 - docs/0.9.5/Wiki-Index.html | 1 - docs/0.9.5/Zones.html | 1 - docs/0.9.5/_modules/django/conf.html | 1 - .../db/models/fields/related_descriptors.html | 1 - .../_modules/django/db/models/manager.html | 1 - .../django/db/models/query_utils.html | 1 - .../_modules/django/utils/functional.html | 525 -- docs/0.9.5/_modules/evennia.html | 7 +- .../_modules/evennia/accounts/accounts.html | 227 +- .../0.9.5/_modules/evennia/accounts/bots.html | 6 +- .../_modules/evennia/accounts/manager.html | 1 - .../_modules/evennia/accounts/models.html | 10 +- .../_modules/evennia/commands/cmdhandler.html | 134 +- .../_modules/evennia/commands/cmdparser.html | 36 +- .../_modules/evennia/commands/cmdset.html | 23 +- .../evennia/commands/cmdsethandler.html | 31 +- .../_modules/evennia/commands/command.html | 45 +- .../evennia/commands/default/account.html | 3 +- .../evennia/commands/default/admin.html | 1 - .../commands/default/batchprocess.html | 3 +- .../evennia/commands/default/building.html | 39 +- .../commands/default/cmdset_account.html | 5 +- .../commands/default/cmdset_character.html | 2 +- .../commands/default/cmdset_session.html | 1 - .../commands/default/cmdset_unloggedin.html | 1 - .../evennia/commands/default/comms.html | 1792 +++++-- .../evennia/commands/default/general.html | 12 +- .../evennia/commands/default/help.html | 882 +++- .../evennia/commands/default/muxcommand.html | 5 +- .../evennia/commands/default/syscommands.html | 49 - .../evennia/commands/default/system.html | 404 +- .../evennia/commands/default/tests.html | 822 ++- .../evennia/commands/default/unloggedin.html | 2 +- docs/0.9.5/_modules/evennia/comms/admin.html | 227 - .../evennia/comms/channelhandler.html | 427 -- docs/0.9.5/_modules/evennia/comms/comms.html | 630 +-- .../_modules/evennia/comms/managers.html | 108 +- docs/0.9.5/_modules/evennia/comms/models.html | 269 +- .../_modules/evennia/contrib/barter.html | 1 - .../evennia/contrib/building_menu.html | 1 - .../_modules/evennia/contrib/chargen.html | 1 - .../_modules/evennia/contrib/clothing.html | 1 - .../evennia/contrib/custom_gametime.html | 1 - docs/0.9.5/_modules/evennia/contrib/dice.html | 1 - .../_modules/evennia/contrib/email_login.html | 1 - .../evennia/contrib/extended_room.html | 1 - .../_modules/evennia/contrib/fieldfill.html | 1 - .../_modules/evennia/contrib/gendersub.html | 1 - .../_modules/evennia/contrib/health_bar.html | 1 - .../ingame_python/callbackhandler.html | 1 - .../contrib/ingame_python/commands.html | 1 - .../contrib/ingame_python/eventfuncs.html | 1 - .../contrib/ingame_python/scripts.html | 6 +- .../evennia/contrib/ingame_python/tests.html | 9 +- .../evennia/contrib/ingame_python/utils.html | 2 - docs/0.9.5/_modules/evennia/contrib/mail.html | 1 - .../_modules/evennia/contrib/multidescer.html | 1 - .../_modules/evennia/contrib/puzzles.html | 1 - .../contrib/random_string_generator.html | 1 - .../_modules/evennia/contrib/rplanguage.html | 120 +- .../_modules/evennia/contrib/rpsystem.html | 4 +- .../contrib/security/auditing/outputs.html | 1 - .../contrib/security/auditing/server.html | 1 - .../contrib/security/auditing/tests.html | 1 - .../_modules/evennia/contrib/simpledoor.html | 1 - .../_modules/evennia/contrib/slow_exit.html | 1 - .../_modules/evennia/contrib/talking_npc.html | 1 - .../_modules/evennia/contrib/tree_select.html | 1 - .../evennia/contrib/turnbattle/tb_basic.html | 7 +- .../evennia/contrib/turnbattle/tb_equip.html | 1 - .../evennia/contrib/turnbattle/tb_items.html | 1 - .../evennia/contrib/turnbattle/tb_magic.html | 1 - .../evennia/contrib/turnbattle/tb_range.html | 2 - .../tutorial_examples/bodyfunctions.html | 1 - .../tutorial_examples/cmdset_red_button.html | 439 -- .../contrib/tutorial_examples/red_button.html | 659 ++- .../tutorial_examples/red_button_scripts.html | 389 -- .../contrib/tutorial_examples/tests.html | 1 - .../contrib/tutorial_world/intro_menu.html | 8 +- .../evennia/contrib/tutorial_world/mob.html | 14 +- .../contrib/tutorial_world/objects.html | 24 +- .../evennia/contrib/tutorial_world/rooms.html | 17 +- .../_modules/evennia/contrib/unixcommand.html | 3 +- .../_modules/evennia/contrib/wilderness.html | 1 - docs/0.9.5/_modules/evennia/help/manager.html | 4 +- docs/0.9.5/_modules/evennia/help/models.html | 94 +- .../_modules/evennia/locks/lockfuncs.html | 107 +- .../_modules/evennia/locks/lockhandler.html | 49 +- .../0.9.5/_modules/evennia/objects/admin.html | 301 -- .../_modules/evennia/objects/manager.html | 6 +- .../_modules/evennia/objects/models.html | 68 +- .../_modules/evennia/objects/objects.html | 381 +- .../_modules/evennia/prototypes/menus.html | 12 +- .../evennia/prototypes/protfuncs.html | 342 +- .../evennia/prototypes/prototypes.html | 181 +- .../_modules/evennia/prototypes/spawner.html | 89 +- .../0.9.5/_modules/evennia/scripts/admin.html | 195 - .../_modules/evennia/scripts/manager.html | 109 +- .../_modules/evennia/scripts/models.html | 7 +- .../evennia/scripts/monitorhandler.html | 3 +- .../evennia/scripts/scripthandler.html | 38 +- .../_modules/evennia/scripts/scripts.html | 710 +-- .../_modules/evennia/scripts/taskhandler.html | 87 +- .../evennia/scripts/tickerhandler.html | 1 - .../_modules/evennia/server/amp_client.html | 5 +- .../evennia/server/connection_wizard.html | 1 - .../_modules/evennia/server/deprecations.html | 38 +- .../evennia/server/evennia_launcher.html | 22 +- .../server/game_index_client/client.html | 1 - .../server/game_index_client/service.html | 1 - .../evennia/server/initial_setup.html | 22 +- .../_modules/evennia/server/inputfuncs.html | 6 +- .../_modules/evennia/server/manager.html | 1 - .../0.9.5/_modules/evennia/server/models.html | 9 +- .../_modules/evennia/server/portal/amp.html | 23 +- .../evennia/server/portal/amp_server.html | 11 +- .../evennia/server/portal/grapevine.html | 3 +- .../_modules/evennia/server/portal/irc.html | 1 - .../_modules/evennia/server/portal/mccp.html | 192 + .../_modules/evennia/server/portal/mssp.html | 237 + .../_modules/evennia/server/portal/mxp.html | 189 + .../_modules/evennia/server/portal/naws.html | 187 + .../evennia/server/portal/portal.html | 548 ++ .../server/portal/portalsessionhandler.html | 46 +- .../_modules/evennia/server/portal/rss.html | 2 +- .../_modules/evennia/server/portal/ssh.html | 43 +- .../_modules/evennia/server/portal/ssl.html | 223 + .../evennia/server/portal/suppress_ga.html | 171 + .../evennia/server/portal/telnet.html | 613 +++ .../evennia/server/portal/telnet_oob.html | 542 ++ .../evennia/server/portal/telnet_ssl.html | 255 + .../_modules/evennia/server/portal/tests.html | 424 ++ .../_modules/evennia/server/portal/ttype.html | 290 + .../evennia/server/portal/webclient.html | 14 +- .../evennia/server/portal/webclient_ajax.html | 9 +- .../evennia/server/profiling/dummyrunner.html | 269 +- .../profiling/dummyrunner_settings.html | 277 +- .../evennia/server/profiling/memplot.html | 1 - .../server/profiling/test_queries.html | 1 - .../evennia/server/profiling/tests.html | 55 +- .../evennia/server/profiling/timetrace.html | 1 - .../0.9.5/_modules/evennia/server/server.html | 93 +- .../evennia/server/serversession.html | 167 +- .../_modules/evennia/server/session.html | 29 +- .../evennia/server/sessionhandler.html | 187 +- .../_modules/evennia/server/throttle.html | 144 +- .../_modules/evennia/server/validators.html | 5 +- .../_modules/evennia/server/webserver.html | 1 - .../_modules/evennia/typeclasses/admin.html | 448 -- .../evennia/typeclasses/attributes.html | 1268 +++-- .../evennia/typeclasses/managers.html | 39 +- .../_modules/evennia/typeclasses/models.html | 251 +- .../_modules/evennia/typeclasses/tags.html | 55 +- docs/0.9.5/_modules/evennia/utils/ansi.html | 97 +- .../evennia/utils/batchprocessors.html | 151 +- .../_modules/evennia/utils/containers.html | 14 +- docs/0.9.5/_modules/evennia/utils/create.html | 77 +- .../_modules/evennia/utils/dbserialize.html | 5 +- .../_modules/evennia/utils/eveditor.html | 247 +- docs/0.9.5/_modules/evennia/utils/evform.html | 70 +- docs/0.9.5/_modules/evennia/utils/evmenu.html | 533 +- docs/0.9.5/_modules/evennia/utils/evmore.html | 173 +- .../0.9.5/_modules/evennia/utils/evtable.html | 76 +- .../_modules/evennia/utils/gametime.html | 3 +- .../evennia/utils/idmapper/manager.html | 1 - .../evennia/utils/idmapper/models.html | 23 +- .../evennia/utils/idmapper/tests.html | 1 - .../_modules/evennia/utils/inlinefuncs.html | 726 --- docs/0.9.5/_modules/evennia/utils/logger.html | 64 +- .../_modules/evennia/utils/optionclasses.html | 13 +- .../_modules/evennia/utils/optionhandler.html | 17 +- .../_modules/evennia/utils/picklefield.html | 3 +- docs/0.9.5/_modules/evennia/utils/search.html | 16 +- .../evennia/utils/test_resources.html | 21 +- .../_modules/evennia/utils/text2html.html | 20 +- docs/0.9.5/_modules/evennia/utils/utils.html | 734 ++- .../evennia/utils/validatorfuncs.html | 77 +- .../_modules/evennia/web/utils/backends.html | 1 - .../evennia/web/utils/general_context.html | 71 +- .../evennia/web/utils/middleware.html | 1 - .../_modules/evennia/web/utils/tests.html | 10 +- .../_modules/evennia/web/webclient/views.html | 1 - .../_modules/evennia/web/website/forms.html | 3 +- .../_modules/evennia/web/website/tests.html | 1 - .../_modules/evennia/web/website/views.html | 1236 ----- docs/0.9.5/_modules/functools.html | 1 - docs/0.9.5/_modules/index.html | 27 +- docs/0.9.5/_static/nature.css | 13 +- docs/0.9.5/api/evennia-api.html | 26 +- docs/0.9.5/api/evennia.accounts.accounts.html | 189 +- docs/0.9.5/api/evennia.accounts.admin.html | 305 +- docs/0.9.5/api/evennia.accounts.bots.html | 1 - docs/0.9.5/api/evennia.accounts.html | 1 - docs/0.9.5/api/evennia.accounts.manager.html | 1 - docs/0.9.5/api/evennia.accounts.models.html | 1 - .../api/evennia.commands.cmdhandler.html | 22 +- .../0.9.5/api/evennia.commands.cmdparser.html | 5 +- docs/0.9.5/api/evennia.commands.cmdset.html | 1 - .../api/evennia.commands.cmdsethandler.html | 9 +- docs/0.9.5/api/evennia.commands.command.html | 31 +- .../api/evennia.commands.default.account.html | 70 +- .../api/evennia.commands.default.admin.html | 41 +- ...evennia.commands.default.batchprocess.html | 13 +- .../evennia.commands.default.building.html | 141 +- ...ennia.commands.default.cmdset_account.html | 1 - ...nia.commands.default.cmdset_character.html | 1 - ...ennia.commands.default.cmdset_session.html | 1 - ...ia.commands.default.cmdset_unloggedin.html | 1 - .../api/evennia.commands.default.comms.html | 951 +++- .../api/evennia.commands.default.general.html | 71 +- .../api/evennia.commands.default.help.html | 317 +- docs/0.9.5/api/evennia.commands.default.html | 1 - .../evennia.commands.default.muxcommand.html | 11 +- .../evennia.commands.default.syscommands.html | 124 +- .../api/evennia.commands.default.system.html | 175 +- .../api/evennia.commands.default.tests.html | 440 +- .../evennia.commands.default.unloggedin.html | 30 +- docs/0.9.5/api/evennia.commands.html | 1 - docs/0.9.5/api/evennia.comms.admin.html | 194 +- .../api/evennia.comms.channelhandler.html | 225 +- docs/0.9.5/api/evennia.comms.comms.html | 505 +- docs/0.9.5/api/evennia.comms.html | 1 - docs/0.9.5/api/evennia.comms.managers.html | 35 +- docs/0.9.5/api/evennia.comms.models.html | 132 +- docs/0.9.5/api/evennia.contrib.barter.html | 46 +- .../api/evennia.contrib.building_menu.html | 16 +- docs/0.9.5/api/evennia.contrib.chargen.html | 13 +- docs/0.9.5/api/evennia.contrib.clothing.html | 38 +- .../api/evennia.contrib.color_markups.html | 1 - .../api/evennia.contrib.custom_gametime.html | 1 - docs/0.9.5/api/evennia.contrib.dice.html | 6 +- .../api/evennia.contrib.email_login.html | 30 +- .../api/evennia.contrib.extended_room.html | 21 +- docs/0.9.5/api/evennia.contrib.fieldfill.html | 6 +- docs/0.9.5/api/evennia.contrib.gendersub.html | 6 +- .../0.9.5/api/evennia.contrib.health_bar.html | 1 - docs/0.9.5/api/evennia.contrib.html | 6 +- ...contrib.ingame_python.callbackhandler.html | 1 - ...vennia.contrib.ingame_python.commands.html | 6 +- ...nnia.contrib.ingame_python.eventfuncs.html | 1 - .../api/evennia.contrib.ingame_python.html | 1 - ...evennia.contrib.ingame_python.scripts.html | 5 +- .../evennia.contrib.ingame_python.tests.html | 1 - ...nia.contrib.ingame_python.typeclasses.html | 1 - .../evennia.contrib.ingame_python.utils.html | 1 - docs/0.9.5/api/evennia.contrib.mail.html | 11 +- .../0.9.5/api/evennia.contrib.mapbuilder.html | 1 - .../0.9.5/api/evennia.contrib.menu_login.html | 1 - .../api/evennia.contrib.multidescer.html | 6 +- docs/0.9.5/api/evennia.contrib.puzzles.html | 31 +- ...ennia.contrib.random_string_generator.html | 1 - .../0.9.5/api/evennia.contrib.rplanguage.html | 45 +- docs/0.9.5/api/evennia.contrib.rpsystem.html | 43 +- .../evennia.contrib.security.auditing.html | 1 - ...nia.contrib.security.auditing.outputs.html | 1 - ...nnia.contrib.security.auditing.server.html | 1 - ...ennia.contrib.security.auditing.tests.html | 1 - docs/0.9.5/api/evennia.contrib.security.html | 1 - .../0.9.5/api/evennia.contrib.simpledoor.html | 11 +- docs/0.9.5/api/evennia.contrib.slow_exit.html | 11 +- .../api/evennia.contrib.talking_npc.html | 6 +- .../api/evennia.contrib.tree_select.html | 6 +- .../0.9.5/api/evennia.contrib.turnbattle.html | 1 - .../evennia.contrib.turnbattle.tb_basic.html | 31 +- .../evennia.contrib.turnbattle.tb_equip.html | 51 +- .../evennia.contrib.turnbattle.tb_items.html | 36 +- .../evennia.contrib.turnbattle.tb_magic.html | 46 +- .../evennia.contrib.turnbattle.tb_range.html | 51 +- ...ntrib.tutorial_examples.bodyfunctions.html | 1 - ...b.tutorial_examples.cmdset_red_button.html | 448 +- ....tutorial_examples.example_batch_code.html | 1 - .../evennia.contrib.tutorial_examples.html | 6 +- ....contrib.tutorial_examples.red_button.html | 661 ++- ....tutorial_examples.red_button_scripts.html | 349 +- ...ennia.contrib.tutorial_examples.tests.html | 1 - .../api/evennia.contrib.tutorial_world.html | 1 - ...nia.contrib.tutorial_world.intro_menu.html | 1 - .../evennia.contrib.tutorial_world.mob.html | 8 +- ...vennia.contrib.tutorial_world.objects.html | 100 +- .../evennia.contrib.tutorial_world.rooms.html | 65 +- .../api/evennia.contrib.unixcommand.html | 6 +- .../0.9.5/api/evennia.contrib.wilderness.html | 1 - docs/0.9.5/api/evennia.help.admin.html | 131 +- docs/0.9.5/api/evennia.help.html | 1 - docs/0.9.5/api/evennia.help.manager.html | 1 - docs/0.9.5/api/evennia.help.models.html | 100 +- docs/0.9.5/api/evennia.html | 27 +- docs/0.9.5/api/evennia.locks.html | 6 +- docs/0.9.5/api/evennia.locks.lockfuncs.html | 124 +- docs/0.9.5/api/evennia.locks.lockhandler.html | 1 - docs/0.9.5/api/evennia.objects.admin.html | 264 +- docs/0.9.5/api/evennia.objects.html | 1 - docs/0.9.5/api/evennia.objects.manager.html | 1 - docs/0.9.5/api/evennia.objects.models.html | 19 +- docs/0.9.5/api/evennia.objects.objects.html | 186 +- docs/0.9.5/api/evennia.prototypes.html | 1 - docs/0.9.5/api/evennia.prototypes.menus.html | 1 - .../api/evennia.prototypes.protfuncs.html | 170 +- .../api/evennia.prototypes.prototypes.html | 30 +- .../0.9.5/api/evennia.prototypes.spawner.html | 13 +- docs/0.9.5/api/evennia.scripts.admin.html | 129 +- docs/0.9.5/api/evennia.scripts.html | 1 - docs/0.9.5/api/evennia.scripts.manager.html | 1 - docs/0.9.5/api/evennia.scripts.models.html | 1 - .../api/evennia.scripts.monitorhandler.html | 1 - .../api/evennia.scripts.scripthandler.html | 20 - docs/0.9.5/api/evennia.scripts.scripts.html | 216 +- .../api/evennia.scripts.taskhandler.html | 6 +- .../api/evennia.scripts.tickerhandler.html | 1 - docs/0.9.5/api/evennia.server.admin.html | 52 +- docs/0.9.5/api/evennia.server.amp_client.html | 1 - .../api/evennia.server.connection_wizard.html | 1 - .../api/evennia.server.deprecations.html | 1 - .../api/evennia.server.evennia_launcher.html | 1 - ...ennia.server.game_index_client.client.html | 1 - .../api/evennia.server.game_index_client.html | 1 - ...nnia.server.game_index_client.service.html | 1 - docs/0.9.5/api/evennia.server.html | 1 - .../api/evennia.server.initial_setup.html | 1 - docs/0.9.5/api/evennia.server.inputfuncs.html | 1 - docs/0.9.5/api/evennia.server.manager.html | 1 - docs/0.9.5/api/evennia.server.models.html | 1 - docs/0.9.5/api/evennia.server.portal.amp.html | 5 +- .../api/evennia.server.portal.amp_server.html | 3 +- .../api/evennia.server.portal.grapevine.html | 1 - docs/0.9.5/api/evennia.server.portal.html | 1 - docs/0.9.5/api/evennia.server.portal.irc.html | 1 - .../0.9.5/api/evennia.server.portal.mccp.html | 75 +- .../0.9.5/api/evennia.server.portal.mssp.html | 76 +- docs/0.9.5/api/evennia.server.portal.mxp.html | 68 +- .../0.9.5/api/evennia.server.portal.naws.html | 64 +- .../api/evennia.server.portal.portal.html | 63 +- ...ia.server.portal.portalsessionhandler.html | 14 +- docs/0.9.5/api/evennia.server.portal.rss.html | 1 - docs/0.9.5/api/evennia.server.portal.ssh.html | 19 +- docs/0.9.5/api/evennia.server.portal.ssl.html | 46 +- .../evennia.server.portal.suppress_ga.html | 54 +- .../api/evennia.server.portal.telnet.html | 247 +- .../api/evennia.server.portal.telnet_oob.html | 217 +- .../api/evennia.server.portal.telnet_ssl.html | 57 +- .../api/evennia.server.portal.tests.html | 113 +- .../api/evennia.server.portal.ttype.html | 63 +- .../api/evennia.server.portal.webclient.html | 1 - .../evennia.server.portal.webclient_ajax.html | 6 +- .../evennia.server.profiling.dummyrunner.html | 95 +- ...server.profiling.dummyrunner_settings.html | 56 +- docs/0.9.5/api/evennia.server.profiling.html | 1 - .../api/evennia.server.profiling.memplot.html | 1 - ...ennia.server.profiling.settings_mixin.html | 1 - ...evennia.server.profiling.test_queries.html | 1 - .../api/evennia.server.profiling.tests.html | 1 - .../evennia.server.profiling.timetrace.html | 1 - docs/0.9.5/api/evennia.server.server.html | 33 +- .../api/evennia.server.serversession.html | 140 +- docs/0.9.5/api/evennia.server.session.html | 1 - .../api/evennia.server.sessionhandler.html | 76 +- docs/0.9.5/api/evennia.server.signals.html | 21 +- docs/0.9.5/api/evennia.server.throttle.html | 63 +- docs/0.9.5/api/evennia.server.validators.html | 1 - docs/0.9.5/api/evennia.server.webserver.html | 1 - docs/0.9.5/api/evennia.settings_default.html | 1 - docs/0.9.5/api/evennia.typeclasses.admin.html | 296 +- .../api/evennia.typeclasses.attributes.html | 966 +++- docs/0.9.5/api/evennia.typeclasses.html | 1 - .../api/evennia.typeclasses.managers.html | 19 +- .../0.9.5/api/evennia.typeclasses.models.html | 379 +- docs/0.9.5/api/evennia.typeclasses.tags.html | 33 +- docs/0.9.5/api/evennia.utils.ansi.html | 80 +- .../api/evennia.utils.batchprocessors.html | 138 +- docs/0.9.5/api/evennia.utils.containers.html | 1 - docs/0.9.5/api/evennia.utils.create.html | 66 +- docs/0.9.5/api/evennia.utils.dbserialize.html | 3 +- docs/0.9.5/api/evennia.utils.eveditor.html | 97 +- docs/0.9.5/api/evennia.utils.evform.html | 12 +- docs/0.9.5/api/evennia.utils.evmenu.html | 367 +- docs/0.9.5/api/evennia.utils.evmore.html | 166 +- docs/0.9.5/api/evennia.utils.evtable.html | 34 +- docs/0.9.5/api/evennia.utils.gametime.html | 1 - docs/0.9.5/api/evennia.utils.html | 16 +- docs/0.9.5/api/evennia.utils.idmapper.html | 1 - .../api/evennia.utils.idmapper.manager.html | 1 - .../api/evennia.utils.idmapper.models.html | 1 - .../api/evennia.utils.idmapper.tests.html | 1 - docs/0.9.5/api/evennia.utils.inlinefuncs.html | 296 +- docs/0.9.5/api/evennia.utils.logger.html | 59 +- .../api/evennia.utils.optionclasses.html | 7 +- .../api/evennia.utils.optionhandler.html | 1 - docs/0.9.5/api/evennia.utils.picklefield.html | 1 - docs/0.9.5/api/evennia.utils.search.html | 35 +- .../api/evennia.utils.test_resources.html | 2 - docs/0.9.5/api/evennia.utils.text2html.html | 22 +- docs/0.9.5/api/evennia.utils.utils.html | 418 +- .../api/evennia.utils.validatorfuncs.html | 24 +- docs/0.9.5/api/evennia.web.html | 7 +- docs/0.9.5/api/evennia.web.urls.html | 16 +- .../0.9.5/api/evennia.web.utils.backends.html | 1 - .../evennia.web.utils.general_context.html | 9 +- docs/0.9.5/api/evennia.web.utils.html | 1 - .../api/evennia.web.utils.middleware.html | 1 - docs/0.9.5/api/evennia.web.utils.tests.html | 1 - docs/0.9.5/api/evennia.web.webclient.html | 1 - .../0.9.5/api/evennia.web.webclient.urls.html | 4 +- .../api/evennia.web.webclient.views.html | 1 - docs/0.9.5/api/evennia.web.website.forms.html | 1 - docs/0.9.5/api/evennia.web.website.html | 1 - ...nia.web.website.templatetags.addclass.html | 10 +- .../api/evennia.web.website.templatetags.html | 1 - docs/0.9.5/api/evennia.web.website.tests.html | 1 - docs/0.9.5/api/evennia.web.website.urls.html | 3 +- docs/0.9.5/api/evennia.web.website.views.html | 789 +-- docs/0.9.5/genindex.html | 2846 +++++----- docs/0.9.5/index.html | 1 - docs/0.9.5/objects.inv | Bin 70684 -> 71148 bytes docs/0.9.5/py-modindex.html | 121 +- docs/0.9.5/search.html | 1 - docs/0.9.5/searchindex.js | 2 +- docs/0.9.5/toc.html | 1 - docs/1.0-dev/.buildinfo | 2 +- docs/1.0-dev/Coding/Coding-Introduction.html | 3 +- docs/1.0-dev/Coding/Coding-Overview.html | 3 +- .../Coding/Continuous-Integration.html | 3 +- docs/1.0-dev/Coding/Debugging.html | 3 +- docs/1.0-dev/Coding/Flat-API.html | 3 +- docs/1.0-dev/Coding/Profiling.html | 3 +- docs/1.0-dev/Coding/Quirks.html | 3 +- docs/1.0-dev/Coding/Setting-up-PyCharm.html | 3 +- docs/1.0-dev/Coding/Unit-Testing.html | 3 +- docs/1.0-dev/Coding/Updating-Your-Game.html | 3 +- docs/1.0-dev/Coding/Using-Travis.html | 3 +- docs/1.0-dev/Coding/Version-Control.html | 3 +- docs/1.0-dev/Components/Accounts.html | 3 +- docs/1.0-dev/Components/Attributes.html | 3 +- .../Components/Batch-Code-Processor.html | 3 +- .../Components/Batch-Command-Processor.html | 3 +- docs/1.0-dev/Components/Batch-Processors.html | 3 +- .../Bootstrap-Components-and-Utilities.html | 3 +- docs/1.0-dev/Components/Channels.html | 3 +- docs/1.0-dev/Components/Coding-Utils.html | 3 +- docs/1.0-dev/Components/Command-Sets.html | 3 +- docs/1.0-dev/Components/Command-System.html | 3 +- docs/1.0-dev/Components/Commands.html | 3 +- docs/1.0-dev/Components/Communications.html | 3 +- .../Components/Components-Overview.html | 3 +- .../1.0-dev/Components/Connection-Screen.html | 3 +- docs/1.0-dev/Components/EvEditor.html | 3 +- docs/1.0-dev/Components/EvMenu.html | 3 +- docs/1.0-dev/Components/EvMore.html | 3 +- docs/1.0-dev/Components/FuncParser.html | 3 +- docs/1.0-dev/Components/Help-System.html | 3 +- docs/1.0-dev/Components/Inputfuncs.html | 3 +- docs/1.0-dev/Components/Locks.html | 3 +- docs/1.0-dev/Components/MonitorHandler.html | 3 +- docs/1.0-dev/Components/Msg.html | 3 +- docs/1.0-dev/Components/Nicks.html | 3 +- docs/1.0-dev/Components/Objects.html | 3 +- docs/1.0-dev/Components/Outputfuncs.html | 3 +- docs/1.0-dev/Components/Permissions.html | 3 +- .../1.0-dev/Components/Portal-And-Server.html | 3 +- docs/1.0-dev/Components/Prototypes.html | 3 +- docs/1.0-dev/Components/Scripts.html | 3 +- docs/1.0-dev/Components/Server-Conf.html | 3 +- docs/1.0-dev/Components/Server.html | 3 +- docs/1.0-dev/Components/Sessions.html | 3 +- docs/1.0-dev/Components/Signals.html | 3 +- docs/1.0-dev/Components/Tags.html | 3 +- docs/1.0-dev/Components/TickerHandler.html | 3 +- docs/1.0-dev/Components/Typeclasses.html | 3 +- docs/1.0-dev/Components/Web-API.html | 3 +- docs/1.0-dev/Components/Web-Admin.html | 3 +- docs/1.0-dev/Components/Webclient.html | 3 +- docs/1.0-dev/Components/Webserver.html | 3 +- docs/1.0-dev/Components/Website.html | 3 +- docs/1.0-dev/Concepts/Async-Process.html | 3 +- docs/1.0-dev/Concepts/Banning.html | 3 +- .../1.0-dev/Concepts/Bootstrap-&-Evennia.html | 3 +- .../Concepts/Building-Permissions.html | 3 +- docs/1.0-dev/Concepts/Clickable-Links.html | 10 +- docs/1.0-dev/Concepts/Colors.html | 3 +- docs/1.0-dev/Concepts/Concepts-Overview.html | 3 +- docs/1.0-dev/Concepts/Custom-Protocols.html | 3 +- docs/1.0-dev/Concepts/Guest-Logins.html | 3 +- .../Concepts/Internationalization.html | 3 +- docs/1.0-dev/Concepts/Messagepath.html | 3 +- docs/1.0-dev/Concepts/Multisession-modes.html | 3 +- docs/1.0-dev/Concepts/New-Models.html | 3 +- docs/1.0-dev/Concepts/OOB.html | 3 +- docs/1.0-dev/Concepts/Soft-Code.html | 3 +- docs/1.0-dev/Concepts/Text-Encodings.html | 3 +- docs/1.0-dev/Concepts/TextTags.html | 3 +- .../Concepts/Using-MUX-as-a-Standard.html | 3 +- docs/1.0-dev/Concepts/Web-Features.html | 3 +- docs/1.0-dev/Concepts/Zones.html | 3 +- ...-voice-operated-elevator-using-events.html | 3 +- .../Contribs/Arxcode-installing-help.html | 3 +- docs/1.0-dev/Contribs/Building-menus.html | 3 +- docs/1.0-dev/Contribs/Contrib-Overview.html | 3 +- docs/1.0-dev/Contribs/Crafting.html | 3 +- .../1.0-dev/Contribs/Dialogues-in-events.html | 3 +- .../1.0-dev/Contribs/Dynamic-In-Game-Map.html | 3 +- docs/1.0-dev/Contribs/Static-In-Game-Map.html | 3 +- docs/1.0-dev/Contributing-Docs.html | 3 +- docs/1.0-dev/Contributing.html | 3 +- docs/1.0-dev/Evennia-API.html | 3 +- docs/1.0-dev/Evennia-Introduction.html | 3 +- docs/1.0-dev/Glossary.html | 3 +- docs/1.0-dev/How-To-Get-And-Give-Help.html | 7 +- .../Howto/Add-a-wiki-on-your-website.html | 3 +- .../Howto/Building-a-mech-tutorial.html | 3 +- docs/1.0-dev/Howto/Coding-FAQ.html | 3 +- docs/1.0-dev/Howto/Command-Cooldown.html | 3 +- docs/1.0-dev/Howto/Command-Duration.html | 3 +- docs/1.0-dev/Howto/Command-Prompt.html | 3 +- docs/1.0-dev/Howto/Coordinates.html | 3 +- docs/1.0-dev/Howto/Default-Exit-Errors.html | 3 +- .../1.0-dev/Howto/Evennia-for-Diku-Users.html | 3 +- .../1.0-dev/Howto/Evennia-for-MUSH-Users.html | 3 +- .../Evennia-for-roleplaying-sessions.html | 3 +- docs/1.0-dev/Howto/Gametime-Tutorial.html | 3 +- docs/1.0-dev/Howto/Help-System-Tutorial.html | 3 +- docs/1.0-dev/Howto/Howto-Overview.html | 3 +- .../Howto/Manually-Configuring-Color.html | 3 +- .../Howto/Mass-and-weight-for-objects.html | 3 +- docs/1.0-dev/Howto/NPC-shop-Tutorial.html | 3 +- .../Howto/Parsing-commands-tutorial.html | 3 +- .../Howto/Starting/Part1/Adding-Commands.html | 3 +- .../Starting/Part1/Building-Quickstart.html | 3 +- .../Howto/Starting/Part1/Creating-Things.html | 3 +- .../Howto/Starting/Part1/Django-queries.html | 3 +- .../Part1/Evennia-Library-Overview.html | 3 +- .../Starting/Part1/Gamedir-Overview.html | 3 +- .../Starting/Part1/Learning-Typeclasses.html | 3 +- .../Starting/Part1/More-on-Commands.html | 3 +- .../Part1/Python-basic-introduction.html | 3 +- .../Part1/Python-classes-and-objects.html | 3 +- .../Starting/Part1/Searching-Things.html | 3 +- .../Howto/Starting/Part1/Starting-Part1.html | 3 +- .../Part1/Tutorial-World-Introduction.html | 3 +- .../Howto/Starting/Part2/Game-Planning.html | 3 +- .../Part2/Planning-Some-Useful-Contribs.html | 3 +- .../Part2/Planning-The-Tutorial-Game.html | 3 +- .../Part2/Planning-Where-Do-I-Begin.html | 3 +- .../Howto/Starting/Part2/Starting-Part2.html | 3 +- .../Starting/Part3/A-Sittable-Object.html | 3 +- .../Implementing-a-game-rule-system.html | 3 +- .../Howto/Starting/Part3/Starting-Part3.html | 3 +- .../Part3/Turn-based-Combat-System.html | 3 +- .../Tutorial-for-basic-MUSH-like-game.html | 3 +- .../Howto/Starting/Part4/Starting-Part4.html | 3 +- .../Part5/Add-a-simple-new-web-page.html | 3 +- .../Howto/Starting/Part5/Starting-Part5.html | 3 +- .../Howto/Starting/Part5/Web-Tutorial.html | 3 +- .../Howto/Tutorial-Aggressive-NPCs.html | 3 +- .../Howto/Tutorial-NPCs-listening.html | 3 +- .../Howto/Tutorial-Tweeting-Game-Stats.html | 3 +- docs/1.0-dev/Howto/Tutorial-Vehicles.html | 3 +- .../Howto/Understanding-Color-Tags.html | 3 +- docs/1.0-dev/Howto/Weather-Tutorial.html | 3 +- .../Howto/Web-Character-Generation.html | 3 +- .../Howto/Web-Character-View-Tutorial.html | 3 +- docs/1.0-dev/Licensing.html | 3 +- docs/1.0-dev/Links.html | 3 +- docs/1.0-dev/Setup/Apache-Config.html | 3 +- .../1.0-dev/Setup/Choosing-An-SQL-Server.html | 3 +- docs/1.0-dev/Setup/Client-Support-Grid.html | 3 +- docs/1.0-dev/Setup/Evennia-Game-Index.html | 3 +- docs/1.0-dev/Setup/Extended-Installation.html | 3 +- docs/1.0-dev/Setup/Grapevine.html | 3 +- docs/1.0-dev/Setup/HAProxy-Config.html | 3 +- .../How-to-connect-Evennia-to-Twitter.html | 3 +- docs/1.0-dev/Setup/IRC.html | 3 +- docs/1.0-dev/Setup/Installing-on-Android.html | 3 +- docs/1.0-dev/Setup/Online-Setup.html | 3 +- docs/1.0-dev/Setup/RSS.html | 3 +- .../Setup/Running-Evennia-in-Docker.html | 3 +- docs/1.0-dev/Setup/Security.html | 3 +- docs/1.0-dev/Setup/Settings-File.html | 3 +- docs/1.0-dev/Setup/Setup-Overview.html | 3 +- docs/1.0-dev/Setup/Setup-Quickstart.html | 3 +- docs/1.0-dev/Setup/Start-Stop-Reload.html | 3 +- docs/1.0-dev/Unimplemented.html | 3 +- docs/1.0-dev/_modules/django/conf.html | 3 +- .../db/models/fields/related_descriptors.html | 3 +- .../_modules/django/db/models/manager.html | 3 +- .../_modules/django/db/models/query.html | 2117 ++++++++ .../django/db/models/query_utils.html | 3 +- .../_modules/django/utils/deconstruct.html | 158 + .../_modules/django/utils/functional.html | 3 +- docs/1.0-dev/_modules/evennia.html | 9 +- .../_modules/evennia/accounts/accounts.html | 229 +- .../_modules/evennia/accounts/bots.html | 8 +- .../_modules/evennia/accounts/manager.html | 3 +- .../_modules/evennia/accounts/models.html | 10 +- .../_modules/evennia/commands/cmdhandler.html | 136 +- .../_modules/evennia/commands/cmdparser.html | 38 +- .../_modules/evennia/commands/cmdset.html | 25 +- .../evennia/commands/cmdsethandler.html | 33 +- .../_modules/evennia/commands/command.html | 47 +- .../evennia/commands/default/account.html | 5 +- .../evennia/commands/default/admin.html | 3 +- .../commands/default/batchprocess.html | 5 +- .../evennia/commands/default/building.html | 41 +- .../commands/default/cmdset_account.html | 7 +- .../commands/default/cmdset_character.html | 4 +- .../commands/default/cmdset_session.html | 3 +- .../commands/default/cmdset_unloggedin.html | 3 +- .../evennia/commands/default/comms.html | 1794 +++++-- .../evennia/commands/default/general.html | 14 +- .../evennia/commands/default/help.html | 884 +++- .../evennia/commands/default/muxcommand.html | 7 +- .../evennia/commands/default/syscommands.html | 51 +- .../evennia/commands/default/system.html | 406 +- .../evennia/commands/default/tests.html | 824 ++- .../evennia/commands/default/unloggedin.html | 4 +- .../1.0-dev/_modules/evennia/comms/comms.html | 632 +-- .../_modules/evennia/comms/managers.html | 110 +- .../_modules/evennia/comms/models.html | 243 +- .../contrib/awsstorage/aws_s3_cdn.html | 968 ++++ .../evennia/contrib/awsstorage/tests.html | 713 +++ .../_modules/evennia/contrib/barter.html | 3 +- .../evennia/contrib/building_menu.html | 3 +- .../_modules/evennia/contrib/chargen.html | 3 +- .../_modules/evennia/contrib/clothing.html | 3 +- .../evennia/contrib/crafting/crafting.html | 1166 ++++ .../contrib/crafting/example_recipes.html | 407 ++ .../evennia/contrib/crafting/tests.html | 793 +++ .../evennia/contrib/custom_gametime.html | 3 +- .../_modules/evennia/contrib/dice.html | 3 +- .../_modules/evennia/contrib/email_login.html | 3 +- .../evennia/contrib/evscaperoom/commands.html | 3 +- .../evennia/contrib/evscaperoom/menu.html | 3 +- .../evennia/contrib/evscaperoom/objects.html | 3 +- .../evennia/contrib/evscaperoom/room.html | 3 +- .../evennia/contrib/evscaperoom/state.html | 3 +- .../evennia/contrib/evscaperoom/tests.html | 12 +- .../evennia/contrib/evscaperoom/utils.html | 3 +- .../evennia/contrib/extended_room.html | 3 +- .../_modules/evennia/contrib/fieldfill.html | 3 +- .../_modules/evennia/contrib/gendersub.html | 3 +- .../_modules/evennia/contrib/health_bar.html | 3 +- .../ingame_python/callbackhandler.html | 3 +- .../contrib/ingame_python/commands.html | 3 +- .../contrib/ingame_python/eventfuncs.html | 3 +- .../contrib/ingame_python/scripts.html | 8 +- .../evennia/contrib/ingame_python/tests.html | 11 +- .../evennia/contrib/ingame_python/utils.html | 4 +- .../_modules/evennia/contrib/mail.html | 3 +- .../_modules/evennia/contrib/multidescer.html | 3 +- .../_modules/evennia/contrib/puzzles.html | 3 +- .../contrib/random_string_generator.html | 3 +- .../_modules/evennia/contrib/rplanguage.html | 122 +- .../_modules/evennia/contrib/rpsystem.html | 6 +- .../contrib/security/auditing/outputs.html | 3 +- .../contrib/security/auditing/server.html | 3 +- .../contrib/security/auditing/tests.html | 3 +- .../_modules/evennia/contrib/simpledoor.html | 3 +- .../_modules/evennia/contrib/slow_exit.html | 3 +- .../_modules/evennia/contrib/talking_npc.html | 3 +- .../_modules/evennia/contrib/test_traits.html | 1010 ++++ .../_modules/evennia/contrib/traits.html | 1532 ++++++ .../_modules/evennia/contrib/tree_select.html | 3 +- .../evennia/contrib/turnbattle/tb_basic.html | 9 +- .../evennia/contrib/turnbattle/tb_equip.html | 3 +- .../evennia/contrib/turnbattle/tb_items.html | 3 +- .../evennia/contrib/turnbattle/tb_magic.html | 3 +- .../evennia/contrib/turnbattle/tb_range.html | 4 +- .../tutorial_examples/bodyfunctions.html | 3 +- .../contrib/tutorial_examples/mirror.html | 167 + .../contrib/tutorial_examples/red_button.html | 661 ++- .../contrib/tutorial_examples/tests.html | 3 +- .../contrib/tutorial_world/intro_menu.html | 10 +- .../evennia/contrib/tutorial_world/mob.html | 16 +- .../contrib/tutorial_world/objects.html | 26 +- .../evennia/contrib/tutorial_world/rooms.html | 19 +- .../_modules/evennia/contrib/unixcommand.html | 5 +- .../_modules/evennia/contrib/wilderness.html | 3 +- .../_modules/evennia/help/filehelp.html | 314 ++ .../_modules/evennia/help/manager.html | 6 +- .../1.0-dev/_modules/evennia/help/models.html | 78 +- docs/1.0-dev/_modules/evennia/help/utils.html | 336 ++ .../_modules/evennia/locks/lockfuncs.html | 109 +- .../_modules/evennia/locks/lockhandler.html | 51 +- .../_modules/evennia/objects/manager.html | 8 +- .../_modules/evennia/objects/models.html | 52 +- .../_modules/evennia/objects/objects.html | 383 +- .../_modules/evennia/prototypes/menus.html | 14 +- .../evennia/prototypes/protfuncs.html | 344 +- .../evennia/prototypes/prototypes.html | 183 +- .../_modules/evennia/prototypes/spawner.html | 91 +- .../_modules/evennia/scripts/manager.html | 111 +- .../_modules/evennia/scripts/models.html | 7 +- .../evennia/scripts/monitorhandler.html | 5 +- .../evennia/scripts/scripthandler.html | 40 +- .../_modules/evennia/scripts/scripts.html | 712 +-- .../_modules/evennia/scripts/taskhandler.html | 89 +- .../evennia/scripts/tickerhandler.html | 3 +- .../_modules/evennia/server/amp_client.html | 7 +- .../evennia/server/connection_wizard.html | 3 +- .../_modules/evennia/server/deprecations.html | 40 +- .../evennia/server/evennia_launcher.html | 24 +- .../server/game_index_client/client.html | 3 +- .../server/game_index_client/service.html | 3 +- .../evennia/server/initial_setup.html | 24 +- .../_modules/evennia/server/inputfuncs.html | 8 +- .../_modules/evennia/server/manager.html | 3 +- .../_modules/evennia/server/models.html | 11 +- .../_modules/evennia/server/portal/amp.html | 25 +- .../evennia/server/portal/amp_server.html | 13 +- .../evennia/server/portal/grapevine.html | 5 +- .../_modules/evennia/server/portal/irc.html | 3 +- .../_modules/evennia/server/portal/mccp.html | 194 + .../_modules/evennia/server/portal/mssp.html | 239 + .../_modules/evennia/server/portal/mxp.html | 191 + .../_modules/evennia/server/portal/naws.html | 189 + .../evennia/server/portal/portal.html | 550 ++ .../server/portal/portalsessionhandler.html | 48 +- .../_modules/evennia/server/portal/rss.html | 4 +- .../_modules/evennia/server/portal/ssh.html | 45 +- .../_modules/evennia/server/portal/ssl.html | 225 + .../evennia/server/portal/suppress_ga.html | 173 + .../evennia/server/portal/telnet.html | 615 +++ .../evennia/server/portal/telnet_oob.html | 544 ++ .../evennia/server/portal/telnet_ssl.html | 257 + .../_modules/evennia/server/portal/tests.html | 426 ++ .../_modules/evennia/server/portal/ttype.html | 292 + .../evennia/server/portal/webclient.html | 16 +- .../evennia/server/portal/webclient_ajax.html | 11 +- .../evennia/server/profiling/dummyrunner.html | 271 +- .../profiling/dummyrunner_settings.html | 279 +- .../evennia/server/profiling/memplot.html | 3 +- .../server/profiling/test_queries.html | 3 +- .../evennia/server/profiling/tests.html | 57 +- .../evennia/server/profiling/timetrace.html | 3 +- .../_modules/evennia/server/server.html | 95 +- .../evennia/server/serversession.html | 169 +- .../_modules/evennia/server/session.html | 31 +- .../evennia/server/sessionhandler.html | 189 +- .../_modules/evennia/server/throttle.html | 146 +- .../_modules/evennia/server/validators.html | 7 +- .../_modules/evennia/server/webserver.html | 3 +- .../evennia/typeclasses/attributes.html | 1270 +++-- .../evennia/typeclasses/managers.html | 41 +- .../_modules/evennia/typeclasses/models.html | 253 +- .../_modules/evennia/typeclasses/tags.html | 57 +- docs/1.0-dev/_modules/evennia/utils/ansi.html | 99 +- .../evennia/utils/batchprocessors.html | 153 +- .../_modules/evennia/utils/containers.html | 16 +- .../_modules/evennia/utils/create.html | 79 +- .../_modules/evennia/utils/dbserialize.html | 7 +- .../_modules/evennia/utils/eveditor.html | 249 +- .../_modules/evennia/utils/evform.html | 72 +- .../_modules/evennia/utils/evmenu.html | 535 +- .../_modules/evennia/utils/evmore.html | 175 +- .../_modules/evennia/utils/evtable.html | 78 +- .../_modules/evennia/utils/funcparser.html | 1286 +++++ .../_modules/evennia/utils/gametime.html | 5 +- .../evennia/utils/idmapper/manager.html | 3 +- .../evennia/utils/idmapper/models.html | 25 +- .../evennia/utils/idmapper/tests.html | 3 +- .../_modules/evennia/utils/logger.html | 66 +- .../_modules/evennia/utils/optionclasses.html | 15 +- .../_modules/evennia/utils/optionhandler.html | 19 +- .../_modules/evennia/utils/picklefield.html | 5 +- .../_modules/evennia/utils/search.html | 18 +- .../evennia/utils/test_resources.html | 23 +- .../_modules/evennia/utils/text2html.html | 22 +- .../1.0-dev/_modules/evennia/utils/utils.html | 736 ++- .../evennia/utils/validatorfuncs.html | 79 +- .../utils/verb_conjugation/conjugate.html | 492 ++ .../evennia/utils/verb_conjugation/tests.html | 346 ++ .../_modules/evennia/web/admin/accounts.html} | 409 +- .../evennia/web/admin/attributes.html | 312 ++ .../_modules/evennia/web/admin/comms.html | 389 ++ .../_modules/evennia/web/admin/frontpage.html | 132 + .../_modules/evennia/web/admin/help.html} | 94 +- .../_modules/evennia/web/admin/objects.html | 456 ++ .../_modules/evennia/web/admin/scripts.html | 265 + .../_modules/evennia/web/admin/server.html} | 77 +- .../_modules/evennia/web/admin/tags.html | 339 ++ .../_modules/evennia/web/admin/utils.html | 184 + .../_modules/evennia/web/api/filters.html | 252 + .../_modules/evennia/web/api/permissions.html | 198 + .../_modules/evennia/web/api/root.html | 122 + .../_modules/evennia/web/api/serializers.html | 441 ++ .../_modules/evennia/web/api/tests.html | 284 + .../_modules/evennia/web/api/views.html | 278 + .../evennia/web}/templatetags/addclass.html | 63 +- .../_modules/evennia/web/utils/adminsite.html | 142 + .../_modules/evennia/web/utils/backends.html | 3 +- .../evennia/web/utils/general_context.html | 73 +- .../evennia/web/utils/middleware.html | 3 +- .../_modules/evennia/web/utils/tests.html | 12 +- .../_modules/evennia/web/webclient/views.html | 3 +- .../_modules/evennia/web/website/forms.html | 5 +- .../_modules/evennia/web/website/tests.html | 3 +- .../_modules/evennia/web/website/views.html | 1236 ----- .../evennia/web/website/views/accounts.html | 181 + .../evennia/web/website/views/channels.html | 280 + .../evennia/web/website/views/characters.html | 359 ++ .../evennia/web/website/views/errors.html | 121 + .../evennia/web/website/views/help.html | 267 + .../evennia/web/website/views/index.html | 219 + .../evennia/web/website/views/mixins.html | 196 + .../evennia/web/website/views/objects.html | 373 ++ docs/1.0-dev/_modules/functools.html | 3 +- docs/1.0-dev/_modules/index.html | 58 +- .../1.0-dev/_modules/rest_framework/test.html | 499 ++ .../_sources/Concepts/Clickable-Links.md.txt | 7 +- .../_sources/How-To-Get-And-Give-Help.md.txt | 24 +- docs/1.0-dev/_static/nature.css | 13 +- docs/1.0-dev/api/evennia-api.html | 60 +- .../api/evennia.accounts.accounts.html | 191 +- docs/1.0-dev/api/evennia.accounts.bots.html | 3 +- docs/1.0-dev/api/evennia.accounts.html | 3 +- .../1.0-dev/api/evennia.accounts.manager.html | 3 +- docs/1.0-dev/api/evennia.accounts.models.html | 3 +- .../api/evennia.commands.cmdhandler.html | 24 +- .../api/evennia.commands.cmdparser.html | 7 +- docs/1.0-dev/api/evennia.commands.cmdset.html | 3 +- .../api/evennia.commands.cmdsethandler.html | 11 +- .../1.0-dev/api/evennia.commands.command.html | 33 +- .../api/evennia.commands.default.account.html | 72 +- .../api/evennia.commands.default.admin.html | 43 +- ...evennia.commands.default.batchprocess.html | 13 +- .../evennia.commands.default.building.html | 145 +- ...ennia.commands.default.cmdset_account.html | 3 +- ...nia.commands.default.cmdset_character.html | 3 +- ...ennia.commands.default.cmdset_session.html | 3 +- ...ia.commands.default.cmdset_unloggedin.html | 3 +- .../api/evennia.commands.default.comms.html | 949 +++- .../api/evennia.commands.default.general.html | 75 +- .../api/evennia.commands.default.help.html | 319 +- .../1.0-dev/api/evennia.commands.default.html | 3 +- .../evennia.commands.default.muxcommand.html | 13 +- .../evennia.commands.default.syscommands.html | 126 +- .../api/evennia.commands.default.system.html | 175 +- .../api/evennia.commands.default.tests.html | 442 +- .../evennia.commands.default.unloggedin.html | 36 +- docs/1.0-dev/api/evennia.commands.html | 3 +- docs/1.0-dev/api/evennia.comms.comms.html | 507 +- docs/1.0-dev/api/evennia.comms.html | 3 +- docs/1.0-dev/api/evennia.comms.managers.html | 37 +- docs/1.0-dev/api/evennia.comms.models.html | 134 +- ...evennia.contrib.awsstorage.aws_s3_cdn.html | 470 +- .../api/evennia.contrib.awsstorage.html | 4 +- .../api/evennia.contrib.awsstorage.tests.html | 224 +- docs/1.0-dev/api/evennia.contrib.barter.html | 50 +- .../api/evennia.contrib.building_menu.html | 18 +- docs/1.0-dev/api/evennia.contrib.chargen.html | 15 +- .../1.0-dev/api/evennia.contrib.clothing.html | 38 +- .../api/evennia.contrib.color_markups.html | 3 +- .../evennia.contrib.crafting.crafting.html | 786 ++- ...nnia.contrib.crafting.example_recipes.html | 351 +- .../1.0-dev/api/evennia.contrib.crafting.html | 16 +- .../api/evennia.contrib.crafting.tests.html | 220 +- .../api/evennia.contrib.custom_gametime.html | 3 +- docs/1.0-dev/api/evennia.contrib.dice.html | 10 +- .../api/evennia.contrib.email_login.html | 36 +- .../evennia.contrib.evscaperoom.commands.html | 100 +- .../api/evennia.contrib.evscaperoom.html | 3 +- .../api/evennia.contrib.evscaperoom.menu.html | 3 +- .../evennia.contrib.evscaperoom.objects.html | 3 +- .../api/evennia.contrib.evscaperoom.room.html | 3 +- .../evennia.contrib.evscaperoom.scripts.html | 3 +- .../evennia.contrib.evscaperoom.state.html | 3 +- .../evennia.contrib.evscaperoom.tests.html | 3 +- .../evennia.contrib.evscaperoom.utils.html | 3 +- .../api/evennia.contrib.extended_room.html | 25 +- .../api/evennia.contrib.fieldfill.html | 8 +- .../api/evennia.contrib.gendersub.html | 8 +- .../api/evennia.contrib.health_bar.html | 3 +- docs/1.0-dev/api/evennia.contrib.html | 40 +- ...contrib.ingame_python.callbackhandler.html | 3 +- ...vennia.contrib.ingame_python.commands.html | 10 +- ...nnia.contrib.ingame_python.eventfuncs.html | 3 +- .../api/evennia.contrib.ingame_python.html | 3 +- ...evennia.contrib.ingame_python.scripts.html | 7 +- .../evennia.contrib.ingame_python.tests.html | 3 +- ...nia.contrib.ingame_python.typeclasses.html | 3 +- .../evennia.contrib.ingame_python.utils.html | 3 +- docs/1.0-dev/api/evennia.contrib.mail.html | 13 +- .../api/evennia.contrib.mapbuilder.html | 3 +- .../api/evennia.contrib.menu_login.html | 3 +- .../api/evennia.contrib.multidescer.html | 8 +- docs/1.0-dev/api/evennia.contrib.puzzles.html | 33 +- ...ennia.contrib.random_string_generator.html | 3 +- .../api/evennia.contrib.rplanguage.html | 47 +- .../1.0-dev/api/evennia.contrib.rpsystem.html | 45 +- .../evennia.contrib.security.auditing.html | 3 +- ...nia.contrib.security.auditing.outputs.html | 3 +- ...nnia.contrib.security.auditing.server.html | 3 +- ...ennia.contrib.security.auditing.tests.html | 3 +- .../1.0-dev/api/evennia.contrib.security.html | 3 +- .../api/evennia.contrib.simpledoor.html | 13 +- .../api/evennia.contrib.slow_exit.html | 13 +- .../api/evennia.contrib.talking_npc.html | 8 +- .../api/evennia.contrib.test_traits.html | 405 +- docs/1.0-dev/api/evennia.contrib.traits.html | 832 ++- .../api/evennia.contrib.tree_select.html | 8 +- .../api/evennia.contrib.turnbattle.html | 3 +- .../evennia.contrib.turnbattle.tb_basic.html | 35 +- .../evennia.contrib.turnbattle.tb_equip.html | 55 +- .../evennia.contrib.turnbattle.tb_items.html | 40 +- .../evennia.contrib.turnbattle.tb_magic.html | 50 +- .../evennia.contrib.turnbattle.tb_range.html | 55 +- ...ntrib.tutorial_examples.bodyfunctions.html | 3 +- ....tutorial_examples.example_batch_code.html | 3 +- .../evennia.contrib.tutorial_examples.html | 8 +- ...nnia.contrib.tutorial_examples.mirror.html | 78 +- ....contrib.tutorial_examples.red_button.html | 663 ++- ...ennia.contrib.tutorial_examples.tests.html | 3 +- .../api/evennia.contrib.tutorial_world.html | 3 +- ...nia.contrib.tutorial_world.intro_menu.html | 3 +- .../evennia.contrib.tutorial_world.mob.html | 10 +- ...vennia.contrib.tutorial_world.objects.html | 106 +- .../evennia.contrib.tutorial_world.rooms.html | 69 +- .../api/evennia.contrib.unixcommand.html | 8 +- .../api/evennia.contrib.wilderness.html | 3 +- docs/1.0-dev/api/evennia.help.filehelp.html | 167 +- docs/1.0-dev/api/evennia.help.html | 3 +- docs/1.0-dev/api/evennia.help.manager.html | 3 +- docs/1.0-dev/api/evennia.help.models.html | 102 +- docs/1.0-dev/api/evennia.help.utils.html | 109 +- docs/1.0-dev/api/evennia.html | 61 +- docs/1.0-dev/api/evennia.locks.html | 8 +- docs/1.0-dev/api/evennia.locks.lockfuncs.html | 126 +- .../api/evennia.locks.lockhandler.html | 3 +- docs/1.0-dev/api/evennia.objects.html | 3 +- docs/1.0-dev/api/evennia.objects.manager.html | 3 +- docs/1.0-dev/api/evennia.objects.models.html | 21 +- docs/1.0-dev/api/evennia.objects.objects.html | 188 +- docs/1.0-dev/api/evennia.prototypes.html | 3 +- .../1.0-dev/api/evennia.prototypes.menus.html | 3 +- .../api/evennia.prototypes.protfuncs.html | 172 +- .../api/evennia.prototypes.prototypes.html | 32 +- .../api/evennia.prototypes.spawner.html | 15 +- docs/1.0-dev/api/evennia.scripts.html | 3 +- docs/1.0-dev/api/evennia.scripts.manager.html | 3 +- docs/1.0-dev/api/evennia.scripts.models.html | 3 +- .../api/evennia.scripts.monitorhandler.html | 3 +- .../api/evennia.scripts.scripthandler.html | 22 +- docs/1.0-dev/api/evennia.scripts.scripts.html | 218 +- .../api/evennia.scripts.taskhandler.html | 8 +- .../api/evennia.scripts.tickerhandler.html | 3 +- .../api/evennia.server.amp_client.html | 3 +- .../api/evennia.server.connection_wizard.html | 3 +- .../api/evennia.server.deprecations.html | 3 +- .../api/evennia.server.evennia_launcher.html | 3 +- ...ennia.server.game_index_client.client.html | 3 +- .../api/evennia.server.game_index_client.html | 3 +- ...nnia.server.game_index_client.service.html | 3 +- docs/1.0-dev/api/evennia.server.html | 3 +- .../api/evennia.server.initial_setup.html | 3 +- .../api/evennia.server.inputfuncs.html | 3 +- docs/1.0-dev/api/evennia.server.manager.html | 3 +- docs/1.0-dev/api/evennia.server.models.html | 3 +- .../api/evennia.server.portal.amp.html | 7 +- .../api/evennia.server.portal.amp_server.html | 5 +- .../api/evennia.server.portal.grapevine.html | 3 +- docs/1.0-dev/api/evennia.server.portal.html | 3 +- .../api/evennia.server.portal.irc.html | 3 +- .../api/evennia.server.portal.mccp.html | 77 +- .../api/evennia.server.portal.mssp.html | 78 +- .../api/evennia.server.portal.mxp.html | 70 +- .../api/evennia.server.portal.naws.html | 66 +- .../api/evennia.server.portal.portal.html | 65 +- ...ia.server.portal.portalsessionhandler.html | 16 +- .../api/evennia.server.portal.rss.html | 3 +- .../api/evennia.server.portal.ssh.html | 21 +- .../api/evennia.server.portal.ssl.html | 48 +- .../evennia.server.portal.suppress_ga.html | 56 +- .../api/evennia.server.portal.telnet.html | 249 +- .../api/evennia.server.portal.telnet_oob.html | 219 +- .../api/evennia.server.portal.telnet_ssl.html | 59 +- .../api/evennia.server.portal.tests.html | 115 +- .../api/evennia.server.portal.ttype.html | 65 +- .../api/evennia.server.portal.webclient.html | 3 +- .../evennia.server.portal.webclient_ajax.html | 8 +- .../evennia.server.profiling.dummyrunner.html | 97 +- ...server.profiling.dummyrunner_settings.html | 58 +- .../1.0-dev/api/evennia.server.profiling.html | 3 +- .../api/evennia.server.profiling.memplot.html | 3 +- ...ennia.server.profiling.settings_mixin.html | 3 +- ...evennia.server.profiling.test_queries.html | 3 +- .../api/evennia.server.profiling.tests.html | 3 +- .../evennia.server.profiling.timetrace.html | 3 +- docs/1.0-dev/api/evennia.server.server.html | 35 +- .../api/evennia.server.serversession.html | 142 +- docs/1.0-dev/api/evennia.server.session.html | 3 +- .../api/evennia.server.sessionhandler.html | 78 +- docs/1.0-dev/api/evennia.server.signals.html | 23 +- docs/1.0-dev/api/evennia.server.throttle.html | 65 +- .../api/evennia.server.validators.html | 3 +- .../1.0-dev/api/evennia.server.webserver.html | 3 +- .../1.0-dev/api/evennia.settings_default.html | 3 +- .../api/evennia.typeclasses.attributes.html | 968 +++- docs/1.0-dev/api/evennia.typeclasses.html | 3 +- .../api/evennia.typeclasses.managers.html | 21 +- .../api/evennia.typeclasses.models.html | 381 +- .../1.0-dev/api/evennia.typeclasses.tags.html | 35 +- docs/1.0-dev/api/evennia.utils.ansi.html | 82 +- .../api/evennia.utils.batchprocessors.html | 140 +- .../1.0-dev/api/evennia.utils.containers.html | 3 +- docs/1.0-dev/api/evennia.utils.create.html | 68 +- .../api/evennia.utils.dbserialize.html | 5 +- docs/1.0-dev/api/evennia.utils.eveditor.html | 99 +- docs/1.0-dev/api/evennia.utils.evform.html | 14 +- docs/1.0-dev/api/evennia.utils.evmenu.html | 369 +- docs/1.0-dev/api/evennia.utils.evmore.html | 168 +- docs/1.0-dev/api/evennia.utils.evtable.html | 36 +- .../1.0-dev/api/evennia.utils.funcparser.html | 614 ++- docs/1.0-dev/api/evennia.utils.gametime.html | 3 +- docs/1.0-dev/api/evennia.utils.html | 18 +- docs/1.0-dev/api/evennia.utils.idmapper.html | 3 +- .../api/evennia.utils.idmapper.manager.html | 3 +- .../api/evennia.utils.idmapper.models.html | 3 +- .../api/evennia.utils.idmapper.tests.html | 3 +- docs/1.0-dev/api/evennia.utils.logger.html | 61 +- .../api/evennia.utils.optionclasses.html | 9 +- .../api/evennia.utils.optionhandler.html | 3 +- .../api/evennia.utils.picklefield.html | 3 +- docs/1.0-dev/api/evennia.utils.search.html | 37 +- .../api/evennia.utils.test_resources.html | 4 +- docs/1.0-dev/api/evennia.utils.text2html.html | 24 +- docs/1.0-dev/api/evennia.utils.utils.html | 420 +- .../api/evennia.utils.validatorfuncs.html | 26 +- ...nnia.utils.verb_conjugation.conjugate.html | 261 +- .../api/evennia.utils.verb_conjugation.html | 3 +- .../evennia.utils.verb_conjugation.tests.html | 710 ++- .../api/evennia.web.admin.accounts.html | 391 +- .../api/evennia.web.admin.attributes.html | 150 +- docs/1.0-dev/api/evennia.web.admin.comms.html | 391 +- .../api/evennia.web.admin.frontpage.html | 20 +- docs/1.0-dev/api/evennia.web.admin.help.html | 143 +- docs/1.0-dev/api/evennia.web.admin.html | 4 +- .../api/evennia.web.admin.objects.html | 311 +- .../api/evennia.web.admin.scripts.html | 193 +- .../1.0-dev/api/evennia.web.admin.server.html | 56 +- docs/1.0-dev/api/evennia.web.admin.tags.html | 235 +- docs/1.0-dev/api/evennia.web.admin.urls.html | 9 +- docs/1.0-dev/api/evennia.web.admin.utils.html | 48 +- docs/1.0-dev/api/evennia.web.api.filters.html | 218 +- docs/1.0-dev/api/evennia.web.api.html | 3 +- .../api/evennia.web.api.permissions.html | 103 +- docs/1.0-dev/api/evennia.web.api.root.html | 27 +- .../api/evennia.web.api.serializers.html | 457 +- docs/1.0-dev/api/evennia.web.api.tests.html | 73 +- docs/1.0-dev/api/evennia.web.api.urls.html | 21 +- docs/1.0-dev/api/evennia.web.api.views.html | 408 +- docs/1.0-dev/api/evennia.web.html | 9 +- .../evennia.web.templatetags.addclass.html | 12 +- .../1.0-dev/api/evennia.web.templatetags.html | 3 +- docs/1.0-dev/api/evennia.web.urls.html | 18 +- .../api/evennia.web.utils.adminsite.html | 49 +- .../api/evennia.web.utils.backends.html | 3 +- .../evennia.web.utils.general_context.html | 11 +- docs/1.0-dev/api/evennia.web.utils.html | 3 +- .../api/evennia.web.utils.middleware.html | 3 +- docs/1.0-dev/api/evennia.web.utils.tests.html | 3 +- docs/1.0-dev/api/evennia.web.webclient.html | 3 +- .../api/evennia.web.webclient.urls.html | 6 +- .../api/evennia.web.webclient.views.html | 3 +- .../api/evennia.web.website.forms.html | 3 +- docs/1.0-dev/api/evennia.web.website.html | 3 +- .../api/evennia.web.website.tests.html | 3 +- .../1.0-dev/api/evennia.web.website.urls.html | 5 +- .../evennia.web.website.views.accounts.html | 55 +- .../evennia.web.website.views.channels.html | 130 +- .../evennia.web.website.views.characters.html | 221 +- .../api/evennia.web.website.views.errors.html | 15 +- .../api/evennia.web.website.views.help.html | 99 +- .../api/evennia.web.website.views.html | 791 +-- .../api/evennia.web.website.views.index.html | 56 +- .../api/evennia.web.website.views.mixins.html | 82 +- .../evennia.web.website.views.objects.html | 180 +- docs/1.0-dev/genindex.html | 4676 +++++++++++++++-- docs/1.0-dev/index.html | 3 +- docs/1.0-dev/objects.inv | Bin 76964 -> 87631 bytes docs/1.0-dev/py-modindex.html | 268 +- docs/1.0-dev/search.html | 3 +- docs/1.0-dev/searchindex.js | 2 +- docs/1.0-dev/toc.html | 3 +- 1221 files changed, 76528 insertions(+), 29095 deletions(-) delete mode 100644 docs/0.9.5/_modules/django/utils/functional.html delete mode 100644 docs/0.9.5/_modules/evennia/comms/admin.html delete mode 100644 docs/0.9.5/_modules/evennia/comms/channelhandler.html delete mode 100644 docs/0.9.5/_modules/evennia/contrib/tutorial_examples/cmdset_red_button.html delete mode 100644 docs/0.9.5/_modules/evennia/contrib/tutorial_examples/red_button_scripts.html delete mode 100644 docs/0.9.5/_modules/evennia/objects/admin.html delete mode 100644 docs/0.9.5/_modules/evennia/scripts/admin.html create mode 100644 docs/0.9.5/_modules/evennia/server/portal/mccp.html create mode 100644 docs/0.9.5/_modules/evennia/server/portal/mssp.html create mode 100644 docs/0.9.5/_modules/evennia/server/portal/mxp.html create mode 100644 docs/0.9.5/_modules/evennia/server/portal/naws.html create mode 100644 docs/0.9.5/_modules/evennia/server/portal/portal.html create mode 100644 docs/0.9.5/_modules/evennia/server/portal/ssl.html create mode 100644 docs/0.9.5/_modules/evennia/server/portal/suppress_ga.html create mode 100644 docs/0.9.5/_modules/evennia/server/portal/telnet.html create mode 100644 docs/0.9.5/_modules/evennia/server/portal/telnet_oob.html create mode 100644 docs/0.9.5/_modules/evennia/server/portal/telnet_ssl.html create mode 100644 docs/0.9.5/_modules/evennia/server/portal/tests.html create mode 100644 docs/0.9.5/_modules/evennia/server/portal/ttype.html delete mode 100644 docs/0.9.5/_modules/evennia/typeclasses/admin.html delete mode 100644 docs/0.9.5/_modules/evennia/utils/inlinefuncs.html delete mode 100644 docs/0.9.5/_modules/evennia/web/website/views.html create mode 100644 docs/1.0-dev/_modules/django/db/models/query.html create mode 100644 docs/1.0-dev/_modules/django/utils/deconstruct.html create mode 100644 docs/1.0-dev/_modules/evennia/contrib/awsstorage/aws_s3_cdn.html create mode 100644 docs/1.0-dev/_modules/evennia/contrib/awsstorage/tests.html create mode 100644 docs/1.0-dev/_modules/evennia/contrib/crafting/crafting.html create mode 100644 docs/1.0-dev/_modules/evennia/contrib/crafting/example_recipes.html create mode 100644 docs/1.0-dev/_modules/evennia/contrib/crafting/tests.html create mode 100644 docs/1.0-dev/_modules/evennia/contrib/test_traits.html create mode 100644 docs/1.0-dev/_modules/evennia/contrib/traits.html create mode 100644 docs/1.0-dev/_modules/evennia/contrib/tutorial_examples/mirror.html create mode 100644 docs/1.0-dev/_modules/evennia/help/filehelp.html create mode 100644 docs/1.0-dev/_modules/evennia/help/utils.html create mode 100644 docs/1.0-dev/_modules/evennia/server/portal/mccp.html create mode 100644 docs/1.0-dev/_modules/evennia/server/portal/mssp.html create mode 100644 docs/1.0-dev/_modules/evennia/server/portal/mxp.html create mode 100644 docs/1.0-dev/_modules/evennia/server/portal/naws.html create mode 100644 docs/1.0-dev/_modules/evennia/server/portal/portal.html create mode 100644 docs/1.0-dev/_modules/evennia/server/portal/ssl.html create mode 100644 docs/1.0-dev/_modules/evennia/server/portal/suppress_ga.html create mode 100644 docs/1.0-dev/_modules/evennia/server/portal/telnet.html create mode 100644 docs/1.0-dev/_modules/evennia/server/portal/telnet_oob.html create mode 100644 docs/1.0-dev/_modules/evennia/server/portal/telnet_ssl.html create mode 100644 docs/1.0-dev/_modules/evennia/server/portal/tests.html create mode 100644 docs/1.0-dev/_modules/evennia/server/portal/ttype.html create mode 100644 docs/1.0-dev/_modules/evennia/utils/funcparser.html create mode 100644 docs/1.0-dev/_modules/evennia/utils/verb_conjugation/conjugate.html create mode 100644 docs/1.0-dev/_modules/evennia/utils/verb_conjugation/tests.html rename docs/{0.9.5/_modules/evennia/accounts/admin.html => 1.0-dev/_modules/evennia/web/admin/accounts.html} (53%) create mode 100644 docs/1.0-dev/_modules/evennia/web/admin/attributes.html create mode 100644 docs/1.0-dev/_modules/evennia/web/admin/comms.html create mode 100644 docs/1.0-dev/_modules/evennia/web/admin/frontpage.html rename docs/{0.9.5/_modules/evennia/help/admin.html => 1.0-dev/_modules/evennia/web/admin/help.html} (56%) create mode 100644 docs/1.0-dev/_modules/evennia/web/admin/objects.html create mode 100644 docs/1.0-dev/_modules/evennia/web/admin/scripts.html rename docs/{0.9.5/_modules/evennia/server/admin.html => 1.0-dev/_modules/evennia/web/admin/server.html} (54%) create mode 100644 docs/1.0-dev/_modules/evennia/web/admin/tags.html create mode 100644 docs/1.0-dev/_modules/evennia/web/admin/utils.html create mode 100644 docs/1.0-dev/_modules/evennia/web/api/filters.html create mode 100644 docs/1.0-dev/_modules/evennia/web/api/permissions.html create mode 100644 docs/1.0-dev/_modules/evennia/web/api/root.html create mode 100644 docs/1.0-dev/_modules/evennia/web/api/serializers.html create mode 100644 docs/1.0-dev/_modules/evennia/web/api/tests.html create mode 100644 docs/1.0-dev/_modules/evennia/web/api/views.html rename docs/{0.9.5/_modules/evennia/web/website => 1.0-dev/_modules/evennia/web}/templatetags/addclass.html (64%) create mode 100644 docs/1.0-dev/_modules/evennia/web/utils/adminsite.html delete mode 100644 docs/1.0-dev/_modules/evennia/web/website/views.html create mode 100644 docs/1.0-dev/_modules/evennia/web/website/views/accounts.html create mode 100644 docs/1.0-dev/_modules/evennia/web/website/views/channels.html create mode 100644 docs/1.0-dev/_modules/evennia/web/website/views/characters.html create mode 100644 docs/1.0-dev/_modules/evennia/web/website/views/errors.html create mode 100644 docs/1.0-dev/_modules/evennia/web/website/views/help.html create mode 100644 docs/1.0-dev/_modules/evennia/web/website/views/index.html create mode 100644 docs/1.0-dev/_modules/evennia/web/website/views/mixins.html create mode 100644 docs/1.0-dev/_modules/evennia/web/website/views/objects.html create mode 100644 docs/1.0-dev/_modules/rest_framework/test.html diff --git a/docs/0.9.5/.buildinfo b/docs/0.9.5/.buildinfo index 44b66df96b..968c143413 100644 --- a/docs/0.9.5/.buildinfo +++ b/docs/0.9.5/.buildinfo @@ -1,4 +1,4 @@ # Sphinx build info version 1 # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. -config: 309a848b9229079210e6ddb568dd313d +config: 86151e183f64ea732443e3117128c91d tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/docs/0.9.5/A-voice-operated-elevator-using-events.html b/docs/0.9.5/A-voice-operated-elevator-using-events.html index 9fd3813e70..f7a3f0d952 100644 --- a/docs/0.9.5/A-voice-operated-elevator-using-events.html +++ b/docs/0.9.5/A-voice-operated-elevator-using-events.html @@ -578,7 +578,6 @@ shown in the next tutorial.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/API-refactoring.html b/docs/0.9.5/API-refactoring.html index 9c78edb7f4..4582313f82 100644 --- a/docs/0.9.5/API-refactoring.html +++ b/docs/0.9.5/API-refactoring.html @@ -154,7 +154,6 @@ easier passthrough on extension.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Accounts.html b/docs/0.9.5/Accounts.html index 979a62cf5f..70f2426be7 100644 --- a/docs/0.9.5/Accounts.html +++ b/docs/0.9.5/Accounts.html @@ -215,7 +215,6 @@ any.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Add-a-simple-new-web-page.html b/docs/0.9.5/Add-a-simple-new-web-page.html index 22bd737b99..1124bfd730 100644 --- a/docs/0.9.5/Add-a-simple-new-web-page.html +++ b/docs/0.9.5/Add-a-simple-new-web-page.html @@ -220,7 +220,6 @@ to.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Add-a-wiki-on-your-website.html b/docs/0.9.5/Add-a-wiki-on-your-website.html index 1aee04d570..50e8d021c1 100644 --- a/docs/0.9.5/Add-a-wiki-on-your-website.html +++ b/docs/0.9.5/Add-a-wiki-on-your-website.html @@ -427,7 +427,6 @@ necessary. If you’re interested in supporting this little project, you are mo
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Adding-Command-Tutorial.html b/docs/0.9.5/Adding-Command-Tutorial.html index c1046d7064..497eeccc93 100644 --- a/docs/0.9.5/Adding-Command-Tutorial.html +++ b/docs/0.9.5/Adding-Command-Tutorial.html @@ -318,7 +318,6 @@ default character cmdset defaults to being defined as

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Adding-Object-Typeclass-Tutorial.html b/docs/0.9.5/Adding-Object-Typeclass-Tutorial.html index f413613047..ba425e3dd4 100644 --- a/docs/0.9.5/Adding-Object-Typeclass-Tutorial.html +++ b/docs/0.9.5/Adding-Object-Typeclass-Tutorial.html @@ -228,7 +228,6 @@ objects you can use 0.9.5 (v0.9.5 branch) -
    diff --git a/docs/0.9.5/Administrative-Docs.html b/docs/0.9.5/Administrative-Docs.html index 16592a604f..5ef49de62d 100644 --- a/docs/0.9.5/Administrative-Docs.html +++ b/docs/0.9.5/Administrative-Docs.html @@ -172,7 +172,6 @@ Settings

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Apache-Config.html b/docs/0.9.5/Apache-Config.html index fbc25cabe2..1a61778fa5 100644 --- a/docs/0.9.5/Apache-Config.html +++ b/docs/0.9.5/Apache-Config.html @@ -296,7 +296,6 @@ port but this should be applicable also to other types of proxies (like nginx).<
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Arxcode-installing-help.html b/docs/0.9.5/Arxcode-installing-help.html index e91248a1e3..b965d6f634 100644 --- a/docs/0.9.5/Arxcode-installing-help.html +++ b/docs/0.9.5/Arxcode-installing-help.html @@ -337,7 +337,6 @@ on localhost at port 4000, and the webserver at http://localhost:4001/

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Async-Process.html b/docs/0.9.5/Async-Process.html index a4db249fe2..4eabfa29a7 100644 --- a/docs/0.9.5/Async-Process.html +++ b/docs/0.9.5/Async-Process.html @@ -368,7 +368,6 @@ your own liking.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Attributes.html b/docs/0.9.5/Attributes.html index 75abc3fc3d..0d9f242373 100644 --- a/docs/0.9.5/Attributes.html +++ b/docs/0.9.5/Attributes.html @@ -538,7 +538,6 @@ those will check for the 0.9.5 (v0.9.5 branch) -
    diff --git a/docs/0.9.5/Banning.html b/docs/0.9.5/Banning.html index 62fb897e93..8773d63a6a 100644 --- a/docs/0.9.5/Banning.html +++ b/docs/0.9.5/Banning.html @@ -257,7 +257,6 @@ password of any account, including the superuser or admin accounts. This is a fe
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Batch-Code-Processor.html b/docs/0.9.5/Batch-Code-Processor.html index e698ff1cf2..10288e5464 100644 --- a/docs/0.9.5/Batch-Code-Processor.html +++ b/docs/0.9.5/Batch-Code-Processor.html @@ -384,7 +384,6 @@ executed. When the code runs it has no knowledge of what file those strings wher
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Batch-Command-Processor.html b/docs/0.9.5/Batch-Command-Processor.html index 30ebf172b9..5a524db857 100644 --- a/docs/0.9.5/Batch-Command-Processor.html +++ b/docs/0.9.5/Batch-Command-Processor.html @@ -308,7 +308,6 @@ mode instead, see its readme for install instructions.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Batch-Processors.html b/docs/0.9.5/Batch-Processors.html index 3e0674306f..55582edce2 100644 --- a/docs/0.9.5/Batch-Processors.html +++ b/docs/0.9.5/Batch-Processors.html @@ -162,7 +162,6 @@ allowed.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Bootstrap-&-Evennia.html b/docs/0.9.5/Bootstrap-&-Evennia.html index 7db5904b52..9a1bfd554d 100644 --- a/docs/0.9.5/Bootstrap-&-Evennia.html +++ b/docs/0.9.5/Bootstrap-&-Evennia.html @@ -206,7 +206,6 @@ learn more about them, please 0.9.5 (v0.9.5 branch) -
    diff --git a/docs/0.9.5/Bootstrap-Components-and-Utilities.html b/docs/0.9.5/Bootstrap-Components-and-Utilities.html index 80307b5491..68e77c1334 100644 --- a/docs/0.9.5/Bootstrap-Components-and-Utilities.html +++ b/docs/0.9.5/Bootstrap-Components-and-Utilities.html @@ -213,7 +213,6 @@ over 0.9.5 (v0.9.5 branch) -
    diff --git a/docs/0.9.5/Builder-Docs.html b/docs/0.9.5/Builder-Docs.html index 5810351612..4443ea1ec7 100644 --- a/docs/0.9.5/Builder-Docs.html +++ b/docs/0.9.5/Builder-Docs.html @@ -132,7 +132,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Building-Permissions.html b/docs/0.9.5/Building-Permissions.html index 186a9056a7..7c65ab44e5 100644 --- a/docs/0.9.5/Building-Permissions.html +++ b/docs/0.9.5/Building-Permissions.html @@ -177,7 +177,6 @@ levels. Note that you cannot escalate your permissions this way; If the Characte
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Building-Quickstart.html b/docs/0.9.5/Building-Quickstart.html index 7a0cf2ace4..026115c2eb 100644 --- a/docs/0.9.5/Building-Quickstart.html +++ b/docs/0.9.5/Building-Quickstart.html @@ -370,7 +370,6 @@ World-Introduction).

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Building-a-mech-tutorial.html b/docs/0.9.5/Building-a-mech-tutorial.html index f09c75a4af..828b55f7ab 100644 --- a/docs/0.9.5/Building-a-mech-tutorial.html +++ b/docs/0.9.5/Building-a-mech-tutorial.html @@ -402,7 +402,6 @@ shooting goodness would be made available to you only when you enter it.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Building-menus.html b/docs/0.9.5/Building-menus.html index ee2455f762..2fa6beccd9 100644 --- a/docs/0.9.5/Building-menus.html +++ b/docs/0.9.5/Building-menus.html @@ -1673,7 +1673,6 @@ exhaustive but user-friendly.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Choosing-An-SQL-Server.html b/docs/0.9.5/Choosing-An-SQL-Server.html index b384c9bd84..09a9eed0b5 100644 --- a/docs/0.9.5/Choosing-An-SQL-Server.html +++ b/docs/0.9.5/Choosing-An-SQL-Server.html @@ -388,7 +388,6 @@ others. If you try other databases out, consider expanding this page with instru
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Client-Support-Grid.html b/docs/0.9.5/Client-Support-Grid.html index 43c6db4489..3034d72e5a 100644 --- a/docs/0.9.5/Client-Support-Grid.html +++ b/docs/0.9.5/Client-Support-Grid.html @@ -250,7 +250,6 @@ parameter to disable it for that Evennia account permanently.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Coding-FAQ.html b/docs/0.9.5/Coding-FAQ.html index cc8e728e7b..bac53a5a11 100644 --- a/docs/0.9.5/Coding-FAQ.html +++ b/docs/0.9.5/Coding-FAQ.html @@ -621,7 +621,6 @@ discussion where some suitable fonts are suggested.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Coding-Introduction.html b/docs/0.9.5/Coding-Introduction.html index d25cb2bcac..2154fdc52d 100644 --- a/docs/0.9.5/Coding-Introduction.html +++ b/docs/0.9.5/Coding-Introduction.html @@ -207,7 +207,6 @@ can’t find the answer in the docs, don’t be shy to ask questions! The
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Coding-Utils.html b/docs/0.9.5/Coding-Utils.html index cfe8995747..28e3ed0cd6 100644 --- a/docs/0.9.5/Coding-Utils.html +++ b/docs/0.9.5/Coding-Utils.html @@ -468,7 +468,6 @@ instructions.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Command-Cooldown.html b/docs/0.9.5/Command-Cooldown.html index ccc7bb87b3..cbd490671f 100644 --- a/docs/0.9.5/Command-Cooldown.html +++ b/docs/0.9.5/Command-Cooldown.html @@ -243,7 +243,6 @@ other types of attacks for a while before the warrior can recover.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Command-Duration.html b/docs/0.9.5/Command-Duration.html index 6e9ee5727d..aed8f695e3 100644 --- a/docs/0.9.5/Command-Duration.html +++ b/docs/0.9.5/Command-Duration.html @@ -730,7 +730,6 @@ callback when the server comes back up (it will resume the countdown and ignore
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Command-Prompt.html b/docs/0.9.5/Command-Prompt.html index e5d23eff36..23eb07d501 100644 --- a/docs/0.9.5/Command-Prompt.html +++ b/docs/0.9.5/Command-Prompt.html @@ -288,7 +288,6 @@ directly the easiest way is to just wrap those with a multiple inheritance to yo
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Command-Sets.html b/docs/0.9.5/Command-Sets.html index ea49c1e475..7091319b86 100644 --- a/docs/0.9.5/Command-Sets.html +++ b/docs/0.9.5/Command-Sets.html @@ -513,7 +513,6 @@ commands having any combination of the keys and/or aliases “kick”, “punch
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Command-System.html b/docs/0.9.5/Command-System.html index f50682d72d..34c8dc79a2 100644 --- a/docs/0.9.5/Command-System.html +++ b/docs/0.9.5/Command-System.html @@ -109,7 +109,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Commands.html b/docs/0.9.5/Commands.html index 8e2fba872f..af6a34741b 100644 --- a/docs/0.9.5/Commands.html +++ b/docs/0.9.5/Commands.html @@ -885,7 +885,6 @@ on.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Communications.html b/docs/0.9.5/Communications.html index e7f5ca228a..f6969b6189 100644 --- a/docs/0.9.5/Communications.html +++ b/docs/0.9.5/Communications.html @@ -224,7 +224,6 @@ for channel communication (since the default ChannelCommand instead logs to a fi
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Connection-Screen.html b/docs/0.9.5/Connection-Screen.html index 72e4d28979..b056065f12 100644 --- a/docs/0.9.5/Connection-Screen.html +++ b/docs/0.9.5/Connection-Screen.html @@ -139,7 +139,6 @@ tutorial section on how to add new commands to a default command set.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Continuous-Integration.html b/docs/0.9.5/Continuous-Integration.html index 6fac451285..bad7f44030 100644 --- a/docs/0.9.5/Continuous-Integration.html +++ b/docs/0.9.5/Continuous-Integration.html @@ -429,7 +429,6 @@ build steps could be added or removed at this point, adding some features like U
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Contributing-Docs.html b/docs/0.9.5/Contributing-Docs.html index 70b69487dc..d7be56d777 100644 --- a/docs/0.9.5/Contributing-Docs.html +++ b/docs/0.9.5/Contributing-Docs.html @@ -815,7 +815,6 @@ to understand our friendly Google-style docstrings used in classes and functions
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Contributing.html b/docs/0.9.5/Contributing.html index e5a8f3e067..f1bae79aab 100644 --- a/docs/0.9.5/Contributing.html +++ b/docs/0.9.5/Contributing.html @@ -220,7 +220,6 @@ UBBFWIuVDEZxC0M_2pM6ywO&dispatch=5885d80a13c0db1f8e263663d3faee8d66f31424b43
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Coordinates.html b/docs/0.9.5/Coordinates.html index 37581c92f9..74cfad9bf0 100644 --- a/docs/0.9.5/Coordinates.html +++ b/docs/0.9.5/Coordinates.html @@ -590,7 +590,6 @@ square (E, G, M and O) are not in this circle. So we remove them.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Custom-Protocols.html b/docs/0.9.5/Custom-Protocols.html index e2f229d7de..5ac15a3bbb 100644 --- a/docs/0.9.5/Custom-Protocols.html +++ b/docs/0.9.5/Custom-Protocols.html @@ -446,7 +446,6 @@ ways.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Customize-channels.html b/docs/0.9.5/Customize-channels.html index fb7ddce8cf..f48222626d 100644 --- a/docs/0.9.5/Customize-channels.html +++ b/docs/0.9.5/Customize-channels.html @@ -776,7 +776,6 @@ this article.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Debugging.html b/docs/0.9.5/Debugging.html index 5f86c6b263..44e6b6cfdd 100644 --- a/docs/0.9.5/Debugging.html +++ b/docs/0.9.5/Debugging.html @@ -385,7 +385,6 @@ topic here.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Default-Command-Help.html b/docs/0.9.5/Default-Command-Help.html index 206a985d50..196c3a31fb 100644 --- a/docs/0.9.5/Default-Command-Help.html +++ b/docs/0.9.5/Default-Command-Help.html @@ -2927,7 +2927,6 @@ Belongs to command set ‘DefaultUnloggedin’ of class 0.9.5 (v0.9.5 branch) -
    diff --git a/docs/0.9.5/Default-Exit-Errors.html b/docs/0.9.5/Default-Exit-Errors.html index 822fb559ba..a0b3c989a0 100644 --- a/docs/0.9.5/Default-Exit-Errors.html +++ b/docs/0.9.5/Default-Exit-Errors.html @@ -265,7 +265,6 @@ matching “north” exit-command.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Developer-Central.html b/docs/0.9.5/Developer-Central.html index d13f10c706..9131d605d6 100644 --- a/docs/0.9.5/Developer-Central.html +++ b/docs/0.9.5/Developer-Central.html @@ -261,7 +261,6 @@ over time

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Dialogues-in-events.html b/docs/0.9.5/Dialogues-in-events.html index e823cdad27..453fe6440f 100644 --- a/docs/0.9.5/Dialogues-in-events.html +++ b/docs/0.9.5/Dialogues-in-events.html @@ -347,7 +347,6 @@ events).

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Directory-Overview.html b/docs/0.9.5/Directory-Overview.html index 93d37ef13c..4a2ae332e1 100644 --- a/docs/0.9.5/Directory-Overview.html +++ b/docs/0.9.5/Directory-Overview.html @@ -184,7 +184,6 @@ having to import from their actual locations inside the source tree.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Docs-refactoring.html b/docs/0.9.5/Docs-refactoring.html index 071da08096..c3780893b5 100644 --- a/docs/0.9.5/Docs-refactoring.html +++ b/docs/0.9.5/Docs-refactoring.html @@ -217,7 +217,6 @@ call return_appearance

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Dynamic-In-Game-Map.html b/docs/0.9.5/Dynamic-In-Game-Map.html index 7da23adab4..4c1b672654 100644 --- a/docs/0.9.5/Dynamic-In-Game-Map.html +++ b/docs/0.9.5/Dynamic-In-Game-Map.html @@ -823,7 +823,6 @@ also look into up/down directions and figure out how to display that in a good w
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/EvEditor.html b/docs/0.9.5/EvEditor.html index bd52ab18ba..f0d57056c3 100644 --- a/docs/0.9.5/EvEditor.html +++ b/docs/0.9.5/EvEditor.html @@ -347,7 +347,6 @@ editor can be useful if you want to test the code you have typed but add new lin
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/EvMenu.html b/docs/0.9.5/EvMenu.html index d255dabe6b..a390f476d6 100644 --- a/docs/0.9.5/EvMenu.html +++ b/docs/0.9.5/EvMenu.html @@ -1790,7 +1790,6 @@ until the exit node.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/EvMore.html b/docs/0.9.5/EvMore.html index 4b5bf3d8ba..a8093d7040 100644 --- a/docs/0.9.5/EvMore.html +++ b/docs/0.9.5/EvMore.html @@ -140,7 +140,6 @@ paging.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Evennia-API.html b/docs/0.9.5/Evennia-API.html index dc0a9e510b..1c8cdc572f 100644 --- a/docs/0.9.5/Evennia-API.html +++ b/docs/0.9.5/Evennia-API.html @@ -231,7 +231,6 @@ The flat API is defined in 0.9.5 (v0.9.5 branch) -
    diff --git a/docs/0.9.5/Evennia-Game-Index.html b/docs/0.9.5/Evennia-Game-Index.html index db344c71c9..03924f6bdf 100644 --- a/docs/0.9.5/Evennia-Game-Index.html +++ b/docs/0.9.5/Evennia-Game-Index.html @@ -193,7 +193,6 @@ if you are not ready for players yet.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Evennia-Introduction.html b/docs/0.9.5/Evennia-Introduction.html index 77454b80a9..b8134875b9 100644 --- a/docs/0.9.5/Evennia-Introduction.html +++ b/docs/0.9.5/Evennia-Introduction.html @@ -282,7 +282,6 @@ your own game, you will end up with a small (very small) game that you can build
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Evennia-for-Diku-Users.html b/docs/0.9.5/Evennia-for-Diku-Users.html index c2949a325b..7c534178ba 100644 --- a/docs/0.9.5/Evennia-for-Diku-Users.html +++ b/docs/0.9.5/Evennia-for-Diku-Users.html @@ -370,7 +370,6 @@ your mob.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Evennia-for-MUSH-Users.html b/docs/0.9.5/Evennia-for-MUSH-Users.html index d133675049..3db9b78e2f 100644 --- a/docs/0.9.5/Evennia-for-MUSH-Users.html +++ b/docs/0.9.5/Evennia-for-MUSH-Users.html @@ -331,7 +331,6 @@ question in our 0.9.5 (v0.9.5 branch) -
    diff --git a/docs/0.9.5/Evennia-for-roleplaying-sessions.html b/docs/0.9.5/Evennia-for-roleplaying-sessions.html index 224aa2dca2..ab6e594f56 100644 --- a/docs/0.9.5/Evennia-for-roleplaying-sessions.html +++ b/docs/0.9.5/Evennia-for-roleplaying-sessions.html @@ -1158,7 +1158,6 @@ when the message was sent.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Execute-Python-Code.html b/docs/0.9.5/Execute-Python-Code.html index 4bf7e51473..965f19f563 100644 --- a/docs/0.9.5/Execute-Python-Code.html +++ b/docs/0.9.5/Execute-Python-Code.html @@ -227,7 +227,6 @@ Out[3]: [<ObjectDB: Harry>, <ObjectDB: Limbo>, ...]
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/First-Steps-Coding.html b/docs/0.9.5/First-Steps-Coding.html index c6274814ac..56d48f405b 100644 --- a/docs/0.9.5/First-Steps-Coding.html +++ b/docs/0.9.5/First-Steps-Coding.html @@ -451,7 +451,6 @@ developers.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Game-Planning.html b/docs/0.9.5/Game-Planning.html index 0cfc999a0a..ae6c6beb7e 100644 --- a/docs/0.9.5/Game-Planning.html +++ b/docs/0.9.5/Game-Planning.html @@ -322,7 +322,6 @@ have made their dream game a reality!

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Gametime-Tutorial.html b/docs/0.9.5/Gametime-Tutorial.html index ed14d217ff..cfda784f79 100644 --- a/docs/0.9.5/Gametime-Tutorial.html +++ b/docs/0.9.5/Gametime-Tutorial.html @@ -483,7 +483,6 @@ same way as described for the default one above.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Getting-Started.html b/docs/0.9.5/Getting-Started.html index 98015e5910..474f8b2c42 100644 --- a/docs/0.9.5/Getting-Started.html +++ b/docs/0.9.5/Getting-Started.html @@ -598,7 +598,6 @@ virus software interfering. Try disabling or changing your anti-virus software s
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Glossary.html b/docs/0.9.5/Glossary.html index c57b54e72b..2720281373 100644 --- a/docs/0.9.5/Glossary.html +++ b/docs/0.9.5/Glossary.html @@ -472,7 +472,6 @@ activated whenever you want to use the 0.9.5 (v0.9.5 branch) -
    diff --git a/docs/0.9.5/Grapevine.html b/docs/0.9.5/Grapevine.html index e8feb8abf3..dee834d40e 100644 --- a/docs/0.9.5/Grapevine.html +++ b/docs/0.9.5/Grapevine.html @@ -168,7 +168,6 @@ it to your channel in-game.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Guest-Logins.html b/docs/0.9.5/Guest-Logins.html index 0b81f70944..8e4f134167 100644 --- a/docs/0.9.5/Guest-Logins.html +++ b/docs/0.9.5/Guest-Logins.html @@ -124,7 +124,6 @@ of nine names from
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/HAProxy-Config.html b/docs/0.9.5/HAProxy-Config.html index eb0dddf467..1f05b614fc 100644 --- a/docs/0.9.5/HAProxy-Config.html +++ b/docs/0.9.5/HAProxy-Config.html @@ -241,7 +241,6 @@ Linux mechanism for running things at specific times.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Help-System-Tutorial.html b/docs/0.9.5/Help-System-Tutorial.html index e4f6a88e2a..f8a54bb306 100644 --- a/docs/0.9.5/Help-System-Tutorial.html +++ b/docs/0.9.5/Help-System-Tutorial.html @@ -681,7 +681,6 @@ themselves links to display their details.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Help-System.html b/docs/0.9.5/Help-System.html index 776b4e5ffc..e2c751da1e 100644 --- a/docs/0.9.5/Help-System.html +++ b/docs/0.9.5/Help-System.html @@ -239,7 +239,6 @@ definition
    :

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/How-To-Get-And-Give-Help.html b/docs/0.9.5/How-To-Get-And-Give-Help.html index 5567a98c7d..ae64d776d0 100644 --- a/docs/0.9.5/How-To-Get-And-Give-Help.html +++ b/docs/0.9.5/How-To-Get-And-Give-Help.html @@ -151,7 +151,6 @@ a particular

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/How-to-connect-Evennia-to-Twitter.html b/docs/0.9.5/How-to-connect-Evennia-to-Twitter.html index 29d6b7f9a9..a8b7a8046f 100644 --- a/docs/0.9.5/How-to-connect-Evennia-to-Twitter.html +++ b/docs/0.9.5/How-to-connect-Evennia-to-Twitter.html @@ -250,7 +250,6 @@ help.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/IRC.html b/docs/0.9.5/IRC.html index 686aeaefeb..86cea2829f 100644 --- a/docs/0.9.5/IRC.html +++ b/docs/0.9.5/IRC.html @@ -186,7 +186,6 @@ name of the IRC channel you used (#evennia here).

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Implementing-a-game-rule-system.html b/docs/0.9.5/Implementing-a-game-rule-system.html index a8943b6ff0..ef5e110b0c 100644 --- a/docs/0.9.5/Implementing-a-game-rule-system.html +++ b/docs/0.9.5/Implementing-a-game-rule-system.html @@ -544,7 +544,6 @@ tag dummy=training_dummy

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Inputfuncs.html b/docs/0.9.5/Inputfuncs.html index 66c9117c97..3901a72171 100644 --- a/docs/0.9.5/Inputfuncs.html +++ b/docs/0.9.5/Inputfuncs.html @@ -300,7 +300,6 @@ add more. By default the following fields/attributes can be monitored:

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Installing-on-Android.html b/docs/0.9.5/Installing-on-Android.html index f74a7c20fb..3526efb7d6 100644 --- a/docs/0.9.5/Installing-on-Android.html +++ b/docs/0.9.5/Installing-on-Android.html @@ -222,7 +222,6 @@ killed if your phone is heavily taxed. Termux seems to keep a notification up to
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Internationalization.html b/docs/0.9.5/Internationalization.html index b757a47dc7..524e405c59 100644 --- a/docs/0.9.5/Internationalization.html +++ b/docs/0.9.5/Internationalization.html @@ -191,7 +191,6 @@ your own repository clone) so we can integrate your translation into Evennia!

    0.9.5 (v0.9.5 branch) -
    diff --git a/docs/0.9.5/Learn-Python-for-Evennia-The-Hard-Way.html b/docs/0.9.5/Learn-Python-for-Evennia-The-Hard-Way.html index e7ab8fadc7..364f156129 100644 --- a/docs/0.9.5/Learn-Python-for-Evennia-The-Hard-Way.html +++ b/docs/0.9.5/Learn-Python-for-Evennia-The-Hard-Way.html @@ -162,7 +162,6 @@ commands when obtaining a weapon.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Licensing.html b/docs/0.9.5/Licensing.html index f1ace577f3..3b7eecac9f 100644 --- a/docs/0.9.5/Licensing.html +++ b/docs/0.9.5/Licensing.html @@ -119,7 +119,6 @@ as Evennia itself, unless the individual contributor has specifically defined ot
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Links.html b/docs/0.9.5/Links.html index 36d4c0b639..182cf1a661 100644 --- a/docs/0.9.5/Links.html +++ b/docs/0.9.5/Links.html @@ -295,7 +295,6 @@ programming curriculum for different skill levels

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Locks.html b/docs/0.9.5/Locks.html index f6acfc5433..3d851e18b3 100644 --- a/docs/0.9.5/Locks.html +++ b/docs/0.9.5/Locks.html @@ -650,7 +650,6 @@ interface. It’s stand-alone from the permissions described above.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Manually-Configuring-Color.html b/docs/0.9.5/Manually-Configuring-Color.html index b43a93a31b..6d0c7750b0 100644 --- a/docs/0.9.5/Manually-Configuring-Color.html +++ b/docs/0.9.5/Manually-Configuring-Color.html @@ -321,7 +321,6 @@ regardless of if Evennia thinks their client supports it or not.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Mass-and-weight-for-objects.html b/docs/0.9.5/Mass-and-weight-for-objects.html index 89f7c58f2c..c25b3be7c9 100644 --- a/docs/0.9.5/Mass-and-weight-for-objects.html +++ b/docs/0.9.5/Mass-and-weight-for-objects.html @@ -229,7 +229,6 @@ default_cmdsets.py file:

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Messagepath.html b/docs/0.9.5/Messagepath.html index 8de03676e2..2582647644 100644 --- a/docs/0.9.5/Messagepath.html +++ b/docs/0.9.5/Messagepath.html @@ -422,7 +422,6 @@ information needed between server and client.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/MonitorHandler.html b/docs/0.9.5/MonitorHandler.html index 035ab16c35..e6624706b4 100644 --- a/docs/0.9.5/MonitorHandler.html +++ b/docs/0.9.5/MonitorHandler.html @@ -197,7 +197,6 @@ the monitor to remove:

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/NPC-shop-Tutorial.html b/docs/0.9.5/NPC-shop-Tutorial.html index 8c5ce0c263..cad9803a2a 100644 --- a/docs/0.9.5/NPC-shop-Tutorial.html +++ b/docs/0.9.5/NPC-shop-Tutorial.html @@ -581,7 +581,6 @@ it well stocked.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/New-Models.html b/docs/0.9.5/New-Models.html index 930ba277ce..9e4b1b0e7f 100644 --- a/docs/0.9.5/New-Models.html +++ b/docs/0.9.5/New-Models.html @@ -387,7 +387,6 @@ lot more information about querying the database.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Nicks.html b/docs/0.9.5/Nicks.html index 6f66145034..eeb8ec59ed 100644 --- a/docs/0.9.5/Nicks.html +++ b/docs/0.9.5/Nicks.html @@ -236,7 +236,6 @@ basically the unchanged strings you enter to the 0.9.5 (v0.9.5 branch) -
    diff --git a/docs/0.9.5/OOB.html b/docs/0.9.5/OOB.html index 5900e20996..108e0e6c93 100644 --- a/docs/0.9.5/OOB.html +++ b/docs/0.9.5/OOB.html @@ -285,7 +285,6 @@ same example ("
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Objects.html b/docs/0.9.5/Objects.html index 866375985a..73c6abb7a6 100644 --- a/docs/0.9.5/Objects.html +++ b/docs/0.9.5/Objects.html @@ -305,7 +305,6 @@ and display this as an error message. If this is not found, the Exit will instea
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Online-Setup.html b/docs/0.9.5/Online-Setup.html index 06579187d7..80154106dc 100644 --- a/docs/0.9.5/Online-Setup.html +++ b/docs/0.9.5/Online-Setup.html @@ -665,7 +665,6 @@ https://aws.amazon.com/cloud9/

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Parsing-command-arguments,-theory-and-best-practices.html b/docs/0.9.5/Parsing-command-arguments,-theory-and-best-practices.html index d078ff0e87..7bca492345 100644 --- a/docs/0.9.5/Parsing-command-arguments,-theory-and-best-practices.html +++ b/docs/0.9.5/Parsing-command-arguments,-theory-and-best-practices.html @@ -1093,7 +1093,6 @@ code.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Portal-And-Server.html b/docs/0.9.5/Portal-And-Server.html index b42ec99513..a7dd173a25 100644 --- a/docs/0.9.5/Portal-And-Server.html +++ b/docs/0.9.5/Portal-And-Server.html @@ -107,7 +107,6 @@ This allows the two programs to communicate seamlessly.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Profiling.html b/docs/0.9.5/Profiling.html index f9cf29b525..6dfa008754 100644 --- a/docs/0.9.5/Profiling.html +++ b/docs/0.9.5/Profiling.html @@ -228,7 +228,6 @@ course hard to actually mimic human user behavior. For this, actual real-game te
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Python-3.html b/docs/0.9.5/Python-3.html index 8fb483f9f3..a1b73cfeac 100644 --- a/docs/0.9.5/Python-3.html +++ b/docs/0.9.5/Python-3.html @@ -85,7 +85,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Python-basic-introduction.html b/docs/0.9.5/Python-basic-introduction.html index 62012b1a8f..ebb585d570 100644 --- a/docs/0.9.5/Python-basic-introduction.html +++ b/docs/0.9.5/Python-basic-introduction.html @@ -354,7 +354,6 @@ about objects and to explore the Evennia library.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Python-basic-tutorial-part-two.html b/docs/0.9.5/Python-basic-tutorial-part-two.html index e98eeda50d..2f2714d5fa 100644 --- a/docs/0.9.5/Python-basic-tutorial-part-two.html +++ b/docs/0.9.5/Python-basic-tutorial-part-two.html @@ -613,7 +613,6 @@ of the beginning-level 0.9.5 (v0.9.5 branch) -
    diff --git a/docs/0.9.5/Quirks.html b/docs/0.9.5/Quirks.html index e2b8aead77..4b66a62ae1 100644 --- a/docs/0.9.5/Quirks.html +++ b/docs/0.9.5/Quirks.html @@ -223,7 +223,6 @@ instructions, use the following command to fix it:

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/RSS.html b/docs/0.9.5/RSS.html index 33f16f4dc6..c22a29f1eb 100644 --- a/docs/0.9.5/RSS.html +++ b/docs/0.9.5/RSS.html @@ -153,7 +153,6 @@ same channels as 0.9.5 (v0.9.5 branch) -
    diff --git a/docs/0.9.5/Roadmap.html b/docs/0.9.5/Roadmap.html index d0e487b02d..2ca4ade4c3 100644 --- a/docs/0.9.5/Roadmap.html +++ b/docs/0.9.5/Roadmap.html @@ -86,7 +86,6 @@ Page.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Running-Evennia-in-Docker.html b/docs/0.9.5/Running-Evennia-in-Docker.html index 140430a9dc..231d9d3936 100644 --- a/docs/0.9.5/Running-Evennia-in-Docker.html +++ b/docs/0.9.5/Running-Evennia-in-Docker.html @@ -400,7 +400,6 @@ line.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Screenshot.html b/docs/0.9.5/Screenshot.html index c75a66a274..bcf660f680 100644 --- a/docs/0.9.5/Screenshot.html +++ b/docs/0.9.5/Screenshot.html @@ -96,7 +96,6 @@ interface for editing the database online.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Scripts.html b/docs/0.9.5/Scripts.html index ed8c514aab..54e0b828ba 100644 --- a/docs/0.9.5/Scripts.html +++ b/docs/0.9.5/Scripts.html @@ -560,7 +560,6 @@ tutorial.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Security.html b/docs/0.9.5/Security.html index b2695718c4..3aacb374f7 100644 --- a/docs/0.9.5/Security.html +++ b/docs/0.9.5/Security.html @@ -250,7 +250,6 @@ ISP snooping.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Server-Conf.html b/docs/0.9.5/Server-Conf.html index 02342f84f3..a65b5d907a 100644 --- a/docs/0.9.5/Server-Conf.html +++ b/docs/0.9.5/Server-Conf.html @@ -210,7 +210,6 @@ know about if you are an Evennia developer.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Sessions.html b/docs/0.9.5/Sessions.html index dcd7201772..5597a83189 100644 --- a/docs/0.9.5/Sessions.html +++ b/docs/0.9.5/Sessions.html @@ -290,7 +290,6 @@ module for details on the capabilities of the 0.9.5 (v0.9.5 branch) -
    diff --git a/docs/0.9.5/Setting-up-PyCharm.html b/docs/0.9.5/Setting-up-PyCharm.html index 0366bba6a7..2e741d7a87 100644 --- a/docs/0.9.5/Setting-up-PyCharm.html +++ b/docs/0.9.5/Setting-up-PyCharm.html @@ -227,7 +227,6 @@ still running in interactive mode.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Signals.html b/docs/0.9.5/Signals.html index c745c059ce..db1a1baa48 100644 --- a/docs/0.9.5/Signals.html +++ b/docs/0.9.5/Signals.html @@ -223,7 +223,6 @@ decorator (only relevant for unit testing)

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Soft-Code.html b/docs/0.9.5/Soft-Code.html index 7c71b37f2b..7aed45f7f6 100644 --- a/docs/0.9.5/Soft-Code.html +++ b/docs/0.9.5/Soft-Code.html @@ -177,7 +177,6 @@ pseudo-softcode plugin aimed at developers wanting to script their game from ins
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Spawner-and-Prototypes.html b/docs/0.9.5/Spawner-and-Prototypes.html index e655dbbe02..e083eb0452 100644 --- a/docs/0.9.5/Spawner-and-Prototypes.html +++ b/docs/0.9.5/Spawner-and-Prototypes.html @@ -449,7 +449,6 @@ the api docs.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Start-Stop-Reload.html b/docs/0.9.5/Start-Stop-Reload.html index 3f87e1138c..de81074647 100644 --- a/docs/0.9.5/Start-Stop-Reload.html +++ b/docs/0.9.5/Start-Stop-Reload.html @@ -304,7 +304,6 @@ In-game you should now get the message that the Server has successfully restarte
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Static-In-Game-Map.html b/docs/0.9.5/Static-In-Game-Map.html index c7d798b9c2..a004bc836d 100644 --- a/docs/0.9.5/Static-In-Game-Map.html +++ b/docs/0.9.5/Static-In-Game-Map.html @@ -702,7 +702,6 @@ not add more features to your game by trying other tutorials: 0.9.5 (v0.9.5 branch) -
    diff --git a/docs/0.9.5/Tags.html b/docs/0.9.5/Tags.html index a4d537cd39..25cda92543 100644 --- a/docs/0.9.5/Tags.html +++ b/docs/0.9.5/Tags.html @@ -304,7 +304,6 @@ is found in the 0.9.5 (v0.9.5 branch) -
    diff --git a/docs/0.9.5/Text-Encodings.html b/docs/0.9.5/Text-Encodings.html index 8429fe6788..f77ee1e606 100644 --- a/docs/0.9.5/Text-Encodings.html +++ b/docs/0.9.5/Text-Encodings.html @@ -164,7 +164,6 @@ the Wikipedia article 0.9.5 (v0.9.5 branch) -
    diff --git a/docs/0.9.5/TextTags.html b/docs/0.9.5/TextTags.html index 79e722623d..89c450bc04 100644 --- a/docs/0.9.5/TextTags.html +++ b/docs/0.9.5/TextTags.html @@ -477,7 +477,6 @@ value will be a float (so 0.9.5 (v0.9.5 branch) -
    diff --git a/docs/0.9.5/TickerHandler.html b/docs/0.9.5/TickerHandler.html index f8c8c89845..9bf0419ab7 100644 --- a/docs/0.9.5/TickerHandler.html +++ b/docs/0.9.5/TickerHandler.html @@ -230,7 +230,6 @@ same time without input from something else.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Turn-based-Combat-System.html b/docs/0.9.5/Turn-based-Combat-System.html index a0d390fca2..d293e98cd3 100644 --- a/docs/0.9.5/Turn-based-Combat-System.html +++ b/docs/0.9.5/Turn-based-Combat-System.html @@ -932,7 +932,6 @@ show others what’s going on.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Tutorial-Aggressive-NPCs.html b/docs/0.9.5/Tutorial-Aggressive-NPCs.html index 32362cda33..d1071b9b44 100644 --- a/docs/0.9.5/Tutorial-Aggressive-NPCs.html +++ b/docs/0.9.5/Tutorial-Aggressive-NPCs.html @@ -242,7 +242,6 @@ AI code).

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Tutorial-NPCs-listening.html b/docs/0.9.5/Tutorial-NPCs-listening.html index 4179cf4dd4..9c53221941 100644 --- a/docs/0.9.5/Tutorial-NPCs-listening.html +++ b/docs/0.9.5/Tutorial-NPCs-listening.html @@ -252,7 +252,6 @@ Which way to go depends on the design requirements of your particular game.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Tutorial-Searching-For-Objects.html b/docs/0.9.5/Tutorial-Searching-For-Objects.html index 8f701e45ef..e0138f214a 100644 --- a/docs/0.9.5/Tutorial-Searching-For-Objects.html +++ b/docs/0.9.5/Tutorial-Searching-For-Objects.html @@ -583,7 +583,6 @@ in a format like the following:

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Tutorial-Tweeting-Game-Stats.html b/docs/0.9.5/Tutorial-Tweeting-Game-Stats.html index 1e37612eb8..43452566fa 100644 --- a/docs/0.9.5/Tutorial-Tweeting-Game-Stats.html +++ b/docs/0.9.5/Tutorial-Tweeting-Game-Stats.html @@ -255,7 +255,6 @@ as mygame/typeclass
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Tutorial-Vehicles.html b/docs/0.9.5/Tutorial-Vehicles.html index 8d9a52a1b7..94c322e83d 100644 --- a/docs/0.9.5/Tutorial-Vehicles.html +++ b/docs/0.9.5/Tutorial-Vehicles.html @@ -652,7 +652,6 @@ direction to which room it goes.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Tutorial-World-Introduction.html b/docs/0.9.5/Tutorial-World-Introduction.html index 2983250252..2ae8b761b2 100644 --- a/docs/0.9.5/Tutorial-World-Introduction.html +++ b/docs/0.9.5/Tutorial-World-Introduction.html @@ -209,7 +209,6 @@ itself.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Tutorial-for-basic-MUSH-like-game.html b/docs/0.9.5/Tutorial-for-basic-MUSH-like-game.html index 5eca4d39e8..a4d9cd6716 100644 --- a/docs/0.9.5/Tutorial-for-basic-MUSH-like-game.html +++ b/docs/0.9.5/Tutorial-for-basic-MUSH-like-game.html @@ -989,7 +989,6 @@ as the 0.9.5 (v0.9.5 branch) -
    diff --git a/docs/0.9.5/Tutorials.html b/docs/0.9.5/Tutorials.html index a229896003..f74f591758 100644 --- a/docs/0.9.5/Tutorials.html +++ b/docs/0.9.5/Tutorials.html @@ -267,7 +267,6 @@ to MUSH-style servers.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Typeclasses.html b/docs/0.9.5/Typeclasses.html index f33d34bf1f..2cd53a4912 100644 --- a/docs/0.9.5/Typeclasses.html +++ b/docs/0.9.5/Typeclasses.html @@ -455,7 +455,6 @@ comments for examples and solutions.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Understanding-Color-Tags.html b/docs/0.9.5/Understanding-Color-Tags.html index 27c5f0e610..dba7e92343 100644 --- a/docs/0.9.5/Understanding-Color-Tags.html +++ b/docs/0.9.5/Understanding-Color-Tags.html @@ -266,7 +266,6 @@ push it over the limit, so to speak.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Unit-Testing.html b/docs/0.9.5/Unit-Testing.html index 3cfcf5c071..624caae945 100644 --- a/docs/0.9.5/Unit-Testing.html +++ b/docs/0.9.5/Unit-Testing.html @@ -638,7 +638,6 @@ string.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Updating-Your-Game.html b/docs/0.9.5/Updating-Your-Game.html index eb9be692a2..01a95baad4 100644 --- a/docs/0.9.5/Updating-Your-Game.html +++ b/docs/0.9.5/Updating-Your-Game.html @@ -235,7 +235,6 @@ you then just run e
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Using-MUX-as-a-Standard.html b/docs/0.9.5/Using-MUX-as-a-Standard.html index 56dec0df4c..3181237c62 100644 --- a/docs/0.9.5/Using-MUX-as-a-Standard.html +++ b/docs/0.9.5/Using-MUX-as-a-Standard.html @@ -219,7 +219,6 @@ something to the effect of

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Using-Travis.html b/docs/0.9.5/Using-Travis.html index 5bab3a991c..db545b3700 100644 --- a/docs/0.9.5/Using-Travis.html +++ b/docs/0.9.5/Using-Travis.html @@ -144,7 +144,6 @@ to that for making tests fitting your game.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Version-Control.html b/docs/0.9.5/Version-Control.html index f5ae12e95b..caed398263 100644 --- a/docs/0.9.5/Version-Control.html +++ b/docs/0.9.5/Version-Control.html @@ -558,7 +558,6 @@ understand the underlying ideas behind GIT
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Weather-Tutorial.html b/docs/0.9.5/Weather-Tutorial.html index 747905b60f..1e9d040290 100644 --- a/docs/0.9.5/Weather-Tutorial.html +++ b/docs/0.9.5/Weather-Tutorial.html @@ -163,7 +163,6 @@ weather came before it. Expanding it to be more realistic is a useful exercise.<
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Web-Character-Generation.html b/docs/0.9.5/Web-Character-Generation.html index 5f544d5e9a..4df20b24d9 100644 --- a/docs/0.9.5/Web-Character-Generation.html +++ b/docs/0.9.5/Web-Character-Generation.html @@ -991,7 +991,6 @@ to see what happens. And do the same while checking the checkbox!

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Web-Character-View-Tutorial.html b/docs/0.9.5/Web-Character-View-Tutorial.html index 8f41943bf0..6bf246c071 100644 --- a/docs/0.9.5/Web-Character-View-Tutorial.html +++ b/docs/0.9.5/Web-Character-View-Tutorial.html @@ -379,7 +379,6 @@ here.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Web-Features.html b/docs/0.9.5/Web-Features.html index bce83b5211..75169c8f19 100644 --- a/docs/0.9.5/Web-Features.html +++ b/docs/0.9.5/Web-Features.html @@ -244,7 +244,6 @@ implementation, the relevant django “applications” in default Evennia are 0.9.5 (v0.9.5 branch) -
    diff --git a/docs/0.9.5/Web-Tutorial.html b/docs/0.9.5/Web-Tutorial.html index 8aa43816c1..72da7ae620 100644 --- a/docs/0.9.5/Web-Tutorial.html +++ b/docs/0.9.5/Web-Tutorial.html @@ -216,7 +216,6 @@ possibilities exist.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Webclient-brainstorm.html b/docs/0.9.5/Webclient-brainstorm.html index ddf25eee93..e0db573e5d 100644 --- a/docs/0.9.5/Webclient-brainstorm.html +++ b/docs/0.9.5/Webclient-brainstorm.html @@ -437,7 +437,6 @@ could stay in this mode, but they could also “lock” the gui layout at any ti
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Webclient.html b/docs/0.9.5/Webclient.html index e9a8b7960d..58466de549 100644 --- a/docs/0.9.5/Webclient.html +++ b/docs/0.9.5/Webclient.html @@ -376,7 +376,6 @@ clear your browser cache before loading the webclient page.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Wiki-Index.html b/docs/0.9.5/Wiki-Index.html index 9a1d1390e7..8f35d11684 100644 --- a/docs/0.9.5/Wiki-Index.html +++ b/docs/0.9.5/Wiki-Index.html @@ -299,7 +299,6 @@ character-info

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/Zones.html b/docs/0.9.5/Zones.html index a5c36c8efb..4909283a52 100644 --- a/docs/0.9.5/Zones.html +++ b/docs/0.9.5/Zones.html @@ -154,7 +154,6 @@ properly search the inheritance tree.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/django/conf.html b/docs/0.9.5/_modules/django/conf.html index 3d8473340b..f7fedc5eea 100644 --- a/docs/0.9.5/_modules/django/conf.html +++ b/docs/0.9.5/_modules/django/conf.html @@ -348,7 +348,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/django/db/models/fields/related_descriptors.html b/docs/0.9.5/_modules/django/db/models/fields/related_descriptors.html index 63a105a24d..e60a2abd55 100644 --- a/docs/0.9.5/_modules/django/db/models/fields/related_descriptors.html +++ b/docs/0.9.5/_modules/django/db/models/fields/related_descriptors.html @@ -1280,7 +1280,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/django/db/models/manager.html b/docs/0.9.5/_modules/django/db/models/manager.html index f7188c51d2..2781e22b3d 100644 --- a/docs/0.9.5/_modules/django/db/models/manager.html +++ b/docs/0.9.5/_modules/django/db/models/manager.html @@ -278,7 +278,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/django/db/models/query_utils.html b/docs/0.9.5/_modules/django/db/models/query_utils.html index f51f2ab47b..ee9469b2a7 100644 --- a/docs/0.9.5/_modules/django/db/models/query_utils.html +++ b/docs/0.9.5/_modules/django/db/models/query_utils.html @@ -421,7 +421,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/django/utils/functional.html b/docs/0.9.5/_modules/django/utils/functional.html deleted file mode 100644 index f4e9dff483..0000000000 --- a/docs/0.9.5/_modules/django/utils/functional.html +++ /dev/null @@ -1,525 +0,0 @@ - - - - - - - - django.utils.functional — Evennia 0.9.5 documentation - - - - - - - - - - - - - -
    -
    -
    -
    - -

    Source code for django.utils.functional

    -import copy
    -import itertools
    -import operator
    -from functools import total_ordering, wraps
    -
    -
    -class cached_property:
    -    """
    -    Decorator that converts a method with a single self argument into a
    -    property cached on the instance.
    -
    -    A cached property can be made out of an existing method:
    -    (e.g. ``url = cached_property(get_absolute_url)``).
    -    The optional ``name`` argument is obsolete as of Python 3.6 and will be
    -    deprecated in Django 4.0 (#30127).
    -    """
    -    name = None
    -
    -    @staticmethod
    -    def func(instance):
    -        raise TypeError(
    -            'Cannot use cached_property instance without calling '
    -            '__set_name__() on it.'
    -        )
    -
    -    def __init__(self, func, name=None):
    -        self.real_func = func
    -        self.__doc__ = getattr(func, '__doc__')
    -
    -    def __set_name__(self, owner, name):
    -        if self.name is None:
    -            self.name = name
    -            self.func = self.real_func
    -        elif name != self.name:
    -            raise TypeError(
    -                "Cannot assign the same cached_property to two different names "
    -                "(%r and %r)." % (self.name, name)
    -            )
    -
    -    def __get__(self, instance, cls=None):
    -        """
    -        Call the function and put the return value in instance.__dict__ so that
    -        subsequent attribute access on the instance returns the cached value
    -        instead of calling cached_property.__get__().
    -        """
    -        if instance is None:
    -            return self
    -        res = instance.__dict__[self.name] = self.func(instance)
    -        return res
    -
    -
    -class classproperty:
    -    """
    -    Decorator that converts a method with a single cls argument into a property
    -    that can be accessed directly from the class.
    -    """
    -    def __init__(self, method=None):
    -        self.fget = method
    -
    -    def __get__(self, instance, cls=None):
    -        return self.fget(cls)
    -
    -    def getter(self, method):
    -        self.fget = method
    -        return self
    -
    -
    -class Promise:
    -    """
    -    Base class for the proxy class created in the closure of the lazy function.
    -    It's used to recognize promises in code.
    -    """
    -    pass
    -
    -
    -def lazy(func, *resultclasses):
    -    """
    -    Turn any callable into a lazy evaluated callable. result classes or types
    -    is required -- at least one is needed so that the automatic forcing of
    -    the lazy evaluation code is triggered. Results are not memoized; the
    -    function is evaluated on every access.
    -    """
    -
    -    @total_ordering
    -    class __proxy__(Promise):
    -        """
    -        Encapsulate a function call and act as a proxy for methods that are
    -        called on the result of that function. The function is not evaluated
    -        until one of the methods on the result is called.
    -        """
    -        __prepared = False
    -
    -        def __init__(self, args, kw):
    -            self.__args = args
    -            self.__kw = kw
    -            if not self.__prepared:
    -                self.__prepare_class__()
    -            self.__class__.__prepared = True
    -
    -        def __reduce__(self):
    -            return (
    -                _lazy_proxy_unpickle,
    -                (func, self.__args, self.__kw) + resultclasses
    -            )
    -
    -        def __repr__(self):
    -            return repr(self.__cast())
    -
    -        @classmethod
    -        def __prepare_class__(cls):
    -            for resultclass in resultclasses:
    -                for type_ in resultclass.mro():
    -                    for method_name in type_.__dict__:
    -                        # All __promise__ return the same wrapper method, they
    -                        # look up the correct implementation when called.
    -                        if hasattr(cls, method_name):
    -                            continue
    -                        meth = cls.__promise__(method_name)
    -                        setattr(cls, method_name, meth)
    -            cls._delegate_bytes = bytes in resultclasses
    -            cls._delegate_text = str in resultclasses
    -            assert not (cls._delegate_bytes and cls._delegate_text), (
    -                "Cannot call lazy() with both bytes and text return types.")
    -            if cls._delegate_text:
    -                cls.__str__ = cls.__text_cast
    -            elif cls._delegate_bytes:
    -                cls.__bytes__ = cls.__bytes_cast
    -
    -        @classmethod
    -        def __promise__(cls, method_name):
    -            # Builds a wrapper around some magic method
    -            def __wrapper__(self, *args, **kw):
    -                # Automatically triggers the evaluation of a lazy value and
    -                # applies the given magic method of the result type.
    -                res = func(*self.__args, **self.__kw)
    -                return getattr(res, method_name)(*args, **kw)
    -            return __wrapper__
    -
    -        def __text_cast(self):
    -            return func(*self.__args, **self.__kw)
    -
    -        def __bytes_cast(self):
    -            return bytes(func(*self.__args, **self.__kw))
    -
    -        def __bytes_cast_encoded(self):
    -            return func(*self.__args, **self.__kw).encode()
    -
    -        def __cast(self):
    -            if self._delegate_bytes:
    -                return self.__bytes_cast()
    -            elif self._delegate_text:
    -                return self.__text_cast()
    -            else:
    -                return func(*self.__args, **self.__kw)
    -
    -        def __str__(self):
    -            # object defines __str__(), so __prepare_class__() won't overload
    -            # a __str__() method from the proxied class.
    -            return str(self.__cast())
    -
    -        def __eq__(self, other):
    -            if isinstance(other, Promise):
    -                other = other.__cast()
    -            return self.__cast() == other
    -
    -        def __lt__(self, other):
    -            if isinstance(other, Promise):
    -                other = other.__cast()
    -            return self.__cast() < other
    -
    -        def __hash__(self):
    -            return hash(self.__cast())
    -
    -        def __mod__(self, rhs):
    -            if self._delegate_text:
    -                return str(self) % rhs
    -            return self.__cast() % rhs
    -
    -        def __add__(self, other):
    -            return self.__cast() + other
    -
    -        def __radd__(self, other):
    -            return other + self.__cast()
    -
    -        def __deepcopy__(self, memo):
    -            # Instances of this class are effectively immutable. It's just a
    -            # collection of functions. So we don't need to do anything
    -            # complicated for copying.
    -            memo[id(self)] = self
    -            return self
    -
    -    @wraps(func)
    -    def __wrapper__(*args, **kw):
    -        # Creates the proxy object, instead of the actual value.
    -        return __proxy__(args, kw)
    -
    -    return __wrapper__
    -
    -
    -def _lazy_proxy_unpickle(func, args, kwargs, *resultclasses):
    -    return lazy(func, *resultclasses)(*args, **kwargs)
    -
    -
    -def lazystr(text):
    -    """
    -    Shortcut for the common case of a lazy callable that returns str.
    -    """
    -    return lazy(str, str)(text)
    -
    -
    -def keep_lazy(*resultclasses):
    -    """
    -    A decorator that allows a function to be called with one or more lazy
    -    arguments. If none of the args are lazy, the function is evaluated
    -    immediately, otherwise a __proxy__ is returned that will evaluate the
    -    function when needed.
    -    """
    -    if not resultclasses:
    -        raise TypeError("You must pass at least one argument to keep_lazy().")
    -
    -    def decorator(func):
    -        lazy_func = lazy(func, *resultclasses)
    -
    -        @wraps(func)
    -        def wrapper(*args, **kwargs):
    -            if any(isinstance(arg, Promise) for arg in itertools.chain(args, kwargs.values())):
    -                return lazy_func(*args, **kwargs)
    -            return func(*args, **kwargs)
    -        return wrapper
    -    return decorator
    -
    -
    -def keep_lazy_text(func):
    -    """
    -    A decorator for functions that accept lazy arguments and return text.
    -    """
    -    return keep_lazy(str)(func)
    -
    -
    -empty = object()
    -
    -
    -def new_method_proxy(func):
    -    def inner(self, *args):
    -        if self._wrapped is empty:
    -            self._setup()
    -        return func(self._wrapped, *args)
    -    return inner
    -
    -
    -class LazyObject:
    -    """
    -    A wrapper for another class that can be used to delay instantiation of the
    -    wrapped class.
    -
    -    By subclassing, you have the opportunity to intercept and alter the
    -    instantiation. If you don't need to do that, use SimpleLazyObject.
    -    """
    -
    -    # Avoid infinite recursion when tracing __init__ (#19456).
    -    _wrapped = None
    -
    -    def __init__(self):
    -        # Note: if a subclass overrides __init__(), it will likely need to
    -        # override __copy__() and __deepcopy__() as well.
    -        self._wrapped = empty
    -
    -    __getattr__ = new_method_proxy(getattr)
    -
    -    def __setattr__(self, name, value):
    -        if name == "_wrapped":
    -            # Assign to __dict__ to avoid infinite __setattr__ loops.
    -            self.__dict__["_wrapped"] = value
    -        else:
    -            if self._wrapped is empty:
    -                self._setup()
    -            setattr(self._wrapped, name, value)
    -
    -    def __delattr__(self, name):
    -        if name == "_wrapped":
    -            raise TypeError("can't delete _wrapped.")
    -        if self._wrapped is empty:
    -            self._setup()
    -        delattr(self._wrapped, name)
    -
    -    def _setup(self):
    -        """
    -        Must be implemented by subclasses to initialize the wrapped object.
    -        """
    -        raise NotImplementedError('subclasses of LazyObject must provide a _setup() method')
    -
    -    # Because we have messed with __class__ below, we confuse pickle as to what
    -    # class we are pickling. We're going to have to initialize the wrapped
    -    # object to successfully pickle it, so we might as well just pickle the
    -    # wrapped object since they're supposed to act the same way.
    -    #
    -    # Unfortunately, if we try to simply act like the wrapped object, the ruse
    -    # will break down when pickle gets our id(). Thus we end up with pickle
    -    # thinking, in effect, that we are a distinct object from the wrapped
    -    # object, but with the same __dict__. This can cause problems (see #25389).
    -    #
    -    # So instead, we define our own __reduce__ method and custom unpickler. We
    -    # pickle the wrapped object as the unpickler's argument, so that pickle
    -    # will pickle it normally, and then the unpickler simply returns its
    -    # argument.
    -    def __reduce__(self):
    -        if self._wrapped is empty:
    -            self._setup()
    -        return (unpickle_lazyobject, (self._wrapped,))
    -
    -    def __copy__(self):
    -        if self._wrapped is empty:
    -            # If uninitialized, copy the wrapper. Use type(self), not
    -            # self.__class__, because the latter is proxied.
    -            return type(self)()
    -        else:
    -            # If initialized, return a copy of the wrapped object.
    -            return copy.copy(self._wrapped)
    -
    -    def __deepcopy__(self, memo):
    -        if self._wrapped is empty:
    -            # We have to use type(self), not self.__class__, because the
    -            # latter is proxied.
    -            result = type(self)()
    -            memo[id(self)] = result
    -            return result
    -        return copy.deepcopy(self._wrapped, memo)
    -
    -    __bytes__ = new_method_proxy(bytes)
    -    __str__ = new_method_proxy(str)
    -    __bool__ = new_method_proxy(bool)
    -
    -    # Introspection support
    -    __dir__ = new_method_proxy(dir)
    -
    -    # Need to pretend to be the wrapped class, for the sake of objects that
    -    # care about this (especially in equality tests)
    -    __class__ = property(new_method_proxy(operator.attrgetter("__class__")))
    -    __eq__ = new_method_proxy(operator.eq)
    -    __lt__ = new_method_proxy(operator.lt)
    -    __gt__ = new_method_proxy(operator.gt)
    -    __ne__ = new_method_proxy(operator.ne)
    -    __hash__ = new_method_proxy(hash)
    -
    -    # List/Tuple/Dictionary methods support
    -    __getitem__ = new_method_proxy(operator.getitem)
    -    __setitem__ = new_method_proxy(operator.setitem)
    -    __delitem__ = new_method_proxy(operator.delitem)
    -    __iter__ = new_method_proxy(iter)
    -    __len__ = new_method_proxy(len)
    -    __contains__ = new_method_proxy(operator.contains)
    -
    -
    -def unpickle_lazyobject(wrapped):
    -    """
    -    Used to unpickle lazy objects. Just return its argument, which will be the
    -    wrapped object.
    -    """
    -    return wrapped
    -
    -
    -class SimpleLazyObject(LazyObject):
    -    """
    -    A lazy object initialized from any function.
    -
    -    Designed for compound objects of unknown type. For builtins or objects of
    -    known type, use django.utils.functional.lazy.
    -    """
    -    def __init__(self, func):
    -        """
    -        Pass in a callable that returns the object to be wrapped.
    -
    -        If copies are made of the resulting SimpleLazyObject, which can happen
    -        in various circumstances within Django, then you must ensure that the
    -        callable can be safely run more than once and will return the same
    -        value.
    -        """
    -        self.__dict__['_setupfunc'] = func
    -        super().__init__()
    -
    -    def _setup(self):
    -        self._wrapped = self._setupfunc()
    -
    -    # Return a meaningful representation of the lazy object for debugging
    -    # without evaluating the wrapped object.
    -    def __repr__(self):
    -        if self._wrapped is empty:
    -            repr_attr = self._setupfunc
    -        else:
    -            repr_attr = self._wrapped
    -        return '<%s: %r>' % (type(self).__name__, repr_attr)
    -
    -    def __copy__(self):
    -        if self._wrapped is empty:
    -            # If uninitialized, copy the wrapper. Use SimpleLazyObject, not
    -            # self.__class__, because the latter is proxied.
    -            return SimpleLazyObject(self._setupfunc)
    -        else:
    -            # If initialized, return a copy of the wrapped object.
    -            return copy.copy(self._wrapped)
    -
    -    def __deepcopy__(self, memo):
    -        if self._wrapped is empty:
    -            # We have to use SimpleLazyObject, not self.__class__, because the
    -            # latter is proxied.
    -            result = SimpleLazyObject(self._setupfunc)
    -            memo[id(self)] = result
    -            return result
    -        return copy.deepcopy(self._wrapped, memo)
    -
    -
    -def partition(predicate, values):
    -    """
    -    Split the values into two sets, based on the return value of the function
    -    (True/False). e.g.:
    -
    -        >>> partition(lambda x: x > 3, range(5))
    -        [0, 1, 2, 3], [4]
    -    """
    -    results = ([], [])
    -    for item in values:
    -        results[predicate(item)].append(item)
    -    return results
    -
    - -
    -
    -
    -
    - -
    -
    - - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia.html b/docs/0.9.5/_modules/evennia.html index 63c895a17b..1dcdc09634 100644 --- a/docs/0.9.5/_modules/evennia.html +++ b/docs/0.9.5/_modules/evennia.html @@ -135,7 +135,6 @@ TASK_HANDLER = None TICKER_HANDLER = None MONITOR_HANDLER = None -CHANNEL_HANDLER = None # Containers GLOBAL_SCRIPTS = None @@ -189,7 +188,7 @@ global signals global settings, lockfuncs, logger, utils, gametime, ansi, spawn, managers global contrib, TICKER_HANDLER, MONITOR_HANDLER, SESSION_HANDLER - global CHANNEL_HANDLER, TASK_HANDLER + global TASK_HANDLER global GLOBAL_SCRIPTS, OPTION_CLASSES global EvMenu, EvTable, EvForm, EvMore, EvEditor global ANSIString @@ -252,7 +251,6 @@ from .scripts.tickerhandler import TICKER_HANDLER from .scripts.taskhandler import TASK_HANDLER from .server.sessionhandler import SESSION_HANDLER - from .comms.channelhandler import CHANNEL_HANDLER from .scripts.monitorhandler import MONITOR_HANDLER # containers @@ -381,7 +379,6 @@ CMD_NOINPUT - no input was given on command line CMD_NOMATCH - no valid command key was found CMD_MULTIMATCH - multiple command matches were found - CMD_CHANNEL - the command name is a channel name CMD_LOGINSTART - this command will be called as the very first command when an account connects to the server. @@ -396,7 +393,6 @@ CMD_NOINPUT = cmdhandler.CMD_NOINPUT CMD_NOMATCH = cmdhandler.CMD_NOMATCH CMD_MULTIMATCH = cmdhandler.CMD_MULTIMATCH - CMD_CHANNEL = cmdhandler.CMD_CHANNEL CMD_LOGINSTART = cmdhandler.CMD_LOGINSTART del cmdhandler @@ -514,7 +510,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/accounts/accounts.html b/docs/0.9.5/_modules/evennia/accounts/accounts.html index eb46e9ee62..9f65229765 100644 --- a/docs/0.9.5/_modules/evennia/accounts/accounts.html +++ b/docs/0.9.5/_modules/evennia/accounts/accounts.html @@ -40,7 +40,7 @@

    Source code for evennia.accounts.accounts

     """
    -Typeclass for Account objects
    +Typeclass for Account objects.
     
     Note that this object is primarily intended to
     store OOC information, not game info! This
    @@ -72,7 +72,7 @@
         SIGNAL_OBJECT_POST_PUPPET,
         SIGNAL_OBJECT_POST_UNPUPPET,
     )
    -from evennia.typeclasses.attributes import NickHandler
    +from evennia.typeclasses.attributes import NickHandler, ModelAttributeBackend
     from evennia.scripts.scripthandler import ScriptHandler
     from evennia.commands.cmdsethandler import CmdSetHandler
     from evennia.utils.optionhandler import OptionHandler
    @@ -80,7 +80,7 @@
     from django.utils.translation import gettext as _
     from random import getrandbits
     
    -__all__ = ("DefaultAccount",)
    +__all__ = ("DefaultAccount", "DefaultGuest")
     
     _SESSIONS = None
     
    @@ -89,14 +89,17 @@
     _MAX_NR_CHARACTERS = settings.MAX_NR_CHARACTERS
     _CMDSET_ACCOUNT = settings.CMDSET_ACCOUNT
     _MUDINFO_CHANNEL = None
    +_CONNECT_CHANNEL = None
     _CMDHANDLER = None
     
    +
     # Create throttles for too many account-creations and login attempts
     CREATION_THROTTLE = Throttle(
    -    limit=settings.CREATION_THROTTLE_LIMIT, timeout=settings.CREATION_THROTTLE_TIMEOUT
    +    name='creation', limit=settings.CREATION_THROTTLE_LIMIT,
    +    timeout=settings.CREATION_THROTTLE_TIMEOUT
     )
     LOGIN_THROTTLE = Throttle(
    -    limit=settings.LOGIN_THROTTLE_LIMIT, timeout=settings.LOGIN_THROTTLE_TIMEOUT
    +    name='login', limit=settings.LOGIN_THROTTLE_LIMIT, timeout=settings.LOGIN_THROTTLE_TIMEOUT
     )
     
     
    @@ -240,7 +243,7 @@
     
     
    [docs] @lazy_property def nicks(self): - return NickHandler(self)
    + return NickHandler(self, ModelAttributeBackend)
    [docs] @lazy_property def sessions(self): @@ -274,6 +277,21 @@ return objs +
    [docs] def get_display_name(self, looker, **kwargs): + """ + This is used by channels and other OOC communications methods to give a + custom display of this account's input. + + Args: + looker (Account): The one that will see this name. + **kwargs: Unused by default, can be used to pass game-specific data. + + Returns: + str: The name, possibly modified. + + """ + return f"|c{self.key}|n"
    + # session-related methods
    [docs] def disconnect_session_from_account(self, session, reason=None): @@ -316,11 +334,11 @@ raise RuntimeError("Session not found") if self.get_puppet(session) == obj: # already puppeting this object - self.msg(_("You are already puppeting this object.")) + self.msg("You are already puppeting this object.") return if not obj.access(self, "puppet"): # no access - self.msg(_("You don't have permission to puppet '{key}'.").format(key=obj.key)) + self.msg("You don't have permission to puppet '{obj.key}'.") return if obj.account: # object already puppeted @@ -336,8 +354,8 @@ else: txt1 = f"Taking over |c{obj.name}|n from another of your sessions." txt2 = f"|c{obj.name}|n|R is now acted from another of your sessions.|n" - self.msg(_(txt1), session=session) - self.msg(_(txt2), session=obj.sessions.all()) + self.msg(txt1, session=session) + self.msg(txt2, session=obj.sessions.all()) self.unpuppet_object(obj.sessions.get()) elif obj.account.is_connected: # controlled by another account @@ -359,8 +377,6 @@ obj.account = self session.puid = obj.id session.puppet = obj - # validate/start persistent scripts on object - obj.scripts.validate() # re-cache locks to make sure superuser bypass is updated obj.locks.cache_lock_bypass(obj) @@ -569,7 +585,7 @@ # Update throttle if ip: - LOGIN_THROTTLE.update(ip, "Too many authentication failures.") + LOGIN_THROTTLE.update(ip, _("Too many authentication failures.")) # Try to call post-failure hook session = kwargs.get("session", None) @@ -684,8 +700,9 @@ password (str): Password to set. Notes: - This is called by Django also when logging in; it should not be mixed up with validation, since that - would mean old passwords in the database (pre validation checks) could get invalidated. + This is called by Django also when logging in; it should not be mixed up with + validation, since that would mean old passwords in the database (pre validation checks) + could get invalidated. """ super(DefaultAccount, self).set_password(password) @@ -824,12 +841,10 @@ ) logger.log_sec(f"Account Created: {account} (IP: {ip}).") - except Exception as e: + except Exception: errors.append( - _( - "There was an error creating the Account. If this problem persists, contact an admin." - ) - ) + _("There was an error creating the Account. " + "If this problem persists, contact an admin.")) logger.log_trace() return None, errors @@ -845,7 +860,7 @@ # join the new account to the public channel pchannel = ChannelDB.objects.get_channel(settings.DEFAULT_CHANNELS[0]["key"]) if not pchannel or not pchannel.connect(account): - string = f"New account '{account.key}' could not connect to public channel!" + string = "New account '{account.key}' could not connect to public channel!" errors.append(string) logger.log_err(string) @@ -988,6 +1003,89 @@ self, raw_string, callertype="account", session=session, **kwargs )
    + # channel receive hooks + +
    [docs] def at_pre_channel_msg(self, message, channel, senders=None, **kwargs): + """ + Called by the Channel just before passing a message into `channel_msg`. + This allows for tweak messages per-user and also to abort the + receive on the receiver-level. + + Args: + message (str): The message sent to the channel. + channel (Channel): The sending channel. + senders (list, optional): Accounts or Objects acting as senders. + For most normal messages, there is only a single sender. If + there are no senders, this may be a broadcasting message. + **kwargs: These are additional keywords passed into `channel_msg`. + If `no_prefix=True` or `emit=True` are passed, the channel + prefix will not be added (`[channelname]: ` by default) + + Returns: + str or None: Allows for customizing the message for this recipient. + If returning `None` (or `False`) message-receiving is aborted. + The returning string will be passed into `self.channel_msg`. + + Notes: + This support posing/emotes by starting channel-send with : or ;. + + """ + if senders: + sender_string = ', '.join(sender.get_display_name(self) for sender in senders) + message_lstrip = message.lstrip() + if message_lstrip.startswith((':', ';')): + # this is a pose, should show as e.g. "User1 smiles to channel" + spacing = "" if message_lstrip[1:].startswith((':', '\'', ',')) else " " + message = f"{sender_string}{spacing}{message_lstrip[1:]}" + else: + # normal message + message = f"{sender_string}: {message}" + + if not kwargs.get("no_prefix") or not kwargs.get("emit"): + message = channel.channel_prefix() + message + + return message
    + +
    [docs] def channel_msg(self, message, channel, senders=None, **kwargs): + """ + This performs the actions of receiving a message to an un-muted + channel. + + Args: + message (str): The message sent to the channel. + channel (Channel): The sending channel. + senders (list, optional): Accounts or Objects acting as senders. + For most normal messages, there is only a single sender. If + there are no senders, this may be a broadcasting message or + similar. + **kwargs: These are additional keywords originally passed into + `Channel.msg`. + + Notes: + Before this, `Channel.at_pre_channel_msg` will fire, which offers a way + to customize the message for the receiver on the channel-level. + + """ + self.msg(text=(message, {"from_channel": channel.id}), + from_obj=senders, options={"from_channel": channel.id})
    + +
    [docs] def at_post_channel_msg(self, message, channel, senders=None, **kwargs): + """ + Called by `self.channel_msg` after message was received. + + Args: + message (str): The message sent to the channel. + channel (Channel): The sending channel. + senders (list, optional): Accounts or Objects acting as senders. + For most normal messages, there is only a single sender. If + there are no senders, this may be a broadcasting message. + **kwargs: These are additional keywords passed into `channel_msg`. + + """ + pass
    + + # search method +
    [docs] def search( self, searchdata, @@ -1295,30 +1393,42 @@ def _send_to_connect_channel(self, message): """ - Helper method for loading and sending to the comm channel - dedicated to connection messages. + Helper method for loading and sending to the comm channel dedicated to + connection messages. This will also be sent to the mudinfo channel. Args: message (str): A message to send to the connect channel. """ - global _MUDINFO_CHANNEL - if not _MUDINFO_CHANNEL: - try: - _MUDINFO_CHANNEL = ChannelDB.objects.filter(db_key=settings.CHANNEL_MUDINFO["key"])[ - 0 - ] - except Exception: - logger.log_trace() + global _MUDINFO_CHANNEL, _CONNECT_CHANNEL + if _MUDINFO_CHANNEL is None: + if settings.CHANNEL_MUDINFO: + try: + _MUDINFO_CHANNEL = ChannelDB.objects.get( + db_key=settings.CHANNEL_MUDINFO["key"]) + except ChannelDB.DoesNotExist: + logger.log_trace() + else: + _MUDINFO = False + if _CONNECT_CHANNEL is None: + if settings.CHANNEL_CONNECTINFO: + try: + _CONNECT_CHANNEL = ChannelDB.objects.get( + db_key=settings.CHANNEL_CONNECTINFO["key"]) + except ChannelDB.DoesNotExist: + logger.log_trace() + else: + _CONNECT_CHANNEL = False + if settings.USE_TZ: now = timezone.localtime() else: now = timezone.now() now = "%02i-%02i-%02i(%02i:%02i)" % (now.year, now.month, now.day, now.hour, now.minute) if _MUDINFO_CHANNEL: - _MUDINFO_CHANNEL.tempmsg(f"[{_MUDINFO_CHANNEL.key}, {now}]: {message}") - else: - logger.log_info(f"[{now}]: {message}") + _MUDINFO_CHANNEL.msg(f"[{now}]: {message}") + if _CONNECT_CHANNEL: + _CONNECT_CHANNEL.msg(f"[{now}]: {message}")
    [docs] def at_post_login(self, session=None, **kwargs): """ @@ -1505,7 +1615,7 @@ if hasattr(target, "return_appearance"): return target.return_appearance(self) else: - return _("{target} has no in-game appearance.").format(target=target) + return f"{target} has no in-game appearance." else: # list of targets - make list to disconnect from db characters = list(tar for tar in target if tar) if target else [] @@ -1548,19 +1658,18 @@ if is_su or len(characters) < charmax: if not characters: result.append( - _( - "\n\n You don't have any characters yet. See |whelp @charcreate|n for creating one." - ) + "\n\n You don't have any characters yet. See |whelp charcreate|n for " + "creating one." ) else: - result.append("\n |w@charcreate <name> [=description]|n - create new character") + result.append("\n |wcharcreate <name> [=description]|n - create new character") result.append( - "\n |w@chardelete <name>|n - delete a character (cannot be undone!)" + "\n |wchardelete <name>|n - delete a character (cannot be undone!)" ) if characters: string_s_ending = len(characters) > 1 and "s" or "" - result.append("\n |w@ic <character>|n - enter the game (|w@ooc|n to get back here)") + result.append("\n |wic <character>|n - enter the game (|wooc|n to get back here)") if is_su: result.append( f"\n\nAvailable character{string_s_ending} ({len(characters)}/unlimited):" @@ -1582,11 +1691,12 @@ sid = sess in sessions and sessions.index(sess) + 1 if sess and sid: result.append( - f"\n - |G{char.key}|n [{', '.join(char.permissions.all())}] (played by you in session {sid})" - ) + f"\n - |G{char.key}|n [{', '.join(char.permissions.all())}] " + f"(played by you in session {sid})") else: result.append( - f"\n - |R{char.key}|n [{', '.join(char.permissions.all())}] (played by someone else)" + f"\n - |R{char.key}|n [{', '.join(char.permissions.all())}] " + "(played by someone else)" ) else: # character is "free to puppet" @@ -1595,21 +1705,23 @@ return look_string
    -class DefaultGuest(DefaultAccount): +
    [docs]class DefaultGuest(DefaultAccount): """ This class is used for guest logins. Unlike Accounts, Guests and their characters are deleted after disconnection. + """ - @classmethod +
    [docs] @classmethod def create(cls, **kwargs): """ Forwards request to cls.authenticate(); returns a DefaultGuest object if one is available for use. - """ - return cls.authenticate(**kwargs) - @classmethod + """ + return cls.authenticate(**kwargs)
    + +
    [docs] @classmethod def authenticate(cls, **kwargs): """ Gets or creates a Guest account object. @@ -1673,7 +1785,7 @@ return account, errors - except Exception as e: + except Exception: # We are in the middle between logged in and -not, so we have # to handle tracebacks ourselves at this point. If we don't, # we won't see any errors at all. @@ -1681,9 +1793,9 @@ logger.log_trace() return None, errors - return account, errors + return account, errors
    - def at_post_login(self, session=None, **kwargs): +
    [docs] def at_post_login(self, session=None, **kwargs): """ In theory, guests only have one character regardless of which MULTISESSION_MODE we're in. They don't get a choice. @@ -1695,9 +1807,9 @@ """ self._send_to_connect_channel(_("|G{key} connected|n").format(key=self.key)) - self.puppet_object(session, self.db._last_puppet) + self.puppet_object(session, self.db._last_puppet)
    - def at_server_shutdown(self): +
    [docs] def at_server_shutdown(self): """ We repeat the functionality of `at_disconnect()` here just to be on the safe side. @@ -1706,9 +1818,9 @@ characters = self.db._playable_characters for character in characters: if character: - character.delete() + character.delete()
    - def at_post_disconnect(self, **kwargs): +
    [docs] def at_post_disconnect(self, **kwargs): """ Once having disconnected, destroy the guest's characters and @@ -1722,7 +1834,7 @@ for character in characters: if character: character.delete() - self.delete() + self.delete()
    @@ -1760,7 +1872,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/accounts/bots.html b/docs/0.9.5/_modules/evennia/accounts/bots.html index 7137b991c9..73eef99d8f 100644 --- a/docs/0.9.5/_modules/evennia/accounts/bots.html +++ b/docs/0.9.5/_modules/evennia/accounts/bots.html @@ -371,7 +371,7 @@ nicklist = ", ".join(sorted(kwargs["nicklist"], key=lambda n: n.lower())) for obj in self._nicklist_callers: obj.msg( - _("Nicks at {chstr}:\n {nicklist}").format(chstr=chstr, nicklist=nicklist) + "Nicks at {chstr}:\n {nicklist}".format(chstr=chstr, nicklist=nicklist) ) self._nicklist_callers = [] return @@ -382,7 +382,7 @@ chstr = f"{self.db.irc_channel} ({self.db.irc_network}:{self.db.irc_port})" for obj in self._ping_callers: obj.msg( - _("IRC ping return from {chstr} took {time}s.").format( + "IRC ping return from {chstr} took {time}s.".format( chstr=chstr, time=kwargs["timing"] ) ) @@ -438,6 +438,7 @@ # # RSS +#
    [docs]class RSSBot(Bot): @@ -655,7 +656,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/accounts/manager.html b/docs/0.9.5/_modules/evennia/accounts/manager.html index 67092c9db6..9bd6cf4776 100644 --- a/docs/0.9.5/_modules/evennia/accounts/manager.html +++ b/docs/0.9.5/_modules/evennia/accounts/manager.html @@ -265,7 +265,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/accounts/models.html b/docs/0.9.5/_modules/evennia/accounts/models.html index 7fe7e688f8..50ca520337 100644 --- a/docs/0.9.5/_modules/evennia/accounts/models.html +++ b/docs/0.9.5/_modules/evennia/accounts/models.html @@ -87,7 +87,7 @@ # ------------------------------------------------------------ -
    [docs]class AccountDB(TypedObject, AbstractUser): +
    [docs]class AccountDB(TypedObject, AbstractUser): """ This is a special model using Django's 'profile' functionality and extends the default Django User model. It is defined as such @@ -135,7 +135,8 @@ "cmdset", max_length=255, null=True, - help_text="optional python path to a cmdset class. If creating a Character, this will default to settings.CMDSET_CHARACTER.", + help_text="optional python path to a cmdset class. If creating a Character, this will " + "default to settings.CMDSET_CHARACTER.", ) # marks if this is a "virtual" bot account object db_is_bot = models.BooleanField( @@ -150,8 +151,8 @@ __applabel__ = "accounts" __settingsclasspath__ = settings.BASE_SCRIPT_TYPECLASS - # class Meta: - # verbose_name = "Account" + class Meta: + verbose_name = "Account" # cmdset_storage property # This seems very sensitive to caching, so leaving it be for now /Griatch @@ -257,7 +258,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/commands/cmdhandler.html b/docs/0.9.5/_modules/evennia/commands/cmdhandler.html index 43fba3d2dc..feb200b0b5 100644 --- a/docs/0.9.5/_modules/evennia/commands/cmdhandler.html +++ b/docs/0.9.5/_modules/evennia/commands/cmdhandler.html @@ -47,10 +47,6 @@ 1. The calling object (caller) is analyzed based on its callertype. 2. Cmdsets are gathered from different sources: - - channels: all available channel names are auto-created into a cmdset, to allow - for giving the channel name and have the following immediately - sent to the channel. The sending is performed by the CMD_CHANNEL - system command. - object cmdsets: all objects at caller's location are scanned for non-empty cmdsets. This includes cmdsets on exits. - caller: the caller is searched for its own currently active cmdset. @@ -64,14 +60,12 @@ cmdset, or fallback to error message. Exit. 7. If no match was found -> check for CMD_NOMATCH in current cmdset or fallback to error message. Exit. -8. A single match was found. If this is a channel-command (i.e. the - ommand name is that of a channel), --> check for CMD_CHANNEL in - current cmdset or use channelhandler default. Exit. -9. At this point we have found a normal command. We assign useful variables to it that +8. At this point we have found a normal command. We assign useful variables to it that will be available to the command coder at run-time. -12. We have a unique cmdobject, primed for use. Call all hooks: +9. We have a unique cmdobject, primed for use. Call all hooks: `at_pre_cmd()`, `cmdobj.parse()`, `cmdobj.func()` and finally `at_post_cmd()`. -13. Return deferred that will fire with the return from `cmdobj.func()` (unused by default). +10. Return deferred that will fire with the return from `cmdobj.func()` (unused by default). + """ from collections import defaultdict @@ -85,7 +79,6 @@ from twisted.internet.defer import inlineCallbacks, returnValue from django.conf import settings from evennia.commands.command import InterruptCommand -from evennia.comms.channelhandler import CHANNELHANDLER from evennia.utils import logger, utils from evennia.utils.utils import string_suggestions @@ -116,12 +109,11 @@ CMD_NOMATCH = "__nomatch_command" # command to call if multiple command matches were found CMD_MULTIMATCH = "__multimatch_command" -# command to call if found command is the name of a channel -CMD_CHANNEL = "__send_to_channel_command" # command to call as the very first one when the user connects. # (is expected to display the login screen) CMD_LOGINSTART = "__unloggedin_look_command" + # Function for handling multiple command matches. _SEARCH_AT_RESULT = utils.variable_from_module(*settings.SEARCH_AT_RESULT.rsplit(".", 1)) @@ -129,50 +121,50 @@ # is the normal "production message to echo to the account. _ERROR_UNTRAPPED = ( - """ -An untrapped error occurred. -""", - """ -An untrapped error occurred. Please file a bug report detailing the steps to reproduce. -""", + _(""" +An untrapped error occurred. +"""), + _(""" +An untrapped error occurred. Please file a bug report detailing the steps to reproduce. +"""), ) _ERROR_CMDSETS = ( - """ -A cmdset merger-error occurred. This is often due to a syntax -error in one of the cmdsets to merge. -""", - """ -A cmdset merger-error occurred. Please file a bug report detailing the -steps to reproduce. -""", + _(""" +A cmdset merger-error occurred. This is often due to a syntax +error in one of the cmdsets to merge. +"""), + _(""" +A cmdset merger-error occurred. Please file a bug report detailing the +steps to reproduce. +"""), ) _ERROR_NOCMDSETS = ( - """ -No command sets found! This is a critical bug that can have -multiple causes. -""", - """ -No command sets found! This is a sign of a critical bug. If -disconnecting/reconnecting doesn't" solve the problem, try to contact -the server admin through" some other means for assistance. -""", + _(""" +No command sets found! This is a critical bug that can have +multiple causes. +"""), + _(""" +No command sets found! This is a sign of a critical bug. If +disconnecting/reconnecting doesn't" solve the problem, try to contact +the server admin through" some other means for assistance. +"""), ) _ERROR_CMDHANDLER = ( - """ -A command handler bug occurred. If this is not due to a local change, -please file a bug report with the Evennia project, including the -traceback and steps to reproduce. -""", - """ -A command handler bug occurred. Please notify staff - they should -likely file a bug report with the Evennia project. -""", + _(""" +A command handler bug occurred. If this is not due to a local change, +please file a bug report with the Evennia project, including the +traceback and steps to reproduce. +"""), + _(""" +A command handler bug occurred. Please notify staff - they should +likely file a bug report with the Evennia project. +"""), ) -_ERROR_RECURSION_LIMIT = ( +_ERROR_RECURSION_LIMIT = _( "Command recursion limit ({recursion_limit}) " "reached for '{raw_cmdname}' ({cmdclass})." ) @@ -195,7 +187,7 @@ production string (with a timestamp) to be shown to the user. """ - string = "{traceback}\n{errmsg}\n(Traceback was logged {timestamp})." + string = _("{traceback}\n{errmsg}\n(Traceback was logged {timestamp}).") timestamp = logger.timeformat() tracestring = format_exc() logger.log_trace() @@ -344,23 +336,11 @@ """ try: - @inlineCallbacks - def _get_channel_cmdset(account_or_obj): - """ - Helper-method; Get channel-cmdsets - """ - # Create cmdset for all account's available channels - try: - channel_cmdset = yield CHANNELHANDLER.get_cmdset(account_or_obj) - returnValue([channel_cmdset]) - except Exception: - _msg_err(caller, _ERROR_CMDSETS) - raise ErrorReported(raw_string) - @inlineCallbacks def _get_local_obj_cmdsets(obj): """ Helper-method; Get Object-level cmdsets + """ # Gather cmdsets from location, objects in location or carried try: @@ -414,6 +394,7 @@ """ Helper method; Get cmdset while making sure to trigger all hooks safely. Returns the stack and the valid options. + """ try: yield obj.at_cmdset_get() @@ -446,13 +427,6 @@ cmdset for cmdset in local_obj_cmdsets if cmdset.key != "ExitCmdSet" ] cmdsets += local_obj_cmdsets - if not current.no_channels: - # also objs may have channels - channel_cmdsets = yield _get_channel_cmdset(obj) - cmdsets += channel_cmdsets - if not current.no_channels: - channel_cmdsets = yield _get_channel_cmdset(account) - cmdsets += channel_cmdsets elif callertype == "account": # we are calling the command from the account level @@ -470,11 +444,6 @@ cmdset for cmdset in local_obj_cmdsets if cmdset.key != "ExitCmdSet" ] cmdsets += local_obj_cmdsets - if not current.no_channels: - # also objs may have channels - cmdsets += yield _get_channel_cmdset(obj) - if not current.no_channels: - cmdsets += yield _get_channel_cmdset(account) elif callertype == "object": # we are calling the command from the object level @@ -488,9 +457,6 @@ cmdset for cmdset in local_obj_cmdsets if cmdset.key != "ExitCmdSet" ] cmdsets += yield local_obj_cmdsets - if not current.no_channels: - # also objs may have channels - cmdsets += yield _get_channel_cmdset(obj) else: raise Exception("get_and_merge_cmdsets: callertype %s is not valid." % callertype) @@ -649,11 +615,6 @@ # since this may be different for every command when # merging multiple cmdsets - if hasattr(cmd, "obj") and hasattr(cmd.obj, "scripts"): - # cmd.obj is automatically made available by the cmdhandler. - # we make sure to validate its scripts. - yield cmd.obj.scripts.validate() - if _testing: # only return the command instance returnValue(cmd) @@ -818,18 +779,6 @@ sysarg += _(' Type "help" for help.') raise ExecSystemCommand(syscmd, sysarg) - # Check if this is a Channel-cmd match. - if hasattr(cmd, "is_channel") and cmd.is_channel: - # even if a user-defined syscmd is not defined, the - # found cmd is already a system command in its own right. - syscmd = yield cmdset.get(CMD_CHANNEL) - if syscmd: - # replace system command with custom version - cmd = syscmd - cmd.session = session - sysarg = "%s:%s" % (cmdname, args) - raise ExecSystemCommand(cmd, sysarg) - # A normal command. ret = yield _run_command(cmd, cmdname, args, raw_cmdname, cmdset, session, account) returnValue(ret) @@ -903,7 +852,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/commands/cmdparser.html b/docs/0.9.5/_modules/evennia/commands/cmdparser.html index fd69794617..ca35e5729f 100644 --- a/docs/0.9.5/_modules/evennia/commands/cmdparser.html +++ b/docs/0.9.5/_modules/evennia/commands/cmdparser.html @@ -112,7 +112,7 @@ for cmdname in [cmd.key] + cmd.aliases if cmdname and l_raw_string.startswith(cmdname.lower()) - and (not cmd.arg_regex or cmd.arg_regex.match(l_raw_string[len(cmdname) :])) + and (not cmd.arg_regex or cmd.arg_regex.match(l_raw_string[len(cmdname):])) ] ) else: @@ -131,7 +131,7 @@ if ( cmdname and l_raw_string.startswith(cmdname.lower()) - and (not cmd.arg_regex or cmd.arg_regex.match(l_raw_string[len(cmdname) :])) + and (not cmd.arg_regex or cmd.arg_regex.match(l_raw_string[len(cmdname):])) ): matches.append(create_match(cmdname, raw_string, cmd, raw_cmdname)) except Exception: @@ -139,7 +139,7 @@ return matches -
    [docs]def try_num_prefixes(raw_string): +
    [docs]def try_num_differentiators(raw_string): """ Test if user tried to separate multi-matches with a number separator (default 1-name, 2-name etc). This is usually called last, if no other @@ -167,7 +167,7 @@ # with a #num-command style syntax. We expect the regex to # contain the groups "number" and "name". mindex, new_raw_string = (num_ref_match.group("number"), num_ref_match.group("name")) - return mindex, new_raw_string + return int(mindex), new_raw_string else: return None, None
    @@ -211,19 +211,22 @@ if not raw_string: return [] - # find mathces, first using the full name + # find matches, first using the full name matches = build_matches(raw_string, cmdset, include_prefixes=True) - if not matches: - # try to match a number 1-cmdname, 2-cmdname etc - mindex, new_raw_string = try_num_prefixes(raw_string) - if mindex is not None: - return cmdparser(new_raw_string, cmdset, caller, match_index=int(mindex)) - if _CMD_IGNORE_PREFIXES: - # still no match. Try to strip prefixes - raw_string = ( - raw_string.lstrip(_CMD_IGNORE_PREFIXES) if len(raw_string) > 1 else raw_string - ) - matches = build_matches(raw_string, cmdset, include_prefixes=False) + + if not matches or len(matches) > 1: + # no single match, try parsing for optional numerical tags like 1-cmd + # or cmd-2, cmd.2 etc + match_index, new_raw_string = try_num_differentiators(raw_string) + if match_index is not None: + matches.extend(build_matches(new_raw_string, cmdset, include_prefixes=True)) + + if not matches and _CMD_IGNORE_PREFIXES: + # still no match. Try to strip prefixes + raw_string = ( + raw_string.lstrip(_CMD_IGNORE_PREFIXES) if len(raw_string) > 1 else raw_string + ) + matches = build_matches(raw_string, cmdset, include_prefixes=False) # only select command matches we are actually allowed to call. matches = [match for match in matches if match[2].access(caller, "cmd")] @@ -299,7 +302,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/commands/cmdset.html b/docs/0.9.5/_modules/evennia/commands/cmdset.html index f4750ae0e7..dbbc1fdb01 100644 --- a/docs/0.9.5/_modules/evennia/commands/cmdset.html +++ b/docs/0.9.5/_modules/evennia/commands/cmdset.html @@ -399,18 +399,14 @@ """ perm = "perm" if self.permanent else "non-perm" - options = ", ".join( - [ - "{}:{}".format(opt, "T" if getattr(self, opt) else "F") - for opt in ("no_exits", "no_objs", "no_channels", "duplicates") - if getattr(self, opt) is not None - ] - ) + options = ", ".join([ + "{}:{}".format(opt, "T" if getattr(self, opt) else "F") + for opt in ("no_exits", "no_objs", "no_channels", "duplicates") + if getattr(self, opt) is not None + ]) options = (", " + options) if options else "" - return ( - f"<CmdSet {self.key}, {self.mergetype}, {perm}, prio {self.priority}{options}>: " - + ", ".join([str(cmd) for cmd in sorted(self.commands, key=lambda o: o.key)]) - ) + return (f"<CmdSet {self.key}, {self.mergetype}, {perm}, prio {self.priority}{options}>: " + + ", ".join([str(cmd) for cmd in sorted(self.commands, key=lambda o: o.key)])) def __iter__(self): """ @@ -522,7 +518,8 @@ # This is used for diagnosis. cmdset_c.actual_mergetype = mergetype - # print "__add__ for %s (prio %i) called with %s (prio %i)." % (self.key, self.priority, cmdset_a.key, cmdset_a.priority) + # print "__add__ for %s (prio %i) called with %s (prio %i)." % (self.key, self.priority, + # cmdset_a.key, cmdset_a.priority) # return the system commands to the cmdset cmdset_c.add(sys_commands, allow_duplicates=True) @@ -715,6 +712,7 @@ Hook method - this should be overloaded in the inheriting class, and should take care of populating the cmdset by use of self.add(). + """ pass @@ -754,7 +752,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/commands/cmdsethandler.html b/docs/0.9.5/_modules/evennia/commands/cmdsethandler.html index a2137a6435..d2e520247e 100644 --- a/docs/0.9.5/_modules/evennia/commands/cmdsethandler.html +++ b/docs/0.9.5/_modules/evennia/commands/cmdsethandler.html @@ -103,6 +103,7 @@ can then implement separate sets for different situations. For example, you can have a 'On a boat' set, onto which you then tack on the 'Fishing' set. Fishing from a boat? No problem! + """ import sys from traceback import format_exc @@ -144,7 +145,7 @@ _ERROR_CMDSET_EXCEPTION = _( """{traceback} -Compile/Run error when loading cmdset '{path}'.", +Compile/Run error when loading cmdset '{path}'. (Traceback was logged {timestamp})""" ) @@ -209,7 +210,7 @@ if "." in path: modpath, classname = python_path.rsplit(".", 1) else: - raise ImportError("The path '%s' is not on the form modulepath.ClassName" % path) + raise ImportError(f"The path '{path}' is not on the form modulepath.ClassName") try: # first try to get from cache @@ -353,6 +354,7 @@ def __str__(self): """ Display current commands + """ strings = ["<CmdSetHandler> stack:"] @@ -462,7 +464,8 @@ self.mergetype_stack.append(new_current.actual_mergetype) self.current = new_current -
    [docs] def add(self, cmdset, emit_to_obj=None, permanent=False, default_cmdset=False): +
    [docs] def add(self, cmdset, emit_to_obj=None, persistent=True, default_cmdset=False, + **kwargs): """ Add a cmdset to the handler, on top of the old ones, unless it is set as the default one (it will then end up at the bottom of the stack) @@ -471,7 +474,7 @@ cmdset (CmdSet or str): Can be a cmdset object or the python path to such an object. emit_to_obj (Object, optional): An object to receive error messages. - permanent (bool, optional): This cmdset will remain across a server reboot. + persistent (bool, optional): Let cmdset remain across server reload. default_cmdset (Cmdset, optional): Insert this to replace the default cmdset position (there is only one such position, always at the bottom of the stack). @@ -488,6 +491,11 @@ it's a 'quirk' that has to be documented. """ + if "permanent" in kwargs: + logger.log_dep("obj.cmdset.add() kwarg 'permanent' has changed name to " + "'persistent' and now defaults to True.") + persistent = kwargs['permanent'] if persistent is None else persistent + if not (isinstance(cmdset, str) or utils.inherits_from(cmdset, CmdSet)): string = _("Only CmdSets can be added to the cmdsethandler!") raise Exception(string) @@ -498,8 +506,8 @@ # this is (maybe) a python path. Try to import from cache. cmdset = self._import_cmdset(cmdset) if cmdset and cmdset.key != "_CMDSET_ERROR": - cmdset.permanent = permanent - if permanent and cmdset.key != "_CMDSET_ERROR": + cmdset.permanent = persistent # TODO change on cmdset too + if persistent and cmdset.key != "_CMDSET_ERROR": # store the path permanently storage = self.obj.cmdset_storage or [""] if default_cmdset: @@ -513,17 +521,21 @@ self.cmdset_stack.append(cmdset) self.update()
    -
    [docs] def add_default(self, cmdset, emit_to_obj=None, permanent=True): +
    [docs] def add_default(self, cmdset, emit_to_obj=None, persistent=True, **kwargs): """ Shortcut for adding a default cmdset. Args: cmdset (Cmdset): The Cmdset to add. emit_to_obj (Object, optional): Gets error messages - permanent (bool, optional): The new Cmdset should survive a server reboot. + persistent (bool, optional): The new Cmdset should survive a server reboot. """ - self.add(cmdset, emit_to_obj=emit_to_obj, permanent=permanent, default_cmdset=True)
    + if "permanent" in kwargs: + logger.log_dep("obj.cmdset.add_default() kwarg 'permanent' has changed name to " + "'persistent'.") + persistent = kwargs['permanent'] if persistent is None else persistent + self.add(cmdset, emit_to_obj=emit_to_obj, persistent=persistent, default_cmdset=True)
    [docs] def remove(self, cmdset=None, default_cmdset=False): """ @@ -730,7 +742,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/commands/command.html b/docs/0.9.5/_modules/evennia/commands/command.html index 9555dfb6a8..dd2d83cc49 100644 --- a/docs/0.9.5/_modules/evennia/commands/command.html +++ b/docs/0.9.5/_modules/evennia/commands/command.html @@ -57,6 +57,13 @@ from evennia.utils.ansi import ANSIString +
    [docs]class InterruptCommand(Exception): + + """Cleanly interrupt a command.""" + + pass
    + + def _init_command(cls, **kwargs): """ Helper command. @@ -125,6 +132,15 @@ break cls.help_category = cls.help_category.lower() + # pre-prepare a help index entry for quicker lookup + cls.search_index_entry = { + "key": cls.key, + "aliases": " ".join(cls.aliases), + "category": cls.help_category, + "text": cls.__doc__, + "tags": "", + } +
    [docs]class CommandMeta(type): """ @@ -144,9 +160,11 @@ # parsing errors. -
    [docs]class Command(object, metaclass=CommandMeta): +
    [docs]class Command(metaclass=CommandMeta): """ - Base command + ## Base command + + (you may see this if a child command had no help text defined) Usage: command [args] @@ -551,20 +569,6 @@ )[0] return settings.CLIENT_DEFAULT_WIDTH
    -
    [docs] def client_height(self): - """ - Get the client screenheight for the session using this command. - - Returns: - client height (int): The height (in characters) of the client window. - - """ - if self.session: - return self.session.protocol_flags.get( - "SCREENHEIGHT", {0: settings.CLIENT_DEFAULT_HEIGHT} - )[0] - return settings.CLIENT_DEFAULT_HEIGHT
    -
    [docs] def styled_table(self, *args, **kwargs): """ Create an EvTable styled by on user preferences. @@ -609,6 +613,7 @@ border_left_char=border_left_char, border_right_char=border_right_char, border_top_char=border_top_char, + border_bottom_char=border_bottom_char, **kwargs, ) return table
    @@ -712,13 +717,6 @@ if "mode" not in kwargs: kwargs["mode"] = "footer" return self._render_decoration(*args, **kwargs)
    - - -
    [docs]class InterruptCommand(Exception): - - """Cleanly interrupt a command.""" - - pass
    @@ -756,7 +754,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/commands/default/account.html b/docs/0.9.5/_modules/evennia/commands/default/account.html index e01b8a3494..bb032b4c50 100644 --- a/docs/0.9.5/_modules/evennia/commands/default/account.html +++ b/docs/0.9.5/_modules/evennia/commands/default/account.html @@ -861,7 +861,7 @@ testing which colors your client support Usage: - color ansi||xterm256 + color ansi | xterm256 Prints a color map along with in-mud color codes to use to produce them. It also tests what is supported in your client. Choices are @@ -1130,7 +1130,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/commands/default/admin.html b/docs/0.9.5/_modules/evennia/commands/default/admin.html index f01264fe7f..144de973db 100644 --- a/docs/0.9.5/_modules/evennia/commands/default/admin.html +++ b/docs/0.9.5/_modules/evennia/commands/default/admin.html @@ -671,7 +671,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/commands/default/batchprocess.html b/docs/0.9.5/_modules/evennia/commands/default/batchprocess.html index a278b39d4a..f53ffd43a0 100644 --- a/docs/0.9.5/_modules/evennia/commands/default/batchprocess.html +++ b/docs/0.9.5/_modules/evennia/commands/default/batchprocess.html @@ -224,7 +224,7 @@ # something went wrong. Purge cmdset except default caller.cmdset.clear() - caller.scripts.validate() # this will purge interactive mode + # caller.scripts.validate() # this will purge interactive mode # ------------------------------------------------------------- @@ -897,7 +897,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/commands/default/building.html b/docs/0.9.5/_modules/evennia/commands/default/building.html index 4adae11939..71ca069c2d 100644 --- a/docs/0.9.5/_modules/evennia/commands/default/building.html +++ b/docs/0.9.5/_modules/evennia/commands/default/building.html @@ -48,7 +48,7 @@ from evennia.objects.models import ObjectDB from evennia.locks.lockhandler import LockException from evennia.commands.cmdhandler import get_and_merge_cmdsets -from evennia.utils import create, utils, search, logger +from evennia.utils import create, utils, search, logger, funcparser from evennia.utils.utils import ( inherits_from, class_from_module, @@ -63,10 +63,11 @@ from evennia.utils.evmore import EvMore from evennia.prototypes import spawner, prototypes as protlib, menus as olc_menus from evennia.utils.ansi import raw as ansi_raw -from evennia.utils.inlinefuncs import raw as inlinefunc_raw COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS) +_FUNCPARSER = None + # limit symbol import for API __all__ = ( "ObjManipCommand", @@ -2163,7 +2164,8 @@ ) if "prototype" in self.switches: - modified = spawner.batch_update_objects_with_prototype(prototype, objects=[obj]) + modified = spawner.batch_update_objects_with_prototype( + prototype, objects=[obj], caller=self.caller) prototype_success = modified > 0 if not prototype_success: caller.msg("Prototype %s failed to apply." % prototype["key"]) @@ -2421,12 +2423,16 @@ value (any): Attribute value. Returns: """ + global _FUNCPARSER + if not _FUNCPARSER: + _FUNCPARSER = funcparser.FuncParser(settings.FUNCPARSER_OUTGOING_MESSAGES_MODULES) + if attr is None: return "No such attribute was found." value = utils.to_str(value) if crop: value = utils.crop(value) - value = inlinefunc_raw(ansi_raw(value)) + value = _FUNCPARSER.parse(ansi_raw(value), escape=True) if category: return f"{attr}[{category}] = {value}" else: @@ -2558,14 +2564,12 @@ def _format_options(cmdset): """helper for cmdset-option display""" - def _truefalse(string, value): if value is None: return "" if value: return f"{string}: T" return f"{string}: F" - options = ", ".join( _truefalse(opt, getattr(cmdset, opt)) for opt in ("no_exits", "no_objs", "no_channels", "duplicates") @@ -2582,8 +2586,7 @@ continue options = _format_options(cmdset) stored.append( - f"{cmdset.path} [{cmdset.key}] ({cmdset.mergetype}, prio {cmdset.priority}{options})" - ) + f"{cmdset.path} [{cmdset.key}] ({cmdset.mergetype}, prio {cmdset.priority}{options})") output["Stored Cmdset(s)"] = "\n " + "\n ".join(stored) # this gets all components of the currently merged set @@ -2621,15 +2624,13 @@ # the resulting merged cmdset options = _format_options(current_cmdset) merged = [ - f"<Current merged cmdset> ({current_cmdset.mergetype} prio {current_cmdset.priority}{options})" - ] + f"<Current merged cmdset> ({current_cmdset.mergetype} prio {current_cmdset.priority}{options})"] # the merge stack for cmdset in all_cmdsets: options = _format_options(cmdset) merged.append( - f"{cmdset.path} [{cmdset.key}] ({cmdset.mergetype} prio {cmdset.priority}{options})" - ) + f"{cmdset.path} [{cmdset.key}] ({cmdset.mergetype} prio {cmdset.priority}{options})") output["Merged Cmdset(s)"] = "\n " + "\n ".join(merged) # list the commands available to this object @@ -3109,7 +3110,7 @@ attach a script to an object Usage: - script[/switch] <obj> [= script_path or <scriptkey>] + addscript[/switch] <obj> [= script_path or <scriptkey>] Switches: start - start all non-running scripts on object, or a given script only @@ -3124,8 +3125,8 @@ the object. """ - key = "script" - aliases = "addscript" + key = "addscript" + aliases = ["attachscript"] switch_options = ("start", "stop") locks = "cmd:perm(script) or perm(Builder)" help_category = "Building" @@ -3170,7 +3171,6 @@ % (script.get_display_name(caller), obj.get_display_name(caller)) ) script.stop() - obj.scripts.validate() else: # rhs exists if not self.switches: # adding a new script, and starting it @@ -3509,7 +3509,7 @@ "Python structures are allowed. \nMake sure to use correct " "Python syntax. Remember especially to put quotes around all " "strings inside lists and dicts.|n For more advanced uses, embed " - "inlinefuncs in the strings." + "funcparser callables ($funcs) in the strings." ) else: string = "Expected {}, got {}.".format(expect, type(prototype)) @@ -3605,7 +3605,7 @@ return try: n_updated = spawner.batch_update_objects_with_prototype( - prototype, objects=existing_objects + prototype, objects=existing_objects, caller=caller, ) except Exception: logger.log_trace() @@ -3857,7 +3857,7 @@ # proceed to spawning try: - for obj in spawner.spawn(prototype): + for obj in spawner.spawn(prototype, caller=self.caller): self.caller.msg("Spawned %s." % obj.get_display_name(self.caller)) if not prototype.get("location") and not noloc: # we don't hardcode the location in the prototype (unless the user @@ -3903,7 +3903,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/commands/default/cmdset_account.html b/docs/0.9.5/_modules/evennia/commands/default/cmdset_account.html index 686df65745..a2feff7e1c 100644 --- a/docs/0.9.5/_modules/evennia/commands/default/cmdset_account.html +++ b/docs/0.9.5/_modules/evennia/commands/default/cmdset_account.html @@ -100,15 +100,15 @@ self.add(admin.CmdNewPassword()) # Comm commands + self.add(comms.CmdChannel()) + # self.add(comms.CmdChannels()) self.add(comms.CmdAddCom()) self.add(comms.CmdDelCom()) self.add(comms.CmdAllCom()) - self.add(comms.CmdChannels()) self.add(comms.CmdCdestroy()) self.add(comms.CmdChannelCreate()) self.add(comms.CmdClock()) self.add(comms.CmdCBoot()) - self.add(comms.CmdCemit()) self.add(comms.CmdCWho()) self.add(comms.CmdCdesc()) self.add(comms.CmdPage()) @@ -153,7 +153,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/commands/default/cmdset_character.html b/docs/0.9.5/_modules/evennia/commands/default/cmdset_character.html index d7bfb66a8d..133dce2d27 100644 --- a/docs/0.9.5/_modules/evennia/commands/default/cmdset_character.html +++ b/docs/0.9.5/_modules/evennia/commands/default/cmdset_character.html @@ -91,6 +91,7 @@ self.add(system.CmdServerLoad()) # self.add(system.CmdPs()) self.add(system.CmdTickers()) + self.add(system.CmdTasks()) # Admin commands self.add(admin.CmdBoot()) @@ -168,7 +169,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/commands/default/cmdset_session.html b/docs/0.9.5/_modules/evennia/commands/default/cmdset_session.html index 3d4eb1cf9b..f210285fdc 100644 --- a/docs/0.9.5/_modules/evennia/commands/default/cmdset_session.html +++ b/docs/0.9.5/_modules/evennia/commands/default/cmdset_session.html @@ -94,7 +94,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/commands/default/cmdset_unloggedin.html b/docs/0.9.5/_modules/evennia/commands/default/cmdset_unloggedin.html index a15eb59541..40c4d930ed 100644 --- a/docs/0.9.5/_modules/evennia/commands/default/cmdset_unloggedin.html +++ b/docs/0.9.5/_modules/evennia/commands/default/cmdset_unloggedin.html @@ -103,7 +103,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/commands/default/comms.html b/docs/0.9.5/_modules/evennia/commands/default/comms.html index 3b239f2275..9c86abcdf7 100644 --- a/docs/0.9.5/_modules/evennia/commands/default/comms.html +++ b/docs/0.9.5/_modules/evennia/commands/default/comms.html @@ -40,24 +40,24 @@

    Source code for evennia.commands.default.comms

     """
    -Comsystem command module.
    +Communication commands:
     
    -Comm commands are OOC commands and intended to be made available to
    -the Account at all times (they go into the AccountCmdSet). So we
    -make sure to homogenize self.caller to always be the account object
    -for easy handling.
    +- channel
    +- page
    +- irc/rss/grapevine linking
     
     """
    -import hashlib
    -import time
    +
     from django.conf import settings
    -from evennia.comms.models import ChannelDB, Msg
    +from evennia.comms.models import Msg
     from evennia.accounts.models import AccountDB
     from evennia.accounts import bots
    -from evennia.comms.channelhandler import CHANNELHANDLER
     from evennia.locks.lockhandler import LockException
    -from evennia.utils import create, logger, utils, evtable
    -from evennia.utils.utils import make_iter, class_from_module
    +from evennia.comms.comms import DefaultChannel
    +from evennia.utils import create, logger, utils
    +from evennia.utils.logger import tail_log_file
    +from evennia.utils.utils import class_from_module
    +from evennia.utils.evmenu import ask_yes_no
     
     COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
     CHANNEL_DEFAULT_TYPECLASS = class_from_module(
    @@ -66,18 +66,20 @@
     
     # limit symbol import for API
     __all__ = (
    +    "CmdChannel",
    +
         "CmdAddCom",
         "CmdDelCom",
         "CmdAllCom",
    -    "CmdChannels",
         "CmdCdestroy",
         "CmdCBoot",
    -    "CmdCemit",
         "CmdCWho",
         "CmdChannelCreate",
         "CmdClock",
         "CmdCdesc",
    +
         "CmdPage",
    +
         "CmdIRC2Chan",
         "CmdIRCStatus",
         "CmdRSS2Chan",
    @@ -85,36 +87,1212 @@
     )
     _DEFAULT_WIDTH = settings.CLIENT_DEFAULT_WIDTH
     
    +# helper functions to make it easier to override the main CmdChannel
    +# command and to keep the legacy addcom etc commands around.
     
    -def find_channel(caller, channelname, silent=False, noaliases=False):
    +
    +
    [docs]class CmdChannel(COMMAND_DEFAULT_CLASS): """ - Helper function for searching for a single channel with - some error handling. + Use and manage in-game channels. + + Usage: + channel channelname <msg> + channel channel name = <msg> + channel (show all subscription) + channel/all (show available channels) + channel/alias channelname = alias[;alias...] + channel/unalias alias + channel/who channelname + channel/history channelname [= index] + channel/sub channelname [= alias[;alias...]] + channel/unsub channelname[,channelname, ...] + channel/mute channelname[,channelname,...] + channel/unmute channelname[,channelname,...] + + channel/create channelname[;alias;alias[:typeclass]] [= description] + channel/destroy channelname [= reason] + channel/desc channelname = description + channel/lock channelname = lockstring + channel/unlock channelname = lockstring + channel/ban channelname (list bans) + channel/ban[/quiet] channelname[, channelname, ...] = subscribername [: reason] + channel/unban[/quiet] channelname[, channelname, ...] = subscribername + channel/boot[/quiet] channelname[,channelname,...] = subscribername [: reason] + + # subtopics + + ## sending + + Usage: channel channelname msg + channel channel name = msg (with space in channel name) + + This sends a message to the channel. Note that you will rarely use this + command like this; instead you can use the alias + + channelname <msg> + channelalias <msg> + + For example + + public Hello World + pub Hello World + + (this shortcut doesn't work for aliases containing spaces) + + See channel/alias for help on setting channel aliases. + + ## alias and unalias + + Usage: channel/alias channel = alias[;alias[;alias...]] + channel/unalias alias + channel - this will list your subs and aliases to each channel + + Set one or more personal aliases for referencing a channel. For example: + + channel/alias warrior's guild = warrior;wguild;warchannel;warrior guild + + You can now send to the channel using all of these: + + warrior's guild Hello + warrior Hello + wguild Hello + warchannel Hello + + Note that this will not work if the alias has a space in it. So the + 'warrior guild' alias must be used with the `channel` command: + + channel warrior guild = Hello + + Channel-aliases can be removed one at a time, using the '/unalias' switch. + + ## who + + Usage: channel/who channelname + + List the channel's subscribers. Shows who are currently offline or are + muting the channel. Subscribers who are 'muting' will not see messages sent + to the channel (use channel/mute to mute a channel). + + ## history + + Usage: channel/history channel [= index] + + This will display the last |c20|n lines of channel history. By supplying an + index number, you will step that many lines back before viewing those 20 lines. + + For example: + + channel/history public = 35 + + will go back 35 lines and show the previous 20 lines from that point (so + lines -35 to -55). + + ## sub and unsub + + Usage: channel/sub channel [=alias[;alias;...]] + channel/unsub channel + + This subscribes you to a channel and optionally assigns personal shortcuts + for you to use to send to that channel (see aliases). When you unsub, all + your personal aliases will also be removed. + + ## mute and unmute + + Usage: channel/mute channelname + channel/unmute channelname + + Muting silences all output from the channel without actually + un-subscribing. Other channel members will see that you are muted in the /who + list. Sending a message to the channel will automatically unmute you. + + ## create and destroy + + Usage: channel/create channelname[;alias;alias[:typeclass]] [= description] + channel/destroy channelname [= reason] + + Creates a new channel (or destroys one you control). You will automatically + join the channel you create and everyone will be kicked and loose all aliases + to a destroyed channel. + + ## lock and unlock + + Usage: channel/lock channelname = lockstring + channel/unlock channelname = lockstring + + Note: this is an admin command. + + A lockstring is on the form locktype:lockfunc(). Channels understand three + locktypes: + listen - who may listen or join the channel. + send - who may send messages to the channel + control - who controls the channel. This is usually the one creating + the channel. + + Common lockfuncs are all() and perm(). To make a channel everyone can + listen to but only builders can talk on, use this: + + listen:all() + send: perm(Builders) + + ## boot and ban + + Usage: + channel/boot[/quiet] channelname[,channelname,...] = subscribername [: reason] + channel/ban channelname[, channelname, ...] = subscribername [: reason] + channel/unban channelname[, channelname, ...] = subscribername + channel/unban channelname + channel/ban channelname (list bans) + + Booting will kick a named subscriber from channel(s) temporarily. The + 'reason' will be passed to the booted user. Unless the /quiet switch is + used, the channel will also be informed of the action. A booted user is + still able to re-connect, but they'll have to set up their aliases again. + + Banning will blacklist a user from (re)joining the provided channels. It + will then proceed to boot them from those channels if they were connected. + The 'reason' and `/quiet` works the same as for booting. + + Example: + boot mychannel1 = EvilUser : Kicking you to cool down a bit. + ban mychannel1,mychannel2= EvilUser : Was banned for spamming. + """ - channels = CHANNEL_DEFAULT_TYPECLASS.objects.channel_search(channelname) - if not channels: - if not noaliases: - channels = [ - chan - for chan in CHANNEL_DEFAULT_TYPECLASS.objects.get_all_channels() - if channelname in chan.aliases.all() - ] - if channels: + key = "channel" + aliases = ["chan", "channels"] + help_category = "Comms" + # these cmd: lock controls access to the channel command itself + # the admin: lock controls access to /boot/ban/unban switches + # the manage: lock controls access to /create/destroy/desc/lock/unlock switches + locks = "cmd:not pperm(channel_banned);admin:all();manage:all();changelocks:perm(Admin)" + switch_options = ( + "list", "all", "history", "sub", "unsub", "mute", "unmute", "alias", "unalias", + "create", "destroy", "desc", "lock", "unlock", "boot", "ban", "unban", "who",) + # disable this in child command classes if wanting on-character channels + account_caller = True + +
    [docs] def search_channel(self, channelname, exact=False, handle_errors=True): + """ + Helper function for searching for a single channel with some error + handling. + + Args: + channelname (str): Name, alias #dbref or partial name/alias to search + for. + exact (bool, optional): If an exact or fuzzy-match of the name should be done. + Note that even for a fuzzy match, an exactly given, unique channel name + will always be returned. + handle_errors (bool): If true, use `self.msg` to report errors if + there are non/multiple matches. If so, the return will always be + a single match or None. + Returns: + object, list or None: If `handle_errors` is `True`, this is either a found Channel + or `None`. Otherwise it's a list of zero, one or more channels found. + Notes: + The 'listen' and 'control' accesses are checked before returning. + + """ + caller = self.caller + # first see if this is a personal alias + channelname = caller.nicks.get(key=channelname, category="channel") or channelname + + # always try the exact match first. + channels = CHANNEL_DEFAULT_TYPECLASS.objects.channel_search(channelname, exact=True) + + if not channels and not exact: + # try fuzzy matching as well + channels = CHANNEL_DEFAULT_TYPECLASS.objects.channel_search(channelname, exact=exact) + + # check permissions + channels = [channel for channel in channels + if channel.access(caller, 'listen') or channel.access(caller, 'control')] + + if handle_errors: + if not channels: + self.msg(f"No channel found matching '{channelname}' " + "(could also be due to missing access).") + return None + elif len(channels) > 1: + self.msg("Multiple possible channel matches/alias for " + "'{channelname}':\n" + ", ".join(chan.key for chan in channels)) + return None return channels[0] - if not silent: - caller.msg("Channel '%s' not found." % channelname) - return None - elif len(channels) > 1: - matches = ", ".join(["%s(%s)" % (chan.key, chan.id) for chan in channels]) - if not silent: - caller.msg("Multiple channels match (be more specific): \n%s" % matches) - return None - return channels[0] + else: + if not channels: + return [] + elif len(channels) > 1: + return list(channels) + return [channels[0]]
    + +
    [docs] def msg_channel(self, channel, message, **kwargs): + """ + Send a message to a given channel. This will check the 'send' + permission on the channel. + + Args: + channel (Channel): The channel to send to. + message (str): The message to send. + **kwargs: Unused by default. These kwargs will be passed into + all channel messaging hooks for custom overriding. + + """ + if not channel.access(self.caller, "send"): + caller.msg(f"You are not allowed to send messages to channel {channel}") + return + + channel.msg(message, senders=self.caller, **kwargs)
    + +
    [docs] def get_channel_history(self, channel, start_index=0): + """ + View a channel's history. + + Args: + channel (Channel): The channel to access. + message (str): The message to send. + **kwargs: Unused by default. These kwargs will be passed into + all channel messaging hooks for custom overriding. + + """ + caller = self.caller + log_file = channel.get_log_filename() + + def send_msg(lines): + return self.msg( + "".join(line.split("[-]", 1)[1] if "[-]" in line else line for line in lines) + ) + # asynchronously tail the log file + tail_log_file(log_file, start_index, 20, callback=send_msg)
    + +
    [docs] def sub_to_channel(self, channel): + """ + Subscribe to a channel. Note that all permissions should + be checked before this step. + + Args: + channel (Channel): The channel to access. + + Returns: + bool, str: True, None if connection failed. If False, + the second part is an error string. + + """ + caller = self.caller + + if channel.has_connection(caller): + return False, f"Already listening to channel {channel.key}." + + # this sets up aliases in post_join_channel by default + result = channel.connect(caller) + + return result, "" if result else f"Were not allowed to subscribe to channel {channel.key}"
    + +
    [docs] def unsub_from_channel(self, channel, **kwargs): + """ + Un-Subscribe to a channel. Note that all permissions should + be checked before this step. + + Args: + channel (Channel): The channel to unsub from. + **kwargs: Passed on to nick removal. + + Returns: + bool, str: True, None if un-connection succeeded. If False, + the second part is an error string. + + """ + caller = self.caller + + if not channel.has_connection(caller): + return False, f"Not listening to channel {channel.key}." + + # this will also clean aliases + result = channel.disconnect(caller) + + return result, "" if result else f"Could not unsubscribe from channel {channel.key}"
    + +
    [docs] def add_alias(self, channel, alias, **kwargs): + """ + Add a new alias (nick) for the user to use with this channel. + + Args: + channel (Channel): The channel to alias. + alias (str): The personal alias to use for this channel. + **kwargs: If given, passed into nicks.add. + + Note: + We add two nicks - one is a plain `alias -> channel.key` that + we need to be able to reference this channel easily. The other + is a templated nick to easily be able to send messages to the + channel without needing to give the full `channel` command. The + structure of this nick is given by `self.channel_msg_pattern` + and `self.channel_msg_nick_replacement`. By default it maps + `alias <msg> -> channel <channelname> = <msg>`, so that you can + for example just write `pub Hello` to send a message. + + The alias created is `alias $1 -> channel channel = $1`, to allow + for sending to channel using the main channel command. + + """ + channel.add_user_channel_alias(self.caller, alias, **kwargs)
    + +
    [docs] def remove_alias(self, alias, **kwargs): + """ + Remove an alias from a channel. + + Args: + alias (str, optional): The alias to remove. + The channel will be reverse-determined from the + alias, if it exists. + + Returns: + bool, str: True, None if removal succeeded. If False, + the second part is an error string. + **kwargs: If given, passed into nicks.get/add. + + Note: + This will remove two nicks - the plain channel alias and the templated + nick used for easily sending messages to the channel. + + """ + if self.caller.nicks.has(alias, category="channel", **kwargs): + DefaultChannel.remove_user_channel_alias(self.caller, alias) + return True, "" + return False, "No such alias was defined."
    + +
    [docs] def get_channel_aliases(self, channel): + """ + Get a user's aliases for a given channel. The user is retrieved + through self.caller. + + Args: + channel (Channel): The channel to act on. + + Returns: + list: A list of zero, one or more alias-strings. + + """ + chan_key = channel.key.lower() + nicktuples = self.caller.nicks.get(category="channel", return_tuple=True, return_list=True) + if nicktuples: + return [tup[2] for tup in nicktuples if tup[3].lower() == chan_key] + return []
    + +
    [docs] def mute_channel(self, channel): + """ + Temporarily mute a channel. + + Args: + channel (Channel): The channel to alias. + + Returns: + bool, str: True, None if muting successful. If False, + the second part is an error string. + """ + if channel.mute(self.caller): + return True, "" + return False, f"Channel {channel.key} was already muted."
    + +
    [docs] def unmute_channel(self, channel): + """ + Unmute a channel. + + Args: + channel (Channel): The channel to alias. + + Returns: + bool, str: True, None if unmuting successful. If False, + the second part is an error string. + + """ + if channel.unmute(self.caller): + return True, "" + return False, f"Channel {channel.key} was already unmuted."
    + +
    [docs] def create_channel(self, name, description, typeclass=None, aliases=None): + """ + Create a new channel. Its name must not previously exist + (users can alias as needed). Will also connect to the + new channel. + + Args: + name (str): The new channel name/key. + description (str): This is used in listings. + aliases (list): A list of strings - alternative aliases for the channel + (not to be confused with per-user aliases; these are available for + everyone). + + Returns: + channel, str: new_channel, "" if creation successful. If False, + the second part is an error string. + + """ + caller = self.caller + if typeclass: + typeclass = class_from_module(typeclass) + else: + typeclass = CHANNEL_DEFAULT_TYPECLASS + + if typeclass.objects.channel_search(name, exact=True): + return False, f"Channel {name} already exists." + + # set up the new channel + lockstring = "send:all();listen:all();control:id(%s)" % caller.id + + new_chan = create.create_channel( + name, aliases=aliases, desc=description, locks=lockstring, typeclass=typeclass) + self.sub_to_channel(new_chan) + return new_chan, ""
    + +
    [docs] def destroy_channel(self, channel, message=None): + """ + Destroy an existing channel. Access should be checked before + calling this function. + + Args: + channel (Channel): The channel to alias. + message (str, optional): Final message to send onto the channel + before destroying it. If not given, a default message is + used. Set to the empty string for no message. + + if typeclass: + pass + + """ + caller = self.caller + + channel_key = channel.key + if message is None: + message = (f"|rChannel {channel_key} is being destroyed. " + "Make sure to clean any channel aliases.|n") + if message: + channel.msg(message, senders=caller, bypass_mute=True) + channel.delete() + logger.log_sec( + "Channel {} was deleted by {}".format(channel_key, caller) + )
    + +
    [docs] def set_lock(self, channel, lockstring): + """ + Set a lockstring on a channel. Permissions must have been + checked before this call. + + Args: + channel (Channel): The channel to operate on. + lockstring (str): A lockstring on the form 'type:lockfunc();...' + + Returns: + bool, str: True, None if setting lock was successful. If False, + the second part is an error string. + + """ + try: + channel.locks.add(lockstring) + except LockException as err: + return False, err + return True, ""
    + +
    [docs] def unset_lock(self, channel, lockstring): + """ + Remove locks in a lockstring on a channel. Permissions must have been + checked before this call. + + Args: + channel (Channel): The channel to operate on. + lockstring (str): A lockstring on the form 'type:lockfunc();...' + + Returns: + bool, str: True, None if setting lock was successful. If False, + the second part is an error string. + + """ + try: + channel.locks.remove(lockstring) + except LockException as err: + return False, err + return True, ""
    + +
    [docs] def set_desc(self, channel, description): + """ + Set a channel description. This is shown in listings etc. + + Args: + caller (Object or Account): The entity performing the action. + channel (Channel): The channel to operate on. + description (str): A short description of the channel. + + Returns: + bool, str: True, None if setting lock was successful. If False, + the second part is an error string. + + """ + channel.db.desc = description
    + +
    [docs] def boot_user(self, channel, target, quiet=False, reason=""): + """ + Boot a user from a channel, with optional reason. This will + also remove all their aliases for this channel. + + Args: + channel (Channel): The channel to operate on. + target (Object or Account): The entity to boot. + quiet (bool, optional): Whether or not to announce to channel. + reason (str, optional): A reason for the boot. + + Returns: + bool, str: True, None if setting lock was successful. If False, + the second part is an error string. + + """ + if not channel.subscriptions.has(target): + return False, f"{target} is not connected to channel {channel.key}." + # find all of target's nicks linked to this channel and delete them + for nick in [ + nick + for nick in target.nicks.get(category="channel") or [] + if nick.value[3].lower() == channel.key + ]: + nick.delete() + channel.disconnect(target) + reason = f" Reason: {reason}" if reason else "" + target.msg(f"You were booted from channel {channel.key} by {self.caller.key}.{reason}") + if not quiet: + channel.msg(f"{target.key} was booted from channel by {self.caller.key}.{reason}") + + logger.log_sec(f"Channel Boot: {target} (Channel: {channel}, " + f"Reason: {reason.strip()}, Caller: {self.caller}") + return True, ""
    + +
    [docs] def ban_user(self, channel, target, quiet=False, reason=""): + """ + Ban a user from a channel, by locking them out. This will also + boot them, if they are currently connected. + + Args: + channel (Channel): The channel to operate on. + target (Object or Account): The entity to ban + quiet (bool, optional): Whether or not to announce to channel. + reason (str, optional): A reason for the ban + + Returns: + bool, str: True, None if banning was successful. If False, + the second part is an error string. + + """ + self.boot_user(channel, target, quiet=quiet, reason=reason) + if channel.ban(target): + return True, "" + return False, f"{target} is already banned from this channel."
    + +
    [docs] def unban_user(self, channel, target): + """ + Un-Ban a user from a channel. This will not reconnect them + to the channel, just allow them to connect again (assuming + they have the suitable 'listen' lock like everyone else). + + Args: + channel (Channel): The channel to operate on. + target (Object or Account): The entity to unban + + Returns: + bool, str: True, None if unbanning was successful. If False, + the second part is an error string. + + """ + if channel.unban(target): + return True, "" + return False, f"{target} was not previously banned from this channel."
    + +
    [docs] def channel_list_bans(self, channel): + """ + Show a channel's bans. + + Args: + channel (Channel): The channel to operate on. + + Returns: + list: A list of strings, each the name of a banned user. + + """ + return [banned.key for banned in channel.banlist]
    + +
    [docs] def channel_list_who(self, channel): + """ + Show a list of online people is subscribing to a channel. This will check + the 'control' permission of `caller` to determine if only online users + should be returned or everyone. + + Args: + channel (Channel): The channel to operate on. + + Returns: + list: A list of prepared strings, with name + markers for if they are + muted or offline. + + """ + caller = self.caller + mute_list = list(channel.mutelist) + online_list = channel.subscriptions.online() + if channel.access(caller, 'control'): + # for those with channel control, show also offline users + all_subs = list(channel.subscriptions.all()) + else: + # for others, only show online users + all_subs = online_list + + who_list = [] + for subscriber in all_subs: + name = subscriber.get_display_name(caller) + conditions = ("muting" if subscriber in mute_list else "", + "offline" if subscriber not in online_list else "") + conditions = [cond for cond in conditions if cond] + cond_text = "(" + ", ".join(conditions) + ")" if conditions else "" + who_list.append(f"{name}{cond_text}") + + return who_list
    + +
    [docs] def list_channels(self, channelcls=CHANNEL_DEFAULT_TYPECLASS): + """ + Return a available channels. + + Args: + channelcls (Channel, optional): The channel-class to query on. Defaults + to the default channel class from settings. + + Returns: + tuple: A tuple `(subbed_chans, available_chans)` with the channels + currently subscribed to, and those we have 'listen' access to but + don't actually sub to yet. + + """ + caller = self.caller + subscribed_channels = list(channelcls.objects.get_subscriptions(caller)) + unsubscribed_available_channels = [ + chan + for chan in channelcls.objects.get_all_channels() + if chan not in subscribed_channels and chan.access(caller, "listen") + ] + return subscribed_channels, unsubscribed_available_channels
    + +
    [docs] def display_subbed_channels(self, subscribed): + """ + Display channels subscribed to. + + Args: + subscribed (list): List of subscribed channels + + Returns: + EvTable: Table to display. + + """ + comtable = self.styled_table( + "channel", + "my aliases", + "locks", + "description", + align="l", + maxwidth=_DEFAULT_WIDTH + ) + for chan in subscribed: + + locks = "-" + if chan.access(self.caller, "control"): + locks = chan.locks + + my_aliases = ", ".join(self.get_channel_aliases(chan)) + comtable.add_row( + *("{}{}".format( + chan.key, + "({})".format(",".join(chan.aliases.all())) if chan.aliases.all() else ""), + my_aliases, + locks, + chan.db.desc)) + return comtable
    + +
    [docs] def display_all_channels(self, subscribed, available): + """ + Display all available channels + + Args: + subscribed (list): List of subscribed channels + Returns: + EvTable: Table to display. + + """ + caller = self.caller + + comtable = self.styled_table( + "sub", + "channel", + "aliases", + "my aliases", + "description", + maxwidth=_DEFAULT_WIDTH, + ) + channels = subscribed + available + + for chan in channels: + if chan not in subscribed: + substatus = "|rNo|n" + elif caller in chan.mutelist: + substatus = "|rMuting|n" + else: + substatus = "|gYes|n" + my_aliases = ", ".join(self.get_channel_aliases(chan)) + comtable.add_row( + *(substatus, + chan.key, + ",".join(chan.aliases.all()) if chan.aliases.all() else "", + my_aliases, + chan.db.desc)) + comtable.reformat_column(0, width=8) + + return comtable
    + +
    [docs] def func(self): + """ + Main functionality of command. + """ + # from evennia import set_trace;set_trace() + + caller = self.caller + switches = self.switches + channel_names = [name for name in self.lhslist if name] + + #from evennia import set_trace;set_trace() + + if 'all' in switches: + # show all available channels + subscribed, available = self.list_channels() + table = self.display_all_channels(subscribed, available) + + self.msg( + "\n|wAvailable channels|n (use no argument to " + f"only show your subscriptions)\n{table}") + return + + if not channel_names: + # empty arg show only subscribed channels + subscribed, _ = self.list_channels() + table = self.display_subbed_channels(subscribed) + + self.msg("\n|wChannel subscriptions|n " + f"(use |w/all|n to see all available):\n{table}") + return + + if not self.switches and not self.args: + self.msg("Usage[/switches]: channel [= message]") + return + + if 'create' in switches: + # create a new channel + + if not self.access(caller, "manage"): + self.msg("You don't have access to use channel/create.") + return + + config = self.lhs + if not config: + self.msg("To create: channel/create name[;aliases][:typeclass] [= description]") + return + name, *typeclass = config.rsplit(":", 1) + typeclass = typeclass[0] if typeclass else None + name, *aliases = name.rsplit(";") + description = self.rhs or "" + chan, err = self.create_channel(name, description, typeclass=typeclass, aliases=aliases) + if chan: + self.msg(f"Created (and joined) new channel '{chan.key}'.") + else: + self.msg(err) + return + + if 'unalias' in switches: + # remove a personal alias (no channel needed) + alias = self.args.strip() + if not alias: + self.msg("Specify the alias to remove as channel/unalias <alias>") + return + success, err = self.remove_alias(alias) + if success: + self.msg(f"Removed your channel alias '{alias}'.") + else: + self.msg(err) + return + + possible_lhs_message = "" + if not self.rhs and self.args and " " in self.args: + # since we want to support messaging with `channel name text` (for + # channels without a space in their name), we need to check if the + # first 'channel name' is in fact 'channelname text' + no_rhs_channel_name = self.args.split(" ", 1)[0] + possible_lhs_message = self.args[len(no_rhs_channel_name):] + if possible_lhs_message.strip() == '=': + possible_lhs_message = "" + channel_names.append(no_rhs_channel_name) -
    [docs]class CmdAddCom(COMMAND_DEFAULT_CLASS): + channels = [] + errors = [] + for channel_name in channel_names: + # find a channel by fuzzy-matching. This also checks + # 'listen/control' perms. + found_channels = self.search_channel(channel_name, exact=False, handle_errors=False) + if not found_channels: + errors.append(f"No channel found matching '{channel_name}' " + "(could also be due to missing access).") + elif len(found_channels) > 1: + errors.append("Multiple possible channel matches/alias for " + "'{channel_name}':\n" + ", ".join(chan.key for chan in found_channels)) + else: + channels.append(found_channels[0]) + + if not channels: + self.msg('\n'.join(errors)) + return + + # we have at least one channel at this point + channel = channels[0] + + if not switches: + if self.rhs: + # send message to channel + self.msg_channel(channel, self.rhs.strip()) + elif channel and possible_lhs_message: + # called on the form channelname message without = + self.msg_channel(channel, possible_lhs_message.strip()) + else: + # inspect a given channel + subscribed, available = self.list_channels() + if channel in subscribed: + table = self.display_subbed_channels([channel]) + header = f"Channel |w{channel.key}|n" + self.msg(f"{header}\n(use |w{channel.key} <msg>|n (or a channel-alias) " + f"to chat and the 'channel' command " + f"to customize)\n{table}") + elif channel in available: + table = self.display_all_channels([], [channel]) + self.msg( + "\n|wNot subscribed to this channel|n (use /list to " + f"show all subscriptions)\n{table}") + return + + if 'history' in switches or 'hist' in switches: + # view channel history + + index = self.rhs or 0 + try: + index = max(0, int(index)) + except ValueError: + self.msg("The history index (describing how many lines to go back) " + "must be an integer >= 0.") + return + self.get_channel_history(channel, start_index=index) + return + + if 'sub' in switches: + # subscribe to a channel + aliases = [] + if self.rhs: + aliases = set(alias.strip().lower() for alias in self.rhs.split(";")) + success, err = self.sub_to_channel(channel) + if success: + for alias in aliases: + self.add_alias(channel, alias) + alias_txt = ', '.join(aliases) + alias_txt = f" using alias(es) {alias_txt}" if aliases else '' + self.msg("You are now subscribed " + f"to the channel {channel.key}{alias_txt}. Use /alias to " + "add additional aliases for referring to the channel.") + else: + self.msg(err) + return + + if 'unsub' in switches: + # un-subscribe from a channel + success, err = self.unsub_from_channel(channel) + if success: + self.msg(f"You un-subscribed from channel {channel.key}. " + "All aliases were cleared.") + else: + self.msg(err) + return + + if 'alias' in switches: + # create a new personal alias for a channel + alias = self.rhs + if not alias: + self.msg("Specify the alias as channel/alias channelname = alias") + return + self.add_alias(channel, alias) + self.msg(f"Added/updated your alias '{alias}' for channel {channel.key}.") + return + + if 'mute' in switches: + # mute a given channel + success, err = self.mute_channel(channel) + if success: + self.msg(f"Muted channel {channel.key}.") + else: + self.msg(err) + return + + if 'unmute' in switches: + # unmute a given channel + success, err = self.unmute_channel(channel) + if success: + self.msg(f"Un-muted channel {channel.key}.") + else: + self.msg(err) + return + + if 'destroy' in switches or 'delete' in switches: + # destroy a channel we control + + if not self.access(caller, "manage"): + self.msg("You don't have access to use channel/destroy.") + return + + if not channel.access(caller, "control"): + self.msg("You can only delete channels you control.") + return + + reason = self.rhs or None + + def _perform_delete(caller, *args, **kwargs): + self.destroy_channel(channel, message=reason) + self.msg(f"Channel {channel.key} was successfully deleted.") + + ask_yes_no( + caller, + prompt=f"Are you sure you want to delete channel '{channel.key}' " + "(make sure name is correct!)?\nThis will disconnect and " + "remove all users' aliases. {options}?", + yes_action=_perform_delete, + no_action="Aborted.", + default="N" + ) + + if 'desc' in switches: + # set channel description + + if not self.access(caller, "manage"): + self.msg("You don't have access to use channel/desc.") + return + + if not channel.access(caller, "control"): + self.msg("You can only change description of channels you control.") + return + + desc = self.rhs.strip() + + if not desc: + self.msg("Usage: /desc channel = description") + return + + self.set_desc(channel, desc) + self.msg("Updated channel description.") + + if 'lock' in switches: + # add a lockstring to channel + + if not self.access(caller, "changelocks"): + self.msg("You don't have access to use channel/lock.") + return + + if not channel.access(caller, "control"): + self.msg("You need 'control'-access to change locks on this channel.") + return + + lockstring = self.rhs.strip() + + if not lockstring: + self.msg("Usage: channel/lock channelname = lockstring") + return + + success, err = self.set_lock(channel, self.rhs) + if success: + self.msg("Added/updated lock on channel.") + else: + self.msg(f"Could not add/update lock: {err}") + return + + if 'unlock' in switches: + # remove/update lockstring from channel + + if not self.access(caller, "changelocks"): + self.msg("You don't have access to use channel/unlock.") + return + + if not channel.access(caller, "control"): + self.msg("You need 'control'-access to change locks on this channel.") + return + + lockstring = self.rhs.strip() + + if not lockstring: + self.msg("Usage: channel/unlock channelname = lockstring") + return + + success, err = self.unset_lock(channel, self.rhs) + if success: + self.msg("Removed lock from channel.") + else: + self.msg(f"Could not remove lock: {err}") + return + + if 'boot' in switches: + # boot a user from channel(s) + + if not self.access(caller, "admin"): + self.msg("You don't have access to use channel/boot.") + return + + if not self.rhs: + self.msg("Usage: channel/boot channel[,channel,...] = username [:reason]") + return + + target_str, *reason = self.rhs.rsplit(":", 1) + reason = reason[0].strip() if reason else "" + + for chan in channels: + + if not chan.access(caller, "control"): + self.msg(f"You need 'control'-access to boot a user from {chan.key}.") + return + + # the target must be a member of all given channels + target = caller.search(target_str, candidates=chan.subscriptions.all()) + if not target: + self.msg(f"Cannot boot '{target_str}' - not in channel {chan.key}.") + return + + def _boot_user(caller, *args, **kwargs): + for chan in channels: + success, err = self.boot_user(chan, target, quiet=False, reason=reason) + if success: + self.msg(f"Booted {target.key} from channel {chan.key}.") + else: + self.msg(f"Cannot boot {target.key} from channel {chan.key}: {err}") + + channames = ", ".join(chan.key for chan in channels) + reasonwarn = (". Also note that your reason will be echoed to the channel" + if reason else '') + ask_yes_no( + caller, + prompt=f"Are you sure you want to boot user {target.key} from " + f"channel(s) {channames} (make sure name/channels are correct{reasonwarn}). " + "{options}?", + yes_action=_boot_user, + no_action="Aborted.", + default="Y" + ) + return + + if 'ban' in switches: + # ban a user from channel(s) + + if not self.access(caller, "admin"): + self.msg("You don't have access to use channel/ban.") + return + + if not self.rhs: + # view bans for channels + + if not channel.access(caller, "control"): + self.msg(f"You need 'control'-access to view bans on channel {channel.key}") + return + + bans = ["Channel bans " + "(to ban, use channel/ban channel[,channel,...] = username [:reason]"] + bans.extend(self.channel_list_bans(channel)) + self.msg("\n".join(bans)) + return + + target_str, *reason = self.rhs.rsplit(":", 1) + reason = reason[0].strip() if reason else "" + + for chan in channels: + # the target must be a member of all given channels + if not chan.access(caller, "control"): + self.msg(f"You don't have access to ban users on channel {chan.key}") + return + + target = caller.search(target_str, candidates=chan.subscriptions.all()) + + if not target: + self.msg(f"Cannot ban '{target_str}' - not in channel {chan.key}.") + return + + def _ban_user(caller, *args, **kwargs): + for chan in channels: + success, err = self.ban_user(chan, target, quiet=False, reason=reason) + if success: + self.msg(f"Banned {target.key} from channel {chan.key}.") + else: + self.msg(f"Cannot boot {target.key} from channel {chan.key}: {err}") + + channames = ", ".join(chan.key for chan in channels) + reasonwarn = (". Also note that your reason will be echoed to the channel" + if reason else '') + ask_yes_no( + caller, + f"Are you sure you want to ban user {target.key} from " + f"channel(s) {channames} (make sure name/channels are correct{reasonwarn}) " + "{options}?", + _ban_user, + "Aborted.", + ) + return + + if 'unban' in switches: + # unban a previously banned user from channel + + if not self.access(caller, "admin"): + self.msg("You don't have access to use channel/unban.") + return + + target_str = self.rhs.strip() + + if not target_str: + self.msg("Usage: channel[,channel,...] = user") + return + + banlists = [] + for chan in channels: + # the target must be a member of all given channels + if not chan.access(caller, "control"): + self.msg(f"You don't have access to unban users on channel {chan.key}") + return + banlists.extend(chan.banlist) + + target = caller.search(target_str, candidates=banlists) + if not target: + self.msg("Could not find a banned user '{target_str}' in given channel(s).") + return + + for chan in channels: + success, err = self.unban_user(channel, target) + if success: + self.msg(f"Un-banned {target_str} from channel {chan.key}") + else: + self.msg(err) + return + + if "who" in switches: + # view who's a member of a channel + + who_list = [f"Subscribed to {channel.key}:"] + who_list.extend(self.channel_list_who(channel)) + self.msg("\n".join(who_list)) + return
    + + +# a channel-command parent for use with Characters/Objects. +class CmdObjectChannel(CmdChannel): + account_caller = False + + +
    [docs]class CmdAddCom(CmdChannel): """ - add a channel alias and/or subscribe to a channel + Add a channel alias and/or subscribe to a channel Usage: addcom [alias=] <channel> @@ -138,7 +1316,6 @@ caller = self.caller args = self.args - account = caller if not args: self.msg("Usage: addcom [alias =] channelname.") @@ -152,42 +1329,36 @@ channelname = self.args alias = None - channel = find_channel(caller, channelname) + channel = self.search_channel(channelname) if not channel: - # we use the custom search method to handle errors. - return - - # check permissions - if not channel.access(account, "listen"): - self.msg("%s: You are not allowed to listen to this channel." % channel.key) return string = "" - if not channel.has_connection(account): + if not channel.has_connection(caller): # we want to connect as well. - if not channel.connect(account): + success, err = self.sub_to_channel(channel) + if success: # if this would have returned True, the account is connected - self.msg("%s: You are not allowed to join this channel." % channel.key) + self.msg(f"You now listen to the channel {channel.key}") + else: + self.msg(f"{channel.key}: You are not allowed to join this channel.") return - else: - string += "You now listen to the channel %s. " % channel.key + + if channel.unmute(caller): + self.msg(f"You unmute channel {channel.key}.") else: - if channel.unmute(account): - string += "You unmute channel %s." % channel.key - else: - string += "You are already connected to channel %s." % channel.key + self.msg(f"You are already connected to channel {channel.key}.") if alias: # create a nick and add it to the caller. - caller.nicks.add(alias, channel.key, category="channel") - string += " You can now refer to the channel %s with the alias '%s'." - self.msg(string % (channel.key, alias)) + self.add_alias(channel, alias) + self.msg(f" You can now refer to the channel {channel} with the alias '{alias}'.") else: string += " No alias added." self.msg(string)
    -
    [docs]class CmdDelCom(COMMAND_DEFAULT_CLASS): +
    [docs]class CmdDelCom(CmdChannel): """ remove a channel alias and/or unsubscribe from channel @@ -213,49 +1384,42 @@ """Implementing the command. """ caller = self.caller - account = caller if not self.args: self.msg("Usage: delcom <alias or channel>") return - ostring = self.args.lower() + ostring = self.args.lower().strip() - channel = find_channel(caller, ostring, silent=True, noaliases=True) - if channel: - # we have given a channel name - unsubscribe - if not channel.has_connection(account): - self.msg("You are not listening to that channel.") - return - chkey = channel.key.lower() + channel = self.search_channel(ostring) + if not channel: + return + + if not channel.has_connection(caller): + self.msg("You are not listening to that channel.") + return + + if ostring == channel.key.lower(): + # an exact channel name - unsubscribe delnicks = "all" in self.switches # find all nicks linked to this channel and delete them if delnicks: - for nick in [ - nick - for nick in make_iter(caller.nicks.get(category="channel", return_obj=True)) - if nick and nick.pk and nick.value[3].lower() == chkey - ]: - nick.delete() - disconnect = channel.disconnect(account) - if disconnect: + aliases = self.get_channel_aliases(channel) + for alias in aliases: + self.remove_alias(alias) + success, err = self.unsub_from_channel(channel) + if success: wipednicks = " Eventual aliases were removed." if delnicks else "" - self.msg("You stop listening to channel '%s'.%s" % (channel.key, wipednicks)) + self.msg(f"You stop listening to channel '{channel.key}'.{wipednicks}") + else: + self.msg(err) return else: # we are removing a channel nick - channame = caller.nicks.get(key=ostring, category="channel") - channel = find_channel(caller, channame, silent=True) - if not channel: - self.msg("No channel with alias '%s' was found." % ostring) - else: - if caller.nicks.get(ostring, category="channel"): - caller.nicks.remove(ostring, category="channel") - self.msg("Your alias '%s' for channel %s was cleared." % (ostring, channel.key)) - else: - self.msg("You had no such alias defined for this channel.")
    + self.remove_alias(ostring) + self.msg(f"Any alias '{ostring}' for channel {channel.key} was cleared.")
    -
    [docs]class CmdAllCom(COMMAND_DEFAULT_CLASS): +
    [docs]class CmdAllCom(CmdChannel): """ perform admin operations on all channels @@ -270,6 +1434,7 @@ """ key = "allcom" + aliases = [] # important to not inherit parent's aliases locks = "cmd: not pperm(channel_banned)" help_category = "Comms" @@ -282,8 +1447,11 @@ caller = self.caller args = self.args if not args: - self.execute_cmd("channels") - self.msg("(Usage: allcom on | off | who | destroy)") + subscribed, available = self.list_channels() + table = self.display_all_channels(subscribed, available) + self.msg( + "\n|wAvailable channels:\n{table}") + return return if args == "on": @@ -327,125 +1495,7 @@ # wrong input self.msg("Usage: allcom on | off | who | clear")
    - -
    [docs]class CmdChannels(COMMAND_DEFAULT_CLASS): - """ - list all channels available to you - - Usage: - channels - clist - comlist - - Lists all channels available to you, whether you listen to them or not. - Use 'comlist' to only view your current channel subscriptions. - Use addcom/delcom to join and leave channels - """ - - key = "channels" - aliases = ["clist", "comlist", "chanlist", "channellist", "all channels"] - help_category = "Comms" - locks = "cmd: not pperm(channel_banned)" - - # this is used by the COMMAND_DEFAULT_CLASS parent - account_caller = True - -
    [docs] def func(self): - """Implement function""" - - caller = self.caller - - # all channels we have available to listen to - channels = [ - chan - for chan in CHANNEL_DEFAULT_TYPECLASS.objects.get_all_channels() - if chan.access(caller, "listen") - ] - if not channels: - self.msg("No channels available.") - return - # all channel we are already subscribed to - subs = CHANNEL_DEFAULT_TYPECLASS.objects.get_subscriptions(caller) - - if self.cmdstring == "comlist": - # just display the subscribed channels with no extra info - comtable = self.styled_table( - "|wchannel|n", - "|wmy aliases|n", - "|wdescription|n", - align="l", - maxwidth=_DEFAULT_WIDTH, - ) - for chan in subs: - clower = chan.key.lower() - nicks = caller.nicks.get(category="channel", return_obj=True) - comtable.add_row( - *[ - "%s%s" - % ( - chan.key, - chan.aliases.all() and "(%s)" % ",".join(chan.aliases.all()) or "", - ), - "%s" - % ",".join( - nick.db_key - for nick in make_iter(nicks) - if nick and nick.value[3].lower() == clower - ), - chan.db.desc, - ] - ) - self.msg( - "\n|wChannel subscriptions|n (use |wchannels|n to list all," - " |waddcom|n/|wdelcom|n to sub/unsub):|n\n%s" % comtable - ) - else: - # full listing (of channels caller is able to listen to) - comtable = self.styled_table( - "|wsub|n", - "|wchannel|n", - "|wmy aliases|n", - "|wlocks|n", - "|wdescription|n", - maxwidth=_DEFAULT_WIDTH, - ) - for chan in channels: - clower = chan.key.lower() - nicks = caller.nicks.get(category="channel", return_obj=True) - nicks = nicks or [] - if chan not in subs: - substatus = "|rNo|n" - elif caller in chan.mutelist: - substatus = "|rMuted|n" - else: - substatus = "|gYes|n" - comtable.add_row( - *[ - substatus, - "%s%s" - % ( - chan.key, - chan.aliases.all() and "(%s)" % ",".join(chan.aliases.all()) or "", - ), - "%s" - % ",".join( - nick.db_key - for nick in make_iter(nicks) - if nick.value[3].lower() == clower - ), - str(chan.locks), - chan.db.desc, - ] - ) - comtable.reformat_column(0, width=9) - comtable.reformat_column(3, width=14) - self.msg( - "\n|wAvailable channels|n (use |wcomlist|n,|waddcom|n and |wdelcom|n" - " to manage subscriptions):\n%s" % comtable - )
    - - -
    [docs]class CmdCdestroy(COMMAND_DEFAULT_CLASS): +
    [docs]class CmdCdestroy(CmdChannel): """ destroy a channel you created @@ -456,6 +1506,7 @@ """ key = "cdestroy" + aliases = [] help_category = "Comms" locks = "cmd: not pperm(channel_banned)" @@ -464,12 +1515,15 @@
    [docs] def func(self): """Destroy objects cleanly.""" + caller = self.caller if not self.args: self.msg("Usage: cdestroy <channelname>") return - channel = find_channel(caller, self.args) + + channel = self.search_channel(self.args) + if not channel: self.msg("Could not find channel %s." % self.args) return @@ -477,11 +1531,8 @@ self.msg("You are not allowed to do that.") return channel_key = channel.key - message = "%s is being destroyed. Make sure to change your aliases." % channel_key - msgobj = create.create_message(caller, message, channel) - channel.msg(msgobj) - channel.delete() - CHANNELHANDLER.update() + message = f"{channel.key} is being destroyed. Make sure to change your aliases." + self.destroy_channel(channel, message) self.msg("Channel '%s' was destroyed." % channel_key) logger.log_sec( "Channel Deleted: %s (Caller: %s, IP: %s)." @@ -489,7 +1540,7 @@ )
    -
    [docs]class CmdCBoot(COMMAND_DEFAULT_CLASS): +
    [docs]class CmdCBoot(CmdChannel): """ kick an account from a channel you control @@ -504,6 +1555,7 @@ """ key = "cboot" + aliases = [] switch_options = ("quiet",) locks = "cmd: not pperm(channel_banned)" help_category = "Comms" @@ -519,17 +1571,21 @@ self.msg(string) return - channel = find_channel(self.caller, self.lhs) + channel = self.search_channel(self.lhs) if not channel: return + reason = "" if ":" in self.rhs: - accountname, reason = self.rhs.rsplit(":", 1) - searchstring = accountname.lstrip("*") + target, reason = self.rhs.rsplit(":", 1) + is_account = target.strip().startswith("*") + searchstring = target.lstrip("*") else: + is_account = target.strip().startswith("*") searchstring = self.rhs.lstrip("*") - account = self.caller.search(searchstring, account=True) - if not account: + + target = self.caller.search(searchstring, account=is_account) + if not target: return if reason: reason = " (reason: %s)" % reason @@ -537,79 +1593,19 @@ string = "You don't control this channel." self.msg(string) return - if not channel.subscriptions.has(account): - string = "Account %s is not connected to channel %s." % (account.key, channel.key) - self.msg(string) - return - if "quiet" not in self.switches: - string = "%s boots %s from channel.%s" % (self.caller, account.key, reason) - channel.msg(string) - # find all account's nicks linked to this channel and delete them - for nick in [ - nick - for nick in account.character.nicks.get(category="channel") or [] - if nick.value[3].lower() == channel.key - ]: - nick.delete() - # disconnect account - channel.disconnect(account) - CHANNELHANDLER.update() - logger.log_sec( - "Channel Boot: %s (Channel: %s, Reason: %s, Caller: %s, IP: %s)." - % (account, channel, reason, self.caller, self.session.address) - )
    + + success, err = self.boot_user(target, quiet='quiet' in self.switches) + if success: + self.msg(f"Booted {target.key} from {channel.key}") + logger.log_sec( + "Channel Boot: %s (Channel: %s, Reason: %s, Caller: %s, IP: %s)." + % (self.caller, channel, reason, self.caller, self.session.address) + ) + else: + self.msg(err)
    -
    [docs]class CmdCemit(COMMAND_DEFAULT_CLASS): - """ - send an admin message to a channel you control - - Usage: - cemit[/switches] <channel> = <message> - - Switches: - sendername - attach the sender's name before the message - quiet - don't echo the message back to sender - - Allows the user to broadcast a message over a channel as long as - they control it. It does not show the user's name unless they - provide the /sendername switch. - - """ - - key = "cemit" - aliases = ["cmsg"] - switch_options = ("sendername", "quiet") - locks = "cmd: not pperm(channel_banned) and pperm(Player)" - help_category = "Comms" - - # this is used by the COMMAND_DEFAULT_CLASS parent - account_caller = True - -
    [docs] def func(self): - """Implement function""" - - if not self.args or not self.rhs: - string = "Usage: cemit[/switches] <channel> = <message>" - self.msg(string) - return - channel = find_channel(self.caller, self.lhs) - if not channel: - return - if not channel.access(self.caller, "control"): - string = "You don't control this channel." - self.msg(string) - return - message = self.rhs - if "sendername" in self.switches: - message = "%s: %s" % (self.caller.key, message) - channel.msg(message) - if "quiet" not in self.switches: - string = "Sent to channel %s: %s" % (channel.key, message) - self.msg(string)
    - - -
    [docs]class CmdCWho(COMMAND_DEFAULT_CLASS): +
    [docs]class CmdCWho(CmdChannel): """ show who is listening to a channel @@ -620,6 +1616,7 @@ """ key = "cwho" + aliases = [] locks = "cmd: not pperm(channel_banned)" help_category = "Comms" @@ -634,7 +1631,7 @@ self.msg(string) return - channel = find_channel(self.caller, self.lhs) + channel = self.search_channel(self.lhs) if not channel: return if not channel.access(self.caller, "listen"): @@ -646,7 +1643,7 @@ self.msg(string.strip())
    -
    [docs]class CmdChannelCreate(COMMAND_DEFAULT_CLASS): +
    [docs]class CmdChannelCreate(CmdChannel): """ create a new channel @@ -667,8 +1664,6 @@
    [docs] def func(self): """Implement the command""" - caller = self.caller - if not self.args: self.msg("Usage ccreate <channelname>[;alias;alias..] = description") return @@ -683,19 +1678,15 @@ if ";" in lhs: channame, aliases = lhs.split(";", 1) aliases = [alias.strip().lower() for alias in aliases.split(";")] - channel = CHANNEL_DEFAULT_TYPECLASS.objects.channel_search(channame) - if channel: - self.msg("A channel with that name already exists.") - return - # Create and set the channel up - lockstring = "send:all();listen:all();control:id(%s)" % caller.id - new_chan = create.create_channel(channame.strip(), aliases, description, locks=lockstring) - new_chan.connect(caller) - CHANNELHANDLER.update() - self.msg("Created channel %s and connected to it." % new_chan.key)
    + + new_chan, err = self.create_channel(channame, description, aliases=aliases) + if new_chan: + self.msg(f"Created channel {new_chan.key} and connected to it.") + else: + self.msg(err)
    -
    [docs]class CmdClock(COMMAND_DEFAULT_CLASS): +
    [docs]class CmdClock(CmdChannel): """ change channel locks of a channel you control @@ -707,8 +1698,8 @@ """ key = "clock" - locks = "cmd:not pperm(channel_banned)" aliases = ["clock"] + locks = "cmd:not pperm(channel_banned) and perm(Admin)" help_category = "Comms" # this is used by the COMMAND_DEFAULT_CLASS parent @@ -722,14 +1713,13 @@ self.msg(string) return - channel = find_channel(self.caller, self.lhs) + channel = self.search_channel(self.lhs) if not channel: return + if not self.rhs: # no =, so just view the current locks - string = "Current locks on %s:" % channel.key - string = "%s\n %s" % (string, channel.locks) - self.msg(string) + self.msg(f"Current locks on {channel.key}\n{channel.locks}") return # we want to add/change a lock. if not channel.access(self.caller, "control"): @@ -737,18 +1727,13 @@ self.msg(string) return # Try to add the lock - try: - channel.locks.add(self.rhs) - except LockException as err: - self.msg(err) - return - string = "Lock(s) applied. " - string += "Current locks on %s:" % channel.key - string = "%s\n %s" % (string, channel.locks) - self.msg(string)
    + success, err = self.set_lock(channel, self.rhs) + if success: + self.msg(f"Lock(s) applied. Current locks on {channel.key}:\n{channel.locks}") + else: + self.msg(err) - -
    [docs]class CmdCdesc(COMMAND_DEFAULT_CLASS): +
    [docs]class CmdCdesc(CmdChannel): """ describe a channel you control @@ -757,9 +1742,11 @@ Changes the description of the channel as shown in channel lists. + """ key = "cdesc" + aliases = [] locks = "cmd:not pperm(channel_banned)" help_category = "Comms" @@ -774,18 +1761,15 @@ if not self.rhs: self.msg("Usage: cdesc <channel> = <description>") return - channel = find_channel(caller, self.lhs) + channel = self.search_channel(self.lhs) if not channel: - self.msg("Channel '%s' not found." % self.lhs) return # check permissions if not channel.access(caller, "control"): self.msg("You cannot admin this channel.") return - # set the description - channel.db.desc = self.rhs - channel.save() - self.msg("Description of channel '%s' set to '%s'." % (channel.key, self.rhs))
    + self.set_desc(channel, self.rhs) + self.msg(f"Description of channel '{channel.key}' set to '{self.rhs}'.")
    [docs]class CmdPage(COMMAND_DEFAULT_CLASS): @@ -793,16 +1777,19 @@ send a private message to another account Usage: + page <account> <message> page[/switches] [<account>,<account>,... = <message>] tell '' page <number> - Switch: + Switches: last - shows who you last messaged list - show your last <number> of tells/pages (default) - Send a message to target user (if online). If no - argument is given, you will get a list of your latest messages. + Send a message to target user (if online). If no argument is given, you + will get a list of your latest messages. The equal sign is needed for + multiple targets or if sending to target with space in the name. + """ key = "page" @@ -821,9 +1808,10 @@ caller = self.caller # get the messages we've sent (not to channels) - pages_we_sent = Msg.objects.get_messages_by_sender(caller, exclude_channel_messages=True) + pages_we_sent = Msg.objects.get_messages_by_sender(caller) # get last messages we've got pages_we_got = Msg.objects.get_messages_by_receiver(caller) + targets, message, number = [], None, None if "last" in self.switches: if pages_we_sent: @@ -834,19 +1822,76 @@ self.msg("You haven't paged anyone yet.") return - if not self.args or not self.rhs: - pages = pages_we_sent + pages_we_got - pages = sorted(pages, key=lambda page: page.date_created) + if self.args: + if self.rhs: + for target in self.lhslist: + target_obj = self.caller.search(target) + if not target_obj: + return + targets.append(target_obj) + message = self.rhs.strip() + else: + target, *message = self.args.split(" ", 4) + if target and target.isnumeric(): + # a number to specify a historic page + number = int(target) + elif target: + target_obj = self.caller.search(target, quiet=True) + if target_obj: + # a proper target + targets = [target_obj[0]] + message = message[0].strip() + else: + # a message with a space in it - put it back together + message = target + " " + (message[0] if message else "") + else: + # a single-word message + message = message[0].strip() - number = 5 - if self.args: - try: - number = int(self.args) - except ValueError: - self.msg("Usage: tell [<account> = msg]") + pages = list(pages_we_sent) + list(pages_we_got) + pages = sorted(pages, key=lambda page: page.date_created) + + if message: + # send a message + if not targets: + # no target given - send to last person we paged + if pages_we_sent: + targets = pages_we_sent[-1].receivers + else: + self.msg("Who do you want page?") return - if len(pages) > number: + header = "|wAccount|n |c%s|n |wpages:|n" % caller.key + if message.startswith(":"): + message = "%s %s" % (caller.key, message.strip(":").strip()) + + # create the persistent message object + create.create_message(caller, message, receivers=targets) + + # tell the accounts they got a message. + received = [] + rstrings = [] + for target in targets: + if not target.access(caller, "msg"): + rstrings.append(f"You are not allowed to page {target}.") + continue + target.msg(f"{header} {message}") + if hasattr(target, "sessions") and not target.sessions.count(): + received.append(f"|C{target.name}|n") + rstrings.append( + f"{received[-1]} is offline. They will see your message " + "if they list their pages later." + ) + else: + received.append(f"|c{target.name}|n") + if rstrings: + self.msg("\n".join(rstrings)) + self.msg("You paged %s with: '%s'." % (", ".join(received), message)) + return + + else: + # no message to send + if number is not None and len(pages) > number: lastpages = pages[-number:] else: lastpages = pages @@ -890,6 +1935,7 @@ receiver=receiver, message=page.message, ) + ) lastpages = "\n ".join(listing) @@ -898,65 +1944,7 @@ else: string = "You haven't paged anyone yet." self.msg(string) - return - - # We are sending. Build a list of targets - - if not self.lhs: - # If there are no targets, then set the targets - # to the last person we paged. - if pages_we_sent: - receivers = pages_we_sent[-1].receivers - else: - self.msg("Who do you want to page?") - return - else: - receivers = self.lhslist - - recobjs = [] - for receiver in set(receivers): - if isinstance(receiver, str): - pobj = caller.search(receiver) - elif hasattr(receiver, "character"): - pobj = receiver - else: - self.msg("Who do you want to page?") - return - if pobj: - recobjs.append(pobj) - if not recobjs: - self.msg("Noone found to page.") - return - - header = "|wAccount|n |c%s|n |wpages:|n" % caller.key - message = self.rhs - - # if message begins with a :, we assume it is a 'page-pose' - if message.startswith(":"): - message = "%s %s" % (caller.key, message.strip(":").strip()) - - # create the persistent message object - create.create_message(caller, message, receivers=recobjs) - - # tell the accounts they got a message. - received = [] - rstrings = [] - for pobj in recobjs: - if not pobj.access(caller, "msg"): - rstrings.append("You are not allowed to page %s." % pobj) - continue - pobj.msg("%s %s" % (header, message)) - if hasattr(pobj, "sessions") and not pobj.sessions.count(): - received.append("|C%s|n" % pobj.name) - rstrings.append( - "%s is offline. They will see your message if they list their pages later." - % received[-1] - ) - else: - received.append("|c%s|n" % pobj.name) - if rstrings: - self.msg("\n".join(rstrings)) - self.msg("You paged %s with: '%s'." % (", ".join(received), message))
    + return def _list_bots(cmd): @@ -998,7 +1986,6 @@ else: return "No irc bots found." -
    [docs]class CmdIRC2Chan(COMMAND_DEFAULT_CLASS): """ Link an evennia channel to an external IRC channel @@ -1120,7 +2107,7 @@ Check and reboot IRC bot. Usage: - ircstatus [#dbref ping||nicklist||reconnect] + ircstatus [#dbref ping | nicklist | reconnect] If not given arguments, will return a list of all bots (like irc2chan/list). The 'ping' argument will ping the IRC network to @@ -1433,7 +2420,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/commands/default/general.html b/docs/0.9.5/_modules/evennia/commands/default/general.html index c904d4c8b5..22af78c29e 100644 --- a/docs/0.9.5/_modules/evennia/commands/default/general.html +++ b/docs/0.9.5/_modules/evennia/commands/default/general.html @@ -44,7 +44,7 @@ """ import re from django.conf import settings -from evennia.utils import utils, evtable +from evennia.utils import utils from evennia.typeclasses.attributes import NickTemplateInvalid COMMAND_DEFAULT_CLASS = utils.class_from_module(settings.COMMAND_DEFAULT_CLASS) @@ -420,13 +420,10 @@ string = "You are not carrying anything." else: from evennia.utils.ansi import raw as raw_ansi - table = self.styled_table(border="header") for item in items: - table.add_row( - f"|C{item.name}|n", - "{}|n".format(utils.crop(raw_ansi(item.db.desc), width=50) or ""), - ) + table.add_row(f"|C{item.name}|n", + "{}|n".format(utils.crop(raw_ansi(item.db.desc or ""), width=50) or "")) string = f"|wYou are carrying:\n{table}" self.caller.msg(string) @@ -444,7 +441,7 @@ key = "get" aliases = "grab" - locks = "cmd:all()" + locks = "cmd:all();view:perm(Developer);read:perm(Developer)" arg_regex = r"\s|$"
    [docs] def func(self): @@ -807,7 +804,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/commands/default/help.html b/docs/0.9.5/_modules/evennia/commands/default/help.html index 733b418516..e20c3ef13e 100644 --- a/docs/0.9.5/_modules/evennia/commands/default/help.html +++ b/docs/0.9.5/_modules/evennia/commands/default/help.html @@ -40,43 +40,74 @@

    Source code for evennia.commands.default.help

     """
    -The help command. The basic idea is that help texts for commands
    -are best written by those that write the commands - the admins. So
    -command-help is all auto-loaded and searched from the current command
    -set. The normal, database-tied help system is used for collaborative
    -creation of other help topics such as RP help or game-world aides.
    +The help command. The basic idea is that help texts for commands are best
    +written by those that write the commands - the developers. So command-help is
    +all auto-loaded and searched from the current command set. The normal,
    +database-tied help system is used for collaborative creation of other help
    +topics such as RP help or game-world aides. Help entries can also be created
    +outside the game in modules given by ``settings.FILE_HELP_ENTRY_MODULES``.
    +
     """
     
    +from dataclasses import dataclass
     from django.conf import settings
     from collections import defaultdict
    -from evennia.utils.utils import fill, dedent
    -from evennia.commands.command import Command
    +from evennia.utils.utils import dedent
     from evennia.help.models import HelpEntry
     from evennia.utils import create, evmore
    +from evennia.utils.ansi import ANSIString
    +from evennia.help.filehelp import FILE_HELP_ENTRIES
     from evennia.utils.eveditor import EvEditor
    -from evennia.utils.utils import string_suggestions, class_from_module
    +from evennia.utils.utils import (
    +    class_from_module,
    +    inherits_from,
    +    format_grid, pad
    +)
    +from evennia.help.utils import help_search_with_index, parse_entry_for_subcategories
     
     COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
    -HELP_MORE = settings.HELP_MORE
    -CMD_IGNORE_PREFIXES = settings.CMD_IGNORE_PREFIXES
    +HELP_MORE_ENABLED = settings.HELP_MORE_ENABLED
    +DEFAULT_HELP_CATEGORY = settings.DEFAULT_HELP_CATEGORY
    +HELP_CLICKABLE_TOPICS = settings.HELP_CLICKABLE_TOPICS
     
     # limit symbol import for API
     __all__ = ("CmdHelp", "CmdSetHelp")
    -_DEFAULT_WIDTH = settings.CLIENT_DEFAULT_WIDTH
    -_SEP = "|C" + "-" * _DEFAULT_WIDTH + "|n"
    +
    +@dataclass
    +class HelpCategory:
    +    """
    +    Mock 'help entry' to search categories with the same code.
    +
    +    """
    +    key: str
    +
    +    @property
    +    def search_index_entry(self):
    +        return {
    +            "key": self.key,
    +            "aliases": "",
    +            "category": self.key,
    +            "tags": "",
    +            "text": "",
    +        }
    +
    +    def __hash__(self):
    +        return hash(id(self))
     
     
     
    [docs]class CmdHelp(COMMAND_DEFAULT_CLASS): """ - View help or a list of topics + Get help. Usage: - help <topic or command> - help list - help all + help + help <topic, command or category> + help <topic>/<subtopic> + help <topic>/<subtopic>/<subsubtopic> ... + + Use the 'help' command alone to see an index of all help topics, organized + by category.eSome big topics may offer additional sub-topics. - This will search for help on commands and other - topics related to the game. """ key = "help" @@ -90,8 +121,13 @@ # Help messages are wrapped in an EvMore call (unless using the webclient # with separate help popups) If you want to avoid this, simply add - # 'HELP_MORE = False' in your settings/conf/settings.py - help_more = HELP_MORE + # 'HELP_MORE_ENABLED = False' in your settings/conf/settings.py + help_more = HELP_MORE_ENABLED + + # colors for the help index + index_type_separator_clr = "|w" + index_category_clr = "|W" + index_topic_clr = "|G" # suggestion cutoff, between 0 and 1 (1 => perfect match) suggestion_cutoff = 0.6 @@ -99,6 +135,12 @@ # number of suggestions (set to 0 to remove suggestions from help) suggestion_maxnum = 5 + # separator between subtopics: + subtopic_separator_char = r"/" + + # should topics disply their help entry when clicked + clickable_topics = HELP_CLICKABLE_TOPICS +
    [docs] def msg_help(self, text): """ messages text to the caller, adding an extra oob argument to indicate @@ -108,7 +150,7 @@ if type(self).help_more: usemore = True - if self.session and self.session.protocol_key in ("websocket", "ajax/comet"): + if self.session and self.session.protocol_key in ("websocket", "ajax/comet",): try: options = self.account.db._saved_webclient_options if options and options["helppopup"]: @@ -122,241 +164,541 @@ self.msg(text=(text, {"type": "help"}))
    -
    [docs] @staticmethod - def format_help_entry(title, help_text, aliases=None, suggested=None): - """ - This visually formats the help entry. +
    [docs] def format_help_entry(self, topic="", help_text="", aliases=None, suggested=None, + subtopics=None, click_topics=True): + """This visually formats the help entry. This method can be overriden to customize the way a help entry is displayed. Args: - title (str): the title of the help entry. - help_text (str): the text of the help entry. - aliases (list of str or None): the list of aliases. - suggested (list of str or None): suggested reading. + title (str, optional): The title of the help entry. + help_text (str, optional): Text of the help entry. + aliases (list, optional): List of help-aliases (displayed in header). + suggested (list, optional): Strings suggested reading (based on title). + subtopics (list, optional): A list of strings - the subcategories available + for this entry. + click_topics (bool, optional): Should help topics be clickable. Default is True. - Returns the formatted string, ready to be sent. + Returns: + help_message (str): Help entry formated for console. """ - string = _SEP + "\n" - if title: - string += "|CHelp for |w%s|n" % title + separator = "|C" + "-" * self.client_width() + "|n" + start = f"{separator}\n" + + title = f"|CHelp for |w{topic}|n" if topic else "|rNo help found|n" + if aliases: - string += " |C(aliases: %s|C)|n" % ("|C,|n ".join("|w%s|n" % ali for ali in aliases)) - if help_text: - string += "\n%s" % dedent(help_text.rstrip()) + aliases = ( + " |C(aliases: {}|C)|n".format("|C,|n ".join(f"|w{ali}|n" for ali in aliases)) + ) + else: + aliases = '' + + help_text = "\n" + dedent(help_text.strip('\n')) if help_text else "" + + if subtopics: + if click_topics: + subtopics = [ + f"|lchelp {topic}/{subtop}|lt|w{topic}/{subtop}|n|le" + for subtop in subtopics + ] + else: + subtopics = [f"|w{topic}/{subtop}|n" for subtop in subtopics] + subtopics = ( + "\n|CSubtopics:|n\n {}".format( + "\n ".join(format_grid(subtopics, width=self.client_width()))) + ) + else: + subtopics = '' + if suggested: - string += "\n\n|CSuggested:|n " - string += "%s" % fill("|C,|n ".join("|w%s|n" % sug for sug in suggested)) - string.strip() - string += "\n" + _SEP - return string
    + if click_topics: + suggested = [f"|lchelp {sug}|lt|w{sug}|n|le" for sug in suggested] + else: + suggested = [f"|w{sug}|n" for sug in suggested] + suggested = ( + "\n|COther topic suggestions:|n\n{}".format( + "\n ".join(format_grid(suggested, width=self.client_width()))) + ) + else: + suggested = '' -
    [docs] @staticmethod - def format_help_list(hdict_cmds, hdict_db): - """ - Output a category-ordered list. The input are the - pre-loaded help files for commands and database-helpfiles - respectively. You can override this method to return a - custom display of the list of commands and topics. - """ - string = "" - if hdict_cmds and any(hdict_cmds.values()): - string += "\n" + _SEP + "\n |CCommand help entries|n\n" + _SEP - for category in sorted(hdict_cmds.keys()): - string += "\n |w%s|n:\n" % (str(category).title()) - string += "|G" + fill("|C, |G".join(sorted(hdict_cmds[category]))) + "|n" - if hdict_db and any(hdict_db.values()): - string += "\n\n" + _SEP + "\n\r |COther help entries|n\n" + _SEP - for category in sorted(hdict_db.keys()): - string += "\n\r |w%s|n:\n" % (str(category).title()) - string += ( - "|G" - + fill(", ".join(sorted([str(topic) for topic in hdict_db[category]]))) - + "|n" - ) - return string
    + end = start -
    [docs] def check_show_help(self, cmd, caller): - """ - Helper method. If this return True, the given cmd - auto-help will be viewable in the help listing. - Override this to easily select what is shown to - the account. Note that only commands available - in the caller's merged cmdset are available. + partorder = (start, title + aliases, help_text, subtopics, suggested, end) + + return "\n".join(part.rstrip() for part in partorder if part)
    + +
    [docs] def format_help_index(self, cmd_help_dict=None, db_help_dict=None, title_lone_category=False, + click_topics=True): + """Output a category-ordered g for displaying the main help, grouped by + category. Args: - cmd (Command): Command class from the merged cmdset - caller (Character, Account or Session): The current caller - executing the help command. + cmd_help_dict (dict): A dict `{"category": [topic, topic, ...]}` for + command-based help. + db_help_dict (dict): A dict `{"category": [topic, topic], ...]}` for + database-based help. + title_lone_category (bool, optional): If a lone category should + be titled with the category name or not. While pointless in a + general index, the title should probably show when explicitly + listing the category itself. + click_topics (bool, optional): If help-topics are clickable or not + (for webclient or telnet clients with MXP support). + Returns: + str: The help index organized into a grid. + + Notes: + The input are the pre-loaded help files for commands and database-helpfiles + respectively. You can override this method to return a custom display of the list of + commands and topics. """ - # return only those with auto_help set and passing the cmd: lock - return cmd.auto_help and cmd.access(caller)
    + def _group_by_category(help_dict): + grid = [] + verbatim_elements = [] -
    [docs] def should_list_cmd(self, cmd, caller): + if len(help_dict) == 1 and not title_lone_category: + # don't list categories if there is only one + for category in help_dict: + # gather and sort the entries from the help dictionary + entries = sorted(set(help_dict.get(category, []))) + + # make the help topics clickable + if click_topics: + entries = [ + f'|lchelp {entry}|lt{entry}|le' for entry in entries + ] + + # add the entries to the grid + grid.extend(entries) + else: + # list the categories + for category in sorted(set(list(help_dict.keys()))): + category_str = f"-- {category.title()} " + grid.append( + ANSIString( + self.index_category_clr + category_str + + "-" * (width - len(category_str)) + + self.index_topic_clr + ) + ) + verbatim_elements.append(len(grid) - 1) + + # gather and sort the entries from the help dictionary + entries = sorted(set(help_dict.get(category, []))) + + # make the help topics clickable + if click_topics: + entries = [ + f'|lchelp {entry}|lt{entry}|le' for entry in entries + ] + + # add the entries to the grid + grid.extend(entries) + + return grid, verbatim_elements + + help_index = "" + width = self.client_width() + grid = [] + verbatim_elements = [] + cmd_grid, db_grid = "", "" + + if any(cmd_help_dict.values()): + # get the command-help entries by-category + sep1 = (self.index_type_separator_clr + + pad("Commands", width=width, fillchar='-') + + self.index_topic_clr) + grid, verbatim_elements = _group_by_category(cmd_help_dict) + gridrows = format_grid(grid, width, sep=" ", verbatim_elements=verbatim_elements) + cmd_grid = ANSIString("\n").join(gridrows) if gridrows else "" + + if any(db_help_dict.values()): + # get db-based help entries by-category + sep2 = (self.index_type_separator_clr + + pad("Game & World", width=width, fillchar='-') + + self.index_topic_clr) + grid, verbatim_elements = _group_by_category(db_help_dict) + gridrows = format_grid(grid, width, sep=" ", verbatim_elements=verbatim_elements) + db_grid = ANSIString("\n").join(gridrows) if gridrows else "" + + # only show the main separators if there are actually both cmd and db-based help + if cmd_grid and db_grid: + help_index = f"{sep1}\n{cmd_grid}\n{sep2}\n{db_grid}" + else: + help_index = f"{cmd_grid}{db_grid}" + + return help_index
    + +
    [docs] def can_read_topic(self, cmd_or_topic, caller): + """ + Helper method. If this return True, the given help topic + be viewable in the help listing. Note that even if this returns False, + the entry will still be visible in the help index unless `should_list_topic` + is also returning False. + + Args: + cmd_or_topic (Command, HelpEntry or FileHelpEntry): The topic/command to test. + caller: the caller checking for access. + + Returns: + bool: If command can be viewed or not. + + Notes: + This uses the 'read' lock. If no 'read' lock is defined, the topic is assumed readable + by all. + + """ + if inherits_from(cmd_or_topic, "evennia.commands.command.Command"): + return cmd_or_topic.auto_help and cmd_or_topic.access(caller, 'read', default=True) + else: + return cmd_or_topic.access(caller, 'read', default=True)
    + +
    [docs] def can_list_topic(self, cmd_or_topic, caller): """ Should the specified command appear in the help table? - This method only checks whether a specified command should - appear in the table of topics/commands. The command can be - used by the caller (see the 'check_show_help' method) and - the command will still be available, for instance, if a - character type 'help name of the command'. However, if - you return False, the specified command will not appear in - the table. This is sometimes useful to "hide" commands in - the table, but still access them through the help system. + This method only checks whether a specified command should appear in the table of + topics/commands. The command can be used by the caller (see the 'should_show_help' method) + and the command will still be available, for instance, if a character type 'help name of the + command'. However, if you return False, the specified command will not appear in the table. + This is sometimes useful to "hide" commands in the table, but still access them through the + help system. Args: - cmd: the command to be tested. - caller: the caller of the help system. + cmd_or_topic (Command, HelpEntry or FileHelpEntry): The topic/command to test. + caller: the caller checking for access. - Return: - True: the command should appear in the table. - False: the command shouldn't appear in the table. + Returns: + bool: If command should be listed or not. + + Notes: + By default, the 'view' lock will be checked, and if no such lock is defined, the 'read' + lock will be used. If neither lock is defined, the help entry is assumed to be + accessible to all. """ - return cmd.access(caller, "view", default=True)
    + has_view = ( + "view:" in cmd_or_topic.locks + if inherits_from(cmd_or_topic, "evennia.commands.command.Command") + else cmd_or_topic.locks.get("view") + ) + + if has_view: + return cmd_or_topic.access(caller, 'view', default=True) + else: + # no explicit 'view' lock - use the 'read' lock + return cmd_or_topic.access(caller, 'read', default=True)
    + +
    [docs] def collect_topics(self, caller, mode='list'): + """ + Collect help topics from all sources (cmd/db/file). + + Args: + caller (Object or Account): The user of the Command. + mode (str): One of 'list' or 'query', where the first means we are collecting to view + the help index and the second because of wanting to search for a specific help + entry/cmd to read. This determines which access should be checked. + + Returns: + tuple: A tuple of three dicts containing the different types of help entries + in the order cmd-help, db-help, file-help: + `({key: cmd,...}, {key: dbentry,...}, {key: fileentry,...}` + + """ + # start with cmd-help + cmdset = self.cmdset + # removing doublets in cmdset, caused by cmdhandler + # having to allow doublet commands to manage exits etc. + cmdset.make_unique(caller) + # retrieve all available commands and database / file-help topics. + # also check the 'cmd:' lock here + cmd_help_topics = [cmd for cmd in cmdset if cmd and cmd.access(caller, 'cmd')] + # get all file-based help entries, checking perms + file_help_topics = { + topic.key.lower().strip(): topic + for topic in FILE_HELP_ENTRIES.all() + } + # get db-based help entries, checking perms + db_help_topics = { + topic.key.lower().strip(): topic + for topic in HelpEntry.objects.all() + } + if mode == 'list': + # check the view lock for all help entries/commands and determine key + cmd_help_topics = { + cmd.auto_help_display_key + if hasattr(cmd, "auto_help_display_key") else cmd.key: cmd + for cmd in cmd_help_topics if self.can_list_topic(cmd, caller)} + db_help_topics = { + key: entry for key, entry in db_help_topics.items() + if self.can_list_topic(entry, caller) + } + file_help_topics = { + key: entry for key, entry in file_help_topics.items() + if self.can_list_topic(entry, caller)} + else: + # query + cmd_help_topics = { + cmd.auto_help_display_key + if hasattr(cmd, "auto_help_display_key") else cmd.key: cmd + for cmd in cmd_help_topics if self.can_read_topic(cmd, caller)} + db_help_topics = { + key: entry for key, entry in db_help_topics.items() + if self.can_read_topic(entry, caller) + } + file_help_topics = { + key: entry for key, entry in file_help_topics.items() + if self.can_read_topic(entry, caller)} + + return cmd_help_topics, db_help_topics, file_help_topics
    + +
    [docs] def parse(self): """ input is a string containing the command or topic to match. + + The allowed syntax is + :: + + help <topic>[/<subtopic>[/<subtopic>[/...]]] + + The database/command query is always for `<topic>`, and any subtopics + is then parsed from there. If a `<topic>` has spaces in it, it is + always matched before assuming the space begins a subtopic. + """ - self.original_args = self.args.strip() - self.args = self.args.strip().lower()
    + # parse the query + + if self.args: + self.subtopics = [part.strip().lower() + for part in self.args.split(self.subtopic_separator_char)] + self.topic = self.subtopics.pop(0) + else: + self.topic = "" + self.subtopics = []
    [docs] def func(self): """ Run the dynamic help entry creator. """ - query, cmdset = self.args, self.cmdset caller = self.caller - - suggestion_cutoff = self.suggestion_cutoff - suggestion_maxnum = self.suggestion_maxnum + query, subtopics, cmdset = self.topic, self.subtopics, self.cmdset + clickable_topics = self.clickable_topics if not query: - query = "all" + # list all available help entries, grouped by category. We want to + # build dictionaries {category: [topic, topic, ...], ...} - # removing doublets in cmdset, caused by cmdhandler - # having to allow doublet commands to manage exits etc. - cmdset.make_unique(caller) + cmd_help_topics, db_help_topics, file_help_topics = \ + self.collect_topics(caller, mode='list') - # retrieve all available commands and database topics - all_cmds = [cmd for cmd in cmdset if self.check_show_help(cmd, caller)] - all_topics = [ - topic for topic in HelpEntry.objects.all() if topic.access(caller, "view", default=True) - ] - all_categories = list( - set( - [cmd.help_category.lower() for cmd in all_cmds] - + [topic.help_category.lower() for topic in all_topics] - ) - ) + # db-topics override file-based ones + file_db_help_topics = {**file_help_topics, **db_help_topics} + + # group by category (cmds are listed separately) + cmd_help_by_category = defaultdict(list) + file_db_help_by_category = defaultdict(list) + for key, cmd in cmd_help_topics.items(): + cmd_help_by_category[cmd.help_category].append(key) + for key, entry in file_db_help_topics.items(): + file_db_help_by_category[entry.help_category].append(key) + + # generate the index and display + output = self.format_help_index(cmd_help_by_category, + file_db_help_by_category, + click_topics=clickable_topics) + self.msg_help(output) - if query in ("list", "all"): - # we want to list all available help entries, grouped by category - hdict_cmd = defaultdict(list) - hdict_topic = defaultdict(list) - # create the dictionaries {category:[topic, topic ...]} required by format_help_list - # Filter commands that should be reached by the help - # system, but not be displayed in the table, or be displayed differently. - for cmd in all_cmds: - if self.should_list_cmd(cmd, caller): - key = ( - cmd.auto_help_display_key - if hasattr(cmd, "auto_help_display_key") - else cmd.key - ) - hdict_cmd[cmd.help_category].append(key) - [hdict_topic[topic.help_category].append(topic.key) for topic in all_topics] - # report back - self.msg_help(self.format_help_list(hdict_cmd, hdict_topic)) return - # Try to access a particular command + # search for a specific entry. We need to check for 'read' access here before # building the + # set of possibilities. + cmd_help_topics, db_help_topics, file_help_topics = \ + self.collect_topics(caller, mode='query') - # build vocabulary of suggestions and rate them by string similarity. - suggestions = None - if suggestion_maxnum > 0: - vocabulary = ( - [cmd.key for cmd in all_cmds if cmd] - + [topic.key for topic in all_topics] - + all_categories - ) - [vocabulary.extend(cmd.aliases) for cmd in all_cmds] - suggestions = [ - sugg - for sugg in string_suggestions( - query, set(vocabulary), cutoff=suggestion_cutoff, maxnum=suggestion_maxnum - ) - if sugg != query - ] - if not suggestions: - suggestions = [ - sugg for sugg in vocabulary if sugg != query and sugg.startswith(query) - ] + # db-help topics takes priority over file-help + file_db_help_topics = {**file_help_topics, **db_help_topics} - # try an exact command auto-help match - match = [cmd for cmd in all_cmds if cmd == query] + # commands take priority over the other types + all_topics = {**file_db_help_topics, **cmd_help_topics} + + # get all categories + all_categories = list(set( + HelpCategory(topic.help_category) for topic in all_topics.values())) + + # all available help options - will be searched in order. We also check # the + # read-permission here. + entries = list(all_topics.values()) + all_categories + + # lunr search fields/boosts + match, suggestions = self.do_search(query, entries) if not match: - # try an inexact match with prefixes stripped from query and cmds - _query = query[1:] if query[0] in CMD_IGNORE_PREFIXES else query + # no topic matches found. Only give suggestions. + help_text = f"There is no help topic matching '{query}'." - match = [ - cmd - for cmd in all_cmds - for m in cmd._matchset - if m == _query or m[0] in CMD_IGNORE_PREFIXES and m[1:] == _query - ] + if not suggestions: + # we don't even have a good suggestion. Run a second search, + # doing a full-text search in the actual texts of the help + # entries - if len(match) == 1: - cmd = match[0] - key = cmd.auto_help_display_key if hasattr(cmd, "auto_help_display_key") else cmd.key - formatted = self.format_help_entry( - key, cmd.get_help(caller, cmdset), aliases=cmd.aliases, suggested=suggestions, - ) - self.msg_help(formatted) - return + search_fields = [ + {"field_name": "text", "boost": 1}, + ] - # try an exact database help entry match - match = list(HelpEntry.objects.find_topicmatch(query, exact=True)) - if len(match) == 1: - formatted = self.format_help_entry( - match[0].key, - match[0].entrytext, - aliases=match[0].aliases.all(), + for match_query in [query, f"{query}*"]: + _, suggestions = help_search_with_index( + match_query, entries, + suggestion_maxnum=self.suggestion_maxnum, + fields=search_fields + ) + + if suggestions: + help_text += ( + "\n... But matches where found within the help " + "texts of the suggestions below.") + break + + output = self.format_help_entry( + topic=None, # this will give a no-match style title + help_text=help_text, suggested=suggestions, + click_topics=clickable_topics ) - self.msg_help(formatted) + + self.msg_help(output) return - # try to see if a category name was entered - if query in all_categories: - self.msg_help( - self.format_help_list( - { - query: [ - cmd.auto_help_display_key - if hasattr(cmd, "auto_help_display_key") - else cmd.key - for cmd in all_cmds - if cmd.help_category == query - ] - }, - {query: [topic.key for topic in all_topics if topic.help_category == query]}, - ) - ) + if isinstance(match, HelpCategory): + # no subtopics for categories - these are just lists of topics + category = match.key + category_lower = category.lower() + cmds_in_category = [key for key, cmd in cmd_help_topics.items() + if category_lower == cmd.help_category] + topics_in_category = [key for key, topic in file_db_help_topics.items() + if category_lower == topic.help_category] + output = self.format_help_index({category: cmds_in_category}, + {category: topics_in_category}, + title_lone_category=True, + click_topics=clickable_topics) + self.msg_help(output) return - # no exact matches found. Just give suggestions. - self.msg( - self.format_help_entry( - "", f"No help entry found for '{query}'", None, suggested=suggestions - ), - options={"type": "help"}, - )
    + if inherits_from(match, "evennia.commands.command.Command"): + # a command match + topic = match.key + help_text = match.get_help(caller, cmdset) + aliases = match.aliases + suggested = suggestions[1:] + else: + # a database (or file-help) match + topic = match.key + help_text = match.entrytext + aliases = match.aliases if isinstance(match.aliases, list) else match.aliases.all() + suggested = suggestions[1:] + + # parse for subtopics. The subtopic_map is a dict with the current topic/subtopic + # text is stored under a `None` key and all other keys are subtopic titles pointing + # to nested dicts. + + subtopic_map = parse_entry_for_subcategories(help_text) + help_text = subtopic_map[None] + subtopic_index = [subtopic for subtopic in subtopic_map if subtopic is not None] + + if subtopics: + # if we asked for subtopics, parse the found topic_text to see if any match. + # the subtopics is a list describing the path through the subtopic_map. + + for subtopic_query in subtopics: + + if subtopic_query not in subtopic_map: + # exact match failed. Try startswith-match + fuzzy_match = False + for key in subtopic_map: + if key and key.startswith(subtopic_query): + subtopic_query = key + fuzzy_match = True + break + + if not fuzzy_match: + # startswith failed - try an 'in' match + for key in subtopic_map: + if key and subtopic_query in key: + subtopic_query = key + fuzzy_match = True + break + + if not fuzzy_match: + # no match found - give up + checked_topic = topic + f"/{subtopic_query}" + output = self.format_help_entry( + topic=topic, + help_text=f"No help entry found for '{checked_topic}'", + subtopics=subtopic_index, + click_topics=clickable_topics + ) + self.msg_help(output) + return + + # if we get here we have an exact or fuzzy match + + subtopic_map = subtopic_map.pop(subtopic_query) + subtopic_index = [subtopic for subtopic in subtopic_map if subtopic is not None] + # keep stepping down into the tree, append path to show position + topic = topic + f"/{subtopic_query}" + + # we reached the bottom of the topic tree + help_text = subtopic_map[None] + + output = self.format_help_entry( + topic=topic, + help_text=help_text, + aliases=aliases if not subtopics else None, + subtopics=subtopic_index, + suggested=suggested, + click_topics=clickable_topics + ) + + self.msg_help(output) def _loadhelp(caller): @@ -379,7 +721,7 @@ del caller.db._editing_help -
    [docs]class CmdSetHelp(COMMAND_DEFAULT_CLASS): +
    [docs]class CmdSetHelp(CmdHelp): """ Edit the help database. @@ -394,22 +736,64 @@ delete - remove help topic. Examples: - sethelp throw = This throws something at ... + sethelp lore = In the beginning was ... sethelp/append pickpocketing,Thievery = This steals ... sethelp/replace pickpocketing, ,attr(is_thief) = This steals ... sethelp/edit thievery - This command manipulates the help database. A help entry can be created, - appended/merged to and deleted. If you don't assign a category, the - "General" category will be used. If no lockstring is specified, default - is to let everyone read the help file. + If not assigning a category, the `settings.DEFAULT_HELP_CATEGORY` category + will be used. If no lockstring is specified, everyone will be able to read + the help entry. Sub-topics are embedded in the help text. + + Note that this cannot modify command-help entries - these are modified + in-code, outside the game. + + # SUBTOPICS + + ## Adding subtopics + + Subtopics helps to break up a long help entry into sub-sections. Users can + access subtopics with |whelp topic/subtopic/...|n Subtopics are created and + stored together with the main topic. + + To start adding subtopics, add the text '# SUBTOPICS' on a new line at the + end of your help text. After this you can now add any number of subtopics, + each starting with '## <subtopic-name>' on a line, followed by the + help-text of that subtopic. + Use '### <subsub-name>' to add a sub-subtopic and so on. Max depth is 5. A + subtopic's title is case-insensitive and can consist of multiple words - + the user will be able to enter a partial match to access it. + + For example: + + | Main help text for <topic> + | + | # SUBTOPICS + | + | ## about + | + | Text for the '<topic>/about' subtopic' + | + | ### more about-info + | + | Text for the '<topic>/about/more about-info sub-subtopic + | + | ## extra + | + | Text for the '<topic>/extra' subtopic """ key = "sethelp" + aliases = [] switch_options = ("edit", "replace", "append", "extend", "delete") locks = "cmd:perm(Helper)" help_category = "Building" + arg_regex = None + +
    [docs] def parse(self): + """We want to use the default parser rather than the CmdHelp.parse""" + return COMMAND_DEFAULT_CLASS.parse(self)
    [docs] def func(self): """Implement the function""" @@ -429,23 +813,71 @@ self.msg("You have to define a topic!") return topicstrlist = topicstr.split(";") - topicstr, aliases = (topicstrlist[0], topicstrlist[1:] if len(topicstr) > 1 else []) + topicstr, aliases = ( + topicstrlist[0], + topicstrlist[1:] if len(topicstr) > 1 else [], + ) aliastxt = ("(aliases: %s)" % ", ".join(aliases)) if aliases else "" old_entry = None # check if we have an old entry with the same name - try: - for querystr in topicstrlist: - old_entry = HelpEntry.objects.find_topicmatch(querystr) # also search by alias - if old_entry: - old_entry = list(old_entry)[0] + + cmd_help_topics, db_help_topics, file_help_topics = \ + self.collect_topics(self.caller, mode='query') + # db-help topics takes priority over file-help + file_db_help_topics = {**file_help_topics, **db_help_topics} + # commands take priority over the other types + all_topics = {**file_db_help_topics, **cmd_help_topics} + # get all categories + all_categories = list(set( + HelpCategory(topic.help_category) for topic in all_topics.values())) + # all available help options - will be searched in order. We also check # the + # read-permission here. + entries = list(all_topics.values()) + all_categories + + # default setup + category = lhslist[1] if nlist > 1 else DEFAULT_HELP_CATEGORY + lockstring = ",".join(lhslist[2:]) if nlist > 2 else "read:all()" + + # search for existing entries of this or other types + old_entry = None + for querystr in topicstrlist: + match, _ = self.do_search(querystr, entries) + if match: + warning = None + if isinstance(match, HelpCategory): + warning = (f"'{querystr}' matches (or partially matches) the name of " + "help-category '{match.key}'. If you continue, your help entry will " + "take precedence and the category (or part of its name) *may* not " + "be usable for grouping help entries anymore.") + elif inherits_from(match, "evennia.commands.command.Command"): + warning = (f"'{querystr}' matches (or partially matches) the key/alias of " + "Command '{match.key}'. Command-help take precedence over other " + "help entries so your help *may* be impossible to reach for those " + "with access to that command.") + elif inherits_from(match, "evennia.help.filehelp.FileHelpEntry"): + warning = (f"'{querystr}' matches (or partially matches) the name/alias of the " + "file-based help file '{match.key}'. File-help entries cannot be " + "modified from in-game (they are files on-disk). If you continue, " + "your help entry *may* shadow the file-based one's name partly or " + "completely.") + if warning: + # show a warning for a clashing help-entry type. Even if user accepts this + # we don't break here since we may need to show warnings for other inputs. + # We don't count this as an old-entry hit because we can't edit these + # types of entries. + self.msg(f"|rWarning:\n|r{warning}|n") + repl = yield("|wDo you still want to continue? Y/[N]?|n") + if repl.lower() not in ('y', 'yes'): + self.msg("Aborted.") + return + else: + # a db-based help entry - this is OK + old_entry = match + category = lhslist[1] if nlist > 1 else old_entry.help_category + lockstring = ",".join(lhslist[2:]) if nlist > 2 else old_entry.locks.get() break - category = lhslist[1] if nlist > 1 else old_entry.help_category - lockstring = ",".join(lhslist[2:]) if nlist > 2 else old_entry.locks.get() - except Exception: - old_entry = None - category = lhslist[1] if nlist > 1 else "General" - lockstring = ",".join(lhslist[2:]) if nlist > 2 else "view:all()" + category = category.lower() if "edit" in switches: @@ -458,7 +890,7 @@ helpentry = old_entry else: helpentry = create.create_help_entry( - topicstr, self.rhs, category=category, locks=lockstring, aliases=aliases + topicstr, self.rhs, category=category, locks=lockstring, aliases=aliases, ) self.caller.db._editing_help = helpentry @@ -487,6 +919,7 @@ old_entry.aliases.add(aliases) self.msg("Entry updated:\n%s%s" % (old_entry.entrytext, aliastxt)) return + if "delete" in switches or "del" in switches: # delete the help entry if not old_entry: @@ -513,8 +946,8 @@ self.msg("Overwrote the old topic '%s'%s." % (topicstr, aliastxt)) else: self.msg( - "Topic '%s'%s already exists. Use /replace to overwrite " - "or /append or /merge to add text to it." % (topicstr, aliastxt) + f"Topic '{topicstr}'{aliastxt} already exists. Use /edit to open in editor, or " + "/replace, /append and /merge to modify it directly." ) else: # no old entry. Create a new one. @@ -522,7 +955,7 @@ topicstr, self.rhs, category=category, locks=lockstring, aliases=aliases ) if new_entry: - self.msg("Topic '%s'%s was successfully created." % (topicstr, aliastxt)) + self.msg(f"Topic '{topicstr}'{aliastxt} was successfully created.") if "edit" in switches: # open the line editor to edit the helptext self.caller.db._editing_help = new_entry @@ -537,7 +970,7 @@ return else: self.msg( - "Error when creating topic '%s'%s! Contact an admin." % (topicstr, aliastxt) + f"Error when creating topic '{topicstr}'{aliastxt}! Contact an admin." )
    @@ -576,7 +1009,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/commands/default/muxcommand.html b/docs/0.9.5/_modules/evennia/commands/default/muxcommand.html index 268cf31fd6..c5b8472be5 100644 --- a/docs/0.9.5/_modules/evennia/commands/default/muxcommand.html +++ b/docs/0.9.5/_modules/evennia/commands/default/muxcommand.html @@ -216,8 +216,8 @@ rhs = rhs.strip() if rhs is not None else None lhs = lhs.strip() # Further split left/right sides by comma delimiter - lhslist = [arg.strip() for arg in lhs.split(",")] if lhs is not None else "" - rhslist = [arg.strip() for arg in rhs.split(",")] if rhs is not None else "" + lhslist = [arg.strip() for arg in lhs.split(",")] if lhs is not None else [] + rhslist = [arg.strip() for arg in rhs.split(",")] if rhs is not None else [] # save to object properties: self.raw = raw self.switches = switches @@ -346,7 +346,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/commands/default/syscommands.html b/docs/0.9.5/_modules/evennia/commands/default/syscommands.html index cc3167d62e..9126cbd6ca 100644 --- a/docs/0.9.5/_modules/evennia/commands/default/syscommands.html +++ b/docs/0.9.5/_modules/evennia/commands/default/syscommands.html @@ -68,7 +68,6 @@ from evennia.commands.cmdhandler import CMD_NOINPUT from evennia.commands.cmdhandler import CMD_NOMATCH from evennia.commands.cmdhandler import CMD_MULTIMATCH -from evennia.commands.cmdhandler import CMD_CHANNEL from evennia.utils import utils from django.conf import settings @@ -145,53 +144,6 @@ matches = self.matches # at_search_result will itself msg the multimatch options to the caller. at_search_result([match[2] for match in matches], self.caller, query=matches[0][0]) - - -# Command called when the command given at the command line -# was identified as a channel name, like there existing a -# channel named 'ooc' and the user wrote -# > ooc Hello! - - -
    [docs]class SystemSendToChannel(COMMAND_DEFAULT_CLASS): - """ - This is a special command that the cmdhandler calls - when it detects that the command given matches - an existing Channel object key (or alias). - """ - - key = CMD_CHANNEL - locks = "cmd:all()" - -
    [docs] def parse(self): - channelname, msg = self.args.split(":", 1) - self.args = channelname.strip(), msg.strip()
    - -
    [docs] def func(self): - """ - Create a new message and send it to channel, using - the already formatted input. - """ - caller = self.caller - channelkey, msg = self.args - if not msg: - caller.msg("Say what?") - return - channel = ChannelDB.objects.get_channel(channelkey) - if not channel: - caller.msg("Channel '%s' not found." % channelkey) - return - if not channel.has_connection(caller): - string = "You are not connected to channel '%s'." - caller.msg(string % channelkey) - return - if not channel.access(caller, "send"): - string = "You are not permitted to send to channel '%s'." - caller.msg(string % channelkey) - return - msg = "[%s] %s: %s" % (channel.key, caller.name, msg) - msgobj = create.create_message(caller, msg, channels=[channel]) - channel.msg(msgobj)
    @@ -229,7 +181,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/commands/default/system.html b/docs/0.9.5/_modules/evennia/commands/default/system.html index 877023c225..df7a4e7aa5 100644 --- a/docs/0.9.5/_modules/evennia/commands/default/system.html +++ b/docs/0.9.5/_modules/evennia/commands/default/system.html @@ -49,7 +49,6 @@ import code import traceback import os -import io import datetime import sys import django @@ -66,9 +65,12 @@ from evennia.utils.eveditor import EvEditor from evennia.utils.evtable import EvTable from evennia.utils.evmore import EvMore -from evennia.utils.utils import crop, class_from_module +from evennia.utils.evmenu import ask_yes_no +from evennia.utils.utils import crop, class_from_module, iter_to_str +from evennia.scripts.taskhandler import TaskHandlerTask COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS) +_TASK_HANDLER = None # delayed imports _RESOURCE = None @@ -86,6 +88,7 @@ "CmdAbout", "CmdTime", "CmdServerLoad", + "CmdTasks", ) @@ -434,7 +437,9 @@ if noecho: prompt = "..." if console.push(line) else main_prompt else: - prompt = line if console.push(line) else f"{line}\n{main_prompt}" + if line: + self.caller.msg(f">>> {line}") + prompt = line if console.push(line) else main_prompt except SystemExit: break self.msg("|gClosing the Python console.|n") @@ -475,7 +480,6 @@ "|wintval|n", "|wnext|n", "|wrept|n", - "|wdb", "|wtypeclass|n", "|wdesc|n", align="r", @@ -487,9 +491,10 @@ nextrep = script.time_until_next_repeat() if nextrep is None: - nextrep = "PAUSED" if script.db._paused_time else "--" + nextrep = script.db._paused_time + nextrep = f"PAUSED {int(nextrep)}s" if nextrep else "--" else: - nextrep = "%ss" % nextrep + nextrep = f"{nextrep}s" maxrepeat = script.repeats remaining = script.remaining_repeats() or 0 @@ -499,7 +504,7 @@ rept = "-/-" table.add_row( - script.id, + f"#{script.id}", f"{script.obj.key}({script.obj.dbref})" if (hasattr(script, "obj") and script.obj) else "<Global>", @@ -507,7 +512,6 @@ script.interval if script.interval > 0 else "--", nextrep, rept, - "*" if script.persistent else "-", script.typeclass_path.rsplit(".", 1)[-1], crop(script.desc, width=20), ) @@ -517,16 +521,19 @@
    [docs]class CmdScripts(COMMAND_DEFAULT_CLASS): """ - list and manage all running scripts + List and manage all running scripts. Allows for creating new global + scripts. Usage: - scripts[/switches] [#dbref, key, script.path or <obj>] + script[/switches] [#dbref, key, script.path or <obj>] Switches: - start - start a script (must supply a script path) - stop - stops an existing script - kill - kills a script - without running its cleanup hooks - validate - run a validation on the script(s) + create - create a new global script of given typeclass path. This will + auto-start the script's timer if it has one. + start - start/unpause an existing script's timer. + stop - stops an existing script's timer + pause - pause a script's timer + delete - deletes script. This will also stop the timer as needed If no switches are given, this command just views all active scripts. The argument can be either an object, at which point it @@ -534,83 +541,100 @@ or #dbref. For using the /stop switch, a unique script #dbref is required since whole classes of scripts often have the same name. - Use script for managing commands on objects. + Use the `script` build-level command for managing scripts attached to + objects. + """ key = "scripts" - aliases = ["globalscript", "listscripts"] - switch_options = ("start", "stop", "kill", "validate") + aliases = ["scripts"] + switch_options = ("create", "start", "stop", "pause", "delete") locks = "cmd:perm(listscripts) or perm(Admin)" help_category = "System" excluded_typeclass_paths = ["evennia.prototypes.prototypes.DbPrototype"] + switch_mapping = { + "create": "|gCreated|n", + "start": "|gStarted|n", + "stop": "|RStopped|n", + "pause": "|Paused|n", + "delete": "|rDeleted|n" + } + + def _search_script(self, args): + # test first if this is a script match + scripts = ScriptDB.objects.get_all_scripts(key=args) + if scripts: + return scripts + # try typeclass path + scripts = ScriptDB.objects.filter(db_typeclass_path__iendswith=args) + if scripts: + return scripts + # try to find an object instead. + objects = ObjectDB.objects.object_search(args) + if objects: + scripts = ScriptDB.objects.filter(db_obj__in=objects) + return scripts +
    [docs] def func(self): """implement method""" caller = self.caller args = self.args - if args: - if "start" in self.switches: - # global script-start mode - new_script = create.create_script(args) - if new_script: - caller.msg("Global script %s was started successfully." % args) - else: - caller.msg("Global script %s could not start correctly. See logs." % args) + if "create" in self.switches: + # global script-start mode + verb = self.switch_mapping['create'] + if not args: + caller.msg("Usage script/create <key or typeclass>") return - - # test first if this is a script match - scripts = ScriptDB.objects.get_all_scripts(key=args) - if not scripts: - # try to find an object instead. - objects = ObjectDB.objects.object_search(args) - if objects: - scripts = [] - for obj in objects: - # get all scripts on the object(s) - scripts.extend(ScriptDB.objects.get_all_scripts_on_obj(obj)) - else: - # we want all scripts. - scripts = ScriptDB.objects.get_all_scripts() - if not scripts: - caller.msg("No scripts are running.") - return - # filter any found scripts by tag category. - scripts = scripts.exclude(db_typeclass_path__in=self.excluded_typeclass_paths) - - if not scripts: - string = "No scripts found with a key '%s', or on an object named '%s'." % (args, args) - caller.msg(string) + new_script = create.create_script(args) + if new_script: + caller.msg(f"Global Script {verb} - {new_script.key} ({new_script.typeclass_path})") + ScriptEvMore(caller, [new_script], session=self.session) + else: + caller.msg(f"Global Script |rNOT|n {verb} |r(see log)|n - arguments: {args}") return - if self.switches and self.switches[0] in ("stop", "del", "delete", "kill"): - # we want to delete something - if len(scripts) == 1: - # we have a unique match! - if "kill" in self.switches: - string = "Killing script '%s'" % scripts[0].key - scripts[0].stop(kill=True) - else: - string = "Stopping script '%s'." % scripts[0].key - scripts[0].stop() - # import pdb # DEBUG - # pdb.set_trace() # DEBUG - ScriptDB.objects.validate() # just to be sure all is synced - caller.msg(string) - else: - # multiple matches. - ScriptEvMore(caller, scripts, session=self.session) - caller.msg("Multiple script matches. Please refine your search") - elif self.switches and self.switches[0] in ("validate", "valid", "val"): - # run validation on all found scripts - nr_started, nr_stopped = ScriptDB.objects.validate(scripts=scripts) - string = "Validated %s scripts. " % ScriptDB.objects.all().count() - string += "Started %s and stopped %s scripts." % (nr_started, nr_stopped) - caller.msg(string) + # all other switches require existing scripts + if args: + scripts = self._search_script(args) + if not scripts: + caller.msg(f"No scripts found matching '{args}'.") + return else: - # No stopping or validation. We just want to view things. + scripts = ScriptDB.objects.all() + if not scripts: + caller.msg("No scripts found.") + return + + if args and self.switches: + # global script-modifying mode + if scripts.count() > 1: + caller.msg("Multiple script matches. Please refine your search.") + return + script = scripts[0] + script_key = script.key + script_typeclass_path = script.typeclass_path + for switch in self.switches: + verb = self.switch_mapping[switch] + msgs = [] + try: + getattr(script, switch)() + except Exception: + logger.log_trace() + msgs.append(f"Global Script |rNOT|n {verb} |r(see log)|n - " + f"{script_key} ({script_typeclass_path})|n") + else: + msgs.append(f"Global Script {verb} - " + f"{script_key} ({script_typeclass_path})") + caller.msg("\n".join(msgs)) + if "delete" not in self.switches: + ScriptEvMore(caller, [script], session=self.session) + return + else: + # simply show the found scripts ScriptEvMore(caller, scripts.order_by("id"), session=self.session)
    @@ -949,10 +973,14 @@ |wTwisted|n: {twisted} |wDjango|n: {django} - |wLicence|n https://opensource.org/licenses/BSD-3-Clause - |wWeb|n http://www.evennia.com + |wHomepage|n https://evennia.com + |wCode|n https://github.com/evennia/evennia + |wDemo|n https://demo.evennia.com + |wGame listing|n https://games.evennia.com |wIrc|n #evennia on irc.freenode.net:6667 - |wForum|n http://www.evennia.com/discussions + |wDiscord|n https://discord.gg/SVCkd4cY3q + |wForum|n https://github.com/evennia/evennia/discussions + |wLicence|n https://opensource.org/licenses/BSD-3-Clause |wMaintainer|n (2010-) Griatch (griatch AT gmail DOT com) |wMaintainer|n (2006-10) Greg Taylor @@ -995,7 +1023,7 @@ "|wIn-Game time", "|wReal time x %g" % gametime.TIMEFACTOR, align="l", - width=77, + width=78, border_top=0, ) epochtxt = "Epoch (%s)" % ("from settings" if settings.TIME_GAME_EPOCH else "server start") @@ -1219,6 +1247,227 @@ "*" if sub[5] else "-", ) self.caller.msg("|wActive tickers|n:\n" + str(table)) + + +
    [docs]class CmdTasks(COMMAND_DEFAULT_CLASS): + """ + Display or terminate active tasks (delays). + + Usage: + tasks[/switch] [task_id or function_name] + + Switches: + pause - Pause the callback of a task. + unpause - Process all callbacks made since pause() was called. + do_task - Execute the task (call its callback). + call - Call the callback of this task. + remove - Remove a task without executing it. + cancel - Stop a task from automatically executing. + + Notes: + A task is a single use method of delaying the call of a function. Calls are created + in code, using `evennia.utils.delay`. + See |luhttps://www.evennia.com/docs/latest/Command-Duration.html|ltthe docs|le for help. + + By default, tasks that are canceled and never called are cleaned up after one minute. + + Examples: + - `tasks/cancel move_callback` - Cancels all movement delays from the slow_exit contrib. + In this example slow exits creates it's tasks with + `utils.delay(move_delay, move_callback)` + - `tasks/cancel 2` - Cancel task id 2. + + """ + + key = "tasks" + aliases = ["delays", "task"] + switch_options = ("pause", "unpause", "do_task", "call", "remove", "cancel") + locks = "perm(Developer)" + help_category = "System" + +
    [docs] @staticmethod + def coll_date_func(task): + """Replace regex characters in date string and collect deferred function name.""" + t_comp_date = str(task[0]).replace('-', '/') + t_func_name = str(task[1]).split(' ') + t_func_mem_ref = t_func_name[3] if len(t_func_name) >= 4 else None + return t_comp_date, t_func_mem_ref
    + +
    [docs] def do_task_action(self, *args, **kwargs): + """ + Process the action of a tasks command. + + This exists to gain support with yes or no function from EvMenu. + """ + task_id = self.task_id + + # get a reference of the global task handler + global _TASK_HANDLER + if _TASK_HANDLER is None: + from evennia.scripts.taskhandler import TASK_HANDLER as _TASK_HANDLER + + # verify manipulating the correct task + task_args = _TASK_HANDLER.tasks.get(task_id, False) + if not task_args: # check if the task is still active + self.msg('Task completed while waiting for input.') + return + else: + # make certain a task with matching IDs has not been created + t_comp_date, t_func_mem_ref = self.coll_date_func(task_args) + if self.t_comp_date != t_comp_date or self.t_func_mem_ref != t_func_mem_ref: + self.msg('Task completed while waiting for input.') + return + + # Do the action requested by command caller + action_return = self.task_action() + self.msg(f'{self.action_request} request completed.') + self.msg(f'The task function {self.action_request} returned: {action_return}')
    + +
    [docs] def func(self): + # get a reference of the global task handler + global _TASK_HANDLER + if _TASK_HANDLER is None: + from evennia.scripts.taskhandler import TASK_HANDLER as _TASK_HANDLER + # handle no tasks active. + if not _TASK_HANDLER.tasks: + self.msg('There are no active tasks.') + if self.switches or self.args: + self.msg('Likely the task has completed and been removed.') + return + + # handle caller's request to manipulate a task(s) + if self.switches and self.lhs: + + # find if the argument is a task id or function name + action_request = self.switches[0] + try: + arg_is_id = int(self.lhslist[0]) + except ValueError: + arg_is_id = False + + # if the argument is a task id, proccess the action on a single task + if arg_is_id: + + err_arg_msg = 'Switch and task ID are required when manipulating a task.' + task_comp_msg = 'Task completed while processing request.' + + # handle missing arguments or switches + if not self.switches and self.lhs: + self.msg(err_arg_msg) + return + + # create a handle for the task + task_id = arg_is_id + task = TaskHandlerTask(task_id) + + # handle task no longer existing + if not task.exists(): + self.msg(f'Task {task_id} does not exist.') + return + + # get a reference of the function caller requested + switch_action = getattr(task, action_request, False) + if not switch_action: + self.msg(f'{self.switches[0]}, is not an acceptable task action or ' \ + f'{task_comp_msg.lower()}') + + # verify manipulating the correct task + if task_id in _TASK_HANDLER.tasks: + task_args = _TASK_HANDLER.tasks.get(task_id, False) + if not task_args: # check if the task is still active + self.msg(task_comp_msg) + return + else: + t_comp_date, t_func_mem_ref = self.coll_date_func(task_args) + t_func_name = str(task_args[1]).split(' ') + t_func_name = t_func_name[1] if len(t_func_name) >= 2 else None + + if task.exists(): # make certain the task has not been called yet. + prompt = (f'{action_request.capitalize()} task {task_id} with completion date ' + f'{t_comp_date} ({t_func_name}) {{options}}?') + no_msg = f'No {action_request} processed.' + # record variables for use in do_task_action method + self.task_id = task_id + self.t_comp_date = t_comp_date + self.t_func_mem_ref = t_func_mem_ref + self.task_action = switch_action + self.action_request = action_request + ask_yes_no(self.caller, + prompt=prompt, + yes_action=self.do_task_action, + no_action=no_msg, + default="Y", + allow_abort=True) + return True + else: + self.msg(task_comp_msg) + return + + # the argument is not a task id, process the action on all task deferring the function + # specified as an argument + else: + + name_match_found = False + arg_func_name = self.lhslist[0].lower() + + # repack tasks into a new dictionary + current_tasks = {} + for task_id, task_args in _TASK_HANDLER.tasks.items(): + current_tasks.update({task_id: task_args}) + + # call requested action on all tasks with the function name + for task_id, task_args in current_tasks.items(): + t_func_name = str(task_args[1]).split(' ') + t_func_name = t_func_name[1] if len(t_func_name) >= 2 else None + # skip this task if it is not for the function desired + if arg_func_name != t_func_name: + continue + name_match_found = True + task = TaskHandlerTask(task_id) + switch_action = getattr(task, action_request, False) + if switch_action: + action_return = switch_action() + self.msg(f'Task action {action_request} completed on task ID {task_id}.') + self.msg(f'The task function {action_request} returned: {action_return}') + + # provide a message if not tasks of the function name was found + if not name_match_found: + self.msg(f'No tasks deferring function name {arg_func_name} found.') + return + return True + + # check if an maleformed request was created + elif self.switches or self.lhs: + self.msg('Task command misformed.') + self.msg('Proper format tasks[/switch] [function name or task id]') + return + + # No task manupilation requested, build a table of tasks and display it + # get the width of screen in characters + width = self.client_width() + # create table header and list to hold tasks data and actions + tasks_header = ('Task ID', 'Completion Date', 'Function', 'Arguments', 'KWARGS', + 'persistent') + # empty list of lists, the size of the header + tasks_list = [list() for i in range(len(tasks_header))] + for task_id, task in _TASK_HANDLER.tasks.items(): + # collect data from the task + t_comp_date, t_func_mem_ref = self.coll_date_func(task) + t_func_name = str(task[1]).split(' ') + t_func_name = t_func_name[1] if len(t_func_name) >= 2 else None + t_args = str(task[2]) + t_kwargs = str(task[3]) + t_pers = str(task[4]) + # add task data to the tasks list + task_data = (task_id, t_comp_date, t_func_name, t_args, t_kwargs, t_pers) + for i in range(len(tasks_header)): + tasks_list[i].append(task_data[i]) + # create and display the table + tasks_table = EvTable(*tasks_header, table=tasks_list, maxwidth=width, border='cells', + align='center') + actions = (f'/{switch}' for switch in self.switch_options) + helptxt = f"\nActions: {iter_to_str(actions)}" + self.msg(str(tasks_table) + helptxt)
    @@ -1256,7 +1505,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/commands/default/tests.html b/docs/0.9.5/_modules/evennia/commands/default/tests.html index 1be2d42e36..1f225bc793 100644 --- a/docs/0.9.5/_modules/evennia/commands/default/tests.html +++ b/docs/0.9.5/_modules/evennia/commands/default/tests.html @@ -57,14 +57,16 @@ import datetime from anything import Anything +from parameterized import parameterized from django.conf import settings +from twisted.internet import task from unittest.mock import patch, Mock, MagicMock from evennia import DefaultRoom, DefaultExit, ObjectDB from evennia.commands.default.cmdset_character import CharacterCmdSet from evennia.utils.test_resources import EvenniaTest from evennia.commands.default import ( - help, + help as help_module, general, system, admin, @@ -75,7 +77,6 @@ unloggedin, syscommands, ) -from evennia.commands.cmdparser import build_matches from evennia.commands.default.muxcommand import MuxCommand from evennia.commands.command import Command, InterruptCommand from evennia.commands import cmdparser @@ -89,24 +90,50 @@ # set up signal here since we are not starting the server -_RE = re.compile(r"^\+|-+\+|\+-+|--+|\|(?:\s|$)", re.MULTILINE) +_RE_STRIP_EVMENU = re.compile(r"^\+|-+\+|\+-+|--+|\|(?:\s|$)", re.MULTILINE) # ------------------------------------------------------------ # Command testing # ------------------------------------------------------------ -
    [docs]@patch("evennia.server.portal.portal.LoopingCall", new=MagicMock()) class CommandTest(EvenniaTest): """ - Tests a command + Tests a Command by running it and comparing what messages it sends with + expected values. This tests without actually spinning up the cmdhandler + for every test, which is more controlled. + + Example: + :: + + from commands.echo import CmdEcho + + class MyCommandTest(CommandTest): + + def test_echo(self): + ''' + Test that the echo command really returns + what you pass into it. + ''' + self.call(MyCommand(), "hello world!", + "You hear your echo: 'Hello world!'") + """ + # formatting for .call's error message + _ERROR_FORMAT = """ +=========================== Wanted message =================================== +{expected_msg} +=========================== Returned message ================================= +{returned_msg} +============================================================================== +""".rstrip() +
    [docs] def call( self, cmdobj, - args, + input_args, msg=None, cmdset=None, noansi=True, @@ -118,54 +145,140 @@ raw_string=None, ): """ - Test a command by assigning all the needed - properties to cmdobj and running - cmdobj.at_pre_cmd() - cmdobj.parse() - cmdobj.func() - cmdobj.at_post_cmd() - The msgreturn value is compared to eventual - output sent to caller.msg in the game + Test a command by assigning all the needed properties to a cmdobj and + running the sequence. The resulting `.msg` calls will be mocked and + the text= calls to them compared to a expected output. + + Args: + cmdobj (Command): The command object to use. + input_args (str): This should be the full input the Command should + see, such as 'look here'. This will become `.args` for the Command + instance to parse. + msg (str or dict, optional): This is the expected return value(s) + returned through `caller.msg(text=...)` calls in the command. If a string, the + receiver is controlled with the `receiver` kwarg (defaults to `caller`). + If this is a `dict`, it is a mapping + `{receiver1: "expected1", receiver2: "expected2",...}` and `receiver` is + ignored. The message(s) are compared with the actual messages returned + to the receiver(s) as the Command runs. Each check uses `.startswith`, + so you can choose to only include the first part of the + returned message if that's enough to verify a correct result. EvMenu + decorations (like borders) are stripped and should not be included. This + should also not include color tags unless `noansi=False`. + If the command returns texts in multiple separate `.msg`- + calls to a receiver, separate these with `|` if `noansi=True` + (default) and `||` if `noansi=False`. If no `msg` is given (`None`), + then no automatic comparison will be done. + cmdset (str, optional): If given, make `.cmdset` available on the Command + instance as it runs. While `.cmdset` is normally available on the + Command instance by default, this is usually only used by + commands that explicitly operates/displays cmdsets, like + `examine`. + noansi (str, optional): By default the color tags of the `msg` is + ignored, this makes them significant. If unset, `msg` must contain + the same color tags as the actual return message. + caller (Object or Account, optional): By default `self.char1` is used as the + command-caller (the `.caller` property on the Command). This allows to + execute with another caller, most commonly an Account. + receiver (Object or Account, optional): This is the object to receive the + return messages we want to test. By default this is the same as `caller` + (which in turn defaults to is `self.char1`). Note that if `msg` is + a `dict`, this is ignored since the receiver is already specified there. + cmdstring (str, optional): Normally this is the Command's `key`. + This allows for tweaking the `.cmdname` property of the + Command`. This isb used for commands with multiple aliases, + where the command explicitly checs which alias was used to + determine its functionality. + obj (str, optional): This sets the `.obj` property of the Command - the + object on which the Command 'sits'. By default this is the same as `caller`. + This can be used for testing on-object Command interactions. + inputs (list, optional): A list of strings to pass to functions that pause to + take input from the user (normally using `@interactive` and + `ret = yield(question)` or `evmenu.get_input`). Each element of the + list will be passed into the command as if the user wrote that at the prompt. + raw_string (str, optional): Normally the `.raw_string` property is set as + a combination of your `key/cmdname` and `input_args`. This allows + direct control of what this is, for example for testing edge cases + or malformed inputs. Returns: - msg (str): The received message that was sent to the caller. + str or dict: The message sent to `receiver`, or a dict of + `{receiver: "msg", ...}` if multiple are given. This is usually + only used with `msg=None` to do the validation externally. + + Raises: + AssertionError: If the returns of `.msg` calls (tested with `.startswith`) does not + match `expected_input`. + + Notes: + As part of the tests, all methods of the Command will be called in + the proper order: + + - cmdobj.at_pre_cmd() + - cmdobj.parse() + - cmdobj.func() + - cmdobj.at_post_cmd() """ + # The `self.char1` is created in the `EvenniaTest` base along with + # other helper objects like self.room and self.obj caller = caller if caller else self.char1 - receiver = receiver if receiver else caller cmdobj.caller = caller cmdobj.cmdname = cmdstring if cmdstring else cmdobj.key cmdobj.raw_cmdname = cmdobj.cmdname cmdobj.cmdstring = cmdobj.cmdname # deprecated - cmdobj.args = args + cmdobj.args = input_args cmdobj.cmdset = cmdset cmdobj.session = SESSIONS.session_from_sessid(1) cmdobj.account = self.account - cmdobj.raw_string = raw_string if raw_string is not None else cmdobj.key + " " + args + cmdobj.raw_string = raw_string if raw_string is not None else cmdobj.key + " " + input_args cmdobj.obj = obj or (caller if caller else self.char1) - # test - old_msg = receiver.msg inputs = inputs or [] - try: + # set up receivers + receiver_mapping = {} + if isinstance(msg, dict): + # a mapping {receiver: msg, ...} + receiver_mapping = {recv: str(msg).strip() if msg else None + for recv, msg in msg.items()} + else: + # a single expected string and thus a single receiver (defaults to caller) + receiver = receiver if receiver else caller + receiver_mapping[receiver] = str(msg).strip() if msg is not None else None + + unmocked_msg_methods = {} + for receiver in receiver_mapping: + # save the old .msg method so we can get it back + # cleanly after the test + unmocked_msg_methods[receiver] = receiver.msg + # replace normal `.msg` with a mock receiver.msg = Mock() + + # Run the methods of the Command. This mimics what happens in the + # cmdhandler. This will have the mocked .msg be called as part of the + # execution. Mocks remembers what was sent to them so we will be able + # to retrieve what was sent later. + try: if cmdobj.at_pre_cmd(): return cmdobj.parse() ret = cmdobj.func() - # handle func's with yield in them (generators) + # handle func's with yield in them (making them generators) if isinstance(ret, types.GeneratorType): while True: try: inp = inputs.pop() if inputs else None if inp: try: + # this mimics a user's reply to a prompt ret.send(inp) except TypeError: next(ret) ret = ret.send(inp) else: + # non-input yield, like yield(10). We don't pause + # but fire it immediately. next(ret) except StopIteration: break @@ -176,40 +289,62 @@ except InterruptCommand: pass - # clean out evtable sugar. We only operate on text-type - stored_msg = [ - args[0] if args and args[0] else kwargs.get("text", utils.to_str(kwargs)) - for name, args, kwargs in receiver.msg.mock_calls - ] - # Get the first element of a tuple if msg received a tuple instead of a string - stored_msg = [str(smsg[0]) if isinstance(smsg, tuple) else str(smsg) for smsg in stored_msg] - if msg is not None: - msg = str(msg) # to be safe, e.g. `py` command may return ints - # set our separator for returned messages based on parsing ansi or not - msg_sep = "|" if noansi else "||" - # Have to strip ansi for each returned message for the regex to handle it correctly - returned_msg = msg_sep.join( - _RE.sub("", ansi.parse_ansi(mess, strip_ansi=noansi)) for mess in stored_msg - ).strip() - msg = msg.strip() - if msg == "" and returned_msg or not returned_msg.startswith(msg): - prt = "" - for ic, char in enumerate(msg): - import re + for inp in inputs: + # if there are any inputs left, we may have a non-generator + # input to handle (get_input/ask_yes_no that uses a separate + # cmdset rather than a yield + caller.execute_cmd(inp) - prt += char + # At this point the mocked .msg methods on each receiver will have + # stored all calls made to them (that's a basic function of the Mock + # class). We will not extract them and compare to what we expected to + # go to each receiver. - sep1 = "\n" + "=" * 30 + "Wanted message" + "=" * 34 + "\n" - sep2 = "\n" + "=" * 30 + "Returned message" + "=" * 32 + "\n" - sep3 = "\n" + "=" * 78 - retval = sep1 + msg + sep2 + returned_msg + sep3 - raise AssertionError(retval) - else: - returned_msg = "\n".join(str(msg) for msg in stored_msg) - returned_msg = ansi.parse_ansi(returned_msg, strip_ansi=noansi).strip() - receiver.msg = old_msg + returned_msgs = {} + for receiver, expected_msg in receiver_mapping.items(): + # get the stored messages from the Mock with Mock.mock_calls. + stored_msg = [ + args[0] if args and args[0] else kwargs.get("text", utils.to_str(kwargs)) + for name, args, kwargs in receiver.msg.mock_calls + ] + # we can return this now, we are done using the mock + receiver.msg = unmocked_msg_methods[receiver] - return returned_msg
    + # Get the first element of a tuple if msg received a tuple instead of a string + stored_msg = [str(smsg[0]) + if isinstance(smsg, tuple) else str(smsg) for smsg in stored_msg] + if expected_msg is None: + # no expected_msg; just build the returned_msgs dict + + returned_msg = "\n".join(str(msg) for msg in stored_msg) + returned_msgs[receiver] = ansi.parse_ansi(returned_msg, strip_ansi=noansi).strip() + else: + # compare messages to expected + + # set our separator for returned messages based on parsing ansi or not + msg_sep = "|" if noansi else "||" + + # We remove Evmenu decorations since that just makes it harder + # to write the comparison string. We also strip ansi before this + # comparison since otherwise it would mess with the regex. + returned_msg = msg_sep.join( + _RE_STRIP_EVMENU.sub( + "", ansi.parse_ansi(mess, strip_ansi=noansi)) + for mess in stored_msg).strip() + + # this is the actual test + if expected_msg == "" and returned_msg or not returned_msg.startswith(expected_msg): + # failed the test + raise AssertionError( + self._ERROR_FORMAT.format( + expected_msg=expected_msg, returned_msg=returned_msg) + ) + # passed! + returned_msgs[receiver] = returned_msg + + if len(returned_msgs) == 1: + return list(returned_msgs.values())[0] + return returned_msgs # ------------------------------------------------------------ @@ -314,16 +449,153 @@
    [docs]class TestHelp(CommandTest): + + maxDiff = None + +
    [docs] def setUp(self): + super().setUp() + # we need to set up a logger here since lunr takes over the logger otherwise + import logging + + logging.basicConfig(level=logging.ERROR)
    + +
    [docs] def tearDown(self): + super().tearDown() + import logging + + logging.disable(level=logging.ERROR)
    +
    [docs] def test_help(self): - self.call(help.CmdHelp(), "", "Command help entries", cmdset=CharacterCmdSet())
    + self.call(help_module.CmdHelp(), "", "Commands", cmdset=CharacterCmdSet())
    [docs] def test_set_help(self): self.call( - help.CmdSetHelp(), + help_module.CmdSetHelp(), "testhelp, General = This is a test", "Topic 'testhelp' was successfully created.", + cmdset=CharacterCmdSet() ) - self.call(help.CmdHelp(), "testhelp", "Help for testhelp", cmdset=CharacterCmdSet())
    + self.call(help_module.CmdHelp(), "testhelp", "Help for testhelp", cmdset=CharacterCmdSet()) + + @parameterized.expand([ + ("test", # main help entry + "Help for test\n\n" + "Main help text\n\n" + "Subtopics:\n" + " test/creating extra stuff" + " test/something else" + " test/more" + ), + ("test/creating extra stuff", # subtopic, full match + "Help for test/creating extra stuff\n\n" + "Help on creating extra stuff.\n\n" + "Subtopics:\n" + " test/creating extra stuff/subsubtopic\n" + ), + ("test/creating", # startswith-match + "Help for test/creating extra stuff\n\n" + "Help on creating extra stuff.\n\n" + "Subtopics:\n" + " test/creating extra stuff/subsubtopic\n" + ), + ("test/extra", # partial match + "Help for test/creating extra stuff\n\n" + "Help on creating extra stuff.\n\n" + "Subtopics:\n" + " test/creating extra stuff/subsubtopic\n" + ), + ("test/extra/subsubtopic", # partial subsub-match + "Help for test/creating extra stuff/subsubtopic\n\n" + "A subsubtopic text" + ), + ("test/creating extra/subsub", # partial subsub-match + "Help for test/creating extra stuff/subsubtopic\n\n" + "A subsubtopic text" + ), + ("test/Something else", # case + "Help for test/something else\n\n" + "Something else" + ), + ("test/More", # case + "Help for test/more\n\n" + "Another text\n\n" + "Subtopics:\n" + " test/more/second-more" + ), + ("test/More/Second-more", + "Help for test/more/second-more\n\n" + "The Second More text.\n\n" + "Subtopics:\n" + " test/more/second-more/more again" + " test/more/second-more/third more" + ), + ("test/More/-more", # partial match + "Help for test/more/second-more\n\n" + "The Second More text.\n\n" + "Subtopics:\n" + " test/more/second-more/more again" + " test/more/second-more/third more" + ), + ("test/more/second/more again", + "Help for test/more/second-more/more again\n\n" + "Even more text.\n" + ), + ("test/more/second/third", + "Help for test/more/second-more/third more\n\n" + "Third more text\n" + ), + ]) + def test_subtopic_fetch(self, helparg, expected): + """ + Check retrieval of subtopics. + + """ + class TestCmd(Command): + """ + Main help text + + # SUBTOPICS + + ## creating extra stuff + + Help on creating extra stuff. + + ### subsubtopic + + A subsubtopic text + + ## Something else + + Something else + + ## More + + Another text + + ### Second-More + + The Second More text. + + #### More again + + Even more text. + + #### Third more + + Third more text + + """ + key = "test" + + class TestCmdSet(CmdSet): + def at_cmdset_creation(self): + self.add(TestCmd()) + self.add(help_module.CmdHelp()) + + self.call(help_module.CmdHelp(), + helparg, + expected, + cmdset=TestCmdSet())
    [docs]class TestSystem(CommandTest): @@ -345,6 +617,170 @@
    [docs] def test_server_load(self): self.call(system.CmdServerLoad(), "", "Server CPU and Memory load:")
    +_TASK_HANDLER = None + +
    [docs]def func_test_cmd_tasks(): + return 'success'
    + +
    [docs]class TestCmdTasks(CommandTest): + +
    [docs] def setUp(self): + super().setUp() + # get a reference of TASK_HANDLER + self.timedelay = 5 + global _TASK_HANDLER + if _TASK_HANDLER is None: + from evennia.scripts.taskhandler import TASK_HANDLER as _TASK_HANDLER + _TASK_HANDLER.clock = task.Clock() + self.task_handler = _TASK_HANDLER + self.task_handler.clear() + self.task = self.task_handler.add(self.timedelay, func_test_cmd_tasks) + task_args = self.task_handler.tasks.get(self.task.get_id(), False)
    + + +
    [docs] def tearDown(self): + super().tearDown() + self.task_handler.clear()
    + +
    [docs] def test_no_tasks(self): + self.task_handler.clear() + self.call(system.CmdTasks(), '', 'There are no active tasks.')
    + +
    [docs] def test_active_task(self): + cmd_result = self.call(system.CmdTasks(), '') + for ptrn in ('Task ID', 'Completion Date', 'Function', 'KWARGS', 'persisten', + '1', r'\d+/\d+/\d+', r'\d+\:\d+\:\d+', r'ms\:\d+', 'func_test', '{}', + 'False'): + self.assertRegex(cmd_result, ptrn)
    + +
    [docs] def test_persistent_task(self): + self.task_handler.clear() + self.task_handler.add(self.timedelay, func_test_cmd_tasks, persistent=True) + cmd_result = self.call(system.CmdTasks(), '') + self.assertRegex(cmd_result, 'True')
    + +
    [docs] def test_pause_unpause(self): + # test pause + args = f'/pause {self.task.get_id()}' + wanted_msg = 'Yes or No, pause task 1? With completion date' + cmd_result = self.call(system.CmdTasks(), args, wanted_msg) + self.assertRegex(cmd_result, '\. Deferring function func_test_cmd_tasks\.') + self.char1.execute_cmd('y') + self.assertTrue(self.task.paused) + self.task_handler.clock.advance(self.timedelay + 1) + # test unpause + args = f'/unpause {self.task.get_id()}' + self.assertTrue(self.task.exists()) + wanted_msg = 'Yes or No, unpause task 1? With completion date' + cmd_result = self.call(system.CmdTasks(), args, wanted_msg) + self.assertRegex(cmd_result, '\. Deferring function func_test_cmd_tasks\.') + self.char1.execute_cmd('y') + # verify task continues after unpause + self.task_handler.clock.advance(1) + self.assertFalse(self.task.exists())
    + +
    [docs] def test_do_task(self): + args = f'/do_task {self.task.get_id()}' + wanted_msg = 'Yes or No, do_task task 1? With completion date' + cmd_result = self.call(system.CmdTasks(), args, wanted_msg) + self.assertRegex(cmd_result, '\. Deferring function func_test_cmd_tasks\.') + self.char1.execute_cmd('y') + self.assertFalse(self.task.exists())
    + +
    [docs] def test_remove(self): + args = f'/remove {self.task.get_id()}' + wanted_msg = 'Yes or No, remove task 1? With completion date' + cmd_result = self.call(system.CmdTasks(), args, wanted_msg) + self.assertRegex(cmd_result, '\. Deferring function func_test_cmd_tasks\.') + self.char1.execute_cmd('y') + self.assertFalse(self.task.exists())
    + +
    [docs] def test_call(self): + args = f'/call {self.task.get_id()}' + wanted_msg = 'Yes or No, call task 1? With completion date' + cmd_result = self.call(system.CmdTasks(), args, wanted_msg) + self.assertRegex(cmd_result, '\. Deferring function func_test_cmd_tasks\.') + self.char1.execute_cmd('y') + # make certain the task is still active + self.assertTrue(self.task.active()) + # go past delay time, the task should call do_task and remove itself after calling. + self.task_handler.clock.advance(self.timedelay + 1) + self.assertFalse(self.task.exists())
    + +
    [docs] def test_cancel(self): + args = f'/cancel {self.task.get_id()}' + wanted_msg = 'Yes or No, cancel task 1? With completion date' + cmd_result = self.call(system.CmdTasks(), args, wanted_msg) + self.assertRegex(cmd_result, '\. Deferring function func_test_cmd_tasks\.') + self.char1.execute_cmd('y') + self.assertTrue(self.task.exists()) + self.assertFalse(self.task.active())
    + +
    [docs] def test_func_name_manipulation(self): + self.task_handler.add(self.timedelay, func_test_cmd_tasks) # add an extra task + args = f'/remove func_test_cmd_tasks' + wanted_msg = 'Task action remove completed on task ID 1.|The task function remove returned: True|' \ + 'Task action remove completed on task ID 2.|The task function remove returned: True' + self.call(system.CmdTasks(), args, wanted_msg) + self.assertFalse(self.task_handler.tasks) # no tasks should exist.
    + +
    [docs] def test_wrong_func_name(self): + args = f'/remove intentional_fail' + wanted_msg = 'No tasks deferring function name intentional_fail found.' + self.call(system.CmdTasks(), args, wanted_msg) + self.assertTrue(self.task.active())
    + +
    [docs] def test_no_input(self): + args = f'/cancel {self.task.get_id()}' + self.call(system.CmdTasks(), args) + # task should complete since no input was received + self.task_handler.clock.advance(self.timedelay + 1) + self.assertFalse(self.task.exists())
    + +
    [docs] def test_responce_of_yes(self): + self.call(system.CmdTasks(), f'/cancel {self.task.get_id()}') + self.char1.msg = Mock() + self.char1.execute_cmd('y') + text = '' + for _, _, kwargs in self.char1.msg.mock_calls: + text += kwargs.get('text', '') + self.assertEqual(text, 'cancel request completed.The task function cancel returned: True') + self.assertTrue(self.task.exists())
    + +
    [docs] def test_task_complete_waiting_input(self): + """Test for task completing while waiting for input.""" + self.call(system.CmdTasks(), f'/cancel {self.task.get_id()}') + self.task_handler.clock.advance(self.timedelay + 1) + self.char1.msg = Mock() + self.char1.execute_cmd('y') + text = '' + for _, _, kwargs in self.char1.msg.mock_calls: + text += kwargs.get('text', '') + self.assertEqual(text, 'Task completed while waiting for input.') + self.assertFalse(self.task.exists())
    + +
    [docs] def test_new_task_waiting_input(self): + """ + Test task completing than a new task with the same ID being made while waitinf for input. + """ + self.assertTrue(self.task.get_id(), 1) + self.call(system.CmdTasks(), f'/cancel {self.task.get_id()}') + self.task_handler.clock.advance(self.timedelay + 1) + self.assertFalse(self.task.exists()) + self.task = self.task_handler.add(self.timedelay, func_test_cmd_tasks) + self.assertTrue(self.task.get_id(), 1) + self.char1.msg = Mock() + self.char1.execute_cmd('y') + text = '' + for _, _, kwargs in self.char1.msg.mock_calls: + text += kwargs.get('text', '') + self.assertEqual(text, 'Task completed while waiting for input.')
    + +
    [docs] def test_misformed_command(self): + wanted_msg = 'Task command misformed.|Proper format tasks[/switch] ' \ + '[function name or task id]' + self.call(system.CmdTasks(), f'/cancel', wanted_msg)
    +
    [docs]class TestAdmin(CommandTest):
    [docs] def test_emit(self): @@ -1012,11 +1448,8 @@ self.call(building.CmdSetHome(), "Obj = Room2", "Home location of Obj was set to Room")
    [docs] def test_list_cmdsets(self): - self.call( - building.CmdListCmdSets(), - "", - "<CmdSetHandler> stack:\n <CmdSet DefaultCharacter, Union, perm, prio 0>:", - ) + self.call(building.CmdListCmdSets(), "", + "<CmdSetHandler> stack:\n <CmdSet DefaultCharacter, Union, perm, prio 0>:") self.call(building.CmdListCmdSets(), "NotFound", "Could not find 'NotFound'")
    [docs] def test_typeclass(self): @@ -1194,8 +1627,8 @@ self.call(building.CmdScript(), "Obj ", "dbref ") self.call( - building.CmdScript(), "/start Obj", "0 scripts started on Obj" - ) # because it's already started + building.CmdScript(), "/start Obj", "1 scripts started on Obj" + ) # we allow running start again; this should still happen self.call(building.CmdScript(), "/stop Obj", "Stopping script") self.call( @@ -1464,21 +1897,13 @@ self.call( comms.CmdAddCom(), "tc = testchan", - "You are already connected to channel testchan. You can now", + "You are already connected to channel testchan.| You can now", receiver=self.account, ) self.call( comms.CmdDelCom(), "tc", - "Your alias 'tc' for channel testchan was cleared.", - receiver=self.account, - )
    - -
    [docs] def test_channels(self): - self.call( - comms.CmdChannels(), - "", - "Available channels (use comlist,addcom and delcom to manage", + "Any alias 'tc' for channel testchan was cleared.", receiver=self.account, )
    @@ -1486,7 +1911,7 @@ self.call( comms.CmdAllCom(), "", - "Available channels (use comlist,addcom and delcom to manage", + "Available channels:", receiver=self.account, )
    @@ -1506,14 +1931,6 @@ receiver=self.account, ) -
    [docs] def test_cemit(self): - self.call( - comms.CmdCemit(), - "testchan = Test Message", - "[testchan] Test Message|Sent to channel testchan: Test Message", - receiver=self.account, - )
    -
    [docs] def test_cwho(self): self.call( comms.CmdCWho(), @@ -1550,8 +1967,232 @@ )
    +from evennia.utils.create import create_channel # noqa + +
    [docs]class TestCommsChannel(CommandTest): + """ + Test the central `channel` command. + + """ +
    [docs] def setUp(self): + super(CommandTest, self).setUp() + self.channel = create_channel( + key="testchannel", + desc="A test channel") + self.channel.connect(self.char1) + self.cmdchannel = comms.CmdChannel + self.cmdchannel.account_caller = False
    + +
    [docs] def tearDown(self): + if self.channel.pk: + self.channel.delete()
    + + # test channel command +
    [docs] def test_channel__noarg(self): + self.call( + self.cmdchannel(), + "", + "Channel subscriptions" + )
    + +
    [docs] def test_channel__msg(self): + self.channel.msg = Mock() + self.call( + self.cmdchannel(), + "testchannel = Test message", + "" + ) + self.channel.msg.assert_called_with("Test message", senders=self.char1)
    + +
    [docs] def test_channel__list(self): + self.call( + self.cmdchannel(), + "/list", + "Channel subscriptions" + )
    + +
    [docs] def test_channel__all(self): + self.call( + self.cmdchannel(), + "/all", + "Available channels" + )
    + +
    [docs] def test_channel__history(self): + with patch("evennia.commands.default.comms.tail_log_file") as mock_tail: + self.call( + self.cmdchannel(), + "/history testchannel", + "" + ) + mock_tail.assert_called()
    + +
    [docs] def test_channel__sub(self): + self.channel.disconnect(self.char1) + + self.call( + self.cmdchannel(), + "/sub testchannel", + "You are now subscribed" + ) + self.assertTrue(self.char1 in self.channel.subscriptions.all()) + self.assertEqual(self.char1.nicks.nickreplace("testchannel Hello"), "channel testchannel = Hello")
    + +
    [docs] def test_channel__unsub(self): + self.call( + self.cmdchannel(), + "/unsub testchannel", + "You un-subscribed" + ) + self.assertFalse(self.char1 in self.channel.subscriptions.all())
    + +
    [docs] def test_channel__alias__unalias(self): + """Add and then remove a channel alias""" + # add alias + self.call( + self.cmdchannel(), + "/alias testchannel = foo", + "Added/updated your alias 'foo' for channel testchannel." + ) + self.assertEqual( + self.char1.nicks.nickreplace('foo Hello'), "channel testchannel = Hello") + + # use alias + self.channel.msg = Mock() + self.call( + self.cmdchannel(), + "foo = test message", + "") + self.channel.msg.assert_called_with("test message", senders=self.char1) + + # remove alias + self.call( + self.cmdchannel(), + "/unalias foo", + "Removed your channel alias 'foo'" + ) + self.assertEqual(self.char1.nicks.get('foo $1', category="channel"), None)
    + +
    [docs] def test_channel__mute(self): + self.call( + self.cmdchannel(), + "/mute testchannel", + "Muted channel testchannel" + ) + self.assertTrue(self.char1 in self.channel.mutelist)
    + +
    [docs] def test_channel__unmute(self): + self.channel.mute(self.char1) + + self.call( + self.cmdchannel(), + "/unmute testchannel = Char1", + "Un-muted channel testchannel" + ) + self.assertFalse(self.char1 in self.channel.mutelist)
    + +
    [docs] def test_channel__create(self): + self.call( + self.cmdchannel(), + "/create testchannel2", + "Created (and joined) new channel" + )
    + +
    [docs] def test_channel__destroy(self): + self.channel.msg = Mock() + self.call( + self.cmdchannel(), + "/destroy testchannel = delete reason", + "Are you sure you want to delete channel ", + inputs=['Yes'] + ) + self.channel.msg.assert_called_with( + "delete reason", bypass_mute=True, senders=self.char1)
    + +
    [docs] def test_channel__desc(self): + self.call( + self.cmdchannel(), + "/desc testchannel = Another description", + "Updated channel description." + )
    + +
    [docs] def test_channel__lock(self): + self.call( + self.cmdchannel(), + "/lock testchannel = foo:false()", + "Added/updated lock on channel" + ) + self.assertEqual(self.channel.locks.get('foo'), 'foo:false()')
    + +
    [docs] def test_channel__unlock(self): + self.channel.locks.add("foo:true()") + self.call( + self.cmdchannel(), + "/unlock testchannel = foo", + "Removed lock from channel" + ) + self.assertEqual(self.channel.locks.get('foo'), '')
    + +
    [docs] def test_channel__boot(self): + self.channel.connect(self.char2) + self.assertTrue(self.char2 in self.channel.subscriptions.all()) + self.channel.msg = Mock() + self.char2.msg = Mock() + + self.call( + self.cmdchannel(), + "/boot testchannel = Char2 : Booting from channel!", + "Are you sure ", + inputs=["Yes"] + ) + self.channel.msg.assert_called_with( + "Char2 was booted from channel by Char. Reason: Booting from channel!") + self.char2.msg.assert_called_with( + "You were booted from channel testchannel by Char. Reason: Booting from channel!")
    + +
    [docs] def test_channel__ban__unban(self): + """Test first ban and then unban""" + + # ban + self.channel.connect(self.char2) + self.assertTrue(self.char2 in self.channel.subscriptions.all()) + self.channel.msg = Mock() + self.char2.msg = Mock() + + self.call( + self.cmdchannel(), + "/ban testchannel = Char2 : Banning from channel!", + "Are you sure ", + inputs=["Yes"] + ) + self.channel.msg.assert_called_with( + "Char2 was booted from channel by Char. Reason: Banning from channel!") + self.char2.msg.assert_called_with( + "You were booted from channel testchannel by Char. Reason: Banning from channel!") + self.assertTrue(self.char2 in self.channel.banlist) + + # unban + + self.call( + self.cmdchannel(), + "/unban testchannel = Char2", + "Un-banned Char2 from channel testchannel" + ) + self.assertFalse(self.char2 in self.channel.banlist)
    + +
    [docs] def test_channel__who(self): + self.call( + self.cmdchannel(), + "/who testchannel", + "Subscribed to testchannel:\nChar" + )
    + +
    [docs]class TestBatchProcess(CommandTest): -
    [docs] def test_batch_commands(self): + +
    [docs] @patch("evennia.contrib.tutorial_examples.red_button.repeat") + @patch("evennia.contrib.tutorial_examples.red_button.delay") + def test_batch_commands(self, mock_delay, mock_repeat): # cannot test batchcode here, it must run inside the server process self.call( batchprocess.CmdBatchCommands(), @@ -1562,7 +2203,8 @@ confirm = building.CmdDestroy.confirm building.CmdDestroy.confirm = False self.call(building.CmdDestroy(), "button", "button was destroyed.") - building.CmdDestroy.confirm = confirm
    + building.CmdDestroy.confirm = confirm + mock_repeat.assert_called()
    [docs]class CmdInterrupt(Command): @@ -1617,16 +2259,7 @@ multimatch = syscommands.SystemMultimatch() multimatch.matches = matches - self.call(multimatch, "look", "")
    - -
    [docs] @patch("evennia.commands.default.syscommands.ChannelDB") - def test_channelcommand(self, mock_channeldb): - channel = MagicMock() - channel.msg = MagicMock() - mock_channeldb.objects.get_channel = MagicMock(return_value=channel) - - self.call(syscommands.SystemSendToChannel(), "public:Hello") - channel.msg.assert_called()
    + self.call(multimatch, "look", "")
    @@ -1664,7 +2297,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/commands/default/unloggedin.html b/docs/0.9.5/_modules/evennia/commands/default/unloggedin.html index 9a71d40229..46fe8ac28a 100644 --- a/docs/0.9.5/_modules/evennia/commands/default/unloggedin.html +++ b/docs/0.9.5/_modules/evennia/commands/default/unloggedin.html @@ -335,6 +335,7 @@ |wquit|n - abort the connection First create an account e.g. with |wcreate Anna c67jHL8p|n +(If you have spaces in your name, use double quotes: |wcreate "Anna the Barbarian" c67jHL8p|n Next you can connect to the game: |wconnect Anna c67jHL8p|n You can use the |wlook|n command if you want to see the connect screen again. @@ -572,7 +573,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/comms/admin.html b/docs/0.9.5/_modules/evennia/comms/admin.html deleted file mode 100644 index de33d66b4d..0000000000 --- a/docs/0.9.5/_modules/evennia/comms/admin.html +++ /dev/null @@ -1,227 +0,0 @@ - - - - - - - - evennia.comms.admin — Evennia 0.9.5 documentation - - - - - - - - - - - - - -
    -
    -
    -
    - -

    Source code for evennia.comms.admin

    -"""
    -This defines how Comm models are displayed in the web admin interface.
    -
    -"""
    -
    -from django.contrib import admin
    -from evennia.comms.models import ChannelDB
    -from evennia.typeclasses.admin import AttributeInline, TagInline
    -from django.conf import settings
    -
    -
    -
    [docs]class ChannelAttributeInline(AttributeInline): - """ - Inline display of Channel Attribute - experimental - - """ - - model = ChannelDB.db_attributes.through - related_field = "channeldb"
    - - -
    [docs]class ChannelTagInline(TagInline): - """ - Inline display of Channel Tags - experimental - - """ - - model = ChannelDB.db_tags.through - related_field = "channeldb"
    - - -
    [docs]class MsgAdmin(admin.ModelAdmin): - """ - Defines display for Msg objects - - """ - - list_display = ( - "id", - "db_date_created", - "db_sender", - "db_receivers", - "db_channels", - "db_message", - "db_lock_storage", - ) - list_display_links = ("id",) - ordering = ["db_date_created", "db_sender", "db_receivers", "db_channels"] - # readonly_fields = ['db_message', 'db_sender', 'db_receivers', 'db_channels'] - search_fields = ["id", "^db_date_created", "^db_message"] - save_as = True - save_on_top = True - list_select_related = True
    - - -# admin.site.register(Msg, MsgAdmin) - - -
    [docs]class ChannelAdmin(admin.ModelAdmin): - """ - Defines display for Channel objects - - """ - - inlines = [ChannelTagInline, ChannelAttributeInline] - list_display = ("id", "db_key", "db_lock_storage", "subscriptions") - list_display_links = ("id", "db_key") - ordering = ["db_key"] - search_fields = ["id", "db_key", "db_tags__db_key"] - save_as = True - save_on_top = True - list_select_related = True - raw_id_fields = ("db_object_subscriptions", "db_account_subscriptions") - fieldsets = ( - ( - None, - { - "fields": ( - ("db_key",), - "db_lock_storage", - "db_account_subscriptions", - "db_object_subscriptions", - ) - }, - ), - ) - -
    [docs] def subscriptions(self, obj): - """ - Helper method to get subs from a channel. - - Args: - obj (Channel): The channel to get subs from. - - """ - return ", ".join([str(sub) for sub in obj.subscriptions.all()])
    - -
    [docs] def save_model(self, request, obj, form, change): - """ - Model-save hook. - - Args: - request (Request): Incoming request. - obj (Object): Database object. - form (Form): Form instance. - change (bool): If this is a change or a new object. - - """ - obj.save() - if not change: - # adding a new object - # have to call init with typeclass passed to it - obj.set_class_from_typeclass(typeclass_path=settings.BASE_CHANNEL_TYPECLASS) - obj.at_init()
    - -
    [docs] def response_add(self, request, obj, post_url_continue=None): - from django.http import HttpResponseRedirect - from django.urls import reverse - - return HttpResponseRedirect(reverse("admin:comms_channeldb_change", args=[obj.id]))
    - - -admin.site.register(ChannelDB, ChannelAdmin) -
    - -
    -
    -
    -
    - -
    -
    - - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/comms/channelhandler.html b/docs/0.9.5/_modules/evennia/comms/channelhandler.html deleted file mode 100644 index 563b37f7fc..0000000000 --- a/docs/0.9.5/_modules/evennia/comms/channelhandler.html +++ /dev/null @@ -1,427 +0,0 @@ - - - - - - - - evennia.comms.channelhandler — Evennia 0.9.5 documentation - - - - - - - - - - - - - -
    -
    -
    -
    - -

    Source code for evennia.comms.channelhandler

    -"""
    -The channel handler, accessed from this module as CHANNEL_HANDLER is a
    -singleton that handles the stored set of channels and how they are
    -represented against the cmdhandler.
    -
    -If there is a channel named 'newbie', we want to be able to just write
    -
    -    newbie Hello!
    -
    -For this to work, 'newbie', the name of the channel, must be
    -identified by the cmdhandler as a command name. The channelhandler
    -stores all channels as custom 'commands' that the cmdhandler can
    -import and look through.
    -
    -> Warning - channel names take precedence over command names, so make
    -sure to not pick clashing channel names.
    -
    -Unless deleting a channel you normally don't need to bother about the
    -channelhandler at all - the create_channel method handles the update.
    -
    -To delete a channel cleanly, delete the channel object, then call
    -update() on the channelhandler. Or use Channel.objects.delete() which
    -does this for you.
    -
    -"""
    -from django.conf import settings
    -from evennia.commands import cmdset
    -from evennia.utils.logger import tail_log_file
    -from evennia.utils.utils import class_from_module
    -from django.utils.translation import gettext as _
    -
    -# we must late-import these since any overloads are likely to
    -# themselves be using these classes leading to a circular import.
    -
    -_CHANNEL_HANDLER_CLASS = None
    -_CHANNEL_COMMAND_CLASS = None
    -_CHANNELDB = None
    -_COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
    -
    -
    [docs]class ChannelCommand(_COMMAND_DEFAULT_CLASS): - """ - {channelkey} channel - - {channeldesc} - - Usage: - {lower_channelkey} <message> - {lower_channelkey}/history [start] - {lower_channelkey} off - mutes the channel - {lower_channelkey} on - unmutes the channel - - Switch: - history: View 20 previous messages, either from the end or - from <start> number of messages from the end. - - Example: - {lower_channelkey} Hello World! - {lower_channelkey}/history - {lower_channelkey}/history 30 - - """ - - # ^note that channeldesc and lower_channelkey will be filled - # automatically by ChannelHandler - - # this flag is what identifies this cmd as a channel cmd - # and branches off to the system send-to-channel command - # (which is customizable by admin) - is_channel = True - key = "general" - help_category = "Channel Names" - obj = None - arg_regex = r"\s.*?|/history.*?" - -
    [docs] def parse(self): - """ - Simple parser - """ - # cmdhandler sends channame:msg here. - channelname, msg = self.args.split(":", 1) - self.history_start = None - if msg.startswith("/history"): - arg = msg[8:] - try: - self.history_start = int(arg) if arg else 0 - except ValueError: - # if no valid number was given, ignore it - pass - self.args = (channelname.strip(), msg.strip())
    - -
    [docs] def func(self): - """ - Create a new message and send it to channel, using - the already formatted input. - """ - global _CHANNELDB - if not _CHANNELDB: - from evennia.comms.models import ChannelDB as _CHANNELDB - - channelkey, msg = self.args - caller = self.caller - if not msg: - self.msg(_("Say what?")) - return - channel = _CHANNELDB.objects.get_channel(channelkey) - - if not channel: - self.msg(_("Channel '%s' not found.") % channelkey) - return - if not channel.has_connection(caller): - string = _("You are not connected to channel '%s'.") - self.msg(string % channelkey) - return - if not channel.access(caller, "send"): - string = _("You are not permitted to send to channel '%s'.") - self.msg(string % channelkey) - return - if msg == "on": - caller = caller if not hasattr(caller, "account") else caller.account - unmuted = channel.unmute(caller) - if unmuted: - self.msg(_("You start listening to %s.") % channel) - return - self.msg(_("You were already listening to %s.") % channel) - return - if msg == "off": - caller = caller if not hasattr(caller, "account") else caller.account - muted = channel.mute(caller) - if muted: - self.msg(_("You stop listening to %s.") % channel) - return - self.msg(_("You were already not listening to %s.") % channel) - return - if self.history_start is not None: - # Try to view history - log_file = channel.attributes.get("log_file", default="channel_%s.log" % channel.key) - - def send_msg(lines): - return self.msg( - "".join(line.split("[-]", 1)[1] if "[-]" in line else line for line in lines) - ) - - tail_log_file(log_file, self.history_start, 20, callback=send_msg) - else: - caller = caller if not hasattr(caller, "account") else caller.account - if caller in channel.mutelist: - self.msg(_("You currently have %s muted.") % channel) - return - channel.msg(msg, senders=self.caller, online=True)
    - -
    [docs] def get_extra_info(self, caller, **kwargs): - """ - Let users know that this command is for communicating on a channel. - - Args: - caller (TypedObject): A Character or Account who has entered an ambiguous command. - - Returns: - A string with identifying information to disambiguate the object, conventionally with a preceding space. - """ - return _(" (channel)")
    - - -
    [docs]class ChannelHandler(object): - """ - The ChannelHandler manages all active in-game channels and - dynamically creates channel commands for users so that they can - just give the channel's key or alias to write to it. Whenever a - new channel is created in the database, the update() method on - this handler must be called to sync it with the database (this is - done automatically if creating the channel with - evennia.create_channel()) - - """ - -
    [docs] def __init__(self): - """ - Initializes the channel handler's internal state. - - """ - self._cached_channel_cmds = {} - self._cached_cmdsets = {} - self._cached_channels = {}
    - - def __str__(self): - """ - Returns the string representation of the handler - - """ - return ", ".join(str(cmd) for cmd in self._cached_channel_cmds) - -
    [docs] def clear(self): - """ - Reset the cache storage. - - """ - self._cached_channel_cmds = {} - self._cached_cmdsets = {} - self._cached_channels = {}
    - -
    [docs] def add(self, channel): - """ - Add an individual channel to the handler. This is called - whenever a new channel is created. - - Args: - channel (Channel): The channel to add. - - Notes: - To remove a channel, simply delete the channel object and - run self.update on the handler. This should usually be - handled automatically by one of the deletion methos of - the Channel itself. - - """ - global _CHANNEL_COMMAND_CLASS - if not _CHANNEL_COMMAND_CLASS: - _CHANNEL_COMMAND_CLASS = class_from_module(settings.CHANNEL_COMMAND_CLASS) - - # map the channel to a searchable command - cmd = _CHANNEL_COMMAND_CLASS( - key=channel.key.strip().lower(), - aliases=channel.aliases.all(), - locks="cmd:all();%s" % channel.locks, - help_category="Channel names", - obj=channel, - is_channel=True, - ) - # format the help entry - key = channel.key - cmd.__doc__ = cmd.__doc__.format( - channelkey=key, - lower_channelkey=key.strip().lower(), - channeldesc=channel.attributes.get("desc", default="").strip(), - ) - self._cached_channel_cmds[channel] = cmd - self._cached_channels[key] = channel - self._cached_cmdsets = {}
    - - add_channel = add # legacy alias - -
    [docs] def remove(self, channel): - """ - Remove channel from channelhandler. This will also delete it. - - Args: - channel (Channel): Channel to remove/delete. - - """ - if channel.pk: - channel.delete() - self.update()
    - -
    [docs] def update(self): - """ - Updates the handler completely, including removing old removed - Channel objects. This must be called after deleting a Channel. - - """ - global _CHANNELDB - if not _CHANNELDB: - from evennia.comms.models import ChannelDB as _CHANNELDB - self._cached_channel_cmds = {} - self._cached_cmdsets = {} - self._cached_channels = {} - for channel in _CHANNELDB.objects.get_all_channels(): - self.add(channel)
    - -
    [docs] def get(self, channelname=None): - """ - Get a channel from the handler, or all channels - - Args: - channelame (str, optional): Channel key, case insensitive. - Returns - channels (list): The matching channels in a list, or all - channels in the handler. - - """ - if channelname: - channel = self._cached_channels.get(channelname.lower(), None) - return [channel] if channel else [] - return list(self._cached_channels.values())
    - -
    [docs] def get_cmdset(self, source_object): - """ - Retrieve cmdset for channels this source_object has - access to send to. - - Args: - source_object (Object): An object subscribing to one - or more channels. - - Returns: - cmdsets (list): The Channel-Cmdsets `source_object` has - access to. - - """ - if source_object in self._cached_cmdsets: - return self._cached_cmdsets[source_object] - else: - # create a new cmdset holding all viable channels - chan_cmdset = None - chan_cmds = [ - channelcmd - for channel, channelcmd in self._cached_channel_cmds.items() - if channel.subscriptions.has(source_object) - and channelcmd.access(source_object, "send") - ] - if chan_cmds: - chan_cmdset = cmdset.CmdSet() - chan_cmdset.key = "ChannelCmdSet" - chan_cmdset.priority = 101 - chan_cmdset.duplicates = True - for cmd in chan_cmds: - chan_cmdset.add(cmd) - self._cached_cmdsets[source_object] = chan_cmdset - return chan_cmdset
    - - -# set up the singleton -CHANNEL_HANDLER = class_from_module(settings.CHANNEL_HANDLER_CLASS)() -CHANNELHANDLER = CHANNEL_HANDLER # legacy -
    - -
    -
    -
    -
    - -
    -
    - - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/comms/comms.html b/docs/0.9.5/_modules/evennia/comms/comms.html index 878b2e8826..5229476fb6 100644 --- a/docs/0.9.5/_modules/evennia/comms/comms.html +++ b/docs/0.9.5/_modules/evennia/comms/comms.html @@ -48,23 +48,48 @@ from django.utils.text import slugify from evennia.typeclasses.models import TypeclassBase -from evennia.comms.models import TempMsg, ChannelDB +from evennia.comms.models import ChannelDB from evennia.comms.managers import ChannelManager from evennia.utils import create, logger from evennia.utils.utils import make_iter -_CHANNEL_HANDLER = None -
    [docs]class DefaultChannel(ChannelDB, metaclass=TypeclassBase): """ This is the base class for all Channel Comms. Inherit from this to create different types of communication channels. + Class-level variables: + - `send_to_online_only` (bool, default True) - if set, will only try to + send to subscribers that are actually active. This is a useful optimization. + - `log_file` (str, default `"channel_{channelname}.log"`). This is the + log file to which the channel history will be saved. The `{channelname}` tag + will be replaced by the key of the Channel. If an Attribute 'log_file' + is set, this will be used instead. If this is None and no Attribute is found, + no history will be saved. + - `channel_prefix_string` (str, default `"[{channelname} ]"`) - this is used + as a simple template to get the channel prefix with `.channel_prefix()`. + """ objects = ChannelManager() + # channel configuration + + # only send to characters/accounts who has an active session (this is a + # good optimization since people can still recover history separately). + send_to_online_only = True + # store log in log file. `channel_key tag will be replace with key of channel. + # Will use log_file Attribute first, if given + log_file = "channel_{channelname}.log" + # which prefix to use when showing were a message is coming from. Set to + # None to disable and set this later. + channel_prefix_string = "[{channelname}] " + + # default nick-alias replacements (default using the 'channel' command) + channel_msg_nick_pattern = r"{alias}\s*?|{alias}\s+?(?P<arg1>.+?)" + channel_msg_nick_replacement = "channel {channelname} = $1" +
    [docs] def at_first_save(self): """ Called by the typeclass system the very first time the channel @@ -74,7 +99,6 @@ """ self.basetype_setup() self.at_channel_creation() - self.attributes.add("log_file", "channel_%s.log" % self.key) if hasattr(self, "_createdict"): # this is only set if the channel was created # with the utils.create.create_channel function. @@ -96,14 +120,11 @@ self.tags.batch_add(*cdict["tags"])
    [docs] def basetype_setup(self): - # delayed import of the channelhandler - global _CHANNEL_HANDLER - if not _CHANNEL_HANDLER: - from evennia.comms.channelhandler import CHANNEL_HANDLER as _CHANNEL_HANDLER - # register ourselves with the channelhandler. - _CHANNEL_HANDLER.add(self) + self.locks.add("send:all();listen:all();control:perm(Admin)") - self.locks.add("send:all();listen:all();control:perm(Admin)")
    + # make sure we don't have access to a same-named old channel's history. + log_file = self.get_log_filename() + logger.rotate_log_file(log_file, num_lines_to_append=0)
    [docs] def at_channel_creation(self): """ @@ -114,6 +135,33 @@ # helper methods, for easy overloading + _log_file = None + +
    [docs] def get_log_filename(self): + """ + File name to use for channel log. + + Returns: + str: The filename to use (this is always assumed to be inside + settings.LOG_DIR) + + """ + if not self._log_file: + self._log_file = self.attributes.get( + "log_file", self.log_file.format(channelname=self.key.lower())) + return self._log_file
    + +
    [docs] def set_log_filename(self, filename): + """ + Set a custom log filename. + + Args: + filename (str): The filename to set. This is a path starting from + inside the settings.LOG_DIR location. + + """ + self.attributes.add("log_file", filename)
    +
    [docs] def has_connection(self, subscriber): """ Checks so this account is actually listening @@ -142,6 +190,10 @@ def mutelist(self): return self.db.mute_list or [] + @property + def banlist(self): + return self.db.ban_list or [] + @property def wholist(self): subs = self.subscriptions.all() @@ -170,6 +222,10 @@ **kwargs (dict): Arbitrary, optional arguments for users overriding the call (unused by default). + Returns: + bool: True if muting was successful, False if we were already + muted. + """ mutelist = self.mutelist if subscriber not in mutelist: @@ -180,19 +236,67 @@
    [docs] def unmute(self, subscriber, **kwargs): """ - Removes an entity to the list of muted subscribers. A muted subscriber will no longer see channel messages, - but may use channel commands. + Removes an entity from the list of muted subscribers. A muted subscriber + will no longer see channel messages, but may use channel commands. Args: subscriber (Object or Account): The subscriber to unmute. **kwargs (dict): Arbitrary, optional arguments for users overriding the call (unused by default). + Returns: + bool: True if unmuting was successful, False if we were already + unmuted. + """ mutelist = self.mutelist if subscriber in mutelist: mutelist.remove(subscriber) - self.db.mute_list = mutelist + return True + return False
    + +
    [docs] def ban(self, target, **kwargs): + """ + Ban a given user from connecting to the channel. This will not stop + users already connected, so the user must be booted for this to take + effect. + + Args: + target (Object or Account): The entity to unmute. This need not + be a subscriber. + **kwargs (dict): Arbitrary, optional arguments for users + overriding the call (unused by default). + + Returns: + bool: True if banning was successful, False if target was already + banned. + """ + banlist = self.banlist + if target not in banlist: + banlist.append(target) + self.db.ban_list = banlist + return True + return False
    + +
    [docs] def unban(self, target, **kwargs): + """ + Un-Ban a given user. This will not reconnect them - they will still + have to reconnect and set up aliases anew. + + Args: + target (Object or Account): The entity to unmute. This need not + be a subscriber. + **kwargs (dict): Arbitrary, optional arguments for users + overriding the call (unused by default). + + Returns: + bool: True if unbanning was successful, False if target was not + previously banned. + """ + banlist = list(self.banlist) + if target in banlist: + banlist = [banned for banned in banlist if banned != target] + self.db.ban_list = banlist return True return False
    @@ -212,7 +316,7 @@ """ # check access - if not self.access(subscriber, "listen"): + if subscriber in self.banlist or not self.access(subscriber, "listen"): return False # pre-join hook connect = self.pre_join_channel(subscriber) @@ -285,7 +389,7 @@ )
    [docs] @classmethod - def create(cls, key, account=None, *args, **kwargs): + def create(cls, key, creator=None, *args, **kwargs): """ Creates a basic Channel with default parameters, unless otherwise specified or extended. @@ -294,7 +398,8 @@ Args: key (str): This must be unique. - account (Account): Account to attribute this object to. + creator (Account or Object): Entity to associate with this channel + (used for tracking) Keyword Args: aliases (list of str): List of alternative (likely shorter) keynames. @@ -322,8 +427,8 @@ # Record creator id and creation IP if ip: obj.db.creator_ip = ip - if account: - obj.db.creator_id = account.id + if creator: + obj.db.creator_id = creator.id except Exception as exc: errors.append("An error occurred while creating this '%s' object." % key) @@ -333,284 +438,189 @@
    [docs] def delete(self): """ - Deletes channel while also cleaning up channelhandler. + Deletes channel. """ self.attributes.clear() self.aliases.clear() - super().delete() - from evennia.comms.channelhandler import CHANNELHANDLER + for subscriber in self.subscriptions.all(): + self.disconnect(subscriber) + super().delete()
    - CHANNELHANDLER.update()
    - -
    [docs] def message_transform( - self, msgobj, emit=False, prefix=True, sender_strings=None, external=False, **kwargs - ): - """ - Generates the formatted string sent to listeners on a channel. - - Args: - msgobj (Msg): Message object to send. - emit (bool, optional): In emit mode the message is not associated - with a specific sender name. - prefix (bool, optional): Prefix `msg` with a text given by `self.channel_prefix`. - sender_strings (list, optional): Used by bots etc, one string per external sender. - external (bool, optional): If this is an external sender or not. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - """ - if sender_strings or external: - body = self.format_external(msgobj, sender_strings, emit=emit) - else: - body = self.format_message(msgobj, emit=emit) - if prefix: - body = "%s%s" % (self.channel_prefix(msgobj, emit=emit), body) - msgobj.message = body - return msgobj
    - -
    [docs] def distribute_message(self, msgobj, online=False, **kwargs): - """ - Method for grabbing all listeners that a message should be - sent to on this channel, and sending them a message. - - Args: - msgobj (Msg or TempMsg): Message to distribute. - online (bool): Only send to receivers who are actually online - (not currently used): - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Notes: - This is also where logging happens, if enabled. - - """ - # get all accounts or objects connected to this channel and send to them - if online: - subs = self.subscriptions.online() - else: - subs = self.subscriptions.all() - for entity in subs: - # if the entity is muted, we don't send them a message - if entity in self.mutelist: - continue - try: - # note our addition of the from_channel keyword here. This could be checked - # by a custom account.msg() to treat channel-receives differently. - entity.msg( - msgobj.message, from_obj=msgobj.senders, options={"from_channel": self.id} - ) - except AttributeError as e: - logger.log_trace("%s\nCannot send msg to '%s'." % (e, entity)) - - if msgobj.keep_log: - # log to file - logger.log_file( - msgobj.message, self.attributes.get("log_file") or "channel_%s.log" % self.key - )
    - -
    [docs] def msg( - self, - msgobj, - header=None, - senders=None, - sender_strings=None, - keep_log=None, - online=False, - emit=False, - external=False, - ): - """ - Send the given message to all accounts connected to channel. Note that - no permission-checking is done here; it is assumed to have been - done before calling this method. The optional keywords are not used if - persistent is False. - - Args: - msgobj (Msg, TempMsg or str): If a Msg/TempMsg, the remaining - keywords will be ignored (since the Msg/TempMsg object already - has all the data). If a string, this will either be sent as-is - (if persistent=False) or it will be used together with `header` - and `senders` keywords to create a Msg instance on the fly. - header (str, optional): A header for building the message. - senders (Object, Account or list, optional): Optional if persistent=False, used - to build senders for the message. - sender_strings (list, optional): Name strings of senders. Used for external - connections where the sender is not an account or object. - When this is defined, external will be assumed. The list will be - filtered so each sender-string only occurs once. - keep_log (bool or None, optional): This allows to temporarily change the logging status of - this channel message. If `None`, the Channel's `keep_log` Attribute will - be used. If `True` or `False`, that logging status will be used for this - message only (note that for unlogged channels, a `True` value here will - create a new log file only for this message). - online (bool, optional) - If this is set true, only messages people who are - online. Otherwise, messages all accounts connected. This can - make things faster, but may not trigger listeners on accounts - that are offline. - emit (bool, optional) - Signals to the message formatter that this message is - not to be directly associated with a name. - external (bool, optional): Treat this message as being - agnostic of its sender. - - Returns: - success (bool): Returns `True` if message sending was - successful, `False` otherwise. - - """ - senders = make_iter(senders) if senders else [] - if isinstance(msgobj, str): - # given msgobj is a string - convert to msgobject (always TempMsg) - msgobj = TempMsg(senders=senders, header=header, message=msgobj, channels=[self]) - # we store the logging setting for use in distribute_message() - msgobj.keep_log = keep_log if keep_log is not None else self.db.keep_log - - # start the sending - msgobj = self.pre_send_message(msgobj) - if not msgobj: - return False - if sender_strings: - sender_strings = list(set(make_iter(sender_strings))) - msgobj = self.message_transform( - msgobj, emit=emit, sender_strings=sender_strings, external=external - ) - self.distribute_message(msgobj, online=online) - self.post_send_message(msgobj) - return True
    - -
    [docs] def tempmsg(self, message, header=None, senders=None): - """ - A wrapper for sending non-persistent messages. - - Args: - message (str): Message to send. - header (str, optional): Header of message to send. - senders (Object or list, optional): Senders of message to send. - - """ - self.msg(message, senders=senders, header=header, keep_log=False)
    - - # hooks - -
    [docs] def channel_prefix(self, msg=None, emit=False, **kwargs): +
    [docs] def channel_prefix(self): """ Hook method. How the channel should prefix itself for users. - Args: - msg (str, optional): Prefix text - emit (bool, optional): Switches to emit mode, which usually - means to not prefix the channel's info. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - Returns: - prefix (str): The created channel prefix. + str: The channel prefix. """ - return "" if emit else "[%s] " % self.key
    + return self.channel_prefix_string.format(channelname=self.key)
    -
    [docs] def format_senders(self, senders=None, **kwargs): +
    [docs] def add_user_channel_alias(self, user, alias, **kwargs): """ - Hook method. Function used to format a list of sender names. + Add a personal user-alias for this channel to a given subscriber. Args: - senders (list): Sender object names. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). + user (Object or Account): The one to alias this channel. + alias (str): The desired alias. - Returns: - formatted_list (str): The list of names formatted appropriately. + Note: + This is tightly coupled to the default `channel` command. If you + change that, you need to change this as well. + + We add two nicks - one is a plain `alias -> channel.key` that + users need to be able to reference this channel easily. The other + is a templated nick to easily be able to send messages to the + channel without needing to give the full `channel` command. The + structure of this nick is given by `self.channel_msg_nick_pattern` + and `self.channel_msg_nick_replacement`. By default it maps + `alias <msg> -> channel <channelname> = <msg>`, so that you can + for example just write `pub Hello` to send a message. + + The alias created is `alias $1 -> channel channel = $1`, to allow + for sending to channel using the main channel command. + + """ + chan_key = self.key.lower() + + # the message-pattern allows us to type the channel on its own without + # needing to use the `channel` command explicitly. + msg_nick_pattern = self.channel_msg_nick_pattern.format(alias=alias) + msg_nick_replacement = self.channel_msg_nick_replacement.format(channelname=chan_key) + user.nicks.add(msg_nick_pattern, msg_nick_replacement, category="inputline", + pattern_is_regex=True, **kwargs) + + if chan_key != alias: + # this allows for using the alias for general channel lookups + user.nicks.add(alias, chan_key, category="channel", **kwargs)
    + +
    [docs] @classmethod + def remove_user_channel_alias(cls, user, alias, **kwargs): + """ + Remove a personal channel alias from a user. + + Args: + user (Object or Account): The user to remove an alias from. + alias (str): The alias to remove. + **kwargs: Unused by default. Can be used to pass extra variables + into a custom implementation. Notes: - This function exists separately so that external sources - can use it to format source names in the same manner as - normal object/account names. + The channel-alias actually consists of two aliases - one + channel-based one for searching channels with the alias and one + inputline one for doing the 'channelalias msg' - call. + + This is a classmethod because it doesn't actually operate on the + channel instance. + + It sits on the channel because the nick structure for this is + pretty complex and needs to be located in a central place (rather + on, say, the channel command). """ - if not senders: - return "" - return ", ".join(senders)
    + user.nicks.remove(alias, category="channel", **kwargs) + msg_nick_pattern = cls.channel_msg_nick_pattern.format(alias=alias) + user.nicks.remove(msg_nick_pattern, category="inputline", **kwargs)
    -
    [docs] def pose_transform(self, msgobj, sender_string, **kwargs): +
    [docs] def at_pre_msg(self, message, **kwargs): """ - Hook method. Detects if the sender is posing, and modifies the - message accordingly. + Called before the starting of sending the message to a receiver. This + is called before any hooks on the receiver itself. If this returns + None/False, the sending will be aborted. Args: - msgobj (Msg or TempMsg): The message to analyze for a pose. - sender_string (str): The name of the sender/poser. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). + message (str): The message to send. + **kwargs (any): Keywords passed on from `.msg`. This includes + `senders`. Returns: - string (str): A message that combines the `sender_string` - component with `msg` in different ways depending on if a - pose was performed or not (this must be analyzed by the - hook). + str, False or None: Any custom changes made to the message. If + falsy, no message will be sent. """ - pose = False - message = msgobj.message - message_start = message.lstrip() - if message_start.startswith((":", ";")): - pose = True - message = message[1:] - if not message.startswith((":", "'", ",")): - if not message.startswith(" "): - message = " " + message - if pose: - return "%s%s" % (sender_string, message) + return message
    + +
    [docs] def msg(self, message, senders=None, bypass_mute=False, **kwargs): + """ + Send message to channel, causing it to be distributed to all non-muted + subscribed users of that channel. + + Args: + message (str): The message to send. + senders (Object, Account or list, optional): If not given, there is + no way to associate one or more senders with the message (like + a broadcast message or similar). + bypass_mute (bool, optional): If set, always send, regardless of + individual mute-state of subscriber. This can be used for + global announcements or warnings/alerts. + **kwargs (any): This will be passed on to all hooks. Use `no_prefix` + to exclude the channel prefix. + + Notes: + The call hook calling sequence is: + + - `msg = channel.at_pre_msg(message, **kwargs)` (aborts for all if return None) + - `msg = receiver.at_pre_channel_msg(msg, channel, **kwargs)` (aborts for receiver if return None) + - `receiver.at_channel_msg(msg, channel, **kwargs)` + - `receiver.at_post_channel_msg(msg, channel, **kwargs)`` + Called after all receivers are processed: + - `channel.at_post_all_msg(message, **kwargs)` + + (where the senders/bypass_mute are embedded into **kwargs for + later access in hooks) + + """ + senders = make_iter(senders) if senders else [] + if self.send_to_online_only: + receivers = self.subscriptions.online() else: - return "%s: %s" % (sender_string, message)
    + receivers = self.subscriptions.all() + if not bypass_mute: + receivers = [receiver for receiver in receivers if receiver not in self.mutelist] -
    [docs] def format_external(self, msgobj, senders, emit=False, **kwargs): + send_kwargs = {'senders': senders, 'bypass_mute': bypass_mute, **kwargs} + + # pre-send hook + message = self.at_pre_msg(message, **send_kwargs) + if message in (None, False): + return + + for receiver in receivers: + # send to each individual subscriber + + try: + recv_message = receiver.at_pre_channel_msg(message, self, **send_kwargs) + if recv_message in (None, False): + return + + receiver.channel_msg(recv_message, self, **send_kwargs) + + receiver.at_post_channel_msg(recv_message, self, **send_kwargs) + + except Exception: + logger.log_trace(f"Error sending channel message to {receiver}.") + + # post-send hook + self.at_post_msg(message, **send_kwargs)
    + +
    [docs] def at_post_msg(self, message, **kwargs): """ - Hook method. Used for formatting external messages. This is - needed as a separate operation because the senders of external - messages may not be in-game objects/accounts, and so cannot - have things like custom user preferences. + This is called after sending to *all* valid recipients. It is normally + used for logging/channel history. Args: - msgobj (Msg or TempMsg): The message to send. - senders (list): Strings, one per sender. - emit (bool, optional): A sender-agnostic message or not. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Returns: - transformed (str): A formatted string. + message (str): The message sent. + **kwargs (any): Keywords passed on from `msg`, including `senders`. """ - if emit or not senders: - return msgobj.message - senders = ", ".join(senders) - return self.pose_transform(msgobj, senders)
    - -
    [docs] def format_message(self, msgobj, emit=False, **kwargs): - """ - Hook method. Formats a message body for display. - - Args: - msgobj (Msg or TempMsg): The message object to send. - emit (bool, optional): The message is agnostic of senders. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Returns: - transformed (str): The formatted message. - - """ - # We don't want to count things like external sources as senders for - # the purpose of constructing the message string. - senders = [sender for sender in msgobj.senders if hasattr(sender, "key")] - if not senders: - emit = True - if emit: - return msgobj.message - else: - senders = [sender.key for sender in msgobj.senders] - senders = ", ".join(senders) - return self.pose_transform(msgobj, senders)
    + # save channel history to log file + log_file = self.get_log_filename() + if log_file: + senders = ",".join(sender.key for sender in kwargs.get("senders", [])) + senders = f"{senders}: " if senders else "" + message = f"{senders}{message}" + logger.log_file(message, log_file)
    [docs] def pre_join_channel(self, joiner, **kwargs): """ @@ -637,8 +647,13 @@ **kwargs (dict): Arbitrary, optional arguments for users overriding the call (unused by default). + Notes: + By default this adds the needed channel nicks to the joiner. + """ - pass
    + key_and_aliases = [self.key.lower()] + [alias.lower() for alias in self.aliases.all()] + for key_or_alias in key_and_aliases: + self.add_user_channel_alias(joiner, key_or_alias, **kwargs)
    [docs] def pre_leave_channel(self, leaver, **kwargs): """ @@ -666,36 +681,12 @@ overriding the call (unused by default). """ - pass
    - -
    [docs] def pre_send_message(self, msg, **kwargs): - """ - Hook method. Runs before a message is sent to the channel and - should return the message object, after any transformations. - If the message is to be discarded, return a false value. - - Args: - msg (Msg or TempMsg): Message to send. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Returns: - result (Msg, TempMsg or bool): If False, abort send. - - """ - return msg
    - -
    [docs] def post_send_message(self, msg, **kwargs): - """ - Hook method. Run after a message is sent to the channel. - - Args: - msg (Msg or TempMsg): Message sent. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - """ - pass
    + chan_key = self.key.lower() + key_or_aliases = [self.key.lower()] + [alias.lower() for alias in self.aliases.all()] + nicktuples = leaver.nicks.get(category="channel", return_tuple=True, return_list=True) + key_or_aliases += [tup[2] for tup in nicktuples if tup[3].lower() == chan_key] + for key_or_alias in key_or_aliases: + self.remove_user_channel_alias(leaver, key_or_alias, **kwargs)
    [docs] def at_init(self): """ @@ -755,7 +746,7 @@ """ try: return reverse("%s-create" % slugify(cls._meta.verbose_name)) - except: + except Exception: return "#"
    [docs] def web_get_detail_url(self): @@ -770,8 +761,10 @@ a named view of 'channel-detail' would be referenced by this method. ex. - url(r'channels/(?P<slug>[\w\d\-]+)/$', - ChannelDetailView.as_view(), name='channel-detail') + :: + + url(r'channels/(?P<slug>[\w\d\-]+)/$', + ChannelDetailView.as_view(), name='channel-detail') If no View has been created and defined in urls.py, returns an HTML anchor. @@ -789,7 +782,7 @@ "%s-detail" % slugify(self._meta.verbose_name), kwargs={"slug": slugify(self.db_key)}, ) - except: + except Exception: return "#"
    [docs] def web_get_update_url(self): @@ -804,8 +797,10 @@ a named view of 'channel-update' would be referenced by this method. ex. - url(r'channels/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/change/$', - ChannelUpdateView.as_view(), name='channel-update') + :: + + url(r'channels/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/change/$', + ChannelUpdateView.as_view(), name='channel-update') If no View has been created and defined in urls.py, returns an HTML anchor. @@ -823,7 +818,7 @@ "%s-update" % slugify(self._meta.verbose_name), kwargs={"slug": slugify(self.db_key)}, ) - except: + except Exception: return "#"
    [docs] def web_get_delete_url(self): @@ -856,11 +851,41 @@ "%s-delete" % slugify(self._meta.verbose_name), kwargs={"slug": slugify(self.db_key)}, ) - except: + except Exception: return "#"
    # Used by Django Sites/Admin - get_absolute_url = web_get_detail_url + get_absolute_url = web_get_detail_url + + # TODO Evennia 1.0+ removed hooks. Remove in 1.1. +
    [docs] def message_transform(self, *args, **kwargs): + raise RuntimeError("Channel.message_transform is no longer used in 1.0+. " + "Use Account/Object.at_pre_channel_msg instead.")
    + +
    [docs] def distribute_message(self, msgobj, online=False, **kwargs): + raise RuntimeError("Channel.distribute_message is no longer used in 1.0+.")
    + +
    [docs] def format_senders(self, senders=None, **kwargs): + raise RuntimeError("Channel.format_senders is no longer used in 1.0+. " + "Use Account/Object.at_pre_channel_msg instead.")
    + +
    [docs] def pose_transform(self, msgobj, sender_string, **kwargs): + raise RuntimeError("Channel.pose_transform is no longer used in 1.0+. " + "Use Account/Object.at_pre_channel_msg instead.")
    + +
    [docs] def format_external(self, msgobj, senders, emit=False, **kwargs): + raise RuntimeError("Channel.format_external is no longer used in 1.0+. " + "Use Account/Object.at_pre_channel_msg instead.")
    + +
    [docs] def format_message(self, msgobj, emit=False, **kwargs): + raise RuntimeError("Channel.format_message is no longer used in 1.0+. " + "Use Account/Object.at_pre_channel_msg instead.")
    + +
    [docs] def pre_send_message(self, msg, **kwargs): + raise RuntimeError("Channel.pre_send_message was renamed to Channel.at_pre_msg.")
    + +
    [docs] def post_send_message(self, msg, **kwargs): + raise RuntimeError("Channel.post_send_message was renamed to Channel.at_post_msg.")
    @@ -898,7 +923,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/comms/managers.html b/docs/0.9.5/_modules/evennia/comms/managers.html index d7154cfc20..b31a5cf45c 100644 --- a/docs/0.9.5/_modules/evennia/comms/managers.html +++ b/docs/0.9.5/_modules/evennia/comms/managers.html @@ -55,6 +55,7 @@ _AccountDB = None _ObjectDB = None _ChannelDB = None +_ScriptDB = None _SESSIONS = None # error class @@ -95,6 +96,8 @@ return inp, "object" elif clsname == "ChannelDB": return inp, "channel" + elif clsname == "ScriptDB": + return inp, "script" if isinstance(inp, str): return inp, "string" elif dbref(inp): @@ -144,6 +147,14 @@ return _ChannelDB.objects.get(id=obj) logger.log_err("%s %s %s %s %s" % (objtype, inp, obj, typ, type(inp))) raise CommError() + elif objtype == "script": + if typ == "string": + return _ScriptDB.objects.get(db_key__iexact=obj) + if typ == "dbref": + return _ScriptDB.objects.get(id=obj) + logger.log_err("%s %s %s %s %s" % (objtype, inp, obj, typ, type(inp))) + raise CommError() + # an unknown return None @@ -199,48 +210,30 @@ except Exception: return None -
    [docs] def get_messages_by_sender(self, sender, exclude_channel_messages=False): +
    [docs] def get_messages_by_sender(self, sender): """ Get all messages sent by one entity - this could be either a account or an object Args: sender (Account or Object): The sender of the message. - exclude_channel_messages (bool, optional): Only return messages - not aimed at a channel (that is, private tells for example) Returns: - messages (list): List of matching messages + QuerySet: Matching messages. Raises: CommError: For incorrect sender types. """ obj, typ = identify_object(sender) - if exclude_channel_messages: - # explicitly exclude channel recipients - if typ == "account": - return list( - self.filter(db_sender_accounts=obj, db_receivers_channels__isnull=True).exclude( - db_hide_from_accounts=obj - ) - ) - elif typ == "object": - return list( - self.filter(db_sender_objects=obj, db_receivers_channels__isnull=True).exclude( - db_hide_from_objects=obj - ) - ) - else: - raise CommError + if typ == "account": + return self.filter(db_sender_accounts=obj).exclude(db_hide_from_accounts=obj) + elif typ == "object": + return self.filter(db_sender_objects=obj).exclude(db_hide_from_objects=obj) + elif typ == "script": + return self.filter(db_sender_scripts=obj) else: - # get everything, channel or not - if typ == "account": - return list(self.filter(db_sender_accounts=obj).exclude(db_hide_from_accounts=obj)) - elif typ == "object": - return list(self.filter(db_sender_objects=obj).exclude(db_hide_from_objects=obj)) - else: - raise CommError
    + raise CommError
    [docs] def get_messages_by_receiver(self, recipient): """ @@ -250,7 +243,7 @@ recipient (Object, Account or Channel): The recipient of the messages to search for. Returns: - messages (list): Matching messages. + Queryset: Matching messages. Raises: CommError: If the `recipient` is not of a valid type. @@ -258,34 +251,21 @@ """ obj, typ = identify_object(recipient) if typ == "account": - return list(self.filter(db_receivers_accounts=obj).exclude(db_hide_from_accounts=obj)) + return self.filter(db_receivers_accounts=obj).exclude(db_hide_from_accounts=obj) elif typ == "object": - return list(self.filter(db_receivers_objects=obj).exclude(db_hide_from_objects=obj)) - elif typ == "channel": - return list(self.filter(db_receivers_channels=obj).exclude(db_hide_from_channels=obj)) + return self.filter(db_receivers_objects=obj).exclude(db_hide_from_objects=obj) + elif typ == 'script': + return self.filter(db_receivers_scripts=obj) else: raise CommError
    -
    [docs] def get_messages_by_channel(self, channel): - """ - Get all persistent messages sent to one channel. - - Args: - channel (Channel): The channel to find messages for. - - Returns: - messages (list): Persistent Msg objects saved for this channel. - - """ - return self.filter(db_receivers_channels=channel).exclude(db_hide_from_channels=channel)
    -
    [docs] def search_message(self, sender=None, receiver=None, freetext=None, dbref=None): """ Search the message database for particular messages. At least one of the arguments must be given to do a search. Args: - sender (Object or Account, optional): Get messages sent by a particular account or object + sender (Object, Account or Script, optional): Get messages sent by a particular sender. receiver (Object, Account or Channel, optional): Get messages received by a certain account,object or channel freetext (str): Search for a text string in a message. NOTE: @@ -296,40 +276,45 @@ always gives only one match. Returns: - messages (list or Msg): A list of message matches or a single match if `dbref` was given. + Queryset: Message matches. """ # unique msg id if dbref: - msg = self.objects.filter(id=dbref) - if msg: - return msg[0] + return self.objects.filter(id=dbref) # We use Q objects to gradually build up the query - this way we only # need to do one database lookup at the end rather than gradually # refining with multiple filter:s. Django Note: Q objects can be # combined with & and | (=AND,OR). ~ negates the queryset - # filter by sender + # filter by sender (we need __pk to avoid an error with empty Q() objects) sender, styp = identify_object(sender) + if sender: + spk = sender.pk if styp == "account": - sender_restrict = Q(db_sender_accounts=sender) & ~Q(db_hide_from_accounts=sender) + sender_restrict = Q(db_sender_accounts__pk=spk) & ~Q(db_hide_from_accounts__pk=spk) elif styp == "object": - sender_restrict = Q(db_sender_objects=sender) & ~Q(db_hide_from_objects=sender) + sender_restrict = Q(db_sender_objects__pk=spk) & ~Q(db_hide_from_objects__pk=spk) + elif styp == 'script': + sender_restrict = Q(db_sender_scripts__pk=spk) else: sender_restrict = Q() # filter by receiver receiver, rtyp = identify_object(receiver) + if receiver: + rpk = receiver.pk if rtyp == "account": - receiver_restrict = Q(db_receivers_accounts=receiver) & ~Q( - db_hide_from_accounts=receiver - ) + receiver_restrict = ( + Q(db_receivers_accounts__pk=rpk) & ~Q(db_hide_from_accounts__pk=rpk)) elif rtyp == "object": - receiver_restrict = Q(db_receivers_objects=receiver) & ~Q(db_hide_from_objects=receiver) + receiver_restrict = Q(db_receivers_objects__pk=rpk) & ~Q(db_hide_from_objects__pk=rpk) + elif rtyp == 'script': + receiver_restrict = Q(db_receivers_scripts__pk=rpk) elif rtyp == "channel": - receiver_restrict = Q(db_receivers_channels=receiver) & ~Q( - db_hide_from_channels=receiver - ) + raise DeprecationWarning( + "Msg.objects.search don't accept channel recipients since " + "Channels no longer accepts Msg objects.") else: receiver_restrict = Q() # filter by full text @@ -338,7 +323,7 @@ else: fulltext_restrict = Q() # execute the query - return list(self.filter(sender_restrict & receiver_restrict & fulltext_restrict))
    + return self.filter(sender_restrict & receiver_restrict & fulltext_restrict) # back-compatibility alias message_search = search_message @@ -491,7 +476,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/comms/models.html b/docs/0.9.5/_modules/evennia/comms/models.html index 9fc772f293..dcf1e67da1 100644 --- a/docs/0.9.5/_modules/evennia/comms/models.html +++ b/docs/0.9.5/_modules/evennia/comms/models.html @@ -57,6 +57,7 @@ Channels are central objects that act as targets for Msgs. Accounts can connect to channels by use of a ChannelConnect object (this object is necessary to easily be able to delete connections on the fly). + """ from django.conf import settings from django.utils import timezone @@ -75,8 +76,6 @@ _SA = object.__setattr__ _DA = object.__delattr__ -_CHANNELHANDLER = None - # ------------------------------------------------------------ # @@ -85,7 +84,7 @@ # ------------------------------------------------------------ -
    [docs]class Msg(SharedMemoryModel): +
    [docs]class Msg(SharedMemoryModel): """ A single message. This model describes all ooc messages sent in-game, both to channels and between accounts. @@ -96,17 +95,16 @@ - db_sender_accounts: Account senders - db_sender_objects: Object senders - db_sender_scripts: Script senders - - db_sender_external: External senders (defined as string names) + - db_sender_external: External sender (defined as string name) - db_receivers_accounts: Receiving accounts - db_receivers_objects: Receiving objects - db_receivers_scripts: Receiveing scripts - - db_receivers_channels: Receiving channels + - db_receiver_external: External sender (defined as string name) - db_header: Header text - db_message: The actual message text - db_date_created: time message was created / sent - db_hide_from_sender: bool if message should be hidden from sender - db_hide_from_receivers: list of receiver objects to hide message from - - db_hide_from_channels: list of channels objects to hide message from - db_lock_storage: Internal storage of lock strings. """ @@ -118,14 +116,11 @@ # These databse fields are all set using their corresponding properties, # named same as the field, but withtout the db_* prefix. - # Sender is either an account, an object or an external sender, like - # an IRC channel; normally there is only one, but if co-modification of - # a message is allowed, there may be more than one "author" db_sender_accounts = models.ManyToManyField( "accounts.AccountDB", related_name="sender_account_set", blank=True, - verbose_name="sender(account)", + verbose_name="Senders (Accounts)", db_index=True, ) @@ -133,14 +128,14 @@ "objects.ObjectDB", related_name="sender_object_set", blank=True, - verbose_name="sender(object)", + verbose_name="Senders (Objects)", db_index=True, ) db_sender_scripts = models.ManyToManyField( "scripts.ScriptDB", related_name="sender_script_set", blank=True, - verbose_name="sender(script)", + verbose_name="Senders (Scripts)", db_index=True, ) db_sender_external = models.CharField( @@ -149,16 +144,15 @@ null=True, blank=True, db_index=True, - help_text="identifier for external sender, for example a sender over an " - "IRC connection (i.e. someone who doesn't have an exixtence in-game).", + help_text="Identifier for single external sender, for use with senders " + "not represented by a regular database model." ) - # The destination objects of this message. Stored as a - # comma-separated string of object dbrefs. Can be defined along - # with channels below. + db_receivers_accounts = models.ManyToManyField( "accounts.AccountDB", related_name="receiver_account_set", blank=True, + verbose_name="Receivers (Accounts)", help_text="account receivers", ) @@ -166,16 +160,25 @@ "objects.ObjectDB", related_name="receiver_object_set", blank=True, + verbose_name="Receivers (Objects)", help_text="object receivers", ) db_receivers_scripts = models.ManyToManyField( "scripts.ScriptDB", related_name="receiver_script_set", blank=True, + verbose_name="Receivers (Scripts)", help_text="script_receivers", ) - db_receivers_channels = models.ManyToManyField( - "ChannelDB", related_name="channel_set", blank=True, help_text="channel recievers" + + db_receiver_external = models.CharField( + "external receiver", + max_length=1024, + null=True, + blank=True, + db_index=True, + help_text="Identifier for single external receiver, for use with recievers " + "not represented by a regular database model." ) # header could be used for meta-info about the message if your system needs @@ -192,7 +195,7 @@ "locks", blank=True, help_text="access locks on this message." ) - # these can be used to filter/hide a given message from supplied objects/accounts/channels + # these can be used to filter/hide a given message from supplied objects/accounts db_hide_from_accounts = models.ManyToManyField( "accounts.AccountDB", related_name="hide_from_accounts_set", blank=True ) @@ -200,33 +203,27 @@ db_hide_from_objects = models.ManyToManyField( "objects.ObjectDB", related_name="hide_from_objects_set", blank=True ) - db_hide_from_channels = models.ManyToManyField( - "ChannelDB", related_name="hide_from_channels_set", blank=True - ) db_tags = models.ManyToManyField( Tag, blank=True, - help_text="tags on this message. Tags are simple string markers to identify, group and alias messages.", + help_text="tags on this message. Tags are simple string markers to " + "identify, group and alias messages.", ) # Database manager objects = managers.MsgManager() _is_deleted = False -
    [docs] def __init__(self, *args, **kwargs): - SharedMemoryModel.__init__(self, *args, **kwargs) - self.extra_senders = []
    - class Meta(object): "Define Django meta options" verbose_name = "Msg" -
    [docs] @lazy_property +
    [docs] @lazy_property def locks(self): return LockHandler(self)
    -
    [docs] @lazy_property +
    [docs] @lazy_property def tags(self): return TagHandler(self)
    @@ -238,28 +235,28 @@ # value = self.attr and del self.attr respectively (where self # is the object in question). - # sender property (wraps db_sender_*) - # @property - def __senders_get(self): - "Getter. Allows for value = self.sender" + @property + def senders(self): + "Getter. Allows for value = self.senders" return ( list(self.db_sender_accounts.all()) + list(self.db_sender_objects.all()) + list(self.db_sender_scripts.all()) - + self.extra_senders + + ([self.db_sender_external] if self.db_sender_external else []) ) - # @sender.setter - def __senders_set(self, senders): + @senders.setter + def senders(self, senders): "Setter. Allows for self.sender = value" + + if isinstance(senders, str): + self.db_sender_external = senders + self.save(update_fields=["db_sender_external"]) + return + for sender in make_iter(senders): if not sender: continue - if isinstance(sender, str): - self.db_sender_external = sender - self.extra_senders.append(sender) - self.save(update_fields=["db_sender_external"]) - continue if not hasattr(sender, "__dbclass__"): raise ValueError("This is a not a typeclassed object!") clsname = sender.__dbclass__.__name__ @@ -270,32 +267,32 @@ elif clsname == "ScriptDB": self.db_sender_scripts.add(sender) - # @sender.deleter - def __senders_del(self): + @senders.deleter + def senders(self): "Deleter. Clears all senders" self.db_sender_accounts.clear() self.db_sender_objects.clear() self.db_sender_scripts.clear() self.db_sender_external = "" - self.extra_senders = [] self.save() - senders = property(__senders_get, __senders_set, __senders_del) - -
    [docs] def remove_sender(self, senders): +
    [docs] def remove_sender(self, senders): """ Remove a single sender or a list of senders. Args: senders (Account, Object, str or list): Senders to remove. + If a string, removes the external sender. """ + if isinstance(senders, str): + self.db_sender_external = "" + self.save(update_fields=["db_sender_external"]) + return + for sender in make_iter(senders): if not sender: continue - if isinstance(sender, str): - self.db_sender_external = "" - self.save(update_fields=["db_sender_external"]) if not hasattr(sender, "__dbclass__"): raise ValueError("This is a not a typeclassed object!") clsname = sender.__dbclass__.__name__ @@ -306,26 +303,33 @@ elif clsname == "ScriptDB": self.db_sender_accounts.remove(sender)
    - # receivers property - # @property - def __receivers_get(self): + @property + def receivers(self): """ Getter. Allows for value = self.receivers. - Returns four lists of receivers: accounts, objects, scripts and channels. + Returns four lists of receivers: accounts, objects, scripts and + external_receivers. + """ return ( list(self.db_receivers_accounts.all()) + list(self.db_receivers_objects.all()) + list(self.db_receivers_scripts.all()) - + list(self.db_receivers_channels.all()) + + ([self.db_receiver_external] if self.db_receiver_external else []) ) - # @receivers.setter - def __receivers_set(self, receivers): + @receivers.setter + def receivers(self, receivers): """ - Setter. Allows for self.receivers = value. - This appends a new receiver to the message. + Setter. Allows for self.receivers = value. This appends a new receiver + to the message. If a string, replaces an external receiver. + """ + if isinstance(receivers, str): + self.db_receiver_external = receivers + self.save(update_fields=['db_receiver_external']) + return + for receiver in make_iter(receivers): if not receiver: continue @@ -338,32 +342,34 @@ self.db_receivers_accounts.add(receiver) elif clsname == "ScriptDB": self.db_receivers_scripts.add(receiver) - elif clsname == "ChannelDB": - self.db_receivers_channels.add(receiver) - # @receivers.deleter - def __receivers_del(self): + @receivers.deleter + def receivers(self): "Deleter. Clears all receivers" self.db_receivers_accounts.clear() self.db_receivers_objects.clear() self.db_receivers_scripts.clear() - self.db_receivers_channels.clear() + self.db_receiver_external = "" self.save() - receivers = property(__receivers_get, __receivers_set, __receivers_del) - -
    [docs] def remove_receiver(self, receivers): +
    [docs] def remove_receiver(self, receivers): """ - Remove a single receiver or a list of receivers. + Remove a single receiver, a list of receivers, or a single extral receiver. Args: - receivers (Account, Object, Script, Channel or list): Receiver to remove. + receivers (Account, Object, Script, list or str): Receiver + to remove. A string removes the external receiver. """ + if isinstance(receivers, str): + self.db_receiver_external = "" + self.save(update_fields="db_receiver_external") + return + for receiver in make_iter(receivers): if not receiver: continue - if not hasattr(receiver, "__dbclass__"): + elif not hasattr(receiver, "__dbclass__"): raise ValueError("This is a not a typeclassed object!") clsname = receiver.__dbclass__.__name__ if clsname == "ObjectDB": @@ -371,47 +377,26 @@ elif clsname == "AccountDB": self.db_receivers_accounts.remove(receiver) elif clsname == "ScriptDB": - self.db_receivers_scripts.remove(receiver) - elif clsname == "ChannelDB": - self.db_receivers_channels.remove(receiver)
    + self.db_receivers_scripts.remove(receiver)
    - # channels property - # @property - def __channels_get(self): - "Getter. Allows for value = self.channels. Returns a list of channels." - return self.db_receivers_channels.all() - - # @channels.setter - def __channels_set(self, value): - """ - Setter. Allows for self.channels = value. - Requires a channel to be added. - """ - for val in (v for v in make_iter(value) if v): - self.db_receivers_channels.add(val) - - # @channels.deleter - def __channels_del(self): - "Deleter. Allows for del self.channels" - self.db_receivers_channels.clear() - self.save() - - channels = property(__channels_get, __channels_set, __channels_del) - - def __hide_from_get(self): + @property + def hide_from(self): """ Getter. Allows for value = self.hide_from. - Returns 3 lists of accounts, objects and channels + Returns two lists of accounts and objects. + """ return ( self.db_hide_from_accounts.all(), self.db_hide_from_objects.all(), - self.db_hide_from_channels.all(), ) - # @hide_from_sender.setter - def __hide_from_set(self, hiders): - "Setter. Allows for self.hide_from = value. Will append to hiders" + @hide_from.setter + def hide_from(self, hiders): + """ + Setter. Allows for self.hide_from = value. Will append to hiders. + + """ for hider in make_iter(hiders): if not hider: continue @@ -422,34 +407,31 @@ self.db_hide_from_accounts.add(hider.__dbclass__) elif clsname == "ObjectDB": self.db_hide_from_objects.add(hider.__dbclass__) - elif clsname == "ChannelDB": - self.db_hide_from_channels.add(hider.__dbclass__) - # @hide_from_sender.deleter - def __hide_from_del(self): - "Deleter. Allows for del self.hide_from_senders" + @hide_from.deleter + def hide_from(self): + """ + Deleter. Allows for del self.hide_from_senders + + """ self.db_hide_from_accounts.clear() self.db_hide_from_objects.clear() - self.db_hide_from_channels.clear() self.save() - hide_from = property(__hide_from_get, __hide_from_set, __hide_from_del) - # # Msg class methods # def __str__(self): - "This handles what is shown when e.g. printing the message" - senders = ",".join(getattr(obj, "key", str(obj)) for obj in self.senders) + """ + This handles what is shown when e.g. printing the message. - receivers = ",".join( - ["[%s]" % getattr(obj, "key", str(obj)) for obj in self.channels] - + [getattr(obj, "key", str(obj)) for obj in self.receivers] - ) + """ + senders = ",".join(getattr(obj, "key", str(obj)) for obj in self.senders) + receivers = ",".join(getattr(obj, "key", str(obj)) for obj in self.receivers) return "%s->%s: %s" % (senders, receivers, crop(self.message, width=40)) -
    [docs] def access(self, accessing_obj, access_type="read", default=False): +
    [docs] def access(self, accessing_obj, access_type="read", default=False): """ Checks lock access. @@ -472,19 +454,17 @@ # ------------------------------------------------------------ -
    [docs]class TempMsg(object): +
    [docs]class TempMsg(object): """ - This is a non-persistent object for sending temporary messages - that will not be stored. It mimics the "real" Msg object, but - doesn't require sender to be given. + This is a non-persistent object for sending temporary messages that will not be stored. It + mimics the "real" Msg object, but doesn't require sender to be given. """ -
    [docs] def __init__( +
    [docs] def __init__( self, senders=None, receivers=None, - channels=None, message="", header="", type="", @@ -496,18 +476,16 @@ Args: senders (any or list, optional): Senders of the message. - receivers (Account, Object, Channel or list, optional): Receivers of this message. - channels (Channel or list, optional): Channels to send to. + receivers (Account, Object, Script or list, optional): Receivers of this message. message (str, optional): Message to send. header (str, optional): Header of message. type (str, optional): Message class, if any. lockstring (str, optional): Lock for the message. - hide_from (Account, Object, Channel or list, optional): Entities to hide this message from. + hide_from (Account, Object, or list, optional): Entities to hide this message from. """ self.senders = senders and make_iter(senders) or [] self.receivers = receivers and make_iter(receivers) or [] - self.channels = channels and make_iter(channels) or [] self.type = type self.header = header self.message = message @@ -515,21 +493,20 @@ self.hide_from = hide_from and make_iter(hide_from) or [] self.date_created = timezone.now()
    -
    [docs] @lazy_property +
    [docs] @lazy_property def locks(self): return LockHandler(self)
    def __str__(self): """ This handles what is shown when e.g. printing the message. + """ senders = ",".join(obj.key for obj in self.senders) - receivers = ",".join( - ["[%s]" % obj.key for obj in self.channels] + [obj.key for obj in self.receivers] - ) + receivers = ",".join(obj.key for obj in self.receivers) return "%s->%s: %s" % (senders, receivers, crop(self.message, width=40)) -
    [docs] def remove_sender(self, sender): +
    [docs] def remove_sender(self, sender): """ Remove a sender or a list of senders. @@ -543,12 +520,13 @@ except ValueError: pass # nothing to remove
    -
    [docs] def remove_receiver(self, receiver): +
    [docs] def remove_receiver(self, receiver): """ Remove a receiver or a list of receivers Args: - receiver (Object, Account, Channel, str or list): Receivers to remove. + receiver (Object, Account, Script, str or list): Receivers to remove. + """ for o in make_iter(receiver): @@ -557,7 +535,7 @@ except ValueError: pass # nothing to remove
    -
    [docs] def access(self, accessing_obj, access_type="read", default=False): +
    [docs] def access(self, accessing_obj, access_type="read", default=False): """ Checks lock access. @@ -585,6 +563,7 @@ This handler manages subscriptions to the channel and hides away which type of entity is subscribing (Account or Object) + """ def __init__(self, obj): @@ -644,9 +623,6 @@ no hooks will be called. """ - global _CHANNELHANDLER - if not _CHANNELHANDLER: - from evennia.comms.channelhandler import CHANNEL_HANDLER as _CHANNELHANDLER for subscriber in make_iter(entity): if subscriber: clsname = subscriber.__dbclass__.__name__ @@ -655,7 +631,6 @@ self.obj.db_object_subscriptions.add(subscriber) elif clsname == "AccountDB": self.obj.db_account_subscriptions.add(subscriber) - _CHANNELHANDLER._cached_cmdsets.pop(subscriber, None) self._recache() def remove(self, entity): @@ -667,9 +642,6 @@ entities to un-subscribe from the channel. """ - global _CHANNELHANDLER - if not _CHANNELHANDLER: - from evennia.comms.channelhandler import CHANNEL_HANDLER as _CHANNELHANDLER for subscriber in make_iter(entity): if subscriber: clsname = subscriber.__dbclass__.__name__ @@ -678,7 +650,6 @@ self.obj.db_account_subscriptions.remove(entity) elif clsname == "ObjectDB": self.obj.db_object_subscriptions.remove(entity) - _CHANNELHANDLER._cached_cmdsets.pop(subscriber, None) self._recache() def all(self): @@ -714,7 +685,8 @@ if not obj.is_connected: continue except ObjectDoesNotExist: - # a subscribed object has already been deleted. Mark that we need a recache and ignore it + # a subscribed object has already been deleted. Mark that we need a recache and + # ignore it recache_needed = True continue subs.append(obj) @@ -732,7 +704,7 @@ self._cache = None -
    [docs]class ChannelDB(TypedObject): +
    [docs]class ChannelDB(TypedObject): """ This is the basis of a comm channel, only implementing the very basics of distributing messages. @@ -768,7 +740,7 @@ __defaultclasspath__ = "evennia.comms.comms.DefaultChannel" __applabel__ = "comms" - class Meta(object): + class Meta: "Define Django meta options" verbose_name = "Channel" verbose_name_plural = "Channels" @@ -777,7 +749,7 @@ "Echoes the text representation of the channel." return "Channel '%s' (%s)" % (self.key, self.db.desc) -
    [docs] @lazy_property +
    [docs] @lazy_property def subscriptions(self): return SubscriptionHandler(self)
    @@ -817,7 +789,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/barter.html b/docs/0.9.5/_modules/evennia/contrib/barter.html index adf1069095..205d0065d5 100644 --- a/docs/0.9.5/_modules/evennia/contrib/barter.html +++ b/docs/0.9.5/_modules/evennia/contrib/barter.html @@ -973,7 +973,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/building_menu.html b/docs/0.9.5/_modules/evennia/contrib/building_menu.html index 3d5bdb65af..6939ddba31 100644 --- a/docs/0.9.5/_modules/evennia/contrib/building_menu.html +++ b/docs/0.9.5/_modules/evennia/contrib/building_menu.html @@ -1343,7 +1343,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/chargen.html b/docs/0.9.5/_modules/evennia/contrib/chargen.html index 6d57c57ca9..d302b3b6b9 100644 --- a/docs/0.9.5/_modules/evennia/contrib/chargen.html +++ b/docs/0.9.5/_modules/evennia/contrib/chargen.html @@ -270,7 +270,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/clothing.html b/docs/0.9.5/_modules/evennia/contrib/clothing.html index 5dce751a9b..40db39578d 100644 --- a/docs/0.9.5/_modules/evennia/contrib/clothing.html +++ b/docs/0.9.5/_modules/evennia/contrib/clothing.html @@ -820,7 +820,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/custom_gametime.html b/docs/0.9.5/_modules/evennia/contrib/custom_gametime.html index d74af263bd..53f53dd4b9 100644 --- a/docs/0.9.5/_modules/evennia/contrib/custom_gametime.html +++ b/docs/0.9.5/_modules/evennia/contrib/custom_gametime.html @@ -385,7 +385,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/dice.html b/docs/0.9.5/_modules/evennia/contrib/dice.html index 2983a03220..269d803342 100644 --- a/docs/0.9.5/_modules/evennia/contrib/dice.html +++ b/docs/0.9.5/_modules/evennia/contrib/dice.html @@ -338,7 +338,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/email_login.html b/docs/0.9.5/_modules/evennia/contrib/email_login.html index 914a12518d..e6544f6c4f 100644 --- a/docs/0.9.5/_modules/evennia/contrib/email_login.html +++ b/docs/0.9.5/_modules/evennia/contrib/email_login.html @@ -439,7 +439,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/extended_room.html b/docs/0.9.5/_modules/evennia/contrib/extended_room.html index 18def7d2b1..ae18579d05 100644 --- a/docs/0.9.5/_modules/evennia/contrib/extended_room.html +++ b/docs/0.9.5/_modules/evennia/contrib/extended_room.html @@ -669,7 +669,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/fieldfill.html b/docs/0.9.5/_modules/evennia/contrib/fieldfill.html index b10827b972..49286fc90b 100644 --- a/docs/0.9.5/_modules/evennia/contrib/fieldfill.html +++ b/docs/0.9.5/_modules/evennia/contrib/fieldfill.html @@ -792,7 +792,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/gendersub.html b/docs/0.9.5/_modules/evennia/contrib/gendersub.html index 9013cd8b45..22f74f657e 100644 --- a/docs/0.9.5/_modules/evennia/contrib/gendersub.html +++ b/docs/0.9.5/_modules/evennia/contrib/gendersub.html @@ -233,7 +233,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/health_bar.html b/docs/0.9.5/_modules/evennia/contrib/health_bar.html index 325e46a1aa..b84d903cbc 100644 --- a/docs/0.9.5/_modules/evennia/contrib/health_bar.html +++ b/docs/0.9.5/_modules/evennia/contrib/health_bar.html @@ -196,7 +196,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/ingame_python/callbackhandler.html b/docs/0.9.5/_modules/evennia/contrib/ingame_python/callbackhandler.html index 98f7d9345f..0f3d64a098 100644 --- a/docs/0.9.5/_modules/evennia/contrib/ingame_python/callbackhandler.html +++ b/docs/0.9.5/_modules/evennia/contrib/ingame_python/callbackhandler.html @@ -301,7 +301,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/ingame_python/commands.html b/docs/0.9.5/_modules/evennia/contrib/ingame_python/commands.html index 0319d5e8b2..3c17bb1d7b 100644 --- a/docs/0.9.5/_modules/evennia/contrib/ingame_python/commands.html +++ b/docs/0.9.5/_modules/evennia/contrib/ingame_python/commands.html @@ -659,7 +659,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/ingame_python/eventfuncs.html b/docs/0.9.5/_modules/evennia/contrib/ingame_python/eventfuncs.html index 35c7bdaf3c..9ef301682f 100644 --- a/docs/0.9.5/_modules/evennia/contrib/ingame_python/eventfuncs.html +++ b/docs/0.9.5/_modules/evennia/contrib/ingame_python/eventfuncs.html @@ -167,7 +167,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/ingame_python/scripts.html b/docs/0.9.5/_modules/evennia/contrib/ingame_python/scripts.html index ad9d0c65f1..e80dd73b14 100644 --- a/docs/0.9.5/_modules/evennia/contrib/ingame_python/scripts.html +++ b/docs/0.9.5/_modules/evennia/contrib/ingame_python/scripts.html @@ -87,9 +87,10 @@ self.db.locked = [] # Tasks - self.db.tasks = {} + self.db.tasks = {} + self.at_server_start() -
    [docs] def at_start(self): +
    [docs] def at_server_start(self): """Set up the event system when starting. Note that this hook is called every time the server restarts @@ -744,7 +745,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/ingame_python/tests.html b/docs/0.9.5/_modules/evennia/contrib/ingame_python/tests.html index ea798cb63c..ef624b2852 100644 --- a/docs/0.9.5/_modules/evennia/contrib/ingame_python/tests.html +++ b/docs/0.9.5/_modules/evennia/contrib/ingame_python/tests.html @@ -89,7 +89,7 @@ """Stop the event handler.""" OLD_EVENTS.clear() OLD_EVENTS.update(self.handler.ndb.events) - self.handler.stop() + self.handler.delete() CallbackHandler.script = None super().tearDown() @@ -311,11 +311,11 @@ """Stop the callback handler.""" OLD_EVENTS.clear() OLD_EVENTS.update(self.handler.ndb.events) - self.handler.stop() + self.handler.delete() for script in ScriptDB.objects.filter( db_typeclass_path="evennia.contrib.ingame_python.scripts.TimeEventScript" ): - script.stop() + script.delete() CallbackHandler.script = None super().tearDown() @@ -490,7 +490,7 @@ """Stop the callback handler.""" OLD_EVENTS.clear() OLD_EVENTS.update(self.handler.ndb.events) - self.handler.stop() + self.handler.delete() CallbackHandler.script = None super().tearDown() @@ -619,7 +619,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/ingame_python/utils.html b/docs/0.9.5/_modules/evennia/contrib/ingame_python/utils.html index ebd2427efb..889d22bd05 100644 --- a/docs/0.9.5/_modules/evennia/contrib/ingame_python/utils.html +++ b/docs/0.9.5/_modules/evennia/contrib/ingame_python/utils.html @@ -99,7 +99,6 @@ typeclass_name = typeclass.__module__ + "." + typeclass.__name__ try: storage = ScriptDB.objects.get(db_key="event_handler") - assert storage.is_active assert storage.ndb.events is not None except (ScriptDB.DoesNotExist, AssertionError): storage = EVENTS @@ -339,7 +338,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/mail.html b/docs/0.9.5/_modules/evennia/contrib/mail.html index bd161c4d4f..3cf0aa13f0 100644 --- a/docs/0.9.5/_modules/evennia/contrib/mail.html +++ b/docs/0.9.5/_modules/evennia/contrib/mail.html @@ -435,7 +435,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/multidescer.html b/docs/0.9.5/_modules/evennia/contrib/multidescer.html index 55e4b093bb..a06b7a5bb1 100644 --- a/docs/0.9.5/_modules/evennia/contrib/multidescer.html +++ b/docs/0.9.5/_modules/evennia/contrib/multidescer.html @@ -346,7 +346,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/puzzles.html b/docs/0.9.5/_modules/evennia/contrib/puzzles.html index 124489a007..5803f4e598 100644 --- a/docs/0.9.5/_modules/evennia/contrib/puzzles.html +++ b/docs/0.9.5/_modules/evennia/contrib/puzzles.html @@ -890,7 +890,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/random_string_generator.html b/docs/0.9.5/_modules/evennia/contrib/random_string_generator.html index da44639d33..26a8f6b45f 100644 --- a/docs/0.9.5/_modules/evennia/contrib/random_string_generator.html +++ b/docs/0.9.5/_modules/evennia/contrib/random_string_generator.html @@ -430,7 +430,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/rplanguage.html b/docs/0.9.5/_modules/evennia/contrib/rplanguage.html index 49b532011a..3f97eb48da 100644 --- a/docs/0.9.5/_modules/evennia/contrib/rplanguage.html +++ b/docs/0.9.5/_modules/evennia/contrib/rplanguage.html @@ -101,21 +101,46 @@ Below is an example of "elvish", using "rounder" vowels and sounds: ```python - phonemes = "oi oh ee ae aa eh ah ao aw ay er ey ow ia ih iy " \ - "oy ua uh uw y p b t d f v t dh s z sh zh ch jh k " \ - "ng g m n l r w", + # vowel/consonant grammar possibilities + grammar = ("v vv vvc vcc vvcc cvvc vccv vvccv vcvccv vcvcvcc vvccvvcc " + "vcvvccvvc cvcvvcvvcc vcvcvvccvcvv") + + # all not in this group is considered a consonant vowels = "eaoiuy" - grammar = "v vv vvc vcc vvcc cvvc vccv vvccv vcvccv vcvcvcc vvccvvcc " \ - "vcvvccvvc cvcvvcvvcc vcvcvvccvcvv", + + # you need a representative of all of the minimal grammars here, so if a + # grammar v exists, there must be atleast one phoneme available with only + # one vowel in it + phonemes = ("oi oh ee ae aa eh ah ao aw ay er ey ow ia ih iy " + "oy ua uh uw y p b t d f v t dh s z sh zh ch jh k " + "ng g m n l r w") + + # how much the translation varies in length compared to the original. 0 is + # smallest, higher values give ever bigger randomness (including removing + # short words entirely) word_length_variance = 1 + + # if a proper noun (word starting with capitalized letter) should be + # translated or not. If not (default) it means e.g. names will remain + # unchanged across languages. + noun_translate = False + + # all proper nouns (words starting with a capital letter not at the beginning + # of a sentence) can have either a postfix or -prefix added at all times noun_postfix = "'la" + + # words in dict will always be translated this way. The 'auto_translations' + # is instead a list or filename to file with words to use to help build a + # bigger dictionary by creating random translations of each word in the + # list *once* and saving the result for subsequent use. manual_translations = {"the":"y'e", "we":"uyi", "she":"semi", "he":"emi", "you": "do", 'me':'mi','i':'me', 'be':"hy'e", 'and':'y'} rplanguage.add_language(key="elvish", phonemes=phonemes, grammar=grammar, word_length_variance=word_length_variance, + noun_translate=noun_translate, noun_postfix=noun_postfix, vowels=vowels, - manual_translations=manual_translations + manual_translations=manual_translations, auto_translations="my_word_file.txt") ``` @@ -158,7 +183,8 @@ _RE_FLAGS = re.MULTILINE + re.IGNORECASE + re.DOTALL + re.UNICODE _RE_GRAMMAR = re.compile(r"vv|cc|v|c", _RE_FLAGS) _RE_WORD = re.compile(r"\w+", _RE_FLAGS) -_RE_EXTRA_CHARS = re.compile(r"\s+(?=\W)|[,.?;](?=[,.?;]|\s+[,.?;])", _RE_FLAGS) +# superfluous chars, except ` ... ` +_RE_EXTRA_CHARS = re.compile(r"\s+(?!... )(?=\W)|[,.?;](?!.. )(?=[,?;]|\s+[,.?;])", _RE_FLAGS)
    [docs]class LanguageError(RuntimeError): @@ -239,9 +265,13 @@ 0 means a minimal variance, higher variance may mean words have wildly varying length; this strongly affects how the language "looks". - noun_translate (bool, optional): If a proper noun, identified as a - capitalized word, should be translated or not. By default they - will not, allowing for e.g. the names of characters to be understandable. + noun_translate (bool, optional): If a proper noun should be translated or + not. By default they will not, allowing for e.g. the names of characters + to be understandable. A 'noun' is identified as a capitalized word + *not at the start of a sentence*. This simple metric means that names + starting a sentence always will be translated (- but hey, maybe + the fantasy language just never uses a noun at the beginning of + sentences, who knows?) noun_prefix (str, optional): A prefix to go before every noun in this language (if any). noun_postfix (str, optuonal): A postfix to go after every noun @@ -286,7 +316,7 @@ # {"vv": ["ea", "oh", ...], ...} grammar2phonemes = defaultdict(list) for phoneme in phonemes.split(): - if re.search("\W", phoneme): + if re.search(r"\W", phoneme): raise LanguageError("The phoneme '%s' contains an invalid character" % phoneme) gram = "".join(["v" if char in vowels else "c" for char in phoneme]) grammar2phonemes[gram].append(phoneme) @@ -294,7 +324,7 @@ # allowed grammar are grouped by length gramdict = defaultdict(list) for gram in grammar.split(): - if re.search("\W|(!=[cv])", gram): + if re.search(r"\W|(!=[cv])", gram): raise LanguageError( "The grammar '%s' is invalid (only 'c' and 'v' are allowed)" % gram ) @@ -321,7 +351,13 @@ # use the corresponding length structure = choice(grammar[wlen]) for match in _RE_GRAMMAR.finditer(structure): - new_word += choice(grammar2phonemes[match.group()]) + try: + new_word += choice(grammar2phonemes[match.group()]) + except IndexError: + raise IndexError( + "Could not find a matching phoneme for the grammar " + f"'{match.group()}'. Make there is at least one phoneme matching this " + "combination of consonants and vowels.") translation[word.lower()] = new_word.lower() if manual_translations: @@ -360,6 +396,11 @@ word = match.group() lword = len(word) + # find out what preceeded this word + wpos = match.start() + preceeding = match.string[:wpos].strip() + start_sentence = preceeding.endswith((".", "!", "?")) or not preceeding + if len(word) <= self.level: # below level. Don't translate new_word = word @@ -369,11 +410,6 @@ if not new_word: # no dictionary translation. Generate one - # find out what preceeded this word - wpos = match.start() - preceeding = match.string[:wpos].strip() - start_sentence = preceeding.endswith((".", "!", "?")) or not preceeding - # make up translation on the fly. Length can # vary from un-translated word. wlen = max( @@ -408,24 +444,30 @@ break if word.istitle(): - title_word = "" - if not start_sentence and not self.language.get("noun_translate", False): - # don't translate what we identify as proper nouns (names) - title_word = word - elif new_word: - title_word = new_word + if not start_sentence: + # this is a noun. We miss nouns at the start of + # sentences this way, but it's as good as we can get + # with this simple analysis. Maybe the fantasy language + # just don't consider nouns at the beginning of + # sentences, who knows? + if not self.language.get("noun_translate", False): + # don't translate what we identify as proper nouns (names) + new_word = word - if title_word: - # Regardless of if we translate or not, we will add the custom prefix/postfixes - new_word = "%s%s%s" % ( - self.language["noun_prefix"], - title_word.capitalize(), - self.language["noun_postfix"], + # add noun prefix and/or postfix + new_word = "{prefix}{word}{postfix}".format( + prefix=self.language["noun_prefix"], + word=new_word.capitalize(), + postfix=self.language["noun_postfix"], ) if len(word) > 1 and word.isupper(): # keep LOUD words loud also when translated new_word = new_word.upper() + + if start_sentence: + new_word = new_word.capitalize() + return new_word
    [docs] def translate(self, text, level=0.0, language="default"): @@ -532,19 +574,18 @@ return list(_LANGUAGE_HANDLER.attributes.get("language_storage", {}))
    -# ------------------------------------------------------------ +# ----------------------------------------------------------------------------- # # Whisper obscuration # -# This obsucration table is designed by obscuring certain -# vowels first, following by consonants that tend to be -# more audible over long distances, like s. Finally it -# does non-auditory replacements, like exclamation marks -# and capitalized letters (assumed to be spoken louder) that may still -# give a user some idea of the sentence structure. Then the word -# lengths are also obfuscated and finally the whisper # length itself. +# This obsucration table is designed by obscuring certain vowels first, +# following by consonants that tend to be more audible over long distances, +# like s. Finally it does non-auditory replacements, like exclamation marks and +# capitalized letters (assumed to be spoken louder) that may still give a user +# some idea of the sentence structure. Then the word lengths are also +# obfuscated and finally the whisper length itself. # -# ------------------------------------------------------------ +# ------------------------------------------------------------------------------ _RE_WHISPER_OBSCURE = [ @@ -621,7 +662,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/rpsystem.html b/docs/0.9.5/_modules/evennia/contrib/rpsystem.html index 6c6cf18278..fbe24c2cf3 100644 --- a/docs/0.9.5/_modules/evennia/contrib/rpsystem.html +++ b/docs/0.9.5/_modules/evennia/contrib/rpsystem.html @@ -324,7 +324,8 @@ the markers and a tuple (langname, saytext), where langname can be None. Raises: - rplanguage.LanguageError: If an invalid language was specified. + evennia.contrib.rpsystem.LanguageError: If an invalid language was + specified. Notes: Note that no errors are raised if the wrong language identifier @@ -1702,7 +1703,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/security/auditing/outputs.html b/docs/0.9.5/_modules/evennia/contrib/security/auditing/outputs.html index e7d1bb7651..5f29e8dee8 100644 --- a/docs/0.9.5/_modules/evennia/contrib/security/auditing/outputs.html +++ b/docs/0.9.5/_modules/evennia/contrib/security/auditing/outputs.html @@ -136,7 +136,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/security/auditing/server.html b/docs/0.9.5/_modules/evennia/contrib/security/auditing/server.html index 91e3814d9b..29e1aad88d 100644 --- a/docs/0.9.5/_modules/evennia/contrib/security/auditing/server.html +++ b/docs/0.9.5/_modules/evennia/contrib/security/auditing/server.html @@ -325,7 +325,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/security/auditing/tests.html b/docs/0.9.5/_modules/evennia/contrib/security/auditing/tests.html index 046fbe11be..204d5343cd 100644 --- a/docs/0.9.5/_modules/evennia/contrib/security/auditing/tests.html +++ b/docs/0.9.5/_modules/evennia/contrib/security/auditing/tests.html @@ -190,7 +190,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/simpledoor.html b/docs/0.9.5/_modules/evennia/contrib/simpledoor.html index 3724667b5f..7fd4937ff6 100644 --- a/docs/0.9.5/_modules/evennia/contrib/simpledoor.html +++ b/docs/0.9.5/_modules/evennia/contrib/simpledoor.html @@ -248,7 +248,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/slow_exit.html b/docs/0.9.5/_modules/evennia/contrib/slow_exit.html index d5f2987579..27c8bde0b9 100644 --- a/docs/0.9.5/_modules/evennia/contrib/slow_exit.html +++ b/docs/0.9.5/_modules/evennia/contrib/slow_exit.html @@ -220,7 +220,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/talking_npc.html b/docs/0.9.5/_modules/evennia/contrib/talking_npc.html index 4574f7a349..2ddc3d7653 100644 --- a/docs/0.9.5/_modules/evennia/contrib/talking_npc.html +++ b/docs/0.9.5/_modules/evennia/contrib/talking_npc.html @@ -209,7 +209,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/tree_select.html b/docs/0.9.5/_modules/evennia/contrib/tree_select.html index cd994c85c6..a32c6c40de 100644 --- a/docs/0.9.5/_modules/evennia/contrib/tree_select.html +++ b/docs/0.9.5/_modules/evennia/contrib/tree_select.html @@ -653,7 +653,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/turnbattle/tb_basic.html b/docs/0.9.5/_modules/evennia/contrib/turnbattle/tb_basic.html index 4c9261e2c8..53e071c8c0 100644 --- a/docs/0.9.5/_modules/evennia/contrib/turnbattle/tb_basic.html +++ b/docs/0.9.5/_modules/evennia/contrib/turnbattle/tb_basic.html @@ -221,10 +221,10 @@
    [docs]def at_defeat(defeated): """ Announces the defeat of a fighter in combat. - + Args: defeated (obj): Fighter that's been defeated. - + Notes: All this does is announce a defeat message by default, but if you want anything else to happen to defeated fighters (like putting them @@ -523,6 +523,7 @@ if disengage_check: # All characters have disengaged self.obj.msg_contents("All fighters have disengaged! Combat is over!") self.stop() # Stop this script and end combat. + self.delete() return # Check to see if only one character is left standing. If so, end combat. @@ -538,6 +539,7 @@ LastStanding = fighter # Pick the one fighter left with HP remaining self.obj.msg_contents("Only %s remains! Combat is over!" % LastStanding) self.stop() # Stop this script and end combat. + self.delete() return # Cycle to the next turn. @@ -856,7 +858,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/turnbattle/tb_equip.html b/docs/0.9.5/_modules/evennia/contrib/turnbattle/tb_equip.html index 9b0841f3ef..0e07fda407 100644 --- a/docs/0.9.5/_modules/evennia/contrib/turnbattle/tb_equip.html +++ b/docs/0.9.5/_modules/evennia/contrib/turnbattle/tb_equip.html @@ -1214,7 +1214,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/turnbattle/tb_items.html b/docs/0.9.5/_modules/evennia/contrib/turnbattle/tb_items.html index da8eacf1b3..d548ce83dc 100644 --- a/docs/0.9.5/_modules/evennia/contrib/turnbattle/tb_items.html +++ b/docs/0.9.5/_modules/evennia/contrib/turnbattle/tb_items.html @@ -1533,7 +1533,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/turnbattle/tb_magic.html b/docs/0.9.5/_modules/evennia/contrib/turnbattle/tb_magic.html index 2965249a15..d92d4d27f7 100644 --- a/docs/0.9.5/_modules/evennia/contrib/turnbattle/tb_magic.html +++ b/docs/0.9.5/_modules/evennia/contrib/turnbattle/tb_magic.html @@ -1455,7 +1455,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/turnbattle/tb_range.html b/docs/0.9.5/_modules/evennia/contrib/turnbattle/tb_range.html index 7f8e8f8e7b..a19b1b81f9 100644 --- a/docs/0.9.5/_modules/evennia/contrib/turnbattle/tb_range.html +++ b/docs/0.9.5/_modules/evennia/contrib/turnbattle/tb_range.html @@ -683,7 +683,6 @@ Args: to_init (object): Object to initialize range field for. - Keyword Args: anchor_obj (object): Object to copy range values from, or None for a random object. add_distance (int): Distance to put between to_init object and anchor object. @@ -1512,7 +1511,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/tutorial_examples/bodyfunctions.html b/docs/0.9.5/_modules/evennia/contrib/tutorial_examples/bodyfunctions.html index 612a2b2ed8..6060905848 100644 --- a/docs/0.9.5/_modules/evennia/contrib/tutorial_examples/bodyfunctions.html +++ b/docs/0.9.5/_modules/evennia/contrib/tutorial_examples/bodyfunctions.html @@ -142,7 +142,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/tutorial_examples/cmdset_red_button.html b/docs/0.9.5/_modules/evennia/contrib/tutorial_examples/cmdset_red_button.html deleted file mode 100644 index 1653fcbd8f..0000000000 --- a/docs/0.9.5/_modules/evennia/contrib/tutorial_examples/cmdset_red_button.html +++ /dev/null @@ -1,439 +0,0 @@ - - - - - - - - evennia.contrib.tutorial_examples.cmdset_red_button — Evennia 0.9.5 documentation - - - - - - - - - - - - - -
    -
    -
    -
    - -

    Source code for evennia.contrib.tutorial_examples.cmdset_red_button

    -"""
    -This defines the cmdset for the red_button. Here we have defined
    -the commands and the cmdset in the same module, but if you
    -have many different commands to merge it is often better
    -to define the cmdset separately, picking and choosing from
    -among the available commands as to what should be included in the
    -cmdset - this way you can often re-use the commands too.
    -"""
    -
    -import random
    -from evennia import Command, CmdSet
    -
    -# Some simple commands for the red button
    -
    -# ------------------------------------------------------------
    -# Commands defined on the red button
    -# ------------------------------------------------------------
    -
    -
    -
    [docs]class CmdNudge(Command): - """ - Try to nudge the button's lid - - Usage: - nudge lid - - This command will have you try to - push the lid of the button away. - """ - - key = "nudge lid" # two-word command name! - aliases = ["nudge"] - locks = "cmd:all()" - -
    [docs] def func(self): - """ - nudge the lid. Random chance of success to open it. - """ - rand = random.random() - if rand < 0.5: - self.caller.msg("You nudge at the lid. It seems stuck.") - elif rand < 0.7: - self.caller.msg("You move the lid back and forth. It won't budge.") - else: - self.caller.msg("You manage to get a nail under the lid.") - self.caller.execute_cmd("open lid")
    - - -
    [docs]class CmdPush(Command): - """ - Push the red button - - Usage: - push button - - """ - - key = "push button" - aliases = ["push", "press button", "press"] - locks = "cmd:all()" - -
    [docs] def func(self): - """ - Note that we choose to implement this with checking for - if the lid is open/closed. This is because this command - is likely to be tried regardless of the state of the lid. - - An alternative would be to make two versions of this command - and tuck them into the cmdset linked to the Open and Closed - lid-state respectively. - - """ - - if self.obj.db.lid_open: - string = "You reach out to press the big red button ..." - string += "\n\nA BOOM! A bright light blinds you!" - string += "\nThe world goes dark ..." - self.caller.msg(string) - self.caller.location.msg_contents( - "%s presses the button. BOOM! %s is blinded by a flash!" - % (self.caller.name, self.caller.name), - exclude=self.caller, - ) - # the button's method will handle all setup of scripts etc. - self.obj.press_button(self.caller) - else: - string = "You cannot push the button - there is a glass lid covering it." - self.caller.msg(string)
    - - -
    [docs]class CmdSmashGlass(Command): - """ - smash glass - - Usage: - smash glass - - Try to smash the glass of the button. - """ - - key = "smash glass" - aliases = ["smash lid", "break lid", "smash"] - locks = "cmd:all()" - -
    [docs] def func(self): - """ - The lid won't open, but there is a small chance - of causing the lamp to break. - """ - rand = random.random() - - if rand < 0.2: - string = "You smash your hand against the glass" - string += " with all your might. The lid won't budge" - string += " but you cause quite the tremor through the button's mount." - string += "\nIt looks like the button's lamp stopped working for the time being." - self.obj.lamp_works = False - elif rand < 0.6: - string = "You hit the lid hard. It doesn't move an inch." - else: - string = "You place a well-aimed fist against the glass of the lid." - string += " Unfortunately all you get is a pain in your hand. Maybe" - string += " you should just try to open the lid instead?" - self.caller.msg(string) - self.caller.location.msg_contents( - "%s tries to smash the glass of the button." % (self.caller.name), exclude=self.caller - )
    - - -
    [docs]class CmdOpenLid(Command): - """ - open lid - - Usage: - open lid - - """ - - key = "open lid" - aliases = ["open button", "open"] - locks = "cmd:all()" - -
    [docs] def func(self): - "simply call the right function." - - if self.obj.db.lid_locked: - self.caller.msg("This lid seems locked in place for the moment.") - return - - string = "\nA ticking sound is heard, like a winding mechanism. Seems " - string += "the lid will soon close again." - self.caller.msg(string) - self.caller.location.msg_contents( - "%s opens the lid of the button." % (self.caller.name), exclude=self.caller - ) - # add the relevant cmdsets to button - self.obj.cmdset.add(LidClosedCmdSet) - # call object method - self.obj.open_lid()
    - - -
    [docs]class CmdCloseLid(Command): - """ - close the lid - - Usage: - close lid - - Closes the lid of the red button. - """ - - key = "close lid" - aliases = ["close"] - locks = "cmd:all()" - -
    [docs] def func(self): - "Close the lid" - - self.obj.close_lid() - - # this will clean out scripts dependent on lid being open. - self.caller.msg("You close the button's lid. It clicks back into place.") - self.caller.location.msg_contents( - "%s closes the button's lid." % (self.caller.name), exclude=self.caller - )
    - - -
    [docs]class CmdBlindLook(Command): - """ - Looking around in darkness - - Usage: - look <obj> - - ... not that there's much to see in the dark. - - """ - - key = "look" - aliases = ["l", "get", "examine", "ex", "feel", "listen"] - locks = "cmd:all()" - -
    [docs] def func(self): - "This replaces all the senses when blinded." - - # we decide what to reply based on which command was - # actually tried - - if self.cmdstring == "get": - string = "You fumble around blindly without finding anything." - elif self.cmdstring == "examine": - string = "You try to examine your surroundings, but can't see a thing." - elif self.cmdstring == "listen": - string = "You are deafened by the boom." - elif self.cmdstring == "feel": - string = "You fumble around, hands outstretched. You bump your knee." - else: - # trying to look - string = "You are temporarily blinded by the flash. " - string += "Until it wears off, all you can do is feel around blindly." - self.caller.msg(string) - self.caller.location.msg_contents( - "%s stumbles around, blinded." % (self.caller.name), exclude=self.caller - )
    - - -
    [docs]class CmdBlindHelp(Command): - """ - Help function while in the blinded state - - Usage: - help - - """ - - key = "help" - aliases = "h" - locks = "cmd:all()" - -
    [docs] def func(self): - "Give a message." - self.caller.msg("You are beyond help ... until you can see again.")
    - - -# --------------------------------------------------------------- -# Command sets for the red button -# --------------------------------------------------------------- - -# We next tuck these commands into their respective command sets. -# (note that we are overdoing the cdmset separation a bit here -# to show how it works). - - -
    [docs]class DefaultCmdSet(CmdSet): - """ - The default cmdset always sits - on the button object and whereas other - command sets may be added/merge onto it - and hide it, removing them will always - bring it back. It's added to the object - using obj.cmdset.add_default(). - """ - - key = "RedButtonDefault" - mergetype = "Union" # this is default, we don't really need to put it here. - -
    [docs] def at_cmdset_creation(self): - "Init the cmdset" - self.add(CmdPush())
    - - -
    [docs]class LidClosedCmdSet(CmdSet): - """ - A simple cmdset tied to the redbutton object. - - It contains the commands that launches the other - command sets, making the red button a self-contained - item (i.e. you don't have to manually add any - scripts etc to it when creating it). - """ - - key = "LidClosedCmdSet" - # default Union is used *except* if we are adding to a - # cmdset named LidOpenCmdSet - this one we replace - # completely. - key_mergetype = {"LidOpenCmdSet": "Replace"} - -
    [docs] def at_cmdset_creation(self): - "Populates the cmdset when it is instantiated." - self.add(CmdNudge()) - self.add(CmdSmashGlass()) - self.add(CmdOpenLid())
    - - -
    [docs]class LidOpenCmdSet(CmdSet): - """ - This is the opposite of the Closed cmdset. - """ - - key = "LidOpenCmdSet" - # default Union is used *except* if we are adding to a - # cmdset named LidClosedCmdSet - this one we replace - # completely. - key_mergetype = {"LidClosedCmdSet": "Replace"} - -
    [docs] def at_cmdset_creation(self): - "setup the cmdset (just one command)" - self.add(CmdCloseLid())
    - - -
    [docs]class BlindCmdSet(CmdSet): - """ - This is the cmdset added to the *account* when - the button is pushed. - """ - - key = "BlindCmdSet" - # we want it to completely replace all normal commands - # until the timed script removes it again. - mergetype = "Replace" - # we want to stop the account from walking around - # in this blinded state, so we hide all exits too. - # (channel commands will still work). - no_exits = True # keep account in the same room - no_objs = True # don't allow object commands - -
    [docs] def at_cmdset_creation(self): - "Setup the blind cmdset" - from evennia.commands.default.general import CmdSay - from evennia.commands.default.general import CmdPose - - self.add(CmdSay()) - self.add(CmdPose()) - self.add(CmdBlindLook()) - self.add(CmdBlindHelp())
    -
    - -
    -
    -
    -
    - -
    -
    - - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/contrib/tutorial_examples/red_button.html b/docs/0.9.5/_modules/evennia/contrib/tutorial_examples/red_button.html index 65f6d86cfa..a9b4a3e63e 100644 --- a/docs/0.9.5/_modules/evennia/contrib/tutorial_examples/red_button.html +++ b/docs/0.9.5/_modules/evennia/contrib/tutorial_examples/red_button.html @@ -47,14 +47,381 @@ Create this button with - @create/drop examples.red_button.RedButton + create/drop red_button.RedButton Note that you must drop the button before you can see its messages! + +## Technical + +The button's functionality is controlled by CmdSets that gets added and removed +depending on the 'state' the button is in. + +- Lid-closed state: In this state the button is covered by a glass cover and trying + to 'push' it will fail. You can 'nudge', 'smash' or 'open' the lid. +- Lid-open state: In this state the lid is open but will close again after a certain + time. Using 'push' now will press the button and trigger the Blind-state. +- Blind-state: In this mode you are blinded by a bright flash. This will affect your + normal commands like 'look' and help until the blindness wears off after a certain + time. + +Timers are handled by persistent delays on the button. These are examples of +`evennia.utils.utils.delay` calls that wait a certain time before calling a method - +such as when closing the lid and un-blinding a character. + """ import random from evennia import DefaultObject -from evennia.contrib.tutorial_examples import red_button_scripts as scriptexamples -from evennia.contrib.tutorial_examples import cmdset_red_button as cmdsetexamples +from evennia import Command, CmdSet +from evennia.utils.utils import delay, repeat, interactive + + +# Commands on the button (not all awailable at the same time) + + +# Commands for the state when the lid covering the button is closed. + +
    [docs]class CmdPushLidClosed(Command): + """ + Push the red button (lid closed) + + Usage: + push button + + """ + + key = "push button" + aliases = ["push", "press button", "press"] + locks = "cmd:all()" + +
    [docs] def func(self): + """ + This is the version of push used when the lid is closed. + + An alternative would be to make a 'push' command in a default cmdset + that is always available on the button and then use if-statements to + check if the lid is open or closed. + + """ + self.caller.msg("You cannot push the button = there is a glass lid covering it.")
    + + +
    [docs]class CmdNudge(Command): + """ + Try to nudge the button's lid. + + Usage: + nudge lid + + This command will have you try to push the lid of the button away. + + """ + + key = "nudge lid" # two-word command name! + aliases = ["nudge"] + locks = "cmd:all()" + +
    [docs] def func(self): + """ + Nudge the lid. Random chance of success to open it. + + """ + rand = random.random() + if rand < 0.5: + self.caller.msg("You nudge at the lid. It seems stuck.") + elif rand < 0.7: + self.caller.msg("You move the lid back and forth. It won't budge.") + else: + self.caller.msg("You manage to get a nail under the lid.") + # self.obj is the button object + self.obj.to_open_state()
    + + +
    [docs]class CmdSmashGlass(Command): + """ + Smash the protective glass. + + Usage: + smash glass + + Try to smash the glass of the button. + + """ + + key = "smash glass" + aliases = ["smash lid", "break lid", "smash"] + locks = "cmd:all()" + +
    [docs] def func(self): + """ + The lid won't open, but there is a small chance of causing the lamp to + break. + + """ + rand = random.random() + self.caller.location.msg_contents( + f"{self.caller.name} tries to smash the glass of the button.", + exclude=self.caller) + + if rand < 0.2: + string = ("You smash your hand against the glass" + " with all your might. The lid won't budge" + " but you cause quite the tremor through the button's mount." + "\nIt looks like the button's lamp stopped working for the time being, " + "but the lid is still as closed as ever.") + # self.obj is the button itself + self.obj.break_lamp() + elif rand < 0.6: + string = "You hit the lid hard. It doesn't move an inch." + else: + string = ("You place a well-aimed fist against the glass of the lid." + " Unfortunately all you get is a pain in your hand. Maybe" + " you should just try to just ... open the lid instead?") + self.caller.msg(string)
    + + +
    [docs]class CmdOpenLid(Command): + """ + open lid + + Usage: + open lid + + """ + + key = "open lid" + aliases = ["open button"] + locks = "cmd:all()" + +
    [docs] def func(self): + "simply call the right function." + + if self.obj.db.lid_locked: + self.caller.msg("This lid seems locked in place for the moment.") + return + + string = "\nA ticking sound is heard, like a winding mechanism. Seems " + string += "the lid will soon close again." + self.caller.msg(string) + self.caller.location.msg_contents( + f"{self.caller.name} opens the lid of the button.", + exclude=self.caller) + self.obj.to_open_state()
    + + +
    [docs]class LidClosedCmdSet(CmdSet): + """ + A simple cmdset tied to the redbutton object. + + It contains the commands that launches the other + command sets, making the red button a self-contained + item (i.e. you don't have to manually add any + scripts etc to it when creating it). + + Note that this is given with a `key_mergetype` set. This + is set up so that the cmdset with merge with Union merge type + *except* if the other cmdset to merge with is LidOpenCmdSet, + in which case it will Replace that. So these two cmdsets will + be mutually exclusive. + + """ + + key = "LidClosedCmdSet" + +
    [docs] def at_cmdset_creation(self): + "Populates the cmdset when it is instantiated." + self.add(CmdPushLidClosed()) + self.add(CmdNudge()) + self.add(CmdSmashGlass()) + self.add(CmdOpenLid())
    + + +# Commands for the state when the button's protective cover is open - now the +# push command will work. You can also close the lid again. + +
    [docs]class CmdPushLidOpen(Command): + """ + Push the red button + + Usage: + push button + + """ + + key = "push button" + aliases = ["push", "press button", "press"] + locks = "cmd:all()" + + @interactive + def func(self): + """ + This version of push will immediately trigger the next button state. + + The use of the @interactive decorator allows for using `yield` to add + simple pauses in how quickly a message is returned to the user. This + kind of pause will not survive a server reload. + + """ + # pause a little between each message. + self.caller.msg("You reach out to press the big red button ...") + yield(2) # pause 2s before next message + self.caller.msg("\n\n|wBOOOOM! A bright light blinds you!|n") + yield(1) # pause 1s before next message + self.caller.msg("\n\n|xThe world goes dark ...|n") + + name = self.caller.name + self.caller.location.msg_contents( + f"{name} presses the button. BOOM! {name} is blinded by a flash!", + exclude=self.caller) + self.obj.blind_target(self.caller)
    + + +
    [docs]class CmdCloseLid(Command): + """ + Close the lid + + Usage: + close lid + + Closes the lid of the red button. + """ + + key = "close lid" + aliases = ["close"] + locks = "cmd:all()" + +
    [docs] def func(self): + "Close the lid" + + self.obj.to_closed_state() + + # this will clean out scripts dependent on lid being open. + self.caller.msg("You close the button's lid. It clicks back into place.") + self.caller.location.msg_contents( + f"{self.caller.name} closes the button's lid.", + exclude=self.caller)
    + + +
    [docs]class LidOpenCmdSet(CmdSet): + """ + This is the opposite of the Closed cmdset. + + Note that this is given with a `key_mergetype` set. This + is set up so that the cmdset with merge with Union merge type + *except* if the other cmdset to merge with is LidClosedCmdSet, + in which case it will Replace that. So these two cmdsets will + be mutually exclusive. + + """ + + key = "LidOpenCmdSet" + +
    [docs] def at_cmdset_creation(self): + """Setup the cmdset""" + self.add(CmdPushLidOpen()) + self.add(CmdCloseLid())
    + + +# Commands for when the button has been pushed and the player is blinded. This +# replaces commands on the player making them 'blind' for a while. + +
    [docs]class CmdBlindLook(Command): + """ + Looking around in darkness + + Usage: + look <obj> + + ... not that there's much to see in the dark. + + """ + + key = "look" + aliases = ["l", "get", "examine", "ex", "feel", "listen"] + locks = "cmd:all()" + +
    [docs] def func(self): + "This replaces all the senses when blinded." + + # we decide what to reply based on which command was + # actually tried + + if self.cmdstring == "get": + string = "You fumble around blindly without finding anything." + elif self.cmdstring == "examine": + string = "You try to examine your surroundings, but can't see a thing." + elif self.cmdstring == "listen": + string = "You are deafened by the boom." + elif self.cmdstring == "feel": + string = "You fumble around, hands outstretched. You bump your knee." + else: + # trying to look + string = ("You are temporarily blinded by the flash. " + "Until it wears off, all you can do is feel around blindly.") + self.caller.msg(string) + self.caller.location.msg_contents( + f"{self.caller.name} stumbles around, blinded.", + exclude=self.caller)
    + + +
    [docs]class CmdBlindHelp(Command): + """ + Help function while in the blinded state + + Usage: + help + + """ + + key = "help" + aliases = "h" + locks = "cmd:all()" + +
    [docs] def func(self): + """ + Just give a message while blinded. We could have added this to the + CmdBlindLook command too if we wanted to keep things more compact. + + """ + self.caller.msg("You are beyond help ... until you can see again.")
    + + +
    [docs]class BlindCmdSet(CmdSet): + """ + This is the cmdset added to the *account* when + the button is pushed. + + Since this has mergetype Replace it will completely remove the commands of + all other cmdsets while active. To allow some limited interaction + (pose/say) we import those default commands and add them too. + + We also disable all exit-commands generated by exits and + object-interactions while blinded by setting `no_exits` and `no_objs` flags + on the cmdset. This is to avoid the player walking off or interfering with + other objects while blinded. Account-level commands however (channel messaging + etc) will not be affected by the blinding. + + """ + + key = "BlindCmdSet" + # we want it to completely replace all normal commands + # until the timed script removes it again. + mergetype = "Replace" + # we want to stop the player from walking around + # in this blinded state, so we hide all exits too. + # (channel commands will still work). + no_exits = True # keep player in the same room + no_objs = True # don't allow object commands + +
    [docs] def at_cmdset_creation(self): + "Setup the blind cmdset" + from evennia.commands.default.general import CmdSay + from evennia.commands.default.general import CmdPose + + self.add(CmdSay()) + self.add(CmdPose()) + self.add(CmdBlindLook()) + self.add(CmdBlindHelp())
    + # # Definition of the object itself @@ -63,149 +430,192 @@
    [docs]class RedButton(DefaultObject): """ - This class describes an evil red button. It will use the script - definition in contrib/examples/red_button_scripts to blink at regular - intervals. It also uses a series of script and commands to handle - pushing the button and causing effects when doing so. + This class describes an evil red button. It will blink invitingly and + temporarily blind whomever presses it. - The following attributes can be set on the button: - desc_lid_open - description when lid is open - desc_lid_closed - description when lid is closed - desc_lamp_broken - description when lamp is broken + The button can take a few optional attributes controlling how things will + be displayed in its various states. This is a useful way to give builders + the option to customize a complex object from in-game. Actual return messages + to event-actions are (in this example) left with each command, but one could + also imagine having those handled via Attributes as well, if one wanted a + completely in-game customizable button without needing to tweak command + classes. + + Attributes: + - `desc_closed_lid`: This is the description to show of the button + when the lid is closed. + - `desc_open_lid`": Shown when the lid is open + - `auto_close_msg`: Message to show when lid auto-closes + - `desc_add_lamp_broken`: Extra desc-line added after normal desc when lamp + is broken. + - blink_msg: A list of strings to randomly choose from when the lamp + blinks. + + Notes: + The button starts with lid closed. To set the initial description, + you can either set desc after creating it or pass a `desc` attribute + when creating it, such as + `button = create_object(RedButton, ..., attributes=[('desc', 'my desc')])`. """ + # these are the pre-set descriptions. Setting attributes will override + # these on the fly. + + desc_closed_lid = ("This is a large red button, inviting yet evil-looking. " + "A closed glass lid protects it.") + desc_open_lid = ("This is a large red button, inviting yet evil-looking. " + "Its glass cover is open and the button exposed.") + auto_close_msg = "The button's glass lid silently slides back in place." + lamp_breaks_msg = "The lamp flickers, the button going dark." + desc_add_lamp_broken = "\nThe big red button has stopped blinking for the time being." + # note that this is a list. A random message will display each time + blink_msgs = ["The red button flashes briefly.", + "The red button blinks invitingly.", + "The red button flashes. You know you wanna push it!"]
    [docs] def at_object_creation(self): """ - This function is called when object is created. Use this - instead of e.g. __init__. - """ - # store desc (default, you can change this at creation time) - desc = "This is a large red button, inviting yet evil-looking. " - desc += "A closed glass lid protects it." - self.db.desc = desc + This function is called (once) when object is created. - # We have to define all the variables the scripts - # are checking/using *before* adding the scripts or - # they might be deactivated before even starting! - self.db.lid_open = False + """ self.db.lamp_works = True - self.db.lid_locked = False - self.cmdset.add_default(cmdsetexamples.DefaultCmdSet, permanent=True) + # start closed + self.to_closed_state() - # since the cmdsets relevant to the button are added 'on the fly', - # we need to setup custom scripts to do this for us (also, these scripts - # check so they are valid (i.e. the lid is actually still closed)). - # The AddClosedCmdSet script makes sure to add the Closed-cmdset. - self.scripts.add(scriptexamples.ClosedLidState) - # the script EventBlinkButton makes the button blink regularly. - self.scripts.add(scriptexamples.BlinkButtonEvent)
    + # start blinking every 35s. + repeat(35, self._do_blink, persistent=True)
    - # state-changing methods - -
    [docs] def open_lid(self): + def _do_blink(self): """ - Opens the glass lid and start the timer so it will soon close - again. + Have the button blink invitingly unless it's broken. """ + if self.location and self.db.lamp_works: + possible_messages = self.db.blink_msgs or self.blink_msgs + self.location.msg_contents(random.choice(possible_messages)) - if self.db.lid_open: - return - desc = self.db.desc_lid_open - if not desc: - desc = "This is a large red button, inviting yet evil-looking. " - desc += "Its glass cover is open and the button exposed." - self.db.desc = desc - self.db.lid_open = True - - # with the lid open, we validate scripts; this will clean out - # scripts that depend on the lid to be closed. - self.scripts.validate() - # now add new scripts that define the open-lid state - self.scripts.add(scriptexamples.OpenLidState) - # we also add a scripted event that will close the lid after a while. - # (this one cleans itself after being called once) - self.scripts.add(scriptexamples.CloseLidEvent)
    - -
    [docs] def close_lid(self): + def _set_desc(self, attrname=None): """ - Close the glass lid. This validates all scripts on the button, - which means that scripts only being valid when the lid is open - will go away automatically. - - """ - - if not self.db.lid_open: - return - desc = self.db.desc_lid_closed - if not desc: - desc = "This is a large red button, inviting yet evil-looking. " - desc += "Its glass cover is closed, protecting it." - self.db.desc = desc - self.db.lid_open = False - - # clean out scripts depending on lid to be open - self.scripts.validate() - # add scripts related to the closed state - self.scripts.add(scriptexamples.ClosedLidState)
    - -
    [docs] def break_lamp(self, feedback=True): - """ - Breaks the lamp in the button, stopping it from blinking. + Set a description, based on the attrname given, taking the lamp-status + into account. Args: - feedback (bool): Show a message about breaking the lamp. + attrname (str, optional): This will first check for an Attribute with this name, + secondly for a property on the class. So if `attrname="auto_close_msg"`, + we will first look for an attribute `.db.auto_close_msg` and if that's + not found we'll use `.auto_close_msg` instead. If unset (`None`), the + currently set desc will not be changed (only lamp will be checked). + + Notes: + If `self.db.lamp_works` is `False`, we'll append + `desc_add_lamp_broken` text. + + """ + if attrname: + # change desc + desc = self.attributes.get(attrname) or getattr(self, attrname) + else: + # use existing desc + desc = self.db.desc + + if not self.db.lamp_works: + # lamp not working. Add extra to button's desc + desc += self.db.desc_add_lamp_broken or self.desc_add_lamp_broken + + self.db.desc = desc + + # state-changing methods and actions + +
    [docs] def to_closed_state(self, msg=None): + """ + Switches the button to having its lid closed. + + Args: + msg (str, optional): If given, display a message to the room + when lid closes. + + This will first try to get the Attribute (self.db.desc_closed_lid) in + case it was set by a builder and if that was None, it will fall back to + self.desc_closed_lid, the default description (note that lack of .db). + """ + self._set_desc("desc_closed_lid") + # remove lidopen-state, if it exists + self.cmdset.remove(LidOpenCmdSet) + # add lid-closed cmdset + self.cmdset.add(LidClosedCmdSet) + + if msg and self.location: + self.location.msg_contents(msg)
    + +
    [docs] def to_open_state(self): + """ + Switches the button to having its lid open. This also starts a timer + that will eventually close it again. + + """ + self._set_desc("desc_open_lid") + # remove lidopen-state, if it exists + self.cmdset.remove(LidClosedCmdSet) + # add lid-open cmdset + self.cmdset.add(LidOpenCmdSet) + + # wait 20s then call self.to_closed_state with a message as argument + delay(35, self.to_closed_state, + self.db.auto_close_msg or self.auto_close_msg, + persistent=True)
    + + def _unblind_target(self, caller): + """ + This is called to un-blind after a certain time. + + """ + caller.cmdset.remove(BlindCmdSet) + caller.msg("You blink feverishly as your eyesight slowly returns.") + self.location.msg_contents( + f"{caller.name} seems to be recovering their eyesight, blinking feverishly.", + exclude=caller) + +
    [docs] def blind_target(self, caller): + """ + Someone was foolish enough to press the button! Blind them + temporarily. + + Args: + caller (Object): The one to be blinded. + + """ + + # we don't need to remove other cmdsets, this will replace all, + # then restore whatever was there when it goes away. + caller.cmdset.add(BlindCmdSet) + + # wait 20s then call self._unblind to remove blindness effect. The + # persistent=True means the delay should survive a server reload. + delay(20, self._unblind_target, caller, + persistent=True)
    + + def _unbreak_lamp(self): + """ + This is called to un-break the lamp after a certain time. + + """ + # we do this quietly, the user will just notice it starting blinking again + self.db.lamp_works = True + self._set_desc() + +
    [docs] def break_lamp(self): + """ + Breaks the lamp in the button, stopping it from blinking for a while """ self.db.lamp_works = False - desc = self.db.desc_lamp_broken - if not desc: - self.db.desc += "\nThe big red button has stopped blinking for the time being." - else: - self.db.desc = desc + # this will update the desc with the info about the broken lamp + self._set_desc() + self.location.msg_contents(self.db.lamp_breaks_msg or self.lamp_breaks_msg) - if feedback and self.location: - self.location.msg_contents("The lamp flickers, the button going dark.") - self.scripts.validate()
    - -
    [docs] def press_button(self, pobject): - """ - Someone was foolish enough to press the button! - - Args: - pobject (Object): The person pressing the button - - """ - # deactivate the button so it won't flash/close lid etc. - self.scripts.add(scriptexamples.DeactivateButtonEvent) - # blind the person pressing the button. Note that this - # script is set on the *character* pressing the button! - pobject.scripts.add(scriptexamples.BlindedState)
    - - # script-related methods - -
    + # wait 21s before unbreaking the lamp again + delay(21, self._unbreak_lamp)
    @@ -243,7 +653,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/tutorial_examples/red_button_scripts.html b/docs/0.9.5/_modules/evennia/contrib/tutorial_examples/red_button_scripts.html deleted file mode 100644 index f57f49361c..0000000000 --- a/docs/0.9.5/_modules/evennia/contrib/tutorial_examples/red_button_scripts.html +++ /dev/null @@ -1,389 +0,0 @@ - - - - - - - - evennia.contrib.tutorial_examples.red_button_scripts — Evennia 0.9.5 documentation - - - - - - - - - - - - - -
    -
    -
    -
    - -

    Source code for evennia.contrib.tutorial_examples.red_button_scripts

    -"""
    -Example of scripts.
    -
    -These are scripts intended for a particular object - the
    -red_button object type in contrib/examples. A few variations
    -on uses of scripts are included.
    -
    -"""
    -from evennia import DefaultScript
    -from evennia.contrib.tutorial_examples import cmdset_red_button as cmdsetexamples
    -
    -#
    -# Scripts as state-managers
    -#
    -# Scripts have many uses, one of which is to statically
    -# make changes when a particular state of an object changes.
    -# There is no "timer" involved in this case (although there could be),
    -# whenever the script determines it is "invalid", it simply shuts down
    -# along with all the things it controls.
    -#
    -# To show as many features as possible of the script and cmdset systems,
    -# we will use three scripts controlling one state each of the red_button,
    -# each with its own set of commands, handled by cmdsets - one for when
    -# the button has its lid open, and one for when it is closed and a
    -# last one for when the player pushed the button and gets blinded by
    -# a bright light. The last one also has a timer component that allows it
    -# to remove itself after a while (and the player recovers their eyesight).
    -
    -
    -
    [docs]class ClosedLidState(DefaultScript): - """ - This manages the cmdset for the "closed" button state. What this - means is that while this script is valid, we add the RedButtonClosed - cmdset to it (with commands like open, nudge lid etc) - """ - -
    [docs] def at_script_creation(self): - "Called when script first created." - self.key = "closed_lid_script" - self.desc = "Script that manages the closed-state cmdsets for red button." - self.persistent = True
    - -
    [docs] def at_start(self): - """ - This is called once every server restart, so we want to add the - (memory-resident) cmdset to the object here. is_valid is automatically - checked so we don't need to worry about adding the script to an - open lid. - """ - # All we do is add the cmdset for the closed state. - self.obj.cmdset.add(cmdsetexamples.LidClosedCmdSet)
    - -
    [docs] def is_valid(self): - """ - The script is only valid while the lid is closed. - self.obj is the red_button on which this script is defined. - """ - return not self.obj.db.lid_open
    - -
    [docs] def at_stop(self): - """ - When the script stops we must make sure to clean up after us. - - """ - self.obj.cmdset.delete(cmdsetexamples.LidClosedCmdSet)
    - - -
    [docs]class OpenLidState(DefaultScript): - """ - This manages the cmdset for the "open" button state. This will add - the RedButtonOpen - """ - -
    [docs] def at_script_creation(self): - "Called when script first created." - self.key = "open_lid_script" - self.desc = "Script that manages the opened-state cmdsets for red button." - self.persistent = True
    - -
    [docs] def at_start(self): - """ - This is called once every server restart, so we want to add the - (memory-resident) cmdset to the object here. is_valid is - automatically checked, so we don't need to worry about - adding the cmdset to a closed lid-button. - """ - self.obj.cmdset.add(cmdsetexamples.LidOpenCmdSet)
    - -
    [docs] def is_valid(self): - """ - The script is only valid while the lid is open. - self.obj is the red_button on which this script is defined. - """ - return self.obj.db.lid_open
    - -
    [docs] def at_stop(self): - """ - When the script stops (like if the lid is closed again) - we must make sure to clean up after us. - """ - self.obj.cmdset.delete(cmdsetexamples.LidOpenCmdSet)
    - - -
    [docs]class BlindedState(DefaultScript): - """ - This is a timed state. - - This adds a (very limited) cmdset TO THE ACCOUNT, during a certain time, - after which the script will close and all functions are - restored. It's up to the function starting the script to actually - set it on the right account object. - """ - -
    [docs] def at_script_creation(self): - """ - We set up the script here. - """ - self.key = "temporary_blinder" - self.desc = "Temporarily blinds the account for a little while." - self.interval = 20 # seconds - self.start_delay = True # we don't want it to stop until after 20s. - self.repeats = 1 # this will go away after interval seconds. - self.persistent = False # we will ditch this if server goes down
    - -
    [docs] def at_start(self): - """ - We want to add the cmdset to the linked object. - - Note that the RedButtonBlind cmdset is defined to completly - replace the other cmdsets on the stack while it is active - (this means that while blinded, only operations in this cmdset - will be possible for the account to perform). It is however - not persistent, so should there be a bug in it, we just need - to restart the server to clear out of it during development. - """ - self.obj.cmdset.add(cmdsetexamples.BlindCmdSet)
    - -
    [docs] def at_stop(self): - """ - It's important that we clear out that blinded cmdset - when we are done! - """ - self.obj.msg("You blink feverishly as your eyesight slowly returns.") - self.obj.location.msg_contents( - "%s seems to be recovering their eyesight." % self.obj.name, exclude=self.obj - ) - self.obj.cmdset.delete() # this will clear the latest added cmdset,
    - # (which is the blinded one). - - -# -# Timer/Event-like Scripts -# -# Scripts can also work like timers, or "events". Below we -# define three such timed events that makes the button a little -# more "alive" - one that makes the button blink menacingly, another -# that makes the lid covering the button slide back after a while. -# - - -
    [docs]class CloseLidEvent(DefaultScript): - """ - This event closes the glass lid over the button - some time after it was opened. It's a one-off - script that should be started/created when the - lid is opened. - """ - -
    [docs] def at_script_creation(self): - """ - Called when script object is first created. Sets things up. - We want to have a lid on the button that the user can pull - aside in order to make the button 'pressable'. But after a set - time that lid should auto-close again, making the button safe - from pressing (and deleting this command). - """ - self.key = "lid_closer" - self.desc = "Closes lid on a red buttons" - self.interval = 20 # seconds - self.start_delay = True # we want to pospone the launch. - self.repeats = 1 # we only close the lid once - self.persistent = True # even if the server crashes in those 20 seconds,
    - # the lid will still close once the game restarts. - -
    [docs] def is_valid(self): - """ - This script can only operate if the lid is open; if it - is already closed, the script is clearly invalid. - - Note that we are here relying on an self.obj being - defined (and being a RedButton object) - this we should be able to - expect since this type of script is always tied to one individual - red button object and not having it would be an error. - """ - return self.obj.db.lid_open
    - -
    [docs] def at_repeat(self): - """ - Called after self.interval seconds. It closes the lid. Before this method is - called, self.is_valid() is automatically checked, so there is no need to - check this manually. - """ - self.obj.close_lid()
    - - -
    [docs]class BlinkButtonEvent(DefaultScript): - """ - This timed script lets the button flash at regular intervals. - """ - -
    [docs] def at_script_creation(self): - """ - Sets things up. We want the button's lamp to blink at - regular intervals, unless it's broken (can happen - if you try to smash the glass, say). - """ - self.key = "blink_button" - self.desc = "Blinks red buttons" - self.interval = 35 # seconds - self.start_delay = False # blink right away - self.persistent = True # keep blinking also after server reboot
    - -
    [docs] def is_valid(self): - """ - Button will keep blinking unless it is broken. - """ - return self.obj.db.lamp_works
    - -
    [docs] def at_repeat(self): - """ - Called every self.interval seconds. Makes the lamp in - the button blink. - """ - self.obj.blink()
    - - -
    [docs]class DeactivateButtonEvent(DefaultScript): - """ - This deactivates the button for a short while (it won't blink, won't - close its lid etc). It is meant to be called when the button is pushed - and run as long as the blinded effect lasts. We cannot put these methods - in the AddBlindedCmdSet script since that script is defined on the *account* - whereas this one must be defined on the *button*. - """ - -
    [docs] def at_script_creation(self): - """ - Sets things up. - """ - self.key = "deactivate_button" - self.desc = "Deactivate red button temporarily" - self.interval = 21 # seconds - self.start_delay = True # wait with the first repeat for self.interval seconds. - self.persistent = True - self.repeats = 1 # only do this once
    - -
    [docs] def at_start(self): - """ - Deactivate the button. Observe that this method is always - called directly, regardless of the value of self.start_delay - (that just controls when at_repeat() is called) - """ - # closing the lid will also add the ClosedState script - self.obj.close_lid() - # lock the lid so other accounts can't access it until the - # first one's effect has worn off. - self.obj.db.lid_locked = True - # breaking the lamp also sets a correct desc - self.obj.break_lamp(feedback=False)
    - -
    [docs] def at_repeat(self): - """ - When this is called, reset the functionality of the button. - """ - # restore button's desc. - - self.obj.db.lamp_works = True - desc = "This is a large red button, inviting yet evil-looking. " - desc += "Its glass cover is closed, protecting it." - self.db.desc = desc - # re-activate the blink button event. - self.obj.scripts.add(BlinkButtonEvent) - # unlock the lid - self.obj.db.lid_locked = False - self.obj.scripts.validate()
    -
    - -
    -
    -
    -
    - -
    -
    - - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/contrib/tutorial_examples/tests.html b/docs/0.9.5/_modules/evennia/contrib/tutorial_examples/tests.html index 92fd98cdf1..add0bf97c6 100644 --- a/docs/0.9.5/_modules/evennia/contrib/tutorial_examples/tests.html +++ b/docs/0.9.5/_modules/evennia/contrib/tutorial_examples/tests.html @@ -147,7 +147,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/tutorial_world/intro_menu.html b/docs/0.9.5/_modules/evennia/contrib/tutorial_world/intro_menu.html index 791970ed09..04e990a98a 100644 --- a/docs/0.9.5/_modules/evennia/contrib/tutorial_world/intro_menu.html +++ b/docs/0.9.5/_modules/evennia/contrib/tutorial_world/intro_menu.html @@ -473,8 +473,9 @@ and the main window. - Use |y<Return>|n (or click the arrow on the right) to send your input. -- Use |yShift + <up/down-arrow>|n to step back and forth in your command-history. -- Use |yShift + <Return>|n to add a new line to your input without sending. +- Use |yCtrl + <up/down-arrow>|n to step back and forth in your command-history. +- Use |yCtrl + <Return>|n to add a new line to your input without sending. +(Cmd instead of Ctrl-key on Macs) There is also some |wextra|n info to learn about customizing the webclient. @@ -735,7 +736,7 @@ After playing through the tutorial-world quest, if you aim to make a game with Evennia you are wise to take a look at the |wEvennia documentation|n at - |yhttps://www.evennia.com/docs/latest + |yhttps://www.evennia.com/docs/latest|n - You can start by trying to build some stuff by following the |wBuilder quick-start|n: @@ -857,7 +858,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/tutorial_world/mob.html b/docs/0.9.5/_modules/evennia/contrib/tutorial_world/mob.html index df7851cb77..a56e5de2b8 100644 --- a/docs/0.9.5/_modules/evennia/contrib/tutorial_world/mob.html +++ b/docs/0.9.5/_modules/evennia/contrib/tutorial_world/mob.html @@ -110,7 +110,7 @@ stationary (idling) until attacked. aggressive: if set, will attack Characters in the same room using whatever Weapon it - carries (see tutorial_world.objects.Weapon). + carries (see tutorial_world.objects.TutorialWeapon). if unset, the mob will never engage in combat no matter what. hunting: if set, the mob will pursue enemies trying @@ -209,9 +209,9 @@ be "ticked". Args: - interval (int): The number of seconds + interval (int or None): The number of seconds between ticks - hook_key (str): The name of the method + hook_key (str or None): The name of the method (on this mob) to call every interval seconds. stop (bool, optional): Just stop the @@ -413,16 +413,11 @@ return # we use the same attack commands as defined in - # tutorial_world.objects.Weapon, assuming that + # tutorial_world.objects.TutorialWeapon, assuming that # the mob is given a Weapon to attack with. attack_cmd = random.choice(("thrust", "pierce", "stab", "slash", "chop")) self.execute_cmd("%s %s" % (attack_cmd, target)) - if target.db.health is None: - # This is not an attackable target - logger.log_err(f"{self.key} found {target} had an `health` attribute of `None`.") - return - # analyze the current state if target.db.health <= 0: # we reduced the target to <= 0 health. Move them to the @@ -517,7 +512,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/tutorial_world/objects.html b/docs/0.9.5/_modules/evennia/contrib/tutorial_world/objects.html index 67dbabe55b..9574e1aa7e 100644 --- a/docs/0.9.5/_modules/evennia/contrib/tutorial_world/objects.html +++ b/docs/0.9.5/_modules/evennia/contrib/tutorial_world/objects.html @@ -55,8 +55,8 @@ Obelisk LightSource CrumblingWall -Weapon -WeaponRack +TutorialWeapon +TutorialWeaponRack """ @@ -832,7 +832,7 @@ # ------------------------------------------------------------- # -# Weapon - object type +# TutorialWeapon - object type # # A weapon is necessary in order to fight in the tutorial # world. A weapon (which here is assumed to be a bladed @@ -972,7 +972,7 @@ self.add(CmdAttack()) -
    [docs]class Weapon(TutorialObject): +
    [docs]class TutorialWeapon(TutorialObject): """ This defines a bladed weapon. @@ -984,7 +984,7 @@ """ -
    [docs] def at_object_creation(self): +
    [docs] def at_object_creation(self): """Called at first creation of the object""" super().at_object_creation() self.db.hit = 0.4 # hit chance @@ -993,7 +993,7 @@ self.db.magic = False self.cmdset.add_default(CmdSetWeapon, permanent=True)
    -
    [docs] def reset(self): +
    [docs] def reset(self): """ When reset, the weapon is simply deleted, unless it has a place to return to. @@ -1023,7 +1023,7 @@ WEAPON_PROTOTYPES = { "weapon": { - "typeclass": "evennia.contrib.tutorial_world.objects.Weapon", + "typeclass": "evennia.contrib.tutorial_world.objects.TutorialWeapon", "key": "Weapon", "hit": 0.2, "parry": 0.2, @@ -1168,7 +1168,7 @@ self.add(CmdGetWeapon())
    -
    [docs]class WeaponRack(TutorialObject): +
    [docs]class TutorialWeaponRack(TutorialObject): """ This object represents a weapon store. When people use the "get weapon" command on this rack, it will produce one @@ -1185,7 +1185,7 @@ """ -
    [docs] def at_object_creation(self): +
    [docs] def at_object_creation(self): """ called at creation """ @@ -1199,13 +1199,12 @@ |wstab/thrust/pierce <target>|n - poke at the enemy. More damage but harder to hit. |wslash/chop/bash <target>|n - swipe at the enemy. Less damage but easier to hit. |wdefend/parry|n - protect yourself and make yourself harder to hit.) - """ - ).strip() + """).strip() self.db.no_more_weapons_msg = "you find nothing else of use." self.db.available_weapons = ["knife", "dagger", "sword", "club"]
    -
    [docs] def produce_weapon(self, caller): +
    [docs] def produce_weapon(self, caller): """ This will produce a new weapon from the rack, assuming the caller hasn't already gotten one. When @@ -1261,7 +1260,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/tutorial_world/rooms.html b/docs/0.9.5/_modules/evennia/contrib/tutorial_world/rooms.html index 0fc3e2d28d..2d5d3f7640 100644 --- a/docs/0.9.5/_modules/evennia/contrib/tutorial_world/rooms.html +++ b/docs/0.9.5/_modules/evennia/contrib/tutorial_world/rooms.html @@ -119,7 +119,6 @@ helptext += "\n\n (Write 'give up' if you want to abandon your quest.)" caller.msg(helptext)
    - # for the @detail command we inherit from MuxCommand, since # we want to make use of MuxCommand's pre-parsing of '=' in the # argument. @@ -244,26 +243,22 @@ looking_at_obj.at_desc(looker=caller) return
    -
    [docs]class CmdTutorialGiveUp(default_cmds.MuxCommand): """ Give up the tutorial-world quest and return to Limbo, the start room of the server. """ - key = "give up" - aliases = ["abort"] + aliases = ['abort']
    [docs] def func(self): outro_room = OutroRoom.objects.all() if outro_room: outro_room = outro_room[0] else: - self.caller.msg( - "That didn't work (seems like a bug). " - "Try to use the |wteleport|n command instead." - ) + self.caller.msg("That didn't work (seems like a bug). " + "Try to use the |wteleport|n command instead.") return self.caller.move_to(outro_room)
    @@ -431,7 +426,6 @@ # # ------------------------------------------------------------- -
    [docs]class CmdEvenniaIntro(Command): """ Start the Evennia intro wizard. @@ -440,12 +434,10 @@ intro """ - key = "intro"
    [docs] def func(self): from .intro_menu import init_menu - # quell also superusers if self.caller.account: self.caller.account.execute_cmd("quell") @@ -501,7 +493,6 @@ character.account.execute_cmd("quell") character.msg("(Auto-quelling while in tutorial-world)")
    - # ------------------------------------------------------------- # # Bridge - unique room @@ -1215,6 +1206,7 @@
    [docs] def at_object_leave(self, character, destination): if character.account: character.account.execute_cmd("unquell")
    +
    @@ -1252,7 +1244,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/unixcommand.html b/docs/0.9.5/_modules/evennia/contrib/unixcommand.html index 566e99bb32..712d042057 100644 --- a/docs/0.9.5/_modules/evennia/contrib/unixcommand.html +++ b/docs/0.9.5/_modules/evennia/contrib/unixcommand.html @@ -164,7 +164,7 @@ # Replace the -h/--help self.add_argument( - "-h", "--hel", nargs=0, action=HelpAction, help="display the command help" + "-h", "--help", nargs=0, action=HelpAction, help="display the command help" )
    [docs] def format_usage(self): @@ -371,7 +371,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/contrib/wilderness.html b/docs/0.9.5/_modules/evennia/contrib/wilderness.html index af3df63e2d..6ee75c97ca 100644 --- a/docs/0.9.5/_modules/evennia/contrib/wilderness.html +++ b/docs/0.9.5/_modules/evennia/contrib/wilderness.html @@ -853,7 +853,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/help/manager.html b/docs/0.9.5/_modules/evennia/help/manager.html index 3965f63321..1d5772ffea 100644 --- a/docs/0.9.5/_modules/evennia/help/manager.html +++ b/docs/0.9.5/_modules/evennia/help/manager.html @@ -42,7 +42,6 @@ """ Custom manager for HelpEntry objects. """ -from django.db import models from evennia.utils import logger, utils from evennia.typeclasses.managers import TypedObjectManager @@ -172,7 +171,7 @@ for topic in topics: topic.help_category = default_category topic.save() - string = _("Help database moved to category {default_category}").format( + string = "Help database moved to category {default_category}".format( default_category=default_category ) logger.log_info(string) @@ -228,7 +227,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/help/models.html b/docs/0.9.5/_modules/evennia/help/models.html index 6c7f3f620d..78836660b0 100644 --- a/docs/0.9.5/_modules/evennia/help/models.html +++ b/docs/0.9.5/_modules/evennia/help/models.html @@ -71,7 +71,7 @@ # ------------------------------------------------------------ -
    [docs]class HelpEntry(SharedMemoryModel): +
    [docs]class HelpEntry(SharedMemoryModel): """ A generic help entry. @@ -114,11 +114,11 @@ db_tags = models.ManyToManyField( Tag, blank=True, - help_text="tags on this object. Tags are simple string markers to identify, group and alias objects.", + help_text="tags on this object. Tags are simple string markers to " + "identify, group and alias objects.", ) - # (deprecated, only here to allow MUX helpfile load (don't use otherwise)). - # TODO: remove this when not needed anymore. - db_staff_only = models.BooleanField(default=False) + # Creation date. This is not changed once the object is created. + db_date_created = models.DateTimeField("creation date", editable=False, auto_now=True) # Database manager objects = HelpEntryManager() @@ -126,19 +126,19 @@ # lazy-loaded handlers -
    [docs] @lazy_property +
    [docs] @lazy_property def locks(self): return LockHandler(self)
    -
    [docs] @lazy_property +
    [docs] @lazy_property def tags(self): return TagHandler(self)
    -
    [docs] @lazy_property +
    [docs] @lazy_property def aliases(self): return AliasHandler(self)
    - class Meta(object): + class Meta: "Define Django meta options" verbose_name = "Help Entry" verbose_name_plural = "Help Entries" @@ -148,27 +148,46 @@ # HelpEntry main class methods # # - def __str__(self): - return self.key + return str(self.key) def __repr__(self): - return "%s" % self.key + return f"<HelpEntry {self.key}>" -
    [docs] def access(self, accessing_obj, access_type="read", default=False): +
    [docs] def access(self, accessing_obj, access_type="read", default=True): """ - Determines if another object has permission to access. - accessing_obj - object trying to access this one - access_type - type of access sought - default - what to return if no lock of access_type was found + Determines if another object has permission to access this help entry. + + Accesses used by default: + 'read' - read the help entry itself. + 'view' - see help entry in help index. + + Args: + accessing_obj (Object or Account): Entity trying to access this one. + access_type (str): type of access sought. + default (bool): What to return if no lock of `access_type` was found. + """ return self.locks.check(accessing_obj, access_type=access_type, default=default)
    + @property + def search_index_entry(self): + """ + Property for easily retaining a search index entry for this object. + """ + return { + "key": self.db_key, + "aliases": " ".join(self.aliases.all()), + "category": self.db_help_category, + "text": self.db_entrytext, + "tags": " ".join(str(tag) for tag in self.tags.all()), + } + # # Web/Django methods # -
    [docs] def web_get_admin_url(self): +
    [docs] def web_get_admin_url(self): """ Returns the URI path for the Django Admin page for this object. @@ -183,7 +202,7 @@ "admin:%s_%s_change" % (content_type.app_label, content_type.model), args=(self.id,) )
    -
    [docs] @classmethod +
    [docs] @classmethod def web_get_create_url(cls): """ Returns the URI path for a View that allows users to create new @@ -196,7 +215,9 @@ a named view of 'character-create' would be referenced by this method. ex. - url(r'characters/create/', ChargenView.as_view(), name='character-create') + :: + + url(r'characters/create/', ChargenView.as_view(), name='character-create') If no View has been created and defined in urls.py, returns an HTML anchor. @@ -211,10 +232,10 @@ """ try: return reverse("%s-create" % slugify(cls._meta.verbose_name)) - except: + except Exception: return "#"
    -
    [docs] def web_get_detail_url(self): +
    [docs] def web_get_detail_url(self): """ Returns the URI path for a View that allows users to view details for this object. @@ -226,8 +247,9 @@ a named view of 'character-detail' would be referenced by this method. ex. - url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/$', - CharDetailView.as_view(), name='character-detail') + :: + url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/$', + CharDetailView.as_view(), name='character-detail') If no View has been created and defined in urls.py, returns an HTML anchor. @@ -245,11 +267,10 @@ "%s-detail" % slugify(self._meta.verbose_name), kwargs={"category": slugify(self.db_help_category), "topic": slugify(self.db_key)}, ) - except Exception as e: - print(e) + except Exception: return "#"
    -
    [docs] def web_get_update_url(self): +
    [docs] def web_get_update_url(self): """ Returns the URI path for a View that allows users to update this object. @@ -261,8 +282,10 @@ a named view of 'character-update' would be referenced by this method. ex. - url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/change/$', - CharUpdateView.as_view(), name='character-update') + :: + + url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/change/$', + CharUpdateView.as_view(), name='character-update') If no View has been created and defined in urls.py, returns an HTML anchor. @@ -280,10 +303,10 @@ "%s-update" % slugify(self._meta.verbose_name), kwargs={"category": slugify(self.db_help_category), "topic": slugify(self.db_key)}, ) - except: + except Exception: return "#"
    -
    [docs] def web_get_delete_url(self): +
    [docs] def web_get_delete_url(self): """ Returns the URI path for a View that allows users to delete this object. @@ -294,8 +317,10 @@ a named view of 'character-detail' would be referenced by this method. ex. - url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/delete/$', - CharDeleteView.as_view(), name='character-delete') + :: + + url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/delete/$', + CharDeleteView.as_view(), name='character-delete') If no View has been created and defined in urls.py, returns an HTML anchor. @@ -313,7 +338,7 @@ "%s-delete" % slugify(self._meta.verbose_name), kwargs={"category": slugify(self.db_help_category), "topic": slugify(self.db_key)}, ) - except: + except Exception: return "#"
    # Used by Django Sites/Admin @@ -355,7 +380,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/locks/lockfuncs.html b/docs/0.9.5/_modules/evennia/locks/lockfuncs.html index a535b34acb..af555513a7 100644 --- a/docs/0.9.5/_modules/evennia/locks/lockfuncs.html +++ b/docs/0.9.5/_modules/evennia/locks/lockfuncs.html @@ -52,81 +52,6 @@ with a lock variable/field, so be careful to not expect a certain object type. - -**Appendix: MUX locks** - -Below is a list nicked from the MUX help file on the locks available -in standard MUX. Most of these are not relevant to core Evennia since -locks in Evennia are considerably more flexible and can be implemented -on an individual command/typeclass basis rather than as globally -available like the MUX ones. So many of these are not available in -basic Evennia, but could all be implemented easily if needed for the -individual game. - -``` -MUX Name: Affects: Effect: ----------------------------------------------------------------------- -DefaultLock: Exits: controls who may traverse the exit to - its destination. - Evennia: "traverse:<lockfunc()>" - Rooms: controls whether the account sees the - SUCC or FAIL message for the room - following the room description when - looking at the room. - Evennia: Custom typeclass - Accounts/Things: controls who may GET the object. - Evennia: "get:<lockfunc()" - EnterLock: Accounts/Things: controls who may ENTER the object - Evennia: - GetFromLock: All but Exits: controls who may gets things from a - given location. - Evennia: - GiveLock: Accounts/Things: controls who may give the object. - Evennia: - LeaveLock: Accounts/Things: controls who may LEAVE the object. - Evennia: - LinkLock: All but Exits: controls who may link to the location - if the location is LINK_OK (for linking - exits or setting drop-tos) or ABODE (for - setting homes) - Evennia: - MailLock: Accounts: controls who may @mail the account. - Evennia: - OpenLock: All but Exits: controls who may open an exit. - Evennia: - PageLock: Accounts: controls who may page the account. - Evennia: "send:<lockfunc()>" - ParentLock: All: controls who may make @parent links to - the object. - Evennia: Typeclasses and - "puppet:<lockstring()>" - ReceiveLock: Accounts/Things: controls who may give things to the - object. - Evennia: - SpeechLock: All but Exits: controls who may speak in that location - Evennia: - TeloutLock: All but Exits: controls who may teleport out of the - location. - Evennia: - TportLock: Rooms/Things: controls who may teleport there - Evennia: - UseLock: All but Exits: controls who may USE the object, GIVE - the object money and have the PAY - attributes run, have their messages - heard and possibly acted on by LISTEN - and AxHEAR, and invoke $-commands - stored on the object. - Evennia: Commands and Cmdsets. - DropLock: All but rooms: controls who may drop that object. - Evennia: - VisibleLock: All: Controls object visibility when the - object is not dark and the looker - passes the lock. In DARK locations, the - object must also be set LIGHT and the - viewer must pass the VisibleLock. - Evennia: Room typeclass with - Dark/light script -``` """ @@ -153,16 +78,21 @@
    [docs]def true(*args, **kwargs): - "Always returns True." - return True
    + """ + Always returns True. + """ + return True
    [docs]def all(*args, **kwargs): return True
    [docs]def false(*args, **kwargs): - "Always returns False" + """ + Always returns False + + """ return False
    @@ -170,6 +100,10 @@ return False
    +
    [docs]def superuser(*args, **kwargs): + return False
    + +
    [docs]def self(accessing_obj, accessed_obj, *args, **kwargs): """ Check if accessing_obj is the same as accessed_obj @@ -580,8 +514,6 @@ Only true if accessed_obj has the specified tag and optional category. """ - if hasattr(accessed_obj, "obj"): - accessed_obj = accessed_obj.obj tagkey = args[0] if args else None category = args[1] if len(args) > 1 else None return bool(accessed_obj.tags.get(tagkey, category=category))
    @@ -613,9 +545,6 @@ in your inventory will also pass the lock). """ - if hasattr(accessed_obj, "obj"): - accessed_obj = accessed_obj.obj - def _recursive_inside(obj, accessed_obj, lvl=1): if obj.location: if obj.location == accessed_obj: @@ -690,17 +619,6 @@ return False
    -
    [docs]def superuser(*args, **kwargs): - """ - Only accepts an accesing_obj that is superuser (e.g. user #1) - - Since a superuser would not ever reach this check (superusers - bypass the lock entirely), any user who gets this far cannot be a - superuser, hence we just return False. :) - """ - return False
    - -
    [docs]def has_account(accessing_obj, accessed_obj, *args, **kwargs): """ Only returns true if accessing_obj has_account is true, that is, @@ -779,7 +697,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/locks/lockhandler.html b/docs/0.9.5/_modules/evennia/locks/lockhandler.html index b8ad4130cb..f79c9035fb 100644 --- a/docs/0.9.5/_modules/evennia/locks/lockhandler.html +++ b/docs/0.9.5/_modules/evennia/locks/lockhandler.html @@ -165,6 +165,7 @@
    [docs]class LockException(Exception): """ Raised during an error in a lock. + """ pass
    @@ -180,6 +181,7 @@ def _cache_lockfuncs(): """ Updates the cache. + """ global _LOCKFUNCS _LOCKFUNCS = {} @@ -204,7 +206,7 @@ # -
    [docs]class LockHandler(object): +
    [docs]class LockHandler: """ This handler should be attached to all objects implementing permission checks, under the property 'lockhandler'. @@ -274,7 +276,8 @@ funcname, rest = (part.strip().strip(")") for part in funcstring.split("(", 1)) func = _LOCKFUNCS.get(funcname, None) if not callable(func): - elist.append(_("Lock: lock-function '%s' is not available.") % funcstring) + elist.append(_("Lock: lock-function '{lockfunc}' is not available.").format( + lockfunc=funcstring)) continue args = list(arg.strip() for arg in rest.split(",") if arg and "=" not in arg) kwargs = dict( @@ -301,16 +304,13 @@ continue if access_type in locks: duplicates += 1 - wlist.append( - _( - "LockHandler on %(obj)s: access type '%(access_type)s' changed from '%(source)s' to '%(goal)s' " - % { - "obj": self.obj, - "access_type": access_type, - "source": locks[access_type][2], - "goal": raw_lockstring, - } - ) + wlist.append(_( + "LockHandler on {obj}: access type '{access_type}' " + "changed from '{source}' to '{goal}' ".format( + obj=self.obj, + access_type=access_type, + source=locks[access_type][2], + goal=raw_lockstring)) ) locks[access_type] = (evalstring, tuple(lock_funcs), raw_lockstring) if wlist and WARNING_LOG: @@ -325,12 +325,14 @@ def _cache_locks(self, storage_lockstring): """ Store data + """ self.locks = self._parse_lockstring(storage_lockstring) def _save_locks(self): """ Store locks to obj + """ self.obj.lock_storage = ";".join([tup[2] for tup in self.locks.values()]) @@ -734,6 +736,28 @@ access_type=access_type, ) +def check_perm(obj, permission, no_superuser_bypass=False): + """ + Shortcut for checking if an object has the given `permission`. If the + permission is in `settings.PERMISSION_HIERARCHY`, the check passes + if the object has this permission or higher. + + This is equivalent to calling the perm() lockfunc, but without needing + an accessed object. + + Args: + obj (Object, Account): The object to check access. If this has a linked + Account, the account is checked instead (same rules as per perm()). + permission (str): The permission string to check. + no_superuser_bypass (bool, optional): If unset, the superuser + will always pass this check. + + """ + from evennia.locks.lockfuncs import perm + if not no_superuser_bypass and obj.is_superuser: + return True + return perm(obj, None, permission) + def validate_lockstring(lockstring): """ @@ -833,7 +857,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/objects/admin.html b/docs/0.9.5/_modules/evennia/objects/admin.html deleted file mode 100644 index faa0f792fc..0000000000 --- a/docs/0.9.5/_modules/evennia/objects/admin.html +++ /dev/null @@ -1,301 +0,0 @@ - - - - - - - - evennia.objects.admin — Evennia 0.9.5 documentation - - - - - - - - - - - - - -
    -
    -
    -
    - -

    Source code for evennia.objects.admin

    -#
    -# This sets up how models are displayed
    -# in the web admin interface.
    -#
    -from django import forms
    -from django.conf import settings
    -from django.contrib import admin
    -from evennia.typeclasses.admin import AttributeInline, TagInline
    -from evennia.objects.models import ObjectDB
    -from django.contrib.admin.utils import flatten_fieldsets
    -from django.utils.translation import gettext as _
    -
    -
    -
    [docs]class ObjectAttributeInline(AttributeInline): - """ - Defines inline descriptions of Attributes (experimental) - - """ - - model = ObjectDB.db_attributes.through - related_field = "objectdb"
    - - -
    [docs]class ObjectTagInline(TagInline): - """ - Defines inline descriptions of Tags (experimental) - - """ - - model = ObjectDB.db_tags.through - related_field = "objectdb"
    - - -
    [docs]class ObjectCreateForm(forms.ModelForm): - """ - This form details the look of the fields. - - """ - -
    [docs] class Meta(object): - model = ObjectDB - fields = "__all__"
    - - db_key = forms.CharField( - label="Name/Key", - widget=forms.TextInput(attrs={"size": "78"}), - help_text="Main identifier, like 'apple', 'strong guy', 'Elizabeth' etc. " - "If creating a Character, check so the name is unique among characters!", - ) - db_typeclass_path = forms.CharField( - label="Typeclass", - initial=settings.BASE_OBJECT_TYPECLASS, - widget=forms.TextInput(attrs={"size": "78"}), - help_text="This defines what 'type' of entity this is. This variable holds a " - "Python path to a module with a valid Evennia Typeclass. If you are " - "creating a Character you should use the typeclass defined by " - "settings.BASE_CHARACTER_TYPECLASS or one derived from that.", - ) - db_cmdset_storage = forms.CharField( - label="CmdSet", - initial="", - required=False, - widget=forms.TextInput(attrs={"size": "78"}), - help_text="Most non-character objects don't need a cmdset" - " and can leave this field blank.", - ) - raw_id_fields = ("db_destination", "db_location", "db_home")
    - - -
    [docs]class ObjectEditForm(ObjectCreateForm): - """ - Form used for editing. Extends the create one with more fields - - """ - -
    [docs] class Meta(object): - fields = "__all__"
    - - db_lock_storage = forms.CharField( - label="Locks", - required=False, - widget=forms.Textarea(attrs={"cols": "100", "rows": "2"}), - help_text="In-game lock definition string. If not given, defaults will be used. " - "This string should be on the form " - "<i>type:lockfunction(args);type2:lockfunction2(args);...", - )
    - - -
    [docs]class ObjectDBAdmin(admin.ModelAdmin): - """ - Describes the admin page for Objects. - - """ - - inlines = [ObjectTagInline, ObjectAttributeInline] - list_display = ("id", "db_key", "db_account", "db_typeclass_path") - list_display_links = ("id", "db_key") - ordering = ["db_account", "db_typeclass_path", "id"] - search_fields = ["=id", "^db_key", "db_typeclass_path", "^db_account__db_key"] - raw_id_fields = ("db_destination", "db_location", "db_home") - - save_as = True - save_on_top = True - list_select_related = True - list_filter = ("db_typeclass_path",) - - # editing fields setup - - form = ObjectEditForm - fieldsets = ( - ( - None, - { - "fields": ( - ("db_key", "db_typeclass_path"), - ("db_lock_storage",), - ("db_location", "db_home"), - "db_destination", - "db_cmdset_storage", - ) - }, - ), - ) - - add_form = ObjectCreateForm - add_fieldsets = ( - ( - None, - { - "fields": ( - ("db_key", "db_typeclass_path"), - ("db_location", "db_home"), - "db_destination", - "db_cmdset_storage", - ) - }, - ), - ) - -
    [docs] def get_fieldsets(self, request, obj=None): - """ - Return fieldsets. - - Args: - request (Request): Incoming request. - obj (ObjectDB, optional): Database object. - """ - if not obj: - return self.add_fieldsets - return super().get_fieldsets(request, obj)
    - -
    [docs] def get_form(self, request, obj=None, **kwargs): - """ - Use special form during creation. - - Args: - request (Request): Incoming request. - obj (Object, optional): Database object. - - """ - defaults = {} - if obj is None: - defaults.update( - {"form": self.add_form, "fields": flatten_fieldsets(self.add_fieldsets)} - ) - defaults.update(kwargs) - return super().get_form(request, obj, **defaults)
    - -
    [docs] def save_model(self, request, obj, form, change): - """ - Model-save hook. - - Args: - request (Request): Incoming request. - obj (Object): Database object. - form (Form): Form instance. - change (bool): If this is a change or a new object. - - """ - obj.save() - if not change: - # adding a new object - # have to call init with typeclass passed to it - obj.set_class_from_typeclass(typeclass_path=obj.db_typeclass_path) - obj.basetype_setup() - obj.basetype_posthook_setup() - obj.at_object_creation() - obj.at_init()
    - -
    [docs] def response_add(self, request, obj, post_url_continue=None): - from django.http import HttpResponseRedirect - from django.urls import reverse - - return HttpResponseRedirect(reverse("admin:objects_objectdb_change", args=[obj.id]))
    - - -admin.site.register(ObjectDB, ObjectDBAdmin) -
    - -
    -
    -
    -
    - -
    -
    - - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/objects/manager.html b/docs/0.9.5/_modules/evennia/objects/manager.html index 873baddf8f..f40d3bb5c3 100644 --- a/docs/0.9.5/_modules/evennia/objects/manager.html +++ b/docs/0.9.5/_modules/evennia/objects/manager.html @@ -43,7 +43,6 @@ Custom manager for Objects. """ import re -from itertools import chain from django.db.models import Q from django.conf import settings from django.db.models.fields import exceptions @@ -195,7 +194,8 @@ Args: attribute_name (str): Attribute key to search for. - attribute_value (any): Attribute value to search for. This can also be database objects. + attribute_value (any): Attribute value to search for. This can also be database + objects. candidates (list, optional): Candidate objects to limit search to. typeclasses (list, optional): Python pats to restrict matches with. @@ -632,6 +632,7 @@ """ Clear the db_sessid field of all objects having also the db_account field set. + """ self.filter(db_sessid__isnull=False).update(db_sessid=None) @@ -675,7 +676,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/objects/models.html b/docs/0.9.5/_modules/evennia/objects/models.html index 3c624913c7..931679cee2 100644 --- a/docs/0.9.5/_modules/evennia/objects/models.html +++ b/docs/0.9.5/_modules/evennia/objects/models.html @@ -54,6 +54,7 @@ the database object. Like everything else, they can be accessed transparently through the decorating TypeClass. """ +from collections import defaultdict from django.conf import settings from django.db import models from django.core.exceptions import ObjectDoesNotExist @@ -65,7 +66,7 @@ from evennia.utils.utils import make_iter, dbref, lazy_property -
    [docs]class ContentsHandler: +
    [docs]class ContentsHandler: """ Handles and caches the contents of an object to avoid excessive lookups (this is done very often due to cmdhandler needing to look @@ -73,7 +74,7 @@ of the ObjectDB. """ -
    [docs] def __init__(self, obj): +
    [docs] def __init__(self, obj): """ Sets up the contents handler. @@ -83,34 +84,49 @@ """ self.obj = obj - self._pkcache = {} + self._pkcache = set() self._idcache = obj.__class__.__instance_cache__ + self._typecache = defaultdict(set) self.init()
    -
    [docs] def init(self): +
    [docs] def load(self): + """ + Retrieves all objects from database. Used for initializing. + + Returns: + Objects (list of ObjectDB) + """ + return list(self.obj.locations_set.all())
    + +
    [docs] def init(self): """ Re-initialize the content cache """ - self._pkcache.update( - dict((obj.pk, None) for obj in ObjectDB.objects.filter(db_location=self.obj) if obj.pk) - )
    + objects = self.load() + self._pkcache = {obj.pk for obj in objects} + for obj in objects: + for ctype in obj._content_types: + self._typecache[ctype].add(obj.pk)
    -
    [docs] def get(self, exclude=None): +
    [docs] def get(self, exclude=None, content_type=None): """ Return the contents of the cache. Args: exclude (Object or list of Object): object(s) to ignore + content_type (str or None): Filter list by a content-type. If None, don't filter. Returns: objects (list): the Objects inside this location """ - if exclude: - pks = [pk for pk in self._pkcache if pk not in [excl.pk for excl in make_iter(exclude)]] + if content_type is not None: + pks = self._typecache[content_type] else: pks = self._pkcache + if exclude: + pks = pks - {excl.pk for excl in make_iter(exclude)} try: return [self._idcache[pk] for pk in pks] except KeyError: @@ -120,12 +136,11 @@ try: return [self._idcache[pk] for pk in pks] except KeyError: - # this means the central instance_cache was totally flushed. - # Re-fetching from database will rebuild the necessary parts of the cache - # for next fetch. - return list(ObjectDB.objects.filter(db_location=self.obj))
    + # this means an actual failure of caching. Return real database match. + logger.log_err("contents cache failed for %s." % self.obj.key) + return self.load()
    -
    [docs] def add(self, obj): +
    [docs] def add(self, obj): """ Add a new object to this location @@ -133,9 +148,11 @@ obj (Object): object to add """ - self._pkcache[obj.pk] = None
    + self._pkcache.add(obj.pk) + for ctype in obj._content_types: + self._typecache[ctype].add(obj.pk)
    -
    [docs] def remove(self, obj): +
    [docs] def remove(self, obj): """ Remove object from this location @@ -143,14 +160,18 @@ obj (Object): object to remove """ - self._pkcache.pop(obj.pk, None)
    + self._pkcache.remove(obj.pk) + for ctype in obj._content_types: + if obj.pk in self._typecache[ctype]: + self._typecache[ctype].remove(obj.pk)
    -
    [docs] def clear(self): +
    [docs] def clear(self): """ Clear the contents cache and re-initialize """ self._pkcache = {} + self._typecache = defaultdict(set) self.init()
    @@ -161,7 +182,7 @@ # ------------------------------------------------------------- -
    [docs]class ObjectDB(TypedObject): +
    [docs]class ObjectDB(TypedObject): """ All objects in the game use the ObjectDB model to store data in the database. This is handled transparently through @@ -280,7 +301,7 @@ __defaultclasspath__ = "evennia.objects.objects.DefaultObject" __applabel__ = "objects" -
    [docs] @lazy_property +
    [docs] @lazy_property def contents_cache(self): return ContentsHandler(self)
    @@ -372,7 +393,7 @@ location = property(__location_get, __location_set, __location_del) -
    [docs] def at_db_location_postsave(self, new): +
    [docs] def at_db_location_postsave(self, new): """ This is called automatically after the location field was saved, no matter how. It checks for a variable @@ -398,7 +419,7 @@ ) [o.contents_cache.init() for o in self.__dbclass__.get_all_cached_instances()]
    - class Meta(object): + class Meta: """Define Django meta options""" verbose_name = "Object" @@ -440,7 +461,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/objects/objects.html b/docs/0.9.5/_modules/evennia/objects/objects.html index 34ee6b4556..0b5f7f7202 100644 --- a/docs/0.9.5/_modules/evennia/objects/objects.html +++ b/docs/0.9.5/_modules/evennia/objects/objects.html @@ -45,34 +45,27 @@ These are the (default) starting points for all in-game visible entities. +This is the v1.0 develop version (for ref in doc building). + """ import time -import inflect from collections import defaultdict +import inflect from django.conf import settings +from django.utils.translation import gettext as _ -from evennia.typeclasses.models import TypeclassBase -from evennia.typeclasses.attributes import NickHandler +from evennia.commands import cmdset +from evennia.commands.cmdsethandler import CmdSetHandler from evennia.objects.manager import ObjectManager from evennia.objects.models import ObjectDB from evennia.scripts.scripthandler import ScriptHandler -from evennia.commands import cmdset, command -from evennia.commands.cmdsethandler import CmdSetHandler -from evennia.utils import create -from evennia.utils import search -from evennia.utils import logger -from evennia.utils import ansi -from evennia.utils.utils import ( - class_from_module, - variable_from_module, - lazy_property, - make_iter, - is_iter, - list_to_string, - to_str, -) -from django.utils.translation import gettext as _ +from evennia.typeclasses.attributes import ModelAttributeBackend, NickHandler +from evennia.typeclasses.models import TypeclassBase +from evennia.utils import ansi, create, funcparser, logger, search +from evennia.utils.utils import (class_from_module, is_iter, lazy_property, + list_to_string, make_iter, to_str, + variable_from_module) _INFLECT = inflect.engine() _MULTISESSION_MODE = settings.MULTISESSION_MODE @@ -86,11 +79,19 @@ # the sessid_max is based on the length of the db_sessid csv field (excluding commas) _SESSID_MAX = 16 if _MULTISESSION_MODE in (1, 3) else 1 +_MSG_CONTENTS_PARSER = funcparser.FuncParser( + { + "you": funcparser.funcparser_callable_you, + "You": funcparser.funcparser_callable_You, + "conj": funcparser.funcparser_callable_conjugate + } +) -
    [docs]class ObjectSessionHandler(object): + +
    [docs]class ObjectSessionHandler: """ - Handles the get/setting of the sessid - comma-separated integer field + Handles the get/setting of the sessid comma-separated integer field + """
    [docs] def __init__(self, obj): @@ -148,7 +149,7 @@ ] if None in sessions: # this happens only if our cache has gone out of sync with the SessionHandler. - self._recache() + return self.get(sessid=sessid) return sessions
    @@ -247,6 +248,9 @@ """ + # Used for sorting / filtering in inventories / room contents. + _content_types = ("object",) + # lockstring of newly created objects, for easy overloading. # Will be formatted with the appropriate attributes. lockstring = "control:id({account_id}) or perm(Admin);delete:id({account_id}) or perm(Admin)" @@ -265,7 +269,7 @@
    [docs] @lazy_property def nicks(self): - return NickHandler(self)
    + return NickHandler(self, ModelAttributeBackend)
    [docs] @lazy_property def sessions(self): @@ -300,7 +304,7 @@ and not self.db_account.attributes.get("_quell") ) -
    [docs] def contents_get(self, exclude=None): +
    [docs] def contents_get(self, exclude=None, content_type=None): """ Returns the contents of this object, i.e. all objects that has this object set as its location. @@ -309,17 +313,18 @@ Args: exclude (Object): Object to exclude from returned contents list + content_type (str): A content_type to filter by. None for no + filtering. Returns: contents (list): List of contents of this Object. Notes: - Also available as the `contents` property. + Also available as the `contents` property, minus exclusion + and filtering. """ - con = self.contents_cache.get(exclude=exclude) - # print "contents_get:", self, con, id(self), calledby() # DEBUG - return con
    + return self.contents_cache.get(exclude=exclude, content_type=content_type)
    [docs] def contents_set(self, *args): "You cannot replace this property" @@ -335,6 +340,7 @@ """ Returns all exits from this object, i.e. all objects at this location having the property destination != `None`. + """ return [exi for exi in self.contents if exi.destination] @@ -381,6 +387,7 @@ Returns: singular (str): The singular form to display. plural (str): The determined plural form of the key, including the count. + """ plural_category = "plural_key" key = kwargs.get("key", self.key) @@ -415,6 +422,7 @@ nofound_string=None, multimatch_string=None, use_dbref=None, + stacked=0, ): """ Returns an Object matching a search string/condition @@ -443,7 +451,9 @@ to search. Note that this is used to query the *contents* of a location and will not match for the location itself - if you want that, don't set this or use `candidates` to specify - exactly which objects should be searched. + exactly which objects should be searched. If this nor candidates are + given, candidates will include caller's inventory, current location and + all objects in the current location. attribute_name (str): Define which property to search. If set, no key+alias search will be performed. This can be used to search database fields (db_ will be automatically @@ -471,10 +481,19 @@ will be treated like a normal string. If `None` (default), the ability to query by #dbref is turned on if `self` has the permission 'Builder' and is turned off otherwise. + stacked (int, optional): If > 0, multimatches will be analyzed to determine if they + only contains identical objects; these are then assumed 'stacked' and no multi-match + error will be generated, instead `stacked` number of matches will be returned. If + `stacked` is larger than number of matches, returns that number of matches. If + the found stack is a mix of objects, return None and handle the multi-match + error depending on the value of `quiet`. Returns: - match (Object, None or list): will return an Object/None if `quiet=False`, - otherwise it will return a list of 0, 1 or more matches. + Object: If finding a match an `quiet=False` + None: If not finding a unique match and `quiet=False`. + list: With 0, 1 or more matching objects if `quiet=True` + list: With 2 or more matching objects if `stacked` is a positive integer and + the matched stack has only object-copies. Notes: To find Accounts, use eg. `evennia.account_search`. If @@ -542,8 +561,29 @@ use_dbref=use_dbref, ) + nresults = len(results) + if stacked > 0 and nresults > 1: + # handle stacks, disable multimatch errors + nstack = nresults + if not exact: + # we re-run exact match agains one of the matches to + # make sure we were not catching partial matches not belonging + # to the stack + nstack = len(ObjectDB.objects.get_objs_with_key_or_alias( + results[0].key, + exact=True, + candidates=list(results), + typeclasses=[typeclass] if typeclass else None + )) + if nstack == nresults: + # a valid stack, return multiple results + return list(results)[:stacked] + if quiet: + # don't auto-handle error messaging return list(results) + + # handle error messages return _AT_SEARCH_RESULT( results, self, @@ -703,6 +743,7 @@ Keyword Args: Keyword arguments will be passed to the function for all objects. + """ contents = self.contents if exclude: @@ -719,64 +760,94 @@ text (str or tuple): Message to send. If a tuple, this should be on the valid OOB outmessage form `(message, {kwargs})`, where kwargs are optional data passed to the `text` - outputfunc. + outputfunc. The message will be parsed for `{key}` formatting and + `$You/$you()/$You(key)` and `$conj(verb)` inline function callables. + The `key` is taken from the `mapping` kwarg {"key": object, ...}`. + The `mapping[key].get_display_name(looker=recipient)` will be called + for that key for every recipient of the string. exclude (list, optional): A list of objects not to send to. from_obj (Object, optional): An object designated as the "sender" of the message. See `DefaultObject.msg()` for more info. mapping (dict, optional): A mapping of formatting keys - `{"key":<object>, "key2":<object2>,...}. The keys - must match `{key}` markers in the `text` if this is a string or - in the internal `message` if `text` is a tuple. These - formatting statements will be - replaced by the return of `<object>.get_display_name(looker)` - for every looker in contents that receives the - message. This allows for every object to potentially - get its own customized string. - Keyword Args: - Keyword arguments will be passed on to `obj.msg()` for all - messaged objects. + `{"key":<object>, "key2":<object2>,...}. + The keys must either match `{key}` or `$You(key)/$you(key)` markers + in the `text` string. If `<object>` doesn't have a `get_display_name` + method, it will be returned as a string. If not set, a key `you` will + be auto-added to point to `from_obj` if given, otherwise to `self`. + **kwargs: Keyword arguments will be passed on to `obj.msg()` for all + messaged objects. Notes: - The `mapping` argument is required if `message` contains - {}-style format syntax. The keys of `mapping` should match - named format tokens, and its values will have their - `get_display_name()` function called for each object in - the room before substitution. If an item in the mapping does - not have `get_display_name()`, its string value will be used. + For 'actor-stance' reporting (You say/Name says), use the + `$You()/$you()/$You(key)` and `$conj(verb)` (verb-conjugation) + inline callables. This will use the respective `get_display_name()` + for all onlookers except for `from_obj or self`, which will become + 'You/you'. If you use `$You/you(key)`, the key must be in `mapping`. - Example: - Say Char is a Character object and Npc is an NPC object: + For 'director-stance' reporting (Name says/Name says), use {key} + syntax directly. For both `{key}` and `You/you(key)`, + `mapping[key].get_display_name(looker=recipient)` may be called + depending on who the recipient is. - char.location.msg_contents( - "{attacker} kicks {defender}", - mapping=dict(attacker=char, defender=npc), exclude=(char, npc)) + Examples: - This will result in everyone in the room seeing 'Char kicks NPC' - where everyone may potentially see different results for Char and Npc - depending on the results of `char.get_display_name(looker)` and - `npc.get_display_name(looker)` for each particular onlooker + Let's assume + - `player1.key -> "Player1"`, + `player1.get_display_name(looker=player2) -> "The First girl"` + - `player2.key -> "Player2"`, + `player2.get_display_name(looker=player1) -> "The Second girl"` + + Actor-stance: + :: + + char.location.msg_contents( + "$You() $conj(attack) $you(defender).", + mapping={"defender": player2}) + + - player1 will see `You attack The Second girl.` + - player2 will see 'The First girl attacks you.' + + Director-stance: + :: + + char.location.msg_contents( + "{attacker} attacks {defender}.", + mapping={"attacker:player1, "defender":player2}) + + - player1 will see: 'Player1 attacks The Second girl.' + - player2 will see: 'The First girl attacks Player2' """ # we also accept an outcommand on the form (message, {kwargs}) is_outcmd = text and is_iter(text) inmessage = text[0] if is_outcmd else text outkwargs = text[1] if is_outcmd and len(text) > 1 else {} + mapping = mapping or {} + you = from_obj or self + + if 'you' not in mapping: + mapping[you] = you contents = self.contents if exclude: exclude = make_iter(exclude) contents = [obj for obj in contents if obj not in exclude] - for obj in contents: - if mapping: - substitutions = { - t: sub.get_display_name(obj) if hasattr(sub, "get_display_name") else str(sub) - for t, sub in mapping.items() - } - outmessage = inmessage.format(**substitutions) - else: - outmessage = inmessage - obj.msg(text=(outmessage, outkwargs), from_obj=from_obj, **kwargs)
    + + for receiver in contents: + + # actor-stance replacements + inmessage = _MSG_CONTENTS_PARSER.parse( + inmessage, raise_errors=True, return_string=True, + caller=you, receiver=receiver, mapping=mapping) + + # director-stance replacements + outmessage = inmessage.format( + **{key: obj.get_display_name(looker=receiver) + if hasattr(obj, "get_display_name") else str(obj) + for key, obj in mapping.items()}) + + receiver.msg(text=(outmessage, outkwargs), from_obj=from_obj, **kwargs)
    [docs] def move_to( self, @@ -838,7 +909,7 @@ self.msg("%s%s" % (string, "" if err is None else " (%s)" % err)) return - errtxt = _("Couldn't perform move ('%s'). Contact an admin.") + errtxt = _("Couldn't perform move ({err}). Contact an admin.") if not emit_to_obj: emit_to_obj = self @@ -857,10 +928,10 @@ # Before the move, call eventual pre-commands. if move_hooks: try: - if not self.at_before_move(destination): + if not self.at_before_move(destination, **kwargs): return False except Exception as err: - logerr(errtxt % "at_before_move()", err) + logerr(errtxt.format(err="at_before_move()"), err) return False # Save the old location @@ -869,9 +940,9 @@ # Call hook on source location if move_hooks and source_location: try: - source_location.at_object_leave(self, destination) + source_location.at_object_leave(self, destination, **kwargs) except Exception as err: - logerr(errtxt % "at_object_leave()", err) + logerr(errtxt.format(err="at_object_leave()"), err) return False if not quiet: @@ -879,14 +950,14 @@ try: self.announce_move_from(destination, **kwargs) except Exception as err: - logerr(errtxt % "at_announce_move()", err) + logerr(errtxt.format(err="at_announce_move()"), err) return False # Perform move try: self.location = destination except Exception as err: - logerr(errtxt % "location change", err) + logerr(errtxt.format(err="location change"), err) return False if not quiet: @@ -894,25 +965,25 @@ try: self.announce_move_to(source_location, **kwargs) except Exception as err: - logerr(errtxt % "announce_move_to()", err) + logerr(errtxt.format(err="announce_move_to()"), err) return False if move_hooks: # Perform eventual extra commands on the receiving location # (the object has already arrived at this point) try: - destination.at_object_receive(self, source_location) + destination.at_object_receive(self, source_location, **kwargs) except Exception as err: - logerr(errtxt % "at_object_receive()", err) + logerr(errtxt.format(err="at_object_receive()"), err) return False # Execute eventual extra commands on this object after moving it # (usually calling 'look') if move_hooks: try: - self.at_after_move(source_location) + self.at_after_move(source_location, **kwargs) except Exception as err: - logerr(errtxt % "at_after_move", err) + logerr(errtxt.format(err="at_after_move"), err) return False return True
    @@ -920,6 +991,7 @@ """ Destroys all of the exits and any exits pointing to this object as a destination. + """ for out_exit in [exi for exi in ObjectDB.objects.get_contents(self) if exi.db_destination]: out_exit.delete() @@ -930,6 +1002,7 @@ """ Moves all objects (accounts/things) to their home location or to default home. + """ # Gather up everything that thinks this is its location. default_home_id = int(settings.DEFAULT_HOME.lstrip("#")) @@ -939,8 +1012,8 @@ # we are deleting default home! default_home = None except Exception: - string = _("Could not find default home '(#%d)'.") - logger.log_err(string % default_home_id) + string = _("Could not find default home '(#{dbid})'.") + logger.log_err(string.format(dbid=default_home_id)) default_home = None for obj in self.contents: @@ -952,18 +1025,17 @@ # If for some reason it's still None... if not home: - string = "Missing default home, '%s(#%d)' " - string += "now has a null location." obj.location = None obj.msg(_("Something went wrong! You are dumped into nowhere. Contact an admin.")) - logger.log_err(string % (obj.name, obj.dbid)) + logger.log_err("Missing default home - '{name}(#{dbid})' now " + "has a null location.".format(name=obj.name, dbid=obj.dbid)) return if obj.has_account: if home: string = "Your current location has ceased to exist," - string += " moving you to %s(#%d)." - obj.msg(_(string) % (home.name, home.dbid)) + string += " moving you to (#{dbid})." + obj.msg(_(string).format(dbid=home.dbid)) else: # Famous last words: The account should never see this. string = "This place should not exist ... contact an admin." @@ -1070,8 +1142,8 @@
    [docs] def at_object_post_copy(self, new_obj, **kwargs): """ - Called by DefaultObject.copy(). Meant to be overloaded. In case there's extra data not covered by - .copy(), this can be used to deal with it. + Called by DefaultObject.copy(). Meant to be overloaded. In case there's extra data not + covered by .copy(), this can be used to deal with it. Args: new_obj (Object): The new Copy of this object. @@ -1119,7 +1191,7 @@ self.account = None for script in _ScriptDB.objects.get_all_scripts_on_obj(self): - script.stop() + script.delete() # Destroy any exits to and from this room, if any self.clear_exits() @@ -1512,7 +1584,8 @@ if not source_location and self.location.has_account: # This was created from nowhere and added to an account's # inventory; it's probably the result of a create command. - string = "You now have %s in your possession." % self.get_display_name(self.location) + string = _("You now have {name} in your possession.").format( + name=self.get_display_name(self.location)) self.location.msg(string) return @@ -1520,9 +1593,9 @@ if msg: string = msg else: - string = "{object} arrives to {destination} from {origin}." + string = _("{object} arrives to {destination} from {origin}.") else: - string = "{object} arrives to {destination}." + string = _("{object} arrives to {destination}.") origin = source_location destination = self.location @@ -1705,20 +1778,26 @@ **kwargs (dict): Arbitrary, optional arguments for users overriding the call (unused by default). """ + + def filter_visible(obj_list): + # Helper method to determine if objects are visible to the looker. + return [obj for obj in obj_list if obj != looker and obj.access(looker, "view")] + if not looker: return "" + # get and identify all objects - visible = (con for con in self.contents if con != looker and con.access(looker, "view")) - exits, users, things = [], [], defaultdict(list) - for con in visible: - key = con.get_display_name(looker) - if con.destination: - exits.append(key) - elif con.has_account: - users.append("|c%s|n" % key) - else: - # things can be pluralized - things[key].append(con) + exits_list = filter_visible(self.contents_get(content_type="exit")) + users_list = filter_visible(self.contents_get(content_type="character")) + things_list = filter_visible(self.contents_get(content_type="object")) + + things = defaultdict(list) + + for thing in things_list: + things[thing.key].append(thing) + users = [f"|c{user.key}|n" for user in users_list] + exits = [ex.key for ex in exits_list] + # get description, build string string = "|c%s|n\n" % self.get_display_name(looker) desc = self.db.desc @@ -1923,7 +2002,8 @@ a say. This is sent by the whisper command by default. Other verbal commands could use this hook in similar ways. - receivers (Object or iterable): If set, this is the target or targets for the say/whisper. + receivers (Object or iterable): If set, this is the target or targets for the + say/whisper. Returns: message (str): The (possibly modified) text to be spoken. @@ -1954,8 +2034,8 @@ msg_self (bool or str, optional): If boolean True, echo `message` to self. If a string, return that message. If False or unset, don't echo to self. msg_location (str, optional): The message to echo to self's location. - receivers (Object or iterable, optional): An eventual receiver or receivers of the message - (by default only used by whispers). + receivers (Object or iterable, optional): An eventual receiver or receivers of the + message (by default only used by whispers). msg_receivers(str): Specific message to pass to the receiver(s). This will parsed with the {receiver} placeholder replaced with the given receiver. Keyword Args: @@ -1990,8 +2070,7 @@ msg_type = "whisper" msg_self = ( '{self} whisper to {all_receivers}, "|n{speech}|n"' - if msg_self is True - else msg_self + if msg_self is True else msg_self ) msg_receivers = msg_receivers or '{object} whispers: "|n{speech}|n"' msg_location = None @@ -2078,6 +2157,9 @@ """ + # Tuple of types used for indexing inventory contents. Characters generally wouldn't be in + # anyone's inventory, but this also governs displays in room contents. + _content_types = ("character",) # lockstring of newly created rooms, for easy overloading. # Will be formatted with the appropriate attributes. lockstring = ( @@ -2117,6 +2199,13 @@ # If no typeclass supplied, use this class kwargs["typeclass"] = kwargs.pop("typeclass", cls) + # Normalize to latin characters and validate, if necessary, the supplied key + key = cls.normalize_name(key) + + if not cls.validate_name(key): + errors.append(_("Invalid character name.")) + return obj, errors + # Set the supplied key as the name of the intended object kwargs["key"] = key @@ -2133,7 +2222,7 @@ # Check to make sure account does not have too many chars if account: if len(account.characters) >= settings.MAX_NR_CHARACTERS: - errors.append("There are too many characters associated with this account.") + errors.append(_("There are too many characters associated with this account.")) return obj, errors # Create the Character @@ -2149,7 +2238,8 @@ # Add locks if not locks and account: - # Allow only the character itself and the creator account to puppet this character (and Developers). + # Allow only the character itself and the creator account to puppet this character + # (and Developers). locks = cls.lockstring.format(**{"character_id": obj.id, "account_id": account.id}) elif not locks and not account: locks = cls.lockstring.format(**{"character_id": obj.id, "account_id": -1}) @@ -2158,14 +2248,47 @@ # If no description is set, set a default description if description or not obj.db.desc: - obj.db.desc = description if description else "This is a character." + obj.db.desc = description if description else _("This is a character.") except Exception as e: - errors.append("An error occurred while creating this '%s' object." % key) + errors.append(f"An error occurred while creating object '{key} object.") logger.log_err(e) return obj, errors
    +
    [docs] @classmethod + def normalize_name(cls, name): + """ + Normalize the character name prior to creating. Note that this should be refactored to + support i18n for non-latin scripts, but as we (currently) have no bug reports requesting + better support of non-latin character sets, requiring character names to be latinified is an + acceptable option. + + Args: + name (str) : The name of the character + + Returns: + latin_name (str) : A valid name. + """ + + from evennia.utils.utils import latinify + + latin_name = latinify(name, default="X") + return latin_name
    + +
    [docs] @classmethod + def validate_name(cls, name): + """ Validate the character name prior to creating. Overload this function to add custom validators + + Args: + name (str) : The name of the character + Returns: + valid (bool) : True if character creation should continue; False if it should fail + + """ + + return True # Default validator does not perform any operations
    +
    [docs] def basetype_setup(self): """ Setup character-specific security. @@ -2197,6 +2320,7 @@ Args: account (Account): This is the connecting account. session (Session): Session controlling the connection. + """ if ( self.location is None @@ -2210,7 +2334,8 @@ self.db.prelogout_location = self.location # save location again to be sure. else: account.msg( - "|r%s has no location and no home is set.|n" % self, session=session + _("|r{obj} has no location and no home is set.|n").format(obj=self), + session=session ) # Note to set home.
    [docs] def at_post_puppet(self, **kwargs): @@ -2228,11 +2353,12 @@ puppeting this Object. """ - self.msg("\nYou become |c%s|n.\n" % self.name) + self.msg(_("\nYou become |c{name}|n.\n").format(name=self.key)) self.msg((self.at_look(self.location), {"type": "look"}), options=None) def message(obj, from_obj): - obj.msg("%s has entered the game." % self.get_display_name(obj), from_obj=from_obj) + obj.msg(_("{name} has entered the game.").format(name=self.get_display_name(obj)), + from_obj=from_obj) self.location.for_contents(message, exclude=[self], from_obj=self)
    @@ -2255,7 +2381,8 @@ if self.location: def message(obj, from_obj): - obj.msg("%s has left the game." % self.get_display_name(obj), from_obj=from_obj) + obj.msg(_("{name} has left the game.").format(name=self.get_display_name(obj)), + from_obj=from_obj) self.location.for_contents(message, exclude=[self], from_obj=self) self.db.prelogout_location = self.location @@ -2266,6 +2393,7 @@ """ Returns the idle time of the least idle session in seconds. If no sessions are connected it returns nothing. + """ idle = [session.cmd_last_visible for session in self.sessions.all()] if idle: @@ -2277,6 +2405,7 @@ """ Returns the maximum connection time of all connected sessions in seconds. Returns nothing if there are no sessions. + """ conn = [session.conn_time for session in self.sessions.all()] if conn: @@ -2294,6 +2423,10 @@ location is always `None`. """ + # A tuple of strings used for indexing this object inside an inventory. + # Generally, a room isn't expected to HAVE a location, but maybe in some games? + _content_types = ("room",) + # lockstring of newly created rooms, for easy overloading. # Will be formatted with the {id} of the creating object. lockstring = ( @@ -2366,7 +2499,7 @@ # If no description is set, set a default description if description or not obj.db.desc: - obj.db.desc = description if description else "This is a room." + obj.db.desc = description if description else _("This is a room.") except Exception as e: errors.append("An error occurred while creating this '%s' object." % key) @@ -2428,7 +2561,9 @@ overriding the call (unused by default). Returns: - A string with identifying information to disambiguate the command, conventionally with a preceding space. + A string with identifying information to disambiguate the command, conventionally with a + preceding space. + """ if self.obj.destination: return " (exit to %s)" % self.obj.destination.get_display_name(caller) @@ -2452,6 +2587,7 @@ """ + _content_types = ("exit",) exit_command = ExitCommand priority = 101 @@ -2569,7 +2705,7 @@ # If no description is set, set a default description if description or not obj.db.desc: - obj.db.desc = description if description else "This is an exit." + obj.db.desc = description if description else _("This is an exit.") except Exception as e: errors.append("An error occurred while creating this '%s' object." % key) @@ -2666,7 +2802,7 @@ read for an error string instead. """ - traversing_object.msg("You cannot go there.")
    + traversing_object.msg(_("You cannot go there."))
    @@ -2704,7 +2840,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/prototypes/menus.html b/docs/0.9.5/_modules/evennia/prototypes/menus.html index aa51e135d3..45b0835c5c 100644 --- a/docs/0.9.5/_modules/evennia/prototypes/menus.html +++ b/docs/0.9.5/_modules/evennia/prototypes/menus.html @@ -218,9 +218,7 @@ if kwargs.get("test_parse", True): out.append(" Simulating prototype-func parsing ...") - err, parsed_value = protlib.protfunc_parser(value, testing=True) - if err: - out.append(" |yPython `literal_eval` warning: {}|n".format(err)) + parsed_value = protlib.protfunc_parser(value, testing=True, prototype=prototype) if parsed_value != value: out.append( " |g(Example-)value when parsed ({}):|n {}".format(type(parsed_value), parsed_value) @@ -305,7 +303,7 @@ def _format_protfuncs(): out = [] sorted_funcs = [ - (key, func) for key, func in sorted(protlib.PROT_FUNCS.items(), key=lambda tup: tup[0]) + (key, func) for key, func in sorted(protlib.FUNC_PARSER.callables.items(), key=lambda tup: tup[0]) ] for protfunc_name, protfunc in sorted_funcs: out.append( @@ -2156,7 +2154,8 @@ objects = kwargs["objects"] back_node = kwargs["back_node"] diff = kwargs.get("diff", None) - num_changed = spawner.batch_update_objects_with_prototype(prototype, diff=diff, objects=objects) + num_changed = spawner.batch_update_objects_with_prototype(prototype, diff=diff, objects=objects, + caller=caller) caller.msg("|g{num} objects were updated successfully.|n".format(num=num_changed)) return back_node @@ -2524,7 +2523,7 @@ if not prototype.get("location"): prototype["location"] = caller - obj = spawner.spawn(prototype) + obj = spawner.spawn(prototype, caller=caller) if obj: obj = obj[0] text = "|gNew instance|n {key} ({dbref}) |gspawned at location |n{loc}|n|g.|n".format( @@ -2835,7 +2834,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/prototypes/protfuncs.html b/docs/0.9.5/_modules/evennia/prototypes/protfuncs.html index 5dfa9887e5..6c33769fe7 100644 --- a/docs/0.9.5/_modules/evennia/prototypes/protfuncs.html +++ b/docs/0.9.5/_modules/evennia/prototypes/protfuncs.html @@ -40,35 +40,30 @@

    Source code for evennia.prototypes.protfuncs

     """
    -Protfuncs are function-strings embedded in a prototype and allows for a builder to create a
    -prototype with custom logics without having access to Python. The Protfunc is parsed using the
    -inlinefunc parser but is fired at the moment the spawning happens, using the creating object's
    -session as input.
    +Protfuncs are FuncParser-callables that can be embedded in a prototype to
    +provide custom logic without having access to Python. The protfunc is parsed at
    +the time of spawning, using the creating object's session as input. If the
    +protfunc returns a non-string, this is what will be added to the prototype.
     
     In the prototype dict, the protfunc is specified as a string inside the prototype, e.g.:
     
         { ...
     
    -    "key": "$funcname(arg1, arg2, ...)"
    +    "key": "$funcname(args, kwargs)"
     
         ...  }
     
    -and multiple functions can be nested (no keyword args are supported). The result will be used as the
    -value for that prototype key for that individual spawn.
    -
    -Available protfuncs are callables in one of the modules of `settings.PROT_FUNC_MODULES`. They
    -are specified as functions
    +Available protfuncs are either all callables in one of the modules of `settings.PROT_FUNC_MODULES`
    +or all callables added to a dict FUNCPARSER_CALLABLES in such a module.
     
         def funcname (*args, **kwargs)
     
    -where *args are the arguments given in the prototype, and **kwargs are inserted by Evennia:
    +At spawn-time the spawner passes the following extra kwargs into each callable (in addition to
    +what is added in the call itself):
     
         - session (Session): The Session of the entity spawning using this prototype.
         - prototype (dict): The dict this protfunc is a part of.
         - current_key (str): The active key this value belongs to in the prototype.
    -    - testing (bool): This is set if this function is called as part of the prototype validation; if
    -        set, the protfunc should take care not to perform any persistent actions, such as operate on
    -        objects or add things to the database.
     
     Any traceback raised by this function will be handled at the time of spawning and abort the spawn
     before any object is created/updated. It must otherwise return the value to store for the specified
    @@ -76,315 +71,33 @@
     
     """
     
    -from ast import literal_eval
    -from random import randint as base_randint, random as base_random, choice as base_choice
    -import re
    -
    -from evennia.utils import search
    -from evennia.utils.utils import justify as base_justify, is_iter, to_str
    -
    -_PROTLIB = None
    -
    -_RE_DBREF = re.compile(r"\#[0-9]+")
    +from evennia.utils import funcparser
     
     
    -# default protfuncs
    -
    -
    -
    [docs]def random(*args, **kwargs): +
    [docs]def protfunc_callable_protkey(*args, **kwargs): """ - Usage: $random() - Returns a random value in the interval [0, 1) - - """ - return base_random()
    - - -
    [docs]def randint(*args, **kwargs): - """ - Usage: $randint(start, end) - Returns random integer in interval [start, end] - - """ - if len(args) != 2: - raise TypeError("$randint needs two arguments - start and end.") - start, end = int(args[0]), int(args[1]) - return base_randint(start, end)
    - - -
    [docs]def left_justify(*args, **kwargs): - """ - Usage: $left_justify(<text>) - Returns <text> left-justified. - - """ - if args: - return base_justify(args[0], align="l") - return ""
    - - -
    [docs]def right_justify(*args, **kwargs): - """ - Usage: $right_justify(<text>) - Returns <text> right-justified across screen width. - - """ - if args: - return base_justify(args[0], align="r") - return ""
    - - -
    [docs]def center_justify(*args, **kwargs): - - """ - Usage: $center_justify(<text>) - Returns <text> centered in screen width. - - """ - if args: - return base_justify(args[0], align="c") - return ""
    - - -
    [docs]def choice(*args, **kwargs): - """ - Usage: $choice(val, val, val, ...) - Returns one of the values randomly - """ - if args: - return base_choice(args) - return ""
    - - -
    [docs]def full_justify(*args, **kwargs): - - """ - Usage: $full_justify(<text>) - Returns <text> filling up screen width by adding extra space. - - """ - if args: - return base_justify(args[0], align="f") - return ""
    - - -
    [docs]def protkey(*args, **kwargs): - """ - Usage: $protkey(<key>) + Usage: $protkey(keyname) Returns the value of another key in this prototoype. Will raise an error if the key is not found in this prototype. """ - if args: - prototype = kwargs["prototype"] - return prototype[args[0].strip()]
    + if not args: + return "" + + prototype = kwargs.get("prototype", {}) + prot_value = prototype[args[0]] + try: + return funcparser.funcparser_callable_eval(prot_value, **kwargs) + except funcparser.ParsingError: + return prot_value
    -
    [docs]def add(*args, **kwargs): - """ - Usage: $add(val1, val2) - Returns the result of val1 + val2. Values must be - valid simple Python structures possible to add, - such as numbers, lists etc. - - """ - if len(args) > 1: - val1, val2 = args[0], args[1] - # try to convert to python structures, otherwise, keep as strings - try: - val1 = literal_eval(val1.strip()) - except Exception: - pass - try: - val2 = literal_eval(val2.strip()) - except Exception: - pass - return val1 + val2 - raise ValueError("$add requires two arguments.")
    - - -
    [docs]def sub(*args, **kwargs): - """ - Usage: $del(val1, val2) - Returns the value of val1 - val2. Values must be - valid simple Python structures possible to - subtract. - - """ - if len(args) > 1: - val1, val2 = args[0], args[1] - # try to convert to python structures, otherwise, keep as strings - try: - val1 = literal_eval(val1.strip()) - except Exception: - pass - try: - val2 = literal_eval(val2.strip()) - except Exception: - pass - return val1 - val2 - raise ValueError("$sub requires two arguments.")
    - - -
    [docs]def mult(*args, **kwargs): - """ - Usage: $mul(val1, val2) - Returns the value of val1 * val2. The values must be - valid simple Python structures possible to - multiply, like strings and/or numbers. - - """ - if len(args) > 1: - val1, val2 = args[0], args[1] - # try to convert to python structures, otherwise, keep as strings - try: - val1 = literal_eval(val1.strip()) - except Exception: - pass - try: - val2 = literal_eval(val2.strip()) - except Exception: - pass - return val1 * val2 - raise ValueError("$mul requires two arguments.")
    - - -
    [docs]def div(*args, **kwargs): - """ - Usage: $div(val1, val2) - Returns the value of val1 / val2. Values must be numbers and - the result is always a float. - - """ - if len(args) > 1: - val1, val2 = args[0], args[1] - # try to convert to python structures, otherwise, keep as strings - try: - val1 = literal_eval(val1.strip()) - except Exception: - pass - try: - val2 = literal_eval(val2.strip()) - except Exception: - pass - return val1 / float(val2) - raise ValueError("$mult requires two arguments.")
    - - -
    [docs]def toint(*args, **kwargs): - """ - Usage: $toint(<number>) - Returns <number> as an integer. - """ - if args: - val = args[0] - try: - return int(literal_eval(val.strip())) - except ValueError: - return val - raise ValueError("$toint requires one argument.")
    - - -
    [docs]def eval(*args, **kwargs): - """ - Usage $eval(<expression>) - Returns evaluation of a simple Python expression. The string may *only* consist of the following - Python literal structures: strings, numbers, tuples, lists, dicts, booleans, - and None. The strings can also contain #dbrefs. Escape embedded protfuncs as $$protfunc(..) - - those will then be evaluated *after* $eval. - - """ - global _PROTLIB - if not _PROTLIB: - from evennia.prototypes import prototypes as _PROTLIB - - string = ",".join(args) - struct = literal_eval(string) - - if isinstance(struct, str): - # we must shield the string, otherwise it will be merged as a string and future - # literal_evas will pick up e.g. '2' as something that should be converted to a number - struct = '"{}"'.format(struct) - - # convert any #dbrefs to objects (also in nested structures) - struct = _PROTLIB.value_to_obj_or_any(struct) - - return struct
    - - -def _obj_search(*args, **kwargs): - "Helper function to search for an object" - - query = "".join(args) - session = kwargs.get("session", None) - return_list = kwargs.pop("return_list", False) - account = None - - if session: - account = session.account - - targets = search.search_object(query) - - if return_list: - retlist = [] - if account: - for target in targets: - if target.access(account, target, "control"): - retlist.append(target) - else: - retlist = targets - return retlist - else: - # single-match - if not targets: - raise ValueError("$obj: Query '{}' gave no matches.".format(query)) - if len(targets) > 1: - raise ValueError( - "$obj: Query '{query}' gave {nmatches} matches. Limit your " - "query or use $objlist instead.".format(query=query, nmatches=len(targets)) - ) - target = targets[0] - if account: - if not target.access(account, target, "control"): - raise ValueError( - "$obj: Obj {target}(#{dbref} cannot be added - " - "Account {account} does not have 'control' access.".format( - target=target.key, dbref=target.id, account=account - ) - ) - return target - - -
    [docs]def obj(*args, **kwargs): - """ - Usage $obj(<query>) - Returns one Object searched globally by key, alias or #dbref. Error if more than one. - - """ - obj = _obj_search(return_list=False, *args, **kwargs) - if obj: - return "#{}".format(obj.id) - return "".join(args)
    - - -
    [docs]def objlist(*args, **kwargs): - """ - Usage $objlist(<query>) - Returns list with one or more Objects searched globally by key, alias or #dbref. - - """ - return ["#{}".format(obj.id) for obj in _obj_search(return_list=True, *args, **kwargs)]
    - - -
    [docs]def dbref(*args, **kwargs): - """ - Usage $dbref(<#dbref>) - Validate that a #dbref input is valid. - """ - if not args or len(args) < 1 or _RE_DBREF.match(args[0]) is None: - raise ValueError("$dbref requires a valid #dbref argument.") - - return obj(args[0])
    +# this is picked up by FuncParser +FUNCPARSER_CALLABLES = { + "protkey": protfunc_callable_protkey, + **funcparser.FUNCPARSER_CALLABLES, + **funcparser.SEARCHING_CALLABLES, +}
    @@ -422,7 +135,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/prototypes/prototypes.html b/docs/0.9.5/_modules/evennia/prototypes/prototypes.html index f6dee44be0..81ad83558a 100644 --- a/docs/0.9.5/_modules/evennia/prototypes/prototypes.html +++ b/docs/0.9.5/_modules/evennia/prototypes/prototypes.html @@ -48,10 +48,10 @@ import hashlib import time -from ast import literal_eval from django.conf import settings -from django.db.models import Q, Subquery +from django.db.models import Q from django.core.paginator import Paginator +from django.utils.translation import gettext as _ from evennia.scripts.scripts import DefaultScript from evennia.objects.models import ObjectDB from evennia.typeclasses.attributes import Attribute @@ -59,19 +59,17 @@ from evennia.utils.evmore import EvMore from evennia.utils.utils import ( all_from_module, + variable_from_module, make_iter, is_iter, dbid_to_obj, - callables_from_module, - get_all_typeclasses, - to_str, - dbref, justify, class_from_module, ) from evennia.locks.lockhandler import validate_lockstring, check_lockstring from evennia.utils import logger -from evennia.utils import inlinefuncs, dbserialize +from evennia.utils.funcparser import FuncParser +from evennia.utils import dbserialize from evennia.utils.evtable import EvTable @@ -97,13 +95,18 @@ "tags", "attrs", ) +_ERRSTR = _("Error") +_WARNSTR = _("Warning") PROTOTYPE_TAG_CATEGORY = "from_prototype" _PROTOTYPE_TAG_META_CATEGORY = "db_prototype" -PROT_FUNCS = {} _PROTOTYPE_FALLBACK_LOCK = "spawn:all();edit:all()" +# the protfunc parser +FUNC_PARSER = FuncParser(settings.PROT_FUNC_MODULES) + +
    [docs]class PermissionError(RuntimeError): pass
    @@ -120,7 +123,6 @@ """ Homogenize the more free-form prototype supported pre Evennia 0.7 into the stricter form. - Args: prototype (dict): Prototype. custom_keys (list, optional): Custom keys which should not be interpreted as attrs, beyond @@ -195,11 +197,30 @@ # to remove a default prototype, override it with an empty dict. # internally we store as (key, desc, locks, tags, prototype_dict) prots = [] - for variable_name, prot in all_from_module(mod).items(): - if isinstance(prot, dict): - if "prototype_key" not in prot: - prot["prototype_key"] = variable_name.lower() + + prototype_list = variable_from_module(mod, "PROTOTYPE_LIST") + if prototype_list: + # found mod.PROTOTYPE_LIST - this should be a list of valid + # prototype dicts that must have 'prototype_key' set. + for prot in prototype_list: + if not isinstance(prot, dict): + logger.log_err(f"Prototype read from {mod}.PROTOTYPE_LIST " + f"is not a dict (skipping): {prot}") + continue + elif "prototype_key" not in prot: + logger.log_err(f"Prototype read from {mod}.PROTOTYPE_LIST " + f"is missing the 'prototype_key' (skipping): {prot}") + continue prots.append((prot["prototype_key"], homogenize_prototype(prot))) + else: + # load all global dicts in module as prototypes. If the prototype_key + # is not given, the variable name will be used. + for variable_name, prot in all_from_module(mod).items(): + if isinstance(prot, dict): + if "prototype_key" not in prot: + prot["prototype_key"] = variable_name.lower() + prots.append((prot["prototype_key"], homogenize_prototype(prot))) + # assign module path to each prototype_key for easy reference _MODULE_PROTOTYPE_MODULES.update({prototype_key.lower(): mod for prototype_key, _ in prots}) # make sure the prototype contains all meta info @@ -228,6 +249,7 @@
    [docs]class DbPrototype(DefaultScript): """ This stores a single prototype, in an Attribute `prototype`. + """
    [docs] def at_script_creation(self): @@ -279,7 +301,7 @@ prototype_key = in_prototype.get("prototype_key") if not prototype_key: - raise ValidationError("Prototype requires a prototype_key") + raise ValidationError(_("Prototype requires a prototype_key")) prototype_key = str(prototype_key).lower() @@ -287,7 +309,8 @@ if prototype_key in _MODULE_PROTOTYPES: mod = _MODULE_PROTOTYPE_MODULES.get(prototype_key, "N/A") raise PermissionError( - "{} is a read-only prototype " "(defined as code in {}).".format(prototype_key, mod) + _("{protkey} is a read-only prototype " "(defined as code in {module}).").format( + protkey=prototype_key, module=mod) ) # make sure meta properties are included with defaults @@ -354,20 +377,23 @@ if prototype_key in _MODULE_PROTOTYPES: mod = _MODULE_PROTOTYPE_MODULES.get(prototype_key.lower(), "N/A") raise PermissionError( - "{} is a read-only prototype " "(defined as code in {}).".format(prototype_key, mod) + _("{protkey} is a read-only prototype " "(defined as code in {module}).").format( + protkey=prototype_key, module=mod) ) stored_prototype = DbPrototype.objects.filter(db_key__iexact=prototype_key) if not stored_prototype: - raise PermissionError("Prototype {} was not found.".format(prototype_key)) + raise PermissionError(_("Prototype {prototype_key} was not found.").format( + prototype_key=prototype_key)) stored_prototype = stored_prototype[0] if caller: if not stored_prototype.access(caller, "edit"): raise PermissionError( - "{} needs explicit 'edit' permissions to " - "delete prototype {}.".format(caller, prototype_key) + _("{caller} needs explicit 'edit' permissions to " + "delete prototype {prototype_key}.").format( + caller=caller, prototype_key=prototype_key) ) stored_prototype.delete() return True
    @@ -466,7 +492,11 @@ nmodules = len(module_prototypes) ndbprots = db_matches.count() if nmodules + ndbprots != 1: - raise KeyError(f"Found {nmodules + ndbprots} matching prototypes {module_prototypes}.") + raise KeyError(_( + "Found {num} matching prototypes {module_prototypes}.").format( + num=nmodules + ndbprots, + module_prototypes=module_prototypes) + ) if return_iterators: # trying to get the entire set of prototypes - we must paginate @@ -496,10 +526,14 @@ Listing 1000+ prototypes can be very slow. So we customize EvMore to display an EvTable per paginated page rather than to try creating an EvTable for the entire dataset and then paginate it. + """
    [docs] def __init__(self, caller, *args, session=None, **kwargs): - """Store some extra properties on the EvMore class""" + """ + Store some extra properties on the EvMore class + + """ self.show_non_use = kwargs.pop("show_non_use", False) self.show_non_edit = kwargs.pop("show_non_edit", False) super().__init__(caller, *args, session=session, **kwargs)
    @@ -510,6 +544,7 @@ and we must handle these separately since they cannot be paginated in the same way. We will build the prototypes so that the db-prototypes come first (they are likely the most volatile), followed by the mod-prototypes. + """ dbprot_query, modprot_list = inp # set the number of entries per page to half the reported height of the screen @@ -531,6 +566,7 @@ """ The listing is separated in db/mod prototypes, so we need to figure out which one to pick based on the page number. Also, pageno starts from 0. + """ dbprot_pages, modprot_list = self._data @@ -539,15 +575,16 @@ else: # get the correct slice, adjusted for the db-prototypes pageno = max(0, pageno - self._npages_db) - return modprot_list[pageno * self.height : pageno * self.height + self.height]
    + return modprot_list[pageno * self.height: pageno * self.height + self.height]
    [docs] def page_formatter(self, page): - """Input is a queryset page from django.Paginator""" + """ + Input is a queryset page from django.Paginator + + """ caller = self._caller # get use-permissions of readonly attributes (edit is always False) - display_tuples = [] - table = EvTable( "|wKey|n", "|wSpawn/Edit|n", @@ -616,7 +653,7 @@ dbprot_query, modprot_list = search_prototype(key, tags, return_iterators=True) if not dbprot_query and not modprot_list: - caller.msg("No prototypes found.", session=session) + caller.msg(_("No prototypes found."), session=session) return None # get specific prototype (one value or exception) @@ -667,7 +704,7 @@ protkey = protkey and protkey.lower() or prototype.get("prototype_key", None) if strict and not bool(protkey): - _flags["errors"].append("Prototype lacks a `prototype_key`.") + _flags["errors"].append(_("Prototype lacks a 'prototype_key'.")) protkey = "[UNSET]" typeclass = prototype.get("typeclass") @@ -676,12 +713,13 @@ if strict and not (typeclass or prototype_parent): if is_prototype_base: _flags["errors"].append( - "Prototype {} requires `typeclass` " "or 'prototype_parent'.".format(protkey) + _("Prototype {protkey} requires `typeclass` " "or 'prototype_parent'.").format( + protkey=protkey) ) else: _flags["warnings"].append( - "Prototype {} can only be used as a mixin since it lacks " - "a typeclass or a prototype_parent.".format(protkey) + _("Prototype {protkey} can only be used as a mixin since it lacks " + "'typeclass' or 'prototype_parent' keys.").format(protkey=protkey) ) if strict and typeclass: @@ -689,9 +727,9 @@ class_from_module(typeclass) except ImportError as err: _flags["errors"].append( - "{}: Prototype {} is based on typeclass {}, which could not be imported!".format( - err, protkey, typeclass - ) + _("{err}: Prototype {protkey} is based on typeclass {typeclass}, " + "which could not be imported!").format( + err=err, protkey=protkey, typeclass=typeclass) ) # recursively traverse prototype_parent chain @@ -699,19 +737,22 @@ for protstring in make_iter(prototype_parent): protstring = protstring.lower() if protkey is not None and protstring == protkey: - _flags["errors"].append("Prototype {} tries to parent itself.".format(protkey)) + _flags["errors"].append(_("Prototype {protkey} tries to parent itself.").format( + protkey=protkey)) protparent = protparents.get(protstring) if not protparent: _flags["errors"].append( - "Prototype {}'s prototype_parent '{}' was not found.".format(protkey, protstring) + _("Prototype {protkey}'s prototype_parent '{parent}' was not found.").format( + protkey=protkey, parent=protstring) ) if id(prototype) in _flags["visited"]: _flags["errors"].append( - "{} has infinite nesting of prototypes.".format(protkey or prototype) + _("{protkey} has infinite nesting of prototypes.").format( + protkey=protkey or prototype) ) if _flags["errors"]: - raise RuntimeError("Error: " + "\nError: ".join(_flags["errors"])) + raise RuntimeError(f"{_ERRSTR}: " + f"\n{_ERRSTR}: ".join(_flags["errors"])) _flags["visited"].append(id(prototype)) _flags["depth"] += 1 validate_prototype( @@ -726,16 +767,16 @@ # if we get back to the current level without a typeclass it's an error. if strict and is_prototype_base and _flags["depth"] <= 0 and not _flags["typeclass"]: _flags["errors"].append( - "Prototype {} has no `typeclass` defined anywhere in its parent\n " - "chain. Add `typeclass`, or a `prototype_parent` pointing to a " - "prototype with a typeclass.".format(protkey) + _("Prototype {protkey} has no `typeclass` defined anywhere in its parent\n " + "chain. Add `typeclass`, or a `prototype_parent` pointing to a " + "prototype with a typeclass.").format(protkey=protkey) ) if _flags["depth"] <= 0: if _flags["errors"]: - raise RuntimeError("Error: " + "\nError: ".join(_flags["errors"])) + raise RuntimeError(f"{_ERRSTR}:_" + f"\n{_ERRSTR}: ".join(_flags["errors"])) if _flags["warnings"]: - raise RuntimeWarning("Warning: " + "\nWarning: ".join(_flags["warnings"])) + raise RuntimeWarning(f"{_WARNSTR}: " + f"\n{_WARNSTR}: ".join(_flags["warnings"])) # make sure prototype_locks are set to defaults prototype_locks = [ @@ -752,18 +793,7 @@ prototype["prototype_locks"] = prototype_locks
    -# Protfunc parsing (in-prototype functions) - -for mod in settings.PROT_FUNC_MODULES: - try: - callables = callables_from_module(mod) - PROT_FUNCS.update(callables) - except ImportError: - logger.log_trace() - raise - - -
    [docs]def protfunc_parser(value, available_functions=None, testing=False, stacktrace=False, **kwargs): +
    [docs]def protfunc_parser(value, available_functions=None, testing=False, stacktrace=False, caller=None, **kwargs): """ Parse a prototype value string for a protfunc and process it. @@ -775,45 +805,27 @@ protfuncs, all other types are returned as-is. available_functions (dict, optional): Mapping of name:protfunction to use for this parsing. If not set, use default sources. - testing (bool, optional): Passed to protfunc. If in a testing mode, some protfuncs may - behave differently. stacktrace (bool, optional): If set, print the stack parsing process of the protfunc-parser. Keyword Args: session (Session): Passed to protfunc. Session of the entity spawning the prototype. protototype (dict): Passed to protfunc. The dict this protfunc is a part of. current_key(str): Passed to protfunc. The key in the prototype that will hold this value. + caller (Object or Account): This is necessary for certain protfuncs that perform object + searches and have to check permissions. any (any): Passed on to the protfunc. Returns: - testresult (tuple): If `testing` is set, returns a tuple (error, result) where error is - either None or a string detailing the error from protfunc_parser or seen when trying to - run `literal_eval` on the parsed string. - any (any): A structure to replace the string on the prototype level. If this is a - callable or a (callable, (args,)) structure, it will be executed as if one had supplied - it to the prototype directly. This structure is also passed through literal_eval so one - can get actual Python primitives out of it (not just strings). It will also identify - eventual object #dbrefs in the output from the protfunc. + any: A structure to replace the string on the prototype leve. Note + that FunctionParser functions $funcname(*args, **kwargs) can return any + data type to insert into the prototype. """ if not isinstance(value, str): return value - available_functions = PROT_FUNCS if available_functions is None else available_functions + result = FUNC_PARSER.parse(value, raise_errors=True, return_str=False, caller=caller, **kwargs) - result = inlinefuncs.parse_inlinefunc( - value, available_funcs=available_functions, stacktrace=stacktrace, testing=testing, **kwargs - ) - - err = None - try: - result = literal_eval(result) - except ValueError: - pass - except Exception as exc: - err = str(exc) - if testing: - return err, result return result
    @@ -828,7 +840,7 @@ clr (str, optional): What coloration tag to use. """ out = [] - for protfunc_name, protfunc in PROT_FUNCS.items(): + for protfunc_name, protfunc in FUNC_PARSER.callables.items(): out.append( "- |c${name}|n - |W{docs}".format( name=protfunc_name, docs=protfunc.__doc__.strip().replace("\n", "") @@ -877,10 +889,10 @@ category=category if category else "|wNone|n" ) out.append( - "{attrkey}{cat_locks} |c=|n {value}".format( + "{attrkey}{cat_locks}{locks} |c=|n {value}".format( attrkey=attrkey, cat_locks=cat_locks, - locks=locks if locks else "|wNone|n", + locks=" |w(locks:|n {locks})".format(locks=locks) if locks else "", value=value, ) ) @@ -953,7 +965,7 @@ return default
    -
    [docs]def init_spawn_value(value, validator=None): +
    [docs]def init_spawn_value(value, validator=None, caller=None): """ Analyze the prototype value and produce a value useful at the point of spawning. @@ -964,6 +976,8 @@ other - will be assigned depending on the variable type validator (callable, optional): If given, this will be called with the value to check and guarantee the outcome is of a given type. + caller (Object or Account): This is necessary for certain protfuncs that perform object + searches and have to check permissions. Returns: any (any): The (potentially pre-processed value to use for this prototype key) @@ -978,7 +992,7 @@ value = validator(value[0](*make_iter(args))) else: value = validator(value) - result = protfunc_parser(value) + result = protfunc_parser(value, caller=caller) if result != value: return validator(result) return result
    @@ -1044,7 +1058,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/prototypes/spawner.html b/docs/0.9.5/_modules/evennia/prototypes/spawner.html index 7a5cc8d0da..d1409cbac8 100644 --- a/docs/0.9.5/_modules/evennia/prototypes/spawner.html +++ b/docs/0.9.5/_modules/evennia/prototypes/spawner.html @@ -81,8 +81,8 @@ supported are 'edit' and 'use'. prototype_tags(list, optional): List of tags or tuples (tag, category) used to group prototype in listings - prototype_parent (str, tuple or callable, optional): name (prototype_key) of eventual parent prototype, or - a list of parents, for multiple left-to-right inheritance. + prototype_parent (str, tuple or callable, optional): name (prototype_key) of eventual parent + prototype, or a list of parents, for multiple left-to-right inheritance. prototype: Deprecated. Same meaning as 'parent'. typeclass (str or callable, optional): if not set, will use typeclass of parent prototype or use @@ -179,6 +179,7 @@ import time from django.conf import settings +from django.utils.translation import gettext as _ import evennia from evennia.objects.models import ObjectDB @@ -396,8 +397,8 @@ This is most useful for displaying. implicit_keep (bool, optional): If set, the resulting diff will assume KEEP unless the new prototype explicitly change them. That is, if a key exists in `prototype1` and - not in `prototype2`, it will not be REMOVEd but set to KEEP instead. This is particularly - useful for auto-generated prototypes when updating objects. + not in `prototype2`, it will not be REMOVEd but set to KEEP instead. This is + particularly useful for auto-generated prototypes when updating objects. Returns: diff (dict): A structure detailing how to convert prototype1 to prototype2. All @@ -510,8 +511,8 @@ out.extend(_get_all_nested_diff_instructions(val)) else: raise RuntimeError( - "Diff contains non-dicts that are not on the " - "form (old, new, inst): {}".format(diffpart) + _("Diff contains non-dicts that are not on the " + "form (old, new, action_to_take): {diffpart}").format(diffpart) ) return out @@ -648,7 +649,8 @@ return "\n ".join(line for line in texts if line) -
    [docs]def batch_update_objects_with_prototype(prototype, diff=None, objects=None, exact=False): +
    [docs]def batch_update_objects_with_prototype(prototype, diff=None, objects=None, + exact=False, caller=None): """ Update existing objects with the latest version of the prototype. @@ -665,6 +667,7 @@ if it's not set in the prototype. With `exact=True`, all un-specified properties of the objects will be removed if they exist. This will lead to a more accurate 1:1 correlation between the object and the prototype but is usually impractical. + caller (Object or Account, optional): This may be used by protfuncs to do permission checks. Returns: changed (int): The number of objects that had changes applied to them. @@ -716,33 +719,35 @@ do_save = True if key == "key": - obj.db_key = init_spawn_value(val, str) + obj.db_key = init_spawn_value(val, str, caller=caller) elif key == "typeclass": - obj.db_typeclass_path = init_spawn_value(val, str) + obj.db_typeclass_path = init_spawn_value(val, str, caller=caller) elif key == "location": - obj.db_location = init_spawn_value(val, value_to_obj) + obj.db_location = init_spawn_value(val, value_to_obj, caller=caller) elif key == "home": - obj.db_home = init_spawn_value(val, value_to_obj) + obj.db_home = init_spawn_value(val, value_to_obj, caller=caller) elif key == "destination": - obj.db_destination = init_spawn_value(val, value_to_obj) + obj.db_destination = init_spawn_value(val, value_to_obj, caller=caller) elif key == "locks": if directive == "REPLACE": obj.locks.clear() - obj.locks.add(init_spawn_value(val, str)) + obj.locks.add(init_spawn_value(val, str, caller=caller)) elif key == "permissions": if directive == "REPLACE": obj.permissions.clear() - obj.permissions.batch_add(*(init_spawn_value(perm, str) for perm in val)) + obj.permissions.batch_add(*(init_spawn_value(perm, str, caller=caller) + for perm in val)) elif key == "aliases": if directive == "REPLACE": obj.aliases.clear() - obj.aliases.batch_add(*(init_spawn_value(alias, str) for alias in val)) + obj.aliases.batch_add(*(init_spawn_value(alias, str, caller=caller) + for alias in val)) elif key == "tags": if directive == "REPLACE": obj.tags.clear() obj.tags.batch_add( *( - (init_spawn_value(ttag, str), tcategory, tdata) + (init_spawn_value(ttag, str, caller=caller), tcategory, tdata) for ttag, tcategory, tdata in val ) ) @@ -752,8 +757,8 @@ obj.attributes.batch_add( *( ( - init_spawn_value(akey, str), - init_spawn_value(aval, value_to_obj), + init_spawn_value(akey, str, caller=caller), + init_spawn_value(aval, value_to_obj, caller=caller), acategory, alocks, ) @@ -764,7 +769,7 @@ # we don't auto-rerun exec statements, it would be huge security risk! pass else: - obj.attributes.add(key, init_spawn_value(val, value_to_obj)) + obj.attributes.add(key, init_spawn_value(val, value_to_obj, caller=caller)) elif directive == "REMOVE": do_save = True if key == "key": @@ -877,7 +882,7 @@ # Spawner mechanism -
    [docs]def spawn(*prototypes, **kwargs): +
    [docs]def spawn(*prototypes, caller=None, **kwargs): """ Spawn a number of prototyped objects. @@ -886,6 +891,7 @@ prototype_key (will be used to find the prototype) or a full prototype dictionary. These will be batched-spawned as one object each. Keyword Args: + caller (Object or Account, optional): This may be used by protfuncs to do access checks. prototype_modules (str or list): A python-path to a prototype module, or a list of such paths. These will be used to build the global protparents dictionary accessible by the input @@ -951,32 +957,41 @@ "key", "Spawned-{}".format(hashlib.md5(bytes(str(time.time()), "utf-8")).hexdigest()[:6]), ) - create_kwargs["db_key"] = init_spawn_value(val, str) + create_kwargs["db_key"] = init_spawn_value(val, str, caller=caller) val = prot.pop("location", None) - create_kwargs["db_location"] = init_spawn_value(val, value_to_obj) + create_kwargs["db_location"] = init_spawn_value(val, value_to_obj, caller=caller) - val = prot.pop("home", settings.DEFAULT_HOME) - create_kwargs["db_home"] = init_spawn_value(val, value_to_obj) + val = prot.pop("home", None) + if val: + create_kwargs["db_home"] = init_spawn_value(val, value_to_obj, caller=caller) + else: + try: + create_kwargs["db_home"] = init_spawn_value( + settings.DEFAULT_HOME, value_to_obj, caller=caller) + except ObjectDB.DoesNotExist: + # settings.DEFAULT_HOME not existing is common for unittests + pass val = prot.pop("destination", None) - create_kwargs["db_destination"] = init_spawn_value(val, value_to_obj) + create_kwargs["db_destination"] = init_spawn_value(val, value_to_obj, caller=caller) val = prot.pop("typeclass", settings.BASE_OBJECT_TYPECLASS) - create_kwargs["db_typeclass_path"] = init_spawn_value(val, str) + create_kwargs["db_typeclass_path"] = init_spawn_value(val, str, caller=caller) # extract calls to handlers val = prot.pop("permissions", []) - permission_string = init_spawn_value(val, make_iter) + permission_string = init_spawn_value(val, make_iter, caller=caller) val = prot.pop("locks", "") - lock_string = init_spawn_value(val, str) + lock_string = init_spawn_value(val, str, caller=caller) val = prot.pop("aliases", []) - alias_string = init_spawn_value(val, make_iter) + alias_string = init_spawn_value(val, make_iter, caller=caller) val = prot.pop("tags", []) tags = [] - for (tag, category, data) in val: - tags.append((init_spawn_value(tag, str), category, data)) + for (tag, category, *data) in val: + tags.append((init_spawn_value(tag, str, caller=caller), category, data[0] + if data else None)) prototype_key = prototype.get("prototype_key", None) if prototype_key: @@ -984,11 +999,11 @@ tags.append((prototype_key, PROTOTYPE_TAG_CATEGORY)) val = prot.pop("exec", "") - execs = init_spawn_value(val, make_iter) + execs = init_spawn_value(val, make_iter, caller=caller) # extract ndb assignments nattributes = dict( - (key.split("_", 1)[1], init_spawn_value(val, value_to_obj)) + (key.split("_", 1)[1], init_spawn_value(val, value_to_obj, caller=caller)) for key, val in prot.items() if key.startswith("ndb_") ) @@ -996,8 +1011,9 @@ # the rest are attribute tuples (attrname, value, category, locks) val = make_iter(prot.pop("attrs", [])) attributes = [] - for (attrname, value, category, locks) in val: - attributes.append((attrname, init_spawn_value(value), category, locks)) + for (attrname, value, *rest) in val: + attributes.append((attrname, init_spawn_value(value, caller=caller), + rest[0] if rest else None, rest[1] if len(rest) > 1 else None)) simple_attributes = [] for key, value in ( @@ -1008,7 +1024,7 @@ continue else: simple_attributes.append( - (key, init_spawn_value(value, value_to_obj_or_any), None, None) + (key, init_spawn_value(value, value_to_obj_or_any, caller=caller), None, None) ) attributes = attributes + simple_attributes @@ -1068,7 +1084,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/scripts/admin.html b/docs/0.9.5/_modules/evennia/scripts/admin.html deleted file mode 100644 index 25b11af691..0000000000 --- a/docs/0.9.5/_modules/evennia/scripts/admin.html +++ /dev/null @@ -1,195 +0,0 @@ - - - - - - - - evennia.scripts.admin — Evennia 0.9.5 documentation - - - - - - - - - - - - - -
    -
    -
    -
    - -

    Source code for evennia.scripts.admin

    -#
    -# This sets up how models are displayed
    -# in the web admin interface.
    -#
    -from django.conf import settings
    -
    -from evennia.typeclasses.admin import AttributeInline, TagInline
    -
    -from evennia.scripts.models import ScriptDB
    -from django.contrib import admin
    -
    -
    -
    [docs]class ScriptTagInline(TagInline): - """ - Inline script tags. - - """ - - model = ScriptDB.db_tags.through - related_field = "scriptdb"
    - - -
    [docs]class ScriptAttributeInline(AttributeInline): - """ - Inline attribute tags. - - """ - - model = ScriptDB.db_attributes.through - related_field = "scriptdb"
    - - -
    [docs]class ScriptDBAdmin(admin.ModelAdmin): - """ - Displaying the main Script page. - - """ - - list_display = ( - "id", - "db_key", - "db_typeclass_path", - "db_obj", - "db_interval", - "db_repeats", - "db_persistent", - ) - list_display_links = ("id", "db_key") - ordering = ["db_obj", "db_typeclass_path"] - search_fields = ["^db_key", "db_typeclass_path"] - save_as = True - save_on_top = True - list_select_related = True - raw_id_fields = ("db_obj",) - - fieldsets = ( - ( - None, - { - "fields": ( - ("db_key", "db_typeclass_path"), - "db_interval", - "db_repeats", - "db_start_delay", - "db_persistent", - "db_obj", - ) - }, - ), - ) - inlines = [ScriptTagInline, ScriptAttributeInline] - -
    [docs] def save_model(self, request, obj, form, change): - """ - Model-save hook. - - Args: - request (Request): Incoming request. - obj (Object): Database object. - form (Form): Form instance. - change (bool): If this is a change or a new object. - - """ - obj.save() - if not change: - # adding a new object - # have to call init with typeclass passed to it - obj.set_class_from_typeclass(typeclass_path=obj.db_typeclass_path)
    - - -admin.site.register(ScriptDB, ScriptDBAdmin) -
    - -
    -
    -
    -
    - -
    -
    - - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/scripts/manager.html b/docs/0.9.5/_modules/evennia/scripts/manager.html index ee6fe1d221..a525c6a5bf 100644 --- a/docs/0.9.5/_modules/evennia/scripts/manager.html +++ b/docs/0.9.5/_modules/evennia/scripts/manager.html @@ -145,112 +145,22 @@ scripts = self.get_id(dbref) for script in make_iter(scripts): script.stop() - - def remove_non_persistent(self, obj=None): - """ - This cleans up the script database of all non-persistent - scripts. It is called every time the server restarts. - - Args: - obj (Object, optional): Only remove non-persistent scripts - assigned to this object. - - """ - if obj: - to_stop = self.filter(db_obj=obj, db_persistent=False, db_is_active=True) - to_delete = self.filter(db_obj=obj, db_persistent=False, db_is_active=False) - else: - to_stop = self.filter(db_persistent=False, db_is_active=True) - to_delete = self.filter(db_persistent=False, db_is_active=False) - nr_deleted = to_stop.count() + to_delete.count() - for script in to_stop: - script.stop() - for script in to_delete: script.delete() - return nr_deleted - def validate(self, scripts=None, obj=None, key=None, dbref=None, init_mode=None): + def update_scripts_after_server_start(self): """ - This will step through the script database and make sure - all objects run scripts that are still valid in the context - they are in. This is called by the game engine at regular - intervals but can also be initiated by player scripts. - - Only one of the arguments are supposed to be supplied - at a time, since they are exclusive to each other. - - Args: - scripts (list, optional): A list of script objects to - validate. - obj (Object, optional): Validate only scripts defined on - this object. - key (str): Validate only scripts with this key. - dbref (int): Validate only the single script with this - particular id. - init_mode (str, optional): This is used during server - upstart and can have three values: - - `None` (no init mode). Called during run. - - `"reset"` - server reboot. Kill non-persistent scripts - - `"reload"` - server reload. Keep non-persistent scripts. - Returns: - nr_started, nr_stopped (tuple): Statistics on how many objects - where started and stopped. - - Notes: - This method also makes sure start any scripts it validates - which should be harmless, since already-active scripts have - the property 'is_running' set and will be skipped. + Update/sync/restart/delete scripts after server shutdown/restart. """ + for script in self.filter(db_is_active=True, db_persistent=False): + script._stop_task() - # we store a variable that tracks if we are calling a - # validation from within another validation (avoids - # loops). + for script in self.filter(db_is_active=True): + script._unpause_task(auto_unpause=True) + script.at_server_start() - global VALIDATE_ITERATION - if VALIDATE_ITERATION > 0: - # we are in a nested validation. Exit. - VALIDATE_ITERATION -= 1 - return None, None - VALIDATE_ITERATION += 1 - - # not in a validation - loop. Validate as normal. - - nr_started = 0 - nr_stopped = 0 - - if init_mode: - if init_mode == "reset": - # special mode when server starts or object logs in. - # This deletes all non-persistent scripts from database - nr_stopped += self.remove_non_persistent(obj=obj) - # turn off the activity flag for all remaining scripts - scripts = self.get_all_scripts() - for script in scripts: - script.is_active = False - - elif not scripts: - # normal operation - if dbref and self.dbref(dbref, reqhash=False): - scripts = self.get_id(dbref) - elif obj: - scripts = self.get_all_scripts_on_obj(obj, key=key) - else: - scripts = self.get_all_scripts(key=key) - - if not scripts: - # no scripts available to validate - VALIDATE_ITERATION -= 1 - return None, None - - for script in scripts: - if script.is_valid(): - nr_started += script.start(force_restart=init_mode) - else: - script.stop() - nr_stopped += 1 - VALIDATE_ITERATION -= 1 - return nr_started, nr_stopped + for script in self.filter(db_is_active=False): + script.at_server_start() def search_script(self, ostring, obj=None, only_timed=False, typeclass=None): """ @@ -362,7 +272,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/scripts/models.html b/docs/0.9.5/_modules/evennia/scripts/models.html index dbc998cf2d..edaebb492c 100644 --- a/docs/0.9.5/_modules/evennia/scripts/models.html +++ b/docs/0.9.5/_modules/evennia/scripts/models.html @@ -84,7 +84,7 @@ # ------------------------------------------------------------ -
    [docs]class ScriptDB(TypedObject): +
    [docs]class ScriptDB(TypedObject): """ The Script database representation. @@ -142,7 +142,7 @@ # how often to run Script (secs). -1 means there is no timer db_interval = models.IntegerField( - "interval", default=-1, help_text="how often to repeat script, in seconds. -1 means off." + "interval", default=-1, help_text="how often to repeat script, in seconds. <= 0 means off." ) # start script right away or wait interval seconds first db_start_delay = models.BooleanField( @@ -151,7 +151,7 @@ # how many times this script is to be repeated, if interval!=0. db_repeats = models.IntegerField("number of repeats", default=0, help_text="0 means off.") # defines if this script should survive a reboot or not - db_persistent = models.BooleanField("survive server reboot", default=False) + db_persistent = models.BooleanField("survive server reboot", default=True) # defines if this script has already been started in this session db_is_active = models.BooleanField("script active", default=False) @@ -257,7 +257,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/scripts/monitorhandler.html b/docs/0.9.5/_modules/evennia/scripts/monitorhandler.html index d6534ca340..4400da98c8 100644 --- a/docs/0.9.5/_modules/evennia/scripts/monitorhandler.html +++ b/docs/0.9.5/_modules/evennia/scripts/monitorhandler.html @@ -68,11 +68,13 @@ """ This is a resource singleton that allows for registering callbacks for when a field or Attribute is updated (saved). + """
    [docs] def __init__(self): """ Initialize the handler. + """ self.savekey = "_monitorhandler_save" self.monitors = defaultdict(lambda: defaultdict(dict))
    @@ -281,7 +283,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/scripts/scripthandler.html b/docs/0.9.5/_modules/evennia/scripts/scripthandler.html index 29c537610e..2cde5eba8a 100644 --- a/docs/0.9.5/_modules/evennia/scripts/scripthandler.html +++ b/docs/0.9.5/_modules/evennia/scripts/scripthandler.html @@ -89,15 +89,11 @@ next_repeat = script.time_until_next_repeat() except Exception: next_repeat = "?" - string += _( - "\n '%(key)s' (%(next_repeat)s/%(interval)s, %(repeats)s repeats): %(desc)s" - ) % { - "key": script.key, - "next_repeat": next_repeat, - "interval": interval, - "repeats": repeats, - "desc": script.desc, - } + string += _("\n '{key}' ({next_repeat}/{interval}, {repeats} repeats): {desc}").format( + key=script.key, next_repeat=next_repeat, + interval=interval, + repeats=repeats, + desc=script.desc) return string.strip()
    [docs] def add(self, scriptclass, key=None, autostart=True): @@ -149,7 +145,8 @@ scripts = ScriptDB.objects.get_all_scripts_on_obj(self.obj, key=key) num = 0 for script in scripts: - num += script.start() + script.start() + num += 1 return num
    [docs] def get(self, key): @@ -184,7 +181,8 @@ ] num = 0 for script in delscripts: - num += script.stop() + script.delete() + num += 1 return num
    # alias to delete @@ -195,22 +193,7 @@ Get all scripts stored in this handler. """ - return ScriptDB.objects.get_all_scripts_on_obj(self.obj) - -
    [docs] def validate(self, init_mode=False): - """ - Runs a validation on this object's scripts only. This should - be called regularly to crank the wheels. - - Args: - init_mode (str, optional): - This is used during server - upstart and can have three values: - - `False` (no init mode). Called during run. - - `"reset"` - server reboot. Kill non-persistent scripts - - `"reload"` - server reload. Keep non-persistent scripts. - - """ - ScriptDB.objects.validate(obj=self.obj, init_mode=init_mode)
    + return ScriptDB.objects.get_all_scripts_on_obj(self.obj)
    @@ -248,7 +231,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/scripts/scripts.html b/docs/0.9.5/_modules/evennia/scripts/scripts.html index 9dfd4ad981..4b4a11ac23 100644 --- a/docs/0.9.5/_modules/evennia/scripts/scripts.html +++ b/docs/0.9.5/_modules/evennia/scripts/scripts.html @@ -48,7 +48,6 @@ from twisted.internet.defer import Deferred, maybeDeferred from twisted.internet.task import LoopingCall -from django.core.exceptions import ObjectDoesNotExist from django.utils.translation import gettext as _ from evennia.typeclasses.models import TypeclassBase from evennia.scripts.models import ScriptDB @@ -58,21 +57,11 @@ __all__ = ["DefaultScript", "DoNothing", "Store"] -FLUSHING_INSTANCES = False # whether we're in the process of flushing scripts from the cache -SCRIPT_FLUSH_TIMERS = {} # stores timers for scripts that are currently being flushed - - -def restart_scripts_after_flush(): - """After instances are flushed, validate scripts so they're not dead for a long period of time""" - global FLUSHING_INSTANCES - ScriptDB.objects.validate() - FLUSHING_INSTANCES = False - - class ExtendedLoopingCall(LoopingCall): """ - LoopingCall that can start at a delay different - than `self.interval`. + Custom child of LoopingCall that can start at a delay different than + `self.interval` and self.count=0. This allows it to support pausing + by resuming at a later period. """ @@ -90,10 +79,10 @@ interval (int): Repeat interval in seconds. now (bool, optional): Whether to start immediately or after `start_delay` seconds. - start_delay (int): The number of seconds before starting. - If None, wait interval seconds. Only valid if `now` is `False`. - It is used as a way to start with a variable start time - after a pause. + start_delay (int, optional): This only applies is `now=False`. It gives + number of seconds to wait before starting. If `None`, use + `interval` as this value instead. Internally, this is used as a + way to start with a variable start time after a pause. count_start (int): Number of repeats to start at. The count goes up every time the system repeats. This is used to implement something repeating `N` number of times etc. @@ -172,7 +161,7 @@ of start_delay into account. Returns: - next (int or None): The time in seconds until the next call. This + int or None: The time in seconds until the next call. This takes `start_delay` into account. Returns `None` if the task is not running. @@ -180,7 +169,7 @@ if self.running and self.interval > 0: total_runtime = self.clock.seconds() - self.starttime interval = self.start_delay or self.interval - return interval - (total_runtime % self.interval) + return max(0, interval - (total_runtime % self.interval)) class ScriptBase(ScriptDB, metaclass=TypeclassBase): @@ -188,6 +177,8 @@ Base class for scripts. Don't inherit from this, inherit from the class `DefaultScript` below instead. + This handles the timer-component of the Script. + """ objects = ScriptManager() @@ -198,36 +189,176 @@ def __repr__(self): return str(self) - def _start_task(self): + def at_idmapper_flush(self): """ - Start task runner. + If we're flushing this object, make sure the LoopingCall is gone too. + """ + ret = super().at_idmapper_flush() + if ret and self.ndb._task: + self.ndb._pause_task(auto_pause=True) + # TODO - restart anew ? + return ret + + def _start_task(self, interval=None, start_delay=None, repeats=None, force_restart=False, + auto_unpause=False, **kwargs): + """ + Start/Unpause task runner, optionally with new values. If given, this will + update the Script's fields. + + Keyword Args: + interval (int): How often to tick the task, in seconds. If this is <= 0, + no task will start and properties will not be updated on the Script. + start_delay (int): If the start should be delayed. + repeats (int): How many repeats. 0 for infinite repeats. + force_restart (bool): If set, always create a new task running even if an + old one already was running. Otherwise this will only happen if + new script properties were passed. + auto_unpause (bool): This is an automatic unpaused (used e.g by Evennia after + a reload) and should not un-pause manually paused Script timers. + Note: + If setting the `start-delay` of a *paused* Script, the Script will + restart exactly after that new start-delay, ignoring the time it + was paused at. If only changing the `interval`, the Script will + come out of pause comparing the time it spent in the *old* interval + with the *new* interval in order to determine when next to fire. + + Examples: + - Script previously had an interval of 10s and was paused 5s into that interval. + Script is now restarted with a 20s interval. It will next fire after 15s. + - Same Script is restarted with a 3s interval. It will fire immediately. """ + if self.pk is None: + # script object already deleted from db - don't start a new timer + raise ScriptDB.DoesNotExist + + # handle setting/updating fields + update_fields = [] + old_interval = self.db_interval + if interval is not None: + self.db_interval = interval + update_fields.append("db_interval") + if start_delay is not None: + self.db_start_delay = start_delay + update_fields.append("db_start_delay") + if repeats is not None: + self.db_repeats = repeats + update_fields.append("db_repeats") + + # validate interval + if self.db_interval and self.db_interval > 0: + if not self.is_active: + self.db_is_active = True + update_fields.append("db_is_active") + else: + # no point in starting a task with no interval. + return + + restart = bool(update_fields) or force_restart + self.save(update_fields=update_fields) + + if self.ndb._task and self.ndb._task.running: + if restart: + # a change needed/forced; stop/remove old task + self._stop_task() + else: + # task alreaady running and no changes needed + return + if not self.ndb._task: + # we should have a fresh task after this point self.ndb._task = ExtendedLoopingCall(self._step_task) - if self.db._paused_time: - # the script was paused; restarting - callcount = self.db._paused_callcount or 0 - self.ndb._task.start( - self.db_interval, now=False, start_delay=self.db._paused_time, count_start=callcount - ) - del self.db._paused_time - del self.db._paused_repeats + self._unpause_task(interval=interval, start_delay=start_delay, + auto_unpause=auto_unpause, + old_interval=old_interval) - elif not self.ndb._task.running: - # starting script anew + if not self.ndb._task.running: + # if not unpausing started it, start script anew with the new values self.ndb._task.start(self.db_interval, now=not self.db_start_delay) - def _stop_task(self): + self.at_start(**kwargs) + + def _pause_task(self, auto_pause=False, **kwargs): """ - Stop task runner + Pause task where it is, saving the current status. + + Args: + auto_pause (str): + + """ + if not self.db._paused_time: + # only allow pause if not already paused + task = self.ndb._task + if task: + self.db._paused_time = task.next_call_time() + self.db._paused_callcount = task.callcount + self.db._manually_paused = not auto_pause + if task.running: + task.stop() + self.ndb._task = None + + self.at_pause(auto_pause=auto_pause, **kwargs) + + def _unpause_task(self, interval=None, start_delay=None, auto_unpause=False, + old_interval=0, **kwargs): + """ + Unpause task from paused status. This is used for auto-paused tasks, such + as tasks paused on a server reload. + + Args: + interval (int): How often to tick the task, in seconds. + start_delay (int): If the start should be delayed. + auto_unpause (bool): If set, this will only unpause scripts that were unpaused + automatically (useful during a system reload/shutdown). + old_interval (int): The old Script interval (or current one if nothing changed). Used + to recalculate the unpause startup interval. + + """ + paused_time = self.db._paused_time + if paused_time: + if auto_unpause and self.db._manually_paused: + # this was manually paused. + return + + # task was paused. This will use the new values as needed. + callcount = self.db._paused_callcount or 0 + if start_delay is None and interval is not None: + # adjust start-delay based on how far we were into previous interval + start_delay = max(0, interval - (old_interval - paused_time)) + else: + start_delay = paused_time + + if not self.ndb._task: + self.ndb._task = ExtendedLoopingCall(self._step_task) + + self.ndb._task.start( + self.db_interval, now=False, start_delay=start_delay, count_start=callcount + ) + del self.db._paused_time + del self.db._paused_callcount + del self.db._manually_paused + + self.at_start(**kwargs) + + def _stop_task(self, **kwargs): + """ + Stop task runner and delete the task. """ task = self.ndb._task if task and task.running: task.stop() self.ndb._task = None + self.db_is_active = False + + # make sure this is not confused as a paused script + del self.db._paused_time + del self.db._paused_callcount + del self.db._manually_paused + + self.save(update_fields=["db_is_active"]) + self.at_stop(**kwargs) def _step_errback(self, e): """ @@ -236,8 +367,8 @@ """ cname = self.__class__.__name__ estring = _( - "Script %(key)s(#%(dbid)s) of type '%(cname)s': at_repeat() error '%(err)s'." - ) % {"key": self.key, "dbid": self.dbid, "cname": cname, "err": e.getErrorMessage()} + "Script {key}(#{dbid}) of type '{name}': at_repeat() error '{err}'.".format( + key=self.key, dbid=self.dbid, name=cname, err=e.getErrorMessage())) try: self.db_obj.msg(estring) except Exception: @@ -280,12 +411,7 @@ logger.log_trace() return None - def at_script_creation(self): - """ - Should be overridden in child. - - """ - pass + # Access methods / hooks def at_first_save(self, **kwargs): """ @@ -347,12 +473,185 @@ for key, value in cdict["nattributes"]: self.nattributes.add(key, value) - if not cdict.get("autostart"): - # don't auto-start the script - return + if cdict.get("autostart"): + # autostart the script + self._start_task(force_restart=True) - # auto-start script (default) - self.start() + def delete(self): + """ + Delete the Script. Makes sure to stop any timer tasks first. + + """ + self._stop_task() + self.at_script_delete() + super().delete() + + def at_script_creation(self): + """ + Should be overridden in child. + + """ + pass + + def at_script_delete(self): + """ + Called when script is deleted, after at_stop. + + """ + pass + + def is_valid(self): + """ + If returning False, `at_repeat` will not be called and timer will stop + updating. + """ + return True + + def at_repeat(self, **kwargs): + """ + Called repeatedly every `interval` seconds, once `.start()` has + been called on the Script at least once. + + Args: + **kwargs (dict): Arbitrary, optional arguments for users + overriding the call (unused by default). + + """ + pass + + def at_start(self, **kwargs): + pass + + def at_pause(self, **kwargs): + pass + + def at_stop(self, **kwargs): + pass + + + def start(self, interval=None, start_delay=None, repeats=None, **kwargs): + """ + Start/Unpause timer component, optionally with new values. If given, + this will update the Script's fields. This will start `at_repeat` being + called every `interval` seconds. + + Keyword Args: + interval (int): How often to fire `at_repeat` in seconds. + start_delay (int): If the start of ticking should be delayed. + repeats (int): How many repeats. 0 for infinite repeats. + **kwargs: Optional (default unused) kwargs passed on into the `at_start` hook. + + Notes: + If setting the `start-delay` of a *paused* Script, the Script will + restart exactly after that new start-delay, ignoring the time it + was paused at. If only changing the `interval`, the Script will + come out of pause comparing the time it spent in the *old* interval + with the *new* interval in order to determine when next to fire. + + Examples: + - Script previously had an interval of 10s and was paused 5s into that interval. + Script is now restarted with a 20s interval. It will next fire after 15s. + - Same Script is restarted with a 3s interval. It will fire immediately. + + """ + self._start_task(interval=interval, start_delay=start_delay, repeats=repeats, **kwargs) + + # legacy alias + update = start + + def stop(self, **kwargs): + """ + Stop the Script's timer component. This will not delete the Sctipt, + just stop the regular firing of `at_repeat`. Running `.start()` will + start the timer anew, optionally with new settings.. + + Args: + **kwargs: Optional (default unused) kwargs passed on into the `at_stop` hook. + + """ + self._stop_task(**kwargs) + + def pause(self, **kwargs): + """ + Manually the Script's timer component manually. + + Args: + **kwargs: Optional (default unused) kwargs passed on into the `at_pause` hook. + + """ + self._pause_task(manual_pause=True, **kwargs) + + def unpause(self, **kwargs): + """ + Manually unpause a Paused Script. + + Args: + **kwargs: Optional (default unused) kwargs passed on into the `at_start` hook. + + """ + self._unpause_task(**kwargs) + + def time_until_next_repeat(self): + """ + Get time until the script fires it `at_repeat` hook again. + + Returns: + int or None: Time in seconds until the script runs again. + If not a timed script, return `None`. + + Notes: + This hook is not used in any way by the script's stepping + system; it's only here for the user to be able to check in + on their scripts and when they will next be run. + + """ + task = self.ndb._task + if task: + try: + return int(round(task.next_call_time())) + except TypeError: + pass + return None + + def remaining_repeats(self): + """ + Get the number of returning repeats for limited Scripts. + + Returns: + int or None: The number of repeats remaining until the Script + stops. Returns `None` if it has unlimited repeats. + + """ + task = self.ndb._task + if task: + return max(0, self.db_repeats - task.callcount) + return None + + def reset_callcount(self, value=0): + """ + Reset the count of the number of calls done. + + Args: + value (int, optional): The repeat value to reset to. Default + is to set it all the way back to 0. + + Notes: + This is only useful if repeats != 0. + + """ + task = self.ndb._task + if task: + task.callcount = max(0, int(value)) + + def force_repeat(self): + """ + Fire a premature triggering of the script callback. This + will reset the timer and count down repeats as if the script + had fired normally. + """ + task = self.ndb._task + if task: + task.force_repeat()
    [docs]class DefaultScript(ScriptBase): @@ -399,287 +698,20 @@ """ pass
    -
    [docs] def time_until_next_repeat(self): - """ - Get time until the script fires it `at_repeat` hook again. - - Returns: - next (int): Time in seconds until the script runs again. - If not a timed script, return `None`. - - Notes: - This hook is not used in any way by the script's stepping - system; it's only here for the user to be able to check in - on their scripts and when they will next be run. - - """ - task = self.ndb._task - if task: - try: - return int(round(task.next_call_time())) - except TypeError: - pass - return None
    - -
    [docs] def remaining_repeats(self): - """ - Get the number of returning repeats for limited Scripts. - - Returns: - remaining (int or `None`): The number of repeats - remaining until the Script stops. Returns `None` - if it has unlimited repeats. - - """ - task = self.ndb._task - if task: - return max(0, self.db_repeats - task.callcount) - return None
    - -
    [docs] def at_idmapper_flush(self): - """If we're flushing this object, make sure the LoopingCall is gone too""" - ret = super(DefaultScript, self).at_idmapper_flush() - if ret and self.ndb._task: - try: - from twisted.internet import reactor - - global FLUSHING_INSTANCES - # store the current timers for the _task and stop it to avoid duplicates after cache flush - paused_time = self.ndb._task.next_call_time() - callcount = self.ndb._task.callcount - self._stop_task() - SCRIPT_FLUSH_TIMERS[self.id] = (paused_time, callcount) - # here we ensure that the restart call only happens once, not once per script - if not FLUSHING_INSTANCES: - FLUSHING_INSTANCES = True - reactor.callLater(2, restart_scripts_after_flush) - except Exception: - import traceback - - traceback.print_exc() - return ret
    - -
    [docs] def start(self, force_restart=False): - """ - Called every time the script is started (for persistent - scripts, this is usually once every server start) - - Args: - force_restart (bool, optional): Normally an already - started script will not be started again. if - `force_restart=True`, the script will always restart - the script, regardless of if it has started before. - - Returns: - result (int): 0 or 1 depending on if the script successfully - started or not. Used in counting. - - """ - if self.is_active and not force_restart: - # The script is already running, but make sure we have a _task if - # this is after a cache flush - if not self.ndb._task and self.db_interval > 0: - self.ndb._task = ExtendedLoopingCall(self._step_task) - try: - start_delay, callcount = SCRIPT_FLUSH_TIMERS[self.id] - del SCRIPT_FLUSH_TIMERS[self.id] - now = False - except (KeyError, ValueError, TypeError): - now = not self.db_start_delay - start_delay = None - callcount = 0 - self.ndb._task.start( - self.db_interval, now=now, start_delay=start_delay, count_start=callcount - ) - return 0 - - obj = self.obj - if obj: - # check so the scripted object is valid and initalized - try: - obj.cmdset - except AttributeError: - # this means the object is not initialized. - logger.log_trace() - self.is_active = False - return 0 - - # try to restart a paused script - try: - if self.unpause(manual_unpause=False): - return 1 - except RuntimeError: - # manually paused. - return 0 - - # start the script from scratch - self.is_active = True - try: - self.at_start() - except Exception: - logger.log_trace() - - if self.db_interval > 0: - self._start_task() - return 1
    - -
    [docs] def stop(self, kill=False): - """ - Called to stop the script from running. This also deletes the - script. - - Args: - kill (bool, optional): - Stop the script without - calling any relevant script hooks. - - Returns: - result (int): 0 if the script failed to stop, 1 otherwise. - Used in counting. - - """ - if not kill: - try: - self.at_stop() - except Exception: - logger.log_trace() - self._stop_task() - try: - self.delete() - except AssertionError: - logger.log_trace() - return 0 - except ObjectDoesNotExist: - return 0 - return 1
    - -
    [docs] def pause(self, manual_pause=True): - """ - This stops a running script and stores its active state. - It WILL NOT call the `at_stop()` hook. - - """ - self.db._manual_pause = manual_pause - if not self.db._paused_time: - # only allow pause if not already paused - task = self.ndb._task - if task: - self.db._paused_time = task.next_call_time() - self.db._paused_callcount = task.callcount - self._stop_task() - self.is_active = False
    - -
    [docs] def unpause(self, manual_unpause=True): - """ - Restart a paused script. This WILL call the `at_start()` hook. - - Args: - manual_unpause (bool, optional): This is False if unpause is - called by the server reload/reset mechanism. - Returns: - result (bool): True if unpause was triggered, False otherwise. - - Raises: - RuntimeError: If trying to automatically resart this script - (usually after a reset/reload), but it was manually paused, - and so should not the auto-unpaused. - - """ - if not manual_unpause and self.db._manual_pause: - # if this script was paused manually (by a direct call of pause), - # it cannot be automatically unpaused (e.g. by a @reload) - raise RuntimeError - - # Ensure that the script is fully unpaused, so that future calls - # to unpause do not raise a RuntimeError - self.db._manual_pause = False - - if self.db._paused_time: - # only unpause if previously paused - self.is_active = True - - try: - self.at_start() - except Exception: - logger.log_trace() - - self._start_task() - return True
    - -
    [docs] def restart(self, interval=None, repeats=None, start_delay=None): - """ - Restarts an already existing/running Script from the - beginning, optionally using different settings. This will - first call the stop hooks, and then the start hooks again. - Args: - interval (int, optional): Allows for changing the interval - of the Script. Given in seconds. if `None`, will use the already stored interval. - repeats (int, optional): The number of repeats. If unset, will - use the previous setting. - start_delay (bool, optional): If we should wait `interval` seconds - before starting or not. If `None`, re-use the previous setting. - - """ - try: - self.at_stop() - except Exception: - logger.log_trace() - self._stop_task() - self.is_active = False - # remove all pause flags - del self.db._paused_time - del self.db._manual_pause - del self.db._paused_callcount - # set new flags and start over - if interval is not None: - interval = max(0, interval) - self.interval = interval - if repeats is not None: - self.repeats = repeats - if start_delay is not None: - self.start_delay = start_delay - self.start()
    - -
    [docs] def reset_callcount(self, value=0): - """ - Reset the count of the number of calls done. - - Args: - value (int, optional): The repeat value to reset to. Default - is to set it all the way back to 0. - - Notes: - This is only useful if repeats != 0. - - """ - task = self.ndb._task - if task: - task.callcount = max(0, int(value))
    - -
    [docs] def force_repeat(self): - """ - Fire a premature triggering of the script callback. This - will reset the timer and count down repeats as if the script - had fired normally. - """ - task = self.ndb._task - if task: - task.force_repeat()
    -
    [docs] def is_valid(self): """ - Is called to check if the script is valid to run at this time. - Should return a boolean. The method is assumed to collect all - needed information from its related self.obj. + Is called to check if the script's timer is valid to run at this time. + Should return a boolean. If False, the timer will be stopped. """ - return not self._is_deleted
    + return True
    [docs] def at_start(self, **kwargs): """ - Called whenever the script is started, which for persistent - scripts is at least once every server start. It will also be - called when starting again after a pause (such as after a - server reload) + Called whenever the script timer is started, which for persistent + timed scripts is at least once every server start. It will also be + called when starting again after a pause (including after a + server reload). Args: **kwargs (dict): Arbitrary, optional arguments for users @@ -696,18 +728,38 @@ **kwargs (dict): Arbitrary, optional arguments for users overriding the call (unused by default). + """ + pass
    + +
    [docs] def at_pause(self, manual_pause=True, **kwargs): + """ + Called when this script's timer pauses. + + Args: + manual_pause (bool): If set, pausing was done by a direct call. The + non-manual pause indicates the script was paused as part of + the server reload. + """ pass
    [docs] def at_stop(self, **kwargs): """ - Called whenever when it's time for this script to stop (either - because is_valid returned False or it runs out of iterations) + Called whenever when it's time for this script's timer to stop (either + because is_valid returned False, it ran out of iterations or it was manuallys + stopped. - Args + Args: **kwargs (dict): Arbitrary, optional arguments for users overriding the call (unused by default). + """ + pass
    + +
    [docs] def at_script_delete(self): + """ + Called when the Script is deleted, after at_stop(). + """ pass
    @@ -724,6 +776,15 @@ """ This hook is called whenever the server is shutting down fully (i.e. not for a restart). + """ + pass + +
    [docs] def at_server_start(self): + """ + This hook is called after the server has started. It can be used to add + post-startup setup for Scripts without a timer component (for which at_start + could be used). + """ pass
    @@ -792,7 +853,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/scripts/taskhandler.html b/docs/0.9.5/_modules/evennia/scripts/taskhandler.html index 52b4c0d5a3..f499b5cdf6 100644 --- a/docs/0.9.5/_modules/evennia/scripts/taskhandler.html +++ b/docs/0.9.5/_modules/evennia/scripts/taskhandler.html @@ -103,22 +103,28 @@ return TASK_HANDLER.get_deferred(self.task_id)
    [docs] def pause(self): - """Pause the callback of a task. - To resume use TaskHandlerTask.unpause + """ + Pause the callback of a task. + To resume use `TaskHandlerTask.unpause`. + """ d = self.deferred if d: d.pause()
    [docs] def unpause(self): - """Unpause a task, run the task if it has passed delay time.""" + """ + Unpause a task, run the task if it has passed delay time. + + """ d = self.deferred if d: d.unpause()
    @property def paused(self): - """A task attribute to check if the deferred instance of a task has been paused. + """ + A task attribute to check if the deferred instance of a task has been paused. This exists to mock usage of a twisted deferred object. @@ -134,7 +140,8 @@ return None
    [docs] def do_task(self): - """Execute the task (call its callback). + """ + Execute the task (call its callback). If calling before timedelay, cancel the deferred instance affliated to this task. Remove the task from the dictionary of current tasks on a successful callback. @@ -147,7 +154,8 @@ return TASK_HANDLER.do_task(self.task_id)
    [docs] def call(self): - """Call the callback of a task. + """ + Call the callback of a task. Leave the task unaffected otherwise. This does not use the task's deferred instance. The only requirement is that the task exist in task handler. @@ -214,7 +222,8 @@ return None
    [docs] def exists(self): - """Check if a task exists. + """ + Check if a task exists. Most task handler methods check for existence for you. Returns: @@ -224,7 +233,8 @@ return TASK_HANDLER.exists(self.task_id)
    [docs] def get_id(self): - """ Returns the global id for this task. For use with + """ + Returns the global id for this task. For use with `evennia.scripts.taskhandler.TASK_HANDLER`. Returns: @@ -256,7 +266,7 @@ self.clock = reactor # number of seconds before an uncalled canceled task is removed from TaskHandler self.stale_timeout = 60 - self._now = False # used in unit testing to manually set now time
    + self._now = False # used in unit testing to manually set now time
    [docs] def load(self): """Load from the ServerConfig. @@ -312,7 +322,10 @@ return True
    [docs] def save(self): - """Save the tasks in ServerConfig.""" + """ + Save the tasks in ServerConfig. + + """ for task_id, (date, callback, args, kwargs, persistent, _) in self.tasks.items(): if task_id in self.to_save: @@ -320,21 +333,30 @@ if not persistent: continue + safe_callback = callback if getattr(callback, "__self__", None): # `callback` is an instance method obj = callback.__self__ name = callback.__name__ - callback = (obj, name) + safe_callback = (obj, name) # Check if callback can be pickled. args and kwargs have been checked - safe_callback = None + try: + dbserialize(safe_callback) + except (TypeError, AttributeError, PickleError) as err: + raise ValueError( + "the specified callback {callback} cannot be pickled. " + "It must be a top-level function in a module or an " + "instance method ({err}).".format(callback=callback, err=err) + ) + self.to_save[task_id] = dbserialize((date, safe_callback, args, kwargs)) - self.to_save[task_id] = dbserialize((date, callback, args, kwargs)) ServerConfig.objects.conf("delayed_tasks", self.to_save)
    [docs] def add(self, timedelay, callback, *args, **kwargs): - """Add a new task. + """ + Add a new task. If the persistent kwarg is truthy: The callback, args and values for kwarg will be serialized. Type @@ -378,17 +400,6 @@ safe_args = [] safe_kwargs = {} - # an unsaveable callback should immediately abort - try: - dbserialize(callback) - except (TypeError, AttributeError, PickleError): - raise ValueError( - "the specified callback {} cannot be pickled. " - "It must be a top-level function in a module or an " - "instance method.".format(callback) - ) - return - # Check that args and kwargs contain picklable information for arg in args: try: @@ -440,7 +451,8 @@ return TaskHandlerTask(task_id)
    [docs] def exists(self, task_id): - """Check if a task exists. + """ + Check if a task exists. Most task handler methods check for existence for you. Args: @@ -456,7 +468,8 @@ return False
    [docs] def active(self, task_id): - """Check if a task is active (has not been called yet). + """ + Check if a task is active (has not been called yet). Args: task_id (int): an existing task ID. @@ -474,7 +487,8 @@ return False
    [docs] def cancel(self, task_id): - """Stop a task from automatically executing. + """ + Stop a task from automatically executing. This will not remove the task. Args: @@ -500,7 +514,8 @@ return False
    [docs] def remove(self, task_id): - """Remove a task without executing it. + """ + Remove a task without executing it. Deletes the instance of the task's deferred. Args: @@ -526,8 +541,8 @@ return True
    [docs] def clear(self, save=True, cancel=True): - """clear all tasks. - By default tasks are canceled and removed from the database also. + """ + Clear all tasks. By default tasks are canceled and removed from the database as well. Args: save=True (bool): Should changes to persistent tasks be saved to database. @@ -549,7 +564,8 @@ return True
    [docs] def call_task(self, task_id): - """Call the callback of a task. + """ + Call the callback of a task. Leave the task unaffected otherwise. This does not use the task's deferred instance. The only requirement is that the task exist in task handler. @@ -569,7 +585,8 @@ return callback(*args, **kwargs)
    [docs] def do_task(self, task_id): - """Execute the task (call its callback). + """ + Execute the task (call its callback). If calling before timedelay cancel the deferred instance affliated to this task. Remove the task from the dictionary of current tasks on a successful callback. @@ -614,7 +631,8 @@ return None
    [docs] def create_delays(self): - """Create the delayed tasks for the persistent tasks. + """ + Create the delayed tasks for the persistent tasks. This method should be automatically called when Evennia starts. """ @@ -668,7 +686,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/scripts/tickerhandler.html b/docs/0.9.5/_modules/evennia/scripts/tickerhandler.html index f90640a06d..9c09522581 100644 --- a/docs/0.9.5/_modules/evennia/scripts/tickerhandler.html +++ b/docs/0.9.5/_modules/evennia/scripts/tickerhandler.html @@ -719,7 +719,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/amp_client.html b/docs/0.9.5/_modules/evennia/server/amp_client.html index 6159b4ed78..ab365913fc 100644 --- a/docs/0.9.5/_modules/evennia/server/amp_client.html +++ b/docs/0.9.5/_modules/evennia/server/amp_client.html @@ -46,9 +46,11 @@ """ import os +from django.conf import settings from evennia.server.portal import amp from twisted.internet import protocol from evennia.utils import logger +from evennia.utils.utils import class_from_module
    [docs]class AMPClientFactory(protocol.ReconnectingClientFactory): @@ -74,7 +76,7 @@ """ self.server = server - self.protocol = AMPServerClientProtocol + self.protocol = class_from_module(settings.AMP_CLIENT_PROTOCOL_CLASS) self.maxDelay = 10 # not really used unless connecting to multiple servers, but # avoids having to check for its existence on the protocol @@ -326,7 +328,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/connection_wizard.html b/docs/0.9.5/_modules/evennia/server/connection_wizard.html index 55b645df2e..7d27524762 100644 --- a/docs/0.9.5/_modules/evennia/server/connection_wizard.html +++ b/docs/0.9.5/_modules/evennia/server/connection_wizard.html @@ -597,7 +597,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/deprecations.html b/docs/0.9.5/_modules/evennia/server/deprecations.html index 02ce935419..3e972a9a05 100644 --- a/docs/0.9.5/_modules/evennia/server/deprecations.html +++ b/docs/0.9.5/_modules/evennia/server/deprecations.html @@ -45,7 +45,7 @@ These all print to the terminal. """ - +import os
    [docs]def check_errors(settings): """ @@ -100,6 +100,21 @@ "Update your settings file (see evennia/settings_default.py " "for more info)." ) + depstring = ( + "settings.{} was renamed to {}. Update your settings file (the FuncParser " + "replaces and generalizes that which inlinefuncs used to do).") + if hasattr(settings, "INLINEFUNC_ENABLED"): + raise DeprecationWarning(depstring.format( + "settings.INLINEFUNC_ENABLED", "FUNCPARSER_PARSE_OUTGOING_MESSAGES_ENABLED")) + if hasattr(settings, "INLINEFUNC_STACK_MAXSIZE"): + raise DeprecationWarning(depstring.format( + "settings.INLINEFUNC_STACK_MAXSIZE", "FUNCPARSER_MAX_NESTING")) + if hasattr(settings, "INLINEFUNC_MODULES"): + raise DeprecationWarning(depstring.format( + "settings.INLINEFUNC_MODULES", "FUNCPARSER_OUTGOING_MESSAGES_MODULES")) + if hasattr(settings, "PROTFUNC_MODULES"): + raise DeprecationWarning(depstring.format( + "settings.PROTFUNC_MODULES", "FUNCPARSER_PROTOTYPE_VALUE_MODULES")) gametime_deprecation = ( "The settings TIME_SEC_PER_MIN, TIME_MIN_PER_HOUR," @@ -142,6 +157,26 @@ "settings.CYCLE_LOGFILES is unused and should be removed. " "Use PORTAL/SERVER_LOG_DAY_ROTATION and PORTAL/SERVER_LOG_MAX_SIZE " "to control log cycling." + ) + if hasattr(settings, "CHANNEL_COMMAND_CLASS") or hasattr(settings, "CHANNEL_HANDLER_CLASS"): + raise DeprecationWarning( + "settings.CHANNEL_HANDLER_CLASS and CHANNEL COMMAND_CLASS are " + "unused and should be removed. The ChannelHandler is no more; " + "channels are now handled by aliasing the default 'channel' command.") + + template_overrides_dir = os.path.join(settings.GAME_DIR, "web", "template_overrides") + static_overrides_dir = os.path.join(settings.GAME_DIR, "web", "static_overrides") + if os.path.exists(template_overrides_dir): + raise DeprecationWarning( + f"The template_overrides directory ({template_overrides_dir}) has changed name.\n" + " - Rename your existing `template_overrides` folder to `templates` instead." + ) + if os.path.exists(static_overrides_dir): + raise DeprecationWarning( + f"The static_overrides directory ({static_overrides_dir}) has changed name.\n" + " 1. Delete any existing `web/static` folder and all its contents (this " + "was auto-generated)\n" + " 2. Rename your existing `static_overrides` folder to `static` instead." )
    @@ -200,7 +235,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/evennia_launcher.html b/docs/0.9.5/_modules/evennia/server/evennia_launcher.html index d2e031c5ca..c25733b858 100644 --- a/docs/0.9.5/_modules/evennia/server/evennia_launcher.html +++ b/docs/0.9.5/_modules/evennia/server/evennia_launcher.html @@ -133,9 +133,9 @@ # requirements PYTHON_MIN = "3.7" -TWISTED_MIN = "18.0.0" -DJANGO_MIN = "2.2.5" -DJANGO_LT = "3.0" +TWISTED_MIN = "20.3.0" +DJANGO_MIN = "3.2.0" +DJANGO_LT = "4.0" try: sys.path[1] = EVENNIA_ROOT @@ -1464,7 +1464,18 @@ "\nCreate a superuser below. The superuser is Account #1, the 'owner' " "account of the server. Email is optional and can be empty.\n" ) - django.core.management.call_command("createsuperuser", interactive=True) + from os import environ + + username = environ.get("EVENNIA_SUPERUSER_USERNAME") + email = environ.get("EVENNIA_SUPERUSER_EMAIL") + password = environ.get("EVENNIA_SUPERUSER_PASSWORD") + + if (username is not None) and (password is not None) and len(password) > 0: + from evennia.accounts.models import AccountDB + superuser = AccountDB.objects.create_superuser(username, email, password) + superuser.save() + else: + django.core.management.call_command("createsuperuser", interactive=True)
    [docs]def check_database(always_return=False): @@ -2300,7 +2311,7 @@ if option in ("makemessages", "compilemessages"): # some commands don't require the presence of a game directory to work need_gamedir = False - if option in ("shell", "check", "makemigrations", "createsuperuser"): + if option in ("shell", "check", "makemigrations", "createsuperuser", "shell_plus"): # some django commands requires the database to exist, # or evennia._init to have run before they work right. check_db = True @@ -2370,7 +2381,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/game_index_client/client.html b/docs/0.9.5/_modules/evennia/server/game_index_client/client.html index 7f303138d2..2119954c42 100644 --- a/docs/0.9.5/_modules/evennia/server/game_index_client/client.html +++ b/docs/0.9.5/_modules/evennia/server/game_index_client/client.html @@ -255,7 +255,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/game_index_client/service.html b/docs/0.9.5/_modules/evennia/server/game_index_client/service.html index b8b49b90a2..839733652a 100644 --- a/docs/0.9.5/_modules/evennia/server/game_index_client/service.html +++ b/docs/0.9.5/_modules/evennia/server/game_index_client/service.html @@ -134,7 +134,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/initial_setup.html b/docs/0.9.5/_modules/evennia/server/initial_setup.html index 86dd556b1d..0d2e6f2144 100644 --- a/docs/0.9.5/_modules/evennia/server/initial_setup.html +++ b/docs/0.9.5/_modules/evennia/server/initial_setup.html @@ -66,13 +66,11 @@ """ -LIMBO_DESC = _( - """ -Welcome to your new |wEvennia|n-based game! Visit http://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 '|wbatchcommand tutorial_world.build|n'. - """ -) +LIMBO_DESC = _(""" +Welcome to your new |wEvennia|n-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 '|wbatchcommand tutorial_world.build|n'. +""") WARNING_POSTGRESQL_FIX = """ @@ -81,7 +79,7 @@ but the superuser was not yet connected to them. Please use in game commands to connect Account #1 to those channels when first logging in. - """ +"""
    [docs]def get_god_account(): @@ -172,10 +170,9 @@ goduser = get_god_account() channel_mudinfo = settings.CHANNEL_MUDINFO - if not channel_mudinfo: - raise RuntimeError("settings.CHANNEL_MUDINFO must be defined.") - channel = create.create_channel(**channel_mudinfo) - channel.connect(goduser) + if channel_mudinfo: + channel = create.create_channel(**channel_mudinfo) + channel.connect(goduser) channel_connectinfo = settings.CHANNEL_CONNECTINFO if channel_connectinfo: @@ -315,7 +312,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/inputfuncs.html b/docs/0.9.5/_modules/evennia/server/inputfuncs.html index 67d31a0778..44379e260c 100644 --- a/docs/0.9.5/_modules/evennia/server/inputfuncs.html +++ b/docs/0.9.5/_modules/evennia/server/inputfuncs.html @@ -119,11 +119,11 @@ puppet = session.puppet if puppet: txt = puppet.nicks.nickreplace( - txt, categories=("inputline", "channel"), include_account=True + txt, categories=("inputline"), include_account=True ) else: txt = session.account.nicks.nickreplace( - txt, categories=("inputline", "channel"), include_account=False + txt, categories=("inputline"), include_account=False ) kwargs.pop("options", None) cmdhandler(session, txt, callertype="session", session=session, **kwargs) @@ -528,7 +528,6 @@ Keyword Args: <option name>: an option to save - """ account = session.account @@ -694,7 +693,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/manager.html b/docs/0.9.5/_modules/evennia/server/manager.html index 141a88dce1..b60803184f 100644 --- a/docs/0.9.5/_modules/evennia/server/manager.html +++ b/docs/0.9.5/_modules/evennia/server/manager.html @@ -129,7 +129,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/models.html b/docs/0.9.5/_modules/evennia/server/models.html index c153817421..7c8bac26a7 100644 --- a/docs/0.9.5/_modules/evennia/server/models.html +++ b/docs/0.9.5/_modules/evennia/server/models.html @@ -49,9 +49,8 @@ manager's conf() method. """ -import pickle - from django.db import models + from evennia.utils.idmapper.models import WeakSharedMemoryModel from evennia.utils import logger, utils from evennia.utils.dbserialize import to_pickle, from_pickle @@ -151,7 +150,7 @@ value = property(__value_get, __value_set, __value_del) - class Meta(object): + class Meta: "Define Django meta options" verbose_name = "Server Config value" verbose_name_plural = "Server Config values" @@ -159,9 +158,8 @@ # # ServerConfig other methods # - def __repr__(self): - return "<{} {}>".format(self.__class__.__name__, self.key, self.value) + return "<{} {}>".format(self.__class__.__name__, self.key)
    [docs] def store(self, key, value): """ @@ -211,7 +209,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/portal/amp.html b/docs/0.9.5/_modules/evennia/server/portal/amp.html index 6f0a507000..c6d45688aa 100644 --- a/docs/0.9.5/_modules/evennia/server/portal/amp.html +++ b/docs/0.9.5/_modules/evennia/server/portal/amp.html @@ -56,7 +56,7 @@ import pickle from twisted.internet.defer import DeferredList, Deferred -from evennia.utils.utils import to_str, variable_from_module +from evennia.utils.utils import variable_from_module # delayed import _LOGGER = None @@ -134,7 +134,10 @@ def _get_logger(): - "Delay import of logger until absolutely necessary" + """ + Delay import of logger until absolutely necessary + + """ global _LOGGER if not _LOGGER: from evennia.utils import logger as _LOGGER @@ -143,7 +146,10 @@ @wraps def catch_traceback(func): - "Helper decorator" + """ + Helper decorator + + """ def decorator(*args, **kwargs): try: @@ -394,6 +400,7 @@
    [docs] def dataReceived(self, data): """ Handle non-AMP messages, such as HTTP communication. + """ # print("dataReceived: {}".format(data)) if data[:1] == NUL: @@ -454,6 +461,7 @@ that is irrelevant. If a true connection error happens, the portal will continuously try to reconnect, showing the problem that way. + """ # print("ConnectionLost: {}: {}".format(self, reason)) try: @@ -463,20 +471,20 @@ # Error handling -
    [docs] def errback(self, e, info): +
    [docs] def errback(self, err, info): """ Error callback. Handles errors to avoid dropping connections on server tracebacks. Args: - e (Failure): Deferred error instance. + err (Failure): Deferred error instance. info (str): Error string. """ - e.trap(Exception) + err.trap(Exception) _get_logger().log_err( "AMP Error from {info}: {trcbck} {err}".format( - info=info, trcbck=e.getTraceback(), err=e.getErrorMessage() + info=info, trcbck=err.getTraceback(), err=err.getErrorMessage() ) )
    @@ -616,7 +624,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/portal/amp_server.html b/docs/0.9.5/_modules/evennia/server/portal/amp_server.html index 88e37307bc..7807e9cff0 100644 --- a/docs/0.9.5/_modules/evennia/server/portal/amp_server.html +++ b/docs/0.9.5/_modules/evennia/server/portal/amp_server.html @@ -52,6 +52,7 @@ from django.conf import settings from subprocess import Popen, STDOUT from evennia.utils import logger +from evennia.utils.utils import class_from_module def _is_windows(): @@ -83,7 +84,10 @@ noisy = False
    [docs] def logPrefix(self): - "How this is named in logs" + """ + How this is named in logs + + """ return "AMP"
    [docs] def __init__(self, portal): @@ -97,7 +101,7 @@ """ self.portal = portal - self.protocol = AMPServerProtocol + self.protocol = class_from_module(settings.AMP_SERVER_PROTOCOL_CLASS) self.broadcasts = [] self.server_connection = None self.launcher_connection = None @@ -115,7 +119,7 @@ protocol (Protocol): The created protocol. """ - self.portal.amp_protocol = AMPServerProtocol() + self.portal.amp_protocol = self.protocol() self.portal.amp_protocol.factory = self return self.portal.amp_protocol
    @@ -557,7 +561,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/portal/grapevine.html b/docs/0.9.5/_modules/evennia/server/portal/grapevine.html index 08faf457fe..07ff26a755 100644 --- a/docs/0.9.5/_modules/evennia/server/portal/grapevine.html +++ b/docs/0.9.5/_modules/evennia/server/portal/grapevine.html @@ -376,7 +376,7 @@ # incoming broadcast from network payload = data["payload"] - print("channels/broadcast:", payload["channel"], self.channel) + # print("channels/broadcast:", payload["channel"], self.channel) if str(payload["channel"]) != self.channel: # only echo from channels this particular bot actually listens to return @@ -435,7 +435,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/portal/irc.html b/docs/0.9.5/_modules/evennia/server/portal/irc.html index 430a5da198..6d26fa9e20 100644 --- a/docs/0.9.5/_modules/evennia/server/portal/irc.html +++ b/docs/0.9.5/_modules/evennia/server/portal/irc.html @@ -554,7 +554,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/portal/mccp.html b/docs/0.9.5/_modules/evennia/server/portal/mccp.html new file mode 100644 index 0000000000..2bcf12a748 --- /dev/null +++ b/docs/0.9.5/_modules/evennia/server/portal/mccp.html @@ -0,0 +1,192 @@ + + + + + + + + evennia.server.portal.mccp — Evennia 0.9.5 documentation + + + + + + + + + + + + + +
    +
    +
    +
    + +

    Source code for evennia.server.portal.mccp

    +"""
    +
    +MCCP - Mud Client Compression Protocol
    +
    +This implements the MCCP v2 telnet protocol as per
    +http://tintin.sourceforge.net/mccp/. MCCP allows for the server to
    +compress data when sending to supporting clients, reducing bandwidth
    +by 70-90%.. The compression is done using Python's builtin zlib
    +library. If the client doesn't support MCCP, server sends uncompressed
    +as normal.  Note: On modern hardware you are not likely to notice the
    +effect of MCCP unless you have extremely heavy traffic or sits on a
    +terribly slow connection.
    +
    +This protocol is implemented by the telnet protocol importing
    +mccp_compress and calling it from its write methods.
    +"""
    +import zlib
    +
    +# negotiations for v1 and v2 of the protocol
    +MCCP = bytes([86])  # b"\x56"
    +FLUSH = zlib.Z_SYNC_FLUSH
    +
    +
    +
    [docs]def mccp_compress(protocol, data): + """ + Handles zlib compression, if applicable. + + Args: + data (str): Incoming data to compress. + + Returns: + stream (binary): Zlib-compressed data. + + """ + if hasattr(protocol, "zlib"): + return protocol.zlib.compress(data) + protocol.zlib.flush(FLUSH) + return data
    + + +
    [docs]class Mccp: + """ + Implements the MCCP protocol. Add this to a + variable on the telnet protocol to set it up. + + """ + +
    [docs] def __init__(self, protocol): + """ + initialize MCCP by storing protocol on + ourselves and calling the client to see if + it supports MCCP. Sets callbacks to + start zlib compression in that case. + + Args: + protocol (Protocol): The active protocol instance. + + """ + + self.protocol = protocol + self.protocol.protocol_flags["MCCP"] = False + # ask if client will mccp, connect callbacks to handle answer + self.protocol.will(MCCP).addCallbacks(self.do_mccp, self.no_mccp)
    + +
    [docs] def no_mccp(self, option): + """ + Called if client doesn't support mccp or chooses to turn it off. + + Args: + option (Option): Option dict (not used). + + """ + if hasattr(self.protocol, "zlib"): + del self.protocol.zlib + self.protocol.protocol_flags["MCCP"] = False + self.protocol.handshake_done()
    + +
    [docs] def do_mccp(self, option): + """ + The client supports MCCP. Set things up by + creating a zlib compression stream. + + Args: + option (Option): Option dict (not used). + + """ + self.protocol.protocol_flags["MCCP"] = True + self.protocol.requestNegotiation(MCCP, b"") + self.protocol.zlib = zlib.compressobj(9) + self.protocol.handshake_done()
    +
    + +
    +
    +
    +
    + +
    +
    + + + + \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/mssp.html b/docs/0.9.5/_modules/evennia/server/portal/mssp.html new file mode 100644 index 0000000000..8add0fc7f0 --- /dev/null +++ b/docs/0.9.5/_modules/evennia/server/portal/mssp.html @@ -0,0 +1,237 @@ + + + + + + + + evennia.server.portal.mssp — Evennia 0.9.5 documentation + + + + + + + + + + + + + +
    +
    +
    +
    + +

    Source code for evennia.server.portal.mssp

    +"""
    +
    +MSSP - Mud Server Status Protocol
    +
    +This implements the MSSP telnet protocol as per
    +http://tintin.sourceforge.net/mssp/.  MSSP allows web portals and
    +listings to have their crawlers find the mud and automatically
    +extract relevant information about it, such as genre, how many
    +active players and so on.
    +
    +
    +"""
    +from django.conf import settings
    +from evennia.utils import utils
    +
    +MSSP = bytes([70])  # b"\x46"
    +MSSP_VAR = bytes([1])  # b"\x01"
    +MSSP_VAL = bytes([2])  # b"\x02"
    +
    +# try to get the customized mssp info, if it exists.
    +MSSPTable_CUSTOM = utils.variable_from_module(settings.MSSP_META_MODULE, "MSSPTable", default={})
    +
    +
    +
    [docs]class Mssp: + """ + Implements the MSSP protocol. Add this to a variable on the telnet + protocol to set it up. + + """ + +
    [docs] def __init__(self, protocol): + """ + initialize MSSP by storing protocol on ourselves and calling + the client to see if it supports MSSP. + + Args: + protocol (Protocol): The active protocol instance. + + """ + self.protocol = protocol + self.protocol.will(MSSP).addCallbacks(self.do_mssp, self.no_mssp)
    + +
    [docs] def get_player_count(self): + """ + Get number of logged-in players. + + Returns: + count (int): The number of players in the MUD. + + """ + return str(self.protocol.sessionhandler.count_loggedin())
    + +
    [docs] def get_uptime(self): + """ + Get how long the portal has been online (reloads are not counted). + + Returns: + uptime (int): Number of seconds of uptime. + + """ + return str(self.protocol.sessionhandler.uptime)
    + +
    [docs] def no_mssp(self, option): + """ + Called when mssp is not requested. This is the normal + operation. + + Args: + option (Option): Not used. + + """ + self.protocol.handshake_done()
    + +
    [docs] def do_mssp(self, option): + """ + Negotiate all the information. + + Args: + option (Option): Not used. + + """ + + self.mssp_table = { + # Required fields + "NAME": settings.SERVERNAME, + "PLAYERS": self.get_player_count, + "UPTIME": self.get_uptime, + "PORT": list( + str(port) for port in reversed(settings.TELNET_PORTS) + ), # most important port should be last in list + # Evennia auto-filled + "CRAWL DELAY": "-1", + "CODEBASE": utils.get_evennia_version(mode="pretty"), + "FAMILY": "Custom", + "ANSI": "1", + "GMCP": "1" if settings.TELNET_OOB_ENABLED else "0", + "ATCP": "0", + "MCCP": "1", + "MCP": "0", + "MSDP": "1" if settings.TELNET_OOB_ENABLED else "0", + "MSP": "0", + "MXP": "1", + "PUEBLO": "0", + "SSL": "1" if settings.SSL_ENABLED else "0", + "UTF-8": "1", + "ZMP": "0", + "VT100": "1", + "XTERM 256 COLORS": "1", + } + + # update the static table with the custom one + if MSSPTable_CUSTOM: + self.mssp_table.update(MSSPTable_CUSTOM) + + varlist = b"" + for variable, value in self.mssp_table.items(): + if callable(value): + value = value() + if utils.is_iter(value): + for partval in value: + varlist += ( + MSSP_VAR + + bytes(str(variable), "utf-8") + + MSSP_VAL + + bytes(str(partval), "utf-8") + ) + else: + varlist += ( + MSSP_VAR + bytes(str(variable), "utf-8") + MSSP_VAL + bytes(str(value), "utf-8") + ) + + # send to crawler by subnegotiation + self.protocol.requestNegotiation(MSSP, varlist) + self.protocol.handshake_done()
    +
    + +
    +
    +
    +
    + +
    +
    + + + + \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/mxp.html b/docs/0.9.5/_modules/evennia/server/portal/mxp.html new file mode 100644 index 0000000000..bce4d1791b --- /dev/null +++ b/docs/0.9.5/_modules/evennia/server/portal/mxp.html @@ -0,0 +1,189 @@ + + + + + + + + evennia.server.portal.mxp — Evennia 0.9.5 documentation + + + + + + + + + + + + + +
    +
    +
    +
    + +

    Source code for evennia.server.portal.mxp

    +"""
    +MXP - Mud eXtension Protocol.
    +
    +Partial implementation of the MXP protocol.
    +The MXP protocol allows more advanced formatting options for telnet clients
    +that supports it (mudlet, zmud, mushclient are a few)
    +
    +This only implements the SEND tag.
    +
    +More information can be found on the following links:
    +http://www.zuggsoft.com/zmud/mxp.htm
    +http://www.mushclient.com/mushclient/mxp.htm
    +http://www.gammon.com.au/mushclient/addingservermxp.htm
    +
    +"""
    +import re
    +
    +LINKS_SUB = re.compile(r"\|lc(.*?)\|lt(.*?)\|le", re.DOTALL)
    +URL_SUB = re.compile(r"\|lu(.*?)\|lt(.*?)\|le", re.DOTALL)
    +
    +# MXP Telnet option
    +MXP = bytes([91])  # b"\x5b"
    +
    +MXP_TEMPSECURE = "\x1B[4z"
    +MXP_SEND = MXP_TEMPSECURE + '<SEND HREF="\\1">' + "\\2" + MXP_TEMPSECURE + "</SEND>"
    +MXP_URL = MXP_TEMPSECURE + '<A HREF="\\1">' + "\\2" + MXP_TEMPSECURE + "</A>"
    +
    +
    +
    [docs]def mxp_parse(text): + """ + Replaces links to the correct format for MXP. + + Args: + text (str): The text to parse. + + Returns: + parsed (str): The parsed text. + + """ + text = text.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;") + + text = LINKS_SUB.sub(MXP_SEND, text) + text = URL_SUB.sub(MXP_URL, text) + return text
    + + +
    [docs]class Mxp: + """ + Implements the MXP protocol. + + """ + +
    [docs] def __init__(self, protocol): + """ + Initializes the protocol by checking if the client supports it. + + Args: + protocol (Protocol): The active protocol instance. + + """ + self.protocol = protocol + self.protocol.protocol_flags["MXP"] = False + self.protocol.will(MXP).addCallbacks(self.do_mxp, self.no_mxp)
    + +
    [docs] def no_mxp(self, option): + """ + Called when the Client reports to not support MXP. + + Args: + option (Option): Not used. + + """ + self.protocol.protocol_flags["MXP"] = False + self.protocol.handshake_done()
    + +
    [docs] def do_mxp(self, option): + """ + Called when the Client reports to support MXP. + + Args: + option (Option): Not used. + + """ + self.protocol.protocol_flags["MXP"] = True + self.protocol.requestNegotiation(MXP, b"") + self.protocol.handshake_done()
    +
    + +
    +
    +
    +
    + +
    +
    + + + + \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/naws.html b/docs/0.9.5/_modules/evennia/server/portal/naws.html new file mode 100644 index 0000000000..9242a03bf6 --- /dev/null +++ b/docs/0.9.5/_modules/evennia/server/portal/naws.html @@ -0,0 +1,187 @@ + + + + + + + + evennia.server.portal.naws — Evennia 0.9.5 documentation + + + + + + + + + + + + + +
    +
    +
    +
    + +

    Source code for evennia.server.portal.naws

    +"""
    +
    +NAWS - Negotiate About Window Size
    +
    +This implements the NAWS telnet option as per
    +https://www.ietf.org/rfc/rfc1073.txt
    +
    +NAWS allows telnet clients to report their current window size to the
    +client and update it when the size changes
    +
    +"""
    +from codecs import encode as codecs_encode
    +from django.conf import settings
    +
    +NAWS = bytes([31])  # b"\x1f"
    +IS = bytes([0])  # b"\x00"
    +
    +# default taken from telnet specification
    +DEFAULT_WIDTH = settings.CLIENT_DEFAULT_WIDTH
    +DEFAULT_HEIGHT = settings.CLIENT_DEFAULT_HEIGHT
    +
    +# try to get the customized mssp info, if it exists.
    +
    +
    +
    [docs]class Naws: + """ + Implements the NAWS protocol. Add this to a variable on the telnet + protocol to set it up. + + """ + +
    [docs] def __init__(self, protocol): + """ + initialize NAWS by storing protocol on ourselves and calling + the client to see if it supports NAWS. + + Args: + protocol (Protocol): The active protocol instance. + + """ + self.naws_step = 0 + self.protocol = protocol + self.protocol.protocol_flags["SCREENWIDTH"] = { + 0: DEFAULT_WIDTH + } # windowID (0 is root):width + self.protocol.protocol_flags["SCREENHEIGHT"] = {0: DEFAULT_HEIGHT} # windowID:width + self.protocol.negotiationMap[NAWS] = self.negotiate_sizes + self.protocol.do(NAWS).addCallbacks(self.do_naws, self.no_naws)
    + +
    [docs] def no_naws(self, option): + """ + Called when client is not reporting NAWS. This is the normal + operation. + + Args: + option (Option): Not used. + + """ + self.protocol.handshake_done()
    + +
    [docs] def do_naws(self, option): + """ + Client wants to negotiate all the NAWS information. + + Args: + option (Option): Not used. + + """ + self.protocol.handshake_done()
    + +
    [docs] def negotiate_sizes(self, options): + """ + Step through the NAWS handshake. + + Args: + option (list): The incoming NAWS options. + + """ + if len(options) == 4: + # NAWS is negotiated with 16bit words + width = options[0] + options[1] + self.protocol.protocol_flags["SCREENWIDTH"][0] = int(codecs_encode(width, "hex"), 16) + height = options[2] + options[3] + self.protocol.protocol_flags["SCREENHEIGHT"][0] = int(codecs_encode(height, "hex"), 16)
    +
    + +
    +
    +
    +
    + +
    +
    + + + + \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/portal.html b/docs/0.9.5/_modules/evennia/server/portal/portal.html new file mode 100644 index 0000000000..32a0ec9d29 --- /dev/null +++ b/docs/0.9.5/_modules/evennia/server/portal/portal.html @@ -0,0 +1,548 @@ + + + + + + + + evennia.server.portal.portal — Evennia 0.9.5 documentation + + + + + + + + + + + + + +
    +
    +
    +
    + +

    Source code for evennia.server.portal.portal

    +"""
    +This module implements the main Evennia server process, the core of
    +the game engine.
    +
    +This module should be started with the 'twistd' executable since it
    +sets up all the networking features.  (this is done automatically
    +by game/evennia.py).
    +
    +"""
    +import sys
    +import os
    +import time
    +
    +from os.path import dirname, abspath
    +from twisted.application import internet, service
    +from twisted.internet.task import LoopingCall
    +from twisted.internet import protocol, reactor
    +from twisted.python.log import ILogObserver
    +
    +import django
    +
    +django.setup()
    +from django.conf import settings
    +from django.db import connection
    +
    +import evennia
    +
    +evennia._init()
    +
    +from evennia.utils.utils import get_evennia_version, mod_import, make_iter, class_from_module
    +from evennia.server.portal.portalsessionhandler import PORTAL_SESSIONS
    +from evennia.utils import logger
    +from evennia.server.webserver import EvenniaReverseProxyResource
    +
    +
    +# we don't need a connection to the database so close it right away
    +try:
    +    connection.close()
    +except Exception:
    +    pass
    +
    +PORTAL_SERVICES_PLUGIN_MODULES = [
    +    mod_import(module) for module in make_iter(settings.PORTAL_SERVICES_PLUGIN_MODULES)
    +]
    +LOCKDOWN_MODE = settings.LOCKDOWN_MODE
    +
    +# -------------------------------------------------------------
    +# Evennia Portal settings
    +# -------------------------------------------------------------
    +
    +VERSION = get_evennia_version()
    +
    +SERVERNAME = settings.SERVERNAME
    +
    +PORTAL_RESTART = os.path.join(settings.GAME_DIR, "server", "portal.restart")
    +
    +TELNET_PORTS = settings.TELNET_PORTS
    +SSL_PORTS = settings.SSL_PORTS
    +SSH_PORTS = settings.SSH_PORTS
    +WEBSERVER_PORTS = settings.WEBSERVER_PORTS
    +WEBSOCKET_CLIENT_PORT = settings.WEBSOCKET_CLIENT_PORT
    +
    +TELNET_INTERFACES = ["127.0.0.1"] if LOCKDOWN_MODE else settings.TELNET_INTERFACES
    +SSL_INTERFACES = ["127.0.0.1"] if LOCKDOWN_MODE else settings.SSL_INTERFACES
    +SSH_INTERFACES = ["127.0.0.1"] if LOCKDOWN_MODE else settings.SSH_INTERFACES
    +WEBSERVER_INTERFACES = ["127.0.0.1"] if LOCKDOWN_MODE else settings.WEBSERVER_INTERFACES
    +WEBSOCKET_CLIENT_INTERFACE = "127.0.0.1" if LOCKDOWN_MODE else settings.WEBSOCKET_CLIENT_INTERFACE
    +WEBSOCKET_CLIENT_URL = settings.WEBSOCKET_CLIENT_URL
    +
    +TELNET_ENABLED = settings.TELNET_ENABLED and TELNET_PORTS and TELNET_INTERFACES
    +SSL_ENABLED = settings.SSL_ENABLED and SSL_PORTS and SSL_INTERFACES
    +SSH_ENABLED = settings.SSH_ENABLED and SSH_PORTS and SSH_INTERFACES
    +WEBSERVER_ENABLED = settings.WEBSERVER_ENABLED and WEBSERVER_PORTS and WEBSERVER_INTERFACES
    +WEBCLIENT_ENABLED = settings.WEBCLIENT_ENABLED
    +WEBSOCKET_CLIENT_ENABLED = (
    +    settings.WEBSOCKET_CLIENT_ENABLED and WEBSOCKET_CLIENT_PORT and WEBSOCKET_CLIENT_INTERFACE
    +)
    +
    +AMP_HOST = settings.AMP_HOST
    +AMP_PORT = settings.AMP_PORT
    +AMP_INTERFACE = settings.AMP_INTERFACE
    +AMP_ENABLED = AMP_HOST and AMP_PORT and AMP_INTERFACE
    +
    +INFO_DICT = {
    +    "servername": SERVERNAME,
    +    "version": VERSION,
    +    "errors": "",
    +    "info": "",
    +    "lockdown_mode": "",
    +    "amp": "",
    +    "telnet": [],
    +    "telnet_ssl": [],
    +    "ssh": [],
    +    "webclient": [],
    +    "webserver_proxy": [],
    +    "webserver_internal": [],
    +}
    +
    +try:
    +    WEB_PLUGINS_MODULE = mod_import(settings.WEB_PLUGINS_MODULE)
    +except ImportError:
    +    WEB_PLUGINS_MODULE = None
    +    INFO_DICT["errors"] = (
    +        "WARNING: settings.WEB_PLUGINS_MODULE not found - "
    +        "copy 'evennia/game_template/server/conf/web_plugins.py to "
    +        "mygame/server/conf."
    +    )
    +
    +
    +_MAINTENANCE_COUNT = 0
    +
    +
    +def _portal_maintenance():
    +    """
    +    Repeated maintenance tasks for the portal.
    +
    +    """
    +    global _MAINTENANCE_COUNT
    +
    +    _MAINTENANCE_COUNT += 1
    +
    +    if _MAINTENANCE_COUNT % (60 * 7) == 0:
    +        # drop database connection every 7 hrs to avoid default timeouts on MySQL
    +        # (see https://github.com/evennia/evennia/issues/1376)
    +        connection.close()
    +
    +
    +# -------------------------------------------------------------
    +# Portal Service object
    +# -------------------------------------------------------------
    +
    +
    +
    [docs]class Portal(object): + + """ + The main Portal server handler. This object sets up the database + and tracks and interlinks all the twisted network services that + make up Portal. + + """ + +
    [docs] def __init__(self, application): + """ + Setup the server. + + Args: + application (Application): An instantiated Twisted application + + """ + sys.path.append(".") + + # create a store of services + self.services = service.MultiService() + self.services.setServiceParent(application) + self.amp_protocol = None # set by amp factory + self.sessions = PORTAL_SESSIONS + self.sessions.portal = self + self.process_id = os.getpid() + + self.server_process_id = None + self.server_restart_mode = "shutdown" + self.server_info_dict = {} + + self.start_time = time.time() + + self.maintenance_task = LoopingCall(_portal_maintenance) + self.maintenance_task.start(60, now=True) # call every minute + + # in non-interactive portal mode, this gets overwritten by + # cmdline sent by the evennia launcher + self.server_twistd_cmd = self._get_backup_server_twistd_cmd() + + # set a callback if the server is killed abruptly, + # by Ctrl-C, reboot etc. + reactor.addSystemEventTrigger( + "before", "shutdown", self.shutdown, _reactor_stopping=True, _stop_server=True + )
    + + def _get_backup_server_twistd_cmd(self): + """ + For interactive Portal mode there is no way to get the server cmdline from the launcher, so + we need to guess it here (it's very likely to not change) + + Returns: + server_twistd_cmd (list): An instruction for starting the server, to pass to Popen. + + """ + server_twistd_cmd = [ + "twistd", + "--python={}".format(os.path.join(dirname(dirname(abspath(__file__))), "server.py")), + ] + if os.name != "nt": + gamedir = os.getcwd() + server_twistd_cmd.append( + "--pidfile={}".format(os.path.join(gamedir, "server", "server.pid")) + ) + return server_twistd_cmd + +
    [docs] def get_info_dict(self): + """ + Return the Portal info, for display. + + """ + return INFO_DICT
    + +
    [docs] def shutdown(self, _reactor_stopping=False, _stop_server=False): + """ + Shuts down the server from inside it. + + Args: + _reactor_stopping (bool, optional): This is set if server + is already in the process of shutting down; in this case + we don't need to stop it again. + _stop_server (bool, optional): Only used in portal-interactive mode; + makes sure to stop the Server cleanly. + + Note that restarting (regardless of the setting) will not work + if the Portal is currently running in daemon mode. In that + case it always needs to be restarted manually. + + """ + if _reactor_stopping and hasattr(self, "shutdown_complete"): + # we get here due to us calling reactor.stop below. No need + # to do the shutdown procedure again. + return + + self.sessions.disconnect_all() + if _stop_server: + self.amp_protocol.stop_server(mode="shutdown") + if not _reactor_stopping: + # shutting down the reactor will trigger another signal. We set + # a flag to avoid loops. + self.shutdown_complete = True + reactor.callLater(0, reactor.stop)
    + + +# ------------------------------------------------------------- +# +# Start the Portal proxy server and add all active services +# +# ------------------------------------------------------------- + + +# twistd requires us to define the variable 'application' so it knows +# what to execute from. +application = service.Application("Portal") + +# custom logging + +if "--nodaemon" not in sys.argv: + logfile = logger.WeeklyLogFile( + os.path.basename(settings.PORTAL_LOG_FILE), + os.path.dirname(settings.PORTAL_LOG_FILE), + day_rotation=settings.PORTAL_LOG_DAY_ROTATION, + max_size=settings.PORTAL_LOG_MAX_SIZE, + ) + application.setComponent(ILogObserver, logger.PortalLogObserver(logfile).emit) + +# The main Portal server program. This sets up the database +# and is where we store all the other services. +PORTAL = Portal(application) + +if LOCKDOWN_MODE: + + INFO_DICT["lockdown_mode"] = " LOCKDOWN_MODE active: Only local connections." + +if AMP_ENABLED: + + # The AMP protocol handles the communication between + # the portal and the mud server. Only reason to ever deactivate + # it would be during testing and debugging. + + from evennia.server.portal import amp_server + + INFO_DICT["amp"] = "amp: %s" % AMP_PORT + + factory = amp_server.AMPServerFactory(PORTAL) + amp_service = internet.TCPServer(AMP_PORT, factory, interface=AMP_INTERFACE) + amp_service.setName("PortalAMPServer") + PORTAL.services.addService(amp_service) + + +# We group all the various services under the same twisted app. +# These will gradually be started as they are initialized below. + +if TELNET_ENABLED: + + # Start telnet game connections + + from evennia.server.portal import telnet + + _telnet_protocol = class_from_module(settings.TELNET_PROTOCOL_CLASS) + + for interface in TELNET_INTERFACES: + ifacestr = "" + if interface not in ("0.0.0.0", "::") or len(TELNET_INTERFACES) > 1: + ifacestr = "-%s" % interface + for port in TELNET_PORTS: + pstring = "%s:%s" % (ifacestr, port) + factory = telnet.TelnetServerFactory() + factory.noisy = False + factory.protocol = _telnet_protocol + factory.sessionhandler = PORTAL_SESSIONS + telnet_service = internet.TCPServer(port, factory, interface=interface) + telnet_service.setName("EvenniaTelnet%s" % pstring) + PORTAL.services.addService(telnet_service) + + INFO_DICT["telnet"].append("telnet%s: %s" % (ifacestr, port)) + + +if SSL_ENABLED: + + # Start Telnet+SSL game connection (requires PyOpenSSL). + + from evennia.server.portal import telnet_ssl + + _ssl_protocol = class_from_module(settings.SSL_PROTOCOL_CLASS) + + for interface in SSL_INTERFACES: + ifacestr = "" + if interface not in ("0.0.0.0", "::") or len(SSL_INTERFACES) > 1: + ifacestr = "-%s" % interface + for port in SSL_PORTS: + pstring = "%s:%s" % (ifacestr, port) + factory = protocol.ServerFactory() + factory.noisy = False + factory.sessionhandler = PORTAL_SESSIONS + factory.protocol = _ssl_protocol + + ssl_context = telnet_ssl.getSSLContext() + if ssl_context: + ssl_service = internet.SSLServer( + port, factory, telnet_ssl.getSSLContext(), interface=interface + ) + ssl_service.setName("EvenniaSSL%s" % pstring) + PORTAL.services.addService(ssl_service) + + INFO_DICT["telnet_ssl"].append("telnet+ssl%s: %s" % (ifacestr, port)) + else: + INFO_DICT["telnet_ssl"].append( + "telnet+ssl%s: %s (deactivated - keys/cert unset)" % (ifacestr, port) + ) + + +if SSH_ENABLED: + + # Start SSH game connections. Will create a keypair in + # evennia/game if necessary. + + from evennia.server.portal import ssh + + _ssh_protocol = class_from_module(settings.SSH_PROTOCOL_CLASS) + + for interface in SSH_INTERFACES: + ifacestr = "" + if interface not in ("0.0.0.0", "::") or len(SSH_INTERFACES) > 1: + ifacestr = "-%s" % interface + for port in SSH_PORTS: + pstring = "%s:%s" % (ifacestr, port) + factory = ssh.makeFactory( + {"protocolFactory": _ssh_protocol, + "protocolArgs": (), "sessions": PORTAL_SESSIONS} + ) + factory.noisy = False + ssh_service = internet.TCPServer(port, factory, interface=interface) + ssh_service.setName("EvenniaSSH%s" % pstring) + PORTAL.services.addService(ssh_service) + + INFO_DICT["ssh"].append("ssh%s: %s" % (ifacestr, port)) + + +if WEBSERVER_ENABLED: + from evennia.server.webserver import Website + + # Start a reverse proxy to relay data to the Server-side webserver + + websocket_started = False + _websocket_protocol = class_from_module(settings.WEBSOCKET_PROTOCOL_CLASS) + for interface in WEBSERVER_INTERFACES: + ifacestr = "" + if interface not in ("0.0.0.0", "::") or len(WEBSERVER_INTERFACES) > 1: + ifacestr = "-%s" % interface + for proxyport, serverport in WEBSERVER_PORTS: + web_root = EvenniaReverseProxyResource("127.0.0.1", serverport, "") + webclientstr = "" + if WEBCLIENT_ENABLED: + # create ajax client processes at /webclientdata + from evennia.server.portal import webclient_ajax + + ajax_webclient = webclient_ajax.AjaxWebClient() + ajax_webclient.sessionhandler = PORTAL_SESSIONS + web_root.putChild(b"webclientdata", ajax_webclient) + webclientstr = "webclient (ajax only)" + + if WEBSOCKET_CLIENT_ENABLED and not websocket_started: + # start websocket client port for the webclient + # we only support one websocket client + from evennia.server.portal import webclient # noqa + from autobahn.twisted.websocket import WebSocketServerFactory + + w_interface = WEBSOCKET_CLIENT_INTERFACE + w_ifacestr = "" + if w_interface not in ("0.0.0.0", "::") or len(WEBSERVER_INTERFACES) > 1: + w_ifacestr = "-%s" % w_interface + port = WEBSOCKET_CLIENT_PORT + +
    [docs] class Websocket(WebSocketServerFactory): + "Only here for better naming in logs" + pass
    + + factory = Websocket() + factory.noisy = False + factory.protocol = _websocket_protocol + factory.sessionhandler = PORTAL_SESSIONS + websocket_service = internet.TCPServer(port, factory, interface=w_interface) + websocket_service.setName("EvenniaWebSocket%s:%s" % (w_ifacestr, port)) + PORTAL.services.addService(websocket_service) + websocket_started = True + webclientstr = "webclient-websocket%s: %s" % (w_ifacestr, port) + INFO_DICT["webclient"].append(webclientstr) + + if WEB_PLUGINS_MODULE: + try: + web_root = WEB_PLUGINS_MODULE.at_webproxy_root_creation(web_root) + except Exception: + # Legacy user has not added an at_webproxy_root_creation function in existing + # web plugins file + INFO_DICT["errors"] = ( + "WARNING: WEB_PLUGINS_MODULE is enabled but at_webproxy_root_creation() " + "not found copy 'evennia/game_template/server/conf/web_plugins.py to " + "mygame/server/conf." + ) + web_root = Website(web_root, logPath=settings.HTTP_LOG_FILE) + web_root.is_portal = True + proxy_service = internet.TCPServer(proxyport, web_root, interface=interface) + proxy_service.setName("EvenniaWebProxy%s:%s" % (ifacestr, proxyport)) + PORTAL.services.addService(proxy_service) + INFO_DICT["webserver_proxy"].append("webserver-proxy%s: %s" % (ifacestr, proxyport)) + INFO_DICT["webserver_internal"].append("webserver: %s" % serverport) + + +for plugin_module in PORTAL_SERVICES_PLUGIN_MODULES: + # external plugin services to start + if plugin_module: + plugin_module.start_plugin_services(PORTAL) +
    + +
    +
    +
    +
    + +
    +
    + + + + \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/portalsessionhandler.html b/docs/0.9.5/_modules/evennia/server/portal/portalsessionhandler.html index 20688dc9aa..91d3b876a2 100644 --- a/docs/0.9.5/_modules/evennia/server/portal/portalsessionhandler.html +++ b/docs/0.9.5/_modules/evennia/server/portal/portalsessionhandler.html @@ -40,7 +40,8 @@

    Source code for evennia.server.portal.portalsessionhandler

     """
    -Sessionhandler for portal sessions
    +Sessionhandler for portal sessions.
    +
     """
     
     
    @@ -48,8 +49,11 @@
     from collections import deque, namedtuple
     from twisted.internet import reactor
     from django.conf import settings
    -from evennia.server.sessionhandler import SessionHandler, PCONN, PDISCONN, PCONNSYNC, PDISCONNALL
    +from evennia.server.sessionhandler import SessionHandler
    +from evennia.server.portal.amp import PCONN, PDISCONN, PCONNSYNC, PDISCONNALL
     from evennia.utils.logger import log_trace
    +from evennia.utils.utils import class_from_module
    +from django.utils.translation import gettext as _
     
     # module import
     _MOD_IMPORT = None
    @@ -74,6 +78,9 @@
     # Portal-SessionHandler class
     # -------------------------------------------------------------
     
    +DOS_PROTECTION_MSG = _("{servername} DoS protection is active."
    +                       "You are queued to connect in {num} seconds ...")
    +
     
     
    [docs]class PortalSessionHandler(SessionHandler): """ @@ -109,6 +116,19 @@ """ self.connection_time = time.time()
    +
    [docs] def generate_sessid(self): + """ + Simply generates a sessid that's guaranteed to be unique for this Portal run. + + Returns: + sessid + + """ + self.latest_sessid += 1 + if self.latest_sessid in self: + return self.generate_sessid() + return self.latest_sessid
    +
    [docs] def connect(self, session): """ Called by protocol at first connect. This adds a not-yet @@ -132,22 +152,17 @@ if not session.sessid: # if the session already has a sessid (e.g. being inherited in the # case of a webclient auto-reconnect), keep it - self.latest_sessid += 1 - session.sessid = self.latest_sessid + session.sessid = self.generate_sessid() session.server_connected = False _CONNECTION_QUEUE.appendleft(session) if len(_CONNECTION_QUEUE) > 1: session.data_out( - text=[ - [ - "%s DoS protection is active. You are queued to connect in %g seconds ..." - % ( - settings.SERVERNAME, - len(_CONNECTION_QUEUE) * _MIN_TIME_BETWEEN_CONNECTS, - ) - ], + text=( + (DOS_PROTECTION_MSG.format( + servername=settings.SERVERNAME, + num=len(_CONNECTION_QUEUE) * _MIN_TIME_BETWEEN_CONNECTS),), {}, - ] + ) ) now = time.time() if ( @@ -247,6 +262,7 @@
    [docs] def disconnect_all(self): """ Disconnect all sessions, informing the Server. + """ def _callback(result, sessionhandler): @@ -504,7 +520,8 @@ log_trace()
    -PORTAL_SESSIONS = PortalSessionHandler() +_PORTAL_SESSION_HANDLER_CLASS = class_from_module(settings.PORTAL_SESSION_HANDLER_CLASS) +PORTAL_SESSIONS = _PORTAL_SESSION_HANDLER_CLASS()
    @@ -542,7 +559,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/portal/rss.html b/docs/0.9.5/_modules/evennia/server/portal/rss.html index 4853cea8f6..4a0086a144 100644 --- a/docs/0.9.5/_modules/evennia/server/portal/rss.html +++ b/docs/0.9.5/_modules/evennia/server/portal/rss.html @@ -186,6 +186,7 @@
    [docs] def start(self): """ Called by portalsessionhandler. Starts the bot. + """ def errback(fail): @@ -239,7 +240,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/portal/ssh.html b/docs/0.9.5/_modules/evennia/server/portal/ssh.html index d3ba43a5fe..85aa2e316a 100644 --- a/docs/0.9.5/_modules/evennia/server/portal/ssh.html +++ b/docs/0.9.5/_modules/evennia/server/portal/ssh.html @@ -84,10 +84,9 @@ from twisted.python import components from django.conf import settings -from evennia.server import session from evennia.accounts.models import AccountDB from evennia.utils import ansi -from evennia.utils.utils import to_str +from evennia.utils.utils import to_str, class_from_module _RE_N = re.compile(r"\|n$") _RE_SCREENREADER_REGEX = re.compile( @@ -103,29 +102,32 @@ CTRL_BACKSLASH = "\x1c" CTRL_L = "\x0c" -_NO_AUTOGEN = """ -Evennia could not generate SSH private- and public keys ({{err}}) +_NO_AUTOGEN = f""" +Evennia could not generate SSH private- and public keys ({{err}}) Using conch default keys instead. If this error persists, create the keys manually (using the tools for your OS) and put them here: - {} - {} -""".format( - _PRIVATE_KEY_FILE, _PUBLIC_KEY_FILE -) + {_PRIVATE_KEY_FILE} + {_PUBLIC_KEY_FILE} +""" + +_BASE_SESSION_CLASS = class_from_module(settings.BASE_SESSION_CLASS) # not used atm
    [docs]class SSHServerFactory(protocol.ServerFactory): - "This is only to name this better in logs" + """ + This is only to name this better in logs + + """ noisy = False
    [docs] def logPrefix(self): return "SSH"
    -
    [docs]class SshProtocol(Manhole, session.Session): +
    [docs]class SshProtocol(Manhole, _BASE_SESSION_CLASS): """ Each account connecting over ssh gets this protocol assigned to them. All communication between game and account goes through @@ -318,18 +320,18 @@ text (str): The first argument is always the text string to send. No other arguments are considered. Keyword Args: - options (dict): Send-option flags: + options (dict): Send-option flags (booleans) - - mxp: Enforce MXP link support. - - ansi: Enforce no ANSI colors. - - xterm256: Enforce xterm256 colors, regardless of TTYPE setting. - - nocolor: Strip all colors. - - raw: Pass string through without any ansi processing - (i.e. include Evennia ansi markers but do not + - mxp: enforce mxp link support. + - ansi: enforce no ansi colors. + - xterm256: enforce xterm256 colors, regardless of ttype setting. + - nocolor: strip all colors. + - raw: pass string through without any ansi processing + (i.e. include evennia ansi markers but do not convert them into ansi tokens) - - echo: Turn on/off line echo on the client. Turn + - echo: turn on/off line echo on the client. turn off line echo for client, for example for password. - Note that it must be actively turned back on again! + note that it must be actively turned back on again! """ # print "telnet.send_text", args,kwargs # DEBUG @@ -602,7 +604,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/portal/ssl.html b/docs/0.9.5/_modules/evennia/server/portal/ssl.html new file mode 100644 index 0000000000..3b92579ac7 --- /dev/null +++ b/docs/0.9.5/_modules/evennia/server/portal/ssl.html @@ -0,0 +1,223 @@ + + + + + + + + evennia.server.portal.ssl — Evennia 0.9.5 documentation + + + + + + + + + + + + + +
    +
    +
    +
    + +

    Source code for evennia.server.portal.ssl

    +"""
    +This is a simple context factory for auto-creating
    +SSL keys and certificates.
    +
    +"""
    +import os
    +import sys
    +
    +try:
    +    import OpenSSL
    +    from twisted.internet import ssl as twisted_ssl
    +except ImportError as error:
    +    errstr = """
    +    {err}
    +    SSL requires the PyOpenSSL library:
    +        pip install pyopenssl
    +    """
    +    raise ImportError(errstr.format(err=error))
    +
    +from django.conf import settings
    +from evennia.utils.utils import class_from_module
    +
    +_GAME_DIR = settings.GAME_DIR
    +
    +# messages
    +
    +NO_AUTOGEN = """
    +
    +{err}
    +Evennia could not auto-generate the SSL private key. If this error
    +persists, create {keyfile} yourself using third-party tools.
    +"""
    +
    +NO_AUTOCERT = """
    +
    +{err}
    +Evennia's SSL context factory could not automatically, create an SSL
    +certificate {certfile}.
    +
    +A private key {keyfile} was already created. Please create {certfile}
    +manually using the commands valid  for your operating system, for
    +example (linux, using the openssl program):
    +    {exestring}
    +"""
    +
    +_TELNET_PROTOCOL_CLASS = class_from_module(settings.TELNET_PROTOCOL_CLASS)
    +
    +
    +
    [docs]class SSLProtocol(_TELNET_PROTOCOL_CLASS): + """ + Communication is the same as telnet, except data transfer + is done with encryption. + + """ + +
    [docs] def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.protocol_name = "ssl"
    + + +
    [docs]def verify_SSL_key_and_cert(keyfile, certfile): + """ + This function looks for RSA key and certificate in the current + directory. If files ssl.key and ssl.cert does not exist, they + are created. + + """ + + if not (os.path.exists(keyfile) and os.path.exists(certfile)): + # key/cert does not exist. Create. + import subprocess + from Crypto.PublicKey import RSA + from twisted.conch.ssh.keys import Key + + print(" Creating SSL key and certificate ... ", end=" ") + + try: + # create the RSA key and store it. + KEY_LENGTH = 2048 + rsa_key = Key(RSA.generate(KEY_LENGTH)) + key_string = rsa_key.toString(type="OPENSSH") + with open(keyfile, "w+b") as fil: + fil.write(key_string) + except Exception as err: + print(NO_AUTOGEN.format(err=err, keyfile=keyfile)) + sys.exit(5) + + # try to create the certificate + CERT_EXPIRE = 365 * 20 # twenty years validity + # default: + # openssl req -new -x509 -key ssl.key -out ssl.cert -days 7300 + exestring = "openssl req -new -x509 -key %s -out %s -days %s" % ( + keyfile, + certfile, + CERT_EXPIRE, + ) + try: + subprocess.call(exestring) + except OSError as err: + raise OSError( + NO_AUTOCERT.format(err=err, certfile=certfile, keyfile=keyfile, exestring=exestring) + ) + print("done.")
    + + +
    [docs]def getSSLContext(): + """ + This is called by the portal when creating the SSL context + server-side. + + Returns: + ssl_context (tuple): A key and certificate that is either + existing previously or or created on the fly. + + """ + keyfile = os.path.join(_GAME_DIR, "server", "ssl.key") + certfile = os.path.join(_GAME_DIR, "server", "ssl.cert") + + verify_SSL_key_and_cert(keyfile, certfile) + return twisted_ssl.DefaultOpenSSLContextFactory(keyfile, certfile)
    +
    + +
    +
    +
    +
    + +
    +
    + + + + \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/suppress_ga.html b/docs/0.9.5/_modules/evennia/server/portal/suppress_ga.html new file mode 100644 index 0000000000..c9d9d71468 --- /dev/null +++ b/docs/0.9.5/_modules/evennia/server/portal/suppress_ga.html @@ -0,0 +1,171 @@ + + + + + + + + evennia.server.portal.suppress_ga — Evennia 0.9.5 documentation + + + + + + + + + + + + + +
    +
    +
    +
    + +

    Source code for evennia.server.portal.suppress_ga

    +"""
    +
    +SUPPRESS-GO-AHEAD
    +
    +This supports suppressing or activating Evennia
    +the GO-AHEAD telnet operation after every server reply.
    +If the client sends no explicit DONT SUPRESS GO-AHEAD,
    +Evennia will default to supressing it since many clients
    +will fail to use it and has no knowledge of this standard.
    +
    +It is set as the NOGOAHEAD protocol_flag option.
    +
    +http://www.faqs.org/rfcs/rfc858.html
    +
    +"""
    +
    +SUPPRESS_GA = bytes([3])  # b"\x03"
    +
    +# default taken from telnet specification
    +
    +# try to get the customized mssp info, if it exists.
    +
    +
    +
    [docs]class SuppressGA: + """ + Implements the SUPRESS-GO-AHEAD protocol. Add this to a variable on the telnet + protocol to set it up. + + """ + +
    [docs] def __init__(self, protocol): + """ + Initialize suppression of GO-AHEADs. + + Args: + protocol (Protocol): The active protocol instance. + + """ + self.protocol = protocol + + self.protocol.protocol_flags["NOGOAHEAD"] = True + self.protocol.protocol_flags[ + "NOPROMPTGOAHEAD" + ] = True # Used to send a GA after a prompt line only, set in TTYPE (per client) + # tell the client that we prefer to suppress GA ... + self.protocol.will(SUPPRESS_GA).addCallbacks(self.will_suppress_ga, self.wont_suppress_ga)
    + +
    [docs] def wont_suppress_ga(self, option): + """ + Called when client requests to not suppress GA. + + Args: + option (Option): Not used. + + """ + self.protocol.protocol_flags["NOGOAHEAD"] = False + self.protocol.handshake_done()
    + +
    [docs] def will_suppress_ga(self, option): + """ + Client will suppress GA + + Args: + option (Option): Not used. + + """ + self.protocol.protocol_flags["NOGOAHEAD"] = True + self.protocol.handshake_done()
    +
    + +
    +
    +
    +
    + +
    +
    + + + + \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/telnet.html b/docs/0.9.5/_modules/evennia/server/portal/telnet.html new file mode 100644 index 0000000000..6e5757309d --- /dev/null +++ b/docs/0.9.5/_modules/evennia/server/portal/telnet.html @@ -0,0 +1,613 @@ + + + + + + + + evennia.server.portal.telnet — Evennia 0.9.5 documentation + + + + + + + + + + + + + +
    +
    +
    +
    + +

    Source code for evennia.server.portal.telnet

    +"""
    +This module implements the telnet protocol.
    +
    +This depends on a generic session module that implements
    +the actual login procedure of the game, tracks
    +sessions etc.
    +
    +"""
    +
    +import re
    +from twisted.internet import protocol
    +from twisted.internet.task import LoopingCall
    +from twisted.conch.telnet import Telnet, StatefulTelnetProtocol
    +from twisted.conch.telnet import (
    +    IAC,
    +    NOP,
    +    LINEMODE,
    +    GA,
    +    WILL,
    +    WONT,
    +    ECHO,
    +    NULL,
    +    MODE,
    +    LINEMODE_EDIT,
    +    LINEMODE_TRAPSIG,
    +)
    +from django.conf import settings
    +from evennia.server.portal import ttype, mssp, telnet_oob, naws, suppress_ga
    +from evennia.server.portal.mccp import Mccp, mccp_compress, MCCP
    +from evennia.server.portal.mxp import Mxp, mxp_parse
    +from evennia.utils import ansi
    +from evennia.utils.utils import to_bytes, class_from_module
    +
    +_RE_N = re.compile(r"\|n$")
    +_RE_LEND = re.compile(br"\n$|\r$|\r\n$|\r\x00$|", re.MULTILINE)
    +_RE_LINEBREAK = re.compile(br"\n\r|\r\n|\n|\r", re.DOTALL + re.MULTILINE)
    +_RE_SCREENREADER_REGEX = re.compile(
    +    r"%s" % settings.SCREENREADER_REGEX_STRIP, re.DOTALL + re.MULTILINE
    +)
    +_IDLE_COMMAND = str.encode(settings.IDLE_COMMAND + "\n")
    +
    +# identify HTTP indata
    +_HTTP_REGEX = re.compile(
    +    b"(GET|HEAD|POST|PUT|DELETE|TRACE|OPTIONS|CONNECT|PATCH) (.*? HTTP/[0-9]\.[0-9])", re.I
    +)
    +
    +_HTTP_WARNING = bytes(
    +    """
    +    This is Evennia's Telnet port and cannot be used for regular HTTP traffic.
    +    Use a telnet client to connect here and point your browser to the server's
    +    dedicated web port instead.
    +
    +    """.strip(),
    +    "utf-8",
    +)
    +
    +
    +_BASE_SESSION_CLASS = class_from_module(settings.BASE_SESSION_CLASS)
    +
    +
    +
    [docs]class TelnetServerFactory(protocol.ServerFactory): + """ + This exists only to name this better in logs. + + """ + noisy = False + +
    [docs] def logPrefix(self): + return "Telnet"
    + + +
    [docs]class TelnetProtocol(Telnet, StatefulTelnetProtocol, _BASE_SESSION_CLASS): + """ + Each player connecting over telnet (ie using most traditional mud + clients) gets a telnet protocol instance assigned to them. All + communication between game and player goes through here. + + """ + +
    [docs] def __init__(self, *args, **kwargs): + self.protocol_key = "telnet" + super().__init__(*args, **kwargs)
    + +
    [docs] def dataReceived(self, data): + """ + Unused by default, but a good place to put debug printouts + of incoming data. + + """ + # print(f"telnet dataReceived: {data}") + try: + super().dataReceived(data) + except ValueError as err: + from evennia.utils import logger + logger.log_err(f"Malformed telnet input: {err}")
    + +
    [docs] def connectionMade(self): + """ + This is called when the connection is first established. + + """ + # important in order to work normally with standard telnet + self.do(LINEMODE).addErrback(self._wont_linemode) + # initialize the session + self.line_buffer = b"" + client_address = self.transport.client + client_address = client_address[0] if client_address else None + # this number is counted down for every handshake that completes. + # when it reaches 0 the portal/server syncs their data + self.handshakes = 8 # suppress-go-ahead, naws, ttype, mccp, mssp, msdp, gmcp, mxp + + self.init_session(self.protocol_key, client_address, self.factory.sessionhandler) + self.protocol_flags["ENCODING"] = settings.ENCODINGS[0] if settings.ENCODINGS else "utf-8" + # add this new connection to sessionhandler so + # the Server becomes aware of it. + self.sessionhandler.connect(self) + # change encoding to ENCODINGS[0] which reflects Telnet default encoding + + # suppress go-ahead + self.sga = suppress_ga.SuppressGA(self) + # negotiate client size + self.naws = naws.Naws(self) + # negotiate ttype (client info) + # Obs: mudlet ttype does not seem to work if we start mccp before ttype. /Griatch + self.ttype = ttype.Ttype(self) + # negotiate mccp (data compression) - turn this off for wireshark analysis + self.mccp = Mccp(self) + # negotiate mssp (crawler communication) + self.mssp = mssp.Mssp(self) + # oob communication (MSDP, GMCP) - two handshake calls! + self.oob = telnet_oob.TelnetOOB(self) + # mxp support + self.mxp = Mxp(self) + + from evennia.utils.utils import delay + + # timeout the handshakes in case the client doesn't reply at all + self._handshake_delay = delay(2, callback=self.handshake_done, timeout=True) + + # TCP/IP keepalive watches for dead links + self.transport.setTcpKeepAlive(1) + # The TCP/IP keepalive is not enough for some networks; + # we have to complement it with a NOP keep-alive. + self.protocol_flags["NOPKEEPALIVE"] = True + self.nop_keep_alive = None + self.toggle_nop_keepalive()
    + + def _wont_linemode(self, *args): + """ + Client refuses do(linemode). This is common for MUD-specific + clients, but we must ask for the sake of raw telnet. We ignore + this error. + + """ + pass + + def _send_nop_keepalive(self): + """ + Send NOP keepalive unless flag is set + + """ + if self.protocol_flags.get("NOPKEEPALIVE"): + self._write(IAC + NOP) + +
    [docs] def toggle_nop_keepalive(self): + """ + Allow to toggle the NOP keepalive for those sad clients that + can't even handle a NOP instruction. This is turned off by the + protocol_flag NOPKEEPALIVE (settable e.g. by the default + `option` command). + + """ + if self.nop_keep_alive and self.nop_keep_alive.running: + self.nop_keep_alive.stop() + else: + self.nop_keep_alive = LoopingCall(self._send_nop_keepalive) + self.nop_keep_alive.start(30, now=False)
    + +
    [docs] def handshake_done(self, timeout=False): + """ + This is called by all telnet extensions once they are finished. + When all have reported, a sync with the server is performed. + The system will force-call this sync after a small time to handle + clients that don't reply to handshakes at all. + + """ + if timeout: + if self.handshakes > 0: + self.handshakes = 0 + self.sessionhandler.sync(self) + else: + self.handshakes -= 1 + if self.handshakes <= 0: + # do the sync + self.sessionhandler.sync(self)
    + +
    [docs] def at_login(self): + """ + Called when this session gets authenticated by the server. + + """ + pass
    + +
    [docs] def enableRemote(self, option): + """ + This sets up the remote-activated options we allow for this protocol. + + Args: + option (char): The telnet option to enable. + + Returns: + enable (bool): If this option should be enabled. + + """ + if option == LINEMODE: + # make sure to activate line mode with local editing for all clients + self.requestNegotiation( + LINEMODE, MODE + bytes(chr(ord(LINEMODE_EDIT) + ord(LINEMODE_TRAPSIG)), "ascii") + ) + return True + else: + return ( + option == ttype.TTYPE + or option == naws.NAWS + or option == MCCP + or option == mssp.MSSP + or option == suppress_ga.SUPPRESS_GA + )
    + +
    [docs] def disableRemote(self, option): + return ( + option == LINEMODE + or option == ttype.TTYPE + or option == naws.NAWS + or option == MCCP + or option == mssp.MSSP + or option == suppress_ga.SUPPRESS_GA + )
    + +
    [docs] def enableLocal(self, option): + """ + Call to allow the activation of options for this protocol + + Args: + option (char): The telnet option to enable locally. + + Returns: + enable (bool): If this option should be enabled. + + """ + return ( + option == LINEMODE + or option == MCCP + or option == ECHO + or option == suppress_ga.SUPPRESS_GA + )
    + +
    [docs] def disableLocal(self, option): + """ + Disable a given option locally. + + Args: + option (char): The telnet option to disable locally. + + """ + if option == LINEMODE: + return True + if option == ECHO: + return True + if option == MCCP: + self.mccp.no_mccp(option) + return True + else: + try: + return super().disableLocal(option) + except Exception: + from evennia.utils import logger + + logger.log_trace()
    + +
    [docs] def connectionLost(self, reason): + """ + this is executed when the connection is lost for whatever + reason. it can also be called directly, from the disconnect + method + + Args: + reason (str): Motivation for losing connection. + + """ + self.sessionhandler.disconnect(self) + self.transport.loseConnection()
    + +
    [docs] def applicationDataReceived(self, data): + """ + Telnet method called when non-telnet-command data is coming in + over the telnet connection. We pass it on to the game engine + directly. + + Args: + data (str): Incoming data. + + """ + if not data: + data = [data] + elif data.strip() == NULL: + # this is an ancient type of keepalive used by some + # legacy clients. There should never be a reason to send a + # lone NULL character so this seems to be a safe thing to + # support for backwards compatibility. It also stops the + # NULL from continuously popping up as an unknown command. + data = [_IDLE_COMMAND] + else: + data = _RE_LINEBREAK.split(data) + + if len(data) > 2 and _HTTP_REGEX.match(data[0]): + # guard against HTTP request on the Telnet port; we + # block and kill the connection. + self.transport.write(_HTTP_WARNING) + self.transport.loseConnection() + return + + if self.line_buffer and len(data) > 1: + # buffer exists, it is terminated by the first line feed + data[0] = self.line_buffer + data[0] + self.line_buffer = b"" + # if the last data split is empty, it means all splits have + # line breaks, if not, it is unterminated and must be + # buffered. + self.line_buffer += data.pop() + # send all data chunks + for dat in data: + self.data_in(text=dat + b"\n")
    + + def _write(self, data): + """ + Hook overloading the one used in plain telnet + + """ + data = data.replace(b"\n", b"\r\n").replace(b"\r\r\n", b"\r\n") + super()._write(mccp_compress(self, data)) + +
    [docs] def sendLine(self, line): + """ + Hook overloading the one used by linereceiver. + + Args: + line (str): Line to send. + + """ + line = to_bytes(line, self) + # escape IAC in line mode, and correctly add \r\n (the TELNET end-of-line) + line = line.replace(IAC, IAC + IAC) + line = line.replace(b"\n", b"\r\n") + if not line.endswith(b"\r\n") and self.protocol_flags.get("FORCEDENDLINE", True): + line += b"\r\n" + if not self.protocol_flags.get("NOGOAHEAD", True): + line += IAC + GA + return self.transport.write(mccp_compress(self, line))
    + + # Session hooks + +
    [docs] def disconnect(self, reason=""): + """ + Generic hook for the engine to call in order to + disconnect this protocol. + + Args: + reason (str, optional): Reason for disconnecting. + + """ + self.data_out(text=((reason,), {})) + self.connectionLost(reason)
    + +
    [docs] def data_in(self, **kwargs): + """ + Data User -> Evennia + + Keyword Args: + kwargs (any): Options from the protocol. + + """ + # from evennia.server.profiling.timetrace import timetrace # DEBUG + # text = timetrace(text, "telnet.data_in") # DEBUG + + self.sessionhandler.data_in(self, **kwargs)
    + +
    [docs] def data_out(self, **kwargs): + """ + Data Evennia -> User + + Keyword Args: + kwargs (any): Options to the protocol + + """ + self.sessionhandler.data_out(self, **kwargs)
    + + # send_* methods + +
    [docs] def send_text(self, *args, **kwargs): + """ + Send text data. This is an in-band telnet operation. + + Args: + text (str): The first argument is always the text string to send. No other arguments + are considered. + Keyword Args: + options (dict): Send-option flags + + - mxp: Enforce MXP link support. + - ansi: Enforce no ANSI colors. + - xterm256: Enforce xterm256 colors, regardless of TTYPE. + - noxterm256: Enforce no xterm256 color support, regardless of TTYPE. + - nocolor: Strip all Color, regardless of ansi/xterm256 setting. + - raw: Pass string through without any ansi processing + (i.e. include Evennia ansi markers but do not + convert them into ansi tokens) + - echo: Turn on/off line echo on the client. Turn + off line echo for client, for example for password. + Note that it must be actively turned back on again! + + """ + text = args[0] if args else "" + if text is None: + return + + # handle arguments + options = kwargs.get("options", {}) + flags = self.protocol_flags + xterm256 = options.get( + "xterm256", flags.get("XTERM256", False) if flags.get("TTYPE", False) else True + ) + useansi = options.get( + "ansi", flags.get("ANSI", False) if flags.get("TTYPE", False) else True + ) + raw = options.get("raw", flags.get("RAW", False)) + nocolor = options.get("nocolor", flags.get("NOCOLOR") or not (xterm256 or useansi)) + echo = options.get("echo", None) + mxp = options.get("mxp", flags.get("MXP", False)) + screenreader = options.get("screenreader", flags.get("SCREENREADER", False)) + + if screenreader: + # screenreader mode cleans up output + text = ansi.parse_ansi(text, strip_ansi=True, xterm256=False, mxp=False) + text = _RE_SCREENREADER_REGEX.sub("", text) + + if options.get("send_prompt"): + # send a prompt instead. + prompt = text + if not raw: + # processing + prompt = ansi.parse_ansi( + _RE_N.sub("", prompt) + ("||n" if prompt.endswith("|") else "|n"), + strip_ansi=nocolor, + xterm256=xterm256, + ) + if mxp: + prompt = mxp_parse(prompt) + prompt = to_bytes(prompt, self) + prompt = prompt.replace(IAC, IAC + IAC).replace(b"\n", b"\r\n") + if not self.protocol_flags.get("NOPROMPTGOAHEAD", + self.protocol_flags.get("NOGOAHEAD", True)): + prompt += IAC + GA + self.transport.write(mccp_compress(self, prompt)) + else: + if echo is not None: + # turn on/off echo. Note that this is a bit turned around since we use + # echo as if we are "turning off the client's echo" when telnet really + # handles it the other way around. + if echo: + # by telling the client that WE WON'T echo, the client knows + # that IT should echo. This is the expected behavior from + # our perspective. + self.transport.write(mccp_compress(self, IAC + WONT + ECHO)) + else: + # by telling the client that WE WILL echo, the client can + # safely turn OFF its OWN echo. + self.transport.write(mccp_compress(self, IAC + WILL + ECHO)) + if raw: + # no processing + self.sendLine(text) + return + else: + # we need to make sure to kill the color at the end in order + # to match the webclient output. + linetosend = ansi.parse_ansi( + _RE_N.sub("", text) + ("||n" if text.endswith("|") else "|n"), + strip_ansi=nocolor, + xterm256=xterm256, + mxp=mxp, + ) + if mxp: + linetosend = mxp_parse(linetosend) + self.sendLine(linetosend)
    + +
    [docs] def send_prompt(self, *args, **kwargs): + """ + Send a prompt - a text without a line end. See send_text for argument options. + + """ + kwargs["options"].update({"send_prompt": True}) + self.send_text(*args, **kwargs)
    + +
    [docs] def send_default(self, cmdname, *args, **kwargs): + """ + Send other oob data + + """ + if not cmdname == "options": + self.oob.data_out(cmdname, *args, **kwargs)
    +
    + +
    +
    +
    +
    + +
    +
    + + + + \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/telnet_oob.html b/docs/0.9.5/_modules/evennia/server/portal/telnet_oob.html new file mode 100644 index 0000000000..e330c4d5f6 --- /dev/null +++ b/docs/0.9.5/_modules/evennia/server/portal/telnet_oob.html @@ -0,0 +1,542 @@ + + + + + + + + evennia.server.portal.telnet_oob — Evennia 0.9.5 documentation + + + + + + + + + + + + + +
    +
    +
    +
    + +

    Source code for evennia.server.portal.telnet_oob

    +"""
    +
    +Telnet OOB (Out of band communication)
    +
    +OOB protocols allow for asynchronous communication between Evennia and
    +compliant telnet clients. The "text" type of send command will always
    +be sent "in-band", appearing in the client's main text output. OOB
    +commands, by contrast, can have many forms and it is up to the client
    +how and if they are handled.  Examples of OOB instructions could be to
    +instruct the client to play sounds or to update a graphical health
    +bar.
    +
    +Note that in Evennia's Web client, all send commands are "OOB
    +commands", (including the "text" one), there is no equivalence to
    +MSDP/GMCP for the webclient since it doesn't need it.
    +
    +This implements the following telnet OOB communication protocols:
    +
    +- MSDP (Mud Server Data Protocol), as per http://tintin.sourceforge.net/msdp/
    +- GMCP (Generic Mud Communication Protocol) as per
    +  http://www.ironrealms.com/rapture/manual/files/FeatGMCP-txt.html#Generic_MUD_Communication_Protocol%28GMCP%29
    +
    +----
    +
    +"""
    +import re
    +import json
    +from evennia.utils.utils import is_iter
    +
    +# General Telnet
    +from twisted.conch.telnet import IAC, SB, SE
    +
    +# MSDP-relevant telnet cmd/opt-codes
    +MSDP = bytes([69])
    +MSDP_VAR = bytes([1])
    +MSDP_VAL = bytes([2])
    +MSDP_TABLE_OPEN = bytes([3])
    +MSDP_TABLE_CLOSE = bytes([4])
    +
    +MSDP_ARRAY_OPEN = bytes([5])
    +MSDP_ARRAY_CLOSE = bytes([6])
    +
    +# GMCP
    +GMCP = bytes([201])
    +
    +
    +# pre-compiled regexes
    +# returns 2-tuple
    +msdp_regex_table = re.compile(
    +    br"%s\s*(\w*?)\s*%s\s*%s(.*?)%s" % (MSDP_VAR, MSDP_VAL, MSDP_TABLE_OPEN, MSDP_TABLE_CLOSE)
    +)
    +# returns 2-tuple
    +msdp_regex_array = re.compile(
    +    br"%s\s*(\w*?)\s*%s\s*%s(.*?)%s" % (MSDP_VAR, MSDP_VAL, MSDP_ARRAY_OPEN, MSDP_ARRAY_CLOSE)
    +)
    +msdp_regex_var = re.compile(br"%s" % MSDP_VAR)
    +msdp_regex_val = re.compile(br"%s" % MSDP_VAL)
    +
    +EVENNIA_TO_GMCP = {
    +    "client_options": "Core.Supports.Get",
    +    "get_inputfuncs": "Core.Commands.Get",
    +    "get_value": "Char.Value.Get",
    +    "repeat": "Char.Repeat.Update",
    +    "monitor": "Char.Monitor.Update",
    +}
    +
    +
    +# MSDP/GMCP communication handler
    +
    +
    +
    [docs]class TelnetOOB: + """ + Implements the MSDP and GMCP protocols. + """ + +
    [docs] def __init__(self, protocol): + """ + Initiates by storing the protocol on itself and trying to + determine if the client supports MSDP. + + Args: + protocol (Protocol): The active protocol. + + """ + self.protocol = protocol + self.protocol.protocol_flags["OOB"] = False + self.MSDP = False + self.GMCP = False + # ask for the available protocols and assign decoders + # (note that handshake_done() will be called twice!) + self.protocol.negotiationMap[MSDP] = self.decode_msdp + self.protocol.negotiationMap[GMCP] = self.decode_gmcp + self.protocol.will(MSDP).addCallbacks(self.do_msdp, self.no_msdp) + self.protocol.will(GMCP).addCallbacks(self.do_gmcp, self.no_gmcp) + self.oob_reported = {}
    + +
    [docs] def no_msdp(self, option): + """ + Client reports No msdp supported or wanted. + + Args: + option (Option): Not used. + + """ + # no msdp, check GMCP + self.protocol.handshake_done()
    + +
    [docs] def do_msdp(self, option): + """ + Client reports that it supports msdp. + + Args: + option (Option): Not used. + + """ + self.MSDP = True + self.protocol.protocol_flags["OOB"] = True + self.protocol.handshake_done()
    + +
    [docs] def no_gmcp(self, option): + """ + If this is reached, it means neither MSDP nor GMCP is + supported. + + Args: + option (Option): Not used. + + """ + self.protocol.handshake_done()
    + +
    [docs] def do_gmcp(self, option): + """ + Called when client confirms that it can do MSDP or GMCP. + + Args: + option (Option): Not used. + + """ + self.GMCP = True + self.protocol.protocol_flags["OOB"] = True + self.protocol.handshake_done()
    + + # encoders + +
    [docs] def encode_msdp(self, cmdname, *args, **kwargs): + """ + Encode into a valid MSDP command. + + Args: + cmdname (str): Name of send instruction. + args, kwargs (any): Arguments to OOB command. + + Notes: + The output of this encoding will be + MSDP structures on these forms: + :: + + [cmdname, [], {}] -> VAR cmdname VAL "" + [cmdname, [arg], {}] -> VAR cmdname VAL arg + [cmdname, [args],{}] -> VAR cmdname VAL ARRAYOPEN VAL arg VAL arg ... ARRAYCLOSE + [cmdname, [], {kwargs}] -> VAR cmdname VAL TABLEOPEN VAR key VAL val ... TABLECLOSE + [cmdname, [args], {kwargs}] -> VAR cmdname VAL ARRAYOPEN VAL arg VAL arg ... ARRAYCLOSE + VAR cmdname VAL TABLEOPEN VAR key VAL val ... TABLECLOSE + + Further nesting is not supported, so if an array argument + consists of an array (for example), that array will be + json-converted to a string. + + """ + msdp_cmdname = "{msdp_var}{msdp_cmdname}{msdp_val}".format( + msdp_var=MSDP_VAR.decode(), msdp_cmdname=cmdname, msdp_val=MSDP_VAL.decode() + ) + + if not (args or kwargs): + return msdp_cmdname.encode() + + # print("encode_msdp in:", cmdname, args, kwargs) # DEBUG + + msdp_args = "" + if args: + msdp_args = msdp_cmdname + if len(args) == 1: + msdp_args += args[0] + else: + msdp_args += ( + "{msdp_array_open}" + "{msdp_args}" + "{msdp_array_close}".format( + msdp_array_open=MSDP_ARRAY_OPEN.decode(), + msdp_array_close=MSDP_ARRAY_CLOSE.decode(), + msdp_args="".join("%s%s" % (MSDP_VAL.decode(), val) for val in args), + ) + ) + + msdp_kwargs = "" + if kwargs: + msdp_kwargs = msdp_cmdname + msdp_kwargs += ( + "{msdp_table_open}" + "{msdp_kwargs}" + "{msdp_table_close}".format( + msdp_table_open=MSDP_TABLE_OPEN.decode(), + msdp_table_close=MSDP_TABLE_CLOSE.decode(), + msdp_kwargs="".join( + "%s%s%s%s" % (MSDP_VAR.decode(), key, MSDP_VAL.decode(), val) + for key, val in kwargs.items() + ), + ) + ) + + msdp_string = msdp_args + msdp_kwargs + + # print("msdp_string:", msdp_string) # DEBUG + return msdp_string.encode()
    + +
    [docs] def encode_gmcp(self, cmdname, *args, **kwargs): + """ + Encode into GMCP messages. + + Args: + cmdname (str): GMCP OOB command name. + args, kwargs (any): Arguments to OOB command. + + Notes: + GMCP messages will be outgoing on the following + form (the non-JSON cmdname at the start is what + IRE games use, supposedly, and what clients appear + to have adopted). A cmdname without Package will end + up in the Core package, while Core package names will + be stripped on the Evennia side. + :: + + [cmd.name, [], {}] -> Cmd.Name + [cmd.name, [arg], {}] -> Cmd.Name arg + [cmd.name, [args],{}] -> Cmd.Name [args] + [cmd.name, [], {kwargs}] -> Cmd.Name {kwargs} + [cmdname, [args, {kwargs}] -> Core.Cmdname [[args],{kwargs}] + + Notes: + There are also a few default mappings between evennia outputcmds and GMCP: + :: + + client_options -> Core.Supports.Get + get_inputfuncs -> Core.Commands.Get + get_value -> Char.Value.Get + repeat -> Char.Repeat.Update + monitor -> Char.Monitor.Update + + """ + + if cmdname in EVENNIA_TO_GMCP: + gmcp_cmdname = EVENNIA_TO_GMCP[cmdname] + elif "_" in cmdname: + gmcp_cmdname = ".".join(word.capitalize() for word in cmdname.split("_")) + else: + gmcp_cmdname = "Core.%s" % cmdname.capitalize() + + if not (args or kwargs): + gmcp_string = gmcp_cmdname + elif args: + if len(args) == 1: + args = args[0] + if kwargs: + gmcp_string = "%s %s" % (gmcp_cmdname, json.dumps([args, kwargs])) + else: + gmcp_string = "%s %s" % (gmcp_cmdname, json.dumps(args)) + else: # only kwargs + gmcp_string = "%s %s" % (gmcp_cmdname, json.dumps(kwargs)) + + # print("gmcp string", gmcp_string) # DEBUG + return gmcp_string.encode()
    + +
    [docs] def decode_msdp(self, data): + """ + Decodes incoming MSDP data. + + Args: + data (str or list): MSDP data. + + Notes: + Clients should always send MSDP data on + one of the following forms: + :: + + cmdname '' -> [cmdname, [], {}] + cmdname val -> [cmdname, [val], {}] + cmdname array -> [cmdname, [array], {}] + cmdname table -> [cmdname, [], {table}] + cmdname array cmdname table -> [cmdname, [array], {table}] + + Observe that all MSDP_VARS are used to identify cmdnames, + so if there are multiple arrays with the same cmdname + given, they will be merged into one argument array, same + for tables. Different MSDP_VARS (outside tables) will be + identified as separate cmdnames. + + """ + if isinstance(data, list): + data = b"".join(data) + + # print("decode_msdp in:", data) # DEBUG + + tables = {} + arrays = {} + variables = {} + + # decode tables + for key, table in msdp_regex_table.findall(data): + key = key.decode() + tables[key] = {} if key not in tables else tables[key] + for varval in msdp_regex_var.split(table)[1:]: + var, val = msdp_regex_val.split(varval, 1) + var, val = var.decode(), val.decode() + if var: + tables[key][var] = val + + # decode arrays from all that was not a table + data_no_tables = msdp_regex_table.sub(b"", data) + for key, array in msdp_regex_array.findall(data_no_tables): + key = key.decode() + arrays[key] = [] if key not in arrays else arrays[key] + parts = msdp_regex_val.split(array) + parts = [part.decode() for part in parts] + if len(parts) == 2: + arrays[key].append(parts[1]) + elif len(parts) > 1: + arrays[key].extend(parts[1:]) + + # decode remainders from all that were not tables or arrays + data_no_tables_or_arrays = msdp_regex_array.sub(b"", data_no_tables) + for varval in msdp_regex_var.split(data_no_tables_or_arrays): + # get remaining varvals after cleaning away tables/arrays. If mathcing + # an existing key in arrays, it will be added as an argument to that command, + # otherwise it will be treated as a command without argument. + parts = msdp_regex_val.split(varval) + parts = [part.decode() for part in parts] + if len(parts) == 2: + variables[parts[0]] = parts[1] + elif len(parts) > 1: + variables[parts[0]] = parts[1:] + + cmds = {} + # merge matching table/array/variables together + for key, table in tables.items(): + args, kwargs = [], table + if key in arrays: + args.extend(arrays.pop(key)) + if key in variables: + args.append(variables.pop(key)) + cmds[key] = [args, kwargs] + + for key, arr in arrays.items(): + args, kwargs = arr, {} + if key in variables: + args.append(variables.pop(key)) + cmds[key] = [args, kwargs] + + for key, var in variables.items(): + cmds[key] = [[var], {}] + + # remap the 'generic msdp commands' to avoid colliding with builtins etc + # by prepending "msdp_" + lower_case = {key.lower(): key for key in cmds} + for remap in ("list", "report", "reset", "send", "unreport"): + if remap in lower_case: + cmds["msdp_{}".format(remap)] = cmds.pop(lower_case[remap]) + + # print("msdp data in:", cmds) # DEBUG + self.protocol.data_in(**cmds)
    + +
    [docs] def decode_gmcp(self, data): + """ + Decodes incoming GMCP data on the form 'varname <structure>'. + + Args: + data (str or list): GMCP data. + + Notes: + Clients send data on the form "Module.Submodule.Cmdname <structure>". + We assume the structure is valid JSON. + + The following is parsed into Evennia's formal structure: + :: + + Core.Name -> [name, [], {}] + Core.Name string -> [name, [string], {}] + Core.Name [arg, arg,...] -> [name, [args], {}] + Core.Name {key:arg, key:arg, ...} -> [name, [], {kwargs}] + Core.Name [[args], {kwargs}] -> [name, [args], {kwargs}] + + """ + if isinstance(data, list): + data = b"".join(data) + + # print("decode_gmcp in:", data) # DEBUG + if data: + try: + cmdname, structure = data.split(None, 1) + except ValueError: + cmdname, structure = data, b"" + cmdname = cmdname.replace(b".", b"_") + try: + structure = json.loads(structure) + except ValueError: + # maybe the structure is not json-serialized at all + pass + args, kwargs = [], {} + if is_iter(structure): + if isinstance(structure, dict): + kwargs = {key: value for key, value in structure.items() if key} + else: + args = list(structure) + else: + args = (structure,) + if cmdname.lower().startswith(b"core_"): + # if Core.cmdname, then use cmdname + cmdname = cmdname[5:] + self.protocol.data_in(**{cmdname.lower().decode(): [args, kwargs]})
    + + # access methods + +
    [docs] def data_out(self, cmdname, *args, **kwargs): + """ + Return a MSDP- or GMCP-valid subnegotiation across the protocol. + + Args: + cmdname (str): OOB-command name. + args, kwargs (any): Arguments to OOB command. + + """ + kwargs.pop("options", None) + + if self.MSDP: + encoded_oob = self.encode_msdp(cmdname, *args, **kwargs) + self.protocol._write(IAC + SB + MSDP + encoded_oob + IAC + SE) + + if self.GMCP: + encoded_oob = self.encode_gmcp(cmdname, *args, **kwargs) + self.protocol._write(IAC + SB + GMCP + encoded_oob + IAC + SE)
    +
    + +
    +
    +
    +
    + +
    +
    + + + + \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/telnet_ssl.html b/docs/0.9.5/_modules/evennia/server/portal/telnet_ssl.html new file mode 100644 index 0000000000..1fe05fc8af --- /dev/null +++ b/docs/0.9.5/_modules/evennia/server/portal/telnet_ssl.html @@ -0,0 +1,255 @@ + + + + + + + + evennia.server.portal.telnet_ssl — Evennia 0.9.5 documentation + + + + + + + + + + + + + +
    +
    +
    +
    + +

    Source code for evennia.server.portal.telnet_ssl

    +"""
    +This allows for running the telnet communication over an encrypted SSL tunnel. To use it, requires a
    +client supporting Telnet SSL.
    +
    +The protocol will try to automatically create the private key and certificate on the server side
    +when starting and will warn if this was not possible. These will appear as files ssl.key and
    +ssl.cert in mygame/server/.
    +
    +"""
    +import os
    +
    +try:
    +    from OpenSSL import crypto
    +    from twisted.internet import ssl as twisted_ssl
    +except ImportError as error:
    +    errstr = """
    +    {err}
    +    Telnet-SSL requires the PyOpenSSL library and dependencies:
    +
    +        pip install pyopenssl pycrypto enum pyasn1 service_identity
    +
    +    Stop and start Evennia again. If no certificate can be generated, you'll
    +    get a suggestion for a (linux) command to generate this locally.
    +
    +    """
    +    raise ImportError(errstr.format(err=error))
    +
    +from django.conf import settings
    +from evennia.server.portal.telnet import TelnetProtocol
    +
    +_GAME_DIR = settings.GAME_DIR
    +
    +_PRIVATE_KEY_LENGTH = 2048
    +_PRIVATE_KEY_FILE = os.path.join(_GAME_DIR, "server", "ssl.key")
    +_PUBLIC_KEY_FILE = os.path.join(_GAME_DIR, "server", "ssl-public.key")
    +_CERTIFICATE_FILE = os.path.join(_GAME_DIR, "server", "ssl.cert")
    +_CERTIFICATE_EXPIRE = 365 * 24 * 60 * 60 * 20  # 20 years
    +_CERTIFICATE_ISSUER = {
    +    "C": "EV",
    +    "ST": "Evennia",
    +    "L": "Evennia",
    +    "O": "Evennia Security",
    +    "OU": "Evennia Department",
    +    "CN": "evennia",
    +}
    +
    +# messages
    +
    +NO_AUTOGEN = f"""
    +Evennia could not auto-generate the SSL private- and public keys ({{err}}).
    +If this error persists, create them manually (using the tools for your OS). The files
    +should be placed and named like this:
    +    {_PRIVATE_KEY_FILE}
    +    {_PUBLIC_KEY_FILE}
    +"""
    +
    +NO_AUTOCERT = """
    +Evennia's could not auto-generate the SSL certificate ({{err}}).
    +The private key already exists here:
    +    {_PRIVATE_KEY_FILE}
    +If this error persists, create the certificate manually (using the private key and
    +the tools for your OS). The file should be placed and named like this:
    +    {_CERTIFICATE_FILE}
    +"""
    +
    +
    +
    [docs]class SSLProtocol(TelnetProtocol): + """ + Communication is the same as telnet, except data transfer + is done with encryption set up by the portal at start time. + + """ + +
    [docs] def __init__(self, *args, **kwargs): + super(SSLProtocol, self).__init__(*args, **kwargs) + self.protocol_key = "telnet/ssl"
    + + +
    [docs]def verify_or_create_SSL_key_and_cert(keyfile, certfile): + """ + Verify or create new key/certificate files. + + Args: + keyfile (str): Path to ssl.key file. + certfile (str): Parth to ssl.cert file. + + Notes: + If files don't already exist, they are created. + + """ + + if not (os.path.exists(keyfile) and os.path.exists(certfile)): + # key/cert does not exist. Create. + try: + # generate the keypair + keypair = crypto.PKey() + keypair.generate_key(crypto.TYPE_RSA, _PRIVATE_KEY_LENGTH) + + with open(_PRIVATE_KEY_FILE, "wt") as pfile: + pfile.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, keypair).decode("utf-8")) + print("Created SSL private key in '{}'.".format(_PRIVATE_KEY_FILE)) + + with open(_PUBLIC_KEY_FILE, "wt") as pfile: + pfile.write(crypto.dump_publickey(crypto.FILETYPE_PEM, keypair).decode("utf-8")) + print("Created SSL public key in '{}'.".format(_PUBLIC_KEY_FILE)) + + except Exception as err: + print(NO_AUTOGEN.format(err=err)) + return False + + else: + + try: + # create certificate + cert = crypto.X509() + subj = cert.get_subject() + for key, value in _CERTIFICATE_ISSUER.items(): + setattr(subj, key, value) + cert.set_issuer(subj) + + cert.set_serial_number(1000) + cert.gmtime_adj_notBefore(0) + cert.gmtime_adj_notAfter(_CERTIFICATE_EXPIRE) + cert.set_pubkey(keypair) + cert.sign(keypair, "sha1") + + with open(_CERTIFICATE_FILE, "wt") as cfile: + cfile.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert).decode("utf-8")) + print("Created SSL certificate in '{}'.".format(_CERTIFICATE_FILE)) + + except Exception as err: + print(NO_AUTOCERT.format(err=err)) + return False + + return True
    + + +
    [docs]def getSSLContext(): + """ + This is called by the portal when creating the SSL context + server-side. + + Returns: + ssl_context (tuple): A key and certificate that is either + existing previously or created on the fly. + + """ + + if verify_or_create_SSL_key_and_cert(_PRIVATE_KEY_FILE, _CERTIFICATE_FILE): + return twisted_ssl.DefaultOpenSSLContextFactory(_PRIVATE_KEY_FILE, _CERTIFICATE_FILE) + else: + return None
    +
    + +
    +
    +
    +
    + +
    +
    + + + + \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/tests.html b/docs/0.9.5/_modules/evennia/server/portal/tests.html new file mode 100644 index 0000000000..d1f4ee6389 --- /dev/null +++ b/docs/0.9.5/_modules/evennia/server/portal/tests.html @@ -0,0 +1,424 @@ + + + + + + + + evennia.server.portal.tests — Evennia 0.9.5 documentation + + + + + + + + + + + + + +
    +
    +
    +
    + +

    Source code for evennia.server.portal.tests

    +try:
    +    from django.utils.unittest import TestCase
    +except ImportError:
    +    from django.test import TestCase
    +
    +try:
    +    from django.utils import unittest
    +except ImportError:
    +    import unittest
    +
    +import sys
    +import string
    +import mock
    +import pickle
    +import json
    +
    +from mock import Mock, MagicMock
    +from evennia.server.portal import irc
    +from evennia.utils.test_resources import EvenniaTest
    +
    +from twisted.conch.telnet import IAC, WILL, DONT, SB, SE, NAWS, DO
    +from twisted.test import proto_helpers
    +from twisted.trial.unittest import TestCase as TwistedTestCase
    +from twisted.internet.base import DelayedCall
    +
    +from .telnet import TelnetServerFactory, TelnetProtocol
    +from .portal import PORTAL_SESSIONS
    +from .suppress_ga import SUPPRESS_GA
    +from .naws import DEFAULT_HEIGHT, DEFAULT_WIDTH
    +from .ttype import TTYPE, IS
    +from .mccp import MCCP
    +from .mssp import MSSP
    +from .mxp import MXP
    +from .telnet_oob import MSDP, MSDP_VAL, MSDP_VAR
    +
    +from .amp import AMPMultiConnectionProtocol, MsgServer2Portal, MsgPortal2Server, AMP_MAXLEN
    +from .amp_server import AMPServerFactory
    +
    +from autobahn.twisted.websocket import WebSocketServerFactory
    +from .webclient import WebSocketClient
    +
    +
    +
    [docs]class TestAMPServer(TwistedTestCase): + """ + Test AMP communication + """ + +
    [docs] def setUp(self): + super(TestAMPServer, self).setUp() + portal = Mock() + factory = AMPServerFactory(portal) + self.proto = factory.buildProtocol(("localhost", 0)) + self.transport = MagicMock() # proto_helpers.StringTransport() + self.transport.client = ["localhost"] + self.transport.write = MagicMock()
    + +
    [docs] def test_amp_out(self): + self.proto.makeConnection(self.transport) + + self.proto.data_to_server(MsgServer2Portal, 1, test=2) + + if pickle.HIGHEST_PROTOCOL == 5: + # Python 3.8+ + byte_out = ( + b"\x00\x04_ask\x00\x011\x00\x08_command\x00\x10MsgServer2Portal\x00\x0b" + b"packed_data\x00 x\xdak`\x9d*\xc8\x00\x01\xde\x8c\xb5SzXJR" + b"\x8bK\xa6x3\x15\xb7M\xd1\x03\x00VU\x07u\x00\x00" + ) + elif pickle.HIGHEST_PROTOCOL == 4: + # Python 3.7 + byte_out = ( + b"\x00\x04_ask\x00\x011\x00\x08_command\x00\x10MsgServer2Portal\x00\x0b" + b"packed_data\x00 x\xdak`\x99*\xc8\x00\x01\xde\x8c\xb5SzXJR" + b"\x8bK\xa6x3\x15\xb7M\xd1\x03\x00V:\x07t\x00\x00" + ) + self.transport.write.assert_called_with(byte_out) + with mock.patch("evennia.server.portal.amp.amp.AMP.dataReceived") as mocked_amprecv: + self.proto.dataReceived(byte_out) + mocked_amprecv.assert_called_with(byte_out)
    + +
    [docs] def test_amp_in(self): + self.proto.makeConnection(self.transport) + + self.proto.data_to_server(MsgPortal2Server, 1, test=2) + if pickle.HIGHEST_PROTOCOL == 5: + # Python 3.8+ + byte_out = ( + b"\x00\x04_ask\x00\x011\x00\x08_command\x00\x10MsgPortal2Server\x00\x0b" + b"packed_data\x00 x\xdak`\x9d*\xc8\x00\x01\xde\x8c\xb5SzXJR" + b"\x8bK\xa6x3\x15\xb7M\xd1\x03\x00VU\x07u\x00\x00" + ) + elif pickle.HIGHEST_PROTOCOL == 4: + # Python 3.7 + byte_out = ( + b"\x00\x04_ask\x00\x011\x00\x08_command\x00\x10MsgPortal2Server\x00\x0b" + b"packed_data\x00 x\xdak`\x99*\xc8\x00\x01\xde\x8c\xb5SzXJR" + b"\x8bK\xa6x3\x15\xb7M\xd1\x03\x00V:\x07t\x00\x00" + ) + self.transport.write.assert_called_with(byte_out) + with mock.patch("evennia.server.portal.amp.amp.AMP.dataReceived") as mocked_amprecv: + self.proto.dataReceived(byte_out) + mocked_amprecv.assert_called_with(byte_out)
    + +
    [docs] def test_large_msg(self): + """ + Send message larger than AMP_MAXLEN - should be split into several + """ + self.proto.makeConnection(self.transport) + outstr = "test" * AMP_MAXLEN + self.proto.data_to_server(MsgServer2Portal, 1, test=outstr) + + if pickle.HIGHEST_PROTOCOL == 5: + # Python 3.8+ + self.transport.write.assert_called_with( + b"\x00\x04_ask\x00\x011\x00\x08_command\x00\x10MsgServer2Portal\x00\x0bpacked_data" + b"\x00wx\xda\xed\xc6\xc1\t\x80 \x00@Q#=5Z\x0b\xb8\x80\x13\xe85h\x80\x8e\xbam`Dc\xf4><\xf8g" + b"\x1a[\xf8\xda\x97\xa3_\xb1\x95\xdaz\xbe\xe7\x1a\xde\x03\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x1f\x1eP\x1d\x02\r\x00\rpacked_data.2" + b"\x00Zx\xda\xed\xc3\x01\r\x00\x00\x08\xc0\xa0\xb4&\xf0\xfdg\x10a\xa3" + b"\xd9RUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU\xf5\xfb\x03m\xe0\x06" + b"\x1d\x00\rpacked_data.3\x00Zx\xda\xed\xc3\x01\r\x00\x00\x08\xc0\xa0\xb4&\xf0\xfdg\x10a" + b"\xa3fSUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU\xf5\xfb\x03n\x1c" + b"\x06\x1e\x00\rpacked_data.4\x00Zx\xda\xed\xc3\x01\t\x00\x00\x0c\x03\xa0\xb4O\xb0\xf5gA" + b"\xae`\xda\x8b\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + b"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + b"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + b"\xaa\xaa\xaa\xdf\x0fnI\x06,\x00\rpacked_data.5\x00\x18x\xdaK-.)I\xc5\x8e\xa7\xb22@\xc0" + b"\x94\xe2\xb6)z\x00Z\x1e\x0e\xb6\x00\x00" + ) + elif pickle.HIGHEST_PROTOCOL == 4: + # Python 3.7 + self.transport.write.assert_called_with( + b"\x00\x04_ask\x00\x011\x00\x08_command\x00\x10MsgServer2Portal\x00\x0bpacked_data" + b"\x00wx\xda\xed\xc6\xc1\t\x80 \x00@Q#o\x8e\xd6\x02-\xe0\x04z\r\x1a\xa0\xa3m+$\xd2" + b"\x18\xbe\x0f\x0f\xfe\x1d\xdf\x14\xfe\x8e\xedjO\xac\xb9\xd4v\xf6o\x0f\xf3\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00X\xc3\x00P\x10\x02\x0c\x00\rpacked_data.2\x00Zx\xda\xed\xc3\x01\r\x00\x00\x08" + b"\xc0\xa0\xb4&\xf0\xfdg\x10a\xa3\xd9RUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU" + b"\xf5\xfb\x03m\xe0\x06\x1d\x00\rpacked_data.3\x00Zx\xda\xed\xc3\x01\r\x00\x00\x08" + b"\xc0\xa0\xb4&\xf0\xfdg\x10a\xa3fSUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU" + b"\xf5\xfb\x03n\x1c\x06\x1e\x00\rpacked_data.4\x00Zx\xda\xed\xc3\x01\t\x00\x00\x0c" + b"\x03\xa0\xb4O\xb0\xf5gA\xae`\xda\x8b\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + b"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + b"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + b"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xdf\x0fnI\x06,\x00\rpacked_data.5" + b"\x00\x18x\xdaK-.)I\xc5\x8e\xa7\xb22@\xc0\x94\xe2\xb6)z\x00Z\x1e\x0e\xb6\x00\x00" + )
    + + +
    [docs]class TestIRC(TestCase): +
    [docs] def test_plain_ansi(self): + """ + Test that printable characters do not get mangled. + """ + irc_ansi = irc.parse_ansi_to_irc(string.printable) + ansi_irc = irc.parse_irc_to_ansi(string.printable) + self.assertEqual(irc_ansi, string.printable) + self.assertEqual(ansi_irc, string.printable)
    + +
    [docs] def test_bold(self): + s_irc = "\x02thisisatest" + s_eve = r"|hthisisatest" + self.assertEqual(irc.parse_ansi_to_irc(s_eve), s_irc) + self.assertEqual(s_eve, irc.parse_irc_to_ansi(s_irc))
    + +
    [docs] def test_italic(self): + s_irc = "\x02thisisatest" + s_eve = r"|hthisisatest" + self.assertEqual(irc.parse_ansi_to_irc(s_eve), s_irc)
    + +
    [docs] def test_colors(self): + color_map = ( + ("\0030", r"|w"), + ("\0031", r"|X"), + ("\0032", r"|B"), + ("\0033", r"|G"), + ("\0034", r"|r"), + ("\0035", r"|R"), + ("\0036", r"|M"), + ("\0037", r"|Y"), + ("\0038", r"|y"), + ("\0039", r"|g"), + ("\00310", r"|C"), + ("\00311", r"|c"), + ("\00312", r"|b"), + ("\00313", r"|m"), + ("\00314", r"|x"), + ("\00315", r"|W"), + ("\00399,5", r"|[r"), + ("\00399,3", r"|[g"), + ("\00399,7", r"|[y"), + ("\00399,2", r"|[b"), + ("\00399,6", r"|[m"), + ("\00399,10", r"|[c"), + ("\00399,15", r"|[w"), + ("\00399,1", r"|[x"), + ) + + for m in color_map: + self.assertEqual(irc.parse_irc_to_ansi(m[0]), m[1]) + self.assertEqual(m[0], irc.parse_ansi_to_irc(m[1]))
    + +
    [docs] def test_identity(self): + """ + Test that the composition of the function and + its inverse gives the correct string. + """ + + s = r"|wthis|Xis|gis|Ma|C|complex|*string" + + self.assertEqual(irc.parse_irc_to_ansi(irc.parse_ansi_to_irc(s)), s)
    + + +
    [docs]class TestTelnet(TwistedTestCase): +
    [docs] def setUp(self): + super(TestTelnet, self).setUp() + factory = TelnetServerFactory() + factory.protocol = TelnetProtocol + factory.sessionhandler = PORTAL_SESSIONS + factory.sessionhandler.portal = Mock() + self.proto = factory.buildProtocol(("localhost", 0)) + self.transport = proto_helpers.StringTransport() + self.addCleanup(factory.sessionhandler.disconnect_all)
    + +
    [docs] @mock.patch("evennia.server.portal.portalsessionhandler.reactor", new=MagicMock()) + def test_mudlet_ttype(self): + self.transport.client = ["localhost"] + self.transport.setTcpKeepAlive = Mock() + d = self.proto.makeConnection(self.transport) + # test suppress_ga + self.assertTrue(self.proto.protocol_flags["NOGOAHEAD"]) + self.proto.dataReceived(IAC + DONT + SUPPRESS_GA) + self.assertFalse(self.proto.protocol_flags["NOGOAHEAD"]) + self.assertEqual(self.proto.handshakes, 7) + # test naws + self.assertEqual(self.proto.protocol_flags["SCREENWIDTH"], {0: DEFAULT_WIDTH}) + self.assertEqual(self.proto.protocol_flags["SCREENHEIGHT"], {0: DEFAULT_HEIGHT}) + self.proto.dataReceived(IAC + WILL + NAWS) + self.proto.dataReceived(b"".join([IAC, SB, NAWS, b"", b"x", b"", b"d", IAC, SE])) + self.assertEqual(self.proto.protocol_flags["SCREENWIDTH"][0], 78) + self.assertEqual(self.proto.protocol_flags["SCREENHEIGHT"][0], 45) + self.assertEqual(self.proto.handshakes, 6) + # test ttype + self.assertFalse(self.proto.protocol_flags["TTYPE"]) + self.assertTrue(self.proto.protocol_flags["ANSI"]) + self.proto.dataReceived(IAC + WILL + TTYPE) + self.proto.dataReceived(b"".join([IAC, SB, TTYPE, IS, b"MUDLET", IAC, SE])) + self.assertTrue(self.proto.protocol_flags["XTERM256"]) + self.assertEqual(self.proto.protocol_flags["CLIENTNAME"], "MUDLET") + self.assertTrue(self.proto.protocol_flags["FORCEDENDLINE"]) + self.assertTrue(self.proto.protocol_flags["NOGOAHEAD"]) + self.assertFalse(self.proto.protocol_flags["NOPROMPTGOAHEAD"]) + self.proto.dataReceived(b"".join([IAC, SB, TTYPE, IS, b"XTERM", IAC, SE])) + self.proto.dataReceived(b"".join([IAC, SB, TTYPE, IS, b"MTTS 137", IAC, SE])) + self.assertEqual(self.proto.handshakes, 5) + # test mccp + self.proto.dataReceived(IAC + DONT + MCCP) + self.assertFalse(self.proto.protocol_flags["MCCP"]) + self.assertEqual(self.proto.handshakes, 4) + # test mssp + self.proto.dataReceived(IAC + DONT + MSSP) + self.assertEqual(self.proto.handshakes, 3) + # test oob + self.proto.dataReceived(IAC + DO + MSDP) + self.proto.dataReceived( + b"".join([IAC, SB, MSDP, MSDP_VAR, b"LIST", MSDP_VAL, b"COMMANDS", IAC, SE]) + ) + self.assertTrue(self.proto.protocol_flags["OOB"]) + self.assertEqual(self.proto.handshakes, 2) + # test mxp + self.proto.dataReceived(IAC + DONT + MXP) + self.assertFalse(self.proto.protocol_flags["MXP"]) + self.assertEqual(self.proto.handshakes, 1) + # clean up to prevent Unclean reactor + self.proto.nop_keep_alive.stop() + self.proto._handshake_delay.cancel() + return d
    + + +
    [docs]class TestWebSocket(EvenniaTest): +
    [docs] def setUp(self): + super().setUp() + self.proto = WebSocketClient() + self.proto.factory = WebSocketServerFactory() + self.proto.factory.sessionhandler = PORTAL_SESSIONS + self.proto.sessionhandler = PORTAL_SESSIONS + self.proto.sessionhandler.portal = Mock() + self.proto.transport = proto_helpers.StringTransport() + # self.proto.transport = proto_helpers.FakeDatagramTransport() + self.proto.transport.client = ["localhost"] + self.proto.transport.setTcpKeepAlive = Mock() + self.proto.state = MagicMock() + self.addCleanup(self.proto.factory.sessionhandler.disconnect_all) + DelayedCall.debug = True
    + +
    [docs] def tearDown(self): + super().tearDown()
    + +
    [docs] @mock.patch("evennia.server.portal.portalsessionhandler.reactor", new=MagicMock()) + def test_data_in(self): + self.proto.sessionhandler.data_in = MagicMock() + self.proto.onOpen() + msg = json.dumps(["logged_in", (), {}]).encode() + self.proto.onMessage(msg, isBinary=False) + self.proto.sessionhandler.data_in.assert_called_with(self.proto, logged_in=[[], {}]) + sendStr = "You can get anything you want at Alice's Restaurant." + msg = json.dumps(["text", (sendStr,), {}]).encode() + self.proto.onMessage(msg, isBinary=False) + self.proto.sessionhandler.data_in.assert_called_with(self.proto, text=[[sendStr], {}])
    + +
    [docs] @mock.patch("evennia.server.portal.portalsessionhandler.reactor", new=MagicMock()) + def test_data_out(self): + self.proto.onOpen() + self.proto.sendLine = MagicMock() + msg = json.dumps(["logged_in", (), {}]) + self.proto.sessionhandler.data_out(self.proto, text=[["Excepting Alice"], {}]) + self.proto.sendLine.assert_called_with(json.dumps(["text", ["Excepting Alice"], {}]))
    +
    + +
    +
    +
    +
    + +
    +
    + + + + \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/ttype.html b/docs/0.9.5/_modules/evennia/server/portal/ttype.html new file mode 100644 index 0000000000..b00daab663 --- /dev/null +++ b/docs/0.9.5/_modules/evennia/server/portal/ttype.html @@ -0,0 +1,290 @@ + + + + + + + + evennia.server.portal.ttype — Evennia 0.9.5 documentation + + + + + + + + + + + + + +
    +
    +
    +
    + +

    Source code for evennia.server.portal.ttype

    +"""
    +TTYPE (MTTS) - Mud Terminal Type Standard
    +
    +This module implements the TTYPE telnet protocol as per
    +http://tintin.sourceforge.net/mtts/. It allows the server to ask the
    +client about its capabilities. If the client also supports TTYPE, it
    +will return with information such as its name, if it supports colour
    +etc. If the client does not support TTYPE, this will be ignored.
    +
    +All data will be stored on the protocol's protocol_flags dictionary,
    +under the 'TTYPE' key.
    +
    +"""
    +
    +# telnet option codes
    +TTYPE = bytes([24])  # b"\x18"
    +IS = bytes([0])  # b"\x00"
    +SEND = bytes([1])  # b"\x01"
    +
    +# terminal capabilities and their codes
    +MTTS = [
    +    (128, "PROXY"),
    +    (64, "SCREENREADER"),
    +    (32, "OSC_COLOR_PALETTE"),
    +    (16, "MOUSE_TRACKING"),
    +    (8, "XTERM256"),
    +    (4, "UTF-8"),
    +    (2, "VT100"),
    +    (1, "ANSI"),
    +]
    +
    +
    +
    [docs]class Ttype: + """ + Handles ttype negotiations. Called and initiated by the + telnet protocol. + + """ + +
    [docs] def __init__(self, protocol): + """ + Initialize ttype by storing protocol on ourselves and calling + the client to see if it supporst ttype. + + Args: + protocol (Protocol): The protocol instance. + + Notes: + The `self.ttype_step` indicates how far in the data + retrieval we've gotten. + + """ + self.ttype_step = 0 + self.protocol = protocol + # we set FORCEDENDLINE for clients not supporting ttype + self.protocol.protocol_flags["FORCEDENDLINE"] = True + self.protocol.protocol_flags["TTYPE"] = False + # is it a safe bet to assume ANSI is always supported? + self.protocol.protocol_flags["ANSI"] = True + # setup protocol to handle ttype initialization and negotiation + self.protocol.negotiationMap[TTYPE] = self.will_ttype + # ask if client will ttype, connect callback if it does. + self.protocol.do(TTYPE).addCallbacks(self.will_ttype, self.wont_ttype)
    + +
    [docs] def wont_ttype(self, option): + """ + Callback if ttype is not supported by client. + + Args: + option (Option): Not used. + + """ + self.protocol.protocol_flags["TTYPE"] = False + self.protocol.handshake_done()
    + +
    [docs] def will_ttype(self, option): + """ + Handles negotiation of the ttype protocol once the client has + confirmed that it will respond with the ttype protocol. + + Args: + option (Option): Not used. + + Notes: + The negotiation proceeds in several steps, each returning a + certain piece of information about the client. All data is + stored on protocol.protocol_flags under the TTYPE key. + + """ + options = self.protocol.protocol_flags + + if options and options.get("TTYPE", False) or self.ttype_step > 3: + return + + try: + option = b"".join(option).lstrip(IS).decode() + except TypeError: + # option is not on a suitable form for joining + pass + + if self.ttype_step == 0: + # just start the request chain + self.protocol.requestNegotiation(TTYPE, SEND) + + elif self.ttype_step == 1: + # this is supposed to be the name of the client/terminal. + # For clients not supporting the extended TTYPE + # definition, subsequent calls will just repeat-return this. + try: + clientname = option.upper() + except AttributeError: + # malformed option (not a string) + clientname = "UNKNOWN" + + # use name to identify support for xterm256. Many of these + # only support after a certain version, but all support + # it since at least 4 years. We assume recent client here for now. + xterm256 = False + if clientname.startswith("MUDLET"): + # supports xterm256 stably since 1.1 (2010?) + xterm256 = clientname.split("MUDLET", 1)[1].strip() >= "1.1" + # Mudlet likes GA's on a prompt line for the prompt trigger to + # match, if it's not wanting NOGOAHEAD. + if not self.protocol.protocol_flags["NOGOAHEAD"]: + self.protocol.protocol_flags["NOGOAHEAD"] = True + self.protocol.protocol_flags["NOPROMPTGOAHEAD"] = False + + if ( + clientname.startswith("XTERM") + or clientname.endswith("-256COLOR") + or clientname + in ( + "ATLANTIS", # > 0.9.9.0 (aug 2009) + "CMUD", # > 3.04 (mar 2009) + "KILDCLIENT", # > 2.2.0 (sep 2005) + "MUDLET", # > beta 15 (sep 2009) + "MUSHCLIENT", # > 4.02 (apr 2007) + "PUTTY", # > 0.58 (apr 2005) + "BEIP", # > 2.00.206 (late 2009) (BeipMu) + "POTATO", # > 2.00 (maybe earlier) + "TINYFUGUE", # > 4.x (maybe earlier) + ) + ): + xterm256 = True + + # all clients supporting TTYPE at all seem to support ANSI + self.protocol.protocol_flags["ANSI"] = True + self.protocol.protocol_flags["XTERM256"] = xterm256 + self.protocol.protocol_flags["CLIENTNAME"] = clientname + self.protocol.requestNegotiation(TTYPE, SEND) + + elif self.ttype_step == 2: + # this is a term capabilities flag + term = option + tupper = term.upper() + # identify xterm256 based on flag + xterm256 = ( + tupper.endswith("-256COLOR") + or tupper.endswith("XTERM") # Apple Terminal, old Tintin + and not tupper.endswith("-COLOR") # old Tintin, Putty + ) + if xterm256: + self.protocol.protocol_flags["ANSI"] = True + self.protocol.protocol_flags["XTERM256"] = xterm256 + self.protocol.protocol_flags["TERM"] = term + # request next information + self.protocol.requestNegotiation(TTYPE, SEND) + + elif self.ttype_step == 3: + # the MTTS bitstring identifying term capabilities + if option.startswith("MTTS"): + option = option[4:].strip() + if option.isdigit(): + # a number - determine the actual capabilities + option = int(option) + support = dict( + (capability, True) for bitval, capability in MTTS if option & bitval > 0 + ) + self.protocol.protocol_flags.update(support) + else: + # some clients send erroneous MTTS as a string. Add directly. + self.protocol.protocol_flags[option.upper()] = True + + self.protocol.protocol_flags["TTYPE"] = True + # we must sync ttype once it'd done + self.protocol.handshake_done() + self.ttype_step += 1
    +
    + +
    +
    +
    +
    + +
    +
    + + + + \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/webclient.html b/docs/0.9.5/_modules/evennia/server/portal/webclient.html index cb67ab8f87..f58ab9885a 100644 --- a/docs/0.9.5/_modules/evennia/server/portal/webclient.html +++ b/docs/0.9.5/_modules/evennia/server/portal/webclient.html @@ -58,10 +58,8 @@ import re import json import html -from twisted.internet.protocol import Protocol from django.conf import settings -from evennia.server.session import Session -from evennia.utils.utils import to_str, mod_import +from evennia.utils.utils import mod_import, class_from_module from evennia.utils.ansi import parse_ansi from evennia.utils.text2html import parse_html from autobahn.twisted.websocket import WebSocketServerProtocol @@ -81,12 +79,13 @@ # called when the browser is navigating away from the page GOING_AWAY = WebSocketServerProtocol.CLOSE_STATUS_CODE_GOING_AWAY -STATE_CLOSING = WebSocketServerProtocol.STATE_CLOSING +_BASE_SESSION_CLASS = class_from_module(settings.BASE_SESSION_CLASS) -
    [docs]class WebSocketClient(WebSocketServerProtocol, Session): +
    [docs]class WebSocketClient(WebSocketServerProtocol, _BASE_SESSION_CLASS): """ Implements the server-side of the Websocket connection. + """ # nonce value, used to prevent the webclient from erasing the @@ -198,7 +197,7 @@ # in case anyone wants to expose this functionality later. # # sendClose() under autobahn/websocket/interfaces.py - ret = self.sendClose(CLOSE_NORMAL, reason)
    + self.sendClose(CLOSE_NORMAL, reason)
    [docs] def onClose(self, wasClean, code=None, reason=None): """ @@ -302,8 +301,6 @@ return else: return - # just to be sure - text = to_str(text) flags = self.protocol_flags @@ -387,7 +384,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/portal/webclient_ajax.html b/docs/0.9.5/_modules/evennia/server/portal/webclient_ajax.html index b88d29992c..e2b6ea1e90 100644 --- a/docs/0.9.5/_modules/evennia/server/portal/webclient_ajax.html +++ b/docs/0.9.5/_modules/evennia/server/portal/webclient_ajax.html @@ -56,6 +56,7 @@ The WebClient resource in this module will handle these requests and act as a gateway to sessions connected over the webclient. + """ import json import re @@ -68,7 +69,7 @@ from django.conf import settings from evennia.utils.ansi import parse_ansi from evennia.utils import utils -from evennia.utils.utils import to_bytes, to_str +from evennia.utils.utils import to_bytes from evennia.utils.text2html import parse_html from evennia.server import session @@ -264,10 +265,13 @@ return jsonify({"msg": host_string, "csessid": csessid})
    [docs] def mode_keepalive(self, request): - """ This is called by render_POST when the client is replying to the keepalive. + + Args: + request (Request): Incoming request. + """ csessid = self.get_client_sessid(request) self.last_alive[csessid] = (time.time(), False) @@ -543,7 +547,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/profiling/dummyrunner.html b/docs/0.9.5/_modules/evennia/server/profiling/dummyrunner.html index d60724411d..7ee582c81c 100644 --- a/docs/0.9.5/_modules/evennia/server/profiling/dummyrunner.html +++ b/docs/0.9.5/_modules/evennia/server/profiling/dummyrunner.html @@ -81,8 +81,16 @@ from twisted.internet import reactor, protocol from twisted.internet.task import LoopingCall -from django.conf import settings -from evennia.utils import mod_import, time_format +import django +django.setup() +import evennia # noqa +evennia._init() + +from django.conf import settings # noqa +from evennia.utils import mod_import, time_format # noqa +from evennia.commands.command import Command # noqa +from evennia.commands.cmdset import CmdSet # noqa +from evennia.utils.ansi import strip_ansi # noqa # Load the dummyrunner settings module @@ -92,8 +100,10 @@ "Error: Dummyrunner could not find settings file at %s" % settings.DUMMYRUNNER_SETTINGS_MODULE ) +IDMAPPER_CACHE_MAXSIZE = settings.IDMAPPER_CACHE_MAXSIZE DATESTRING = "%Y%m%d%H%M%S" +CLIENTS = [] # Settings @@ -112,18 +122,37 @@ # Port to use, if not specified on command line TELNET_PORT = DUMMYRUNNER_SETTINGS.TELNET_PORT or settings.TELNET_PORTS[0] # -NLOGGED_IN = 0 +NCONNECTED = 0 # client has received a connection +NLOGIN_SCREEN = 0 # client has seen the login screen (server responded) +NLOGGING_IN = 0 # client starting login procedure +NLOGGED_IN = 0 # client has authenticated and logged in - -# Messages +# time when all clients have logged_in +TIME_ALL_LOGIN = 0 +# actions since all logged in +TOTAL_ACTIONS = 0 +TOTAL_LAG_MEASURES = 0 +# lag per 30s for all logged in +TOTAL_LAG = 0 +TOTAL_LAG_IN = 0 +TOTAL_LAG_OUT = 0 INFO_STARTING = """ - Dummyrunner starting using {N} dummy account(s). If you don't see + Dummyrunner starting using {nclients} dummy account(s). If you don't see any connection messages, make sure that the Evennia server is running. - Use Ctrl-C to stop/disconnect clients. + TELNET_PORT = {port} + IDMAPPER_CACHE_MAXSIZE = {idmapper_cache_size} MB + TIMESTEP = {timestep} (rate {rate}/s) + CHANCE_OF_LOGIN = {chance_of_login}% per time step + CHANCE_OF_ACTION = {chance_of_action}% per time step + -> avg rate (per client, after login): {avg_rate} cmds/s + -> total avg rate (after login): {avg_rate_total} cmds/s + + Use Ctrl-C (or Cmd-C) to stop/disconnect all clients. + """ ERROR_NO_MIXIN = """ @@ -138,6 +167,7 @@ to test all commands - change PASSWORD_HASHERS to use a faster (but less safe) algorithm when creating large numbers of accounts at the same time + - set LOGIN_THROTTLE/CREATION_THROTTLE=None to disable it If you don't want to use the custom settings of the mixin for some reason, you can change their values manually after the import, or @@ -209,6 +239,39 @@ """ + +
    [docs]class CmdDummyRunnerEchoResponse(Command): + """ + Dummyrunner command measuring the round-about response time + from sending to receiving a result. + + Usage: + dummyrunner_echo_response <timestamp> + + Responds with + dummyrunner_echo_response:<timestamp>,<current_time> + + The dummyrunner will send this and then compare the send time + with the receive time on both ends. + + """ + key = "dummyrunner_echo_response" + +
    [docs] def func(self): + # returns (dummy_client_timestamp,current_time) + self.msg(f"dummyrunner_echo_response:{self.args},{time.time()}") + if self.caller.account.is_superuser: + print(f"cmddummyrunner lag in: {time.time() - float(self.args)}s")
    + + +
    [docs]class DummyRunnerCmdSet(CmdSet): + """ + Dummyrunner injected cmdset. + + """ +
    [docs] def at_cmdset_creation(self): + self.add(CmdDummyRunnerEchoResponse())
    + # ------------------------------------------------------------ # Helper functions # ------------------------------------------------------------ @@ -222,12 +285,12 @@ Makes unique ids. Returns: - count (int): A globally unique counter. + str: A globally unique id. """ global ICOUNT ICOUNT += 1 - return str(ICOUNT) + return str("{:03d}".format(ICOUNT)) GCOUNT = 0 @@ -243,7 +306,7 @@ """ global GCOUNT GCOUNT += 1 - return "%s-%s" % (time.strftime(DATESTRING), GCOUNT) + return "%s_%s" % (time.strftime(DATESTRING), GCOUNT)
    [docs]def makeiter(obj): @@ -263,7 +326,6 @@ # Client classes # ------------------------------------------------------------ -
    [docs]class DummyClient(telnet.StatefulTelnetProtocol): """ Handles connection to a running Evennia server, @@ -272,29 +334,80 @@ """ +
    [docs] def report(self, text, clientkey): + pad = " " * (25 - len(text)) + tim = round(time.time() - self.connection_timestamp) + print(f"{text} {clientkey}{pad}\t" + f"conn: {NCONNECTED} -> " + f"welcome screen: {NLOGIN_SCREEN} -> " + f"authing: {NLOGGING_IN} -> " + f"loggedin/tot: {NLOGGED_IN}/{NCLIENTS} (after {tim}s)")
    +
    [docs] def connectionMade(self): """ Called when connection is first established. """ + global NCONNECTED # public properties self.cid = idcounter() - self.key = "Dummy-%s" % self.cid - self.gid = "%s-%s" % (time.strftime(DATESTRING), self.cid) + self.key = f"Dummy-{self.cid}" + self.gid = f"{time.strftime(DATESTRING)}_{self.cid}" self.istep = 0 self.exits = [] # exit names created self.objs = [] # obj names created + self.connection_timestamp = time.time() + self.connection_attempt = 0 + self.action_started = 0 self._connected = False self._loggedin = False self._logging_out = False + self._ready = False self._report = "" self._cmdlist = [] # already stepping in a cmd definition self._login = self.factory.actions[0] self._logout = self.factory.actions[1] self._actions = self.factory.actions[2:] - reactor.addSystemEventTrigger("before", "shutdown", self.logout)
    + reactor.addSystemEventTrigger("before", "shutdown", self.logout) + + NCONNECTED += 1 + self.report("-> connected", self.key) + + reactor.callLater(30, self._retry_welcome_screen)
    + + def _retry_welcome_screen(self): + if not self._connected and not self._ready: + # we have connected but not received anything for 30s. + # (unclear why this would be - overload?) + # try sending a look to get something to start with + self.report("?? retrying welcome screen", self.key) + self.sendLine(bytes("look", 'utf-8')) + # make sure to check again later + reactor.callLater(30, self._retry_welcome_screen) + + def _print_statistics(self): + global TIME_ALL_LOGIN, TOTAL_ACTIONS + global TOTAL_LAG, TOTAL_LAG_MEASURES, TOTAL_LAG_IN, TOTAL_LAG_OUT + + tim = time.time() - TIME_ALL_LOGIN + avgrate = round(TOTAL_ACTIONS / tim) + lag = TOTAL_LAG / (TOTAL_LAG_MEASURES or 1) + lag_in = TOTAL_LAG_IN / (TOTAL_LAG_MEASURES or 1) + lag_out = TOTAL_LAG_OUT / (TOTAL_LAG_MEASURES or 1) + + TOTAL_ACTIONS = 0 + TOTAL_LAG = 0 + TOTAL_LAG_IN = 0 + TOTAL_LAG_OUT = 0 + TOTAL_LAG_MEASURES = 0 + TIME_ALL_LOGIN = time.time() + + print(f".. running 30s average: ~{avgrate} actions/s " + f"lag: {lag:.2}s (in: {lag_in:.2}s, out: {lag_out:.2}s)") + + reactor.callLater(30, self._print_statistics)
    [docs] def dataReceived(self, data): """ @@ -305,15 +418,67 @@ data (str): Incoming data. """ - if not self._connected and not data.startswith(chr(255)): - # wait until we actually get text back (not just telnet - # negotiation) - self._connected = True - # start client tick - d = LoopingCall(self.step) - # dissipate exact step by up to +/- 0.5 second - timestep = TIMESTEP + (-0.5 + (random.random() * 1.0)) - d.start(timestep, now=True).addErrback(self.error)
    + global NLOGIN_SCREEN, NLOGGED_IN, NLOGGING_IN, NCONNECTED + global TOTAL_ACTIONS, TIME_ALL_LOGIN + global TOTAL_LAG, TOTAL_LAG_MEASURES, TOTAL_LAG_IN, TOTAL_LAG_OUT + + if not data.startswith(b"\xff"): + # regular text, not a telnet command + + if NCLIENTS == 1: + print("dummy-client sees:", str(data, "utf-8")) + + if not self._connected: + # waiting for connection + # wait until we actually get text back (not just telnet + # negotiation) + # start client tick + d = LoopingCall(self.step) + df = max(abs(TIMESTEP * 0.001), min(TIMESTEP/10, 0.5)) + # dither next attempt with random time + timestep = TIMESTEP + (-df + (random.random() * df)) + d.start(timestep, now=True).addErrback(self.error) + self.connection_attempt += 1 + + self._connected = True + NLOGIN_SCREEN += 1 + NCONNECTED -= 1 + self.report("<- server sent login screen", self.key) + + elif self._loggedin: + if not self._ready: + # logged in, ready to run + NLOGGED_IN += 1 + NLOGGING_IN -= 1 + self._ready = True + self.report("== logged in", self.key) + if NLOGGED_IN == NCLIENTS and not TIME_ALL_LOGIN: + # all are logged in! We can start collecting statistics + print(".. All clients connected and logged in!") + TIME_ALL_LOGIN = time.time() + reactor.callLater(30, self._print_statistics) + + elif TIME_ALL_LOGIN: + TOTAL_ACTIONS += 1 + + try: + data = strip_ansi(str(data, "utf-8").strip()) + if data.startswith("dummyrunner_echo_response:"): + # handle special lag-measuring command. This returns + # dummyrunner_echo_response:<starttime>,<midpointtime> + now = time.time() + _, data = data.split(":", 1) + start_time, mid_time = (float(part) for part in data.split(",", 1)) + lag_in = mid_time - start_time + lag_out = now - mid_time + total_lag = now - start_time # full round-about time + + TOTAL_LAG += total_lag + TOTAL_LAG_IN += lag_in + TOTAL_LAG_OUT += lag_out + TOTAL_LAG_MEASURES += 1 + except Exception: + pass
    [docs] def connectionLost(self, reason): """ @@ -324,7 +489,7 @@ """ if not self._logging_out: - print("client %s(%s) lost connection (%s)" % (self.key, self.cid, reason))
    + self.report("XX lost connection", self.key)
    [docs] def error(self, err): """ @@ -351,9 +516,9 @@ """ self._logging_out = True - cmd = self._logout(self) - print("client %s(%s) logout (%s actions)" % (self.key, self.cid, self.istep)) - self.sendLine(cmd)
    + cmd = self._logout(self)[0] + self.report(f"-> logout/disconnect ({self.istep} actions)", self.key) + self.sendLine(bytes(cmd, 'utf-8'))
    [docs] def step(self): """ @@ -362,7 +527,7 @@ all "intelligence" of the dummy client. """ - global NLOGGED_IN + global NLOGGING_IN, NLOGIN_SCREEN rand = random.random() @@ -370,11 +535,13 @@ # no commands ready. Load some. if not self._loggedin: - if rand < CHANCE_OF_LOGIN: + if rand < CHANCE_OF_LOGIN or NLOGGING_IN < 10: + # lower rate of logins, but not below 1 / s # get the login commands self._cmdlist = list(makeiter(self._login(self))) - NLOGGED_IN += 1 # this is for book-keeping - print("connecting client %s (%i/%i)..." % (self.key, NLOGGED_IN, NCLIENTS)) + NLOGGING_IN += 1 # this is for book-keeping + NLOGIN_SCREEN -= 1 + self.report("-> create/login", self.key) self._loggedin = True else: # no login yet, so cmdlist not yet set @@ -388,12 +555,26 @@ # at this point we always have a list of commands if rand < CHANCE_OF_ACTION: # send to the game - self.sendLine(str(self._cmdlist.pop(0))) - self.istep += 1
    + cmd = str(self._cmdlist.pop(0)) + + if cmd.startswith("dummyrunner_echo_response"): + # we need to set the timer element as close to + # the send as possible + cmd = cmd.format(timestamp=time.time()) + + self.sendLine(bytes(cmd, 'utf-8')) + self.action_started = time.time() + self.istep += 1 + + if NCLIENTS == 1: + print(f"dummy-client sent: {cmd}") -
    [docs]class DummyFactory(protocol.ClientFactory): +
    [docs]class DummyFactory(protocol.ReconnectingClientFactory): protocol = DummyClient + initialDelay = 1 + maxDelay = 1 + noisy = False
    [docs] def __init__(self, actions): "Setup the factory base (shared by all clients)" @@ -438,7 +619,7 @@ # setting up all clients (they are automatically started) factory = DummyFactory(actions) for i in range(NCLIENTS): - reactor.connectTCP("localhost", TELNET_PORT, factory) + reactor.connectTCP("127.0.0.1", TELNET_PORT, factory) # start reactor reactor.run()
    @@ -463,12 +644,23 @@ ) args = parser.parse_args() + nclients = int(args.nclients[0]) - print(INFO_STARTING.format(N=args.nclients[0])) + print(INFO_STARTING.format( + nclients=nclients, + port=TELNET_PORT, + idmapper_cache_size=IDMAPPER_CACHE_MAXSIZE, + timestep=TIMESTEP, + rate=1/TIMESTEP, + chance_of_login=CHANCE_OF_LOGIN * 100, + chance_of_action=CHANCE_OF_ACTION * 100, + avg_rate=(1 / TIMESTEP) * CHANCE_OF_ACTION, + avg_rate_total=(1 / TIMESTEP) * CHANCE_OF_ACTION * nclients + )) # run the dummyrunner - t0 = time.time() - start_all_dummy_clients(nclients=args.nclients[0]) + TIME_START = t0 = time.time() + start_all_dummy_clients(nclients=nclients) ttot = time.time() - t0 # output runtime @@ -510,7 +702,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/profiling/dummyrunner_settings.html b/docs/0.9.5/_modules/evennia/server/profiling/dummyrunner_settings.html index 0d34e4faf5..d21b3a3117 100644 --- a/docs/0.9.5/_modules/evennia/server/profiling/dummyrunner_settings.html +++ b/docs/0.9.5/_modules/evennia/server/profiling/dummyrunner_settings.html @@ -47,45 +47,47 @@ The settings are global variables: -TIMESTEP - time in seconds between each 'tick' -CHANCE_OF_ACTION - chance 0-1 of action happening -CHANCE_OF_LOGIN - chance 0-1 of login happening -TELNET_PORT - port to use, defaults to settings.TELNET_PORT -ACTIONS - see below +- TIMESTEP - time in seconds between each 'tick'. 1 is a good start. +- CHANCE_OF_ACTION - chance 0-1 of action happening. Default is 0.5. +- CHANCE_OF_LOGIN - chance 0-1 of login happening. 0.01 is a good number. +- TELNET_PORT - port to use, defaults to settings.TELNET_PORT +- ACTIONS - see below ACTIONS is a tuple -``` +```python (login_func, logout_func, (0.3, func1), (0.1, func2) ... ) + ``` where the first entry is the function to call on first connect, with a chance of occurring given by CHANCE_OF_LOGIN. This function is usually responsible for logging in the account. The second entry is always called when the dummyrunner disconnects from the server and should -thus issue a logout command. The other entries are tuples (chance, +thus issue a logout command. The other entries are tuples (chance, func). They are picked randomly, their commonality based on the cumulative chance given (the chance is normalized between all options so if will still work also if the given chances don't add up to 1). -Since each function can return a list of game-command strings, each -function may result in multiple operations. + +The PROFILE variable define pre-made ACTION tuples for convenience. + +Each function should return an iterable of one or more command-call +strings (like "look here"), so each can group multiple command operations. An action-function is called with a "client" argument which is a -reference to the dummy client currently performing the action. It -returns a string or a list of command strings to execute. Use the -client object for optionally saving data between actions. +reference to the dummy client currently performing the action. The client object has the following relevant properties and methods: - key - an optional client key. This is only used for dummyrunner output. - Default is "Dummy-<cid>" + Default is "Dummy-<cid>" - cid - client id - gid - globally unique id, hashed with time stamp - istep - the current step - exits - an empty list. Can be used to store exit names - objs - an empty list. Can be used to store object names - counter() - returns a unique increasing id, hashed with time stamp - to make it unique also between dummyrunner instances. + to make it unique also between dummyrunner instances. The return should either be a single command string or a tuple of command strings. This list of commands will always be executed every @@ -93,14 +95,18 @@ (no randomness) and allows for setting up a more complex chain of commands (such as creating an account and logging in). ---- +---- """ +import random +import string + # Dummy runner settings # Time between each dummyrunner "tick", in seconds. Each dummy # will be called with this frequency. -TIMESTEP = 2 +TIMESTEP = 1 +# TIMESTEP = 0.025 # 40/s # Chance of a dummy actually performing an action on a given tick. # This spreads out usage randomly, like it would be in reality. @@ -109,7 +115,7 @@ # Chance of a currently unlogged-in dummy performing its login # action every tick. This emulates not all accounts logging in # at exactly the same time. -CHANCE_OF_LOGIN = 1.0 +CHANCE_OF_LOGIN = 0.01 # Which telnet port to connect to. If set to None, uses the first # default telnet port of the running server. @@ -120,9 +126,10 @@ # some convenient templates -DUMMY_NAME = "Dummy-%s" -DUMMY_PWD = "password-%s" -START_ROOM = "testing_room_start_%s" +DUMMY_NAME = "Dummy_{gid}" +DUMMY_PWD = (''.join(random.choice(string.ascii_letters + string.digits) + for _ in range(20)) + "-{gid}") +START_ROOM = "testing_room_start_{gid}" ROOM_TEMPLATE = "testing_room_%s" EXIT_TEMPLATE = "exit_%s" OBJ_TEMPLATE = "testing_obj_%s" @@ -135,42 +142,45 @@ # login/logout -
    [docs]def c_login(client): "logins to the game" # we always use a new client name - cname = DUMMY_NAME % client.gid - cpwd = DUMMY_PWD % client.gid + cname = DUMMY_NAME.format(gid=client.gid) + cpwd = DUMMY_PWD.format(gid=client.gid) + room_name = START_ROOM.format(gid=client.gid) - # set up for digging a first room (to move to and keep the - # login room clean) - roomname = ROOM_TEMPLATE % client.counter() - exitname1 = EXIT_TEMPLATE % client.counter() - exitname2 = EXIT_TEMPLATE % client.counter() - client.exits.extend([exitname1, exitname2]) + # we assign the dummyrunner cmdsert to ourselves so # we can use special commands + add_cmdset = ( + "py from evennia.server.profiling.dummyrunner import DummyRunnerCmdSet;" + "self.cmdset.add(DummyRunnerCmdSet, persistent=False)" + ) + # create character, log in, then immediately dig a new location and + # teleport it (to keep the login room clean) cmds = ( - "create %s %s" % (cname, cpwd), - "connect %s %s" % (cname, cpwd), - "@dig %s" % START_ROOM % client.gid, - "@teleport %s" % START_ROOM % client.gid, - "@dig %s = %s, %s" % (roomname, exitname1, exitname2), + f"create {cname} {cpwd}", + f"connect {cname} {cpwd}", + f"dig {room_name}", + f"teleport {room_name}", + add_cmdset, ) return cmds
    [docs]def c_login_nodig(client): "logins, don't dig its own room" - cname = DUMMY_NAME % client.gid - cpwd = DUMMY_PWD % client.gid - - cmds = ("create %s %s" % (cname, cpwd), "connect %s %s" % (cname, cpwd)) + cname = DUMMY_NAME.format(gid=client.gid) + cpwd = DUMMY_PWD.format(gid=client.gid) + cmds = ( + f"create {cname} {cpwd}", + f"connect {cname} {cpwd}" + ) return cmds
    [docs]def c_logout(client): "logouts of the game" - return "@quit"
    + return ("quit",) # random commands @@ -182,7 +192,7 @@ if not cmds: cmds = ["look %s" % exi for exi in client.exits] if not cmds: - cmds = "look" + cmds = ("look",) return cmds @@ -192,7 +202,7 @@ if not cmds: cmds = ["examine %s" % exi for exi in client.exits] if not cmds: - cmds = "examine me" + cmds = ("examine me",) return cmds @@ -204,7 +214,7 @@
    [docs]def c_help(client): "reads help files" - cmds = ("help", "help @teleport", "help look", "help @tunnel", "help @dig") + cmds = ("help", "dummyrunner_echo_response",) return cmds
    @@ -214,7 +224,7 @@ exitname1 = EXIT_TEMPLATE % client.counter() exitname2 = EXIT_TEMPLATE % client.counter() client.exits.extend([exitname1, exitname2]) - return "@dig/tel %s = %s, %s" % (roomname, exitname1, exitname2) + return ("dig/tel %s = %s, %s" % (roomname, exitname1, exitname2),)
    [docs]def c_creates_obj(client): @@ -222,10 +232,10 @@ objname = OBJ_TEMPLATE % client.counter() client.objs.append(objname) cmds = ( - "@create %s" % objname, - '@desc %s = "this is a test object' % objname, - "@set %s/testattr = this is a test attribute value." % objname, - "@set %s/testattr2 = this is a second test attribute." % objname, + "create %s" % objname, + 'desc %s = "this is a test object' % objname, + "set %s/testattr = this is a test attribute value." % objname, + "set %s/testattr2 = this is a second test attribute." % objname, ) return cmds
    @@ -234,16 +244,14 @@ "creates example button, storing name on client" objname = TOBJ_TEMPLATE % client.counter() client.objs.append(objname) - cmds = ("@create %s:%s" % (objname, TOBJ_TYPECLASS), "@desc %s = test red button!" % objname) + cmds = ("create %s:%s" % (objname, TOBJ_TYPECLASS), "desc %s = test red button!" % objname) return cmds
    [docs]def c_socialize(client): "socializechats on channel" cmds = ( - "ooc Hello!", - "ooc Testing ...", - "ooc Testing ... times 2", + "pub Hello!", "say Yo!", "emote stands looking around.", ) @@ -253,84 +261,120 @@
    [docs]def c_moves(client): "moves to a previously created room, using the stored exits" cmds = client.exits # try all exits - finally one will work - return "look" if not cmds else cmds
    + return ("look",) if not cmds else cmds
    [docs]def c_moves_n(client): "move through north exit if available" - return "north"
    + return ("north",)
    [docs]def c_moves_s(client): "move through south exit if available" - return "south"
    + return ("south",) -# Action tuple (required) -# -# This is a tuple of client action functions. The first element is the -# function the client should use to log into the game and move to -# STARTROOM . The second element is the logout command, for cleanly -# exiting the mud. The following elements are 2-tuples of (probability, -# action_function). The probablities should normally sum up to 1, -# otherwise the system will normalize them. +
    [docs]def c_measure_lag(client): + """ + Special dummyrunner command, injected in c_login. It measures + response time. Including this in the ACTION tuple will give more + dummyrunner output about just how fast commands are being processed. + + The dummyrunner will treat this special and inject the + {timestamp} just before sending. + + """ + return ("dummyrunner_echo_response {timestamp}",)
    + + +# Action profile (required) + +# Some pre-made profiles to test. To make your own, just assign a tuple to ACTIONS. # +# idler - does nothing after logging in +# looker - just looks around +# normal_player - moves around, reads help, looks around (digs rarely) (spammy) +# normal_builder - digs now and then, examines, creates objects, moves +# heavy_builder - digs and creates a lot, moves and examines +# socializing_builder - builds a lot, creates help entries, moves, chat (spammy) +# only_digger - extreme builder that only digs room after room + +PROFILE = "looker" -# "normal builder" definitionj -# ACTIONS = ( c_login, -# c_logout, -# (0.5, c_looks), -# (0.08, c_examines), -# (0.1, c_help), -# (0.01, c_digs), -# (0.01, c_creates_obj), -# (0.3, c_moves)) -# "heavy" builder definition -# ACTIONS = ( c_login, -# c_logout, -# (0.2, c_looks), -# (0.1, c_examines), -# (0.2, c_help), -# (0.1, c_digs), -# (0.1, c_creates_obj), -# #(0.01, c_creates_button), -# (0.2, c_moves)) -# "passive account" definition -# ACTIONS = ( c_login, -# c_logout, -# (0.7, c_looks), -# #(0.1, c_examines), -# (0.3, c_help)) -# #(0.1, c_digs), -# #(0.1, c_creates_obj), -# #(0.1, c_creates_button), -# #(0.4, c_moves)) -# "inactive account" definition -# ACTIONS = (c_login_nodig, -# c_logout, -# (1.0, c_idles)) -# "normal account" definition -ACTIONS = (c_login, c_logout, (0.01, c_digs), (0.39, c_looks), (0.2, c_help), (0.4, c_moves)) -# walking tester. This requires a pre-made -# "loop" of multiple rooms that ties back -# to limbo (using @tunnel and @open) -# ACTIONS = (c_login_nodig, -# c_logout, -# (1.0, c_moves_n)) -# "socializing heavy builder" definition -# ACTIONS = (c_login, -# c_logout, -# (0.1, c_socialize), -# (0.1, c_looks), -# (0.2, c_help), -# (0.1, c_creates_obj), -# (0.2, c_digs), -# (0.3, c_moves)) -# "heavy digger memory tester" definition -# ACTIONS = (c_login, -# c_logout, -# (1.0, c_digs)) +if PROFILE == 'idler': + ACTIONS = ( + c_login, + c_logout, + (0.9, c_idles), + (0.1, c_measure_lag), + ) +elif PROFILE == 'looker': + ACTIONS = ( + c_login, + c_logout, + (0.8, c_looks), + (0.2, c_measure_lag) + ) +elif PROFILE == 'normal_player': + ACTIONS = ( + c_login, + c_logout, + (0.01, c_digs), + (0.29, c_looks), + (0.2, c_help), + (0.3, c_moves), + (0.05, c_socialize), + (0.1, c_measure_lag) + ) +elif PROFILE == 'normal_builder': + ACTIONS = ( + c_login, + c_logout, + (0.5, c_looks), + (0.08, c_examines), + (0.1, c_help), + (0.01, c_digs), + (0.01, c_creates_obj), + (0.2, c_moves), + (0.1, c_measure_lag) + ) +elif PROFILE == 'heavy_builder': + ACTIONS = ( + c_login, + c_logout, + (0.1, c_looks), + (0.1, c_examines), + (0.2, c_help), + (0.1, c_digs), + (0.1, c_creates_obj), + (0.2, c_moves), + (0.1, c_measure_lag) + ) +elif PROFILE == 'socializing_builder': + ACTIONS = ( + c_login, + c_logout, + (0.1, c_socialize), + (0.1, c_looks), + (0.1, c_help), + (0.1, c_creates_obj), + (0.2, c_digs), + (0.3, c_moves), + (0.1, c_measure_lag) + ) +elif PROFILE == 'only_digger': + ACTIONS = ( + c_login, + c_logout, + (0.9, c_digs), + (0.1, c_measure_lag) + ) + +else: + print("No dummyrunner ACTION profile defined.") + import sys + sys.exit()
    @@ -368,7 +412,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/profiling/memplot.html b/docs/0.9.5/_modules/evennia/server/profiling/memplot.html index 3b50dbc36d..44a803a5a2 100644 --- a/docs/0.9.5/_modules/evennia/server/profiling/memplot.html +++ b/docs/0.9.5/_modules/evennia/server/profiling/memplot.html @@ -192,7 +192,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/profiling/test_queries.html b/docs/0.9.5/_modules/evennia/server/profiling/test_queries.html index 0ed767ae95..be7456a04c 100644 --- a/docs/0.9.5/_modules/evennia/server/profiling/test_queries.html +++ b/docs/0.9.5/_modules/evennia/server/profiling/test_queries.html @@ -119,7 +119,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/profiling/tests.html b/docs/0.9.5/_modules/evennia/server/profiling/tests.html index 45fd02817e..2e09eaf383 100644 --- a/docs/0.9.5/_modules/evennia/server/profiling/tests.html +++ b/docs/0.9.5/_modules/evennia/server/profiling/tests.html @@ -41,6 +41,7 @@

    Source code for evennia.server.profiling.tests

     from django.test import TestCase
     from mock import Mock, patch, mock_open
    +from anything import Something
     from .dummyrunner_settings import (
         c_creates_button,
         c_creates_obj,
    @@ -70,8 +71,8 @@
             self.client.cid = 1
             self.client.counter = Mock(return_value=1)
             self.client.gid = "20171025161153-1"
    -        self.client.name = "Dummy-%s" % self.client.gid
    -        self.client.password = "password-%s" % self.client.gid
    +        self.client.name = "Dummy_%s" % self.client.gid
    +        self.client.password = Something,
             self.client.start_room = "testing_room_start_%s" % self.client.gid
             self.client.objs = []
             self.client.exits = []
    @@ -84,28 +85,25 @@ self.assertEqual( c_login(self.client), ( - "create %s %s" % (self.client.name, self.client.password), - "connect %s %s" % (self.client.name, self.client.password), - "@dig %s" % self.client.start_room, - "@teleport %s" % self.client.start_room, - "@dig testing_room_1 = exit_1, exit_1", + Something, # create + Something, # connect + "dig %s" % self.client.start_room, + "teleport %s" % self.client.start_room, + "py from evennia.server.profiling.dummyrunner import DummyRunnerCmdSet;" + "self.cmdset.add(DummyRunnerCmdSet, persistent=False)" ), )
    [docs] def test_c_login_no_dig(self): - self.assertEqual( - c_login_nodig(self.client), - ( - "create %s %s" % (self.client.name, self.client.password), - "connect %s %s" % (self.client.name, self.client.password), - ), - )
    + cmd1, cmd2 = c_login_nodig(self.client) + self.assertTrue(cmd1.startswith("create " + self.client.name + " ")) + self.assertTrue(cmd2.startswith("connect " + self.client.name + " "))
    [docs] def test_c_logout(self): - self.assertEqual(c_logout(self.client), "@quit")
    + self.assertEqual(c_logout(self.client), ("quit",))
    [docs] def perception_method_tests(self, func, verb, alone_suffix=""): - self.assertEqual(func(self.client), "%s%s" % (verb, alone_suffix)) + self.assertEqual(func(self.client), ("%s%s" % (verb, alone_suffix),)) self.client.exits = ["exit1", "exit2"] self.assertEqual(func(self.client), ["%s exit1" % verb, "%s exit2" % verb]) self.client.objs = ["foo", "bar"] @@ -124,11 +122,11 @@
    [docs] def test_c_help(self): self.assertEqual( c_help(self.client), - ("help", "help @teleport", "help look", "help @tunnel", "help @dig"), + ("help", "dummyrunner_echo_response"), )
    [docs] def test_c_digs(self): - self.assertEqual(c_digs(self.client), ("@dig/tel testing_room_1 = exit_1, exit_1")) + self.assertEqual(c_digs(self.client), ("dig/tel testing_room_1 = exit_1, exit_1", )) self.assertEqual(self.client.exits, ["exit_1", "exit_1"]) self.clear_client_lists()
    @@ -137,10 +135,10 @@ self.assertEqual( c_creates_obj(self.client), ( - "@create %s" % objname, - '@desc %s = "this is a test object' % objname, - "@set %s/testattr = this is a test attribute value." % objname, - "@set %s/testattr2 = this is a second test attribute." % objname, + "create %s" % objname, + 'desc %s = "this is a test object' % objname, + "set %s/testattr = this is a test attribute value." % objname, + "set %s/testattr2 = this is a second test attribute." % objname, ), ) self.assertEqual(self.client.objs, [objname]) @@ -151,7 +149,7 @@ typeclass_name = "contrib.tutorial_examples.red_button.RedButton" self.assertEqual( c_creates_button(self.client), - ("@create %s:%s" % (objname, typeclass_name), "@desc %s = test red button!" % objname), + ("create %s:%s" % (objname, typeclass_name), "desc %s = test red button!" % objname), ) self.assertEqual(self.client.objs, [objname]) self.clear_client_lists()
    @@ -160,25 +158,23 @@ self.assertEqual( c_socialize(self.client), ( - "ooc Hello!", - "ooc Testing ...", - "ooc Testing ... times 2", + "pub Hello!", "say Yo!", "emote stands looking around.", ), )
    [docs] def test_c_moves(self): - self.assertEqual(c_moves(self.client), "look") + self.assertEqual(c_moves(self.client), ("look",)) self.client.exits = ["south", "north"] self.assertEqual(c_moves(self.client), ["south", "north"]) self.clear_client_lists()
    [docs] def test_c_move_n(self): - self.assertEqual(c_moves_n(self.client), "north")
    + self.assertEqual(c_moves_n(self.client), ("north",))
    [docs] def test_c_move_s(self): - self.assertEqual(c_moves_s(self.client), "south")
    + self.assertEqual(c_moves_s(self.client), ("south",))
    [docs]class TestMemPlot(TestCase): @@ -238,7 +234,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/profiling/timetrace.html b/docs/0.9.5/_modules/evennia/server/profiling/timetrace.html index 9539cdcc7f..9ca663788a 100644 --- a/docs/0.9.5/_modules/evennia/server/profiling/timetrace.html +++ b/docs/0.9.5/_modules/evennia/server/profiling/timetrace.html @@ -116,7 +116,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/server.html b/docs/0.9.5/_modules/evennia/server/server.html index a8de11e249..3c04439416 100644 --- a/docs/0.9.5/_modules/evennia/server/server.html +++ b/docs/0.9.5/_modules/evennia/server/server.html @@ -40,12 +40,12 @@

    Source code for evennia.server.server

     """
    -This module implements the main Evennia server process, the core of
    -the game engine.
    +This module implements the main Evennia server process, the core of the game
    +engine.
     
    -This module should be started with the 'twistd' executable since it
    -sets up all the networking features.  (this is done automatically
    -by evennia/server/server_runner.py).
    +This module should be started with the 'twistd' executable since it sets up all
    +the networking features.  (this is done automatically by
    +evennia/server/server_runner.py).
     
     """
     import time
    @@ -63,6 +63,7 @@
     django.setup()
     
     import evennia
    +import importlib
     
     evennia._init()
     
    @@ -73,11 +74,9 @@
     from evennia.accounts.models import AccountDB
     from evennia.scripts.models import ScriptDB
     from evennia.server.models import ServerConfig
    -from evennia.server import initial_setup
     
     from evennia.utils.utils import get_evennia_version, mod_import, make_iter
     from evennia.utils import logger
    -from evennia.comms import channelhandler
     from evennia.server.sessionhandler import SESSIONS
     
     from django.utils.translation import gettext as _
    @@ -184,12 +183,6 @@
         if _MAINTENANCE_COUNT % 5 == 0:
             # check cache size every 5 minutes
             _FLUSH_CACHE(_IDMAPPER_CACHE_MAXSIZE)
    -    if _MAINTENANCE_COUNT % 60 == 0:
    -        # validate scripts every hour
    -        evennia.ScriptDB.objects.validate()
    -    if _MAINTENANCE_COUNT % 61 == 0:
    -        # validate channels off-sync with scripts
    -        evennia.CHANNEL_HANDLER.update()
         if _MAINTENANCE_COUNT % (60 * 7) == 0:
             # drop database connection every 7 hrs to avoid default timeouts on MySQL
             # (see https://github.com/evennia/evennia/issues/1376)
    @@ -216,12 +209,13 @@
     # ------------------------------------------------------------
     
     
    -
    [docs]class Evennia(object): +
    [docs]class Evennia: """ The main Evennia server handler. This object sets up the database and tracks and interlinks all the twisted network services that make up evennia. + """
    [docs] def __init__(self, application): @@ -246,12 +240,6 @@ self.start_time = time.time() - # initialize channelhandler - try: - channelhandler.CHANNELHANDLER.update() - except OperationalError: - print("channelhandler couldn't update - db not set up") - # wrap the SIGINT handler to make sure we empty the threadpool # even when we reload and we have long-running requests in queue. # this is necessary over using Twisted's signal handler. @@ -297,6 +285,7 @@ This allows for changing default cmdset locations and default typeclasses in the settings file and have them auto-update all already existing objects. + """ global INFO_DICT @@ -386,6 +375,7 @@ Once finished the last_initial_setup_step is set to -1. """ global INFO_DICT + initial_setup = importlib.import_module(settings.INITIAL_SETUP_MODULE) last_initial_setup_step = ServerConfig.objects.conf("last_initial_setup_step") if not last_initial_setup_step: # None is only returned if the config does not exist, @@ -444,18 +434,17 @@ """ Shuts down the server from inside it. - Keyword Args: - mode (str): Sets the server restart mode: - - 'reload': server restarts, no "persistent" scripts - are stopped, at_reload hooks called. - - 'reset' - server restarts, non-persistent scripts stopped, - at_shutdown hooks called but sessions will not - be disconnected. - -'shutdown' - like reset, but server will not auto-restart. - _reactor_stopping: This is set if server is stopped by a kill - command OR this method was already called - once - in both cases the reactor is dead/stopping already. - + mode - sets the server restart mode. + - 'reload' - server restarts, no "persistent" scripts + are stopped, at_reload hooks called. + - 'reset' - server restarts, non-persistent scripts stopped, + at_shutdown hooks called but sessions will not + be disconnected. + - 'shutdown' - like reset, but server will not auto-restart. + _reactor_stopping - this is set if server is stopped by a kill + command OR this method was already called + once - in both cases the reactor is + dead/stopping already. """ if _reactor_stopping and hasattr(self, "shutdown_complete"): # this means we have already passed through this method @@ -472,9 +461,9 @@ yield [o.at_server_reload() for o in ObjectDB.get_all_cached_instances()] yield [p.at_server_reload() for p in AccountDB.get_all_cached_instances()] yield [ - (s.pause(manual_pause=False), s.at_server_reload()) + (s._pause_task(auto_pause=True), s.at_server_reload()) for s in ScriptDB.get_all_cached_instances() - if s.id and (s.is_active or s.attributes.has("_manual_pause")) + if s.id and s.is_active ] yield self.sessions.all_sessions_portal_sync() self.at_server_reload_stop() @@ -498,11 +487,9 @@ ] yield ObjectDB.objects.clear_all_sessids() yield [ - ( - s.pause(manual_pause=s.attributes.get("_manual_pause", False)), - s.at_server_shutdown(), - ) + (s._pause_task(auto_pause=True), s.at_server_shutdown()) for s in ScriptDB.get_all_cached_instances() + if s.id and s.is_active ] ServerConfig.objects.conf("server_restart_mode", "reset") self.at_server_cold_stop() @@ -527,7 +514,10 @@ ServerConfig.objects.conf("runtime", _GAMETIME_MODULE.runtime())
    [docs] def get_info_dict(self): - "Return the server info, for display." + """ + Return the server info, for display. + + """ return INFO_DICT
    # server start/stop hooks @@ -536,6 +526,7 @@ """ This is called every time the server starts up, regardless of how it was shut down. + """ if SERVER_STARTSTOP_MODULE: SERVER_STARTSTOP_MODULE.at_server_start()
    @@ -544,6 +535,7 @@ """ This is called just before a server is shut down, regardless of it is fore a reload, reset or shutdown. + """ if SERVER_STARTSTOP_MODULE: SERVER_STARTSTOP_MODULE.at_server_stop()
    @@ -551,6 +543,7 @@
    [docs] def at_server_reload_start(self): """ This is called only when server starts back up after a reload. + """ if SERVER_STARTSTOP_MODULE: SERVER_STARTSTOP_MODULE.at_server_reload_start()
    @@ -561,7 +554,7 @@ after reconnecting. Args: - mode (str): One of reload, reset or shutdown. + mode (str): One of 'reload', 'reset' or 'shutdown'. """ @@ -573,9 +566,8 @@ TICKER_HANDLER.restore(mode == "reload") - # after sync is complete we force-validate all scripts - # (this also starts any that didn't yet start) - ScriptDB.objects.validate(init_mode=mode) + # Un-pause all scripts, stop non-persistent timers + ScriptDB.objects.update_scripts_after_server_start() # start the task handler from evennia.scripts.taskhandler import TASK_HANDLER @@ -591,11 +583,10 @@ god_account = AccountDB.objects.get(id=1) # mudinfo mudinfo_chan = settings.CHANNEL_MUDINFO - if not mudinfo_chan: - raise RuntimeError("settings.CHANNEL_MUDINFO must be defined.") - if not ChannelDB.objects.filter(db_key=mudinfo_chan["key"]): - channel = create_channel(**mudinfo_chan) - channel.connect(god_account) + if mudinfo_chan: + if not ChannelDB.objects.filter(db_key=mudinfo_chan["key"]): + channel = create_channel(**mudinfo_chan) + channel.connect(god_account) # connectinfo connectinfo_chan = settings.CHANNEL_MUDINFO if connectinfo_chan: @@ -613,6 +604,7 @@
    [docs] def at_server_reload_stop(self): """ This is called only time the server stops before a reload. + """ if SERVER_STARTSTOP_MODULE: SERVER_STARTSTOP_MODULE.at_server_reload_stop()
    @@ -621,6 +613,7 @@ """ This is called only when the server starts "cold", i.e. after a shutdown or a reset. + """ # We need to do this just in case the server was killed in a way where # the normal cleanup operations did not have time to run. @@ -632,7 +625,7 @@ from evennia.scripts.models import ScriptDB for script in ScriptDB.objects.filter(db_persistent=False): - script.stop() + script._stop_task() if GUEST_ENABLED: for guest in AccountDB.objects.all().filter( @@ -648,6 +641,7 @@
    [docs] def at_server_cold_stop(self): """ This is called only when the server goes down due to a shutdown or reset. + """ if SERVER_STARTSTOP_MODULE: SERVER_STARTSTOP_MODULE.at_server_cold_stop()
    @@ -818,7 +812,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/serversession.html b/docs/0.9.5/_modules/evennia/server/serversession.html index 0e2e3de87c..ae0b7ba1f9 100644 --- a/docs/0.9.5/_modules/evennia/server/serversession.html +++ b/docs/0.9.5/_modules/evennia/server/serversession.html @@ -47,142 +47,22 @@ It is stored on the Server side (as opposed to protocol-specific sessions which are stored on the Portal side) """ -import weakref import time from django.utils import timezone from django.conf import settings from evennia.comms.models import ChannelDB from evennia.utils import logger -from evennia.utils.utils import make_iter, lazy_property +from evennia.utils.utils import make_iter, lazy_property, class_from_module from evennia.commands.cmdsethandler import CmdSetHandler -from evennia.server.session import Session from evennia.scripts.monitorhandler import MONITOR_HANDLER +from evennia.typeclasses.attributes import AttributeHandler, InMemoryAttributeBackend, DbHolder _GA = object.__getattribute__ _SA = object.__setattr__ _ObjectDB = None _ANSI = None -# i18n -from django.utils.translation import gettext as _ - -# Handlers for Session.db/ndb operation - - -
    [docs]class NDbHolder(object): - """Holder for allowing property access of attributes""" - -
    [docs] def __init__(self, obj, name, manager_name="attributes"): - _SA(self, name, _GA(obj, manager_name)) - _SA(self, "name", name)
    - - def __getattribute__(self, attrname): - if attrname == "all": - # we allow to overload our default .all - attr = _GA(self, _GA(self, "name")).get("all") - return attr if attr else _GA(self, "all") - return _GA(self, _GA(self, "name")).get(attrname) - - def __setattr__(self, attrname, value): - _GA(self, _GA(self, "name")).add(attrname, value) - - def __delattr__(self, attrname): - _GA(self, _GA(self, "name")).remove(attrname) - -
    [docs] def get_all(self): - return _GA(self, _GA(self, "name")).all()
    - - all = property(get_all)
    - - -
    [docs]class NAttributeHandler(object): - """ - NAttributeHandler version without recache protection. - This stand-alone handler manages non-database saving. - It is similar to `AttributeHandler` and is used - by the `.ndb` handler in the same way as `.db` does - for the `AttributeHandler`. - """ - -
    [docs] def __init__(self, obj): - """ - Initialized on the object - """ - self._store = {} - self.obj = weakref.proxy(obj)
    - -
    [docs] def has(self, key): - """ - Check if object has this attribute or not. - - Args: - key (str): The Nattribute key to check. - - Returns: - has_nattribute (bool): If Nattribute is set or not. - - """ - return key in self._store
    - -
    [docs] def get(self, key, default=None): - """ - Get the named key value. - - Args: - key (str): The Nattribute key to get. - - Returns: - the value of the Nattribute. - - """ - return self._store.get(key, default)
    - -
    [docs] def add(self, key, value): - """ - Add new key and value. - - Args: - key (str): The name of Nattribute to add. - value (any): The value to store. - - """ - self._store[key] = value
    - -
    [docs] def remove(self, key): - """ - Remove Nattribute from storage. - - Args: - key (str): The name of the Nattribute to remove. - - """ - if key in self._store: - del self._store[key]
    - -
    [docs] def clear(self): - """ - Remove all NAttributes from handler. - - """ - self._store = {}
    - -
    [docs] def all(self, return_tuples=False): - """ - List the contents of the handler. - - Args: - return_tuples (bool, optional): Defines if the Nattributes - are returns as a list of keys or as a list of `(key, value)`. - - Returns: - nattributes (list): A list of keys `[key, key, ...]` or a - list of tuples `[(key, value), ...]` depending on the - setting of `return_tuples`. - - """ - if return_tuples: - return [(key, value) for (key, value) in self._store.items() if not key.startswith("_")] - return [key for key in self._store if not key.startswith("_")]
    +_BASE_SESSION_CLASS = class_from_module(settings.BASE_SESSION_CLASS) # ------------------------------------------------------------- @@ -190,7 +70,7 @@ # ------------------------------------------------------------- -
    [docs]class ServerSession(Session): +
    [docs]class ServerSession(_BASE_SESSION_CLASS): """ This class represents an account's session and is a template for individual protocols to communicate with Evennia. @@ -202,7 +82,10 @@ """
    [docs] def __init__(self): - """Initiate to avoid AttributeErrors down the line""" + """ + Initiate to avoid AttributeErrors down the line + + """ self.puppet = None self.account = None self.cmdset_storage_string = "" @@ -216,6 +99,10 @@ cmdset_storage = property(__cmdset_storage_get, __cmdset_storage_set) + @property + def id(self): + return self.sessid +
    [docs] def at_sync(self): """ This is called whenever a session has been resynced with the @@ -385,7 +272,7 @@ Update the protocol_flags and sync them with Portal. Keyword Args: - any: A key:value pair to set in the + protocol_flag (any): A key and value to set in the protocol_flags dictionary. Notes: @@ -417,14 +304,13 @@ the respective inputfuncs. Keyword Args: - any: Incoming data from protocol on + kwargs (any): Incoming data from protocol on the form `{"commandname": ((args), {kwargs}),...}` Notes: This method is here in order to give the user a single place to catch and possibly process all incoming data from the client. It should usually always end by sending this data off to `self.sessionhandler.call_inputfuncs(self, **kwargs)`. - """ self.sessionhandler.call_inputfuncs(self, **kwargs)
    @@ -434,7 +320,9 @@ Args: text (str): String input. - kwargs (str or tuple): Send-commands identified + + Keyword Args: + any (str or tuple): Send-commands identified by their keys. Or "options", carrying options for the protocol(s). @@ -473,7 +361,10 @@ self.sessionhandler.data_in(session or self, **kwargs)
    def __eq__(self, other): - """Handle session comparisons""" + """ + Handle session comparisons + + """ try: return self.address == other.address except AttributeError: @@ -520,6 +411,7 @@
    [docs] def at_cmdset_get(self, **kwargs): """ A dummy hook all objects with cmdsets need to have + """ pass
    @@ -530,7 +422,7 @@
    [docs] @lazy_property def nattributes(self): - return NAttributeHandler(self)
    + return AttributeHandler(self, InMemoryAttributeBackend)
    [docs] @lazy_property def attributes(self): @@ -548,7 +440,7 @@ try: return self._ndb_holder except AttributeError: - self._ndb_holder = NDbHolder(self, "nattrhandler", manager_name="nattributes") + self._ndb_holder = DbHolder(self, "nattrhandler", manager_name="nattributes") return self._ndb_holder
    # @ndb.setter @@ -566,7 +458,10 @@ # @ndb.deleter
    [docs] def ndb_del(self): - """Stop accidental deletion.""" + """ + Stop accidental deletion. + + """ raise Exception("Cannot delete the ndb object!")
    ndb = property(ndb_get, ndb_set, ndb_del) @@ -575,7 +470,10 @@ # Mock access method for the session (there is no lock info # at this stage, so we just present a uniform API)
    [docs] def access(self, *args, **kwargs): - """Dummy method to mimic the logged-in API.""" + """ + Dummy method to mimic the logged-in API. + + """ return True
    @@ -614,7 +512,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/session.html b/docs/0.9.5/_modules/evennia/server/session.html index 1f057971c5..33bbf47e05 100644 --- a/docs/0.9.5/_modules/evennia/server/session.html +++ b/docs/0.9.5/_modules/evennia/server/session.html @@ -53,7 +53,7 @@ # ------------------------------------------------------------ -
    [docs]class Session(object): +
    [docs]class Session: """ This class represents a player's session and is a template for both portal- and server-side sessions. @@ -76,26 +76,6 @@ """ - # names of attributes that should be affected by syncing. - _attrs_to_sync = ( - "protocol_key", - "address", - "suid", - "sessid", - "uid", - "csessid", - "uname", - "logged_in", - "puid", - "conn_time", - "cmd_last", - "cmd_last_visible", - "cmd_total", - "protocol_flags", - "server_data", - "cmdset_storage_string", - ) -
    [docs] def init_session(self, protocol_key, address, sessionhandler): """ Initialize the Session. This should be called by the protocol when @@ -162,9 +142,9 @@ the keys given by self._attrs_to_sync. """ - return dict( - (key, value) for key, value in self.__dict__.items() if key in self._attrs_to_sync - )
    + return { + attr: getattr(self, attr) for attr in settings.SESSION_SYNC_ATTRS if hasattr(self, attr) + }
    [docs] def load_sync_data(self, sessdata): """ @@ -270,7 +250,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/sessionhandler.html b/docs/0.9.5/_modules/evennia/server/sessionhandler.html index 0a67cc4cc7..7a61d84708 100644 --- a/docs/0.9.5/_modules/evennia/server/sessionhandler.html +++ b/docs/0.9.5/_modules/evennia/server/sessionhandler.html @@ -45,12 +45,12 @@ There are two similar but separate stores of sessions: - - ServerSessionHandler - this stores generic game sessions - for the game. These sessions has no knowledge about - how they are connected to the world. - - PortalSessionHandler - this stores sessions created by - twisted protocols. These are dumb connectors that - handle network communication but holds no game info. +- ServerSessionHandler - this stores generic game sessions + for the game. These sessions has no knowledge about + how they are connected to the world. +- PortalSessionHandler - this stores sessions created by + twisted protocols. These are dumb connectors that + handle network communication but holds no game info. """ import time @@ -59,18 +59,19 @@ from evennia.commands.cmdhandler import CMD_LOGINSTART from evennia.utils.logger import log_trace from evennia.utils.utils import ( - variable_from_module, is_iter, make_iter, delay, callables_from_module, + class_from_module, ) +from evennia.server.portal import amp from evennia.server.signals import SIGNAL_ACCOUNT_POST_LOGIN, SIGNAL_ACCOUNT_POST_LOGOUT from evennia.server.signals import SIGNAL_ACCOUNT_POST_FIRST_LOGIN, SIGNAL_ACCOUNT_POST_LAST_LOGOUT -from evennia.utils.inlinefuncs import parse_inlinefunc from codecs import decode as codecs_decode +from django.utils.translation import gettext as _ -_INLINEFUNC_ENABLED = settings.INLINEFUNC_ENABLED +_FUNCPARSER_PARSE_OUTGOING_MESSAGES_ENABLED = settings.FUNCPARSER_PARSE_OUTGOING_MESSAGES_ENABLED # delayed imports _AccountDB = None @@ -79,7 +80,7 @@ _ScriptDB = None _OOB_HANDLER = None -_ERR_BAD_UTF8 = "Your client sent an incorrect UTF-8 sequence." +_ERR_BAD_UTF8 = _("Your client sent an incorrect UTF-8 sequence.")
    [docs]class DummySession(object): @@ -88,28 +89,6 @@ DUMMYSESSION = DummySession() -# AMP signals -PCONN = chr(1) # portal session connect -PDISCONN = chr(2) # portal session disconnect -PSYNC = chr(3) # portal session sync -SLOGIN = chr(4) # server session login -SDISCONN = chr(5) # server session disconnect -SDISCONNALL = chr(6) # server session disconnect all -SSHUTD = chr(7) # server shutdown -SSYNC = chr(8) # server session sync -SCONN = chr(11) # server portal connection (for bots) -PCONNSYNC = chr(12) # portal post-syncing session -PDISCONNALL = chr(13) # portal session discnnect all -SRELOAD = chr(14) # server reloading (have portal start a new server) -SSTART = chr(15) # server start (portal must already be running anyway) -PSHUTD = chr(16) # portal (+server) shutdown -SSHUTD = chr(17) # server shutdown -PSTATUS = chr(18) # ping server or portal status -SRESET = chr(19) # server shutdown in reset mode - -# i18n -from django.utils.translation import gettext as _ - _SERVERNAME = settings.SERVERNAME _MULTISESSION_MODE = settings.MULTISESSION_MODE _IDLE_TIMEOUT = settings.IDLE_TIMEOUT @@ -117,6 +96,8 @@ _MAX_SERVER_COMMANDS_PER_SECOND = 100.0 _MAX_SESSION_COMMANDS_PER_SECOND = 5.0 _MODEL_MAP = None +_FUNCPARSER = None + # input handlers @@ -133,8 +114,7 @@ global _ServerSession, _AccountDB, _ServerConfig, _ScriptDB if not _ServerSession: # we allow optional arbitrary serversession class for overloading - modulename, classname = settings.SERVER_SESSION_CLASS.rsplit(".", 1) - _ServerSession = variable_from_module(modulename, classname) + _ServerSession = class_from_module(settings.SERVER_SESSION_CLASS) if not _AccountDB: from evennia.accounts.models import AccountDB as _AccountDB if not _ServerConfig: @@ -142,10 +122,10 @@ if not _ScriptDB: from evennia.scripts.models import ScriptDB as _ScriptDB # including once to avoid warnings in Python syntax checkers - assert _ServerSession - assert _AccountDB - assert _ServerConfig - assert _ScriptDB
    + assert _ServerSession, "ServerSession class could not load" + assert _AccountDB, "AccountDB class could not load" + assert _ServerConfig, "ServerConfig class could not load" + assert _ScriptDB, "ScriptDB class c ould not load" # ----------------------------------------------------------- @@ -160,24 +140,36 @@ """ def __getitem__(self, key): - "Clean out None-sessions automatically." + """ + Clean out None-sessions automatically. + + """ if None in self: del self[None] return super().__getitem__(key)
    [docs] def get(self, key, default=None): - "Clean out None-sessions automatically." + """ + Clean out None-sessions automatically. + + """ if None in self: del self[None] return super().get(key, default)
    def __setitem__(self, key, value): - "Don't assign None sessions" + """ + Don't assign None sessions" + + """ if key is not None: super().__setitem__(key, value) def __contains__(self, key): - "None-keys are not accepted." + """ + None-keys are not accepted. + + """ return False if key is None else super().__contains__(key)
    [docs] def get_sessions(self, include_unloggedin=False): @@ -210,29 +202,32 @@
    [docs] def clean_senddata(self, session, kwargs): """ - Clean up data for sending across the AMP wire. Also apply INLINEFUNCS. + Clean up data for sending across the AMP wire. Also apply the + FuncParser using callables from `settings.FUNCPARSER_OUTGOING_MESSAGES_MODULES`. Args: session (Session): The relevant session instance. - kwargs (dict) Each keyword represents a - send-instruction, with the keyword itself being the name - of the instruction (like "text"). Suitable values for each - keyword are: - :: - - arg -> [[arg], {}] - [args] -> [[args], {}] - {kwargs} -> [[], {kwargs}] - [args, {kwargs}] -> [[arg], {kwargs}] - [[args], {kwargs}] -> [[args], {kwargs}] + kwargs (dict) Each keyword represents a send-instruction, with the keyword itself being + the name of the instruction (like "text"). Suitable values for each keyword are: + - arg -> [[arg], {}] + - [args] -> [[args], {}] + - {kwargs} -> [[], {kwargs}] + - [args, {kwargs}] -> [[arg], {kwargs}] + - [[args], {kwargs}] -> [[args], {kwargs}] Returns: kwargs (dict): A cleaned dictionary of cmdname:[[args],{kwargs}] pairs, - where the keys, args and kwargs have all been converted to - send-safe entities (strings or numbers), and inlinefuncs have been - applied. + where the keys, args and kwargs have all been converted to + send-safe entities (strings or numbers), and funcparser parsing has been + applied. """ + global _FUNCPARSER + if not _FUNCPARSER: + from evennia.utils.funcparser import FuncParser + _FUNCPARSER = FuncParser(settings.FUNCPARSER_OUTGOING_MESSAGES_MODULES, + raise_errors=True) + options = kwargs.pop("options", None) or {} raw = options.get("raw", False) strip_inlinefunc = options.get("strip_inlinefunc", False) @@ -253,7 +248,10 @@ return data def _validate(data): - "Helper function to convert data to AMP-safe (picketable) values" + """ + Helper function to convert data to AMP-safe (picketable) values" + + """ if isinstance(data, dict): newdict = {} for key, part in data.items(): @@ -264,9 +262,11 @@ elif isinstance(data, (str, bytes)): data = _utf8(data) - if _INLINEFUNC_ENABLED and not raw and isinstance(self, ServerSessionHandler): - # only parse inlinefuncs on the outgoing path (sessionhandler->) - data = parse_inlinefunc(data, strip=strip_inlinefunc, session=session) + if (_FUNCPARSER_PARSE_OUTGOING_MESSAGES_ENABLED + and not raw and isinstance(self, ServerSessionHandler)): + # only apply funcparser on the outgoing path (sessionhandler->) + # data = parse_inlinefunc(data, strip=strip_inlinefunc, session=session) + data = _FUNCPARSER.parse(data, strip=strip_inlinefunc, session=session) return str(data) elif ( @@ -314,14 +314,11 @@
    [docs]class ServerSessionHandler(SessionHandler): """ - This object holds the stack of sessions active in the game at - any time. + This object holds the stack of sessions active in the game at any time. - A session register with the handler in two steps, first by - registering itself with the connect() method. This indicates an - non-authenticated session. Whenever the session is authenticated - the session together with the related account is sent to the login() - method. + A session register with the handler in two steps, first by registering itself with the connect() + method. This indicates an non-authenticated session. Whenever the session is authenticated the + session together with the related account is sent to the login() method. """ @@ -366,7 +363,7 @@ sess.load_sync_data(portalsessiondata) sess.at_sync() # validate all scripts - _ScriptDB.objects.validate() + # _ScriptDB.objects.validate() self[sess.sessid] = sess if sess.logged_in and sess.uid: @@ -494,7 +491,7 @@ """ self.server.amp_protocol.send_AdminServer2Portal( - DUMMYSESSION, operation=SCONN, protocol_path=protocol_path, config=configdict + DUMMYSESSION, operation=amp.SCONN, protocol_path=protocol_path, config=configdict )
    [docs] def portal_restart_server(self): @@ -502,14 +499,14 @@ Called by server when reloading. We tell the portal to start a new server instance. """ - self.server.amp_protocol.send_AdminServer2Portal(DUMMYSESSION, operation=SRELOAD)
    + self.server.amp_protocol.send_AdminServer2Portal(DUMMYSESSION, operation=amp.SRELOAD)
    [docs] def portal_reset_server(self): """ Called by server when reloading. We tell the portal to start a new server instance. """ - self.server.amp_protocol.send_AdminServer2Portal(DUMMYSESSION, operation=SRESET)
    + self.server.amp_protocol.send_AdminServer2Portal(DUMMYSESSION, operation=amp.SRESET)
    [docs] def portal_shutdown(self): """ @@ -517,13 +514,12 @@ itself down) """ - self.server.amp_protocol.send_AdminServer2Portal(DUMMYSESSION, operation=PSHUTD)
    + self.server.amp_protocol.send_AdminServer2Portal(DUMMYSESSION, operation=amp.PSHUTD)
    [docs] def login(self, session, account, force=False, testmode=False): """ - Log in the previously unloggedin session and the account we by - now should know is connected to it. After this point we assume - the session to be logged in one way or another. + Log in the previously unloggedin session and the account we by now should know is connected + to it. After this point we assume the session to be logged in one way or another. Args: session (Session): The Session to authenticate. @@ -565,7 +561,7 @@ # sync the portal to the session if not testmode: self.server.amp_protocol.send_AdminServer2Portal( - session, operation=SLOGIN, sessiondata={"logged_in": True, "uid": session.uid} + session, operation=amp.SLOGIN, sessiondata={"logged_in": True, "uid": session.uid} ) account.at_post_login(session=session) if nsess < 2: @@ -610,7 +606,7 @@ if sync_portal: # inform portal that session should be closed. self.server.amp_protocol.send_AdminServer2Portal( - session, operation=SDISCONN, reason=reason + session, operation=amp.SDISCONN, reason=reason )
    [docs] def all_sessions_portal_sync(self): @@ -621,7 +617,7 @@ """ sessdata = self.get_all_sync_data() return self.server.amp_protocol.send_AdminServer2Portal( - DUMMYSESSION, operation=SSYNC, sessiondata=sessdata + DUMMYSESSION, operation=amp.SSYNC, sessiondata=sessdata )
    [docs] def session_portal_sync(self, session): @@ -632,7 +628,7 @@ """ sessdata = {session.sessid: session.get_sync_data()} return self.server.amp_protocol.send_AdminServer2Portal( - DUMMYSESSION, operation=SSYNC, sessiondata=sessdata, clean=False + DUMMYSESSION, operation=amp.SSYNC, sessiondata=sessdata, clean=False )
    [docs] def session_portal_partial_sync(self, session_data): @@ -645,7 +641,7 @@ """ return self.server.amp_protocol.send_AdminServer2Portal( - DUMMYSESSION, operation=SSYNC, sessiondata=session_data, clean=False + DUMMYSESSION, operation=amp.SSYNC, sessiondata=session_data, clean=False )
    [docs] def disconnect_all_sessions(self, reason="You have been disconnected."): @@ -661,7 +657,7 @@ del session # tell portal to disconnect all sessions self.server.amp_protocol.send_AdminServer2Portal( - DUMMYSESSION, operation=SDISCONNALL, reason=reason + DUMMYSESSION, operation=amp.SDISCONNALL, reason=reason )
    [docs] def disconnect_duplicate_sessions( @@ -680,7 +676,8 @@ # mean connecting from the same host would not catch duplicates sid = id(curr_session) doublet_sessions = [ - sess for sess in self.values() if sess.logged_in and sess.uid == uid and id(sess) != sid + sess for sess in self.values() + if sess.logged_in and sess.uid == uid and id(sess) != sid ] for session in doublet_sessions: @@ -790,8 +787,8 @@ puppet (Object): Object puppeted Returns. - sessions (Session or list): Can be more than one of Object is controlled by - more than one Session (MULTISESSION_MODE > 1). + sessions (Session or list): Can be more than one of Object is controlled by more than + one Session (MULTISESSION_MODE > 1). """ sessions = puppet.sessid.get() @@ -804,8 +801,9 @@ Given a client identification hash (for session types that offer them) return all sessions with a matching hash. - Args: + Args csessid (str): The session hash. + Returns: sessions (list): The sessions with matching .csessid, if any. @@ -868,9 +866,9 @@
    [docs] def call_inputfuncs(self, session, **kwargs): """ - Split incoming data into its inputfunc counterparts. - This should be called by the serversession.data_in - as `sessionhandler.call_inputfunc(self, **kwargs)`. + Split incoming data into its inputfunc counterparts. This should be + called by the `serversession.data_in` as + `sessionhandler.call_inputfunc(self, **kwargs)`. We also intercept OOB communication here. @@ -878,8 +876,8 @@ sessions (Session): Session. Keyword Args: - kwargs (any): Incoming data from protocol on - the form `{"commandname": ((args), {kwargs}),...}` + any (tuple): Incoming data from protocol, each + on the form `commandname=((args), {kwargs})`. """ @@ -900,7 +898,11 @@ log_trace()
    -SESSION_HANDLER = ServerSessionHandler() +# import class from settings +_SESSION_HANDLER_CLASS = class_from_module(settings.SERVER_SESSION_HANDLER_CLASS) + +# Instantiate class. These globals are used to provide singleton-like behavior. +SESSION_HANDLER = _SESSION_HANDLER_CLASS() SESSIONS = SESSION_HANDLER # legacy @@ -939,7 +941,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/throttle.html b/docs/0.9.5/_modules/evennia/server/throttle.html index 2606eefc66..f9621d8cae 100644 --- a/docs/0.9.5/_modules/evennia/server/throttle.html +++ b/docs/0.9.5/_modules/evennia/server/throttle.html @@ -39,12 +39,14 @@

    Source code for evennia.server.throttle

    -from collections import defaultdict, deque
    +from django.core.cache import caches
    +from collections import deque
     from evennia.utils import logger
     import time
    +from django.utils.translation import gettext as _
     
     
    -
    [docs]class Throttle(object): +
    [docs]class Throttle: """ Keeps a running count of failed actions per IP address. @@ -53,28 +55,58 @@ This version of the throttle is usable by both the terminal server as well as the web server, imposes limits on memory consumption by using deques - with length limits instead of open-ended lists, and removes sparse keys when - no recent failures have been recorded. + with length limits instead of open-ended lists, and uses native Django + caches for automatic key eviction and persistence configurability. """ - error_msg = "Too many failed attempts; you must wait a few minutes before trying again." + error_msg = _("Too many failed attempts; you must wait a few minutes before trying again.")
    [docs] def __init__(self, **kwargs): """ Allows setting of throttle parameters. Keyword Args: - limit (int): Max number of failures before imposing limiter + name (str): Name of this throttle. + limit (int): Max number of failures before imposing limiter. If `None`, + the throttle is disabled. timeout (int): number of timeout seconds after max number of tries has been reached. cache_size (int): Max number of attempts to record per IP within a rolling window; this is NOT the same as the limit after which the throttle is imposed! """ - self.storage = defaultdict(deque) - self.cache_size = self.limit = kwargs.get("limit", 5) + try: + self.storage = caches['throttle'] + except Exception: + logger.log_trace("Throttle: Errors encountered; using default cache.") + self.storage = caches['default'] + + self.name = kwargs.get('name', 'undefined-throttle') + self.limit = kwargs.get("limit", 5) + self.cache_size = kwargs.get('cache_size', self.limit) self.timeout = kwargs.get("timeout", 5 * 60)
    +
    [docs] def get_cache_key(self, *args, **kwargs): + """ + Creates a 'prefixed' key containing arbitrary terms to prevent key + collisions in the same namespace. + + """ + return '-'.join((self.name, *args))
    + +
    [docs] def touch(self, key, *args, **kwargs): + """ + Refreshes the timeout on a given key and ensures it is recorded in the + key register. + + Args: + key(str): Key of entry to renew. + + """ + cache_key = self.get_cache_key(key) + if self.storage.touch(cache_key, self.timeout): + self.record_key(key)
    +
    [docs] def get(self, ip=None): """ Convenience function that returns the storage table, or part of. @@ -91,9 +123,18 @@ """ if ip: - return self.storage.get(ip, deque(maxlen=self.cache_size)) + cache_key = self.get_cache_key(str(ip)) + return self.storage.get(cache_key, deque(maxlen=self.cache_size)) else: - return self.storage
    + keys_key = self.get_cache_key('keys') + keys = self.storage.get_or_set(keys_key, set(), self.timeout) + data = self.storage.get_many((self.get_cache_key(x) for x in keys)) + + found_keys = set(data.keys()) + if len(keys) != len(found_keys): + self.storage.set(keys_key, found_keys, self.timeout) + + return data
    [docs] def update(self, ip, failmsg="Exceeded threshold."): """ @@ -108,14 +149,17 @@ None """ + cache_key = self.get_cache_key(ip) + # Get current status previously_throttled = self.check(ip) - # Enforce length limits - if not self.storage[ip].maxlen: - self.storage[ip] = deque(maxlen=self.cache_size) + # Get previous failures, if any + entries = self.storage.get(cache_key, []) + entries.append(time.time()) - self.storage[ip].append(time.time()) + # Store updated record + self.storage.set(cache_key, deque(entries, maxlen=self.cache_size), self.timeout) # See if this update caused a change in status currently_throttled = self.check(ip) @@ -123,9 +167,63 @@ # If this makes it engage, log a single activation event if not previously_throttled and currently_throttled: logger.log_sec( - "Throttle Activated: %s (IP: %s, %i hits in %i seconds.)" - % (failmsg, ip, self.limit, self.timeout) - )
    + f"Throttle Activated: {failmsg} (IP: {ip}, " + f"{self.limit} hits in {self.timeout} seconds.)" + ) + + self.record_ip(ip)
    + +
    [docs] def remove(self, ip, *args, **kwargs): + """ + Clears data stored for an IP from the throttle. + + Args: + ip(str): IP to clear. + + """ + exists = self.get(ip) + if not exists: + return False + + cache_key = self.get_cache_key(ip) + self.storage.delete(cache_key) + self.unrecord_ip(ip) + + # Return True if NOT exists + return not bool(self.get(ip))
    + +
    [docs] def record_ip(self, ip, *args, **kwargs): + """ + Tracks keys as they are added to the cache (since there is no way to + get a list of keys after-the-fact). + + Args: + ip(str): IP being added to cache. This should be the original + IP, not the cache-prefixed key. + + """ + keys_key = self.get_cache_key('keys') + keys = self.storage.get(keys_key, set()) + keys.add(ip) + self.storage.set(keys_key, keys, self.timeout) + return True
    + +
    [docs] def unrecord_ip(self, ip, *args, **kwargs): + """ + Forces removal of a key from the key registry. + + Args: + ip(str): IP to remove from list of keys. + + """ + keys_key = self.get_cache_key('keys') + keys = self.storage.get(keys_key, set()) + try: + keys.remove(ip) + self.storage.set(keys_key, keys, self.timeout) + return True + except KeyError: + return False
    [docs] def check(self, ip): """ @@ -141,19 +239,26 @@ False otherwise. """ + if self.limit is None: + # throttle is disabled + return False + now = time.time() ip = str(ip) + cache_key = self.get_cache_key(ip) + # checking mode - latest_fails = self.storage[ip] + latest_fails = self.storage.get(cache_key) if latest_fails and len(latest_fails) >= self.limit: # too many fails recently if now - latest_fails[-1] < self.timeout: # too soon - timeout in play + self.touch(cache_key) return True else: # timeout has passed. clear faillist - del self.storage[ip] + self.remove(ip) return False else: return False
    @@ -194,7 +299,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/validators.html b/docs/0.9.5/_modules/evennia/server/validators.html index a396964bcc..ff1c97a4c6 100644 --- a/docs/0.9.5/_modules/evennia/server/validators.html +++ b/docs/0.9.5/_modules/evennia/server/validators.html @@ -126,8 +126,8 @@ """ return _( - "%s From a terminal client, you can also use a phrase of multiple words if " - "you enclose the password in double quotes." % self.policy + "{policy} From a terminal client, you can also use a phrase of multiple words if " + "you enclose the password in double quotes.".format(policy=self.policy) ) @@ -166,7 +166,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/server/webserver.html b/docs/0.9.5/_modules/evennia/server/webserver.html index 4a4cabd717..2be5ed545c 100644 --- a/docs/0.9.5/_modules/evennia/server/webserver.html +++ b/docs/0.9.5/_modules/evennia/server/webserver.html @@ -376,7 +376,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/typeclasses/admin.html b/docs/0.9.5/_modules/evennia/typeclasses/admin.html deleted file mode 100644 index ff4a8730e1..0000000000 --- a/docs/0.9.5/_modules/evennia/typeclasses/admin.html +++ /dev/null @@ -1,448 +0,0 @@ - - - - - - - - evennia.typeclasses.admin — Evennia 0.9.5 documentation - - - - - - - - - - - - - -
    -
    -
    -
    - -

    Source code for evennia.typeclasses.admin

    -import traceback
    -from datetime import datetime
    -from django.contrib import admin
    -from evennia.typeclasses.models import Tag
    -from django import forms
    -from evennia.utils.picklefield import PickledFormField
    -from evennia.utils.dbserialize import from_pickle, _SaverSet
    -
    -
    -
    [docs]class TagAdmin(admin.ModelAdmin): - """ - A django Admin wrapper for Tags. - """ - - search_fields = ("db_key", "db_category", "db_tagtype") - list_display = ("db_key", "db_category", "db_tagtype", "db_data") - fields = ("db_key", "db_category", "db_tagtype", "db_data") - list_filter = ("db_tagtype",)
    - - -
    [docs]class TagForm(forms.ModelForm): - """ - This form overrides the base behavior of the ModelForm that would be used for a - Tag-through-model. Since the through-models only have access to the foreignkeys of the Tag and - the Object that they're attached to, we need to spoof the behavior of it being a form that would - correspond to its tag, or the creation of a tag. Instead of being saved, we'll call to the - Object's handler, which will handle the creation, change, or deletion of a tag for us, as well - as updating the handler's cache so that all changes are instantly updated in-game. - """ - - tag_key = forms.CharField( - label="Tag Name", required=True, help_text="This is the main key identifier" - ) - tag_category = forms.CharField( - label="Category", - help_text="Used for grouping tags. Unset (default) gives a category of None", - required=False, - ) - tag_type = forms.CharField( - label="Type", - help_text='Internal use. Either unset, "alias" or "permission"', - required=False, - ) - tag_data = forms.CharField( - label="Data", - help_text="Usually unused. Intended for eventual info about the tag itself", - required=False, - ) - -
    [docs] class Meta: - fields = ("tag_key", "tag_category", "tag_data", "tag_type")
    - -
    [docs] def __init__(self, *args, **kwargs): - """ - If we have a tag, then we'll prepopulate our instance with the fields we'd expect it - to have based on the tag. tag_key, tag_category, tag_type, and tag_data all refer to - the corresponding tag fields. The initial data of the form fields will similarly be - populated. - """ - super().__init__(*args, **kwargs) - tagkey = None - tagcategory = None - tagtype = None - tagdata = None - if hasattr(self.instance, "tag"): - tagkey = self.instance.tag.db_key - tagcategory = self.instance.tag.db_category - tagtype = self.instance.tag.db_tagtype - tagdata = self.instance.tag.db_data - self.fields["tag_key"].initial = tagkey - self.fields["tag_category"].initial = tagcategory - self.fields["tag_type"].initial = tagtype - self.fields["tag_data"].initial = tagdata - self.instance.tag_key = tagkey - self.instance.tag_category = tagcategory - self.instance.tag_type = tagtype - self.instance.tag_data = tagdata
    - -
    [docs] def save(self, commit=True): - """ - One thing we want to do here is the or None checks, because forms are saved with an empty - string rather than null from forms, usually, and the Handlers may handle empty strings - differently than None objects. So for consistency with how things are handled in game, - we'll try to make sure that empty form fields will be None, rather than ''. - """ - # we are spoofing a tag for the Handler that will be called - # instance = super().save(commit=False) - instance = self.instance - instance.tag_key = self.cleaned_data["tag_key"] - instance.tag_category = self.cleaned_data["tag_category"] or None - instance.tag_type = self.cleaned_data["tag_type"] or None - instance.tag_data = self.cleaned_data["tag_data"] or None - return instance
    - - -
    [docs]class TagFormSet(forms.BaseInlineFormSet): - """ - The Formset handles all the inline forms that are grouped together on the change page of the - corresponding object. All the tags will appear here, and we'll save them by overriding the - formset's save method. The forms will similarly spoof their save methods to return an instance - which hasn't been saved to the database, but have the relevant fields filled out based on the - contents of the cleaned form. We'll then use that to call to the handler of the corresponding - Object, where the handler is an AliasHandler, PermissionsHandler, or TagHandler, based on the - type of tag. - """ - -
    [docs] def save(self, commit=True): - def get_handler(finished_object): - related = getattr(finished_object, self.related_field) - try: - tagtype = finished_object.tag_type - except AttributeError: - tagtype = finished_object.tag.db_tagtype - if tagtype == "alias": - handler_name = "aliases" - elif tagtype == "permission": - handler_name = "permissions" - else: - handler_name = "tags" - return getattr(related, handler_name) - - instances = super().save(commit=False) - # self.deleted_objects is a list created when super of save is called, we'll remove those - for obj in self.deleted_objects: - handler = get_handler(obj) - handler.remove(obj.tag_key, category=obj.tag_category) - for instance in instances: - handler = get_handler(instance) - handler.add(instance.tag_key, category=instance.tag_category, data=instance.tag_data)
    - - -
    [docs]class TagInline(admin.TabularInline): - """ - A handler for inline Tags. This class should be subclassed in the admin of your models, - and the 'model' and 'related_field' class attributes must be set. model should be the - through model (ObjectDB_db_tag', for example), while related field should be the name - of the field on that through model which points to the model being used: 'objectdb', - 'msg', 'accountdb', etc. - """ - - # Set this to the through model of your desired M2M when subclassing. - model = None - form = TagForm - formset = TagFormSet - related_field = None # Must be 'objectdb', 'accountdb', 'msg', etc. Set when subclassing - # raw_id_fields = ('tag',) - # readonly_fields = ('tag',) - extra = 0 - -
    [docs] def get_formset(self, request, obj=None, **kwargs): - """ - get_formset has to return a class, but we need to make the class that we return - know about the related_field that we'll use. Returning the class itself rather than - a proxy isn't threadsafe, since it'd be the base class and would change if multiple - people used the admin at the same time - """ - formset = super().get_formset(request, obj, **kwargs) - - class ProxyFormset(formset): - pass - - ProxyFormset.related_field = self.related_field - return ProxyFormset
    - - -
    [docs]class AttributeForm(forms.ModelForm): - """ - This form overrides the base behavior of the ModelForm that would be used for a Attribute-through-model. - Since the through-models only have access to the foreignkeys of the Attribute and the Object that they're - attached to, we need to spoof the behavior of it being a form that would correspond to its Attribute, - or the creation of an Attribute. Instead of being saved, we'll call to the Object's handler, which will handle - the creation, change, or deletion of an Attribute for us, as well as updating the handler's cache so that all - changes are instantly updated in-game. - """ - - attr_key = forms.CharField( - label="Attribute Name", required=False, initial="Enter Attribute Name Here" - ) - attr_category = forms.CharField( - label="Category", help_text="type of attribute, for sorting", required=False, max_length=128 - ) - attr_value = PickledFormField(label="Value", help_text="Value to pickle/save", required=False) - attr_type = forms.CharField( - label="Type", - help_text='Internal use. Either unset (normal Attribute) or "nick"', - required=False, - max_length=16, - ) - attr_lockstring = forms.CharField( - label="Locks", - required=False, - help_text="Lock string on the form locktype:lockdef;lockfunc:lockdef;...", - widget=forms.Textarea(attrs={"rows": 1, "cols": 8}), - ) - -
    [docs] class Meta: - fields = ("attr_key", "attr_value", "attr_category", "attr_lockstring", "attr_type")
    - -
    [docs] def __init__(self, *args, **kwargs): - """ - If we have an Attribute, then we'll prepopulate our instance with the fields we'd expect it - to have based on the Attribute. attr_key, attr_category, attr_value, attr_type, - and attr_lockstring all refer to the corresponding Attribute fields. The initial data of the form fields will - similarly be populated. - - """ - super().__init__(*args, **kwargs) - attr_key = None - attr_category = None - attr_value = None - attr_type = None - attr_lockstring = None - if hasattr(self.instance, "attribute"): - attr_key = self.instance.attribute.db_key - attr_category = self.instance.attribute.db_category - attr_value = self.instance.attribute.db_value - attr_type = self.instance.attribute.db_attrtype - attr_lockstring = self.instance.attribute.db_lock_storage - self.fields["attr_key"].initial = attr_key - self.fields["attr_category"].initial = attr_category - self.fields["attr_type"].initial = attr_type - self.fields["attr_value"].initial = attr_value - self.fields["attr_lockstring"].initial = attr_lockstring - self.instance.attr_key = attr_key - self.instance.attr_category = attr_category - self.instance.attr_value = attr_value - - # prevent from being transformed to str - if isinstance(attr_value, (set, _SaverSet)): - self.fields["attr_value"].disabled = True - - self.instance.deserialized_value = from_pickle(attr_value) - self.instance.attr_type = attr_type - self.instance.attr_lockstring = attr_lockstring
    - -
    [docs] def save(self, commit=True): - """ - One thing we want to do here is the or None checks, because forms are saved with an empty - string rather than null from forms, usually, and the Handlers may handle empty strings - differently than None objects. So for consistency with how things are handled in game, - we'll try to make sure that empty form fields will be None, rather than ''. - """ - # we are spoofing an Attribute for the Handler that will be called - instance = self.instance - instance.attr_key = self.cleaned_data["attr_key"] or "no_name_entered_for_attribute" - instance.attr_category = self.cleaned_data["attr_category"] or None - instance.attr_value = self.cleaned_data["attr_value"] - # convert the serialized string value into an object, if necessary, for AttributeHandler - instance.attr_value = from_pickle(instance.attr_value) - instance.attr_type = self.cleaned_data["attr_type"] or None - instance.attr_lockstring = self.cleaned_data["attr_lockstring"] - return instance
    - -
    [docs] def clean_attr_value(self): - """ - Prevent certain data-types from being cleaned due to literal_eval - failing on them. Otherwise they will be turned into str. - - """ - data = self.cleaned_data["attr_value"] - initial = self.instance.attr_value - if isinstance(initial, (set, _SaverSet, datetime)): - return initial - return data
    - - -
    [docs]class AttributeFormSet(forms.BaseInlineFormSet): - """ - Attribute version of TagFormSet, as above. - """ - -
    [docs] def save(self, commit=True): - def get_handler(finished_object): - related = getattr(finished_object, self.related_field) - try: - attrtype = finished_object.attr_type - except AttributeError: - attrtype = finished_object.attribute.db_attrtype - if attrtype == "nick": - handler_name = "nicks" - else: - handler_name = "attributes" - return getattr(related, handler_name) - - instances = super().save(commit=False) - for obj in self.deleted_objects: - # self.deleted_objects is a list created when super of save is called, we'll remove those - handler = get_handler(obj) - handler.remove(obj.attr_key, category=obj.attr_category) - - for instance in instances: - handler = get_handler(instance) - - value = instance.attr_value - - try: - handler.add( - instance.attr_key, - value, - category=instance.attr_category, - strattr=False, - lockstring=instance.attr_lockstring, - ) - except (TypeError, ValueError): - # catch errors in nick templates and continue - traceback.print_exc() - continue
    - - -
    [docs]class AttributeInline(admin.TabularInline): - """ - A handler for inline Attributes. This class should be subclassed in the admin of your models, - and the 'model' and 'related_field' class attributes must be set. model should be the - through model (ObjectDB_db_tag', for example), while related field should be the name - of the field on that through model which points to the model being used: 'objectdb', - 'msg', 'accountdb', etc. - """ - - # Set this to the through model of your desired M2M when subclassing. - model = None - form = AttributeForm - formset = AttributeFormSet - related_field = None # Must be 'objectdb', 'accountdb', 'msg', etc. Set when subclassing - # raw_id_fields = ('attribute',) - # readonly_fields = ('attribute',) - extra = 0 - -
    [docs] def get_formset(self, request, obj=None, **kwargs): - """ - get_formset has to return a class, but we need to make the class that we return - know about the related_field that we'll use. Returning the class itself rather than - a proxy isn't threadsafe, since it'd be the base class and would change if multiple - people used the admin at the same time - """ - formset = super().get_formset(request, obj, **kwargs) - - class ProxyFormset(formset): - pass - - ProxyFormset.related_field = self.related_field - return ProxyFormset
    - - -admin.site.register(Tag, TagAdmin) -
    - -
    -
    -
    -
    - -
    -
    - - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/typeclasses/attributes.html b/docs/0.9.5/_modules/evennia/typeclasses/attributes.html index d39e22b521..897370aa08 100644 --- a/docs/0.9.5/_modules/evennia/typeclasses/attributes.html +++ b/docs/0.9.5/_modules/evennia/typeclasses/attributes.html @@ -51,7 +51,8 @@ """ import re import fnmatch -import weakref + +from collections import defaultdict from django.db import models from django.conf import settings @@ -72,7 +73,7 @@ # ------------------------------------------------------------- -
    [docs]class Attribute(SharedMemoryModel): +
    [docs]class IAttribute: """ Attributes are things that are specific to different types of objects. For example, a drink container needs to store its fill level, whereas an exit @@ -94,6 +95,115 @@ - category (str): Optional character string for grouping the Attribute. + This class is an API/Interface/Abstract base class; do not instantiate it directly. + """ + +
    [docs] @lazy_property + def locks(self): + return LockHandler(self)
    + + key = property(lambda self: self.db_key) + strvalue = property(lambda self: self.db_strvalue) + category = property(lambda self: self.db_category) + model = property(lambda self: self.db_model) + attrtype = property(lambda self: self.db_attrtype) + date_created = property(lambda self: self.db_date_created) + + def __lock_storage_get(self): + return self.db_lock_storage + + def __lock_storage_set(self, value): + self.db_lock_storage = value + + def __lock_storage_del(self): + self.db_lock_storage = "" + + lock_storage = property(__lock_storage_get, __lock_storage_set, __lock_storage_del) + +
    [docs] def access(self, accessing_obj, access_type="read", default=False, **kwargs): + """ + Determines if another object has permission to access. + + Args: + accessing_obj (object): Entity trying to access this one. + access_type (str, optional): Type of access sought, see + the lock documentation. + default (bool, optional): What result to return if no lock + of access_type was found. The default, `False`, means a lockdown + policy, only allowing explicit access. + kwargs (any, optional): Not used; here to make the API consistent with + other access calls. + + Returns: + result (bool): If the lock was passed or not. + + """ + result = self.locks.check(accessing_obj, access_type=access_type, default=default) + return result
    + + # + # + # Attribute methods + # + # + + def __str__(self): + return smart_str("%s(%s)" % (self.db_key, self.id)) + + def __repr__(self): + return "%s(%s)" % (self.db_key, self.id)
    + + +
    [docs]class InMemoryAttribute(IAttribute): + """ + This Attribute is used purely for NAttributes/NAttributeHandler. It has no database backend. + + """ + + # Primary Key has no meaning for an InMemoryAttribute. This merely serves to satisfy other code. + +
    [docs] def __init__(self, pk, **kwargs): + """ + Create an Attribute that exists only in Memory. + + Args: + pk (int): This is a fake 'primary key' / id-field. It doesn't actually have to be + unique, but is fed an incrementing number from the InMemoryBackend by default. This + is needed only so Attributes can be sorted. Some parts of the API also see the lack + of a .pk field as a sign that the Attribute was deleted. + **kwargs: Other keyword arguments are used to construct the actual Attribute. + + """ + self.id = pk + self.pk = pk + + # Copy all kwargs to local properties. We use db_ for compatability here. + for key, value in kwargs.items(): + # Value and locks are special. We must call the wrappers. + if key == "value": + self.value = value + elif key == "lock_storage": + self.lock_storage = value + else: + setattr(self, f"db_{key}", value)
    + + # value property (wraps db_value) + def __value_get(self): + return self.db_value + + def __value_set(self, new_value): + self.db_value = new_value + + def __value_del(self): + pass + + value = property(__value_get, __value_set, __value_del)
    + + +
    [docs]class Attribute(IAttribute, SharedMemoryModel): + """ + This attribute is stored via Django. Most Attributes will be using this class. + """ # @@ -150,34 +260,9 @@ # Database manager # objects = managers.AttributeManager() -
    [docs] @lazy_property - def locks(self): - return LockHandler(self)
    - class Meta(object): "Define Django meta options" - verbose_name = "Evennia Attribute" - - # read-only wrappers - key = property(lambda self: self.db_key) - strvalue = property(lambda self: self.db_strvalue) - category = property(lambda self: self.db_category) - model = property(lambda self: self.db_model) - attrtype = property(lambda self: self.db_attrtype) - date_created = property(lambda self: self.db_date_created) - - def __lock_storage_get(self): - return self.db_lock_storage - - def __lock_storage_set(self, value): - self.db_lock_storage = value - self.save(update_fields=["db_lock_storage"]) - - def __lock_storage_del(self): - self.db_lock_storage = "" - self.save(update_fields=["db_lock_storage"]) - - lock_storage = property(__lock_storage_get, __lock_storage_set, __lock_storage_del) + verbose_name = "Attribute" # Wrapper properties to easily set database fields. These are # @property decorators that allows to access these fields using @@ -187,9 +272,23 @@ # value = self.attr and del self.attr respectively (where self # is the object in question). + # lock_storage wrapper. Overloaded for saving to database. + def __lock_storage_get(self): + return self.db_lock_storage + + def __lock_storage_set(self, value): + super().__lock_storage_set(value) + self.save(update_fields=["db_lock_storage"]) + + def __lock_storage_del(self): + super().__lock_storage_del() + self.save(update_fields=["db_lock_storage"]) + + lock_storage = property(__lock_storage_get, __lock_storage_set, __lock_storage_del) + # value property (wraps db_value) - # @property - def __value_get(self): + @property + def value(self): """ Getter. Allows for `value = self.value`. We cannot cache here since it makes certain cases (such @@ -198,115 +297,164 @@ """ return from_pickle(self.db_value, db_obj=self) - # @value.setter - def __value_set(self, new_value): + @value.setter + def value(self, new_value): """ Setter. Allows for self.value = value. We cannot cache here, see self.__value_get. """ self.db_value = to_pickle(new_value) - # print("value_set, self.db_value:", repr(self.db_value)) # DEBUG self.save(update_fields=["db_value"]) - # @value.deleter - def __value_del(self): + @value.deleter + def value(self): """Deleter. Allows for del attr.value. This removes the entire attribute.""" - self.delete() - - value = property(__value_get, __value_set, __value_del) - - # - # - # Attribute methods - # - # - - def __str__(self): - return smart_str("%s[category=%s](#%s)" % (self.db_key, self.db_category, self.id)) - - def __repr__(self): - return "%s[category=%s](#%s)" % (self.db_key, self.db_category, self.id) - -
    [docs] def access(self, accessing_obj, access_type="attrread", default=False, **kwargs): - """ - Determines if another object has permission to access. - - Args: - accessing_obj (object): Entity trying to access this one. - access_type (str, optional): Type of access sought, see - the lock documentation. - default (bool, optional): What result to return if no lock - of access_type was found. The default, `False`, means a lockdown - policy, only allowing explicit access. - kwargs (any, optional): Not used; here to make the API consistent with - other access calls. - - Returns: - result (bool): If the lock was passed or not. - - """ - result = self.locks.check(accessing_obj, access_type=access_type, default=default) - return result
    - + self.delete()
    # # Handlers making use of the Attribute model # -
    [docs]class AttributeHandler(object): +
    [docs]class IAttributeBackend: """ - Handler for adding Attributes to the object. + Abstract interface for the backends used by the Attribute Handler. + + All Backends must implement this base class. """ - _m2m_fieldname = "db_attributes" _attrcreate = "attrcreate" _attredit = "attredit" _attrread = "attrread" - _attrtype = None + _attrclass = None -
    [docs] def __init__(self, obj): - """Initialize handler.""" - self.obj = obj - self._objid = obj.id - self._model = to_str(obj.__dbclass__.__name__.lower()) +
    [docs] def __init__(self, handler, attrtype): + self.handler = handler + self.obj = handler.obj + self._attrtype = attrtype + self._objid = handler.obj.id self._cache = {} # store category names fully cached self._catcache = {} # full cache was run on all attributes self._cache_complete = False
    - def _query_all(self): - "Fetch all Attributes on this object" - query = { - "%s__id" % self._model: self._objid, - "attribute__db_model__iexact": self._model, - "attribute__db_attrtype": self._attrtype, - } - return [ - conn.attribute - for conn in getattr(self.obj, self._m2m_fieldname).through.objects.filter(**query) - ] +
    [docs] def query_all(self): + """ + Fetch all Attributes from this object. - def _fullcache(self): + Returns: + attrlist (list): A list of Attribute objects. + """ + raise NotImplementedError()
    + +
    [docs] def query_key(self, key, category): + """ + + Args: + key (str): The key of the Attribute being searched for. + category (str or None): The category of the desired Attribute. + + Returns: + attribute (IAttribute): A single Attribute. + """ + raise NotImplementedError()
    + +
    [docs] def query_category(self, category): + """ + Returns every matching Attribute as a list, given a category. + + This method calls up whatever storage the backend uses. + + Args: + category (str or None): The category to query. + + Returns: + attrs (list): The discovered Attributes. + """ + raise NotImplementedError()
    + + def _full_cache(self): """Cache all attributes of this object""" if not _TYPECLASS_AGGRESSIVE_CACHE: return - attrs = self._query_all() - self._cache = dict( - ( - "%s-%s" - % ( - to_str(attr.db_key).lower(), - attr.db_category.lower() if attr.db_category is not None else None, - ), - attr, - ) + attrs = self.query_all() + self._cache = { + f"{to_str(attr.key).lower()}-{attr.category.lower() if attr.category else None}": attr for attr in attrs - ) + } self._cache_complete = True - def _getcache(self, key=None, category=None): + def _get_cache_key(self, key, category): + """ + Fetch cache key. + + Args: + key (str): The key of the Attribute being searched for. + category (str or None): The category of the desired Attribute. + + Returns: + attribute (IAttribute): A single Attribute. + """ + cachekey = "%s-%s" % (key, category) + cachefound = False + try: + attr = _TYPECLASS_AGGRESSIVE_CACHE and self._cache[cachekey] + cachefound = True + except KeyError: + attr = None + + if attr and (not hasattr(attr, "pk") and attr.pk is None): + # clear out Attributes deleted from elsewhere. We must search this anew. + attr = None + cachefound = False + del self._cache[cachekey] + if cachefound and _TYPECLASS_AGGRESSIVE_CACHE: + if attr: + return [attr] # return cached entity + else: + return [] # no such attribute: return an empty list + else: + conn = self.query_key(key, category) + if conn: + attr = conn[0].attribute + if _TYPECLASS_AGGRESSIVE_CACHE: + self._cache[cachekey] = attr + return [attr] if attr.pk else [] + else: + # There is no such attribute. We will explicitly save that + # in our cache to avoid firing another query if we try to + # retrieve that (non-existent) attribute again. + if _TYPECLASS_AGGRESSIVE_CACHE: + self._cache[cachekey] = None + return [] + + def _get_cache_category(self, category): + """ + Retrieves Attribute list (by category) from cache. + + Args: + category (str or None): The category to query. + + Returns: + attrs (list): The discovered Attributes. + """ + catkey = "-%s" % category + if _TYPECLASS_AGGRESSIVE_CACHE and catkey in self._catcache: + return [attr for key, attr in self._cache.items() if key.endswith(catkey) and attr] + else: + # we have to query to make this category up-date in the cache + attrs = self.query_category(category) + if _TYPECLASS_AGGRESSIVE_CACHE: + for attr in attrs: + if attr.pk: + cachekey = "%s-%s" % (attr.key, category) + self._cache[cachekey] = attr + # mark category cache as up-to-date + self._catcache[catkey] = True + return attrs + + def _get_cache(self, key=None, category=None): """ Retrieve from cache or database (always caches) @@ -332,85 +480,31 @@ key = key.strip().lower() if key else None category = category.strip().lower() if category is not None else None if key: - cachekey = "%s-%s" % (key, category) - cachefound = False - try: - attr = _TYPECLASS_AGGRESSIVE_CACHE and self._cache[cachekey] - cachefound = True - except KeyError: - attr = None + return self._get_cache_key(key, category) + return self._get_cache_category(category) - if attr and (not hasattr(attr, "pk") and attr.pk is None): - # clear out Attributes deleted from elsewhere. We must search this anew. - attr = None - cachefound = False - del self._cache[cachekey] - if cachefound and _TYPECLASS_AGGRESSIVE_CACHE: - if attr: - return [attr] # return cached entity - else: - return [] # no such attribute: return an empty list - else: - query = { - "%s__id" % self._model: self._objid, - "attribute__db_model__iexact": self._model, - "attribute__db_attrtype": self._attrtype, - "attribute__db_key__iexact": key.lower(), - "attribute__db_category__iexact": category.lower() if category else None, - } - if not self.obj.pk: - return [] - conn = getattr(self.obj, self._m2m_fieldname).through.objects.filter(**query) - if conn: - attr = conn[0].attribute - if _TYPECLASS_AGGRESSIVE_CACHE: - self._cache[cachekey] = attr - return [attr] if attr.pk else [] - else: - # There is no such attribute. We will explicitly save that - # in our cache to avoid firing another query if we try to - # retrieve that (non-existent) attribute again. - if _TYPECLASS_AGGRESSIVE_CACHE: - self._cache[cachekey] = None - return [] - else: - # only category given (even if it's None) - we can't - # assume the cache to be complete unless we have queried - # for this category before - catkey = "-%s" % category - if _TYPECLASS_AGGRESSIVE_CACHE and catkey in self._catcache: - return [attr for key, attr in self._cache.items() if key.endswith(catkey) and attr] - else: - # we have to query to make this category up-date in the cache - query = { - "%s__id" % self._model: self._objid, - "attribute__db_model__iexact": self._model, - "attribute__db_attrtype": self._attrtype, - "attribute__db_category__iexact": category.lower() if category else None, - } - attrs = [ - conn.attribute - for conn in getattr(self.obj, self._m2m_fieldname).through.objects.filter( - **query - ) - ] - if _TYPECLASS_AGGRESSIVE_CACHE: - for attr in attrs: - if attr.pk: - cachekey = "%s-%s" % (attr.db_key, category) - self._cache[cachekey] = attr - # mark category cache as up-to-date - self._catcache[catkey] = True - return attrs +
    [docs] def get(self, key=None, category=None): + """ + Frontend for .get_cache. Retrieves Attribute(s). - def _setcache(self, key, category, attr_obj): + Args: + key (str, optional): Attribute key to query for + category (str, optional): Attribiute category + + Returns: + args (list): Returns a list of zero or more matches + found from cache or database. + """ + return self._get_cache(key, category)
    + + def _set_cache(self, key, category, attr_obj): """ Update cache. Args: key (str): A cleaned key string category (str or None): A cleaned category name - attr_obj (Attribute): The newly saved attribute + attr_obj (IAttribute): The newly saved attribute """ if not _TYPECLASS_AGGRESSIVE_CACHE: @@ -424,7 +518,7 @@ self._catcache.pop(catkey, None) self._cache_complete = False - def _delcache(self, key, category): + def _delete_cache(self, key, category): """ Remove attribute from cache @@ -447,7 +541,7 @@ self._catcache.pop(catkey, None) self._cache_complete = False -
    [docs] def reset_cache(self): +
    [docs] def reset_cache(self): """ Reset cache from the outside. """ @@ -455,6 +549,435 @@ self._cache = {} self._catcache = {}
    +
    [docs] def do_create_attribute(self, key, category, lockstring, value, strvalue): + """ + Does the hard work of actually creating Attributes, whatever is needed. + + Args: + key (str): The Attribute's key. + category (str or None): The Attribute's category, or None + lockstring (str): Any locks for the Attribute. + value (obj): The Value of the Attribute. + strvalue (bool): Signifies if this is a strvalue Attribute. Value MUST be a string or + this will lead to Trouble. Ignored for InMemory attributes. + + Returns: + attr (IAttribute): The new Attribute. + """ + raise NotImplementedError()
    + +
    [docs] def create_attribute(self, key, category, lockstring, value, strvalue=False, cache=True): + """ + Creates Attribute (using the class specified for the backend), (optionally) caches it, and + returns it. + + This MUST actively save the Attribute to whatever database backend is used, AND + call self.set_cache(key, category, new_attrobj) + + Args: + key (str): The Attribute's key. + category (str or None): The Attribute's category, or None + lockstring (str): Any locks for the Attribute. + value (obj): The Value of the Attribute. + strvalue (bool): Signifies if this is a strvalue Attribute. Value MUST be a string or + this will lead to Trouble. Ignored for InMemory attributes. + cache (bool): Whether to cache the new Attribute + + Returns: + attr (IAttribute): The new Attribute. + """ + attr = self.do_create_attribute(key, category, lockstring, value, strvalue) + if cache: + self._set_cache(key, category, attr) + return attr
    + +
    [docs] def do_update_attribute(self, attr, value): + """ + Simply sets a new Value to an Attribute. + + Args: + attr (IAttribute): The Attribute being changed. + value (obj): The Value for the Attribute. + + """ + raise NotImplementedError()
    + +
    [docs] def do_batch_update_attribute(self, attr_obj, category, lock_storage, new_value, strvalue): + """ + Called opnly by batch add. For the database backend, this is a method + of updating that can alter category and lock-storage. + + Args: + attr_obj (IAttribute): The Attribute being altered. + category (str or None): The attribute's (new) category. + lock_storage (str): The attribute's new locks. + new_value (obj): The Attribute's new value. + strvalue (bool): Signifies if this is a strvalue Attribute. Value MUST be a string or + this will lead to Trouble. Ignored for InMemory attributes. + """ + raise NotImplementedError()
    + +
    [docs] def do_batch_finish(self, attr_objs): + """ + Called after batch_add completed. Used for handling database operations + and/or caching complications. + + Args: + attr_objs (list of IAttribute): The Attributes created/updated thus far. + + """ + raise NotImplementedError()
    + +
    [docs] def batch_add(self, *args, **kwargs): + """ + Batch-version of `.add()`. This is more efficient than repeat-calling + `.add` when having many Attributes to add. + + Args: + *args (tuple): Tuples of varying length representing the + Attribute to add to this object. Supported tuples are + + - (key, value) + - (key, value, category) + - (key, value, category, lockstring) + - (key, value, category, lockstring, default_access) + + Raises: + RuntimeError: If trying to pass a non-iterable as argument. + + Notes: + The indata tuple order matters, so if you want a lockstring but no + category, set the category to `None`. This method does not have the + ability to check editing permissions and is mainly used internally. + It does not use the normal `self.add` but applies the Attributes + directly to the database. + + """ + new_attrobjs = [] + strattr = kwargs.get("strattr", False) + for tup in args: + if not is_iter(tup) or len(tup) < 2: + raise RuntimeError("batch_add requires iterables as arguments (got %r)." % tup) + ntup = len(tup) + keystr = str(tup[0]).strip().lower() + new_value = tup[1] + category = str(tup[2]).strip().lower() if ntup > 2 and tup[2] is not None else None + lockstring = tup[3] if ntup > 3 else "" + + attr_objs = self._get_cache(keystr, category) + + if attr_objs: + attr_obj = attr_objs[0] + # update an existing attribute object + self.do_batch_update_attribute(attr_obj, category, lockstring, new_value, strattr) + else: + new_attr = self.do_create_attribute( + keystr, category, lockstring, new_value, strvalue=strattr + ) + new_attrobjs.append(new_attr) + if new_attrobjs: + self.do_batch_finish(new_attrobjs)
    + +
    [docs] def do_delete_attribute(self, attr): + """ + Does the hard work of actually deleting things. + + Args: + attr (IAttribute): The attribute to delete. + """ + raise NotImplementedError()
    + +
    [docs] def delete_attribute(self, attr): + """ + Given an Attribute, deletes it. Also remove it from cache. + + Args: + attr (IAttribute): The attribute to delete. + """ + if not attr: + return + self._delete_cache(attr.key, attr.category) + self.do_delete_attribute(attr)
    + +
    [docs] def update_attribute(self, attr, value): + """ + Simply updates an Attribute. + + Args: + attr (IAttribute): The attribute to delete. + value (obj): The new value. + """ + self.do_update_attribute(attr, value)
    + +
    [docs] def do_batch_delete(self, attribute_list): + """ + Given a list of attributes, deletes them all. + The default implementation is fine, but this is overridable since some databases may allow + for a better method. + + Args: + attribute_list (list of IAttribute): + """ + for attribute in attribute_list: + self.delete_attribute(attribute)
    + +
    [docs] def clear_attributes(self, category, accessing_obj, default_access): + """ + Remove all Attributes on this object. + + Args: + category (str, optional): If given, clear only Attributes + of this category. + accessing_obj (object, optional): If given, check the + `attredit` lock on each Attribute before continuing. + default_access (bool, optional): Use this permission as + fallback if `access_obj` is given but there is no lock of + type `attredit` on the Attribute in question. + + """ + category = category.strip().lower() if category is not None else None + + if not self._cache_complete: + self._full_cache() + + if category is not None: + attrs = [attr for attr in self._cache.values() if attr.category == category] + else: + attrs = self._cache.values() + + if accessing_obj: + self.do_batch_delete( + [ + attr + for attr in attrs + if attr.access(accessing_obj, self._attredit, default=default_access) + ] + ) + else: + # have to cast the results to a list or we'll get a RuntimeError for removing from the + # dict we're iterating + self.do_batch_delete(list(attrs)) + self.reset_cache()
    + +
    [docs] def get_all_attributes(self): + """ + Simply returns all Attributes of this object, sorted by their IDs. + + Returns: + attributes (list of IAttribute) + """ + if _TYPECLASS_AGGRESSIVE_CACHE: + if not self._cache_complete: + self._full_cache() + return sorted([attr for attr in self._cache.values() if attr], key=lambda o: o.id) + else: + return sorted([attr for attr in self.query_all() if attr], key=lambda o: o.id)
    + + +
    [docs]class InMemoryAttributeBackend(IAttributeBackend): + """ + This Backend for Attributes stores NOTHING in the database. Everything is kept in memory, and + normally lost on a crash, reload, shared memory flush, etc. It generates IDs for the Attributes + it manages, but these are of little importance beyond sorting and satisfying the caching logic + to know an Attribute hasn't been deleted out from under the cache's nose. + + """ + + _attrclass = InMemoryAttribute + +
    [docs] def __init__(self, handler, attrtype): + super().__init__(handler, attrtype) + self._storage = dict() + self._category_storage = defaultdict(list) + self._id_counter = 0
    + + def _next_id(self): + """ + Increments the internal ID counter and returns the new value. + + Returns: + next_id (int): A simple integer. + """ + self._id_counter += 1 + return self._id_counter + +
    [docs] def query_all(self): + return self._storage.values()
    + +
    [docs] def query_key(self, key, category): + found = self._storage.get((key, category), None) + if found: + return [found] + return []
    + +
    [docs] def query_category(self, category): + if category is None: + return self._storage.values() + return self._category_storage.get(category, [])
    + +
    [docs] def do_create_attribute(self, key, category, lockstring, value, strvalue): + """ + See parent class. + + strvalue has no meaning for InMemory attributes. + + """ + new_attr = self._attrclass( + pk=self._next_id(), key=key, category=category, lock_storage=lockstring, value=value + ) + self._storage[(key, category)] = new_attr + self._category_storage[category].append(new_attr) + return new_attr
    + +
    [docs] def do_update_attribute(self, attr, value): + attr.value = value
    + +
    [docs] def do_batch_update_attribute(self, attr_obj, category, lock_storage, new_value, strvalue): + """ + No need to bother saving anything. Just set some values. + """ + attr_obj.db_category = category + attr_obj.db_lock_storage = lock_storage if lock_storage else "" + attr_obj.value = new_value
    + +
    [docs] def do_batch_finish(self, attr_objs): + """ + Nothing to do here for In-Memory. + + Args: + attr_objs (list of IAttribute): The Attributes created/updated thus far. + """ + pass
    + +
    [docs] def do_delete_attribute(self, attr): + """ + Removes the Attribute from local storage. Once it's out of the cache, garbage collection + will handle the rest. + + Args: + attr (IAttribute): The attribute to delete. + """ + del self._storage[(attr.key, attr.category)] + self._category_storage[attr.category].remove(attr)
    + + +
    [docs]class ModelAttributeBackend(IAttributeBackend): + """ + Uses Django models for storing Attributes. + """ + + _attrclass = Attribute + _m2m_fieldname = "db_attributes" + +
    [docs] def __init__(self, handler, attrtype): + super().__init__(handler, attrtype) + self._model = to_str(handler.obj.__dbclass__.__name__.lower())
    + +
    [docs] def query_all(self): + query = { + "%s__id" % self._model: self._objid, + "attribute__db_model__iexact": self._model, + "attribute__db_attrtype": self._attrtype, + } + return [ + conn.attribute + for conn in getattr(self.obj, self._m2m_fieldname).through.objects.filter(**query) + ]
    + +
    [docs] def query_key(self, key, category): + query = { + "%s__id" % self._model: self._objid, + "attribute__db_model__iexact": self._model, + "attribute__db_attrtype": self._attrtype, + "attribute__db_key__iexact": key.lower(), + "attribute__db_category__iexact": category.lower() if category else None, + } + if not self.obj.pk: + return [] + return getattr(self.obj, self._m2m_fieldname).through.objects.filter(**query)
    + +
    [docs] def query_category(self, category): + query = { + "%s__id" % self._model: self._objid, + "attribute__db_model__iexact": self._model, + "attribute__db_attrtype": self._attrtype, + "attribute__db_category__iexact": category.lower() if category else None, + } + return [ + conn.attribute + for conn in getattr(self.obj, self._m2m_fieldname).through.objects.filter(**query) + ]
    + +
    [docs] def do_create_attribute(self, key, category, lockstring, value, strvalue): + kwargs = { + "db_key": key, + "db_category": category, + "db_model": self._model, + "db_lock_storage": lockstring if lockstring else "", + "db_attrtype": self._attrtype, + } + if strvalue: + kwargs["db_value"] = None + kwargs["db_strvalue"] = value + else: + kwargs["db_value"] = to_pickle(value) + kwargs["db_strvalue"] = None + new_attr = self._attrclass(**kwargs) + new_attr.save() + getattr(self.obj, self._m2m_fieldname).add(new_attr) + self._set_cache(key, category, new_attr) + return new_attr
    + +
    [docs] def do_update_attribute(self, attr, value): + attr.value = value
    + +
    [docs] def do_batch_update_attribute(self, attr_obj, category, lock_storage, new_value, strvalue): + attr_obj.db_category = category + attr_obj.db_lock_storage = lock_storage if lock_storage else "" + if strvalue: + # store as a simple string (will not notify OOB handlers) + attr_obj.db_strvalue = new_value + attr_obj.value = None + else: + # store normally (this will also notify OOB handlers) + attr_obj.value = new_value + attr_obj.db_strvalue = None + attr_obj.save(update_fields=["db_strvalue", "db_value", "db_category", "db_lock_storage"])
    + +
    [docs] def do_batch_finish(self, attr_objs): + # Add new objects to m2m field all at once + getattr(self.obj, self._m2m_fieldname).add(*attr_objs)
    + +
    [docs] def do_delete_attribute(self, attr): + try: + attr.delete() + except AssertionError: + # This could happen if the Attribute has already been deleted. + pass
    + + +
    [docs]class AttributeHandler: + """ + Handler for adding Attributes to the object. + """ + + _attrcreate = "attrcreate" + _attredit = "attredit" + _attrread = "attrread" + _attrtype = None + +
    [docs] def __init__(self, obj, backend_class): + """ + Setup the AttributeHandler. + + Args: + obj (TypedObject): An Account, Object, Channel, ServerSession (not technically a typed + object), etc. backend_class (IAttributeBackend class): The class of the backend to + use. + """ + self.obj = obj + self.backend = backend_class(self, self._attrtype)
    +
    [docs] def has(self, key=None, category=None): """ Checks if the given Attribute (or list of Attributes) exists on @@ -476,7 +999,7 @@ category = category.strip().lower() if category is not None else None for keystr in make_iter(key): keystr = key.strip().lower() - ret.extend(bool(attr) for attr in self._getcache(keystr, category)) + ret.extend(bool(attr) for attr in self.backend.get(keystr, category)) return ret[0] if len(ret) == 1 else ret
    [docs] def get( @@ -516,7 +1039,8 @@ looked-after Attribute. default_access (bool, optional): If no `attrread` lock is set on object, this determines if the lock should then be passed or not. - return_list (bool, optional): + return_list (bool, optional): Always return a list, also if there is only + one or zero matches found. Returns: result (any or list): One or more matches for keys and/or @@ -534,7 +1058,7 @@ ret = [] for keystr in make_iter(key): # it's okay to send a None key - attr_objs = self._getcache(keystr, category) + attr_objs = self.backend.get(keystr, category) if attr_objs: ret.extend(attr_objs) elif raise_exception: @@ -599,35 +1123,16 @@ return category = category.strip().lower() if category is not None else None - keystr = key.strip().lower() - attr_obj = self._getcache(key, category) + attr_obj = self.backend.get(key, category) if attr_obj: # update an existing attribute object attr_obj = attr_obj[0] - if strattr: - # store as a simple string (will not notify OOB handlers) - attr_obj.db_strvalue = value - attr_obj.save(update_fields=["db_strvalue"]) - else: - # store normally (this will also notify OOB handlers) - attr_obj.value = value + self.backend.update_attribute(attr_obj, value) else: # create a new Attribute (no OOB handlers can be notified) - kwargs = { - "db_key": keystr, - "db_category": category, - "db_model": self._model, - "db_attrtype": self._attrtype, - "db_value": None if strattr else to_pickle(value), - "db_strvalue": value if strattr else None, - } - new_attr = Attribute(**kwargs) - new_attr.save() - getattr(self.obj, self._m2m_fieldname).add(new_attr) - # update cache - self._setcache(keystr, category, new_attr)
    + self.backend.create_attribute(keystr, category, lockstring, value, strattr)
    [docs] def batch_add(self, *args, **kwargs): """ @@ -639,10 +1144,10 @@ length) representing the Attribute to add to this object. Supported tuples are - - `(key, value)` - - `(key, value, category)` - - `(key, value, category, lockstring)` - - `(key, value, category, lockstring, default_access)` + - (key, value) + - (key, value, category) + - (key, value, category, lockstring) + - (key, value, category, lockstring, default_access) Keyword Args: strattr (bool): If `True`, value must be a string. This @@ -662,50 +1167,7 @@ to the database. """ - new_attrobjs = [] - strattr = kwargs.get("strattr", False) - for tup in args: - if not is_iter(tup) or len(tup) < 2: - raise RuntimeError("batch_add requires iterables as arguments (got %r)." % tup) - ntup = len(tup) - keystr = str(tup[0]).strip().lower() - new_value = tup[1] - category = str(tup[2]).strip().lower() if ntup > 2 and tup[2] is not None else None - lockstring = tup[3] if ntup > 3 else "" - - attr_objs = self._getcache(keystr, category) - - if attr_objs: - attr_obj = attr_objs[0] - # update an existing attribute object - attr_obj.db_category = category - attr_obj.db_lock_storage = lockstring or "" - attr_obj.save(update_fields=["db_category", "db_lock_storage"]) - if strattr: - # store as a simple string (will not notify OOB handlers) - attr_obj.db_strvalue = new_value - attr_obj.save(update_fields=["db_strvalue"]) - else: - # store normally (this will also notify OOB handlers) - attr_obj.value = new_value - else: - # create a new Attribute (no OOB handlers can be notified) - kwargs = { - "db_key": keystr, - "db_category": category, - "db_model": self._model, - "db_attrtype": self._attrtype, - "db_value": None if strattr else to_pickle(new_value), - "db_strvalue": new_value if strattr else None, - "db_lock_storage": lockstring or "", - } - new_attr = Attribute(**kwargs) - new_attr.save() - new_attrobjs.append(new_attr) - self._setcache(keystr, category, new_attr) - if new_attrobjs: - # Add new objects to m2m field all at once - getattr(self.obj, self._m2m_fieldname).add(*new_attrobjs)
    + self.backend.batch_add(*args, **kwargs)
    [docs] def remove( self, @@ -754,20 +1216,13 @@ for keystr in make_iter(key): keystr = keystr.lower() - attr_objs = self._getcache(keystr, category) + attr_objs = self.backend.get(keystr, category) for attr_obj in attr_objs: if not ( accessing_obj and not attr_obj.access(accessing_obj, self._attredit, default=default_access) ): - try: - attr_obj.delete() - except AssertionError: - print("Assertionerror for attr.delete()") - # this happens if the attr was already deleted - pass - finally: - self._delcache(keystr, category) + self.backend.delete_attribute(attr_obj) if not attr_objs and raise_exception: raise AttributeError
    @@ -785,27 +1240,7 @@ type `attredit` on the Attribute in question. """ - category = category.strip().lower() if category is not None else None - - if not self._cache_complete: - self._fullcache() - - if category is not None: - attrs = [attr for attr in self._cache.values() if attr.category == category] - else: - attrs = self._cache.values() - - if accessing_obj: - [ - attr.delete() - for attr in attrs - if attr and attr.access(accessing_obj, self._attredit, default=default_access) - ] - else: - [attr.delete() for attr in attrs if attr and attr.pk] - self._cache = {} - self._catcache = {} - self._cache_complete = False
    + self.backend.clear_attributes(category, accessing_obj, default_access)
    [docs] def all(self, accessing_obj=None, default_access=True): """ @@ -824,12 +1259,7 @@ their values!) in the handler. """ - if _TYPECLASS_AGGRESSIVE_CACHE: - if not self._cache_complete: - self._fullcache() - attrs = sorted([attr for attr in self._cache.values() if attr], key=lambda o: o.id) - else: - attrs = sorted([attr for attr in self._query_all() if attr], key=lambda o: o.id) + attrs = self.backend.get_all_attributes() if accessing_obj: return [ @@ -838,9 +1268,45 @@ if attr.access(accessing_obj, self._attredit, default=default_access) ] else: - return attrs
    + return attrs + +
    [docs] def reset_cache(self): + self.backend.reset_cache()
    +# DbHolders for .db and .ndb properties on Typeclasses. + +_GA = object.__getattribute__ +_SA = object.__setattr__ + + +
    [docs]class DbHolder: + "Holder for allowing property access of attributes" + +
    [docs] def __init__(self, obj, name, manager_name="attributes"): + _SA(self, name, _GA(obj, manager_name)) + _SA(self, "name", name)
    + + def __getattribute__(self, attrname): + if attrname == "all": + # we allow to overload our default .all + attr = _GA(self, _GA(self, "name")).get("all") + return attr if attr else _GA(self, "all") + return _GA(self, _GA(self, "name")).get(attrname) + + def __setattr__(self, attrname, value): + _GA(self, _GA(self, "name")).add(attrname, value) + + def __delattr__(self, attrname): + _GA(self, _GA(self, "name")).remove(attrname) + +
    [docs] def get_all(self): + return _GA(self, _GA(self, "name")).get_all_attributes()
    + + all = property(get_all)
    + + +# # Nick templating # @@ -860,7 +1326,7 @@ This will be converted to the following regex: -\@desc (?P<1>\w+) (?P<2>\w+) $(?P<3>\w+) + \@desc (?P<1>\w+) (?P<2>\w+) $(?P<3>\w+) Supported template markers (through fnmatch) * matches anything (non-greedy) -> .*? @@ -871,8 +1337,10 @@ $N argument position (1-99) """ +_RE_OR = re.compile(r"(?<!\\)\|") +_RE_NICK_RE_ARG = re.compile(r"arg([1-9][0-9]?)") _RE_NICK_ARG = re.compile(r"\\(\$)([1-9][0-9]?)") -_RE_NICK_TEMPLATE_ARG = re.compile(r"(\$)([1-9][0-9]?)") +_RE_NICK_RAW_ARG = re.compile(r"(\$)([1-9][0-9]?)") _RE_NICK_SPACE = re.compile(r"\\ ") @@ -880,45 +1348,72 @@ pass -
    [docs]def initialize_nick_templates(in_template, out_template): +
    [docs]def initialize_nick_templates(pattern, replacement, pattern_is_regex=False): """ Initialize the nick templates for matching and remapping a string. Args: - in_template (str): The template to be used for nick recognition. - out_template (str): The template to be used to replace the string - matched by the in_template. + pattern (str): The pattern to be used for nick recognition. This will + be parsed for shell patterns into a regex, unless `pattern_is_regex` + is `True`, in which case it must be an already valid regex string. In + this case, instead of `$N`, numbered arguments must instead be given + as matching groups named as `argN`, such as `(?P<arg1>.+?)`. + replacement (str): The template to be used to replace the string + matched by the pattern. This can contain `$N` markers and is never + parsed into a regex. + pattern_is_regex (bool): If set, `pattern` is a full regex string + instead of containing shell patterns. Returns: - (regex, str): Regex to match against strings and a template - Template with markers `{arg1}`, `{arg2}`, etc for - replacement using the standard `.format` method. + regex, template (str): Regex to match against strings and template + with markers ``{arg1}, {arg2}``, etc for replacement using the standard + `.format` method. Raises: - attributes.NickTemplateInvalid: If the in/out template does not have a matching - number of $args. + evennia.typecalasses.attributes.NickTemplateInvalid: If the in/out + template does not have a matching number of `$args`. + + Examples: + - `pattern` (shell syntax): `"grin $1"` + - `pattern` (regex): `"grin (?P<arg1.+?>)"` + - `replacement`: `"emote gives a wicked grin to $1"` """ - # create the regex for in_template - regex_string = fnmatch.translate(in_template) - # we must account for a possible line break coming over the wire + # create the regex from the pattern + if pattern_is_regex: + # Note that for a regex we can't validate in the way we do for the shell + # pattern, since you may have complex OR statements or optional arguments. - # NOTE-PYTHON3: fnmatch.translate format changed since Python2 - regex_string = regex_string[:-2] + r"(?:[\n\r]*?)\Z" + # Explicit regex given from the onset - this already contains argN + # groups. we need to split out any | - separated parts so we can + # attach the line-break/ending extras all regexes require. + pattern_regex_string = r"|".join( + or_part + r"(?:[\n\r]*?)\Z" + for or_part in _RE_OR.split(pattern)) - # validate the templates - regex_args = [match.group(2) for match in _RE_NICK_ARG.finditer(regex_string)] - temp_args = [match.group(2) for match in _RE_NICK_TEMPLATE_ARG.finditer(out_template)] - if set(regex_args) != set(temp_args): - # We don't have the same $-tags in input/output. - raise NickTemplateInvalid + else: + # Shell pattern syntax - convert $N to argN groups + # for the shell pattern we make sure we have matching $N on both sides + pattern_args = [match.group(1) for match in _RE_NICK_RAW_ARG.finditer(pattern)] + replacement_args = [ + match.group(1) for match in _RE_NICK_RAW_ARG.finditer(replacement)] + if set(pattern_args) != set(replacement_args): + # We don't have the same amount of argN/$N tags in input/output. + raise NickTemplateInvalid("Nicks: Both in/out-templates must contain the same $N tags.") - regex_string = _RE_NICK_SPACE.sub(r"\\s+", regex_string) - regex_string = _RE_NICK_ARG.sub(lambda m: "(?P<arg%s>.+?)" % m.group(2), regex_string) - template_string = _RE_NICK_TEMPLATE_ARG.sub(lambda m: "{arg%s}" % m.group(2), out_template) + # generate regex from shell pattern + pattern_regex_string = fnmatch.translate(pattern) + pattern_regex_string = _RE_NICK_SPACE.sub(r"\\s+", pattern_regex_string) + pattern_regex_string = _RE_NICK_ARG.sub( + lambda m: "(?P<arg%s>.+?)" % m.group(2), pattern_regex_string) + # we must account for a possible line break coming over the wire + pattern_regex_string = pattern_regex_string[:-2] + r"(?:[\n\r]*?)\Z" - return regex_string, template_string
    + # map the replacement to match the arg1 group-names, to make replacement easy + replacement_string = _RE_NICK_RAW_ARG.sub(lambda m: "{arg%s}" % m.group(2), replacement) + + return pattern_regex_string, replacement_string
    [docs]def parse_nick_template(string, template_regex, outtemplate): @@ -926,17 +1421,21 @@ Parse a text using a template and map it to another template Args: - string (str): The input string to processj + string (str): The input string to process template_regex (regex): A template regex created with initialize_nick_template. outtemplate (str): The template to which to map the matches produced by the template_regex. This should have $1, $2, - etc to match the regex. + etc to match the template-regex. Un-found $N-markers (possible if + the regex has optional matching groups) are replaced with empty + strings. """ match = template_regex.match(string) if match: - return True, outtemplate.format(**match.groupdict()) + matchdict = {key: value if value is not None else "" + for key, value in match.groupdict().items()} + return True, outtemplate.format(**matchdict) return False, string
    @@ -985,6 +1484,9 @@ a string. kwargs (any, optional): These are passed on to `AttributeHandler.get`. + Returns: + str or tuple: The nick replacement string or nick tuple. + """ if return_tuple or "return_obj" in kwargs: return super().get(key=key, category=category, **kwargs) @@ -998,24 +1500,46 @@ ) return None -
    [docs] def add(self, key, replacement, category="inputline", **kwargs): +
    [docs] def add(self, pattern, replacement, category="inputline", pattern_is_regex=False, **kwargs): """ - Add a new nick. + Add a new nick, a mapping pattern -> replacement. Args: - key (str): A key (or template) for the nick to match for. - replacement (str): The string (or template) to replace `key` with (the "nickname"). + pattern (str): A pattern to match for. This will be parsed for + shell patterns using the `fnmatch` library and can contain + `$N`-markers to indicate the locations of arguments to catch. If + `pattern_is_regex=True`, this must instead be a valid regular + expression and the `$N`-markers must be named `argN` that matches + numbered regex groups (see examples). + replacement (str): The string (or template) to replace `key` with + (the "nickname"). This may contain `$N` markers to indicate where to + place the argument-matches category (str, optional): the category within which to retrieve the nick. The "inputline" means replacing data sent by the user. - kwargs (any, optional): These are passed on to `AttributeHandler.get`. + pattern_is_regex (bool): If `True`, the `pattern` will be parsed as a + raw regex string. Instead of using `$N` markers in this string, one + then must mark numbered arguments as a named regex-groupd named `argN`. + For example, `(?P<arg1>.+?)` will match the behavior of using `$1` + in the shell pattern. + **kwargs (any, optional): These are passed on to `AttributeHandler.get`. + + Notes: + For most cases, the shell-pattern is much shorter and easier. The + regex pattern form can be useful for more complex matchings though, + for example in order to add optional arguments, such as with + `(?P<argN>.*?)`. + + Example: + - pattern (default shell syntax): `"gr $1 at $2"` + - pattern (with pattern_is_regex=True): `r"gr (?P<arg1>.+?) at (?P<arg2>.+?)"` + - replacement: `"emote With a flourish, $1 grins at $2."` """ - if category == "channel": - nick_regex, nick_template = initialize_nick_templates(key + " $1", replacement + " $1") - else: - nick_regex, nick_template = initialize_nick_templates(key, replacement) - super().add(key, (nick_regex, nick_template, key, replacement), category=category, **kwargs)
    + nick_regex, nick_template = initialize_nick_templates( + pattern, replacement, pattern_is_regex=pattern_is_regex) + super().add(pattern, (nick_regex, nick_template, pattern, replacement), + category=category, **kwargs)
    [docs] def remove(self, key, category="inputline", **kwargs): """ @@ -1081,95 +1605,6 @@ if is_match: break return raw_string
    - - -
    [docs]class NAttributeHandler(object): - """ - This stand-alone handler manages non-database saving. - It is similar to `AttributeHandler` and is used - by the `.ndb` handler in the same way as `.db` does - for the `AttributeHandler`. - """ - -
    [docs] def __init__(self, obj): - """ - Initialized on the object - """ - self._store = {} - self.obj = weakref.proxy(obj)
    - -
    [docs] def has(self, key): - """ - Check if object has this attribute or not. - - Args: - key (str): The Nattribute key to check. - - Returns: - has_nattribute (bool): If Nattribute is set or not. - - """ - return key in self._store
    - -
    [docs] def get(self, key): - """ - Get the named key value. - - Args: - key (str): The Nattribute key to get. - - Returns: - the value of the Nattribute. - - """ - return self._store.get(key, None)
    - -
    [docs] def add(self, key, value): - """ - Add new key and value. - - Args: - key (str): The name of Nattribute to add. - value (any): The value to store. - - """ - self._store[key] = value
    - -
    [docs] def remove(self, key): - """ - Remove Nattribute from storage. - - Args: - key (str): The name of the Nattribute to remove. - - """ - if key in self._store: - del self._store[key]
    - -
    [docs] def clear(self): - """ - Remove all NAttributes from handler. - - """ - self._store = {}
    - -
    [docs] def all(self, return_tuples=False): - """ - List the contents of the handler. - - Args: - return_tuples (bool, optional): Defines if the Nattributes - are returns as a list of keys or as a list of `(key, value)`. - - Returns: - nattributes (list): A list of keys `[key, key, ...]` or a - list of tuples `[(key, value), ...]` depending on the - setting of `return_tuples`. - - """ - if return_tuples: - return [(key, value) for (key, value) in self._store.items() if not key.startswith("_")] - return [key for key in self._store if not key.startswith("_")]
    @@ -1207,7 +1642,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/typeclasses/managers.html b/docs/0.9.5/_modules/evennia/typeclasses/managers.html index c41f400c71..1a98c2e99b 100644 --- a/docs/0.9.5/_modules/evennia/typeclasses/managers.html +++ b/docs/0.9.5/_modules/evennia/typeclasses/managers.html @@ -75,14 +75,12 @@ self, key=None, category=None, value=None, strvalue=None, obj=None, attrtype=None, **kwargs ): """ - Return Attribute objects by key, by category, by value, by - `strvalue`, by object (it is stored on) or with a combination of - those criteria. + Return Attribute objects by key, by category, by value, by strvalue, by + object (it is stored on) or with a combination of those criteria. Args: - key (str, optional): The attribute's key to search for. - category (str, optional): The category of the attribute(s) - to search for. + key (str, optional): The attribute's key to search for + category (str, optional): The category of the attribute(s) to search for. value (str, optional): The attribute value to search for. Note that this is not a very efficient operation since it will query for a pickled entity. Mutually exclusive to @@ -93,13 +91,13 @@ precedence if given. obj (Object, optional): On which object the Attribute to search for is. - attrtype (str, optional): An attribute-type to search for. + attrype (str, optional): An attribute-type to search for. By default this is either `None` (normal Attributes) or `"nick"`. - kwargs (any): Currently unused. Reserved for future use. + **kwargs (any): Currently unused. Reserved for future use. Returns: - attributes (list): The matching Attributes. + list: The matching Attributes. """ dbmodel = self.model.__dbclass__.__name__.lower() @@ -217,7 +215,7 @@ to search for. obj (Object, optional): On which object the Tag to search for is. - tagtype (str, optional): One of None (normal tags), + tagtype (str, optional): One of `None` (normal tags), "alias" or "permission" global_search (bool, optional): Include all possible tags, not just tags on this object @@ -620,7 +618,7 @@ for parent in (parent for parent in parents if hasattr(parent, "path")): query = query | Q(db_typeclass_path__exact=parent.path) # actually query the database - return self.filter(query) + return super().filter(query) class TypeclassManager(TypedObjectManager): @@ -638,13 +636,21 @@ Search by supplying a string with optional extra search criteria to aid the query. Args: - query (str): A search criteria that accepts extra search criteria on the + query (str): A search criteria that accepts extra search criteria on the following + forms: + + [key|alias|#dbref...] + [tag==<tagstr>[:category]...] + [attr==<key>:<value>:category...] + + All three can be combined in the same query, separated by spaces. - following forms: [key|alias|#dbref...] [tag==<tagstr>[:category]...] [attr==<key>:<value>:category...] - " != " != " Returns: - matches (queryset): A queryset result matching all queries exactly. If wanting to use spaces or - ==, != in tags or attributes, enclose them in quotes. + matches (queryset): A queryset result matching all queries exactly. If wanting to use + spaces or ==, != in tags or attributes, enclose them in quotes. + + Example: + house = smart_search("key=foo alias=bar tag=house:building tag=magic attr=color:red") Note: The flexibility of this method is limited by the input line format. Tag/attribute @@ -926,7 +932,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/typeclasses/models.html b/docs/0.9.5/_modules/evennia/typeclasses/models.html index de1abcbf76..58666ce271 100644 --- a/docs/0.9.5/_modules/evennia/typeclasses/models.html +++ b/docs/0.9.5/_modules/evennia/typeclasses/models.html @@ -65,8 +65,6 @@ This module also contains the Managers for the respective models; inherit from these to create custom managers. ----- - """ from django.db.models import signals @@ -79,7 +77,13 @@ from django.utils.encoding import smart_str from django.utils.text import slugify -from evennia.typeclasses.attributes import Attribute, AttributeHandler, NAttributeHandler +from evennia.typeclasses.attributes import ( + Attribute, + AttributeHandler, + ModelAttributeBackend, + InMemoryAttributeBackend, +) +from evennia.typeclasses.attributes import DbHolder from evennia.typeclasses.tags import Tag, TagHandler, AliasHandler, PermissionHandler from evennia.utils.idmapper.models import SharedMemoryModel, SharedMemoryModelBase @@ -106,6 +110,7 @@ def call_at_first_save(sender, instance, created, **kwargs): """ Receives a signal just after the object is saved. + """ if created: instance.at_first_save() @@ -114,6 +119,7 @@ def remove_attributes_on_delete(sender, instance, **kwargs): """ Wipe object's Attributes when it's deleted + """ instance.db_attributes.all().delete() @@ -135,6 +141,7 @@ Metaclass which should be set for the root of model proxies that don't define any new fields, like Object, Script etc. This is the basis for the typeclassing system. + """ def __new__(cls, name, bases, attrs): @@ -203,35 +210,6 @@ return new_class -class DbHolder(object): - """ - Holder for allowing property access of attributes. - - """ - - def __init__(self, obj, name, manager_name="attributes"): - _SA(self, name, _GA(obj, manager_name)) - _SA(self, "name", name) - - def __getattribute__(self, attrname): - if attrname == "all": - # we allow to overload our default .all - attr = _GA(self, _GA(self, "name")).get("all") - return attr if attr else _GA(self, "all") - return _GA(self, _GA(self, "name")).get(attrname) - - def __setattr__(self, attrname, value): - _GA(self, _GA(self, "name")).add(attrname, value) - - def __delattr__(self, attrname): - _GA(self, _GA(self, "name")).remove(attrname) - - def get_all(self): - return _GA(self, _GA(self, "name")).all() - - all = property(get_all) - - # # Main TypedObject abstraction # @@ -245,15 +223,16 @@ mechanics for managing connected attributes. The TypedObject has the following properties: - key - main name - name - alias for key - typeclass_path - the path to the decorating typeclass - typeclass - auto-linked typeclass - date_created - time stamp of object creation - permissions - perm strings - dbref - #id of object - db - persistent attribute storage - ndb - non-persistent attribute storage + + - key - main name + - name - alias for key + - typeclass_path - the path to the decorating typeclass + - typeclass - auto-linked typeclass + - date_created - time stamp of object creation + - permissions - perm strings + - dbref - #id of object + - db - persistent attribute storage + - ndb - non-persistent attribute storage """ @@ -274,7 +253,8 @@ "typeclass", max_length=255, null=True, - help_text="this defines what 'type' of entity this is. This variable holds a Python path to a module with a valid Evennia Typeclass.", + help_text="this defines what 'type' of entity this is. This variable holds " + "a Python path to a module with a valid Evennia Typeclass.", db_index=True, ) # Creation date. This is not changed once the object is created. @@ -283,16 +263,20 @@ db_lock_storage = models.TextField( "locks", blank=True, - help_text="locks limit access to an entity. A lock is defined as a 'lock string' on the form 'type:lockfunctions', defining what functionality is locked and how to determine access. Not defining a lock means no access is granted.", + help_text="locks limit access to an entity. A lock is defined as a 'lock string' " + "on the form 'type:lockfunctions', defining what functionality is locked and " + "how to determine access. Not defining a lock means no access is granted.", ) # many2many relationships db_attributes = models.ManyToManyField( Attribute, - help_text="attributes on this object. An attribute can hold any pickle-able python object (see docs for special cases).", + help_text="attributes on this object. An attribute can hold any pickle-able " + "python object (see docs for special cases).", ) db_tags = models.ManyToManyField( Tag, - help_text="tags on this object. Tags are simple string markers to identify, group and alias objects.", + help_text="tags on this object. Tags are simple string markers to identify, " + "group and alias objects.", ) # Database manager @@ -355,8 +339,10 @@ than use the one in the model. Args: - *args: Passed through to parent. - **kwargs: Passed through to parent. + Passed through to parent. + + Keyword Args: + Passed through to parent. Notes: The loading mechanism will attempt the following steps: @@ -383,7 +369,7 @@ # initialize all handlers in a lazy fashion
    [docs] @lazy_property def attributes(self): - return AttributeHandler(self)
    + return AttributeHandler(self, ModelAttributeBackend)
    [docs] @lazy_property def locks(self): @@ -403,9 +389,9 @@
    [docs] @lazy_property def nattributes(self): - return NAttributeHandler(self)
    + return AttributeHandler(self, InMemoryAttributeBackend)
    -
    [docs] class Meta(object): +
    [docs] class Meta: """ Django setup info. """ @@ -680,7 +666,7 @@ superuser lock bypass (be careful with this one). Keyword Args: - kwargs (any): Ignored, but is there to make the api + kwar (any): Ignored, but is there to make the api consistent with the object-typeclass method access, which use it to feed to its hook methods. @@ -765,22 +751,22 @@ # Attribute storage # - # @property db - def __db_get(self): + @property + def db(self): """ Attribute handler wrapper. Allows for the syntax - :: + ```python obj.db.attrname = value - and + # and value = obj.db.attrname - and + # and del obj.db.attrname - and + # and all_attr = obj.db.all() - - (unless there is an attribute named 'all', in which case that will be - returned instead). + # (unless there is an attribute + # named 'all', in which case that will be returned instead). + ``` """ try: @@ -789,44 +775,29 @@ self._db_holder = DbHolder(self, "attributes") return self._db_holder - # @db.setter - def __db_set(self, value): - """Stop accidentally replacing the db object""" + @db.setter + def db(self, value): + "Stop accidentally replacing the db object" string = "Cannot assign directly to db object! " string += "Use db.attr=value instead." raise Exception(string) - # @db.deleter - def __db_del(self): - """Stop accidental deletion.""" + @db.deleter + def db(self): + "Stop accidental deletion." raise Exception("Cannot delete the db object!") - db = property(__db_get, __db_set, __db_del) - # # Non-persistent (ndb) storage # - # @property ndb - def __ndb_get(self): + @property + def ndb(self): """ - A non-attr_obj store (NonDataBase). Everything stored to this is - guaranteed to be cleared when a server is shutdown. Syntax is same as - for the `.db` property, e.g. - :: - - obj.ndb.attrname = value - and - value = obj.ndb.attrname - and - del obj.ndb.attrname - and - all_attr = obj.ndb.all() - - What makes this preferable over just assigning properties directly on - the object is that Evennia can track caching for these properties and - for example avoid wiping objects with set `.ndb` data on cache flushes. - + A non-attr_obj store (ndb: NonDataBase). Everything stored + to this is guaranteed to be cleared when a server is shutdown. + Syntax is same as for the _get_db_holder() method and + property, e.g. obj.ndb.attr = value etc. """ try: return self._ndb_holder @@ -834,20 +805,18 @@ self._ndb_holder = DbHolder(self, "nattrhandler", manager_name="nattributes") return self._ndb_holder - # @db.setter - def __ndb_set(self, value): + @ndb.setter + def ndb(self, value): "Stop accidentally replacing the ndb object" string = "Cannot assign directly to ndb object! " string += "Use ndb.attr=value instead." raise Exception(string) - # @db.deleter - def __ndb_del(self): + @ndb.deleter + def ndb(self): "Stop accidental deletion." raise Exception("Cannot delete the ndb object!") - ndb = property(__ndb_get, __ndb_set, __ndb_del) -
    [docs] def get_display_name(self, looker, **kwargs): """ Displays the name of the object in a viewer-aware manner. @@ -931,37 +900,32 @@
    [docs] @classmethod def web_get_create_url(cls): """ - Returns the URI path for a View that allows users to create new instances of this object. + ex. Chargen = '/characters/create/' + + For this to work, the developer must have defined a named view somewhere + in urls.py that follows the format 'modelname-action', so in this case + a named view of 'character-create' would be referenced by this method. + + ex. + url(r'characters/create/', ChargenView.as_view(), name='character-create') + + If no View has been created and defined in urls.py, returns an + HTML anchor. + + This method is naive and simply returns a path. Securing access to + the actual view and limiting who can create new objects is the + developer's responsibility. + Returns: path (str): URI path to object creation page, if defined. - Examples: - :: - - Chargen = '/characters/create/' - - For this to work, the developer must have defined a named view somewhere - in urls.py that follows the format 'modelname-action', so in this case - a named view of 'character-create' would be referenced by this method. - :: - - url(r'characters/create/', ChargenView.as_view(), name='character-create') - - If no View has been created and defined in urls.py, returns an - HTML anchor. - - Notes: - This method is naive and simply returns a path. Securing access to - the actual view and limiting who can create new objects is the - developer's responsibility. - """ try: return reverse("%s-create" % slugify(cls._meta.verbose_name)) - except: + except Exception: return "#"
    [docs] def web_get_detail_url(self): @@ -973,21 +937,24 @@ path (str): URI path to object detail page, if defined. Examples: - :: - Oscar (Character) = '/characters/oscar/1/' + ```python + Oscar (Character) = '/characters/oscar/1/' + ``` For this to work, the developer must have defined a named view somewhere in urls.py that follows the format 'modelname-action', so in this case a named view of 'character-detail' would be referenced by this method. - :: + + ```python + url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/$', CharDetailView.as_view(), name='character-detail') + ``` If no View has been created and defined in urls.py, returns an HTML anchor. - Notes: This method is naive and simply returns a path. Securing access to the actual view and limiting who can view this object is the developer's responsibility. @@ -998,7 +965,7 @@ "%s-detail" % slugify(self._meta.verbose_name), kwargs={"pk": self.pk, "slug": slugify(self.name)}, ) - except: + except Exception: return "#"
    [docs] def web_get_puppet_url(self): @@ -1007,7 +974,7 @@ object. Returns: - path (str): URI path to object puppet page, if defined. + str: URI path to object puppet page, if defined. Examples: :: @@ -1025,7 +992,6 @@ If no View has been created and defined in urls.py, returns an HTML anchor. - Notes: This method is naive and simply returns a path. Securing access to the actual view and limiting who can view this object is the developer's responsibility. @@ -1037,7 +1003,7 @@ "%s-puppet" % slugify(self._meta.verbose_name), kwargs={"pk": self.pk, "slug": slugify(self.name)}, ) - except: + except Exception: return "#"
    [docs] def web_get_update_url(self): @@ -1046,12 +1012,13 @@ object. Returns: - path (str): URI path to object update page, if defined. + str: URI path to object update page, if defined. Examples: - :: - Oscar (Character) = '/characters/oscar/1/change/' + ```python + Oscar (Character) = '/characters/oscar/1/change/' + ``` For this to work, the developer must have defined a named view somewhere in urls.py that follows the format 'modelname-action', so in this case @@ -1059,23 +1026,23 @@ :: url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/change/$', - CharUpdateView.as_view(), name='character-update') + CharUpdateView.as_view(), name='character-update') If no View has been created and defined in urls.py, returns an HTML anchor. - Notes: This method is naive and simply returns a path. Securing access to the actual view and limiting who can modify objects is the developer's responsibility. + """ try: return reverse( "%s-update" % slugify(self._meta.verbose_name), kwargs={"pk": self.pk, "slug": slugify(self.name)}, ) - except: + except Exception: return "#"
    [docs] def web_get_delete_url(self): @@ -1086,25 +1053,26 @@ path (str): URI path to object deletion page, if defined. Examples: - :: - Oscar (Character) = '/characters/oscar/1/delete/' + ```python + Oscar (Character) = '/characters/oscar/1/delete/' + ``` - For this to work, the developer must have defined a named view somewhere - in urls.py that follows the format 'modelname-action', so in this case - a named view of 'character-detail' would be referenced by this method. + For this to work, the developer must have defined a named view + somewhere in urls.py that follows the format 'modelname-action', so + in this case a named view of 'character-detail' would be referenced + by this method. :: url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/delete/$', - CharDeleteView.as_view(), name='character-delete') + CharDeleteView.as_view(), name='character-delete') - If no View has been created and defined in urls.py, returns an - HTML anchor. + If no View has been created and defined in urls.py, returns an HTML + anchor. - Notes: This method is naive and simply returns a path. Securing access to - the actual view and limiting who can delete this object is the developer's - responsibility. + the actual view and limiting who can delete this object is the + developer's responsibility. """ @@ -1113,7 +1081,7 @@ "%s-delete" % slugify(self._meta.verbose_name), kwargs={"pk": self.pk, "slug": slugify(self.name)}, ) - except: + except Exception: return "#"
    # Used by Django Sites/Admin @@ -1155,7 +1123,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/typeclasses/tags.html b/docs/0.9.5/_modules/evennia/typeclasses/tags.html index 62e01414a7..b59d2c392c 100644 --- a/docs/0.9.5/_modules/evennia/typeclasses/tags.html +++ b/docs/0.9.5/_modules/evennia/typeclasses/tags.html @@ -94,7 +94,7 @@ "key", max_length=255, null=True, help_text="tag identifier", db_index=True ) db_category = models.CharField( - "category", max_length=64, null=True, help_text="tag category", db_index=True + "category", max_length=64, null=True, blank=True, help_text="tag category", db_index=True ) db_data = models.TextField( "data", @@ -116,7 +116,7 @@ db_index=True, ) - class Meta(object): + class Meta: "Define Django meta options" verbose_name = "Tag" unique_together = (("db_key", "db_category", "db_tagtype", "db_model"),) @@ -166,7 +166,10 @@ self._cache_complete = False
    def _query_all(self): - "Get all tags for this objects" + """ + Get all tags for this object. + + """ query = { "%s__id" % self._model: self._objid, "tag__db_model": self._model, @@ -178,7 +181,10 @@ ] def _fullcache(self): - "Cache all tags of this object" + """ + Cache all tags of this object. + + """ if not _TYPECLASS_AGGRESSIVE_CACHE: return tags = self._query_all() @@ -318,6 +324,7 @@
    [docs] def reset_cache(self): """ Reset the cache from the outside. + """ self._cache_complete = False self._cache = {} @@ -360,6 +367,40 @@ getattr(self.obj, self._m2m_fieldname).add(tagobj) self._setcache(tagstr, category, tagobj)
    +
    [docs] def has(self, tag=None, category=None, return_list=False): + """ + Checks if the given Tag (or list of Tags) exists on the object. + + Args: + tag (str or iterable): The Tag key or tags to check for. + If `None`, search by category. + category (str, optional): Limit the check to Tags with this + category (note, that `None` is the default category). + + Returns: + has_tag (bool or list): If the Tag exists on this object or not. + If `tag` was given as an iterable then the return is a list of booleans. + + Raises: + ValueError: If neither `tag` nor `category` is given. + + """ + ret = [] + category = category.strip().lower() if category is not None else None + if tag: + for tag_str in make_iter(tag): + tag_str = tag_str.strip().lower() + ret.extend(bool(tag) for tag in self._getcache(tag_str, category)) + elif category: + ret.extend(bool(tag) for tag in self._getcache(category=category)) + else: + raise ValueError("Either tag or category must be provided.") + + if return_list: + return ret + + return ret[0] if len(ret) == 1 else ret
    +
    [docs] def get(self, key=None, default=None, category=None, return_tagobj=False, return_list=False): """ Get the tag for the given key, category or combination of the two. @@ -490,8 +531,9 @@ Batch-add tags from a list of tuples. Args: - *args (tuple or str): Each argument should be a `tagstr` keys or tuple `(keystr, category)` or - `(keystr, category, data)`. It's possible to mix input types. + *args (tuple or str): Each argument should be a `tagstr` keys or tuple + `(keystr, category)` or `(keystr, category, data)`. It's possible to mix input + types. Notes: This will generate a mimimal number of self.add calls, @@ -572,7 +614,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/utils/ansi.html b/docs/0.9.5/_modules/evennia/utils/ansi.html index 9ef4a26ebc..6924b4fe5f 100644 --- a/docs/0.9.5/_modules/evennia/utils/ansi.html +++ b/docs/0.9.5/_modules/evennia/utils/ansi.html @@ -42,18 +42,64 @@ """ ANSI - Gives colour to text. -Use the codes defined in ANSIPARSER in your text to apply colour to text -according to the ANSI standard. +Use the codes defined in the *ANSIParser* class to apply colour to text. The +`parse_ansi` function in this module parses text for markup and `strip_ansi` +removes it. -Examples: +You should usually not need to call `parse_ansi` explicitly; it is run by +Evennia just before returning data to/from the user. Alternative markup is +possible by overriding the parser class (see also contrib/ for deprecated +markup schemes). + + +Supported standards: + +- ANSI 8 bright and 8 dark fg (foreground) colors +- ANSI 8 dark bg (background) colors +- 'ANSI' 8 bright bg colors 'faked' with xterm256 (bright bg not included in ANSI standard) +- Xterm256 - 255 fg/bg colors + 26 greyscale fg/bg colors + +## Markup + +ANSI colors: `r` ed, `g` reen, `y` ellow, `b` lue, `m` agenta, `c` yan, `n` ormal (no color). +Capital letters indicate the 'dark' variant. + +- `|r` fg bright red +- `|R` fg dark red +- `|[r` bg bright red +- `|[R` bg dark red +- `|[R|g` bg dark red, fg bright green ```python "This is |rRed text|n and this is normal again." + ``` -Mostly you should not need to call `parse_ansi()` explicitly; it is run by -Evennia just before returning data to/from the user. Depreciated example forms -are available by extending the ansi mapping. +Xterm256 colors are given as RGB (Red-Green-Blue), with values 0-5: + +- `|500` fg bright red +- `|050` fg bright green +- `|005` fg bright blue +- `|110` fg dark brown +- `|425` fg pink +- `|[431` bg orange + +Xterm256 greyscale: + +- `|=a` fg black +- `|=g` fg dark grey +- `|=o` fg middle grey +- `|=v` fg bright grey +- `|=z` fg white +- `|[=r` bg middle grey + +```python +"This is |500Red text|n and this is normal again." +"This is |[=jText on dark grey background" + +``` + +---- """ import functools @@ -121,9 +167,11 @@
    [docs]class ANSIParser(object): """ - A class that parses ANSI markup to ANSI command sequences. + A class that parses ANSI markup + to ANSI command sequences - We also allow to escape colour codes by prepending with an extra `|`. + We also allow to escape colour codes + by prepending with an extra `|`. """ @@ -216,6 +264,7 @@ ansi_xterm256_bright_bg_map += settings.COLOR_ANSI_XTERM256_BRIGHT_BG_EXTRA_MAP mxp_re = r"\|lc(.*?)\|lt(.*?)\|le" + mxp_url_re = r"\|lu(.*?)\|lt(.*?)\|le" # prepare regex matching brightbg_sub = re.compile( @@ -230,6 +279,7 @@ # xterm256_sub = re.compile(r"|".join([tup[0] for tup in xterm256_map]), re.DOTALL) ansi_sub = re.compile(r"|".join([re.escape(tup[0]) for tup in ansi_map]), re.DOTALL) mxp_sub = re.compile(mxp_re, re.DOTALL) + mxp_url_sub = re.compile(mxp_url_re, re.DOTALL) # used by regex replacer to correctly map ansi sequences ansi_map_dict = dict(ansi_map) @@ -330,8 +380,9 @@ colval = 16 + (red * 36) + (green * 6) + blue return "\033[%s8;5;%sm" % (3 + int(background), colval) - # replaced since some clients (like Potato) does not accept codes with leading zeroes, see issue #1024. - # return "\033[%s8;5;%s%s%sm" % (3 + int(background), colval // 100, (colval % 100) // 10, colval%10) + # replaced since some clients (like Potato) does not accept codes with leading zeroes, + # see issue #1024. + # return "\033[%s8;5;%s%s%sm" % (3 + int(background), colval // 100, (colval % 100) // 10, colval%10) # noqa else: # xterm256 not supported, convert the rgb value to ansi instead @@ -416,7 +467,9 @@ string (str): The processed string. """ - return self.mxp_sub.sub(r"\2", string)
    + string = self.mxp_sub.sub(r"\2", string) + string = self.mxp_url_sub.sub(r"\1", string) # replace with url verbatim + return string
    [docs] def parse_ansi(self, string, strip_ansi=False, xterm256=False, mxp=False): """ @@ -722,7 +775,8 @@ """ - # A compiled Regex for the format mini-language: https://docs.python.org/3/library/string.html#formatspec + # A compiled Regex for the format mini-language: + # https://docs.python.org/3/library/string.html#formatspec re_format = re.compile( r"(?i)(?P<just>(?P<fill>.)?(?P<align>\<|\>|\=|\^))?(?P<sign>\+|\-| )?(?P<alt>\#)?" r"(?P<zero>0)?(?P<width>\d+)?(?P<grouping>\_|\,)?(?:\.(?P<precision>\d+))?" @@ -795,12 +849,14 @@ Current features supported: fill, align, width. Args: - format_spec (str): The format specification passed by f-string or str.format(). This is a string such as - "0<30" which would mean "left justify to 30, filling with zeros". The full specification can be found - at https://docs.python.org/3/library/string.html#formatspec + format_spec (str): The format specification passed by f-string or str.format(). This is + a string such as "0<30" which would mean "left justify to 30, filling with zeros". + The full specification can be found at + https://docs.python.org/3/library/string.html#formatspec Returns: ansi_str (str): The formatted ANSIString's .raw() form, for display. + """ # This calls the compiled regex stored on ANSIString's class to analyze the format spec. # It returns a dictionary. @@ -1060,7 +1116,7 @@ current_index = 0 result = tuple() for section in parent_result: - result += (self[current_index : current_index + len(section)],) + result += (self[current_index: current_index + len(section)],) current_index += len(section) return result
    @@ -1180,7 +1236,7 @@ start = next + bylen maxsplit -= 1 # NB. if it's already < 0, it stays < 0 - res.append(self[start : len(self)]) + res.append(self[start: len(self)]) if drop_spaces: return [part for part in res if part != ""] return res @@ -1223,7 +1279,7 @@ if next < 0: break # Get character codes after the index as well. - res.append(self[next + bylen : end]) + res.append(self[next + bylen: end]) end = next maxsplit -= 1 # NB. if it's already < 0, it stays < 0 @@ -1277,7 +1333,7 @@ ic -= 1 ir2 -= 1 rstripped = rstripped[::-1] - return ANSIString(lstripped + raw[ir1 : ir2 + 1] + rstripped) + return ANSIString(lstripped + raw[ir1: ir2 + 1] + rstripped)
    [docs] def lstrip(self, chars=None): """ @@ -1396,7 +1452,7 @@ start = None end = char._char_indexes[0] prefix = char._raw_string[start:end] - postfix = char._raw_string[end + 1 :] + postfix = char._raw_string[end + 1:] line = char._clean_string * amount code_indexes = [i for i in range(0, len(prefix))] length = len(prefix) + len(line) @@ -1494,7 +1550,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/utils/batchprocessors.html b/docs/0.9.5/_modules/evennia/utils/batchprocessors.html index 15b6333255..52a9d81213 100644 --- a/docs/0.9.5/_modules/evennia/utils/batchprocessors.html +++ b/docs/0.9.5/_modules/evennia/utils/batchprocessors.html @@ -41,24 +41,22 @@

    Source code for evennia.utils.batchprocessors

     """
     This module contains the core methods for the Batch-command- and
    -Batch-code-processors respectively. In short, these are two different
    -ways to build a game world using a normal text-editor without having
    -to do so 'on the fly' in-game. They also serve as an automatic backup
    -so you can quickly recreate a world also after a server reset. The
    -functions in this module is meant to form the backbone of a system
    -called and accessed through game commands.
    +Batch-code-processors respectively. In short, these are two different ways to
    +build a game world using a normal text-editor without having to do so 'on the
    +fly' in-game. They also serve as an automatic backup so you can quickly
    +recreate a world also after a server reset. The functions in this module is
    +meant to form the backbone of a system called and accessed through game
    +commands.
     
    -The Batch-command processor is the simplest. It simply runs a list of
    -in-game commands in sequence by reading them from a text file. The
    -advantage of this is that the builder only need to remember the normal
    -in-game commands. They are also executing with full permission checks
    -etc, making it relatively safe for builders to use. The drawback is
    -that in-game there is really a builder-character walking around
    -building things, and it can be important to create rooms and objects
    -in the right order, so the character can move between them. Also
    -objects that affects players (such as mobs, dark rooms etc) will
    -affect the building character too, requiring extra care to turn
    -off/on.
    +The Batch-command processor is the simplest. It simply runs a list of in-game
    +commands in sequence by reading them from a text file. The advantage of this is
    +that the builder only need to remember the normal in-game commands. They are
    +also executing with full permission checks etc, making it relatively safe for
    +builders to use. The drawback is that in-game there is really a
    +builder-character walking around building things, and it can be important to
    +create rooms and objects in the right order, so the character can move between
    +them. Also objects that affects players (such as mobs, dark rooms etc) will
    +affect the building character too, requiring extra care to turn off/on.
     
     The Batch-code processor is a more advanced system that accepts full
     Python code, executing in chunks. The advantage of this is much more
    @@ -72,8 +70,7 @@
     recommended that the batch-code processor is limited only to
     superusers or highly trusted staff.
     
    -Batch-Command processor file syntax
    ------------------------------------
    +# Batch-command processor file syntax
     
     The batch-command processor accepts 'batchcommand files' e.g
     `batch.ev`, containing a sequence of valid Evennia commands in a
    @@ -81,31 +78,39 @@
     had been run at the game prompt.
     
     Each Evennia command must be delimited by a line comment to mark its
    -end. This way entire game worlds can be created and planned offline; it is
    +end.
    +
    +::
    +
    +    look
    +    # delimiting comment
    +    create/drop box
    +    # another required comment
    +
    +One can also inject another batchcmdfile:
    +
    +::
    +
    +    #INSERT path.batchcmdfile
    +
    +This way entire game worlds can be created and planned offline; it is
     especially useful in order to create long room descriptions where a
     real offline text editor is often much better than any online text
     editor or prompt.
     
    -There is only one batchcommand-specific entry to use in a batch-command
    -files (all others are just like in-game commands):
    +## Example of batch.ev file:
     
    -- `#INSERT path.batchcmdfile` - this as the first entry on a line will
    -  import and run a batch.ev file in this position, as if it was
    -  written in this file.
    -
    -
    -Example of batch.ev file:
     ::
     
         # batch file
         # all lines starting with # are comments; they also indicate
         # that a command definition is over.
     
    -    @create box
    +    create box
     
         # this comment ends the @create command.
     
    -    @set box/desc = A large box.
    +    set box/desc = A large box.
     
         Inside are some scattered piles of clothing.
     
    @@ -117,25 +122,22 @@
         # is ignored.  An empty line in the command definition is parsed as a \n
         # (so two empty lines becomes a new paragraph).
     
    -    @teleport #221
    +    teleport #221
     
         # (Assuming #221 is a warehouse or something.)
         # (remember, this comment ends the @teleport command! Don'f forget it)
     
         # Example of importing another file at this point.
    -    #INSERT examples.batch
    +    #IMPORT examples.batch
     
    -    @drop box
    +    drop box
     
         # Done, the box is in the warehouse! (this last comment is not necessary to
    -    # close the @drop command since it's the end of the file)
    -
    +    # close the drop command since it's the end of the file)
     
     An example batch file is `contrib/examples/batch_example.ev`.
     
    -
    -Batch-Code processor file syntax
    ---------------------------------
    +# Batch-code processor file syntax
     
     The Batch-code processor accepts full python modules (e.g. `batch.py`)
     that looks identical to normal Python files. The difference from
    @@ -169,13 +171,14 @@
     Importing works as normal. The following variables are automatically
     made available in the script namespace.
     
    -- `caller` -  The object executing the batchscript
    +- `caller` - The object executing the batchscript
     - `DEBUG` - This is a boolean marking if the batchprocessor is running
    -  in debug mode. It can be checked to e.g. delete created objects
    -  when running a CODE block multiple times during testing.
    -  (avoids creating a slew of same-named db objects)
    +            in debug mode. It can be checked to e.g. delete created objects
    +            when running a CODE block multiple times during testing.
    +            (avoids creating a slew of same-named db objects)
    +
    +## Example batch.py file
     
    -Example batch.py file:
     ::
     
         #HEADER
    @@ -204,8 +207,6 @@
     
         script = create.create_script()
     
    -----
    -
     """
     import re
     import codecs
    @@ -243,7 +244,7 @@
             file_ending (str): The file ending of this file (.ev or .py)
     
         Returns:
    -        str: The text content of the batch file.
    +        text (str): The text content of the batch file.
     
         Raises:
             IOError: If problems reading file.
    @@ -290,22 +291,30 @@
     
     
    [docs] def parse_file(self, pythonpath): """ - This parses the lines of a batchfile according to the following - rules: + This parses the lines of a batch-command-file. - 1. `#` at the beginning of a line marks the end of the command before - it. It is also a comment and any number of # can exist on - subsequent lines (but not inside comments). - 2. `#INSERT` at the beginning of a line imports another - batch-cmd file file and pastes it into the batch file as if - it was written there. - 3. Commands are placed alone at the beginning of a line and their - arguments are considered to be everything following (on any - number of lines) until the next comment line beginning with #. - 4. Newlines are ignored in command definitions - 5. A completely empty line in a command line definition is condered - a newline (so two empty lines is a paragraph). - 6. Excess spaces and indents inside arguments are stripped. + Args: + pythonpath (str): The dot-python path to the file. + + Returns: + list: A list of all parsed commands with arguments, as strings. + + Notes: + Parsing follows the following rules: + + 1. A `#` at the beginning of a line marks the end of the command before + it. It is also a comment and any number of # can exist on + subsequent lines (but not inside comments). + 2. #INSERT at the beginning of a line imports another + batch-cmd file file and pastes it into the batch file as if + it was written there. + 3. Commands are placed alone at the beginning of a line and their + arguments are considered to be everything following (on any + number of lines) until the next comment line beginning with #. + 4. Newlines are ignored in command definitions + 5. A completely empty line in a command line definition is condered + a newline (so two empty lines is a paragraph). + 6. Excess spaces and indents inside arguments are stripped. """ @@ -316,7 +325,7 @@ try: path = match.group(1) return "\n#\n".join(self.parse_file(path)) - except IOError as err: + except IOError: raise IOError("#INSERT {} failed.".format(path)) text = _RE_INSERT.sub(replace_insert, text) @@ -354,21 +363,23 @@
    [docs] def parse_file(self, pythonpath): """ - This parses the lines of a batchfile according to the following - rules: + This parses the lines of a batch-code file Args: pythonpath (str): The dot-python path to the file. Returns: - codeblocks (list): A list of all #CODE blocks, each with - prepended #HEADER data. If no #CODE blocks were found, - this will be a list of one element. + list: A list of all `#CODE` blocks, each with + prepended `#HEADER` block data. If no `#CODE` + blocks were found, this will be a list of one element + containing all code in the file (so a normal Python file). Notes: + Parsing is done according to the following rules: + 1. Code before a #CODE/HEADER block are considered part of - the first code/header block or is the ONLY block if no - #CODE/HEADER blocks are defined. + the first code/header block or is the ONLY block if no + `#CODE/HEADER` blocks are defined. 2. Lines starting with #HEADER starts a header block (ends other blocks) 3. Lines starting with #CODE begins a code block (ends other blocks) 4. Lines starting with #INSERT are on form #INSERT filename. Code from @@ -377,6 +388,7 @@ 5. Code after the last block is considered part of the last header/code block + """ text = "".join(read_batchfile(pythonpath, file_ending=".py")) @@ -503,7 +515,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/utils/containers.html b/docs/0.9.5/_modules/evennia/utils/containers.html index 4736988abc..75bf5d93c4 100644 --- a/docs/0.9.5/_modules/evennia/utils/containers.html +++ b/docs/0.9.5/_modules/evennia/utils/containers.html @@ -60,7 +60,7 @@ SCRIPTDB = None -
    [docs]class Container(object): +
    [docs]class Container: """ Base container class. A container is simply a storage object whose properties can be acquired as a property on it. This is generally @@ -196,12 +196,11 @@ new_script.start() return new_script - if ( - (found.interval != interval) - or (found.start_delay != start_delay) - or (found.repeats != repeats) - ): - found.restart(interval=interval, start_delay=start_delay, repeats=repeats) + if ((found.interval != interval) + or (found.start_delay != start_delay) + or (found.repeats != repeats)): + # the setup changed + found.start(interval=interval, start_delay=start_delay, repeats=repeats) if found.desc != desc: found.desc = desc return found @@ -318,7 +317,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/utils/create.html b/docs/0.9.5/_modules/evennia/utils/create.html index 9f8b25e124..d9df73c1a5 100644 --- a/docs/0.9.5/_modules/evennia/utils/create.html +++ b/docs/0.9.5/_modules/evennia/utils/create.html @@ -40,27 +40,19 @@

    Source code for evennia.utils.create

     """
    -This module gathers all the essential database-creation
    -functions for the game engine's various object types.
    +This module gathers all the essential database-creation functions for the game
    +engine's various object types.
     
    -Only objects created 'stand-alone' are in here, e.g. object Attributes
    -are always created directly through their respective objects.
    +Only objects created 'stand-alone' are in here. E.g. object Attributes are
    +always created through their respective objects handlers.
     
    -Each creation_* function also has an alias named for the entity being
    -created, such as create_object() and object().  This is for
    -consistency with the utils.search module and allows you to do the
    -shorter "create.object()".
    +Each `creation_*` function also has an alias named for the entity being created,
    +such as create_object() and object(). This is for consistency with the
    +utils.search module and allows you to do the shorter `create.object()`.
     
    -The respective object managers hold more methods for manipulating and
    -searching objects already existing in the database.
    +The respective object managers hold more methods for manipulating and searching
    +objects already existing in the database.
     
    -Models covered:
    - Objects
    - Scripts
    - Help
    - Message
    - Channel
    - Accounts
     """
     from django.conf import settings
     from django.db import IntegrityError
    @@ -81,7 +73,6 @@
     _AccountDB = None
     _to_object = None
     _ChannelDB = None
    -_channelhandler = None
     
     
     # limit symbol import from API
    @@ -122,31 +113,30 @@
         Keyword Args:
             typeclass (class or str): Class or python path to a typeclass.
             key (str): Name of the new object. If not set, a name of
    -            #dbref will be set.
    +            `#dbref` will be set.
             home (Object or str): Obj or #dbref to use as the object's
                 home location.
             permissions (list): A list of permission strings or tuples (permstring, category).
             locks (str): one or more lockstrings, separated by semicolons.
             aliases (list): A list of alternative keys or tuples (aliasstring, category).
             tags (list): List of tag keys or tuples (tagkey, category) or (tagkey, category, data).
    -        destination (Object or str): Obj or #dbref to use as an Exit's
    -            target.
    +        destination (Object or str): Obj or #dbref to use as an Exit's target.
             report_to (Object): The object to return error messages to.
             nohome (bool): This allows the creation of objects without a
                 default home location; only used when creating the default
                 location itself or during unittests.
             attributes (list): Tuples on the form (key, value) or (key, value, category),
    -           (key, value, lockstring) or (key, value, lockstring, default_access).
    -           to set as Attributes on the new object.
    +            (key, value, lockstring) or (key, value, lockstring, default_access).
    +            to set as Attributes on the new object.
             nattributes (list): Non-persistent tuples on the form (key, value). Note that
    -           adding this rarely makes sense since this data will not survive a reload.
    +            adding this rarely makes sense since this data will not survive a reload.
     
         Returns:
             object (Object): A newly created object of the given typeclass.
     
         Raises:
             ObjectDB.DoesNotExist: If trying to create an Object with
    -        `location` or `home` that can't be found.
    +            `location` or `home` that can't be found.
     
         """
         global _ObjectDB
    @@ -270,9 +260,8 @@
             report_to (Object): The object to return error messages to.
             desc (str): Optional description of script
             tags (list): List of tags or tuples (tag, category).
    -        attributes (list): List of tuples `(key, value)`, `(key, value, category)`,
    -           `(key, value, category, lockstring)` or
    -           `(key, value, category, lockstring, default_access)`.
    +        attributes (list): List if tuples (key, value) or (key, value, category)
    +           (key, value, lockstring) or (key, value, lockstring, default_access).
     
         Returns:
             script (obj): An instance of the script created
    @@ -412,33 +401,38 @@
     
     
     
    [docs]def create_message( - senderobj, message, channels=None, receivers=None, locks=None, tags=None, header=None -): + senderobj, message, receivers=None, locks=None, tags=None, + header=None, **kwargs): """ Create a new communication Msg. Msgs represent a unit of database-persistent communication between entites. Args: - senderobj (Object or Account): The entity sending the Msg. + senderobj (Object, Account, Script, str or list): The entity (or + entities) sending the Msg. If a `str`, this is the id-string + for an external sender type. message (str): Text with the message. Eventual headers, titles etc should all be included in this text string. Formatting will be retained. - channels (Channel, key or list): A channel or a list of channels to - send to. The channels may be actual channel objects or their - unique key strings. - receivers (Object, Account, str or list): An Account/Object to send - to, or a list of them. May be Account objects or accountnames. + receivers (Object, Account, Script, str or list): An Account/Object to send + to, or a list of them. If a string, it's an identifier for an external + receiver. locks (str): Lock definition string. tags (list): A list of tags or tuples `(tag, category)`. header (str): Mime-type or other optional information for the message Notes: - The Comm system is created very open-ended, so it's fully possible - to let a message both go to several channels and to several - receivers at the same time, it's up to the command definitions to - limit this as desired. + The Comm system is created to be very open-ended, so it's fully + possible to let a message both go several receivers at the same time, + it's up to the command definitions to limit this as desired. """ + if 'channels' in kwargs: + raise DeprecationWarning( + "create_message() does not accept 'channel' kwarg anymore " + "- channels no longer accept Msg objects." + ) + global _Msg if not _Msg: from evennia.comms.models import Msg as _Msg @@ -450,8 +444,6 @@ for sender in make_iter(senderobj): new_message.senders = sender new_message.header = header - for channel in make_iter(channels): - new_message.channels = channel for receiver in make_iter(receivers): new_message.receivers = receiver if locks: @@ -670,7 +662,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/utils/dbserialize.html b/docs/0.9.5/_modules/evennia/utils/dbserialize.html index f178e700fe..c102529543 100644 --- a/docs/0.9.5/_modules/evennia/utils/dbserialize.html +++ b/docs/0.9.5/_modules/evennia/utils/dbserialize.html @@ -70,7 +70,7 @@ from django.core.exceptions import ObjectDoesNotExist from django.contrib.contenttypes.models import ContentType from django.utils.safestring import SafeString -from evennia.utils.utils import uses_database, is_iter, to_str, to_bytes +from evennia.utils.utils import uses_database, is_iter, to_bytes from evennia.utils import logger __all__ = ("to_pickle", "from_pickle", "do_pickle", "do_unpickle", "dbserialize", "dbunserialize") @@ -657,7 +657,7 @@ that saves assigned data to the database. Skip if not serializing onto a given object. If db_obj is given, this function will convert lists, dicts and sets to their - `_SaverList`, `_SaverDict` and `_SaverSet` counterparts. + _SaverList, _SaverDict and _SaverSet counterparts. Returns: data (any): Unpickled data. @@ -832,7 +832,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/utils/eveditor.html b/docs/0.9.5/_modules/evennia/utils/eveditor.html index f6c34b5aec..cc30f40668 100644 --- a/docs/0.9.5/_modules/evennia/utils/eveditor.html +++ b/docs/0.9.5/_modules/evennia/utils/eveditor.html @@ -42,56 +42,52 @@ """ EvEditor (Evennia Line Editor) -This implements an advanced line editor for editing longer texts -in-game. The editor mimics the command mechanisms of the "VI" editor -(a famous line-by-line editor) as far as reasonable. +This implements an advanced line editor for editing longer texts in-game. The +editor mimics the command mechanisms of the "VI" editor (a famous line-by-line +editor) as far as reasonable. Features of the editor: - - undo/redo. - - edit/replace on any line of the buffer. - - search&replace text anywhere in buffer. - - formatting of buffer, or selection, to certain width + indentations. - - allow to echo the input or not, depending on your client. +- undo/redo. +- edit/replace on any line of the buffer. +- search&replace text anywhere in buffer. +- formatting of buffer, or selection, to certain width + indentations. +- allow to echo the input or not, depending on your client. +- in-built help -To use the editor, just import EvEditor from this module -and initialize it: -:: +To use the editor, just import EvEditor from this module and initialize it: - from evennia.utils.eveditor import EvEditor - EvEditor(caller, loadfunc=None, savefunc=None, quitfunc=None, key="", persistent=True) +```python +from evennia.utils.eveditor import EvEditor -- `caller` is the user of the editor, the one to see all feedback. -- `loadfunc(caller)` is called when the editor is first launched; the - return from this function is loaded as the starting buffer in the - editor. -- `safefunc(caller, buffer)` is called with the current buffer when - saving in the editor. The function should return True/False depending - on if the saving was successful or not. -- `quitfunc(caller)` is called when the editor exits. If this is given, - no automatic quit messages will be given. -- `key` is an optional identifier for the editing session, to be - displayed in the editor. -- `persistent` means the editor state will be saved to the database making it - survive a server reload. Note that using this mode, the load- save- - and quit-funcs must all be possible to pickle - notable unusable - callables are class methods and functions defined inside other - functions. With persistent=False, no such restriction exists. -- `code` set to True activates features on the EvEditor to enter Python code. +# set up an editor to edit the caller's 'desc' Attribute +def _loadfunc(caller): + return caller.db.desc -In addition, the EvEditor can be used to enter Python source code, -and offers basic handling of indentation. +def _savefunc(caller, buffer): + caller.db.desc = buffer.strip() + return True ----- +def _quitfunc(caller): + caller.msg("Custom quit message") + +# start the editor +EvEditor(caller, loadfunc=None, savefunc=None, quitfunc=None, key="", + persistent=True, code=False) +``` + +The editor can also be used to format Python code and be made to +survive a reload. See the `EvEditor` class for more details. """ import re from django.conf import settings -from evennia import Command, CmdSet +from evennia import CmdSet from evennia.utils import is_iter, fill, dedent, logger, justify, to_str, utils from evennia.utils.ansi import raw from evennia.commands import cmdhandler +from django.utils.translation import gettext as _ # we use cmdhandler instead of evennia.syscmdkeys to # avoid some cases of loading before evennia init'd @@ -109,7 +105,7 @@ # # ------------------------------------------------------------- -_HELP_TEXT = """ +_HELP_TEXT = _(""" <txt> - any non-command is appended to the end of the buffer. : <l> - view buffer or only line(s) <l> :: <l> - raw-view buffer or only line(s) <l> @@ -145,66 +141,66 @@ :fd <l> - de-indent entire buffer or line <l> :echo - turn echoing of the input on/off (helpful for some clients) -""" +""") -_HELP_LEGEND = """ +_HELP_LEGEND = _(""" Legend: <l> - line number, like '5' or range, like '3:7'. <w> - a single word, or multiple words with quotes around them. <txt> - longer string, usually not needing quotes. -""" +""") -_HELP_CODE = """ +_HELP_CODE = _(""" :! - Execute code buffer without saving :< - Decrease the level of automatic indentation for the next lines :> - Increase the level of automatic indentation for the next lines := - Switch automatic indentation on/off """.lstrip( "\n" -) +)) -_ERROR_LOADFUNC = """ +_ERROR_LOADFUNC = _(""" {error} |rBuffer load function error. Could not load initial data.|n -""" +""") -_ERROR_SAVEFUNC = """ +_ERROR_SAVEFUNC = _(""" {error} |rSave function returned an error. Buffer not saved.|n -""" +""") -_ERROR_NO_SAVEFUNC = "|rNo save function defined. Buffer cannot be saved.|n" +_ERROR_NO_SAVEFUNC = _("|rNo save function defined. Buffer cannot be saved.|n") -_MSG_SAVE_NO_CHANGE = "No changes need saving" -_DEFAULT_NO_QUITFUNC = "Exited editor." +_MSG_SAVE_NO_CHANGE = _("No changes need saving") +_DEFAULT_NO_QUITFUNC = _("Exited editor.") -_ERROR_QUITFUNC = """ +_ERROR_QUITFUNC = _(""" {error} |rQuit function gave an error. Skipping.|n -""" +""") -_ERROR_PERSISTENT_SAVING = """ +_ERROR_PERSISTENT_SAVING = _(""" {error} |rThe editor state could not be saved for persistent mode. Switching to non-persistent mode (which means the editor session won't survive an eventual server reload - so save often!)|n -""" +""") -_TRACE_PERSISTENT_SAVING = ( +_TRACE_PERSISTENT_SAVING = _( "EvEditor persistent-mode error. Commonly, this is because one or " "more of the EvEditor callbacks could not be pickled, for example " "because it's a class method or is defined inside another function." ) -_MSG_NO_UNDO = "Nothing to undo." -_MSG_NO_REDO = "Nothing to redo." -_MSG_UNDO = "Undid one step." -_MSG_REDO = "Redid one step." +_MSG_NO_UNDO = _("Nothing to undo.") +_MSG_NO_REDO = _("Nothing to redo.") +_MSG_UNDO = _("Undid one step.") +_MSG_REDO = _("Redid one step.") # ------------------------------------------------------------- # @@ -226,7 +222,10 @@ help_cateogory = "LineEditor"
    [docs] def func(self): - """Implement the yes/no choice.""" + """ + Implement the yes/no choice. + + """ # this is only called from inside the lineeditor # so caller.ndb._lineditor must be set. @@ -241,7 +240,10 @@
    [docs]class SaveYesNoCmdSet(CmdSet): - """Stores the yesno question""" + """ + Stores the yesno question + + """ key = "quitsave_yesno" priority = 150 # override other cmdsets. @@ -271,17 +273,18 @@
    [docs] def parse(self): """ - Handles pre-parsing + Handles pre-parsing. Editor commands are on the form + + :: - Usage: :cmd [li] [w] [txt] Where all arguments are optional. - - li - line number (int), starting from 1. This could also - be a range given as <l>:<l>. - - w - word(s) (string), could be encased in quotes. - - txt - extra text (string), could be encased in quotes. + - `li` - line number (int), starting from 1. This could also + be a range given as <l>:<l>. + - `w` - word(s) (string), could be encased in quotes. + - `txt` - extra text (string), could be encased in quotes. """ @@ -376,6 +379,7 @@ def _load_editor(caller): """ Load persistent editor from storage. + """ saved_options = caller.attributes.get("_eveditor_saved") saved_buffer, saved_undo = caller.attributes.get("_eveditor_buffer_temp", (None, None)) @@ -401,6 +405,7 @@
    [docs]class CmdLineInput(CmdEditorBase): """ No command match - Inputs line of text into buffer. + """ key = _CMD_NOMATCH @@ -485,6 +490,7 @@ This command handles all the in-editor :-style commands. Since each command is small and very limited, this makes for a more efficient presentation. + """ caller = self.caller editor = caller.ndb._eveditor @@ -512,7 +518,7 @@ # Insert single colon alone on a line editor.update_buffer([":"] if lstart == 0 else linebuffer + [":"]) if echo_mode: - caller.msg("Single ':' added to buffer.") + caller.msg(_("Single ':' added to buffer.")) elif cmd == ":h": # help entry editor.display_help() @@ -527,7 +533,7 @@ # quit. If not saved, will ask if self.editor._unsaved: caller.cmdset.add(SaveYesNoCmdSet) - caller.msg("Save before quitting? |lcyes|lt[Y]|le/|lcno|ltN|le") + caller.msg(_("Save before quitting?") + " |lcyes|lt[Y]|le/|lcno|ltN|le") else: editor.quit() elif cmd == ":q!": @@ -542,24 +548,26 @@ elif cmd == ":UU": # reset buffer editor.update_buffer(editor._pristine_buffer) - caller.msg("Reverted all changes to the buffer back to original state.") + caller.msg(_("Reverted all changes to the buffer back to original state.")) elif cmd == ":dd": # :dd <l> - delete line <l> buf = linebuffer[:lstart] + linebuffer[lend:] editor.update_buffer(buf) - caller.msg("Deleted %s." % self.lstr) + caller.msg(_("Deleted {string}.").format(string=self.lstr)) elif cmd == ":dw": # :dw <w> - delete word in entire buffer # :dw <l> <w> delete word only on line(s) <l> if not self.arg1: - caller.msg("You must give a search word to delete.") + caller.msg(_("You must give a search word to delete.")) else: if not self.linerange: lstart = 0 lend = self.cline + 1 - caller.msg("Removed %s for lines %i-%i." % (self.arg1, lstart + 1, lend + 1)) + caller.msg(_("Removed {arg1} for lines {l1}-{l2}.").format( + arg1=self.arg1, l1=lstart + 1, l2=lend + 1)) else: - caller.msg("Removed %s for %s." % (self.arg1, self.lstr)) + caller.msg(_("Removed {arg1} for {line}.").format( + arg1=self.arg1, line=self.lstr)) sarea = "\n".join(linebuffer[lstart:lend]) sarea = re.sub(r"%s" % self.arg1.strip("'").strip('"'), "", sarea, re.MULTILINE) buf = linebuffer[:lstart] + sarea.split("\n") + linebuffer[lend:] @@ -574,49 +582,52 @@ editor._indent = 0 if editor._persistent: caller.attributes.add("_eveditor_indent", 0) - caller.msg("Cleared %i lines from buffer." % self.nlines) + caller.msg(_("Cleared {nlines} lines from buffer.").format(nlines=self.nlines)) elif cmd == ":y": # :y <l> - yank line(s) to copy buffer cbuf = linebuffer[lstart:lend] editor._copy_buffer = cbuf - caller.msg("%s, %s yanked." % (self.lstr.capitalize(), cbuf)) + caller.msg(_("{line}, {cbuf} yanked.").format(line=self.lstr.capitalize(), cbuf=cbuf)) elif cmd == ":x": # :x <l> - cut line to copy buffer cbuf = linebuffer[lstart:lend] editor._copy_buffer = cbuf buf = linebuffer[:lstart] + linebuffer[lend:] editor.update_buffer(buf) - caller.msg("%s, %s cut." % (self.lstr.capitalize(), cbuf)) + caller.msg(_("{line}, {cbuf} cut.").format(line=self.lstr.capitalize(), cbuf=cbuf)) elif cmd == ":p": # :p <l> paste line(s) from copy buffer if not editor._copy_buffer: - caller.msg("Copy buffer is empty.") + caller.msg(_("Copy buffer is empty.")) else: buf = linebuffer[:lstart] + editor._copy_buffer + linebuffer[lstart:] editor.update_buffer(buf) - caller.msg("Pasted buffer %s to %s." % (editor._copy_buffer, self.lstr)) + caller.msg(_("Pasted buffer {cbuf} to {line}.").format( + cbuf=editor._copy_buffer, line=self.lstr)) elif cmd == ":i": # :i <l> <txt> - insert new line new_lines = self.args.split("\n") if not new_lines: - caller.msg("You need to enter a new line and where to insert it.") + caller.msg(_("You need to enter a new line and where to insert it.")) else: buf = linebuffer[:lstart] + new_lines + linebuffer[lstart:] editor.update_buffer(buf) - caller.msg("Inserted %i new line(s) at %s." % (len(new_lines), self.lstr)) + caller.msg(_("Inserted {num} new line(s) at {line}.").format( + num=len(new_lines), line=self.lstr)) elif cmd == ":r": # :r <l> <txt> - replace lines new_lines = self.args.split("\n") if not new_lines: - caller.msg("You need to enter a replacement string.") + caller.msg(_("You need to enter a replacement string.")) else: buf = linebuffer[:lstart] + new_lines + linebuffer[lend:] editor.update_buffer(buf) - caller.msg("Replaced %i line(s) at %s." % (len(new_lines), self.lstr)) + caller.msg(_("Replaced {num} line(s) at {line}.").format( + num=len(new_lines), line=self.lstr)) elif cmd == ":I": # :I <l> <txt> - insert text at beginning of line(s) <l> if not self.raw_string and not editor._codefunc: - caller.msg("You need to enter text to insert.") + caller.msg(_("You need to enter text to insert.")) else: buf = ( linebuffer[:lstart] @@ -624,11 +635,11 @@ + linebuffer[lend:] ) editor.update_buffer(buf) - caller.msg("Inserted text at beginning of %s." % self.lstr) + caller.msg(_("Inserted text at beginning of {line}.").format(line=self.lstr)) elif cmd == ":A": # :A <l> <txt> - append text after end of line(s) if not self.args: - caller.msg("You need to enter text to append.") + caller.msg(_("You need to enter text to append.")) else: buf = ( linebuffer[:lstart] @@ -636,23 +647,24 @@ + linebuffer[lend:] ) editor.update_buffer(buf) - caller.msg("Appended text to end of %s." % self.lstr) + caller.msg(_("Appended text to end of {line}.").format(line=self.lstr)) elif cmd == ":s": # :s <li> <w> <txt> - search and replace words # in entire buffer or on certain lines if not self.arg1 or not self.arg2: - caller.msg("You must give a search word and something to replace it with.") + caller.msg(_("You must give a search word and something to replace it with.")) else: if not self.linerange: lstart = 0 lend = self.cline + 1 caller.msg( - "Search-replaced %s -> %s for lines %i-%i." - % (self.arg1, self.arg2, lstart + 1, lend) + _("Search-replaced {arg1} -> {arg2} for lines {l1}-{l2}.").format( + arg1=self.arg1, arg2=self.arg2, l1=lstart + 1, l2=lend) ) else: caller.msg( - "Search-replaced %s -> %s for %s." % (self.arg1, self.arg2, self.lstr) + _("Search-replaced {arg1} -> {arg2} for {line}.").format( + arg1=self.arg1, arg2=self.arg2, line=self.lstr) ) sarea = "\n".join(linebuffer[lstart:lend]) @@ -674,9 +686,10 @@ if not self.linerange: lstart = 0 lend = self.cline + 1 - caller.msg("Flood filled lines %i-%i." % (lstart + 1, lend)) + caller.msg(_("Flood filled lines {l1}-{l2}.").format( + l1=lstart + 1, l2=lend)) else: - caller.msg("Flood filled %s." % self.lstr) + caller.msg(_("Flood filled {line}.").format(line=self.lstr)) fbuf = "\n".join(linebuffer[lstart:lend]) fbuf = fill(fbuf, width=width) buf = linebuffer[:lstart] + fbuf.split("\n") + linebuffer[lend:] @@ -698,16 +711,19 @@ width = _DEFAULT_WIDTH if self.arg1 and self.arg1.lower() not in align_map: self.caller.msg( - "Valid justifications are [f]ull (default), [c]enter, [r]right or [l]eft" + _("Valid justifications are") + + " [f]ull (default), [c]enter, [r]right or [l]eft" ) return align = align_map[self.arg1.lower()] if self.arg1 else "f" if not self.linerange: lstart = 0 lend = self.cline + 1 - self.caller.msg("%s-justified lines %i-%i." % (align_name[align], lstart + 1, lend)) + self.caller.msg(_("{align}-justified lines {l1}-{l2}.").format( + align=align_name[align], l1=lstart + 1, l2=lend)) else: - self.caller.msg("%s-justified %s." % (align_name[align], self.lstr)) + self.caller.msg(_("{align}-justified {line}.").format( + align=align_name[align], line=self.lstr)) jbuf = "\n".join(linebuffer[lstart:lend]) jbuf = justify(jbuf, width=width, align=align) buf = linebuffer[:lstart] + jbuf.split("\n") + linebuffer[lend:] @@ -718,9 +734,9 @@ if not self.linerange: lstart = 0 lend = self.cline + 1 - caller.msg("Indented lines %i-%i." % (lstart + 1, lend)) + caller.msg(_("Indented lines {l1}-{l2}.").format(l1=lstart + 1, l2=lend)) else: - caller.msg("Indented %s." % self.lstr) + caller.msg(_("Indented {line}.").format(line=self.lstr)) fbuf = [indent + line for line in linebuffer[lstart:lend]] buf = linebuffer[:lstart] + fbuf + linebuffer[lend:] editor.update_buffer(buf) @@ -729,9 +745,10 @@ if not self.linerange: lstart = 0 lend = self.cline + 1 - caller.msg("Removed left margin (dedented) lines %i-%i." % (lstart + 1, lend)) + caller.msg(_("Removed left margin (dedented) lines {l1}-{l2}.").format( + l1=lstart + 1, l2=lend)) else: - caller.msg("Removed left margin (dedented) %s." % self.lstr) + caller.msg(_("Removed left margin (dedented) {line}.").format(line=self.lstr)) fbuf = "\n".join(linebuffer[lstart:lend]) fbuf = dedent(fbuf) buf = linebuffer[:lstart] + fbuf.split("\n") + linebuffer[lend:] @@ -739,45 +756,49 @@ elif cmd == ":echo": # set echoing on/off editor._echo_mode = not editor._echo_mode - caller.msg("Echo mode set to %s" % editor._echo_mode) + caller.msg(_("Echo mode set to {mode}").format(mode=editor._echo_mode)) elif cmd == ":!": if editor._codefunc: editor._codefunc(caller, editor._buffer) else: - caller.msg("This command is only available in code editor mode.") + caller.msg(_("This command is only available in code editor mode.")) elif cmd == ":<": # :< if editor._codefunc: editor.decrease_indent() indent = editor._indent if indent >= 0: - caller.msg("Decreased indentation: new indentation is {}.".format(indent)) + caller.msg(_( + "Decreased indentation: new indentation is {indent}.").format( + indent=indent)) else: - caller.msg("|rManual indentation is OFF.|n Use := to turn it on.") + caller.msg(_("|rManual indentation is OFF.|n Use := to turn it on.")) else: - caller.msg("This command is only available in code editor mode.") + caller.msg(_("This command is only available in code editor mode.")) elif cmd == ":>": # :> if editor._codefunc: editor.increase_indent() indent = editor._indent if indent >= 0: - caller.msg("Increased indentation: new indentation is {}.".format(indent)) + caller.msg(_( + "Increased indentation: new indentation is {indent}.").format( + indent=indent)) else: - caller.msg("|rManual indentation is OFF.|n Use := to turn it on.") + caller.msg(_("|rManual indentation is OFF.|n Use := to turn it on.")) else: - caller.msg("This command is only available in code editor mode.") + caller.msg(_("This command is only available in code editor mode.")) elif cmd == ":=": # := if editor._codefunc: editor.swap_autoindent() indent = editor._indent if indent >= 0: - caller.msg("Auto-indentation turned on.") + caller.msg(_("Auto-indentation turned on.")) else: - caller.msg("Auto-indentation turned off.") + caller.msg(_("Auto-indentation turned off.")) else: - caller.msg("This command is only available in code editor mode.")
    + caller.msg(_("This command is only available in code editor mode."))
    [docs]class EvEditorCmdSet(CmdSet): @@ -798,7 +819,7 @@ # ------------------------------------------------------------- -
    [docs]class EvEditor(object): +
    [docs]class EvEditor: """ This defines a line editor object. It creates all relevant commands and tracks the current state of the buffer. It also cleans up after @@ -924,12 +945,13 @@
    [docs] def load_buffer(self): """ Load the buffer using the load function hook. + """ try: self._buffer = self._loadfunc(self._caller) if not isinstance(self._buffer, str): self._buffer = to_str(self._buffer) - self._caller.msg("|rNote: input buffer was converted to a string.|n") + self._caller.msg(_("|rNote: input buffer was converted to a string.|n")) except Exception as e: from evennia.utils import logger @@ -1066,7 +1088,7 @@ header = ( "|n" + sep * 10 - + "Line Editor [%s]" % self._key + + _("Line Editor [{name}]").format(name=self._key) + sep * (_DEFAULT_WIDTH - 24 - len(self._key)) ) footer = ( @@ -1074,7 +1096,7 @@ + sep * 10 + "[l:%02i w:%03i c:%04i]" % (nlines, nwords, nchars) + sep * 12 - + "(:h for help)" + + _("(:h for help)") + sep * (_DEFAULT_WIDTH - 54) ) if linenums: @@ -1195,7 +1217,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/utils/evform.html b/docs/0.9.5/_modules/evennia/utils/evform.html index 340425da19..dfc2d7d2b6 100644 --- a/docs/0.9.5/_modules/evennia/utils/evform.html +++ b/docs/0.9.5/_modules/evennia/utils/evform.html @@ -54,32 +54,34 @@ object when displaying the form. Example of input file `testform.py`: -:: - FORMCHAR = "x" - TABLECHAR = "c" +```python +FORMCHAR = "x" +TABLECHAR = "c" - FORM = ''' - .------------------------------------------------. - | | - | Name: xxxxx1xxxxx Player: xxxxxxx2xxxxxxx | - | xxxxxxxxxxx | - | | - >----------------------------------------------< - | | - | Desc: xxxxxxxxxxx STR: x4x DEX: x5x | - | xxxxx3xxxxx INT: x6x STA: x7x | - | xxxxxxxxxxx LUC: x8x MAG: x9x | - | | - >----------------------------------------------< - | | | - | cccccccc | ccccccccccccccccccccccccccccccccccc | - | cccccccc | ccccccccccccccccccccccccccccccccccc | - | cccAcccc | ccccccccccccccccccccccccccccccccccc | - | cccccccc | ccccccccccccccccccccccccccccccccccc | - | cccccccc | cccccccccccccccccBccccccccccccccccc | - | | | - ------------------------------------------------- +FORM = ''' +.------------------------------------------------. +| | +| Name: xxxxx1xxxxx Player: xxxxxxx2xxxxxxx | +| xxxxxxxxxxx | +| | + >----------------------------------------------< +| | +| Desc: xxxxxxxxxxx STR: x4x DEX: x5x | +| xxxxx3xxxxx INT: x6x STA: x7x | +| xxxxxxxxxxx LUC: x8x MAG: x9x | +| | + >----------------------------------------------< +| | | +| cccccccc | ccccccccccccccccccccccccccccccccccc | +| cccccccc | ccccccccccccccccccccccccccccccccccc | +| cccAcccc | ccccccccccccccccccccccccccccccccccc | +| cccccccc | ccccccccccccccccccccccccccccccccccc | +| cccccccc | cccccccccccccccccBccccccccccccccccc | +| | | +------------------------------------------------- +''' +``` The first line of the `FORM` string is ignored. The forms and table markers must mark out complete, unbroken rectangles, each containing @@ -93,8 +95,8 @@ Use as follows: -:: +```python from evennia import EvForm, EvTable # create a new form from the template @@ -126,9 +128,10 @@ "B": tableB}) print(form) - +``` This produces the following result: + :: .------------------------------------------------. @@ -152,7 +155,6 @@ | | | ------------------------------------------------ - The marked forms have been replaced with EvCells of text and with EvTables. The form can be updated by simply re-applying `form.map()` with the updated data. @@ -230,15 +232,16 @@
    [docs] def __init__(self, filename=None, cells=None, tables=None, form=None, **kwargs): """ - Initiate the form. + Initiate the form Keyword Args: filename (str): Path to template file. - cells (dict): A dictionary mapping of `{id:text}`. - tables (dict): A dictionary mapping of `{id:EvTable}`. - form (dict): A dictionary of - `{"FORMCHAR":char, "TABLECHAR":char, "FORM":templatestring}`. - if this is given, filename is not read. + cells (dict): A dictionary mapping `{id: text}` + tables (dict): A dictionary mapping `{id: EvTable}`. + form (dict): A dictionary + `{"FORMCHAR":char, "TABLECHAR":char, "FORM":templatestring}`. + If this is given, filename is not read. + Notes: Other kwargs are fed as options to the EvCells and EvTables (see `evtable.EvCell` and `evtable.EvTable` for more info). @@ -541,7 +544,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/utils/evmenu.html b/docs/0.9.5/_modules/evennia/utils/evmenu.html index 4cc02b0dd1..e27b144dcb 100644 --- a/docs/0.9.5/_modules/evennia/utils/evmenu.html +++ b/docs/0.9.5/_modules/evennia/utils/evmenu.html @@ -40,12 +40,14 @@

    Source code for evennia.utils.evmenu

     """
    -The EvMenu is a full in-game menu system for Evennia.
    +EvMenu
    +
    +This implements a full menu system for Evennia.
     
     To start the menu, just import the EvMenu class from this module.
    -
     Example usage:
    -::
    +
    +```python
     
         from evennia.utils.evmenu import EvMenu
     
    @@ -53,10 +55,11 @@
              startnode="node1",
              cmdset_mergetype="Replace", cmdset_priority=1,
              auto_quit=True, cmd_on_exit="look", persistent=True)
    +```
     
     Where `caller` is the Object to use the menu on - it will get a new
    -cmdset while using the Menu. The `menu_module_path` is the python path
    -to a python module containing function definitions. By adjusting the
    +cmdset while using the Menu. The menu_module_path is the python path
    +to a python module containing function definitions.  By adjusting the
     keyword options of the Menu() initialization call you can start the
     menu at different places in the menu definition file, adjust if the
     menu command should overload the normal commands or not, etc.
    @@ -70,7 +73,8 @@
     
     The menu is defined in a module (this can be the same module as the
     command definition too) with function definitions:
    -::
    +
    +```python
     
         def node1(caller):
             # (this is the start node if called like above)
    @@ -84,8 +88,9 @@
         def another_node(caller, input_string, **kwargs):
             # code
             return text, options
    +```
     
    -Where `caller` is the object using the menu and input_string is the
    +Where caller is the object using the menu and input_string is the
     command entered by the user on the *previous* node (the command
     entered to get to this node). The node function code will only be
     executed once per node-visit and the system will accept nodes with
    @@ -102,42 +107,42 @@
     menu is immediately exited and the default "look" command is called.
     
     - `text` (str, tuple or None): Text shown at this node. If a tuple, the
    -  second element in the tuple is a help text to display at this
    -  node when the user enters the menu help command there.
    +   second element in the tuple is a help text to display at this
    +   node when the user enters the menu help command there.
     - `options` (tuple, dict or None): If `None`, this exits the menu.
       If a single dict, this is a single-option node. If a tuple,
    -  it should be a tuple of option dictionaries. Option dicts have
    -  the following keys:
    +  it should be a tuple of option dictionaries. Option dicts have the following keys:
     
       - `key` (str or tuple, optional): What to enter to choose this option.
    -      If a tuple, it must be a tuple of strings, where the first string is the
    -      key which will be shown to the user and the others are aliases.
    -      If unset, the options' number will be used. The special key `_default`
    -      marks this option as the default fallback when no other option matches
    -      the user input. There can only be one `_default` option per node. It
    -      will not be displayed in the list.
    +    If a tuple, it must be a tuple of strings, where the first string is the
    +    key which will be shown to the user and the others are aliases.
    +    If unset, the options' number will be used. The special key `_default`
    +    marks this option as the default fallback when no other option matches
    +    the user input. There can only be one `_default` option per node. It
    +    will not be displayed in the list.
       - `desc` (str, optional): This describes what choosing the option will do.
       - `goto` (str, tuple or callable): If string, should be the name of node to go to
    -      when this option is selected. If a callable, it has the signature
    -      `callable(caller[,raw_input][,**kwargs])`. If a tuple, the first element
    -      is the callable and the second is a dict with the kwargs to pass to
    -      the callable. Those kwargs will also be passed into the next node if possible.
    -      Such a callable should return either a str or a (str, dict), where the
    -      string is the name of the next node to go to and the dict is the new,
    -      (possibly modified) kwarg to pass into the next node. If the callable returns
    -      None or the empty string, the current node will be revisited.
    +    when this option is selected. If a callable, it has the signature
    +    `callable(caller[,raw_input][,**kwargs])`. If a tuple, the first element
    +    is the callable and the second is a dict with the `**kwargs` to pass to
    +    the callable. Those kwargs will also be passed into the next node if possible.
    +    Such a callable should return either a str or a (str, dict), where the
    +    string is the name of the next node to go to and the dict is the new,
    +    (possibly modified) kwarg to pass into the next node. If the callable returns
    +    None or the empty string, the current node will be revisited.
       - `exec` (str, callable or tuple, optional): This takes the same input as `goto` above
    -      and runs before it. If given a node name, the node will be executed but will not
    -      be considered the next node. If node/callback returns str or (str, dict), these will
    -      replace the `goto` step (`goto` callbacks will not fire), with the string being the
    -      next node name and the optional dict acting as the kwargs-input for the next node.
    -      If an exec callable returns `None`, the current node is re-run.
    +    and runs before it. If given a node name, the node will be executed but will not
    +    be considered the next node. If node/callback returns str or (str, dict), these will
    +    replace the `goto` step (`goto` callbacks will not fire), with the string being the
    +    next node name and the optional dict acting as the kwargs-input for the next node.
    +    If an exec callable returns the empty string (only), the current node is re-run.
     
    -If key is not given, the option will automatically be identified by
    +If `key` is not given, the option will automatically be identified by
     its number 1..N.
     
     Example:
    -::
    +
    +```python
     
         # in menu_module.py
     
    @@ -173,8 +178,11 @@
             text = "This ends the menu since there are no options."
             return text, None
     
    +```
    +
     When starting this menu with  `Menu(caller, "path.to.menu_module")`,
     the first node will look something like this:
    +
     ::
     
         This is a node text
    @@ -193,9 +201,8 @@
     reaching a node without any options.
     
     
    -For a menu demo, import CmdTestMenu from this module and add it to
    -your default cmdset. Run it with this module, like `testmenu
    -evennia.utils.evmenu`.
    +For a menu demo, import `CmdTestMenu` from this module and add it to
    +your default cmdset. Run it with this module, like `testmenu evennia.utils.evmenu`.
     
     
     ## Menu generation from template string
    @@ -211,10 +218,13 @@
     For maximum flexibility you can inject normally-created nodes in the menu tree
     before passing it to EvMenu. If that's not needed, you can also create a menu
     in one step with:
    -::
    +
    +```python
     
         evmenu.template2menu(caller, menu_template, goto_callables)
     
    +```
    +
     The `goto_callables` is a mapping `{"funcname": callable, ...}`, where each
     callable must be a module-global function on the form
     `funcname(caller, raw_string, **kwargs)` (like any goto-callable). The
    @@ -292,9 +302,9 @@
     key:values will be converted to strings/numbers with literal_eval before passed
     into the callable.
     
    -The "> " option takes a glob or regex to perform different actions depending on user
    -input. Make sure to sort these in increasing order of generality since they
    -will be tested in sequence.
    +The \\> option takes a glob or regex to perform different actions depending
    +on user input. Make sure to sort these in increasing order of generality since
    +they will be tested in sequence.
     
     ----
     
    @@ -446,7 +456,8 @@
                         )  # don't give the session as a kwarg here, direct to original
                         raise EvMenuError(err)
             # we must do this after the caller with the menu has been correctly identified since it
    -        # can be either Account, Object or Session (in the latter case this info will be superfluous).
    +        # can be either Account, Object or Session (in the latter case this info will be
    +        # superfluous).
             caller.ndb._evmenu._session = self.session
             # we have a menu, use it.
             menu.parse_input(self.raw_string)
    @@ -573,9 +584,7 @@ by default in all nodes of the menu. This will print out the current state of the menu. Deactivate for production use! When the debug flag is active, the `persistent` flag is deactivated. - - Keyword Args: - any (any): All kwargs will become initialization variables on `caller.ndb._evmenu`, + **kwargs: All kwargs will become initialization variables on `caller.ndb._menutree`, to be available at run. Raises: @@ -652,7 +661,8 @@ ).intersection(set(kwargs.keys())) if reserved_clash: raise RuntimeError( - f"One or more of the EvMenu `**kwargs` ({list(reserved_clash)}) is reserved by EvMenu for internal use." + f"One or more of the EvMenu `**kwargs` ({list(reserved_clash)}) " + "is reserved by EvMenu for internal use." ) for key, val in kwargs.items(): setattr(self, key, val) @@ -775,30 +785,6 @@ Call a node-like callable, with a variable number of raw_string, *args, **kwargs, all of which should work also if not present (only `caller` is always required). Return its result. - Viable node-like callable forms: - :: - - _callname(caller) - _callname(caller, raw_string) - _callname(caller, **kwargs) - _callname(caller, raw_string, **kwargs) - - If this is a node: - - - `caller` is the one using the menu. - - `raw_string` is the users exact input on the *previous* node. - - `**kwargs` is either passed through the previous node or returned - along with the node name from the goto-callable leading to this node. - - If this is a goto-callable: - - - `caller` is the one using the menu. - - `raw_string` is the user's exact input when chosing the option that triggered - this goto-callable. - - `**kwargs` is any extra dict passed to the callable in the option - definition, or (if no explit kwarg was given to the callable) the - previous node's kwarg, if any. - """ try: try: @@ -1003,8 +989,7 @@ raw_string (str): The raw default string entered on the previous node (only used if the node accepts it as an argument) - Keyword Args: - any: Extra arguments to goto callables. + **kwargs: Extra arguments to goto callables. """ @@ -1320,7 +1305,7 @@ table.extend([" " for i in range(nrows - nlastcol)]) # build the actual table grid - table = [table[icol * nrows : (icol * nrows) + nrows] for icol in range(0, ncols)] + table = [table[icol * nrows: (icol * nrows) + nrows] for icol in range(0, ncols)] # adjust the width of each column for icol in range(len(table)): @@ -1377,33 +1362,50 @@ option_generator (callable or list): A list of strings indicating the options, or a callable that is called as option_generator(caller) to produce such a list. select (callable or str, optional): Node to redirect a selection to. Its `**kwargs` will - contain the `available_choices` list and `selection` will hold one - of the elements in that list. If a callable, it will be called as - `select(caller, menuchoice, **kwargs)` where menuchoice is the - chosen option as a string and `available_choices` is the list of available - options offered by the option_generator. The callable whould return - the name of the target node to goto after this selection (or None to repeat the - list-node). Note that if this is not given, the decorated node - must itself provide a way to continue from the node! + contain the `available_choices` list and `selection` will hold one of the elements in + that list. If a callable, it will be called as + `select(caller, menuchoice, **kwargs)` where menuchoice is the chosen option as a + string and `available_choices` is a kwarg mapping the option keys to the choices + offered by the option_generator. The callable whould return the name of the target node + to goto after this selection (or None to repeat the list-node). Note that if this is not + given, the decorated node must itself provide a way to continue from the node! pagesize (int): How many options to show per page. Example: - :: - def _selectfunc(caller, menuchoice, **kwargs): - # menuchoice would be either 'foo' or 'bar' here - # kwargs['available_choices'] would be the list ['foo', 'bar'] - return "the_next_node_to_go_to" + ```python + def select(caller, selection, available_choices=None, **kwargs): + ''' + Args: + caller (Object or Account): User of the menu. + selection (str): What caller chose in the menu + available_choices (list): The keys of elements available on the *current listing + page*. + **kwargs: Kwargs passed on from the node. + Returns: + tuple, str or None: A tuple (nextnodename, **kwargs) or just nextnodename. Return + `None` to go back to the listnode. - @list_node(['foo', 'bar'], _selectfunc) - def node_index(caller): - text = "describing the list" - return text, [] + # (do something with `selection` here) + + return "nextnode", **kwargs + + @list_node(['foo', 'bar'], select) + def node_index(caller): + text = "describing the list" + + # optional extra options in addition to the list-options + extra_options = [] + + return text, extra_options + + ``` Notes: - All normal `goto` or `exec` callables returned from the decorated nodes will, if they accept - `**kwargs`, get a new kwarg `available_choices` injected. This is the ordered list of named - options (descs) visible on the current node page. + All normal `goto` or `exec` callables returned from the decorated nodes + will, if they accept `**kwargs`, get a new kwarg 'available_choices' + injected. These are the ordered list of named options (descs) visible + on the current node page. """ @@ -1411,6 +1413,7 @@ def _select_parser(caller, raw_string, **kwargs): """ Parse the select action + """ available_choices = kwargs.get("available_choices", []) @@ -1418,14 +1421,15 @@ index = int(raw_string.strip()) - 1 selection = available_choices[index] except Exception: - caller.msg("|rInvalid choice.|n") + caller.msg(_("|rInvalid choice.|n")) else: if callable(select): try: if bool(getargspec(select).keywords): - return select(caller, selection, available_choices=available_choices) + return select( + caller, selection, available_choices=available_choices, **kwargs) else: - return select(caller, selection) + return select(caller, selection, **kwargs) except Exception: logger.log_trace() elif select: @@ -1450,7 +1454,7 @@ if option_list: nall_options = len(option_list) pages = [ - option_list[ind : ind + pagesize] for ind in range(0, nall_options, pagesize) + option_list[ind: ind + pagesize] for ind in range(0, nall_options, pagesize) ] npages = len(pages) @@ -1464,7 +1468,7 @@ # callback being called with a result from the available choices options.extend( [ - {"desc": opt, "goto": (_select_parser, {"available_choices": page})} + {"desc": opt, "goto": (_select_parser, {"available_choices": page, **kwargs})} for opt in page ] ) @@ -1475,7 +1479,7 @@ # allows us to call ourselves over and over, using different kwargs. options.append( { - "key": ("|Wcurrent|n", "c"), + "key": (_("|Wcurrent|n"), "c"), "desc": "|W({}/{})|n".format(page_index + 1, npages), "goto": (lambda caller: None, {"optionpage_index": page_index}), } @@ -1483,14 +1487,14 @@ if page_index > 0: options.append( { - "key": ("|wp|Wrevious page|n", "p"), + "key": (_("|wp|Wrevious page|n"), "p"), "goto": (lambda caller: None, {"optionpage_index": page_index - 1}), } ) if page_index < npages - 1: options.append( { - "key": ("|wn|Wext page|n", "n"), + "key": (_("|wn|Wext page|n"), "n"), "goto": (lambda caller: None, {"optionpage_index": page_index + 1}), } ) @@ -1616,7 +1620,7 @@ self.add(CmdGetInput()) -class _Prompt(object): +class _Prompt: """Dummy holder""" pass @@ -1624,60 +1628,51 @@
    [docs]def get_input(caller, prompt, callback, session=None, *args, **kwargs): """ - This is a helper function for easily request input from - the caller. + This is a helper function for easily request input from the caller. Args: - caller (Account or Object): The entity being asked - the question. This should usually be an object - controlled by a user. - prompt (str): This text will be shown to the user, - in order to let them know their input is needed. + caller (Account or Object): The entity being asked the question. This + should usually be an object controlled by a user. + prompt (str): This text will be shown to the user, in order to let them + know their input is needed. callback (callable): A function that will be called - when the user enters a reply. It must take three - arguments: the `caller`, the `prompt` text and the - `result` of the input given by the user. If the - callback doesn't return anything or return False, - the input prompt will be cleaned up and exited. If - returning True, the prompt will remain and continue to - accept input. + when the user enters a reply. It must take three arguments: the + `caller`, the `prompt` text and the `result` of the input given by + the user. If the callback doesn't return anything or return False, + the input prompt will be cleaned up and exited. If returning True, + the prompt will remain and continue to accept input. session (Session, optional): This allows to specify the - session to send the prompt to. It's usually only - needed if `caller` is an Account in multisession modes - greater than 2. The session is then updated by the - command and is available (for example in callbacks) - through `caller.ndb.getinput._session`. - args, kwargs (optional): Extra arguments will be - passed to the fall back function as a list 'args' - and all keyword arguments as a dictionary 'kwargs'. - To utilise `*args` and `**kwargs`, a value for the - session argument must be provided (None by default) - and the callback function must take `*args` and - `**kwargs` as arguments. + session to send the prompt to. It's usually only needed if `caller` + is an Account in multisession modes greater than 2. The session is + then updated by the command and is available (for example in + callbacks) through `caller.ndb.getinput._session`. + *args (any): Extra arguments to pass to `callback`. To utilise `*args` + (and `**kwargs`), a value for the `session` argument must also be + provided. + **kwargs (any): Extra kwargs to pass to `callback`. Raises: RuntimeError: If the given callback is not callable. Notes: - The result value sent to the callback is raw and not - processed in any way. This means that you will get - the ending line return character from most types of - client inputs. So make sure to strip that before - doing a comparison. + The result value sent to the callback is raw and not processed in any + way. This means that you will get the ending line return character from + most types of client inputs. So make sure to strip that before doing a + comparison. - When the prompt is running, a temporary object - `caller.ndb._getinput` is stored; this will be removed - when the prompt finishes. - If you need the specific Session of the caller (which - may not be easy to get if caller is an account in higher - multisession modes), then it is available in the - callback through `caller.ndb._getinput._session`. + When the prompt is running, a temporary object `caller.ndb._getinput` + is stored; this will be removed when the prompt finishes. - Chaining get_input functions will result in the caller - stacking ever more instances of InputCmdSets. Whilst - they will all be cleared on concluding the get_input - chain, EvMenu should be considered for anything beyond - a single question. + If you need the specific Session of the caller (which may not be easy + to get if caller is an account in higher multisession modes), then it + is available in the callback through `caller.ndb._getinput._session`. + This is why the `session` is required as input. + + It's not recommended to 'chain' `get_input` into a sequence of + questions. This will result in the caller stacking ever more instances + of InputCmdSets. While they will all be cleared on concluding the + get_input chain, EvMenu should be considered for anything beyond a + single question. """ if not callable(callback): @@ -1692,6 +1687,186 @@ caller.msg(prompt, session=session)
    +
    [docs]class CmdYesNoQuestion(Command): + """ + Handle a prompt for yes or no. Press [return] for the default choice. + + """ + + key = _CMD_NOINPUT + aliases = [_CMD_NOMATCH, "yes", "no", 'y', 'n', 'a', 'abort'] + arg_regex = r"^$" + + def _clean(self, caller): + del caller.ndb._yes_no_question + if not caller.cmdset.has(YesNoQuestionCmdSet) and hasattr(caller, "account"): + caller.account.cmdset.remove(YesNoQuestionCmdSet) + else: + caller.cmdset.remove(YesNoQuestionCmdSet) + +
    [docs] def func(self): + """This is called when user enters anything.""" + caller = self.caller + try: + yes_no_question = caller.ndb._yes_no_question + if not yes_no_question and hasattr(caller, "account"): + yes_no_question = caller.account.ndb._yes_no_question + caller = caller.account + + if not yes_no_question: + self._clean(caller) + return + + inp = self.cmdname + + if inp == _CMD_NOINPUT: + raw = self.raw_cmdname.strip() + if not raw: + # use default + inp = yes_no_question.default + else: + inp = raw + + if inp in ('a', 'abort') and yes_no_question.allow_abort: + caller.msg(_("Aborted.")) + self._clean(caller) + return + + caller.ndb._yes_no_question.session = self.session + + args = yes_no_question.args + kwargs = yes_no_question.kwargs + kwargs['caller_session'] = self.session + + if inp in ('yes', 'y'): + yes_no_question.yes_callable(caller, *args, **kwargs) + elif inp in ('no', 'n'): + yes_no_question.no_callable(caller, *args, **kwargs) + else: + # invalid input. Resend prompt without cleaning + caller.msg(yes_no_question.prompt, session=self.session) + return + + # cleanup + self._clean(caller) + except Exception: + # make sure to clean up cmdset if something goes wrong + caller.msg(_("|rError in ask_yes_no. Choice not confirmed (report to admin)|n")) + logger.log_trace("Error in ask_yes_no") + self._clean(caller) + raise
    + + +
    [docs]class YesNoQuestionCmdSet(CmdSet): + """ + This stores the input command + """ + + key = "yes_no_question_cmdset" + priority = 1 + mergetype = "Replace" + no_objs = True + no_exits = True + no_channels = False + +
    [docs] def at_cmdset_creation(self): + """called once at creation""" + self.add(CmdYesNoQuestion())
    + + +
    [docs]def ask_yes_no(caller, prompt="Yes or No {options}?", yes_action="Yes", no_action="No", + default=None, allow_abort=False, session=None, *args, **kwargs): + """ + A helper question for asking a simple yes/no question. This will cause + the system to pause and wait for input from the player. + + Args: + prompt (str): The yes/no question to ask. This takes an optional formatting + marker `{options}` which will be filled with 'Y/N', '[Y]/N' or + 'Y/[N]' depending on the setting of `default`. If `allow_abort` is set, + then the 'A(bort)' option will also be available. + yes_action (callable or str): If a callable, this will be called + with `(caller, *args, **kwargs)` when the Yes-choice is made. + If a string, this string will be echoed back to the caller. + no_action (callable or str): If a callable, this will be called + with `(caller, *args, **kwargs)` when the No-choice is made. + If a string, this string will be echoed back to the caller. + default (str optional): This is what the user will get if they just press the + return key without giving any input. One of 'N', 'Y', 'A' or `None` + for no default (an explicit choice must be given). If 'A' (abort) + is given, `allow_abort` kwarg is ignored and assumed set. + allow_abort (bool, optional): If set, the 'A(bort)' option is available + (a third option meaning neither yes or no but just exits the prompt). + session (Session, optional): This allows to specify the + session to send the prompt to. It's usually only needed if `caller` + is an Account in multisession modes greater than 2. The session is + then updated by the command and is available (for example in + callbacks) through `caller.ndb._yes_no_question.session`. + *args: Additional arguments passed on into callables. + **kwargs: Additional keyword args passed on into callables. + + Raises: + RuntimeError, FooError: If default and `allow_abort` clashes. + + Example: + :: + + # just returning strings + ask_yes_no(caller, "Are you happy {options}?", + "you answered yes", "you answered no") + # trigger callables + ask_yes_no(caller, "Are you sad {options}?", + _callable_yes, _callable_no, allow_abort=True) + + """ + def _callable_yes_txt(caller, *args, **kwargs): + yes_txt = kwargs['yes_txt'] + session = kwargs['caller_session'] + caller.msg(yes_txt, session=session) + + def _callable_no_txt(caller, *args, **kwargs): + no_txt = kwargs['no_txt'] + session = kwargs['caller_session'] + caller.msg(no_txt, session=session) + + if not callable(yes_action): + kwargs['yes_txt'] = str(yes_action) + yes_action = _callable_yes_txt + + if not callable(no_action): + kwargs['no_txt'] = str(no_action) + no_action = _callable_no_txt + + # prepare the prompt with options + options = "Y/N" + abort_txt = "/Abort" if allow_abort else "" + if default: + default = default.lower() + if default == "y": + options = "[Y]/N" + elif default == "n": + options = "Y/[N]" + elif default == "a": + allow_abort = True + abort_txt = "/[A]bort" + options += abort_txt + prompt = prompt.format(options=options) + + caller.ndb._yes_no_question = _Prompt() + caller.ndb._yes_no_question.prompt = prompt + caller.ndb._yes_no_question.session = session + caller.ndb._yes_no_question.prompt = prompt + caller.ndb._yes_no_question.default = default + caller.ndb._yes_no_question.allow_abort = allow_abort + caller.ndb._yes_no_question.yes_callable = yes_action + caller.ndb._yes_no_question.no_callable = no_action + caller.ndb._yes_no_question.args = args + caller.ndb._yes_no_question.kwargs = kwargs + + caller.cmdset.add(YesNoQuestionCmdSet) + caller.msg(prompt, session=session)
    + + # ------------------------------------------------------------- # # Menu generation from menu template string @@ -1701,7 +1876,9 @@ _RE_NODE = re.compile(r"##\s*?NODE\s+?(?P<nodename>\S[\S\s]*?)$", re.I + re.M) _RE_OPTIONS_SEP = re.compile(r"##\s*?OPTIONS\s*?$", re.I + re.M) _RE_CALLABLE = re.compile(r"\S+?\(\)", re.I + re.M) -_RE_CALLABLE = re.compile(r"(?P<funcname>\S+?)(?:\((?P<kwargs>[\S\s]+?)\)|\(\))", re.I + re.M) +_RE_CALLABLE = re.compile( + r"(?P<funcname>\S+?)(?:\((?P<kwargs>[\S\s]+?)\)|\(\))", re.I + re.M +) _HELP_NO_OPTION_MATCH = _("Choose an option or try 'help'.") @@ -1715,8 +1892,8 @@ # Input/option/goto handler functions that allows for dynamically generated # nodes read from the menu template. - -def _process_callable(caller, goto, goto_callables, raw_string, current_nodename, kwargs): +def _process_callable(caller, goto, goto_callables, raw_string, + current_nodename, kwargs): """ Central helper for parsing a goto-callable (`funcname(**kwargs)`) out of the right-hand-side of the template options and map this to an actual @@ -1732,18 +1909,12 @@ for kwarg in gotokwargs.split(","): if kwarg and "=" in kwarg: key, value = [part.strip() for part in kwarg.split("=", 1)] - if key in ( - "evmenu_goto", - "evmenu_gotomap", - "_current_nodename", - "evmenu_current_nodename", - "evmenu_goto_callables", - ): + if key in ("evmenu_goto", "evmenu_gotomap", "_current_nodename", + "evmenu_current_nodename", "evmenu_goto_callables"): raise RuntimeError( f"EvMenu template error: goto-callable '{goto}' uses a " f"kwarg ({kwarg}) that is reserved for the EvMenu templating " - "system. Rename the kwarg." - ) + "system. Rename the kwarg.") try: key = literal_eval(key) except ValueError: @@ -1770,7 +1941,8 @@ goto = kwargs["evmenu_goto"] goto_callables = kwargs["evmenu_goto_callables"] current_nodename = kwargs["evmenu_current_nodename"] - return _process_callable(caller, goto, goto_callables, raw_string, current_nodename, kwargs) + return _process_callable(caller, goto, goto_callables, raw_string, + current_nodename, kwargs) def _generated_input_goto_func(caller, raw_string, **kwargs): @@ -1790,15 +1962,13 @@ # start with glob patterns for pattern, goto in gotomap.items(): if fnmatch(raw_string.lower(), pattern): - return _process_callable( - caller, goto, goto_callables, raw_string, current_nodename, kwargs - ) + return _process_callable(caller, goto, goto_callables, raw_string, + current_nodename, kwargs) # no glob pattern match; try regex for pattern, goto in gotomap.items(): if pattern and re.match(pattern, raw_string.lower(), flags=re.I + re.M): - return _process_callable( - caller, goto, goto_callables, raw_string, current_nodename, kwargs - ) + return _process_callable(caller, goto, goto_callables, raw_string, + current_nodename, kwargs) # no match, show error raise EvMenuGotoAbortMessage(_HELP_NO_OPTION_MATCH) @@ -1829,35 +1999,28 @@ dict: A `{"node": nodefunc}` menutree suitable to pass into EvMenu. """ - def _validate_kwarg(goto, kwarg): """ Validate goto-callable kwarg is on correct form. """ - if not "=" in kwarg: + if "=" not in kwarg: raise RuntimeError( f"EvMenu template error: goto-callable '{goto}' has a " f"non-kwarg argument ({kwarg}). All callables in the " "template must have only keyword-arguments, or no " - "args at all." - ) + "args at all.") key, _ = [part.strip() for part in kwarg.split("=", 1)] - if key in ( - "evmenu_goto", - "evmenu_gotomap", - "_current_nodename", - "evmenu_current_nodename", - "evmenu_goto_callables", - ): + if key in ("evmenu_goto", "evmenu_gotomap", "_current_nodename", + "evmenu_current_nodename", "evmenu_goto_callables"): raise RuntimeError( f"EvMenu template error: goto-callable '{goto}' uses a " f"kwarg ({kwarg}) that is reserved for the EvMenu templating " - "system. Rename the kwarg." - ) + "system. Rename the kwarg.") def _parse_options(nodename, optiontxt, goto_callables): """ Parse option section into option dict. + """ options = [] optiontxt = optiontxt[0].strip() if optiontxt else "" @@ -1883,7 +2046,7 @@ if match: kwargs = match.group("kwargs") if kwargs: - for kwarg in kwargs.split(","): + for kwarg in kwargs.split(','): _validate_kwarg(goto, kwarg) # parse key [;aliases|pattern] @@ -1895,7 +2058,7 @@ if main_key.startswith(_OPTION_INPUT_MARKER): # if we have a pattern, build the arguments for _default later - pattern = main_key[len(_OPTION_INPUT_MARKER) :].strip() + pattern = main_key[len(_OPTION_INPUT_MARKER):].strip() inputparsemap[pattern] = goto else: # a regular goto string/callable target @@ -1935,6 +2098,7 @@ def _parse(caller, menu_template, goto_callables): """ Parse the menu string format into a node tree. + """ nodetree = {} splits = _RE_NODE.split(menu_template) @@ -1956,7 +2120,12 @@
    [docs]def template2menu( - caller, menu_template, goto_callables=None, startnode="start", persistent=False, **kwargs, + caller, + menu_template, + goto_callables=None, + startnode="start", + persistent=False, + **kwargs, ): """ Helper function to generate and start an EvMenu based on a menu template @@ -1981,7 +2150,12 @@ """ goto_callables = goto_callables or {} menu_tree = parse_menu_template(caller, menu_template, goto_callables) - return EvMenu(caller, menu_tree, persistent=persistent, **kwargs,)
    + return EvMenu( + caller, + menu_tree, + persistent=persistent, + **kwargs, + )
    @@ -2019,7 +2193,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/utils/evmore.html b/docs/0.9.5/_modules/evennia/utils/evmore.html index a85dca37e0..d75c7715ae 100644 --- a/docs/0.9.5/_modules/evennia/utils/evmore.html +++ b/docs/0.9.5/_modules/evennia/utils/evmore.html @@ -43,29 +43,34 @@ """ EvMore - pager mechanism -This is a pager for displaying long texts and allows stepping up and -down in the text (the name comes from the traditional 'more' unix -command). +This is a pager for displaying long texts and allows stepping up and down in +the text (the name comes from the traditional 'more' unix command). To use, simply pass the text through the EvMore object: -:: + + +```python from evennia.utils.evmore import EvMore text = some_long_text_output() EvMore(caller, text, always_page=False, session=None, justify_kwargs=None, **kwargs) +``` -One can also use the convenience function msg from this module: -:: +One can also use the convenience function `msg` from this module to avoid +having to set up the `EvMenu` object manually: + +```python from evennia.utils import evmore text = some_long_text_output() evmore.msg(caller, text, always_page=False, session=None, justify_kwargs=None, **kwargs) +``` -Where always_page decides if the pager is used also if the text is not long -enough to need to scroll, session is used to determine which session to relay -to and `justify_kwargs` are kwargs to pass to `utils.utils.justify` in order to +The `always_page` argument decides if the pager is used also if the text is not long +enough to need to scroll, `session` is used to determine which session to relay +to and `justify_kwargs` are kwargs to pass to utils.utils.justify in order to change the formatting of the text. The remaining `**kwargs` will be passed on to the `caller.msg()` construct every time the page is updated. @@ -77,7 +82,9 @@ from django.core.paginator import Paginator from evennia import Command, CmdSet from evennia.commands import cmdhandler -from evennia.utils.utils import make_iter, inherits_from, justify +from evennia.utils.ansi import ANSIString +from evennia.utils.utils import make_iter, inherits_from, justify, dedent +from django.utils.translation import gettext as _ _CMD_NOMATCH = cmdhandler.CMD_NOMATCH _CMD_NOINPUT = cmdhandler.CMD_NOINPUT @@ -88,6 +95,8 @@ _EVTABLE = None +_LBR = ANSIString("\n") + # text _DISPLAY = """{text} @@ -169,10 +178,9 @@ return qs.count() -
    [docs]class EvMore: +
    [docs]class EvMore(object): """ - The main pager object. - + The main pager object """
    [docs] def __init__( @@ -190,16 +198,15 @@ ): """ - Initialization of the Evmore input handler. + Initialization of the EvMore pager. Args: caller (Object or Account): Entity reading the text. inp (str, EvTable, Paginator or iterator): The text or data to put under paging. - If a string, paginage normally. If this text contains - one or more \\\\f (backslash + f) format symbols, automatic - pagination and justification are force-disabled and - page-breaks will only happen after each \\\\f. + one or more `\\\\f` format symbol, automatic pagination and justification + are force-disabled and page-breaks will only happen after each `\\\\f`. - If `EvTable`, the EvTable will be paginated with the same setting on each page if it is too long. The table decorations will be considered in the size of the page. @@ -207,8 +214,9 @@ expected to be a line in the final display. Each line will be run through `iter_callable`. - always_page (bool, optional): If `False`, the pager will only kick - in if `inp` is too big to fit the screen. + always_page (bool, optional): If `False`, the + pager will only kick in if `inp` is too big + to fit the screen. session (Session, optional): If given, this session will be used to determine the screen width and will receive all output. justify (bool, optional): If set, auto-justify long lines. This must be turned @@ -224,51 +232,29 @@ the caller when the more page exits. Note that this will be using whatever cmdset the user had *before* the evmore pager was activated (so none of the evmore commands will be available when this is run). - kwargs (any, any): These will be passed on to the `caller.msg` method. + kwargs (any, optional): These will be passed on to the `caller.msg` method. Examples: - Basic use: - :: - super_long_text = " ... " - EvMore(caller, super_long_text) - - Paginated query data - this is an optimization to avoid fetching - database data until it's actually paged to. - :: - - from django.core.paginator import Paginator - - query = ObjectDB.objects.all() - pages = Paginator(query, 10) # 10 objs per page - EvMore(caller, pages) - - Automatic split EvTable over multiple EvMore pages - :: - - table = EvMore(*header, table=tabledata) - EvMore(caller, table) - - Every page a separate EvTable (optimization for very large data sets) - :: - - from evennia import EvTable, EvMore - - class TableEvMore(EvMore): - def init_pages(self, data): - pages = # depends on data type - super().init_pages(pages) - - def page_formatter(self, page): - table = EvTable() - - for line in page: - cols = # split raw line into columns - table.add_row(*cols) - - return str(table) - - TableEvMore(caller, pages) + ```python + super_long_text = " ... " + EvMore(caller, super_long_text) + ``` + Paginator + ```python + from django.core.paginator import Paginator + query = ObjectDB.objects.all() + pages = Paginator(query, 10) # 10 objs per page + EvMore(caller, pages) + ``` + Every page an EvTable + ```python + from evennia import EvTable + def _to_evtable(page): + table = ... # convert page to a table + return EvTable(*headers, table=table, ...) + EvMore(caller, pages, page_formatter=_to_evtable) + ``` """ self._caller = caller @@ -287,7 +273,7 @@ self._justify_kwargs = justify_kwargs self.exit_on_lastpage = exit_on_lastpage self.exit_cmd = exit_cmd - self._exit_msg = "Exited |wmore|n pager." + self._exit_msg = _("Exited |wmore|n pager.") self._kwargs = kwargs self._data = None @@ -410,8 +396,9 @@ """ Paginate by slice. This is done with an eye on memory efficiency (usually for querysets); to avoid fetching all objects at the same time. + """ - return self._data[pageno * self.height : pageno * self.height + self.height]
    + return self._data[pageno * self.height: pageno * self.height + self.height]
    [docs] def paginator_django(self, pageno): """ @@ -455,9 +442,12 @@
    [docs] def init_f_str(self, text): """ - The input contains \\\\f (backslash + f) markers. We use \\\\f to indicate - the user wants to enforce their line breaks on their own. If so, we do - no automatic line-breaking/justification at all. + The input contains `\\f` markers. We use `\\f` to indicate the user wants to + enforce their line breaks on their own. If so, we do no automatic + line-breaking/justification at all. + + Args: + text (str): The string to format with f-markers. """ self._data = text.split("\f") @@ -486,7 +476,7 @@ lines = text.split("\n") self._data = [ - "\n".join(lines[i : i + self.height]) for i in range(0, len(lines), self.height) + _LBR.join(lines[i: i + self.height]) for i in range(0, len(lines), self.height) ] self._npages = len(self._data)
    @@ -504,16 +494,15 @@ Notes: If overridden, this method must perform the following actions: - - read and re-store `self._data` (the incoming data set) if needed - for pagination to work. + - read and re-store `self._data` (the incoming data set) if needed for pagination to + work. - set `self._npages` to the total number of pages. Default is 1. - set `self._paginator` to a callable that will take a page number 1...N and return the data to display on that page (not any decorations or next/prev buttons). If only wanting to change the paginator, override `self.paginator` instead. - - set `self._page_formatter` to a callable that will receive the - page from `self._paginator` and format it with one element per - line. Default is `str`. Or override `self.page_formatter` - directly instead. + - set `self._page_formatter` to a callable that will receive the page from + `self._paginator` and format it with one element per line. Default is `str`. Or + override `self.page_formatter` directly instead. By default, helper methods are called that perform these actions depending on supported inputs. @@ -590,40 +579,6 @@ """ EvMore-supported version of msg, mimicking the normal msg method. - Args: - caller (Object or Account): Entity reading the text. - text (str, EvTable or iterator): The text or data to put under paging. - - - If a string, paginage normally. If this text contains - one or more \\\\f (backslash + f) format symbol, automatic pagination is disabled - and page-breaks will only happen after each \\\\f. - - If `EvTable`, the EvTable will be paginated with the same - setting on each page if it is too long. The table - decorations will be considered in the size of the page. - - Otherwise `text` is converted to an iterator, where each step is - is expected to be a line in the final display, and each line - will be run through repr(). - - always_page (bool, optional): If `False`, the - pager will only kick in if `text` is too big - to fit the screen. - session (Session, optional): If given, this session will be used - to determine the screen width and will receive all output. - justify (bool, optional): If set, justify long lines in output. Disable for - fixed-format output, like tables. - justify_kwargs (dict, bool or None, optional): If given, this should - be valid keyword arguments to the utils.justify() function. If False, - no justification will be done. - exit_on_lastpage (bool, optional): Immediately exit pager when reaching the last page. - use_evtable (bool, optional): If True, each page will be rendered as an - EvTable. For this to work, `text` must be an iterable, where each element - is the table (list of list) to render on that page. - evtable_args (tuple, optional): The args to use for EvTable on each page. - evtable_kwargs (dict, optional): The kwargs to use for EvTable on each - page (except `table`, which is supplied by EvMore per-page). - kwargs (any, optional): These will be passed on - to the `caller.msg` method. - """ EvMore( caller, @@ -635,6 +590,9 @@ exit_on_lastpage=exit_on_lastpage, **kwargs, )
    + + +msg.__doc__ += dedent(EvMore.__init__.__doc__)
    @@ -672,7 +630,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/utils/evtable.html b/docs/0.9.5/_modules/evennia/utils/evtable.html index 26c85813a4..59b75dd609 100644 --- a/docs/0.9.5/_modules/evennia/utils/evtable.html +++ b/docs/0.9.5/_modules/evennia/utils/evtable.html @@ -40,21 +40,25 @@

    Source code for evennia.utils.evtable

     """
    -This is an advanced ASCII table creator. It was inspired by
    -[prettytable](https://code.google.com/p/prettytable/) but shares no code.
    +This is an advanced ASCII table creator. It was inspired by Prettytable
    +(https://code.google.com/p/prettytable/) but shares no code and is considerably
    +more advanced, supporting auto-balancing of incomplete tables and ANSI colors among
    +other things.
     
     Example usage:
    -::
     
    -    from evennia.utils import evtable
    +```python
    +  from evennia.utils import evtable
     
    -    table = evtable.EvTable("Heading1", "Heading2",
    +  table = evtable.EvTable("Heading1", "Heading2",
                       table=[[1,2,3],[4,5,6],[7,8,9]], border="cells")
    -    table.add_column("This is long data", "This is even longer data")
    -    table.add_row("This is a single row")
    -    print table
    +  table.add_column("This is long data", "This is even longer data")
    +  table.add_row("This is a single row")
    +  print table
    +```
     
     Result:
    +
     ::
     
         +----------------------+----------+---+--------------------------+
    @@ -71,13 +75,15 @@
     
     As seen, the table will automatically expand with empty cells to make
     the table symmetric. Tables can be restricted to a given width:
    -::
     
    -    table.reformat(width=50, align="l")
    +```python
    +  table.reformat(width=50, align="l")
    +```
     
     (We could just have added these keywords to the table creation call)
     
     This yields the following result:
    +
     ::
     
         +-----------+------------+-----------+-----------+
    @@ -98,16 +104,21 @@
         | row       |            |           |           |
         +-----------+------------+-----------+-----------+
     
    +
     Table-columns can be individually formatted. Note that if an
     individual column is set with a specific width, table auto-balancing
     will not affect this column (this may lead to the full table being too
     wide, so be careful mixing fixed-width columns with auto- balancing).
     Here we change the width and alignment of the column at index 3
     (Python starts from 0):
    -::
     
    -    table.reformat_column(3, width=30, align="r")
    -    print table
    +```python
    +
    +table.reformat_column(3, width=30, align="r")
    +print table
    +```
    +
    +::
     
         +-----------+-------+-----+-----------------------------+---------+
         | Heading1  | Headi |     |                             |         |
    @@ -131,15 +142,14 @@
     vertically. This will lead to text contents being cropped. Each cell
     can only shrink to a minimum width and height of 1.
     
    -`EvTable` is intended to be used with [ANSIString](evennia.utils.ansi#ansistring)
    -for supporting ANSI-coloured string types.
    +`EvTable` is intended to be used with `ANSIString` for supporting ANSI-coloured
    +string types.
     
    -When a cell is auto-wrapped across multiple lines, ANSI-reset
    -sequences will be put at the end of each wrapped line. This means that
    -the colour of a wrapped cell will not "bleed", but it also means that
    -eventual colour outside the table will not transfer "across" a table,
    -you need to re-set the color to have it appear on both sides of the
    -table string.
    +When a cell is auto-wrapped across multiple lines, ANSI-reset sequences will be
    +put at the end of each wrapped line. This means that the colour of a wrapped
    +cell will not "bleed", but it also means that eventual colour outside the table
    +will not transfer "across" a table, you need to re-set the color to have it
    +appear on both sides of the table string.
     
     ----
     
    @@ -270,12 +280,12 @@
                     del chunks[-1]
     
                 while chunks:
    -                l = d_len(chunks[-1])
    +                ln = d_len(chunks[-1])
     
                     # Can at least squeeze this chunk onto the current line.
    -                if cur_len + l <= width:
    +                if cur_len + ln <= width:
                         cur_line.append(chunks.pop())
    -                    cur_len += l
    +                    cur_len += ln
     
                     # Nope, this line is full.
                     else:
    @@ -293,10 +303,10 @@
                 # Convert current line back to a string and store it in list
                 # of all lines (return value).
                 if cur_line:
    -                l = ""
    +                ln = ""
                     for w in cur_line:  # ANSI fix
    -                    l += w  #
    -                lines.append(indent + l)
    +                    ln += w  #
    +                lines.append(indent + ln)
             return lines
    @@ -1130,8 +1140,9 @@ height (int, optional): Fixed height of table. Defaults to being unset. Width is still given precedence. If given, table cells will crop text rather than expand vertically. - evenwidth (bool, optional): Used with the `width` keyword. Adjusts columns to have as even width as - possible. This often looks best also for mixed-length tables. Default is `False`. + evenwidth (bool, optional): Used with the `width` keyword. Adjusts columns to have as + even width as possible. This often looks best also for mixed-length tables. Default + is `False`. maxwidth (int, optional): This will set a maximum width of the table while allowing it to be smaller. Only if it grows wider than this size will it be resized by expanding horizontally (or crop `height` is given). @@ -1378,7 +1389,8 @@ self.ncols = ncols self.nrows = nrowmax - # add borders - these add to the width/height, so we must do this before calculating width/height + # add borders - these add to the width/height, so we must do this before calculating + # width/height self._borders() # equalize widths within each column @@ -1465,7 +1477,8 @@ except Exception: raise - # equalize heights for each row (we must do this here, since it may have changed to fit new widths) + # equalize heights for each row (we must do this here, since it may have changed to fit new + # widths) cheights = [ max(cell.get_height() for cell in (col[iy] for col in self.worktable)) for iy in range(nrowmax) @@ -1826,7 +1839,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/utils/gametime.html b/docs/0.9.5/_modules/evennia/utils/gametime.html index 1642cf046f..73ad949c3c 100644 --- a/docs/0.9.5/_modules/evennia/utils/gametime.html +++ b/docs/0.9.5/_modules/evennia/utils/gametime.html @@ -48,7 +48,6 @@ """ import time -from calendar import monthrange from datetime import datetime, timedelta from django.db.utils import OperationalError @@ -68,6 +67,7 @@ try: GAME_TIME_OFFSET = ServerConfig.objects.conf("gametime_offset", default=0) except OperationalError: + # the db is not initialized print("Gametime offset could not load - db not set up.") GAME_TIME_OFFSET = 0 @@ -349,7 +349,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/utils/idmapper/manager.html b/docs/0.9.5/_modules/evennia/utils/idmapper/manager.html index b87716d2f5..1322088124 100644 --- a/docs/0.9.5/_modules/evennia/utils/idmapper/manager.html +++ b/docs/0.9.5/_modules/evennia/utils/idmapper/manager.html @@ -109,7 +109,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/utils/idmapper/models.html b/docs/0.9.5/_modules/evennia/utils/idmapper/models.html index db2449338c..e8e63d8020 100644 --- a/docs/0.9.5/_modules/evennia/utils/idmapper/models.html +++ b/docs/0.9.5/_modules/evennia/utils/idmapper/models.html @@ -104,7 +104,8 @@ return super(SharedMemoryModelBase, cls).__call__(*args, **kwargs) instance_key = cls._get_cache_key(args, kwargs) - # depending on the arguments, we might not be able to infer the PK, so in that case we create a new instance + # depending on the arguments, we might not be able to infer the PK, so in that case we + # create a new instance if instance_key is None: return new_instance() cached_instance = cls.get_cached_instance(instance_key) @@ -195,9 +196,9 @@ if isinstance(value, (str, int)): value = to_str(value) if value.isdigit() or value.startswith("#"): - # we also allow setting using dbrefs, if so we try to load the matching object. - # (we assume the object is of the same type as the class holding the field, if - # not a custom handler must be used for that field) + # we also allow setting using dbrefs, if so we try to load the matching + # object. (we assume the object is of the same type as the class holding + # the field, if not a custom handler must be used for that field) dbid = dbref(value, reqhash=False) if dbid: model = _GA(cls, "_meta").get_field(fname).model @@ -307,21 +308,24 @@ pk = cls._meta.pks[0] else: pk = cls._meta.pk - # get the index of the pk in the class fields. this should be calculated *once*, but isn't atm + # get the index of the pk in the class fields. this should be calculated *once*, but isn't + # atm pk_position = cls._meta.fields.index(pk) if len(args) > pk_position: # if it's in the args, we can get it easily by index result = args[pk_position] elif pk.attname in kwargs: - # retrieve the pk value. Note that we use attname instead of name, to handle the case where the pk is a - # a ForeignKey. + # retrieve the pk value. Note that we use attname instead of name, to handle the case + # where the pk is a a ForeignKey. result = kwargs[pk.attname] elif pk.name != pk.attname and pk.name in kwargs: - # ok we couldn't find the value, but maybe it's a FK and we can find the corresponding object instead + # ok we couldn't find the value, but maybe it's a FK and we can find the corresponding + # object instead result = kwargs[pk.name] if result is not None and isinstance(result, Model): - # if the pk value happens to be a model instance (which can happen wich a FK), we'd rather use its own pk as the key + # if the pk value happens to be a model instance (which can happen wich a FK), we'd + # rather use its own pk as the key result = result._get_pk_val() return result @@ -749,7 +753,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/utils/idmapper/tests.html b/docs/0.9.5/_modules/evennia/utils/idmapper/tests.html index d93ebc3b2a..78e2979047 100644 --- a/docs/0.9.5/_modules/evennia/utils/idmapper/tests.html +++ b/docs/0.9.5/_modules/evennia/utils/idmapper/tests.html @@ -154,7 +154,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/utils/inlinefuncs.html b/docs/0.9.5/_modules/evennia/utils/inlinefuncs.html deleted file mode 100644 index 7a1926af8c..0000000000 --- a/docs/0.9.5/_modules/evennia/utils/inlinefuncs.html +++ /dev/null @@ -1,726 +0,0 @@ - - - - - - - - evennia.utils.inlinefuncs — Evennia 0.9.5 documentation - - - - - - - - - - - - - -
    -
    -
    -
    - -

    Source code for evennia.utils.inlinefuncs

    -"""
    -Inline functions (nested form).
    -
    -This parser accepts nested inlinefunctions on the form
    -::
    -
    -    $funcname(arg, arg, ...)
    -
    -embedded in any text where any arg can be another `$funcname{}` call.
    -This functionality is turned off by default - to activate,
    -`settings.INLINEFUNC_ENABLED` must be set to `True`.
    -
    -Each token starts with `$funcname(` where there must be no space between the
    -$funcname and "(". It ends with a matched ending parentesis ")".
    -
    -Inside the inlinefunc definition, one can use \\\\ to escape. This is
    -mainly needed for escaping commas in flowing text (which would
    -otherwise be interpreted as an argument separator), or to escape `}`
    -when not intended to close the function block. Enclosing text in
    -matched `\"\"\"` (triple quotes) or `'''` (triple single-quotes) will
    -also escape *everything* within without needing to escape individual
    -characters.
    -
    -The available inlinefuncs are defined as global-level functions in
    -modules defined by `settings.INLINEFUNC_MODULES`. They are identified
    -by their function name (and ignored if this name starts with `_`). They
    -should be on the following form:
    -::
    -
    -    def funcname (*args, **kwargs):
    -    # ...
    -
    -Here, the arguments given to `$funcname(arg1,arg2)` will appear as the
    -`*args` tuple. This will be populated by the arguments given to the
    -inlinefunc in-game - the only part that will be available from
    -in-game. `**kwargs` are not supported from in-game but are only used
    -internally by Evennia to make details about the caller available to
    -the function. The kwarg passed to all functions is `session`, the
    -Sessionobject for the object seeing the string. This may be `None` if
    -the string is sent to a non-puppetable object. The inlinefunc should
    -never raise an exception.
    -
    -There are two reserved function names:
    -
    -- "nomatch": This is called if the user uses a functionname that is
    -  not registered. The nomatch function will get the name of the
    -  not-found function as its first argument followed by the normal
    -  arguments to the given function. If not defined the default effect is
    -  to print `<UNKNOWN>` to replace the unknown function.
    -- "stackfull": This is called when the maximum nested function stack is reached.
    -  When this happens, the original parsed string is returned and the result of
    -  the `stackfull` inlinefunc is appended to the end. By default this is an
    -  error message.
    -
    -Syntax errors, notably not completely closing all inlinefunc blocks, will lead
    -to the entire string remaining unparsed.
    -
    -----
    -
    -"""
    -
    -import re
    -import fnmatch
    -import random as base_random
    -from django.conf import settings
    -
    -from evennia.utils import utils, logger
    -
    -# The stack size is a security measure. Set to <=0 to disable.
    -_STACK_MAXSIZE = settings.INLINEFUNC_STACK_MAXSIZE
    -
    -
    -# example/testing inline functions
    -
    -
    -
    [docs]def random(*args, **kwargs): - """ - Inlinefunc. Returns a random number between - 0 and 1, from 0 to a maximum value, or within a given range (inclusive). - - Args: - minval (str, optional): Minimum value. If not given, assumed 0. - maxval (str, optional): Maximum value. - - Keyword argumuents: - session (Session): Session getting the string. - - Notes: - If either of the min/maxvalue has a '.' in it, a floating-point random - value will be returned. Otherwise it will be an integer value in the - given range. - - Example: - - - `$random()` - - `$random(5)` - - `$random(5, 10)` - - """ - nargs = len(args) - if nargs == 1: - # only maxval given - minval, maxval = "0", args[0] - elif nargs > 1: - minval, maxval = args[:2] - else: - minval, maxval = ("0", "1") - - if "." in minval or "." in maxval: - # float mode - try: - minval, maxval = float(minval), float(maxval) - except ValueError: - minval, maxval = 0, 1 - return "{:.2f}".format(minval + maxval * base_random.random()) - else: - # int mode - try: - minval, maxval = int(minval), int(maxval) - except ValueError: - minval, maxval = 0, 1 - return str(base_random.randint(minval, maxval))
    - - -
    [docs]def pad(*args, **kwargs): - """ - Inlinefunc. Pads text to given width. - - Args: - text (str, optional): Text to pad. - width (str, optional): Will be converted to integer. Width - of padding. - align (str, optional): Alignment of padding; one of 'c', 'l' or 'r'. - fillchar (str, optional): Character used for padding. Defaults to a - space. - - Keyword Args: - session (Session): Session performing the pad. - - Example: - `$pad(text, width, align, fillchar)` - - """ - text, width, align, fillchar = "", 78, "c", " " - nargs = len(args) - if nargs > 0: - text = args[0] - if nargs > 1: - width = int(args[1]) if args[1].strip().isdigit() else 78 - if nargs > 2: - align = args[2] if args[2] in ("c", "l", "r") else "c" - if nargs > 3: - fillchar = args[3] - return utils.pad(text, width=width, align=align, fillchar=fillchar)
    - - -
    [docs]def crop(*args, **kwargs): - """ - Inlinefunc. Crops ingoing text to given widths. - - Args: - text (str, optional): Text to crop. - width (str, optional): Will be converted to an integer. Width of - crop in characters. - suffix (str, optional): End string to mark the fact that a part - of the string was cropped. Defaults to `[...]`. - Keyword Args: - session (Session): Session performing the crop. - - Example: - `$crop(text, width=78, suffix='[...]')` - - """ - text, width, suffix = "", 78, "[...]" - nargs = len(args) - if nargs > 0: - text = args[0] - if nargs > 1: - width = int(args[1]) if args[1].strip().isdigit() else 78 - if nargs > 2: - suffix = args[2] - return utils.crop(text, width=width, suffix=suffix)
    - - -
    [docs]def space(*args, **kwargs): - """ - Inlinefunc. Inserts an arbitrary number of spaces. Defaults to 4 spaces. - - Args: - spaces (int, optional): The number of spaces to insert. - - Keyword Args: - session (Session): Session performing the crop. - - Example: - `$space(20)` - - """ - width = 4 - if args: - width = abs(int(args[0])) if args[0].strip().isdigit() else 4 - return " " * width
    - - -
    [docs]def clr(*args, **kwargs): - """ - Inlinefunc. Colorizes nested text. - - Args: - startclr (str, optional): An ANSI color abbreviation without the - prefix `|`, such as `r` (red foreground) or `[r` (red background). - text (str, optional): Text - endclr (str, optional): The color to use at the end of the string. Defaults - to `|n` (reset-color). - Keyword Args: - session (Session): Session object triggering inlinefunc. - - Example: - `$clr(startclr, text, endclr)` - - """ - text = "" - nargs = len(args) - if nargs > 0: - color = args[0].strip() - if nargs > 1: - text = args[1] - text = "|" + color + text - if nargs > 2: - text += "|" + args[2].strip() - else: - text += "|n" - return text
    - - -
    [docs]def null(*args, **kwargs): - return args[0] if args else ""
    - - -
    [docs]def nomatch(name, *args, **kwargs): - """ - Default implementation of nomatch returns the function as-is as a string. - - """ - kwargs.pop("inlinefunc_stack_depth", None) - kwargs.pop("session") - - return "${name}({args}{kwargs})".format( - name=name, - args=",".join(args), - kwargs=",".join("{}={}".format(key, val) for key, val in kwargs.items()), - )
    - - -_INLINE_FUNCS = {} - -# we specify a default nomatch function to use if no matching func was -# found. This will be overloaded by any nomatch function defined in -# the imported modules. -_DEFAULT_FUNCS = { - "nomatch": lambda *args, **kwargs: "<UNKNOWN>", - "stackfull": lambda *args, **kwargs: "\n (not parsed: ", -} - -_INLINE_FUNCS.update(_DEFAULT_FUNCS) - -# load custom inline func modules. -for module in utils.make_iter(settings.INLINEFUNC_MODULES): - try: - _INLINE_FUNCS.update(utils.callables_from_module(module)) - except ImportError as err: - if module == "server.conf.inlinefuncs": - # a temporary warning since the default module changed name - raise ImportError( - "Error: %s\nPossible reason: mygame/server/conf/inlinefunc.py should " - "be renamed to mygame/server/conf/inlinefuncs.py (note " - "the S at the end)." % err - ) - else: - raise - - -# regex definitions - -_RE_STARTTOKEN = re.compile(r"(?<!\\)\$(\w+)\(") # unescaped $funcname( (start of function call) - -# note: this regex can be experimented with at https://regex101.com/r/kGR3vE/2 -_RE_TOKEN = re.compile( - r""" - (?<!\\)\'\'\'(?P<singlequote>.*?)(?<!\\)\'\'\'| # single-triplets escape all inside - (?<!\\)\"\"\"(?P<doublequote>.*?)(?<!\\)\"\"\"| # double-triplets escape all inside - (?P<comma>(?<!\\)\,)| # , (argument sep) - (?P<end>(?<!\\)\))| # ) (possible end of func call) - (?P<leftparens>(?<!\\)\()| # ( (lone left-parens) - (?P<start>(?<!\\)\$\w+\()| # $funcname (start of func call) - (?P<escaped> # escaped tokens to re-insert sans backslash - \\\'|\\\"|\\\)|\\\$\w+\(|\\\()| - (?P<rest> # everything else to re-insert verbatim - \$(?!\w+\()|\'|\"|\\|[^),$\'\"\\\(]+)""", - re.UNICODE | re.IGNORECASE | re.VERBOSE | re.DOTALL, -) - -# Cache for function lookups. -_PARSING_CACHE = utils.LimitedSizeOrderedDict(size_limit=1000) - - -
    [docs]class ParseStack(list): - """ - Custom stack that always concatenates strings together when the - strings are added next to one another. Tuples are stored - separately and None is used to mark that a string should be broken - up into a new chunk. Below is the resulting stack after separately - appending 3 strings, None, 2 strings, a tuple and finally 2 - strings: - - [string + string + string, - None - string + string, - tuple, - string + string] - - """ - -
    [docs] def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - # always start stack with the empty string - list.append(self, "") - # indicates if the top of the stack is a string or not - self._string_last = True
    - - def __eq__(self, other): - return ( - super().__eq__(other) - and hasattr(other, "_string_last") - and self._string_last == other._string_last - ) - - def __ne__(self, other): - return not self.__eq__(other) - -
    [docs] def append(self, item): - """ - The stack will merge strings, add other things as normal - """ - if isinstance(item, str): - if self._string_last: - self[-1] += item - else: - list.append(self, item) - self._string_last = True - else: - # everything else is added as normal - list.append(self, item) - self._string_last = False
    - - -
    [docs]class InlinefuncError(RuntimeError): - pass
    - - -
    [docs]def parse_inlinefunc(string, strip=False, available_funcs=None, stacktrace=False, **kwargs): - """ - Parse the incoming string. - - Args: - string (str): The incoming string to parse. - strip (bool, optional): Whether to strip function calls rather than - execute them. - available_funcs (dict, optional): Define an alternative source of functions to parse for. - If unset, use the functions found through `settings.INLINEFUNC_MODULES`. - stacktrace (bool, optional): If set, print the stacktrace to log. - Keyword Args: - session (Session): This is sent to this function by Evennia when triggering - it. It is passed to the inlinefunc. - kwargs (any): All other kwargs are also passed on to the inlinefunc. - - - """ - global _PARSING_CACHE - usecache = False - if not available_funcs: - available_funcs = _INLINE_FUNCS - usecache = True - else: - # make sure the default keys are available, but also allow overriding - tmp = _DEFAULT_FUNCS.copy() - tmp.update(available_funcs) - available_funcs = tmp - - if usecache and string in _PARSING_CACHE: - # stack is already cached - stack = _PARSING_CACHE[string] - elif not _RE_STARTTOKEN.search(string): - # if there are no unescaped start tokens at all, return immediately. - return string - else: - # no cached stack; build a new stack and continue - stack = ParseStack() - - # process string on stack - ncallable = 0 - nlparens = 0 - nvalid = 0 - - if stacktrace: - out = "STRING: {} =>".format(string) - print(out) - logger.log_info(out) - - for match in _RE_TOKEN.finditer(string): - gdict = match.groupdict() - - if stacktrace: - out = " MATCH: {}".format({key: val for key, val in gdict.items() if val}) - print(out) - logger.log_info(out) - - if gdict["singlequote"]: - stack.append(gdict["singlequote"]) - elif gdict["doublequote"]: - stack.append(gdict["doublequote"]) - elif gdict["leftparens"]: - # we have a left-parens inside a callable - if ncallable: - nlparens += 1 - stack.append("(") - elif gdict["end"]: - if nlparens > 0: - nlparens -= 1 - stack.append(")") - continue - if ncallable <= 0: - stack.append(")") - continue - args = [] - while stack: - operation = stack.pop() - if callable(operation): - if not strip: - stack.append((operation, [arg for arg in reversed(args)])) - ncallable -= 1 - break - else: - args.append(operation) - elif gdict["start"]: - funcname = _RE_STARTTOKEN.match(gdict["start"]).group(1) - try: - # try to fetch the matching inlinefunc from storage - stack.append(available_funcs[funcname]) - nvalid += 1 - except KeyError: - stack.append(available_funcs["nomatch"]) - stack.append(funcname) - stack.append(None) - ncallable += 1 - elif gdict["escaped"]: - # escaped tokens - token = gdict["escaped"].lstrip("\\") - stack.append(token) - elif gdict["comma"]: - if ncallable > 0: - # commas outside strings and inside a callable are - # used to mark argument separation - we use None - # in the stack to indicate such a separation. - stack.append(None) - else: - # no callable active - just a string - stack.append(",") - else: - # the rest - stack.append(gdict["rest"]) - - if ncallable > 0: - # this means not all inlinefuncs were complete - return string - - if _STACK_MAXSIZE > 0 and _STACK_MAXSIZE < nvalid: - # if stack is larger than limit, throw away parsing - return string + available_funcs["stackfull"](*args, **kwargs) - elif usecache: - # cache the stack - we do this also if we don't check the cache above - _PARSING_CACHE[string] = stack - - # run the stack recursively - def _run_stack(item, depth=0): - retval = item - if isinstance(item, tuple): - if strip: - return "" - else: - func, arglist = item - args = [""] - for arg in arglist: - if arg is None: - # an argument-separating comma - start a new arg - args.append("") - else: - # all other args should merge into one string - args[-1] += _run_stack(arg, depth=depth + 1) - # execute the inlinefunc at this point or strip it. - kwargs["inlinefunc_stack_depth"] = depth - retval = "" if strip else func(*args, **kwargs) - return utils.to_str(retval) - - retval = "".join(_run_stack(item) for item in stack) - if stacktrace: - out = "STACK: \n{} => {}\n".format(stack, retval) - print(out) - logger.log_info(out) - - # execute the stack - return retval
    - - -
    [docs]def raw(string): - """ - Escape all inlinefuncs in a string so they won't get parsed. - - Args: - string (str): String with inlinefuncs to escape. - """ - - def _escape(match): - return "\\" + match.group(0) - - return _RE_STARTTOKEN.sub(_escape, string)
    - - -# -# Nick templating -# - - -""" -This supports the use of replacement templates in nicks: - -This happens in two steps: - -1) The user supplies a template that is converted to a regex according - to the unix-like templating language. -2) This regex is tested against nicks depending on which nick replacement - strategy is considered (most commonly inputline). -3) If there is a template match and there are templating markers, - these are replaced with the arguments actually given. - -@desc $1 $2 $3 - -This will be converted to the following regex: - -\@desc (?P<1>\w+) (?P<2>\w+) $(?P<3>\w+) - -Supported template markers (through fnmatch) - * matches anything (non-greedy) -> .*? - ? matches any single character -> - [seq] matches any entry in sequence - [!seq] matches entries not in sequence -Custom arg markers - $N argument position (1-99) - -""" -_RE_NICK_ARG = re.compile(r"\\(\$)([1-9][0-9]?)") -_RE_NICK_TEMPLATE_ARG = re.compile(r"(\$)([1-9][0-9]?)") -_RE_NICK_SPACE = re.compile(r"\\ ") - - -
    [docs]class NickTemplateInvalid(ValueError): - pass
    - - -
    [docs]def initialize_nick_templates(in_template, out_template): - """ - Initialize the nick templates for matching and remapping a string. - - Args: - in_template (str): The template to be used for nick recognition. - out_template (str): The template to be used to replace the string - matched by the `in_template`. - - Returns: - regex, template (regex, str): Regex to match against strings and a - template with markers `{arg1}`, `{arg2}`, etc for replacement using the - standard `.format` method. - - Raises: - inlinefuncs.NickTemplateInvalid: If the in/out template does not have a matching - number of $args. - - """ - # create the regex for in_template - regex_string = fnmatch.translate(in_template) - n_inargs = len(_RE_NICK_ARG.findall(regex_string)) - regex_string = _RE_NICK_SPACE.sub("\s+", regex_string) - regex_string = _RE_NICK_ARG.sub(lambda m: "(?P<arg%s>.+?)" % m.group(2), regex_string) - - # create the out_template - template_string = _RE_NICK_TEMPLATE_ARG.sub(lambda m: "{arg%s}" % m.group(2), out_template) - - # validate the tempaltes - they should at least have the same number of args - n_outargs = len(_RE_NICK_TEMPLATE_ARG.findall(out_template)) - if n_inargs != n_outargs: - raise NickTemplateInvalid - - return re.compile(regex_string), template_string
    - - -
    [docs]def parse_nick_template(string, template_regex, outtemplate): - """ - Parse a text using a template and map it to another template - - Args: - string (str): The input string to processj - template_regex (regex): A template regex created with - initialize_nick_template. - outtemplate (str): The template to which to map the matches - produced by the template_regex. This should have $1, $2, - etc to match the regex. - - """ - match = template_regex.match(string) - if match: - return outtemplate.format(**match.groupdict()) - return string
    -
    - -
    -
    -
    -
    - -
    -
    - - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/utils/logger.html b/docs/0.9.5/_modules/evennia/utils/logger.html index 4a02a01b93..8566473a6a 100644 --- a/docs/0.9.5/_modules/evennia/utils/logger.html +++ b/docs/0.9.5/_modules/evennia/utils/logger.html @@ -57,7 +57,6 @@ import os import time -import glob from datetime import datetime from traceback import format_exc from twisted.python import log, logfile @@ -88,6 +87,7 @@ Returns: timestring (str): A formatted string of the given time. + """ when = when if when else time.time() @@ -167,6 +167,7 @@ server.log.2020_01_29 server.log.2020_01_29__1 server.log.2020_01_29__2 + """ suffix = "" copy_suffix = 0 @@ -187,7 +188,10 @@ return suffix
    [docs] def write(self, data): - "Write data to log file" + """ + Write data to log file + + """ logfile.BaseLogFile.write(self, data) self.lastDate = max(self.lastDate, self.toDate()) self.size += len(data)
    @@ -196,6 +200,7 @@
    [docs]class PortalLogObserver(log.FileLogObserver): """ Reformat logging + """ timeFormat = None @@ -330,6 +335,7 @@ Prints any generic debugging/informative info that should appear in the log. infomsg: (string) The message to be logged. + """ try: infomsg = str(infomsg) @@ -348,6 +354,7 @@ Args: depmsg (str): The deprecation message to log. + """ try: depmsg = str(depmsg) @@ -366,6 +373,7 @@ Args: secmsg (str): The security message to log. + """ try: secmsg = str(secmsg) @@ -387,6 +395,7 @@ the LogFile's rotate method in order to append some of the last lines of the previous log to the start of the new log, in order to preserve a continuous chat history for channel log files. + """ # we delay import of settings to keep logger module as free @@ -398,12 +407,15 @@ _CHANNEL_LOG_NUM_TAIL_LINES = settings.CHANNEL_LOG_NUM_TAIL_LINES num_lines_to_append = _CHANNEL_LOG_NUM_TAIL_LINES -
    [docs] def rotate(self): +
    [docs] def rotate(self, num_lines_to_append=None): """ Rotates our log file and appends some number of lines from the previous log to the start of the new one. + """ - append_tail = self.num_lines_to_append > 0 + append_tail = (num_lines_to_append + if num_lines_to_append is not None + else self.num_lines_to_append) if not append_tail: logfile.LogFile.rotate(self) return @@ -416,9 +428,11 @@ """ Convenience method for accessing our _file attribute's seek method, which is used in tail_log_function. + Args: *args: Same args as file.seek **kwargs: Same kwargs as file.seek + """ return self._file.seek(*args, **kwargs)
    @@ -426,12 +440,14 @@ """ Convenience method for accessing our _file attribute's readlines method, which is used in tail_log_function. + Args: *args: same args as file.readlines **kwargs: same kwargs as file.readlines Returns: lines (list): lines from our _file attribute. + """ return [line.decode("utf-8") for line in self._file.readlines(*args, **kwargs)]
    @@ -513,6 +529,43 @@ deferToThread(callback, filehandle, msg).addErrback(errback) +
    [docs]def log_file_exists(filename="game.log"): + """ + Determine if a log-file already exists. + + Args: + filename (str): The filename (within the log-dir). + + Returns: + bool: If the log file exists or not. + + """ + global _LOGDIR + if not _LOGDIR: + from django.conf import settings + _LOGDIR = settings.LOG_DIR + + filename = os.path.join(_LOGDIR, filename) + return os.path.exists(filename)
    + + +
    [docs]def rotate_log_file(filename="game.log", num_lines_to_append=None): + """ + Force-rotate a log-file, without + + Args: + filename (str): The log file, located in settings.LOG_DIR. + num_lines_to_append (int, optional): Include N number of + lines from previous file in new one. If `None`, use default. + Set to 0 to include no lines. + + """ + if log_file_exists(filename): + file_handle = _open_log_file(filename) + if file_handle: + file_handle.rotate(num_lines_to_append=num_lines_to_append)
    + +
    [docs]def tail_log_file(filename, offset, nlines, callback=None): """ Return the tail of the log file. @@ -552,7 +605,7 @@ lines_found = filehandle.readlines() block_count -= 1 # return the right number of lines - lines_found = lines_found[-nlines - offset : -offset if offset else None] + lines_found = lines_found[-nlines - offset: -offset if offset else None] if callback: callback(lines_found) return None @@ -610,7 +663,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/utils/optionclasses.html b/docs/0.9.5/_modules/evennia/utils/optionclasses.html index 7f3c45953f..6e6b3dddbb 100644 --- a/docs/0.9.5/_modules/evennia/utils/optionclasses.html +++ b/docs/0.9.5/_modules/evennia/utils/optionclasses.html @@ -39,13 +39,7 @@

    Source code for evennia.utils.optionclasses

    -"""
    -Option classes store user- or server Options in a generic way
    -while also providing validation.
    -
    -"""
    -
    -import datetime
    +import datetime
     from evennia import logger
     from evennia.utils.ansi import strip_ansi
     from evennia.utils.validatorfuncs import _TZ_DICT
    @@ -157,8 +151,8 @@
     
    [docs] def save(self, **kwargs): """ Stores the current value using `.handler.save_handler(self.key, value, **kwargs)` - where kwargs are a combination of those passed into this function and the - ones specified by the OptionHandler. + where `kwargs` are a combination of those passed into this function and + the ones specified by the `OptionHandler`. Keyword Args: any (any): Not used by default. These are passed in from self.set @@ -405,7 +399,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/utils/optionhandler.html b/docs/0.9.5/_modules/evennia/utils/optionhandler.html index 292cce3e6d..b13d79f992 100644 --- a/docs/0.9.5/_modules/evennia/utils/optionhandler.html +++ b/docs/0.9.5/_modules/evennia/utils/optionhandler.html @@ -41,12 +41,13 @@

    Source code for evennia.utils.optionhandler

     from evennia.utils.utils import string_partial_matching
     from evennia.utils.containers import OPTION_CLASSES
    +from django.utils.translation import gettext as _
     
     _GA = object.__getattribute__
     _SA = object.__setattr__
     
     
    -
    [docs]class InMemorySaveHandler(object): +
    [docs]class InMemorySaveHandler: """ Fallback SaveHandler, implementing a minimum of the required save mechanism and storing data in memory. @@ -63,7 +64,7 @@ return self.storage.get(key, default)
    -
    [docs]class OptionHandler(object): +
    [docs]class OptionHandler: """ This is a generic Option handler. Retrieve options either as properties on this handler or by using the .get method. @@ -98,6 +99,7 @@ A common one to pass would be AttributeHandler.get. save_kwargs (any): Optional extra kwargs to pass into `savefunc` above. load_kwargs (any): Optional extra kwargs to pass into `loadfunc` above. + Notes: Both loadfunc and savefunc must be specified. If only one is given, the other will be ignored and in-memory storage will be used. @@ -174,7 +176,7 @@ """ if key not in self.options_dict: if raise_error: - raise KeyError("Option not found!") + raise KeyError(_("Option not found!")) return default # get the options or load/recache it op_found = self.options.get(key) or self._load_option(key) @@ -195,12 +197,14 @@ """ if not key: - raise ValueError("Option field blank!") + raise ValueError(_("Option field blank!")) match = string_partial_matching(list(self.options_dict.keys()), key, ret_index=False) if not match: - raise ValueError("Option not found!") + raise ValueError(_("Option not found!")) if len(match) > 1: - raise ValueError(f"Multiple matches: {', '.join(match)}. Please be more specific.") + raise ValueError(_("Multiple matches:") + + f"{', '.join(match)}. " + + _("Please be more specific.")) match = match[0] op = self.get(match, return_obj=True) op.set(value, **kwargs) @@ -256,7 +260,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/utils/picklefield.html b/docs/0.9.5/_modules/evennia/utils/picklefield.html index 97a87d3602..d7d0762231 100644 --- a/docs/0.9.5/_modules/evennia/utils/picklefield.html +++ b/docs/0.9.5/_modules/evennia/utils/picklefield.html @@ -327,7 +327,7 @@ return value
    [docs] def value_to_string(self, obj): - value = self._get_val_from_obj(obj) + value = self.value_from_object(obj) return self.get_db_prep_value(value)
    [docs] def get_internal_type(self): @@ -378,7 +378,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/utils/search.html b/docs/0.9.5/_modules/evennia/utils/search.html index 883f4230dd..516fc36d7b 100644 --- a/docs/0.9.5/_modules/evennia/utils/search.html +++ b/docs/0.9.5/_modules/evennia/utils/search.html @@ -78,6 +78,7 @@ "search_message", "search_channel", "search_help_entry", + "search_tag", "search_script_tag", "search_account_tag", "search_channel_tag", @@ -95,13 +96,13 @@ Tag = ContentType.objects.get(app_label="typeclasses", model="tag").model_class() except OperationalError: # this is a fallback used during tests/doc building - print("Couldn't initialize search managers - db not set up.") - from evennia.objects.models import ObjectDB - from evennia.accounts.models import AccountDB - from evennia.scripts.models import ScriptDB - from evennia.comms.models import Msg, ChannelDB - from evennia.help.models import HelpEntry - from evennia.typeclasses.tags import Tag + print("Couldn't initialize search managers - db not set up.") + from evennia.objects.models import ObjectDB + from evennia.accounts.models import AccountDB + from evennia.scripts.models import ScriptDB + from evennia.comms.models import Msg, ChannelDB + from evennia.help.models import HelpEntry + from evennia.typeclasses.tags import Tag # noqa # ------------------------------------------------------------------- # Search manager-wrappers @@ -439,7 +440,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/utils/test_resources.html b/docs/0.9.5/_modules/evennia/utils/test_resources.html index 2984f02bfd..cf2e11a20c 100644 --- a/docs/0.9.5/_modules/evennia/utils/test_resources.html +++ b/docs/0.9.5/_modules/evennia/utils/test_resources.html @@ -80,18 +80,18 @@ should directly give the module pathname to unload. Example: - :: - # (in a test method) - unload_module(foo) - with mock.patch("foo.GLOBALTHING", "mockval"): - import foo - ... # test code using foo.GLOBALTHING, now set to 'mockval' + ```python + # (in a test method) + unload_module(foo) + with mock.patch("foo.GLOBALTHING", "mockval"): + import foo + ... # test code using foo.GLOBALTHING, now set to 'mockval' + ``` - Notes: - This allows for mocking constants global to the module, since - otherwise those would not be mocked (since a module is only - loaded once). + This allows for mocking constants global to the module, since + otherwise those would not be mocked (since a module is only + loaded once). """ if isinstance(module, str): @@ -251,7 +251,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/utils/text2html.html b/docs/0.9.5/_modules/evennia/utils/text2html.html index ddcf85ce27..85873aa198 100644 --- a/docs/0.9.5/_modules/evennia/utils/text2html.html +++ b/docs/0.9.5/_modules/evennia/utils/text2html.html @@ -144,9 +144,10 @@ ) re_dblspace = re.compile(r" {2,}", re.M) re_url = re.compile( - r'((?:ftp|www|https?)\W+(?:(?!\.(?:\s|$)|&\w+;)[^"\',;$*^\\(){}<>\[\]\s])+)(\.(?:\s|$)|&\w+;|)' + r'(?<!=")((?:ftp|www|https?)\W+(?:(?!\.(?:\s|$)|&\w+;)[^"\',;$*^\\(){}<>\[\]\s])+)(\.(?:\s|$)|&\w+;|)' ) re_mxplink = re.compile(r"\|lc(.*?)\|lt(.*?)\|le", re.DOTALL) + re_mxpurl = re.compile(r"\|lu(.*?)\|lt(.*?)\|le", re.DOTALL) def _sub_bgfg(self, colormatch): # print("colormatch.groups()", colormatch.groups()) @@ -331,6 +332,21 @@ ) return val +
    [docs] def sub_mxp_urls(self, match): + """ + Helper method to be passed to re.sub, + replaces MXP links with HTML code. + Args: + match (re.Matchobject): Match for substitution. + Returns: + text (str): Processed text. + """ + url, text = [grp.replace('"', "\\&quot;") for grp in match.groups()] + val = ( + r"""<a id="mxplink" href="{url}" target="_blank">{text}</a>""".format(url=url, text=text) + ) + return val
    +
    [docs] def sub_text(self, match): """ Helper method to be passed to re.sub, @@ -378,6 +394,7 @@ # convert all ansi to html result = re.sub(self.re_string, self.sub_text, text) result = re.sub(self.re_mxplink, self.sub_mxp_links, result) + result = re.sub(self.re_mxpurl, self.sub_mxp_urls, result) result = self.re_color(result) result = self.re_bold(result) result = self.re_underline(result) @@ -444,7 +461,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/utils/utils.html b/docs/0.9.5/_modules/evennia/utils/utils.html index 1997764828..f6490d16ee 100644 --- a/docs/0.9.5/_modules/evennia/utils/utils.html +++ b/docs/0.9.5/_modules/evennia/utils/utils.html @@ -50,7 +50,6 @@ import os import gc import sys -import copy import types import math import re @@ -61,6 +60,8 @@ import importlib import importlib.util import importlib.machinery +from ast import literal_eval +from simpleeval import simple_eval from unicodedata import east_asian_width from twisted.internet.task import deferLater from twisted.internet.defer import returnValue # noqa - used as import target @@ -74,18 +75,23 @@ from django.apps import apps from django.core.validators import validate_email as django_validate_email from django.core.exceptions import ValidationError as DjangoValidationError + from evennia.utils import logger _MULTIMATCH_TEMPLATE = settings.SEARCH_MULTIMATCH_TEMPLATE _EVENNIA_DIR = settings.EVENNIA_DIR _GAME_DIR = settings.GAME_DIR ENCODINGS = settings.ENCODINGS + +_TASK_HANDLER = None +_TICKER_HANDLER = None + _GA = object.__getattribute__ _SA = object.__setattr__ _DA = object.__delattr__ -
    [docs]def is_iter(obj): +
    [docs]def is_iter(obj): """ Checks if an object behaves iterably. @@ -110,7 +116,7 @@ return False
    -
    [docs]def make_iter(obj): +
    [docs]def make_iter(obj): """ Makes sure that the object is always iterable. @@ -125,7 +131,7 @@ return not is_iter(obj) and [obj] or obj
    -
    [docs]def wrap(text, width=None, indent=0): +
    [docs]def wrap(text, width=None, indent=0): """ Safely wrap text to a certain number of characters. @@ -149,7 +155,7 @@ fill = wrap -
    [docs]def pad(text, width=None, align="c", fillchar=" "): +
    [docs]def pad(text, width=None, align="c", fillchar=" "): """ Pads to a given width. @@ -175,7 +181,7 @@ return text.center(width, fillchar)
    -
    [docs]def crop(text, width=None, suffix="[...]"): +
    [docs]def crop(text, width=None, suffix="[...]"): """ Crop text to a certain width, throwing away text from too-long lines. @@ -203,16 +209,18 @@ return to_str(text)
    -
    [docs]def dedent(text, baseline_index=None): +
    [docs]def dedent(text, baseline_index=None, indent=None): """ Safely clean all whitespace at the left of a paragraph. Args: text (str): The text to dedent. - baseline_index (int or None, optional): Which row to use as a 'base' + baseline_index (int, optional): Which row to use as a 'base' for the indentation. Lines will be dedented to this level but no further. If None, indent so as to completely deindent the least indented text. + indent (int, optional): If given, force all lines to this indent. + This bypasses `baseline_index`. Returns: text (str): Dedented string. @@ -225,18 +233,23 @@ """ if not text: return "" - if baseline_index is None: + if indent is not None: + lines = text.split("\n") + ind = " " * indent + indline = "\n" + ind + return ind + indline.join(line.strip() for line in lines) + elif baseline_index is None: return textwrap.dedent(text) else: lines = text.split("\n") baseline = lines[baseline_index] spaceremove = len(baseline) - len(baseline.lstrip(" ")) return "\n".join( - line[min(spaceremove, len(line) - len(line.lstrip(" "))) :] for line in lines + line[min(spaceremove, len(line) - len(line.lstrip(" "))):] for line in lines )
    -
    [docs]def justify(text, width=None, align="f", indent=0): +
    [docs]def justify(text, width=None, align="f", indent=0): """ Fully justify a text so that it fits inside `width`. When using full justification (default) this will be done by padding between @@ -329,7 +342,7 @@ return "\n".join([indentstring + line for line in lines])
    -
    [docs]def columnize(string, columns=2, spacing=4, align="l", width=None): +
    [docs]def columnize(string, columns=2, spacing=4, align="l", width=None): """ Break a string into a number of columns, using as little vertical space as possible. @@ -371,7 +384,7 @@ cols = [] istart = 0 for irows in nrows: - cols.append(onecol[istart : istart + irows]) + cols.append(onecol[istart: istart + irows]) istart = istart + irows for col in cols: if len(col) < height: @@ -385,7 +398,7 @@ return "\n".join(rows)
    -
    [docs]def iter_to_string(initer, endsep="and", addquote=False): +
    [docs]def iter_to_str(initer, endsep="and", addquote=False): """ This pretty-formats an iterable list as string output, adding an optional alternative separator to the second to last entry. If `addquote` @@ -401,23 +414,21 @@ values with double quotes. Returns: - liststr (str): The list represented as a string. + str: The list represented as a string. Examples: ```python - # no endsep: - [1,2,3] -> '1, 2, 3' - # with endsep=='and': - [1,2,3] -> '1, 2 and 3' - # with addquote and endsep - [1,2,3] -> '"1", "2" and "3"' + >>> list_to_string([1,2,3], endsep='') + '1, 2, 3' + >>> list_to_string([1,2,3], ensdep='and') + '1, 2, and 3' + >>> list_to_string([1,2,3], endsep='and', addquote=True) + '"1", "2", and "3"' ``` """ - if not endsep: - endsep = "," - else: + if endsep: endsep = " " + endsep if not initer: return "" @@ -425,18 +436,23 @@ if addquote: if len(initer) == 1: return '"%s"' % initer[0] - return ", ".join('"%s"' % v for v in initer[:-1]) + "%s %s" % (endsep, '"%s"' % initer[-1]) + elif len(initer) == 2: + return '"%s"' % ('"%s "' % endsep).join(str(v) for v in initer) + return ", ".join('"%s"' % v for v in initer[:-1]) + ",%s %s" % (endsep, '"%s"' % initer[-1]) else: if len(initer) == 1: return str(initer[0]) - return ", ".join(str(v) for v in initer[:-1]) + "%s %s" % (endsep, initer[-1])
    + elif len(initer) == 2: + return ("%s " % endsep).join(str(v) for v in initer) + return ", ".join(str(v) for v in initer[:-1]) + ",%s %s" % (endsep, initer[-1])
    -# legacy alias -list_to_string = iter_to_string +# legacy aliases +list_to_string = iter_to_str +iter_to_string = iter_to_str -
    [docs]def wildcard_to_regexp(instring): +
    [docs]def wildcard_to_regexp(instring): """ Converts a player-supplied string that may have wildcards in it to regular expressions. This is useful for name matching. @@ -468,7 +484,7 @@ return regexp_string
    -
    [docs]def time_format(seconds, style=0): +
    [docs]def time_format(seconds, style=0): """ Function to return a 'prettified' version of a value in seconds. @@ -604,7 +620,7 @@ return retval.strip()
    -
    [docs]def datetime_format(dtobj): +
    [docs]def datetime_format(dtobj): """ Pretty-prints the time since a given time. @@ -635,7 +651,7 @@ return timestring
    -
    [docs]def host_os_is(osname): +
    [docs]def host_os_is(osname): """ Check to see if the host OS matches the query. @@ -650,7 +666,7 @@ return os.name == osname
    -
    [docs]def get_evennia_version(mode="long"): +
    [docs]def get_evennia_version(mode="long"): """ Helper method for getting the current evennia version. @@ -676,7 +692,7 @@ return vers
    -
    [docs]def pypath_to_realpath(python_path, file_ending=".py", pypath_prefixes=None): +
    [docs]def pypath_to_realpath(python_path, file_ending=".py", pypath_prefixes=None): """ Converts a dotted Python path to an absolute path under the Evennia library directory or under the current game directory. @@ -736,7 +752,7 @@ return list(set(p for p in paths if os.path.isfile(p)))
    -
    [docs]def dbref(inp, reqhash=True): +
    [docs]def dbref(inp, reqhash=True): """ Converts/checks if input is a valid dbref. @@ -764,7 +780,7 @@ return inp if isinstance(inp, int) else None
    -
    [docs]def dbref_to_obj(inp, objclass, raise_errors=True): +
    [docs]def dbref_to_obj(inp, objclass, raise_errors=True): """ Convert a #dbref to a valid object. @@ -820,7 +836,7 @@ } -
    [docs]def latinify(string, default="?", pure_ascii=False): +
    [docs]def latinify(string, default="?", pure_ascii=False): """ Convert a unicode string to "safe" ascii/latin-1 characters. This is used as a last resort when normal encoding does not work. @@ -874,7 +890,7 @@ return "".join(converted)
    -
    [docs]def to_bytes(text, session=None): +
    [docs]def to_bytes(text, session=None): """ Try to encode the given text to bytes, using encodings from settings or from Session. Will always return a bytes, even if given something that is not str or bytes. @@ -891,7 +907,7 @@ the text with "?" in place of problematic characters. If the specified encoding cannot be found, the protocol flag is reset to utf-8. In any case, returns bytes. - Note: + Notes: If `text` is already bytes, return it as is. """ @@ -917,7 +933,7 @@ return text.encode(default_encoding, errors="replace")
    -
    [docs]def to_str(text, session=None): +
    [docs]def to_str(text, session=None): """ Try to decode a bytestream to a python str, using encoding schemas from settings or from Session. Will always return a str(), also if not given a str/bytes. @@ -931,7 +947,7 @@ Returns: decoded_text (str): The decoded text. - Note: + Notes: If `text` is already str, return it as is. """ if isinstance(text, str): @@ -956,7 +972,7 @@ return text.decode(default_encoding, errors="replace")
    -
    [docs]def validate_email_address(emailaddress): +
    [docs]def validate_email_address(emailaddress): """ Checks if an email address is syntactically correct. Makes use of the django email-validator for consistency. @@ -979,24 +995,23 @@ return True
    -
    [docs]def inherits_from(obj, parent): +
    [docs]def inherits_from(obj, parent): """ Takes an object and tries to determine if it inherits at *any* distance from parent. Args: - obj (any): Object to analyze. This may be either an instance - or a class. - parent (any): Can be either instance, class or python path to class. + obj (any): Object to analyze. This may be either an instance or + a class. + parent (any): Can be either an instance, a class or the python + path to the class. Returns: inherits_from (bool): If `parent` is a parent to `obj` or not. Notes: - What differs this function from e.g. `isinstance()` is that `obj` - may be both an instance and a class, and parent may be an - instance, a class, or the python path to a class (counting from - the evennia root directory). + What differentiates this function from Python's `isinstance()` is the + flexibility in the types allowed for the object and parent being compared. """ @@ -1017,7 +1032,7 @@ return any(1 for obj_path in obj_paths if obj_path == parent_path)
    -
    [docs]def server_services(): +
    [docs]def server_services(): """ Lists all services active on the Server. Observe that since services are launched in memory, this function will only return @@ -1038,14 +1053,13 @@ return server
    -
    [docs]def uses_database(name="sqlite3"): +
    [docs]def uses_database(name="sqlite3"): """ Checks if the game is currently using a given database. This is a shortcut to having to use the full backend name. Args: - name (str): One of 'sqlite3', 'mysql', 'postgresql' - or 'oracle'. + name (str): One of 'sqlite3', 'mysql', 'postgresql' or 'oracle'. Returns: uses (bool): If the given database is used or not. @@ -1058,10 +1072,7 @@ return engine == "django.db.backends.%s" % name
    -_TASK_HANDLER = None - - -
    [docs]def delay(timedelay, callback, *args, **kwargs): +
    [docs]def delay(timedelay, callback, *args, **kwargs): """ Delay the calling of a callback (function). @@ -1069,8 +1080,7 @@ timedelay (int or float): The delay in seconds. callback (callable): Will be called as `callback(*args, **kwargs)` after `timedelay` seconds. - args (any): Will be used as arguments to callback. - + *args: Will be used as arguments to callback Keyword Args: persistent (bool, optional): If True the delay remains after a server restart. persistent is False by default. @@ -1080,7 +1090,7 @@ task (TaskHandlerTask): An instance of a task. Refer to, evennia.scripts.taskhandler.TaskHandlerTask - Note: + Notes: The task handler (`evennia.scripts.taskhandler.TASK_HANDLER`) will be called for persistent or non-persistent tasks. If persistent is set to True, the callback, its arguments @@ -1097,18 +1107,88 @@ """ global _TASK_HANDLER - # Do some imports here to avoid circular import and speed things up if _TASK_HANDLER is None: from evennia.scripts.taskhandler import TASK_HANDLER as _TASK_HANDLER + return _TASK_HANDLER.add(timedelay, callback, *args, **kwargs)
    +
    [docs]def repeat(interval, callback, persistent=True, idstring="", stop=False, + store_key=None, *args, **kwargs): + """ + Start a repeating task using the TickerHandler. + + Args: + interval (int): How often to call callback. + callback (callable): This will be called with `*args, **kwargs` every + `interval` seconds. This must be possible to pickle regardless + of if `persistent` is set or not! + persistent (bool, optional): If ticker survives a server reload. + idstring (str, optional): Separates multiple tickers. This is useful + mainly if wanting to set up multiple repeats for the same + interval/callback but with different args/kwargs. + stop (bool, optional): If set, use the given parameters to _stop_ a running + ticker instead of creating a new one. + store_key (tuple, optional): This is only used in combination with `stop` and + should be the return given from the original `repeat` call. If this + is given, all other args except `stop` are ignored. + *args: Used as arguments to `callback`. + **kwargs: Keyword-arguments to pass to `callback`. + + Returns: + tuple or None: The tuple is the `store_key` - the identifier for the + created ticker. Store this and pass into unrepat() in order to to stop + this ticker later. Returns `None` if `stop=True`. + + Raises: + KeyError: If trying to stop a ticker that was not found. + + """ + global _TICKER_HANDLER + if _TICKER_HANDLER is None: + from evennia.scripts.tickerhandler import TICKER_HANDLER as _TICKER_HANDLER + + if stop: + # we pass all args, but only store_key matters if given + _TICKER_HANDLER.remove(interval=interval, + callback=callback, + idstring=idstring, + persistent=persistent, + store_key=store_key) + else: + return _TICKER_HANDLER.add(interval=interval, + callback=callback, + idstring=idstring, + persistent=persistent)
    + +
    [docs]def unrepeat(store_key): + """ + This is used to stop a ticker previously started with `repeat`. + + Args: + store_key (tuple): This is the return from `repeat`, used to uniquely + identify the ticker to stop. Without the store_key, the ticker + must be stopped by passing its parameters to `TICKER_HANDLER.remove` + directly. + + Returns: + bool: True if a ticker was stopped, False if not (for example because no + matching ticker was found or it was already stopped). + + """ + try: + repeat(None, None, stop=True, store_key=store_key) + return True + except KeyError: + return False
    + + _PPOOL = None _PCMD = None _PROC_ERR = "A process has ended with a probable error condition: process ended by signal 9." -
    [docs]def run_async(to_execute, *args, **kwargs): +
    [docs]def run_async(to_execute, *args, **kwargs): """ Runs a function or executes a code snippet asynchronously. @@ -1117,17 +1197,16 @@ executed with `*args` and non-reserved `**kwargs` as arguments. The callable will be executed using ProcPool, or in a thread if ProcPool is not available. - Keyword Args: at_return (callable): Should point to a callable with one - argument. It will be called with the return value from - to_execute. + argument. It will be called with the return value from + to_execute. at_return_kwargs (dict): This dictionary will be used as - keyword arguments to the at_return callback. + keyword arguments to the at_return callback. at_err (callable): This will be called with a Failure instance - if there is an error in to_execute. + if there is an error in to_execute. at_err_kwargs (dict): This dictionary will be used as keyword - arguments to the at_err errback. + arguments to the at_err errback. Notes: All other `*args` and `**kwargs` will be passed on to @@ -1167,7 +1246,7 @@ deferred.addErrback(errback, **errback_kwargs)
    -
    [docs]def check_evennia_dependencies(): +
    [docs]def check_evennia_dependencies(): """ Checks the versions of Evennia's dependencies including making some checks for runtime libraries. @@ -1200,8 +1279,8 @@ except ImportError: errstring += ( "\n ERROR: IRC is enabled, but twisted.words is not installed. Please install it." - "\n Linux Debian/Ubuntu users should install package 'python-twisted-words', others" - "\n can get it from http://twistedmatrix.com/trac/wiki/TwistedWords." + "\n Linux Debian/Ubuntu users should install package 'python-twisted-words', " + "\n others can get it from http://twistedmatrix.com/trac/wiki/TwistedWords." ) not_error = False errstring = errstring.strip() @@ -1211,9 +1290,9 @@ return not_error
    -
    [docs]def has_parent(basepath, obj): +
    [docs]def has_parent(basepath, obj): """ - Checks if `basepath` is somewhere in `obj`'s parent tree. + Checks if `basepath` is somewhere in obj's parent tree. Args: basepath (str): Python dotpath to compare against obj path. @@ -1235,7 +1314,7 @@ return False
    -
    [docs]def mod_import_from_path(path): +
    [docs]def mod_import_from_path(path): """ Load a Python module at the specified path. @@ -1259,7 +1338,7 @@ return None
    -
    [docs]def mod_import(module): +
    [docs]def mod_import(module): """ A generic Python module loader. @@ -1290,7 +1369,7 @@ return None
    -
    [docs]def all_from_module(module): +
    [docs]def all_from_module(module): """ Return all global-level variables defined in a module. @@ -1301,23 +1380,24 @@ already imported module object (e.g. `models`) Returns: - variables (dict): A dict of {variablename: variable} for all + dict: A dict of {variablename: variable} for all variables in the given module. Notes: - Ignores modules and variable names starting with an underscore. + Ignores modules and variable names starting with an underscore, as well + as variables imported into the module from other modules. """ mod = mod_import(module) if not mod: return {} # make sure to only return variables actually defined in this - # module if available (try to avoid not imports) + # module if available (try to avoid imports) members = getmembers(mod, predicate=lambda obj: getmodule(obj) in (mod, None)) return dict((key, val) for key, val in members if not key.startswith("_"))
    -
    [docs]def callables_from_module(module): +
    [docs]def callables_from_module(module): """ Return all global-level callables defined in a module. @@ -1340,7 +1420,7 @@ return dict((key, val) for key, val in members if not key.startswith("_"))
    -
    [docs]def variable_from_module(module, variable=None, default=None): +
    [docs]def variable_from_module(module, variable=None, default=None): """ Retrieve a variable or list of variables from a module. The variable(s) must be defined globally in the module. If no variable @@ -1387,7 +1467,7 @@ return result
    -
    [docs]def string_from_module(module, variable=None, default=None): +
    [docs]def string_from_module(module, variable=None, default=None): """ This is a wrapper for `variable_from_module` that requires return value to be a string to pass. It's primarily used by login screen. @@ -1416,7 +1496,7 @@ return default
    -
    [docs]def random_string_from_module(module): +
    [docs]def random_string_from_module(module): """ Returns a random global string from a module. @@ -1429,7 +1509,7 @@ return random.choice(string_from_module(module))
    -
    [docs]def fuzzy_import_from_module(path, variable, default=None, defaultpaths=None): +
    [docs]def fuzzy_import_from_module(path, variable, default=None, defaultpaths=None): """ Import a variable based on a fuzzy path. First the literal `path` will be tried, then all given `defaultpaths` will be @@ -1461,9 +1541,9 @@ return default
    -
    [docs]def class_from_module(path, defaultpaths=None, fallback=None): +
    [docs]def class_from_module(path, defaultpaths=None, fallback=None): """ - Return a class from a module, given the module's path. This is + Return a class from a module, given the class' full python path. This is primarily used to convert db_typeclass_path:s to classes. Args: @@ -1541,7 +1621,7 @@ object_from_module = class_from_module -
    [docs]def init_new_account(account): +
    [docs]def init_new_account(account): """ Deprecated. """ @@ -1550,7 +1630,7 @@ logger.log_dep("evennia.utils.utils.init_new_account is DEPRECATED and should not be used.")
    -
    [docs]def string_similarity(string1, string2): +
    [docs]def string_similarity(string1, string2): """ This implements a "cosine-similarity" algorithm as described for example in *Proceedings of the 22nd International Conference on Computation @@ -1580,7 +1660,7 @@ return 0
    -
    [docs]def string_suggestions(string, vocabulary, cutoff=0.6, maxnum=3): +
    [docs]def string_suggestions(string, vocabulary, cutoff=0.6, maxnum=3): """ Given a `string` and a `vocabulary`, return a match or a list of suggestions based on string similarity. @@ -1594,8 +1674,8 @@ Returns: suggestions (list): Suggestions from `vocabulary` with a - similarity-rating that higher than or equal to `cutoff`. - Could be empty if there are no matches. + similarity-rating that higher than or equal to `cutoff`. + Could be empty if there are no matches. """ return [ @@ -1609,7 +1689,7 @@ ][:maxnum]
    -
    [docs]def string_partial_matching(alternatives, inp, ret_index=True): +
    [docs]def string_partial_matching(alternatives, inp, ret_index=True): """ Partially matches a string based on a list of `alternatives`. Matching is made from the start of each subword in each @@ -1661,13 +1741,11 @@ return []
    -
    [docs]def format_table(table, extra_space=1): +
    [docs]def format_table(table, extra_space=1): """ - Note: `evennia.utils.evtable` is more powerful than this, but this function - can be useful when the number of columns and rows are unknown and must be - calculated on the fly. + Format a 2D array of strings into a multi-column table. - Args. + Args: table (list): A list of lists to represent columns in the table: `[[val,val,val,...], [val,val,val,...], ...]`, where each val will be placed on a separate row in the @@ -1677,26 +1755,30 @@ padding (in characters) should be left between columns. Returns: - table (list): A list of lists representing the rows to print - out one by one. + list: A list of lists representing the rows to print out one by one. Notes: The function formats the columns to be as wide as the widest member of each column. - Example: - :: + `evennia.utils.evtable` is more powerful than this, but this + function can be useful when the number of columns and rows are + unknown and must be calculated on the fly. - ftable = format_table([[...], [...], ...]) - for ir, row in enumarate(ftable): - if ir == 0: - # make first row white - string += "\\\\n|w" + ""join(row) + "|n" - else: - string += "\\\\n" + "".join(row) - print(string) + Examples: :: + + ftable = format_table([[1,2,3], [4,5,6]]) + string = "" + for ir, row in enumarate(ftable): + if ir == 0: + # make first row white + string += "\\n|w" + "".join(row) + "|n" + else: + string += "\\n" + "".join(row) + print(string) """ + if not table: return [[]] @@ -1712,7 +1794,226 @@ return ftable
    -
    [docs]def get_evennia_pids(): +
    [docs]def percent(value, minval, maxval, formatting="{:3.1f}%"): + """ + Get a value in an interval as a percentage of its position + in that interval. This also understands negative numbers. + + Args: + value (number): This should be a value minval<=value<=maxval. + minval (number or None): Smallest value in interval. This could be None + for an open interval (then return will always be 100%) + maxval (number or None): Biggest value in interval. This could be None + for an open interval (then return will always be 100%) + formatted (str, optional): This is a string that should + accept one formatting tag. This will receive the + current value as a percentage. If None, the + raw float will be returned instead. + Returns: + str or float: The formatted value or the raw percentage as a float. + Notes: + We try to handle a weird interval gracefully. + + - If either maxval or minval is None (open interval), we (aribtrarily) assume 100%. + - If minval > maxval, we return 0%. + - If minval == maxval == value we are looking at a single value match and return 100%. + - If minval == maxval != value we return 0%. + - If value not in [minval..maxval], we set value to the closest + boundary, so the result will be 0% or 100%, respectively. + + """ + result = None + if None in (minval, maxval): + # we have no boundaries, percent calculation makes no sense, + # we set this to 100% since it + result = 100.0 + elif minval > maxval: + # interval has no width so we cannot + # occupy any position within it. + result = 0.0 + elif minval == maxval == value: + # this is a single value that we match + result = 100.0 + elif minval == maxval != value: + # interval has no width so we cannot be in it. + result = 0.0 + + if result is None: + # constrain value to interval + value = min(max(minval, value), maxval) + + # these should both be >0 + dpart = value - minval + dfull = maxval - minval + result = (dpart / dfull) * 100.0 + + if isinstance(formatting, str): + return formatting.format(result) + return result
    + + +import functools # noqa + + +
    [docs]def percentile(iterable, percent, key=lambda x: x): + """ + Find the percentile of a list of values. + + Args: + iterable (iterable): A list of values. Note N MUST BE already sorted. + percent (float): A value from 0.0 to 1.0. + key (callable, optional). Function to compute value from each element of N. + + Returns: + float: The percentile of the values + + """ + if not iterable: + return None + k = (len(iterable) - 1) * percent + f = math.floor(k) + c = math.ceil(k) + if f == c: + return key(iterable[int(k)]) + d0 = key(iterable[int(f)]) * (c - k) + d1 = key(iterable[int(c)]) * (k - f) + return d0 + d1
    + + +
    [docs]def format_grid(elements, width=78, sep=" ", verbatim_elements=None): + """ + This helper function makes a 'grid' output, where it distributes the given + string-elements as evenly as possible to fill out the given width. + will not work well if the variation of length is very big! + + Args: + elements (iterable): A 1D list of string elements to put in the grid. + width (int, optional): The width of the grid area to fill. + sep (str, optional): The extra separator to put between words. If + set to the empty string, words may run into each other. + verbatim_elements (list, optional): This is a list of indices pointing to + specific items in the `elements` list. An element at this index will + not be included in the calculation of the slot sizes. It will still + be inserted into the grid at the correct position and may be surrounded + by padding unless filling the entire line. This is useful for embedding + decorations in the grid, such as horizontal bars. + ignore_ansi (bool, optional): Ignore ansi markups when calculating white spacing. + + Returns: + list: The grid as a list of ready-formatted rows. We return it + like this to make it easier to insert decorations between rows, such + as horizontal bars. + """ + + def _minimal_rows(elements): + """ + Minimalistic distribution with minimal spacing, good for single-line + grids but will look messy over many lines. + """ + rows = [""] + for element in elements: + rowlen = display_len((rows[-1])) + elen = display_len((element)) + if rowlen + elen <= width: + rows[-1] += element + else: + rows.append(element) + return rows + + def _weighted_rows(elements): + """ + Dynamic-space, good for making even columns in a multi-line grid but + will look strange for a single line. + """ + wls = [display_len((elem)) for elem in elements] + wls_percentile = [wl for iw, wl in enumerate(wls) if iw not in verbatim_elements] + + if wls_percentile: + # get the nth percentile as a good representation of average width + averlen = int(percentile(sorted(wls_percentile), 0.9)) + 2 # include extra space + aver_per_row = width // averlen + 1 + else: + # no adjustable rows, just keep all as-is + aver_per_row = 1 + + if aver_per_row == 1: + # one line per row, output directly since this is trivial + # we use rstrip here to remove extra spaces added by sep + return [ + crop(element.rstrip(), width) + " " \ + * max(0, width - display_len((element.rstrip()))) + for iel, element in enumerate(elements) + ] + + indices = [averlen * ind for ind in range(aver_per_row - 1)] + + rows = [] + ic = 0 + row = "" + for ie, element in enumerate(elements): + + wl = wls[ie] + lrow = display_len((row)) + # debug = row.replace(" ", ".") + + if lrow + wl > width: + # this slot extends outside grid, move to next line + row += " " * (width - lrow) + rows.append(row) + if wl >= width: + # remove sep if this fills the entire line + element = element.rstrip() + row = crop(element, width) + ic = 0 + elif ic >= aver_per_row - 1: + # no more slots available on this line + row += " " * max(0, (width - lrow)) + rows.append(row) + row = crop(element, width) + ic = 0 + else: + try: + while lrow > max(0, indices[ic]): + # slot too wide, extend into adjacent slot + ic += 1 + row += " " * max(0, indices[ic] - lrow) + except IndexError: + # we extended past edge of grid, crop or move to next line + if ic == 0: + row = crop(element, width) + else: + row += " " * max(0, width - lrow) + rows.append(row) + ic = 0 + else: + # add a new slot + row += element + " " * max(0, averlen - wl) + ic += 1 + + if ie >= nelements - 1: + # last element, make sure to store + row += " " * max(0, width - display_len((row))) + rows.append(row) + return rows + + if not elements: + return [] + if not verbatim_elements: + verbatim_elements = [] + + nelements = len(elements) + # add sep to all but the very last element + elements = [elements[ie] + sep for ie in range(nelements - 1)] + [elements[-1]] + + if sum(display_len((element)) for element in elements) <= width: + # grid fits in one line + return _minimal_rows(elements) + else: + # full multi-line grid + return _weighted_rows(elements)
    + + +
    [docs]def get_evennia_pids(): """ Get the currently valid PIDs (Process IDs) of the Portal and Server by trying to access a PID file. @@ -1723,13 +2024,13 @@ Examples: This can be used to determine if we are in a subprocess by - something like: ```python self_pid = os.getpid() server_pid, portal_pid = get_evennia_pids() is_subprocess = self_pid not in (server_pid, portal_pid) ``` + """ server_pidfile = os.path.join(settings.GAME_DIR, "server.pid") portal_pidfile = os.path.join(settings.GAME_DIR, "portal.pid") @@ -1745,7 +2046,7 @@ return None, None
    -
    [docs]def deepsize(obj, max_depth=4): +
    [docs]def deepsize(obj, max_depth=4): """ Get not only size of the given object, but also the size of objects referenced by the object, down to `max_depth` distance @@ -1787,7 +2088,7 @@ _missing = object() -
    [docs]class lazy_property(object): +
    [docs]class lazy_property(object): """ Delays loading of property until first access. Credit goes to the Implementation in the werkzeug suite: @@ -1807,7 +2108,7 @@ """ -
    [docs] def __init__(self, func, name=None, doc=None): +
    [docs] def __init__(self, func, name=None, doc=None): """Store all properties for now""" self.__name__ = name or func.__name__ self.__module__ = func.__module__ @@ -1831,7 +2132,7 @@ ) # + range(127,160)]))) -
    [docs]def strip_control_sequences(string): +
    [docs]def strip_control_sequences(string): """ Remove non-print text sequences. @@ -1848,7 +2149,7 @@ return _RE_CONTROL_CHAR.sub("", _STRIP_ANSI(string))
    -
    [docs]def calledby(callerdepth=1): +
    [docs]def calledby(callerdepth=1): """ Only to be used for debug purposes. Insert this debug function in another function; it will print which function called it. @@ -1873,7 +2174,7 @@ return "[called by '%s': %s:%s %s]" % (frame[3], path, frame[2], frame[4])
    -
    [docs]def m_len(target): +
    [docs]def m_len(target): """ Provides length checking for strings with MXP patterns, and falls back to normal len for other objects. @@ -1894,7 +2195,7 @@ return len(target)
    -
    [docs]def display_len(target): +
    [docs]def display_len(target): """ Calculate the 'visible width' of text. This is not necessarily the same as the number of characters in the case of certain asian characters. This will also @@ -1928,7 +2229,7 @@ # Replace this hook function by changing settings.SEARCH_AT_RESULT. -
    [docs]def at_search_result(matches, caller, query="", quiet=False, **kwargs): +
    [docs]def at_search_result(matches, caller, query="", quiet=False, **kwargs): """ This is a generic hook for handling all processing of a search result, including error reporting. This is also called by the cmdhandler @@ -1945,23 +2246,22 @@ query (str, optional): The search query used to produce `matches`. quiet (bool, optional): If `True`, no messages will be echoed to caller on errors. - Keyword Args: nofound_string (str): Replacement string to echo on a notfound error. multimatch_string (str): Replacement string to echo on a multimatch error. Returns: processed_result (Object or None): This is always a single result - or `None`. If `None`, any error reporting/handling should - already have happened. The returned object is of the type we are - checking multimatches for (e.g. Objects or Commands) + or `None`. If `None`, any error reporting/handling should + already have happened. The returned object is of the type we are + checking multimatches for (e.g. Objects or Commands) """ error = "" if not matches: # no results. - error = kwargs.get("nofound_string") or _("Could not find '%s'." % query) + error = kwargs.get("nofound_string") or _("Could not find '{query}'.").format(query=query) matches = None elif len(matches) > 1: multimatch_string = kwargs.get("multimatch_string") @@ -1986,7 +2286,7 @@ name=result.get_display_name(caller) if hasattr(result, "get_display_name") else query, - aliases=" [%s]" % ";".join(aliases) if aliases else "", + aliases=" [{alias}]".format(alias=";".join(aliases) if aliases else ""), info=result.get_extra_info(caller), ) matches = None @@ -1999,7 +2299,7 @@ return matches
    -
    [docs]class LimitedSizeOrderedDict(OrderedDict): +
    [docs]class LimitedSizeOrderedDict(OrderedDict): """ This dictionary subclass is both ordered and limited to a maximum number of elements. Its main use is to hold a cache that can never @@ -2007,16 +2307,16 @@ """ -
    [docs] def __init__(self, *args, **kwargs): +
    [docs] def __init__(self, *args, **kwargs): """ Limited-size ordered dict. Keyword Args: size_limit (int): Use this to limit the number of elements - alloweds to be in this list. By default the overshooting elements - will be removed in FIFO order. + alloweds to be in this list. By default the overshooting elements + will be removed in FIFO order. fifo (bool, optional): Defaults to `True`. Remove overshooting elements - in FIFO order. If `False`, remove in FILO order. + in FIFO order. If `False`, remove in FILO order. """ super().__init__() @@ -2049,12 +2349,12 @@ super().__setitem__(key, value) self._check_size() -
    [docs] def update(self, *args, **kwargs): +
    [docs] def update(self, *args, **kwargs): super().update(*args, **kwargs) self._check_size()
    -
    [docs]def get_game_dir_path(): +
    [docs]def get_game_dir_path(): """ This is called by settings_default in order to determine the path of the game directory. @@ -2064,7 +2364,7 @@ """ # current working directory, assumed to be somewhere inside gamedir. - for _ in range(10): + for inum in range(10): gpath = os.getcwd() if "server" in os.listdir(gpath): if os.path.isfile(os.path.join("server", "conf", "settings.py")): @@ -2074,21 +2374,21 @@ raise RuntimeError("server/conf/settings.py not found: Must start from inside game dir.")
    -
    [docs]def get_all_typeclasses(parent=None): +
    [docs]def get_all_typeclasses(parent=None): """ List available typeclasses from all available modules. Args: - parent (str, optional): If given, only return typeclasses inheriting (at any distance) - from this parent. + parent (str, optional): If given, only return typeclasses inheriting + (at any distance) from this parent. Returns: - typeclasses (dict): On the form {"typeclass.path": typeclass, ...} + dict: On the form `{"typeclass.path": typeclass, ...}` Notes: - This will dynamicall retrieve all abstract django models inheriting at any distance - from the TypedObject base (aka a Typeclass) so it will work fine with any custom - classes being added. + This will dynamically retrieve all abstract django models inheriting at + any distance from the TypedObject base (aka a Typeclass) so it will + work fine with any custom classes being added. """ from evennia.typeclasses.models import TypedObject @@ -2107,16 +2407,49 @@ return typeclasses
    -
    [docs]def interactive(func): +
    [docs]def get_all_cmdsets(parent=None): """ - Decorator to make a method pausable with yield(seconds) and able to ask for - user-input with `response=yield(question)`. For the question-asking to - work, 'caller' must the name of an argument or kwarg to the decorated - function. + List available cmdsets from all available modules. - Example: - :: + Args: + parent (str, optional): If given, only return cmdsets inheriting (at + any distance) from this parent. + Returns: + dict: On the form {"cmdset.path": cmdset, ...} + + Notes: + This will dynamically retrieve all abstract django models inheriting at + any distance from the CmdSet base so it will work fine with any custom + classes being added. + + """ + from evennia.commands.cmdset import CmdSet + + base_cmdset = class_from_module(parent) if parent else CmdSet + + cmdsets = { + "{}.{}".format(subclass.__module__, subclass.__name__): subclass + for subclass in base_cmdset.__subclasses__() + } + return cmdsets
    + + +
    [docs]def interactive(func): + """ + Decorator to make a method pausable with `yield(seconds)` + and able to ask for user-input with `response=yield(question)`. + For the question-asking to work, one of the args or kwargs to the + decorated function must be named 'caller'. + + Raises: + ValueError: If asking an interactive question but the decorated + function has no arg or kwarg named 'caller'. + ValueError: If passing non int/float to yield using for pausing. + + Examples: + + ```python @interactive def myfunc(caller): caller.msg("This is a test") @@ -2128,9 +2461,10 @@ yield(5) else: # ... + ``` Notes: - This turns the method into a generator! + This turns the decorated function or method into a generator. """ from evennia.utils.evmenu import get_input @@ -2174,6 +2508,107 @@ return ret return decorator
    + + +
    [docs]def safe_convert_to_types(converters, *args, raise_errors=True, **kwargs): + """ + Helper function to safely convert inputs to expected data types. + + Args: + converters (tuple): A tuple `((converter, converter,...), {kwarg: converter, ...})` to + match a converter to each element in `*args` and `**kwargs`. + Each converter will will be called with the arg/kwarg-value as the only argument. + If there are too few converters given, the others will simply not be converter. If the + converter is given as the string 'py', it attempts to run + `safe_eval`/`literal_eval` on the input arg or kwarg value. It's possible to + skip the arg/kwarg part of the tuple, an empty tuple/dict will then be assumed. + *args: The arguments to convert with `argtypes`. + raise_errors (bool, optional): If set, raise any errors. This will + abort the conversion at that arg/kwarg. Otherwise, just skip the + conversion of the failing arg/kwarg. This will be set by the FuncParser if + this is used as a part of a FuncParser callable. + **kwargs: The kwargs to convert with `kwargtypes` + + Returns: + tuple: `(args, kwargs)` in converted form. + + Raises: + utils.funcparser.ParsingError: If parsing failed in the `'py'` + converter. This also makes this compatible with the FuncParser + interface. + any: Any other exception raised from other converters, if raise_errors is True. + + Notes: + This function is often used to validate/convert input from untrusted sources. For + security, the "py"-converter is deliberately limited and uses `safe_eval`/`literal_eval` + which only supports simple expressions or simple containers with literals. NEVER + use the python `eval` or `exec` methods as a converter for any untrusted input! Allowing + untrusted sources to execute arbitrary python on your server is a severe security risk, + + Example: + :: + + $funcname(1, 2, 3.0, c=[1,2,3]) + + def _funcname(*args, **kwargs): + args, kwargs = safe_convert_input(((int, int, float), {'c': 'py'}), *args, **kwargs) + # ... + + """ + def _safe_eval(inp): + if not inp: + return '' + if not isinstance(inp, str): + # already converted + return inp + + try: + return literal_eval(inp) + except Exception as err: + literal_err = f"{err.__class__.__name__}: {err}" + try: + return simple_eval(inp) + except Exception as err: + simple_err = f"{str(err.__class__.__name__)}: {err}" + pass + + if raise_errors: + from evennia.utils.funcparser import ParsingError + err = (f"Errors converting '{inp}' to python:\n" + f"literal_eval raised {literal_err}\n" + f"simple_eval raised {simple_err}") + raise ParsingError(err) + + # handle an incomplete/mixed set of input converters + if not converters: + return args, kwargs + arg_converters, *kwarg_converters = converters + arg_converters = make_iter(arg_converters) + kwarg_converters = kwarg_converters[0] if kwarg_converters else {} + + # apply the converters + if args and arg_converters: + args = list(args) + arg_converters = make_iter(arg_converters) + for iarg, arg in enumerate(args[:len(arg_converters)]): + converter = arg_converters[iarg] + converter = _safe_eval if converter in ('py', 'python') else converter + try: + args[iarg] = converter(arg) + except Exception: + if raise_errors: + raise + args = tuple(args) + if kwarg_converters and isinstance(kwarg_converters, dict): + for key, converter in kwarg_converters.items(): + converter = _safe_eval if converter in ('py', 'python') else converter + if key in {**kwargs}: + try: + kwargs[key] = converter(kwargs[key]) + except Exception: + if raise_errors: + raise + return args, kwargs
    @@ -2211,7 +2646,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/utils/validatorfuncs.html b/docs/0.9.5/_modules/evennia/utils/validatorfuncs.html index c75a158a41..04043b8f35 100644 --- a/docs/0.9.5/_modules/evennia/utils/validatorfuncs.html +++ b/docs/0.9.5/_modules/evennia/utils/validatorfuncs.html @@ -63,18 +63,20 @@ try: return str(entry) except Exception as err: - raise ValueError(f"Input could not be converted to text ({err})")
    + raise ValueError(_("Input could not be converted to text ({err})").format(err=err))
    [docs]def color(entry, option_key="Color", **kwargs): """ The color should be just a color character, so 'r' if red color is desired. + """ if not entry: - raise ValueError(f"Nothing entered for a {option_key}!") + raise ValueError(_("Nothing entered for a {option_key}!").format(option_key=option_key)) test_str = strip_ansi(f"|{entry}|n") if test_str: - raise ValueError(f"'{entry}' is not a valid {option_key}.") + raise ValueError(_("'{entry}' is not a valid {option_key}.").format( + entry=entry, option_key=option_key)) return entry
    @@ -89,12 +91,10 @@ account (AccountDB): The Account performing this lookup. Unless `from_tz` is provided, the account's timezone option will be used. from_tz (pytz.timezone): An instance of a pytz timezone object from the - user. If not provided, tries to use the timezone option of the `account`. + user. If not provided, tries to use the timezone option of `account`. If neither one is provided, defaults to UTC. - Returns: datetime in UTC. - Raises: ValueError: If encountering a malformed timezone, date string or other format error. @@ -126,13 +126,17 @@ entry = f"{split_time[0]} {split_time[1]} {split_time[2]} {split_time[3]}" else: raise ValueError( - f"{option_key} must be entered in a 24-hour format such as: {now.strftime('%b %d %H:%M')}" + _("{option_key} must be entered in a 24-hour format such as: {timeformat}").format( + option_key=option_key, + timeformat=now.strftime('%b %d %H:%M')) ) try: local = _dt.datetime.strptime(entry, "%b %d %H:%M %Y") except ValueError: raise ValueError( - f"{option_key} must be entered in a 24-hour format such as: {now.strftime('%b %d %H:%M')}" + _("{option_key} must be entered in a 24-hour format such as: {timeformat}").format( + option_key=option_key, + timeformat=now.strftime('%b %d %H:%M')) ) local_tz = from_tz.localize(local) return local_tz.astimezone(utc)
    @@ -143,8 +147,9 @@ Take a string and derive a datetime timedelta from it. Args: - entry (string): This is a string from user-input. The intended format is, for example: "5d 2w 90s" for - 'five days, two weeks, and ninety seconds.' Invalid sections are ignored. + entry (string): This is a string from user-input. The intended format is, for example: + "5d 2w 90s" for 'five days, two weeks, and ninety seconds.' Invalid sections are + ignored. option_key (str): Name to display this query as. Returns: @@ -172,7 +177,10 @@ elif _re.match(r"^[\d]+y$", interval): days += int(interval.rstrip("y")) * 365 else: - raise ValueError(f"Could not convert section '{interval}' to a {option_key}.") + raise ValueError( + _("Could not convert section '{interval}' to a {option_key}.").format( + interval=interval, option_key=option_key) + ) return _dt.timedelta(days, seconds, 0, 0, minutes, hours, weeks)
    @@ -180,45 +188,56 @@
    [docs]def future(entry, option_key="Future Datetime", from_tz=None, **kwargs): time = datetime(entry, option_key, from_tz=from_tz) if time < _dt.datetime.utcnow().replace(tzinfo=_dt.timezone.utc): - raise ValueError(f"That {option_key} is in the past! Must give a Future datetime!") + raise ValueError(_("That {option_key} is in the past! Must give a Future datetime!").format( + option_key=option_key)) return time
    [docs]def signed_integer(entry, option_key="Signed Integer", **kwargs): if not entry: - raise ValueError(f"Must enter a whole number for {option_key}!") + raise ValueError(_("Must enter a whole number for {option_key}!").format( + option_key=option_key)) try: num = int(entry) except ValueError: - raise ValueError(f"Could not convert '{entry}' to a whole number for {option_key}!") + raise ValueError(_("Could not convert '{entry}' to a whole " + "number for {option_key}!").format( + entry=entry, option_key=option_key)) return num
    [docs]def positive_integer(entry, option_key="Positive Integer", **kwargs): num = signed_integer(entry, option_key) if not num >= 1: - raise ValueError(f"Must enter a whole number greater than 0 for {option_key}!") + raise ValueError(_("Must enter a whole number greater than 0 for {option_key}!").format( + option_key=option_key)) return num
    [docs]def unsigned_integer(entry, option_key="Unsigned Integer", **kwargs): num = signed_integer(entry, option_key) if not num >= 0: - raise ValueError(f"{option_key} must be a whole number greater than or equal to 0!") + raise ValueError(_("{option_key} must be a whole number greater than " + "or equal to 0!").format( + option_key=option_key)) return num
    [docs]def boolean(entry, option_key="True/False", **kwargs): """ Simplest check in computer logic, right? This will take user input to flick the switch on or off + Args: entry (str): A value such as True, On, Enabled, Disabled, False, 0, or 1. option_key (str): What kind of Boolean we are setting. What Option is this for? Returns: Boolean + """ - error = f"Must enter 0 (false) or 1 (true) for {option_key}. Also accepts True, False, On, Off, Yes, No, Enabled, and Disabled" + error = (_("Must enter a true/false input for {option_key}. Accepts {alternatives}.").format( + option_key=option_key, + alternatives="0/1, True/False, On/Off, Yes/No, Enabled/Disabled")) if not isinstance(entry, str): raise ValueError(error) entry = entry.upper() @@ -239,41 +258,44 @@ Returns: A PYTZ timezone. + """ if not entry: - raise ValueError(f"No {option_key} entered!") + raise ValueError(_("No {option_key} entered!").format(option_key=option_key)) found = _partial(list(_TZ_DICT.keys()), entry, ret_index=False) if len(found) > 1: raise ValueError( - f"That matched: {', '.join(str(t) for t in found)}. Please be more specific!" - ) + _("That matched: {matches}. Please be more specific!").format( + matches=', '.join(str(t) for t in found))) if found: return _TZ_DICT[found[0]] - raise ValueError(f"Could not find timezone '{entry}' for {option_key}!")
    + raise ValueError(_("Could not find timezone '{entry}' for {option_key}!").format( + entry=entry, option_key=option_key))
    [docs]def email(entry, option_key="Email Address", **kwargs): if not entry: - raise ValueError("Email address field empty!") + raise ValueError(_("Email address field empty!")) valid = validate_email_address(entry) if not valid: - raise ValueError(f"That isn't a valid {option_key}!") + raise ValueError(_("That isn't a valid {option_key}!").format(option_key=option_key)) return entry
    [docs]def lock(entry, option_key="locks", access_options=None, **kwargs): entry = entry.strip() if not entry: - raise ValueError(f"No {option_key} entered to set!") + raise ValueError(_("No {option_key} entered to set!").format(option_key=option_key)) for locksetting in entry.split(";"): access_type, lockfunc = locksetting.split(":", 1) if not access_type: - raise ValueError("Must enter an access type!") + raise ValueError(_("Must enter an access type!")) if access_options: if access_type not in access_options: - raise ValueError(f"Access type must be one of: {', '.join(access_options)}") + raise ValueError(_("Access type must be one of: {alternatives}").format( + alternatives=', '.join(access_options))) if not lockfunc: - raise ValueError("Lock func not entered.") + raise ValueError(_("Lock func not entered.")) return entry
    @@ -312,7 +334,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/web/utils/backends.html b/docs/0.9.5/_modules/evennia/web/utils/backends.html index 9c6e566101..c4d42a0486 100644 --- a/docs/0.9.5/_modules/evennia/web/utils/backends.html +++ b/docs/0.9.5/_modules/evennia/web/utils/backends.html @@ -119,7 +119,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/web/utils/general_context.html b/docs/0.9.5/_modules/evennia/web/utils/general_context.html index a9689f2eab..6263bf67ca 100644 --- a/docs/0.9.5/_modules/evennia/web/utils/general_context.html +++ b/docs/0.9.5/_modules/evennia/web/utils/general_context.html @@ -39,41 +39,20 @@

    Source code for evennia.web.utils.general_context

    -#
    -# This file defines global variables that will always be
    -# available in a view context without having to repeatedly
    -# include it. For this to work, this file is included in
    -# the settings file, in the TEMPLATE_CONTEXT_PROCESSORS
    -# tuple.
    -#
    +"""
    +This file defines global variables that will always be available in a view
    +context without having to repeatedly include it.
    +
    +For this to work, this file is included in the settings file, in the
    +TEMPLATES["OPTIONS"]["context_processors"] list.
    +
    +"""
    +
     
     import os
     from django.conf import settings
     from evennia.utils.utils import get_evennia_version
     
    -# Determine the site name and server version
    -
    [docs]def set_game_name_and_slogan(): - """ - Sets global variables GAME_NAME and GAME_SLOGAN which are used by - general_context. - - Notes: - This function is used for unit testing the values of the globals. - """ - global GAME_NAME, GAME_SLOGAN, SERVER_VERSION - try: - GAME_NAME = settings.SERVERNAME.strip() - except AttributeError: - GAME_NAME = "Evennia" - SERVER_VERSION = get_evennia_version() - try: - GAME_SLOGAN = settings.GAME_SLOGAN.strip() - except AttributeError: - GAME_SLOGAN = SERVER_VERSION
    - - -set_game_name_and_slogan() - # Setup lists of the most relevant apps so # the adminsite becomes more readable. @@ -82,7 +61,30 @@ GAME_SETUP = ["Permissions", "Config"] CONNECTIONS = ["Irc"] WEBSITE = ["Flatpages", "News", "Sites"] +REST_API_ENABLED = False +# Determine the site name and server version +
    [docs]def set_game_name_and_slogan(): + """ + Sets global variables GAME_NAME and GAME_SLOGAN which are used by + general_context. + + Notes: + This function is used for unit testing the values of the globals. + + """ + global GAME_NAME, GAME_SLOGAN, SERVER_VERSION, REST_API_ENABLED + try: + GAME_NAME = settings.SERVERNAME.strip() + except AttributeError: + GAME_NAME = "Evennia" + SERVER_VERSION = get_evennia_version() + try: + GAME_SLOGAN = settings.GAME_SLOGAN.strip() + except AttributeError: + GAME_SLOGAN = SERVER_VERSION + + REST_API_ENABLED = settings.REST_API_ENABLED
    [docs]def set_webclient_settings(): """ @@ -91,6 +93,7 @@ Notes: Used for unit testing. + """ global WEBCLIENT_ENABLED, WEBSOCKET_CLIENT_ENABLED, WEBSOCKET_PORT, WEBSOCKET_URL WEBCLIENT_ENABLED = settings.WEBCLIENT_ENABLED @@ -105,13 +108,15 @@ WEBSOCKET_URL = settings.WEBSOCKET_CLIENT_URL
    +set_game_name_and_slogan() set_webclient_settings() # The main context processor function
    [docs]def general_context(request): """ - Returns common Evennia-related context stuff, which - is automatically added to context of all views. + Returns common Evennia-related context stuff, which is automatically added + to context of all views. + """ account = None if request.user.is_authenticated: @@ -136,6 +141,7 @@ "websocket_enabled": WEBSOCKET_CLIENT_ENABLED, "websocket_port": WEBSOCKET_PORT, "websocket_url": WEBSOCKET_URL, + "rest_api_enabled": REST_API_ENABLED, }
    @@ -174,7 +180,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/web/utils/middleware.html b/docs/0.9.5/_modules/evennia/web/utils/middleware.html index b4e8875da5..9091bb1d91 100644 --- a/docs/0.9.5/_modules/evennia/web/utils/middleware.html +++ b/docs/0.9.5/_modules/evennia/web/utils/middleware.html @@ -148,7 +148,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/web/utils/tests.html b/docs/0.9.5/_modules/evennia/web/utils/tests.html index bad8f781e2..e95c5cfa48 100644 --- a/docs/0.9.5/_modules/evennia/web/utils/tests.html +++ b/docs/0.9.5/_modules/evennia/web/utils/tests.html @@ -50,13 +50,12 @@
    [docs] @patch("evennia.web.utils.general_context.GAME_NAME", "test_name") @patch("evennia.web.utils.general_context.GAME_SLOGAN", "test_game_slogan") - @patch( - "evennia.web.utils.general_context.WEBSOCKET_CLIENT_ENABLED", - "websocket_client_enabled_testvalue", - ) + @patch("evennia.web.utils.general_context.WEBSOCKET_CLIENT_ENABLED", + "websocket_client_enabled_testvalue") @patch("evennia.web.utils.general_context.WEBCLIENT_ENABLED", "webclient_enabled_testvalue") @patch("evennia.web.utils.general_context.WEBSOCKET_PORT", "websocket_client_port_testvalue") @patch("evennia.web.utils.general_context.WEBSOCKET_URL", "websocket_client_url_testvalue") + @patch("evennia.web.utils.general_context.REST_API_ENABLED", True) def test_general_context(self): request = RequestFactory().get("/") request.user = AnonymousUser() @@ -80,6 +79,7 @@ "websocket_enabled": "websocket_client_enabled_testvalue", "websocket_port": "websocket_client_port_testvalue", "websocket_url": "websocket_client_url_testvalue", + "rest_api_enabled": True, }, )
    @@ -89,6 +89,7 @@ def test_set_game_name_and_slogan(self, mock_get_version, mock_settings): mock_get_version.return_value = "version 1" # test default/fallback values + mock_settings.REST_API_ENABLED = False general_context.set_game_name_and_slogan() self.assertEqual(general_context.GAME_NAME, "Evennia") self.assertEqual(general_context.GAME_SLOGAN, "version 1") @@ -147,7 +148,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/web/webclient/views.html b/docs/0.9.5/_modules/evennia/web/webclient/views.html index df6b6beaad..ded8704aa1 100644 --- a/docs/0.9.5/_modules/evennia/web/webclient/views.html +++ b/docs/0.9.5/_modules/evennia/web/webclient/views.html @@ -106,7 +106,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/web/website/forms.html b/docs/0.9.5/_modules/evennia/web/website/forms.html index 3e044d9a84..43112a3cc5 100644 --- a/docs/0.9.5/_modules/evennia/web/website/forms.html +++ b/docs/0.9.5/_modules/evennia/web/website/forms.html @@ -69,7 +69,7 @@ """ # Call parent function - cleaned = super(EvenniaForm, self).clean() + cleaned = super().clean() # Escape all values provided by user cleaned = {k: escape(v) for k, v in cleaned.items()} @@ -251,7 +251,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/web/website/tests.html b/docs/0.9.5/_modules/evennia/web/website/tests.html index cb6551f694..bc07b3af43 100644 --- a/docs/0.9.5/_modules/evennia/web/website/tests.html +++ b/docs/0.9.5/_modules/evennia/web/website/tests.html @@ -366,7 +366,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/evennia/web/website/views.html b/docs/0.9.5/_modules/evennia/web/website/views.html deleted file mode 100644 index 0206c1f0f7..0000000000 --- a/docs/0.9.5/_modules/evennia/web/website/views.html +++ /dev/null @@ -1,1236 +0,0 @@ - - - - - - - - evennia.web.website.views — Evennia 0.9.5 documentation - - - - - - - - - - - - - -
    -
    -
    -
    - -

    Source code for evennia.web.website.views

    -"""
    -This file contains the generic, assorted views that don't fall under one of the other applications.
    -Views are django's way of processing e.g. html templates on the fly.
    -
    -"""
    -
    -from collections import OrderedDict
    -
    -from django.contrib.admin.sites import site
    -from django.conf import settings
    -from django.contrib import messages
    -from django.contrib.auth.mixins import LoginRequiredMixin
    -from django.contrib.admin.views.decorators import staff_member_required
    -from django.core.exceptions import PermissionDenied
    -from django.db.models.functions import Lower
    -from django.http import HttpResponseBadRequest, HttpResponseRedirect
    -from django.shortcuts import render
    -from django.urls import reverse_lazy
    -from django.views.generic import TemplateView, ListView, DetailView
    -from django.views.generic.base import RedirectView
    -from django.views.generic.edit import CreateView, UpdateView, DeleteView
    -
    -from evennia import SESSION_HANDLER
    -from evennia.help.models import HelpEntry
    -from evennia.objects.models import ObjectDB
    -from evennia.accounts.models import AccountDB
    -from evennia.utils import class_from_module
    -from evennia.utils.logger import tail_log_file
    -from evennia.web.website import forms as website_forms
    -
    -from django.utils.text import slugify
    -
    -_BASE_CHAR_TYPECLASS = settings.BASE_CHARACTER_TYPECLASS
    -
    -# typeclass fallbacks
    -
    -def _gamestats():
    -    # Some misc. configurable stuff.
    -    # TODO: Move this to either SQL or settings.py based configuration.
    -    fpage_account_limit = 4
    -
    -    # A QuerySet of the most recently connected accounts.
    -    recent_users = AccountDB.objects.get_recently_connected_accounts()[:fpage_account_limit]
    -    nplyrs_conn_recent = len(recent_users) or "none"
    -    nplyrs = AccountDB.objects.num_total_accounts() or "none"
    -    nplyrs_reg_recent = len(AccountDB.objects.get_recently_created_accounts()) or "none"
    -    nsess = SESSION_HANDLER.account_count()
    -    # nsess = len(AccountDB.objects.get_connected_accounts()) or "no one"
    -
    -    nobjs = ObjectDB.objects.count()
    -    nobjs = nobjs or 1  # fix zero-div error with empty database
    -    Character = class_from_module(settings.BASE_CHARACTER_TYPECLASS,
    -                                  fallback=settings.FALLBACK_CHARACTER_TYPECLASS)
    -    nchars = Character.objects.all_family().count()
    -    Room = class_from_module(settings.BASE_ROOM_TYPECLASS,
    -                             fallback=settings.FALLBACK_ROOM_TYPECLASS)
    -    nrooms = Room.objects.all_family().count()
    -    Exit = class_from_module(settings.BASE_EXIT_TYPECLASS,
    -                             fallback=settings.FALLBACK_EXIT_TYPECLASS)
    -    nexits = Exit.objects.all_family().count()
    -    nothers = nobjs - nchars - nrooms - nexits
    -
    -    pagevars = {
    -        "page_title": "Front Page",
    -        "accounts_connected_recent": recent_users,
    -        "num_accounts_connected": nsess or "no one",
    -        "num_accounts_registered": nplyrs or "no",
    -        "num_accounts_connected_recent": nplyrs_conn_recent or "no",
    -        "num_accounts_registered_recent": nplyrs_reg_recent or "no one",
    -        "num_rooms": nrooms or "none",
    -        "num_exits": nexits or "no",
    -        "num_objects": nobjs or "none",
    -        "num_characters": nchars or "no",
    -        "num_others": nothers or "no",
    -    }
    -    return pagevars
    -
    -
    -
    [docs]def to_be_implemented(request): - """ - A notice letting the user know that this particular feature hasn't been - implemented yet. - """ - - pagevars = {"page_title": "To Be Implemented..."} - - return render(request, "tbi.html", pagevars)
    - - -
    [docs]@staff_member_required -def evennia_admin(request): - """ - Helpful Evennia-specific admin page. - """ - return render(request, "evennia_admin.html", {"accountdb": AccountDB})
    - - -
    [docs]def admin_wrapper(request): - """ - Wrapper that allows us to properly use the base Django admin site, if needed. - """ - return staff_member_required(site.index)(request)
    - - -# -# Class-based views -# - - -
    [docs]class EvenniaIndexView(TemplateView): - """ - This is a basic example of a Django class-based view, which are functionally - very similar to Evennia Commands but differ in structure. Commands are used - to interface with users using a terminal client. Views are used to interface - with users using a web browser. - - To use a class-based view, you need to have written a template in HTML, and - then you write a view like this to tell Django what values to display on it. - - While there are simpler ways of writing views using plain functions (and - Evennia currently contains a few examples of them), just like Commands, - writing views as classes provides you with more flexibility-- you can extend - classes and change things to suit your needs rather than having to copy and - paste entire code blocks over and over. Django also comes with many default - views for displaying things, all of them implemented as classes. - - This particular example displays the index page. - - """ - - # Tell the view what HTML template to use for the page - template_name = "website/index.html" - - # This method tells the view what data should be displayed on the template. -
    [docs] def get_context_data(self, **kwargs): - """ - This is a common Django method. Think of this as the website - equivalent of the Evennia Command.func() method. - - If you just want to display a static page with no customization, you - don't need to define this method-- just create a view, define - template_name and you're done. - - The only catch here is that if you extend or overwrite this method, - you'll always want to make sure you call the parent method to get a - context object. It's just a dict, but it comes prepopulated with all - sorts of background data intended for display on the page. - - You can do whatever you want to it, but it must be returned at the end - of this method. - - Keyword Args: - any (any): Passed through. - - Returns: - context (dict): Dictionary of data you want to display on the page. - - """ - # Always call the base implementation first to get a context object - context = super(EvenniaIndexView, self).get_context_data(**kwargs) - - # Add game statistics and other pagevars - context.update(_gamestats()) - - return context
    - - -
    [docs]class TypeclassMixin(object): - """ - This is a "mixin", a modifier of sorts. - - Django views typically work with classes called "models." Evennia objects - are an enhancement upon these Django models and are called "typeclasses." - But Django itself has no idea what a "typeclass" is. - - For the sake of mitigating confusion, any view class with this in its - inheritance list will be modified to work with Evennia Typeclass objects or - Django models interchangeably. - - """ - - @property - def typeclass(self): - return self.model - - @typeclass.setter - def typeclass(self, value): - self.model = value
    - - -
    [docs]class EvenniaCreateView(CreateView, TypeclassMixin): - """ - This view extends Django's default CreateView. - - CreateView is used for creating new objects, be they Accounts, Characters or - otherwise. - - """ - - @property - def page_title(self): - # Makes sure the page has a sensible title. - return "Create %s" % self.typeclass._meta.verbose_name.title()
    - - -
    [docs]class EvenniaDetailView(DetailView, TypeclassMixin): - """ - This view extends Django's default DetailView. - - DetailView is used for displaying objects, be they Accounts, Characters or - otherwise. - - """ - - @property - def page_title(self): - # Makes sure the page has a sensible title. - return "%s Detail" % self.typeclass._meta.verbose_name.title()
    - - -
    [docs]class EvenniaUpdateView(UpdateView, TypeclassMixin): - """ - This view extends Django's default UpdateView. - - UpdateView is used for updating objects, be they Accounts, Characters or - otherwise. - - """ - - @property - def page_title(self): - # Makes sure the page has a sensible title. - return "Update %s" % self.typeclass._meta.verbose_name.title()
    - - -
    [docs]class EvenniaDeleteView(DeleteView, TypeclassMixin): - """ - This view extends Django's default DeleteView. - - DeleteView is used for deleting objects, be they Accounts, Characters or - otherwise. - - """ - - @property - def page_title(self): - # Makes sure the page has a sensible title. - return "Delete %s" % self.typeclass._meta.verbose_name.title()
    - - -# -# Object views -# - - -
    [docs]class ObjectDetailView(EvenniaDetailView): - """ - This is an important view. - - Any view you write that deals with displaying, updating or deleting a - specific object will want to inherit from this. It provides the mechanisms - by which to retrieve the object and make sure the user requesting it has - permissions to actually *do* things to it. - - """ - - # -- Django constructs -- - # - # Choose what class of object this view will display. Note that this should - # be an actual Python class (i.e. do `from typeclasses.characters import - # Character`, then put `Character`), not an Evennia typeclass path - # (i.e. `typeclasses.characters.Character`). - # - # So when you extend it, this line should look simple, like: - # model = Object - model = class_from_module(settings.BASE_OBJECT_TYPECLASS, - fallback=settings.FALLBACK_OBJECT_TYPECLASS) - - # What HTML template you wish to use to display this page. - template_name = "website/object_detail.html" - - # -- Evennia constructs -- - # - # What lock type to check for the requesting user, authenticated or not. - # https://github.com/evennia/evennia/wiki/Locks#valid-access_types - access_type = "view" - - # What attributes of the object you wish to display on the page. Model-level - # attributes will take precedence over identically-named db.attributes! - # The order you specify here will be followed. - attributes = ["name", "desc"] - -
    [docs] def get_context_data(self, **kwargs): - """ - Adds an 'attributes' list to the request context consisting of the - attributes specified at the class level, and in the order provided. - - Django views do not provide a way to reference dynamic attributes, so - we have to grab them all before we render the template. - - Returns: - context (dict): Django context object - - """ - # Get the base Django context object - context = super(ObjectDetailView, self).get_context_data(**kwargs) - - # Get the object in question - obj = self.get_object() - - # Create an ordered dictionary to contain the attribute map - attribute_list = OrderedDict() - - for attribute in self.attributes: - # Check if the attribute is a core fieldname (name, desc) - if attribute in self.typeclass._meta._property_names: - attribute_list[attribute.title()] = getattr(obj, attribute, "") - - # Check if the attribute is a db attribute (char1.db.favorite_color) - else: - attribute_list[attribute.title()] = getattr(obj.db, attribute, "") - - # Add our attribute map to the Django request context, so it gets - # displayed on the template - context["attribute_list"] = attribute_list - - # Return the comprehensive context object - return context
    - -
    [docs] def get_object(self, queryset=None): - """ - Override of Django hook that provides some important Evennia-specific - functionality. - - Evennia does not natively store slugs, so where a slug is provided, - calculate the same for the object and make sure it matches. - - This also checks to make sure the user has access to view/edit/delete - this object! - - """ - # A queryset can be provided to pre-emptively limit what objects can - # possibly be returned. For example, you can supply a queryset that - # only returns objects whose name begins with "a". - if not queryset: - queryset = self.get_queryset() - - # Get the object, ignoring all checks and filters for now - obj = self.typeclass.objects.get(pk=self.kwargs.get("pk")) - - # Check if this object was requested in a valid manner - if slugify(obj.name) != self.kwargs.get(self.slug_url_kwarg): - raise HttpResponseBadRequest( - "No %(verbose_name)s found matching the query" - % {"verbose_name": queryset.model._meta.verbose_name} - ) - - # Check if the requestor account has permissions to access object - account = self.request.user - if not obj.access(account, self.access_type): - raise PermissionDenied("You are not authorized to %s this object." % self.access_type) - - # Get the object, if it is in the specified queryset - obj = super(ObjectDetailView, self).get_object(queryset) - - return obj
    - - -
    [docs]class ObjectCreateView(LoginRequiredMixin, EvenniaCreateView): - """ - This is an important view. - - Any view you write that deals with creating a specific object will want to - inherit from this. It provides the mechanisms by which to make sure the user - requesting creation of an object is authenticated, and provides a sane - default title for the page. - - """ - - model = class_from_module(settings.BASE_OBJECT_TYPECLASS, - fallback=settings.FALLBACK_OBJECT_TYPECLASS)
    - - -
    [docs]class ObjectDeleteView(LoginRequiredMixin, ObjectDetailView, EvenniaDeleteView): - """ - This is an important view for obvious reasons! - - Any view you write that deals with deleting a specific object will want to - inherit from this. It provides the mechanisms by which to make sure the user - requesting deletion of an object is authenticated, and that they have - permissions to delete the requested object. - - """ - - # -- Django constructs -- - model = class_from_module(settings.BASE_OBJECT_TYPECLASS, - fallback=settings.FALLBACK_OBJECT_TYPECLASS) - template_name = "website/object_confirm_delete.html" - - # -- Evennia constructs -- - access_type = "delete" - -
    [docs] def delete(self, request, *args, **kwargs): - """ - Calls the delete() method on the fetched object and then - redirects to the success URL. - - We extend this so we can capture the name for the sake of confirmation. - - """ - # Get the object in question. ObjectDetailView.get_object() will also - # check to make sure the current user (authenticated or not) has - # permission to delete it! - obj = str(self.get_object()) - - # Perform the actual deletion (the parent class handles this, which will - # in turn call the delete() method on the object) - response = super(ObjectDeleteView, self).delete(request, *args, **kwargs) - - # Notify the user of the deletion - messages.success(request, "Successfully deleted '%s'." % obj) - return response
    - - -
    [docs]class ObjectUpdateView(LoginRequiredMixin, ObjectDetailView, EvenniaUpdateView): - """ - This is an important view. - - Any view you write that deals with updating a specific object will want to - inherit from this. It provides the mechanisms by which to make sure the user - requesting editing of an object is authenticated, and that they have - permissions to edit the requested object. - - This functions slightly different from default Django UpdateViews in that - it does not update core model fields, *only* object attributes! - - """ - - # -- Django constructs -- - model = class_from_module(settings.BASE_OBJECT_TYPECLASS, - fallback=settings.FALLBACK_OBJECT_TYPECLASS) - - # -- Evennia constructs -- - access_type = "edit" - -
    [docs] def get_success_url(self): - """ - Django hook. - - Can be overridden to return any URL you want to redirect the user to - after the object is successfully updated, but by default it goes to the - object detail page so the user can see their changes reflected. - - """ - if self.success_url: - return self.success_url - return self.object.web_get_detail_url()
    - -
    [docs] def get_initial(self): - """ - Django hook, modified for Evennia. - - Prepopulates the update form field values based on object db attributes. - - Returns: - data (dict): Dictionary of key:value pairs containing initial form - data. - - """ - # Get the object we want to update - obj = self.get_object() - - # Get attributes - data = {k: getattr(obj.db, k, "") for k in self.form_class.base_fields} - - # Get model fields - data.update({k: getattr(obj, k, "") for k in self.form_class.Meta.fields}) - - return data
    - -
    [docs] def form_valid(self, form): - """ - Override of Django hook. - - Updates object attributes based on values submitted. - - This is run when the form is submitted and the data on it is deemed - valid-- all values are within expected ranges, all strings contain - valid characters and lengths, etc. - - This method is only called if all values for the fields submitted - passed form validation, so at this point we can assume the data is - validated and sanitized. - - """ - # Get the attributes after they've been cleaned and validated - data = {k: v for k, v in form.cleaned_data.items() if k not in self.form_class.Meta.fields} - - # Update the object attributes - for key, value in data.items(): - self.object.attributes.add(key, value) - messages.success(self.request, "Successfully updated '%s' for %s." % (key, self.object)) - - # Do not return super().form_valid; we don't want to update the model - # instance, just its attributes. - return HttpResponseRedirect(self.get_success_url())
    - - -# -# Account views -# - - -
    [docs]class AccountMixin(TypeclassMixin): - """ - This is a "mixin", a modifier of sorts. - - Any view class with this in its inheritance list will be modified to work - with Account objects instead of generic Objects or otherwise. - - """ - - # -- Django constructs -- - model = class_from_module(settings.BASE_ACCOUNT_TYPECLASS, - fallback=settings.FALLBACK_ACCOUNT_TYPECLASS) - form_class = website_forms.AccountForm
    - - -
    [docs]class AccountCreateView(AccountMixin, EvenniaCreateView): - """ - Account creation view. - - """ - - # -- Django constructs -- - template_name = "website/registration/register.html" - success_url = reverse_lazy("login") - -
    [docs] def form_valid(self, form): - """ - Django hook, modified for Evennia. - - This hook is called after a valid form is submitted. - - When an account creation form is submitted and the data is deemed valid, - proceeds with creating the Account object. - - """ - # Get values provided - username = form.cleaned_data["username"] - password = form.cleaned_data["password1"] - email = form.cleaned_data.get("email", "") - - # Create account - account, errs = self.typeclass.create(username=username, password=password, email=email) - - # If unsuccessful, display error messages to user - if not account: - [messages.error(self.request, err) for err in errs] - - # Call the Django "form failure" hook - return self.form_invalid(form) - - # Inform user of success - messages.success( - self.request, - "Your account '%s' was successfully created! " - "You may log in using it now." % account.name, - ) - - # Redirect the user to the login page - return HttpResponseRedirect(self.success_url)
    - - -# -# Character views -# - - -
    [docs]class CharacterMixin(TypeclassMixin): - """ - This is a "mixin", a modifier of sorts. - - Any view class with this in its inheritance list will be modified to work - with Character objects instead of generic Objects or otherwise. - - """ - - # -- Django constructs -- - model = class_from_module(settings.BASE_CHARACTER_TYPECLASS, - fallback=settings.FALLBACK_CHARACTER_TYPECLASS) - form_class = website_forms.CharacterForm - success_url = reverse_lazy("character-manage") - -
    [docs] def get_queryset(self): - """ - This method will override the Django get_queryset method to only - return a list of characters associated with the current authenticated - user. - - Returns: - queryset (QuerySet): Django queryset for use in the given view. - - """ - # Get IDs of characters owned by account - account = self.request.user - ids = [getattr(x, "id") for x in account.characters if x] - - # Return a queryset consisting of those characters - return self.typeclass.objects.filter(id__in=ids).order_by(Lower("db_key"))
    - - -
    [docs]class CharacterListView(LoginRequiredMixin, CharacterMixin, ListView): - """ - This view provides a mechanism by which a logged-in player can view a list - of all other characters. - - This view requires authentication by default as a nominal effort to prevent - human stalkers and automated bots/scrapers from harvesting data on your users. - - """ - - # -- Django constructs -- - template_name = "website/character_list.html" - paginate_by = 100 - - # -- Evennia constructs -- - page_title = "Character List" - access_type = "view" - -
    [docs] def get_queryset(self): - """ - This method will override the Django get_queryset method to return a - list of all characters (filtered/sorted) instead of just those limited - to the account. - - Returns: - queryset (QuerySet): Django queryset for use in the given view. - - """ - account = self.request.user - - # Return a queryset consisting of characters the user is allowed to - # see. - ids = [ - obj.id for obj in self.typeclass.objects.all() if obj.access(account, self.access_type) - ] - - return self.typeclass.objects.filter(id__in=ids).order_by(Lower("db_key"))
    - - -
    [docs]class CharacterPuppetView(LoginRequiredMixin, CharacterMixin, RedirectView, ObjectDetailView): - """ - This view provides a mechanism by which a logged-in player can "puppet" one - of their characters within the context of the website. - - It also ensures that any user attempting to puppet something is logged in, - and that their intended puppet is one that they own. - - """ - -
    [docs] def get_redirect_url(self, *args, **kwargs): - """ - Django hook. - - This view returns the URL to which the user should be redirected after - a passed or failed puppet attempt. - - Returns: - url (str): Path to post-puppet destination. - - """ - # Get the requested character, if it belongs to the authenticated user - char = self.get_object() - - # Get the page the user came from - next_page = self.request.GET.get("next", self.success_url) - - if char: - # If the account owns the char, store the ID of the char in the - # Django request's session (different from Evennia session!). - # We do this because characters don't serialize well. - self.request.session["puppet"] = int(char.pk) - messages.success(self.request, "You become '%s'!" % char) - else: - # If the puppeting failed, clear out the cached puppet value - self.request.session["puppet"] = None - messages.error(self.request, "You cannot become '%s'." % char) - - return next_page
    - - -
    [docs]class CharacterManageView(LoginRequiredMixin, CharacterMixin, ListView): - """ - This view provides a mechanism by which a logged-in player can browse, - edit, or delete their own characters. - - """ - - # -- Django constructs -- - paginate_by = 10 - template_name = "website/character_manage_list.html" - - # -- Evennia constructs -- - page_title = "Manage Characters"
    - - -
    [docs]class CharacterUpdateView(CharacterMixin, ObjectUpdateView): - """ - This view provides a mechanism by which a logged-in player (enforced by - ObjectUpdateView) can edit the attributes of a character they own. - - """ - - # -- Django constructs -- - form_class = website_forms.CharacterUpdateForm - template_name = "website/character_form.html"
    - - -
    [docs]class CharacterDetailView(CharacterMixin, ObjectDetailView): - """ - This view provides a mechanism by which a user can view the attributes of - a character, owned by them or not. - - """ - - # -- Django constructs -- - template_name = "website/object_detail.html" - - # -- Evennia constructs -- - # What attributes to display for this object - attributes = ["name", "desc"] - access_type = "view" - -
    [docs] def get_queryset(self): - """ - This method will override the Django get_queryset method to return a - list of all characters the user may access. - - Returns: - queryset (QuerySet): Django queryset for use in the given view. - - """ - account = self.request.user - - # Return a queryset consisting of characters the user is allowed to - # see. - ids = [ - obj.id for obj in self.typeclass.objects.all() if obj.access(account, self.access_type) - ] - - return self.typeclass.objects.filter(id__in=ids).order_by(Lower("db_key"))
    - - -
    [docs]class CharacterDeleteView(CharacterMixin, ObjectDeleteView): - """ - This view provides a mechanism by which a logged-in player (enforced by - ObjectDeleteView) can delete a character they own. - - """ - - pass
    - - -
    [docs]class CharacterCreateView(CharacterMixin, ObjectCreateView): - """ - This view provides a mechanism by which a logged-in player (enforced by - ObjectCreateView) can create a new character. - - """ - - # -- Django constructs -- - template_name = "website/character_form.html" - -
    [docs] def form_valid(self, form): - """ - Django hook, modified for Evennia. - - This hook is called after a valid form is submitted. - - When an character creation form is submitted and the data is deemed valid, - proceeds with creating the Character object. - - """ - # Get account object creating the character - account = self.request.user - character = None - - # Get attributes from the form - self.attributes = {k: form.cleaned_data[k] for k in form.cleaned_data.keys()} - charname = self.attributes.pop("db_key") - description = self.attributes.pop("desc") - # Create a character - character, errors = self.typeclass.create(charname, account, description=description) - - if errors: - # Echo error messages to the user - [messages.error(self.request, x) for x in errors] - - if character: - # Assign attributes from form - for key, value in self.attributes.items(): - setattr(character.db, key, value) - - # Return the user to the character management page, unless overridden - messages.success(self.request, "Your character '%s' was created!" % character.name) - return HttpResponseRedirect(self.success_url) - - else: - # Call the Django "form failed" hook - messages.error(self.request, "Your character could not be created.") - return self.form_invalid(form)
    - - -# -# Channel views -# - - -
    [docs]class ChannelMixin(TypeclassMixin): - """ - This is a "mixin", a modifier of sorts. - - Any view class with this in its inheritance list will be modified to work - with HelpEntry objects instead of generic Objects or otherwise. - - """ - - # -- Django constructs -- - model = class_from_module(settings.BASE_CHANNEL_TYPECLASS, - fallback=settings.FALLBACK_CHANNEL_TYPECLASS) - - # -- Evennia constructs -- - page_title = "Channels" - - # What lock type to check for the requesting user, authenticated or not. - # https://github.com/evennia/evennia/wiki/Locks#valid-access_types - access_type = "listen" - -
    [docs] def get_queryset(self): - """ - Django hook; here we want to return a list of only those Channels - and other documentation that the current user is allowed to see. - - Returns: - queryset (QuerySet): List of Channels available to the user. - - """ - account = self.request.user - - # Get list of all Channels - channels = self.typeclass.objects.all().iterator() - - # Now figure out which ones the current user is allowed to see - bucket = [channel.id for channel in channels if channel.access(account, "listen")] - - # Re-query and set a sorted list - filtered = self.typeclass.objects.filter(id__in=bucket).order_by(Lower("db_key")) - - return filtered
    - - -
    [docs]class ChannelListView(ChannelMixin, ListView): - """ - Returns a list of channels that can be viewed by a user, authenticated - or not. - - """ - - # -- Django constructs -- - paginate_by = 100 - template_name = "website/channel_list.html" - - # -- Evennia constructs -- - page_title = "Channel Index" - - max_popular = 10 - -
    [docs] def get_context_data(self, **kwargs): - """ - Django hook; we override it to calculate the most popular channels. - - Returns: - context (dict): Django context object - - """ - context = super(ChannelListView, self).get_context_data(**kwargs) - - # Calculate which channels are most popular - context["most_popular"] = sorted( - list(self.get_queryset()), - key=lambda channel: len(channel.subscriptions.all()), - reverse=True, - )[: self.max_popular] - - return context
    - - -
    [docs]class ChannelDetailView(ChannelMixin, ObjectDetailView): - """ - Returns the log entries for a given channel. - - """ - - # -- Django constructs -- - template_name = "website/channel_detail.html" - - # -- Evennia constructs -- - # What attributes of the object you wish to display on the page. Model-level - # attributes will take precedence over identically-named db.attributes! - # The order you specify here will be followed. - attributes = ["name"] - - # How many log entries to read and display. - max_num_lines = 10000 - -
    [docs] def get_context_data(self, **kwargs): - """ - Django hook; before we can display the channel logs, we need to recall - the logfile and read its lines. - - Returns: - context (dict): Django context object - - """ - # Get the parent context object, necessary first step - context = super(ChannelDetailView, self).get_context_data(**kwargs) - - # Get the filename this Channel is recording to - filename = self.object.attributes.get( - "log_file", default="channel_%s.log" % self.object.key - ) - - # Split log entries so we can filter by time - bucket = [] - for log in (x.strip() for x in tail_log_file(filename, 0, self.max_num_lines)): - if not log: - continue - time, msg = log.split(" [-] ") - time_key = time.split(":")[0] - - bucket.append({"key": time_key, "timestamp": time, "message": msg}) - - # Add the processed entries to the context - context["object_list"] = bucket - - # Get a list of unique timestamps by hour and sort them - context["object_filters"] = sorted(set([x["key"] for x in bucket])) - - return context
    - -
    [docs] def get_object(self, queryset=None): - """ - Override of Django hook that retrieves an object by slugified channel - name. - - Returns: - channel (Channel): Channel requested in the URL. - - """ - # Get the queryset for the help entries the user can access - if not queryset: - queryset = self.get_queryset() - - # Find the object in the queryset - channel = slugify(self.kwargs.get("slug", "")) - obj = next((x for x in queryset if slugify(x.db_key) == channel), None) - - # Check if this object was requested in a valid manner - if not obj: - raise HttpResponseBadRequest( - "No %(verbose_name)s found matching the query" - % {"verbose_name": queryset.model._meta.verbose_name} - ) - - return obj
    - - -# -# Help views -# - - -
    [docs]class HelpMixin(TypeclassMixin): - """ - This is a "mixin", a modifier of sorts. - - Any view class with this in its inheritance list will be modified to work - with HelpEntry objects instead of generic Objects or otherwise. - - """ - - # -- Django constructs -- - model = HelpEntry - - # -- Evennia constructs -- - page_title = "Help" - -
    [docs] def get_queryset(self): - """ - Django hook; here we want to return a list of only those HelpEntries - and other documentation that the current user is allowed to see. - - Returns: - queryset (QuerySet): List of Help entries available to the user. - - """ - account = self.request.user - - # Get list of all HelpEntries - entries = self.typeclass.objects.all().iterator() - - # Now figure out which ones the current user is allowed to see - bucket = [entry.id for entry in entries if entry.access(account, "view")] - - # Re-query and set a sorted list - filtered = ( - self.typeclass.objects.filter(id__in=bucket) - .order_by(Lower("db_key")) - .order_by(Lower("db_help_category")) - ) - - return filtered
    - - -
    [docs]class HelpListView(HelpMixin, ListView): - """ - Returns a list of help entries that can be viewed by a user, authenticated - or not. - - """ - - # -- Django constructs -- - paginate_by = 500 - template_name = "website/help_list.html" - - # -- Evennia constructs -- - page_title = "Help Index"
    - - -
    [docs]class HelpDetailView(HelpMixin, EvenniaDetailView): - """ - Returns the detail page for a given help entry. - - """ - - # -- Django constructs -- - template_name = "website/help_detail.html" - -
    [docs] def get_context_data(self, **kwargs): - """ - Adds navigational data to the template to let browsers go to the next - or previous entry in the help list. - - Returns: - context (dict): Django context object - - """ - context = super(HelpDetailView, self).get_context_data(**kwargs) - - # Get the object in question - obj = self.get_object() - - # Get queryset and filter out non-related categories - queryset = ( - self.get_queryset() - .filter(db_help_category=obj.db_help_category) - .order_by(Lower("db_key")) - ) - context["topic_list"] = queryset - - # Find the index position of the given obj in the queryset - objs = list(queryset) - for i, x in enumerate(objs): - if obj is x: - break - - # Find the previous and next topics, if either exist - try: - assert i + 1 <= len(objs) and objs[i + 1] is not obj - context["topic_next"] = objs[i + 1] - except: - context["topic_next"] = None - - try: - assert i - 1 >= 0 and objs[i - 1] is not obj - context["topic_previous"] = objs[i - 1] - except: - context["topic_previous"] = None - - # Format the help entry using HTML instead of newlines - text = obj.db_entrytext - text = text.replace("\r\n\r\n", "\n\n") - text = text.replace("\r\n", "\n") - text = text.replace("\n", "<br />") - context["entry_text"] = text - - return context
    - -
    [docs] def get_object(self, queryset=None): - """ - Override of Django hook that retrieves an object by category and topic - instead of pk and slug. - - Returns: - entry (HelpEntry): HelpEntry requested in the URL. - - """ - # Get the queryset for the help entries the user can access - if not queryset: - queryset = self.get_queryset() - - # Find the object in the queryset - category = slugify(self.kwargs.get("category", "")) - topic = slugify(self.kwargs.get("topic", "")) - obj = next( - ( - x - for x in queryset - if slugify(x.db_help_category) == category and slugify(x.db_key) == topic - ), - None, - ) - - # Check if this object was requested in a valid manner - if not obj: - return HttpResponseBadRequest( - "No %(verbose_name)s found matching the query" - % {"verbose_name": queryset.model._meta.verbose_name} - ) - - return obj
    -
    - -
    -
    -
    -
    - -
    -
    - - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/functools.html b/docs/0.9.5/_modules/functools.html index 08040b3d3d..c72c574f82 100644 --- a/docs/0.9.5/_modules/functools.html +++ b/docs/0.9.5/_modules/functools.html @@ -1055,7 +1055,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_modules/index.html b/docs/0.9.5/_modules/index.html index a0d5d2b7ae..3f6136eb0e 100644 --- a/docs/0.9.5/_modules/index.html +++ b/docs/0.9.5/_modules/index.html @@ -41,10 +41,8 @@
  • django.db.models.fields.related_descriptors
  • django.db.models.manager
  • django.db.models.query_utils
  • -
  • django.utils.functional
  • evennia
  • functools
  • @@ -250,7 +248,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/_static/nature.css b/docs/0.9.5/_static/nature.css index 81f2fb719c..f0cad24e91 100644 --- a/docs/0.9.5/_static/nature.css +++ b/docs/0.9.5/_static/nature.css @@ -340,7 +340,8 @@ div.code-block-caption { } .versionchanged { - background-color: #f7f7f7; + background-color: #b7e6e8; + padding-left: 10px; } .deprecated { @@ -398,6 +399,16 @@ code.descname { padding: 5px; } +/* The develop-branch warning header */ + +.develop { + background-color: #ffe4e4; + align-content: center; + width: auto; + text-align: center; + letter-spacing: 15px; +} + /* -- screen sizes ------------------------------------------------------------------ */ diff --git a/docs/0.9.5/api/evennia-api.html b/docs/0.9.5/api/evennia-api.html index e9ded9c837..e47dcba0b7 100644 --- a/docs/0.9.5/api/evennia-api.html +++ b/docs/0.9.5/api/evennia-api.html @@ -144,7 +144,10 @@
  • evennia.contrib.tutorial_examples.bodyfunctions
  • evennia.contrib.tutorial_examples.cmdset_red_button
  • evennia.contrib.tutorial_examples.example_batch_code
  • -
  • evennia.contrib.tutorial_examples.red_button
  • +
  • evennia.contrib.tutorial_examples.red_button +
  • evennia.contrib.tutorial_examples.red_button_scripts
  • evennia.contrib.tutorial_examples.tests
  • @@ -165,10 +168,7 @@
  • evennia.locks
  • @@ -265,10 +265,19 @@
  • evennia.utils -
  • diff --git a/docs/0.9.5/api/evennia.accounts.accounts.html b/docs/0.9.5/api/evennia.accounts.accounts.html index 7010e3de86..e49c18e290 100644 --- a/docs/0.9.5/api/evennia.accounts.accounts.html +++ b/docs/0.9.5/api/evennia.accounts.accounts.html @@ -39,7 +39,7 @@

    evennia.accounts.accounts

    -

    Typeclass for Account objects

    +

    Typeclass for Account objects.

    Note that this object is primarily intended to store OOC information, not game info! This object represents the actual user (not their @@ -180,6 +180,24 @@ at_account_creation()

    property characters
    +
    +
    +get_display_name(looker, **kwargs)[source]
    +

    This is used by channels and other OOC communications methods to give a +custom display of this account’s input.

    +
    +
    Parameters
    +
      +
    • looker (Account) – The one that will see this name.

    • +
    • **kwargs – Unused by default, can be used to pass game-specific data.

    • +
    +
    +
    Returns
    +

    str – The name, possibly modified.

    +
    +
    +
    +
    disconnect_session_from_account(session, reason=None)[source]
    @@ -436,8 +454,9 @@ error (ValidationError, None): Any validation error(s) raised. Multiple

    Notes

    -

    This is called by Django also when logging in; it should not be mixed up with validation, since that -would mean old passwords in the database (pre validation checks) could get invalidated.

    +

    This is called by Django also when logging in; it should not be mixed up with +validation, since that would mean old passwords in the database (pre validation checks) +could get invalidated.

    @@ -554,6 +573,81 @@ commands at run-time.

    +
    +
    +at_pre_channel_msg(message, channel, senders=None, **kwargs)[source]
    +

    Called by the Channel just before passing a message into channel_msg. +This allows for tweak messages per-user and also to abort the +receive on the receiver-level.

    +
    +
    Parameters
    +
      +
    • message (str) – The message sent to the channel.

    • +
    • channel (Channel) – The sending channel.

    • +
    • senders (list, optional) – Accounts or Objects acting as senders. +For most normal messages, there is only a single sender. If +there are no senders, this may be a broadcasting message.

    • +
    • **kwargs – These are additional keywords passed into channel_msg. +If no_prefix=True or emit=True are passed, the channel +prefix will not be added (**[channelname]: ** by default)

    • +
    +
    +
    Returns
    +

    str or None

    +
    +
    Allows for customizing the message for this recipient.

    If returning None (or False) message-receiving is aborted. +The returning string will be passed into self.channel_msg.

    +
    +
    +

    +
    +
    +

    Notes

    +

    This support posing/emotes by starting channel-send with : or ;.

    +
    + +
    +
    +channel_msg(message, channel, senders=None, **kwargs)[source]
    +

    This performs the actions of receiving a message to an un-muted +channel.

    +
    +
    Parameters
    +
      +
    • message (str) – The message sent to the channel.

    • +
    • channel (Channel) – The sending channel.

    • +
    • senders (list, optional) – Accounts or Objects acting as senders. +For most normal messages, there is only a single sender. If +there are no senders, this may be a broadcasting message or +similar.

    • +
    • **kwargs – These are additional keywords originally passed into +Channel.msg.

    • +
    +
    +
    +

    Notes

    +

    Before this, Channel.at_pre_channel_msg will fire, which offers a way +to customize the message for the receiver on the channel-level.

    +
    + +
    +
    +at_post_channel_msg(message, channel, senders=None, **kwargs)[source]
    +

    Called by self.channel_msg after message was received.

    +
    +
    Parameters
    +
      +
    • message (str) – The message sent to the channel.

    • +
    • channel (Channel) – The sending channel.

    • +
    • senders (list, optional) – Accounts or Objects acting as senders. +For most normal messages, there is only a single sender. If +there are no senders, this may be a broadcasting message.

    • +
    • **kwargs – These are additional keywords passed into channel_msg.

    • +
    +
    +
    +
    +
    search(searchdata, return_puppet=False, search_object=False, typeclass=None, nofound_string=None, multimatch_string=None, use_nicks=True, quiet=False, **kwargs)[source]
    @@ -940,6 +1034,94 @@ overriding the call (unused by default).

    +
    +
    +class evennia.accounts.accounts.DefaultGuest(*args, **kwargs)[source]
    +

    Bases: evennia.accounts.accounts.DefaultAccount

    +

    This class is used for guest logins. Unlike Accounts, Guests and +their characters are deleted after disconnection.

    +
    +
    +classmethod create(**kwargs)[source]
    +

    Forwards request to cls.authenticate(); returns a DefaultGuest object +if one is available for use.

    +
    + +
    +
    +classmethod authenticate(**kwargs)[source]
    +

    Gets or creates a Guest account object.

    +
    +
    Keyword Arguments
    +

    ip (str, optional) – IP address of requestor; used for ban checking, +throttling and logging

    +
    +
    Returns
    +

    account (Object) – Guest account object, if available +errors (list): List of error messages accrued during this request.

    +
    +
    +
    + +
    +
    +at_post_login(session=None, **kwargs)[source]
    +

    In theory, guests only have one character regardless of which +MULTISESSION_MODE we’re in. They don’t get a choice.

    +
    +
    Parameters
    +
      +
    • session (Session, optional) – Session connecting.

    • +
    • **kwargs (dict) – Arbitrary, optional arguments for users +overriding the call (unused by default).

    • +
    +
    +
    +
    + +
    +
    +at_server_shutdown()[source]
    +

    We repeat the functionality of at_disconnect() here just to +be on the safe side.

    +
    + +
    +
    +at_post_disconnect(**kwargs)[source]
    +

    Once having disconnected, destroy the guest’s characters and

    +
    +
    Parameters
    +

    **kwargs (dict) – Arbitrary, optional arguments for users +overriding the call (unused by default).

    +
    +
    +
    + +
    +
    +exception DoesNotExist
    +

    Bases: evennia.accounts.accounts.DefaultAccount.DoesNotExist

    +
    + +
    +
    +exception MultipleObjectsReturned
    +

    Bases: evennia.accounts.accounts.DefaultAccount.MultipleObjectsReturned

    +
    + +
    +
    +path = 'evennia.accounts.accounts.DefaultGuest'
    +
    + +
    +
    +typename = 'DefaultGuest'
    +
    + +
    +
    @@ -985,7 +1167,6 @@ overriding the call (unused by default).

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.accounts.admin.html b/docs/0.9.5/api/evennia.accounts.admin.html index c0be39fe2c..0dff3c2a71 100644 --- a/docs/0.9.5/api/evennia.accounts.admin.html +++ b/docs/0.9.5/api/evennia.accounts.admin.html @@ -37,308 +37,8 @@
    -
    -

    evennia.accounts.admin

    -
    -
    -class evennia.accounts.admin.AccountDBChangeForm(*args, **kwargs)[source]
    -

    Bases: django.contrib.auth.forms.UserChangeForm

    -

    Modify the accountdb class.

    -
    -
    -class Meta[source]
    -

    Bases: object

    -
    -
    -model
    -

    alias of evennia.accounts.models.AccountDB

    -
    - -
    -
    -fields = '__all__'
    -
    - -
    - -
    -
    -clean_username()[source]
    -

    Clean the username and check its existence.

    -
    - -
    -
    -base_fields = {'date_joined': <django.forms.fields.DateTimeField object>, 'db_attributes': <django.forms.models.ModelMultipleChoiceField object>, 'db_cmdset_storage': <django.forms.fields.CharField object>, 'db_is_bot': <django.forms.fields.BooleanField object>, 'db_is_connected': <django.forms.fields.BooleanField object>, 'db_key': <django.forms.fields.CharField object>, 'db_lock_storage': <django.forms.fields.CharField object>, 'db_tags': <django.forms.models.ModelMultipleChoiceField object>, 'db_typeclass_path': <django.forms.fields.CharField object>, 'email': <django.forms.fields.EmailField object>, 'first_name': <django.forms.fields.CharField object>, 'groups': <django.forms.models.ModelMultipleChoiceField object>, 'is_active': <django.forms.fields.BooleanField object>, 'is_staff': <django.forms.fields.BooleanField object>, 'is_superuser': <django.forms.fields.BooleanField object>, 'last_login': <django.forms.fields.DateTimeField object>, 'last_name': <django.forms.fields.CharField object>, 'password': <django.contrib.auth.forms.ReadOnlyPasswordHashField object>, 'user_permissions': <django.forms.models.ModelMultipleChoiceField object>, 'username': <django.forms.fields.RegexField object>}
    -
    - -
    -
    -declared_fields = {'password': <django.contrib.auth.forms.ReadOnlyPasswordHashField object>, 'username': <django.forms.fields.RegexField object>}
    -
    - -
    -
    -property media
    -

    Return all media required to render the widgets on this form.

    -
    - -
    - -
    -
    -class evennia.accounts.admin.AccountDBCreationForm(*args, **kwargs)[source]
    -

    Bases: django.contrib.auth.forms.UserCreationForm

    -

    Create a new AccountDB instance.

    -
    -
    -class Meta[source]
    -

    Bases: object

    -
    -
    -model
    -

    alias of evennia.accounts.models.AccountDB

    -
    - -
    -
    -fields = '__all__'
    -
    - -
    - -
    -
    -clean_username()[source]
    -

    Cleanup username.

    -
    - -
    -
    -base_fields = {'date_joined': <django.forms.fields.DateTimeField object>, 'db_attributes': <django.forms.models.ModelMultipleChoiceField object>, 'db_cmdset_storage': <django.forms.fields.CharField object>, 'db_is_bot': <django.forms.fields.BooleanField object>, 'db_is_connected': <django.forms.fields.BooleanField object>, 'db_key': <django.forms.fields.CharField object>, 'db_lock_storage': <django.forms.fields.CharField object>, 'db_tags': <django.forms.models.ModelMultipleChoiceField object>, 'db_typeclass_path': <django.forms.fields.CharField object>, 'email': <django.forms.fields.EmailField object>, 'first_name': <django.forms.fields.CharField object>, 'groups': <django.forms.models.ModelMultipleChoiceField object>, 'is_active': <django.forms.fields.BooleanField object>, 'is_staff': <django.forms.fields.BooleanField object>, 'is_superuser': <django.forms.fields.BooleanField object>, 'last_login': <django.forms.fields.DateTimeField object>, 'last_name': <django.forms.fields.CharField object>, 'password': <django.forms.fields.CharField object>, 'password1': <django.forms.fields.CharField object>, 'password2': <django.forms.fields.CharField object>, 'user_permissions': <django.forms.models.ModelMultipleChoiceField object>, 'username': <django.forms.fields.RegexField object>}
    -
    - -
    -
    -declared_fields = {'password1': <django.forms.fields.CharField object>, 'password2': <django.forms.fields.CharField object>, 'username': <django.forms.fields.RegexField object>}
    -
    - -
    -
    -property media
    -

    Return all media required to render the widgets on this form.

    -
    - -
    - -
    -
    -class evennia.accounts.admin.AccountForm(data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=<class 'django.forms.utils.ErrorList'>, label_suffix=None, empty_permitted=False, instance=None, use_required_attribute=None, renderer=None)[source]
    -

    Bases: django.forms.models.ModelForm

    -

    Defines how to display Accounts

    -
    -
    -class Meta[source]
    -

    Bases: object

    -
    -
    -model
    -

    alias of evennia.accounts.models.AccountDB

    -
    - -
    -
    -fields = '__all__'
    -
    - -
    -
    -app_label = 'accounts'
    -
    - -
    - -
    -
    -base_fields = {'date_joined': <django.forms.fields.DateTimeField object>, 'db_attributes': <django.forms.models.ModelMultipleChoiceField object>, 'db_cmdset_storage': <django.forms.fields.CharField object>, 'db_is_bot': <django.forms.fields.BooleanField object>, 'db_is_connected': <django.forms.fields.BooleanField object>, 'db_key': <django.forms.fields.RegexField object>, 'db_lock_storage': <django.forms.fields.CharField object>, 'db_permissions': <django.forms.fields.CharField object>, 'db_tags': <django.forms.models.ModelMultipleChoiceField object>, 'db_typeclass_path': <django.forms.fields.CharField object>, 'email': <django.forms.fields.EmailField object>, 'first_name': <django.forms.fields.CharField object>, 'groups': <django.forms.models.ModelMultipleChoiceField object>, 'is_active': <django.forms.fields.BooleanField object>, 'is_staff': <django.forms.fields.BooleanField object>, 'is_superuser': <django.forms.fields.BooleanField object>, 'last_login': <django.forms.fields.DateTimeField object>, 'last_name': <django.forms.fields.CharField object>, 'password': <django.forms.fields.CharField object>, 'user_permissions': <django.forms.models.ModelMultipleChoiceField object>, 'username': <django.forms.fields.CharField object>}
    -
    - -
    -
    -declared_fields = {'db_cmdset_storage': <django.forms.fields.CharField object>, 'db_key': <django.forms.fields.RegexField object>, 'db_lock_storage': <django.forms.fields.CharField object>, 'db_permissions': <django.forms.fields.CharField object>, 'db_typeclass_path': <django.forms.fields.CharField object>}
    -
    - -
    -
    -property media
    -

    Return all media required to render the widgets on this form.

    -
    - -
    - -
    -
    -class evennia.accounts.admin.AccountInline(parent_model, admin_site)[source]
    -

    Bases: django.contrib.admin.options.StackedInline

    -

    Inline creation of Account

    -
    -
    -model
    -

    alias of evennia.accounts.models.AccountDB

    -
    - -
    -
    -template = 'admin/accounts/stacked.html'
    -
    - -
    -
    -form
    -

    alias of AccountForm

    -
    - -
    -
    -fieldsets = (('In-game Permissions and Locks', {'fields': ('db_lock_storage',), 'description': '<i>These are permissions/locks for in-game use. They are unrelated to website access rights.</i>'}), ('In-game Account data', {'fields': ('db_typeclass_path', 'db_cmdset_storage'), 'description': '<i>These fields define in-game-specific properties for the Account object in-game.</i>'}))
    -
    - -
    -
    -extra = 1
    -
    - -
    -
    -max_num = 1
    -
    - -
    -
    -property media
    -
    - -
    - -
    -
    -class evennia.accounts.admin.AccountTagInline(parent_model, admin_site)[source]
    -

    Bases: evennia.typeclasses.admin.TagInline

    -

    Inline Account Tags.

    -
    -
    -model
    -

    alias of evennia.accounts.models.AccountDB_db_tags

    -
    - -
    -
    -related_field = 'accountdb'
    -
    - -
    -
    -property media
    -
    - -
    - -
    -
    -class evennia.accounts.admin.AccountAttributeInline(parent_model, admin_site)[source]
    -

    Bases: evennia.typeclasses.admin.AttributeInline

    -

    Inline Account Attributes.

    -
    -
    -model
    -

    alias of evennia.accounts.models.AccountDB_db_attributes

    -
    - -
    -
    -related_field = 'accountdb'
    -
    - -
    -
    -property media
    -
    - -
    - -
    -
    -class evennia.accounts.admin.AccountDBAdmin(model, admin_site)[source]
    -

    Bases: django.contrib.auth.admin.UserAdmin

    -

    This is the main creation screen for Users/accounts

    -
    -
    -list_display = ('username', 'email', 'is_staff', 'is_superuser')
    -
    - -
    -
    -form
    -

    alias of AccountDBChangeForm

    -
    - -
    -
    -add_form
    -

    alias of AccountDBCreationForm

    -
    - -
    -
    -inlines = [<class 'evennia.accounts.admin.AccountTagInline'>, <class 'evennia.accounts.admin.AccountAttributeInline'>]
    -
    - -
    -
    -fieldsets = ((None, {'fields': ('username', 'password', 'email')}), ('Website profile', {'fields': ('first_name', 'last_name'), 'description': '<i>These are not used in the default system.</i>'}), ('Website dates', {'fields': ('last_login', 'date_joined'), 'description': '<i>Relevant only to the website.</i>'}), ('Website Permissions', {'fields': ('is_active', 'is_staff', 'is_superuser', 'user_permissions', 'groups'), 'description': '<i>These are permissions/permission groups for accessing the admin site. They are unrelated to in-game access rights.</i>'}), ('Game Options', {'fields': ('db_typeclass_path', 'db_cmdset_storage', 'db_lock_storage'), 'description': '<i>These are attributes that are more relevant to gameplay.</i>'}))
    -
    - -
    -
    -add_fieldsets = ((None, {'fields': ('username', 'password1', 'password2', 'email'), 'description': '<i>These account details are shared by the admin system and the game.</i>'}),)
    -
    - -
    -
    -user_change_password(request, id, form_url='')[source]
    -
    - -
    -
    -save_model(request, obj, form, change)[source]
    -

    Custom save actions.

    -
    -
    Parameters
    -
      -
    • request (Request) – Incoming request.

    • -
    • obj (Object) – Object to save.

    • -
    • form (Form) – Related form instance.

    • -
    • change (bool) – False if this is a new save and not an update.

    • -
    -
    -
    -
    - -
    -
    -response_add(request, obj, post_url_continue=None)[source]
    -

    Determine the HttpResponse for the add_view stage. It mostly defers to -its superclass implementation but is customized because the User model -has a slightly different workflow.

    -
    - -
    -
    -property media
    -
    - -
    - +
    +

    evennia.accounts.admin

    @@ -384,7 +84,6 @@ has a slightly different workflow.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.accounts.bots.html b/docs/0.9.5/api/evennia.accounts.bots.html index 82e88a2c76..b6cb051db4 100644 --- a/docs/0.9.5/api/evennia.accounts.bots.html +++ b/docs/0.9.5/api/evennia.accounts.bots.html @@ -494,7 +494,6 @@ triggered by the bot_data_in Inputfunc.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.accounts.html b/docs/0.9.5/api/evennia.accounts.html index 66a22a8a17..627d394066 100644 --- a/docs/0.9.5/api/evennia.accounts.html +++ b/docs/0.9.5/api/evennia.accounts.html @@ -96,7 +96,6 @@ more Objects depending on settings. An Account has no in-game existence.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.accounts.manager.html b/docs/0.9.5/api/evennia.accounts.manager.html index c528da9250..d67c255e92 100644 --- a/docs/0.9.5/api/evennia.accounts.manager.html +++ b/docs/0.9.5/api/evennia.accounts.manager.html @@ -91,7 +91,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.accounts.models.html b/docs/0.9.5/api/evennia.accounts.models.html index 23c32c62af..8bb4da2a1b 100644 --- a/docs/0.9.5/api/evennia.accounts.models.html +++ b/docs/0.9.5/api/evennia.accounts.models.html @@ -412,7 +412,6 @@ class built by **create_forward_many_to_many_manager()** define
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.commands.cmdhandler.html b/docs/0.9.5/api/evennia.commands.cmdhandler.html index f9a8f1c6aa..417cc727fe 100644 --- a/docs/0.9.5/api/evennia.commands.cmdhandler.html +++ b/docs/0.9.5/api/evennia.commands.cmdhandler.html @@ -45,15 +45,11 @@ command line. The processing of a command works as follows:

    1. The calling object (caller) is analyzed based on its callertype.

    2. Cmdsets are gathered from different sources: -- channels: all available channel names are auto-created into a cmdset, to allow

      +- object cmdsets: all objects at caller’s location are scanned for non-empty

      -

      for giving the channel name and have the following immediately -sent to the channel. The sending is performed by the CMD_CHANNEL -system command.

      +

      cmdsets. This includes cmdsets on exits.

        -
      • object cmdsets: all objects at caller’s location are scanned for non-empty -cmdsets. This includes cmdsets on exits.

      • caller: the caller is searched for its own currently active cmdset.

      • account: lastly the cmdsets defined on caller.account are added.

      @@ -67,19 +63,10 @@ input string for possible command matches.

    3. cmdset, or fallback to error message. Exit.

    4. If no match was found -> check for CMD_NOMATCH in current cmdset or fallback to error message. Exit.

    5. -
    6. A single match was found. If this is a channel-command (i.e. the -ommand name is that of a channel), –> check for CMD_CHANNEL in -current cmdset or use channelhandler default. Exit.

    7. At this point we have found a normal command. We assign useful variables to it that will be available to the command coder at run-time.

    8. -
    -
      -
    1. We have a unique cmdobject, primed for use. Call all hooks:

    2. -
    -
    -

    at_pre_cmd(), cmdobj.parse(), cmdobj.func() and finally at_post_cmd().

    -
    -
      +
    1. We have a unique cmdobject, primed for use. Call all hooks: +at_pre_cmd(), cmdobj.parse(), cmdobj.func() and finally at_post_cmd().

    2. Return deferred that will fire with the return from cmdobj.func() (unused by default).

    @@ -183,7 +170,6 @@ default Evennia.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.commands.cmdparser.html b/docs/0.9.5/api/evennia.commands.cmdparser.html index 88f4c21de9..392e2412e1 100644 --- a/docs/0.9.5/api/evennia.commands.cmdparser.html +++ b/docs/0.9.5/api/evennia.commands.cmdparser.html @@ -96,8 +96,8 @@ in the match, otherwise strip them before matching.

    -
    -evennia.commands.cmdparser.try_num_prefixes(raw_string)[source]
    +
    +evennia.commands.cmdparser.try_num_differentiators(raw_string)[source]

    Test if user tried to separate multi-matches with a number separator (default 1-name, 2-name etc). This is usually called last, if no other match was found.

    @@ -206,7 +206,6 @@ the remaining arguments, and the matched cmdobject from the cmdset.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.commands.cmdset.html b/docs/0.9.5/api/evennia.commands.cmdset.html index 05aad699d1..8ca423ed37 100644 --- a/docs/0.9.5/api/evennia.commands.cmdset.html +++ b/docs/0.9.5/api/evennia.commands.cmdset.html @@ -423,7 +423,6 @@ self.add().

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.commands.cmdsethandler.html b/docs/0.9.5/api/evennia.commands.cmdsethandler.html index e132724ed5..92de8f282c 100644 --- a/docs/0.9.5/api/evennia.commands.cmdsethandler.html +++ b/docs/0.9.5/api/evennia.commands.cmdsethandler.html @@ -176,7 +176,7 @@ to the central cmdhandler.get_and_merge_cmdsets()!

    -add(cmdset, emit_to_obj=None, permanent=False, default_cmdset=False)[source]
    +add(cmdset, emit_to_obj=None, persistent=True, default_cmdset=False, **kwargs)[source]

    Add a cmdset to the handler, on top of the old ones, unless it is set as the default one (it will then end up at the bottom of the stack)

    @@ -185,7 +185,7 @@ is set as the default one (it will then end up at the bottom of the stack)

  • cmdset (CmdSet or str) – Can be a cmdset object or the python path to such an object.

  • emit_to_obj (Object, optional) – An object to receive error messages.

  • -
  • permanent (bool, optional) – This cmdset will remain across a server reboot.

  • +
  • persistent (bool, optional) – Let cmdset remain across server reload.

  • default_cmdset (Cmdset, optional) – Insert this to replace the default cmdset position (there is only one such position, always at the bottom of the stack).

  • @@ -206,14 +206,14 @@ it’s a ‘quirk’ that has to be documented.

    -add_default(cmdset, emit_to_obj=None, permanent=True)[source]
    +add_default(cmdset, emit_to_obj=None, persistent=True, **kwargs)[source]

    Shortcut for adding a default cmdset.

    Parameters
    • cmdset (Cmdset) – The Cmdset to add.

    • emit_to_obj (Object, optional) – Gets error messages

    • -
    • permanent (bool, optional) – The new Cmdset should survive a server reboot.

    • +
    • persistent (bool, optional) – The new Cmdset should survive a server reboot.

    @@ -391,7 +391,6 @@ handled automatically by @reload).

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.commands.command.html b/docs/0.9.5/api/evennia.commands.command.html index 3a5bee384b..eeaf969229 100644 --- a/docs/0.9.5/api/evennia.commands.command.html +++ b/docs/0.9.5/api/evennia.commands.command.html @@ -41,6 +41,13 @@

    evennia.commands.command

    The base Command class.

    All commands in Evennia inherit from the ‘Command’ class in this module.

    +
    +
    +exception evennia.commands.command.InterruptCommand[source]
    +

    Bases: Exception

    +

    Cleanly interrupt a command.

    +
    +
    class evennia.commands.command.CommandMeta(*args, **kwargs)[source]
    @@ -58,7 +65,7 @@
    class evennia.commands.command.Command(**kwargs)[source]

    Bases: object

    -

    Base command

    +

    (you may see this if a child command had no help text defined)

    Usage:

    command [args]

    @@ -375,17 +382,6 @@ commands the caller can use.

    -
    -
    -client_height()[source]
    -

    Get the client screenheight for the session using this command.

    -
    -
    Returns
    -

    client height (int) – The height (in characters) of the client window.

    -
    -
    -
    -
    styled_table(*args, **kwargs)[source]
    @@ -438,13 +434,11 @@ detailing the contents of the table.

    save_for_next = False
    - +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'command', 'tags': '', 'text': '\n ## Base command\n\n (you may see this if a child command had no help text defined)\n\n Usage:\n command [args]\n\n This is the base command class. Inherit from this\n to create new commands.\n\n The cmdhandler makes the following variables available to the\n command methods (so you can always assume them to be there):\n self.caller - the game object calling the command\n self.cmdstring - the command name used to trigger this command (allows\n you to know which alias was used, for example)\n cmd.args - everything supplied to the command following the cmdstring\n (this is usually what is parsed in self.parse())\n cmd.cmdset - the cmdset from which this command was matched (useful only\n seldomly, notably for help-type commands, to create dynamic\n help entries and lists)\n cmd.obj - the object on which this command is defined. If a default command,\n this is usually the same as caller.\n cmd.rawstring - the full raw string input, including any args and no parsing.\n\n The following class properties can/should be defined on your child class:\n\n key - identifier for command (e.g. "look")\n aliases - (optional) list of aliases (e.g. ["l", "loo"])\n locks - lock string (default is "cmd:all()")\n help_category - how to organize this help entry in help system\n (default is "General")\n auto_help - defaults to True. Allows for turning off auto-help generation\n arg_regex - (optional) raw string regex defining how the argument part of\n the command should look in order to match for this command\n (e.g. must it be a space between cmdname and arg?)\n auto_help_display_key - (optional) if given, this replaces the string shown\n in the auto-help listing. This is particularly useful for system-commands\n whose actual key is not really meaningful.\n\n (Note that if auto_help is on, this initial string is also used by the\n system to create the help entry for the command, so it\'s a good idea to\n format it similar to this one). This behavior can be changed by\n overriding the method \'get_help\' of a command: by default, this\n method returns cmd.__doc__ (that is, this very docstring, or\n the docstring of your command). You can, however, extend or\n replace this without disabling auto_help.\n '}
    +
    -
    -
    -exception evennia.commands.command.InterruptCommand[source]
    -

    Bases: Exception

    -

    Cleanly interrupt a command.

    @@ -492,7 +486,6 @@ detailing the contents of the table.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.commands.default.account.html b/docs/0.9.5/api/evennia.commands.default.account.html index ef9deac1ae..78b2b2919a 100644 --- a/docs/0.9.5/api/evennia.commands.default.account.html +++ b/docs/0.9.5/api/evennia.commands.default.account.html @@ -70,7 +70,7 @@ method. Otherwise all text will be returned to all connected sessions.

    -aliases = ['l', 'ls']
    +aliases = ['ls', 'l']
    @@ -99,6 +99,11 @@ method. Otherwise all text will be returned to all connected sessions.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'ls l', 'category': 'general', 'key': 'look', 'tags': '', 'text': '\n look while out-of-character\n\n Usage:\n look\n\n Look in the ooc state.\n '}
    +
    +
    @@ -153,6 +158,11 @@ as you the account have access right to puppet it.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'puppet', 'category': 'general', 'key': 'ic', 'tags': '', 'text': '\n control an object you have permission to puppet\n\n Usage:\n ic <character>\n\n Go in-character (IC) as a given Character.\n\n This will attempt to "become" a different object assuming you have\n the right to do so. Note that it\'s the ACCOUNT character that puppets\n characters/objects and which needs to have the correct permission!\n\n You cannot become an object that is already controlled by another\n account. In principle <character> can be any in-game object as long\n as you the account have access right to puppet it.\n '}
    +
    +
    @@ -202,6 +212,11 @@ as you the account have access right to puppet it.

    lock_storage = 'cmd:pperm(Player)'
    +
    +
    +search_index_entry = {'aliases': 'unpuppet', 'category': 'general', 'key': 'ooc', 'tags': '', 'text': '\n stop puppeting and go ooc\n\n Usage:\n ooc\n\n Go out-of-character (OOC).\n\n This will leave your current character and put you in a incorporeal OOC state.\n '}
    +
    +
    @@ -250,6 +265,11 @@ as you the account have access right to puppet it.

    lock_storage = 'cmd:pperm(Player)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'password', 'tags': '', 'text': '\n change your password\n\n Usage:\n password <old password> = <new password>\n\n Changes your password. Make sure to pick a safe one.\n '}
    +
    +
    @@ -306,6 +326,11 @@ game. Use the /all switch to disconnect from all sessions.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'quit', 'tags': '', 'text': '\n quit the game\n\n Usage:\n quit\n\n Switch:\n all - disconnect all connected sessions\n\n Gracefully disconnect your current session from the\n game. Use the /all switch to disconnect from all sessions.\n '}
    +
    +
    @@ -357,6 +382,11 @@ if you want.

    lock_storage = 'cmd:pperm(Player)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'charcreate', 'tags': '', 'text': '\n create a new character\n\n Usage:\n charcreate <charname> [= desc]\n\n Create a new character, optionally giving it a description. You\n may use upper-case letters in the name - you will nevertheless\n always be able to access your character using lower-case letters\n if you want.\n '}
    +
    +
    @@ -415,6 +445,11 @@ later connecting with a client with different capabilities.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'options', 'category': 'general', 'key': 'option', 'tags': '', 'text': '\n Set an account option\n\n Usage:\n option[/save] [name = value]\n\n Switches:\n save - Save the current option settings for future logins.\n clear - Clear the saved options.\n\n This command allows for viewing and setting client interface\n settings. Note that saved options may not be able to be used if\n later connecting with a client with different capabilities.\n\n\n '}
    +
    +
    @@ -463,6 +498,11 @@ later connecting with a client with different capabilities.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'sessions', 'tags': '', 'text': '\n check your connected session(s)\n\n Usage:\n sessions\n\n Lists the sessions currently connected to your account.\n\n '}
    +
    +
    @@ -513,6 +553,11 @@ also for those with all permissions.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'doing', 'category': 'general', 'key': 'who', 'tags': '', 'text': '\n list who is currently online\n\n Usage:\n who\n doing\n\n Shows who is currently online. Doing is an alias that limits info\n also for those with all permissions.\n '}
    +
    +
    @@ -521,7 +566,7 @@ also for those with all permissions.

    Bases: evennia.commands.default.muxcommand.MuxCommand

    testing which colors your client support

    -
    Usage:

    color ansi||xterm256

    +
    Usage:

    color ansi | xterm256

    Prints a color map along with in-mud color codes to use to produce @@ -592,6 +637,11 @@ Takes a table of columns [[val,val,…],[val,val,…],…]

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'color', 'tags': '', 'text': '\n testing which colors your client support\n\n Usage:\n color ansi | xterm256\n\n Prints a color map along with in-mud color codes to use to produce\n them. It also tests what is supported in your client. Choices are\n 16-color ansi (supported in most muds) or the 256-color xterm256\n standard. No checking is done to determine your client supports\n color - if not you will see rubbish appear.\n '}
    +
    +
    @@ -647,6 +697,11 @@ Use the unquell command to revert back to normal operation.

    lock_storage = 'cmd:pperm(Player)'
    +
    +
    +search_index_entry = {'aliases': 'unquell', 'category': 'general', 'key': 'quell', 'tags': '', 'text': "\n use character's permissions instead of account's\n\n Usage:\n quell\n unquell\n\n Normally the permission level of the Account is used when puppeting a\n Character/Object to determine access. This command will switch the lock\n system to make use of the puppeted Object's permissions instead. This is\n useful mainly for testing.\n Hierarchical permission quelling only work downwards, thus an Account cannot\n use a higher-permission Character to escalate their permission level.\n Use the unquell command to revert back to normal operation.\n "}
    +
    +
    @@ -690,6 +745,11 @@ Use the unquell command to revert back to normal operation.

    lock_storage = 'cmd:pperm(Player)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'chardelete', 'tags': '', 'text': '\n delete a character - this cannot be undone!\n\n Usage:\n chardelete <charname>\n\n Permanently deletes one of your characters.\n '}
    +
    +
    @@ -747,6 +807,11 @@ to all the variables defined therein.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'style', 'tags': '', 'text': '\n In-game style options\n\n Usage:\n style\n style <option> = <value>\n\n Configure stylings for in-game display elements like table borders, help\n entriest etc. Use without arguments to see all available options.\n\n '}
    +
    + @@ -794,7 +859,6 @@ to all the variables defined therein.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.commands.default.admin.html b/docs/0.9.5/api/evennia.commands.default.admin.html index 3cac099b32..6dc6896860 100644 --- a/docs/0.9.5/api/evennia.commands.default.admin.html +++ b/docs/0.9.5/api/evennia.commands.default.admin.html @@ -90,6 +90,11 @@ supplied it will be echoed to the user unless /quiet is set.

    lock_storage = 'cmd:perm(boot) or perm(Admin)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'admin', 'key': 'boot', 'tags': '', 'text': '\n kick an account from the server.\n\n Usage\n boot[/switches] <account obj> [: reason]\n\n Switches:\n quiet - Silently boot without informing account\n sid - boot by session id instead of name or dbref\n\n Boot an account object from the server. If a reason is\n supplied it will be echoed to the user unless /quiet is set.\n '}
    +
    +
    @@ -164,6 +169,11 @@ values in each tuple is set to the empty string.

    lock_storage = 'cmd:perm(ban) or perm(Developer)'
    +
    +
    +search_index_entry = {'aliases': 'bans', 'category': 'admin', 'key': 'ban', 'tags': '', 'text': "\n ban an account from the server\n\n Usage:\n ban [<name or ip> [: reason]]\n\n Without any arguments, shows numbered list of active bans.\n\n This command bans a user from accessing the game. Supply an optional\n reason to be able to later remember why the ban was put in place.\n\n It is often preferable to ban an account from the server than to\n delete an account with accounts/delete. If banned by name, that account\n account can no longer be logged into.\n\n IP (Internet Protocol) address banning allows blocking all access\n from a specific address or subnet. Use an asterisk (*) as a\n wildcard.\n\n Examples:\n ban thomas - ban account 'thomas'\n ban/ip 134.233.2.111 - ban specific ip address\n ban/ip 134.233.2.* - ban all in a subnet\n ban/ip 134.233.*.* - even wider ban\n\n A single IP filter can be easy to circumvent by changing computers\n or requesting a new IP address. Setting a wide IP block filter with\n wildcards might be tempting, but remember that it may also\n accidentally block innocent users connecting from the same country\n or region.\n\n "}
    +
    +
    @@ -210,6 +220,11 @@ unban.

    lock_storage = 'cmd:perm(unban) or perm(Developer)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'admin', 'key': 'unban', 'tags': '', 'text': '\n remove a ban from an account\n\n Usage:\n unban <banid>\n\n This will clear an account name/ip ban previously set with the ban\n command. Use this command without an argument to view a numbered\n list of bans. Use the numbers in this list to select which one to\n unban.\n\n '}
    +
    +
    @@ -268,6 +283,11 @@ to accounts respectively.

    lock_storage = 'cmd:perm(emit) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': 'remit pemit', 'category': 'admin', 'key': 'emit', 'tags': '', 'text': '\n admin command for emitting message to multiple objects\n\n Usage:\n emit[/switches] [<obj>, <obj>, ... =] <message>\n remit [<obj>, <obj>, ... =] <message>\n pemit [<obj>, <obj>, ... =] <message>\n\n Switches:\n room - limit emits to rooms only (default)\n accounts - limit emits to accounts only\n contents - send to the contents of matched objects too\n\n Emits a message to the selected objects or to\n your immediate surroundings. If the object is a room,\n send to its contents. remit and pemit are just\n limited forms of emit, for sending to rooms and\n to accounts respectively.\n '}
    +
    +
    @@ -311,6 +331,11 @@ to accounts respectively.

    lock_storage = 'cmd:perm(newpassword) or perm(Admin)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'admin', 'key': 'userpassword', 'tags': '', 'text': "\n change the password of an account\n\n Usage:\n userpassword <user obj> = <new password>\n\n Set an account's password.\n "}
    +
    +
    @@ -364,6 +389,11 @@ or account. If no permission is given, list all permissions on <object>.lock_storage = 'cmd:perm(perm) or perm(Developer)'
    +
    +
    +search_index_entry = {'aliases': 'setperm', 'category': 'admin', 'key': 'perm', 'tags': '', 'text': '\n set the permissions of an account/object\n\n Usage:\n perm[/switch] <object> [= <permission>[,<permission>,...]]\n perm[/switch] *<account> [= <permission>[,<permission>,...]]\n\n Switches:\n del - delete the given permission from <object> or <account>.\n account - set permission on an account (same as adding * to name)\n\n This command sets/clears individual permission strings on an object\n or account. If no permission is given, list all permissions on <object>.\n '}
    +
    +
    @@ -408,6 +438,11 @@ including all currently unlogged in.

    lock_storage = 'cmd:perm(wall) or perm(Admin)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'admin', 'key': 'wall', 'tags': '', 'text': '\n make an announcement to all\n\n Usage:\n wall <message>\n\n Announces a message to all connected sessions\n including all currently unlogged in.\n '}
    +
    +
    @@ -457,6 +492,11 @@ including all currently unlogged in.

    lock_storage = 'cmd:perm(spawn) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'building', 'key': 'force', 'tags': '', 'text': '\n forces an object to execute a command\n\n Usage:\n force <object>=<command string>\n\n Example:\n force bob=get stick\n '}
    +
    + @@ -504,7 +544,6 @@ including all currently unlogged in.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.commands.default.batchprocess.html b/docs/0.9.5/api/evennia.commands.default.batchprocess.html index 4fd9c2be23..1d0298b263 100644 --- a/docs/0.9.5/api/evennia.commands.default.batchprocess.html +++ b/docs/0.9.5/api/evennia.commands.default.batchprocess.html @@ -75,7 +75,7 @@ skipping, reloading etc.

    -aliases = ['batchcommand', 'batchcmd']
    +aliases = ['batchcmd', 'batchcommand']
    @@ -104,6 +104,11 @@ skipping, reloading etc.

    lock_storage = 'cmd:perm(batchcommands) or perm(Developer)'
    +
    +
    +search_index_entry = {'aliases': 'batchcmd batchcommand', 'category': 'building', 'key': 'batchcommands', 'tags': '', 'text': '\n build from batch-command file\n\n Usage:\n batchcommands[/interactive] <python.path.to.file>\n\n Switch:\n interactive - this mode will offer more control when\n executing the batch file, like stepping,\n skipping, reloading etc.\n\n Runs batches of commands from a batch-cmd text file (*.ev).\n\n '}
    +
    +
    @@ -162,6 +167,11 @@ object copies behind when testing out the script.

    lock_storage = 'cmd:superuser()'
    +
    +
    +search_index_entry = {'aliases': 'batchcodes', 'category': 'building', 'key': 'batchcode', 'tags': '', 'text': '\n build from batch-code file\n\n Usage:\n batchcode[/interactive] <python path to file>\n\n Switch:\n interactive - this mode will offer more control when\n executing the batch file, like stepping,\n skipping, reloading etc.\n debug - auto-delete all objects that has been marked as\n deletable in the script file (see example files for\n syntax). This is useful so as to to not leave multiple\n object copies behind when testing out the script.\n\n Runs batches of commands from a batch-code text file (*.py).\n\n '}
    +
    + @@ -209,7 +219,6 @@ object copies behind when testing out the script.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.commands.default.building.html b/docs/0.9.5/api/evennia.commands.default.building.html index 38fbf504e9..91f1b679b1 100644 --- a/docs/0.9.5/api/evennia.commands.default.building.html +++ b/docs/0.9.5/api/evennia.commands.default.building.html @@ -86,6 +86,11 @@ the cases, see the module doc.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'command', 'tags': '', 'text': "\n This is a parent class for some of the defining objmanip commands\n since they tend to have some more variables to define new objects.\n\n Each object definition can have several components. First is\n always a name, followed by an optional alias list and finally an\n some optional data, such as a typeclass or a location. A comma ','\n separates different objects. Like this:\n\n name1;alias;alias;alias:option, name2;alias;alias ...\n\n Spaces between all components are stripped.\n\n A second situation is attribute manipulation. Such commands\n are simpler and offer combinations\n\n objname/attr/attr/attr, objname/attr, ...\n\n "}
    +
    +
    @@ -147,6 +152,11 @@ by everyone.

    lock_storage = 'cmd:perm(setobjalias) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': 'setobjalias', 'category': 'building', 'key': 'alias', 'tags': '', 'text': "\n adding permanent aliases for object\n\n Usage:\n alias <obj> [= [alias[,alias,alias,...]]]\n alias <obj> =\n alias/category <obj> = [alias[,alias,...]:<category>\n\n Switches:\n category - requires ending input with :category, to store the\n given aliases with the given category.\n\n Assigns aliases to an object so it can be referenced by more\n than one name. Assign empty to remove all aliases from object. If\n assigning a category, all aliases given will be using this category.\n\n Observe that this is not the same thing as personal aliases\n created with the 'nick' command! Aliases set with alias are\n changing the object in question, making those aliases usable\n by everyone.\n "}
    +
    +
    @@ -192,6 +202,11 @@ one exact copy of the original object will be created with the name lock_storage = 'cmd:perm(copy) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'building', 'key': 'copy', 'tags': '', 'text': "\n copy an object and its properties\n\n Usage:\n copy <original obj> [= <new_name>][;alias;alias..]\n [:<new_location>] [,<new_name2> ...]\n\n Create one or more copies of an object. If you don't supply any targets,\n one exact copy of the original object will be created with the name *_copy.\n "}
    +
    +
    @@ -284,6 +299,11 @@ required and get the attribute from the object.

    lock_storage = 'cmd:perm(cpattr) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'building', 'key': 'cpattr', 'tags': '', 'text': "\n copy attributes between objects\n\n Usage:\n cpattr[/switch] <obj>/<attr> = <obj1>/<attr1> [,<obj2>/<attr2>,<obj3>/<attr3>,...]\n cpattr[/switch] <obj>/<attr> = <obj1> [,<obj2>,<obj3>,...]\n cpattr[/switch] <attr> = <obj1>/<attr1> [,<obj2>/<attr2>,<obj3>/<attr3>,...]\n cpattr[/switch] <attr> = <obj1>[,<obj2>,<obj3>,...]\n\n Switches:\n move - delete the attribute from the source object after copying.\n\n Example:\n cpattr coolness = Anna/chillout, Anna/nicety, Tom/nicety\n ->\n copies the coolness attribute (defined on yourself), to attributes\n on Anna and Tom.\n\n Copy the attribute one object to one or more attributes on another object.\n If you don't supply a source object, yourself is used.\n "}
    +
    +
    @@ -338,6 +358,11 @@ object. If you don’t supply a source object, yourself is used.

    lock_storage = 'cmd:perm(mvattr) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'building', 'key': 'mvattr', 'tags': '', 'text': "\n move attributes between objects\n\n Usage:\n mvattr[/switch] <obj>/<attr> = <obj1>/<attr1> [,<obj2>/<attr2>,<obj3>/<attr3>,...]\n mvattr[/switch] <obj>/<attr> = <obj1> [,<obj2>,<obj3>,...]\n mvattr[/switch] <attr> = <obj1>/<attr1> [,<obj2>/<attr2>,<obj3>/<attr3>,...]\n mvattr[/switch] <attr> = <obj1>[,<obj2>,<obj3>,...]\n\n Switches:\n copy - Don't delete the original after moving.\n\n Move an attribute from one object to one or more attributes on another\n object. If you don't supply a source object, yourself is used.\n "}
    +
    +
    @@ -406,6 +431,11 @@ object of this type like this:

    lock_storage = 'cmd:perm(create) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'building', 'key': 'create', 'tags': '', 'text': "\n create new objects\n\n Usage:\n create[/drop] <objname>[;alias;alias...][:typeclass], <objname>...\n\n switch:\n drop - automatically drop the new object into your current\n location (this is not echoed). This also sets the new\n object's home to the current location rather than to you.\n\n Creates one or more new objects. If typeclass is given, the object\n is created as a child of this typeclass. The typeclass script is\n assumed to be located under types/ and any further\n directory structure is given in Python notation. So if you have a\n correct typeclass 'RedButton' defined in\n types/examples/red_button.py, you could create a new\n object of this type like this:\n\n create/drop button;red : examples.red_button.RedButton\n\n "}
    +
    +
    @@ -462,6 +492,11 @@ describe the current room.

    lock_storage = 'cmd:perm(desc) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': 'describe', 'category': 'building', 'key': 'desc', 'tags': '', 'text': '\n describe an object or the current room.\n\n Usage:\n desc [<obj> =] <description>\n\n Switches:\n edit - Open up a line editor for more advanced editing.\n\n Sets the "desc" attribute on an object. If an object is not given,\n describe the current room.\n '}
    +
    +
    @@ -533,6 +568,11 @@ You can specify the /force switch to bypass this confirmation.

    lock_storage = 'cmd:perm(destroy) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': 'del delete', 'category': 'building', 'key': 'destroy', 'tags': '', 'text': '\n permanently delete objects\n\n Usage:\n destroy[/switches] [obj, obj2, obj3, [dbref-dbref], ...]\n\n Switches:\n override - The destroy command will usually avoid accidentally\n destroying account objects. This switch overrides this safety.\n force - destroy without confirmation.\n Examples:\n destroy house, roof, door, 44-78\n destroy 5-10, flower, 45\n destroy/force north\n\n Destroys one or many objects. If dbrefs are used, a range to delete can be\n given, e.g. 4-10. Also the end points will be deleted. This command\n displays a confirmation before destroying, to make sure of your choice.\n You can specify the /force switch to bypass this confirmation.\n '}
    +
    +
    @@ -602,6 +642,11 @@ would be ‘north;no;n’.

    lock_storage = 'cmd:perm(dig) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'building', 'key': 'dig', 'tags': '', 'text': "\n build new rooms and connect them to the current location\n\n Usage:\n dig[/switches] <roomname>[;alias;alias...][:typeclass]\n [= <exit_to_there>[;alias][:typeclass]]\n [, <exit_to_here>[;alias][:typeclass]]\n\n Switches:\n tel or teleport - move yourself to the new room\n\n Examples:\n dig kitchen = north;n, south;s\n dig house:myrooms.MyHouseTypeclass\n dig sheer cliff;cliff;sheer = climb up, climb down\n\n This command is a convenient way to build rooms quickly; it creates the\n new room and you can optionally set up exits back and forth between your\n current room and the new one. You can add as many aliases as you\n like to the name of the room and the exits in question; an example\n would be 'north;no;n'.\n "}
    +
    +
    @@ -672,6 +717,11 @@ For more flexibility and power in creating rooms, use dig.

    lock_storage = 'cmd: perm(tunnel) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': 'tun', 'category': 'building', 'key': 'tunnel', 'tags': '', 'text': '\n create new rooms in cardinal directions only\n\n Usage:\n tunnel[/switch] <direction>[:typeclass] [= <roomname>[;alias;alias;...][:typeclass]]\n\n Switches:\n oneway - do not create an exit back to the current location\n tel - teleport to the newly created room\n\n Example:\n tunnel n\n tunnel n = house;mike\'s place;green building\n\n This is a simple way to build using pre-defined directions:\n |wn,ne,e,se,s,sw,w,nw|n (north, northeast etc)\n |wu,d|n (up and down)\n |wi,o|n (in and out)\n The full names (north, in, southwest, etc) will always be put as\n main name for the exit, using the abbreviation as an alias (so an\n exit will always be able to be used with both "north" as well as\n "n" for example). Opposite directions will automatically be\n created back from the new room unless the /oneway switch is given.\n For more flexibility and power in creating rooms, use dig.\n '}
    +
    +
    @@ -727,6 +777,11 @@ currently set destination.

    lock_storage = 'cmd:perm(link) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'building', 'key': 'link', 'tags': '', 'text': '\n link existing rooms together with exits\n\n Usage:\n link[/switches] <object> = <target>\n link[/switches] <object> =\n link[/switches] <object>\n\n Switch:\n twoway - connect two exits. For this to work, BOTH <object>\n and <target> must be exit objects.\n\n If <object> is an exit, set its destination to <target>. Two-way operation\n instead sets the destination to the *locations* of the respective given\n arguments.\n The second form (a lone =) sets the destination to None (same as\n the unlink command) and the third form (without =) just shows the\n currently set destination.\n '}
    +
    +
    @@ -777,6 +832,11 @@ and call func in CmdLink

    lock_storage = 'cmd:perm(unlink) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'building', 'key': 'unlink', 'tags': '', 'text': '\n remove exit-connections between rooms\n\n Usage:\n unlink <Object>\n\n Unlinks an object, for example an exit, disconnecting\n it from whatever it was connected to.\n '}
    +
    +
    @@ -825,6 +885,11 @@ It is also a convenient target of the “home” command.

    lock_storage = 'cmd:perm(sethome) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'building', 'key': 'sethome', 'tags': '', 'text': '\n set an object\'s home location\n\n Usage:\n sethome <obj> [= <home_location>]\n sethom <obj>\n\n The "home" location is a "safety" location for objects; they\n will be moved there if their current location ceases to exist. All\n objects should always have a home location for this reason.\n It is also a convenient target of the "home" command.\n\n If no location is given, just view the object\'s home location.\n '}
    +
    +
    @@ -869,6 +934,11 @@ to a user. Defaults to yourself.

    lock_storage = 'cmd:perm(listcmdsets) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': 'listcmsets', 'category': 'building', 'key': 'cmdsets', 'tags': '', 'text': '\n list command sets defined on an object\n\n Usage:\n cmdsets <obj>\n\n This displays all cmdsets assigned\n to a user. Defaults to yourself.\n '}
    +
    +
    @@ -913,6 +983,11 @@ rename an account.

    lock_storage = 'cmd:perm(rename) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': 'rename', 'category': 'building', 'key': 'name', 'tags': '', 'text': '\n change the name and/or aliases of an object\n\n Usage:\n name <obj> = <newname>;alias1;alias2\n\n Rename an object to something new. Use *obj to\n rename an account.\n\n '}
    +
    +
    @@ -974,6 +1049,11 @@ as well as the self.create_exit() method.

    lock_storage = 'cmd:perm(open) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'building', 'key': 'open', 'tags': '', 'text': '\n open a new exit from the current room\n\n Usage:\n open <new exit>[;alias;alias..][:typeclass] [,<return exit>[;alias;..][:typeclass]]] = <destination>\n\n Handles the creation of exits. If a destination is given, the exit\n will point there. The <return exit> argument sets up an exit at the\n destination leading back to the current room. Destination name\n can be given both as a #dbref and a name, if that name is globally\n unique.\n\n '}
    +
    +
    @@ -1129,6 +1209,11 @@ with older attrs that might have been named with []’s.

    lock_storage = 'cmd:perm(set) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'building', 'key': 'set', 'tags': '', 'text': '\n set attribute on an object or account\n\n Usage:\n set <obj>/<attr> = <value>\n set <obj>/<attr> =\n set <obj>/<attr>\n set *<account>/<attr> = <value>\n\n Switch:\n edit: Open the line editor (string values only)\n script: If we\'re trying to set an attribute on a script\n channel: If we\'re trying to set an attribute on a channel\n account: If we\'re trying to set an attribute on an account\n room: Setting an attribute on a room (global search)\n exit: Setting an attribute on an exit (global search)\n char: Setting an attribute on a character (global search)\n character: Alias for char, as above.\n\n Sets attributes on objects. The second example form above clears a\n previously set attribute while the third form inspects the current value of\n the attribute (if any). The last one (with the star) is a shortcut for\n operating on a player Account rather than an Object.\n\n The most common data to save with this command are strings and\n numbers. You can however also set Python primitives such as lists,\n dictionaries and tuples on objects (this might be important for\n the functionality of certain custom objects). This is indicated\n by you starting your value with one of |c\'|n, |c"|n, |c(|n, |c[|n\n or |c{ |n.\n\n Once you have stored a Python primitive as noted above, you can include\n |c[<key>]|n in <attr> to reference nested values in e.g. a list or dict.\n\n Remember that if you use Python primitives like this, you must\n write proper Python syntax too - notably you must include quotes\n around your strings or you will get an error.\n\n '}
    +
    +
    @@ -1183,7 +1268,7 @@ server settings.

    -aliases = ['type', 'swap', 'parent', 'update']
    +aliases = ['parent', 'type', 'update', 'swap']
    @@ -1212,6 +1297,11 @@ server settings.

    lock_storage = 'cmd:perm(typeclass) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': 'parent type update swap', 'category': 'building', 'key': 'typeclass', 'tags': '', 'text': "\n set or change an object's typeclass\n\n Usage:\n typeclass[/switch] <object> [= typeclass.path]\n typeclass/prototype <object> = prototype_key\n\n typeclass/list/show [typeclass.path]\n swap - this is a shorthand for using /force/reset flags.\n update - this is a shorthand for using the /force/reload flag.\n\n Switch:\n show, examine - display the current typeclass of object (default) or, if\n given a typeclass path, show the docstring of that typeclass.\n update - *only* re-run at_object_creation on this object\n meaning locks or other properties set later may remain.\n reset - clean out *all* the attributes and properties on the\n object - basically making this a new clean object.\n force - change to the typeclass also if the object\n already has a typeclass of the same name.\n list - show available typeclasses. Only typeclasses in modules actually\n imported or used from somewhere in the code will show up here\n (those typeclasses are still available if you know the path)\n prototype - clean and overwrite the object with the specified\n prototype key - effectively making a whole new object.\n\n Example:\n type button = examples.red_button.RedButton\n type/prototype button=a red button\n\n If the typeclass_path is not given, the current object's typeclass is\n assumed.\n\n View or set an object's typeclass. If setting, the creation hooks of the\n new typeclass will be run on the object. If you have clashing properties on\n the old class, use /reset. By default you are protected from changing to a\n typeclass of the same name as the one you already have - use /force to\n override this protection.\n\n The given typeclass must be identified by its location using python\n dot-notation pointing to the correct module and class. If no typeclass is\n given (or a wrong typeclass is given). Errors in the path or new typeclass\n will lead to the old typeclass being kept. The location of the typeclass\n module is searched from the default typeclass directory, as defined in the\n server settings.\n\n "}
    +
    +
    @@ -1259,6 +1349,11 @@ matching the given attribute-wildcard search string.

    lock_storage = 'cmd:perm(wipe) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'building', 'key': 'wipe', 'tags': '', 'text': "\n clear all attributes from an object\n\n Usage:\n wipe <object>[/<attr>[/<attr>...]]\n\n Example:\n wipe box\n wipe box/colour\n\n Wipes all of an object's attributes, or optionally only those\n matching the given attribute-wildcard search string.\n "}
    +
    +
    @@ -1326,6 +1421,11 @@ them by ‘;’, i.e:

    lock_storage = 'cmd: perm(locks) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': 'locks', 'category': 'building', 'key': 'lock', 'tags': '', 'text': "\n assign a lock definition to an object\n\n Usage:\n lock <object or *account>[ = <lockstring>]\n or\n lock[/switch] <object or *account>/<access_type>\n\n Switch:\n del - delete given access type\n view - view lock associated with given access type (default)\n\n If no lockstring is given, shows all locks on\n object.\n\n Lockstring is of the form\n access_type:[NOT] func1(args)[ AND|OR][ NOT] func2(args) ...]\n Where func1, func2 ... valid lockfuncs with or without arguments.\n Separator expressions need not be capitalized.\n\n For example:\n 'get: id(25) or perm(Admin)'\n The 'get' lock access_type is checked e.g. by the 'get' command.\n An object locked with this example lock will only be possible to pick up\n by Admins or by an object with id=25.\n\n You can add several access_types after one another by separating\n them by ';', i.e:\n 'get:id(25); delete:perm(Builder)'\n "}
    +
    +
    @@ -1447,6 +1547,11 @@ non-persistent data stored on object

    lock_storage = 'cmd:perm(examine) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': 'exam ex', 'category': 'building', 'key': 'examine', 'tags': '', 'text': '\n get detailed information about an object\n\n Usage:\n examine [<object>[/attrname]]\n examine [*<account>[/attrname]]\n\n Switch:\n account - examine an Account (same as adding *)\n object - examine an Object (useful when OOC)\n\n The examine command shows detailed game info about an\n object and optionally a specific attribute on it.\n If object is not specified, the current location is examined.\n\n Append a * before the search string to examine an account.\n\n '}
    +
    +
    @@ -1478,7 +1583,7 @@ one is given.

    -aliases = ['search', 'locate']
    +aliases = ['locate', 'search']
    @@ -1507,6 +1612,11 @@ one is given.

    lock_storage = 'cmd:perm(find) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': 'locate search', 'category': 'building', 'key': 'find', 'tags': '', 'text': '\n search the database for objects\n\n Usage:\n find[/switches] <name or dbref or *account> [= dbrefmin[-dbrefmax]]\n locate - this is a shorthand for using the /loc switch.\n\n Switches:\n room - only look for rooms (location=None)\n exit - only look for exits (destination!=None)\n char - only look for characters (BASE_CHARACTER_TYPECLASS)\n exact - only exact matches are returned.\n loc - display object location if exists and match has one result\n startswith - search for names starting with the string, rather than containing\n\n Searches the database for an object of a particular name or exact #dbref.\n Use *accountname to search for an account. The switches allows for\n limiting object matches to certain game entities. Dbrefmin and dbrefmax\n limits matches to within the given dbrefs range, or above/below if only\n one is given.\n '}
    +
    +
    @@ -1580,6 +1690,11 @@ teleported to the target location.

    lock_storage = 'cmd:perm(teleport) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': 'teleport', 'category': 'building', 'key': 'tel', 'tags': '', 'text': "\n teleport object to another location\n\n Usage:\n tel/switch [<object> to||=] <target location>\n\n Examples:\n tel Limbo\n tel/quiet box = Limbo\n tel/tonone box\n\n Switches:\n quiet - don't echo leave/arrive messages to the source/target\n locations for the move.\n intoexit - if target is an exit, teleport INTO\n the exit object instead of to its destination\n tonone - if set, teleport the object to a None-location. If this\n switch is set, <target location> is ignored.\n Note that the only way to retrieve\n an object from a None location is by direct #dbref\n reference. A puppeted object cannot be moved to None.\n loc - teleport object to the target's location instead of its contents\n\n Teleports an object somewhere. If no object is given, you yourself are\n teleported to the target location.\n "}
    +
    +
    @@ -1588,7 +1703,7 @@ teleported to the target location.

    Bases: evennia.commands.default.muxcommand.MuxCommand

    attach a script to an object

    -
    Usage:

    script[/switch] <obj> [= script_path or <scriptkey>]

    +
    Usage:

    addscript[/switch] <obj> [= script_path or <scriptkey>]

    Switches:

    start - start all non-running scripts on object, or a given script only stop - stop all scripts on objects, or a given script only

    @@ -1603,12 +1718,12 @@ object without specifying a script key/path will start/stop ALL scripts on the object.

    -key = 'script'
    +key = 'addscript'
    -aliases = ['addscript']
    +aliases = ['attachscript']
    @@ -1637,6 +1752,11 @@ the object.

    lock_storage = 'cmd:perm(script) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': 'attachscript', 'category': 'building', 'key': 'addscript', 'tags': '', 'text': '\n attach a script to an object\n\n Usage:\n addscript[/switch] <obj> [= script_path or <scriptkey>]\n\n Switches:\n start - start all non-running scripts on object, or a given script only\n stop - stop all scripts on objects, or a given script only\n\n If no script path/key is given, lists all scripts active on the given\n object.\n Script path can be given from the base location for scripts as given in\n settings. If adding a new script, it will be started automatically\n (no /start switch is needed). Using the /start or /stop switches on an\n object without specifying a script key/path will start/stop ALL scripts on\n the object.\n '}
    +
    +
    @@ -1703,6 +1823,11 @@ enough to for most grouping schemes.

    lock_storage = 'cmd:perm(tag) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': 'tags', 'category': 'building', 'key': 'tag', 'tags': '', 'text': '\n handles the tags of an object\n\n Usage:\n tag[/del] <obj> [= <tag>[:<category>]]\n tag/search <tag>[:<category]\n\n Switches:\n search - return all objects with a given Tag\n del - remove the given tag. If no tag is specified,\n clear all tags on object.\n\n Manipulates and lists tags on objects. Tags allow for quick\n grouping of and searching for objects. If only <obj> is given,\n list all tags on the object. If /search is used, list objects\n with the given tag.\n The category can be used for grouping tags themselves, but it\n should be used with restrain - tags on their own are usually\n enough to for most grouping schemes.\n '}
    +
    +
    @@ -1809,6 +1934,11 @@ displays a list of available prototypes.

    lock_storage = 'cmd:perm(spawn) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': 'olc', 'category': 'building', 'key': 'spawn', 'tags': '', 'text': '\n spawn objects from prototype\n\n Usage:\n spawn[/noloc] <prototype_key>\n spawn[/noloc] <prototype_dict>\n\n spawn/search [prototype_keykey][;tag[,tag]]\n spawn/list [tag, tag, ...]\n spawn/list modules - list only module-based prototypes\n spawn/show [<prototype_key>]\n spawn/update <prototype_key>\n\n spawn/save <prototype_dict>\n spawn/edit [<prototype_key>]\n olc - equivalent to spawn/edit\n\n Switches:\n noloc - allow location to be None if not specified explicitly. Otherwise,\n location will default to caller\'s current location.\n search - search prototype by name or tags.\n list - list available prototypes, optionally limit by tags.\n show, examine - inspect prototype by key. If not given, acts like list.\n raw - show the raw dict of the prototype as a one-line string for manual editing.\n save - save a prototype to the database. It will be listable by /list.\n delete - remove a prototype from database, if allowed to.\n update - find existing objects with the same prototype_key and update\n them with latest version of given prototype. If given with /save,\n will auto-update all objects with the old version of the prototype\n without asking first.\n edit, menu, olc - create/manipulate prototype in a menu interface.\n\n Example:\n spawn GOBLIN\n spawn {"key":"goblin", "typeclass":"monster.Monster", "location":"#2"}\n spawn/save {"key": "grunt", prototype: "goblin"};;mobs;edit:all()\n \x0c\n Dictionary keys:\n |wprototype_parent |n - name of parent prototype to use. Required if typeclass is\n not set. Can be a path or a list for multiple inheritance (inherits\n left to right). If set one of the parents must have a typeclass.\n |wtypeclass |n - string. Required if prototype_parent is not set.\n |wkey |n - string, the main object identifier\n |wlocation |n - this should be a valid object or #dbref\n |whome |n - valid object or #dbref\n |wdestination|n - only valid for exits (object or dbref)\n |wpermissions|n - string or list of permission strings\n |wlocks |n - a lock-string\n |waliases |n - string or list of strings.\n |wndb_|n<name> - value of a nattribute (ndb_ is stripped)\n\n |wprototype_key|n - name of this prototype. Unique. Used to store/retrieve from db\n and update existing prototyped objects if desired.\n |wprototype_desc|n - desc of this prototype. Used in listings\n |wprototype_locks|n - locks of this prototype. Limits who may use prototype\n |wprototype_tags|n - tags of this prototype. Used to find prototype\n\n any other keywords are interpreted as Attributes and their values.\n\n The available prototypes are defined globally in modules set in\n settings.PROTOTYPE_MODULES. If spawn is used without arguments it\n displays a list of available prototypes.\n\n '}
    +
    + @@ -1856,7 +1986,6 @@ displays a list of available prototypes.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.commands.default.cmdset_account.html b/docs/0.9.5/api/evennia.commands.default.cmdset_account.html index 9a25b4f31b..e937e85b89 100644 --- a/docs/0.9.5/api/evennia.commands.default.cmdset_account.html +++ b/docs/0.9.5/api/evennia.commands.default.cmdset_account.html @@ -118,7 +118,6 @@ command method rather than caller.msg().

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.commands.default.cmdset_character.html b/docs/0.9.5/api/evennia.commands.default.cmdset_character.html index 5ea377965e..b5a908d5f1 100644 --- a/docs/0.9.5/api/evennia.commands.default.cmdset_character.html +++ b/docs/0.9.5/api/evennia.commands.default.cmdset_character.html @@ -116,7 +116,6 @@ Account cmdset. Account commands remain available also to Characters.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.commands.default.cmdset_session.html b/docs/0.9.5/api/evennia.commands.default.cmdset_session.html index 67e48014d7..c762bc9aa6 100644 --- a/docs/0.9.5/api/evennia.commands.default.cmdset_session.html +++ b/docs/0.9.5/api/evennia.commands.default.cmdset_session.html @@ -113,7 +113,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.commands.default.cmdset_unloggedin.html b/docs/0.9.5/api/evennia.commands.default.cmdset_unloggedin.html index ac9d3268de..f3f460c80d 100644 --- a/docs/0.9.5/api/evennia.commands.default.cmdset_unloggedin.html +++ b/docs/0.9.5/api/evennia.commands.default.cmdset_unloggedin.html @@ -115,7 +115,6 @@ of the state instance in this module.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.commands.default.comms.html b/docs/0.9.5/api/evennia.commands.default.comms.html index 7379b884bd..4c806bd6a0 100644 --- a/docs/0.9.5/api/evennia.commands.default.comms.html +++ b/docs/0.9.5/api/evennia.commands.default.comms.html @@ -39,16 +39,696 @@

    evennia.commands.default.comms

    -

    Comsystem command module.

    -

    Comm commands are OOC commands and intended to be made available to -the Account at all times (they go into the AccountCmdSet). So we -make sure to homogenize self.caller to always be the account object -for easy handling.

    +

    Communication commands:

    +
      +
    • channel

    • +
    • page

    • +
    • irc/rss/grapevine linking

    • +
    +
    +
    +class evennia.commands.default.comms.CmdChannel(**kwargs)[source]
    +

    Bases: evennia.commands.default.muxcommand.MuxCommand

    +

    Use and manage in-game channels.

    +
    +
    Usage:

    channel channelname <msg> +channel channel name = <msg> +channel (show all subscription) +channel/all (show available channels) +channel/alias channelname = alias[;alias…] +channel/unalias alias +channel/who channelname +channel/history channelname [= index] +channel/sub channelname [= alias[;alias…]] +channel/unsub channelname[,channelname, …] +channel/mute channelname[,channelname,…] +channel/unmute channelname[,channelname,…]

    +

    channel/create channelname[;alias;alias[:typeclass]] [= description] +channel/destroy channelname [= reason] +channel/desc channelname = description +channel/lock channelname = lockstring +channel/unlock channelname = lockstring +channel/ban channelname (list bans) +channel/ban[/quiet] channelname[, channelname, …] = subscribername [: reason] +channel/unban[/quiet] channelname[, channelname, …] = subscribername +channel/boot[/quiet] channelname[,channelname,…] = subscribername [: reason]

    +
    +
    +
    +
    Usage: channel channelname msg

    channel channel name = msg (with space in channel name)

    +
    +
    +

    This sends a message to the channel. Note that you will rarely use this +command like this; instead you can use the alias

    +
    +

    channelname <msg> +channelalias <msg>

    +
    +

    For example

    +
    +

    public Hello World +pub Hello World

    +
    +

    (this shortcut doesn’t work for aliases containing spaces)

    +

    See channel/alias for help on setting channel aliases.

    +
    +
    Usage: channel/alias channel = alias[;alias[;alias…]]

    channel/unalias alias +channel - this will list your subs and aliases to each channel

    +
    +
    +

    Set one or more personal aliases for referencing a channel. For example:

    +
    +

    channel/alias warrior’s guild = warrior;wguild;warchannel;warrior guild

    +
    +

    You can now send to the channel using all of these:

    +
    +

    warrior’s guild Hello +warrior Hello +wguild Hello +warchannel Hello

    +
    +

    Note that this will not work if the alias has a space in it. So the +‘warrior guild’ alias must be used with the channel command:

    +
    +

    channel warrior guild = Hello

    +
    +

    Channel-aliases can be removed one at a time, using the ‘/unalias’ switch.

    +

    Usage: channel/who channelname

    +

    List the channel’s subscribers. Shows who are currently offline or are +muting the channel. Subscribers who are ‘muting’ will not see messages sent +to the channel (use channel/mute to mute a channel).

    +

    Usage: channel/history channel [= index]

    +

    This will display the last |c20|n lines of channel history. By supplying an +index number, you will step that many lines back before viewing those 20 lines.

    +

    For example:

    +
    +

    channel/history public = 35

    +
    +

    will go back 35 lines and show the previous 20 lines from that point (so +lines -35 to -55).

    +
    +
    Usage: channel/sub channel [=alias[;alias;…]]

    channel/unsub channel

    +
    +
    +

    This subscribes you to a channel and optionally assigns personal shortcuts +for you to use to send to that channel (see aliases). When you unsub, all +your personal aliases will also be removed.

    +
    +
    Usage: channel/mute channelname

    channel/unmute channelname

    +
    +
    +

    Muting silences all output from the channel without actually +un-subscribing. Other channel members will see that you are muted in the /who +list. Sending a message to the channel will automatically unmute you.

    +
    +
    Usage: channel/create channelname[;alias;alias[:typeclass]] [= description]

    channel/destroy channelname [= reason]

    +
    +
    +

    Creates a new channel (or destroys one you control). You will automatically +join the channel you create and everyone will be kicked and loose all aliases +to a destroyed channel.

    +
    +
    Usage: channel/lock channelname = lockstring

    channel/unlock channelname = lockstring

    +
    +
    +

    Note: this is an admin command.

    +

    A lockstring is on the form locktype:lockfunc(). Channels understand three +locktypes:

    +
    +

    listen - who may listen or join the channel. +send - who may send messages to the channel +control - who controls the channel. This is usually the one creating

    +
    +

    the channel.

    +
    +
    +

    Common lockfuncs are all() and perm(). To make a channel everyone can +listen to but only builders can talk on, use this:

    +
    +

    listen:all() +send: perm(Builders)

    +
    +
    +
    Usage:

    channel/boot[/quiet] channelname[,channelname,…] = subscribername [: reason] +channel/ban channelname[, channelname, …] = subscribername [: reason] +channel/unban channelname[, channelname, …] = subscribername +channel/unban channelname +channel/ban channelname (list bans)

    +
    +
    +

    Booting will kick a named subscriber from channel(s) temporarily. The +‘reason’ will be passed to the booted user. Unless the /quiet switch is +used, the channel will also be informed of the action. A booted user is +still able to re-connect, but they’ll have to set up their aliases again.

    +

    Banning will blacklist a user from (re)joining the provided channels. It +will then proceed to boot them from those channels if they were connected. +The ‘reason’ and /quiet works the same as for booting.

    +

    Example

    +

    boot mychannel1 = EvilUser : Kicking you to cool down a bit. +ban mychannel1,mychannel2= EvilUser : Was banned for spamming.

    +
    +
    +key = 'channel'
    +
    + +
    +
    +aliases = ['channels', 'chan']
    +
    + +
    +
    +help_category = 'comms'
    +
    + +
    +
    +locks = 'cmd:not pperm(channel_banned);admin:all();manage:all();changelocks:perm(Admin)'
    +
    + +
    +
    +switch_options = ('list', 'all', 'history', 'sub', 'unsub', 'mute', 'unmute', 'alias', 'unalias', 'create', 'destroy', 'desc', 'lock', 'unlock', 'boot', 'ban', 'unban', 'who')
    +
    + +
    +
    +account_caller = True
    +
    + +
    +
    +search_channel(channelname, exact=False, handle_errors=True)[source]
    +

    Helper function for searching for a single channel with some error +handling.

    +
    +
    Parameters
    +
      +
    • channelname (str) – Name, alias #dbref or partial name/alias to search +for.

    • +
    • exact (bool, optional) – If an exact or fuzzy-match of the name should be done. +Note that even for a fuzzy match, an exactly given, unique channel name +will always be returned.

    • +
    • handle_errors (bool) – If true, use self.msg to report errors if +there are non/multiple matches. If so, the return will always be +a single match or None.

    • +
    +
    +
    Returns
    +

    object, list or None

    +
    +
    If handle_errors is True, this is either a found Channel

    or None. Otherwise it’s a list of zero, one or more channels found.

    +
    +
    +

    +
    +
    +

    Notes

    +

    The ‘listen’ and ‘control’ accesses are checked before returning.

    +
    + +
    +
    +msg_channel(channel, message, **kwargs)[source]
    +

    Send a message to a given channel. This will check the ‘send’ +permission on the channel.

    +
    +
    Parameters
    +
      +
    • channel (Channel) – The channel to send to.

    • +
    • message (str) – The message to send.

    • +
    • **kwargs – Unused by default. These kwargs will be passed into +all channel messaging hooks for custom overriding.

    • +
    +
    +
    +
    + +
    +
    +get_channel_history(channel, start_index=0)[source]
    +

    View a channel’s history.

    +
    +
    Parameters
    +
      +
    • channel (Channel) – The channel to access.

    • +
    • message (str) – The message to send.

    • +
    • **kwargs – Unused by default. These kwargs will be passed into +all channel messaging hooks for custom overriding.

    • +
    +
    +
    +
    + +
    +
    +sub_to_channel(channel)[source]
    +

    Subscribe to a channel. Note that all permissions should +be checked before this step.

    +
    +
    Parameters
    +

    channel (Channel) – The channel to access.

    +
    +
    Returns
    +

    bool, str

    +
    +
    True, None if connection failed. If False,

    the second part is an error string.

    +
    +
    +

    +
    +
    +
    + +
    +
    +unsub_from_channel(channel, **kwargs)[source]
    +

    Un-Subscribe to a channel. Note that all permissions should +be checked before this step.

    +
    +
    Parameters
    +
      +
    • channel (Channel) – The channel to unsub from.

    • +
    • **kwargs – Passed on to nick removal.

    • +
    +
    +
    Returns
    +

    bool, str

    +
    +
    True, None if un-connection succeeded. If False,

    the second part is an error string.

    +
    +
    +

    +
    +
    +
    + +
    +
    +add_alias(channel, alias, **kwargs)[source]
    +

    Add a new alias (nick) for the user to use with this channel.

    +
    +
    Parameters
    +
      +
    • channel (Channel) – The channel to alias.

    • +
    • alias (str) – The personal alias to use for this channel.

    • +
    • **kwargs – If given, passed into nicks.add.

    • +
    +
    +
    +
    +

    Note

    +

    We add two nicks - one is a plain alias -> channel.key that +we need to be able to reference this channel easily. The other +is a templated nick to easily be able to send messages to the +channel without needing to give the full channel command. The +structure of this nick is given by self.channel_msg_pattern +and self.channel_msg_nick_replacement. By default it maps +alias <msg> -> channel <channelname> = <msg>, so that you can +for example just write pub Hello to send a message.

    +

    The alias created is alias $1 -> channel channel = $1, to allow +for sending to channel using the main channel command.

    +
    +
    + +
    +
    +remove_alias(alias, **kwargs)[source]
    +

    Remove an alias from a channel.

    +
    +
    Parameters
    +

    alias (str, optional) – The alias to remove. +The channel will be reverse-determined from the +alias, if it exists.

    +
    +
    Returns
    +

    bool, str

    +
    +
    True, None if removal succeeded. If False,

    the second part is an error string.

    +
    +
    +

    **kwargs: If given, passed into nicks.get/add.

    +

    +
    +
    +
    +

    Note

    +

    This will remove two nicks - the plain channel alias and the templated +nick used for easily sending messages to the channel.

    +
    +
    + +
    +
    +get_channel_aliases(channel)[source]
    +

    Get a user’s aliases for a given channel. The user is retrieved +through self.caller.

    +
    +
    Parameters
    +

    channel (Channel) – The channel to act on.

    +
    +
    Returns
    +

    list – A list of zero, one or more alias-strings.

    +
    +
    +
    + +
    +
    +mute_channel(channel)[source]
    +

    Temporarily mute a channel.

    +
    +
    Parameters
    +

    channel (Channel) – The channel to alias.

    +
    +
    Returns
    +

    bool, str

    +
    +
    True, None if muting successful. If False,

    the second part is an error string.

    +
    +
    +

    +
    +
    +
    + +
    +
    +unmute_channel(channel)[source]
    +

    Unmute a channel.

    +
    +
    Parameters
    +

    channel (Channel) – The channel to alias.

    +
    +
    Returns
    +

    bool, str

    +
    +
    True, None if unmuting successful. If False,

    the second part is an error string.

    +
    +
    +

    +
    +
    +
    + +
    +
    +create_channel(name, description, typeclass=None, aliases=None)[source]
    +

    Create a new channel. Its name must not previously exist +(users can alias as needed). Will also connect to the +new channel.

    +
    +
    Parameters
    +
      +
    • name (str) – The new channel name/key.

    • +
    • description (str) – This is used in listings.

    • +
    • aliases (list) – A list of strings - alternative aliases for the channel +(not to be confused with per-user aliases; these are available for +everyone).

    • +
    +
    +
    Returns
    +

    channel, str

    +
    +
    new_channel, “” if creation successful. If False,

    the second part is an error string.

    +
    +
    +

    +
    +
    +
    + +
    +
    +destroy_channel(channel, message=None)[source]
    +

    Destroy an existing channel. Access should be checked before +calling this function.

    +
    +
    Parameters
    +
      +
    • channel (Channel) – The channel to alias.

    • +
    • message (str, optional) – Final message to send onto the channel +before destroying it. If not given, a default message is +used. Set to the empty string for no message.

    • +
    +
    +
    +
    +
    if typeclass:

    pass

    +
    +
    +
    + +
    +
    +set_lock(channel, lockstring)[source]
    +

    Set a lockstring on a channel. Permissions must have been +checked before this call.

    +
    +
    Parameters
    +
      +
    • channel (Channel) – The channel to operate on.

    • +
    • lockstring (str) – A lockstring on the form ‘type:lockfunc();…’

    • +
    +
    +
    Returns
    +

    bool, str

    +
    +
    True, None if setting lock was successful. If False,

    the second part is an error string.

    +
    +
    +

    +
    +
    +
    + +
    +
    +unset_lock(channel, lockstring)[source]
    +

    Remove locks in a lockstring on a channel. Permissions must have been +checked before this call.

    +
    +
    Parameters
    +
      +
    • channel (Channel) – The channel to operate on.

    • +
    • lockstring (str) – A lockstring on the form ‘type:lockfunc();…’

    • +
    +
    +
    Returns
    +

    bool, str

    +
    +
    True, None if setting lock was successful. If False,

    the second part is an error string.

    +
    +
    +

    +
    +
    +
    + +
    +
    +set_desc(channel, description)[source]
    +

    Set a channel description. This is shown in listings etc.

    +
    +
    Parameters
    +
      +
    • caller (Object or Account) – The entity performing the action.

    • +
    • channel (Channel) – The channel to operate on.

    • +
    • description (str) – A short description of the channel.

    • +
    +
    +
    Returns
    +

    bool, str

    +
    +
    True, None if setting lock was successful. If False,

    the second part is an error string.

    +
    +
    +

    +
    +
    +
    + +
    +
    +boot_user(channel, target, quiet=False, reason='')[source]
    +

    Boot a user from a channel, with optional reason. This will +also remove all their aliases for this channel.

    +
    +
    Parameters
    +
      +
    • channel (Channel) – The channel to operate on.

    • +
    • target (Object or Account) – The entity to boot.

    • +
    • quiet (bool, optional) – Whether or not to announce to channel.

    • +
    • reason (str, optional) – A reason for the boot.

    • +
    +
    +
    Returns
    +

    bool, str

    +
    +
    True, None if setting lock was successful. If False,

    the second part is an error string.

    +
    +
    +

    +
    +
    +
    + +
    +
    +ban_user(channel, target, quiet=False, reason='')[source]
    +

    Ban a user from a channel, by locking them out. This will also +boot them, if they are currently connected.

    +
    +
    Parameters
    +
      +
    • channel (Channel) – The channel to operate on.

    • +
    • target (Object or Account) – The entity to ban

    • +
    • quiet (bool, optional) – Whether or not to announce to channel.

    • +
    • reason (str, optional) – A reason for the ban

    • +
    +
    +
    Returns
    +

    bool, str

    +
    +
    True, None if banning was successful. If False,

    the second part is an error string.

    +
    +
    +

    +
    +
    +
    + +
    +
    +unban_user(channel, target)[source]
    +

    Un-Ban a user from a channel. This will not reconnect them +to the channel, just allow them to connect again (assuming +they have the suitable ‘listen’ lock like everyone else).

    +
    +
    Parameters
    +
      +
    • channel (Channel) – The channel to operate on.

    • +
    • target (Object or Account) – The entity to unban

    • +
    +
    +
    Returns
    +

    bool, str

    +
    +
    True, None if unbanning was successful. If False,

    the second part is an error string.

    +
    +
    +

    +
    +
    +
    + +
    +
    +channel_list_bans(channel)[source]
    +

    Show a channel’s bans.

    +
    +
    Parameters
    +

    channel (Channel) – The channel to operate on.

    +
    +
    Returns
    +

    list – A list of strings, each the name of a banned user.

    +
    +
    +
    + +
    +
    +channel_list_who(channel)[source]
    +

    Show a list of online people is subscribing to a channel. This will check +the ‘control’ permission of caller to determine if only online users +should be returned or everyone.

    +
    +
    Parameters
    +

    channel (Channel) – The channel to operate on.

    +
    +
    Returns
    +

    list

    +
    +
    A list of prepared strings, with name + markers for if they are

    muted or offline.

    +
    +
    +

    +
    +
    +
    + +
    +
    +list_channels(channelcls=<class 'evennia.comms.comms.DefaultChannel'>)[source]
    +

    Return a available channels.

    +
    +
    Parameters
    +

    channelcls (Channel, optional) – The channel-class to query on. Defaults +to the default channel class from settings.

    +
    +
    Returns
    +

    tuple

    +
    +
    A tuple (subbed_chans, available_chans) with the channels

    currently subscribed to, and those we have ‘listen’ access to but +don’t actually sub to yet.

    +
    +
    +

    +
    +
    +
    + +
    +
    +display_subbed_channels(subscribed)[source]
    +

    Display channels subscribed to.

    +
    +
    Parameters
    +

    subscribed (list) – List of subscribed channels

    +
    +
    Returns
    +

    EvTable – Table to display.

    +
    +
    +
    + +
    +
    +display_all_channels(subscribed, available)[source]
    +

    Display all available channels

    +
    +
    Parameters
    +

    subscribed (list) – List of subscribed channels

    +
    +
    Returns
    +

    EvTable – Table to display.

    +
    +
    +
    + +
    +
    +func()[source]
    +

    Main functionality of command.

    +
    + +
    +
    +lock_storage = 'cmd:not pperm(channel_banned);admin:all();manage:all();changelocks:perm(Admin)'
    +
    + +
    +
    +search_index_entry = {'aliases': 'channels chan', 'category': 'comms', 'key': 'channel', 'tags': '', 'text': "\n Use and manage in-game channels.\n\n Usage:\n channel channelname <msg>\n channel channel name = <msg>\n channel (show all subscription)\n channel/all (show available channels)\n channel/alias channelname = alias[;alias...]\n channel/unalias alias\n channel/who channelname\n channel/history channelname [= index]\n channel/sub channelname [= alias[;alias...]]\n channel/unsub channelname[,channelname, ...]\n channel/mute channelname[,channelname,...]\n channel/unmute channelname[,channelname,...]\n\n channel/create channelname[;alias;alias[:typeclass]] [= description]\n channel/destroy channelname [= reason]\n channel/desc channelname = description\n channel/lock channelname = lockstring\n channel/unlock channelname = lockstring\n channel/ban channelname (list bans)\n channel/ban[/quiet] channelname[, channelname, ...] = subscribername [: reason]\n channel/unban[/quiet] channelname[, channelname, ...] = subscribername\n channel/boot[/quiet] channelname[,channelname,...] = subscribername [: reason]\n\n # subtopics\n\n ## sending\n\n Usage: channel channelname msg\n channel channel name = msg (with space in channel name)\n\n This sends a message to the channel. Note that you will rarely use this\n command like this; instead you can use the alias\n\n channelname <msg>\n channelalias <msg>\n\n For example\n\n public Hello World\n pub Hello World\n\n (this shortcut doesn't work for aliases containing spaces)\n\n See channel/alias for help on setting channel aliases.\n\n ## alias and unalias\n\n Usage: channel/alias channel = alias[;alias[;alias...]]\n channel/unalias alias\n channel - this will list your subs and aliases to each channel\n\n Set one or more personal aliases for referencing a channel. For example:\n\n channel/alias warrior's guild = warrior;wguild;warchannel;warrior guild\n\n You can now send to the channel using all of these:\n\n warrior's guild Hello\n warrior Hello\n wguild Hello\n warchannel Hello\n\n Note that this will not work if the alias has a space in it. So the\n 'warrior guild' alias must be used with the `channel` command:\n\n channel warrior guild = Hello\n\n Channel-aliases can be removed one at a time, using the '/unalias' switch.\n\n ## who\n\n Usage: channel/who channelname\n\n List the channel's subscribers. Shows who are currently offline or are\n muting the channel. Subscribers who are 'muting' will not see messages sent\n to the channel (use channel/mute to mute a channel).\n\n ## history\n\n Usage: channel/history channel [= index]\n\n This will display the last |c20|n lines of channel history. By supplying an\n index number, you will step that many lines back before viewing those 20 lines.\n\n For example:\n\n channel/history public = 35\n\n will go back 35 lines and show the previous 20 lines from that point (so\n lines -35 to -55).\n\n ## sub and unsub\n\n Usage: channel/sub channel [=alias[;alias;...]]\n channel/unsub channel\n\n This subscribes you to a channel and optionally assigns personal shortcuts\n for you to use to send to that channel (see aliases). When you unsub, all\n your personal aliases will also be removed.\n\n ## mute and unmute\n\n Usage: channel/mute channelname\n channel/unmute channelname\n\n Muting silences all output from the channel without actually\n un-subscribing. Other channel members will see that you are muted in the /who\n list. Sending a message to the channel will automatically unmute you.\n\n ## create and destroy\n\n Usage: channel/create channelname[;alias;alias[:typeclass]] [= description]\n channel/destroy channelname [= reason]\n\n Creates a new channel (or destroys one you control). You will automatically\n join the channel you create and everyone will be kicked and loose all aliases\n to a destroyed channel.\n\n ## lock and unlock\n\n Usage: channel/lock channelname = lockstring\n channel/unlock channelname = lockstring\n\n Note: this is an admin command.\n\n A lockstring is on the form locktype:lockfunc(). Channels understand three\n locktypes:\n listen - who may listen or join the channel.\n send - who may send messages to the channel\n control - who controls the channel. This is usually the one creating\n the channel.\n\n Common lockfuncs are all() and perm(). To make a channel everyone can\n listen to but only builders can talk on, use this:\n\n listen:all()\n send: perm(Builders)\n\n ## boot and ban\n\n Usage:\n channel/boot[/quiet] channelname[,channelname,...] = subscribername [: reason]\n channel/ban channelname[, channelname, ...] = subscribername [: reason]\n channel/unban channelname[, channelname, ...] = subscribername\n channel/unban channelname\n channel/ban channelname (list bans)\n\n Booting will kick a named subscriber from channel(s) temporarily. The\n 'reason' will be passed to the booted user. Unless the /quiet switch is\n used, the channel will also be informed of the action. A booted user is\n still able to re-connect, but they'll have to set up their aliases again.\n\n Banning will blacklist a user from (re)joining the provided channels. It\n will then proceed to boot them from those channels if they were connected.\n The 'reason' and `/quiet` works the same as for booting.\n\n Example:\n boot mychannel1 = EvilUser : Kicking you to cool down a bit.\n ban mychannel1,mychannel2= EvilUser : Was banned for spamming.\n\n "}
    +
    + +
    +
    class evennia.commands.default.comms.CmdAddCom(**kwargs)[source]
    -

    Bases: evennia.commands.default.muxcommand.MuxCommand

    -

    add a channel alias and/or subscribe to a channel

    +

    Bases: evennia.commands.default.comms.CmdChannel

    +

    Add a channel alias and/or subscribe to a channel

    Usage:

    addcom [alias=] <channel>

    @@ -64,7 +744,7 @@ aliases to an already joined channel.

    -aliases = ['chanalias', 'aliaschan']
    +aliases = ['aliaschan', 'chanalias']
    @@ -93,12 +773,17 @@ aliases to an already joined channel.

    lock_storage = 'cmd:not pperm(channel_banned)'
    +
    +
    +search_index_entry = {'aliases': 'aliaschan chanalias', 'category': 'comms', 'key': 'addcom', 'tags': '', 'text': '\n Add a channel alias and/or subscribe to a channel\n\n Usage:\n addcom [alias=] <channel>\n\n Joins a given channel. If alias is given, this will allow you to\n refer to the channel by this alias rather than the full channel\n name. Subsequent calls of this command can be used to add multiple\n aliases to an already joined channel.\n '}
    +
    +
    class evennia.commands.default.comms.CmdDelCom(**kwargs)[source]
    -

    Bases: evennia.commands.default.muxcommand.MuxCommand

    +

    Bases: evennia.commands.default.comms.CmdChannel

    remove a channel alias and/or unsubscribe from channel

    Usage:

    delcom <alias or channel> @@ -116,7 +801,7 @@ for that channel.

    -aliases = ['delchanalias', 'delaliaschan']
    +aliases = ['delaliaschan', 'delchanalias']
    @@ -145,12 +830,17 @@ for that channel.

    lock_storage = 'cmd:not perm(channel_banned)'
    +
    +
    +search_index_entry = {'aliases': 'delaliaschan delchanalias', 'category': 'comms', 'key': 'delcom', 'tags': '', 'text': "\n remove a channel alias and/or unsubscribe from channel\n\n Usage:\n delcom <alias or channel>\n delcom/all <channel>\n\n If the full channel name is given, unsubscribe from the\n channel. If an alias is given, remove the alias but don't\n unsubscribe. If the 'all' switch is used, remove all aliases\n for that channel.\n "}
    +
    +
    class evennia.commands.default.comms.CmdAllCom(**kwargs)[source]
    -

    Bases: evennia.commands.default.muxcommand.MuxCommand

    +

    Bases: evennia.commands.default.comms.CmdChannel

    perform admin operations on all channels

    Usage:

    allcom [on | off | who | destroy]

    @@ -165,6 +855,11 @@ channels that you control.

    key = 'allcom'
    +
    +
    +aliases = []
    +
    +
    locks = 'cmd: not pperm(channel_banned)'
    @@ -186,66 +881,14 @@ channels that you control.

    Runs the function

    -
    -
    -aliases = []
    -
    -
    lock_storage = 'cmd: not pperm(channel_banned)'
    -
    - -
    -
    -class evennia.commands.default.comms.CmdChannels(**kwargs)[source]
    -

    Bases: evennia.commands.default.muxcommand.MuxCommand

    -

    list all channels available to you

    -
    -
    Usage:

    channels -clist -comlist

    -
    -
    -

    Lists all channels available to you, whether you listen to them or not. -Use ‘comlist’ to only view your current channel subscriptions. -Use addcom/delcom to join and leave channels

    -
    -key = 'channels'
    -
    - -
    -
    -aliases = ['chanlist', 'all channels', 'clist', 'comlist', 'channellist']
    -
    - -
    -
    -help_category = 'comms'
    -
    - -
    -
    -locks = 'cmd: not pperm(channel_banned)'
    -
    - -
    -
    -account_caller = True
    -
    - -
    -
    -func()[source]
    -

    Implement function

    -
    - -
    -
    -lock_storage = 'cmd: not pperm(channel_banned)'
    +
    +search_index_entry = {'aliases': '', 'category': 'comms', 'key': 'allcom', 'tags': '', 'text': "\n perform admin operations on all channels\n\n Usage:\n allcom [on | off | who | destroy]\n\n Allows the user to universally turn off or on all channels they are on, as\n well as perform a 'who' for all channels they are on. Destroy deletes all\n channels that you control.\n\n Without argument, works like comlist.\n "}
    @@ -253,7 +896,7 @@ Use addcom/delcom to join and leave channels

    class evennia.commands.default.comms.CmdCdestroy(**kwargs)[source]
    -

    Bases: evennia.commands.default.muxcommand.MuxCommand

    +

    Bases: evennia.commands.default.comms.CmdChannel

    destroy a channel you created

    Usage:

    cdestroy <channel>

    @@ -265,6 +908,11 @@ Use addcom/delcom to join and leave channels

    key = 'cdestroy'
    +
    +
    +aliases = []
    +
    +
    help_category = 'comms'
    @@ -287,13 +935,13 @@ Use addcom/delcom to join and leave channels

    -
    -aliases = []
    +
    +lock_storage = 'cmd: not pperm(channel_banned)'
    -
    -lock_storage = 'cmd: not pperm(channel_banned)'
    +
    +search_index_entry = {'aliases': '', 'category': 'comms', 'key': 'cdestroy', 'tags': '', 'text': '\n destroy a channel you created\n\n Usage:\n cdestroy <channel>\n\n Destroys a channel that you control.\n '}
    @@ -301,7 +949,7 @@ Use addcom/delcom to join and leave channels

    class evennia.commands.default.comms.CmdCBoot(**kwargs)[source]
    -

    Bases: evennia.commands.default.muxcommand.MuxCommand

    +

    Bases: evennia.commands.default.comms.CmdChannel

    kick an account from a channel you control

    Usage:

    cboot[/quiet] <channel> = <account> [:reason]

    @@ -315,6 +963,11 @@ Use addcom/delcom to join and leave channels

    key = 'cboot'
    +
    +
    +aliases = []
    +
    +
    switch_options = ('quiet',)
    @@ -341,72 +994,14 @@ Use addcom/delcom to join and leave channels

    implement the function

    -
    -
    -aliases = []
    -
    -
    lock_storage = 'cmd: not pperm(channel_banned)'
    -
    - -
    -
    -class evennia.commands.default.comms.CmdCemit(**kwargs)[source]
    -

    Bases: evennia.commands.default.muxcommand.MuxCommand

    -

    send an admin message to a channel you control

    -
    -
    Usage:

    cemit[/switches] <channel> = <message>

    -
    -
    Switches:

    sendername - attach the sender’s name before the message -quiet - don’t echo the message back to sender

    -
    -
    -

    Allows the user to broadcast a message over a channel as long as -they control it. It does not show the user’s name unless they -provide the /sendername switch.

    -
    -key = 'cemit'
    -
    - -
    -
    -aliases = ['cmsg']
    -
    - -
    -
    -switch_options = ('sendername', 'quiet')
    -
    - -
    -
    -locks = 'cmd: not pperm(channel_banned) and pperm(Player)'
    -
    - -
    -
    -help_category = 'comms'
    -
    - -
    -
    -account_caller = True
    -
    - -
    -
    -func()[source]
    -

    Implement function

    -
    - -
    -
    -lock_storage = 'cmd: not pperm(channel_banned) and pperm(Player)'
    +
    +search_index_entry = {'aliases': '', 'category': 'comms', 'key': 'cboot', 'tags': '', 'text': "\n kick an account from a channel you control\n\n Usage:\n cboot[/quiet] <channel> = <account> [:reason]\n\n Switch:\n quiet - don't notify the channel\n\n Kicks an account or object from a channel you control.\n\n "}
    @@ -414,7 +1009,7 @@ provide the /sendername switch.

    class evennia.commands.default.comms.CmdCWho(**kwargs)[source]
    -

    Bases: evennia.commands.default.muxcommand.MuxCommand

    +

    Bases: evennia.commands.default.comms.CmdChannel

    show who is listening to a channel

    Usage:

    cwho <channel>

    @@ -426,6 +1021,11 @@ provide the /sendername switch.

    key = 'cwho'
    +
    +
    +aliases = []
    +
    +
    locks = 'cmd: not pperm(channel_banned)'
    @@ -448,13 +1048,13 @@ provide the /sendername switch.

    -
    -aliases = []
    +
    +lock_storage = 'cmd: not pperm(channel_banned)'
    -
    -lock_storage = 'cmd: not pperm(channel_banned)'
    +
    +search_index_entry = {'aliases': '', 'category': 'comms', 'key': 'cwho', 'tags': '', 'text': '\n show who is listening to a channel\n\n Usage:\n cwho <channel>\n\n List who is connected to a given channel you have access to.\n '}
    @@ -462,7 +1062,7 @@ provide the /sendername switch.

    class evennia.commands.default.comms.CmdChannelCreate(**kwargs)[source]
    -

    Bases: evennia.commands.default.muxcommand.MuxCommand

    +

    Bases: evennia.commands.default.comms.CmdChannel

    create a new channel

    Usage:

    ccreate <new channel>[;alias;alias…] = description

    @@ -505,12 +1105,17 @@ provide the /sendername switch.

    lock_storage = 'cmd:not pperm(channel_banned) and pperm(Player)'
    +
    +
    +search_index_entry = {'aliases': 'channelcreate', 'category': 'comms', 'key': 'ccreate', 'tags': '', 'text': '\n create a new channel\n\n Usage:\n ccreate <new channel>[;alias;alias...] = description\n\n Creates a new channel owned by you.\n '}
    +
    +
    class evennia.commands.default.comms.CmdClock(**kwargs)[source]
    -

    Bases: evennia.commands.default.muxcommand.MuxCommand

    +

    Bases: evennia.commands.default.comms.CmdChannel

    change channel locks of a channel you control

    Usage:

    clock <channel> [= <lockstring>]

    @@ -524,13 +1129,13 @@ lockstring was given, view the current lock definitions.

    -
    -locks = 'cmd:not pperm(channel_banned)'
    +
    +aliases = []
    -
    -aliases = []
    +
    +locks = 'cmd:not pperm(channel_banned) and perm(Admin)'
    @@ -551,7 +1156,12 @@ lockstring was given, view the current lock definitions.

    -lock_storage = 'cmd:not pperm(channel_banned)'
    +lock_storage = 'cmd:not pperm(channel_banned) and perm(Admin)' +
    + +
    +
    +search_index_entry = {'aliases': '', 'category': 'comms', 'key': 'clock', 'tags': '', 'text': '\n change channel locks of a channel you control\n\n Usage:\n clock <channel> [= <lockstring>]\n\n Changes the lock access restrictions of a channel. If no\n lockstring was given, view the current lock definitions.\n '}
    @@ -559,7 +1169,7 @@ lockstring was given, view the current lock definitions.

    class evennia.commands.default.comms.CmdCdesc(**kwargs)[source]
    -

    Bases: evennia.commands.default.muxcommand.MuxCommand

    +

    Bases: evennia.commands.default.comms.CmdChannel

    describe a channel you control

    Usage:

    cdesc <channel> = <description>

    @@ -572,6 +1182,11 @@ channel lists.

    key = 'cdesc'
    +
    +
    +aliases = []
    +
    +
    locks = 'cmd:not pperm(channel_banned)'
    @@ -594,13 +1209,13 @@ channel lists.

    -
    -aliases = []
    +
    +lock_storage = 'cmd:not pperm(channel_banned)'
    -
    -lock_storage = 'cmd:not pperm(channel_banned)'
    +
    +search_index_entry = {'aliases': '', 'category': 'comms', 'key': 'cdesc', 'tags': '', 'text': '\n describe a channel you control\n\n Usage:\n cdesc <channel> = <description>\n\n Changes the description of the channel as shown in\n channel lists.\n\n '}
    @@ -611,16 +1226,18 @@ channel lists.

    Bases: evennia.commands.default.muxcommand.MuxCommand

    send a private message to another account

    -
    Usage:

    page[/switches] [<account>,<account>,… = <message>] +

    Usage:

    page <account> <message> +page[/switches] [<account>,<account>,… = <message>] tell ‘’ page <number>

    -
    Switch:

    last - shows who you last messaged +

    Switches:

    last - shows who you last messaged list - show your last <number> of tells/pages (default)

    -

    Send a message to target user (if online). If no -argument is given, you will get a list of your latest messages.

    +

    Send a message to target user (if online). If no argument is given, you +will get a list of your latest messages. The equal sign is needed for +multiple targets or if sending to target with space in the name.

    key = 'page'
    @@ -662,6 +1279,11 @@ argument is given, you will get a list of your latest messages.

    lock_storage = 'cmd:not pperm(page_banned)'
    +
    +
    +search_index_entry = {'aliases': 'tell', 'category': 'comms', 'key': 'page', 'tags': '', 'text': "\n send a private message to another account\n\n Usage:\n page <account> <message>\n page[/switches] [<account>,<account>,... = <message>]\n tell ''\n page <number>\n\n Switches:\n last - shows who you last messaged\n list - show your last <number> of tells/pages (default)\n\n Send a message to target user (if online). If no argument is given, you\n will get a list of your latest messages. The equal sign is needed for\n multiple targets or if sending to target with space in the name.\n\n "}
    +
    +
    @@ -701,7 +1323,7 @@ The bot will relay everything said in the evennia channel to the IRC channel and vice versa. The bot will automatically connect at server start, so this command need only be given once. The /disconnect switch will permanently delete the bot. To only -temporarily deactivate it, use the |wservices|n command instead. +temporarily deactivate it, use the |wservices|n command instead. Provide an optional bot class path to use a custom bot.

    @@ -739,6 +1361,11 @@ Provide an optional bot class path to use a custom bot.

    lock_storage = 'cmd:serversetting(IRC_ENABLED) and pperm(Developer)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'comms', 'key': 'irc2chan', 'tags': '', 'text': '\n Link an evennia channel to an external IRC channel\n\n Usage:\n irc2chan[/switches] <evennia_channel> = <ircnetwork> <port> <#irchannel> <botname>[:typeclass]\n irc2chan/delete botname|#dbid\n\n Switches:\n /delete - this will delete the bot and remove the irc connection\n to the channel. Requires the botname or #dbid as input.\n /remove - alias to /delete\n /disconnect - alias to /delete\n /list - show all irc<->evennia mappings\n /ssl - use an SSL-encrypted connection\n\n Example:\n irc2chan myircchan = irc.dalnet.net 6667 #mychannel evennia-bot\n irc2chan public = irc.freenode.net 6667 #evgaming #evbot:accounts.mybot.MyBot\n\n This creates an IRC bot that connects to a given IRC network and\n channel. If a custom typeclass path is given, this will be used\n instead of the default bot class.\n The bot will relay everything said in the evennia channel to the\n IRC channel and vice versa. The bot will automatically connect at\n server start, so this command need only be given once. The\n /disconnect switch will permanently delete the bot. To only\n temporarily deactivate it, use the |wservices|n command instead.\n Provide an optional bot class path to use a custom bot.\n '}
    +
    +
    @@ -747,7 +1374,7 @@ Provide an optional bot class path to use a custom bot.

    Bases: evennia.commands.default.muxcommand.MuxCommand

    Check and reboot IRC bot.

    -
    Usage:

    ircstatus [#dbref ping||nicklist||reconnect]

    +
    Usage:

    ircstatus [#dbref ping | nicklist | reconnect]

    If not given arguments, will return a list of all bots (like @@ -790,6 +1417,11 @@ messages sent to either channel will be lost.

    lock_storage = 'cmd:serversetting(IRC_ENABLED) and perm(ircstatus) or perm(Builder))'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'comms', 'key': 'ircstatus', 'tags': '', 'text': "\n Check and reboot IRC bot.\n\n Usage:\n ircstatus [#dbref ping | nicklist | reconnect]\n\n If not given arguments, will return a list of all bots (like\n irc2chan/list). The 'ping' argument will ping the IRC network to\n see if the connection is still responsive. The 'nicklist' argument\n (aliases are 'who' and 'users') will return a list of users on the\n remote IRC channel. Finally, 'reconnect' will force the client to\n disconnect and reconnect again. This may be a last resort if the\n client has silently lost connection (this may happen if the remote\n network experience network issues). During the reconnection\n messages sent to either channel will be lost.\n\n "}
    +
    +
    @@ -862,6 +1494,11 @@ to identify the connection uniquely.

    lock_storage = 'cmd:serversetting(RSS_ENABLED) and pperm(Developer)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'comms', 'key': 'rss2chan', 'tags': '', 'text': '\n link an evennia channel to an external RSS feed\n\n Usage:\n rss2chan[/switches] <evennia_channel> = <rss_url>\n\n Switches:\n /disconnect - this will stop the feed and remove the connection to the\n channel.\n /remove - "\n /list - show all rss->evennia mappings\n\n Example:\n rss2chan rsschan = http://code.google.com/feeds/p/evennia/updates/basic\n\n This creates an RSS reader that connects to a given RSS feed url. Updates\n will be echoed as a title and news link to the given channel. The rate of\n updating is set with the RSS_UPDATE_INTERVAL variable in settings (default\n is every 10 minutes).\n\n When disconnecting you need to supply both the channel and url again so as\n to identify the connection uniquely.\n '}
    +
    +
    @@ -935,6 +1572,11 @@ must be added to game settings.

    lock_storage = 'cmd:serversetting(GRAPEVINE_ENABLED) and pperm(Developer)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'comms', 'key': 'grapevine2chan', 'tags': '', 'text': '\n Link an Evennia channel to an exteral Grapevine channel\n\n Usage:\n grapevine2chan[/switches] <evennia_channel> = <grapevine_channel>\n grapevine2chan/disconnect <connection #id>\n\n Switches:\n /list - (or no switch): show existing grapevine <-> Evennia\n mappings and available grapevine chans\n /remove - alias to disconnect\n /delete - alias to disconnect\n\n Example:\n grapevine2chan mygrapevine = gossip\n\n This creates a link between an in-game Evennia channel and an external\n Grapevine channel. The game must be registered with the Grapevine network\n (register at https://grapevine.haus) and the GRAPEVINE_* auth information\n must be added to game settings.\n '}
    +
    +
    @@ -982,7 +1624,6 @@ must be added to game settings.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.commands.default.general.html b/docs/0.9.5/api/evennia.commands.default.general.html index 1006cc4b7e..32ca2f06dc 100644 --- a/docs/0.9.5/api/evennia.commands.default.general.html +++ b/docs/0.9.5/api/evennia.commands.default.general.html @@ -86,6 +86,11 @@ lock_storage = 'cmd:perm(home) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'home', 'tags': '', 'text': "\n move to your character's home location\n\n Usage:\n home\n\n Teleports you to your home location.\n "}
    +
    +
    @@ -107,7 +112,7 @@ look *<account&g
    -aliases = ['l', 'ls']
    +aliases = ['ls', 'l']
    @@ -136,6 +141,11 @@ look *<account&g lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'ls l', 'category': 'general', 'key': 'look', 'tags': '', 'text': '\n look at location or object\n\n Usage:\n look\n look <obj>\n look *<account>\n\n Observes your location or objects in your vicinity.\n '}
    +
    +
    @@ -225,6 +235,11 @@ for everyone to use, you need build privileges and the alias command.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'nicks nickname', 'category': 'general', 'key': 'nick', 'tags': '', 'text': '\n define a personal alias/nick by defining a string to\n match and replace it with another on the fly\n\n Usage:\n nick[/switches] <string> [= [replacement_string]]\n nick[/switches] <template> = <replacement_template>\n nick/delete <string> or number\n nicks\n\n Switches:\n inputline - replace on the inputline (default)\n object - replace on object-lookup\n account - replace on account-lookup\n list - show all defined aliases (also "nicks" works)\n delete - remove nick by index in /list\n clearall - clear all nicks\n\n Examples:\n nick hi = say Hello, I\'m Sarah!\n nick/object tom = the tall man\n nick build $1 $2 = create/drop $1;$2\n nick tell $1 $2=page $1=$2\n nick tm?$1=page tallman=$1\n nick tm\\=$1=page tallman=$1\n\n A \'nick\' is a personal string replacement. Use $1, $2, ... to catch arguments.\n Put the last $-marker without an ending space to catch all remaining text. You\n can also use unix-glob matching for the left-hand side <string>:\n\n * - matches everything\n ? - matches 0 or 1 single characters\n [abcd] - matches these chars in any order\n [!abcd] - matches everything not among these chars\n \\= - escape literal \'=\' you want in your <string>\n\n Note that no objects are actually renamed or changed by this command - your nicks\n are only available to you. If you want to permanently add keywords to an object\n for everyone to use, you need build privileges and the alias command.\n\n '}
    +
    +
    @@ -245,7 +260,7 @@ inv

    -aliases = ['inv', 'i']
    +aliases = ['i', 'inv']
    @@ -274,6 +289,11 @@ inv

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'i inv', 'category': 'general', 'key': 'inventory', 'tags': '', 'text': '\n view inventory\n\n Usage:\n inventory\n inv\n\n Shows your inventory.\n '}
    +
    +
    @@ -324,6 +344,11 @@ look at you.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'setdesc', 'tags': '', 'text': '\n describe yourself\n\n Usage:\n setdesc <description>\n\n Add a description to yourself. This\n will be visible to people when they\n look at you.\n '}
    +
    +
    @@ -349,7 +374,7 @@ your inventory.

    -locks = 'cmd:all()'
    +locks = 'cmd:all();view:perm(Developer);read:perm(Developer)'
    @@ -370,7 +395,12 @@ your inventory.

    -lock_storage = 'cmd:all()'
    +lock_storage = 'cmd:all();view:perm(Developer);read:perm(Developer)' +
    + +
    +
    +search_index_entry = {'aliases': 'grab', 'category': 'general', 'key': 'get', 'tags': '', 'text': '\n pick up something\n\n Usage:\n get <obj>\n\n Picks up an object from your location and puts it in\n your inventory.\n '}
    @@ -422,6 +452,11 @@ location you are currently in.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'drop', 'tags': '', 'text': '\n drop something\n\n Usage:\n drop <obj>\n\n Lets you drop an object from your inventory into the\n location you are currently in.\n '}
    +
    +
    @@ -476,6 +511,11 @@ placing it in their inventory.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'give', 'tags': '', 'text': '\n give away something to someone\n\n Usage:\n give <inventory obj> <to||=> <target>\n\n Gives an items from your inventory to another character,\n placing it in their inventory.\n '}
    +
    +
    @@ -495,7 +535,7 @@ placing it in their inventory.

    -aliases = ['"', "'"]
    +aliases = ["'", '"']
    @@ -519,6 +559,11 @@ placing it in their inventory.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '\' "', 'category': 'general', 'key': 'say', 'tags': '', 'text': '\n speak as your character\n\n Usage:\n say <message>\n\n Talk to those in your current location.\n '}
    +
    +
    @@ -564,6 +609,11 @@ others in the room being informed.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'whisper', 'tags': '', 'text': '\n Speak privately as your character to another\n\n Usage:\n whisper <character> = <message>\n whisper <char1>, <char2> = <message>\n\n Talk privately to one or more characters in your current location, without\n others in the room being informed.\n '}
    +
    +
    @@ -625,6 +675,11 @@ space.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'emote :', 'category': 'general', 'key': 'pose', 'tags': '', 'text': "\n strike a pose\n\n Usage:\n pose <pose text>\n pose's <pose text>\n\n Example:\n pose is standing by the wall, smiling.\n -> others will see:\n Tom is standing by the wall, smiling.\n\n Describe an action being taken. The pose text will\n automatically begin with your name.\n "}
    +
    +
    @@ -674,6 +729,11 @@ which permission groups you are a member of.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'hierarchy groups', 'category': 'general', 'key': 'access', 'tags': '', 'text': '\n show your current game access\n\n Usage:\n access\n\n This command shows you the permission hierarchy and\n which permission groups you are a member of.\n '}
    +
    + @@ -721,7 +781,6 @@ which permission groups you are a member of.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.commands.default.help.html b/docs/0.9.5/api/evennia.commands.default.help.html index aa85f5334f..2fade13158 100644 --- a/docs/0.9.5/api/evennia.commands.default.help.html +++ b/docs/0.9.5/api/evennia.commands.default.help.html @@ -39,24 +39,26 @@

    evennia.commands.default.help

    -

    The help command. The basic idea is that help texts for commands -are best written by those that write the commands - the admins. So -command-help is all auto-loaded and searched from the current command -set. The normal, database-tied help system is used for collaborative -creation of other help topics such as RP help or game-world aides.

    +

    The help command. The basic idea is that help texts for commands are best +written by those that write the commands - the developers. So command-help is +all auto-loaded and searched from the current command set. The normal, +database-tied help system is used for collaborative creation of other help +topics such as RP help or game-world aides. Help entries can also be created +outside the game in modules given by **settings.FILE_HELP_ENTRY_MODULES**.

    class evennia.commands.default.help.CmdHelp(**kwargs)[source]

    Bases: evennia.commands.default.muxcommand.MuxCommand

    -

    View help or a list of topics

    +

    Get help.

    -
    Usage:

    help <topic or command> -help list -help all

    +
    Usage:

    help +help <topic, command or category> +help <topic>/<subtopic> +help <topic>/<subtopic>/<subsubtopic> …

    -

    This will search for help on commands and other -topics related to the game.

    +

    Use the ‘help’ command alone to see an index of all help topics, organized +by category.eSome big topics may offer additional sub-topics.

    key = 'help'
    @@ -87,6 +89,21 @@ topics related to the game.

    help_more = True
    +
    +
    +index_type_separator_clr = '|w'
    +
    + +
    +
    +index_category_clr = '|W'
    +
    + +
    +
    +index_topic_clr = '|G'
    +
    +
    suggestion_cutoff = 0.6
    @@ -97,6 +114,16 @@ topics related to the game.

    suggestion_maxnum = 5
    +
    +
    +subtopic_separator_char = '/'
    +
    + +
    +
    +clickable_topics = True
    +
    +
    msg_help(text)[source]
    @@ -107,73 +134,147 @@ help window

    -static format_help_entry(title, help_text, aliases=None, suggested=None)[source]
    +format_help_entry(topic='', help_text='', aliases=None, suggested=None, subtopics=None, click_topics=True)[source]

    This visually formats the help entry. This method can be overriden to customize the way a help entry is displayed.

    Parameters
      -
    • title (str) – the title of the help entry.

    • -
    • help_text (str) – the text of the help entry.

    • -
    • aliases (list of str or None) – the list of aliases.

    • -
    • suggested (list of str or None) – suggested reading.

    • -
    -
    -
    -

    Returns the formatted string, ready to be sent.

    -
    - -
    -
    -static format_help_list(hdict_cmds, hdict_db)[source]
    -

    Output a category-ordered list. The input are the -pre-loaded help files for commands and database-helpfiles -respectively. You can override this method to return a -custom display of the list of commands and topics.

    -
    - -
    -
    -check_show_help(cmd, caller)[source]
    -

    Helper method. If this return True, the given cmd -auto-help will be viewable in the help listing. -Override this to easily select what is shown to -the account. Note that only commands available -in the caller’s merged cmdset are available.

    -
    -
    Parameters
    -
      -
    • cmd (Command) – Command class from the merged cmdset

    • -
    • caller (Character, Account or Session) – The current caller -executing the help command.

    • -
    -
    -
    -
    - -
    -
    -should_list_cmd(cmd, caller)[source]
    -

    Should the specified command appear in the help table?

    -

    This method only checks whether a specified command should -appear in the table of topics/commands. The command can be -used by the caller (see the ‘check_show_help’ method) and -the command will still be available, for instance, if a -character type ‘help name of the command’. However, if -you return False, the specified command will not appear in -the table. This is sometimes useful to “hide” commands in -the table, but still access them through the help system.

    -
    -
    Parameters
    -
      -
    • cmd – the command to be tested.

    • -
    • caller – the caller of the help system.

    • +
    • title (str, optional) – The title of the help entry.

    • +
    • help_text (str, optional) – Text of the help entry.

    • +
    • aliases (list, optional) – List of help-aliases (displayed in header).

    • +
    • suggested (list, optional) – Strings suggested reading (based on title).

    • +
    • subtopics (list, optional) – A list of strings - the subcategories available +for this entry.

    • +
    • click_topics (bool, optional) – Should help topics be clickable. Default is True.

    Returns
    -

    True – the command should appear in the table. -False: the command shouldn’t appear in the table.

    +

    help_message (str) – Help entry formated for console.

    +
    +
    +
    + +
    +
    +format_help_index(cmd_help_dict=None, db_help_dict=None, title_lone_category=False, click_topics=True)[source]
    +

    Output a category-ordered g for displaying the main help, grouped by +category.

    +
    +
    Parameters
    +
      +
    • cmd_help_dict (dict) – A dict {“category”: [topic, topic, …]} for +command-based help.

    • +
    • db_help_dict (dict) – A dict {“category”: [topic, topic], …]} for +database-based help.

    • +
    • title_lone_category (bool, optional) – If a lone category should +be titled with the category name or not. While pointless in a +general index, the title should probably show when explicitly +listing the category itself.

    • +
    • click_topics (bool, optional) – If help-topics are clickable or not +(for webclient or telnet clients with MXP support).

    • +
    +
    +
    Returns
    +

    str – The help index organized into a grid.

    +
    +
    +

    Notes

    +

    The input are the pre-loaded help files for commands and database-helpfiles +respectively. You can override this method to return a custom display of the list of +commands and topics.

    +
    + +
    +
    +can_read_topic(cmd_or_topic, caller)[source]
    +

    Helper method. If this return True, the given help topic +be viewable in the help listing. Note that even if this returns False, +the entry will still be visible in the help index unless should_list_topic +is also returning False.

    +
    +
    Parameters
    +
      +
    • cmd_or_topic (Command, HelpEntry or FileHelpEntry) – The topic/command to test.

    • +
    • caller – the caller checking for access.

    • +
    +
    +
    Returns
    +

    bool – If command can be viewed or not.

    +
    +
    +

    Notes

    +

    This uses the ‘read’ lock. If no ‘read’ lock is defined, the topic is assumed readable +by all.

    +
    + +
    +
    +can_list_topic(cmd_or_topic, caller)[source]
    +

    Should the specified command appear in the help table?

    +

    This method only checks whether a specified command should appear in the table of +topics/commands. The command can be used by the caller (see the ‘should_show_help’ method) +and the command will still be available, for instance, if a character type ‘help name of the +command’. However, if you return False, the specified command will not appear in the table. +This is sometimes useful to “hide” commands in the table, but still access them through the +help system.

    +
    +
    Parameters
    +
      +
    • cmd_or_topic (Command, HelpEntry or FileHelpEntry) – The topic/command to test.

    • +
    • caller – the caller checking for access.

    • +
    +
    +
    Returns
    +

    bool – If command should be listed or not.

    +
    +
    +

    Notes

    +

    By default, the ‘view’ lock will be checked, and if no such lock is defined, the ‘read’ +lock will be used. If neither lock is defined, the help entry is assumed to be +accessible to all.

    +
    + +
    +
    +collect_topics(caller, mode='list')[source]
    +

    Collect help topics from all sources (cmd/db/file).

    +
    +
    Parameters
    +
      +
    • caller (Object or Account) – The user of the Command.

    • +
    • mode (str) – One of ‘list’ or ‘query’, where the first means we are collecting to view +the help index and the second because of wanting to search for a specific help +entry/cmd to read. This determines which access should be checked.

    • +
    +
    +
    Returns
    +

    tuple – A tuple of three dicts containing the different types of help entries +in the order cmd-help, db-help, file-help:

    +
    +

    ({key: cmd,…}, {key: dbentry,…}, {key: fileentry,…}

    +
    +

    +
    +
    +
    + +
    + +

    Perform a help-query search, default using Lunr search engine.

    +
    +
    Parameters
    +
      +
    • query (str) – The help entry to search for.

    • +
    • entries (list) – All possibilities. A mix of commands, HelpEntries and FileHelpEntries.

    • +
    • search_fields (list) – A list of dicts defining how Lunr will find the +search data on the elements. If not given, will use a default.

    • +
    +
    +
    Returns
    +

    tuple – A tuple (match, suggestions).

    @@ -182,6 +283,13 @@ False: the command shouldn’t appear in the table.

    parse()[source]

    input is a string containing the command or topic to match.

    +

    The allowed syntax is

    +
    help <topic>[/<subtopic>[/<subtopic>[/...]]]
    +
    +
    +

    The database/command query is always for <topic>, and any subtopics +is then parsed from there. If a <topic> has spaces in it, it is +always matched before assuming the space begins a subtopic.

    @@ -200,12 +308,17 @@ False: the command shouldn’t appear in the table.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '?', 'category': 'general', 'key': 'help', 'tags': '', 'text': "\n Get help.\n\n Usage:\n help\n help <topic, command or category>\n help <topic>/<subtopic>\n help <topic>/<subtopic>/<subsubtopic> ...\n\n Use the 'help' command alone to see an index of all help topics, organized\n by category.eSome big topics may offer additional sub-topics.\n\n "}
    +
    +
    class evennia.commands.default.help.CmdSetHelp(**kwargs)[source]
    -

    Bases: evennia.commands.default.muxcommand.MuxCommand

    +

    Bases: evennia.commands.default.help.CmdHelp

    Edit the help database.

    Usage:

    help[/switches] <topic>[[;alias;alias][,category[,locks]] [= <text>]

    @@ -218,19 +331,53 @@ delete - remove help topic.

    Examples

    -

    sethelp throw = This throws something at … +

    sethelp lore = In the beginning was … sethelp/append pickpocketing,Thievery = This steals … sethelp/replace pickpocketing, ,attr(is_thief) = This steals … sethelp/edit thievery

    -

    This command manipulates the help database. A help entry can be created, -appended/merged to and deleted. If you don’t assign a category, the -“General” category will be used. If no lockstring is specified, default -is to let everyone read the help file.

    +

    If not assigning a category, the settings.DEFAULT_HELP_CATEGORY category +will be used. If no lockstring is specified, everyone will be able to read +the help entry. Sub-topics are embedded in the help text.

    +

    Note that this cannot modify command-help entries - these are modified +in-code, outside the game.

    +

    Subtopics helps to break up a long help entry into sub-sections. Users can +access subtopics with |whelp topic/subtopic/…|n Subtopics are created and +stored together with the main topic.

    +

    To start adding subtopics, add the text ‘# SUBTOPICS’ on a new line at the +end of your help text. After this you can now add any number of subtopics, +each starting with ‘## <subtopic-name>’ on a line, followed by the +help-text of that subtopic. +Use ‘### <subsub-name>’ to add a sub-subtopic and so on. Max depth is 5. A +subtopic’s title is case-insensitive and can consist of multiple words - +the user will be able to enter a partial match to access it.

    +

    For example:

    +
    +
    Main help text for <topic>
    +

    +
    # SUBTOPICS
    +

    +
    ## about
    +

    +
    Text for the ‘<topic>/about’ subtopic’
    +

    +
    ### more about-info
    +

    +
    Text for the ‘<topic>/about/more about-info sub-subtopic
    +

    +
    ## extra
    +

    +
    Text for the ‘<topic>/extra’ subtopic
    +
    key = 'sethelp'
    +
    +
    +aliases = []
    +
    +
    switch_options = ('edit', 'replace', 'append', 'extend', 'delete')
    @@ -246,6 +393,17 @@ is to let everyone read the help file.

    help_category = 'building'
    +
    +
    +arg_regex = None
    +
    + +
    +
    +parse()[source]
    +

    We want to use the default parser rather than the CmdHelp.parse

    +
    +
    func()[source]
    @@ -253,13 +411,13 @@ is to let everyone read the help file.

    -
    -aliases = []
    +
    +lock_storage = 'cmd:perm(Helper)'
    -
    -lock_storage = 'cmd:perm(Helper)'
    +
    +search_index_entry = {'aliases': '', 'category': 'building', 'key': 'sethelp', 'tags': '', 'text': "\n Edit the help database.\n\n Usage:\n help[/switches] <topic>[[;alias;alias][,category[,locks]] [= <text>]\n\n Switches:\n edit - open a line editor to edit the topic's help text.\n replace - overwrite existing help topic.\n append - add text to the end of existing topic with a newline between.\n extend - as append, but don't add a newline.\n delete - remove help topic.\n\n Examples:\n sethelp lore = In the beginning was ...\n sethelp/append pickpocketing,Thievery = This steals ...\n sethelp/replace pickpocketing, ,attr(is_thief) = This steals ...\n sethelp/edit thievery\n\n If not assigning a category, the `settings.DEFAULT_HELP_CATEGORY` category\n will be used. If no lockstring is specified, everyone will be able to read\n the help entry. Sub-topics are embedded in the help text.\n\n Note that this cannot modify command-help entries - these are modified\n in-code, outside the game.\n\n # SUBTOPICS\n\n ## Adding subtopics\n\n Subtopics helps to break up a long help entry into sub-sections. Users can\n access subtopics with |whelp topic/subtopic/...|n Subtopics are created and\n stored together with the main topic.\n\n To start adding subtopics, add the text '# SUBTOPICS' on a new line at the\n end of your help text. After this you can now add any number of subtopics,\n each starting with '## <subtopic-name>' on a line, followed by the\n help-text of that subtopic.\n Use '### <subsub-name>' to add a sub-subtopic and so on. Max depth is 5. A\n subtopic's title is case-insensitive and can consist of multiple words -\n the user will be able to enter a partial match to access it.\n\n For example:\n\n | Main help text for <topic>\n |\n | # SUBTOPICS\n |\n | ## about\n |\n | Text for the '<topic>/about' subtopic'\n |\n | ### more about-info\n |\n | Text for the '<topic>/about/more about-info sub-subtopic\n |\n | ## extra\n |\n | Text for the '<topic>/extra' subtopic\n\n "}
    @@ -309,7 +467,6 @@ is to let everyone read the help file.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.commands.default.html b/docs/0.9.5/api/evennia.commands.default.html index 805d9ac1e9..5083fe3afd 100644 --- a/docs/0.9.5/api/evennia.commands.default.html +++ b/docs/0.9.5/api/evennia.commands.default.html @@ -105,7 +105,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.commands.default.muxcommand.html b/docs/0.9.5/api/evennia.commands.default.muxcommand.html index 8fe210ea15..72d3c70322 100644 --- a/docs/0.9.5/api/evennia.commands.default.muxcommand.html +++ b/docs/0.9.5/api/evennia.commands.default.muxcommand.html @@ -184,6 +184,11 @@ to all the variables defined therein.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'command', 'tags': '', 'text': "\n This sets up the basis for a MUX command. The idea\n is that most other Mux-related commands should just\n inherit from this and don't have to implement much\n parsing of their own unless they do something particularly\n advanced.\n\n Note that the class's __doc__ string (this text) is\n used by Evennia to create the automatic help entry for\n the command, so make sure to document consistently here.\n "}
    +
    +
    @@ -224,6 +229,11 @@ character is actually attached to this Account and Session.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'command', 'tags': '', 'text': '\n This is an on-Account version of the MuxCommand. Since these commands sit\n on Accounts rather than on Characters/Objects, we need to check\n this in the parser.\n\n Account commands are available also when puppeting a Character, it\'s\n just that they are applied with a lower priority and are always\n available, also when disconnected from a character (i.e. "ooc").\n\n This class makes sure that caller is always an Account object, while\n creating a new property "character" that is set only if a\n character is actually attached to this Account and Session.\n '}
    +
    +
    @@ -271,7 +281,6 @@ character is actually attached to this Account and Session.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.commands.default.syscommands.html b/docs/0.9.5/api/evennia.commands.default.syscommands.html index 593891dbf0..b770197e48 100644 --- a/docs/0.9.5/api/evennia.commands.default.syscommands.html +++ b/docs/0.9.5/api/evennia.commands.default.syscommands.html @@ -89,6 +89,11 @@ the line is just added to the editor buffer).

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': '__noinput_command', 'tags': '', 'text': '\n This is called when there is no input given\n '}
    +
    +
    @@ -127,6 +132,11 @@ the line is just added to the editor buffer).

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': '__nomatch_command', 'tags': '', 'text': '\n No command was found matching the given input.\n '}
    +
    +
    @@ -175,118 +185,9 @@ the raw_cmdname is the cmdname unmodified by eventual prefix-st lock_storage = 'cmd:all()'
    - - -
    -
    -class evennia.commands.default.syscommands.SystemSendToChannel(**kwargs)[source]
    -

    Bases: evennia.commands.default.muxcommand.MuxCommand

    -

    This is a special command that the cmdhandler calls -when it detects that the command given matches -an existing Channel object key (or alias).

    -
    -key = '__send_to_channel_command'
    -
    - -
    -
    -locks = 'cmd:all()'
    -
    - -
    -
    -parse()[source]
    -

    This method is called by the cmdhandler once the command name -has been identified. It creates a new set of member variables -that can be later accessed from self.func() (see below)

    -

    The following variables are available for our use when entering this -method (from the command definition, and assigned on the fly by the -cmdhandler):

    -
    -

    self.key - the name of this command (‘look’) -self.aliases - the aliases of this cmd (‘l’) -self.permissions - permission string for this command -self.help_category - overall category of command

    -

    self.caller - the object calling this command -self.cmdstring - the actual command name used to call this

    -
    -
    -
    (this allows you to know which alias was used,

    for example)

    -
    -
    -
    -

    self.args - the raw input; everything following self.cmdstring. -self.cmdset - the cmdset from which this command was picked. Not

    -
    -

    often used (useful for commands like ‘help’ or to -list all available commands etc)

    -
    -
    -
    self.obj - the object on which this command was defined. It is often

    the same as self.caller.

    -
    -
    -
    -

    A MUX command has the following possible syntax:

    -
    -

    name[ with several words][/switch[/switch..]] arg1[,arg2,…] [[=|,] arg[,..]]

    -
    -

    The ‘name[ with several words]’ part is already dealt with by the -cmdhandler at this point, and stored in self.cmdname (we don’t use -it here). The rest of the command is stored in self.args, which can -start with the switch indicator /.

    -
    -
    Optional variables to aid in parsing, if set:
    -
    self.switch_options - (tuple of valid /switches expected by this

    command (without the /))

    -
    -
    self.rhs_split - Alternate string delimiter or tuple of strings

    to separate left/right hand sides. tuple form -gives priority split to first string delimiter.

    -
    -
    -
    -
    -

    This parser breaks self.args into its constituents and stores them in the -following variables:

    -
    -

    self.switches = [list of /switches (without the /)] -self.raw = This is the raw argument input, including switches -self.args = This is re-defined to be everything except the switches -self.lhs = Everything to the left of = (lhs:’left-hand side’). If

    -
    -

    no = is found, this is identical to self.args.

    -
    -
    -
    self.rhs: Everything to the right of = (rhs:’right-hand side’).

    If no ‘=’ is found, this is None.

    -
    -
    -

    self.lhslist - [self.lhs split into a list by comma] -self.rhslist - [list of self.rhs split into a list by comma] -self.arglist = [list of space-separated args (stripped, including ‘=’ if it exists)]

    -

    All args and list members are stripped of excess whitespace around the -strings, but case is preserved.

    -
    -
    - -
    -
    -func()[source]
    -

    Create a new message and send it to channel, using -the already formatted input.

    -
    - -
    -
    -aliases = []
    -
    - -
    -
    -help_category = 'general'
    -
    - -
    -
    -lock_storage = 'cmd:all()'
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': '__multimatch_command', 'tags': '', 'text': "\n Multiple command matches.\n\n The cmdhandler adds a special attribute 'matches' to this\n system command.\n\n matches = [(cmdname, args, cmdobj, cmdlen, mratio, raw_cmdname) , (cmdname, ...), ...]\n\n Here, `cmdname` is the command's name and `args` the rest of the incoming string,\n without said command name. `cmdobj` is the Command instance, the cmdlen is\n the same as len(cmdname) and mratio is a measure of how big a part of the\n full input string the cmdname takes up - an exact match would be 1.0. Finally,\n the `raw_cmdname` is the cmdname unmodified by eventual prefix-stripping.\n\n "}
    @@ -336,7 +237,6 @@ the already formatted input.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.commands.default.system.html b/docs/0.9.5/api/evennia.commands.default.system.html index c6d136efc0..aecb5d7352 100644 --- a/docs/0.9.5/api/evennia.commands.default.system.html +++ b/docs/0.9.5/api/evennia.commands.default.system.html @@ -83,6 +83,11 @@ reset to purge) and at_reload() hooks will be called.

    lock_storage = 'cmd:perm(reload) or perm(Developer)'
    +
    +
    +search_index_entry = {'aliases': 'restart', 'category': 'system', 'key': 'reload', 'tags': '', 'text': '\n reload the server\n\n Usage:\n reload [reason]\n\n This restarts the server. The Portal is not\n affected. Non-persistent scripts will survive a reload (use\n reset to purge) and at_reload() hooks will be called.\n '}
    +
    +
    @@ -135,6 +140,11 @@ cmdsets etc will be wiped.

    lock_storage = 'cmd:perm(reload) or perm(Developer)'
    +
    +
    +search_index_entry = {'aliases': 'reboot', 'category': 'system', 'key': 'reset', 'tags': '', 'text': '\n reset and reboot the server\n\n Usage:\n reset\n\n Notes:\n For normal updating you are recommended to use reload rather\n than this command. Use shutdown for a complete stop of\n everything.\n\n This emulates a cold reboot of the Server component of Evennia.\n The difference to shutdown is that the Server will auto-reboot\n and that it does not affect the Portal, so no users will be\n disconnected. Contrary to reload however, all shutdown hooks will\n be called and any non-database saved scripts, ndb-attributes,\n cmdsets etc will be wiped.\n\n '}
    +
    +
    @@ -178,6 +188,11 @@ cmdsets etc will be wiped.

    lock_storage = 'cmd:perm(shutdown) or perm(Developer)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'system', 'key': 'shutdown', 'tags': '', 'text': '\n stop the server completely\n\n Usage:\n shutdown [announcement]\n\n Gracefully shut down both Server and Portal.\n '}
    +
    +
    @@ -265,20 +280,30 @@ should only be accessible by trusted server admins/superusers.|n

    lock_storage = 'cmd:perm(py) or perm(Developer)'
    +
    +
    +search_index_entry = {'aliases': '!', 'category': 'system', 'key': 'py', 'tags': '', 'text': "\n execute a snippet of python code\n\n Usage:\n py [cmd]\n py/edit\n py/time <cmd>\n py/clientraw <cmd>\n py/noecho\n\n Switches:\n time - output an approximate execution time for <cmd>\n edit - open a code editor for multi-line code experimentation\n clientraw - turn off all client-specific escaping. Note that this may\n lead to different output depending on prototocol (such as angular brackets\n being parsed as HTML in the webclient but not in telnet clients)\n noecho - in Python console mode, turn off the input echo (e.g. if your client\n does this for you already)\n\n Without argument, open a Python console in-game. This is a full console,\n accepting multi-line Python code for testing and debugging. Type `exit()` to\n return to the game. If Evennia is reloaded, the console will be closed.\n\n Enter a line of instruction after the 'py' command to execute it\n immediately. Separate multiple commands by ';' or open the code editor\n using the /edit switch (all lines added in editor will be executed\n immediately when closing or using the execute command in the editor).\n\n A few variables are made available for convenience in order to offer access\n to the system (you can import more at execution time).\n\n Available variables in py environment:\n self, me : caller\n here : caller.location\n evennia : the evennia API\n inherits_from(obj, parent) : check object inheritance\n\n You can explore The evennia API from inside the game by calling\n the `__doc__` property on entities:\n py evennia.__doc__\n py evennia.managers.__doc__\n\n |rNote: In the wrong hands this command is a severe security risk. It\n should only be accessible by trusted server admins/superusers.|n\n\n "}
    +
    +
    class evennia.commands.default.system.CmdScripts(**kwargs)[source]

    Bases: evennia.commands.default.muxcommand.MuxCommand

    -

    list and manage all running scripts

    -
    -
    Usage:

    scripts[/switches] [#dbref, key, script.path or <obj>]

    +

    List and manage all running scripts. Allows for creating new global +scripts.

    +
    +
    Usage:

    script[/switches] [#dbref, key, script.path or <obj>]

    -
    Switches:

    start - start a script (must supply a script path) -stop - stops an existing script -kill - kills a script - without running its cleanup hooks -validate - run a validation on the script(s)

    +
    Switches:
    +
    create - create a new global script of given typeclass path. This will

    auto-start the script’s timer if it has one.

    +
    +
    +

    start - start/unpause an existing script’s timer. +stop - stops an existing script’s timer +pause - pause a script’s timer +delete - deletes script. This will also stop the timer as needed

    If no switches are given, this command just views all active @@ -286,7 +311,8 @@ scripts. The argument can be either an object, at which point it will be searched for all scripts defined on it, or a script name or #dbref. For using the /stop switch, a unique script #dbref is required since whole classes of scripts often have the same name.

    -

    Use script for managing commands on objects.

    +

    Use the script build-level command for managing scripts attached to +objects.

    key = 'scripts'
    @@ -294,12 +320,12 @@ required since whole classes of scripts often have the same name.

    -aliases = ['globalscript', 'listscripts']
    +aliases = []
    -switch_options = ('start', 'stop', 'kill', 'validate')
    +switch_options = ('create', 'start', 'stop', 'pause', 'delete')
    @@ -317,6 +343,11 @@ required since whole classes of scripts often have the same name.

    excluded_typeclass_paths = ['evennia.prototypes.prototypes.DbPrototype']
    +
    +
    +switch_mapping = {'create': '|gCreated|n', 'delete': '|rDeleted|n', 'pause': '|Paused|n', 'start': '|gStarted|n', 'stop': '|RStopped|n'}
    +
    +
    func()[source]
    @@ -328,6 +359,11 @@ required since whole classes of scripts often have the same name.

    lock_storage = 'cmd:perm(listscripts) or perm(Admin)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'system', 'key': 'scripts', 'tags': '', 'text': "\n List and manage all running scripts. Allows for creating new global\n scripts.\n\n Usage:\n script[/switches] [#dbref, key, script.path or <obj>]\n\n Switches:\n create - create a new global script of given typeclass path. This will\n auto-start the script's timer if it has one.\n start - start/unpause an existing script's timer.\n stop - stops an existing script's timer\n pause - pause a script's timer\n delete - deletes script. This will also stop the timer as needed\n\n If no switches are given, this command just views all active\n scripts. The argument can be either an object, at which point it\n will be searched for all scripts defined on it, or a script name\n or #dbref. For using the /stop switch, a unique script #dbref is\n required since whole classes of scripts often have the same name.\n\n Use the `script` build-level command for managing scripts attached to\n objects.\n\n "}
    +
    +
    @@ -349,7 +385,7 @@ given, <nr> defaults to 10.

    -aliases = ['listobjs', 'db', 'stats', 'listobjects']
    +aliases = ['stats', 'listobjects', 'listobjs', 'db']
    @@ -373,6 +409,11 @@ given, <nr> defaults to 10.

    lock_storage = 'cmd:perm(listobjects) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': 'stats listobjects listobjs db', 'category': 'system', 'key': 'objects', 'tags': '', 'text': '\n statistics on objects in the database\n\n Usage:\n objects [<nr>]\n\n Gives statictics on objects in database as well as\n a list of <nr> latest objects in database. If not\n given, <nr> defaults to 10.\n '}
    +
    +
    @@ -430,6 +471,11 @@ in the list.

    lock_storage = 'cmd:perm(service) or perm(Developer)'
    +
    +
    +search_index_entry = {'aliases': 'services', 'category': 'system', 'key': 'service', 'tags': '', 'text': '\n manage system services\n\n Usage:\n service[/switch] <service>\n\n Switches:\n list - shows all available services (default)\n start - activates or reactivate a service\n stop - stops/inactivate a service (can often be restarted)\n delete - tries to permanently remove a service\n\n Service management system. Allows for the listing,\n starting, and stopping of services. If no switches\n are given, services will be listed. Note that to operate on the\n service you have to supply the full (green or red) name as given\n in the list.\n '}
    +
    +
    @@ -473,6 +519,11 @@ in the list.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'version', 'category': 'system', 'key': 'about', 'tags': '', 'text': '\n show Evennia info\n\n Usage:\n about\n\n Display info about the game engine.\n '}
    +
    +
    @@ -517,6 +568,11 @@ and the current time stamp.

    lock_storage = 'cmd:perm(time) or perm(Player)'
    +
    +
    +search_index_entry = {'aliases': 'uptime', 'category': 'system', 'key': 'time', 'tags': '', 'text': '\n show server time statistics\n\n Usage:\n time\n\n List Server time statistics such as uptime\n and the current time stamp.\n '}
    +
    +
    @@ -556,7 +612,7 @@ the released memory will instead be re-used by the program.

    -aliases = ['serverprocess', 'serverload']
    +aliases = ['serverload', 'serverprocess']
    @@ -585,6 +641,100 @@ the released memory will instead be re-used by the program.

    lock_storage = 'cmd:perm(list) or perm(Developer)'
    +
    +
    +search_index_entry = {'aliases': 'serverload serverprocess', 'category': 'system', 'key': 'server', 'tags': '', 'text': "\n show server load and memory statistics\n\n Usage:\n server[/mem]\n\n Switches:\n mem - return only a string of the current memory usage\n flushmem - flush the idmapper cache\n\n This command shows server load statistics and dynamic memory\n usage. It also allows to flush the cache of accessed database\n objects.\n\n Some Important statistics in the table:\n\n |wServer load|n is an average of processor usage. It's usually\n between 0 (no usage) and 1 (100% usage), but may also be\n temporarily higher if your computer has multiple CPU cores.\n\n The |wResident/Virtual memory|n displays the total memory used by\n the server process.\n\n Evennia |wcaches|n all retrieved database entities when they are\n loaded by use of the idmapper functionality. This allows Evennia\n to maintain the same instances of an entity and allowing\n non-persistent storage schemes. The total amount of cached objects\n are displayed plus a breakdown of database object types.\n\n The |wflushmem|n switch allows to flush the object cache. Please\n note that due to how Python's memory management works, releasing\n caches may not show you a lower Residual/Virtual memory footprint,\n the released memory will instead be re-used by the program.\n\n "}
    +
    + +
    + +
    +
    +class evennia.commands.default.system.CmdTasks(**kwargs)[source]
    +

    Bases: evennia.commands.default.muxcommand.MuxCommand

    +

    Display or terminate active tasks (delays).

    +
    +
    Usage:

    tasks[/switch] [task_id or function_name]

    +
    +
    Switches:

    pause - Pause the callback of a task. +unpause - Process all callbacks made since pause() was called. +do_task - Execute the task (call its callback). +call - Call the callback of this task. +remove - Remove a task without executing it. +cancel - Stop a task from automatically executing.

    +
    +
    +

    Notes

    +

    A task is a single use method of delaying the call of a function. Calls are created +in code, using evennia.utils.delay. +See |luhttps://www.evennia.com/docs/latest/Command-Duration.html|ltthe docs|le for help.

    +

    By default, tasks that are canceled and never called are cleaned up after one minute.

    +

    Examples

    +
      +
    • +
      tasks/cancel move_callback - Cancels all movement delays from the slow_exit contrib.

      In this example slow exits creates it’s tasks with +utils.delay(move_delay, move_callback)

      +
      +
      +
    • +
    • tasks/cancel 2 - Cancel task id 2.

    • +
    +
    +
    +key = 'tasks'
    +
    + +
    +
    +aliases = ['delays', 'task']
    +
    + +
    +
    +switch_options = ('pause', 'unpause', 'do_task', 'call', 'remove', 'cancel')
    +
    + +
    +
    +locks = 'cmd:all();perm(Developer)'
    +
    + +
    +
    +help_category = 'system'
    +
    + +
    +
    +static coll_date_func(task)[source]
    +

    Replace regex characters in date string and collect deferred function name.

    +
    + +
    +
    +do_task_action(*args, **kwargs)[source]
    +

    Process the action of a tasks command.

    +

    This exists to gain support with yes or no function from EvMenu.

    +
    + +
    +
    +func()[source]
    +

    This is the hook function that actually does all the work. It is called +by the cmdhandler right after self.parser() finishes, and so has access +to all the variables defined therein.

    +
    + +
    +
    +lock_storage = 'cmd:all();cmd:perm(Developer)'
    +
    + +
    +
    +search_index_entry = {'aliases': 'delays task', 'category': 'system', 'key': 'tasks', 'tags': '', 'text': "\n Display or terminate active tasks (delays).\n\n Usage:\n tasks[/switch] [task_id or function_name]\n\n Switches:\n pause - Pause the callback of a task.\n unpause - Process all callbacks made since pause() was called.\n do_task - Execute the task (call its callback).\n call - Call the callback of this task.\n remove - Remove a task without executing it.\n cancel - Stop a task from automatically executing.\n\n Notes:\n A task is a single use method of delaying the call of a function. Calls are created\n in code, using `evennia.utils.delay`.\n See |luhttps://www.evennia.com/docs/latest/Command-Duration.html|ltthe docs|le for help.\n\n By default, tasks that are canceled and never called are cleaned up after one minute.\n\n Examples:\n - `tasks/cancel move_callback` - Cancels all movement delays from the slow_exit contrib.\n In this example slow exits creates it's tasks with\n `utils.delay(move_delay, move_callback)`\n - `tasks/cancel 2` - Cancel task id 2.\n\n "}
    +
    +
    @@ -632,7 +782,6 @@ the released memory will instead be re-used by the program.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.commands.default.tests.html b/docs/0.9.5/api/evennia.commands.default.tests.html index 3579914496..11c05854f8 100644 --- a/docs/0.9.5/api/evennia.commands.default.tests.html +++ b/docs/0.9.5/api/evennia.commands.default.tests.html @@ -51,25 +51,107 @@ main test suite started with

    class evennia.commands.default.tests.CommandTest(methodName='runTest')[source]

    Bases: evennia.utils.test_resources.EvenniaTest

    -

    Tests a command

    +

    Tests a Command by running it and comparing what messages it sends with +expected values. This tests without actually spinning up the cmdhandler +for every test, which is more controlled.

    +

    Example:

    +
    from commands.echo import CmdEcho
    +
    +class MyCommandTest(CommandTest):
    +
    +    def test_echo(self):
    +        '''
    +        Test that the echo command really returns
    +        what you pass into it.
    +        '''
    +        self.call(MyCommand(), "hello world!",
    +                  "You hear your echo: 'Hello world!'")
    +
    +
    -call(cmdobj, args, msg=None, cmdset=None, noansi=True, caller=None, receiver=None, cmdstring=None, obj=None, inputs=None, raw_string=None)[source]
    -

    Test a command by assigning all the needed -properties to cmdobj and running

    -
    -

    cmdobj.at_pre_cmd() -cmdobj.parse() -cmdobj.func() -cmdobj.at_post_cmd()

    -
    -

    The msgreturn value is compared to eventual -output sent to caller.msg in the game

    +call(cmdobj, input_args, msg=None, cmdset=None, noansi=True, caller=None, receiver=None, cmdstring=None, obj=None, inputs=None, raw_string=None)[source] +

    Test a command by assigning all the needed properties to a cmdobj and +running the sequence. The resulting .msg calls will be mocked and +the text= calls to them compared to a expected output.

    -
    Returns
    -

    msg (str) – The received message that was sent to the caller.

    +
    Parameters
    +
      +
    • cmdobj (Command) – The command object to use.

    • +
    • input_args (str) – This should be the full input the Command should +see, such as ‘look here’. This will become .args for the Command +instance to parse.

    • +
    • msg (str or dict, optional) – This is the expected return value(s) +returned through caller.msg(text=…) calls in the command. If a string, the +receiver is controlled with the receiver kwarg (defaults to caller). +If this is a dict, it is a mapping +{receiver1: “expected1”, receiver2: “expected2”,…} and receiver is +ignored. The message(s) are compared with the actual messages returned +to the receiver(s) as the Command runs. Each check uses .startswith, +so you can choose to only include the first part of the +returned message if that’s enough to verify a correct result. EvMenu +decorations (like borders) are stripped and should not be included. This +should also not include color tags unless noansi=False. +If the command returns texts in multiple separate .msg- +calls to a receiver, separate these with | if noansi=True +(default) and || if noansi=False. If no msg is given (None), +then no automatic comparison will be done.

    • +
    • cmdset (str, optional) – If given, make .cmdset available on the Command +instance as it runs. While .cmdset is normally available on the +Command instance by default, this is usually only used by +commands that explicitly operates/displays cmdsets, like +examine.

    • +
    • noansi (str, optional) – By default the color tags of the msg is +ignored, this makes them significant. If unset, msg must contain +the same color tags as the actual return message.

    • +
    • caller (Object or Account, optional) – By default self.char1 is used as the +command-caller (the .caller property on the Command). This allows to +execute with another caller, most commonly an Account.

    • +
    • receiver (Object or Account, optional) – This is the object to receive the +return messages we want to test. By default this is the same as caller +(which in turn defaults to is self.char1). Note that if msg is +a dict, this is ignored since the receiver is already specified there.

    • +
    • cmdstring (str, optional) – Normally this is the Command’s key. +This allows for tweaking the .cmdname property of the +Command**. This isb used for commands with multiple aliases, +where the command explicitly checs which alias was used to +determine its functionality.

    • +
    • obj (str, optional) – This sets the .obj property of the Command - the +object on which the Command ‘sits’. By default this is the same as caller. +This can be used for testing on-object Command interactions.

    • +
    • inputs (list, optional) – A list of strings to pass to functions that pause to +take input from the user (normally using @interactive and +ret = yield(question) or evmenu.get_input). Each element of the +list will be passed into the command as if the user wrote that at the prompt.

    • +
    • raw_string (str, optional) – Normally the .raw_string property is set as +a combination of your key/cmdname and input_args. This allows +direct control of what this is, for example for testing edge cases +or malformed inputs.

    • +
    +
    +
    Returns
    +

    str or dict

    +
    +
    The message sent to receiver, or a dict of

    {receiver: “msg”, …} if multiple are given. This is usually +only used with msg=None to do the validation externally.

    +

    +
    +
    Raises
    +

    AssertionError – If the returns of .msg calls (tested with .startswith) does not +match expected_input.

    +
    +
    +

    Notes

    +

    As part of the tests, all methods of the Command will be called in +the proper order:

    +
      +
    • cmdobj.at_pre_cmd()

    • +
    • cmdobj.parse()

    • +
    • cmdobj.func()

    • +
    • cmdobj.at_post_cmd()

    • +
    @@ -139,6 +221,23 @@ output sent to caller.msg in the game

    class evennia.commands.default.tests.TestHelp(methodName='runTest')[source]

    Bases: evennia.commands.default.tests.CommandTest

    +
    +
    +maxDiff = None
    +
    + +
    +
    +setUp()[source]
    +

    Sets up testing environment

    +
    + +
    +
    +tearDown()[source]
    +

    Hook method for deconstructing the test fixture after testing it.

    +
    +
    test_help()[source]
    @@ -149,6 +248,83 @@ output sent to caller.msg in the game

    test_set_help()[source]
    +
    +
    +test_subtopic_fetch = None
    +
    + +
    +
    +test_subtopic_fetch_00_test()
    +

    Check retrieval of subtopics [with helparg=’test’, expected=’Help for testnnMain help text… test/something else test/more’].

    +
    + +
    +
    +test_subtopic_fetch_01_test_creating_extra_stuff()
    +

    Check retrieval of subtopics [with helparg=’test/creating extra stuff’, expected=’Help for test/creating extra st…ating extra stuff/subsubtopicn’].

    +
    + +
    +
    +test_subtopic_fetch_02_test_creating()
    +

    Check retrieval of subtopics [with helparg=’test/creating’, expected=’Help for test/creating extra st…ating extra stuff/subsubtopicn’].

    +
    + +
    +
    +test_subtopic_fetch_03_test_extra()
    +

    Check retrieval of subtopics [with helparg=’test/extra’, expected=’Help for test/creating extra st…ating extra stuff/subsubtopicn’].

    +
    + +
    +
    +test_subtopic_fetch_04_test_extra_subsubtopic()
    +

    Check retrieval of subtopics [with helparg=’test/extra/subsubtopic’, expected=’Help for test/creating extra st…bsubtopicnnA subsubtopic text’].

    +
    + +
    +
    +test_subtopic_fetch_05_test_creating_extra_subsub()
    +

    Check retrieval of subtopics [with helparg=’test/creating extra/subsub’, expected=’Help for test/creating extra st…bsubtopicnnA subsubtopic text’].

    +
    + +
    +
    +test_subtopic_fetch_06_test_Something_else()
    +

    Check retrieval of subtopics [with helparg=’test/Something else’, expected=’Help for test/something elsennSomething else’].

    +
    + +
    +
    +test_subtopic_fetch_07_test_More()
    +

    Check retrieval of subtopics [with helparg=’test/More’, expected=’Help for test/morennAnother t…opics:n test/more/second-more’].

    +
    + +
    +
    +test_subtopic_fetch_08_test_More_Second_more()
    +

    Check retrieval of subtopics [with helparg=’test/More/Second-more’, expected=’Help for test/more/second-more...est/more/second-more/third more’].

    +
    + +
    +
    +test_subtopic_fetch_09_test_More_more()
    +

    Check retrieval of subtopics [with helparg=’test/More/-more’, expected=’Help for test/more/second-more...est/more/second-more/third more’].

    +
    + +
    +
    +test_subtopic_fetch_10_test_more_second_more_again()
    +

    Check retrieval of subtopics [with helparg=’test/more/second/more again’, expected=’Help for test/more/second-more/more againnnEven more text.n’].

    +
    + +
    +
    +test_subtopic_fetch_11_test_more_second_third()
    +

    Check retrieval of subtopics [with helparg=’test/more/second/third’, expected=’Help for test/more/second-more/third morennThird more textn’].

    +
    +
    @@ -182,6 +358,106 @@ output sent to caller.msg in the game

    +
    +
    +evennia.commands.default.tests.func_test_cmd_tasks()[source]
    +
    + +
    +
    +class evennia.commands.default.tests.TestCmdTasks(methodName='runTest')[source]
    +

    Bases: evennia.commands.default.tests.CommandTest

    +
    +
    +setUp()[source]
    +

    Sets up testing environment

    +
    + +
    +
    +tearDown()[source]
    +

    Hook method for deconstructing the test fixture after testing it.

    +
    + +
    +
    +test_no_tasks()[source]
    +
    + +
    +
    +test_active_task()[source]
    +
    + +
    +
    +test_persistent_task()[source]
    +
    + +
    +
    +test_pause_unpause()[source]
    +
    + +
    +
    +test_do_task()[source]
    +
    + +
    +
    +test_remove()[source]
    +
    + +
    +
    +test_call()[source]
    +
    + +
    +
    +test_cancel()[source]
    +
    + +
    +
    +test_func_name_manipulation()[source]
    +
    + +
    +
    +test_wrong_func_name()[source]
    +
    + +
    +
    +test_no_input()[source]
    +
    + +
    +
    +test_responce_of_yes()[source]
    +
    + +
    +
    +test_task_complete_waiting_input()[source]
    +

    Test for task completing while waiting for input.

    +
    + +
    +
    +test_new_task_waiting_input()[source]
    +

    Test task completing than a new task with the same ID being made while waitinf for input.

    +
    + +
    +
    +test_misformed_command()[source]
    +
    + +
    +
    class evennia.commands.default.tests.TestAdmin(methodName='runTest')[source]
    @@ -447,11 +723,6 @@ output sent to caller.msg in the game

    test_toggle_com()[source]
    -
    -
    -test_channels()[source]
    -
    -
    test_all_com()[source]
    @@ -467,11 +738,6 @@ output sent to caller.msg in the game

    test_cdesc()[source]
    -
    -
    -test_cemit()[source]
    -
    -
    test_cwho()[source]
    @@ -494,13 +760,124 @@ output sent to caller.msg in the game

    +
    +
    +class evennia.commands.default.tests.TestCommsChannel(methodName='runTest')[source]
    +

    Bases: evennia.commands.default.tests.CommandTest

    +

    Test the central channel command.

    +
    +
    +setUp()[source]
    +

    Sets up testing environment

    +
    + +
    +
    +tearDown()[source]
    +

    Hook method for deconstructing the test fixture after testing it.

    +
    + +
    +
    +test_channel__noarg()[source]
    +
    + +
    +
    +test_channel__msg()[source]
    +
    + +
    +
    +test_channel__list()[source]
    +
    + +
    +
    +test_channel__all()[source]
    +
    + +
    +
    +test_channel__history()[source]
    +
    + +
    +
    +test_channel__sub()[source]
    +
    + +
    +
    +test_channel__unsub()[source]
    +
    + +
    +
    +test_channel__alias__unalias()[source]
    +

    Add and then remove a channel alias

    +
    + +
    +
    +test_channel__mute()[source]
    +
    + +
    +
    +test_channel__unmute()[source]
    +
    + +
    +
    +test_channel__create()[source]
    +
    + +
    +
    +test_channel__destroy()[source]
    +
    + +
    +
    +test_channel__desc()[source]
    +
    + +
    +
    +test_channel__lock()[source]
    +
    + +
    +
    +test_channel__unlock()[source]
    +
    + +
    +
    +test_channel__boot()[source]
    +
    + +
    +
    +test_channel__ban__unban()[source]
    +

    Test first ban and then unban

    +
    + +
    +
    +test_channel__who()[source]
    +
    + +
    +
    class evennia.commands.default.tests.TestBatchProcess(methodName='runTest')[source]

    Bases: evennia.commands.default.tests.CommandTest

    -test_batch_commands()[source]
    +test_batch_commands(mock_delay, mock_repeat)[source]
    @@ -509,7 +886,7 @@ output sent to caller.msg in the game

    class evennia.commands.default.tests.CmdInterrupt(**kwargs)[source]

    Bases: evennia.commands.command.Command

    -

    Base command

    +

    (you may see this if a child command had no help text defined)

    Usage:

    command [args]

    @@ -600,6 +977,11 @@ set in self.parse())

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'interrupt', 'tags': '', 'text': '\n ## Base command\n\n (you may see this if a child command had no help text defined)\n\n Usage:\n command [args]\n\n This is the base command class. Inherit from this\n to create new commands.\n\n The cmdhandler makes the following variables available to the\n command methods (so you can always assume them to be there):\n self.caller - the game object calling the command\n self.cmdstring - the command name used to trigger this command (allows\n you to know which alias was used, for example)\n cmd.args - everything supplied to the command following the cmdstring\n (this is usually what is parsed in self.parse())\n cmd.cmdset - the cmdset from which this command was matched (useful only\n seldomly, notably for help-type commands, to create dynamic\n help entries and lists)\n cmd.obj - the object on which this command is defined. If a default command,\n this is usually the same as caller.\n cmd.rawstring - the full raw string input, including any args and no parsing.\n\n The following class properties can/should be defined on your child class:\n\n key - identifier for command (e.g. "look")\n aliases - (optional) list of aliases (e.g. ["l", "loo"])\n locks - lock string (default is "cmd:all()")\n help_category - how to organize this help entry in help system\n (default is "General")\n auto_help - defaults to True. Allows for turning off auto-help generation\n arg_regex - (optional) raw string regex defining how the argument part of\n the command should look in order to match for this command\n (e.g. must it be a space between cmdname and arg?)\n auto_help_display_key - (optional) if given, this replaces the string shown\n in the auto-help listing. This is particularly useful for system-commands\n whose actual key is not really meaningful.\n\n (Note that if auto_help is on, this initial string is also used by the\n system to create the help entry for the command, so it\'s a good idea to\n format it similar to this one). This behavior can be changed by\n overriding the method \'get_help\' of a command: by default, this\n method returns cmd.__doc__ (that is, this very docstring, or\n the docstring of your command). You can, however, extend or\n replace this without disabling auto_help.\n '}
    +
    +
    @@ -638,11 +1020,6 @@ set in self.parse())

    test_multimatch()[source]
    -
    -
    -test_channelcommand(mock_channeldb)[source]
    -
    - @@ -690,7 +1067,6 @@ set in self.parse())

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.commands.default.unloggedin.html b/docs/0.9.5/api/evennia.commands.default.unloggedin.html index 0ec13f1172..7eca92d41b 100644 --- a/docs/0.9.5/api/evennia.commands.default.unloggedin.html +++ b/docs/0.9.5/api/evennia.commands.default.unloggedin.html @@ -59,7 +59,7 @@ connect “account name” “pass word”

    -aliases = ['conn', 'co', 'con']
    +aliases = ['co', 'con', 'conn']
    @@ -92,6 +92,11 @@ there is no object yet before the account has logged in)

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'co con conn', 'category': 'general', 'key': 'connect', 'tags': '', 'text': '\n connect to the game\n\n Usage (at login screen):\n connect accountname password\n connect "account name" "pass word"\n\n Use the create command to first create an account before logging in.\n\n If you have spaces in your name, enclose it in double quotes.\n '}
    +
    +
    @@ -142,6 +147,11 @@ create “account name” “pass word”

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'cre cr', 'category': 'general', 'key': 'create', 'tags': '', 'text': '\n create a new account account\n\n Usage (at login screen):\n create <accountname> <password>\n create "account name" "pass word"\n\n This creates a new account account.\n\n If you have spaces in your name, enclose it in double quotes.\n '}
    +
    +
    @@ -187,6 +197,11 @@ version is a bit more complicated.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'qu q', 'category': 'general', 'key': 'quit', 'tags': '', 'text': '\n quit when in unlogged-in state\n\n Usage:\n quit\n\n We maintain a different version of the quit command\n here for unconnected accounts for the sake of simplicity. The logged in\n version is a bit more complicated.\n '}
    +
    +
    @@ -232,6 +247,11 @@ All it does is display the connect screen.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'l look', 'category': 'general', 'key': '__unloggedin_look_command', 'tags': '', 'text': '\n look when in unlogged-in state\n\n Usage:\n look\n\n This is an unconnected version of the look command for simplicity.\n\n This is called by the server and kicks everything in gear.\n All it does is display the connect screen.\n '}
    +
    +
    @@ -252,7 +272,7 @@ for simplicity. It shows a pane of info.

    -aliases = ['h', '?']
    +aliases = ['?', 'h']
    @@ -276,6 +296,11 @@ for simplicity. It shows a pane of info.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '? h', 'category': 'general', 'key': 'help', 'tags': '', 'text': '\n get help when in unconnected-in state\n\n Usage:\n help\n\n This is an unconnected version of the help command,\n for simplicity. It shows a pane of info.\n '}
    +
    +
    @@ -323,7 +348,6 @@ for simplicity. It shows a pane of info.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.commands.html b/docs/0.9.5/api/evennia.commands.html index 4ed30fbe10..36e79cd272 100644 --- a/docs/0.9.5/api/evennia.commands.html +++ b/docs/0.9.5/api/evennia.commands.html @@ -121,7 +121,6 @@ Evennia.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.comms.admin.html b/docs/0.9.5/api/evennia.comms.admin.html index 6a21f4da3d..eaa6bf187c 100644 --- a/docs/0.9.5/api/evennia.comms.admin.html +++ b/docs/0.9.5/api/evennia.comms.admin.html @@ -37,197 +37,8 @@
    -
    -

    evennia.comms.admin

    -

    This defines how Comm models are displayed in the web admin interface.

    -
    -
    -class evennia.comms.admin.ChannelAttributeInline(parent_model, admin_site)[source]
    -

    Bases: evennia.typeclasses.admin.AttributeInline

    -

    Inline display of Channel Attribute - experimental

    -
    -
    -model
    -

    alias of evennia.comms.models.ChannelDB_db_attributes

    -
    - -
    -
    -related_field = 'channeldb'
    -
    - -
    -
    -property media
    -
    - -
    - -
    -
    -class evennia.comms.admin.ChannelTagInline(parent_model, admin_site)[source]
    -

    Bases: evennia.typeclasses.admin.TagInline

    -

    Inline display of Channel Tags - experimental

    -
    -
    -model
    -

    alias of evennia.comms.models.ChannelDB_db_tags

    -
    - -
    -
    -related_field = 'channeldb'
    -
    - -
    -
    -property media
    -
    - -
    - -
    -
    -class evennia.comms.admin.MsgAdmin(model, admin_site)[source]
    -

    Bases: django.contrib.admin.options.ModelAdmin

    -

    Defines display for Msg objects

    -
    -
    -list_display = ('id', 'db_date_created', 'db_sender', 'db_receivers', 'db_channels', 'db_message', 'db_lock_storage')
    -
    - -
    - -
    - -
    -
    -ordering = ['db_date_created', 'db_sender', 'db_receivers', 'db_channels']
    -
    - -
    -
    -search_fields = ['id', '^db_date_created', '^db_message']
    -
    - -
    -
    -save_as = True
    -
    - -
    -
    -save_on_top = True
    -
    - -
    - -
    - -
    -
    -property media
    -
    - -
    - -
    -
    -class evennia.comms.admin.ChannelAdmin(model, admin_site)[source]
    -

    Bases: django.contrib.admin.options.ModelAdmin

    -

    Defines display for Channel objects

    -
    -
    -inlines = [<class 'evennia.comms.admin.ChannelTagInline'>, <class 'evennia.comms.admin.ChannelAttributeInline'>]
    -
    - -
    -
    -list_display = ('id', 'db_key', 'db_lock_storage', 'subscriptions')
    -
    - -
    - -
    - -
    -
    -ordering = ['db_key']
    -
    - -
    -
    -search_fields = ['id', 'db_key', 'db_tags__db_key']
    -
    - -
    -
    -save_as = True
    -
    - -
    -
    -save_on_top = True
    -
    - -
    - -
    - -
    -
    -raw_id_fields = ('db_object_subscriptions', 'db_account_subscriptions')
    -
    - -
    -
    -fieldsets = ((None, {'fields': (('db_key',), 'db_lock_storage', 'db_account_subscriptions', 'db_object_subscriptions')}),)
    -
    - -
    -
    -subscriptions(obj)[source]
    -

    Helper method to get subs from a channel.

    -
    -
    Parameters
    -

    obj (Channel) – The channel to get subs from.

    -
    -
    -
    - -
    -
    -save_model(request, obj, form, change)[source]
    -

    Model-save hook.

    -
    -
    Parameters
    -
      -
    • request (Request) – Incoming request.

    • -
    • obj (Object) – Database object.

    • -
    • form (Form) – Form instance.

    • -
    • change (bool) – If this is a change or a new object.

    • -
    -
    -
    -
    - -
    -
    -response_add(request, obj, post_url_continue=None)[source]
    -

    Determine the HttpResponse for the add_view stage.

    -
    - -
    -
    -property media
    -
    - -
    - +
    +

    evennia.comms.admin

    @@ -273,7 +84,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.comms.channelhandler.html b/docs/0.9.5/api/evennia.comms.channelhandler.html index 0a4038fb74..2ad3fbac66 100644 --- a/docs/0.9.5/api/evennia.comms.channelhandler.html +++ b/docs/0.9.5/api/evennia.comms.channelhandler.html @@ -37,228 +37,8 @@
    -
    -

    evennia.comms.channelhandler

    -

    The channel handler, accessed from this module as CHANNEL_HANDLER is a -singleton that handles the stored set of channels and how they are -represented against the cmdhandler.

    -

    If there is a channel named ‘newbie’, we want to be able to just write

    -
    -

    newbie Hello!

    -
    -

    For this to work, ‘newbie’, the name of the channel, must be -identified by the cmdhandler as a command name. The channelhandler -stores all channels as custom ‘commands’ that the cmdhandler can -import and look through.

    -

    > Warning - channel names take precedence over command names, so make -sure to not pick clashing channel names.

    -

    Unless deleting a channel you normally don’t need to bother about the -channelhandler at all - the create_channel method handles the update.

    -

    To delete a channel cleanly, delete the channel object, then call -update() on the channelhandler. Or use Channel.objects.delete() which -does this for you.

    -
    -
    -class evennia.comms.channelhandler.ChannelCommand(**kwargs)[source]
    -

    Bases: evennia.commands.default.muxcommand.MuxCommand

    -

    {channelkey} channel

    -

    {channeldesc}

    -
    -
    Usage:

    {lower_channelkey} <message> -{lower_channelkey}/history [start] -{lower_channelkey} off - mutes the channel -{lower_channelkey} on - unmutes the channel

    -
    -
    Switch:
    -
    history: View 20 previous messages, either from the end or

    from <start> number of messages from the end.

    -
    -
    -
    -
    -

    Example

    -

    {lower_channelkey} Hello World! -{lower_channelkey}/history -{lower_channelkey}/history 30

    -
    -
    -is_channel = True
    -
    - -
    -
    -key = 'general'
    -
    - -
    -
    -help_category = 'channel names'
    -
    - -
    -
    -obj = None
    -
    - -
    -
    -arg_regex = re.compile('\\s.*?|/history.*?', re.IGNORECASE)
    -
    - -
    -
    -parse()[source]
    -

    Simple parser

    -
    - -
    -
    -func()[source]
    -

    Create a new message and send it to channel, using -the already formatted input.

    -
    - -
    -
    -get_extra_info(caller, **kwargs)[source]
    -

    Let users know that this command is for communicating on a channel.

    -
    -
    Parameters
    -

    caller (TypedObject) – A Character or Account who has entered an ambiguous command.

    -
    -
    Returns
    -

    A string with identifying information to disambiguate the object, conventionally with a preceding space.

    -
    -
    -
    - -
    -
    -aliases = []
    -
    - -
    -
    -lock_storage = 'cmd:all();'
    -
    - -
    - -
    -
    -class evennia.comms.channelhandler.ChannelHandler[source]
    -

    Bases: object

    -

    The ChannelHandler manages all active in-game channels and -dynamically creates channel commands for users so that they can -just give the channel’s key or alias to write to it. Whenever a -new channel is created in the database, the update() method on -this handler must be called to sync it with the database (this is -done automatically if creating the channel with -evennia.create_channel())

    -
    -
    -__init__()[source]
    -

    Initializes the channel handler’s internal state.

    -
    - -
    -
    -clear()[source]
    -

    Reset the cache storage.

    -
    - -
    -
    -add(channel)[source]
    -

    Add an individual channel to the handler. This is called -whenever a new channel is created.

    -
    -
    Parameters
    -

    channel (Channel) – The channel to add.

    -
    -
    -

    Notes

    -

    To remove a channel, simply delete the channel object and -run self.update on the handler. This should usually be -handled automatically by one of the deletion methos of -the Channel itself.

    -
    - -
    -
    -add_channel(channel)
    -

    Add an individual channel to the handler. This is called -whenever a new channel is created.

    -
    -
    Parameters
    -

    channel (Channel) – The channel to add.

    -
    -
    -

    Notes

    -

    To remove a channel, simply delete the channel object and -run self.update on the handler. This should usually be -handled automatically by one of the deletion methos of -the Channel itself.

    -
    - -
    -
    -remove(channel)[source]
    -

    Remove channel from channelhandler. This will also delete it.

    -
    -
    Parameters
    -

    channel (Channel) – Channel to remove/delete.

    -
    -
    -
    - -
    -
    -update()[source]
    -

    Updates the handler completely, including removing old removed -Channel objects. This must be called after deleting a Channel.

    -
    - -
    -
    -get(channelname=None)[source]
    -

    Get a channel from the handler, or all channels

    -
    -
    Parameters
    -

    channelame (str, optional) – Channel key, case insensitive.

    -
    -
    -
    -
    Returns
    -
    channels (list): The matching channels in a list, or all

    channels in the handler.

    -
    -
    -
    -
    -
    - -
    -
    -get_cmdset(source_object)[source]
    -

    Retrieve cmdset for channels this source_object has -access to send to.

    -
    -
    Parameters
    -

    source_object (Object) – An object subscribing to one -or more channels.

    -
    -
    Returns
    -

    cmdsets (list)

    -
    -
    The Channel-Cmdsets source_object has

    access to.

    -
    -
    -

    -
    -
    -
    - -
    - +
    +

    evennia.comms.channelhandler

    @@ -304,7 +84,6 @@ or more channels.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.comms.comms.html b/docs/0.9.5/api/evennia.comms.comms.html index b3a283742d..7fac4e14cf 100644 --- a/docs/0.9.5/api/evennia.comms.comms.html +++ b/docs/0.9.5/api/evennia.comms.comms.html @@ -46,11 +46,50 @@

    Bases: evennia.comms.models.ChannelDB

    This is the base class for all Channel Comms. Inherit from this to create different types of communication channels.

    +
    +
    Class-level variables:
      +
    • send_to_online_only (bool, default True) - if set, will only try to +send to subscribers that are actually active. This is a useful optimization.

    • +
    • log_file (str, default “channel_{channelname}.log”). This is the +log file to which the channel history will be saved. The {channelname} tag +will be replaced by the key of the Channel. If an Attribute ‘log_file’ +is set, this will be used instead. If this is None and no Attribute is found, +no history will be saved.

    • +
    • channel_prefix_string (str, default “[{channelname} ]”) - this is used +as a simple template to get the channel prefix with .channel_prefix().

    • +
    +
    +
    objects = <evennia.comms.managers.ChannelManager object>
    +
    +
    +send_to_online_only = True
    +
    + +
    +
    +log_file = 'channel_{channelname}.log'
    +
    + +
    +
    +channel_prefix_string = '[{channelname}] '
    +
    + +
    +
    +channel_msg_nick_pattern = '{alias}\\s*?|{alias}\\s+?(?P<arg1>.+?)'
    +
    + +
    +
    +channel_msg_nick_replacement = 'channel {channelname} = $1'
    +
    +
    at_first_save()[source]
    @@ -70,6 +109,34 @@ the hooks called by this method.

    Called once, when the channel is first created.

    +
    +
    +get_log_filename()[source]
    +

    File name to use for channel log.

    +
    +
    Returns
    +

    str

    +
    +
    The filename to use (this is always assumed to be inside

    settings.LOG_DIR)

    +
    +
    +

    +
    +
    +
    + +
    +
    +set_log_filename(filename)[source]
    +

    Set a custom log filename.

    +
    +
    Parameters
    +

    filename (str) – The filename to set. This is a path starting from +inside the settings.LOG_DIR location.

    +
    +
    +
    +
    has_connection(subscriber)[source]
    @@ -100,6 +167,11 @@ to this channel.

    property mutelist
    +
    +
    +property banlist
    +
    +
    property wholist
    @@ -119,14 +191,22 @@ but may use channel commands.

    overriding the call (unused by default).

    +
    Returns
    +

    bool

    +
    +
    True if muting was successful, False if we were already

    muted.

    +
    +
    +

    +
    unmute(subscriber, **kwargs)[source]
    -

    Removes an entity to the list of muted subscribers. A muted subscriber will no longer see channel messages, -but may use channel commands.

    +

    Removes an entity from the list of muted subscribers. A muted subscriber +will no longer see channel messages, but may use channel commands.

    Parameters
      @@ -135,6 +215,65 @@ but may use channel commands.

      overriding the call (unused by default).

    +
    Returns
    +

    bool

    +
    +
    True if unmuting was successful, False if we were already

    unmuted.

    +
    +
    +

    +
    +
    +
    + +
    +
    +ban(target, **kwargs)[source]
    +

    Ban a given user from connecting to the channel. This will not stop +users already connected, so the user must be booted for this to take +effect.

    +
    +
    Parameters
    +
      +
    • target (Object or Account) – The entity to unmute. This need not +be a subscriber.

    • +
    • **kwargs (dict) – Arbitrary, optional arguments for users +overriding the call (unused by default).

    • +
    +
    +
    Returns
    +

    bool

    +
    +
    True if banning was successful, False if target was already

    banned.

    +
    +
    +

    +
    +
    +
    + +
    +
    +unban(target, **kwargs)[source]
    +

    Un-Ban a given user. This will not reconnect them - they will still +have to reconnect and set up aliases anew.

    +
    +
    Parameters
    +
      +
    • target (Object or Account) – The entity to unmute. This need not +be a subscriber.

    • +
    • **kwargs (dict) – Arbitrary, optional arguments for users +overriding the call (unused by default).

    • +
    +
    +
    Returns
    +

    bool

    +
    +
    True if unbanning was successful, False if target was not

    previously banned.

    +
    +
    +

    +
    @@ -210,7 +349,7 @@ overriding the call (unused by default).

    -classmethod create(key, account=None, *args, **kwargs)[source]
    +classmethod create(key, creator=None, *args, **kwargs)[source]

    Creates a basic Channel with default parameters, unless otherwise specified or extended.

    Provides a friendlier interface to the utils.create_channel() function.

    @@ -218,7 +357,8 @@ specified or extended.

    Parameters
    • key (str) – This must be unique.

    • -
    • account (Account) – Account to attribute this object to.

    • +
    • creator (Account or Object) – Entity to associate with this channel +(used for tracking)

    Keyword Arguments
    @@ -242,172 +382,92 @@ errors (list): A list of errors in string form, if any.

    delete()[source]
    -

    Deletes channel while also cleaning up channelhandler.

    -
    - -
    -
    -message_transform(msgobj, emit=False, prefix=True, sender_strings=None, external=False, **kwargs)[source]
    -

    Generates the formatted string sent to listeners on a channel.

    -
    -
    Parameters
    -
      -
    • msgobj (Msg) – Message object to send.

    • -
    • emit (bool, optional) – In emit mode the message is not associated -with a specific sender name.

    • -
    • prefix (bool, optional) – Prefix msg with a text given by self.channel_prefix.

    • -
    • sender_strings (list, optional) – Used by bots etc, one string per external sender.

    • -
    • external (bool, optional) – If this is an external sender or not.

    • -
    • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

    • -
    -
    -
    -
    - -
    -
    -distribute_message(msgobj, online=False, **kwargs)[source]
    -

    Method for grabbing all listeners that a message should be -sent to on this channel, and sending them a message.

    -
    -
    Parameters
    -
      -
    • msgobj (Msg or TempMsg) – Message to distribute.

    • -
    • online (bool) – Only send to receivers who are actually online -(not currently used):

    • -
    • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

    • -
    -
    -
    -

    Notes

    -

    This is also where logging happens, if enabled.

    -
    - -
    -
    -msg(msgobj, header=None, senders=None, sender_strings=None, keep_log=None, online=False, emit=False, external=False)[source]
    -

    Send the given message to all accounts connected to channel. Note that -no permission-checking is done here; it is assumed to have been -done before calling this method. The optional keywords are not used if -persistent is False.

    -
    -
    Parameters
    -
      -
    • msgobj (Msg, TempMsg or str) – If a Msg/TempMsg, the remaining -keywords will be ignored (since the Msg/TempMsg object already -has all the data). If a string, this will either be sent as-is -(if persistent=False) or it will be used together with header -and senders keywords to create a Msg instance on the fly.

    • -
    • header (str, optional) – A header for building the message.

    • -
    • senders (Object, Account or list, optional) – Optional if persistent=False, used -to build senders for the message.

    • -
    • sender_strings (list, optional) – Name strings of senders. Used for external -connections where the sender is not an account or object. -When this is defined, external will be assumed. The list will be -filtered so each sender-string only occurs once.

    • -
    • keep_log (bool or None, optional) – This allows to temporarily change the logging status of -this channel message. If None, the Channel’s keep_log Attribute will -be used. If True or False, that logging status will be used for this -message only (note that for unlogged channels, a True value here will -create a new log file only for this message).

    • -
    • online (bool, optional) – online. Otherwise, messages all accounts connected. This can -make things faster, but may not trigger listeners on accounts -that are offline.

    • -
    • emit (bool, optional) – not to be directly associated with a name.

    • -
    • external (bool, optional) – Treat this message as being -agnostic of its sender.

    • -
    -
    -
    Returns
    -

    success (bool)

    -
    -
    Returns True if message sending was

    successful, False otherwise.

    -
    -
    -

    -
    -
    -
    - -
    -
    -tempmsg(message, header=None, senders=None)[source]
    -

    A wrapper for sending non-persistent messages.

    -
    -
    Parameters
    -
      -
    • message (str) – Message to send.

    • -
    • header (str, optional) – Header of message to send.

    • -
    • senders (Object or list, optional) – Senders of message to send.

    • -
    -
    -
    +

    Deletes channel.

    -channel_prefix(msg=None, emit=False, **kwargs)[source]
    +channel_prefix()[source]

    Hook method. How the channel should prefix itself for users.

    -
    Parameters
    -
      -
    • msg (str, optional) – Prefix text

    • -
    • emit (bool, optional) – Switches to emit mode, which usually -means to not prefix the channel’s info.

    • -
    • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

    • -
    -
    -
    Returns
    -

    prefix (str) – The created channel prefix.

    +
    Returns
    +

    str – The channel prefix.

    -
    -format_senders(senders=None, **kwargs)[source]
    -

    Hook method. Function used to format a list of sender names.

    +
    +add_user_channel_alias(user, alias, **kwargs)[source]
    +

    Add a personal user-alias for this channel to a given subscriber.

    Parameters
      -
    • senders (list) – Sender object names.

    • -
    • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

    • +
    • user (Object or Account) – The one to alias this channel.

    • +
    • alias (str) – The desired alias.

    -
    Returns
    -

    formatted_list (str) – The list of names formatted appropriately.

    +
    +
    +

    Note

    +

    This is tightly coupled to the default channel command. If you +change that, you need to change this as well.

    +

    We add two nicks - one is a plain alias -> channel.key that +users need to be able to reference this channel easily. The other +is a templated nick to easily be able to send messages to the +channel without needing to give the full channel command. The +structure of this nick is given by self.channel_msg_nick_pattern +and self.channel_msg_nick_replacement. By default it maps +alias <msg> -> channel <channelname> = <msg>, so that you can +for example just write pub Hello to send a message.

    +

    The alias created is alias $1 -> channel channel = $1, to allow +for sending to channel using the main channel command.

    +
    +
    + +
    +
    +classmethod remove_user_channel_alias(user, alias, **kwargs)[source]
    +

    Remove a personal channel alias from a user.

    +
    +
    Parameters
    +
      +
    • user (Object or Account) – The user to remove an alias from.

    • +
    • alias (str) – The alias to remove.

    • +
    • **kwargs – Unused by default. Can be used to pass extra variables +into a custom implementation.

    • +

    Notes

    -

    This function exists separately so that external sources -can use it to format source names in the same manner as -normal object/account names.

    +

    The channel-alias actually consists of two aliases - one +channel-based one for searching channels with the alias and one +inputline one for doing the ‘channelalias msg’ - call.

    +

    This is a classmethod because it doesn’t actually operate on the +channel instance.

    +

    It sits on the channel because the nick structure for this is +pretty complex and needs to be located in a central place (rather +on, say, the channel command).

    -
    -pose_transform(msgobj, sender_string, **kwargs)[source]
    -

    Hook method. Detects if the sender is posing, and modifies the -message accordingly.

    +
    +at_pre_msg(message, **kwargs)[source]
    +

    Called before the starting of sending the message to a receiver. This +is called before any hooks on the receiver itself. If this returns +None/False, the sending will be aborted.

    Parameters
      -
    • msgobj (Msg or TempMsg) – The message to analyze for a pose.

    • -
    • sender_string (str) – The name of the sender/poser.

    • -
    • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

    • +
    • message (str) – The message to send.

    • +
    • **kwargs (any) – Keywords passed on from .msg. This includes +senders.

    Returns
    -

    string (str)

    +

    str, False or None

    -
    A message that combines the sender_string

    component with msg in different ways depending on if a -pose was performed or not (this must be analyzed by the -hook).

    +
    Any custom changes made to the message. If

    falsy, no message will be sent.

    @@ -416,44 +476,51 @@ hook).

    -
    -format_external(msgobj, senders, emit=False, **kwargs)[source]
    -

    Hook method. Used for formatting external messages. This is -needed as a separate operation because the senders of external -messages may not be in-game objects/accounts, and so cannot -have things like custom user preferences.

    +
    +msg(message, senders=None, bypass_mute=False, **kwargs)[source]
    +

    Send message to channel, causing it to be distributed to all non-muted +subscribed users of that channel.

    Parameters
      -
    • msgobj (Msg or TempMsg) – The message to send.

    • -
    • senders (list) – Strings, one per sender.

    • -
    • emit (bool, optional) – A sender-agnostic message or not.

    • -
    • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

    • +
    • message (str) – The message to send.

    • +
    • senders (Object, Account or list, optional) – If not given, there is +no way to associate one or more senders with the message (like +a broadcast message or similar).

    • +
    • bypass_mute (bool, optional) – If set, always send, regardless of +individual mute-state of subscriber. This can be used for +global announcements or warnings/alerts.

    • +
    • **kwargs (any) – This will be passed on to all hooks. Use no_prefix +to exclude the channel prefix.

    -
    Returns
    -

    transformed (str) – A formatted string.

    -
    +

    Notes

    +

    The call hook calling sequence is:

    +
      +
    • msg = channel.at_pre_msg(message, **kwargs) (aborts for all if return None)

    • +
    • msg = receiver.at_pre_channel_msg(msg, channel, **kwargs) (aborts for receiver if return None)

    • +
    • receiver.at_channel_msg(msg, channel, **kwargs)

    • +
    • receiver.at_post_channel_msg(msg, channel, **kwargs)**

    • +
    +

    Called after all receivers are processed: +- channel.at_post_all_msg(message, **kwargs)

    +

    (where the senders/bypass_mute are embedded into **kwargs for +later access in hooks)

    -
    -format_message(msgobj, emit=False, **kwargs)[source]
    -

    Hook method. Formats a message body for display.

    +
    +at_post_msg(message, **kwargs)[source]
    +

    This is called after sending to all valid recipients. It is normally +used for logging/channel history.

    Parameters
      -
    • msgobj (Msg or TempMsg) – The message object to send.

    • -
    • emit (bool, optional) – The message is agnostic of senders.

    • -
    • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

    • +
    • message (str) – The message sent.

    • +
    • **kwargs (any) – Keywords passed on from msg, including senders.

    -
    Returns
    -

    transformed (str) – The formatted message.

    -
    @@ -489,6 +556,8 @@ overriding the call (unused by default).

    +

    Notes

    +

    By default this adds the needed channel nicks to the joiner.

    @@ -525,41 +594,6 @@ overriding the call (unused by default).

    -
    -
    -pre_send_message(msg, **kwargs)[source]
    -

    Hook method. Runs before a message is sent to the channel and -should return the message object, after any transformations. -If the message is to be discarded, return a false value.

    -
    -
    Parameters
    -
      -
    • msg (Msg or TempMsg) – Message to send.

    • -
    • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

    • -
    -
    -
    Returns
    -

    result (Msg, TempMsg or bool) – If False, abort send.

    -
    -
    -
    - -
    -
    -post_send_message(msg, **kwargs)[source]
    -

    Hook method. Run after a message is sent to the channel.

    -
    -
    Parameters
    -
      -
    • msg (Msg or TempMsg) – Message sent.

    • -
    • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

    • -
    -
    -
    -
    -
    at_init()[source]
    @@ -614,11 +648,11 @@ this object.

    For this to work, the developer must have defined a named view somewhere in urls.py that follows the format ‘modelname-action’, so in this case a named view of ‘channel-detail’ would be referenced by this method.

    -

    ex. -url(r’channels/(?P<slug>[wd-]+)/$’,

    -
    -

    ChannelDetailView.as_view(), name=’channel-detail’)

    -
    +

    ex.

    +
    url(r'channels/(?P<slug>[\w\d\-]+)/$',
    +    ChannelDetailView.as_view(), name='channel-detail')
    +
    +

    If no View has been created and defined in urls.py, returns an HTML anchor.

    This method is naive and simply returns a path. Securing access to @@ -640,11 +674,11 @@ object.

    For this to work, the developer must have defined a named view somewhere in urls.py that follows the format ‘modelname-action’, so in this case a named view of ‘channel-update’ would be referenced by this method.

    -

    ex. -url(r’channels/(?P<slug>[wd-]+)/(?P<pk>[0-9]+)/change/$’,

    -
    -

    ChannelUpdateView.as_view(), name=’channel-update’)

    -
    +

    ex.

    +
    url(r'channels/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/change/$',
    +    ChannelUpdateView.as_view(), name='channel-update')
    +
    +

    If no View has been created and defined in urls.py, returns an HTML anchor.

    This method is naive and simply returns a path. Securing access to @@ -691,11 +725,11 @@ this object.

    For this to work, the developer must have defined a named view somewhere in urls.py that follows the format ‘modelname-action’, so in this case a named view of ‘channel-detail’ would be referenced by this method.

    -

    ex. -url(r’channels/(?P<slug>[wd-]+)/$’,

    -
    -

    ChannelDetailView.as_view(), name=’channel-detail’)

    -
    +

    ex.

    +
    url(r'channels/(?P<slug>[\w\d\-]+)/$',
    +    ChannelDetailView.as_view(), name='channel-detail')
    +
    +

    If no View has been created and defined in urls.py, returns an HTML anchor.

    This method is naive and simply returns a path. Securing access to @@ -708,6 +742,46 @@ responsibility.

    +
    +
    +message_transform(*args, **kwargs)[source]
    +
    + +
    +
    +distribute_message(msgobj, online=False, **kwargs)[source]
    +
    + +
    +
    +format_senders(senders=None, **kwargs)[source]
    +
    + +
    +
    +pose_transform(msgobj, sender_string, **kwargs)[source]
    +
    + +
    +
    +format_external(msgobj, senders, emit=False, **kwargs)[source]
    +
    + +
    +
    +format_message(msgobj, emit=False, **kwargs)[source]
    +
    + +
    +
    +pre_send_message(msg, **kwargs)[source]
    +
    + +
    +
    +post_send_message(msg, **kwargs)[source]
    +
    +
    exception DoesNotExist
    @@ -777,7 +851,6 @@ responsibility.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.comms.html b/docs/0.9.5/api/evennia.comms.html index fae4a7dbf8..f0091b3726 100644 --- a/docs/0.9.5/api/evennia.comms.html +++ b/docs/0.9.5/api/evennia.comms.html @@ -96,7 +96,6 @@ as code related to external communication like IRC or RSS.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.comms.managers.html b/docs/0.9.5/api/evennia.comms.managers.html index fd330f04c9..b342b220bb 100644 --- a/docs/0.9.5/api/evennia.comms.managers.html +++ b/docs/0.9.5/api/evennia.comms.managers.html @@ -135,19 +135,15 @@ of which may be Channels).

    -get_messages_by_sender(sender, exclude_channel_messages=False)[source]
    +get_messages_by_sender(sender)[source]

    Get all messages sent by one entity - this could be either a account or an object

    Parameters
    -
      -
    • sender (Account or Object) – The sender of the message.

    • -
    • exclude_channel_messages (bool, optional) – Only return messages -not aimed at a channel (that is, private tells for example)

    • -
    +

    sender (Account or Object) – The sender of the message.

    Returns
    -

    messages (list) – List of matching messages

    +

    QuerySet – Matching messages.

    Raises

    CommError – For incorrect sender types.

    @@ -164,7 +160,7 @@ not aimed at a channel (that is, private tells for example)

    recipient (Object, Account or Channel) – The recipient of the messages to search for.

    Returns
    -

    messages (list) – Matching messages.

    +

    Queryset – Matching messages.

    Raises

    CommError – If the recipient is not of a valid type.

    @@ -172,20 +168,6 @@ not aimed at a channel (that is, private tells for example)

    -
    -
    -get_messages_by_channel(channel)[source]
    -

    Get all persistent messages sent to one channel.

    -
    -
    Parameters
    -

    channel (Channel) – The channel to find messages for.

    -
    -
    Returns
    -

    messages (list) – Persistent Msg objects saved for this channel.

    -
    -
    -
    -
    search_message(sender=None, receiver=None, freetext=None, dbref=None)[source]
    @@ -194,7 +176,7 @@ one of the arguments must be given to do a search.

    Parameters
      -
    • sender (Object or Account, optional) – Get messages sent by a particular account or object

    • +
    • sender (Object, Account or Script, optional) – Get messages sent by a particular sender.

    • receiver (Object, Account or Channel, optional) – Get messages received by a certain account,object or channel

    • freetext (str) – Search for a text string in a message. NOTE: @@ -206,7 +188,7 @@ always gives only one match.

    Returns
    -

    messages (list or Msg) – A list of message matches or a single match if dbref was given.

    +

    Queryset – Message matches.

    @@ -219,7 +201,7 @@ one of the arguments must be given to do a search.

    Parameters
      -
    • sender (Object or Account, optional) – Get messages sent by a particular account or object

    • +
    • sender (Object, Account or Script, optional) – Get messages sent by a particular sender.

    • receiver (Object, Account or Channel, optional) – Get messages received by a certain account,object or channel

    • freetext (str) – Search for a text string in a message. NOTE: @@ -231,7 +213,7 @@ always gives only one match.

    Returns
    -

    messages (list or Msg) – A list of message matches or a single match if dbref was given.

    +

    Queryset – Message matches.

    @@ -374,7 +356,6 @@ case sensitive) match.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.comms.models.html b/docs/0.9.5/api/evennia.comms.models.html index ae31a46ede..4337ed1643 100644 --- a/docs/0.9.5/api/evennia.comms.models.html +++ b/docs/0.9.5/api/evennia.comms.models.html @@ -64,17 +64,16 @@ accessed via specific handler methods):

  • db_sender_accounts: Account senders

  • db_sender_objects: Object senders

  • db_sender_scripts: Script senders

  • -
  • db_sender_external: External senders (defined as string names)

  • +
  • db_sender_external: External sender (defined as string name)

  • db_receivers_accounts: Receiving accounts

  • db_receivers_objects: Receiving objects

  • db_receivers_scripts: Receiveing scripts

  • -
  • db_receivers_channels: Receiving channels

  • +
  • db_receiver_external: External sender (defined as string name)

  • db_header: Header text

  • db_message: The actual message text

  • db_date_created: time message was created / sent

  • db_hide_from_sender: bool if message should be hidden from sender

  • db_hide_from_receivers: list of receiver objects to hide message from

  • -
  • db_hide_from_channels: list of channels objects to hide message from

  • db_lock_storage: Internal storage of lock strings.

  • @@ -181,19 +180,10 @@ class built by **create_forward_many_to_many_manager()** define
    -
    -db_receivers_channels
    -

    Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

    -

    In the example:

    -
    class Pizza(Model):
    -    toppings = ManyToManyField(Topping, related_name='pizzas')
    -
    -
    -

    **Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

    -

    Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

    +
    +db_receiver_external
    +

    A wrapper for a deferred-loading field. When the value is read from this +object the first time, the query is executed.

    @@ -256,22 +246,6 @@ instances.

    class built by **create_forward_many_to_many_manager()** defined below.

    -
    -
    -db_hide_from_channels
    -

    Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

    -

    In the example:

    -
    class Pizza(Model):
    -    toppings = ManyToManyField(Topping, related_name='pizzas')
    -
    -
    -

    **Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

    -

    Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

    -
    -
    db_tags
    @@ -293,12 +267,6 @@ class built by **create_forward_many_to_many_manager()** define objects = <evennia.comms.managers.MsgManager object>
    -
    -
    -__init__(*args, **kwargs)[source]
    -

    Initialize self. See help(type(self)) for accurate signature.

    -
    -
    locks[source]
    @@ -312,7 +280,7 @@ class built by **create_forward_many_to_many_manager()** define
    property senders
    -

    Getter. Allows for value = self.sender

    +

    Getter. Allows for value = self.senders

    @@ -321,7 +289,8 @@ class built by **create_forward_many_to_many_manager()** define

    Remove a single sender or a list of senders.

    Parameters
    -

    senders (Account, Object, str or list) – Senders to remove.

    +

    senders (Account, Object, str or list) – Senders to remove. +If a string, removes the external sender.

    @@ -330,31 +299,29 @@ class built by **create_forward_many_to_many_manager()** define
    property receivers

    Getter. Allows for value = self.receivers. -Returns four lists of receivers: accounts, objects, scripts and channels.

    +Returns four lists of receivers: accounts, objects, scripts and

    +
    +

    external_receivers.

    +
    remove_receiver(receivers)[source]
    -

    Remove a single receiver or a list of receivers.

    +

    Remove a single receiver, a list of receivers, or a single extral receiver.

    Parameters
    -

    receivers (Account, Object, Script, Channel or list) – Receiver to remove.

    +

    receivers (Account, Object, Script, list or str) – Receiver +to remove. A string removes the external receiver.

    -
    -
    -property channels
    -

    Getter. Allows for value = self.channels. Returns a list of channels.

    -
    -
    property hide_from

    Getter. Allows for value = self.hide_from. -Returns 3 lists of accounts, objects and channels

    +Returns two lists of accounts and objects.

    @@ -433,6 +400,12 @@ object the first time, the query is executed.

    path = 'evennia.comms.models.Msg'
    +
    +
    +property receiver_external
    +

    A wrapper for getting database field db_receiver_external.

    +
    +
    property sender_external
    @@ -448,26 +421,24 @@ object the first time, the query is executed.

    -class evennia.comms.models.TempMsg(senders=None, receivers=None, channels=None, message='', header='', type='', lockstring='', hide_from=None)[source]
    +class evennia.comms.models.TempMsg(senders=None, receivers=None, message='', header='', type='', lockstring='', hide_from=None)[source]

    Bases: object

    -

    This is a non-persistent object for sending temporary messages -that will not be stored. It mimics the “real” Msg object, but -doesn’t require sender to be given.

    +

    This is a non-persistent object for sending temporary messages that will not be stored. It +mimics the “real” Msg object, but doesn’t require sender to be given.

    -__init__(senders=None, receivers=None, channels=None, message='', header='', type='', lockstring='', hide_from=None)[source]
    +__init__(senders=None, receivers=None, message='', header='', type='', lockstring='', hide_from=None)[source]

    Creates the temp message.

    Parameters
    • senders (any or list, optional) – Senders of the message.

    • -
    • receivers (Account, Object, Channel or list, optional) – Receivers of this message.

    • -
    • channels (Channel or list, optional) – Channels to send to.

    • +
    • receivers (Account, Object, Script or list, optional) – Receivers of this message.

    • message (str, optional) – Message to send.

    • header (str, optional) – Header of message.

    • type (str, optional) – Message class, if any.

    • lockstring (str, optional) – Lock for the message.

    • -
    • hide_from (Account, Object, Channel or list, optional) – Entities to hide this message from.

    • +
    • hide_from (Account, Object, or list, optional) – Entities to hide this message from.

    @@ -495,7 +466,7 @@ doesn’t require sender to be given.

    Remove a receiver or a list of receivers

    Parameters
    -

    receiver (Object, Account, Channel, str or list) – Receivers to remove.

    +

    receiver (Object, Account, Script, str or list) – Receivers to remove.

    @@ -571,11 +542,6 @@ class built by **create_forward_many_to_many_manager()** define objects = <evennia.comms.managers.ChannelDBManager object>
    -
    -
    -subscriptions[source]
    -
    -
    exception DoesNotExist
    @@ -588,22 +554,6 @@ class built by **create_forward_many_to_many_manager()** define

    Bases: django.core.exceptions.MultipleObjectsReturned

    -
    -
    -channel_set
    -

    Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

    -

    In the example:

    -
    class Pizza(Model):
    -    toppings = ManyToManyField(Topping, related_name='pizzas')
    -
    -
    -

    **Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

    -

    Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

    -
    -
    db_attributes
    @@ -646,22 +596,6 @@ class built by **create_forward_many_to_many_manager()** define get_previous_by_db_date_created(*, field=<django.db.models.fields.DateTimeField: db_date_created>, is_next=False, **kwargs)
    -
    -
    -hide_from_channels_set
    -

    Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

    -

    In the example:

    -
    class Pizza(Model):
    -    toppings = ManyToManyField(Topping, related_name='pizzas')
    -
    -
    -

    **Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

    -

    Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

    -
    -
    id
    @@ -679,6 +613,11 @@ object the first time, the query is executed.

    typename = 'SharedMemoryModelBase'
    +
    +
    +subscriptions[source]
    +
    +
    @@ -726,7 +665,6 @@ object the first time, the query is executed.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.barter.html b/docs/0.9.5/api/evennia.contrib.barter.html index 8a371d292c..b1c1b4e224 100644 --- a/docs/0.9.5/api/evennia.contrib.barter.html +++ b/docs/0.9.5/api/evennia.contrib.barter.html @@ -403,6 +403,11 @@ available to the command

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'command', 'tags': '', 'text': '\n Base command for Trade commands to inherit from. Implements the\n custom parsing.\n '}
    +
    +
    @@ -446,6 +451,11 @@ available to the command

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'trade', 'key': 'trade help', 'tags': '', 'text': '\n help command for the trade system.\n\n Usage:\n trade help\n\n Displays help for the trade commands.\n '}
    +
    +
    @@ -490,6 +500,11 @@ standing offer.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'trading', 'key': 'offer', 'tags': '', 'text': '\n offer one or more items in trade.\n\n Usage:\n offer <object> [, object2, ...][:emote]\n\n Offer objects in trade. This will replace the currently\n standing offer.\n '}
    +
    +
    @@ -537,6 +552,11 @@ the current offer using the ‘offers’ command.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'agree', 'category': 'trading', 'key': 'accept', 'tags': '', 'text': "\n accept the standing offer\n\n Usage:\n accept [:emote]\n agreee [:emote]\n\n This will accept the current offer. The other party must also accept\n for the deal to go through. You can use the 'decline' command to change\n your mind as long as the other party has not yet accepted. You can inspect\n the current offer using the 'offers' command.\n "}
    +
    +
    @@ -583,6 +603,11 @@ decline the old offer.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'trading', 'key': 'decline', 'tags': '', 'text': "\n decline the standing offer\n\n Usage:\n decline [:emote]\n\n This will decline a previously 'accept'ed offer (so this allows you to\n change your mind). You can only use this as long as the other party\n has not yet accepted the deal. Also, changing the offer will automatically\n decline the old offer.\n "}
    +
    +
    @@ -627,6 +652,11 @@ determine if it’s worth your while.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'eval', 'category': 'trading', 'key': 'evaluate', 'tags': '', 'text': "\n evaluate objects on offer\n\n Usage:\n evaluate <offered object>\n\n This allows you to examine any object currently on offer, to\n determine if it's worth your while.\n "}
    +
    +
    @@ -675,6 +705,11 @@ try to influence the other part in the deal.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'deal offers', 'category': 'trading', 'key': 'status', 'tags': '', 'text': "\n show a list of the current deal\n\n Usage:\n status\n deal\n offers\n\n Shows the currently suggested offers on each sides of the deal. To\n accept the current deal, use the 'accept' command. Use 'offer' to\n change your deal. You might also want to use 'say', 'emote' etc to\n try to influence the other part in the deal.\n "}
    +
    +
    @@ -719,6 +754,11 @@ finish trade [:say]

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'finish trade', 'category': 'trading', 'key': 'end trade', 'tags': '', 'text': '\n end the trade prematurely\n\n Usage:\n end trade [:say]\n finish trade [:say]\n\n This ends the trade prematurely. No trade will take place.\n\n '}
    +
    +
    @@ -793,6 +833,11 @@ info to your choice.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'barter', 'category': 'general', 'key': 'trade', 'tags': '', 'text': '\n Initiate trade with another party\n\n Usage:\n trade <other party> [:say]\n trade <other party> accept [:say]\n trade <other party> decline [:say]\n\n Initiate trade with another party. The other party needs to repeat\n this command with trade accept/decline within a minute in order to\n properly initiate the trade action. You can use the decline option\n yourself if you want to retract an already suggested trade. The\n optional say part works like the say command and allows you to add\n info to your choice.\n '}
    +
    + @@ -840,7 +885,6 @@ info to your choice.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.building_menu.html b/docs/0.9.5/api/evennia.contrib.building_menu.html index 003e15f12a..c38bd532bb 100644 --- a/docs/0.9.5/api/evennia.contrib.building_menu.html +++ b/docs/0.9.5/api/evennia.contrib.building_menu.html @@ -251,6 +251,11 @@ overloading evential same-named class properties.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': '__noinput_command', 'tags': '', 'text': 'No input has been found.'}
    +
    +
    @@ -297,6 +302,11 @@ overloading evential same-named class properties.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': '__nomatch_command', 'tags': '', 'text': 'No input has been found.'}
    +
    +
    @@ -861,6 +871,11 @@ set in self.parse())

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': '@edit', 'tags': '', 'text': "\n Generic building command.\n\n Syntax:\n @edit [object]\n\n Open a building menu to edit the specified object. This menu allows to\n change the object's key and description.\n\n Examples:\n @edit here\n @edit self\n @edit #142\n\n "}
    +
    + @@ -908,7 +923,6 @@ set in self.parse())

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.chargen.html b/docs/0.9.5/api/evennia.contrib.chargen.html index 780a5e5f86..32a3d0e683 100644 --- a/docs/0.9.5/api/evennia.contrib.chargen.html +++ b/docs/0.9.5/api/evennia.contrib.chargen.html @@ -77,7 +77,7 @@ at them with this command.

    -aliases = ['l', 'ls']
    +aliases = ['ls', 'l']
    @@ -107,6 +107,11 @@ that is checked by the @ic command directly.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'ls l', 'category': 'general', 'key': 'look', 'tags': '', 'text': '\n ooc look\n\n Usage:\n look\n look <character>\n\n This is an OOC version of the look command. Since an Account doesn\'t\n have an in-game existence, there is no concept of location or\n "self".\n\n If any characters are available for you to control, you may look\n at them with this command.\n '}
    +
    +
    @@ -152,6 +157,11 @@ attribute on ourselves to remember it.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'create', 'tags': '', 'text': '\n creates a character\n\n Usage:\n create <character name>\n\n This will create a new character, assuming\n the given character name does not already exist.\n '}
    +
    +
    @@ -217,7 +227,6 @@ attribute on ourselves to remember it.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.clothing.html b/docs/0.9.5/api/evennia.contrib.clothing.html index f7fa5e0ecf..44833552b2 100644 --- a/docs/0.9.5/api/evennia.contrib.clothing.html +++ b/docs/0.9.5/api/evennia.contrib.clothing.html @@ -359,6 +359,11 @@ provide will be displayed after the clothing’s name.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'clothing', 'key': 'wear', 'tags': '', 'text': "\n Puts on an item of clothing you are holding.\n\n Usage:\n wear <obj> [wear style]\n\n Examples:\n wear shirt\n wear scarf wrapped loosely about the shoulders\n\n All the clothes you are wearing are appended to your description.\n If you provide a 'wear style' after the command, the message you\n provide will be displayed after the clothing's name.\n "}
    +
    +
    @@ -399,6 +404,11 @@ off the covering item first.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'clothing', 'key': 'remove', 'tags': '', 'text': "\n Takes off an item of clothing.\n\n Usage:\n remove <obj>\n\n Removes an item of clothing you are wearing. You can't remove\n clothes that are covered up by something else - you must take\n off the covering item first.\n "}
    +
    +
    @@ -439,6 +449,11 @@ You can’t remove an item of clothing if it’s covered.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'clothing', 'key': 'cover', 'tags': '', 'text': "\n Covers a worn item of clothing with another you're holding or wearing.\n\n Usage:\n cover <obj> [with] <obj>\n\n When you cover a clothing item, it is hidden and no longer appears in\n your description until it's uncovered or the item covering it is removed.\n You can't remove an item of clothing if it's covered.\n "}
    +
    +
    @@ -480,6 +495,11 @@ it is also covered by something else.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'clothing', 'key': 'uncover', 'tags': '', 'text': "\n Reveals a worn item of clothing that's currently covered up.\n\n Usage:\n uncover <obj>\n\n When you uncover an item of clothing, you allow it to appear in your\n description without having to take off the garment that's currently\n covering it. You can't uncover an item of clothing if the item covering\n it is also covered by something else.\n "}
    +
    +
    @@ -529,6 +549,11 @@ location you are currently in.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'drop', 'tags': '', 'text': '\n drop something\n\n Usage:\n drop <obj>\n\n Lets you drop an object from your inventory into the\n location you are currently in.\n '}
    +
    +
    @@ -578,6 +603,11 @@ placing it in their inventory.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'give', 'tags': '', 'text': '\n give away something to someone\n\n Usage:\n give <inventory obj> = <target>\n\n Gives an items from your inventory to another character,\n placing it in their inventory.\n '}
    +
    +
    @@ -598,7 +628,7 @@ inv

    -aliases = ['inv', 'i']
    +aliases = ['i', 'inv']
    @@ -627,6 +657,11 @@ inv

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'i inv', 'category': 'general', 'key': 'inventory', 'tags': '', 'text': '\n view inventory\n\n Usage:\n inventory\n inv\n\n Shows your inventory.\n '}
    +
    +
    @@ -700,7 +735,6 @@ items.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.color_markups.html b/docs/0.9.5/api/evennia.contrib.color_markups.html index 2678a9485e..28cebf5845 100644 --- a/docs/0.9.5/api/evennia.contrib.color_markups.html +++ b/docs/0.9.5/api/evennia.contrib.color_markups.html @@ -126,7 +126,6 @@ COLOR_ANSI_BRIGHT_BGS_EXTRA_MAP = color_markups.CURLY_COLOR_ANSI_BRIGHT_BGS_EXTR
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.custom_gametime.html b/docs/0.9.5/api/evennia.contrib.custom_gametime.html index 356e559117..57e80e9d5d 100644 --- a/docs/0.9.5/api/evennia.contrib.custom_gametime.html +++ b/docs/0.9.5/api/evennia.contrib.custom_gametime.html @@ -313,7 +313,6 @@ The time is given in units as keyword arguments.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.dice.html b/docs/0.9.5/api/evennia.contrib.dice.html index d6cb2e2b02..04b8a5a026 100644 --- a/docs/0.9.5/api/evennia.contrib.dice.html +++ b/docs/0.9.5/api/evennia.contrib.dice.html @@ -173,6 +173,11 @@ everyone but the person rolling.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '@dice roll', 'category': 'general', 'key': 'dice', 'tags': '', 'text': "\n roll dice\n\n Usage:\n dice[/switch] <nr>d<sides> [modifier] [success condition]\n\n Switch:\n hidden - tell the room the roll is being done, but don't show the result\n secret - don't inform the room about neither roll nor result\n\n Examples:\n dice 3d6 + 4\n dice 1d100 - 2 < 50\n\n This will roll the given number of dice with given sides and modifiers.\n So e.g. 2d6 + 3 means to 'roll a 6-sided die 2 times and add the result,\n then add 3 to the total'.\n Accepted modifiers are +, -, * and /.\n A success condition is given as normal Python conditionals\n (<,>,<=,>=,==,!=). So e.g. 2d6 + 3 > 10 means that the roll will succeed\n only if the final result is above 8. If a success condition is given, the\n outcome (pass/fail) will be echoed along with how much it succeeded/failed\n with. The hidden/secret switches will hide all or parts of the roll from\n everyone but the person rolling.\n "}
    +
    +
    @@ -239,7 +244,6 @@ Add with @py self.cmdset.add(“contrib.dice.DiceCmdSet”)

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.email_login.html b/docs/0.9.5/api/evennia.contrib.email_login.html index 812aff1b46..b4b9ce8b39 100644 --- a/docs/0.9.5/api/evennia.contrib.email_login.html +++ b/docs/0.9.5/api/evennia.contrib.email_login.html @@ -74,7 +74,7 @@ the module given by settings.CONNECTION_SCREEN_MODULE.

    -aliases = ['conn', 'co', 'con']
    +aliases = ['co', 'con', 'conn']
    @@ -102,6 +102,11 @@ there is no object yet before the account has logged in)

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'co con conn', 'category': 'general', 'key': 'connect', 'tags': '', 'text': '\n Connect to the game.\n\n Usage (at login screen):\n connect <email> <password>\n\n Use the create command to first create an account before logging in.\n '}
    +
    +
    @@ -155,6 +160,11 @@ name enclosed in quotes:

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'cre cr', 'category': 'general', 'key': 'create', 'tags': '', 'text': '\n Create a new account.\n\n Usage (at login screen):\n create "accountname" <email> <password>\n\n This creates a new account account.\n\n '}
    +
    +
    @@ -195,6 +205,11 @@ version is a bit more complicated.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'qu q', 'category': 'general', 'key': 'quit', 'tags': '', 'text': '\n We maintain a different version of the `quit` command\n here for unconnected accounts for the sake of simplicity. The logged in\n version is a bit more complicated.\n '}
    +
    +
    @@ -235,6 +250,11 @@ All it does is display the connect screen.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'l look', 'category': 'general', 'key': '__unloggedin_look_command', 'tags': '', 'text': '\n This is an unconnected version of the `look` command for simplicity.\n\n This is called by the server and kicks everything in gear.\n All it does is display the connect screen.\n '}
    +
    +
    @@ -250,7 +270,7 @@ for simplicity. It shows a pane of info.

    -aliases = ['h', '?']
    +aliases = ['?', 'h']
    @@ -274,6 +294,11 @@ for simplicity. It shows a pane of info.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '? h', 'category': 'general', 'key': 'help', 'tags': '', 'text': '\n This is an unconnected version of the help command,\n for simplicity. It shows a pane of info.\n '}
    +
    +
    @@ -321,7 +346,6 @@ for simplicity. It shows a pane of info.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.extended_room.html b/docs/0.9.5/api/evennia.contrib.extended_room.html index b2896188a4..32590f9f50 100644 --- a/docs/0.9.5/api/evennia.contrib.extended_room.html +++ b/docs/0.9.5/api/evennia.contrib.extended_room.html @@ -294,6 +294,11 @@ look *<account&g lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'l ls', 'category': 'general', 'key': 'look', 'tags': '', 'text': '\n look\n\n Usage:\n look\n look <obj>\n look <room detail>\n look *<account>\n\n Observes your location, details at your location or objects in your vicinity.\n '}
    +
    +
    @@ -357,6 +362,11 @@ version of the desc command.

    lock_storage = 'cmd:perm(desc) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': 'describe', 'category': 'building', 'key': 'desc', 'tags': '', 'text': '\n `desc` - describe an object or room.\n\n Usage:\n desc[/switch] [<obj> =] <description>\n\n Switches for `desc`:\n spring - set description for <season> in current room.\n summer\n autumn\n winter\n\n Sets the "desc" attribute on an object. If an object is not given,\n describe the current room.\n\n You can also embed special time markers in your room description, like this:\n\n ```\n <night>In the darkness, the forest looks foreboding.</night>.\n ```\n\n Text marked this way will only display when the server is truly at the given\n timeslot. The available times are night, morning, afternoon and evening.\n\n Note that seasons and time-of-day slots only work on rooms in this\n version of the `desc` command.\n\n '}
    +
    +
    @@ -415,6 +425,11 @@ to all the variables defined therein.

    lock_storage = 'cmd:perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'building', 'key': '@detail', 'tags': '', 'text': '\n sets a detail on a room\n\n Usage:\n @detail[/del] <key> [= <description>]\n @detail <key>;<alias>;... = description\n\n Example:\n @detail\n @detail walls = The walls are covered in ...\n @detail castle;ruin;tower = The distant ruin ...\n @detail/del wall\n @detail/del castle;ruin;tower\n\n This command allows to show the current room details if you enter it\n without any argument. Otherwise, sets or deletes a detail on the current\n room, if this room supports details like an extended room. To add new\n detail, just use the @detail command, specifying the key, an equal sign\n and the description. You can assign the same description to several\n details using the alias syntax (replace key by alias1;alias2;alias3;...).\n To remove one or several details, use the @detail/del switch.\n\n '}
    +
    +
    @@ -458,6 +473,11 @@ to all the variables defined therein.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'time', 'tags': '', 'text': '\n Check the game time\n\n Usage:\n time\n\n Shows the current in-game time and season.\n '}
    +
    +
    @@ -525,7 +545,6 @@ self.add().

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.fieldfill.html b/docs/0.9.5/api/evennia.contrib.fieldfill.html index 52f3f0cd72..a1956a41d5 100644 --- a/docs/0.9.5/api/evennia.contrib.fieldfill.html +++ b/docs/0.9.5/api/evennia.contrib.fieldfill.html @@ -364,6 +364,11 @@ send

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'testmenu', 'tags': '', 'text': "\n This test command will initialize a menu that presents you with a form.\n You can fill out the fields of this form in any order, and then type in\n 'send' to send a message to another online player, which will reach them\n after a delay you specify.\n\n Usage:\n <field> = <new value>\n clear <field>\n help\n look\n quit\n send\n "}
    +
    +
    @@ -439,7 +444,6 @@ send

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.gendersub.html b/docs/0.9.5/api/evennia.contrib.gendersub.html index 2d68a00072..fa5ca5d3a7 100644 --- a/docs/0.9.5/api/evennia.contrib.gendersub.html +++ b/docs/0.9.5/api/evennia.contrib.gendersub.html @@ -110,6 +110,11 @@ default cmdset before it becomes available.

    lock_storage = 'cmd:all();call:all()'
    +
    +
    +search_index_entry = {'aliases': '@sex', 'category': 'general', 'key': '@gender', 'tags': '', 'text': '\n Sets gender on yourself\n\n Usage:\n @gender male||female||neutral||ambiguous\n\n '}
    +
    +
    @@ -218,7 +223,6 @@ All extra kwargs will be passed on to the protocol.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.health_bar.html b/docs/0.9.5/api/evennia.contrib.health_bar.html index e3662ed471..2749337f73 100644 --- a/docs/0.9.5/api/evennia.contrib.health_bar.html +++ b/docs/0.9.5/api/evennia.contrib.health_bar.html @@ -141,7 +141,6 @@ readers will be unable to read the graphical aspect of the bar.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.html b/docs/0.9.5/api/evennia.contrib.html index fc7117bfd8..f13b345abd 100644 --- a/docs/0.9.5/api/evennia.contrib.html +++ b/docs/0.9.5/api/evennia.contrib.html @@ -105,7 +105,10 @@ useful but are deemed too game-specific to go into the core library.

  • evennia.contrib.tutorial_examples.bodyfunctions
  • evennia.contrib.tutorial_examples.cmdset_red_button
  • evennia.contrib.tutorial_examples.example_batch_code
  • -
  • evennia.contrib.tutorial_examples.red_button
  • +
  • evennia.contrib.tutorial_examples.red_button +
  • evennia.contrib.tutorial_examples.red_button_scripts
  • evennia.contrib.tutorial_examples.tests
  • @@ -164,7 +167,6 @@ useful but are deemed too game-specific to go into the core library.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.ingame_python.callbackhandler.html b/docs/0.9.5/api/evennia.contrib.ingame_python.callbackhandler.html index 1069cf418e..02a30520eb 100644 --- a/docs/0.9.5/api/evennia.contrib.ingame_python.callbackhandler.html +++ b/docs/0.9.5/api/evennia.contrib.ingame_python.callbackhandler.html @@ -319,7 +319,6 @@ the expected fields for a callback (code, author, valid…).

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.ingame_python.commands.html b/docs/0.9.5/api/evennia.contrib.ingame_python.commands.html index 88f41821af..9fc394bd69 100644 --- a/docs/0.9.5/api/evennia.contrib.ingame_python.commands.html +++ b/docs/0.9.5/api/evennia.contrib.ingame_python.commands.html @@ -131,6 +131,11 @@ on user permission.

    lock_storage = 'cmd:perm(developer)'
    +
    +
    +search_index_entry = {'aliases': '@calls @callbacks @callback', 'category': 'building', 'key': '@call', 'tags': '', 'text': '\n Command to edit callbacks.\n '}
    +
    + @@ -178,7 +183,6 @@ on user permission.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.ingame_python.eventfuncs.html b/docs/0.9.5/api/evennia.contrib.ingame_python.eventfuncs.html index d24125b113..a5363a745f 100644 --- a/docs/0.9.5/api/evennia.contrib.ingame_python.eventfuncs.html +++ b/docs/0.9.5/api/evennia.contrib.ingame_python.eventfuncs.html @@ -151,7 +151,6 @@ to be called from inside another event.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.ingame_python.html b/docs/0.9.5/api/evennia.contrib.ingame_python.html index 5340a53855..4c2b68f5d5 100644 --- a/docs/0.9.5/api/evennia.contrib.ingame_python.html +++ b/docs/0.9.5/api/evennia.contrib.ingame_python.html @@ -95,7 +95,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.ingame_python.scripts.html b/docs/0.9.5/api/evennia.contrib.ingame_python.scripts.html index 3a779026f7..a577ba758c 100644 --- a/docs/0.9.5/api/evennia.contrib.ingame_python.scripts.html +++ b/docs/0.9.5/api/evennia.contrib.ingame_python.scripts.html @@ -56,8 +56,8 @@ editing and deleting these events and callbacks.

    -
    -at_start()[source]
    +
    +at_server_start()[source]

    Set up the event system when starting.

    Note that this hook is called every time the server restarts (including when it’s reloaded). This hook performs the following @@ -440,7 +440,6 @@ restart only twice.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.ingame_python.tests.html b/docs/0.9.5/api/evennia.contrib.ingame_python.tests.html index ddf53aa8fd..95000e9f21 100644 --- a/docs/0.9.5/api/evennia.contrib.ingame_python.tests.html +++ b/docs/0.9.5/api/evennia.contrib.ingame_python.tests.html @@ -226,7 +226,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.ingame_python.typeclasses.html b/docs/0.9.5/api/evennia.contrib.ingame_python.typeclasses.html index 12cf7f4efd..faa3fa7c11 100644 --- a/docs/0.9.5/api/evennia.contrib.ingame_python.typeclasses.html +++ b/docs/0.9.5/api/evennia.contrib.ingame_python.typeclasses.html @@ -84,7 +84,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.ingame_python.utils.html b/docs/0.9.5/api/evennia.contrib.ingame_python.utils.html index 575050c618..3182edf9c1 100644 --- a/docs/0.9.5/api/evennia.contrib.ingame_python.utils.html +++ b/docs/0.9.5/api/evennia.contrib.ingame_python.utils.html @@ -204,7 +204,6 @@ either “yes” or “okay” (maybe ‘say I don’t like it, but okay’).

    0.9.5 (v0.9.5 branch) -
    diff --git a/docs/0.9.5/api/evennia.contrib.mail.html b/docs/0.9.5/api/evennia.contrib.mail.html index 67d4fb3510..adccb92052 100644 --- a/docs/0.9.5/api/evennia.contrib.mail.html +++ b/docs/0.9.5/api/evennia.contrib.mail.html @@ -218,6 +218,11 @@ the newly created mails.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': 'mail', 'category': 'general', 'key': '@mail', 'tags': '', 'text': '\n Communicate with others by sending mail.\n\n Usage:\n @mail - Displays all the mail an account has in their mailbox\n @mail <#> - Displays a specific message\n @mail <accounts>=<subject>/<message>\n - Sends a message to the comma separated list of accounts.\n @mail/delete <#> - Deletes a specific message\n @mail/forward <account list>=<#>[/<Message>]\n - Forwards an existing message to the specified list of accounts,\n original message is delivered with optional Message prepended.\n @mail/reply <#>=<message>\n - Replies to a message #. Prepends message to the original\n message text.\n Switches:\n delete - deletes a message\n forward - forward a received message to another object with an optional message attached.\n reply - Replies to a received message, appending the original message to the bottom.\n Examples:\n @mail 2\n @mail Griatch=New mail/Hey man, I am sending you a message!\n @mail/delete 6\n @mail/forward feend78 Griatch=4/You guys should read this.\n @mail/reply 9=Thanks for the info!\n\n '}
    +
    +
    @@ -286,6 +291,11 @@ reply - Replies to a received message, appending the original message to the b lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': 'mail', 'category': 'general', 'key': '@mail', 'tags': '', 'text': '\n Communicate with others by sending mail.\n\n Usage:\n @mail - Displays all the mail an account has in their mailbox\n @mail <#> - Displays a specific message\n @mail <accounts>=<subject>/<message>\n - Sends a message to the comma separated list of accounts.\n @mail/delete <#> - Deletes a specific message\n @mail/forward <account list>=<#>[/<Message>]\n - Forwards an existing message to the specified list of accounts,\n original message is delivered with optional Message prepended.\n @mail/reply <#>=<message>\n - Replies to a message #. Prepends message to the original\n message text.\n Switches:\n delete - deletes a message\n forward - forward a received message to another object with an optional message attached.\n reply - Replies to a received message, appending the original message to the bottom.\n Examples:\n @mail 2\n @mail Griatch=New mail/Hey man, I am sending you a message!\n @mail/delete 6\n @mail/forward feend78 Griatch=4/You guys should read this.\n @mail/reply 9=Thanks for the info!\n\n '}
    +
    + @@ -333,7 +343,6 @@ reply - Replies to a received message, appending the original message to the b
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.mapbuilder.html b/docs/0.9.5/api/evennia.contrib.mapbuilder.html index c2e7d89fe1..5abfd4c943 100644 --- a/docs/0.9.5/api/evennia.contrib.mapbuilder.html +++ b/docs/0.9.5/api/evennia.contrib.mapbuilder.html @@ -84,7 +84,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.menu_login.html b/docs/0.9.5/api/evennia.contrib.menu_login.html index 12e96a41c4..ad55936d1d 100644 --- a/docs/0.9.5/api/evennia.contrib.menu_login.html +++ b/docs/0.9.5/api/evennia.contrib.menu_login.html @@ -84,7 +84,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.multidescer.html b/docs/0.9.5/api/evennia.contrib.multidescer.html index ddf50da9df..a82cb49109 100644 --- a/docs/0.9.5/api/evennia.contrib.multidescer.html +++ b/docs/0.9.5/api/evennia.contrib.multidescer.html @@ -116,6 +116,11 @@ description in use and db.multidesc to store all descriptions.< lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'desc', 'category': 'general', 'key': '+desc', 'tags': '', 'text': '\n Manage multiple descriptions\n\n Usage:\n +desc [key] - show current desc desc with <key>\n +desc <key> = <text> - add/replace desc with <key>\n +desc/list - list descriptions (abbreviated)\n +desc/list/full - list descriptions (full texts)\n +desc/edit <key> - add/edit desc <key> in line editor\n +desc/del <key> - delete desc <key>\n +desc/swap <key1>-<key2> - swap positions of <key1> and <key2> in list\n +desc/set <key> [+key+...] - set desc as default or combine multiple descs\n\n Notes:\n When combining multiple descs with +desc/set <key> + <key2> + ...,\n any keys not matching an actual description will be inserted\n as plain text. Use e.g. ansi line break ||/ to add a new\n paragraph and + + or ansi space ||_ to add extra whitespace.\n\n '}
    +
    + @@ -163,7 +168,6 @@ description in use and db.multidesc to store all descriptions.<
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.puzzles.html b/docs/0.9.5/api/evennia.contrib.puzzles.html index 45c205d49f..c04043eddc 100644 --- a/docs/0.9.5/api/evennia.contrib.puzzles.html +++ b/docs/0.9.5/api/evennia.contrib.puzzles.html @@ -206,6 +206,11 @@ to all the variables defined therein.

    lock_storage = 'cmd:perm(puzzle) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': '@puzzlerecipe', 'category': 'puzzles', 'key': '@puzzle', 'tags': '', 'text': "\n Creates a puzzle recipe. A puzzle consists of puzzle-parts that\n the player can 'use' together to create a specified result.\n\n Usage:\n @puzzle name,<part1[,part2,...>] = <result1[,result2,...]>\n\n Example:\n create/drop balloon\n create/drop glass of water\n create/drop water balloon\n @puzzle waterballon,balloon,glass of water = water balloon\n @del ballon, glass of water, water balloon\n @armpuzzle #1\n\n Notes:\n Each part and result are objects that must (temporarily) exist and be placed in their\n corresponding location in order to create the puzzle. After the creation of the puzzle,\n these objects are not needed anymore and can be deleted. Components of the puzzle\n will be re-created by use of the `@armpuzzle` command later.\n\n "}
    +
    +
    @@ -269,6 +274,11 @@ to all the variables defined therein.

    lock_storage = 'cmd:perm(puzzleedit) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'puzzles', 'key': '@puzzleedit', 'tags': '', 'text': "\n Edits puzzle properties\n\n Usage:\n @puzzleedit[/delete] <#dbref>\n @puzzleedit <#dbref>/use_success_message = <Custom message>\n @puzzleedit <#dbref>/use_success_location_message = <Custom message from {caller} producing {result_names}>\n @puzzleedit <#dbref>/mask = attr1[,attr2,...]>\n @puzzleedit[/addpart] <#dbref> = <obj[,obj2,...]>\n @puzzleedit[/delpart] <#dbref> = <obj[,obj2,...]>\n @puzzleedit[/addresult] <#dbref> = <obj[,obj2,...]>\n @puzzleedit[/delresult] <#dbref> = <obj[,obj2,...]>\n\n Switches:\n addpart - adds parts to the puzzle\n delpart - removes parts from the puzzle\n addresult - adds results to the puzzle\n delresult - removes results from the puzzle\n delete - deletes the recipe. Existing parts and results aren't modified\n\n mask - attributes to exclude during matching (e.g. location, desc, etc.)\n use_success_location_message containing {result_names} and {caller} will\n automatically be replaced with correct values. Both are optional.\n\n When removing parts/results, it's possible to remove all.\n\n "}
    +
    +
    @@ -316,6 +326,11 @@ to all the variables defined therein.

    lock_storage = 'cmd:perm(armpuzzle) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'puzzles', 'key': '@armpuzzle', 'tags': '', 'text': '\n Arms a puzzle by spawning all its parts.\n\n Usage:\n @armpuzzle <puzzle #dbref>\n\n Notes:\n Create puzzles with `@puzzle`; get list of\n defined puzzles using `@lspuzzlerecipes`.\n\n '}
    +
    +
    @@ -364,6 +379,11 @@ to all the variables defined therein.

    lock_storage = 'cmd:pperm(use) or pperm(Player)'
    +
    +
    +search_index_entry = {'aliases': 'combine', 'category': 'puzzles', 'key': 'use', 'tags': '', 'text': '\n Use an object, or a group of objects at once.\n\n\n Example:\n You look around you and see a pole, a long string, and a needle.\n\n use pole, long string, needle\n\n Genius! You built a fishing pole.\n\n\n Usage:\n use <obj1> [,obj2,...]\n '}
    +
    +
    @@ -408,6 +428,11 @@ to all the variables defined therein.

    lock_storage = 'cmd:perm(lspuzzlerecipes) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'puzzles', 'key': '@lspuzzlerecipes', 'tags': '', 'text': '\n Searches for all puzzle recipes\n\n Usage:\n @lspuzzlerecipes\n '}
    +
    +
    @@ -452,6 +477,11 @@ to all the variables defined therein.

    lock_storage = 'cmd:perm(lsarmedpuzzles) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'puzzles', 'key': '@lsarmedpuzzles', 'tags': '', 'text': '\n Searches for all armed puzzles\n\n Usage:\n @lsarmedpuzzles\n '}
    +
    +
    @@ -519,7 +549,6 @@ self.add().

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.random_string_generator.html b/docs/0.9.5/api/evennia.contrib.random_string_generator.html index 9e8bc74100..551bf5effc 100644 --- a/docs/0.9.5/api/evennia.contrib.random_string_generator.html +++ b/docs/0.9.5/api/evennia.contrib.random_string_generator.html @@ -299,7 +299,6 @@ calling the get method.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.rplanguage.html b/docs/0.9.5/api/evennia.contrib.rplanguage.html index e6ed24c56c..73926c618a 100644 --- a/docs/0.9.5/api/evennia.contrib.rplanguage.html +++ b/docs/0.9.5/api/evennia.contrib.rplanguage.html @@ -98,18 +98,46 @@ words compared to the original and can help change the “feel” for the language you are creating. You can also add your own dictionary and “fix” random words for a list of input words.

    Below is an example of “elvish”, using “rounder” vowels and sounds:

    -
    phonemes = "oi oh ee ae aa eh ah ao aw ay er ey ow ia ih iy "                "oy ua uh uw y p b t d f v t dh s z sh zh ch jh k "                "ng g m n l r w",
    +
    # vowel/consonant grammar possibilities
    +grammar = ("v vv vvc vcc vvcc cvvc vccv vvccv vcvccv vcvcvcc vvccvvcc "
    +           "vcvvccvvc cvcvvcvvcc vcvcvvccvcvv")
    +
    +# all not in this group is considered a consonant
     vowels = "eaoiuy"
    -grammar = "v vv vvc vcc vvcc cvvc vccv vvccv vcvccv vcvcvcc vvccvvcc "               "vcvvccvvc cvcvvcvvcc vcvcvvccvcvv",
    +
    +# you need a representative of all of the minimal grammars here, so if a
    +# grammar v exists, there must be atleast one phoneme available with only
    +# one vowel in it
    +phonemes = ("oi oh ee ae aa eh ah ao aw ay er ey ow ia ih iy "
    +            "oy ua uh uw y p b t d f v t dh s z sh zh ch jh k "
    +            "ng g m n l r w")
    +
    +# how much the translation varies in length compared to the original. 0 is
    +# smallest, higher values give ever bigger randomness (including removing
    +# short words entirely)
     word_length_variance = 1
    +
    +# if a proper noun (word starting with capitalized letter) should be
    +# translated or not. If not (default) it means e.g. names will remain
    +# unchanged across languages.
    +noun_translate = False
    +
    +# all proper nouns (words starting with a capital letter not at the beginning
    +# of a sentence) can have either a postfix or -prefix added at all times
     noun_postfix = "'la"
    +
    +# words in dict will always be translated this way. The 'auto_translations'
    +# is instead a list or filename to file with words to use to help build a
    +# bigger dictionary by creating random translations of each word in the
    +# list *once* and saving the result for subsequent use.
     manual_translations = {"the":"y'e", "we":"uyi", "she":"semi", "he":"emi",
                           "you": "do", 'me':'mi','i':'me', 'be':"hy'e", 'and':'y'}
     
     rplanguage.add_language(key="elvish", phonemes=phonemes, grammar=grammar,
                              word_length_variance=word_length_variance,
    +                         noun_translate=noun_translate,
                              noun_postfix=noun_postfix, vowels=vowels,
    -                         manual_translations=manual_translations
    +                         manual_translations=manual_translations,
                              auto_translations="my_word_file.txt")
     
    @@ -190,9 +218,13 @@ cvcvccc would be c+v+c+v+cc+c (a word like ‘galosch’).

    0 means a minimal variance, higher variance may mean words have wildly varying length; this strongly affects how the language “looks”.

    -
  • noun_translate (bool, optional) – If a proper noun, identified as a -capitalized word, should be translated or not. By default they -will not, allowing for e.g. the names of characters to be understandable.

  • +
  • noun_translate (bool, optional) – If a proper noun should be translated or +not. By default they will not, allowing for e.g. the names of characters +to be understandable. A ‘noun’ is identified as a capitalized word +not at the start of a sentence. This simple metric means that names +starting a sentence always will be translated (- but hey, maybe +the fantasy language just never uses a noun at the beginning of +sentences, who knows?)

  • noun_prefix (str, optional) – A prefix to go before every noun in this language (if any).

  • noun_postfix (str, optuonal) – A postfix to go after every noun @@ -379,7 +411,6 @@ means fully obscured.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.rpsystem.html b/docs/0.9.5/api/evennia.contrib.rpsystem.html index b155bd9c56..e77d158964 100644 --- a/docs/0.9.5/api/evennia.contrib.rpsystem.html +++ b/docs/0.9.5/api/evennia.contrib.rpsystem.html @@ -266,7 +266,10 @@ langname can be None.

    Raises
    -

    rplanguage.LanguageError – If an invalid language was specified.

    +

    Notes

    @@ -551,6 +554,11 @@ mechanism. This is useful for adding masks/hoods etc.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'command', 'tags': '', 'text': 'simple parent'}
    +
    +
    @@ -604,6 +612,11 @@ a different language.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': ':', 'category': 'general', 'key': 'emote', 'tags': '', 'text': '\n Emote an action, allowing dynamic replacement of\n text in the emote.\n\n Usage:\n emote text\n\n Example:\n emote /me looks around.\n emote With a flurry /me attacks /tall man with his sword.\n emote "Hello", /me says.\n\n Describes an event in the world. This allows the use of /ref\n markers to replace with the short descriptions or recognized\n strings of objects in the same room. These will be translated to\n emotes to match each person seeing it. Use "..." for saying\n things and langcode"..." without spaces to say something in\n a different language.\n\n '}
    +
    +
    @@ -623,7 +636,7 @@ a different language.

    -aliases = ['"', "'"]
    +aliases = ["'", '"']
    @@ -647,6 +660,11 @@ a different language.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '\' "', 'category': 'general', 'key': 'say', 'tags': '', 'text': '\n speak as your character\n\n Usage:\n say <message>\n\n Talk to those in your current location.\n '}
    +
    +
    @@ -690,6 +708,11 @@ a different language.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'sdesc', 'tags': '', 'text': '\n Assign yourself a short description (sdesc).\n\n Usage:\n sdesc <short description>\n\n Assigns a short description to yourself.\n\n '}
    +
    +
    @@ -748,6 +771,11 @@ sdesc in the emote, regardless of who is seeing it.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'pose', 'tags': '', 'text': "\n Set a static pose\n\n Usage:\n pose <pose>\n pose default <pose>\n pose reset\n pose obj = <pose>\n pose default obj = <pose>\n pose reset obj =\n\n Examples:\n pose leans against the tree\n pose is talking to the barkeep.\n pose box = is sitting on the floor.\n\n Set a static pose. This is the end of a full sentence that starts\n with your sdesc. If no full stop is given, it will be added\n automatically. The default pose is the pose you get when using\n pose reset. Note that you can use sdescs/recogs to reference\n people in your pose, but these always appear as that person's\n sdesc in the emote, regardless of who is seeing it.\n\n "}
    +
    +
    @@ -798,6 +826,11 @@ Using the command without arguments will list all current recogs.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': 'recognize forget', 'category': 'general', 'key': 'recog', 'tags': '', 'text': '\n Recognize another person in the same room.\n\n Usage:\n recog\n recog sdesc as alias\n forget alias\n\n Example:\n recog tall man as Griatch\n forget griatch\n\n This will assign a personal alias for a person, or forget said alias.\n Using the command without arguments will list all current recogs.\n\n '}
    +
    +
    @@ -842,6 +875,11 @@ set in self.parse())

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': 'unmask', 'category': 'general', 'key': 'mask', 'tags': '', 'text': "\n Wear a mask\n\n Usage:\n mask <new sdesc>\n unmask\n\n This will put on a mask to hide your identity. When wearing\n a mask, your sdesc will be replaced by the sdesc you pick and\n people's recognitions of you will be disabled.\n\n "}
    +
    +
    @@ -1250,7 +1288,6 @@ the evennia.contrib.rplanguage module.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.security.auditing.html b/docs/0.9.5/api/evennia.contrib.security.auditing.html index 2cfcea96ce..2ae0b2299c 100644 --- a/docs/0.9.5/api/evennia.contrib.security.auditing.html +++ b/docs/0.9.5/api/evennia.contrib.security.auditing.html @@ -91,7 +91,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.security.auditing.outputs.html b/docs/0.9.5/api/evennia.contrib.security.auditing.outputs.html index 88b9255ebe..eb7ef25c07 100644 --- a/docs/0.9.5/api/evennia.contrib.security.auditing.outputs.html +++ b/docs/0.9.5/api/evennia.contrib.security.auditing.outputs.html @@ -126,7 +126,6 @@ compromised or taken down, losing your logs along with it is no help!).

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.security.auditing.server.html b/docs/0.9.5/api/evennia.contrib.security.auditing.server.html index 6d3e573a53..f0c2e02bb5 100644 --- a/docs/0.9.5/api/evennia.contrib.security.auditing.server.html +++ b/docs/0.9.5/api/evennia.contrib.security.auditing.server.html @@ -165,7 +165,6 @@ writing to log. Recording cleartext password attempts is bad policy.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.security.auditing.tests.html b/docs/0.9.5/api/evennia.contrib.security.auditing.tests.html index d0e27a33e0..1de3dd3e37 100644 --- a/docs/0.9.5/api/evennia.contrib.security.auditing.tests.html +++ b/docs/0.9.5/api/evennia.contrib.security.auditing.tests.html @@ -105,7 +105,6 @@ parsed from the Session object.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.security.html b/docs/0.9.5/api/evennia.contrib.security.html index dd7eed7cbe..8bc62c23e2 100644 --- a/docs/0.9.5/api/evennia.contrib.security.html +++ b/docs/0.9.5/api/evennia.contrib.security.html @@ -94,7 +94,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.simpledoor.html b/docs/0.9.5/api/evennia.contrib.simpledoor.html index e89e8c3b75..b4fa5751c5 100644 --- a/docs/0.9.5/api/evennia.contrib.simpledoor.html +++ b/docs/0.9.5/api/evennia.contrib.simpledoor.html @@ -180,6 +180,11 @@ unique.

    lock_storage = 'cmd:perm(open) or perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'building', 'key': 'open', 'tags': '', 'text': '\n open a new exit from the current room\n\n Usage:\n open <new exit>[;alias;alias..][:typeclass] [,<return exit>[;alias;..][:typeclass]]] = <destination>\n\n Handles the creation of exits. If a destination is given, the exit\n will point there. The <return exit> argument sets up an exit at the\n destination leading back to the current room. Destination name\n can be given both as a #dbref and a name, if that name is globally\n unique.\n\n '}
    +
    +
    @@ -223,6 +228,11 @@ close <door>

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'close', 'category': 'general', 'key': 'open', 'tags': '', 'text': '\n Open and close a door\n\n Usage:\n open <door>\n close <door>\n\n '}
    +
    + @@ -270,7 +280,6 @@ close <door>

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.slow_exit.html b/docs/0.9.5/api/evennia.contrib.slow_exit.html index d8e160df36..6068da69ef 100644 --- a/docs/0.9.5/api/evennia.contrib.slow_exit.html +++ b/docs/0.9.5/api/evennia.contrib.slow_exit.html @@ -134,6 +134,11 @@ is assumed.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'setspeed', 'tags': '', 'text': "\n set your movement speed\n\n Usage:\n setspeed stroll|walk|run|sprint\n\n This will set your movement speed, determining how long time\n it takes to traverse exits. If no speed is set, 'walk' speed\n is assumed.\n "}
    +
    +
    @@ -173,6 +178,11 @@ stored deferred from the exit traversal above.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'stop', 'tags': '', 'text': '\n stop moving\n\n Usage:\n stop\n\n Stops the current movement, if any.\n '}
    +
    + @@ -220,7 +230,6 @@ stored deferred from the exit traversal above.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.talking_npc.html b/docs/0.9.5/api/evennia.contrib.talking_npc.html index 4650e2be3c..1a9a8ab6e7 100644 --- a/docs/0.9.5/api/evennia.contrib.talking_npc.html +++ b/docs/0.9.5/api/evennia.contrib.talking_npc.html @@ -121,6 +121,11 @@ that NPC and give you options on what to talk about.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'talk', 'tags': '', 'text': '\n Talks to an npc\n\n Usage:\n talk\n\n This command is only available if a talkative non-player-character\n (NPC) is actually present. It will strike up a conversation with\n that NPC and give you options on what to talk about.\n '}
    +
    +
    @@ -227,7 +232,6 @@ the conversation defined above.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.tree_select.html b/docs/0.9.5/api/evennia.contrib.tree_select.html index 0a6bb538a9..68cf9ad4ac 100644 --- a/docs/0.9.5/api/evennia.contrib.tree_select.html +++ b/docs/0.9.5/api/evennia.contrib.tree_select.html @@ -370,6 +370,11 @@ set in self.parse())

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'namecolor', 'tags': '', 'text': '\n Set or remove a special color on your name. Just an example for the\n easy menu selection tree contrib.\n '}
    +
    +
    @@ -434,7 +439,6 @@ to determine the color the player chose.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.turnbattle.html b/docs/0.9.5/api/evennia.contrib.turnbattle.html index c5368c166a..b6543a9452 100644 --- a/docs/0.9.5/api/evennia.contrib.turnbattle.html +++ b/docs/0.9.5/api/evennia.contrib.turnbattle.html @@ -93,7 +93,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.turnbattle.tb_basic.html b/docs/0.9.5/api/evennia.contrib.turnbattle.tb_basic.html index 20175fbd6b..a0a39adf74 100644 --- a/docs/0.9.5/api/evennia.contrib.turnbattle.tb_basic.html +++ b/docs/0.9.5/api/evennia.contrib.turnbattle.tb_basic.html @@ -501,6 +501,11 @@ When it’s your turn, you can attack other characters.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'fight', 'tags': '', 'text': "\n Starts a fight with everyone in the same room as you.\n\n Usage:\n fight\n\n When you start a fight, everyone in the room who is able to\n fight is added to combat, and a turn order is randomly rolled.\n When it's your turn, you can attack other characters.\n "}
    +
    +
    @@ -540,6 +545,11 @@ a chance to hit, and if successful, will deal damage.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'attack', 'tags': '', 'text': '\n Attacks another character.\n\n Usage:\n attack <target>\n\n When in a fight, you may attack another character. The attack has\n a chance to hit, and if successful, will deal damage.\n '}
    +
    +
    @@ -579,6 +589,11 @@ if there are still any actions you can take.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': 'wait hold', 'category': 'combat', 'key': 'pass', 'tags': '', 'text': '\n Passes on your turn.\n\n Usage:\n pass\n\n When in a fight, you can use this command to end your turn early, even\n if there are still any actions you can take.\n '}
    +
    +
    @@ -619,6 +634,11 @@ fight ends.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': 'spare', 'category': 'combat', 'key': 'disengage', 'tags': '', 'text': "\n Passes your turn and attempts to end combat.\n\n Usage:\n disengage\n\n Ends your turn early and signals that you're trying to end\n the fight. If all participants in a fight disengage, the\n fight ends.\n "}
    +
    +
    @@ -658,6 +678,11 @@ rest if you’re not in a fight.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'rest', 'tags': '', 'text': "\n Recovers damage.\n\n Usage:\n rest\n\n Resting recovers your HP to its maximum, but you can only\n rest if you're not in a fight.\n "}
    +
    +
    @@ -699,6 +724,11 @@ topics related to the game.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '?', 'category': 'general', 'key': 'help', 'tags': '', 'text': '\n View help or a list of topics\n\n Usage:\n help <topic or command>\n help list\n help all\n\n This will search for help on commands and other\n topics related to the game.\n '}
    +
    +
    @@ -769,7 +799,6 @@ topics related to the game.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.turnbattle.tb_equip.html b/docs/0.9.5/api/evennia.contrib.turnbattle.tb_equip.html index 4eac6b6cf7..63d9742d2d 100644 --- a/docs/0.9.5/api/evennia.contrib.turnbattle.tb_equip.html +++ b/docs/0.9.5/api/evennia.contrib.turnbattle.tb_equip.html @@ -618,6 +618,11 @@ When it’s your turn, you can attack other characters.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'fight', 'tags': '', 'text': "\n Starts a fight with everyone in the same room as you.\n\n Usage:\n fight\n\n When you start a fight, everyone in the room who is able to\n fight is added to combat, and a turn order is randomly rolled.\n When it's your turn, you can attack other characters.\n "}
    +
    +
    @@ -657,6 +662,11 @@ a chance to hit, and if successful, will deal damage.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'attack', 'tags': '', 'text': '\n Attacks another character.\n\n Usage:\n attack <target>\n\n When in a fight, you may attack another character. The attack has\n a chance to hit, and if successful, will deal damage.\n '}
    +
    +
    @@ -696,6 +706,11 @@ if there are still any actions you can take.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': 'wait hold', 'category': 'combat', 'key': 'pass', 'tags': '', 'text': '\n Passes on your turn.\n\n Usage:\n pass\n\n When in a fight, you can use this command to end your turn early, even\n if there are still any actions you can take.\n '}
    +
    +
    @@ -736,6 +751,11 @@ fight ends.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': 'spare', 'category': 'combat', 'key': 'disengage', 'tags': '', 'text': "\n Passes your turn and attempts to end combat.\n\n Usage:\n disengage\n\n Ends your turn early and signals that you're trying to end\n the fight. If all participants in a fight disengage, the\n fight ends.\n "}
    +
    +
    @@ -775,6 +795,11 @@ rest if you’re not in a fight.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'rest', 'tags': '', 'text': "\n Recovers damage.\n\n Usage:\n rest\n\n Resting recovers your HP to its maximum, but you can only\n rest if you're not in a fight.\n "}
    +
    +
    @@ -816,6 +841,11 @@ topics related to the game.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '?', 'category': 'general', 'key': 'help', 'tags': '', 'text': '\n View help or a list of topics\n\n Usage:\n help <topic or command>\n help list\n help all\n\n This will search for help on commands and other\n topics related to the game.\n '}
    +
    +
    @@ -859,6 +889,11 @@ currently wielding.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'wield', 'tags': '', 'text': '\n Wield a weapon you are carrying\n\n Usage:\n wield <weapon>\n\n Select a weapon you are carrying to wield in combat. If\n you are already wielding another weapon, you will switch\n to the weapon you specify instead. Using this command in\n combat will spend your action for your turn. Use the\n "unwield" command to stop wielding any weapon you are\n currently wielding.\n '}
    +
    +
    @@ -898,6 +933,11 @@ weapon you are currently wielding and become unarmed.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'unwield', 'tags': '', 'text': '\n Stop wielding a weapon.\n\n Usage:\n unwield\n\n After using this command, you will stop wielding any\n weapon you are currently wielding and become unarmed.\n '}
    +
    +
    @@ -938,6 +978,11 @@ command to remove any armor you are wearing.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'don', 'tags': '', 'text': '\n Don armor that you are carrying\n\n Usage:\n don <armor>\n\n Select armor to wear in combat. You can\'t use this\n command in the middle of a fight. Use the "doff"\n command to remove any armor you are wearing.\n '}
    +
    +
    @@ -978,6 +1023,11 @@ You can’t use this command in combat.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'doff', 'tags': '', 'text': "\n Stop wearing armor.\n\n Usage:\n doff\n\n After using this command, you will stop wearing any\n armor you are currently using and become unarmored.\n You can't use this command in combat.\n "}
    +
    +
    @@ -1048,7 +1098,6 @@ You can’t use this command in combat.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.turnbattle.tb_items.html b/docs/0.9.5/api/evennia.contrib.turnbattle.tb_items.html index 7f38ac5186..879c0e3e8d 100644 --- a/docs/0.9.5/api/evennia.contrib.turnbattle.tb_items.html +++ b/docs/0.9.5/api/evennia.contrib.turnbattle.tb_items.html @@ -652,6 +652,11 @@ When it’s your turn, you can attack other characters.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'fight', 'tags': '', 'text': "\n Starts a fight with everyone in the same room as you.\n\n Usage:\n fight\n\n When you start a fight, everyone in the room who is able to\n fight is added to combat, and a turn order is randomly rolled.\n When it's your turn, you can attack other characters.\n "}
    +
    +
    @@ -691,6 +696,11 @@ a chance to hit, and if successful, will deal damage.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'attack', 'tags': '', 'text': '\n Attacks another character.\n\n Usage:\n attack <target>\n\n When in a fight, you may attack another character. The attack has\n a chance to hit, and if successful, will deal damage.\n '}
    +
    +
    @@ -730,6 +740,11 @@ if there are still any actions you can take.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': 'wait hold', 'category': 'combat', 'key': 'pass', 'tags': '', 'text': '\n Passes on your turn.\n\n Usage:\n pass\n\n When in a fight, you can use this command to end your turn early, even\n if there are still any actions you can take.\n '}
    +
    +
    @@ -770,6 +785,11 @@ fight ends.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': 'spare', 'category': 'combat', 'key': 'disengage', 'tags': '', 'text': "\n Passes your turn and attempts to end combat.\n\n Usage:\n disengage\n\n Ends your turn early and signals that you're trying to end\n the fight. If all participants in a fight disengage, the\n fight ends.\n "}
    +
    +
    @@ -809,6 +829,11 @@ rest if you’re not in a fight.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'rest', 'tags': '', 'text': "\n Recovers damage.\n\n Usage:\n rest\n\n Resting recovers your HP to its maximum, but you can only\n rest if you're not in a fight.\n "}
    +
    +
    @@ -850,6 +875,11 @@ topics related to the game.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '?', 'category': 'general', 'key': 'help', 'tags': '', 'text': '\n View help or a list of topics\n\n Usage:\n help <topic or command>\n help list\n help all\n\n This will search for help on commands and other\n topics related to the game.\n '}
    +
    +
    @@ -890,6 +920,11 @@ to attack others, and as such can only be used in combat.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'use', 'tags': '', 'text': '\n Use an item.\n\n Usage:\n use <item> [= target]\n\n An item can have various function - looking at the item may\n provide information as to its effects. Some items can be used\n to attack others, and as such can only be used in combat.\n '}
    +
    +
    @@ -1043,7 +1078,6 @@ items using the same function work differently.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.turnbattle.tb_magic.html b/docs/0.9.5/api/evennia.contrib.turnbattle.tb_magic.html index bccc5d630d..6d63039b72 100644 --- a/docs/0.9.5/api/evennia.contrib.turnbattle.tb_magic.html +++ b/docs/0.9.5/api/evennia.contrib.turnbattle.tb_magic.html @@ -524,6 +524,11 @@ When it’s your turn, you can attack other characters.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'fight', 'tags': '', 'text': "\n Starts a fight with everyone in the same room as you.\n\n Usage:\n fight\n\n When you start a fight, everyone in the room who is able to\n fight is added to combat, and a turn order is randomly rolled.\n When it's your turn, you can attack other characters.\n "}
    +
    +
    @@ -563,6 +568,11 @@ a chance to hit, and if successful, will deal damage.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'attack', 'tags': '', 'text': '\n Attacks another character.\n\n Usage:\n attack <target>\n\n When in a fight, you may attack another character. The attack has\n a chance to hit, and if successful, will deal damage.\n '}
    +
    +
    @@ -602,6 +612,11 @@ if there are still any actions you can take.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': 'wait hold', 'category': 'combat', 'key': 'pass', 'tags': '', 'text': '\n Passes on your turn.\n\n Usage:\n pass\n\n When in a fight, you can use this command to end your turn early, even\n if there are still any actions you can take.\n '}
    +
    +
    @@ -642,6 +657,11 @@ fight ends.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': 'spare', 'category': 'combat', 'key': 'disengage', 'tags': '', 'text': "\n Passes your turn and attempts to end combat.\n\n Usage:\n disengage\n\n Ends your turn early and signals that you're trying to end\n the fight. If all participants in a fight disengage, the\n fight ends.\n "}
    +
    +
    @@ -695,6 +715,11 @@ fight ends.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'magic', 'key': 'learnspell', 'tags': '', 'text': "\n Learn a magic spell.\n\n Usage:\n learnspell <spell name>\n\n Adds a spell by name to your list of spells known.\n\n The following spells are provided as examples:\n\n |wmagic missile|n (3 MP): Fires three missiles that never miss. Can target\n up to three different enemies.\n\n |wflame shot|n (3 MP): Shoots a high-damage jet of flame at one target.\n\n |wcure wounds|n (5 MP): Heals damage on one target.\n\n |wmass cure wounds|n (10 MP): Like 'cure wounds', but can heal up to 5\n targets at once.\n\n |wfull heal|n (12 MP): Heals one target back to full HP.\n\n |wcactus conjuration|n (2 MP): Creates a cactus.\n "}
    +
    +
    @@ -742,6 +767,11 @@ function.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'magic', 'key': 'cast', 'tags': '', 'text': "\n Cast a magic spell that you know, provided you have the MP\n to spend on its casting.\n\n Usage:\n cast <spellname> [= <target1>, <target2>, etc...]\n\n Some spells can be cast on multiple targets, some can be cast\n on only yourself, and some don't need a target specified at all.\n Typing 'cast' by itself will give you a list of spells you know.\n "}
    +
    +
    @@ -781,6 +811,11 @@ only rest if you’re not in a fight.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'rest', 'tags': '', 'text': "\n Recovers damage and restores MP.\n\n Usage:\n rest\n\n Resting recovers your HP and MP to their maximum, but you can\n only rest if you're not in a fight.\n "}
    +
    +
    @@ -820,6 +855,11 @@ other targets in combat.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'status', 'tags': '', 'text': '\n Gives combat information.\n\n Usage:\n status\n\n Shows your current and maximum HP and your distance from\n other targets in combat.\n '}
    +
    +
    @@ -861,6 +901,11 @@ topics related to the game.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '?', 'category': 'general', 'key': 'help', 'tags': '', 'text': '\n View help or a list of topics\n\n Usage:\n help <topic or command>\n help list\n help all\n\n This will search for help on commands and other\n topics related to the game.\n '}
    +
    +
    @@ -982,7 +1027,6 @@ instead of creating objects directly.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.turnbattle.tb_range.html b/docs/0.9.5/api/evennia.contrib.turnbattle.tb_range.html index d7e6be2f4e..3207b565ef 100644 --- a/docs/0.9.5/api/evennia.contrib.turnbattle.tb_range.html +++ b/docs/0.9.5/api/evennia.contrib.turnbattle.tb_range.html @@ -815,6 +815,11 @@ When it’s your turn, you can attack other characters.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'fight', 'tags': '', 'text': "\n Starts a fight with everyone in the same room as you.\n\n Usage:\n fight\n\n When you start a fight, everyone in the room who is able to\n fight is added to combat, and a turn order is randomly rolled.\n When it's your turn, you can attack other characters.\n "}
    +
    +
    @@ -856,6 +861,11 @@ you. Use the ‘approach’ command to get closer to a target.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'attack', 'tags': '', 'text': "\n Attacks another character in melee.\n\n Usage:\n attack <target>\n\n When in a fight, you may attack another character. The attack has\n a chance to hit, and if successful, will deal damage. You can only\n attack engaged targets - that is, targets that are right next to\n you. Use the 'approach' command to get closer to a target.\n "}
    +
    +
    @@ -898,6 +908,11 @@ nearby enemies.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'shoot', 'tags': '', 'text': "\n Attacks another character from range.\n\n Usage:\n shoot <target>\n\n When in a fight, you may shoot another character. The attack has\n a chance to hit, and if successful, will deal damage. You can attack\n any target in combat by shooting, but can't shoot if there are any\n targets engaged with you. Use the 'withdraw' command to retreat from\n nearby enemies.\n "}
    +
    +
    @@ -937,6 +952,11 @@ characters you are 0 spaces away from.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'approach', 'tags': '', 'text': '\n Approaches an object.\n\n Usage:\n approach <target>\n\n Move one space toward a character or object. You can only attack\n characters you are 0 spaces away from.\n '}
    +
    +
    @@ -975,6 +995,11 @@ characters you are 0 spaces away from.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'withdraw', 'tags': '', 'text': '\n Moves away from an object.\n\n Usage:\n withdraw <target>\n\n Move one space away from a character or object.\n '}
    +
    +
    @@ -1014,6 +1039,11 @@ if there are still any actions you can take.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': 'wait hold', 'category': 'combat', 'key': 'pass', 'tags': '', 'text': '\n Passes on your turn.\n\n Usage:\n pass\n\n When in a fight, you can use this command to end your turn early, even\n if there are still any actions you can take.\n '}
    +
    +
    @@ -1054,6 +1084,11 @@ fight ends.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': 'spare', 'category': 'combat', 'key': 'disengage', 'tags': '', 'text': "\n Passes your turn and attempts to end combat.\n\n Usage:\n disengage\n\n Ends your turn early and signals that you're trying to end\n the fight. If all participants in a fight disengage, the\n fight ends.\n "}
    +
    +
    @@ -1093,6 +1128,11 @@ rest if you’re not in a fight.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'rest', 'tags': '', 'text': "\n Recovers damage.\n\n Usage:\n rest\n\n Resting recovers your HP to its maximum, but you can only\n rest if you're not in a fight.\n "}
    +
    +
    @@ -1132,6 +1172,11 @@ other targets in combat.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'status', 'tags': '', 'text': '\n Gives combat information.\n\n Usage:\n status\n\n Shows your current and maximum HP and your distance from\n other targets in combat.\n '}
    +
    +
    @@ -1173,6 +1218,11 @@ topics related to the game.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '?', 'category': 'general', 'key': 'help', 'tags': '', 'text': '\n View help or a list of topics\n\n Usage:\n help <topic or command>\n help list\n help all\n\n This will search for help on commands and other\n topics related to the game.\n '}
    +
    +
    @@ -1243,7 +1293,6 @@ topics related to the game.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.tutorial_examples.bodyfunctions.html b/docs/0.9.5/api/evennia.contrib.tutorial_examples.bodyfunctions.html index da711e0725..743f45ccd3 100644 --- a/docs/0.9.5/api/evennia.contrib.tutorial_examples.bodyfunctions.html +++ b/docs/0.9.5/api/evennia.contrib.tutorial_examples.bodyfunctions.html @@ -139,7 +139,6 @@ a random check here so as to only return 33% of the time.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.tutorial_examples.cmdset_red_button.html b/docs/0.9.5/api/evennia.contrib.tutorial_examples.cmdset_red_button.html index c9ee4b99c7..1a907258ca 100644 --- a/docs/0.9.5/api/evennia.contrib.tutorial_examples.cmdset_red_button.html +++ b/docs/0.9.5/api/evennia.contrib.tutorial_examples.cmdset_red_button.html @@ -37,451 +37,8 @@
    -
    -

    evennia.contrib.tutorial_examples.cmdset_red_button

    -

    This defines the cmdset for the red_button. Here we have defined -the commands and the cmdset in the same module, but if you -have many different commands to merge it is often better -to define the cmdset separately, picking and choosing from -among the available commands as to what should be included in the -cmdset - this way you can often re-use the commands too.

    -
    -
    -class evennia.contrib.tutorial_examples.cmdset_red_button.CmdNudge(**kwargs)[source]
    -

    Bases: evennia.commands.command.Command

    -

    Try to nudge the button’s lid

    -
    -
    Usage:

    nudge lid

    -
    -
    -

    This command will have you try to -push the lid of the button away.

    -
    -
    -key = 'nudge lid'
    -
    - -
    -
    -aliases = ['nudge']
    -
    - -
    -
    -locks = 'cmd:all()'
    -
    - -
    -
    -func()[source]
    -

    nudge the lid. Random chance of success to open it.

    -
    - -
    -
    -help_category = 'general'
    -
    - -
    -
    -lock_storage = 'cmd:all()'
    -
    - -
    - -
    -
    -class evennia.contrib.tutorial_examples.cmdset_red_button.CmdPush(**kwargs)[source]
    -

    Bases: evennia.commands.command.Command

    -

    Push the red button

    -
    -
    Usage:

    push button

    -
    -
    -
    -
    -key = 'push button'
    -
    - -
    -
    -aliases = ['press', 'push', 'press button']
    -
    - -
    -
    -locks = 'cmd:all()'
    -
    - -
    -
    -func()[source]
    -

    Note that we choose to implement this with checking for -if the lid is open/closed. This is because this command -is likely to be tried regardless of the state of the lid.

    -

    An alternative would be to make two versions of this command -and tuck them into the cmdset linked to the Open and Closed -lid-state respectively.

    -
    - -
    -
    -help_category = 'general'
    -
    - -
    -
    -lock_storage = 'cmd:all()'
    -
    - -
    - -
    -
    -class evennia.contrib.tutorial_examples.cmdset_red_button.CmdSmashGlass(**kwargs)[source]
    -

    Bases: evennia.commands.command.Command

    -

    smash glass

    -
    -
    Usage:

    smash glass

    -
    -
    -

    Try to smash the glass of the button.

    -
    -
    -key = 'smash glass'
    -
    - -
    -
    -aliases = ['break lid', 'smash', 'smash lid']
    -
    - -
    -
    -locks = 'cmd:all()'
    -
    - -
    -
    -func()[source]
    -

    The lid won’t open, but there is a small chance -of causing the lamp to break.

    -
    - -
    -
    -help_category = 'general'
    -
    - -
    -
    -lock_storage = 'cmd:all()'
    -
    - -
    - -
    -
    -class evennia.contrib.tutorial_examples.cmdset_red_button.CmdOpenLid(**kwargs)[source]
    -

    Bases: evennia.commands.command.Command

    -

    open lid

    -
    -
    Usage:

    open lid

    -
    -
    -
    -
    -key = 'open lid'
    -
    - -
    -
    -aliases = ['open', 'open button']
    -
    - -
    -
    -locks = 'cmd:all()'
    -
    - -
    -
    -func()[source]
    -

    simply call the right function.

    -
    - -
    -
    -help_category = 'general'
    -
    - -
    -
    -lock_storage = 'cmd:all()'
    -
    - -
    - -
    -
    -class evennia.contrib.tutorial_examples.cmdset_red_button.CmdCloseLid(**kwargs)[source]
    -

    Bases: evennia.commands.command.Command

    -

    close the lid

    -
    -
    Usage:

    close lid

    -
    -
    -

    Closes the lid of the red button.

    -
    -
    -key = 'close lid'
    -
    - -
    -
    -aliases = ['close']
    -
    - -
    -
    -locks = 'cmd:all()'
    -
    - -
    -
    -func()[source]
    -

    Close the lid

    -
    - -
    -
    -help_category = 'general'
    -
    - -
    -
    -lock_storage = 'cmd:all()'
    -
    - -
    - -
    -
    -class evennia.contrib.tutorial_examples.cmdset_red_button.CmdBlindLook(**kwargs)[source]
    -

    Bases: evennia.commands.command.Command

    -

    Looking around in darkness

    -
    -
    Usage:

    look <obj>

    -
    -
    -

    … not that there’s much to see in the dark.

    -
    -
    -key = 'look'
    -
    - -
    -
    -aliases = ['get', 'l', 'examine', 'ex', 'feel', 'listen']
    -
    - -
    -
    -locks = 'cmd:all()'
    -
    - -
    -
    -func()[source]
    -

    This replaces all the senses when blinded.

    -
    - -
    -
    -help_category = 'general'
    -
    - -
    -
    -lock_storage = 'cmd:all()'
    -
    - -
    - -
    -
    -class evennia.contrib.tutorial_examples.cmdset_red_button.CmdBlindHelp(**kwargs)[source]
    -

    Bases: evennia.commands.command.Command

    -

    Help function while in the blinded state

    -
    -
    Usage:

    help

    -
    -
    -
    -
    -key = 'help'
    -
    - -
    -
    -aliases = ['h']
    -
    - -
    -
    -locks = 'cmd:all()'
    -
    - -
    -
    -func()[source]
    -

    Give a message.

    -
    - -
    -
    -help_category = 'general'
    -
    - -
    -
    -lock_storage = 'cmd:all()'
    -
    - -
    - -
    -
    -class evennia.contrib.tutorial_examples.cmdset_red_button.DefaultCmdSet(cmdsetobj=None, key=None)[source]
    -

    Bases: evennia.commands.cmdset.CmdSet

    -

    The default cmdset always sits -on the button object and whereas other -command sets may be added/merge onto it -and hide it, removing them will always -bring it back. It’s added to the object -using obj.cmdset.add_default().

    -
    -
    -key = 'RedButtonDefault'
    -
    - -
    -
    -mergetype = 'Union'
    -
    - -
    -
    -at_cmdset_creation()[source]
    -

    Init the cmdset

    -
    - -
    -
    -path = 'evennia.contrib.tutorial_examples.cmdset_red_button.DefaultCmdSet'
    -
    - -
    - -
    -
    -class evennia.contrib.tutorial_examples.cmdset_red_button.LidClosedCmdSet(cmdsetobj=None, key=None)[source]
    -

    Bases: evennia.commands.cmdset.CmdSet

    -

    A simple cmdset tied to the redbutton object.

    -

    It contains the commands that launches the other -command sets, making the red button a self-contained -item (i.e. you don’t have to manually add any -scripts etc to it when creating it).

    -
    -
    -key = 'LidClosedCmdSet'
    -
    - -
    -
    -key_mergetype = {'LidOpenCmdSet': 'Replace'}
    -
    - -
    -
    -at_cmdset_creation()[source]
    -

    Populates the cmdset when it is instantiated.

    -
    - -
    -
    -path = 'evennia.contrib.tutorial_examples.cmdset_red_button.LidClosedCmdSet'
    -
    - -
    - -
    -
    -class evennia.contrib.tutorial_examples.cmdset_red_button.LidOpenCmdSet(cmdsetobj=None, key=None)[source]
    -

    Bases: evennia.commands.cmdset.CmdSet

    -

    This is the opposite of the Closed cmdset.

    -
    -
    -key = 'LidOpenCmdSet'
    -
    - -
    -
    -key_mergetype = {'LidClosedCmdSet': 'Replace'}
    -
    - -
    -
    -at_cmdset_creation()[source]
    -

    setup the cmdset (just one command)

    -
    - -
    -
    -path = 'evennia.contrib.tutorial_examples.cmdset_red_button.LidOpenCmdSet'
    -
    - -
    - -
    -
    -class evennia.contrib.tutorial_examples.cmdset_red_button.BlindCmdSet(cmdsetobj=None, key=None)[source]
    -

    Bases: evennia.commands.cmdset.CmdSet

    -

    This is the cmdset added to the account when -the button is pushed.

    -
    -
    -key = 'BlindCmdSet'
    -
    - -
    -
    -mergetype = 'Replace'
    -
    - -
    -
    -no_exits = True
    -
    - -
    -
    -no_objs = True
    -
    - -
    -
    -at_cmdset_creation()[source]
    -

    Setup the blind cmdset

    -
    - -
    -
    -path = 'evennia.contrib.tutorial_examples.cmdset_red_button.BlindCmdSet'
    -
    - -
    - +
    +

    evennia.contrib.tutorial_examples.cmdset_red_button

    @@ -527,7 +84,6 @@ the button is pushed.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.tutorial_examples.example_batch_code.html b/docs/0.9.5/api/evennia.contrib.tutorial_examples.example_batch_code.html index d185504313..df9606a796 100644 --- a/docs/0.9.5/api/evennia.contrib.tutorial_examples.example_batch_code.html +++ b/docs/0.9.5/api/evennia.contrib.tutorial_examples.example_batch_code.html @@ -84,7 +84,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.tutorial_examples.html b/docs/0.9.5/api/evennia.contrib.tutorial_examples.html index 375f048f5b..fb2913b29a 100644 --- a/docs/0.9.5/api/evennia.contrib.tutorial_examples.html +++ b/docs/0.9.5/api/evennia.contrib.tutorial_examples.html @@ -44,7 +44,10 @@
  • evennia.contrib.tutorial_examples.bodyfunctions
  • evennia.contrib.tutorial_examples.cmdset_red_button
  • evennia.contrib.tutorial_examples.example_batch_code
  • -
  • evennia.contrib.tutorial_examples.red_button
  • +
  • evennia.contrib.tutorial_examples.red_button +
  • evennia.contrib.tutorial_examples.red_button_scripts
  • evennia.contrib.tutorial_examples.tests
  • @@ -94,7 +97,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.tutorial_examples.red_button.html b/docs/0.9.5/api/evennia.contrib.tutorial_examples.red_button.html index 6158de0a2b..a52fafef8b 100644 --- a/docs/0.9.5/api/evennia.contrib.tutorial_examples.red_button.html +++ b/docs/0.9.5/api/evennia.contrib.tutorial_examples.red_button.html @@ -44,74 +44,627 @@ script.examples as well as commands.examples to make an interactive button typeclass.

    Create this button with

    -

    @create/drop examples.red_button.RedButton

    +

    create/drop red_button.RedButton

    Note that you must drop the button before you can see its messages!

    +
    +

    Technical

    +

    The button’s functionality is controlled by CmdSets that gets added and removed +depending on the ‘state’ the button is in.

    +
      +
    • Lid-closed state: In this state the button is covered by a glass cover and trying +to ‘push’ it will fail. You can ‘nudge’, ‘smash’ or ‘open’ the lid.

    • +
    • Lid-open state: In this state the lid is open but will close again after a certain +time. Using ‘push’ now will press the button and trigger the Blind-state.

    • +
    • Blind-state: In this mode you are blinded by a bright flash. This will affect your +normal commands like ‘look’ and help until the blindness wears off after a certain +time.

    • +
    +

    Timers are handled by persistent delays on the button. These are examples of +evennia.utils.utils.delay calls that wait a certain time before calling a method - +such as when closing the lid and un-blinding a character.

    +
    +
    +class evennia.contrib.tutorial_examples.red_button.CmdPushLidClosed(**kwargs)[source]
    +

    Bases: evennia.commands.command.Command

    +

    Push the red button (lid closed)

    +
    +
    Usage:

    push button

    +
    +
    +
    +
    +key = 'push button'
    +
    + +
    +
    +aliases = ['push', 'press', 'press button']
    +
    + +
    +
    +locks = 'cmd:all()'
    +
    + +
    +
    +func()[source]
    +

    This is the version of push used when the lid is closed.

    +

    An alternative would be to make a ‘push’ command in a default cmdset +that is always available on the button and then use if-statements to +check if the lid is open or closed.

    +
    + +
    +
    +help_category = 'general'
    +
    + +
    +
    +lock_storage = 'cmd:all()'
    +
    + +
    +
    +search_index_entry = {'aliases': 'push press press button', 'category': 'general', 'key': 'push button', 'tags': '', 'text': '\n Push the red button (lid closed)\n\n Usage:\n push button\n\n '}
    +
    + +
    + +
    +
    +class evennia.contrib.tutorial_examples.red_button.CmdNudge(**kwargs)[source]
    +

    Bases: evennia.commands.command.Command

    +

    Try to nudge the button’s lid.

    +
    +
    Usage:

    nudge lid

    +
    +
    +

    This command will have you try to push the lid of the button away.

    +
    +
    +key = 'nudge lid'
    +
    + +
    +
    +aliases = ['nudge']
    +
    + +
    +
    +locks = 'cmd:all()'
    +
    + +
    +
    +func()[source]
    +

    Nudge the lid. Random chance of success to open it.

    +
    + +
    +
    +help_category = 'general'
    +
    + +
    +
    +lock_storage = 'cmd:all()'
    +
    + +
    +
    +search_index_entry = {'aliases': 'nudge', 'category': 'general', 'key': 'nudge lid', 'tags': '', 'text': "\n Try to nudge the button's lid.\n\n Usage:\n nudge lid\n\n This command will have you try to push the lid of the button away.\n\n "}
    +
    + +
    + +
    +
    +class evennia.contrib.tutorial_examples.red_button.CmdSmashGlass(**kwargs)[source]
    +

    Bases: evennia.commands.command.Command

    +

    Smash the protective glass.

    +
    +
    Usage:

    smash glass

    +
    +
    +

    Try to smash the glass of the button.

    +
    +
    +key = 'smash glass'
    +
    + +
    +
    +aliases = ['break lid', 'smash', 'smash lid']
    +
    + +
    +
    +locks = 'cmd:all()'
    +
    + +
    +
    +func()[source]
    +

    The lid won’t open, but there is a small chance of causing the lamp to +break.

    +
    + +
    +
    +help_category = 'general'
    +
    + +
    +
    +lock_storage = 'cmd:all()'
    +
    + +
    +
    +search_index_entry = {'aliases': 'break lid smash smash lid', 'category': 'general', 'key': 'smash glass', 'tags': '', 'text': '\n Smash the protective glass.\n\n Usage:\n smash glass\n\n Try to smash the glass of the button.\n\n '}
    +
    + +
    + +
    +
    +class evennia.contrib.tutorial_examples.red_button.CmdOpenLid(**kwargs)[source]
    +

    Bases: evennia.commands.command.Command

    +

    open lid

    +
    +
    Usage:

    open lid

    +
    +
    +
    +
    +key = 'open lid'
    +
    + +
    +
    +aliases = ['open button']
    +
    + +
    +
    +locks = 'cmd:all()'
    +
    + +
    +
    +func()[source]
    +

    simply call the right function.

    +
    + +
    +
    +help_category = 'general'
    +
    + +
    +
    +lock_storage = 'cmd:all()'
    +
    + +
    +
    +search_index_entry = {'aliases': 'open button', 'category': 'general', 'key': 'open lid', 'tags': '', 'text': '\n open lid\n\n Usage:\n open lid\n\n '}
    +
    + +
    + +
    +
    +class evennia.contrib.tutorial_examples.red_button.LidClosedCmdSet(cmdsetobj=None, key=None)[source]
    +

    Bases: evennia.commands.cmdset.CmdSet

    +

    A simple cmdset tied to the redbutton object.

    +

    It contains the commands that launches the other +command sets, making the red button a self-contained +item (i.e. you don’t have to manually add any +scripts etc to it when creating it).

    +

    Note that this is given with a key_mergetype set. This +is set up so that the cmdset with merge with Union merge type +except if the other cmdset to merge with is LidOpenCmdSet, +in which case it will Replace that. So these two cmdsets will +be mutually exclusive.

    +
    +
    +key = 'LidClosedCmdSet'
    +
    + +
    +
    +at_cmdset_creation()[source]
    +

    Populates the cmdset when it is instantiated.

    +
    + +
    +
    +path = 'evennia.contrib.tutorial_examples.red_button.LidClosedCmdSet'
    +
    + +
    + +
    +
    +class evennia.contrib.tutorial_examples.red_button.CmdPushLidOpen(**kwargs)[source]
    +

    Bases: evennia.commands.command.Command

    +

    Push the red button

    +
    +
    Usage:

    push button

    +
    +
    +
    +
    +key = 'push button'
    +
    + +
    +
    +aliases = ['push', 'press', 'press button']
    +
    + +
    +
    +locks = 'cmd:all()'
    +
    + +
    +
    +func(**kwargs)
    +

    This is the actual executing part of the command. It is +called directly after self.parse(). See the docstring of this +module for which object properties are available (beyond those +set in self.parse())

    +
    + +
    +
    +help_category = 'general'
    +
    + +
    +
    +lock_storage = 'cmd:all()'
    +
    + +
    +
    +search_index_entry = {'aliases': 'push press press button', 'category': 'general', 'key': 'push button', 'tags': '', 'text': '\n Push the red button\n\n Usage:\n push button\n\n '}
    +
    + +
    + +
    +
    +class evennia.contrib.tutorial_examples.red_button.CmdCloseLid(**kwargs)[source]
    +

    Bases: evennia.commands.command.Command

    +

    Close the lid

    +
    +
    Usage:

    close lid

    +
    +
    +

    Closes the lid of the red button.

    +
    +
    +key = 'close lid'
    +
    + +
    +
    +aliases = ['close']
    +
    + +
    +
    +locks = 'cmd:all()'
    +
    + +
    +
    +func()[source]
    +

    Close the lid

    +
    + +
    +
    +help_category = 'general'
    +
    + +
    +
    +lock_storage = 'cmd:all()'
    +
    + +
    +
    +search_index_entry = {'aliases': 'close', 'category': 'general', 'key': 'close lid', 'tags': '', 'text': '\n Close the lid\n\n Usage:\n close lid\n\n Closes the lid of the red button.\n '}
    +
    + +
    + +
    +
    +class evennia.contrib.tutorial_examples.red_button.LidOpenCmdSet(cmdsetobj=None, key=None)[source]
    +

    Bases: evennia.commands.cmdset.CmdSet

    +

    This is the opposite of the Closed cmdset.

    +

    Note that this is given with a key_mergetype set. This +is set up so that the cmdset with merge with Union merge type +except if the other cmdset to merge with is LidClosedCmdSet, +in which case it will Replace that. So these two cmdsets will +be mutually exclusive.

    +
    +
    +key = 'LidOpenCmdSet'
    +
    + +
    +
    +at_cmdset_creation()[source]
    +

    Setup the cmdset

    +
    + +
    +
    +path = 'evennia.contrib.tutorial_examples.red_button.LidOpenCmdSet'
    +
    + +
    + +
    +
    +class evennia.contrib.tutorial_examples.red_button.CmdBlindLook(**kwargs)[source]
    +

    Bases: evennia.commands.command.Command

    +

    Looking around in darkness

    +
    +
    Usage:

    look <obj>

    +
    +
    +

    … not that there’s much to see in the dark.

    +
    +
    +key = 'look'
    +
    + +
    +
    +aliases = ['get', 'l', 'feel', 'listen', 'examine', 'ex']
    +
    + +
    +
    +locks = 'cmd:all()'
    +
    + +
    +
    +func()[source]
    +

    This replaces all the senses when blinded.

    +
    + +
    +
    +help_category = 'general'
    +
    + +
    +
    +lock_storage = 'cmd:all()'
    +
    + +
    +
    +search_index_entry = {'aliases': 'get l feel listen examine ex', 'category': 'general', 'key': 'look', 'tags': '', 'text': "\n Looking around in darkness\n\n Usage:\n look <obj>\n\n ... not that there's much to see in the dark.\n\n "}
    +
    + +
    + +
    +
    +class evennia.contrib.tutorial_examples.red_button.CmdBlindHelp(**kwargs)[source]
    +

    Bases: evennia.commands.command.Command

    +

    Help function while in the blinded state

    +
    +
    Usage:

    help

    +
    +
    +
    +
    +key = 'help'
    +
    + +
    +
    +aliases = ['h']
    +
    + +
    +
    +locks = 'cmd:all()'
    +
    + +
    +
    +func()[source]
    +

    Just give a message while blinded. We could have added this to the +CmdBlindLook command too if we wanted to keep things more compact.

    +
    + +
    +
    +help_category = 'general'
    +
    + +
    +
    +lock_storage = 'cmd:all()'
    +
    + +
    +
    +search_index_entry = {'aliases': 'h', 'category': 'general', 'key': 'help', 'tags': '', 'text': '\n Help function while in the blinded state\n\n Usage:\n help\n\n '}
    +
    + +
    + +
    +
    +class evennia.contrib.tutorial_examples.red_button.BlindCmdSet(cmdsetobj=None, key=None)[source]
    +

    Bases: evennia.commands.cmdset.CmdSet

    +

    This is the cmdset added to the account when +the button is pushed.

    +

    Since this has mergetype Replace it will completely remove the commands of +all other cmdsets while active. To allow some limited interaction +(pose/say) we import those default commands and add them too.

    +

    We also disable all exit-commands generated by exits and +object-interactions while blinded by setting no_exits and no_objs flags +on the cmdset. This is to avoid the player walking off or interfering with +other objects while blinded. Account-level commands however (channel messaging +etc) will not be affected by the blinding.

    +
    +
    +key = 'BlindCmdSet'
    +
    + +
    +
    +mergetype = 'Replace'
    +
    + +
    +
    +no_exits = True
    +
    + +
    +
    +no_objs = True
    +
    + +
    +
    +at_cmdset_creation()[source]
    +

    Setup the blind cmdset

    +
    + +
    +
    +path = 'evennia.contrib.tutorial_examples.red_button.BlindCmdSet'
    +
    + +
    +
    class evennia.contrib.tutorial_examples.red_button.RedButton(*args, **kwargs)[source]

    Bases: evennia.objects.objects.DefaultObject

    -

    This class describes an evil red button. It will use the script -definition in contrib/examples/red_button_scripts to blink at regular -intervals. It also uses a series of script and commands to handle -pushing the button and causing effects when doing so.

    -
    -
    The following attributes can be set on the button:

    desc_lid_open - description when lid is open -desc_lid_closed - description when lid is closed -desc_lamp_broken - description when lamp is broken

    -
    -
    +

    This class describes an evil red button. It will blink invitingly and +temporarily blind whomever presses it.

    +

    The button can take a few optional attributes controlling how things will +be displayed in its various states. This is a useful way to give builders +the option to customize a complex object from in-game. Actual return messages +to event-actions are (in this example) left with each command, but one could +also imagine having those handled via Attributes as well, if one wanted a +completely in-game customizable button without needing to tweak command +classes.

    +

    Attributes: +- desc_closed_lid: This is the description to show of the button

    +
    +

    when the lid is closed.

    +
    +
      +
    • desc_open_lid”: Shown when the lid is open

    • +
    • auto_close_msg: Message to show when lid auto-closes

    • +
    • desc_add_lamp_broken: Extra desc-line added after normal desc when lamp +is broken.

    • +
    • blink_msg: A list of strings to randomly choose from when the lamp +blinks.

    • +
    +

    Notes: +The button starts with lid closed. To set the initial description, +you can either set desc after creating it or pass a desc attribute +when creating it, such as +button = create_object(RedButton, …, attributes=[(‘desc’, ‘my desc’)]).

    +
    +
    +desc_closed_lid = 'This is a large red button, inviting yet evil-looking. A closed glass lid protects it.'
    +
    + +
    +
    +desc_open_lid = 'This is a large red button, inviting yet evil-looking. Its glass cover is open and the button exposed.'
    +
    + +
    +
    +auto_close_msg = "The button's glass lid silently slides back in place."
    +
    + +
    +
    +lamp_breaks_msg = 'The lamp flickers, the button going dark.'
    +
    + +
    +
    +desc_add_lamp_broken = '\nThe big red button has stopped blinking for the time being.'
    +
    + +
    + +
    +
    at_object_creation()[source]
    -

    This function is called when object is created. Use this -instead of e.g. __init__.

    +

    This function is called (once) when object is created.

    -
    -open_lid()[source]
    -

    Opens the glass lid and start the timer so it will soon close -again.

    +
    +to_closed_state(msg=None)[source]
    +

    Switches the button to having its lid closed.

    +
    +
    Parameters
    +
      +
    • msg (str, optional) – If given, display a message to the room

    • +
    • lid closes. (when) –

    • +
    +
    +
    +

    This will first try to get the Attribute (self.db.desc_closed_lid) in +case it was set by a builder and if that was None, it will fall back to +self.desc_closed_lid, the default description (note that lack of .db).

    -
    -close_lid()[source]
    -

    Close the glass lid. This validates all scripts on the button, -which means that scripts only being valid when the lid is open -will go away automatically.

    +
    +to_open_state()[source]
    +

    Switches the button to having its lid open. This also starts a timer +that will eventually close it again.

    +
    + +
    +
    +blind_target(caller)[source]
    +

    Someone was foolish enough to press the button! Blind them +temporarily.

    +
    +
    Parameters
    +

    caller (Object) – The one to be blinded.

    +
    +
    -break_lamp(feedback=True)[source]
    -

    Breaks the lamp in the button, stopping it from blinking.

    -
    -
    Parameters
    -

    feedback (bool) – Show a message about breaking the lamp.

    -
    -
    -
    - -
    -
    -press_button(pobject)[source]
    -

    Someone was foolish enough to press the button!

    -
    -
    Parameters
    -

    pobject (Object) – The person pressing the button

    -
    -
    -
    - -
    - -

    The script system will regularly call this -function to make the button blink. Now and then -it won’t blink at all though, to add some randomness -to how often the message is echoed.

    +break_lamp()[source] +

    Breaks the lamp in the button, stopping it from blinking for a while

    @@ -138,6 +691,7 @@ to how often the message is echoed.

    +
    @@ -160,6 +714,14 @@ to how often the message is echoed.

    +

    Table of Contents

    + +
    -
    diff --git a/docs/0.9.5/api/evennia.contrib.tutorial_examples.red_button_scripts.html b/docs/0.9.5/api/evennia.contrib.tutorial_examples.red_button_scripts.html index 69ae0d5dfc..99f4366fbf 100644 --- a/docs/0.9.5/api/evennia.contrib.tutorial_examples.red_button_scripts.html +++ b/docs/0.9.5/api/evennia.contrib.tutorial_examples.red_button_scripts.html @@ -37,352 +37,8 @@
    -
    -

    evennia.contrib.tutorial_examples.red_button_scripts

    -

    Example of scripts.

    -

    These are scripts intended for a particular object - the -red_button object type in contrib/examples. A few variations -on uses of scripts are included.

    -
    -
    -class evennia.contrib.tutorial_examples.red_button_scripts.ClosedLidState(*args, **kwargs)[source]
    -

    Bases: evennia.scripts.scripts.DefaultScript

    -

    This manages the cmdset for the “closed” button state. What this -means is that while this script is valid, we add the RedButtonClosed -cmdset to it (with commands like open, nudge lid etc)

    -
    -
    -at_script_creation()[source]
    -

    Called when script first created.

    -
    - -
    -
    -at_start()[source]
    -

    This is called once every server restart, so we want to add the -(memory-resident) cmdset to the object here. is_valid is automatically -checked so we don’t need to worry about adding the script to an -open lid.

    -
    - -
    -
    -is_valid()[source]
    -

    The script is only valid while the lid is closed. -self.obj is the red_button on which this script is defined.

    -
    - -
    -
    -at_stop()[source]
    -

    When the script stops we must make sure to clean up after us.

    -
    - -
    -
    -exception DoesNotExist
    -

    Bases: evennia.scripts.scripts.DefaultScript.DoesNotExist

    -
    - -
    -
    -exception MultipleObjectsReturned
    -

    Bases: evennia.scripts.scripts.DefaultScript.MultipleObjectsReturned

    -
    - -
    -
    -path = 'evennia.contrib.tutorial_examples.red_button_scripts.ClosedLidState'
    -
    - -
    -
    -typename = 'ClosedLidState'
    -
    - -
    - -
    -
    -class evennia.contrib.tutorial_examples.red_button_scripts.OpenLidState(*args, **kwargs)[source]
    -

    Bases: evennia.scripts.scripts.DefaultScript

    -

    This manages the cmdset for the “open” button state. This will add -the RedButtonOpen

    -
    -
    -at_script_creation()[source]
    -

    Called when script first created.

    -
    - -
    -
    -at_start()[source]
    -

    This is called once every server restart, so we want to add the -(memory-resident) cmdset to the object here. is_valid is -automatically checked, so we don’t need to worry about -adding the cmdset to a closed lid-button.

    -
    - -
    -
    -is_valid()[source]
    -

    The script is only valid while the lid is open. -self.obj is the red_button on which this script is defined.

    -
    - -
    -
    -at_stop()[source]
    -

    When the script stops (like if the lid is closed again) -we must make sure to clean up after us.

    -
    - -
    -
    -exception DoesNotExist
    -

    Bases: evennia.scripts.scripts.DefaultScript.DoesNotExist

    -
    - -
    -
    -exception MultipleObjectsReturned
    -

    Bases: evennia.scripts.scripts.DefaultScript.MultipleObjectsReturned

    -
    - -
    -
    -path = 'evennia.contrib.tutorial_examples.red_button_scripts.OpenLidState'
    -
    - -
    -
    -typename = 'OpenLidState'
    -
    - -
    - -
    -
    -class evennia.contrib.tutorial_examples.red_button_scripts.BlindedState(*args, **kwargs)[source]
    -

    Bases: evennia.scripts.scripts.DefaultScript

    -

    This is a timed state.

    -

    This adds a (very limited) cmdset TO THE ACCOUNT, during a certain time, -after which the script will close and all functions are -restored. It’s up to the function starting the script to actually -set it on the right account object.

    -
    -
    -at_script_creation()[source]
    -

    We set up the script here.

    -
    - -
    -
    -at_start()[source]
    -

    We want to add the cmdset to the linked object.

    -

    Note that the RedButtonBlind cmdset is defined to completly -replace the other cmdsets on the stack while it is active -(this means that while blinded, only operations in this cmdset -will be possible for the account to perform). It is however -not persistent, so should there be a bug in it, we just need -to restart the server to clear out of it during development.

    -
    - -
    -
    -at_stop()[source]
    -

    It’s important that we clear out that blinded cmdset -when we are done!

    -
    - -
    -
    -exception DoesNotExist
    -

    Bases: evennia.scripts.scripts.DefaultScript.DoesNotExist

    -
    - -
    -
    -exception MultipleObjectsReturned
    -

    Bases: evennia.scripts.scripts.DefaultScript.MultipleObjectsReturned

    -
    - -
    -
    -path = 'evennia.contrib.tutorial_examples.red_button_scripts.BlindedState'
    -
    - -
    -
    -typename = 'BlindedState'
    -
    - -
    - -
    -
    -class evennia.contrib.tutorial_examples.red_button_scripts.CloseLidEvent(*args, **kwargs)[source]
    -

    Bases: evennia.scripts.scripts.DefaultScript

    -

    This event closes the glass lid over the button -some time after it was opened. It’s a one-off -script that should be started/created when the -lid is opened.

    -
    -
    -at_script_creation()[source]
    -

    Called when script object is first created. Sets things up. -We want to have a lid on the button that the user can pull -aside in order to make the button ‘pressable’. But after a set -time that lid should auto-close again, making the button safe -from pressing (and deleting this command).

    -
    - -
    -
    -is_valid()[source]
    -

    This script can only operate if the lid is open; if it -is already closed, the script is clearly invalid.

    -

    Note that we are here relying on an self.obj being -defined (and being a RedButton object) - this we should be able to -expect since this type of script is always tied to one individual -red button object and not having it would be an error.

    -
    - -
    -
    -at_repeat()[source]
    -

    Called after self.interval seconds. It closes the lid. Before this method is -called, self.is_valid() is automatically checked, so there is no need to -check this manually.

    -
    - -
    -
    -exception DoesNotExist
    -

    Bases: evennia.scripts.scripts.DefaultScript.DoesNotExist

    -
    - -
    -
    -exception MultipleObjectsReturned
    -

    Bases: evennia.scripts.scripts.DefaultScript.MultipleObjectsReturned

    -
    - -
    -
    -path = 'evennia.contrib.tutorial_examples.red_button_scripts.CloseLidEvent'
    -
    - -
    -
    -typename = 'CloseLidEvent'
    -
    - -
    - -
    -
    -class evennia.contrib.tutorial_examples.red_button_scripts.BlinkButtonEvent(*args, **kwargs)[source]
    -

    Bases: evennia.scripts.scripts.DefaultScript

    -

    This timed script lets the button flash at regular intervals.

    -
    -
    -at_script_creation()[source]
    -

    Sets things up. We want the button’s lamp to blink at -regular intervals, unless it’s broken (can happen -if you try to smash the glass, say).

    -
    - -
    -
    -is_valid()[source]
    -

    Button will keep blinking unless it is broken.

    -
    - -
    -
    -at_repeat()[source]
    -

    Called every self.interval seconds. Makes the lamp in -the button blink.

    -
    - -
    -
    -exception DoesNotExist
    -

    Bases: evennia.scripts.scripts.DefaultScript.DoesNotExist

    -
    - -
    -
    -exception MultipleObjectsReturned
    -

    Bases: evennia.scripts.scripts.DefaultScript.MultipleObjectsReturned

    -
    - -
    -
    -path = 'evennia.contrib.tutorial_examples.red_button_scripts.BlinkButtonEvent'
    -
    - -
    -
    -typename = 'BlinkButtonEvent'
    -
    - -
    - -
    -
    -class evennia.contrib.tutorial_examples.red_button_scripts.DeactivateButtonEvent(*args, **kwargs)[source]
    -

    Bases: evennia.scripts.scripts.DefaultScript

    -

    This deactivates the button for a short while (it won’t blink, won’t -close its lid etc). It is meant to be called when the button is pushed -and run as long as the blinded effect lasts. We cannot put these methods -in the AddBlindedCmdSet script since that script is defined on the account -whereas this one must be defined on the button.

    -
    -
    -at_script_creation()[source]
    -

    Sets things up.

    -
    - -
    -
    -at_start()[source]
    -

    Deactivate the button. Observe that this method is always -called directly, regardless of the value of self.start_delay -(that just controls when at_repeat() is called)

    -
    - -
    -
    -at_repeat()[source]
    -

    When this is called, reset the functionality of the button.

    -
    - -
    -
    -exception DoesNotExist
    -

    Bases: evennia.scripts.scripts.DefaultScript.DoesNotExist

    -
    - -
    -
    -exception MultipleObjectsReturned
    -

    Bases: evennia.scripts.scripts.DefaultScript.MultipleObjectsReturned

    -
    - -
    -
    -path = 'evennia.contrib.tutorial_examples.red_button_scripts.DeactivateButtonEvent'
    -
    - -
    -
    -typename = 'DeactivateButtonEvent'
    -
    - -
    - +
    +

    evennia.contrib.tutorial_examples.red_button_scripts

    @@ -428,7 +84,6 @@ called directly, regardless of the value of self.start_delay
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.tutorial_examples.tests.html b/docs/0.9.5/api/evennia.contrib.tutorial_examples.tests.html index f722e3d371..93959a0a74 100644 --- a/docs/0.9.5/api/evennia.contrib.tutorial_examples.tests.html +++ b/docs/0.9.5/api/evennia.contrib.tutorial_examples.tests.html @@ -120,7 +120,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.tutorial_world.html b/docs/0.9.5/api/evennia.contrib.tutorial_world.html index 05477a5e6a..d5f6e2949e 100644 --- a/docs/0.9.5/api/evennia.contrib.tutorial_world.html +++ b/docs/0.9.5/api/evennia.contrib.tutorial_world.html @@ -93,7 +93,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.tutorial_world.intro_menu.html b/docs/0.9.5/api/evennia.contrib.tutorial_world.intro_menu.html index 0d43b66bdc..78c5df767e 100644 --- a/docs/0.9.5/api/evennia.contrib.tutorial_world.intro_menu.html +++ b/docs/0.9.5/api/evennia.contrib.tutorial_world.intro_menu.html @@ -275,7 +275,6 @@ option related to this node.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.tutorial_world.mob.html b/docs/0.9.5/api/evennia.contrib.tutorial_world.mob.html index b492652173..ba60f71d5a 100644 --- a/docs/0.9.5/api/evennia.contrib.tutorial_world.mob.html +++ b/docs/0.9.5/api/evennia.contrib.tutorial_world.mob.html @@ -88,6 +88,11 @@ to turn on/off the mob.”

    lock_storage = 'cmd:superuser()'
    +
    +
    +search_index_entry = {'aliases': 'moboff', 'category': 'general', 'key': 'mobon', 'tags': '', 'text': "\n Activates/deactivates Mob\n\n Usage:\n mobon <mob>\n moboff <mob>\n\n This turns the mob from active (alive) mode\n to inactive (dead) mode. It is used during\n building to activate the mob once it's\n prepared.\n "}
    +
    +
    @@ -123,7 +128,7 @@ the way it came. If unset, the mob will remain stationary (idling) until attacked.

    aggressive: if set, will attack Characters in

    the same room using whatever Weapon it -carries (see tutorial_world.objects.Weapon). +carries (see tutorial_world.objects.TutorialWeapon). if unset, the mob will never engage in combat no matter what.

    @@ -319,7 +324,6 @@ right away, also when patrolling on a very slow ticker.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.tutorial_world.objects.html b/docs/0.9.5/api/evennia.contrib.tutorial_world.objects.html index 2d42276204..2eeb1ec15d 100644 --- a/docs/0.9.5/api/evennia.contrib.tutorial_world.objects.html +++ b/docs/0.9.5/api/evennia.contrib.tutorial_world.objects.html @@ -50,8 +50,8 @@ TutorialClimbable Obelisk LightSource CrumblingWall -Weapon -WeaponRack

    +TutorialWeapon +TutorialWeaponRack

    class evennia.contrib.tutorial_world.objects.TutorialObject(*args, **kwargs)[source]
    @@ -134,6 +134,11 @@ Attribute “readable_text” on the object and displays that.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'tutorialworld', 'key': 'read', 'tags': '', 'text': '\n Usage:\n read [obj]\n\n Read some text of a readable object.\n '}
    +
    +
    @@ -231,6 +236,11 @@ Attribute and add the readable cmdset.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'tutorialworld', 'key': 'climb', 'tags': '', 'text': '\n Climb an object\n\n Usage:\n climb <object>\n\n This allows you to climb.\n '}
    +
    +
    @@ -376,6 +386,11 @@ to sit on a “lightable” object, we operate only on self.obj.

    lock_storage = 'cmd:holds()'
    +
    +
    +search_index_entry = {'aliases': 'light burn', 'category': 'tutorialworld', 'key': 'on', 'tags': '', 'text': '\n Creates light where there was none. Something to burn.\n '}
    +
    +
    @@ -477,7 +492,7 @@ shift green root up/down

    -aliases = ['shiftroot', 'pull', 'push', 'move']
    +aliases = ['push', 'shiftroot', 'pull', 'move']
    @@ -511,6 +526,11 @@ yellow/green - horizontal roots

    lock_storage = 'cmd:locattr(is_lit)'
    +
    +
    +search_index_entry = {'aliases': 'push shiftroot pull move', 'category': 'tutorialworld', 'key': 'shift', 'tags': '', 'text': '\n Shifts roots around.\n\n Usage:\n shift blue root left/right\n shift red root left/right\n shift yellow root up/down\n shift green root up/down\n\n '}
    +
    +
    @@ -549,6 +569,11 @@ yellow/green - horizontal roots

    lock_storage = 'cmd:objattr(button_exposed) and objlocattr(is_lit)'
    +
    +
    +search_index_entry = {'aliases': 'push button button press button', 'category': 'tutorialworld', 'key': 'press', 'tags': '', 'text': '\n Presses a button.\n '}
    +
    +
    @@ -690,7 +715,7 @@ parry - forgoes your attack but will make you harder to hit on next

    -aliases = ['hit', 'slash', 'parry', 'stab', 'kill', 'pierce', 'thrust', 'bash', 'defend', 'fight', 'chop']
    +aliases = ['hit', 'fight', 'defend', 'thrust', 'pierce', 'slash', 'stab', 'kill', 'parry', 'bash', 'chop']
    @@ -714,6 +739,11 @@ parry - forgoes your attack but will make you harder to hit on next

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'hit fight defend thrust pierce slash stab kill parry bash chop', 'category': 'tutorialworld', 'key': 'attack', 'tags': '', 'text': '\n Attack the enemy. Commands:\n\n stab <enemy>\n slash <enemy>\n parry\n\n stab - (thrust) makes a lot of damage but is harder to hit with.\n slash - is easier to land, but does not make as much damage.\n parry - forgoes your attack but will make you harder to hit on next\n enemy attack.\n\n '}
    +
    +
    @@ -735,8 +765,8 @@ parry - forgoes your attack but will make you harder to hit on next

    -
    -class evennia.contrib.tutorial_world.objects.Weapon(*args, **kwargs)[source]
    +
    +class evennia.contrib.tutorial_world.objects.TutorialWeapon(*args, **kwargs)[source]

    Bases: evennia.contrib.tutorial_world.objects.TutorialObject

    This defines a bladed weapon.

    @@ -749,38 +779,38 @@ damage - base damage given (modified by hit success and

    -
    -at_object_creation()[source]
    +
    +at_object_creation()[source]

    Called at first creation of the object

    -
    -reset()[source]
    +
    +reset()[source]

    When reset, the weapon is simply deleted, unless it has a place to return to.

    -
    -exception DoesNotExist
    +
    +exception DoesNotExist

    Bases: evennia.contrib.tutorial_world.objects.TutorialObject.DoesNotExist

    -
    -exception MultipleObjectsReturned
    +
    +exception MultipleObjectsReturned

    Bases: evennia.contrib.tutorial_world.objects.TutorialObject.MultipleObjectsReturned

    -
    -path = 'evennia.contrib.tutorial_world.objects.Weapon'
    +
    +path = 'evennia.contrib.tutorial_world.objects.TutorialWeapon'
    -
    -typename = 'Weapon'
    +
    +typename = 'TutorialWeapon'
    @@ -826,6 +856,11 @@ itself handle all messages.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'tutorialworld', 'key': 'get weapon', 'tags': '', 'text': '\n Usage:\n get weapon\n\n This will try to obtain a weapon from the container.\n '}
    +
    +
    @@ -852,8 +887,8 @@ itself handle all messages.

    -
    -class evennia.contrib.tutorial_world.objects.WeaponRack(*args, **kwargs)[source]
    +
    +class evennia.contrib.tutorial_world.objects.TutorialWeaponRack(*args, **kwargs)[source]

    Bases: evennia.contrib.tutorial_world.objects.TutorialObject

    This object represents a weapon store. When people use the “get weapon” command on this rack, it will produce one @@ -871,14 +906,14 @@ grab another one.

    -
    -at_object_creation()[source]
    +
    +at_object_creation()[source]

    called at creation

    -
    -produce_weapon(caller)[source]
    +
    +produce_weapon(caller)[source]

    This will produce a new weapon from the rack, assuming the caller hasn’t already gotten one. When doing so, the caller will get Tagged with the id @@ -887,25 +922,25 @@ pulling weapons from it indefinitely.

    -
    -exception DoesNotExist
    +
    +exception DoesNotExist

    Bases: evennia.contrib.tutorial_world.objects.TutorialObject.DoesNotExist

    -
    -exception MultipleObjectsReturned
    +
    +exception MultipleObjectsReturned

    Bases: evennia.contrib.tutorial_world.objects.TutorialObject.MultipleObjectsReturned

    -
    -path = 'evennia.contrib.tutorial_world.objects.WeaponRack'
    +
    +path = 'evennia.contrib.tutorial_world.objects.TutorialWeaponRack'
    -
    -typename = 'WeaponRack'
    +
    +typename = 'TutorialWeaponRack'
    @@ -955,7 +990,6 @@ pulling weapons from it indefinitely.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.tutorial_world.rooms.html b/docs/0.9.5/api/evennia.contrib.tutorial_world.rooms.html index 4c69b7cac2..a6908aedac 100644 --- a/docs/0.9.5/api/evennia.contrib.tutorial_world.rooms.html +++ b/docs/0.9.5/api/evennia.contrib.tutorial_world.rooms.html @@ -87,6 +87,11 @@ called tutorial_info and display that.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'tut', 'category': 'tutorialworld', 'key': 'tutorial', 'tags': '', 'text': '\n Get help during the tutorial\n\n Usage:\n tutorial [obj]\n\n This command allows you to get behind-the-scenes info\n about an object or the current location.\n\n '}
    +
    +
    @@ -140,6 +145,11 @@ the set_detail method and uses it.

    lock_storage = 'cmd:perm(Builder)'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'tutorialworld', 'key': '@detail', 'tags': '', 'text': '\n sets a detail on a room\n\n Usage:\n @detail <key> = <description>\n @detail <key>;<alias>;... = description\n\n Example:\n @detail walls = The walls are covered in ...\n @detail castle;ruin;tower = The distant ruin ...\n\n This sets a "detail" on the object this command is defined on\n (TutorialRoom for this tutorial). This detail can be accessed with\n the TutorialRoomLook command sitting on TutorialRoom objects (details\n are set as a simple dictionary on the room). This is a Builder command.\n\n We custom parse the key for the ;-separator in order to create\n multiple aliases to the detail all at once.\n '}
    +
    +
    @@ -187,6 +197,11 @@ code except for adding in the details.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'l ls', 'category': 'tutorialworld', 'key': 'look', 'tags': '', 'text': '\n looks at the room and on details\n\n Usage:\n look <obj>\n look <room detail>\n look *<account>\n\n Observes your location, details at your location or objects\n in your vicinity.\n\n Tutorial: This is a child of the default Look command, that also\n allows us to look at "details" in the room. These details are\n things to examine and offers some extra description without\n actually having to be actual database objects. It uses the\n return_detail() hook on TutorialRooms for this.\n '}
    +
    +
    @@ -223,6 +238,11 @@ to all the variables defined therein.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': 'abort', 'category': 'general', 'key': 'give up', 'tags': '', 'text': '\n Give up the tutorial-world quest and return to Limbo, the start room of the\n server.\n\n '}
    +
    +
    @@ -428,6 +448,11 @@ set in self.parse())

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'intro', 'tags': '', 'text': '\n Start the Evennia intro wizard.\n\n Usage:\n intro\n\n '}
    +
    +
    @@ -557,6 +582,11 @@ on the bridge, 0 - 4.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'e', 'category': 'tutorialworld', 'key': 'east', 'tags': '', 'text': '\n Go eastwards across the bridge.\n\n Tutorial info:\n This command relies on the caller having two Attributes\n (assigned by the room when entering):\n - east_exit: a unique name or dbref to the room to go to\n when exiting east.\n - west_exit: a unique name or dbref to the room to go to\n when exiting west.\n The room must also have the following Attributes\n - tutorial_bridge_posistion: the current position on\n on the bridge, 0 - 4.\n\n '}
    +
    +
    @@ -615,6 +645,11 @@ on the bridge, 0 - 4.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'w', 'category': 'tutorialworld', 'key': 'west', 'tags': '', 'text': '\n Go westwards across the bridge.\n\n Tutorial info:\n This command relies on the caller having two Attributes\n (assigned by the room when entering):\n - east_exit: a unique name or dbref to the room to go to\n when exiting east.\n - west_exit: a unique name or dbref to the room to go to\n when exiting west.\n The room must also have the following property:\n - tutorial_bridge_posistion: the current position on\n on the bridge, 0 - 4.\n\n '}
    +
    +
    @@ -659,6 +694,11 @@ if they fall off the bridge.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'l', 'category': 'tutorialworld', 'key': 'look', 'tags': '', 'text': '\n looks around at the bridge.\n\n Tutorial info:\n This command assumes that the room has an Attribute\n "fall_exit", a unique name or dbref to the place they end upp\n if they fall off the bridge.\n '}
    +
    +
    @@ -673,7 +713,7 @@ if they fall off the bridge.

    -aliases = ['h', '?']
    +aliases = ['?', 'h']
    @@ -697,6 +737,11 @@ if they fall off the bridge.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '? h', 'category': 'tutorial world', 'key': 'help', 'tags': '', 'text': '\n Overwritten help command while on the bridge.\n '}
    +
    +
    @@ -820,7 +865,7 @@ to find something.

    -aliases = ['search', 'l', 'feel around', 'fiddle', 'feel']
    +aliases = ['search', 'feel', 'l', 'fiddle', 'feel around']
    @@ -846,6 +891,11 @@ random chance of eventually finding a light source.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': 'search feel l fiddle feel around', 'category': 'tutorialworld', 'key': 'look', 'tags': '', 'text': '\n Look around in darkness\n\n Usage:\n look\n\n Look around in the darkness, trying\n to find something.\n '}
    +
    +
    @@ -884,6 +934,11 @@ random chance of eventually finding a light source.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'tutorialworld', 'key': 'help', 'tags': '', 'text': '\n Help command for the dark state.\n '}
    +
    +
    @@ -926,6 +981,11 @@ suggestions)

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': '__nomatch_command', 'tags': '', 'text': "\n This is a system command. Commands with special keys are used to\n override special sitations in the game. The CMD_NOMATCH is used\n when the given command is not found in the current command set (it\n replaces Evennia's default behavior or offering command\n suggestions)\n "}
    +
    +
    @@ -1197,7 +1257,6 @@ overriding the call (unused by default).

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.unixcommand.html b/docs/0.9.5/api/evennia.contrib.unixcommand.html index 781dd78ee8..bf0f7a323d 100644 --- a/docs/0.9.5/api/evennia.contrib.unixcommand.html +++ b/docs/0.9.5/api/evennia.contrib.unixcommand.html @@ -318,6 +318,11 @@ use its add_argument method.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'command', 'tags': '', 'text': '\n Unix-type commands, supporting short and long options.\n\n This command syntax uses the Unix-style commands with short options\n (-X) and long options (--something). The `argparse` module is\n used to parse the command.\n\n In order to use it, you should override two methods:\n - `init_parser`: this method is called when the command is created.\n It can be used to set options in the parser. `self.parser`\n contains the `argparse.ArgumentParser`, so you can add arguments\n here.\n - `func`: this method is called to execute the command, but after\n the parser has checked the arguments given to it are valid.\n You can access the namespace of valid arguments in `self.opts`\n at this point.\n\n The help of UnixCommands is derived from the docstring, in a\n slightly different way than usual: the first line of the docstring\n is used to represent the program description (the very short\n line at the top of the help message). The other lines below are\n used as the program\'s "epilog", displayed below the options. It\n means in your docstring, you don\'t have to write the options.\n They will be automatically provided by the parser and displayed\n accordingly. The `argparse` module provides a default \'-h\' or\n \'--help\' option on the command. Typing |whelp commandname|n will\n display the same as |wcommandname -h|n, though this behavior can\n be changed.\n\n '}
    +
    + @@ -365,7 +370,6 @@ use its add_argument method.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.contrib.wilderness.html b/docs/0.9.5/api/evennia.contrib.wilderness.html index 51c1c2e4e2..39e7926275 100644 --- a/docs/0.9.5/api/evennia.contrib.wilderness.html +++ b/docs/0.9.5/api/evennia.contrib.wilderness.html @@ -711,7 +711,6 @@ coordinate.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.help.admin.html b/docs/0.9.5/api/evennia.help.admin.html index a292e1fc5a..20ed6b9b9b 100644 --- a/docs/0.9.5/api/evennia.help.admin.html +++ b/docs/0.9.5/api/evennia.help.admin.html @@ -37,134 +37,8 @@
    -
    -

    evennia.help.admin

    -

    This defines how to edit help entries in Admin.

    -
    -
    -class evennia.help.admin.HelpTagInline(parent_model, admin_site)[source]
    -

    Bases: evennia.typeclasses.admin.TagInline

    -
    -
    -model
    -

    alias of evennia.help.models.HelpEntry_db_tags

    -
    - -
    -
    -related_field = 'helpentry'
    -
    - -
    -
    -property media
    -
    - -
    - -
    -
    -class evennia.help.admin.HelpEntryForm(data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=<class 'django.forms.utils.ErrorList'>, label_suffix=None, empty_permitted=False, instance=None, use_required_attribute=None, renderer=None)[source]
    -

    Bases: django.forms.models.ModelForm

    -

    Defines how to display the help entry

    -
    -
    -class Meta[source]
    -

    Bases: object

    -
    -
    -model
    -

    alias of evennia.help.models.HelpEntry

    -
    - -
    -
    -fields = '__all__'
    -
    - -
    - -
    -
    -base_fields = {'db_entrytext': <django.forms.fields.CharField object>, 'db_help_category': <django.forms.fields.CharField object>, 'db_key': <django.forms.fields.CharField object>, 'db_lock_storage': <django.forms.fields.CharField object>, 'db_staff_only': <django.forms.fields.BooleanField object>, 'db_tags': <django.forms.models.ModelMultipleChoiceField object>}
    -
    - -
    -
    -declared_fields = {'db_help_category': <django.forms.fields.CharField object>, 'db_lock_storage': <django.forms.fields.CharField object>}
    -
    - -
    -
    -property media
    -

    Return all media required to render the widgets on this form.

    -
    - -
    - -
    -
    -class evennia.help.admin.HelpEntryAdmin(model, admin_site)[source]
    -

    Bases: django.contrib.admin.options.ModelAdmin

    -

    Sets up the admin manaager for help entries

    -
    -
    -inlines = [<class 'evennia.help.admin.HelpTagInline'>]
    -
    - -
    -
    -list_display = ('id', 'db_key', 'db_help_category', 'db_lock_storage')
    -
    - -
    - -
    - -
    -
    -search_fields = ['^db_key', 'db_entrytext']
    -
    - -
    -
    -ordering = ['db_help_category', 'db_key']
    -
    - -
    -
    -save_as = True
    -
    - -
    -
    -save_on_top = True
    -
    - -
    - -
    - -
    -
    -form
    -

    alias of HelpEntryForm

    -
    - -
    -
    -fieldsets = ((None, {'fields': (('db_key', 'db_help_category'), 'db_entrytext', 'db_lock_storage'), 'description': 'Sets a Help entry. Set lock to <i>view:all()</I> unless you want to restrict it.'}),)
    -
    - -
    -
    -property media
    -
    - -
    - +
    +

    evennia.help.admin

    @@ -210,7 +84,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.help.html b/docs/0.9.5/api/evennia.help.html index 2dcdf0127b..bd7fc1154c 100644 --- a/docs/0.9.5/api/evennia.help.html +++ b/docs/0.9.5/api/evennia.help.html @@ -95,7 +95,6 @@ itself.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.help.manager.html b/docs/0.9.5/api/evennia.help.manager.html index 47e509fec8..6d73c3213d 100644 --- a/docs/0.9.5/api/evennia.help.manager.html +++ b/docs/0.9.5/api/evennia.help.manager.html @@ -222,7 +222,6 @@ up in one easily separated category.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.help.models.html b/docs/0.9.5/api/evennia.help.models.html index 1e414759b5..7d7fa3ca1a 100644 --- a/docs/0.9.5/api/evennia.help.models.html +++ b/docs/0.9.5/api/evennia.help.models.html @@ -105,8 +105,8 @@ class built by **create_forward_many_to_many_manager()** define
    -
    -db_staff_only
    +
    +db_date_created

    A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

    @@ -133,11 +133,28 @@ object the first time, the query is executed.

    -access(accessing_obj, access_type='read', default=False)[source]
    -

    Determines if another object has permission to access. -accessing_obj - object trying to access this one -access_type - type of access sought -default - what to return if no lock of access_type was found

    +access(accessing_obj, access_type='read', default=True)[source] +

    Determines if another object has permission to access this help entry.

    +
    +
    Accesses used by default:

    ‘read’ - read the help entry itself. +‘view’ - see help entry in help index.

    +
    +
    +
    +
    Parameters
    +
      +
    • accessing_obj (Object or Account) – Entity trying to access this one.

    • +
    • access_type (str) – type of access sought.

    • +
    • default (bool) – What to return if no lock of access_type was found.

    • +
    +
    +
    +
    + +
    +
    +property search_index_entry
    +

    Property for easily retaining a search index entry for this object.

    @@ -161,8 +178,10 @@ instances of this object.

    For this to work, the developer must have defined a named view somewhere in urls.py that follows the format ‘modelname-action’, so in this case a named view of ‘character-create’ would be referenced by this method.

    -

    ex. -url(r’characters/create/’, ChargenView.as_view(), name=’character-create’)

    +

    ex.

    +
    url(r'characters/create/', ChargenView.as_view(), name='character-create')
    +
    +

    If no View has been created and defined in urls.py, returns an HTML anchor.

    This method is naive and simply returns a path. Securing access to @@ -184,11 +203,11 @@ this object.

    For this to work, the developer must have defined a named view somewhere in urls.py that follows the format ‘modelname-action’, so in this case a named view of ‘character-detail’ would be referenced by this method.

    -

    ex. -url(r’characters/(?P<slug>[wd-]+)/(?P<pk>[0-9]+)/$’,

    -
    -

    CharDetailView.as_view(), name=’character-detail’)

    -
    +

    ex.

    +
    url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/$',
    +    CharDetailView.as_view(), name='character-detail')
    +
    +

    If no View has been created and defined in urls.py, returns an HTML anchor.

    This method is naive and simply returns a path. Securing access to @@ -210,11 +229,11 @@ object.

    For this to work, the developer must have defined a named view somewhere in urls.py that follows the format ‘modelname-action’, so in this case a named view of ‘character-update’ would be referenced by this method.

    -

    ex. -url(r’characters/(?P<slug>[wd-]+)/(?P<pk>[0-9]+)/change/$’,

    -
    -

    CharUpdateView.as_view(), name=’character-update’)

    -
    +

    ex.

    +
    url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/change/$',
    +    CharUpdateView.as_view(), name='character-update')
    +
    +

    If no View has been created and defined in urls.py, returns an HTML anchor.

    This method is naive and simply returns a path. Securing access to @@ -235,11 +254,11 @@ responsibility.

    For this to work, the developer must have defined a named view somewhere in urls.py that follows the format ‘modelname-action’, so in this case a named view of ‘character-detail’ would be referenced by this method.

    -

    ex. -url(r’characters/(?P<slug>[wd-]+)/(?P<pk>[0-9]+)/delete/$’,

    -
    -

    CharDeleteView.as_view(), name=’character-delete’)

    -
    +

    ex.

    +
    url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/delete/$',
    +    CharDeleteView.as_view(), name='character-delete')
    +
    +

    If no View has been created and defined in urls.py, returns an HTML anchor.

    This method is naive and simply returns a path. Securing access to @@ -261,11 +280,11 @@ this object.

    For this to work, the developer must have defined a named view somewhere in urls.py that follows the format ‘modelname-action’, so in this case a named view of ‘character-detail’ would be referenced by this method.

    -

    ex. -url(r’characters/(?P<slug>[wd-]+)/(?P<pk>[0-9]+)/$’,

    -
    -

    CharDetailView.as_view(), name=’character-detail’)

    -
    +

    ex.

    +
    url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/$',
    +    CharDetailView.as_view(), name='character-detail')
    +
    +

    If no View has been created and defined in urls.py, returns an HTML anchor.

    This method is naive and simply returns a path. Securing access to @@ -290,12 +309,28 @@ responsibility.

    Bases: django.core.exceptions.MultipleObjectsReturned

    +
    +
    +property date_created
    +

    A wrapper for getting database field db_date_created.

    +
    +
    property entrytext

    A wrapper for getting database field db_entrytext.

    +
    +
    +get_next_by_db_date_created(*, field=<django.db.models.fields.DateTimeField: db_date_created>, is_next=True, **kwargs)
    +
    + +
    +
    +get_previous_by_db_date_created(*, field=<django.db.models.fields.DateTimeField: db_date_created>, is_next=False, **kwargs)
    +
    +
    property help_category
    @@ -326,12 +361,6 @@ object the first time, the query is executed.

    path = 'evennia.help.models.HelpEntry'
    -
    -
    -property staff_only
    -

    A wrapper for getting database field db_staff_only.

    -
    -
    typename = 'SharedMemoryModelBase'
    @@ -384,7 +413,6 @@ object the first time, the query is executed.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.html b/docs/0.9.5/api/evennia.html index 14ba1ae105..7c1e18b444 100644 --- a/docs/0.9.5/api/evennia.html +++ b/docs/0.9.5/api/evennia.html @@ -45,7 +45,6 @@ @@ -262,10 +264,7 @@ with ‘q’, remove the break line and restart server when finished.

  • evennia.locks
  • @@ -362,10 +361,19 @@ with ‘q’, remove the break line and restart server when finished.

  • evennia.utils -
    diff --git a/docs/0.9.5/api/evennia.locks.html b/docs/0.9.5/api/evennia.locks.html index a91dbaa7f5..2f69d0913c 100644 --- a/docs/0.9.5/api/evennia.locks.html +++ b/docs/0.9.5/api/evennia.locks.html @@ -44,10 +44,7 @@ lock strings are processed through the lockhandler in this package. It also contains the default lock functions used in lock definitions.

    @@ -96,7 +93,6 @@ also contains the default lock functions used in lock definitions.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.locks.lockfuncs.html b/docs/0.9.5/api/evennia.locks.lockfuncs.html index 484a9f98f2..0cce1ff588 100644 --- a/docs/0.9.5/api/evennia.locks.lockfuncs.html +++ b/docs/0.9.5/api/evennia.locks.lockfuncs.html @@ -48,106 +48,6 @@ Run the access() method of the handler to execute the lock chec

    Note that accessing_obj and accessed_obj can be any object type with a lock variable/field, so be careful to not expect a certain object type.

    -

    Appendix: MUX locks

    -

    Below is a list nicked from the MUX help file on the locks available -in standard MUX. Most of these are not relevant to core Evennia since -locks in Evennia are considerably more flexible and can be implemented -on an individual command/typeclass basis rather than as globally -available like the MUX ones. So many of these are not available in -basic Evennia, but could all be implemented easily if needed for the -individual game.

    -
    -

    MUX Name: Affects: Effect:

    -
    -
    DefaultLock: Exits: controls who may traverse the exit to
    -
    -
    -
    its destination.

    Evennia: “traverse:<lockfunc()>”

    -
    -
    -
    -
    -
    Rooms: controls whether the account sees the

    SUCC or FAIL message for the room -following the room description when -looking at the room.

    -
    -

    Evennia: Custom typeclass

    -
    -
    -
    Accounts/Things: controls who may GET the object.

    Evennia: “get:<lockfunc()”

    -
    -
    -
    -
    -
    EnterLock: Accounts/Things: controls who may ENTER the object

    Evennia:

    -
    -
    GetFromLock: All but Exits: controls who may gets things from a
    -
    given location.

    Evennia:

    -
    -
    -
    -
    GiveLock: Accounts/Things: controls who may give the object.

    Evennia:

    -
    -
    LeaveLock: Accounts/Things: controls who may LEAVE the object.

    Evennia:

    -
    -
    LinkLock: All but Exits: controls who may link to the location

    if the location is LINK_OK (for linking -exits or setting drop-tos) or ABODE (for -setting homes)

    -
    -

    Evennia:

    -
    -
    -
    MailLock: Accounts: controls who may @mail the account.

    Evennia:

    -
    -
    OpenLock: All but Exits: controls who may open an exit.

    Evennia:

    -
    -
    PageLock: Accounts: controls who may page the account.

    Evennia: “send:<lockfunc()>”

    -
    -
    ParentLock: All: controls who may make @parent links to
    -
    the object.

    Evennia: Typeclasses and

    -
    -
    -

    “puppet:<lockstring()>”

    -
    -
    ReceiveLock: Accounts/Things: controls who may give things to the
    -
    object.

    Evennia:

    -
    -
    -
    -
    SpeechLock: All but Exits: controls who may speak in that location

    Evennia:

    -
    -
    TeloutLock: All but Exits: controls who may teleport out of the
    -
    location.

    Evennia:

    -
    -
    -
    -
    TportLock: Rooms/Things: controls who may teleport there

    Evennia:

    -
    -
    UseLock: All but Exits: controls who may USE the object, GIVE

    the object money and have the PAY -attributes run, have their messages -heard and possibly acted on by LISTEN -and AxHEAR, and invoke $-commands -stored on the object.

    -
    -

    Evennia: Commands and Cmdsets.

    -
    -
    -
    DropLock: All but rooms: controls who may drop that object.

    Evennia:

    -
    -
    VisibleLock: All: Controls object visibility when the

    object is not dark and the looker -passes the lock. In DARK locations, the -object must also be set LIGHT and the -viewer must pass the VisibleLock.

    -
    -
    -
    Evennia: Room typeclass with

    Dark/light script

    -
    -
    -
    -
    -
    -
    -
    evennia.locks.lockfuncs.true(*args, **kwargs)[source]
    @@ -170,6 +70,11 @@ viewer must pass the VisibleLock.

    evennia.locks.lockfuncs.none(*args, **kwargs)[source]
    +
    +
    +evennia.locks.lockfuncs.superuser(*args, **kwargs)[source]
    +
    +
    evennia.locks.lockfuncs.self(accessing_obj, accessed_obj, *args, **kwargs)[source]
    @@ -461,15 +366,6 @@ accessed_obj.location == accessing_obj), or if accessing_obj itself holds an object matching the given key.

    -
    -
    -evennia.locks.lockfuncs.superuser(*args, **kwargs)[source]
    -

    Only accepts an accesing_obj that is superuser (e.g. user #1)

    -

    Since a superuser would not ever reach this check (superusers -bypass the lock entirely), any user who gets this far cannot be a -superuser, hence we just return False. :)

    -
    -
    evennia.locks.lockfuncs.has_account(accessing_obj, accessed_obj, *args, **kwargs)[source]
    @@ -494,7 +390,6 @@ everything will enter this function as strings, so they have to be unpacked to their real value. We only support basic properties.

    -
    @@ -517,14 +412,6 @@ unpacked to their real value. We only support basic properties.

    -

    Table of Contents

    - -
      @@ -548,7 +435,6 @@ unpacked to their real value. We only support basic properties.

    • 0.9.5 (v0.9.5 branch)
    -
    diff --git a/docs/0.9.5/api/evennia.locks.lockhandler.html b/docs/0.9.5/api/evennia.locks.lockhandler.html index 769dc544b4..3b6a706d7f 100644 --- a/docs/0.9.5/api/evennia.locks.lockhandler.html +++ b/docs/0.9.5/api/evennia.locks.lockhandler.html @@ -456,7 +456,6 @@ among the locks defined by lockstring.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.objects.admin.html b/docs/0.9.5/api/evennia.objects.admin.html index 8e8b5b8f32..e60b438fba 100644 --- a/docs/0.9.5/api/evennia.objects.admin.html +++ b/docs/0.9.5/api/evennia.objects.admin.html @@ -37,267 +37,8 @@
    -
    -

    evennia.objects.admin

    -
    -
    -class evennia.objects.admin.ObjectAttributeInline(parent_model, admin_site)[source]
    -

    Bases: evennia.typeclasses.admin.AttributeInline

    -

    Defines inline descriptions of Attributes (experimental)

    -
    -
    -model
    -

    alias of evennia.objects.models.ObjectDB_db_attributes

    -
    - -
    -
    -related_field = 'objectdb'
    -
    - -
    -
    -property media
    -
    - -
    - -
    -
    -class evennia.objects.admin.ObjectTagInline(parent_model, admin_site)[source]
    -

    Bases: evennia.typeclasses.admin.TagInline

    -

    Defines inline descriptions of Tags (experimental)

    -
    -
    -model
    -

    alias of evennia.objects.models.ObjectDB_db_tags

    -
    - -
    -
    -related_field = 'objectdb'
    -
    - -
    -
    -property media
    -
    - -
    - -
    -
    -class evennia.objects.admin.ObjectCreateForm(data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=<class 'django.forms.utils.ErrorList'>, label_suffix=None, empty_permitted=False, instance=None, use_required_attribute=None, renderer=None)[source]
    -

    Bases: django.forms.models.ModelForm

    -

    This form details the look of the fields.

    -
    -
    -class Meta[source]
    -

    Bases: object

    -
    -
    -model
    -

    alias of evennia.objects.models.ObjectDB

    -
    - -
    -
    -fields = '__all__'
    -
    - -
    - -
    -
    -raw_id_fields = ('db_destination', 'db_location', 'db_home')
    -
    - -
    -
    -base_fields = {'db_account': <django.forms.models.ModelChoiceField object>, 'db_attributes': <django.forms.models.ModelMultipleChoiceField object>, 'db_cmdset_storage': <django.forms.fields.CharField object>, 'db_destination': <django.forms.models.ModelChoiceField object>, 'db_home': <django.forms.models.ModelChoiceField object>, 'db_key': <django.forms.fields.CharField object>, 'db_location': <django.forms.models.ModelChoiceField object>, 'db_lock_storage': <django.forms.fields.CharField object>, 'db_sessid': <django.forms.fields.CharField object>, 'db_tags': <django.forms.models.ModelMultipleChoiceField object>, 'db_typeclass_path': <django.forms.fields.CharField object>}
    -
    - -
    -
    -declared_fields = {'db_cmdset_storage': <django.forms.fields.CharField object>, 'db_key': <django.forms.fields.CharField object>, 'db_typeclass_path': <django.forms.fields.CharField object>}
    -
    - -
    -
    -property media
    -

    Return all media required to render the widgets on this form.

    -
    - -
    - -
    -
    -class evennia.objects.admin.ObjectEditForm(data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=<class 'django.forms.utils.ErrorList'>, label_suffix=None, empty_permitted=False, instance=None, use_required_attribute=None, renderer=None)[source]
    -

    Bases: evennia.objects.admin.ObjectCreateForm

    -

    Form used for editing. Extends the create one with more fields

    -
    -
    -class Meta[source]
    -

    Bases: object

    -
    -
    -fields = '__all__'
    -
    - -
    - -
    -
    -base_fields = {'db_cmdset_storage': <django.forms.fields.CharField object>, 'db_key': <django.forms.fields.CharField object>, 'db_lock_storage': <django.forms.fields.CharField object>, 'db_typeclass_path': <django.forms.fields.CharField object>}
    -
    - -
    -
    -declared_fields = {'db_cmdset_storage': <django.forms.fields.CharField object>, 'db_key': <django.forms.fields.CharField object>, 'db_lock_storage': <django.forms.fields.CharField object>, 'db_typeclass_path': <django.forms.fields.CharField object>}
    -
    - -
    -
    -property media
    -

    Return all media required to render the widgets on this form.

    -
    - -
    - -
    -
    -class evennia.objects.admin.ObjectDBAdmin(model, admin_site)[source]
    -

    Bases: django.contrib.admin.options.ModelAdmin

    -

    Describes the admin page for Objects.

    -
    -
    -inlines = [<class 'evennia.objects.admin.ObjectTagInline'>, <class 'evennia.objects.admin.ObjectAttributeInline'>]
    -
    - -
    -
    -list_display = ('id', 'db_key', 'db_account', 'db_typeclass_path')
    -
    - -
    - -
    - -
    -
    -ordering = ['db_account', 'db_typeclass_path', 'id']
    -
    - -
    -
    -search_fields = ['=id', '^db_key', 'db_typeclass_path', '^db_account__db_key']
    -
    - -
    -
    -raw_id_fields = ('db_destination', 'db_location', 'db_home')
    -
    - -
    -
    -save_as = True
    -
    - -
    -
    -save_on_top = True
    -
    - -
    - -
    - -
    -
    -list_filter = ('db_typeclass_path',)
    -
    - -
    -
    -form
    -

    alias of ObjectEditForm

    -
    - -
    -
    -fieldsets = ((None, {'fields': (('db_key', 'db_typeclass_path'), ('db_lock_storage',), ('db_location', 'db_home'), 'db_destination', 'db_cmdset_storage')}),)
    -
    - -
    -
    -add_form
    -

    alias of ObjectCreateForm

    -
    - -
    -
    -add_fieldsets = ((None, {'fields': (('db_key', 'db_typeclass_path'), ('db_location', 'db_home'), 'db_destination', 'db_cmdset_storage')}),)
    -
    - -
    -
    -get_fieldsets(request, obj=None)[source]
    -

    Return fieldsets.

    -
    -
    Parameters
    -
      -
    • request (Request) – Incoming request.

    • -
    • obj (ObjectDB, optional) – Database object.

    • -
    -
    -
    -
    - -
    -
    -get_form(request, obj=None, **kwargs)[source]
    -

    Use special form during creation.

    -
    -
    Parameters
    -
      -
    • request (Request) – Incoming request.

    • -
    • obj (Object, optional) – Database object.

    • -
    -
    -
    -
    - -
    -
    -save_model(request, obj, form, change)[source]
    -

    Model-save hook.

    -
    -
    Parameters
    -
      -
    • request (Request) – Incoming request.

    • -
    • obj (Object) – Database object.

    • -
    • form (Form) – Form instance.

    • -
    • change (bool) – If this is a change or a new object.

    • -
    -
    -
    -
    - -
    -
    -response_add(request, obj, post_url_continue=None)[source]
    -

    Determine the HttpResponse for the add_view stage.

    -
    - -
    -
    -property media
    -
    - -
    - +
    +

    evennia.objects.admin

    @@ -343,7 +84,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.objects.html b/docs/0.9.5/api/evennia.objects.html index d89df991d0..61fa3c6cbb 100644 --- a/docs/0.9.5/api/evennia.objects.html +++ b/docs/0.9.5/api/evennia.objects.html @@ -94,7 +94,6 @@ objects inherit from classes in this package.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.objects.manager.html b/docs/0.9.5/api/evennia.objects.manager.html index 45edb7c53a..83159ec261 100644 --- a/docs/0.9.5/api/evennia.objects.manager.html +++ b/docs/0.9.5/api/evennia.objects.manager.html @@ -91,7 +91,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.objects.models.html b/docs/0.9.5/api/evennia.objects.models.html index 505740f2f9..3149e3818f 100644 --- a/docs/0.9.5/api/evennia.objects.models.html +++ b/docs/0.9.5/api/evennia.objects.models.html @@ -70,6 +70,17 @@ handler is defined

    +
    +
    +load()[source]
    +

    Retrieves all objects from database. Used for initializing.

    +
    +
    Returns
    +

    Objects (list of ObjectDB)

    +
    +
    +
    +
    init()[source]
    @@ -78,11 +89,14 @@ handler is defined

    -get(exclude=None)[source]
    +get(exclude=None, content_type=None)[source]

    Return the contents of the cache.

    Parameters
    -

    exclude (Object or list of Object) – object(s) to ignore

    +
      +
    • exclude (Object or list of Object) – object(s) to ignore

    • +
    • content_type (str or None) – Filter list by a content-type. If None, don’t filter.

    • +
    Returns

    objects (list) – the Objects inside this location

    @@ -550,7 +564,6 @@ class built by **create_forward_many_to_many_manager()** define
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.objects.objects.html b/docs/0.9.5/api/evennia.objects.objects.html index 1fef2de4d8..d73bbec6cf 100644 --- a/docs/0.9.5/api/evennia.objects.objects.html +++ b/docs/0.9.5/api/evennia.objects.objects.html @@ -43,12 +43,12 @@ DefaultCharacter, DefaultAccount, DefaultRoom and DefaultExit. These are the (default) starting points for all in-game visible entities.

    +

    This is the v1.0 develop version (for ref in doc building).

    class evennia.objects.objects.ObjectSessionHandler(obj)[source]

    Bases: object

    -

    Handles the get/setting of the sessid -comma-separated integer field

    +

    Handles the get/setting of the sessid comma-separated integer field

    __init__(obj)[source]
    @@ -198,21 +198,26 @@ currently connected to this object.

    -contents_get(exclude=None)[source]
    +contents_get(exclude=None, content_type=None)[source]

    Returns the contents of this object, i.e. all objects that has this object set as its location. This should be publically available.

    Parameters
    -

    exclude (Object) – Object to exclude from returned -contents list

    +
      +
    • exclude (Object) – Object to exclude from returned +contents list

    • +
    • content_type (str) – A content_type to filter by. None for no +filtering.

    • +
    Returns

    contents (list) – List of contents of this Object.

    Notes

    -

    Also available as the contents property.

    +

    Also available as the contents property, minus exclusion +and filtering.

    @@ -229,15 +234,20 @@ objects that has this object set as its location. This should be publically available.

    Parameters
    -

    exclude (Object) – Object to exclude from returned -contents list

    +
      +
    • exclude (Object) – Object to exclude from returned +contents list

    • +
    • content_type (str) – A content_type to filter by. None for no +filtering.

    • +
    Returns

    contents (list) – List of contents of this Object.

    Notes

    -

    Also available as the contents property.

    +

    Also available as the contents property, minus exclusion +and filtering.

    @@ -301,7 +311,7 @@ plural (str): The determined plural form of the key, including the count.

    -search(searchdata, global_search=False, use_nicks=True, typeclass=None, location=None, attribute_name=None, quiet=False, exact=False, candidates=None, nofound_string=None, multimatch_string=None, use_dbref=None)[source]
    +search(searchdata, global_search=False, use_nicks=True, typeclass=None, location=None, attribute_name=None, quiet=False, exact=False, candidates=None, nofound_string=None, multimatch_string=None, use_dbref=None, stacked=0)[source]

    Returns an Object matching a search string/condition

    Perform a standard object search in the database, handling multiple results and lack thereof gracefully. By default, only @@ -336,7 +346,9 @@ for a broader search.

    to search. Note that this is used to query the contents of a location and will not match for the location itself - if you want that, don’t set this or use candidates to specify -exactly which objects should be searched.

    +exactly which objects should be searched. If this nor candidates are +given, candidates will include caller’s inventory, current location and +all objects in the current location.

  • attribute_name (str) – Define which property to search. If set, no key+alias search will be performed. This can be used to search database fields (db_ will be automatically @@ -364,14 +376,22 @@ to find an object (globally) by its database-id 123. If False, will be treated like a normal string. If None (default), the ability to query by #dbref is turned on if self has the permission ‘Builder’ and is turned off otherwise.

  • +
  • stacked (int, optional) – If > 0, multimatches will be analyzed to determine if they +only contains identical objects; these are then assumed ‘stacked’ and no multi-match +error will be generated, instead stacked number of matches will be returned. If +stacked is larger than number of matches, returns that number of matches. If +the found stack is a mix of objects, return None and handle the multi-match +error depending on the value of quiet.

  • Returns
    -

    match (Object, None or list)

    -
    -
    will return an Object/None if quiet=False,

    otherwise it will return a list of 0, 1 or more matches.

    -
    -
    +

    Object – If finding a match an quiet=False +None: If not finding a unique match and quiet=False. +list: With 0, 1 or more matching objects if quiet=True +list: With 2 or more matching objects if stacked is a positive integer and

    +
    +

    the matched stack has only object-copies.

    +

    @@ -526,47 +546,66 @@ function on.

  • text (str or tuple) – Message to send. If a tuple, this should be on the valid OOB outmessage form (message, {kwargs}), where kwargs are optional data passed to the text -outputfunc.

  • +outputfunc. The message will be parsed for {key} formatting and +$You/$you()/$You(key) and $conj(verb) inline function callables. +The key is taken from the mapping kwarg {“key”: object, …}**. +The mapping[key].get_display_name(looker=recipient) will be called +for that key for every recipient of the string.

  • exclude (list, optional) – A list of objects not to send to.

  • from_obj (Object, optional) – An object designated as the “sender” of the message. See DefaultObject.msg() for more info.

  • mapping (dict, optional) – A mapping of formatting keys -{“key”:<object>, “key2”:<object2>,…}. The keys -must match **{key} markers in the text if this is a string or -in the internal message if text is a tuple. These -formatting statements will be -replaced by the return of <object>.get_display_name(looker) -for every looker in contents that receives the -message. This allows for every object to potentially -get its own customized string.

  • - -
    -
    Keyword Arguments
    -
      -
    • arguments will be passed on to obj.msg() for all (Keyword) –

    • -
    • objects. (messaged) –

    • +{“key”:<object>, “key2”:<object2>,…}. +The keys must either match **{key} or $You(key)/$you(key) markers +in the text string. If <object> doesn’t have a get_display_name +method, it will be returned as a string. If not set, a key you will +be auto-added to point to from_obj if given, otherwise to self.

      +
    • **kwargs – Keyword arguments will be passed on to obj.msg() for all +messaged objects.

    Notes

    -

    The mapping argument is required if message contains -{}-style format syntax. The keys of mapping should match -named format tokens, and its values will have their -get_display_name() function called for each object in -the room before substitution. If an item in the mapping does -not have get_display_name(), its string value will be used.

    -

    Example

    -

    Say Char is a Character object and Npc is an NPC object:

    -
    -
    char.location.msg_contents(

    “{attacker} kicks {defender}”, -mapping=dict(attacker=char, defender=npc), exclude=(char, npc))

    -
    -
    -

    This will result in everyone in the room seeing ‘Char kicks NPC’ -where everyone may potentially see different results for Char and Npc -depending on the results of char.get_display_name(looker) and -npc.get_display_name(looker) for each particular onlooker

    +

    For ‘actor-stance’ reporting (You say/Name says), use the +$You()/$you()/$You(key) and $conj(verb) (verb-conjugation) +inline callables. This will use the respective get_display_name() +for all onlookers except for from_obj or self, which will become +‘You/you’. If you use $You/you(key), the key must be in mapping.

    +

    For ‘director-stance’ reporting (Name says/Name says), use {key} +syntax directly. For both {key} and You/you(key), +mapping[key].get_display_name(looker=recipient) may be called +depending on who the recipient is.

    +

    Examples

    +

    Let’s assume +- player1.key -> “Player1”,

    +
    +

    player1.get_display_name(looker=player2) -> “The First girl”

    +
    +
      +
    • player2.key -> “Player2”, +player2.get_display_name(looker=player1) -> “The Second girl”

    • +
    +

    Actor-stance:

    +
    char.location.msg_contents(
    +    "$You() $conj(attack) $you(defender).",
    +    mapping={"defender": player2})
    +
    +
    +
      +
    • player1 will see You attack The Second girl.

    • +
    • player2 will see ‘The First girl attacks you.’

    • +
    +

    Director-stance:

    +
    char.location.msg_contents(
    +    "{attacker} attacks {defender}.",
    +    mapping={"attacker:player1, "defender":player2})
    +
    +
    +
      +
    • player1 will see: ‘Player1 attacks The Second girl.’

    • +
    • player2 will see: ‘The First girl attacks Player2’

    • +
    @@ -684,8 +723,8 @@ specified, the copy will be named <old_key>_copy by default.

    at_object_post_copy(new_obj, **kwargs)[source]
    -

    Called by DefaultObject.copy(). Meant to be overloaded. In case there’s extra data not covered by -.copy(), this can be used to deal with it.

    +

    Called by DefaultObject.copy(). Meant to be overloaded. In case there’s extra data not +covered by .copy(), this can be used to deal with it.

    Parameters

    new_obj (Object) – The new Copy of this object.

    @@ -1367,7 +1406,8 @@ text from the object. Returning None aborts the command.

    a say. This is sent by the whisper command by default. Other verbal commands could use this hook in similar ways.

    -
  • receivers (Object or iterable) – If set, this is the target or targets for the say/whisper.

  • +
  • receivers (Object or iterable) – If set, this is the target or targets for the +say/whisper.

  • Returns
    @@ -1392,8 +1432,8 @@ re-writing it completely.

  • msg_self (bool or str, optional) – If boolean True, echo message to self. If a string, return that message. If False or unset, don’t echo to self.

  • msg_location (str, optional) – The message to echo to self’s location.

  • -
  • receivers (Object or iterable, optional) – An eventual receiver or receivers of the message -(by default only used by whispers).

  • +
  • receivers (Object or iterable, optional) – An eventual receiver or receivers of the +message (by default only used by whispers).

  • msg_receivers (str) – Specific message to pass to the receiver(s). This will parsed with the {receiver} placeholder replaced with the given receiver.

  • @@ -1495,6 +1535,37 @@ errors (list): A list of errors in string form, if any.

    +
    +
    +classmethod normalize_name(name)[source]
    +

    Normalize the character name prior to creating. Note that this should be refactored to +support i18n for non-latin scripts, but as we (currently) have no bug reports requesting +better support of non-latin character sets, requiring character names to be latinified is an +acceptable option.

    +
    +
    Parameters
    +

    name (str) – The name of the character

    +
    +
    Returns
    +

    latin_name (str) – A valid name.

    +
    +
    +
    + +
    +
    +classmethod validate_name(name)[source]
    +

    Validate the character name prior to creating. Overload this function to add custom validators

    +
    +
    Parameters
    +

    name (str) – The name of the character

    +
    +
    Returns
    +

    valid (bool) – True if character creation should continue; False if it should fail

    +
    +
    +
    +
    basetype_setup()[source]
    @@ -1699,7 +1770,8 @@ overriding the call (unused by default).

    Returns
    -

    A string with identifying information to disambiguate the command, conventionally with a preceding space.

    +

    A string with identifying information to disambiguate the command, conventionally with a +preceding space.

    @@ -1724,6 +1796,11 @@ overriding the call (unused by default).

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'command', 'tags': '', 'text': '\n This is a command that simply cause the caller to traverse\n the object it is attached to.\n\n '}
    +
    +
    @@ -1933,7 +2010,6 @@ read for an error string instead.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.prototypes.html b/docs/0.9.5/api/evennia.prototypes.html index f630e2b1c7..323096eb34 100644 --- a/docs/0.9.5/api/evennia.prototypes.html +++ b/docs/0.9.5/api/evennia.prototypes.html @@ -92,7 +92,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.prototypes.menus.html b/docs/0.9.5/api/evennia.prototypes.menus.html index 58d4a61b07..98707d16fe 100644 --- a/docs/0.9.5/api/evennia.prototypes.menus.html +++ b/docs/0.9.5/api/evennia.prototypes.menus.html @@ -197,7 +197,6 @@ prototype rather than creating a new one.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.prototypes.protfuncs.html b/docs/0.9.5/api/evennia.prototypes.protfuncs.html index ad53e9b2f2..aecc51c2c7 100644 --- a/docs/0.9.5/api/evennia.prototypes.protfuncs.html +++ b/docs/0.9.5/api/evennia.prototypes.protfuncs.html @@ -39,188 +39,43 @@

    evennia.prototypes.protfuncs

    -

    Protfuncs are function-strings embedded in a prototype and allows for a builder to create a -prototype with custom logics without having access to Python. The Protfunc is parsed using the -inlinefunc parser but is fired at the moment the spawning happens, using the creating object’s -session as input.

    +

    Protfuncs are FuncParser-callables that can be embedded in a prototype to +provide custom logic without having access to Python. The protfunc is parsed at +the time of spawning, using the creating object’s session as input. If the +protfunc returns a non-string, this is what will be added to the prototype.

    In the prototype dict, the protfunc is specified as a string inside the prototype, e.g.:

    { …

    -

    “key”: “$funcname(arg1, arg2, …)”

    +

    “key”: “$funcname(args, kwargs)”

    … }

    -

    and multiple functions can be nested (no keyword args are supported). The result will be used as the -value for that prototype key for that individual spawn.

    -

    Available protfuncs are callables in one of the modules of settings.PROT_FUNC_MODULES. They -are specified as functions

    +

    Available protfuncs are either all callables in one of the modules of settings.PROT_FUNC_MODULES +or all callables added to a dict FUNCPARSER_CALLABLES in such a module.

    def funcname (*args, **kwargs)

    -

    where *args are the arguments given in the prototype, and **kwargs are inserted by Evennia:

    +

    At spawn-time the spawner passes the following extra kwargs into each callable (in addition to +what is added in the call itself):

    • session (Session): The Session of the entity spawning using this prototype.

    • prototype (dict): The dict this protfunc is a part of.

    • current_key (str): The active key this value belongs to in the prototype.

    • -
    • -
      testing (bool): This is set if this function is called as part of the prototype validation; if

      set, the protfunc should take care not to perform any persistent actions, such as operate on -objects or add things to the database.

      -
      -
      -

    Any traceback raised by this function will be handled at the time of spawning and abort the spawn before any object is created/updated. It must otherwise return the value to store for the specified prototype key (this value must be possible to serialize in an Attribute).

    -
    -evennia.prototypes.protfuncs.base_random()
    -

    random() -> x in the interval [0, 1).

    -
    - -
    -
    -evennia.prototypes.protfuncs.random(*args, **kwargs)[source]
    -

    Usage: $random() -Returns a random value in the interval [0, 1)

    -
    - -
    -
    -evennia.prototypes.protfuncs.randint(*args, **kwargs)[source]
    -

    Usage: $randint(start, end) -Returns random integer in interval [start, end]

    -
    - -
    -
    -evennia.prototypes.protfuncs.left_justify(*args, **kwargs)[source]
    -

    Usage: $left_justify(<text>) -Returns <text> left-justified.

    -
    - -
    -
    -evennia.prototypes.protfuncs.right_justify(*args, **kwargs)[source]
    -

    Usage: $right_justify(<text>) -Returns <text> right-justified across screen width.

    -
    - -
    -
    -evennia.prototypes.protfuncs.center_justify(*args, **kwargs)[source]
    -

    Usage: $center_justify(<text>) -Returns <text> centered in screen width.

    -
    - -
    -
    -evennia.prototypes.protfuncs.choice(*args, **kwargs)[source]
    -

    Usage: $choice(val, val, val, …) -Returns one of the values randomly

    -
    - -
    -
    -evennia.prototypes.protfuncs.full_justify(*args, **kwargs)[source]
    -

    Usage: $full_justify(<text>) -Returns <text> filling up screen width by adding extra space.

    -
    - -
    -
    -evennia.prototypes.protfuncs.protkey(*args, **kwargs)[source]
    -

    Usage: $protkey(<key>) +

    +evennia.prototypes.protfuncs.protfunc_callable_protkey(*args, **kwargs)[source]
    +

    Usage: $protkey(keyname) Returns the value of another key in this prototoype. Will raise an error if

    the key is not found in this prototype.

    -
    -
    -evennia.prototypes.protfuncs.add(*args, **kwargs)[source]
    -

    Usage: $add(val1, val2) -Returns the result of val1 + val2. Values must be

    -
    -

    valid simple Python structures possible to add, -such as numbers, lists etc.

    -
    -
    - -
    -
    -evennia.prototypes.protfuncs.sub(*args, **kwargs)[source]
    -

    Usage: $del(val1, val2) -Returns the value of val1 - val2. Values must be

    -
    -

    valid simple Python structures possible to -subtract.

    -
    -
    - -
    -
    -evennia.prototypes.protfuncs.mult(*args, **kwargs)[source]
    -

    Usage: $mul(val1, val2) -Returns the value of val1 * val2. The values must be

    -
    -

    valid simple Python structures possible to -multiply, like strings and/or numbers.

    -
    -
    - -
    -
    -evennia.prototypes.protfuncs.div(*args, **kwargs)[source]
    -

    Usage: $div(val1, val2) -Returns the value of val1 / val2. Values must be numbers and

    -
    -

    the result is always a float.

    -
    -
    - -
    -
    -evennia.prototypes.protfuncs.toint(*args, **kwargs)[source]
    -

    Usage: $toint(<number>) -Returns <number> as an integer.

    -
    - -
    -
    -evennia.prototypes.protfuncs.eval(*args, **kwargs)[source]
    -

    Usage $eval(<expression>) -Returns evaluation of a simple Python expression. The string may only consist of the following

    -
    -

    Python literal structures: strings, numbers, tuples, lists, dicts, booleans, -and None. The strings can also contain #dbrefs. Escape embedded protfuncs as $$protfunc(..) -- those will then be evaluated after $eval.

    -
    -
    - -
    -
    -evennia.prototypes.protfuncs.obj(*args, **kwargs)[source]
    -

    Usage $obj(<query>) -Returns one Object searched globally by key, alias or #dbref. Error if more than one.

    -
    - -
    -
    -evennia.prototypes.protfuncs.objlist(*args, **kwargs)[source]
    -

    Usage $objlist(<query>) -Returns list with one or more Objects searched globally by key, alias or #dbref.

    -
    - -
    -
    -evennia.prototypes.protfuncs.dbref(*args, **kwargs)[source]
    -

    Usage $dbref(<#dbref>) -Validate that a #dbref input is valid.

    -
    -
    @@ -266,7 +121,6 @@ Validate that a #dbref input is valid.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.prototypes.prototypes.html b/docs/0.9.5/api/evennia.prototypes.prototypes.html index 6292a9bd7d..5816682e6e 100644 --- a/docs/0.9.5/api/evennia.prototypes.prototypes.html +++ b/docs/0.9.5/api/evennia.prototypes.prototypes.html @@ -340,7 +340,7 @@ with (it may still be useful as a mix-in prototype).

    -evennia.prototypes.prototypes.protfunc_parser(value, available_functions=None, testing=False, stacktrace=False, **kwargs)[source]
    +evennia.prototypes.prototypes.protfunc_parser(value, available_functions=None, testing=False, stacktrace=False, caller=None, **kwargs)[source]

    Parse a prototype value string for a protfunc and process it.

    Available protfuncs are specified as callables in one of the modules of settings.PROTFUNC_MODULES, or specified on the command line.

    @@ -351,8 +351,6 @@ with (it may still be useful as a mix-in prototype).

    protfuncs, all other types are returned as-is.

  • available_functions (dict, optional) – Mapping of name:protfunction to use for this parsing. If not set, use default sources.

  • -
  • testing (bool, optional) – Passed to protfunc. If in a testing mode, some protfuncs may -behave differently.

  • stacktrace (bool, optional) – If set, print the stack parsing process of the protfunc-parser.

  • @@ -361,22 +359,15 @@ behave differently.

  • session (Session) – Passed to protfunc. Session of the entity spawning the prototype.

  • protototype (dict) – Passed to protfunc. The dict this protfunc is a part of.

  • current_key (str) – Passed to protfunc. The key in the prototype that will hold this value.

  • +
  • caller (Object or Account) – This is necessary for certain protfuncs that perform object +searches and have to check permissions.

  • any (any) – Passed on to the protfunc.

  • Returns
    -

    testresult (tuple)

    -
    -
    If testing is set, returns a tuple (error, result) where error is

    either None or a string detailing the error from protfunc_parser or seen when trying to -run literal_eval on the parsed string.

    -
    -
    any (any): A structure to replace the string on the prototype level. If this is a

    callable or a (callable, (args,)) structure, it will be executed as if one had supplied -it to the prototype directly. This structure is also passed through literal_eval so one -can get actual Python primitives out of it (not just strings). It will also identify -eventual object #dbrefs in the output from the protfunc.

    -
    -
    -

    +

    any – A structure to replace the string on the prototype leve. Note +that FunctionParser functions $funcname(*args, **kwargs) can return any +data type to insert into the prototype.

    @@ -423,18 +414,22 @@ eventual object #dbrefs in the output from the protfunc.

    -evennia.prototypes.prototypes.init_spawn_value(value, validator=None)[source]
    +evennia.prototypes.prototypes.init_spawn_value(value, validator=None, caller=None)[source]

    Analyze the prototype value and produce a value useful at the point of spawning.

    Parameters

    value (any) –

    This can be: callable - will be called as callable() -(callable, (args,)) - will be called as callable(*args) +(callable, (args,)) - will be called as callable(*args) other - will be assigned depending on the variable type validator (callable, optional): If given, this will be called with the value to

    check and guarantee the outcome is of a given type.

    +
    +
    caller (Object or Account): This is necessary for certain protfuncs that perform object

    searches and have to check permissions.

    +
    +

    Returns
    @@ -500,7 +495,6 @@ validator (callable, optional): If given, this will be called with the value to<
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.prototypes.spawner.html b/docs/0.9.5/api/evennia.prototypes.spawner.html index 43fa7355ef..012965e697 100644 --- a/docs/0.9.5/api/evennia.prototypes.spawner.html +++ b/docs/0.9.5/api/evennia.prototypes.spawner.html @@ -80,7 +80,7 @@ prototype_locks (str, optional): locks for restricting access to this prototype.
    prototype_tags(list, optional): List of tags or tuples (tag, category) used to group prototype

    in listings

    -
    prototype_parent (str, tuple or callable, optional): name (prototype_key) of eventual parent prototype, or

    a list of parents, for multiple left-to-right inheritance.

    +
    prototype_parent (str, tuple or callable, optional): name (prototype_key) of eventual parent

    prototype, or a list of parents, for multiple left-to-right inheritance.

    prototype: Deprecated. Same meaning as ‘parent’.

    @@ -224,8 +224,8 @@ attr/tag (for example) are represented by a tuple.

    This is most useful for displaying.

  • implicit_keep (bool, optional) – If set, the resulting diff will assume KEEP unless the new prototype explicitly change them. That is, if a key exists in prototype1 and -not in prototype2, it will not be REMOVEd but set to KEEP instead. This is particularly -useful for auto-generated prototypes when updating objects.

  • +not in prototype2, it will not be REMOVEd but set to KEEP instead. This is +particularly useful for auto-generated prototypes when updating objects.

    Returns
    @@ -349,7 +349,7 @@ of the olc _format_diff_text_and_options without the options.

    -evennia.prototypes.spawner.batch_update_objects_with_prototype(prototype, diff=None, objects=None, exact=False)[source]
    +evennia.prototypes.spawner.batch_update_objects_with_prototype(prototype, diff=None, objects=None, exact=False, caller=None)[source]

    Update existing objects with the latest version of the prototype.

    Parameters
    @@ -366,6 +366,7 @@ expected - for example, one usually do not want to remove the object’s locatio if it’s not set in the prototype. With exact=True, all un-specified properties of the objects will be removed if they exist. This will lead to a more accurate 1:1 correlation between the object and the prototype but is usually impractical.

    +
  • caller (Object or Account, optional) – This may be used by protfuncs to do permission checks.

  • Returns
    @@ -435,7 +436,7 @@ unprivileged users!

    -evennia.prototypes.spawner.spawn(*prototypes, **kwargs)[source]
    +evennia.prototypes.spawner.spawn(*prototypes, caller=None, **kwargs)[source]

    Spawn a number of prototyped objects.

    Parameters
    @@ -445,6 +446,7 @@ dictionary. These will be batched-spawned as one object each.

    Keyword Arguments
      +
    • caller (Object or Account, optional) – This may be used by protfuncs to do access checks.

    • prototype_modules (str or list) – A python-path to a prototype module, or a list of such paths. These will be used to build the global protparents dictionary accessible by the input @@ -518,7 +520,6 @@ custom prototype_parents are given to this function.

    • 0.9.5 (v0.9.5 branch)
    -
    diff --git a/docs/0.9.5/api/evennia.scripts.admin.html b/docs/0.9.5/api/evennia.scripts.admin.html index 92aa40fbcb..b0e711d415 100644 --- a/docs/0.9.5/api/evennia.scripts.admin.html +++ b/docs/0.9.5/api/evennia.scripts.admin.html @@ -37,132 +37,8 @@
    -
    -

    evennia.scripts.admin

    -
    -
    -class evennia.scripts.admin.ScriptTagInline(parent_model, admin_site)[source]
    -

    Bases: evennia.typeclasses.admin.TagInline

    -

    Inline script tags.

    -
    -
    -model
    -

    alias of evennia.scripts.models.ScriptDB_db_tags

    -
    - -
    -
    -related_field = 'scriptdb'
    -
    - -
    -
    -property media
    -
    - -
    - -
    -
    -class evennia.scripts.admin.ScriptAttributeInline(parent_model, admin_site)[source]
    -

    Bases: evennia.typeclasses.admin.AttributeInline

    -

    Inline attribute tags.

    -
    -
    -model
    -

    alias of evennia.scripts.models.ScriptDB_db_attributes

    -
    - -
    -
    -related_field = 'scriptdb'
    -
    - -
    -
    -property media
    -
    - -
    - -
    -
    -class evennia.scripts.admin.ScriptDBAdmin(model, admin_site)[source]
    -

    Bases: django.contrib.admin.options.ModelAdmin

    -

    Displaying the main Script page.

    -
    -
    -list_display = ('id', 'db_key', 'db_typeclass_path', 'db_obj', 'db_interval', 'db_repeats', 'db_persistent')
    -
    - -
    - -
    - -
    -
    -ordering = ['db_obj', 'db_typeclass_path']
    -
    - -
    -
    -search_fields = ['^db_key', 'db_typeclass_path']
    -
    - -
    -
    -save_as = True
    -
    - -
    -
    -save_on_top = True
    -
    - -
    - -
    - -
    -
    -raw_id_fields = ('db_obj',)
    -
    - -
    -
    -fieldsets = ((None, {'fields': (('db_key', 'db_typeclass_path'), 'db_interval', 'db_repeats', 'db_start_delay', 'db_persistent', 'db_obj')}),)
    -
    - -
    -
    -inlines = [<class 'evennia.scripts.admin.ScriptTagInline'>, <class 'evennia.scripts.admin.ScriptAttributeInline'>]
    -
    - -
    -
    -save_model(request, obj, form, change)[source]
    -

    Model-save hook.

    -
    -
    Parameters
    -
      -
    • request (Request) – Incoming request.

    • -
    • obj (Object) – Database object.

    • -
    • form (Form) – Form instance.

    • -
    • change (bool) – If this is a change or a new object.

    • -
    -
    -
    -
    - -
    -
    -property media
    -
    - -
    - +
    +

    evennia.scripts.admin

    @@ -208,7 +84,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.scripts.html b/docs/0.9.5/api/evennia.scripts.html index d94b9f02b4..924d86a267 100644 --- a/docs/0.9.5/api/evennia.scripts.html +++ b/docs/0.9.5/api/evennia.scripts.html @@ -100,7 +100,6 @@ timed effects.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.scripts.manager.html b/docs/0.9.5/api/evennia.scripts.manager.html index 6cbade58c6..0cd04fe48c 100644 --- a/docs/0.9.5/api/evennia.scripts.manager.html +++ b/docs/0.9.5/api/evennia.scripts.manager.html @@ -91,7 +91,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.scripts.models.html b/docs/0.9.5/api/evennia.scripts.models.html index a0ca07e173..88bfbacbce 100644 --- a/docs/0.9.5/api/evennia.scripts.models.html +++ b/docs/0.9.5/api/evennia.scripts.models.html @@ -378,7 +378,6 @@ class built by **create_forward_many_to_many_manager()** define
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.scripts.monitorhandler.html b/docs/0.9.5/api/evennia.scripts.monitorhandler.html index 2153ee743e..88baf7cd28 100644 --- a/docs/0.9.5/api/evennia.scripts.monitorhandler.html +++ b/docs/0.9.5/api/evennia.scripts.monitorhandler.html @@ -200,7 +200,6 @@ all kwargs must be possible to pickle!

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.scripts.scripthandler.html b/docs/0.9.5/api/evennia.scripts.scripthandler.html index 4c8f4c4c2e..24e4967369 100644 --- a/docs/0.9.5/api/evennia.scripts.scripthandler.html +++ b/docs/0.9.5/api/evennia.scripts.scripthandler.html @@ -138,25 +138,6 @@ If no key is given, delete all scripts on the object!

    Get all scripts stored in this handler.

    -
    -
    -validate(init_mode=False)[source]
    -

    Runs a validation on this object’s scripts only. This should -be called regularly to crank the wheels.

    -
    -
    Parameters
    -

    init_mode (str, optional) –

      -
    • This is used during server

    • -
    -

    upstart and can have three values: -- False (no init mode). Called during run. -- “reset” - server reboot. Kill non-persistent scripts -- “reload” - server reload. Keep non-persistent scripts.

    -

    -
    -
    -
    -
    @@ -204,7 +185,6 @@ be called regularly to crank the wheels.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.scripts.scripts.html b/docs/0.9.5/api/evennia.scripts.scripts.html index 7d2bed16b4..f2596b2f92 100644 --- a/docs/0.9.5/api/evennia.scripts.scripts.html +++ b/docs/0.9.5/api/evennia.scripts.scripts.html @@ -70,182 +70,20 @@ errors (list): A list of errors in string form, if any.

    Only called once, when script is first created.

    -
    -
    -time_until_next_repeat()[source]
    -

    Get time until the script fires it at_repeat hook again.

    -
    -
    Returns
    -

    next (int)

    -
    -
    Time in seconds until the script runs again.

    If not a timed script, return None.

    -
    -
    -

    -
    -
    -

    Notes

    -

    This hook is not used in any way by the script’s stepping -system; it’s only here for the user to be able to check in -on their scripts and when they will next be run.

    -
    - -
    -
    -remaining_repeats()[source]
    -

    Get the number of returning repeats for limited Scripts.

    -
    -
    Returns
    -

    remaining (int or None) –

    -
    -
    The number of repeats

    remaining until the Script stops. Returns None -if it has unlimited repeats.

    -
    -
    -

    -
    -
    -
    - -
    -
    -at_idmapper_flush()[source]
    -

    If we’re flushing this object, make sure the LoopingCall is gone too

    -
    - -
    -
    -start(force_restart=False)[source]
    -

    Called every time the script is started (for persistent -scripts, this is usually once every server start)

    -
    -
    Parameters
    -

    force_restart (bool, optional) – Normally an already -started script will not be started again. if -force_restart=True, the script will always restart -the script, regardless of if it has started before.

    -
    -
    Returns
    -

    result (int)

    -
    -
    0 or 1 depending on if the script successfully

    started or not. Used in counting.

    -
    -
    -

    -
    -
    -
    - -
    -
    -stop(kill=False)[source]
    -

    Called to stop the script from running. This also deletes the -script.

    -
    -
    Parameters
    -

    kill (bool, optional) –

      -
    • Stop the script without

    • -
    -

    calling any relevant script hooks.

    -

    -
    -
    Returns
    -

    result (int)

    -
    -
    0 if the script failed to stop, 1 otherwise.

    Used in counting.

    -
    -
    -

    -
    -
    -
    - -
    -
    -pause(manual_pause=True)[source]
    -

    This stops a running script and stores its active state. -It WILL NOT call the at_stop() hook.

    -
    - -
    -
    -unpause(manual_unpause=True)[source]
    -

    Restart a paused script. This WILL call the at_start() hook.

    -
    -
    Parameters
    -

    manual_unpause (bool, optional) – This is False if unpause is -called by the server reload/reset mechanism.

    -
    -
    Returns
    -

    result (bool) – True if unpause was triggered, False otherwise.

    -
    -
    Raises
    -

    RuntimeError – If trying to automatically resart this script -(usually after a reset/reload), but it was manually paused, -and so should not the auto-unpaused.

    -
    -
    -
    - -
    -
    -restart(interval=None, repeats=None, start_delay=None)[source]
    -

    Restarts an already existing/running Script from the -beginning, optionally using different settings. This will -first call the stop hooks, and then the start hooks again. -:param interval: Allows for changing the interval

    -
    -

    of the Script. Given in seconds. if None, will use the already stored interval.

    -
    -
    -
    Parameters
    -
      -
    • repeats (int, optional) – The number of repeats. If unset, will -use the previous setting.

    • -
    • start_delay (bool, optional) – If we should wait interval seconds -before starting or not. If None, re-use the previous setting.

    • -
    -
    -
    -
    - -
    -
    -reset_callcount(value=0)[source]
    -

    Reset the count of the number of calls done.

    -
    -
    Parameters
    -

    value (int, optional) – The repeat value to reset to. Default -is to set it all the way back to 0.

    -
    -
    -

    Notes

    -

    This is only useful if repeats != 0.

    -
    - -
    -
    -force_repeat()[source]
    -

    Fire a premature triggering of the script callback. This -will reset the timer and count down repeats as if the script -had fired normally.

    -
    -
    is_valid()[source]
    -

    Is called to check if the script is valid to run at this time. -Should return a boolean. The method is assumed to collect all -needed information from its related self.obj.

    +

    Is called to check if the script’s timer is valid to run at this time. +Should return a boolean. If False, the timer will be stopped.

    at_start(**kwargs)[source]
    -

    Called whenever the script is started, which for persistent -scripts is at least once every server start. It will also be -called when starting again after a pause (such as after a -server reload)

    +

    Called whenever the script timer is started, which for persistent +timed scripts is at least once every server start. It will also be +called when starting again after a pause (including after a +server reload).

    Parameters

    **kwargs (dict) – Arbitrary, optional arguments for users @@ -266,20 +104,39 @@ overriding the call (unused by default).

    +
    +
    +at_pause(manual_pause=True, **kwargs)[source]
    +

    Called when this script’s timer pauses.

    +
    +
    Parameters
    +

    manual_pause (bool) – If set, pausing was done by a direct call. The +non-manual pause indicates the script was paused as part of +the server reload.

    +
    +
    +
    +
    at_stop(**kwargs)[source]
    -

    Called whenever when it’s time for this script to stop (either -because is_valid returned False or it runs out of iterations)

    -
    -
    Args
    -
    **kwargs (dict): Arbitrary, optional arguments for users

    overriding the call (unused by default).

    -
    -
    +

    Called whenever when it’s time for this script’s timer to stop (either +because is_valid returned False, it ran out of iterations or it was manuallys +stopped.

    +
    +
    Parameters
    +

    **kwargs (dict) – Arbitrary, optional arguments for users +overriding the call (unused by default).

    +
    +
    +at_script_delete()[source]
    +

    Called when the Script is deleted, after at_stop().

    +
    +
    at_server_reload()[source]
    @@ -296,6 +153,14 @@ to do it.

    (i.e. not for a restart).

    +
    +
    +at_server_start()[source]
    +

    This hook is called after the server has started. It can be used to add +post-startup setup for Scripts without a timer component (for which at_start +could be used).

    +
    +
    exception DoesNotExist
    @@ -435,7 +300,6 @@ to do it.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.scripts.taskhandler.html b/docs/0.9.5/api/evennia.scripts.taskhandler.html index 4585ea7129..94ea9a847a 100644 --- a/docs/0.9.5/api/evennia.scripts.taskhandler.html +++ b/docs/0.9.5/api/evennia.scripts.taskhandler.html @@ -139,7 +139,7 @@ called(self): A task attribute to check if the deferred instance of a task has b
    pause()[source]

    Pause the callback of a task. -To resume use TaskHandlerTask.unpause

    +To resume use TaskHandlerTask.unpause.

    @@ -440,8 +440,7 @@ Deletes the instance of the task’s deferred.

    clear(save=True, cancel=True)[source]
    -

    clear all tasks. -By default tasks are canceled and removed from the database also.

    +

    Clear all tasks. By default tasks are canceled and removed from the database as well.

    Parameters
      @@ -564,7 +563,6 @@ This method should be automatically called when Evennia starts.

    • 0.9.5 (v0.9.5 branch)
    -
    diff --git a/docs/0.9.5/api/evennia.scripts.tickerhandler.html b/docs/0.9.5/api/evennia.scripts.tickerhandler.html index 00ae877704..9d45a4ae53 100644 --- a/docs/0.9.5/api/evennia.scripts.tickerhandler.html +++ b/docs/0.9.5/api/evennia.scripts.tickerhandler.html @@ -428,7 +428,6 @@ non-db objects.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.admin.html b/docs/0.9.5/api/evennia.server.admin.html index c1e36bfdac..ed756a117d 100644 --- a/docs/0.9.5/api/evennia.server.admin.html +++ b/docs/0.9.5/api/evennia.server.admin.html @@ -37,55 +37,8 @@
    -
    -

    evennia.server.admin

    -
    -
    -class evennia.server.admin.ServerConfigAdmin(model, admin_site)[source]
    -

    Bases: django.contrib.admin.options.ModelAdmin

    -

    Custom admin for server configs

    -
    -
    -list_display = ('db_key', 'db_value')
    -
    - -
    - -
    - -
    -
    -ordering = ['db_key', 'db_value']
    -
    - -
    -
    -search_fields = ['db_key']
    -
    - -
    -
    -save_as = True
    -
    - -
    -
    -save_on_top = True
    -
    - -
    - -
    - -
    -
    -property media
    -
    - -
    - +
    +

    evennia.server.admin

    @@ -131,7 +84,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.amp_client.html b/docs/0.9.5/api/evennia.server.amp_client.html index 7f844d53e1..b955912945 100644 --- a/docs/0.9.5/api/evennia.server.amp_client.html +++ b/docs/0.9.5/api/evennia.server.amp_client.html @@ -266,7 +266,6 @@ operation, as defined by the global variables in
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.connection_wizard.html b/docs/0.9.5/api/evennia.server.connection_wizard.html index bd1bf8742e..5633b94ac2 100644 --- a/docs/0.9.5/api/evennia.server.connection_wizard.html +++ b/docs/0.9.5/api/evennia.server.connection_wizard.html @@ -205,7 +205,6 @@ fails (and is expected to echo why if so).

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.deprecations.html b/docs/0.9.5/api/evennia.server.deprecations.html index 7cc0a3775d..6fd8847638 100644 --- a/docs/0.9.5/api/evennia.server.deprecations.html +++ b/docs/0.9.5/api/evennia.server.deprecations.html @@ -109,7 +109,6 @@ does not stop launch.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.evennia_launcher.html b/docs/0.9.5/api/evennia.server.evennia_launcher.html index 6093cb989e..155cd1bfd1 100644 --- a/docs/0.9.5/api/evennia.server.evennia_launcher.html +++ b/docs/0.9.5/api/evennia.server.evennia_launcher.html @@ -583,7 +583,6 @@ settings here. The result will be printed to the terminal.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.game_index_client.client.html b/docs/0.9.5/api/evennia.server.game_index_client.client.html index 2991dabcb0..bcc503d0d0 100644 --- a/docs/0.9.5/api/evennia.server.game_index_client.client.html +++ b/docs/0.9.5/api/evennia.server.game_index_client.client.html @@ -195,7 +195,6 @@ to this Protocol. The connection has been closed.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.game_index_client.html b/docs/0.9.5/api/evennia.server.game_index_client.html index 886548c9ae..2e724778e4 100644 --- a/docs/0.9.5/api/evennia.server.game_index_client.html +++ b/docs/0.9.5/api/evennia.server.game_index_client.html @@ -90,7 +90,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.game_index_client.service.html b/docs/0.9.5/api/evennia.server.game_index_client.service.html index fb83b694d3..01a1e680be 100644 --- a/docs/0.9.5/api/evennia.server.game_index_client.service.html +++ b/docs/0.9.5/api/evennia.server.game_index_client.service.html @@ -114,7 +114,6 @@ to the Evennia Game Index.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.html b/docs/0.9.5/api/evennia.server.html index 3b136b2183..d99d4c54e6 100644 --- a/docs/0.9.5/api/evennia.server.html +++ b/docs/0.9.5/api/evennia.server.html @@ -152,7 +152,6 @@ to connect to the game.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.initial_setup.html b/docs/0.9.5/api/evennia.server.initial_setup.html index fc42b2b0fa..6176034ecf 100644 --- a/docs/0.9.5/api/evennia.server.initial_setup.html +++ b/docs/0.9.5/api/evennia.server.initial_setup.html @@ -144,7 +144,6 @@ steps need to be redone.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.inputfuncs.html b/docs/0.9.5/api/evennia.server.inputfuncs.html index dd7266201d..708e6e7251 100644 --- a/docs/0.9.5/api/evennia.server.inputfuncs.html +++ b/docs/0.9.5/api/evennia.server.inputfuncs.html @@ -383,7 +383,6 @@ logging a missing inputfunc for it.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.manager.html b/docs/0.9.5/api/evennia.server.manager.html index e1ac547375..035c1c38aa 100644 --- a/docs/0.9.5/api/evennia.server.manager.html +++ b/docs/0.9.5/api/evennia.server.manager.html @@ -122,7 +122,6 @@ value (str): If key was given, this is the stored value, or

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.models.html b/docs/0.9.5/api/evennia.server.models.html index cc0402e317..f7262727f9 100644 --- a/docs/0.9.5/api/evennia.server.models.html +++ b/docs/0.9.5/api/evennia.server.models.html @@ -176,7 +176,6 @@ object the first time, the query is executed.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.portal.amp.html b/docs/0.9.5/api/evennia.server.portal.amp.html index b82709aab6..f23d0df9af 100644 --- a/docs/0.9.5/api/evennia.server.portal.amp.html +++ b/docs/0.9.5/api/evennia.server.portal.amp.html @@ -436,13 +436,13 @@ that way.

    -errback(e, info)[source]
    +errback(err, info)[source]

    Error callback. Handles errors to avoid dropping connections on server tracebacks.

    Parameters
      -
    • e (Failure) – Deferred error instance.

    • +
    • err (Failure) – Deferred error instance.

    • info (str) – Error string.

    @@ -559,7 +559,6 @@ function call

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.portal.amp_server.html b/docs/0.9.5/api/evennia.server.portal.amp_server.html index 0bf574c16a..ba8ecc2d4d 100644 --- a/docs/0.9.5/api/evennia.server.portal.amp_server.html +++ b/docs/0.9.5/api/evennia.server.portal.amp_server.html @@ -77,7 +77,7 @@ these are the Evennia Server and the evennia launcher).

    Parameters
      -
    • portal (Portal) – The Evennia Portal service instance.

    • +
    • portal (Portal) – The Evennia Portal service instance.

    • protocol (Protocol) – The protocol the factory creates instances of.

    @@ -307,7 +307,6 @@ global variables in evennia/server/amp.py.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.portal.grapevine.html b/docs/0.9.5/api/evennia.server.portal.grapevine.html index 32bef00fff..56a57d03f1 100644 --- a/docs/0.9.5/api/evennia.server.portal.grapevine.html +++ b/docs/0.9.5/api/evennia.server.portal.grapevine.html @@ -304,7 +304,6 @@ disconnect this protocol.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.portal.html b/docs/0.9.5/api/evennia.server.portal.html index 19aab16f2b..c49c39a443 100644 --- a/docs/0.9.5/api/evennia.server.portal.html +++ b/docs/0.9.5/api/evennia.server.portal.html @@ -109,7 +109,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.portal.irc.html b/docs/0.9.5/api/evennia.server.portal.irc.html index 20da285105..9396b5281d 100644 --- a/docs/0.9.5/api/evennia.server.portal.irc.html +++ b/docs/0.9.5/api/evennia.server.portal.irc.html @@ -420,7 +420,6 @@ sessions.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.portal.mccp.html b/docs/0.9.5/api/evennia.server.portal.mccp.html index cc7af2c565..526b7106dc 100644 --- a/docs/0.9.5/api/evennia.server.portal.mccp.html +++ b/docs/0.9.5/api/evennia.server.portal.mccp.html @@ -37,8 +37,78 @@
    -
    -

    evennia.server.portal.mccp

    +
    +

    evennia.server.portal.mccp

    +

    MCCP - Mud Client Compression Protocol

    +

    This implements the MCCP v2 telnet protocol as per +http://tintin.sourceforge.net/mccp/. MCCP allows for the server to +compress data when sending to supporting clients, reducing bandwidth +by 70-90%.. The compression is done using Python’s builtin zlib +library. If the client doesn’t support MCCP, server sends uncompressed +as normal. Note: On modern hardware you are not likely to notice the +effect of MCCP unless you have extremely heavy traffic or sits on a +terribly slow connection.

    +

    This protocol is implemented by the telnet protocol importing +mccp_compress and calling it from its write methods.

    +
    +
    +evennia.server.portal.mccp.mccp_compress(protocol, data)[source]
    +

    Handles zlib compression, if applicable.

    +
    +
    Parameters
    +

    data (str) – Incoming data to compress.

    +
    +
    Returns
    +

    stream (binary) – Zlib-compressed data.

    +
    +
    +
    + +
    +
    +class evennia.server.portal.mccp.Mccp(protocol)[source]
    +

    Bases: object

    +

    Implements the MCCP protocol. Add this to a +variable on the telnet protocol to set it up.

    +
    +
    +__init__(protocol)[source]
    +

    initialize MCCP by storing protocol on +ourselves and calling the client to see if +it supports MCCP. Sets callbacks to +start zlib compression in that case.

    +
    +
    Parameters
    +

    protocol (Protocol) – The active protocol instance.

    +
    +
    +
    + +
    +
    +no_mccp(option)[source]
    +

    Called if client doesn’t support mccp or chooses to turn it off.

    +
    +
    Parameters
    +

    option (Option) – Option dict (not used).

    +
    +
    +
    + +
    +
    +do_mccp(option)[source]
    +

    The client supports MCCP. Set things up by +creating a zlib compression stream.

    +
    +
    Parameters
    +

    option (Option) – Option dict (not used).

    +
    +
    +
    + +
    +
    @@ -84,7 +154,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.portal.mssp.html b/docs/0.9.5/api/evennia.server.portal.mssp.html index be7dacf1c0..00a20500e0 100644 --- a/docs/0.9.5/api/evennia.server.portal.mssp.html +++ b/docs/0.9.5/api/evennia.server.portal.mssp.html @@ -37,8 +37,79 @@
    -
    -

    evennia.server.portal.mssp

    +
    +

    evennia.server.portal.mssp

    +

    MSSP - Mud Server Status Protocol

    +

    This implements the MSSP telnet protocol as per +http://tintin.sourceforge.net/mssp/. MSSP allows web portals and +listings to have their crawlers find the mud and automatically +extract relevant information about it, such as genre, how many +active players and so on.

    +
    +
    +class evennia.server.portal.mssp.Mssp(protocol)[source]
    +

    Bases: object

    +

    Implements the MSSP protocol. Add this to a variable on the telnet +protocol to set it up.

    +
    +
    +__init__(protocol)[source]
    +

    initialize MSSP by storing protocol on ourselves and calling +the client to see if it supports MSSP.

    +
    +
    Parameters
    +

    protocol (Protocol) – The active protocol instance.

    +
    +
    +
    + +
    +
    +get_player_count()[source]
    +

    Get number of logged-in players.

    +
    +
    Returns
    +

    count (int) – The number of players in the MUD.

    +
    +
    +
    + +
    +
    +get_uptime()[source]
    +

    Get how long the portal has been online (reloads are not counted).

    +
    +
    Returns
    +

    uptime (int) – Number of seconds of uptime.

    +
    +
    +
    + +
    +
    +no_mssp(option)[source]
    +

    Called when mssp is not requested. This is the normal +operation.

    +
    +
    Parameters
    +

    option (Option) – Not used.

    +
    +
    +
    + +
    +
    +do_mssp(option)[source]
    +

    Negotiate all the information.

    +
    +
    Parameters
    +

    option (Option) – Not used.

    +
    +
    +
    + +
    +
    @@ -84,7 +155,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.portal.mxp.html b/docs/0.9.5/api/evennia.server.portal.mxp.html index 2f443dbb3e..a3d1bee53a 100644 --- a/docs/0.9.5/api/evennia.server.portal.mxp.html +++ b/docs/0.9.5/api/evennia.server.portal.mxp.html @@ -37,8 +37,71 @@
    -
    -

    evennia.server.portal.mxp

    +
    +

    evennia.server.portal.mxp

    +

    MXP - Mud eXtension Protocol.

    +

    Partial implementation of the MXP protocol. +The MXP protocol allows more advanced formatting options for telnet clients +that supports it (mudlet, zmud, mushclient are a few)

    +

    This only implements the SEND tag.

    +

    More information can be found on the following links: +http://www.zuggsoft.com/zmud/mxp.htm +http://www.mushclient.com/mushclient/mxp.htm +http://www.gammon.com.au/mushclient/addingservermxp.htm

    +
    +
    +evennia.server.portal.mxp.mxp_parse(text)[source]
    +

    Replaces links to the correct format for MXP.

    +
    +
    Parameters
    +

    text (str) – The text to parse.

    +
    +
    Returns
    +

    parsed (str) – The parsed text.

    +
    +
    +
    + +
    +
    +class evennia.server.portal.mxp.Mxp(protocol)[source]
    +

    Bases: object

    +

    Implements the MXP protocol.

    +
    +
    +__init__(protocol)[source]
    +

    Initializes the protocol by checking if the client supports it.

    +
    +
    Parameters
    +

    protocol (Protocol) – The active protocol instance.

    +
    +
    +
    + +
    +
    +no_mxp(option)[source]
    +

    Called when the Client reports to not support MXP.

    +
    +
    Parameters
    +

    option (Option) – Not used.

    +
    +
    +
    + +
    +
    +do_mxp(option)[source]
    +

    Called when the Client reports to support MXP.

    +
    +
    Parameters
    +

    option (Option) – Not used.

    +
    +
    +
    + +
    +
    @@ -84,7 +147,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.portal.naws.html b/docs/0.9.5/api/evennia.server.portal.naws.html index d5fcfef2ba..b22a0d493c 100644 --- a/docs/0.9.5/api/evennia.server.portal.naws.html +++ b/docs/0.9.5/api/evennia.server.portal.naws.html @@ -37,8 +37,67 @@
    -
    -

    evennia.server.portal.naws

    +
    +

    evennia.server.portal.naws

    +

    NAWS - Negotiate About Window Size

    +

    This implements the NAWS telnet option as per +https://www.ietf.org/rfc/rfc1073.txt

    +

    NAWS allows telnet clients to report their current window size to the +client and update it when the size changes

    +
    +
    +class evennia.server.portal.naws.Naws(protocol)[source]
    +

    Bases: object

    +

    Implements the NAWS protocol. Add this to a variable on the telnet +protocol to set it up.

    +
    +
    +__init__(protocol)[source]
    +

    initialize NAWS by storing protocol on ourselves and calling +the client to see if it supports NAWS.

    +
    +
    Parameters
    +

    protocol (Protocol) – The active protocol instance.

    +
    +
    +
    + +
    +
    +no_naws(option)[source]
    +

    Called when client is not reporting NAWS. This is the normal +operation.

    +
    +
    Parameters
    +

    option (Option) – Not used.

    +
    +
    +
    + +
    +
    +do_naws(option)[source]
    +

    Client wants to negotiate all the NAWS information.

    +
    +
    Parameters
    +

    option (Option) – Not used.

    +
    +
    +
    + +
    +
    +negotiate_sizes(options)[source]
    +

    Step through the NAWS handshake.

    +
    +
    Parameters
    +

    option (list) – The incoming NAWS options.

    +
    +
    +
    + +
    +
    @@ -84,7 +143,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.portal.portal.html b/docs/0.9.5/api/evennia.server.portal.portal.html index 0839d537f3..d7dec67b56 100644 --- a/docs/0.9.5/api/evennia.server.portal.portal.html +++ b/docs/0.9.5/api/evennia.server.portal.portal.html @@ -37,8 +37,66 @@
    -
    -

    evennia.server.portal.portal

    +
    +

    evennia.server.portal.portal

    +

    This module implements the main Evennia server process, the core of +the game engine.

    +

    This module should be started with the ‘twistd’ executable since it +sets up all the networking features. (this is done automatically +by game/evennia.py).

    +
    +
    +class evennia.server.portal.portal.Portal(application)[source]
    +

    Bases: object

    +

    The main Portal server handler. This object sets up the database +and tracks and interlinks all the twisted network services that +make up Portal.

    +
    +
    +__init__(application)[source]
    +

    Setup the server.

    +
    +
    Parameters
    +

    application (Application) – An instantiated Twisted application

    +
    +
    +
    + +
    +
    +get_info_dict()[source]
    +

    Return the Portal info, for display.

    +
    + +
    +
    +shutdown(_reactor_stopping=False, _stop_server=False)[source]
    +

    Shuts down the server from inside it.

    +
    +
    Parameters
    +
      +
    • _reactor_stopping (bool, optional) – This is set if server +is already in the process of shutting down; in this case +we don’t need to stop it again.

    • +
    • _stop_server (bool, optional) – Only used in portal-interactive mode; +makes sure to stop the Server cleanly.

    • +
    +
    +
    +

    Note that restarting (regardless of the setting) will not work +if the Portal is currently running in daemon mode. In that +case it always needs to be restarted manually.

    +
    + +
    + +
    +
    +class evennia.server.portal.portal.Websocket(*args, **kwargs)[source]
    +

    Bases: autobahn.twisted.websocket.WebSocketServerFactory

    +

    Only here for better naming in logs

    +
    +
    @@ -84,7 +142,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.portal.portalsessionhandler.html b/docs/0.9.5/api/evennia.server.portal.portalsessionhandler.html index c216b9480c..179b115ec1 100644 --- a/docs/0.9.5/api/evennia.server.portal.portalsessionhandler.html +++ b/docs/0.9.5/api/evennia.server.portal.portalsessionhandler.html @@ -39,7 +39,7 @@

    evennia.server.portal.portalsessionhandler

    -

    Sessionhandler for portal sessions

    +

    Sessionhandler for portal sessions.

    class evennia.server.portal.portalsessionhandler.PortalSessionHandler(*args, **kwargs)[source]
    @@ -63,6 +63,17 @@ to the server using the AMP connection.

    At this point, the AMP connection is already established.

    +
    +
    +generate_sessid()[source]
    +

    Simply generates a sessid that’s guaranteed to be unique for this Portal run.

    +
    +
    Returns
    +

    sessid

    +
    +
    +
    +
    connect(session)[source]
    @@ -332,7 +343,6 @@ method exixts, it sends the data to a method send_default.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.portal.rss.html b/docs/0.9.5/api/evennia.server.portal.rss.html index d527b16de0..2f7e53f9cc 100644 --- a/docs/0.9.5/api/evennia.server.portal.rss.html +++ b/docs/0.9.5/api/evennia.server.portal.rss.html @@ -184,7 +184,6 @@ on slow connections.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.portal.ssh.html b/docs/0.9.5/api/evennia.server.portal.ssh.html index 8f4b82cea0..4c79fac487 100644 --- a/docs/0.9.5/api/evennia.server.portal.ssh.html +++ b/docs/0.9.5/api/evennia.server.portal.ssh.html @@ -225,18 +225,18 @@ reaching this point.

    are considered.

    Keyword Arguments
    -

    options (dict) –

    Send-option flags:

    +

    options (dict) –

    Send-option flags (booleans)

      -
    • mxp: Enforce MXP link support.

    • -
    • ansi: Enforce no ANSI colors.

    • -
    • xterm256: Enforce xterm256 colors, regardless of TTYPE setting.

    • -
    • nocolor: Strip all colors.

    • -
    • raw: Pass string through without any ansi processing -(i.e. include Evennia ansi markers but do not +

    • mxp: enforce mxp link support.

    • +
    • ansi: enforce no ansi colors.

    • +
    • xterm256: enforce xterm256 colors, regardless of ttype setting.

    • +
    • nocolor: strip all colors.

    • +
    • raw: pass string through without any ansi processing +(i.e. include evennia ansi markers but do not convert them into ansi tokens)

    • -
    • echo: Turn on/off line echo on the client. Turn +

    • echo: turn on/off line echo on the client. turn off line echo for client, for example for password. -Note that it must be actively turned back on again!

    • +note that it must be actively turned back on again!

    @@ -405,7 +405,6 @@ do not exist, the keypair is created.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.portal.ssl.html b/docs/0.9.5/api/evennia.server.portal.ssl.html index 8a4c001fe9..269d8397dc 100644 --- a/docs/0.9.5/api/evennia.server.portal.ssl.html +++ b/docs/0.9.5/api/evennia.server.portal.ssl.html @@ -37,8 +37,49 @@
    -
    -

    evennia.server.portal.ssl

    +
    +

    evennia.server.portal.ssl

    +

    This is a simple context factory for auto-creating +SSL keys and certificates.

    +
    +
    +class evennia.server.portal.ssl.SSLProtocol(*args, **kwargs)[source]
    +

    Bases: evennia.server.portal.telnet.TelnetProtocol

    +

    Communication is the same as telnet, except data transfer +is done with encryption.

    +
    +
    +__init__(*args, **kwargs)[source]
    +

    Initialize self. See help(type(self)) for accurate signature.

    +
    + +
    + +
    +
    +evennia.server.portal.ssl.verify_SSL_key_and_cert(keyfile, certfile)[source]
    +

    This function looks for RSA key and certificate in the current +directory. If files ssl.key and ssl.cert does not exist, they +are created.

    +
    + +
    +
    +evennia.server.portal.ssl.getSSLContext()[source]
    +

    This is called by the portal when creating the SSL context +server-side.

    +
    +
    Returns
    +

    ssl_context (tuple)

    +
    +
    A key and certificate that is either

    existing previously or or created on the fly.

    +
    +
    +

    +
    +
    +
    +
    @@ -84,7 +125,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.portal.suppress_ga.html b/docs/0.9.5/api/evennia.server.portal.suppress_ga.html index 6efded5cae..4de5113d64 100644 --- a/docs/0.9.5/api/evennia.server.portal.suppress_ga.html +++ b/docs/0.9.5/api/evennia.server.portal.suppress_ga.html @@ -37,8 +37,57 @@
    -
    -

    evennia.server.portal.suppress_ga

    +
    +

    evennia.server.portal.suppress_ga

    +

    SUPPRESS-GO-AHEAD

    +

    This supports suppressing or activating Evennia +the GO-AHEAD telnet operation after every server reply. +If the client sends no explicit DONT SUPRESS GO-AHEAD, +Evennia will default to supressing it since many clients +will fail to use it and has no knowledge of this standard.

    +

    It is set as the NOGOAHEAD protocol_flag option.

    +

    http://www.faqs.org/rfcs/rfc858.html

    +
    +
    +class evennia.server.portal.suppress_ga.SuppressGA(protocol)[source]
    +

    Bases: object

    +

    Implements the SUPRESS-GO-AHEAD protocol. Add this to a variable on the telnet +protocol to set it up.

    +
    +
    +__init__(protocol)[source]
    +

    Initialize suppression of GO-AHEADs.

    +
    +
    Parameters
    +

    protocol (Protocol) – The active protocol instance.

    +
    +
    +
    + +
    +
    +wont_suppress_ga(option)[source]
    +

    Called when client requests to not suppress GA.

    +
    +
    Parameters
    +

    option (Option) – Not used.

    +
    +
    +
    + +
    +
    +will_suppress_ga(option)[source]
    +

    Client will suppress GA

    +
    +
    Parameters
    +

    option (Option) – Not used.

    +
    +
    +
    + +
    +
    @@ -84,7 +133,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.portal.telnet.html b/docs/0.9.5/api/evennia.server.portal.telnet.html index e9a4aab375..6dcb267fc2 100644 --- a/docs/0.9.5/api/evennia.server.portal.telnet.html +++ b/docs/0.9.5/api/evennia.server.portal.telnet.html @@ -37,8 +37,250 @@
    -
    -

    evennia.server.portal.telnet

    +
    +

    evennia.server.portal.telnet

    +

    This module implements the telnet protocol.

    +

    This depends on a generic session module that implements +the actual login procedure of the game, tracks +sessions etc.

    +
    +
    +class evennia.server.portal.telnet.TelnetServerFactory[source]
    +

    Bases: twisted.internet.protocol.ServerFactory

    +

    This exists only to name this better in logs.

    +
    +
    +noisy = False
    +
    + +
    +
    +logPrefix()[source]
    +

    Describe this factory for log messages.

    +
    + +
    + +
    +
    +class evennia.server.portal.telnet.TelnetProtocol(*args, **kwargs)[source]
    +

    Bases: twisted.conch.telnet.Telnet, twisted.conch.telnet.StatefulTelnetProtocol, evennia.server.session.Session

    +

    Each player connecting over telnet (ie using most traditional mud +clients) gets a telnet protocol instance assigned to them. All +communication between game and player goes through here.

    +
    +
    +__init__(*args, **kwargs)[source]
    +

    Initialize self. See help(type(self)) for accurate signature.

    +
    + +
    +
    +dataReceived(data)[source]
    +

    Unused by default, but a good place to put debug printouts +of incoming data.

    +
    + +
    +
    +connectionMade()[source]
    +

    This is called when the connection is first established.

    +
    + +
    +
    +toggle_nop_keepalive()[source]
    +

    Allow to toggle the NOP keepalive for those sad clients that +can’t even handle a NOP instruction. This is turned off by the +protocol_flag NOPKEEPALIVE (settable e.g. by the default +option command).

    +
    + +
    +
    +handshake_done(timeout=False)[source]
    +

    This is called by all telnet extensions once they are finished. +When all have reported, a sync with the server is performed. +The system will force-call this sync after a small time to handle +clients that don’t reply to handshakes at all.

    +
    + +
    +
    +at_login()[source]
    +

    Called when this session gets authenticated by the server.

    +
    + +
    +
    +enableRemote(option)[source]
    +

    This sets up the remote-activated options we allow for this protocol.

    +
    +
    Parameters
    +

    option (char) – The telnet option to enable.

    +
    +
    Returns
    +

    enable (bool) – If this option should be enabled.

    +
    +
    +
    + +
    +
    +disableRemote(option)[source]
    +

    Signal a programming error by raising an exception.

    +

    L{enableRemote} must return true for the given value of C{option} in +order for this method to be called. If a subclass of L{Telnet} +overrides enableRemote to allow certain options to be enabled, it must +also override disableRemote tto disable those options.

    +

    @raise NotImplementedError: Always raised.

    +
    + +
    +
    +enableLocal(option)[source]
    +

    Call to allow the activation of options for this protocol

    +
    +
    Parameters
    +

    option (char) – The telnet option to enable locally.

    +
    +
    Returns
    +

    enable (bool) – If this option should be enabled.

    +
    +
    +
    + +
    +
    +disableLocal(option)[source]
    +

    Disable a given option locally.

    +
    +
    Parameters
    +

    option (char) – The telnet option to disable locally.

    +
    +
    +
    + +
    +
    +connectionLost(reason)[source]
    +

    this is executed when the connection is lost for whatever +reason. it can also be called directly, from the disconnect +method

    +
    +
    Parameters
    +

    reason (str) – Motivation for losing connection.

    +
    +
    +
    + +
    +
    +applicationDataReceived(data)[source]
    +

    Telnet method called when non-telnet-command data is coming in +over the telnet connection. We pass it on to the game engine +directly.

    +
    +
    Parameters
    +

    data (str) – Incoming data.

    +
    +
    +
    + +
    +
    +sendLine(line)[source]
    +

    Hook overloading the one used by linereceiver.

    +
    +
    Parameters
    +

    line (str) – Line to send.

    +
    +
    +
    + +
    +
    +disconnect(reason='')[source]
    +

    Generic hook for the engine to call in order to +disconnect this protocol.

    +
    +
    Parameters
    +

    reason (str, optional) – Reason for disconnecting.

    +
    +
    +
    + +
    +
    +data_in(**kwargs)[source]
    +

    Data User -> Evennia

    +
    +
    Keyword Arguments
    +

    kwargs (any) – Options from the protocol.

    +
    +
    +
    + +
    +
    +data_out(**kwargs)[source]
    +

    Data Evennia -> User

    +
    +
    Keyword Arguments
    +

    kwargs (any) – Options to the protocol

    +
    +
    +
    + +
    +
    +send_text(*args, **kwargs)[source]
    +

    Send text data. This is an in-band telnet operation.

    +
    +
    Parameters
    +

    text (str) – The first argument is always the text string to send. No other arguments +are considered.

    +
    +
    Keyword Arguments
    +

    options (dict) –

    Send-option flags

    +
      +
    • mxp: Enforce MXP link support.

    • +
    • ansi: Enforce no ANSI colors.

    • +
    • xterm256: Enforce xterm256 colors, regardless of TTYPE.

    • +
    • noxterm256: Enforce no xterm256 color support, regardless of TTYPE.

    • +
    • nocolor: Strip all Color, regardless of ansi/xterm256 setting.

    • +
    • +
      raw: Pass string through without any ansi processing

      (i.e. include Evennia ansi markers but do not +convert them into ansi tokens)

      +
      +
      +
    • +
    • +
      echo: Turn on/off line echo on the client. Turn

      off line echo for client, for example for password. +Note that it must be actively turned back on again!

      +
      +
      +
    • +
    +

    +
    +
    +
    + +
    +
    +send_prompt(*args, **kwargs)[source]
    +

    Send a prompt - a text without a line end. See send_text for argument options.

    +
    + +
    +
    +send_default(cmdname, *args, **kwargs)[source]
    +

    Send other oob data

    +
    + +
    +
    @@ -84,7 +326,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.portal.telnet_oob.html b/docs/0.9.5/api/evennia.server.portal.telnet_oob.html index b6f03b11f4..add57376fb 100644 --- a/docs/0.9.5/api/evennia.server.portal.telnet_oob.html +++ b/docs/0.9.5/api/evennia.server.portal.telnet_oob.html @@ -37,8 +37,220 @@
    -
    -

    evennia.server.portal.telnet_oob

    +
    +

    evennia.server.portal.telnet_oob

    +

    Telnet OOB (Out of band communication)

    +

    OOB protocols allow for asynchronous communication between Evennia and +compliant telnet clients. The “text” type of send command will always +be sent “in-band”, appearing in the client’s main text output. OOB +commands, by contrast, can have many forms and it is up to the client +how and if they are handled. Examples of OOB instructions could be to +instruct the client to play sounds or to update a graphical health +bar.

    +

    Note that in Evennia’s Web client, all send commands are “OOB +commands”, (including the “text” one), there is no equivalence to +MSDP/GMCP for the webclient since it doesn’t need it.

    +

    This implements the following telnet OOB communication protocols:

    + +
    +
    +
    +class evennia.server.portal.telnet_oob.TelnetOOB(protocol)[source]
    +

    Bases: object

    +

    Implements the MSDP and GMCP protocols.

    +
    +
    +__init__(protocol)[source]
    +

    Initiates by storing the protocol on itself and trying to +determine if the client supports MSDP.

    +
    +
    Parameters
    +

    protocol (Protocol) – The active protocol.

    +
    +
    +
    + +
    +
    +no_msdp(option)[source]
    +

    Client reports No msdp supported or wanted.

    +
    +
    Parameters
    +

    option (Option) – Not used.

    +
    +
    +
    + +
    +
    +do_msdp(option)[source]
    +

    Client reports that it supports msdp.

    +
    +
    Parameters
    +

    option (Option) – Not used.

    +
    +
    +
    + +
    +
    +no_gmcp(option)[source]
    +

    If this is reached, it means neither MSDP nor GMCP is +supported.

    +
    +
    Parameters
    +

    option (Option) – Not used.

    +
    +
    +
    + +
    +
    +do_gmcp(option)[source]
    +

    Called when client confirms that it can do MSDP or GMCP.

    +
    +
    Parameters
    +

    option (Option) – Not used.

    +
    +
    +
    + +
    +
    +encode_msdp(cmdname, *args, **kwargs)[source]
    +

    Encode into a valid MSDP command.

    +
    +
    Parameters
    +
      +
    • cmdname (str) – Name of send instruction.

    • +
    • args (any) – Arguments to OOB command.

    • +
    • kwargs (any) – Arguments to OOB command.

    • +
    +
    +
    +

    Notes

    +

    The output of this encoding will be +MSDP structures on these forms:

    +
    [cmdname, [], {}]           -> VAR cmdname VAL ""
    +[cmdname, [arg], {}]        -> VAR cmdname VAL arg
    +[cmdname, [args],{}]        -> VAR cmdname VAL ARRAYOPEN VAL arg VAL arg ... ARRAYCLOSE
    +[cmdname, [], {kwargs}]     -> VAR cmdname VAL TABLEOPEN VAR key VAL val ... TABLECLOSE
    +[cmdname, [args], {kwargs}] -> VAR cmdname VAL ARRAYOPEN VAL arg VAL arg ... ARRAYCLOSE
    +                               VAR cmdname VAL TABLEOPEN VAR key VAL val ... TABLECLOSE
    +
    +
    +

    Further nesting is not supported, so if an array argument +consists of an array (for example), that array will be +json-converted to a string.

    +
    + +
    +
    +encode_gmcp(cmdname, *args, **kwargs)[source]
    +

    Encode into GMCP messages.

    +
    +
    Parameters
    +
      +
    • cmdname (str) – GMCP OOB command name.

    • +
    • args (any) – Arguments to OOB command.

    • +
    • kwargs (any) – Arguments to OOB command.

    • +
    +
    +
    +

    Notes

    +

    GMCP messages will be outgoing on the following +form (the non-JSON cmdname at the start is what +IRE games use, supposedly, and what clients appear +to have adopted). A cmdname without Package will end +up in the Core package, while Core package names will +be stripped on the Evennia side.

    +
    [cmd.name, [], {}]          -> Cmd.Name
    +[cmd.name, [arg], {}]       -> Cmd.Name arg
    +[cmd.name, [args],{}]       -> Cmd.Name [args]
    +[cmd.name, [], {kwargs}]    -> Cmd.Name {kwargs}
    +[cmdname, [args, {kwargs}]  -> Core.Cmdname [[args],{kwargs}]
    +
    +
    +

    Notes

    +

    There are also a few default mappings between evennia outputcmds and GMCP:

    +
    client_options -> Core.Supports.Get
    +get_inputfuncs -> Core.Commands.Get
    +get_value      -> Char.Value.Get
    +repeat         -> Char.Repeat.Update
    +monitor        -> Char.Monitor.Update
    +
    +
    +
    + +
    +
    +decode_msdp(data)[source]
    +

    Decodes incoming MSDP data.

    +
    +
    Parameters
    +

    data (str or list) – MSDP data.

    +
    +
    +

    Notes

    +

    Clients should always send MSDP data on +one of the following forms:

    +
    cmdname ''          -> [cmdname, [], {}]
    +cmdname val         -> [cmdname, [val], {}]
    +cmdname array       -> [cmdname, [array], {}]
    +cmdname table       -> [cmdname, [], {table}]
    +cmdname array cmdname table -> [cmdname, [array], {table}]
    +
    +
    +

    Observe that all MSDP_VARS are used to identify cmdnames, +so if there are multiple arrays with the same cmdname +given, they will be merged into one argument array, same +for tables. Different MSDP_VARS (outside tables) will be +identified as separate cmdnames.

    +
    + +
    +
    +decode_gmcp(data)[source]
    +

    Decodes incoming GMCP data on the form ‘varname <structure>’.

    +
    +
    Parameters
    +

    data (str or list) – GMCP data.

    +
    +
    +

    Notes

    +

    Clients send data on the form “Module.Submodule.Cmdname <structure>”. +We assume the structure is valid JSON.

    +

    The following is parsed into Evennia’s formal structure:

    +
    Core.Name                         -> [name, [], {}]
    +Core.Name string                  -> [name, [string], {}]
    +Core.Name [arg, arg,...]          -> [name, [args], {}]
    +Core.Name {key:arg, key:arg, ...} -> [name, [], {kwargs}]
    +Core.Name [[args], {kwargs}]      -> [name, [args], {kwargs}]
    +
    +
    +
    + +
    +
    +data_out(cmdname, *args, **kwargs)[source]
    +

    Return a MSDP- or GMCP-valid subnegotiation across the protocol.

    +
    +
    Parameters
    +
      +
    • cmdname (str) – OOB-command name.

    • +
    • args (any) – Arguments to OOB command.

    • +
    • kwargs (any) – Arguments to OOB command.

    • +
    +
    +
    +
    + +
    +
    @@ -84,7 +296,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.portal.telnet_ssl.html b/docs/0.9.5/api/evennia.server.portal.telnet_ssl.html index ec929e03db..0d400c0757 100644 --- a/docs/0.9.5/api/evennia.server.portal.telnet_ssl.html +++ b/docs/0.9.5/api/evennia.server.portal.telnet_ssl.html @@ -37,8 +37,60 @@
    -
    -

    evennia.server.portal.telnet_ssl

    +
    +

    evennia.server.portal.telnet_ssl

    +

    This allows for running the telnet communication over an encrypted SSL tunnel. To use it, requires a +client supporting Telnet SSL.

    +

    The protocol will try to automatically create the private key and certificate on the server side +when starting and will warn if this was not possible. These will appear as files ssl.key and +ssl.cert in mygame/server/.

    +
    +
    +class evennia.server.portal.telnet_ssl.SSLProtocol(*args, **kwargs)[source]
    +

    Bases: evennia.server.portal.telnet.TelnetProtocol

    +

    Communication is the same as telnet, except data transfer +is done with encryption set up by the portal at start time.

    +
    +
    +__init__(*args, **kwargs)[source]
    +

    Initialize self. See help(type(self)) for accurate signature.

    +
    + +
    + +
    +
    +evennia.server.portal.telnet_ssl.verify_or_create_SSL_key_and_cert(keyfile, certfile)[source]
    +

    Verify or create new key/certificate files.

    +
    +
    Parameters
    +
      +
    • keyfile (str) – Path to ssl.key file.

    • +
    • certfile (str) – Parth to ssl.cert file.

    • +
    +
    +
    +

    Notes

    +

    If files don’t already exist, they are created.

    +
    + +
    +
    +evennia.server.portal.telnet_ssl.getSSLContext()[source]
    +

    This is called by the portal when creating the SSL context +server-side.

    +
    +
    Returns
    +

    ssl_context (tuple)

    +
    +
    A key and certificate that is either

    existing previously or created on the fly.

    +
    +
    +

    +
    +
    +
    +
    @@ -84,7 +136,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.portal.tests.html b/docs/0.9.5/api/evennia.server.portal.tests.html index ddb08c45f5..6cad9149d0 100644 --- a/docs/0.9.5/api/evennia.server.portal.tests.html +++ b/docs/0.9.5/api/evennia.server.portal.tests.html @@ -37,8 +37,116 @@
    -
    -

    evennia.server.portal.tests

    +
    +

    evennia.server.portal.tests

    +
    +
    +class evennia.server.portal.tests.TestAMPServer(methodName='runTest')[source]
    +

    Bases: twisted.trial._asynctest.TestCase

    +

    Test AMP communication

    +
    +
    +setUp()[source]
    +

    Hook method for setting up the test fixture before exercising it.

    +
    + +
    +
    +test_amp_out()[source]
    +
    + +
    +
    +test_amp_in()[source]
    +
    + +
    +
    +test_large_msg()[source]
    +

    Send message larger than AMP_MAXLEN - should be split into several

    +
    + +
    + +
    +
    +class evennia.server.portal.tests.TestIRC(methodName='runTest')[source]
    +

    Bases: django.test.testcases.TestCase

    +
    +
    +test_plain_ansi()[source]
    +

    Test that printable characters do not get mangled.

    +
    + +
    +
    +test_bold()[source]
    +
    + +
    +
    +test_italic()[source]
    +
    + +
    +
    +test_colors()[source]
    +
    + +
    +
    +test_identity()[source]
    +

    Test that the composition of the function and +its inverse gives the correct string.

    +
    + +
    + +
    +
    +class evennia.server.portal.tests.TestTelnet(methodName='runTest')[source]
    +

    Bases: twisted.trial._asynctest.TestCase

    +
    +
    +setUp()[source]
    +

    Hook method for setting up the test fixture before exercising it.

    +
    + +
    +
    +test_mudlet_ttype()[source]
    +
    + +
    + +
    +
    +class evennia.server.portal.tests.TestWebSocket(methodName='runTest')[source]
    +

    Bases: evennia.utils.test_resources.EvenniaTest

    +
    +
    +setUp()[source]
    +

    Sets up testing environment

    +
    + +
    +
    +tearDown()[source]
    +

    Hook method for deconstructing the test fixture after testing it.

    +
    + +
    +
    +test_data_in()[source]
    +
    + +
    +
    +test_data_out()[source]
    +
    + +
    +
    @@ -84,7 +192,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.portal.ttype.html b/docs/0.9.5/api/evennia.server.portal.ttype.html index 78458595b0..c23d672e19 100644 --- a/docs/0.9.5/api/evennia.server.portal.ttype.html +++ b/docs/0.9.5/api/evennia.server.portal.ttype.html @@ -37,8 +37,66 @@
    -
    -

    evennia.server.portal.ttype

    +
    +

    evennia.server.portal.ttype

    +

    TTYPE (MTTS) - Mud Terminal Type Standard

    +

    This module implements the TTYPE telnet protocol as per +http://tintin.sourceforge.net/mtts/. It allows the server to ask the +client about its capabilities. If the client also supports TTYPE, it +will return with information such as its name, if it supports colour +etc. If the client does not support TTYPE, this will be ignored.

    +

    All data will be stored on the protocol’s protocol_flags dictionary, +under the ‘TTYPE’ key.

    +
    +
    +class evennia.server.portal.ttype.Ttype(protocol)[source]
    +

    Bases: object

    +

    Handles ttype negotiations. Called and initiated by the +telnet protocol.

    +
    +
    +__init__(protocol)[source]
    +

    Initialize ttype by storing protocol on ourselves and calling +the client to see if it supporst ttype.

    +
    +
    Parameters
    +

    protocol (Protocol) – The protocol instance.

    +
    +
    +

    Notes

    +

    The self.ttype_step indicates how far in the data +retrieval we’ve gotten.

    +
    + +
    +
    +wont_ttype(option)[source]
    +

    Callback if ttype is not supported by client.

    +
    +
    Parameters
    +

    option (Option) – Not used.

    +
    +
    +
    + +
    +
    +will_ttype(option)[source]
    +

    Handles negotiation of the ttype protocol once the client has +confirmed that it will respond with the ttype protocol.

    +
    +
    Parameters
    +

    option (Option) – Not used.

    +
    +
    +

    Notes

    +

    The negotiation proceeds in several steps, each returning a +certain piece of information about the client. All data is +stored on protocol.protocol_flags under the TTYPE key.

    +
    + +
    +
    @@ -84,7 +142,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.portal.webclient.html b/docs/0.9.5/api/evennia.server.portal.webclient.html index b8cf4573cc..50b59d8d23 100644 --- a/docs/0.9.5/api/evennia.server.portal.webclient.html +++ b/docs/0.9.5/api/evennia.server.portal.webclient.html @@ -259,7 +259,6 @@ client instead.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.portal.webclient_ajax.html b/docs/0.9.5/api/evennia.server.portal.webclient_ajax.html index 382fe00c0f..bd3f9c95db 100644 --- a/docs/0.9.5/api/evennia.server.portal.webclient_ajax.html +++ b/docs/0.9.5/api/evennia.server.portal.webclient_ajax.html @@ -171,6 +171,11 @@ mode operation (at startup)

    mode_keepalive(request)[source]

    This is called by render_POST when the client is replying to the keepalive.

    +
    +
    Parameters
    +

    request (Request) – Incoming request.

    +
    +
    @@ -384,7 +389,6 @@ client instead.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.profiling.dummyrunner.html b/docs/0.9.5/api/evennia.server.profiling.dummyrunner.html index d479a0c6cf..80eb5c460b 100644 --- a/docs/0.9.5/api/evennia.server.profiling.dummyrunner.html +++ b/docs/0.9.5/api/evennia.server.profiling.dummyrunner.html @@ -67,13 +67,83 @@ change which actions by adding a path to

    in your settings. See utils.dummyrunner_actions.py for instructions on how to define this module.

    +
    +
    +class evennia.server.profiling.dummyrunner.CmdDummyRunnerEchoResponse(**kwargs)[source]
    +

    Bases: evennia.commands.command.Command

    +

    Dummyrunner command measuring the round-about response time +from sending to receiving a result.

    +
    +
    Usage:

    dummyrunner_echo_response <timestamp>

    +
    +
    Responds with

    dummyrunner_echo_response:<timestamp>,<current_time>

    +
    +
    +

    The dummyrunner will send this and then compare the send time +with the receive time on both ends.

    +
    +
    +key = 'dummyrunner_echo_response'
    +
    + +
    +
    +func()[source]
    +

    This is the actual executing part of the command. It is +called directly after self.parse(). See the docstring of this +module for which object properties are available (beyond those +set in self.parse())

    +
    + +
    +
    +aliases = []
    +
    + +
    +
    +help_category = 'general'
    +
    + +
    +
    +lock_storage = 'cmd:all();'
    +
    + +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'dummyrunner_echo_response', 'tags': '', 'text': '\n Dummyrunner command measuring the round-about response time\n from sending to receiving a result.\n\n Usage:\n dummyrunner_echo_response <timestamp>\n\n Responds with\n dummyrunner_echo_response:<timestamp>,<current_time>\n\n The dummyrunner will send this and then compare the send time\n with the receive time on both ends.\n\n '}
    +
    + +
    + +
    +
    +class evennia.server.profiling.dummyrunner.DummyRunnerCmdSet(cmdsetobj=None, key=None)[source]
    +

    Bases: evennia.commands.cmdset.CmdSet

    +

    Dummyrunner injected cmdset.

    +
    +
    +at_cmdset_creation()[source]
    +

    Hook method - this should be overloaded in the inheriting +class, and should take care of populating the cmdset by use of +self.add().

    +
    + +
    +
    +path = 'evennia.server.profiling.dummyrunner.DummyRunnerCmdSet'
    +
    + +
    +
    evennia.server.profiling.dummyrunner.idcounter()[source]

    Makes unique ids.

    Returns
    -

    count (int) – A globally unique counter.

    +

    str – A globally unique id.

    @@ -110,6 +180,11 @@ for instructions on how to define this module.

    Handles connection to a running Evennia server, mimicking a real account by sending commands on a timer.

    +
    +
    +report(text, clientkey)[source]
    +
    +
    connectionMade()[source]
    @@ -180,13 +255,28 @@ all “intelligence” of the dummy client.

    class evennia.server.profiling.dummyrunner.DummyFactory(actions)[source]
    -

    Bases: twisted.internet.protocol.ClientFactory

    +

    Bases: twisted.internet.protocol.ReconnectingClientFactory

    protocol

    alias of DummyClient

    +
    +
    +initialDelay = 1
    +
    + +
    +
    +maxDelay = 1
    +
    + +
    +
    +noisy = False
    +
    +
    __init__(actions)[source]
    @@ -251,7 +341,6 @@ all “intelligence” of the dummy client.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.profiling.dummyrunner_settings.html b/docs/0.9.5/api/evennia.server.profiling.dummyrunner_settings.html index 1e19640c5f..7a3b7ec7cc 100644 --- a/docs/0.9.5/api/evennia.server.profiling.dummyrunner_settings.html +++ b/docs/0.9.5/api/evennia.server.profiling.dummyrunner_settings.html @@ -43,51 +43,48 @@

    This module defines dummyrunner settings and sets up the actions available to dummy accounts.

    The settings are global variables:

    -

    TIMESTEP - time in seconds between each ‘tick’ -CHANCE_OF_ACTION - chance 0-1 of action happening -CHANCE_OF_LOGIN - chance 0-1 of login happening -TELNET_PORT - port to use, defaults to settings.TELNET_PORT -ACTIONS - see below

    +
      +
    • TIMESTEP - time in seconds between each ‘tick’. 1 is a good start.

    • +
    • CHANCE_OF_ACTION - chance 0-1 of action happening. Default is 0.5.

    • +
    • CHANCE_OF_LOGIN - chance 0-1 of login happening. 0.01 is a good number.

    • +
    • TELNET_PORT - port to use, defaults to settings.TELNET_PORT

    • +
    • ACTIONS - see below

    • +

    ACTIONS is a tuple

    -

    (login_func, logout_func, (0.3, func1), (0.1, func2) … )

    +
    (login_func, logout_func, (0.3, func1), (0.1, func2) ... )
    +
    +

    where the first entry is the function to call on first connect, with a chance of occurring given by CHANCE_OF_LOGIN. This function is usually responsible for logging in the account. The second entry is always called when the dummyrunner disconnects from the server and should -thus issue a logout command. The other entries are tuples (chance, +thus issue a logout command. The other entries are tuples (chance, func). They are picked randomly, their commonality based on the cumulative chance given (the chance is normalized between all options -so if will still work also if the given chances don’t add up to 1). -Since each function can return a list of game-command strings, each -function may result in multiple operations.

    +so if will still work also if the given chances don’t add up to 1).

    +

    The PROFILE variable define pre-made ACTION tuples for convenience.

    +

    Each function should return an iterable of one or more command-call +strings (like “look here”), so each can group multiple command operations.

    An action-function is called with a “client” argument which is a -reference to the dummy client currently performing the action. It -returns a string or a list of command strings to execute. Use the -client object for optionally saving data between actions.

    +reference to the dummy client currently performing the action.

    The client object has the following relevant properties and methods:

      -
    • -
      key - an optional client key. This is only used for dummyrunner output.

      Default is “Dummy-<cid>”

      -
      -
      -
    • +
    • key - an optional client key. This is only used for dummyrunner output. +Default is “Dummy-<cid>”

    • cid - client id

    • gid - globally unique id, hashed with time stamp

    • istep - the current step

    • exits - an empty list. Can be used to store exit names

    • objs - an empty list. Can be used to store object names

    • -
    • -
      counter() - returns a unique increasing id, hashed with time stamp

      to make it unique also between dummyrunner instances.

      -
      -
      -
    • +
    • counter() - returns a unique increasing id, hashed with time stamp +to make it unique also between dummyrunner instances.

    The return should either be a single command string or a tuple of command strings. This list of commands will always be executed every TIMESTEP with a chance given by CHANCE_OF_ACTION by in the order given (no randomness) and allows for setting up a more complex chain of commands (such as creating an account and logging in).

    -

    +
    evennia.server.profiling.dummyrunner_settings.c_login(client)[source]
    @@ -172,6 +169,16 @@ commands (such as creating an account and logging in).

    move through south exit if available

    +
    +
    +evennia.server.profiling.dummyrunner_settings.c_measure_lag(client)[source]
    +

    Special dummyrunner command, injected in c_login. It measures +response time. Including this in the ACTION tuple will give more +dummyrunner output about just how fast commands are being processed.

    +

    The dummyrunner will treat this special and inject the +{timestamp} just before sending.

    +
    + @@ -217,7 +224,6 @@ commands (such as creating an account and logging in).

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.profiling.html b/docs/0.9.5/api/evennia.server.profiling.html index 22b39ef14e..d34a014e23 100644 --- a/docs/0.9.5/api/evennia.server.profiling.html +++ b/docs/0.9.5/api/evennia.server.profiling.html @@ -95,7 +95,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.profiling.memplot.html b/docs/0.9.5/api/evennia.server.profiling.memplot.html index e696e0402d..b3264ff00c 100644 --- a/docs/0.9.5/api/evennia.server.profiling.memplot.html +++ b/docs/0.9.5/api/evennia.server.profiling.memplot.html @@ -129,7 +129,6 @@ the script will append to this file if it already exists.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.profiling.settings_mixin.html b/docs/0.9.5/api/evennia.server.profiling.settings_mixin.html index 700bc48bf9..34c708f592 100644 --- a/docs/0.9.5/api/evennia.server.profiling.settings_mixin.html +++ b/docs/0.9.5/api/evennia.server.profiling.settings_mixin.html @@ -91,7 +91,6 @@ servers!

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.profiling.test_queries.html b/docs/0.9.5/api/evennia.server.profiling.test_queries.html index c4169bbe96..464bedb9ed 100644 --- a/docs/0.9.5/api/evennia.server.profiling.test_queries.html +++ b/docs/0.9.5/api/evennia.server.profiling.test_queries.html @@ -93,7 +93,6 @@ to setup the environment to test.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.profiling.tests.html b/docs/0.9.5/api/evennia.server.profiling.tests.html index 364bb84444..26a14e348f 100644 --- a/docs/0.9.5/api/evennia.server.profiling.tests.html +++ b/docs/0.9.5/api/evennia.server.profiling.tests.html @@ -187,7 +187,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.profiling.timetrace.html b/docs/0.9.5/api/evennia.server.profiling.timetrace.html index d05a7d3c99..28b01ded7b 100644 --- a/docs/0.9.5/api/evennia.server.profiling.timetrace.html +++ b/docs/0.9.5/api/evennia.server.profiling.timetrace.html @@ -102,7 +102,6 @@ This message will get attached time stamp.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.server.html b/docs/0.9.5/api/evennia.server.server.html index 59145677b3..edf1aa6f52 100644 --- a/docs/0.9.5/api/evennia.server.server.html +++ b/docs/0.9.5/api/evennia.server.server.html @@ -39,11 +39,11 @@

    evennia.server.server

    -

    This module implements the main Evennia server process, the core of -the game engine.

    -

    This module should be started with the ‘twistd’ executable since it -sets up all the networking features. (this is done automatically -by evennia/server/server_runner.py).

    +

    This module implements the main Evennia server process, the core of the game +engine.

    +

    This module should be started with the ‘twistd’ executable since it sets up all +the networking features. (this is done automatically by +evennia/server/server_runner.py).

    class evennia.server.server.Evennia(application)[source]
    @@ -100,20 +100,20 @@ Once finished the last_initial_setup_step is set to -1.

    shutdown(mode='reload', _reactor_stopping=False)[source]

    Shuts down the server from inside it.

    -
    -
    Keyword Arguments
    -
      -
    • mode (str) – Sets the server restart mode:

    • -
    • 'reload' (-) – server restarts, no “persistent” scripts +

      +
      mode - sets the server restart mode.
        +
      • ‘reload’ - server restarts, no “persistent” scripts are stopped, at_reload hooks called.

      • -
      • 'reset' - server restarts, non-persistent scripts stopped, (-) – at_shutdown hooks called but sessions will not +

      • ‘reset’ - server restarts, non-persistent scripts stopped, +at_shutdown hooks called but sessions will not be disconnected.

      • -
      • - like reset, but server will not auto-restart. (-'shutdown') –

      • -
      • _reactor_stopping – This is set if server is stopped by a kill -command OR this method was already called -once - in both cases the reactor is dead/stopping already.

      • +
      • ‘shutdown’ - like reset, but server will not auto-restart.

      +
      _reactor_stopping - this is set if server is stopped by a kill

      command OR this method was already called +once - in both cases the reactor is +dead/stopping already.

      +
    @@ -150,7 +150,7 @@ of it is fore a reload, reset or shutdown.

    after reconnecting.

    Parameters
    -

    mode (str) – One of reload, reset or shutdown.

    +

    mode (str) – One of ‘reload’, ‘reset’ or ‘shutdown’.

    @@ -221,7 +221,6 @@ shutdown or a reset.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.serversession.html b/docs/0.9.5/api/evennia.server.serversession.html index e0173eaa85..99ae4aadd8 100644 --- a/docs/0.9.5/api/evennia.server.serversession.html +++ b/docs/0.9.5/api/evennia.server.serversession.html @@ -44,126 +44,6 @@ a connection to the outside world but don’t know any details about how the connection actually happens (so it’s the same for telnet, web, ssh etc).

    It is stored on the Server side (as opposed to protocol-specific sessions which are stored on the Portal side)

    -
    -
    -class evennia.server.serversession.NDbHolder(obj, name, manager_name='attributes')[source]
    -

    Bases: object

    -

    Holder for allowing property access of attributes

    -
    -
    -__init__(obj, name, manager_name='attributes')[source]
    -

    Initialize self. See help(type(self)) for accurate signature.

    -
    - -
    -
    -get_all()[source]
    -
    - -
    -
    -property all
    -
    - -
    - -
    -
    -class evennia.server.serversession.NAttributeHandler(obj)[source]
    -

    Bases: object

    -

    NAttributeHandler version without recache protection. -This stand-alone handler manages non-database saving. -It is similar to AttributeHandler and is used -by the .ndb handler in the same way as .db does -for the AttributeHandler.

    -
    -
    -__init__(obj)[source]
    -

    Initialized on the object

    -
    - -
    -
    -has(key)[source]
    -

    Check if object has this attribute or not.

    -
    -
    Parameters
    -

    key (str) – The Nattribute key to check.

    -
    -
    Returns
    -

    has_nattribute (bool) – If Nattribute is set or not.

    -
    -
    -
    - -
    -
    -get(key, default=None)[source]
    -

    Get the named key value.

    -
    -
    Parameters
    -

    key (str) – The Nattribute key to get.

    -
    -
    Returns
    -

    the value of the Nattribute.

    -
    -
    -
    - -
    -
    -add(key, value)[source]
    -

    Add new key and value.

    -
    -
    Parameters
    -
      -
    • key (str) – The name of Nattribute to add.

    • -
    • value (any) – The value to store.

    • -
    -
    -
    -
    - -
    -
    -remove(key)[source]
    -

    Remove Nattribute from storage.

    -
    -
    Parameters
    -

    key (str) – The name of the Nattribute to remove.

    -
    -
    -
    - -
    -
    -clear()[source]
    -

    Remove all NAttributes from handler.

    -
    - -
    -
    -all(return_tuples=False)[source]
    -

    List the contents of the handler.

    -
    -
    Parameters
    -

    return_tuples (bool, optional) – Defines if the Nattributes -are returns as a list of keys or as a list of (key, value).

    -
    -
    Returns
    -

    nattributes (list)

    -
    -
    A list of keys [key, key, …] or a

    list of tuples [(key, value), …] depending on the -setting of return_tuples.

    -
    -
    -

    -
    -
    -
    - -
    -
    class evennia.server.serversession.ServerSession[source]
    @@ -184,6 +64,11 @@ through their session.

    property cmdset_storage
    +
    +
    +property id
    +
    +
    at_sync()[source]
    @@ -296,7 +181,7 @@ idle timers and command counters.

    Update the protocol_flags and sync them with Portal.

    Keyword Arguments
    -

    any – A key:value pair to set in the +

    protocol_flag (any) – A key and value to set in the protocol_flags dictionary.

    @@ -329,7 +214,7 @@ for the protocol(s).

    the respective inputfuncs.

    Keyword Arguments
    -

    any – Incoming data from protocol on +

    kwargs (any) – Incoming data from protocol on the form {“commandname”: ((args), {kwargs}),…}

    @@ -346,12 +231,12 @@ this data off to self.sessionhandler.call_inputfuncs(self, **kwargs)

    Wrapper to mimic msg() functionality of Objects and Accounts.

    Parameters
    -
      -
    • text (str) – String input.

    • -
    • kwargs (str or tuple) – Send-commands identified +

      text (str) – String input.

      +
      +
      Keyword Arguments
      +

      any (str or tuple) – Send-commands identified by their keys. Or “options”, carrying options -for the protocol(s).

    • -
    +for the protocol(s).

    @@ -507,7 +392,6 @@ property, e.g. obj.ndb.attr = value etc.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.session.html b/docs/0.9.5/api/evennia.server.session.html index 24656fbab2..0ed40c9b4f 100644 --- a/docs/0.9.5/api/evennia.server.session.html +++ b/docs/0.9.5/api/evennia.server.session.html @@ -197,7 +197,6 @@ should overload this to format/handle the outgoing data as needed.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.sessionhandler.html b/docs/0.9.5/api/evennia.server.sessionhandler.html index 7b54fb51e7..85a61453a0 100644 --- a/docs/0.9.5/api/evennia.server.sessionhandler.html +++ b/docs/0.9.5/api/evennia.server.sessionhandler.html @@ -42,8 +42,7 @@

    This module defines handlers for storing sessions when handles sessions of users connecting to the server.

    There are two similar but separate stores of sessions:

    -
    -
      +
      • ServerSessionHandler - this stores generic game sessions

        for the game. These sessions has no knowledge about how they are connected to the world.

        @@ -57,7 +56,6 @@ handle network communication but holds no game info.

      -
    class evennia.server.sessionhandler.DummySession[source]
    @@ -116,35 +114,27 @@ sessions in store.

    clean_senddata(session, kwargs)[source]
    -

    Clean up data for sending across the AMP wire. Also apply INLINEFUNCS.

    +

    Clean up data for sending across the AMP wire. Also apply the +FuncParser using callables from settings.FUNCPARSER_OUTGOING_MESSAGES_MODULES.

    Parameters
    • session (Session) – The relevant session instance.

    • -
    • kwargs (dict) –

      send-instruction, with the keyword itself being the name -of the instruction (like “text”). Suitable values for each -keyword are:

      -
      arg                ->  [[arg], {}]
      -[args]             ->  [[args], {}]
      -{kwargs}           ->  [[], {kwargs}]
      -[args, {kwargs}]   ->  [[arg], {kwargs}]
      -[[args], {kwargs}] ->  [[args], {kwargs}]
      -
      -
      -

    • +
    • kwargs (dict) – the name of the instruction (like “text”). Suitable values for each keyword are: +- arg -> [[arg], {}] +- [args] -> [[args], {}] +- {kwargs} -> [[], {kwargs}] +- [args, {kwargs}] -> [[arg], {kwargs}] +- [[args], {kwargs}] -> [[args], {kwargs}]

    Returns
    -

    kwargs (dict)

    -
    -
    A cleaned dictionary of cmdname:[[args],{kwargs}] pairs,

    where the keys, args and kwargs have all been converted to -send-safe entities (strings or numbers), and inlinefuncs have been +

    kwargs (dict) – A cleaned dictionary of cmdname:[[args],{kwargs}] pairs, +where the keys, args and kwargs have all been converted to +send-safe entities (strings or numbers), and funcparser parsing has been applied.

    -

    -
    -
    @@ -153,13 +143,10 @@ applied.

    class evennia.server.sessionhandler.ServerSessionHandler(*args, **kwargs)[source]

    Bases: evennia.server.sessionhandler.SessionHandler

    -

    This object holds the stack of sessions active in the game at -any time.

    -

    A session register with the handler in two steps, first by -registering itself with the connect() method. This indicates an -non-authenticated session. Whenever the session is authenticated -the session together with the related account is sent to the login() -method.

    +

    This object holds the stack of sessions active in the game at any time.

    +

    A session register with the handler in two steps, first by registering itself with the connect() +method. This indicates an non-authenticated session. Whenever the session is authenticated the +session together with the related account is sent to the login() method.

    __init__(*args, **kwargs)[source]
    @@ -279,9 +266,8 @@ itself down)

    login(session, account, force=False, testmode=False)[source]
    -

    Log in the previously unloggedin session and the account we by -now should know is connected to it. After this point we assume -the session to be logged in one way or another.

    +

    Log in the previously unloggedin session and the account we by now should know is connected +to it. After this point we assume the session to be logged in one way or another.

    Parameters
      @@ -463,7 +449,7 @@ object.

    Returns.
    -
    sessions (Session or list): Can be more than one of Object is controlled by

    more than one Session (MULTISESSION_MODE > 1).

    +
    sessions (Session or list): Can be more than one of Object is controlled by more than

    one Session (MULTISESSION_MODE > 1).

    @@ -481,7 +467,7 @@ object.

    Returns.
    -
    sessions (Session or list): Can be more than one of Object is controlled by

    more than one Session (MULTISESSION_MODE > 1).

    +
    sessions (Session or list): Can be more than one of Object is controlled by more than

    one Session (MULTISESSION_MODE > 1).

    @@ -493,12 +479,13 @@ object.

    sessions_from_csessid(csessid)[source]

    Given a client identification hash (for session types that offer them) return all sessions with a matching hash.

    -
    -
    Parameters
    -

    csessid (str) – The session hash.

    +
    +
    Args

    csessid (str): The session hash.

    -
    Returns
    -

    sessions (list) – The sessions with matching .csessid, if any.

    +
    +
    +
    Returns
    +

    sessions (list) – The sessions with matching .csessid, if any.

    @@ -555,17 +542,17 @@ this class’ sessionhandler.call_inputfunc with the
    call_inputfuncs(session, **kwargs)[source]
    -

    Split incoming data into its inputfunc counterparts. -This should be called by the serversession.data_in -as sessionhandler.call_inputfunc(self, **kwargs).

    +

    Split incoming data into its inputfunc counterparts. This should be +called by the serversession.data_in as +sessionhandler.call_inputfunc(self, **kwargs).

    We also intercept OOB communication here.

    Parameters

    sessions (Session) – Session.

    Keyword Arguments
    -

    kwargs (any) – Incoming data from protocol on -the form {“commandname”: ((args), {kwargs}),…}

    +

    any (tuple) – Incoming data from protocol, each +on the form commandname=((args), {kwargs}).

    @@ -617,7 +604,6 @@ the form {“commandname”: ((args), {kwargs}),…}

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.signals.html b/docs/0.9.5/api/evennia.server.signals.html index fa6cabe005..43073571eb 100644 --- a/docs/0.9.5/api/evennia.server.signals.html +++ b/docs/0.9.5/api/evennia.server.signals.html @@ -39,22 +39,20 @@

    evennia.server.signals

    -

    This module brings Django Signals into Evennia. These are events that -can be subscribed to by importing a given Signal and using the -following code.

    -
    THIS_SIGNAL.connect(callback, sender_object**)
    +

    This module brings Django Signals into Evennia. These are events that can be +subscribed to by importing a given Signal and using the following code.

    +
    THIS_SIGNAL.connect(callback, sender_object)
     
    -

    When other code calls THIS_SIGNAL.send(sender, **kwargs), the callback -will be triggered.

    -

    Callbacks must be in the following format:

    +

    When other code calls THIS_SIGNAL.send(sender, **kwargs), the callback will +be triggered.

    +

    Callbacks must be on the following format:

    def my_callback(sender, **kwargs):
    -    ...
    +    # ...
     
    -

    This is used on top of hooks to make certain features easier to -add to contribs without necessitating a full takeover of hooks -that may be in high demand.

    +

    This is used on top of hooks to make certain features easier to add to contribs +without necessitating a full takeover of hooks that may be in high demand.

    @@ -100,7 +98,6 @@ that may be in high demand.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.throttle.html b/docs/0.9.5/api/evennia.server.throttle.html index d1b96dacdc..ead77dec9c 100644 --- a/docs/0.9.5/api/evennia.server.throttle.html +++ b/docs/0.9.5/api/evennia.server.throttle.html @@ -48,8 +48,8 @@ particular threshold.

    This version of the throttle is usable by both the terminal server as well as the web server, imposes limits on memory consumption by using deques -with length limits instead of open-ended lists, and removes sparse keys when -no recent failures have been recorded.

    +with length limits instead of open-ended lists, and uses native Django +caches for automatic key eviction and persistence configurability.

    error_msg = 'Too many failed attempts; you must wait a few minutes before trying again.'
    @@ -62,7 +62,9 @@ no recent failures have been recorded.

    Keyword Arguments
      -
    • limit (int) – Max number of failures before imposing limiter

    • +
    • name (str) – Name of this throttle.

    • +
    • limit (int) – Max number of failures before imposing limiter. If None, +the throttle is disabled.

    • timeout (int) – number of timeout seconds after max number of tries has been reached.

    • cache_size (int) – Max number of attempts to record per IP within a @@ -73,6 +75,25 @@ the throttle is imposed!

    +
    +
    +get_cache_key(*args, **kwargs)[source]
    +

    Creates a ‘prefixed’ key containing arbitrary terms to prevent key +collisions in the same namespace.

    +
    + +
    +
    +touch(key, *args, **kwargs)[source]
    +

    Refreshes the timeout on a given key and ensures it is recorded in the +key register.

    +
    +
    Parameters
    +

    key (str) – Key of entry to renew.

    +
    +
    +
    +
    get(ip=None)[source]
    @@ -113,6 +134,41 @@ of throttle.

    +
    +
    +remove(ip, *args, **kwargs)[source]
    +

    Clears data stored for an IP from the throttle.

    +
    +
    Parameters
    +

    ip (str) – IP to clear.

    +
    +
    +
    + +
    +
    +record_ip(ip, *args, **kwargs)[source]
    +

    Tracks keys as they are added to the cache (since there is no way to +get a list of keys after-the-fact).

    +
    +
    Parameters
    +

    ip (str) – IP being added to cache. This should be the original +IP, not the cache-prefixed key.

    +
    +
    +
    + +
    +
    +unrecord_ip(ip, *args, **kwargs)[source]
    +

    Forces removal of a key from the key registry.

    +
    +
    Parameters
    +

    ip (str) – IP to remove from list of keys.

    +
    +
    +
    +
    check(ip)[source]
    @@ -181,7 +237,6 @@ fails recently.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.validators.html b/docs/0.9.5/api/evennia.server.validators.html index aaed662ceb..0c12c830cd 100644 --- a/docs/0.9.5/api/evennia.server.validators.html +++ b/docs/0.9.5/api/evennia.server.validators.html @@ -146,7 +146,6 @@ by this validator.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.server.webserver.html b/docs/0.9.5/api/evennia.server.webserver.html index 9b712b23d6..a99758e935 100644 --- a/docs/0.9.5/api/evennia.server.webserver.html +++ b/docs/0.9.5/api/evennia.server.webserver.html @@ -304,7 +304,6 @@ directory this path represents.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.settings_default.html b/docs/0.9.5/api/evennia.settings_default.html index ebbc2bcdbc..106b2487f5 100644 --- a/docs/0.9.5/api/evennia.settings_default.html +++ b/docs/0.9.5/api/evennia.settings_default.html @@ -92,7 +92,6 @@ always be sure of what you have changed and what is default behaviour.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.typeclasses.admin.html b/docs/0.9.5/api/evennia.typeclasses.admin.html index f65e25e8a5..08fc34de9b 100644 --- a/docs/0.9.5/api/evennia.typeclasses.admin.html +++ b/docs/0.9.5/api/evennia.typeclasses.admin.html @@ -37,299 +37,8 @@
    -
    -

    evennia.typeclasses.admin

    -
    -
    -class evennia.typeclasses.admin.TagAdmin(model, admin_site)[source]
    -

    Bases: django.contrib.admin.options.ModelAdmin

    -

    A django Admin wrapper for Tags.

    -
    -
    -search_fields = ('db_key', 'db_category', 'db_tagtype')
    -
    - -
    -
    -list_display = ('db_key', 'db_category', 'db_tagtype', 'db_data')
    -
    - -
    -
    -fields = ('db_key', 'db_category', 'db_tagtype', 'db_data')
    -
    - -
    -
    -list_filter = ('db_tagtype',)
    -
    - -
    -
    -property media
    -
    - -
    - -
    -
    -class evennia.typeclasses.admin.TagForm(*args, **kwargs)[source]
    -

    Bases: django.forms.models.ModelForm

    -

    This form overrides the base behavior of the ModelForm that would be used for a -Tag-through-model. Since the through-models only have access to the foreignkeys of the Tag and -the Object that they’re attached to, we need to spoof the behavior of it being a form that would -correspond to its tag, or the creation of a tag. Instead of being saved, we’ll call to the -Object’s handler, which will handle the creation, change, or deletion of a tag for us, as well -as updating the handler’s cache so that all changes are instantly updated in-game.

    -
    -
    -class Meta[source]
    -

    Bases: object

    -
    -
    -fields = ('tag_key', 'tag_category', 'tag_data', 'tag_type')
    -
    - -
    - -
    -
    -__init__(*args, **kwargs)[source]
    -

    If we have a tag, then we’ll prepopulate our instance with the fields we’d expect it -to have based on the tag. tag_key, tag_category, tag_type, and tag_data all refer to -the corresponding tag fields. The initial data of the form fields will similarly be -populated.

    -
    - -
    -
    -save(commit=True)[source]
    -

    One thing we want to do here is the or None checks, because forms are saved with an empty -string rather than null from forms, usually, and the Handlers may handle empty strings -differently than None objects. So for consistency with how things are handled in game, -we’ll try to make sure that empty form fields will be None, rather than ‘’.

    -
    - -
    -
    -base_fields = {'tag_category': <django.forms.fields.CharField object>, 'tag_data': <django.forms.fields.CharField object>, 'tag_key': <django.forms.fields.CharField object>, 'tag_type': <django.forms.fields.CharField object>}
    -
    - -
    -
    -declared_fields = {'tag_category': <django.forms.fields.CharField object>, 'tag_data': <django.forms.fields.CharField object>, 'tag_key': <django.forms.fields.CharField object>, 'tag_type': <django.forms.fields.CharField object>}
    -
    - -
    -
    -property media
    -

    Return all media required to render the widgets on this form.

    -
    - -
    - -
    -
    -class evennia.typeclasses.admin.TagFormSet(data=None, files=None, instance=None, save_as_new=False, prefix=None, queryset=None, **kwargs)[source]
    -

    Bases: django.forms.models.BaseInlineFormSet

    -

    The Formset handles all the inline forms that are grouped together on the change page of the -corresponding object. All the tags will appear here, and we’ll save them by overriding the -formset’s save method. The forms will similarly spoof their save methods to return an instance -which hasn’t been saved to the database, but have the relevant fields filled out based on the -contents of the cleaned form. We’ll then use that to call to the handler of the corresponding -Object, where the handler is an AliasHandler, PermissionsHandler, or TagHandler, based on the -type of tag.

    -
    -
    -save(commit=True)[source]
    -

    Save model instances for every form, adding and changing instances -as necessary, and return the list of instances.

    -
    - -
    - -
    -
    -class evennia.typeclasses.admin.TagInline(parent_model, admin_site)[source]
    -

    Bases: django.contrib.admin.options.TabularInline

    -

    A handler for inline Tags. This class should be subclassed in the admin of your models, -and the ‘model’ and ‘related_field’ class attributes must be set. model should be the -through model (ObjectDB_db_tag’, for example), while related field should be the name -of the field on that through model which points to the model being used: ‘objectdb’, -‘msg’, ‘accountdb’, etc.

    -
    -
    -model = None
    -
    - -
    -
    -form
    -

    alias of TagForm

    -
    - -
    -
    -formset
    -

    alias of TagFormSet

    -
    - -
    -
    -related_field = None
    -
    - -
    -
    -extra = 0
    -
    - -
    -
    -get_formset(request, obj=None, **kwargs)[source]
    -

    get_formset has to return a class, but we need to make the class that we return -know about the related_field that we’ll use. Returning the class itself rather than -a proxy isn’t threadsafe, since it’d be the base class and would change if multiple -people used the admin at the same time

    -
    - -
    -
    -property media
    -
    - -
    - -
    -
    -class evennia.typeclasses.admin.AttributeForm(*args, **kwargs)[source]
    -

    Bases: django.forms.models.ModelForm

    -

    This form overrides the base behavior of the ModelForm that would be used for a Attribute-through-model. -Since the through-models only have access to the foreignkeys of the Attribute and the Object that they’re -attached to, we need to spoof the behavior of it being a form that would correspond to its Attribute, -or the creation of an Attribute. Instead of being saved, we’ll call to the Object’s handler, which will handle -the creation, change, or deletion of an Attribute for us, as well as updating the handler’s cache so that all -changes are instantly updated in-game.

    -
    -
    -class Meta[source]
    -

    Bases: object

    -
    -
    -fields = ('attr_key', 'attr_value', 'attr_category', 'attr_lockstring', 'attr_type')
    -
    - -
    - -
    -
    -__init__(*args, **kwargs)[source]
    -

    If we have an Attribute, then we’ll prepopulate our instance with the fields we’d expect it -to have based on the Attribute. attr_key, attr_category, attr_value, attr_type, -and attr_lockstring all refer to the corresponding Attribute fields. The initial data of the form fields will -similarly be populated.

    -
    - -
    -
    -save(commit=True)[source]
    -

    One thing we want to do here is the or None checks, because forms are saved with an empty -string rather than null from forms, usually, and the Handlers may handle empty strings -differently than None objects. So for consistency with how things are handled in game, -we’ll try to make sure that empty form fields will be None, rather than ‘’.

    -
    - -
    -
    -clean_attr_value()[source]
    -

    Prevent certain data-types from being cleaned due to literal_eval -failing on them. Otherwise they will be turned into str.

    -
    - -
    -
    -base_fields = {'attr_category': <django.forms.fields.CharField object>, 'attr_key': <django.forms.fields.CharField object>, 'attr_lockstring': <django.forms.fields.CharField object>, 'attr_type': <django.forms.fields.CharField object>, 'attr_value': <evennia.utils.picklefield.PickledFormField object>}
    -
    - -
    -
    -declared_fields = {'attr_category': <django.forms.fields.CharField object>, 'attr_key': <django.forms.fields.CharField object>, 'attr_lockstring': <django.forms.fields.CharField object>, 'attr_type': <django.forms.fields.CharField object>, 'attr_value': <evennia.utils.picklefield.PickledFormField object>}
    -
    - -
    -
    -property media
    -

    Return all media required to render the widgets on this form.

    -
    - -
    - -
    -
    -class evennia.typeclasses.admin.AttributeFormSet(data=None, files=None, instance=None, save_as_new=False, prefix=None, queryset=None, **kwargs)[source]
    -

    Bases: django.forms.models.BaseInlineFormSet

    -

    Attribute version of TagFormSet, as above.

    -
    -
    -save(commit=True)[source]
    -

    Save model instances for every form, adding and changing instances -as necessary, and return the list of instances.

    -
    - -
    - -
    -
    -class evennia.typeclasses.admin.AttributeInline(parent_model, admin_site)[source]
    -

    Bases: django.contrib.admin.options.TabularInline

    -

    A handler for inline Attributes. This class should be subclassed in the admin of your models, -and the ‘model’ and ‘related_field’ class attributes must be set. model should be the -through model (ObjectDB_db_tag’, for example), while related field should be the name -of the field on that through model which points to the model being used: ‘objectdb’, -‘msg’, ‘accountdb’, etc.

    -
    -
    -model = None
    -
    - -
    -
    -form
    -

    alias of AttributeForm

    -
    - -
    -
    -formset
    -

    alias of AttributeFormSet

    -
    - -
    -
    -related_field = None
    -
    - -
    -
    -extra = 0
    -
    - -
    -
    -get_formset(request, obj=None, **kwargs)[source]
    -

    get_formset has to return a class, but we need to make the class that we return -know about the related_field that we’ll use. Returning the class itself rather than -a proxy isn’t threadsafe, since it’d be the base class and would change if multiple -people used the admin at the same time

    -
    - -
    -
    -property media
    -
    - -
    - +
    +

    evennia.typeclasses.admin

    @@ -375,7 +84,6 @@ people used the admin at the same time

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.typeclasses.attributes.html b/docs/0.9.5/api/evennia.typeclasses.attributes.html index f76075acde..aa8aa41bc7 100644 --- a/docs/0.9.5/api/evennia.typeclasses.attributes.html +++ b/docs/0.9.5/api/evennia.typeclasses.attributes.html @@ -45,9 +45,9 @@ both pure-string values and pickled arbitrary data.

    the Attribute- and NickHandlers as well as the NAttributeHandler, which is a non-db version of Attributes.

    -
    -class evennia.typeclasses.attributes.Attribute(*args, **kwargs)[source]
    -

    Bases: evennia.utils.idmapper.models.SharedMemoryModel

    +
    +class evennia.typeclasses.attributes.IAttribute[source]
    +

    Bases: object

    Attributes are things that are specific to different types of objects. For example, a drink container needs to store its fill level, whereas an exit needs to store its open/closed/locked/unlocked state. These are done via @@ -82,6 +82,106 @@ attributes on the fly as we like.

    +

    This class is an API/Interface/Abstract base class; do not instantiate it directly.

    +
    +
    +locks[source]
    +
    + +
    +
    +property key
    +
    + +
    +
    +property strvalue
    +
    + +
    +
    +property category
    +
    + +
    +
    +property model
    +
    + +
    +
    +property attrtype
    +
    + +
    +
    +property date_created
    +
    + +
    +
    +property lock_storage
    +
    + +
    +
    +access(accessing_obj, access_type='read', default=False, **kwargs)[source]
    +

    Determines if another object has permission to access.

    +
    +
    Parameters
    +
      +
    • accessing_obj (object) – Entity trying to access this one.

    • +
    • access_type (str, optional) – Type of access sought, see +the lock documentation.

    • +
    • default (bool, optional) – What result to return if no lock +of access_type was found. The default, False, means a lockdown +policy, only allowing explicit access.

    • +
    • kwargs (any, optional) – Not used; here to make the API consistent with +other access calls.

    • +
    +
    +
    Returns
    +

    result (bool) – If the lock was passed or not.

    +
    +
    +
    + +
    + +
    +
    +class evennia.typeclasses.attributes.InMemoryAttribute(pk, **kwargs)[source]
    +

    Bases: evennia.typeclasses.attributes.IAttribute

    +

    This Attribute is used purely for NAttributes/NAttributeHandler. It has no database backend.

    +
    +
    +__init__(pk, **kwargs)[source]
    +

    Create an Attribute that exists only in Memory.

    +
    +
    Parameters
    +
      +
    • pk (int) – This is a fake ‘primary key’ / id-field. It doesn’t actually have to be +unique, but is fed an incrementing number from the InMemoryBackend by default. This +is needed only so Attributes can be sorted. Some parts of the API also see the lack +of a .pk field as a sign that the Attribute was deleted.

    • +
    • **kwargs – Other keyword arguments are used to construct the actual Attribute.

    • +
    +
    +
    +
    + +
    +
    +property value
    +
    + +
    + +
    +
    +class evennia.typeclasses.attributes.Attribute(*args, **kwargs)[source]
    +

    Bases: evennia.typeclasses.attributes.IAttribute, evennia.utils.idmapper.models.SharedMemoryModel

    +

    This attribute is stored via Django. Most Attributes will be using this class.

    db_key
    @@ -138,41 +238,6 @@ object the first time, the query is executed.

    object the first time, the query is executed.

    -
    -
    -locks[source]
    -
    - -
    -
    -property key
    -
    - -
    -
    -property strvalue
    -
    - -
    -
    -property category
    -
    - -
    -
    -property model
    -
    - -
    -
    -property attrtype
    -
    - -
    -
    -property date_created
    -
    -
    property lock_storage
    @@ -187,29 +252,6 @@ as storing a dbobj which is then deleted elsewhere) out-of-sync. The overhead of unpickling seems hard to avoid.

    -
    -
    -access(accessing_obj, access_type='attrread', default=False, **kwargs)[source]
    -

    Determines if another object has permission to access.

    -
    -
    Parameters
    -
      -
    • accessing_obj (object) – Entity trying to access this one.

    • -
    • access_type (str, optional) – Type of access sought, see -the lock documentation.

    • -
    • default (bool, optional) – What result to return if no lock -of access_type was found. The default, False, means a lockdown -policy, only allowing explicit access.

    • -
    • kwargs (any, optional) – Not used; here to make the API consistent with -other access calls.

    • -
    -
    -
    Returns
    -

    result (bool) – If the lock was passed or not.

    -
    -
    -
    -
    exception DoesNotExist
    @@ -238,6 +280,18 @@ instances.

    class built by **create_forward_many_to_many_manager()** defined below.

    +
    +
    +property attrtype
    +

    A wrapper for getting database field db_attrtype.

    +
    + +
    +
    +property category
    +

    A wrapper for getting database field db_category.

    +
    +
    channeldb_set
    @@ -254,6 +308,12 @@ instances.

    class built by **create_forward_many_to_many_manager()** defined below.

    +
    +
    +property date_created
    +

    A wrapper for getting database field db_date_created.

    +
    +
    get_next_by_db_date_created(*, field=<django.db.models.fields.DateTimeField: db_date_created>, is_next=True, **kwargs)
    @@ -271,6 +331,18 @@ class built by **create_forward_many_to_many_manager()** define object the first time, the query is executed.

    +
    +
    +property key
    +

    A wrapper for getting database field db_key.

    +
    + +
    +
    +property model
    +

    A wrapper for getting database field db_model.

    +
    +
    objectdb_set
    @@ -308,6 +380,12 @@ instances.

    class built by **create_forward_many_to_many_manager()** defined below.

    +
    +
    +property strvalue
    +

    A wrapper for getting database field db_strvalue.

    +
    +
    typename = 'SharedMemoryModelBase'
    @@ -315,21 +393,545 @@ class built by **create_forward_many_to_many_manager()** define
    +
    +
    +class evennia.typeclasses.attributes.IAttributeBackend(handler, attrtype)[source]
    +

    Bases: object

    +

    Abstract interface for the backends used by the Attribute Handler.

    +

    All Backends must implement this base class.

    +
    +
    +__init__(handler, attrtype)[source]
    +

    Initialize self. See help(type(self)) for accurate signature.

    +
    + +
    +
    +query_all()[source]
    +

    Fetch all Attributes from this object.

    +
    +
    Returns
    +

    attrlist (list) – A list of Attribute objects.

    +
    +
    +
    + +
    +
    +query_key(key, category)[source]
    +
    +
    Parameters
    +
      +
    • key (str) – The key of the Attribute being searched for.

    • +
    • category (str or None) – The category of the desired Attribute.

    • +
    +
    +
    Returns
    +

    attribute (IAttribute) – A single Attribute.

    +
    +
    +
    + +
    +
    +query_category(category)[source]
    +

    Returns every matching Attribute as a list, given a category.

    +

    This method calls up whatever storage the backend uses.

    +
    +
    Parameters
    +

    category (str or None) – The category to query.

    +
    +
    Returns
    +

    attrs (list) – The discovered Attributes.

    +
    +
    +
    + +
    +
    +get(key=None, category=None)[source]
    +

    Frontend for .get_cache. Retrieves Attribute(s).

    +
    +
    Parameters
    +
      +
    • key (str, optional) – Attribute key to query for

    • +
    • category (str, optional) – Attribiute category

    • +
    +
    +
    Returns
    +

    args (list)

    +
    +
    Returns a list of zero or more matches

    found from cache or database.

    +
    +
    +

    +
    +
    +
    + +
    +
    +reset_cache()[source]
    +

    Reset cache from the outside.

    +
    + +
    +
    +do_create_attribute(key, category, lockstring, value, strvalue)[source]
    +

    Does the hard work of actually creating Attributes, whatever is needed.

    +
    +
    Parameters
    +
      +
    • key (str) – The Attribute’s key.

    • +
    • category (str or None) – The Attribute’s category, or None

    • +
    • lockstring (str) – Any locks for the Attribute.

    • +
    • value (obj) – The Value of the Attribute.

    • +
    • strvalue (bool) – Signifies if this is a strvalue Attribute. Value MUST be a string or +this will lead to Trouble. Ignored for InMemory attributes.

    • +
    +
    +
    Returns
    +

    attr (IAttribute) – The new Attribute.

    +
    +
    +
    + +
    +
    +create_attribute(key, category, lockstring, value, strvalue=False, cache=True)[source]
    +

    Creates Attribute (using the class specified for the backend), (optionally) caches it, and +returns it.

    +

    This MUST actively save the Attribute to whatever database backend is used, AND +call self.set_cache(key, category, new_attrobj)

    +
    +
    Parameters
    +
      +
    • key (str) – The Attribute’s key.

    • +
    • category (str or None) – The Attribute’s category, or None

    • +
    • lockstring (str) – Any locks for the Attribute.

    • +
    • value (obj) – The Value of the Attribute.

    • +
    • strvalue (bool) – Signifies if this is a strvalue Attribute. Value MUST be a string or +this will lead to Trouble. Ignored for InMemory attributes.

    • +
    • cache (bool) – Whether to cache the new Attribute

    • +
    +
    +
    Returns
    +

    attr (IAttribute) – The new Attribute.

    +
    +
    +
    + +
    +
    +do_update_attribute(attr, value)[source]
    +

    Simply sets a new Value to an Attribute.

    +
    +
    Parameters
    +
      +
    • attr (IAttribute) – The Attribute being changed.

    • +
    • value (obj) – The Value for the Attribute.

    • +
    +
    +
    +
    + +
    +
    +do_batch_update_attribute(attr_obj, category, lock_storage, new_value, strvalue)[source]
    +

    Called opnly by batch add. For the database backend, this is a method +of updating that can alter category and lock-storage.

    +
    +
    Parameters
    +
      +
    • attr_obj (IAttribute) – The Attribute being altered.

    • +
    • category (str or None) – The attribute’s (new) category.

    • +
    • lock_storage (str) – The attribute’s new locks.

    • +
    • new_value (obj) – The Attribute’s new value.

    • +
    • strvalue (bool) – Signifies if this is a strvalue Attribute. Value MUST be a string or +this will lead to Trouble. Ignored for InMemory attributes.

    • +
    +
    +
    +
    + +
    +
    +do_batch_finish(attr_objs)[source]
    +

    Called after batch_add completed. Used for handling database operations +and/or caching complications.

    +
    +
    Parameters
    +

    attr_objs (list of IAttribute) – The Attributes created/updated thus far.

    +
    +
    +
    + +
    +
    +batch_add(*args, **kwargs)[source]
    +

    Batch-version of .add(). This is more efficient than repeat-calling +.add when having many Attributes to add.

    +
    +
    Parameters
    +

    *args (tuple) –

    Tuples of varying length representing the +Attribute to add to this object. Supported tuples are

    +
      +
    • (key, value)

    • +
    • (key, value, category)

    • +
    • (key, value, category, lockstring)

    • +
    • (key, value, category, lockstring, default_access)

    • +
    +

    +
    +
    Raises
    +

    RuntimeError – If trying to pass a non-iterable as argument.

    +
    +
    +

    Notes

    +

    The indata tuple order matters, so if you want a lockstring but no +category, set the category to None. This method does not have the +ability to check editing permissions and is mainly used internally. +It does not use the normal self.add but applies the Attributes +directly to the database.

    +
    + +
    +
    +do_delete_attribute(attr)[source]
    +

    Does the hard work of actually deleting things.

    +
    +
    Parameters
    +

    attr (IAttribute) – The attribute to delete.

    +
    +
    +
    + +
    +
    +delete_attribute(attr)[source]
    +

    Given an Attribute, deletes it. Also remove it from cache.

    +
    +
    Parameters
    +

    attr (IAttribute) – The attribute to delete.

    +
    +
    +
    + +
    +
    +update_attribute(attr, value)[source]
    +

    Simply updates an Attribute.

    +
    +
    Parameters
    +
      +
    • attr (IAttribute) – The attribute to delete.

    • +
    • value (obj) – The new value.

    • +
    +
    +
    +
    + +
    +
    +do_batch_delete(attribute_list)[source]
    +

    Given a list of attributes, deletes them all. +The default implementation is fine, but this is overridable since some databases may allow +for a better method.

    +
    +
    Parameters
    +

    attribute_list (list of IAttribute) –

    +
    +
    +
    + +
    +
    +clear_attributes(category, accessing_obj, default_access)[source]
    +

    Remove all Attributes on this object.

    +
    +
    Parameters
    +
      +
    • category (str, optional) – If given, clear only Attributes +of this category.

    • +
    • accessing_obj (object, optional) – If given, check the +attredit lock on each Attribute before continuing.

    • +
    • default_access (bool, optional) – Use this permission as +fallback if access_obj is given but there is no lock of +type attredit on the Attribute in question.

    • +
    +
    +
    +
    + +
    +
    +get_all_attributes()[source]
    +

    Simply returns all Attributes of this object, sorted by their IDs.

    +
    +
    Returns
    +

    attributes (list of IAttribute)

    +
    +
    +
    + +
    + +
    +
    +class evennia.typeclasses.attributes.InMemoryAttributeBackend(handler, attrtype)[source]
    +

    Bases: evennia.typeclasses.attributes.IAttributeBackend

    +

    This Backend for Attributes stores NOTHING in the database. Everything is kept in memory, and +normally lost on a crash, reload, shared memory flush, etc. It generates IDs for the Attributes +it manages, but these are of little importance beyond sorting and satisfying the caching logic +to know an Attribute hasn’t been deleted out from under the cache’s nose.

    +
    +
    +__init__(handler, attrtype)[source]
    +

    Initialize self. See help(type(self)) for accurate signature.

    +
    + +
    +
    +query_all()[source]
    +

    Fetch all Attributes from this object.

    +
    +
    Returns
    +

    attrlist (list) – A list of Attribute objects.

    +
    +
    +
    + +
    +
    +query_key(key, category)[source]
    +
    +
    Parameters
    +
      +
    • key (str) – The key of the Attribute being searched for.

    • +
    • category (str or None) – The category of the desired Attribute.

    • +
    +
    +
    Returns
    +

    attribute (IAttribute) – A single Attribute.

    +
    +
    +
    + +
    +
    +query_category(category)[source]
    +

    Returns every matching Attribute as a list, given a category.

    +

    This method calls up whatever storage the backend uses.

    +
    +
    Parameters
    +

    category (str or None) – The category to query.

    +
    +
    Returns
    +

    attrs (list) – The discovered Attributes.

    +
    +
    +
    + +
    +
    +do_create_attribute(key, category, lockstring, value, strvalue)[source]
    +

    See parent class.

    +

    strvalue has no meaning for InMemory attributes.

    +
    + +
    +
    +do_update_attribute(attr, value)[source]
    +

    Simply sets a new Value to an Attribute.

    +
    +
    Parameters
    +
      +
    • attr (IAttribute) – The Attribute being changed.

    • +
    • value (obj) – The Value for the Attribute.

    • +
    +
    +
    +
    + +
    +
    +do_batch_update_attribute(attr_obj, category, lock_storage, new_value, strvalue)[source]
    +

    No need to bother saving anything. Just set some values.

    +
    + +
    +
    +do_batch_finish(attr_objs)[source]
    +

    Nothing to do here for In-Memory.

    +
    +
    Parameters
    +

    attr_objs (list of IAttribute) – The Attributes created/updated thus far.

    +
    +
    +
    + +
    +
    +do_delete_attribute(attr)[source]
    +

    Removes the Attribute from local storage. Once it’s out of the cache, garbage collection +will handle the rest.

    +
    +
    Parameters
    +

    attr (IAttribute) – The attribute to delete.

    +
    +
    +
    + +
    + +
    +
    +class evennia.typeclasses.attributes.ModelAttributeBackend(handler, attrtype)[source]
    +

    Bases: evennia.typeclasses.attributes.IAttributeBackend

    +

    Uses Django models for storing Attributes.

    +
    +
    +__init__(handler, attrtype)[source]
    +

    Initialize self. See help(type(self)) for accurate signature.

    +
    + +
    +
    +query_all()[source]
    +

    Fetch all Attributes from this object.

    +
    +
    Returns
    +

    attrlist (list) – A list of Attribute objects.

    +
    +
    +
    + +
    +
    +query_key(key, category)[source]
    +
    +
    Parameters
    +
      +
    • key (str) – The key of the Attribute being searched for.

    • +
    • category (str or None) – The category of the desired Attribute.

    • +
    +
    +
    Returns
    +

    attribute (IAttribute) – A single Attribute.

    +
    +
    +
    + +
    +
    +query_category(category)[source]
    +

    Returns every matching Attribute as a list, given a category.

    +

    This method calls up whatever storage the backend uses.

    +
    +
    Parameters
    +

    category (str or None) – The category to query.

    +
    +
    Returns
    +

    attrs (list) – The discovered Attributes.

    +
    +
    +
    + +
    +
    +do_create_attribute(key, category, lockstring, value, strvalue)[source]
    +

    Does the hard work of actually creating Attributes, whatever is needed.

    +
    +
    Parameters
    +
      +
    • key (str) – The Attribute’s key.

    • +
    • category (str or None) – The Attribute’s category, or None

    • +
    • lockstring (str) – Any locks for the Attribute.

    • +
    • value (obj) – The Value of the Attribute.

    • +
    • strvalue (bool) – Signifies if this is a strvalue Attribute. Value MUST be a string or +this will lead to Trouble. Ignored for InMemory attributes.

    • +
    +
    +
    Returns
    +

    attr (IAttribute) – The new Attribute.

    +
    +
    +
    + +
    +
    +do_update_attribute(attr, value)[source]
    +

    Simply sets a new Value to an Attribute.

    +
    +
    Parameters
    +
      +
    • attr (IAttribute) – The Attribute being changed.

    • +
    • value (obj) – The Value for the Attribute.

    • +
    +
    +
    +
    + +
    +
    +do_batch_update_attribute(attr_obj, category, lock_storage, new_value, strvalue)[source]
    +

    Called opnly by batch add. For the database backend, this is a method +of updating that can alter category and lock-storage.

    +
    +
    Parameters
    +
      +
    • attr_obj (IAttribute) – The Attribute being altered.

    • +
    • category (str or None) – The attribute’s (new) category.

    • +
    • lock_storage (str) – The attribute’s new locks.

    • +
    • new_value (obj) – The Attribute’s new value.

    • +
    • strvalue (bool) – Signifies if this is a strvalue Attribute. Value MUST be a string or +this will lead to Trouble. Ignored for InMemory attributes.

    • +
    +
    +
    +
    + +
    +
    +do_batch_finish(attr_objs)[source]
    +

    Called after batch_add completed. Used for handling database operations +and/or caching complications.

    +
    +
    Parameters
    +

    attr_objs (list of IAttribute) – The Attributes created/updated thus far.

    +
    +
    +
    + +
    +
    +do_delete_attribute(attr)[source]
    +

    Does the hard work of actually deleting things.

    +
    +
    Parameters
    +

    attr (IAttribute) – The attribute to delete.

    +
    +
    +
    + +
    +
    -class evennia.typeclasses.attributes.AttributeHandler(obj)[source]
    +class evennia.typeclasses.attributes.AttributeHandler(obj, backend_class)[source]

    Bases: object

    Handler for adding Attributes to the object.

    -__init__(obj)[source]
    -

    Initialize handler.

    -
    - -
    -
    -reset_cache()[source]
    -

    Reset cache from the outside.

    +__init__(obj, backend_class)[source] +

    Setup the AttributeHandler.

    +
    +
    Parameters
    +

    obj (TypedObject) – An Account, Object, Channel, ServerSession (not technically a typed +object), etc. backend_class (IAttributeBackend class): The class of the backend to +use.

    +
    +
    @@ -386,7 +988,8 @@ permission lock will be checked before returning each looked-after Attribute.

  • default_access (bool, optional) – If no attrread lock is set on object, this determines if the lock should then be passed or not.

  • -
  • return_list (bool, optional) –

  • +
  • return_list (bool, optional) – Always return a list, also if there is only +one or zero matches found.

  • Returns
    @@ -444,14 +1047,12 @@ repeat-calling add when having many Attributes to add.

    *args (tuple) –

    Each argument should be a tuples (can be of varying length) representing the Attribute to add to this object. Supported tuples are

    -
    -
      -
    • (key, value)

    • -
    • (key, value, category)

    • -
    • (key, value, category, lockstring)

    • -
    • (key, value, category, lockstring, default_access)

    • +
        +
      • (key, value)

      • +
      • (key, value, category)

      • +
      • (key, value, category, lockstring)

      • +
      • (key, value, category, lockstring, default_access)

      -

    Keyword Arguments
    @@ -550,6 +1151,34 @@ Attributes has no lock of type attrread defined on them.

    +
    +
    +reset_cache()[source]
    +
    + +
    + +
    +
    +class evennia.typeclasses.attributes.DbHolder(obj, name, manager_name='attributes')[source]
    +

    Bases: object

    +

    Holder for allowing property access of attributes

    +
    +
    +__init__(obj, name, manager_name='attributes')[source]
    +

    Initialize self. See help(type(self)) for accurate signature.

    +
    + +
    +
    +get_all()[source]
    +
    + +
    +
    +property all
    +
    +
    @@ -560,30 +1189,45 @@ Attributes has no lock of type attrread defined on them.

    -evennia.typeclasses.attributes.initialize_nick_templates(in_template, out_template)[source]
    +evennia.typeclasses.attributes.initialize_nick_templates(pattern, replacement, pattern_is_regex=False)[source]

    Initialize the nick templates for matching and remapping a string.

    Parameters
      -
    • in_template (str) – The template to be used for nick recognition.

    • -
    • out_template (str) – The template to be used to replace the string -matched by the in_template.

    • +
    • pattern (str) – The pattern to be used for nick recognition. This will +be parsed for shell patterns into a regex, unless pattern_is_regex +is True, in which case it must be an already valid regex string. In +this case, instead of $N, numbered arguments must instead be given +as matching groups named as argN, such as (?P<arg1>.+?).

    • +
    • replacement (str) – The template to be used to replace the string +matched by the pattern. This can contain $N markers and is never +parsed into a regex.

    • +
    • pattern_is_regex (bool) – If set, pattern is a full regex string +instead of containing shell patterns.

    Returns
    -

    (regex, str)

    +

    regex, template (str)

    -
    Regex to match against strings and a template

    Template with markers {arg1}, {arg2}, etc for -replacement using the standard .format method.

    +
    Regex to match against strings and template

    with markers **{arg1}, {arg2}**, etc for replacement using the standard +.format method.

    Raises
    -

    attributes.NickTemplateInvalid – If the in/out template does not have a matching -number of $args.

    +
      +
    • evennia.typecalasses.attributes.NickTemplateInvalid – If the in/out

    • +
    • template does not have a matching number of $args.

    • +
    +

    Examples

    +
      +
    • pattern (shell syntax): “grin $1”

    • +
    • pattern (regex): “grin (?P<arg1.+?>)”

    • +
    • replacement: “emote gives a wicked grin to $1”

    • +
    @@ -593,12 +1237,14 @@ number of $args.

    Parameters
      -
    • string (str) – The input string to processj

    • +
    • string (str) – The input string to process

    • template_regex (regex) – A template regex created with initialize_nick_template.

    • outtemplate (str) – The template to which to map the matches produced by the template_regex. This should have $1, $2, -etc to match the regex.

    • +etc to match the template-regex. Un-found $N-markers (possible if +the regex has optional matching groups) are replaced with empty +strings.

    @@ -614,7 +1260,14 @@ They also always use the strvalue fields for their data.

    __init__(*args, **kwargs)[source]
    -

    Initialize handler.

    +

    Setup the AttributeHandler.

    +
    +
    Parameters
    +

    obj (TypedObject) – An Account, Object, Channel, ServerSession (not technically a typed +object), etc. backend_class (IAttributeBackend class): The class of the backend to +use.

    +
    +
    @@ -659,25 +1312,51 @@ a string.

  • kwargs (any, optional) – These are passed on to AttributeHandler.get.

  • +
    Returns
    +

    str or tuple – The nick replacement string or nick tuple.

    +
    -add(key, replacement, category='inputline', **kwargs)[source]
    -

    Add a new nick.

    +add(pattern, replacement, category='inputline', pattern_is_regex=False, **kwargs)[source] +

    Add a new nick, a mapping pattern -> replacement.

    Parameters
      -
    • key (str) – A key (or template) for the nick to match for.

    • -
    • replacement (str) – The string (or template) to replace key with (the “nickname”).

    • +
    • pattern (str) – A pattern to match for. This will be parsed for +shell patterns using the fnmatch library and can contain +$N-markers to indicate the locations of arguments to catch. If +pattern_is_regex=True, this must instead be a valid regular +expression and the $N-markers must be named argN that matches +numbered regex groups (see examples).

    • +
    • replacement (str) – The string (or template) to replace key with +(the “nickname”). This may contain $N markers to indicate where to +place the argument-matches

    • category (str, optional) – the category within which to retrieve the nick. The “inputline” means replacing data sent by the user.

    • -
    • kwargs (any, optional) – These are passed on to AttributeHandler.get.

    • +
    • pattern_is_regex (bool) – If True, the pattern will be parsed as a +raw regex string. Instead of using $N markers in this string, one +then must mark numbered arguments as a named regex-groupd named argN. +For example, (?P<arg1>.+?) will match the behavior of using $1 +in the shell pattern.

    • +
    • **kwargs (any, optional) – These are passed on to AttributeHandler.get.

    +

    Notes

    +

    For most cases, the shell-pattern is much shorter and easier. The +regex pattern form can be useful for more complex matchings though, +for example in order to add optional arguments, such as with +(?P<argN>.*?).

    +

    Example

    +
      +
    • pattern (default shell syntax): “gr $1 at $2”

    • +
    • pattern (with pattern_is_regex=True): r”gr (?P<arg1>.+?) at (?P<arg2>.+?)”

    • +
    • replacement: “emote With a flourish, $1 grins at $2.”

    • +
    @@ -727,102 +1406,6 @@ with nicks stored on the Account level.

    -
    -
    -class evennia.typeclasses.attributes.NAttributeHandler(obj)[source]
    -

    Bases: object

    -

    This stand-alone handler manages non-database saving. -It is similar to AttributeHandler and is used -by the .ndb handler in the same way as .db does -for the AttributeHandler.

    -
    -
    -__init__(obj)[source]
    -

    Initialized on the object

    -
    - -
    -
    -has(key)[source]
    -

    Check if object has this attribute or not.

    -
    -
    Parameters
    -

    key (str) – The Nattribute key to check.

    -
    -
    Returns
    -

    has_nattribute (bool) – If Nattribute is set or not.

    -
    -
    -
    - -
    -
    -get(key)[source]
    -

    Get the named key value.

    -
    -
    Parameters
    -

    key (str) – The Nattribute key to get.

    -
    -
    Returns
    -

    the value of the Nattribute.

    -
    -
    -
    - -
    -
    -add(key, value)[source]
    -

    Add new key and value.

    -
    -
    Parameters
    -
      -
    • key (str) – The name of Nattribute to add.

    • -
    • value (any) – The value to store.

    • -
    -
    -
    -
    - -
    -
    -remove(key)[source]
    -

    Remove Nattribute from storage.

    -
    -
    Parameters
    -

    key (str) – The name of the Nattribute to remove.

    -
    -
    -
    - -
    -
    -clear()[source]
    -

    Remove all NAttributes from handler.

    -
    - -
    -
    -all(return_tuples=False)[source]
    -

    List the contents of the handler.

    -
    -
    Parameters
    -

    return_tuples (bool, optional) – Defines if the Nattributes -are returns as a list of keys or as a list of (key, value).

    -
    -
    Returns
    -

    nattributes (list)

    -
    -
    A list of keys [key, key, …] or a

    list of tuples [(key, value), …] depending on the -setting of return_tuples.

    -
    -
    -

    -
    -
    -
    - -
    - @@ -868,7 +1451,6 @@ setting of return_tuples.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.typeclasses.html b/docs/0.9.5/api/evennia.typeclasses.html index c55f38ed3d..df8d6503f6 100644 --- a/docs/0.9.5/api/evennia.typeclasses.html +++ b/docs/0.9.5/api/evennia.typeclasses.html @@ -99,7 +99,6 @@ Attribute and Tag models are defined along with their handlers.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.typeclasses.managers.html b/docs/0.9.5/api/evennia.typeclasses.managers.html index d3b4bb8073..6df0f7ebe6 100644 --- a/docs/0.9.5/api/evennia.typeclasses.managers.html +++ b/docs/0.9.5/api/evennia.typeclasses.managers.html @@ -50,15 +50,13 @@ all Attributes and TypedObjects).

    get_attribute(key=None, category=None, value=None, strvalue=None, obj=None, attrtype=None, **kwargs)[source]
    -

    Return Attribute objects by key, by category, by value, by -strvalue, by object (it is stored on) or with a combination of -those criteria.

    +

    Return Attribute objects by key, by category, by value, by strvalue, by +object (it is stored on) or with a combination of those criteria.

    Parameters
      -
    • key (str, optional) – The attribute’s key to search for.

    • -
    • category (str, optional) – The category of the attribute(s) -to search for.

    • +
    • key (str, optional) – The attribute’s key to search for

    • +
    • category (str, optional) – The category of the attribute(s) to search for.

    • value (str, optional) – The attribute value to search for. Note that this is not a very efficient operation since it will query for a pickled entity. Mutually exclusive to @@ -69,14 +67,14 @@ mutually exclusive to the value keyword and will take precedence if given.

    • obj (Object, optional) – On which object the Attribute to search for is.

    • -
    • attrtype (str, optional) – An attribute-type to search for. +

    • attrype (str, optional) – An attribute-type to search for. By default this is either None (normal Attributes) or “nick”.

    • -
    • kwargs (any) – Currently unused. Reserved for future use.

    • +
    • **kwargs (any) – Currently unused. Reserved for future use.

    Returns
    -

    attributes (list) – The matching Attributes.

    +

    list – The matching Attributes.

    @@ -168,7 +166,7 @@ stored on) or with a combination of those criteria.

    to search for.

  • obj (Object, optional) – On which object the Tag to search for is.

  • -
  • tagtype (str, optional) – One of None (normal tags), +

  • tagtype (str, optional) – One of None (normal tags), “alias” or “permission”

  • global_search (bool, optional) – Include all possible tags, not just tags on this object

  • @@ -493,7 +491,6 @@ Mutually exclusive to include_children.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.typeclasses.models.html b/docs/0.9.5/api/evennia.typeclasses.models.html index d0da709195..2ca866d0ed 100644 --- a/docs/0.9.5/api/evennia.typeclasses.models.html +++ b/docs/0.9.5/api/evennia.typeclasses.models.html @@ -60,7 +60,6 @@ The admin should usually not have to deal directly with the database object layer.

    This module also contains the Managers for the respective models; inherit from these to create custom managers.

    -
    class evennia.typeclasses.models.TypedObject(*args, **kwargs)[source]
    @@ -68,18 +67,18 @@ these to create custom managers.

    Abstract Django model.

    This is the basis for a typed object. It also contains all the mechanics for managing connected attributes.

    -
    -
    The TypedObject has the following properties:

    key - main name -name - alias for key -typeclass_path - the path to the decorating typeclass -typeclass - auto-linked typeclass -date_created - time stamp of object creation -permissions - perm strings -dbref - #id of object -db - persistent attribute storage -ndb - non-persistent attribute storage

    -
    -
    +

    The TypedObject has the following properties:

    +
      +
    • key - main name

    • +
    • name - alias for key

    • +
    • typeclass_path - the path to the decorating typeclass

    • +
    • typeclass - auto-linked typeclass

    • +
    • date_created - time stamp of object creation

    • +
    • permissions - perm strings

    • +
    • dbref - #id of object

    • +
    • db - persistent attribute storage

    • +
    • ndb - non-persistent attribute storage

    • +
    db_key
    @@ -159,10 +158,10 @@ a class based on the db_typeclass_path database field rather than use the one in the model.

    Parameters
    -
      -
    • *args – Passed through to parent.

    • -
    • **kwargs – Passed through to parent.

    • -
    +

    through to parent. (Passed) –

    +
    +
    Keyword Arguments
    +

    through to parent. (Passed) –

    Notes

    @@ -368,7 +367,7 @@ superuser lock bypass (be careful with this one).

    Keyword Arguments
    -

    kwargs (any) – Ignored, but is there to make the api +

    kwar (any) – Ignored, but is there to make the api consistent with the object-typeclass method access, which use it to feed to its hook methods.

    @@ -401,36 +400,30 @@ without involving any locks.

    property db

    Attribute handler wrapper. Allows for the syntax

    obj.db.attrname = value
    -  and
    +# and
     value = obj.db.attrname
    -  and
    +# and
     del obj.db.attrname
    -  and
    +# and
     all_attr = obj.db.all()
    +# (unless there is an attribute
    +#  named 'all', in which case that will be returned instead).
     
    -

    (unless there is an attribute named ‘all’, in which case that will be -returned instead).

    property ndb
    -

    A non-attr_obj store (NonDataBase). Everything stored to this is -guaranteed to be cleared when a server is shutdown. Syntax is same as -for the .db property, e.g.

    -
    obj.ndb.attrname = value
    -  and
    -value = obj.ndb.attrname
    -  and
    -del obj.ndb.attrname
    -  and
    -all_attr = obj.ndb.all()
    -
    -
    -

    What makes this preferable over just assigning properties directly on -the object is that Evennia can track caching for these properties and -for example avoid wiping objects with set .ndb data on cache flushes.

    +

    NonDataBase). Everything stored +to this is guaranteed to be cleared when a server is shutdown. +Syntax is same as for the _get_db_holder() method and +property, e.g. obj.ndb.attr = value etc.

    +
    +
    Type
    +

    A non-attr_obj store (ndb

    +
    +
    @@ -517,141 +510,22 @@ at/getting information for this object.

    classmethod web_get_create_url()[source]

    Returns the URI path for a View that allows users to create new instances of this object.

    +

    ex. Chargen = ‘/characters/create/’

    +

    For this to work, the developer must have defined a named view somewhere +in urls.py that follows the format ‘modelname-action’, so in this case +a named view of ‘character-create’ would be referenced by this method.

    +

    ex. +url(r’characters/create/’, ChargenView.as_view(), name=’character-create’)

    +

    If no View has been created and defined in urls.py, returns an +HTML anchor.

    +

    This method is naive and simply returns a path. Securing access to +the actual view and limiting who can create new objects is the +developer’s responsibility.

    Returns

    path (str) – URI path to object creation page, if defined.

    -

    Examples

    -
    Chargen = '/characters/create/'
    -
    -
    -

    For this to work, the developer must have defined a named view somewhere -in urls.py that follows the format ‘modelname-action’, so in this case -a named view of ‘character-create’ would be referenced by this method.

    -
    url(r'characters/create/', ChargenView.as_view(), name='character-create')
    -
    -
    -

    If no View has been created and defined in urls.py, returns an -HTML anchor.

    -

    Notes

    -

    This method is naive and simply returns a path. Securing access to -the actual view and limiting who can create new objects is the -developer’s responsibility.

    -
    - -
    -
    -web_get_detail_url()[source]
    -

    Returns the URI path for a View that allows users to view details for -this object.

    -
    -
    Returns
    -

    path (str) – URI path to object detail page, if defined.

    -
    -
    -

    Examples

    -
    Oscar (Character) = '/characters/oscar/1/'
    -
    -
    -

    For this to work, the developer must have defined a named view somewhere -in urls.py that follows the format ‘modelname-action’, so in this case -a named view of ‘character-detail’ would be referenced by this method.

    -
    CharDetailView.as_view(), name='character-detail')
    -
    -
    -

    If no View has been created and defined in urls.py, returns an -HTML anchor.

    -

    Notes

    -

    This method is naive and simply returns a path. Securing access to -the actual view and limiting who can view this object is the -developer’s responsibility.

    -
    - -
    -
    -web_get_puppet_url()[source]
    -

    Returns the URI path for a View that allows users to puppet a specific -object.

    -
    -
    Returns
    -

    path (str) – URI path to object puppet page, if defined.

    -
    -
    -

    Examples

    -
    Oscar (Character) = '/characters/oscar/1/puppet/'
    -
    -
    -

    For this to work, the developer must have defined a named view somewhere -in urls.py that follows the format ‘modelname-action’, so in this case -a named view of ‘character-puppet’ would be referenced by this method.

    -
    url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/puppet/$',
    -    CharPuppetView.as_view(), name='character-puppet')
    -
    -
    -

    If no View has been created and defined in urls.py, returns an -HTML anchor.

    -

    Notes

    -

    This method is naive and simply returns a path. Securing access to -the actual view and limiting who can view this object is the developer’s -responsibility.

    -
    - -
    -
    -web_get_update_url()[source]
    -

    Returns the URI path for a View that allows users to update this -object.

    -
    -
    Returns
    -

    path (str) – URI path to object update page, if defined.

    -
    -
    -

    Examples

    -
    Oscar (Character) = '/characters/oscar/1/change/'
    -
    -
    -

    For this to work, the developer must have defined a named view somewhere -in urls.py that follows the format ‘modelname-action’, so in this case -a named view of ‘character-update’ would be referenced by this method.

    -
    url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/change/$',
    -    CharUpdateView.as_view(), name='character-update')
    -
    -
    -

    If no View has been created and defined in urls.py, returns an -HTML anchor.

    -

    Notes

    -

    This method is naive and simply returns a path. Securing access to -the actual view and limiting who can modify objects is the developer’s -responsibility.

    -
    - -
    -
    -web_get_delete_url()[source]
    -

    Returns the URI path for a View that allows users to delete this object.

    -
    -
    Returns
    -

    path (str) – URI path to object deletion page, if defined.

    -
    -
    -

    Examples

    -
    Oscar (Character) = '/characters/oscar/1/delete/'
    -
    -
    -

    For this to work, the developer must have defined a named view somewhere -in urls.py that follows the format ‘modelname-action’, so in this case -a named view of ‘character-detail’ would be referenced by this method.

    -
    url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/delete/$',
    -    CharDeleteView.as_view(), name='character-delete')
    -
    -
    -

    If no View has been created and defined in urls.py, returns an -HTML anchor.

    -

    Notes

    -

    This method is naive and simply returns a path. Securing access to -the actual view and limiting who can delete this object is the developer’s -responsibility.

    @@ -660,34 +534,6 @@ responsibility.

    A wrapper for getting database field db_date_created.

    -
    -
    -get_absolute_url()
    -

    Returns the URI path for a View that allows users to view details for -this object.

    -
    -
    Returns
    -

    path (str) – URI path to object detail page, if defined.

    -
    -
    -

    Examples

    -
    Oscar (Character) = '/characters/oscar/1/'
    -
    -
    -

    For this to work, the developer must have defined a named view somewhere -in urls.py that follows the format ‘modelname-action’, so in this case -a named view of ‘character-detail’ would be referenced by this method.

    -
    CharDetailView.as_view(), name='character-detail')
    -
    -
    -

    If no View has been created and defined in urls.py, returns an -HTML anchor.

    -

    Notes

    -

    This method is naive and simply returns a path. Securing access to -the actual view and limiting who can view this object is the -developer’s responsibility.

    -
    -
    get_next_by_db_date_created(*, field=<django.db.models.fields.DateTimeField: db_date_created>, is_next=True, **kwargs)
    @@ -720,6 +566,146 @@ developer’s responsibility.

    typename = 'SharedMemoryModelBase'
    +
    +
    +web_get_detail_url()[source]
    +

    Returns the URI path for a View that allows users to view details for +this object.

    +
    +
    Returns
    +

    path (str) – URI path to object detail page, if defined.

    +
    +
    +

    Examples

    +
    Oscar (Character) = '/characters/oscar/1/'
    +
    +
    +

    For this to work, the developer must have defined a named view somewhere +in urls.py that follows the format ‘modelname-action’, so in this case +a named view of ‘character-detail’ would be referenced by this method.

    +
    url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/$',
    +    CharDetailView.as_view(), name='character-detail')
    +
    +
    +

    If no View has been created and defined in urls.py, returns an +HTML anchor.

    +

    This method is naive and simply returns a path. Securing access to +the actual view and limiting who can view this object is the +developer’s responsibility.

    +
    + +
    +
    +web_get_puppet_url()[source]
    +

    Returns the URI path for a View that allows users to puppet a specific +object.

    +
    +
    Returns
    +

    str – URI path to object puppet page, if defined.

    +
    +
    +

    Examples

    +
    Oscar (Character) = '/characters/oscar/1/puppet/'
    +
    +
    +

    For this to work, the developer must have defined a named view somewhere +in urls.py that follows the format ‘modelname-action’, so in this case +a named view of ‘character-puppet’ would be referenced by this method.

    +
    url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/puppet/$',
    +    CharPuppetView.as_view(), name='character-puppet')
    +
    +
    +

    If no View has been created and defined in urls.py, returns an +HTML anchor.

    +

    This method is naive and simply returns a path. Securing access to +the actual view and limiting who can view this object is the developer’s +responsibility.

    +
    + +
    +
    +web_get_update_url()[source]
    +

    Returns the URI path for a View that allows users to update this +object.

    +
    +
    Returns
    +

    str – URI path to object update page, if defined.

    +
    +
    +

    Examples

    +
    Oscar (Character) = '/characters/oscar/1/change/'
    +
    +
    +

    For this to work, the developer must have defined a named view somewhere +in urls.py that follows the format ‘modelname-action’, so in this case +a named view of ‘character-update’ would be referenced by this method.

    +
    url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/change/$',
    +CharUpdateView.as_view(), name='character-update')
    +
    +
    +

    If no View has been created and defined in urls.py, returns an +HTML anchor.

    +

    This method is naive and simply returns a path. Securing access to +the actual view and limiting who can modify objects is the developer’s +responsibility.

    +
    + +
    +
    +web_get_delete_url()[source]
    +

    Returns the URI path for a View that allows users to delete this object.

    +
    +
    Returns
    +

    path (str) – URI path to object deletion page, if defined.

    +
    +
    +

    Examples

    +
    Oscar (Character) = '/characters/oscar/1/delete/'
    +
    +
    +

    For this to work, the developer must have defined a named view +somewhere in urls.py that follows the format ‘modelname-action’, so +in this case a named view of ‘character-detail’ would be referenced +by this method.

    +
    url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/delete/$',
    +CharDeleteView.as_view(), name='character-delete')
    +
    +
    +

    If no View has been created and defined in urls.py, returns an HTML +anchor.

    +

    This method is naive and simply returns a path. Securing access to +the actual view and limiting who can delete this object is the +developer’s responsibility.

    +
    + +
    +
    +get_absolute_url()
    +

    Returns the URI path for a View that allows users to view details for +this object.

    +
    +
    Returns
    +

    path (str) – URI path to object detail page, if defined.

    +
    +
    +

    Examples

    +
    Oscar (Character) = '/characters/oscar/1/'
    +
    +
    +

    For this to work, the developer must have defined a named view somewhere +in urls.py that follows the format ‘modelname-action’, so in this case +a named view of ‘character-detail’ would be referenced by this method.

    +
    url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/$',
    +    CharDetailView.as_view(), name='character-detail')
    +
    +
    +

    If no View has been created and defined in urls.py, returns an +HTML anchor.

    +

    This method is naive and simply returns a path. Securing access to +the actual view and limiting who can view this object is the +developer’s responsibility.

    +
    +
    @@ -767,7 +753,6 @@ developer’s responsibility.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.typeclasses.tags.html b/docs/0.9.5/api/evennia.typeclasses.tags.html index 1f07bee11e..c50b90f97a 100644 --- a/docs/0.9.5/api/evennia.typeclasses.tags.html +++ b/docs/0.9.5/api/evennia.typeclasses.tags.html @@ -270,6 +270,33 @@ existing Tag object, this will be re-used and no new Tag will be created.

    +
    +
    +has(tag=None, category=None, return_list=False)[source]
    +

    Checks if the given Tag (or list of Tags) exists on the object.

    +
    +
    Parameters
    +
      +
    • tag (str or iterable) – The Tag key or tags to check for. +If None, search by category.

    • +
    • category (str, optional) – Limit the check to Tags with this +category (note, that None is the default category).

    • +
    +
    +
    Returns
    +

    has_tag (bool or list)

    +
    +
    If the Tag exists on this object or not.

    If tag was given as an iterable then the return is a list of booleans.

    +
    +
    +

    +
    +
    Raises
    +

    ValueError – If neither tag nor category is given.

    +
    +
    +
    +
    get(key=None, default=None, category=None, return_tagobj=False, return_list=False)[source]
    @@ -364,8 +391,9 @@ tuples [(key, category), …].

    Batch-add tags from a list of tuples.

    Parameters
    -

    *args (tuple or str) – Each argument should be a tagstr keys or tuple (keystr, category) or -(keystr, category, data). It’s possible to mix input types.

    +

    *args (tuple or str) – Each argument should be a tagstr keys or tuple +(keystr, category) or (keystr, category, data). It’s possible to mix input +types.

    Notes

    @@ -436,7 +464,6 @@ of a latter tuple with the same category).

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.utils.ansi.html b/docs/0.9.5/api/evennia.utils.ansi.html index d771726622..65a2009cf6 100644 --- a/docs/0.9.5/api/evennia.utils.ansi.html +++ b/docs/0.9.5/api/evennia.utils.ansi.html @@ -40,21 +40,65 @@

    evennia.utils.ansi

    ANSI - Gives colour to text.

    -

    Use the codes defined in ANSIPARSER in your text to apply colour to text -according to the ANSI standard.

    -

    Examples:

    +

    Use the codes defined in the ANSIParser class to apply colour to text. The +parse_ansi function in this module parses text for markup and strip_ansi +removes it.

    +

    You should usually not need to call parse_ansi explicitly; it is run by +Evennia just before returning data to/from the user. Alternative markup is +possible by overriding the parser class (see also contrib/ for deprecated +markup schemes).

    +

    Supported standards:

    +
      +
    • ANSI 8 bright and 8 dark fg (foreground) colors

    • +
    • ANSI 8 dark bg (background) colors

    • +
    • ‘ANSI’ 8 bright bg colors ‘faked’ with xterm256 (bright bg not included in ANSI standard)

    • +
    • Xterm256 - 255 fg/bg colors + 26 greyscale fg/bg colors

    • +
    +
    +

    Markup

    +

    ANSI colors: r ed, g reen, y ellow, b lue, m agenta, c yan, n ormal (no color). +Capital letters indicate the ‘dark’ variant.

    +
      +
    • |r fg bright red

    • +
    • |R fg dark red

    • +
    • |[r bg bright red

    • +
    • |[R bg dark red

    • +
    • |[R|g bg dark red, fg bright green

    • +
    "This is |rRed text|n and this is normal again."
     
    -

    Mostly you should not need to call parse_ansi() explicitly; it is run by -Evennia just before returning data to/from the user. Depreciated example forms -are available by extending the ansi mapping.

    +

    Xterm256 colors are given as RGB (Red-Green-Blue), with values 0-5:

    +
      +
    • |500 fg bright red

    • +
    • |050 fg bright green

    • +
    • |005 fg bright blue

    • +
    • |110 fg dark brown

    • +
    • |425 fg pink

    • +
    • |[431 bg orange

    • +
    +

    Xterm256 greyscale:

    +
      +
    • |=a fg black

    • +
    • |=g fg dark grey

    • +
    • |=o fg middle grey

    • +
    • |=v fg bright grey

    • +
    • |=z fg white

    • +
    • |[=r bg middle grey

    • +
    +
    "This is |500Red text|n and this is normal again."
    +"This is |[=jText on dark grey background"
    +
    +
    +
    class evennia.utils.ansi.ANSIParser[source]

    Bases: object

    -

    A class that parses ANSI markup to ANSI command sequences.

    -

    We also allow to escape colour codes by prepending with an extra |.

    +

    A class that parses ANSI markup +to ANSI command sequences

    +

    We also allow to escape colour codes +by prepending with an extra |.

    ansi_map = [('|n', '\x1b[0m'), ('|/', '\r\n'), ('|-', '\t'), ('|>', ' '), ('|_', ' '), ('|*', '\x1b[7m'), ('|^', '\x1b[5m'), ('|u', '\x1b[4m'), ('|r', '\x1b[1m\x1b[31m'), ('|g', '\x1b[1m\x1b[32m'), ('|y', '\x1b[1m\x1b[33m'), ('|b', '\x1b[1m\x1b[34m'), ('|m', '\x1b[1m\x1b[35m'), ('|c', '\x1b[1m\x1b[36m'), ('|w', '\x1b[1m\x1b[37m'), ('|x', '\x1b[1m\x1b[30m'), ('|R', '\x1b[22m\x1b[31m'), ('|G', '\x1b[22m\x1b[32m'), ('|Y', '\x1b[22m\x1b[33m'), ('|B', '\x1b[22m\x1b[34m'), ('|M', '\x1b[22m\x1b[35m'), ('|C', '\x1b[22m\x1b[36m'), ('|W', '\x1b[22m\x1b[37m'), ('|X', '\x1b[22m\x1b[30m'), ('|h', '\x1b[1m'), ('|H', '\x1b[22m'), ('|!R', '\x1b[31m'), ('|!G', '\x1b[32m'), ('|!Y', '\x1b[33m'), ('|!B', '\x1b[34m'), ('|!M', '\x1b[35m'), ('|!C', '\x1b[36m'), ('|!W', '\x1b[37m'), ('|!X', '\x1b[30m'), ('|[R', '\x1b[41m'), ('|[G', '\x1b[42m'), ('|[Y', '\x1b[43m'), ('|[B', '\x1b[44m'), ('|[M', '\x1b[45m'), ('|[C', '\x1b[46m'), ('|[W', '\x1b[47m'), ('|[X', '\x1b[40m')]
    @@ -90,6 +134,11 @@ are available by extending the ansi mapping.

    mxp_re = '\\|lc(.*?)\\|lt(.*?)\\|le'
    +
    +
    +mxp_url_re = '\\|lu(.*?)\\|lt(.*?)\\|le'
    +
    +
    brightbg_sub = re.compile('(?<!\\|)\\|\\[r|(?<!\\|)\\|\\[g|(?<!\\|)\\|\\[y|(?<!\\|)\\|\\[b|(?<!\\|)\\|\\[m|(?<!\\|)\\|\\[c|(?<!\\|)\\|\\[w|(?<!\\|)\\|\\[x', re.DOTALL)
    @@ -125,6 +174,11 @@ are available by extending the ansi mapping.

    mxp_sub = re.compile('\\|lc(.*?)\\|lt(.*?)\\|le', re.DOTALL)
    +
    +
    +mxp_url_sub = re.compile('\\|lu(.*?)\\|lt(.*?)\\|le', re.DOTALL)
    +
    +
    ansi_map_dict = {'|!B': '\x1b[34m', '|!C': '\x1b[36m', '|!G': '\x1b[32m', '|!M': '\x1b[35m', '|!R': '\x1b[31m', '|!W': '\x1b[37m', '|!X': '\x1b[30m', '|!Y': '\x1b[33m', '|*': '\x1b[7m', '|-': '\t', '|/': '\r\n', '|>': ' ', '|B': '\x1b[22m\x1b[34m', '|C': '\x1b[22m\x1b[36m', '|G': '\x1b[22m\x1b[32m', '|H': '\x1b[22m', '|M': '\x1b[22m\x1b[35m', '|R': '\x1b[22m\x1b[31m', '|W': '\x1b[22m\x1b[37m', '|X': '\x1b[22m\x1b[30m', '|Y': '\x1b[22m\x1b[33m', '|[B': '\x1b[44m', '|[C': '\x1b[46m', '|[G': '\x1b[42m', '|[M': '\x1b[45m', '|[R': '\x1b[41m', '|[W': '\x1b[47m', '|[X': '\x1b[40m', '|[Y': '\x1b[43m', '|^': '\x1b[5m', '|_': ' ', '|b': '\x1b[1m\x1b[34m', '|c': '\x1b[1m\x1b[36m', '|g': '\x1b[1m\x1b[32m', '|h': '\x1b[1m', '|m': '\x1b[1m\x1b[35m', '|n': '\x1b[0m', '|r': '\x1b[1m\x1b[31m', '|u': '\x1b[4m', '|w': '\x1b[1m\x1b[37m', '|x': '\x1b[1m\x1b[30m', '|y': '\x1b[1m\x1b[33m'}
    @@ -842,6 +896,7 @@ with.

    +
    @@ -864,6 +919,14 @@ with.

    +

    Table of Contents

    + +
    -
    diff --git a/docs/0.9.5/api/evennia.utils.batchprocessors.html b/docs/0.9.5/api/evennia.utils.batchprocessors.html index ab2e701b5b..6898c4f9cc 100644 --- a/docs/0.9.5/api/evennia.utils.batchprocessors.html +++ b/docs/0.9.5/api/evennia.utils.batchprocessors.html @@ -40,23 +40,21 @@

    evennia.utils.batchprocessors

    This module contains the core methods for the Batch-command- and -Batch-code-processors respectively. In short, these are two different -ways to build a game world using a normal text-editor without having -to do so ‘on the fly’ in-game. They also serve as an automatic backup -so you can quickly recreate a world also after a server reset. The -functions in this module is meant to form the backbone of a system -called and accessed through game commands.

    -

    The Batch-command processor is the simplest. It simply runs a list of -in-game commands in sequence by reading them from a text file. The -advantage of this is that the builder only need to remember the normal -in-game commands. They are also executing with full permission checks -etc, making it relatively safe for builders to use. The drawback is -that in-game there is really a builder-character walking around -building things, and it can be important to create rooms and objects -in the right order, so the character can move between them. Also -objects that affects players (such as mobs, dark rooms etc) will -affect the building character too, requiring extra care to turn -off/on.

    +Batch-code-processors respectively. In short, these are two different ways to +build a game world using a normal text-editor without having to do so ‘on the +fly’ in-game. They also serve as an automatic backup so you can quickly +recreate a world also after a server reset. The functions in this module is +meant to form the backbone of a system called and accessed through game +commands.

    +

    The Batch-command processor is the simplest. It simply runs a list of in-game +commands in sequence by reading them from a text file. The advantage of this is +that the builder only need to remember the normal in-game commands. They are +also executing with full permission checks etc, making it relatively safe for +builders to use. The drawback is that in-game there is really a +builder-character walking around building things, and it can be important to +create rooms and objects in the right order, so the character can move between +them. Also objects that affects players (such as mobs, dark rooms etc) will +affect the building character too, requiring extra care to turn off/on.

    The Batch-code processor is a more advanced system that accepts full Python code, executing in chunks. The advantage of this is much more power; practically anything imaginable can be coded and handled using @@ -69,33 +67,38 @@ etc. You also need to know Python and Evennia’s API. Hence it’s recommended that the batch-code processor is limited only to superusers or highly trusted staff.

    -

    Batch-Command processor file syntax

    +

    Batch-command processor file syntax

    The batch-command processor accepts ‘batchcommand files’ e.g batch.ev, containing a sequence of valid Evennia commands in a simple format. The engine runs each command in sequence, as if they had been run at the game prompt.

    Each Evennia command must be delimited by a line comment to mark its -end. This way entire game worlds can be created and planned offline; it is +end.

    +
    look
    +# delimiting comment
    +create/drop box
    +# another required comment
    +
    +
    +

    One can also inject another batchcmdfile:

    +
    #INSERT path.batchcmdfile
    +
    +
    +

    This way entire game worlds can be created and planned offline; it is especially useful in order to create long room descriptions where a real offline text editor is often much better than any online text editor or prompt.

    -

    There is only one batchcommand-specific entry to use in a batch-command -files (all others are just like in-game commands):

    -
      -
    • #INSERT path.batchcmdfile - this as the first entry on a line will -import and run a batch.ev file in this position, as if it was -written in this file.

    • -
    -

    Example of batch.ev file:

    +
    +

    Example of batch.ev file:

    # batch file
     # all lines starting with # are comments; they also indicate
     # that a command definition is over.
     
    -@create box
    +create box
     
     # this comment ends the @create command.
     
    -@set box/desc = A large box.
    +set box/desc = A large box.
     
     Inside are some scattered piles of clothing.
     
    @@ -108,24 +111,25 @@ written in this file.

    # (so two empty lines becomes a new paragraph). -@teleport #221 +teleport #221 # (Assuming #221 is a warehouse or something.) # (remember, this comment ends the @teleport command! Don'f forget it) # Example of importing another file at this point. -#INSERT examples.batch +#IMPORT examples.batch -@drop box +drop box # Done, the box is in the warehouse! (this last comment is not necessary to -# close the @drop command since it's the end of the file) +# close the drop command since it's the end of the file)

    An example batch file is contrib/examples/batch_example.ev.

    +
    -

    Batch-Code processor file syntax

    +

    Batch-code processor file syntax

    The Batch-code processor accepts full python modules (e.g. batch.py) that looks identical to normal Python files. The difference from importing and running any Python module is that the batch-code module @@ -156,13 +160,17 @@ this file.

    Importing works as normal. The following variables are automatically made available in the script namespace.

      -
    • caller - The object executing the batchscript

    • -
    • DEBUG - This is a boolean marking if the batchprocessor is running -in debug mode. It can be checked to e.g. delete created objects +

    • caller - The object executing the batchscript

    • +
    • +
      DEBUG - This is a boolean marking if the batchprocessor is running

      in debug mode. It can be checked to e.g. delete created objects when running a CODE block multiple times during testing. -(avoids creating a slew of same-named db objects)

    • +(avoids creating a slew of same-named db objects)

      +
    +
    + -

    Example batch.py file:

    +
    +

    Example batch.py file

    #HEADER
     
     from django.conf import settings
    @@ -190,7 +198,6 @@ when running a CODE block multiple times during testing.
     script = create.create_script()
     
    -
    evennia.utils.batchprocessors.read_batchfile(pythonpath, file_ending='.py')[source]
    @@ -207,7 +214,7 @@ or .py). The ending should not be included in the python path.

    Returns
    -

    str – The text content of the batch file.

    +

    text (str) – The text content of the batch file.

    Raises

    IOError – If problems reading file.

    @@ -223,13 +230,22 @@ or .py). The ending should not be included in the python path.

    parse_file(pythonpath)[source]
    -

    This parses the lines of a batchfile according to the following -rules:

    +

    This parses the lines of a batch-command-file.

    +
    +
    Parameters
    +

    pythonpath (str) – The dot-python path to the file.

    +
    +
    Returns
    +

    list – A list of all parsed commands with arguments, as strings.

    +
    +
    +

    Notes

    +

    Parsing follows the following rules:

      -
    1. # at the beginning of a line marks the end of the command before +

    2. A # at the beginning of a line marks the end of the command before it. It is also a comment and any number of # can exist on subsequent lines (but not inside comments).

    3. -
    4. #INSERT at the beginning of a line imports another +

    5. #INSERT at the beginning of a line imports another batch-cmd file file and pastes it into the batch file as if it was written there.

    6. Commands are placed alone at the beginning of a line and their @@ -264,30 +280,28 @@ a newline (so two empty lines is a paragraph).

    7. parse_file(pythonpath)[source]
      -

      This parses the lines of a batchfile according to the following -rules:

      +

      This parses the lines of a batch-code file

      Parameters

      pythonpath (str) – The dot-python path to the file.

      Returns
      -

      codeblocks (list)

      +

      list

      -
      A list of all #CODE blocks, each with

      prepended #HEADER data. If no #CODE blocks were found, -this will be a list of one element.

      +
      A list of all #CODE blocks, each with

      prepended #HEADER block data. If no #CODE +blocks were found, this will be a list of one element +containing all code in the file (so a normal Python file).

      Notes

      +

      Parsing is done according to the following rules:

        -
      1. -
        Code before a #CODE/HEADER block are considered part of

        the first code/header block or is the ONLY block if no -#CODE/HEADER blocks are defined.

        -
        -
        -
      2. +
      3. Code before a #CODE/HEADER block are considered part of +the first code/header block or is the ONLY block if no +#CODE/HEADER blocks are defined.

      4. Lines starting with #HEADER starts a header block (ends other blocks)

      5. Lines starting with #CODE begins a code block (ends other blocks)

      6. Lines starting with #INSERT are on form #INSERT filename. Code from @@ -320,6 +334,7 @@ namespace.

      +
    @@ -346,8 +361,14 @@ namespace.

    Table of Contents

    @@ -375,7 +396,6 @@ namespace.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.utils.containers.html b/docs/0.9.5/api/evennia.utils.containers.html index ceb747f853..0c46cac13b 100644 --- a/docs/0.9.5/api/evennia.utils.containers.html +++ b/docs/0.9.5/api/evennia.utils.containers.html @@ -231,7 +231,6 @@ scripts defined in settings.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.utils.create.html b/docs/0.9.5/api/evennia.utils.create.html index cc7b750321..b7aea69699 100644 --- a/docs/0.9.5/api/evennia.utils.create.html +++ b/docs/0.9.5/api/evennia.utils.create.html @@ -39,25 +39,15 @@

    evennia.utils.create

    -

    This module gathers all the essential database-creation -functions for the game engine’s various object types.

    -

    Only objects created ‘stand-alone’ are in here, e.g. object Attributes -are always created directly through their respective objects.

    -

    Each creation_* function also has an alias named for the entity being -created, such as create_object() and object(). This is for -consistency with the utils.search module and allows you to do the -shorter “create.object()”.

    -

    The respective object managers hold more methods for manipulating and -searching objects already existing in the database.

    -
    -
    Models covered:

    Objects -Scripts -Help -Message -Channel -Accounts

    -
    -
    +

    This module gathers all the essential database-creation functions for the game +engine’s various object types.

    +

    Only objects created ‘stand-alone’ are in here. E.g. object Attributes are +always created through their respective objects handlers.

    +

    Each creation_* function also has an alias named for the entity being created, +such as create_object() and object(). This is for consistency with the +utils.search module and allows you to do the shorter create.object().

    +

    The respective object managers hold more methods for manipulating and searching +objects already existing in the database.

    evennia.utils.create.create_object(typeclass=None, key=None, location=None, home=None, permissions=None, locks=None, aliases=None, tags=None, destination=None, report_to=None, nohome=False, attributes=None, nattributes=None)[source]
    @@ -67,15 +57,14 @@ Accounts

    • typeclass (class or str) – Class or python path to a typeclass.

    • key (str) – Name of the new object. If not set, a name of -#dbref will be set.

    • +#dbref will be set.

    • home (Object or str) – Obj or #dbref to use as the object’s home location.

    • permissions (list) – A list of permission strings or tuples (permstring, category).

    • locks (str) – one or more lockstrings, separated by semicolons.

    • aliases (list) – A list of alternative keys or tuples (aliasstring, category).

    • tags (list) – List of tag keys or tuples (tagkey, category) or (tagkey, category, data).

    • -
    • destination (Object or str) – Obj or #dbref to use as an Exit’s -target.

    • +
    • destination (Object or str) – Obj or #dbref to use as an Exit’s target.

    • report_to (Object) – The object to return error messages to.

    • nohome (bool) – This allows the creation of objects without a default home location; only used when creating the default @@ -91,10 +80,8 @@ adding this rarely makes sense since this data will not survive a reload.

      object (Object) – A newly created object of the given typeclass.

    Raises
    -
    +

    ObjectDB.DoesNotExist – If trying to create an Object with +location or home that can’t be found.

    @@ -132,9 +119,8 @@ created or if the start method must be called explicitly.

    report_to (Object) – The object to return error messages to.

  • desc (str) – Optional description of script

  • tags (list) – List of tags or tuples (tag, category).

  • -
  • attributes (list) – List of tuples (key, value), (key, value, category), -(key, value, category, lockstring) or -(key, value, category, lockstring, default_access).

  • +
  • attributes (list) – List if tuples (key, value) or (key, value, category) +(key, value, lockstring) or (key, value, lockstring, default_access).

  • Returns
    @@ -172,21 +158,21 @@ in-game setting information and so on.

    -evennia.utils.create.create_message(senderobj, message, channels=None, receivers=None, locks=None, tags=None, header=None)[source]
    +evennia.utils.create.create_message(senderobj, message, receivers=None, locks=None, tags=None, header=None, **kwargs)[source]

    Create a new communication Msg. Msgs represent a unit of database-persistent communication between entites.

    Parameters
      -
    • senderobj (Object or Account) – The entity sending the Msg.

    • +
    • senderobj (Object, Account, Script, str or list) – The entity (or +entities) sending the Msg. If a str, this is the id-string +for an external sender type.

    • message (str) – Text with the message. Eventual headers, titles etc should all be included in this text string. Formatting will be retained.

    • -
    • channels (Channel, key or list) – A channel or a list of channels to -send to. The channels may be actual channel objects or their -unique key strings.

    • -
    • receivers (Object, Account, str or list) – An Account/Object to send -to, or a list of them. May be Account objects or accountnames.

    • +
    • receivers (Object, Account, Script, str or list) – An Account/Object to send +to, or a list of them. If a string, it’s an identifier for an external +receiver.

    • locks (str) – Lock definition string.

    • tags (list) – A list of tags or tuples (tag, category).

    • header (str) – Mime-type or other optional information for the message

    • @@ -194,10 +180,9 @@ to, or a list of them. May be Account objects or accountnames.

    Notes

    -

    The Comm system is created very open-ended, so it’s fully possible -to let a message both go to several channels and to several -receivers at the same time, it’s up to the command definitions to -limit this as desired.

    +

    The Comm system is created to be very open-ended, so it’s fully +possible to let a message both go several receivers at the same time, +it’s up to the command definitions to limit this as desired.

    @@ -315,7 +300,6 @@ operations and is thus not suitable for play-testing the game.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.utils.dbserialize.html b/docs/0.9.5/api/evennia.utils.dbserialize.html index 5fbade71d1..1d363e0bc4 100644 --- a/docs/0.9.5/api/evennia.utils.dbserialize.html +++ b/docs/0.9.5/api/evennia.utils.dbserialize.html @@ -88,7 +88,7 @@ will save to when they update. It must have a ‘value’ property that saves assigned data to the database. Skip if not serializing onto a given object. If db_obj is given, this function will convert lists, dicts and sets to their -_SaverList, _SaverDict and _SaverSet counterparts.

    +_SaverList, _SaverDict and _SaverSet counterparts.

    Returns
    @@ -166,7 +166,6 @@ function will convert lists, dicts and sets to their
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.utils.eveditor.html b/docs/0.9.5/api/evennia.utils.eveditor.html index 471346e2a7..0fdbb748d1 100644 --- a/docs/0.9.5/api/evennia.utils.eveditor.html +++ b/docs/0.9.5/api/evennia.utils.eveditor.html @@ -40,47 +40,39 @@

    evennia.utils.eveditor

    EvEditor (Evennia Line Editor)

    -

    This implements an advanced line editor for editing longer texts -in-game. The editor mimics the command mechanisms of the “VI” editor -(a famous line-by-line editor) as far as reasonable.

    +

    This implements an advanced line editor for editing longer texts in-game. The +editor mimics the command mechanisms of the “VI” editor (a famous line-by-line +editor) as far as reasonable.

    Features of the editor:

    -
    -
      +
      • undo/redo.

      • edit/replace on any line of the buffer.

      • search&replace text anywhere in buffer.

      • formatting of buffer, or selection, to certain width + indentations.

      • allow to echo the input or not, depending on your client.

      • +
      • in-built help

      -
    -

    To use the editor, just import EvEditor from this module -and initialize it:

    +

    To use the editor, just import EvEditor from this module and initialize it:

    from evennia.utils.eveditor import EvEditor
    -EvEditor(caller, loadfunc=None, savefunc=None, quitfunc=None, key="", persistent=True)
    +
    +# set up an editor to edit the caller's 'desc' Attribute
    +def _loadfunc(caller):
    +    return caller.db.desc
    +
    +def _savefunc(caller, buffer):
    +    caller.db.desc = buffer.strip()
    +    return True
    +
    +def _quitfunc(caller):
    +    caller.msg("Custom quit message")
    +
    +# start the editor
    +EvEditor(caller, loadfunc=None, savefunc=None, quitfunc=None, key="",
    +         persistent=True, code=False)
     
    -
      -
    • caller is the user of the editor, the one to see all feedback.

    • -
    • loadfunc(caller) is called when the editor is first launched; the -return from this function is loaded as the starting buffer in the -editor.

    • -
    • safefunc(caller, buffer) is called with the current buffer when -saving in the editor. The function should return True/False depending -on if the saving was successful or not.

    • -
    • quitfunc(caller) is called when the editor exits. If this is given, -no automatic quit messages will be given.

    • -
    • key is an optional identifier for the editing session, to be -displayed in the editor.

    • -
    • persistent means the editor state will be saved to the database making it -survive a server reload. Note that using this mode, the load- save- -and quit-funcs must all be possible to pickle - notable unusable -callables are class methods and functions defined inside other -functions. With persistent=False, no such restriction exists.

    • -
    • code set to True activates features on the EvEditor to enter Python code.

    • -
    -

    In addition, the EvEditor can be used to enter Python source code, -and offers basic handling of indentation.

    -
    +

    The editor can also be used to format Python code and be made to +survive a reload. See the EvEditor class for more details.

    class evennia.utils.eveditor.CmdSaveYesNo(**kwargs)[source]
    @@ -124,6 +116,11 @@ command was given specifically as “no” or “n”.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '__noinput_command', 'category': 'general', 'key': '__nomatch_command', 'tags': '', 'text': '\n Save the editor state on quit. This catches\n nomatches (defaults to Yes), and avoid saves only if\n command was given specifically as "no" or "n".\n '}
    +
    +
    @@ -182,17 +179,19 @@ command was given specifically as “no” or “n”.

    parse()[source]
    -

    Handles pre-parsing

    -
    -
    Usage:

    :cmd [li] [w] [txt]

    -
    -
    +

    Handles pre-parsing. Editor commands are on the form

    +
    :cmd [li] [w] [txt]
    +
    +

    Where all arguments are optional.

      -
    • li - line number (int), starting from 1. This could also -be a range given as <l>:<l>.

    • -
    • w - word(s) (string), could be encased in quotes.

    • -
    • txt - extra text (string), could be encased in quotes.

    • +
    • +
      li - line number (int), starting from 1. This could also

      be a range given as <l>:<l>.

      +
      +
      +
    • +
    • w - word(s) (string), could be encased in quotes.

    • +
    • txt - extra text (string), could be encased in quotes.

    @@ -216,6 +215,11 @@ be a range given as <l>:<l>.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'command', 'tags': '', 'text': '\n Base parent for editor commands\n '}
    +
    +
    @@ -251,6 +255,11 @@ indentation.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': '__noinput_command', 'category': 'general', 'key': '__nomatch_command', 'tags': '', 'text': '\n No command match - Inputs line of text into buffer.\n\n '}
    +
    +
    @@ -265,7 +274,7 @@ indentation.

    -aliases = [':>', ':uu', ':S', ':A', ':::', ':u', ':', ':j', ':I', ':=', ':p', ':fd', ':dw', ':!', ':echo', ':x', ':dd', ':fi', ':w', ':DD', ':r', '::', ':s', ':q', ':<', ':y', ':f', ':i', ':wq', ':UU', ':q!', ':h']
    +aliases = [':f', ':q!', ':DD', ':UU', ':::', ':fi', ':u', ':i', ':q', ':uu', ':j', ':<', ':=', ':r', ':echo', ':h', ':I', ':dw', ':y', ':s', ':S', ':A', ':x', ':>', ':w', ':fd', ':dd', ':', ':!', ':p', ':wq', '::']
    @@ -291,6 +300,11 @@ efficient presentation.

    lock_storage = 'cmd:all()'
    +
    +
    +search_index_entry = {'aliases': ':f :q! :DD :UU ::: :fi :u :i :q :uu :j :< := :r :echo :h :I :dw :y :s :S :A :x :> :w :fd :dd : :! :p :wq ::', 'category': 'general', 'key': ':editor_command_group', 'tags': '', 'text': '\n Commands for the editor\n '}
    +
    +
    @@ -519,7 +533,6 @@ formatting information.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.utils.evform.html b/docs/0.9.5/api/evennia.utils.evform.html index 24487a3f5d..28d2ca6de9 100644 --- a/docs/0.9.5/api/evennia.utils.evform.html +++ b/docs/0.9.5/api/evennia.utils.evform.html @@ -73,6 +73,7 @@ object when displaying the form.

    | cccccccc | cccccccccccccccccBccccccccccccccccc | | | | ------------------------------------------------- +'''

    The first line of the FORM string is ignored. The forms and table @@ -163,16 +164,16 @@ EvCell or Tables.

    __init__(filename=None, cells=None, tables=None, form=None, **kwargs)[source]
    -

    Initiate the form.

    +

    Initiate the form

    Keyword Arguments
    • filename (str) – Path to template file.

    • -
    • cells (dict) – A dictionary mapping of {id:text}.

    • -
    • tables (dict) – A dictionary mapping of {id:EvTable}.

    • -
    • form (dict) – A dictionary of +

    • cells (dict) – A dictionary mapping {id: text}

    • +
    • tables (dict) – A dictionary mapping {id: EvTable}.

    • +
    • form (dict) – A dictionary {“FORMCHAR”:char, “TABLECHAR”:char, “FORM”:templatestring}. -if this is given, filename is not read.

    • +If this is given, filename is not read.

    @@ -261,7 +262,6 @@ if this is given, filename is not read.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.utils.evmenu.html b/docs/0.9.5/api/evennia.utils.evmenu.html index 7ffff91b58..6147dc3bee 100644 --- a/docs/0.9.5/api/evennia.utils.evmenu.html +++ b/docs/0.9.5/api/evennia.utils.evmenu.html @@ -39,9 +39,10 @@

    evennia.utils.evmenu

    -

    The EvMenu is a full in-game menu system for Evennia.

    -

    To start the menu, just import the EvMenu class from this module.

    -

    Example usage:

    +

    EvMenu

    +

    This implements a full menu system for Evennia.

    +

    To start the menu, just import the EvMenu class from this module. +Example usage:

    from evennia.utils.evmenu import EvMenu
     
     EvMenu(caller, menu_module_path,
    @@ -51,8 +52,8 @@
     

    Where caller is the Object to use the menu on - it will get a new -cmdset while using the Menu. The menu_module_path is the python path -to a python module containing function definitions. By adjusting the +cmdset while using the Menu. The menu_module_path is the python path +to a python module containing function definitions. By adjusting the keyword options of the Menu() initialization call you can start the menu at different places in the menu definition file, adjust if the menu command should overload the normal commands or not, etc.

    @@ -78,7 +79,7 @@ command definition too) with function definitions:

    return text, options -

    Where caller is the object using the menu and input_string is the +

    Where caller is the object using the menu and input_string is the command entered by the user on the previous node (the command entered to get to this node). The node function code will only be executed once per node-visit and the system will accept nodes with @@ -92,50 +93,43 @@ deleted when the menu is exited.

    returned as None as well. If the options are returned as None, the menu is immediately exited and the default “look” command is called.

      -
    • text (str, tuple or None): Text shown at this node. If a tuple, the -second element in the tuple is a help text to display at this -node when the user enters the menu help command there.

    • +
    • +
      text (str, tuple or None): Text shown at this node. If a tuple, the

      second element in the tuple is a help text to display at this +node when the user enters the menu help command there.

      +
      +
      +
    • options (tuple, dict or None): If None, this exits the menu. If a single dict, this is a single-option node. If a tuple, -it should be a tuple of option dictionaries. Option dicts have -the following keys:

      +it should be a tuple of option dictionaries. Option dicts have the following keys:

        -
      • -
        key (str or tuple, optional): What to enter to choose this option.

        If a tuple, it must be a tuple of strings, where the first string is the +

      • key (str or tuple, optional): What to enter to choose this option. +If a tuple, it must be a tuple of strings, where the first string is the key which will be shown to the user and the others are aliases. If unset, the options’ number will be used. The special key _default marks this option as the default fallback when no other option matches the user input. There can only be one _default option per node. It -will not be displayed in the list.

        -
      • -
        -
      • +will not be displayed in the list.

      • desc (str, optional): This describes what choosing the option will do.

      • -
      • -
        goto (str, tuple or callable): If string, should be the name of node to go to

        when this option is selected. If a callable, it has the signature +

      • goto (str, tuple or callable): If string, should be the name of node to go to +when this option is selected. If a callable, it has the signature callable(caller[,raw_input][,**kwargs]). If a tuple, the first element -is the callable and the second is a dict with the kwargs to pass to +is the callable and the second is a dict with the **kwargs to pass to the callable. Those kwargs will also be passed into the next node if possible. Such a callable should return either a str or a (str, dict), where the string is the name of the next node to go to and the dict is the new, (possibly modified) kwarg to pass into the next node. If the callable returns -None or the empty string, the current node will be revisited.

        -
      • -
        -
      • -
      • -
        exec (str, callable or tuple, optional): This takes the same input as goto above

        and runs before it. If given a node name, the node will be executed but will not +None or the empty string, the current node will be revisited.

      • +
      • exec (str, callable or tuple, optional): This takes the same input as goto above +and runs before it. If given a node name, the node will be executed but will not be considered the next node. If node/callback returns str or (str, dict), these will replace the goto step (goto callbacks will not fire), with the string being the next node name and the optional dict acting as the kwargs-input for the next node. -If an exec callable returns None, the current node is re-run.

        -
    -
    - +If an exec callable returns the empty string (only), the current node is re-run.

    -

    If key is not given, the option will automatically be identified by +

    If key is not given, the option will automatically be identified by its number 1..N.

    Example:

    # in menu_module.py
    @@ -189,9 +183,8 @@ same Using help will show the help text, otherwise a list of
     available commands while in menu mode.

    The menu tree is exited either by using the in-menu quit command or by reaching a node without any options.

    -

    For a menu demo, import CmdTestMenu from this module and add it to -your default cmdset. Run it with this module, like testmenu -evennia.utils.evmenu.

    +

    For a menu demo, import CmdTestMenu from this module and add it to +your default cmdset. Run it with this module, like testmenu evennia.utils.evmenu.

    @@ -497,14 +495,12 @@ menu will not be using this same session anymore after a reload.

    persistent
    flag is deactivated.

    +
  • **kwargs – All kwargs will become initialization variables on caller.ndb._menutree, +to be available at run.

  • -
    Keyword Arguments
    -

    any (any) – All kwargs will become initialization variables on caller.ndb._evmenu, -to be available at run.

    -
    -
    Raises
    -

    EvMenuError – If the start/end node is not found in menu tree.

    +
    Raises
    +

    EvMenuError – If the start/end node is not found in menu tree.

    Notes

    @@ -604,11 +600,9 @@ a (“nodename”, kwargs) tuple.

  • raw_string (str) – The raw default string entered on the previous node (only used if the node accepts it as an argument)

  • +
  • **kwargs – Extra arguments to goto callables.

  • -
    Keyword Arguments
    -

    any – Extra arguments to goto callables.

    -
    @@ -753,34 +747,49 @@ prepending those options added in the node.

  • option_generator (callable or list) – A list of strings indicating the options, or a callable that is called as option_generator(caller) to produce such a list.

  • select (callable or str, optional) – Node to redirect a selection to. Its **kwargs will -contain the available_choices list and selection will hold one -of the elements in that list. If a callable, it will be called as -select(caller, menuchoice, **kwargs) where menuchoice is the -chosen option as a string and available_choices is the list of available -options offered by the option_generator. The callable whould return -the name of the target node to goto after this selection (or None to repeat the -list-node). Note that if this is not given, the decorated node -must itself provide a way to continue from the node!

  • +contain the available_choices list and selection will hold one of the elements in +that list. If a callable, it will be called as +select(caller, menuchoice, **kwargs) where menuchoice is the chosen option as a +string and available_choices is a kwarg mapping the option keys to the choices +offered by the option_generator. The callable whould return the name of the target node +to goto after this selection (or None to repeat the list-node). Note that if this is not +given, the decorated node must itself provide a way to continue from the node!

  • pagesize (int) – How many options to show per page.

  • Example

    -
    def _selectfunc(caller, menuchoice, **kwargs):
    -    # menuchoice would be either 'foo' or 'bar' here
    -    # kwargs['available_choices'] would be the list ['foo', 'bar']
    -    return "the_next_node_to_go_to"
    +
    def select(caller, selection, available_choices=None, **kwargs):
    +    '''
    +    Args:
    +        caller (Object or Account): User of the menu.
    +        selection (str): What caller chose in the menu
    +        available_choices (list): The keys of elements available on the *current listing
    +            page*.
    +        **kwargs: Kwargs passed on from the node.
    +    Returns:
    +        tuple, str or None: A tuple (nextnodename, **kwargs) or just nextnodename.  Return
    +            **None** to go back to the listnode.
     
    -@list_node(['foo', 'bar'], _selectfunc)
    -def node_index(caller):
    -    text = "describing the list"
    -    return text, []
    +    # (do something with **selection** here)
    +
    +    return "nextnode", **kwargs
    +
    +@list_node(['foo', 'bar'], select)
    +def node_index(caller):
    +    text = "describing the list"
    +
    +    # optional extra options in addition to the list-options
    +    extra_options = []
    +
    +    return text, extra_options
     

    Notes

    -

    All normal goto or exec callables returned from the decorated nodes will, if they accept -**kwargs, get a new kwarg available_choices injected. This is the ordered list of named -options (descs) visible on the current node page.

    +

    All normal goto or exec callables returned from the decorated nodes +will, if they accept **kwargs, get a new kwarg ‘available_choices’ +injected. These are the ordered list of named options (descs) visible +on the current node page.

    @@ -814,6 +823,11 @@ options (descs) visible on the current node page.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': '__noinput_command', 'category': 'general', 'key': '__nomatch_command', 'tags': '', 'text': '\n Enter your data and press return.\n '}
    +
    +
    @@ -867,44 +881,29 @@ options (descs) visible on the current node page.

    evennia.utils.evmenu.get_input(caller, prompt, callback, session=None, *args, **kwargs)[source]
    -

    This is a helper function for easily request input from -the caller.

    +

    This is a helper function for easily request input from the caller.

    Parameters
      -
    • caller (Account or Object) – The entity being asked -the question. This should usually be an object -controlled by a user.

    • -
    • prompt (str) – This text will be shown to the user, -in order to let them know their input is needed.

    • +
    • caller (Account or Object) – The entity being asked the question. This +should usually be an object controlled by a user.

    • +
    • prompt (str) – This text will be shown to the user, in order to let them +know their input is needed.

    • callback (callable) – A function that will be called -when the user enters a reply. It must take three -arguments: the caller, the prompt text and the -result of the input given by the user. If the -callback doesn’t return anything or return False, -the input prompt will be cleaned up and exited. If -returning True, the prompt will remain and continue to -accept input.

    • +when the user enters a reply. It must take three arguments: the +caller, the prompt text and the result of the input given by +the user. If the callback doesn’t return anything or return False, +the input prompt will be cleaned up and exited. If returning True, +the prompt will remain and continue to accept input.

    • session (Session, optional) – This allows to specify the -session to send the prompt to. It’s usually only -needed if caller is an Account in multisession modes -greater than 2. The session is then updated by the -command and is available (for example in callbacks) -through caller.ndb.getinput._session.

    • -
    • args (optional) – Extra arguments will be -passed to the fall back function as a list ‘args’ -and all keyword arguments as a dictionary ‘kwargs’. -To utilise *args and **kwargs, a value for the -session argument must be provided (None by default) -and the callback function must take *args and -**kwargs as arguments.

    • -
    • kwargs (optional) – Extra arguments will be -passed to the fall back function as a list ‘args’ -and all keyword arguments as a dictionary ‘kwargs’. -To utilise *args and **kwargs, a value for the -session argument must be provided (None by default) -and the callback function must take *args and -**kwargs as arguments.

    • +session to send the prompt to. It’s usually only needed if caller +is an Account in multisession modes greater than 2. The session is +then updated by the command and is available (for example in +callbacks) through caller.ndb.getinput._session.

      +
    • *args (any) – Extra arguments to pass to callback. To utilise *args +(and **kwargs), a value for the session argument must also be +provided.

    • +
    • **kwargs (any) – Extra kwargs to pass to callback.

    Raises
    @@ -912,23 +911,160 @@ and the callback function must take *args and

    Notes

    -

    The result value sent to the callback is raw and not -processed in any way. This means that you will get -the ending line return character from most types of -client inputs. So make sure to strip that before -doing a comparison.

    -

    When the prompt is running, a temporary object -caller.ndb._getinput is stored; this will be removed -when the prompt finishes. -If you need the specific Session of the caller (which -may not be easy to get if caller is an account in higher -multisession modes), then it is available in the -callback through caller.ndb._getinput._session.

    -

    Chaining get_input functions will result in the caller -stacking ever more instances of InputCmdSets. Whilst -they will all be cleared on concluding the get_input -chain, EvMenu should be considered for anything beyond -a single question.

    +

    The result value sent to the callback is raw and not processed in any +way. This means that you will get the ending line return character from +most types of client inputs. So make sure to strip that before doing a +comparison.

    +

    When the prompt is running, a temporary object caller.ndb._getinput +is stored; this will be removed when the prompt finishes.

    +

    If you need the specific Session of the caller (which may not be easy +to get if caller is an account in higher multisession modes), then it +is available in the callback through caller.ndb._getinput._session. +This is why the session is required as input.

    +

    It’s not recommended to ‘chain’ get_input into a sequence of +questions. This will result in the caller stacking ever more instances +of InputCmdSets. While they will all be cleared on concluding the +get_input chain, EvMenu should be considered for anything beyond a +single question.

    +
    + +
    +
    +class evennia.utils.evmenu.CmdYesNoQuestion(**kwargs)[source]
    +

    Bases: evennia.commands.command.Command

    +

    Handle a prompt for yes or no. Press [return] for the default choice.

    +
    +
    +key = '__noinput_command'
    +
    + +
    +
    +aliases = ['a', 'y', 'yes', '__nomatch_command', 'abort', 'no', 'n']
    +
    + +
    +
    +arg_regex = re.compile('^$', re.IGNORECASE)
    +
    + +
    +
    +func()[source]
    +

    This is called when user enters anything.

    +
    + +
    +
    +help_category = 'general'
    +
    + +
    +
    +lock_storage = 'cmd:all();'
    +
    + +
    +
    +search_index_entry = {'aliases': 'a y yes __nomatch_command abort no n', 'category': 'general', 'key': '__noinput_command', 'tags': '', 'text': '\n Handle a prompt for yes or no. Press [return] for the default choice.\n\n '}
    +
    + +
    + +
    +
    +class evennia.utils.evmenu.YesNoQuestionCmdSet(cmdsetobj=None, key=None)[source]
    +

    Bases: evennia.commands.cmdset.CmdSet

    +

    This stores the input command

    +
    +
    +key = 'yes_no_question_cmdset'
    +
    + +
    +
    +priority = 1
    +
    + +
    +
    +mergetype = 'Replace'
    +
    + +
    +
    +no_objs = True
    +
    + +
    +
    +no_exits = True
    +
    + +
    +
    +no_channels = False
    +
    + +
    +
    +at_cmdset_creation()[source]
    +

    called once at creation

    +
    + +
    +
    +path = 'evennia.utils.evmenu.YesNoQuestionCmdSet'
    +
    + +
    + +
    +
    +evennia.utils.evmenu.ask_yes_no(caller, prompt='Yes or No {options}?', yes_action='Yes', no_action='No', default=None, allow_abort=False, session=None, *args, **kwargs)[source]
    +

    A helper question for asking a simple yes/no question. This will cause +the system to pause and wait for input from the player.

    +
    +
    Parameters
    +
      +
    • prompt (str) – The yes/no question to ask. This takes an optional formatting +marker {options} which will be filled with ‘Y/N’, ‘[Y]/N’ or +‘Y/[N]’ depending on the setting of default. If allow_abort is set, +then the ‘A(bort)’ option will also be available.

    • +
    • yes_action (callable or str) – If a callable, this will be called +with (caller, *args, **kwargs) when the Yes-choice is made. +If a string, this string will be echoed back to the caller.

    • +
    • no_action (callable or str) – If a callable, this will be called +with (caller, *args, **kwargs) when the No-choice is made. +If a string, this string will be echoed back to the caller.

    • +
    • default (str optional) – This is what the user will get if they just press the +return key without giving any input. One of ‘N’, ‘Y’, ‘A’ or None +for no default (an explicit choice must be given). If ‘A’ (abort) +is given, allow_abort kwarg is ignored and assumed set.

    • +
    • allow_abort (bool, optional) – If set, the ‘A(bort)’ option is available +(a third option meaning neither yes or no but just exits the prompt).

    • +
    • session (Session, optional) – This allows to specify the +session to send the prompt to. It’s usually only needed if caller +is an Account in multisession modes greater than 2. The session is +then updated by the command and is available (for example in +callbacks) through caller.ndb._yes_no_question.session.

    • +
    • *args – Additional arguments passed on into callables.

    • +
    • **kwargs – Additional keyword args passed on into callables.

    • +
    +
    +
    Raises
    +

    RuntimeError, FooError – If default and allow_abort clashes.

    +
    +
    +

    Example

    +
    # just returning strings
    +ask_yes_no(caller, "Are you happy {options}?",
    +           "you answered yes", "you answered no")
    +# trigger callables
    +ask_yes_no(caller, "Are you sad {options}?",
    +           _callable_yes, _callable_no, allow_abort=True)
    +
    +
    @@ -1032,7 +1168,6 @@ Must be on the form callable(caller, raw_string, **kwargs).

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.utils.evmore.html b/docs/0.9.5/api/evennia.utils.evmore.html index e5c8662aa9..cb262bb176 100644 --- a/docs/0.9.5/api/evennia.utils.evmore.html +++ b/docs/0.9.5/api/evennia.utils.evmore.html @@ -40,9 +40,8 @@

    evennia.utils.evmore

    EvMore - pager mechanism

    -

    This is a pager for displaying long texts and allows stepping up and -down in the text (the name comes from the traditional ‘more’ unix -command).

    +

    This is a pager for displaying long texts and allows stepping up and down in +the text (the name comes from the traditional ‘more’ unix command).

    To use, simply pass the text through the EvMore object:

    from evennia.utils.evmore import EvMore
     
    @@ -50,16 +49,17 @@ command).

    EvMore(caller, text, always_page=False, session=None, justify_kwargs=None, **kwargs)
    -

    One can also use the convenience function msg from this module:

    +

    One can also use the convenience function msg from this module to avoid +having to set up the EvMenu object manually:

    from evennia.utils import evmore
     
     text = some_long_text_output()
     evmore.msg(caller, text, always_page=False, session=None, justify_kwargs=None, **kwargs)
     
    -

    Where always_page decides if the pager is used also if the text is not long -enough to need to scroll, session is used to determine which session to relay -to and justify_kwargs are kwargs to pass to utils.utils.justify in order to +

    The always_page argument decides if the pager is used also if the text is not long +enough to need to scroll, session is used to determine which session to relay +to and justify_kwargs are kwargs to pass to utils.utils.justify in order to change the formatting of the text. The remaining **kwargs will be passed on to the caller.msg() construct every time the page is updated.


    @@ -75,7 +75,7 @@ the caller.msg() construct every time the page is updated.

    -aliases = ['back', 'e', 'a', 'n', 'q', 'b', 'top', 'abort', 't', 'quit', 'next', 'end']
    +aliases = ['a', 'end', 'b', 'e', 'next', 'quit', 'top', 't', 'q', 'abort', 'n', 'back']
    @@ -99,6 +99,11 @@ the caller.msg() construct every time the page is updated.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': 'a end b e next quit top t q abort n back', 'category': 'general', 'key': '__noinput_command', 'tags': '', 'text': '\n Manipulate the text paging\n '}
    +
    +
    @@ -137,6 +142,11 @@ the caller.msg() construct every time the page is updated.

    lock_storage = 'cmd:all();'
    +
    +
    +search_index_entry = {'aliases': 'l', 'category': 'general', 'key': 'look', 'tags': '', 'text': '\n Override look to display window and prevent OOCLook from firing\n '}
    +
    +
    @@ -178,11 +188,11 @@ self.add().

    class evennia.utils.evmore.EvMore(caller, inp, always_page=False, session=None, justify=False, justify_kwargs=None, exit_on_lastpage=False, exit_cmd=None, page_formatter=<class 'str'>, **kwargs)[source]

    Bases: object

    -

    The main pager object.

    +

    The main pager object

    __init__(caller, inp, always_page=False, session=None, justify=False, justify_kwargs=None, exit_on_lastpage=False, exit_cmd=None, page_formatter=<class 'str'>, **kwargs)[source]
    -

    Initialization of the Evmore input handler.

    +

    Initialization of the EvMore pager.

    Parameters
      @@ -190,9 +200,8 @@ self.add().

    • inp (str, EvTable, Paginator or iterator) –

      The text or data to put under paging.

      • If a string, paginage normally. If this text contains -one or more \f (backslash + f) format symbols, automatic -pagination and justification are force-disabled and -page-breaks will only happen after each \f.

      • +one or more \f format symbol, automatic pagination and justification +are force-disabled and page-breaks will only happen after each \f.

      • If EvTable, the EvTable will be paginated with the same setting on each page if it is too long. The table decorations will be considered in the size of the page.

      • @@ -201,8 +210,9 @@ expected to be a line in the final display. Each line will be run through iter_callable.

    • -
    • always_page (bool, optional) – If False, the pager will only kick -in if inp is too big to fit the screen.

    • +
    • always_page (bool, optional) – If False, the +pager will only kick in if inp is too big +to fit the screen.

    • session (Session, optional) – If given, this session will be used to determine the screen width and will receive all output.

    • justify (bool, optional) – If set, auto-justify long lines. This must be turned @@ -218,48 +228,28 @@ exit message will not be shown.

    • the caller when the more page exits. Note that this will be using whatever cmdset the user had before the evmore pager was activated (so none of the evmore commands will be available when this is run).

      -
    • kwargs (any, any) – These will be passed on to the caller.msg method.

    • +
    • kwargs (any, optional) – These will be passed on to the caller.msg method.

    Examples

    -

    Basic use:

    super_long_text = " ... "
     EvMore(caller, super_long_text)
     
    -

    Paginated query data - this is an optimization to avoid fetching -database data until it’s actually paged to.

    +

    Paginator

    from django.core.paginator import Paginator
    -
     query = ObjectDB.objects.all()
     pages = Paginator(query, 10)  # 10 objs per page
     EvMore(caller, pages)
     
    -

    Automatic split EvTable over multiple EvMore pages

    -
    table = EvMore(*header, table=tabledata)
    -EvMore(caller, table)
    -
    -
    -

    Every page a separate EvTable (optimization for very large data sets)

    -
    from evennia import EvTable, EvMore
    -
    -class TableEvMore(EvMore):
    -    def init_pages(self, data):
    -        pages = # depends on data type
    -        super().init_pages(pages)
    -
    -    def page_formatter(self, page):
    -        table = EvTable()
    -
    -        for line in page:
    -            cols = # split raw line into columns
    -            table.add_row(*cols)
    -
    -        return str(table)
    -
    -TableEvMore(caller, pages)
    +

    Every page an EvTable

    +
    from evennia import EvTable
    +def _to_evtable(page):
    +    table = ... # convert page to a table
    +    return EvTable(*headers, table=table, ...)
    +EvMore(caller, pages, page_formatter=_to_evtable)
     
    @@ -353,9 +343,14 @@ querysets); to avoid fetching all objects at the same time.

    init_f_str(text)[source]
    -

    The input contains \f (backslash + f) markers. We use \f to indicate -the user wants to enforce their line breaks on their own. If so, we do -no automatic line-breaking/justification at all.

    +

    The input contains f markers. We use f to indicate the user wants to +enforce their line breaks on their own. If so, we do no automatic +line-breaking/justification at all.

    +
    +
    Parameters
    +

    text (str) – The string to format with f-markers.

    +
    +
    @@ -378,16 +373,15 @@ strings, querysets, django.Paginator, EvTables and any iterables with strings.Notes

    If overridden, this method must perform the following actions:

      -
    • read and re-store self._data (the incoming data set) if needed -for pagination to work.

    • +
    • read and re-store self._data (the incoming data set) if needed for pagination to +work.

    • set self._npages to the total number of pages. Default is 1.

    • set self._paginator to a callable that will take a page number 1…N and return the data to display on that page (not any decorations or next/prev buttons). If only wanting to change the paginator, override self.paginator instead.

    • -
    • set self._page_formatter to a callable that will receive the -page from self._paginator and format it with one element per -line. Default is str. Or override self.page_formatter -directly instead.

    • +
    • set self._page_formatter to a callable that will receive the page from +self._paginator and format it with one element per line. Default is str. Or +override self.page_formatter directly instead.

    By default, helper methods are called that perform these actions depending on supported inputs.

    @@ -439,46 +433,69 @@ EvTable across many pages and feed it into EvMore all at once).

    evennia.utils.evmore.msg(caller, text='', always_page=False, session=None, justify=False, justify_kwargs=None, exit_on_lastpage=True, **kwargs)[source]
    -

    EvMore-supported version of msg, mimicking the normal msg method.

    +
    +

    EvMore-supported version of msg, mimicking the normal msg method.

    +
    +

    Initialization of the EvMore pager.

    Parameters
    • caller (Object or Account) – Entity reading the text.

    • -
    • text (str, EvTable or iterator) –

      The text or data to put under paging.

      +
    • inp (str, EvTable, Paginator or iterator) –

      The text or data to put under paging.

      • If a string, paginage normally. If this text contains -one or more \f (backslash + f) format symbol, automatic pagination is disabled -and page-breaks will only happen after each \f.

      • +one or more \f format symbol, automatic pagination and justification +are force-disabled and page-breaks will only happen after each \f.

      • If EvTable, the EvTable will be paginated with the same setting on each page if it is too long. The table decorations will be considered in the size of the page.

      • -
      • Otherwise text is converted to an iterator, where each step is -is expected to be a line in the final display, and each line -will be run through repr().

      • +
      • Otherwise inp is converted to an iterator, where each step is +expected to be a line in the final display. Each line +will be run through iter_callable.

    • always_page (bool, optional) – If False, the -pager will only kick in if text is too big +pager will only kick in if inp is too big to fit the screen.

    • session (Session, optional) – If given, this session will be used to determine the screen width and will receive all output.

    • -
    • justify (bool, optional) – If set, justify long lines in output. Disable for -fixed-format output, like tables.

    • -
    • justify_kwargs (dict, bool or None, optional) – If given, this should -be valid keyword arguments to the utils.justify() function. If False, -no justification will be done.

    • -
    • exit_on_lastpage (bool, optional) – Immediately exit pager when reaching the last page.

    • -
    • use_evtable (bool, optional) – If True, each page will be rendered as an -EvTable. For this to work, text must be an iterable, where each element -is the table (list of list) to render on that page.

    • -
    • evtable_args (tuple, optional) – The args to use for EvTable on each page.

    • -
    • evtable_kwargs (dict, optional) – The kwargs to use for EvTable on each -page (except table, which is supplied by EvMore per-page).

    • -
    • kwargs (any, optional) – These will be passed on -to the caller.msg method.

    • +
    • justify (bool, optional) – If set, auto-justify long lines. This must be turned +off for fixed-width or formatted output, like tables. It’s force-disabled +if inp is an EvTable.

    • +
    • justify_kwargs (dict, optional) – Keywords for the justifiy function. Used only +if justify is True. If this is not set, default arguments will be used.

    • +
    • exit_on_lastpage (bool, optional) – If reaching the last page without the +page being completely filled, exit pager immediately. If unset, +another move forward is required to exit. If set, the pager +exit message will not be shown.

    • +
    • exit_cmd (str, optional) – If given, this command-string will be executed on +the caller when the more page exits. Note that this will be using whatever +cmdset the user had before the evmore pager was activated (so none of +the evmore commands will be available when this is run).

    • +
    • kwargs (any, optional) – These will be passed on to the caller.msg method.

    +

    Examples

    +
    super_long_text = " ... "
    +EvMore(caller, super_long_text)
    +
    +
    +

    Paginator

    +
    from django.core.paginator import Paginator
    +query = ObjectDB.objects.all()
    +pages = Paginator(query, 10)  # 10 objs per page
    +EvMore(caller, pages)
    +
    +
    +

    Every page an EvTable

    +
    from evennia import EvTable
    +def _to_evtable(page):
    +    table = ... # convert page to a table
    +    return EvTable(*headers, table=table, ...)
    +EvMore(caller, pages, page_formatter=_to_evtable)
    +
    +
    @@ -526,7 +543,6 @@ to the caller.msg method.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.utils.evtable.html b/docs/0.9.5/api/evennia.utils.evtable.html index ee42d59080..d947833206 100644 --- a/docs/0.9.5/api/evennia.utils.evtable.html +++ b/docs/0.9.5/api/evennia.utils.evtable.html @@ -39,13 +39,15 @@

    evennia.utils.evtable

    -

    This is an advanced ASCII table creator. It was inspired by -[prettytable](https://code.google.com/p/prettytable/) but shares no code.

    +

    This is an advanced ASCII table creator. It was inspired by Prettytable +(https://code.google.com/p/prettytable/) but shares no code and is considerably +more advanced, supporting auto-balancing of incomplete tables and ANSI colors among +other things.

    Example usage:

    from evennia.utils import evtable
     
     table = evtable.EvTable("Heading1", "Heading2",
    -              table=[[1,2,3],[4,5,6],[7,8,9]], border="cells")
    +                table=[[1,2,3],[4,5,6],[7,8,9]], border="cells")
     table.add_column("This is long data", "This is even longer data")
     table.add_row("This is a single row")
     print table
    @@ -99,8 +101,9 @@ Here we change the width and alignment of the column at index 3
     (Python starts from 0):

    table.reformat_column(3, width=30, align="r")
     print table
    -
    -+-----------+-------+-----+-----------------------------+---------+
    +
    +
    +
    +-----------+-------+-----+-----------------------------+---------+
     | Heading1  | Headi |     |                             |         |
     |           | ng2   |     |                             |         |
     +~~~~~~~~~~~+~~~~~~~+~~~~~+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+~~~~~~~~~+
    @@ -121,14 +124,13 @@ Here we change the width and alignment of the column at index 3
     

    If the height is restricted, cells will be restricted from expanding vertically. This will lead to text contents being cropped. Each cell can only shrink to a minimum width and height of 1.

    -

    EvTable is intended to be used with [ANSIString](evennia.utils.ansi#ansistring) -for supporting ANSI-coloured string types.

    -

    When a cell is auto-wrapped across multiple lines, ANSI-reset -sequences will be put at the end of each wrapped line. This means that -the colour of a wrapped cell will not “bleed”, but it also means that -eventual colour outside the table will not transfer “across” a table, -you need to re-set the color to have it appear on both sides of the -table string.

    +

    EvTable is intended to be used with ANSIString for supporting ANSI-coloured +string types.

    +

    When a cell is auto-wrapped across multiple lines, ANSI-reset sequences will be +put at the end of each wrapped line. This means that the colour of a wrapped +cell will not “bleed”, but it also means that eventual colour outside the table +will not transfer “across” a table, you need to re-set the color to have it +appear on both sides of the table string.


    @@ -476,8 +478,9 @@ resize individual columns in the vertical direction to fit.

  • height (int, optional) – Fixed height of table. Defaults to being unset. Width is still given precedence. If given, table cells will crop text rather than expand vertically.

  • -
  • evenwidth (bool, optional) – Used with the width keyword. Adjusts columns to have as even width as -possible. This often looks best also for mixed-length tables. Default is False.

  • +
  • evenwidth (bool, optional) – Used with the width keyword. Adjusts columns to have as +even width as possible. This often looks best also for mixed-length tables. Default +is False.

  • maxwidth (int, optional) – This will set a maximum width of the table while allowing it to be smaller. Only if it grows wider than this size will it be resized by expanding horizontally (or crop height is given). @@ -649,7 +652,6 @@ given from 0 to Ncolumns-1.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.utils.gametime.html b/docs/0.9.5/api/evennia.utils.gametime.html index 8afffd3831..05f65473df 100644 --- a/docs/0.9.5/api/evennia.utils.gametime.html +++ b/docs/0.9.5/api/evennia.utils.gametime.html @@ -273,7 +273,6 @@ the epoch set by settings.TIME_GAME_EPOCH will still apply.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.utils.html b/docs/0.9.5/api/evennia.utils.html index da63a13b84..b7d95c41af 100644 --- a/docs/0.9.5/api/evennia.utils.html +++ b/docs/0.9.5/api/evennia.utils.html @@ -44,10 +44,19 @@ modules in Evennia. It also holds the idmapper in-memory caching functionality.

    diff --git a/docs/0.9.5/api/evennia.utils.idmapper.html b/docs/0.9.5/api/evennia.utils.idmapper.html index e31c9af79f..528a1df60d 100644 --- a/docs/0.9.5/api/evennia.utils.idmapper.html +++ b/docs/0.9.5/api/evennia.utils.idmapper.html @@ -92,7 +92,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.utils.idmapper.manager.html b/docs/0.9.5/api/evennia.utils.idmapper.manager.html index d26026d555..f6ebb06895 100644 --- a/docs/0.9.5/api/evennia.utils.idmapper.manager.html +++ b/docs/0.9.5/api/evennia.utils.idmapper.manager.html @@ -97,7 +97,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.utils.idmapper.models.html b/docs/0.9.5/api/evennia.utils.idmapper.models.html index 21a5c2392b..c5ec664839 100644 --- a/docs/0.9.5/api/evennia.utils.idmapper.models.html +++ b/docs/0.9.5/api/evennia.utils.idmapper.models.html @@ -309,7 +309,6 @@ catch in an easy way here. Ideas are appreciated. /Griatch

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.utils.idmapper.tests.html b/docs/0.9.5/api/evennia.utils.idmapper.tests.html index ce2da73681..2d5fd8904a 100644 --- a/docs/0.9.5/api/evennia.utils.idmapper.tests.html +++ b/docs/0.9.5/api/evennia.utils.idmapper.tests.html @@ -406,7 +406,6 @@ object the first time, the query is executed.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.utils.inlinefuncs.html b/docs/0.9.5/api/evennia.utils.inlinefuncs.html index a18603368c..27c8c5f649 100644 --- a/docs/0.9.5/api/evennia.utils.inlinefuncs.html +++ b/docs/0.9.5/api/evennia.utils.inlinefuncs.html @@ -37,299 +37,8 @@
    -
    -

    evennia.utils.inlinefuncs

    -

    Inline functions (nested form).

    -

    This parser accepts nested inlinefunctions on the form

    -
    $funcname(arg, arg, ...)
    -
    -
    -

    embedded in any text where any arg can be another $funcname{} call. -This functionality is turned off by default - to activate, -settings.INLINEFUNC_ENABLED must be set to True.

    -

    Each token starts with $funcname( where there must be no space between the -$funcname and “(”. It ends with a matched ending parentesis “)”.

    -

    Inside the inlinefunc definition, one can use \ to escape. This is -mainly needed for escaping commas in flowing text (which would -otherwise be interpreted as an argument separator), or to escape } -when not intended to close the function block. Enclosing text in -matched “”” (triple quotes) or ‘’’ (triple single-quotes) will -also escape everything within without needing to escape individual -characters.

    -

    The available inlinefuncs are defined as global-level functions in -modules defined by settings.INLINEFUNC_MODULES. They are identified -by their function name (and ignored if this name starts with _). They -should be on the following form:

    -
    def funcname (*args, **kwargs):
    -# ...
    -
    -
    -

    Here, the arguments given to $funcname(arg1,arg2) will appear as the -*args tuple. This will be populated by the arguments given to the -inlinefunc in-game - the only part that will be available from -in-game. **kwargs are not supported from in-game but are only used -internally by Evennia to make details about the caller available to -the function. The kwarg passed to all functions is session, the -Sessionobject for the object seeing the string. This may be None if -the string is sent to a non-puppetable object. The inlinefunc should -never raise an exception.

    -

    There are two reserved function names:

    -
      -
    • “nomatch”: This is called if the user uses a functionname that is -not registered. The nomatch function will get the name of the -not-found function as its first argument followed by the normal -arguments to the given function. If not defined the default effect is -to print <UNKNOWN> to replace the unknown function.

    • -
    • “stackfull”: This is called when the maximum nested function stack is reached. -When this happens, the original parsed string is returned and the result of -the stackfull inlinefunc is appended to the end. By default this is an -error message.

    • -
    -

    Syntax errors, notably not completely closing all inlinefunc blocks, will lead -to the entire string remaining unparsed.

    -
    -
    -
    -evennia.utils.inlinefuncs.random(*args, **kwargs)[source]
    -

    Inlinefunc. Returns a random number between -0 and 1, from 0 to a maximum value, or within a given range (inclusive).

    -
    -
    Parameters
    -
      -
    • minval (str, optional) – Minimum value. If not given, assumed 0.

    • -
    • maxval (str, optional) – Maximum value.

    • -
    -
    -
    -
    -
    Keyword argumuents:

    session (Session): Session getting the string.

    -
    -
    -

    Notes

    -

    If either of the min/maxvalue has a ‘.’ in it, a floating-point random -value will be returned. Otherwise it will be an integer value in the -given range.

    -

    Example

    -
      -
    • $random()

    • -
    • $random(5)

    • -
    • $random(5, 10)

    • -
    -
    - -
    -
    -evennia.utils.inlinefuncs.pad(*args, **kwargs)[source]
    -

    Inlinefunc. Pads text to given width.

    -
    -
    Parameters
    -
      -
    • text (str, optional) – Text to pad.

    • -
    • width (str, optional) – Will be converted to integer. Width -of padding.

    • -
    • align (str, optional) – Alignment of padding; one of ‘c’, ‘l’ or ‘r’.

    • -
    • fillchar (str, optional) – Character used for padding. Defaults to a -space.

    • -
    -
    -
    Keyword Arguments
    -

    session (Session) – Session performing the pad.

    -
    -
    -

    Example

    -

    $pad(text, width, align, fillchar)

    -
    - -
    -
    -evennia.utils.inlinefuncs.crop(*args, **kwargs)[source]
    -

    Inlinefunc. Crops ingoing text to given widths.

    -
    -
    Parameters
    -
      -
    • text (str, optional) – Text to crop.

    • -
    • width (str, optional) – Will be converted to an integer. Width of -crop in characters.

    • -
    • suffix (str, optional) – End string to mark the fact that a part -of the string was cropped. Defaults to […].

    • -
    -
    -
    Keyword Arguments
    -

    session (Session) – Session performing the crop.

    -
    -
    -

    Example

    -

    $crop(text, width=78, suffix=’[…]’)

    -
    - -
    -
    -evennia.utils.inlinefuncs.space(*args, **kwargs)[source]
    -

    Inlinefunc. Inserts an arbitrary number of spaces. Defaults to 4 spaces.

    -
    -
    Parameters
    -

    spaces (int, optional) – The number of spaces to insert.

    -
    -
    Keyword Arguments
    -

    session (Session) – Session performing the crop.

    -
    -
    -

    Example

    -

    $space(20)

    -
    - -
    -
    -evennia.utils.inlinefuncs.clr(*args, **kwargs)[source]
    -

    Inlinefunc. Colorizes nested text.

    -
    -
    Parameters
    -
      -
    • startclr (str, optional) – An ANSI color abbreviation without the -prefix |, such as r (red foreground) or [r (red background).

    • -
    • text (str, optional) – Text

    • -
    • endclr (str, optional) – The color to use at the end of the string. Defaults -to |n (reset-color).

    • -
    -
    -
    Keyword Arguments
    -

    session (Session) – Session object triggering inlinefunc.

    -
    -
    -

    Example

    -

    $clr(startclr, text, endclr)

    -
    - -
    -
    -evennia.utils.inlinefuncs.null(*args, **kwargs)[source]
    -
    - -
    -
    -evennia.utils.inlinefuncs.nomatch(name, *args, **kwargs)[source]
    -

    Default implementation of nomatch returns the function as-is as a string.

    -
    - -
    -
    -class evennia.utils.inlinefuncs.ParseStack(*args, **kwargs)[source]
    -

    Bases: list

    -

    Custom stack that always concatenates strings together when the -strings are added next to one another. Tuples are stored -separately and None is used to mark that a string should be broken -up into a new chunk. Below is the resulting stack after separately -appending 3 strings, None, 2 strings, a tuple and finally 2 -strings:

    -

    [string + string + string, -None -string + string, -tuple, -string + string]

    -
    -
    -__init__(*args, **kwargs)[source]
    -

    Initialize self. See help(type(self)) for accurate signature.

    -
    - -
    -
    -append(item)[source]
    -

    The stack will merge strings, add other things as normal

    -
    - -
    - -
    -
    -exception evennia.utils.inlinefuncs.InlinefuncError[source]
    -

    Bases: RuntimeError

    -
    - -
    -
    -evennia.utils.inlinefuncs.parse_inlinefunc(string, strip=False, available_funcs=None, stacktrace=False, **kwargs)[source]
    -

    Parse the incoming string.

    -
    -
    Parameters
    -
      -
    • string (str) – The incoming string to parse.

    • -
    • strip (bool, optional) – Whether to strip function calls rather than -execute them.

    • -
    • available_funcs (dict, optional) – Define an alternative source of functions to parse for. -If unset, use the functions found through settings.INLINEFUNC_MODULES.

    • -
    • stacktrace (bool, optional) – If set, print the stacktrace to log.

    • -
    -
    -
    Keyword Arguments
    -
      -
    • session (Session) – This is sent to this function by Evennia when triggering -it. It is passed to the inlinefunc.

    • -
    • kwargs (any) – All other kwargs are also passed on to the inlinefunc.

    • -
    -
    -
    -
    - -
    -
    -evennia.utils.inlinefuncs.raw(string)[source]
    -

    Escape all inlinefuncs in a string so they won’t get parsed.

    -
    -
    Parameters
    -

    string (str) – String with inlinefuncs to escape.

    -
    -
    -
    - -
    -
    -exception evennia.utils.inlinefuncs.NickTemplateInvalid[source]
    -

    Bases: ValueError

    -
    - -
    -
    -evennia.utils.inlinefuncs.initialize_nick_templates(in_template, out_template)[source]
    -

    Initialize the nick templates for matching and remapping a string.

    -
    -
    Parameters
    -
      -
    • in_template (str) – The template to be used for nick recognition.

    • -
    • out_template (str) – The template to be used to replace the string -matched by the in_template.

    • -
    -
    -
    Returns
    -

    regex, template (regex, str) – Regex to match against strings and a -template with markers {arg1}, {arg2}, etc for replacement using the -standard .format method.

    -
    -
    Raises
    -

    inlinefuncs.NickTemplateInvalid – If the in/out template does not have a matching -number of $args.

    -
    -
    -
    - -
    -
    -evennia.utils.inlinefuncs.parse_nick_template(string, template_regex, outtemplate)[source]
    -

    Parse a text using a template and map it to another template

    -
    -
    Parameters
    -
      -
    • string (str) – The input string to processj

    • -
    • template_regex (regex) – A template regex created with -initialize_nick_template.

    • -
    • outtemplate (str) – The template to which to map the matches -produced by the template_regex. This should have $1, $2, -etc to match the regex.

    • -
    -
    -
    -
    - +
    +

    evennia.utils.inlinefuncs

    @@ -375,7 +84,6 @@ etc to match the regex.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.utils.logger.html b/docs/0.9.5/api/evennia.utils.logger.html index 79a9df4a9d..b692ed8dd4 100644 --- a/docs/0.9.5/api/evennia.utils.logger.html +++ b/docs/0.9.5/api/evennia.utils.logger.html @@ -319,7 +319,7 @@ to preserve a continuous chat history for channel log files.

    -rotate()[source]
    +rotate(num_lines_to_append=None)[source]

    Rotates our log file and appends some number of lines from the previous log to the start of the new one.

    @@ -328,21 +328,31 @@ the previous log to the start of the new one.

    seek(*args, **kwargs)[source]

    Convenience method for accessing our _file attribute’s seek method, -which is used in tail_log_function. -:param *args: Same args as file.seek -:param **kwargs: Same kwargs as file.seek

    +which is used in tail_log_function.

    +
    +
    Parameters
    +
      +
    • *args – Same args as file.seek

    • +
    • **kwargs – Same kwargs as file.seek

    • +
    +
    +
    readlines(*args, **kwargs)[source]

    Convenience method for accessing our _file attribute’s readlines method, -which is used in tail_log_function. -:param *args: same args as file.readlines -:param **kwargs: same kwargs as file.readlines

    +which is used in tail_log_function.

    -
    Returns
    -

    lines (list) – lines from our _file attribute.

    +
    Parameters
    +
      +
    • *args – same args as file.readlines

    • +
    • **kwargs – same kwargs as file.readlines

    • +
    +
    +
    Returns
    +

    lines (list) – lines from our _file attribute.

    @@ -365,6 +375,36 @@ on new lines following datetime info.

    +
    +
    +evennia.utils.logger.log_file_exists(filename='game.log')[source]
    +

    Determine if a log-file already exists.

    +
    +
    Parameters
    +

    filename (str) – The filename (within the log-dir).

    +
    +
    Returns
    +

    bool – If the log file exists or not.

    +
    +
    +
    + +
    +
    +evennia.utils.logger.rotate_log_file(filename='game.log', num_lines_to_append=None)[source]
    +

    Force-rotate a log-file, without

    +
    +
    Parameters
    +
      +
    • filename (str) – The log file, located in settings.LOG_DIR.

    • +
    • num_lines_to_append (int, optional) – Include N number of +lines from previous file in new one. If None, use default. +Set to 0 to include no lines.

    • +
    +
    +
    +
    +
    evennia.utils.logger.tail_log_file(filename, offset, nlines, callback=None)[source]
    @@ -440,7 +480,6 @@ all if the file is shorter than nlines.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.utils.optionclasses.html b/docs/0.9.5/api/evennia.utils.optionclasses.html index dd9fc11806..1eb996d32e 100644 --- a/docs/0.9.5/api/evennia.utils.optionclasses.html +++ b/docs/0.9.5/api/evennia.utils.optionclasses.html @@ -39,8 +39,6 @@

    evennia.utils.optionclasses

    -

    Option classes store user- or server Options in a generic way -while also providing validation.

    class evennia.utils.optionclasses.BaseOption(handler, key, description, default)[source]
    @@ -117,8 +115,8 @@ passing extra instructions into the validator.

    save(**kwargs)[source]

    Stores the current value using .handler.save_handler(self.key, value, **kwargs) -where kwargs are a combination of those passed into this function and the -ones specified by the OptionHandler.

    +where kwargs are a combination of those passed into this function and +the ones specified by the OptionHandler.

    Keyword Arguments

    any (any) – Not used by default. These are passed in from self.set @@ -901,7 +899,6 @@ entries are processed.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.utils.optionhandler.html b/docs/0.9.5/api/evennia.utils.optionhandler.html index a73228eea6..2e7a0f3278 100644 --- a/docs/0.9.5/api/evennia.utils.optionhandler.html +++ b/docs/0.9.5/api/evennia.utils.optionhandler.html @@ -207,7 +207,6 @@ than their values.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.utils.picklefield.html b/docs/0.9.5/api/evennia.utils.picklefield.html index 9bbaa4b1f1..7276eb1389 100644 --- a/docs/0.9.5/api/evennia.utils.picklefield.html +++ b/docs/0.9.5/api/evennia.utils.picklefield.html @@ -251,7 +251,6 @@ This is used by the serialization framework.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.utils.search.html b/docs/0.9.5/api/evennia.utils.search.html index 753955b7c7..26cc400d1c 100644 --- a/docs/0.9.5/api/evennia.utils.search.html +++ b/docs/0.9.5/api/evennia.utils.search.html @@ -147,7 +147,7 @@ one of the arguments must be given to do a search.

    Parameters
      -
    • sender (Object or Account, optional) – Get messages sent by a particular account or object

    • +
    • sender (Object, Account or Script, optional) – Get messages sent by a particular sender.

    • receiver (Object, Account or Channel, optional) – Get messages received by a certain account,object or channel

    • freetext (str) – Search for a text string in a message. NOTE: @@ -159,7 +159,7 @@ always gives only one match.

    Returns
    -

    messages (list or Msg) – A list of message matches or a single match if dbref was given.

    +

    Queryset – Message matches.

    @@ -193,6 +193,36 @@ case sensitive) match.

    +
    +
    +evennia.utils.search.search_tag(key=None, category=None, tagtype=None, **kwargs)
    +

    Find object based on tag or category.

    +
    +
    Parameters
    +
      +
    • key (str, optional) – The tag key to search for.

    • +
    • category (str, optional) – The category of tag +to search for. If not set, uncategorized +tags will be searched.

    • +
    • tagtype (str, optional) – ‘type’ of Tag, by default +this is either None (a normal Tag), alias or +permission. This always apply to all queried tags.

    • +
    • kwargs (any) – Other optional parameter that may be supported +by the manager method.

    • +
    +
    +
    Returns
    +

    matches (list)

    +
    +
    List of Objects with tags matching

    the search criteria, or an empty list if no +matches were found.

    +
    +
    +

    +
    +
    +
    +
    evennia.utils.search.search_script_tag(key=None, category=None, tagtype=None, **kwargs)[source]
    @@ -328,7 +358,6 @@ matches were found.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.utils.test_resources.html b/docs/0.9.5/api/evennia.utils.test_resources.html index 9d68fc0b65..0e271914d6 100644 --- a/docs/0.9.5/api/evennia.utils.test_resources.html +++ b/docs/0.9.5/api/evennia.utils.test_resources.html @@ -70,7 +70,6 @@ should directly give the module pathname to unload.

    ... # test code using foo.GLOBALTHING, now set to 'mockval' -

    Notes

    This allows for mocking constants global to the module, since otherwise those would not be mocked (since a module is only loaded once).

    @@ -214,7 +213,6 @@ It helps ensure your tests are run with your own objects.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.utils.text2html.html b/docs/0.9.5/api/evennia.utils.text2html.html index 9f6ffe627e..73eae84453 100644 --- a/docs/0.9.5/api/evennia.utils.text2html.html +++ b/docs/0.9.5/api/evennia.utils.text2html.html @@ -191,7 +191,7 @@ snippet #577349 on
    -re_url = re.compile('((?:ftp|www|https?)\\W+(?:(?!\\.(?:\\s|$)|&\\w+;)[^"\\\',;$*^\\\\(){}<>\\[\\]\\s])+)(\\.(?:\\s|$)|&\\w+;|)')
    +re_url = re.compile('(?<!=")((?:ftp|www|https?)\\W+(?:(?!\\.(?:\\s|$)|&\\w+;)[^"\\\',;$*^\\\\(){}<>\\[\\]\\s])+)(\\.(?:\\s|$)|&\\w+;|)')
    @@ -199,6 +199,11 @@ snippet #577349 on re_mxplink = re.compile('\\|lc(.*?)\\|lt(.*?)\\|le', re.DOTALL)
    +
    +
    +re_mxpurl = re.compile('\\|lu(.*?)\\|lt(.*?)\\|le', re.DOTALL)
    +
    +
    re_color(text)[source]
    @@ -349,6 +354,20 @@ replaces MXP links with HTML code.

    +
    +
    +sub_mxp_urls(match)[source]
    +

    Helper method to be passed to re.sub, +replaces MXP links with HTML code. +:param match: Match for substitution. +:type match: re.Matchobject

    +
    +
    Returns
    +

    text (str) – Processed text.

    +
    +
    +
    +
    sub_text(match)[source]
    @@ -441,7 +460,6 @@ into html statements.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.utils.utils.html b/docs/0.9.5/api/evennia.utils.utils.html index 9a580573bc..8bf22e6381 100644 --- a/docs/0.9.5/api/evennia.utils.utils.html +++ b/docs/0.9.5/api/evennia.utils.utils.html @@ -160,16 +160,18 @@ suffix, the suffix will be dropped.

    -evennia.utils.utils.dedent(text, baseline_index=None)[source]
    +evennia.utils.utils.dedent(text, baseline_index=None, indent=None)[source]

    Safely clean all whitespace at the left of a paragraph.

    Parameters
    • text (str) – The text to dedent.

    • -
    • baseline_index (int or None, optional) – Which row to use as a ‘base’ +

    • baseline_index (int, optional) – Which row to use as a ‘base’ for the indentation. Lines will be dedented to this level but no further. If None, indent so as to completely deindent the least indented text.

    • +
    • indent (int, optional) – If given, force all lines to this indent. +This bypasses baseline_index.

    Returns
    @@ -231,8 +233,8 @@ Defaults to client’s default width.

    -
    -evennia.utils.utils.iter_to_string(initer, endsep='and', addquote=False)[source]
    +
    +evennia.utils.utils.iter_to_str(initer, endsep='and', addquote=False)[source]

    This pretty-formats an iterable list as string output, adding an optional alternative separator to the second to last entry. If addquote is True, the outgoing strings will be surrounded by quotes.

    @@ -249,16 +251,16 @@ values with double quotes.

    Returns
    -

    liststr (str) – The list represented as a string.

    +

    str – The list represented as a string.

    Examples

    -
    # no endsep:
    -   [1,2,3] -> '1, 2, 3'
    -# with endsep=='and':
    -   [1,2,3] -> '1, 2 and 3'
    -# with addquote and endsep
    -   [1,2,3] -> '"1", "2" and "3"'
    +
    >>> list_to_string([1,2,3], endsep='')
    +'1, 2, 3'
    +>>> list_to_string([1,2,3], ensdep='and')
    +'1, 2, and 3'
    +>>> list_to_string([1,2,3], endsep='and', addquote=True)
    +'"1", "2", and "3"'
     
    @@ -282,16 +284,49 @@ values with double quotes.

    Returns
    -

    liststr (str) – The list represented as a string.

    +

    str – The list represented as a string.

    Examples

    -
    # no endsep:
    -   [1,2,3] -> '1, 2, 3'
    -# with endsep=='and':
    -   [1,2,3] -> '1, 2 and 3'
    -# with addquote and endsep
    -   [1,2,3] -> '"1", "2" and "3"'
    +
    >>> list_to_string([1,2,3], endsep='')
    +'1, 2, 3'
    +>>> list_to_string([1,2,3], ensdep='and')
    +'1, 2, and 3'
    +>>> list_to_string([1,2,3], endsep='and', addquote=True)
    +'"1", "2", and "3"'
    +
    +
    + + +
    +
    +evennia.utils.utils.iter_to_string(initer, endsep='and', addquote=False)
    +

    This pretty-formats an iterable list as string output, adding an optional +alternative separator to the second to last entry. If addquote +is True, the outgoing strings will be surrounded by quotes.

    +
    +
    Parameters
    +
      +
    • initer (any) – Usually an iterable to print. Each element must be possible to +present with a string. Note that if this is a generator, it will be +consumed by this operation.

    • +
    • endsep (str, optional) – If set, the last item separator will +be replaced with this value.

    • +
    • addquote (bool, optional) – This will surround all outgoing +values with double quotes.

    • +
    +
    +
    Returns
    +

    str – The list represented as a string.

    +
    +
    +

    Examples

    +
    >>> list_to_string([1,2,3], endsep='')
    +'1, 2, 3'
    +>>> list_to_string([1,2,3], ensdep='and')
    +'1, 2, and 3'
    +>>> list_to_string([1,2,3], endsep='and', addquote=True)
    +'"1", "2", and "3"'
     
    @@ -550,10 +585,8 @@ be found, the protocol flag is reset to utf-8. In any case, returns bytes.

    -
    -

    Note

    +

    Notes

    If text is already bytes, return it as is.

    -
    @@ -574,10 +607,8 @@ falling back to settings.ENCODINGS.

    decoded_text (str) – The decoded text.

    -
    -

    Note

    +

    Notes

    If text is already str, return it as is.

    -
    @@ -603,9 +634,10 @@ distance from parent.

    Parameters
      -
    • obj (any) – Object to analyze. This may be either an instance -or a class.

    • -
    • parent (any) – Can be either instance, class or python path to class.

    • +
    • obj (any) – Object to analyze. This may be either an instance or +a class.

    • +
    • parent (any) – Can be either an instance, a class or the python +path to the class.

    Returns
    @@ -613,10 +645,8 @@ or a class.

    Notes

    -

    What differs this function from e.g. isinstance() is that obj -may be both an instance and a class, and parent may be an -instance, a class, or the python path to a class (counting from -the evennia root directory).

    +

    What differentiates this function from Python’s isinstance() is the +flexibility in the types allowed for the object and parent being compared.

    @@ -639,10 +669,7 @@ any results if called from inside the game.

    shortcut to having to use the full backend name.

    Parameters
    -
      -
    • name (str) – One of ‘sqlite3’, ‘mysql’, ‘postgresql’

    • -
    • 'oracle'. (or) –

    • -
    +

    name (str) – One of ‘sqlite3’, ‘mysql’, ‘postgresql’ or ‘oracle’.

    Returns

    uses (bool) – If the given database is used or not.

    @@ -660,7 +687,7 @@ shortcut to having to use the full backend name.

  • timedelay (int or float) – The delay in seconds.

  • callback (callable) – Will be called as callback(*args, **kwargs) after timedelay seconds.

  • -
  • args (any) – Will be used as arguments to callback.

  • +
  • *args – Will be used as arguments to callback

  • Keyword Arguments
    @@ -679,8 +706,7 @@ persistent is False by default.

    -
    -

    Note

    +

    Notes

    The task handler (evennia.scripts.taskhandler.TASK_HANDLER) will be called for persistent or non-persistent tasks. If persistent is set to True, the callback, its arguments @@ -694,7 +720,63 @@ If persistent is set to True the delay function will return an int which is the task’s id itended for use with TASK_HANDLER’s do_task and remove methods. All persistent tasks whose time delays have passed will be called on server startup.

    -
    +
    + +
    +
    +evennia.utils.utils.repeat(interval, callback, persistent=True, idstring='', stop=False, store_key=None, *args, **kwargs)[source]
    +

    Start a repeating task using the TickerHandler.

    +
    +
    Parameters
    +
      +
    • interval (int) – How often to call callback.

    • +
    • callback (callable) – This will be called with *args, **kwargs every +interval seconds. This must be possible to pickle regardless +of if persistent is set or not!

    • +
    • persistent (bool, optional) – If ticker survives a server reload.

    • +
    • idstring (str, optional) – Separates multiple tickers. This is useful +mainly if wanting to set up multiple repeats for the same +interval/callback but with different args/kwargs.

    • +
    • stop (bool, optional) – If set, use the given parameters to _stop_ a running +ticker instead of creating a new one.

    • +
    • store_key (tuple, optional) – This is only used in combination with stop and +should be the return given from the original repeat call. If this +is given, all other args except stop are ignored.

    • +
    • *args – Used as arguments to callback.

    • +
    • **kwargs – Keyword-arguments to pass to callback.

    • +
    +
    +
    Returns
    +

    tuple or None – The tuple is the store_key - the identifier for the +created ticker. Store this and pass into unrepat() in order to to stop +this ticker later. Returns None if stop=True.

    +
    +
    Raises
    +

    KeyError – If trying to stop a ticker that was not found.

    +
    +
    +
    + +
    +
    +evennia.utils.utils.unrepeat(store_key)[source]
    +

    This is used to stop a ticker previously started with repeat.

    +
    +
    Parameters
    +

    store_key (tuple) – This is the return from repeat, used to uniquely +identify the ticker to stop. Without the store_key, the ticker +must be stopped by passing its parameters to TICKER_HANDLER.remove +directly.

    +
    +
    Returns
    +

    bool

    +
    +
    True if a ticker was stopped, False if not (for example because no

    matching ticker was found or it was already stopped).

    +
    +
    +

    +
    +
    @@ -758,7 +840,7 @@ some checks for runtime libraries.

    evennia.utils.utils.has_parent(basepath, obj)[source]
    -

    Checks if basepath is somewhere in obj’s parent tree.

    +

    Checks if basepath is somewhere in obj’s parent tree.

    Parameters
      @@ -818,7 +900,7 @@ parsed and imported. Returns None and logs error if import fail already imported module object (e.g. models)

    Returns
    -

    variables (dict)

    +

    dict

    A dict of {variablename: variable} for all

    variables in the given module.

    @@ -827,7 +909,8 @@ already imported module object (e.g. models)

    Notes

    -

    Ignores modules and variable names starting with an underscore.

    +

    Ignores modules and variable names starting with an underscore, as well +as variables imported into the module from other modules.

    @@ -942,7 +1025,7 @@ importing directly from path doesn’t work.

    evennia.utils.utils.class_from_module(path, defaultpaths=None, fallback=None)[source]
    -

    Return a class from a module, given the module’s path. This is +

    Return a class from a module, given the class’ full python path. This is primarily used to convert db_typeclass_path:s to classes.

    Parameters
    @@ -968,7 +1051,7 @@ evennia repo itself.

    evennia.utils.utils.object_from_module(path, defaultpaths=None, fallback=None)
    -

    Return a class from a module, given the module’s path. This is +

    Return a class from a module, given the class’ full python path. This is primarily used to convert db_typeclass_path:s to classes.

    Parameters
    @@ -1039,15 +1122,11 @@ the value, the more exact a match is required).

    Returns
    -

    suggestions (list)

    -
    -
    Suggestions from vocabulary with a

    similarity-rating that higher than or equal to cutoff. +

    suggestions (list) – Suggestions from vocabulary with a +similarity-rating that higher than or equal to cutoff. Could be empty if there are no matches.

    -

    -
    -
    @@ -1078,47 +1157,126 @@ array) instead of strings.

    evennia.utils.utils.format_table(table, extra_space=1)[source]
    -

    Note: evennia.utils.evtable is more powerful than this, but this function -can be useful when the number of columns and rows are unknown and must be -calculated on the fly.

    -
    -
    Args.
    -
    table (list): A list of lists to represent columns in the

    table: [[val,val,val,…], [val,val,val,…], …], where +

    Format a 2D array of strings into a multi-column table.

    +
    +
    Parameters
    +
      +
    • table (list) – A list of lists to represent columns in the +table: [[val,val,val,…], [val,val,val,…], …], where each val will be placed on a separate row in the column. All columns must have the same number of rows (some -positions may be empty though).

      +positions may be empty though).

    • +
    • extra_space (int, optional) – Sets how much minimum extra +padding (in characters) should be left between columns.

    • +
    -
    extra_space (int, optional): Sets how much minimum extra

    padding (in characters) should be left between columns.

    -
    -
    -
    -
    -
    -
    Returns
    -

    table (list)

    -
    -
    A list of lists representing the rows to print

    out one by one.

    -
    -
    -

    +
    Returns
    +

    list – A list of lists representing the rows to print out one by one.

    Notes

    The function formats the columns to be as wide as the widest member of each column.

    -

    Example

    -
    ftable = format_table([[...], [...], ...])
    +

    evennia.utils.evtable is more powerful than this, but this +function can be useful when the number of columns and rows are +unknown and must be calculated on the fly.

    +

    Examples:

    +
    ftable = format_table([[1,2,3], [4,5,6]])
    +string = ""
     for ir, row in enumarate(ftable):
         if ir == 0:
             # make first row white
    -        string += "\\n|w" + ""join(row) + "|n"
    +        string += "\n|w" + "".join(row) + "|n"
         else:
    -        string += "\\n" + "".join(row)
    +        string += "\n" + "".join(row)
     print(string)
     
    +
    +
    +evennia.utils.utils.percent(value, minval, maxval, formatting='{:3.1f}%')[source]
    +

    Get a value in an interval as a percentage of its position +in that interval. This also understands negative numbers.

    +
    +
    Parameters
    +
      +
    • value (number) – This should be a value minval<=value<=maxval.

    • +
    • minval (number or None) – Smallest value in interval. This could be None +for an open interval (then return will always be 100%)

    • +
    • maxval (number or None) – Biggest value in interval. This could be None +for an open interval (then return will always be 100%)

    • +
    • formatted (str, optional) – This is a string that should +accept one formatting tag. This will receive the +current value as a percentage. If None, the +raw float will be returned instead.

    • +
    +
    +
    Returns
    +

    str or float – The formatted value or the raw percentage as a float.

    +
    +
    +

    Notes

    +

    We try to handle a weird interval gracefully.

    +
      +
    • If either maxval or minval is None (open interval), we (aribtrarily) assume 100%.

    • +
    • If minval > maxval, we return 0%.

    • +
    • If minval == maxval == value we are looking at a single value match and return 100%.

    • +
    • If minval == maxval != value we return 0%.

    • +
    • If value not in [minval..maxval], we set value to the closest +boundary, so the result will be 0% or 100%, respectively.

    • +
    +
    + +
    +
    +evennia.utils.utils.percentile(iterable, percent, key=<function <lambda>>)[source]
    +

    Find the percentile of a list of values.

    +
    +
    Parameters
    +
      +
    • iterable (iterable) – A list of values. Note N MUST BE already sorted.

    • +
    • percent (float) – A value from 0.0 to 1.0.

    • +
    • key (callable, optional) –

    • +
    +
    +
    Returns
    +

    float – The percentile of the values

    +
    +
    +
    + +
    +
    +evennia.utils.utils.format_grid(elements, width=78, sep=' ', verbatim_elements=None)[source]
    +

    This helper function makes a ‘grid’ output, where it distributes the given +string-elements as evenly as possible to fill out the given width. +will not work well if the variation of length is very big!

    +
    +
    Parameters
    +
      +
    • elements (iterable) – A 1D list of string elements to put in the grid.

    • +
    • width (int, optional) – The width of the grid area to fill.

    • +
    • sep (str, optional) – The extra separator to put between words. If +set to the empty string, words may run into each other.

    • +
    • verbatim_elements (list, optional) – This is a list of indices pointing to +specific items in the elements list. An element at this index will +not be included in the calculation of the slot sizes. It will still +be inserted into the grid at the correct position and may be surrounded +by padding unless filling the entire line. This is useful for embedding +decorations in the grid, such as horizontal bars.

    • +
    • ignore_ansi (bool, optional) – Ignore ansi markups when calculating white spacing.

    • +
    +
    +
    Returns
    +

    list – The grid as a list of ready-formatted rows. We return it +like this to make it easier to insert decorations between rows, such +as horizontal bars.

    +
    +
    +
    +
    evennia.utils.utils.get_evennia_pids()[source]
    @@ -1135,8 +1293,7 @@ Server by trying to access a PID file.

    Examples

    -

    This can be used to determine if we are in a subprocess by -something like:

    +

    This can be used to determine if we are in a subprocess by

    self_pid = os.getpid()
     server_pid, portal_pid = get_evennia_pids()
     is_subprocess = self_pid not in (server_pid, portal_pid)
    @@ -1293,16 +1450,12 @@ on errors.

    Returns
    -

    processed_result (Object or None)

    -
    -
    This is always a single result

    or None. If None, any error reporting/handling should +

    processed_result (Object or None) – This is always a single result +or None. If None, any error reporting/handling should already have happened. The returned object is of the type we are checking multimatches for (e.g. Objects or Commands)

    -

    -
    -
    @@ -1357,27 +1510,55 @@ of the game directory.

    List available typeclasses from all available modules.

    Parameters
    -

    parent (str, optional) – If given, only return typeclasses inheriting (at any distance) -from this parent.

    +

    parent (str, optional) – If given, only return typeclasses inheriting +(at any distance) from this parent.

    Returns
    -

    typeclasses (dict) – On the form {“typeclass.path”: typeclass, …}

    +

    dict – On the form {“typeclass.path”: typeclass, …}

    Notes

    -

    This will dynamicall retrieve all abstract django models inheriting at any distance -from the TypedObject base (aka a Typeclass) so it will work fine with any custom +

    This will dynamically retrieve all abstract django models inheriting at +any distance from the TypedObject base (aka a Typeclass) so it will +work fine with any custom classes being added.

    +
    + +
    +
    +evennia.utils.utils.get_all_cmdsets(parent=None)[source]
    +

    List available cmdsets from all available modules.

    +
    +
    Parameters
    +

    parent (str, optional) – If given, only return cmdsets inheriting (at +any distance) from this parent.

    +
    +
    Returns
    +

    dict – On the form {“cmdset.path”: cmdset, …}

    +
    +
    +

    Notes

    +

    This will dynamically retrieve all abstract django models inheriting at +any distance from the CmdSet base so it will work fine with any custom classes being added.

    evennia.utils.utils.interactive(func)[source]
    -

    Decorator to make a method pausable with yield(seconds) and able to ask for -user-input with response=yield(question). For the question-asking to -work, ‘caller’ must the name of an argument or kwarg to the decorated -function.

    -

    Example:

    +

    Decorator to make a method pausable with yield(seconds) +and able to ask for user-input with response=yield(question). +For the question-asking to work, one of the args or kwargs to the +decorated function must be named ‘caller’.

    +
    +
    Raises
    +
      +
    • ValueError – If asking an interactive question but the decorated +function has no arg or kwarg named ‘caller’.

    • +
    • ValueError – If passing non int/float to yield using for pausing.

    • +
    +
    +
    +

    Examples

    @interactive
     def myfunc(caller):
         caller.msg("This is a test")
    @@ -1392,7 +1573,57 @@ function.

    Notes

    -

    This turns the method into a generator!

    +

    This turns the decorated function or method into a generator.

    +
    + +
    +
    +evennia.utils.utils.safe_convert_to_types(converters, *args, raise_errors=True, **kwargs)[source]
    +

    Helper function to safely convert inputs to expected data types.

    +
    +
    Parameters
    +
      +
    • converters (tuple) – A tuple ((converter, converter,…), {kwarg: converter, …}) to +match a converter to each element in *args and **kwargs. +Each converter will will be called with the arg/kwarg-value as the only argument. +If there are too few converters given, the others will simply not be converter. If the +converter is given as the string ‘py’, it attempts to run +safe_eval/literal_eval on the input arg or kwarg value. It’s possible to +skip the arg/kwarg part of the tuple, an empty tuple/dict will then be assumed.

    • +
    • *args – The arguments to convert with argtypes.

    • +
    • raise_errors (bool, optional) – If set, raise any errors. This will +abort the conversion at that arg/kwarg. Otherwise, just skip the +conversion of the failing arg/kwarg. This will be set by the FuncParser if +this is used as a part of a FuncParser callable.

    • +
    • **kwargs – The kwargs to convert with kwargtypes

    • +
    +
    +
    Returns
    +

    tuple(args, kwargs) in converted form.

    +
    +
    Raises
    +
      +
    • utils.funcparser.ParsingError – If parsing failed in the ‘py’ +converter. This also makes this compatible with the FuncParser +interface.

    • +
    • any – Any other exception raised from other converters, if raise_errors is True.

    • +
    +
    +
    +

    Notes

    +

    This function is often used to validate/convert input from untrusted sources. For +security, the “py”-converter is deliberately limited and uses safe_eval/literal_eval +which only supports simple expressions or simple containers with literals. NEVER +use the python eval or exec methods as a converter for any untrusted input! Allowing +untrusted sources to execute arbitrary python on your server is a severe security risk,

    +

    Example:

    +
    $funcname(1, 2, 3.0, c=[1,2,3])
    +
    +def _funcname(*args, **kwargs):
    +    args, kwargs = safe_convert_input(((int, int, float), {'c': 'py'}), *args, **kwargs)
    +    # ...
    +
    +
    @@ -1440,7 +1671,6 @@ function.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.utils.validatorfuncs.html b/docs/0.9.5/api/evennia.utils.validatorfuncs.html index 36bc66b7c3..c1966a2255 100644 --- a/docs/0.9.5/api/evennia.utils.validatorfuncs.html +++ b/docs/0.9.5/api/evennia.utils.validatorfuncs.html @@ -66,7 +66,7 @@ inputer’s timezone. Always returns a result in UTC.

  • account (AccountDB) – The Account performing this lookup. Unless from_tz is provided, the account’s timezone option will be used.

  • from_tz (pytz.timezone) – An instance of a pytz timezone object from the -user. If not provided, tries to use the timezone option of the account. +user. If not provided, tries to use the timezone option of account. If neither one is provided, defaults to UTC.

  • @@ -86,8 +86,9 @@ If neither one is provided, defaults to UTC.

    Parameters
      -
    • entry (string) – This is a string from user-input. The intended format is, for example: “5d 2w 90s” for -‘five days, two weeks, and ninety seconds.’ Invalid sections are ignored.

    • +
    • entry (string) – This is a string from user-input. The intended format is, for example: +“5d 2w 90s” for ‘five days, two weeks, and ninety seconds.’ Invalid sections are +ignored.

    • option_key (str) – Name to display this query as.

    @@ -120,14 +121,16 @@ If neither one is provided, defaults to UTC.

    evennia.utils.validatorfuncs.boolean(entry, option_key='True/False', **kwargs)[source]
    -

    Simplest check in computer logic, right? This will take user input to flick the switch on or off -:param entry: A value such as True, On, Enabled, Disabled, False, 0, or 1. -:type entry: str -:param option_key: What kind of Boolean we are setting. What Option is this for? -:type option_key: str

    +

    Simplest check in computer logic, right? This will take user input to flick the switch on or off

    -
    Returns
    -

    Boolean

    +
    Parameters
    +
      +
    • entry (str) – A value such as True, On, Enabled, Disabled, False, 0, or 1.

    • +
    • option_key (str) – What kind of Boolean we are setting. What Option is this for?

    • +
    +
    +
    Returns
    +

    Boolean

    @@ -204,7 +207,6 @@ If neither one is provided, defaults to UTC.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.web.html b/docs/0.9.5/api/evennia.web.html index 0aafb44456..99afda405e 100644 --- a/docs/0.9.5/api/evennia.web.html +++ b/docs/0.9.5/api/evennia.web.html @@ -39,10 +39,8 @@

    evennia.web

    -

    This sub-package holds the web presence of Evennia, using normal -Django to relate the database contents to web pages. Also the basic -webclient and the website are defined in here (the webserver itself is -found under the server package).

    +

    This sub-package holds the web presence of Evennia, using normal Django to +relate the database contents to web pages.

    -
    diff --git a/docs/0.9.5/api/evennia.web.urls.html b/docs/0.9.5/api/evennia.web.urls.html index dfdd344711..8ef7e3045e 100644 --- a/docs/0.9.5/api/evennia.web.urls.html +++ b/docs/0.9.5/api/evennia.web.urls.html @@ -39,6 +39,21 @@

    evennia.web.urls

    +

    File that determines what each URL points to. This uses Python regular expressions. +This is the starting point when a user enters an URL.

    +
      +
    1. The URL is matched with a regex, tying it to a given view. Note that this central url.py +file includes url.py from all the various web-components found in views/ so the search +space is much larger than what is shown here.

    2. +
    3. The view (a Python function or class is executed)

    4. +
    5. The view uses a template (a HTML file which may contain template markers for dynamically +modifying its contents; the locations of such templates are given by +settings.TEMPLATES[0][‘DIRS’]) and which may in turn may include static +assets (CSS, images etc).

    6. +
    7. The view ‘renders’ the template into a finished HTML page, replacing all +dynamic content as appropriate.

    8. +
    9. The HTML page is returned to the user.

    10. +
    @@ -84,7 +99,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.web.utils.backends.html b/docs/0.9.5/api/evennia.web.utils.backends.html index 9280939187..2f57100871 100644 --- a/docs/0.9.5/api/evennia.web.utils.backends.html +++ b/docs/0.9.5/api/evennia.web.utils.backends.html @@ -110,7 +110,6 @@ an already authenticated account and bypass authentication.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.web.utils.general_context.html b/docs/0.9.5/api/evennia.web.utils.general_context.html index d1b39a30f3..9dfb89bf46 100644 --- a/docs/0.9.5/api/evennia.web.utils.general_context.html +++ b/docs/0.9.5/api/evennia.web.utils.general_context.html @@ -39,6 +39,10 @@

    evennia.web.utils.general_context

    +

    This file defines global variables that will always be available in a view +context without having to repeatedly include it.

    +

    For this to work, this file is included in the settings file, in the +TEMPLATES[“OPTIONS”][“context_processors”] list.

    evennia.web.utils.general_context.set_game_name_and_slogan()[source]
    @@ -60,8 +64,8 @@ to webclient settings.

    evennia.web.utils.general_context.general_context(request)[source]
    -

    Returns common Evennia-related context stuff, which -is automatically added to context of all views.

    +

    Returns common Evennia-related context stuff, which is automatically added +to context of all views.

    @@ -109,7 +113,6 @@ is automatically added to context of all views.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.web.utils.html b/docs/0.9.5/api/evennia.web.utils.html index 23ea4d0355..e278906212 100644 --- a/docs/0.9.5/api/evennia.web.utils.html +++ b/docs/0.9.5/api/evennia.web.utils.html @@ -92,7 +92,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.web.utils.middleware.html b/docs/0.9.5/api/evennia.web.utils.middleware.html index dfe66e70d2..597a7ce595 100644 --- a/docs/0.9.5/api/evennia.web.utils.middleware.html +++ b/docs/0.9.5/api/evennia.web.utils.middleware.html @@ -102,7 +102,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.web.utils.tests.html b/docs/0.9.5/api/evennia.web.utils.tests.html index a169aa266b..4fa677f507 100644 --- a/docs/0.9.5/api/evennia.web.utils.tests.html +++ b/docs/0.9.5/api/evennia.web.utils.tests.html @@ -110,7 +110,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.web.webclient.html b/docs/0.9.5/api/evennia.web.webclient.html index aadc9061b4..ac2b3072a5 100644 --- a/docs/0.9.5/api/evennia.web.webclient.html +++ b/docs/0.9.5/api/evennia.web.webclient.html @@ -90,7 +90,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.web.webclient.urls.html b/docs/0.9.5/api/evennia.web.webclient.urls.html index 6c473f79ef..426bed1068 100644 --- a/docs/0.9.5/api/evennia.web.webclient.urls.html +++ b/docs/0.9.5/api/evennia.web.webclient.urls.html @@ -39,8 +39,7 @@

    evennia.web.webclient.urls

    -

    This structures the (simple) structure of the -webpage ‘application’.

    +

    This structures the (simple) structure of the webpage ‘application’.

    @@ -86,7 +85,6 @@ webpage ‘application’.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.web.webclient.views.html b/docs/0.9.5/api/evennia.web.webclient.views.html index 2ea9d46829..828c730669 100644 --- a/docs/0.9.5/api/evennia.web.webclient.views.html +++ b/docs/0.9.5/api/evennia.web.webclient.views.html @@ -92,7 +92,6 @@ page and serve it eventual static content.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.web.website.forms.html b/docs/0.9.5/api/evennia.web.website.forms.html index e009cf5b42..94801659bb 100644 --- a/docs/0.9.5/api/evennia.web.website.forms.html +++ b/docs/0.9.5/api/evennia.web.website.forms.html @@ -322,7 +322,6 @@ wish to allow.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.web.website.html b/docs/0.9.5/api/evennia.web.website.html index 1ef76672e4..00e2eee2d5 100644 --- a/docs/0.9.5/api/evennia.web.website.html +++ b/docs/0.9.5/api/evennia.web.website.html @@ -100,7 +100,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.web.website.templatetags.addclass.html b/docs/0.9.5/api/evennia.web.website.templatetags.addclass.html index 2e54ee4a66..df49d80004 100644 --- a/docs/0.9.5/api/evennia.web.website.templatetags.addclass.html +++ b/docs/0.9.5/api/evennia.web.website.templatetags.addclass.html @@ -37,13 +37,8 @@
    -
    -

    evennia.web.website.templatetags.addclass

    -
    -
    -evennia.web.website.templatetags.addclass.addclass(field, given_class)[source]
    -
    - +
    +

    evennia.web.website.templatetags.addclass

    @@ -89,7 +84,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.web.website.templatetags.html b/docs/0.9.5/api/evennia.web.website.templatetags.html index 64f513206b..7045c375ce 100644 --- a/docs/0.9.5/api/evennia.web.website.templatetags.html +++ b/docs/0.9.5/api/evennia.web.website.templatetags.html @@ -89,7 +89,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.web.website.tests.html b/docs/0.9.5/api/evennia.web.website.tests.html index 9752dba9e5..dd329045c6 100644 --- a/docs/0.9.5/api/evennia.web.website.tests.html +++ b/docs/0.9.5/api/evennia.web.website.tests.html @@ -455,7 +455,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.web.website.urls.html b/docs/0.9.5/api/evennia.web.website.urls.html index ce2e952175..5f51da2c45 100644 --- a/docs/0.9.5/api/evennia.web.website.urls.html +++ b/docs/0.9.5/api/evennia.web.website.urls.html @@ -39,7 +39,7 @@

    evennia.web.website.urls

    -

    This structures the website.

    +

    This redirects to website sub-pages.

    @@ -85,7 +85,6 @@
  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/api/evennia.web.website.views.html b/docs/0.9.5/api/evennia.web.website.views.html index e721bd4fe0..dae97c5a58 100644 --- a/docs/0.9.5/api/evennia.web.website.views.html +++ b/docs/0.9.5/api/evennia.web.website.views.html @@ -39,793 +39,7 @@

    evennia.web.website.views

    -

    This file contains the generic, assorted views that don’t fall under one of the other applications. -Views are django’s way of processing e.g. html templates on the fly.

    -
    -
    -evennia.web.website.views.to_be_implemented(request)[source]
    -

    A notice letting the user know that this particular feature hasn’t been -implemented yet.

    -
    - -
    -
    -evennia.web.website.views.evennia_admin(request)[source]
    -

    Helpful Evennia-specific admin page.

    -
    - -
    -
    -evennia.web.website.views.admin_wrapper(request)[source]
    -

    Wrapper that allows us to properly use the base Django admin site, if needed.

    -
    - -
    -
    -class evennia.web.website.views.EvenniaIndexView(**kwargs)[source]
    -

    Bases: django.views.generic.base.TemplateView

    -

    This is a basic example of a Django class-based view, which are functionally -very similar to Evennia Commands but differ in structure. Commands are used -to interface with users using a terminal client. Views are used to interface -with users using a web browser.

    -

    To use a class-based view, you need to have written a template in HTML, and -then you write a view like this to tell Django what values to display on it.

    -

    While there are simpler ways of writing views using plain functions (and -Evennia currently contains a few examples of them), just like Commands, -writing views as classes provides you with more flexibility– you can extend -classes and change things to suit your needs rather than having to copy and -paste entire code blocks over and over. Django also comes with many default -views for displaying things, all of them implemented as classes.

    -

    This particular example displays the index page.

    -
    -
    -template_name = 'website/index.html'
    -
    - -
    -
    -get_context_data(**kwargs)[source]
    -

    This is a common Django method. Think of this as the website -equivalent of the Evennia Command.func() method.

    -

    If you just want to display a static page with no customization, you -don’t need to define this method– just create a view, define -template_name and you’re done.

    -

    The only catch here is that if you extend or overwrite this method, -you’ll always want to make sure you call the parent method to get a -context object. It’s just a dict, but it comes prepopulated with all -sorts of background data intended for display on the page.

    -

    You can do whatever you want to it, but it must be returned at the end -of this method.

    -
    -
    Keyword Arguments
    -

    any (any) – Passed through.

    -
    -
    Returns
    -

    context (dict) – Dictionary of data you want to display on the page.

    -
    -
    -
    - -
    - -
    -
    -class evennia.web.website.views.TypeclassMixin[source]
    -

    Bases: object

    -

    This is a “mixin”, a modifier of sorts.

    -

    Django views typically work with classes called “models.” Evennia objects -are an enhancement upon these Django models and are called “typeclasses.” -But Django itself has no idea what a “typeclass” is.

    -

    For the sake of mitigating confusion, any view class with this in its -inheritance list will be modified to work with Evennia Typeclass objects or -Django models interchangeably.

    -
    -
    -property typeclass
    -
    - -
    - -
    -
    -class evennia.web.website.views.EvenniaCreateView(**kwargs)[source]
    -

    Bases: django.views.generic.edit.CreateView, evennia.web.website.views.TypeclassMixin

    -

    This view extends Django’s default CreateView.

    -

    CreateView is used for creating new objects, be they Accounts, Characters or -otherwise.

    -
    -
    -property page_title
    -
    - -
    - -
    -
    -class evennia.web.website.views.EvenniaDetailView(**kwargs)[source]
    -

    Bases: django.views.generic.detail.DetailView, evennia.web.website.views.TypeclassMixin

    -

    This view extends Django’s default DetailView.

    -

    DetailView is used for displaying objects, be they Accounts, Characters or -otherwise.

    -
    -
    -property page_title
    -
    - -
    - -
    -
    -class evennia.web.website.views.EvenniaUpdateView(**kwargs)[source]
    -

    Bases: django.views.generic.edit.UpdateView, evennia.web.website.views.TypeclassMixin

    -

    This view extends Django’s default UpdateView.

    -

    UpdateView is used for updating objects, be they Accounts, Characters or -otherwise.

    -
    -
    -property page_title
    -
    - -
    - -
    -
    -class evennia.web.website.views.EvenniaDeleteView(**kwargs)[source]
    -

    Bases: django.views.generic.edit.DeleteView, evennia.web.website.views.TypeclassMixin

    -

    This view extends Django’s default DeleteView.

    -

    DeleteView is used for deleting objects, be they Accounts, Characters or -otherwise.

    -
    -
    -property page_title
    -
    - -
    - -
    -
    -class evennia.web.website.views.ObjectDetailView(**kwargs)[source]
    -

    Bases: evennia.web.website.views.EvenniaDetailView

    -

    This is an important view.

    -

    Any view you write that deals with displaying, updating or deleting a -specific object will want to inherit from this. It provides the mechanisms -by which to retrieve the object and make sure the user requesting it has -permissions to actually do things to it.

    -
    -
    -model
    -

    alias of evennia.objects.objects.DefaultObject

    -
    - -
    -
    -template_name = 'website/object_detail.html'
    -
    - -
    -
    -access_type = 'view'
    -
    - -
    -
    -attributes = ['name', 'desc']
    -
    - -
    -
    -get_context_data(**kwargs)[source]
    -

    Adds an ‘attributes’ list to the request context consisting of the -attributes specified at the class level, and in the order provided.

    -

    Django views do not provide a way to reference dynamic attributes, so -we have to grab them all before we render the template.

    -
    -
    Returns
    -

    context (dict) – Django context object

    -
    -
    -
    - -
    -
    -get_object(queryset=None)[source]
    -

    Override of Django hook that provides some important Evennia-specific -functionality.

    -

    Evennia does not natively store slugs, so where a slug is provided, -calculate the same for the object and make sure it matches.

    -

    This also checks to make sure the user has access to view/edit/delete -this object!

    -
    - -
    - -
    -
    -class evennia.web.website.views.ObjectCreateView(**kwargs)[source]
    -

    Bases: django.contrib.auth.mixins.LoginRequiredMixin, evennia.web.website.views.EvenniaCreateView

    -

    This is an important view.

    -

    Any view you write that deals with creating a specific object will want to -inherit from this. It provides the mechanisms by which to make sure the user -requesting creation of an object is authenticated, and provides a sane -default title for the page.

    -
    -
    -model
    -

    alias of evennia.objects.objects.DefaultObject

    -
    - -
    - -
    -
    -class evennia.web.website.views.ObjectDeleteView(**kwargs)[source]
    -

    Bases: django.contrib.auth.mixins.LoginRequiredMixin, evennia.web.website.views.ObjectDetailView, evennia.web.website.views.EvenniaDeleteView

    -

    This is an important view for obvious reasons!

    -

    Any view you write that deals with deleting a specific object will want to -inherit from this. It provides the mechanisms by which to make sure the user -requesting deletion of an object is authenticated, and that they have -permissions to delete the requested object.

    -
    -
    -model
    -

    alias of evennia.objects.objects.DefaultObject

    -
    - -
    -
    -template_name = 'website/object_confirm_delete.html'
    -
    - -
    -
    -access_type = 'delete'
    -
    - -
    -
    -delete(request, *args, **kwargs)[source]
    -

    Calls the delete() method on the fetched object and then -redirects to the success URL.

    -

    We extend this so we can capture the name for the sake of confirmation.

    -
    - -
    - -
    -
    -class evennia.web.website.views.ObjectUpdateView(**kwargs)[source]
    -

    Bases: django.contrib.auth.mixins.LoginRequiredMixin, evennia.web.website.views.ObjectDetailView, evennia.web.website.views.EvenniaUpdateView

    -

    This is an important view.

    -

    Any view you write that deals with updating a specific object will want to -inherit from this. It provides the mechanisms by which to make sure the user -requesting editing of an object is authenticated, and that they have -permissions to edit the requested object.

    -

    This functions slightly different from default Django UpdateViews in that -it does not update core model fields, only object attributes!

    -
    -
    -model
    -

    alias of evennia.objects.objects.DefaultObject

    -
    - -
    -
    -access_type = 'edit'
    -
    - -
    -
    -get_success_url()[source]
    -

    Django hook.

    -

    Can be overridden to return any URL you want to redirect the user to -after the object is successfully updated, but by default it goes to the -object detail page so the user can see their changes reflected.

    -
    - -
    -
    -get_initial()[source]
    -

    Django hook, modified for Evennia.

    -

    Prepopulates the update form field values based on object db attributes.

    -
    -
    Returns
    -

    data (dict)

    -
    -
    Dictionary of key:value pairs containing initial form

    data.

    -
    -
    -

    -
    -
    -
    - -
    -
    -form_valid(form)[source]
    -

    Override of Django hook.

    -

    Updates object attributes based on values submitted.

    -

    This is run when the form is submitted and the data on it is deemed -valid– all values are within expected ranges, all strings contain -valid characters and lengths, etc.

    -

    This method is only called if all values for the fields submitted -passed form validation, so at this point we can assume the data is -validated and sanitized.

    -
    - -
    - -
    -
    -class evennia.web.website.views.AccountMixin[source]
    -

    Bases: evennia.web.website.views.TypeclassMixin

    -

    This is a “mixin”, a modifier of sorts.

    -

    Any view class with this in its inheritance list will be modified to work -with Account objects instead of generic Objects or otherwise.

    -
    -
    -model
    -

    alias of evennia.accounts.accounts.DefaultAccount

    -
    - -
    -
    -form_class
    -

    alias of evennia.web.website.forms.AccountForm

    -
    - -
    - -
    -
    -class evennia.web.website.views.AccountCreateView(**kwargs)[source]
    -

    Bases: evennia.web.website.views.AccountMixin, evennia.web.website.views.EvenniaCreateView

    -

    Account creation view.

    -
    -
    -template_name = 'website/registration/register.html'
    -
    - -
    -
    -success_url
    -
    - -
    -
    -form_valid(form)[source]
    -

    Django hook, modified for Evennia.

    -

    This hook is called after a valid form is submitted.

    -

    When an account creation form is submitted and the data is deemed valid, -proceeds with creating the Account object.

    -
    - -
    - -
    -
    -class evennia.web.website.views.CharacterMixin[source]
    -

    Bases: evennia.web.website.views.TypeclassMixin

    -

    This is a “mixin”, a modifier of sorts.

    -

    Any view class with this in its inheritance list will be modified to work -with Character objects instead of generic Objects or otherwise.

    -
    -
    -model
    -

    alias of evennia.objects.objects.DefaultCharacter

    -
    - -
    -
    -form_class
    -

    alias of evennia.web.website.forms.CharacterForm

    -
    - -
    -
    -success_url
    -
    - -
    -
    -get_queryset()[source]
    -

    This method will override the Django get_queryset method to only -return a list of characters associated with the current authenticated -user.

    -
    -
    Returns
    -

    queryset (QuerySet) – Django queryset for use in the given view.

    -
    -
    -
    - -
    - -
    -
    -class evennia.web.website.views.CharacterListView(**kwargs)[source]
    -

    Bases: django.contrib.auth.mixins.LoginRequiredMixin, evennia.web.website.views.CharacterMixin, django.views.generic.list.ListView

    -

    This view provides a mechanism by which a logged-in player can view a list -of all other characters.

    -

    This view requires authentication by default as a nominal effort to prevent -human stalkers and automated bots/scrapers from harvesting data on your users.

    -
    -
    -template_name = 'website/character_list.html'
    -
    - -
    -
    -paginate_by = 100
    -
    - -
    -
    -page_title = 'Character List'
    -
    - -
    -
    -access_type = 'view'
    -
    - -
    -
    -get_queryset()[source]
    -

    This method will override the Django get_queryset method to return a -list of all characters (filtered/sorted) instead of just those limited -to the account.

    -
    -
    Returns
    -

    queryset (QuerySet) – Django queryset for use in the given view.

    -
    -
    -
    - -
    - -
    -
    -class evennia.web.website.views.CharacterPuppetView(**kwargs)[source]
    -

    Bases: django.contrib.auth.mixins.LoginRequiredMixin, evennia.web.website.views.CharacterMixin, django.views.generic.base.RedirectView, evennia.web.website.views.ObjectDetailView

    -

    This view provides a mechanism by which a logged-in player can “puppet” one -of their characters within the context of the website.

    -

    It also ensures that any user attempting to puppet something is logged in, -and that their intended puppet is one that they own.

    -
    -
    -get_redirect_url(*args, **kwargs)[source]
    -

    Django hook.

    -

    This view returns the URL to which the user should be redirected after -a passed or failed puppet attempt.

    -
    -
    Returns
    -

    url (str) – Path to post-puppet destination.

    -
    -
    -
    - -
    - -
    -
    -class evennia.web.website.views.CharacterManageView(**kwargs)[source]
    -

    Bases: django.contrib.auth.mixins.LoginRequiredMixin, evennia.web.website.views.CharacterMixin, django.views.generic.list.ListView

    -

    This view provides a mechanism by which a logged-in player can browse, -edit, or delete their own characters.

    -
    -
    -paginate_by = 10
    -
    - -
    -
    -template_name = 'website/character_manage_list.html'
    -
    - -
    -
    -page_title = 'Manage Characters'
    -
    - -
    - -
    -
    -class evennia.web.website.views.CharacterUpdateView(**kwargs)[source]
    -

    Bases: evennia.web.website.views.CharacterMixin, evennia.web.website.views.ObjectUpdateView

    -

    This view provides a mechanism by which a logged-in player (enforced by -ObjectUpdateView) can edit the attributes of a character they own.

    -
    -
    -form_class
    -

    alias of evennia.web.website.forms.CharacterUpdateForm

    -
    - -
    -
    -template_name = 'website/character_form.html'
    -
    - -
    - -
    -
    -class evennia.web.website.views.CharacterDetailView(**kwargs)[source]
    -

    Bases: evennia.web.website.views.CharacterMixin, evennia.web.website.views.ObjectDetailView

    -

    This view provides a mechanism by which a user can view the attributes of -a character, owned by them or not.

    -
    -
    -template_name = 'website/object_detail.html'
    -
    - -
    -
    -attributes = ['name', 'desc']
    -
    - -
    -
    -access_type = 'view'
    -
    - -
    -
    -get_queryset()[source]
    -

    This method will override the Django get_queryset method to return a -list of all characters the user may access.

    -
    -
    Returns
    -

    queryset (QuerySet) – Django queryset for use in the given view.

    -
    -
    -
    - -
    - -
    -
    -class evennia.web.website.views.CharacterDeleteView(**kwargs)[source]
    -

    Bases: evennia.web.website.views.CharacterMixin, evennia.web.website.views.ObjectDeleteView

    -

    This view provides a mechanism by which a logged-in player (enforced by -ObjectDeleteView) can delete a character they own.

    -
    - -
    -
    -class evennia.web.website.views.CharacterCreateView(**kwargs)[source]
    -

    Bases: evennia.web.website.views.CharacterMixin, evennia.web.website.views.ObjectCreateView

    -

    This view provides a mechanism by which a logged-in player (enforced by -ObjectCreateView) can create a new character.

    -
    -
    -template_name = 'website/character_form.html'
    -
    - -
    -
    -form_valid(form)[source]
    -

    Django hook, modified for Evennia.

    -

    This hook is called after a valid form is submitted.

    -

    When an character creation form is submitted and the data is deemed valid, -proceeds with creating the Character object.

    -
    - -
    - -
    -
    -class evennia.web.website.views.ChannelMixin[source]
    -

    Bases: evennia.web.website.views.TypeclassMixin

    -

    This is a “mixin”, a modifier of sorts.

    -

    Any view class with this in its inheritance list will be modified to work -with HelpEntry objects instead of generic Objects or otherwise.

    -
    -
    -model
    -

    alias of evennia.comms.comms.DefaultChannel

    -
    - -
    -
    -page_title = 'Channels'
    -
    - -
    -
    -access_type = 'listen'
    -
    - -
    -
    -get_queryset()[source]
    -

    Django hook; here we want to return a list of only those Channels -and other documentation that the current user is allowed to see.

    -
    -
    Returns
    -

    queryset (QuerySet) – List of Channels available to the user.

    -
    -
    -
    - -
    - -
    -
    -class evennia.web.website.views.ChannelListView(**kwargs)[source]
    -

    Bases: evennia.web.website.views.ChannelMixin, django.views.generic.list.ListView

    -

    Returns a list of channels that can be viewed by a user, authenticated -or not.

    -
    -
    -paginate_by = 100
    -
    - -
    -
    -template_name = 'website/channel_list.html'
    -
    - -
    -
    -page_title = 'Channel Index'
    -
    - -
    - -
    - -
    -
    -get_context_data(**kwargs)[source]
    -

    Django hook; we override it to calculate the most popular channels.

    -
    -
    Returns
    -

    context (dict) – Django context object

    -
    -
    -
    - -
    - -
    -
    -class evennia.web.website.views.ChannelDetailView(**kwargs)[source]
    -

    Bases: evennia.web.website.views.ChannelMixin, evennia.web.website.views.ObjectDetailView

    -

    Returns the log entries for a given channel.

    -
    -
    -template_name = 'website/channel_detail.html'
    -
    - -
    -
    -attributes = ['name']
    -
    - -
    -
    -max_num_lines = 10000
    -
    - -
    -
    -get_context_data(**kwargs)[source]
    -

    Django hook; before we can display the channel logs, we need to recall -the logfile and read its lines.

    -
    -
    Returns
    -

    context (dict) – Django context object

    -
    -
    -
    - -
    -
    -get_object(queryset=None)[source]
    -

    Override of Django hook that retrieves an object by slugified channel -name.

    -
    -
    Returns
    -

    channel (Channel) – Channel requested in the URL.

    -
    -
    -
    - -
    - -
    -
    -class evennia.web.website.views.HelpMixin[source]
    -

    Bases: evennia.web.website.views.TypeclassMixin

    -

    This is a “mixin”, a modifier of sorts.

    -

    Any view class with this in its inheritance list will be modified to work -with HelpEntry objects instead of generic Objects or otherwise.

    -
    -
    -model
    -

    alias of evennia.help.models.HelpEntry

    -
    - -
    -
    -page_title = 'Help'
    -
    - -
    -
    -get_queryset()[source]
    -

    Django hook; here we want to return a list of only those HelpEntries -and other documentation that the current user is allowed to see.

    -
    -
    Returns
    -

    queryset (QuerySet) – List of Help entries available to the user.

    -
    -
    -
    - -
    - -
    -
    -class evennia.web.website.views.HelpListView(**kwargs)[source]
    -

    Bases: evennia.web.website.views.HelpMixin, django.views.generic.list.ListView

    -

    Returns a list of help entries that can be viewed by a user, authenticated -or not.

    -
    -
    -paginate_by = 500
    -
    - -
    -
    -template_name = 'website/help_list.html'
    -
    - -
    -
    -page_title = 'Help Index'
    -
    - -
    - -
    -
    -class evennia.web.website.views.HelpDetailView(**kwargs)[source]
    -

    Bases: evennia.web.website.views.HelpMixin, evennia.web.website.views.EvenniaDetailView

    -

    Returns the detail page for a given help entry.

    -
    -
    -template_name = 'website/help_detail.html'
    -
    - -
    -
    -get_context_data(**kwargs)[source]
    -

    Adds navigational data to the template to let browsers go to the next -or previous entry in the help list.

    -
    -
    Returns
    -

    context (dict) – Django context object

    -
    -
    -
    - -
    -
    -get_object(queryset=None)[source]
    -

    Override of Django hook that retrieves an object by category and topic -instead of pk and slug.

    -
    -
    Returns
    -

    entry (HelpEntry) – HelpEntry requested in the URL.

    -
    -
    -
    - -
    - +

    Website views.

    @@ -871,7 +85,6 @@ instead of pk and slug.

  • 0.9.5 (v0.9.5 branch)
  • -
    diff --git a/docs/0.9.5/genindex.html b/docs/0.9.5/genindex.html index d538c51987..80b0d772e0 100644 --- a/docs/0.9.5/genindex.html +++ b/docs/0.9.5/genindex.html @@ -65,6 +65,7 @@ | V | W | X + | Y

    _

    @@ -78,10 +79,6 @@
  • (evennia.commands.command.Command method)
  • (evennia.commands.command.CommandMeta method) -
  • -
  • (evennia.comms.channelhandler.ChannelHandler method) -
  • -
  • (evennia.comms.models.Msg method)
  • (evennia.comms.models.TempMsg method)
  • @@ -152,6 +149,16 @@
  • (evennia.server.portal.grapevine.RestartingWebsocketServerFactory method)
  • (evennia.server.portal.irc.IRCBotFactory method) +
  • +
  • (evennia.server.portal.mccp.Mccp method) +
  • +
  • (evennia.server.portal.mssp.Mssp method) +
  • +
  • (evennia.server.portal.mxp.Mxp method) +
  • +
  • (evennia.server.portal.naws.Naws method) +
  • +
  • (evennia.server.portal.portal.Portal method)
  • (evennia.server.portal.portalsessionhandler.PortalSessionHandler method)
  • @@ -164,6 +171,18 @@
  • (evennia.server.portal.ssh.SshProtocol method)
  • (evennia.server.portal.ssh.TerminalSessionTransport_getPeer method) +
  • +
  • (evennia.server.portal.ssl.SSLProtocol method) +
  • +
  • (evennia.server.portal.suppress_ga.SuppressGA method) +
  • +
  • (evennia.server.portal.telnet.TelnetProtocol method) +
  • +
  • (evennia.server.portal.telnet_oob.TelnetOOB method) +
  • +
  • (evennia.server.portal.telnet_ssl.SSLProtocol method) +
  • +
  • (evennia.server.portal.ttype.Ttype method)
  • (evennia.server.portal.webclient.WebSocketClient method)
  • @@ -174,10 +193,6 @@
  • (evennia.server.profiling.dummyrunner.DummyFactory method)
  • (evennia.server.server.Evennia method) -
  • -
  • (evennia.server.serversession.NAttributeHandler method) -
  • -
  • (evennia.server.serversession.NDbHolder method)
  • (evennia.server.serversession.ServerSession method)
  • @@ -192,14 +207,18 @@
  • (evennia.server.webserver.LockableThreadPool method)
  • (evennia.server.webserver.WSGIWebServer method) -
  • -
  • (evennia.typeclasses.admin.AttributeForm method) -
  • -
  • (evennia.typeclasses.admin.TagForm method)
  • (evennia.typeclasses.attributes.AttributeHandler method)
  • -
  • (evennia.typeclasses.attributes.NAttributeHandler method) +
  • (evennia.typeclasses.attributes.DbHolder method) +
  • +
  • (evennia.typeclasses.attributes.IAttributeBackend method) +
  • +
  • (evennia.typeclasses.attributes.InMemoryAttribute method) +
  • +
  • (evennia.typeclasses.attributes.InMemoryAttributeBackend method) +
  • +
  • (evennia.typeclasses.attributes.ModelAttributeBackend method)
  • (evennia.typeclasses.attributes.NickHandler method)
  • @@ -228,8 +247,6 @@
  • (evennia.utils.evtable.EvColumn method)
  • (evennia.utils.evtable.EvTable method) -
  • -
  • (evennia.utils.inlinefuncs.ParseStack method)
  • (evennia.utils.logger.WeeklyLogFile method)
  • @@ -289,23 +306,9 @@
  • (evennia.server.serversession.ServerSession method)
  • -
  • (evennia.typeclasses.attributes.Attribute method) +
  • (evennia.typeclasses.attributes.IAttribute method)
  • (evennia.typeclasses.models.TypedObject method) -
  • - -
  • access_type (evennia.web.website.views.ChannelMixin attribute) - -
  • account() (evennia.objects.models.ObjectDB property) @@ -347,11 +350,9 @@
  • (evennia.commands.default.comms.CmdCdestroy attribute)
  • -
  • (evennia.commands.default.comms.CmdCemit attribute) +
  • (evennia.commands.default.comms.CmdChannel attribute)
  • (evennia.commands.default.comms.CmdChannelCreate attribute) -
  • -
  • (evennia.commands.default.comms.CmdChannels attribute)
  • (evennia.commands.default.comms.CmdClock attribute)
  • @@ -380,11 +381,7 @@
  • (evennia.web.website.tests.EvenniaWebTest attribute)
  • -
  • AccountAttributeInline (class in evennia.accounts.admin) -
  • AccountCmdSet (class in evennia.commands.default.cmdset_account) -
  • -
  • AccountCreateView (class in evennia.web.website.views)
  • AccountDB (class in evennia.accounts.models)
  • @@ -398,37 +395,13 @@
  • (evennia.typeclasses.tags.Tag attribute)
  • -
  • AccountDBAdmin (class in evennia.accounts.admin) -
  • -
  • AccountDBChangeForm (class in evennia.accounts.admin) -
  • -
  • AccountDBChangeForm.Meta (class in evennia.accounts.admin) -
  • -
  • AccountDBCreationForm (class in evennia.accounts.admin) -
  • -
  • AccountDBCreationForm.Meta (class in evennia.accounts.admin) -
  • AccountDBPasswordChecker (class in evennia.server.portal.ssh)
  • -
  • AccountForm (class in evennia.accounts.admin) - -
  • -
  • AccountForm.Meta (class in evennia.accounts.admin) - -
  • -
  • AccountInline (class in evennia.accounts.admin) +
  • AccountForm.Meta (class in evennia.web.website.forms)
  • AccountManager (class in evennia.accounts.manager) -
  • -
  • AccountMixin (class in evennia.web.website.views) -
  • -
  • AccountTagInline (class in evennia.accounts.admin)
  • action() (evennia.server.portal.irc.IRCBot method)
  • @@ -452,8 +425,6 @@ +
  • add_alias() (evennia.commands.default.comms.CmdChannel method) +
  • add_callback() (evennia.contrib.ingame_python.commands.CmdCallback method)
  • -
  • add_channel() (evennia.comms.channelhandler.ChannelHandler method) -
  • add_choice() (evennia.contrib.building_menu.BuildingMenu method)
  • add_choice_edit() (evennia.contrib.building_menu.BuildingMenu method) @@ -518,18 +483,6 @@
  • add_event() (evennia.contrib.ingame_python.scripts.EventHandler method)
  • -
  • add_fieldsets (evennia.accounts.admin.AccountDBAdmin attribute) - -
  • -
  • add_form (evennia.accounts.admin.AccountDBAdmin attribute) - -
  • add_header() (evennia.utils.evtable.EvTable method)
  • add_language() (in module evennia.contrib.rplanguage) @@ -538,9 +491,7 @@
  • add_rows() (evennia.utils.evtable.EvColumn method)
  • -
  • addclass() (in module evennia.web.website.templatetags.addclass) -
  • -
  • admin_wrapper() (in module evennia.web.website.views) +
  • add_user_channel_alias() (evennia.comms.comms.DefaultChannel method)
  • AdminPortal2Server (class in evennia.server.portal.amp)
  • @@ -663,11 +614,9 @@
  • (evennia.commands.default.comms.CmdCdestroy attribute)
  • -
  • (evennia.commands.default.comms.CmdCemit attribute) +
  • (evennia.commands.default.comms.CmdChannel attribute)
  • (evennia.commands.default.comms.CmdChannelCreate attribute) -
  • -
  • (evennia.commands.default.comms.CmdChannels attribute)
  • (evennia.commands.default.comms.CmdClock attribute)
  • @@ -722,8 +671,6 @@
  • (evennia.commands.default.syscommands.SystemNoInput attribute)
  • (evennia.commands.default.syscommands.SystemNoMatch attribute) -
  • -
  • (evennia.commands.default.syscommands.SystemSendToChannel attribute)
  • (evennia.commands.default.system.CmdAbout attribute)
  • @@ -742,6 +689,8 @@
  • (evennia.commands.default.system.CmdService attribute)
  • (evennia.commands.default.system.CmdShutdown attribute) +
  • +
  • (evennia.commands.default.system.CmdTasks attribute)
  • (evennia.commands.default.system.CmdTime attribute)
  • @@ -756,8 +705,6 @@
  • (evennia.commands.default.unloggedin.CmdUnconnectedLook attribute)
  • (evennia.commands.default.unloggedin.CmdUnconnectedQuit attribute) -
  • -
  • (evennia.comms.channelhandler.ChannelCommand attribute)
  • (evennia.contrib.barter.CmdAccept attribute)
  • @@ -955,19 +902,21 @@
  • (evennia.contrib.turnbattle.tb_range.CmdWithdraw attribute)
  • -
  • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdBlindHelp attribute) +
  • (evennia.contrib.tutorial_examples.red_button.CmdBlindHelp attribute)
  • -
  • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdBlindLook attribute) +
  • (evennia.contrib.tutorial_examples.red_button.CmdBlindLook attribute)
  • -
  • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdCloseLid attribute) +
  • (evennia.contrib.tutorial_examples.red_button.CmdCloseLid attribute)
  • -
  • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdNudge attribute) +
  • (evennia.contrib.tutorial_examples.red_button.CmdNudge attribute)
  • -
  • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdOpenLid attribute) +
  • (evennia.contrib.tutorial_examples.red_button.CmdOpenLid attribute)
  • -
  • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdPush attribute) +
  • (evennia.contrib.tutorial_examples.red_button.CmdPushLidClosed attribute)
  • -
  • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdSmashGlass attribute) +
  • (evennia.contrib.tutorial_examples.red_button.CmdPushLidOpen attribute) +
  • +
  • (evennia.contrib.tutorial_examples.red_button.CmdSmashGlass attribute)
  • (evennia.contrib.tutorial_world.mob.CmdMobOnOff attribute)
  • @@ -1014,6 +963,8 @@
  • (evennia.help.models.HelpEntry attribute)
  • (evennia.objects.objects.ExitCommand attribute) +
  • +
  • (evennia.server.profiling.dummyrunner.CmdDummyRunnerEchoResponse attribute)
  • (evennia.typeclasses.models.TypedObject attribute)
  • @@ -1028,6 +979,8 @@
  • (evennia.utils.evmenu.CmdEvMenuNode attribute)
  • (evennia.utils.evmenu.CmdGetInput attribute) +
  • +
  • (evennia.utils.evmenu.CmdYesNoQuestion attribute)
  • (evennia.utils.evmore.CmdMore attribute)
  • @@ -1054,14 +1007,10 @@
  • (evennia.scripts.scripthandler.ScriptHandler method)
  • (evennia.scripts.tickerhandler.TickerHandler method) -
  • -
  • (evennia.server.serversession.NAttributeHandler method) -
  • -
  • (evennia.server.serversession.NDbHolder property)
  • (evennia.typeclasses.attributes.AttributeHandler method)
  • -
  • (evennia.typeclasses.attributes.NAttributeHandler method) +
  • (evennia.typeclasses.attributes.DbHolder property)
  • (evennia.typeclasses.tags.TagHandler method)
  • @@ -1084,8 +1033,6 @@
  • all_to_category() (evennia.help.manager.HelpEntryManager method)
  • - - +
  • at_hit() (evennia.contrib.tutorial_world.mob.Mob method)
  • -
  • at_idmapper_flush() (evennia.scripts.scripts.DefaultScript method) +
  • at_idmapper_flush() (evennia.typeclasses.models.TypedObject method)
  • @@ -1532,6 +1481,8 @@
  • (evennia.server.portal.irc.IRCBot method)
  • (evennia.server.portal.ssh.SshProtocol method) +
  • +
  • (evennia.server.portal.telnet.TelnetProtocol method)
  • (evennia.server.portal.webclient.WebSocketClient method)
  • @@ -1611,9 +1562,9 @@
  • (evennia.contrib.tutorial_world.objects.TutorialReadable method)
  • -
  • (evennia.contrib.tutorial_world.objects.Weapon method) +
  • (evennia.contrib.tutorial_world.objects.TutorialWeapon method)
  • -
  • (evennia.contrib.tutorial_world.objects.WeaponRack method) +
  • (evennia.contrib.tutorial_world.objects.TutorialWeaponRack method)
  • (evennia.contrib.tutorial_world.rooms.BridgeRoom method)
  • @@ -1667,6 +1618,10 @@
  • at_password_change() (evennia.accounts.accounts.DefaultAccount method) +
  • +
  • at_pause() (evennia.scripts.scripts.DefaultScript method) +
  • +
  • at_post_channel_msg() (evennia.accounts.accounts.DefaultAccount method)
  • at_post_cmd() (evennia.commands.command.Command method) @@ -1675,8 +1630,18 @@
  • at_post_disconnect() (evennia.accounts.accounts.DefaultAccount method) + +
  • at_post_login() (evennia.accounts.accounts.DefaultAccount method) + +
  • +
  • at_post_msg() (evennia.comms.comms.DefaultChannel method)
  • at_post_portal_sync() (evennia.server.server.Evennia method)
  • @@ -1692,6 +1657,8 @@
  • (evennia.objects.objects.DefaultObject method)
  • +
  • at_pre_channel_msg() (evennia.accounts.accounts.DefaultAccount method) +
  • at_pre_cmd() (evennia.commands.command.Command method)
      @@ -1699,6 +1666,8 @@
  • at_pre_login() (evennia.accounts.accounts.DefaultAccount method) +
  • +
  • at_pre_msg() (evennia.comms.comms.DefaultChannel method)
  • at_pre_puppet() (evennia.objects.objects.DefaultCharacter method) @@ -1732,12 +1701,6 @@
  • (evennia.contrib.turnbattle.tb_range.TBRangeTurnHandler method)
  • (evennia.contrib.tutorial_examples.bodyfunctions.BodyFunctions method) -
  • -
  • (evennia.contrib.tutorial_examples.red_button_scripts.BlinkButtonEvent method) -
  • -
  • (evennia.contrib.tutorial_examples.red_button_scripts.CloseLidEvent method) -
  • -
  • (evennia.contrib.tutorial_examples.red_button_scripts.DeactivateButtonEvent method)
  • (evennia.scripts.scripts.DefaultScript method)
  • @@ -1774,18 +1737,6 @@
  • (evennia.contrib.turnbattle.tb_range.TBRangeTurnHandler method)
  • (evennia.contrib.tutorial_examples.bodyfunctions.BodyFunctions method) -
  • -
  • (evennia.contrib.tutorial_examples.red_button_scripts.BlindedState method) -
  • -
  • (evennia.contrib.tutorial_examples.red_button_scripts.BlinkButtonEvent method) -
  • -
  • (evennia.contrib.tutorial_examples.red_button_scripts.ClosedLidState method) -
  • -
  • (evennia.contrib.tutorial_examples.red_button_scripts.CloseLidEvent method) -
  • -
  • (evennia.contrib.tutorial_examples.red_button_scripts.DeactivateButtonEvent method) -
  • -
  • (evennia.contrib.tutorial_examples.red_button_scripts.OpenLidState method)
  • (evennia.contrib.wilderness.WildernessScript method)
  • @@ -1802,6 +1753,8 @@
  • (evennia.utils.gametime.TimeScript method)
  • +
  • at_script_delete() (evennia.scripts.scripts.DefaultScript method) +
  • at_search_result() (in module evennia.utils.utils)
  • at_server_cold_start() (evennia.server.server.Evennia method) @@ -1827,6 +1780,8 @@
  • at_server_shutdown() (evennia.accounts.accounts.DefaultAccount method)
  • -
  • at_server_start() (evennia.server.server.Evennia method) +
  • at_server_start() (evennia.contrib.ingame_python.scripts.EventHandler method) + +
  • at_server_stop() (evennia.server.server.Evennia method)
  • at_start() (evennia.accounts.bots.BotStarter method)
      -
    • (evennia.contrib.ingame_python.scripts.EventHandler method) -
    • -
    • (evennia.contrib.tutorial_examples.red_button_scripts.BlindedState method) -
    • -
    • (evennia.contrib.tutorial_examples.red_button_scripts.ClosedLidState method) -
    • -
    • (evennia.contrib.tutorial_examples.red_button_scripts.DeactivateButtonEvent method) -
    • -
    • (evennia.contrib.tutorial_examples.red_button_scripts.OpenLidState method) -
    • (evennia.contrib.wilderness.WildernessScript method)
    • (evennia.scripts.scripts.DefaultScript method) @@ -1868,12 +1819,6 @@
    • (evennia.contrib.turnbattle.tb_magic.TBMagicTurnHandler method)
    • (evennia.contrib.turnbattle.tb_range.TBRangeTurnHandler method) -
    • -
    • (evennia.contrib.tutorial_examples.red_button_scripts.BlindedState method) -
    • -
    • (evennia.contrib.tutorial_examples.red_button_scripts.ClosedLidState method) -
    • -
    • (evennia.contrib.tutorial_examples.red_button_scripts.OpenLidState method)
    • (evennia.scripts.scripts.DefaultScript method)
    • @@ -1923,31 +1868,21 @@
    • Attribute.DoesNotExist
    • Attribute.MultipleObjectsReturned -
    • -
    • AttributeForm (class in evennia.typeclasses.admin) -
    • -
    • AttributeForm.Meta (class in evennia.typeclasses.admin) -
    • -
    • AttributeFormSet (class in evennia.typeclasses.admin)
    • AttributeHandler (class in evennia.typeclasses.attributes) -
    • -
    • AttributeInline (class in evennia.typeclasses.admin)
    • attributes (evennia.server.serversession.ServerSession attribute)
    • attrtype() (evennia.typeclasses.attributes.Attribute property) + +
    • audit() (evennia.contrib.security.auditing.server.AuditedServerSession method)
    • AuditedServerSession (class in evennia.contrib.security.auditing.server) @@ -1959,12 +1894,16 @@
    • authenticate() (evennia.accounts.accounts.DefaultAccount class method)
    • authenticated_response (evennia.web.website.tests.EvenniaWebTest attribute)
    • author (evennia.contrib.ingame_python.callbackhandler.Callback attribute) +
    • +
    • auto_close_msg (evennia.contrib.tutorial_examples.red_button.RedButton attribute)
    • auto_help (evennia.commands.command.Command attribute) @@ -1984,25 +1923,15 @@

      B

      - + - + - + + - + -
    • category() (evennia.typeclasses.attributes.Attribute property) + +
    • Category.DoesNotExist
    • Category.MultipleObjectsReturned @@ -2255,28 +2186,30 @@
    • center() (evennia.utils.ansi.ANSIString method) -
    • -
    • center_justify() (in module evennia.prototypes.protfuncs)
    • change_name_color() (in module evennia.contrib.tree_select)
    • changed() (evennia.utils.optionclasses.BaseOption property)
    • channel (evennia.server.portal.irc.IRCBot attribute) +
    • +
    • channel_list_bans() (evennia.commands.default.comms.CmdChannel method) +
    • +
    • channel_list_who() (evennia.commands.default.comms.CmdChannel method) +
    • +
    • channel_msg() (evennia.accounts.accounts.DefaultAccount method) +
    • +
    • channel_msg_nick_pattern (evennia.comms.comms.DefaultChannel attribute) +
    • +
    • channel_msg_nick_replacement (evennia.comms.comms.DefaultChannel attribute)
    • channel_prefix() (evennia.comms.comms.DefaultChannel method) +
    • +
    • channel_prefix_string (evennia.comms.comms.DefaultChannel attribute)
    • channel_search() (evennia.comms.managers.ChannelDBManager method) -
    • -
    • channel_set (evennia.comms.models.ChannelDB attribute)
    • channel_typeclass (evennia.web.website.tests.EvenniaWebTest attribute) -
    • -
    • ChannelAdmin (class in evennia.comms.admin) -
    • -
    • ChannelAttributeInline (class in evennia.comms.admin) -
    • -
    • ChannelCommand (class in evennia.comms.channelhandler)
    • ChannelDB (class in evennia.comms.models)
    • @@ -2293,22 +2226,10 @@
    • ChannelDBManager (class in evennia.comms.managers)
    • ChannelDetailTest (class in evennia.web.website.tests) -
    • -
    • ChannelDetailView (class in evennia.web.website.views) -
    • -
    • ChannelHandler (class in evennia.comms.channelhandler)
    • ChannelListTest (class in evennia.web.website.tests) -
    • -
    • ChannelListView (class in evennia.web.website.views)
    • ChannelManager (class in evennia.comms.managers) -
    • -
    • ChannelMixin (class in evennia.web.website.views) -
    • -
    • channels() (evennia.comms.models.Msg property) -
    • -
    • ChannelTagInline (class in evennia.comms.admin)
    • character() (evennia.accounts.accounts.DefaultAccount property)
    • @@ -2323,53 +2244,25 @@
    • CharacterCmdSet (class in evennia.commands.default.cmdset_character)
    • CharacterCreateView (class in evennia.web.website.tests) - -
    • CharacterDeleteView (class in evennia.web.website.tests) - -
    • -
    • CharacterDetailView (class in evennia.web.website.views)
    • CharacterForm (class in evennia.web.website.forms)
    • CharacterForm.Meta (class in evennia.web.website.forms)
    • CharacterListView (class in evennia.web.website.tests) - -
    • CharacterManageView (class in evennia.web.website.tests) - -
    • -
    • CharacterMixin (class in evennia.web.website.views)
    • CharacterPuppetView (class in evennia.web.website.tests) - -
    • characters() (evennia.accounts.accounts.DefaultAccount property)
    • CharacterUpdateForm (class in evennia.web.website.forms)
    • CharacterUpdateView (class in evennia.web.website.tests) - -
    • check() (evennia.locks.lockhandler.LockHandler method)
    • -
    • clean_attr_value() (evennia.typeclasses.admin.AttributeForm method) -
    • clean_senddata() (evennia.server.sessionhandler.SessionHandler method)
    • clean_stale_tasks() (evennia.scripts.taskhandler.TaskHandler method)
    • -
    • clean_username() (evennia.accounts.admin.AccountDBChangeForm method) - -
    • clear() (evennia.commands.cmdsethandler.CmdSetHandler method)
    • +
    • clear_attributes() (evennia.typeclasses.attributes.IAttributeBackend method) +
    • clear_client_lists() (evennia.server.profiling.tests.TestDummyrunnerSettings method)
    • clear_contents() (evennia.objects.objects.DefaultObject method)
    • clear_exits() (evennia.objects.objects.DefaultObject method)
    • -
    • client_disconnect() (evennia.server.portal.webclient_ajax.AjaxWebClient method) +
    • clickable_topics (evennia.commands.default.help.CmdHelp attribute)
    • -
    • client_height() (evennia.commands.command.Command method) +
    • client_disconnect() (evennia.server.portal.webclient_ajax.AjaxWebClient method)
    • client_options() (in module evennia.server.inputfuncs)
    • @@ -2491,8 +2368,6 @@
    • close() (evennia.contrib.building_menu.BuildingMenu method) -
    • -
    • close_lid() (evennia.contrib.tutorial_examples.red_button.RedButton method)
    • close_menu() (evennia.contrib.tutorial_world.intro_menu.TutorialEvMenu method) @@ -2500,18 +2375,6 @@
    • (evennia.utils.evmenu.EvMenu method)
    • -
    • ClosedLidState (class in evennia.contrib.tutorial_examples.red_button_scripts) -
    • -
    • ClosedLidState.DoesNotExist -
    • -
    • ClosedLidState.MultipleObjectsReturned -
    • -
    • CloseLidEvent (class in evennia.contrib.tutorial_examples.red_button_scripts) -
    • -
    • CloseLidEvent.DoesNotExist -
    • -
    • CloseLidEvent.MultipleObjectsReturned -
    • ClothedCharacter (class in evennia.contrib.clothing)
    • ClothedCharacter.DoesNotExist @@ -2527,8 +2390,6 @@
    • Clothing.MultipleObjectsReturned
    • clothing_type_count() (in module evennia.contrib.clothing) -
    • -
    • clr() (in module evennia.utils.inlinefuncs)
    • CmdAbout (class in evennia.commands.default.system)
    • @@ -2564,9 +2425,9 @@
    • CmdBatchCommands (class in evennia.commands.default.batchprocess)
    • -
    • CmdBlindHelp (class in evennia.contrib.tutorial_examples.cmdset_red_button) +
    • CmdBlindHelp (class in evennia.contrib.tutorial_examples.red_button)
    • -
    • CmdBlindLook (class in evennia.contrib.tutorial_examples.cmdset_red_button) +
    • CmdBlindLook (class in evennia.contrib.tutorial_examples.red_button)
    • CmdBoot (class in evennia.commands.default.admin)
    • @@ -2582,11 +2443,9 @@
    • CmdCdestroy (class in evennia.commands.default.comms)
    • -
    • CmdCemit (class in evennia.commands.default.comms) +
    • CmdChannel (class in evennia.commands.default.comms)
    • CmdChannelCreate (class in evennia.commands.default.comms) -
    • -
    • CmdChannels (class in evennia.commands.default.comms)
    • CmdCharCreate (class in evennia.commands.default.account)
    • @@ -2596,7 +2455,7 @@
    • CmdClock (class in evennia.commands.default.comms)
    • -
    • CmdCloseLid (class in evennia.contrib.tutorial_examples.cmdset_red_button) +
    • CmdCloseLid (class in evennia.contrib.tutorial_examples.red_button)
    • CmdColorTest (class in evennia.commands.default.account)
    • @@ -2662,6 +2521,8 @@
    • (class in evennia.contrib.clothing)
    • +
    • CmdDummyRunnerEchoResponse (class in evennia.server.profiling.dummyrunner) +
    • CmdEast (class in evennia.contrib.tutorial_world.rooms)
    • CmdEditorBase (class in evennia.utils.eveditor) @@ -2726,8 +2587,6 @@
    • CmdHelp (class in evennia.commands.default.help)
    • -
    • CmdOpenCloseDoor (class in evennia.contrib.simpledoor)
    • -
    • CmdOpenLid (class in evennia.contrib.tutorial_examples.cmdset_red_button) +
    • CmdOpenLid (class in evennia.contrib.tutorial_examples.red_button)
    • CmdOption (class in evennia.commands.default.account)
    • @@ -2850,7 +2711,9 @@
    • CmdPressButton (class in evennia.contrib.tutorial_world.objects)
    • -
    • CmdPush (class in evennia.contrib.tutorial_examples.cmdset_red_button) +
    • CmdPushLidClosed (class in evennia.contrib.tutorial_examples.red_button) +
    • +
    • CmdPushLidOpen (class in evennia.contrib.tutorial_examples.red_button)
    • CmdPy (class in evennia.commands.default.system)
    • @@ -2956,7 +2819,7 @@
    • CmdShutdown (class in evennia.commands.default.system)
    • -
    • CmdSmashGlass (class in evennia.contrib.tutorial_examples.cmdset_red_button) +
    • CmdSmashGlass (class in evennia.contrib.tutorial_examples.red_button)
    • CmdSpawn (class in evennia.commands.default.building)
    • @@ -2975,6 +2838,8 @@
    • CmdTag (class in evennia.commands.default.building)
    • CmdTalk (class in evennia.contrib.talking_npc) +
    • +
    • CmdTasks (class in evennia.commands.default.system)
    • CmdTeleport (class in evennia.commands.default.building)
    • @@ -3057,10 +2922,16 @@
    • CmdWipe (class in evennia.commands.default.building)
    • CmdWithdraw (class in evennia.contrib.turnbattle.tb_range) +
    • +
    • CmdYesNoQuestion (class in evennia.utils.evmenu)
    • code (evennia.contrib.ingame_python.callbackhandler.Callback attribute)
    • code_exec() (evennia.utils.batchprocessors.BatchCodeProcessor method) +
    • +
    • coll_date_func() (evennia.commands.default.system.CmdTasks static method) +
    • +
    • collect_topics() (evennia.commands.default.help.CmdHelp method)
    • collectstatic() (in module evennia.server.evennia_launcher) @@ -3156,6 +3027,8 @@
    • (evennia.server.portal.amp_server.AMPServerProtocol method)
    • (evennia.server.portal.ssh.SshProtocol method) +
    • +
    • (evennia.server.portal.telnet.TelnetProtocol method)
    • (evennia.server.profiling.dummyrunner.DummyClient method)
    • @@ -3166,6 +3039,8 @@
    • (evennia.server.portal.amp.AMPMultiConnectionProtocol method)
    • (evennia.server.portal.ssh.SshProtocol method) +
    • +
    • (evennia.server.portal.telnet.TelnetProtocol method)
    • (evennia.server.profiling.dummyrunner.DummyClient method)
    • @@ -3227,6 +3102,8 @@
    • create() (evennia.accounts.accounts.DefaultAccount class method)
    • create_account() (in module evennia.utils.create)
    • -
    • create_channel() (in module evennia.utils.create) +
    • create_attribute() (evennia.typeclasses.attributes.IAttributeBackend method)
    • +
    • create_channel() (evennia.commands.default.comms.CmdChannel method) + +
    • create_channels() (in module evennia.server.initial_setup)
    • create_character() (evennia.accounts.accounts.DefaultAccount method) @@ -3288,12 +3171,8 @@
    • credentialInterfaces (evennia.server.portal.ssh.AccountDBPasswordChecker attribute)
    • -
    • crop() (in module evennia.utils.inlinefuncs) - -
    • CrumblingWall (class in evennia.contrib.tutorial_world.objects)
    • CrumblingWall.DoesNotExist @@ -3332,6 +3211,8 @@
    • (evennia.server.portal.portalsessionhandler.PortalSessionHandler method)
    • (evennia.server.portal.rss.RSSReader method) +
    • +
    • (evennia.server.portal.telnet.TelnetProtocol method)
    • (evennia.server.portal.webclient.WebSocketClient method)
    • @@ -3350,6 +3231,10 @@
    • (evennia.server.portal.portalsessionhandler.PortalSessionHandler method)
    • (evennia.server.portal.ssh.SshProtocol method) +
    • +
    • (evennia.server.portal.telnet.TelnetProtocol method) +
    • +
    • (evennia.server.portal.telnet_oob.TelnetOOB method)
    • (evennia.server.portal.webclient_ajax.AjaxWebClientSession method)
    • @@ -3368,6 +3253,8 @@
      + +
    • delete_attribute() (evennia.typeclasses.attributes.IAttributeBackend method) +
    • delete_default() (evennia.commands.cmdsethandler.CmdSetHandler method)
    • delete_prototype() (in module evennia.prototypes.prototypes) @@ -3761,6 +3636,12 @@
    • deny() (in module evennia.contrib.ingame_python.eventfuncs)
    • desc() (evennia.scripts.models.ScriptDB property) +
    • +
    • desc_add_lamp_broken (evennia.contrib.tutorial_examples.red_button.RedButton attribute) +
    • +
    • desc_closed_lid (evennia.contrib.tutorial_examples.red_button.RedButton attribute) +
    • +
    • desc_open_lid (evennia.contrib.tutorial_examples.red_button.RedButton attribute)
    • DescValidateError
    • @@ -3791,6 +3672,8 @@
    • destination() (evennia.objects.models.ObjectDB property)
    • destinations_set (evennia.objects.models.ObjectDB attribute) +
    • +
    • destroy_channel() (evennia.commands.default.comms.CmdChannel method)
    • detail_color (evennia.commands.default.building.CmdExamine attribute)
    • @@ -3799,6 +3682,10 @@
    • directions (evennia.commands.default.building.CmdTunnel attribute)
    • directoryListing() (evennia.server.webserver.PrivateStaticRoot method) +
    • +
    • disableLocal() (evennia.server.portal.telnet.TelnetProtocol method) +
    • +
    • disableRemote() (evennia.server.portal.telnet.TelnetProtocol method)
    • disconnect() (evennia.comms.comms.DefaultChannel method) @@ -3812,6 +3699,8 @@
    • (evennia.server.portal.rss.RSSReader method)
    • (evennia.server.portal.ssh.SshProtocol method) +
    • +
    • (evennia.server.portal.telnet.TelnetProtocol method)
    • (evennia.server.portal.webclient.WebSocketClient method)
    • @@ -3844,6 +3733,8 @@
    • (evennia.utils.optionclasses.Color method)
    • +
    • display_all_channels() (evennia.commands.default.comms.CmdChannel method) +
    • display_buffer() (evennia.utils.eveditor.EvEditor method)
    • display_choice() (evennia.contrib.building_menu.BuildingMenu method) @@ -3863,20 +3754,66 @@
    • display_meter() (in module evennia.contrib.health_bar)
    • display_nodetext() (evennia.utils.evmenu.EvMenu method) +
    • +
    • display_subbed_channels() (evennia.commands.default.comms.CmdChannel method)
    • display_title() (evennia.contrib.building_menu.BuildingMenu method)
    • distance_inc() (in module evennia.contrib.turnbattle.tb_range)
    • distribute_message() (evennia.comms.comms.DefaultChannel method) -
    • -
    • div() (in module evennia.prototypes.protfuncs)
    • DjangoWebRoot (class in evennia.server.webserver)
    • do_attack() (evennia.contrib.tutorial_world.mob.Mob method) +
    • +
    • do_batch_delete() (evennia.typeclasses.attributes.IAttributeBackend method) +
    • +
    • do_batch_finish() (evennia.typeclasses.attributes.IAttributeBackend method) + +
    • +
    • do_batch_update_attribute() (evennia.typeclasses.attributes.IAttributeBackend method) + +
    • +
    • do_create_attribute() (evennia.typeclasses.attributes.IAttributeBackend method) + +
    • +
    • do_delete_attribute() (evennia.typeclasses.attributes.IAttributeBackend method) + +
    • +
    • do_gmcp() (evennia.server.portal.telnet_oob.TelnetOOB method)
    • do_hunting() (evennia.contrib.tutorial_world.mob.Mob method) +
    • +
    • do_mccp() (evennia.server.portal.mccp.Mccp method) +
    • +
    • do_msdp() (evennia.server.portal.telnet_oob.TelnetOOB method) +
    • +
    • do_mssp() (evennia.server.portal.mssp.Mssp method) +
    • +
    • do_mxp() (evennia.server.portal.mxp.Mxp method) +
    • +
    • do_naws() (evennia.server.portal.naws.Naws method)
    • do_nested_lookup() (evennia.commands.default.building.CmdSetAttribute method)
    • @@ -3885,6 +3822,8 @@
    • do_patrol() (evennia.contrib.tutorial_world.mob.Mob method)
    • do_pickle() (in module evennia.utils.dbserialize) +
    • +
    • do_search() (evennia.commands.default.help.CmdHelp method)
    • do_task() (evennia.scripts.taskhandler.TaskHandler method) @@ -3892,8 +3831,18 @@
    • (evennia.scripts.taskhandler.TaskHandlerTask method), [1]
    • +
    • do_task_action() (evennia.commands.default.system.CmdTasks method) +
    • do_unpickle() (in module evennia.utils.dbserialize)
    • +
    • do_update_attribute() (evennia.typeclasses.attributes.IAttributeBackend method) + +
    • DoNothing (class in evennia.scripts.scripts)
    • DoNothing.DoesNotExist @@ -3903,6 +3852,8 @@
    • DummyClient (class in evennia.server.profiling.dummyrunner)
    • DummyFactory (class in evennia.server.profiling.dummyrunner) +
    • +
    • DummyRunnerCmdSet (class in evennia.server.profiling.dummyrunner)
    • DummySession (class in evennia.server.sessionhandler)
    • @@ -3947,8 +3898,16 @@
    • EmoteError
    • empty_threadpool() (evennia.server.webserver.DjangoWebRoot method) +
    • +
    • enableLocal() (evennia.server.portal.telnet.TelnetProtocol method) +
    • +
    • enableRemote() (evennia.server.portal.telnet.TelnetProtocol method)
    • encode() (evennia.utils.ansi.ANSIString method) +
    • +
    • encode_gmcp() (evennia.server.portal.telnet_oob.TelnetOOB method) +
    • +
    • encode_msdp() (evennia.server.portal.telnet_oob.TelnetOOB method)
    • END() (in module evennia.contrib.talking_npc)
    • @@ -3990,8 +3949,6 @@
    • (evennia.server.portal.amp.MsgStatus attribute)
    • -
    • eval() (in module evennia.prototypes.protfuncs) -
    • EvCell (class in evennia.utils.evtable)
    • EvColumn (class in evennia.utils.evtable) @@ -4021,13 +3978,6 @@
    • -
    • - evennia.accounts.admin - -
    • @@ -4210,20 +4160,6 @@
    • -
    • - evennia.comms.admin - -
    • -
    • - evennia.comms.channelhandler - -
    • @@ -4546,13 +4482,6 @@
    • -
    • - evennia.contrib.tutorial_examples.cmdset_red_button - -
    • @@ -4560,13 +4489,6 @@
    • -
    • - evennia.contrib.tutorial_examples.red_button_scripts - -
    • @@ -4630,13 +4552,6 @@
    • -
    • - evennia.help.admin - -
    • @@ -4679,13 +4594,6 @@
    • -
    • - evennia.objects.admin - -
    • @@ -4749,15 +4657,6 @@
    • -
        -
      • - evennia.scripts.admin - -
      • @@ -4788,6 +4687,8 @@
      • module
      +
      • evennia.scripts.scripts @@ -4814,13 +4715,6 @@
      • -
      • - evennia.server.admin - -
      • @@ -4933,6 +4827,41 @@
      • +
      • + evennia.server.portal.mccp + +
      • +
      • + evennia.server.portal.mssp + +
      • +
      • + evennia.server.portal.mxp + +
      • +
      • + evennia.server.portal.naws + +
      • +
      • + evennia.server.portal.portal + +
      • @@ -4954,6 +4883,55 @@
      • +
      • + evennia.server.portal.ssl + +
      • +
      • + evennia.server.portal.suppress_ga + +
      • +
      • + evennia.server.portal.telnet + +
      • +
      • + evennia.server.portal.telnet_oob + +
      • +
      • + evennia.server.portal.telnet_ssl + +
      • +
      • + evennia.server.portal.tests + +
      • +
      • + evennia.server.portal.ttype + +
      • @@ -5094,13 +5072,6 @@
      • -
      • - evennia.typeclasses.admin - -
      • @@ -5241,13 +5212,6 @@
      • -
      • - evennia.utils.inlinefuncs - -
      • @@ -5402,13 +5366,6 @@
      • -
      • - evennia.web.website.templatetags.addclass - -
      • @@ -5432,23 +5389,13 @@
      • module
      -
    • evennia_admin() (in module evennia.web.website.views) -
    • evennia_version() (in module evennia.server.evennia_launcher) -
    • -
    • EvenniaCreateView (class in evennia.web.website.views) -
    • -
    • EvenniaDeleteView (class in evennia.web.website.views) -
    • -
    • EvenniaDetailView (class in evennia.web.website.views)
    • EvenniaForm (class in evennia.web.website.forms)
    • EvenniaGameIndexClient (class in evennia.server.game_index_client.client)
    • EvenniaGameIndexService (class in evennia.server.game_index_client.service) -
    • -
    • EvenniaIndexView (class in evennia.web.website.views)
    • EvenniaLogFile (class in evennia.utils.logger)
    • @@ -5457,8 +5404,6 @@
    • EvenniaReverseProxyResource (class in evennia.server.webserver)
    • EvenniaTest (class in evennia.utils.test_resources) -
    • -
    • EvenniaUpdateView (class in evennia.web.website.views)
    • EvenniaUsernameAvailabilityValidator (class in evennia.server.validators)
    • @@ -5540,14 +5485,6 @@
    • external_discord_hello() (in module evennia.server.inputfuncs)
    • -
    • extra (evennia.accounts.admin.AccountInline attribute) - -
    • extract_goto_exec() (evennia.utils.evmenu.EvMenu method)
    • ExtraInfoAuthServer (class in evennia.server.portal.ssh) @@ -5586,44 +5523,12 @@
    • FieldEvMenu (class in evennia.contrib.fieldfill)
    • -
    • fields (evennia.accounts.admin.AccountDBChangeForm.Meta attribute) +
    • fields (evennia.web.website.forms.AccountForm.Meta attribute)
    • -
    • fieldsets (evennia.accounts.admin.AccountDBAdmin attribute) - -
    • fill() (in module evennia.utils.evtable) @@ -5662,40 +5567,8 @@
    • for_contents() (evennia.objects.objects.DefaultObject method)
    • -
    • force_repeat() (evennia.scripts.scripts.DefaultScript method) -
    • -
    • form (evennia.accounts.admin.AccountDBAdmin attribute) - -
    • -
    • form_class (evennia.web.website.views.AccountMixin attribute) - -
    • form_template_to_dict() (in module evennia.contrib.fieldfill)
    • -
    • form_valid() (evennia.web.website.views.AccountCreateView method) - -
    • format() (evennia.utils.ansi.ANSIString method)
    • format_attributes() (evennia.commands.default.building.CmdExamine method) @@ -5707,12 +5580,14 @@
    • format_diff() (in module evennia.prototypes.spawner)
    • format_external() (evennia.comms.comms.DefaultChannel method) +
    • +
    • format_grid() (in module evennia.utils.utils)
    • format_help() (evennia.contrib.unixcommand.UnixCommandParser method)
    • -
    • format_help_entry() (evennia.commands.default.help.CmdHelp static method) +
    • format_help_entry() (evennia.commands.default.help.CmdHelp method)
    • -
    • format_help_list() (evennia.commands.default.help.CmdHelp static method) +
    • format_help_index() (evennia.commands.default.help.CmdHelp method)
    • format_message() (evennia.comms.comms.DefaultChannel method)
    • @@ -5728,12 +5603,6 @@
    • formfield() (evennia.utils.picklefield.PickledObjectField method)
    • -
    • formset (evennia.typeclasses.admin.AttributeInline attribute) - -
    • from_db_value() (evennia.utils.picklefield.PickledObjectField method)
    • from_pickle() (in module evennia.utils.dbserialize) @@ -5741,8 +5610,6 @@
    • fromBox() (evennia.server.portal.amp.Compressed method)
    • fromString() (evennia.server.portal.amp.Compressed method) -
    • -
    • full_justify() (in module evennia.prototypes.protfuncs)
    • func() (evennia.commands.command.Command method) @@ -5853,11 +5720,9 @@
    • (evennia.commands.default.comms.CmdCdestroy method)
    • -
    • (evennia.commands.default.comms.CmdCemit method) +
    • (evennia.commands.default.comms.CmdChannel method)
    • (evennia.commands.default.comms.CmdChannelCreate method) -
    • -
    • (evennia.commands.default.comms.CmdChannels method)
    • (evennia.commands.default.comms.CmdClock method)
    • @@ -5910,8 +5775,6 @@
    • (evennia.commands.default.syscommands.SystemNoInput method)
    • (evennia.commands.default.syscommands.SystemNoMatch method) -
    • -
    • (evennia.commands.default.syscommands.SystemSendToChannel method)
    • (evennia.commands.default.system.CmdAbout method)
    • @@ -5930,6 +5793,8 @@
    • (evennia.commands.default.system.CmdService method)
    • (evennia.commands.default.system.CmdShutdown method) +
    • +
    • (evennia.commands.default.system.CmdTasks method)
    • (evennia.commands.default.system.CmdTime method)
    • @@ -5944,8 +5809,6 @@
    • (evennia.commands.default.unloggedin.CmdUnconnectedLook method)
    • (evennia.commands.default.unloggedin.CmdUnconnectedQuit method) -
    • -
    • (evennia.comms.channelhandler.ChannelCommand method)
    • (evennia.contrib.barter.CmdAccept method)
    • @@ -6135,19 +5998,21 @@
    • (evennia.contrib.turnbattle.tb_range.CmdWithdraw method)
    • -
    • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdBlindHelp method) +
    • (evennia.contrib.tutorial_examples.red_button.CmdBlindHelp method)
    • -
    • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdBlindLook method) +
    • (evennia.contrib.tutorial_examples.red_button.CmdBlindLook method)
    • -
    • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdCloseLid method) +
    • (evennia.contrib.tutorial_examples.red_button.CmdCloseLid method)
    • -
    • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdNudge method) +
    • (evennia.contrib.tutorial_examples.red_button.CmdNudge method)
    • -
    • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdOpenLid method) +
    • (evennia.contrib.tutorial_examples.red_button.CmdOpenLid method)
    • -
    • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdPush method) +
    • (evennia.contrib.tutorial_examples.red_button.CmdPushLidClosed method)
    • -
    • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdSmashGlass method) +
    • (evennia.contrib.tutorial_examples.red_button.CmdPushLidOpen method) +
    • +
    • (evennia.contrib.tutorial_examples.red_button.CmdSmashGlass method)
    • (evennia.contrib.tutorial_world.mob.CmdMobOnOff method)
    • @@ -6192,6 +6057,8 @@
    • (evennia.contrib.unixcommand.UnixCommand method)
    • (evennia.objects.objects.ExitCommand method) +
    • +
    • (evennia.server.profiling.dummyrunner.CmdDummyRunnerEchoResponse method)
    • (evennia.utils.eveditor.CmdEditorGroup method)
    • @@ -6202,6 +6069,8 @@
    • (evennia.utils.evmenu.CmdEvMenuNode method)
    • (evennia.utils.evmenu.CmdGetInput method) +
    • +
    • (evennia.utils.evmenu.CmdYesNoQuestion method)
    • (evennia.utils.evmore.CmdMore method)
    • @@ -6210,6 +6079,8 @@
      -
    • get_display_name() (evennia.contrib.rpsystem.ContribRPCharacter method) +
    • get_display_name() (evennia.accounts.accounts.DefaultAccount method)
    • -
    • get_info_dict() (evennia.server.server.Evennia method) -
    • -
    • get_initial() (evennia.web.website.views.ObjectUpdateView method) +
    • get_info_dict() (evennia.server.portal.portal.Portal method) + +
    • get_input() (in module evennia.utils.evmenu)
    • get_inputfuncs() (evennia.server.sessionhandler.ServerSessionHandler method) @@ -6534,9 +6391,9 @@
    • get_location_name() (evennia.contrib.wilderness.WildernessMapProvider method)
    • -
    • get_message_by_id() (evennia.comms.managers.MsgManager method) +
    • get_log_filename() (evennia.comms.comms.DefaultChannel method)
    • -
    • get_messages_by_channel() (evennia.comms.managers.MsgManager method) +
    • get_message_by_id() (evennia.comms.managers.MsgManager method)
    • get_messages_by_receiver() (evennia.comms.managers.MsgManager method)
    • @@ -6558,6 +6415,8 @@
    • (evennia.comms.models.ChannelDB method)
    • (evennia.comms.models.Msg method) +
    • +
    • (evennia.help.models.HelpEntry method)
    • (evennia.objects.models.ObjectDB method)
    • @@ -6582,14 +6441,6 @@
    • get_obj_coordinates() (evennia.contrib.wilderness.WildernessScript method)
    • -
    • get_object() (evennia.web.website.views.ChannelDetailView method) - -
    • get_objs_at_coordinates() (evennia.contrib.wilderness.WildernessScript method)
    • get_other() (evennia.contrib.barter.TradeHandler method) @@ -6597,6 +6448,8 @@
    • get_permission() (evennia.typeclasses.managers.TypedObjectManager method)
    • get_pid() (in module evennia.server.evennia_launcher) +
    • +
    • get_player_count() (evennia.server.portal.mssp.Mssp method)
    • get_previous_by_date_joined() (evennia.accounts.models.AccountDB method)
    • @@ -6606,6 +6459,8 @@
    • (evennia.comms.models.ChannelDB method)
    • (evennia.comms.models.Msg method) +
    • +
    • (evennia.help.models.HelpEntry method)
    • (evennia.objects.models.ObjectDB method)
    • @@ -6624,21 +6479,7 @@
    • get_puppet_or_account() (evennia.server.serversession.ServerSession method)
    • -
    • get_queryset() (evennia.web.website.views.ChannelMixin method) - -
    • get_range() (in module evennia.contrib.turnbattle.tb_range) -
    • -
    • get_redirect_url() (evennia.web.website.views.CharacterPuppetView method)
    • get_regex_tuple() (evennia.contrib.rpsystem.RecogHandler method) @@ -6651,8 +6492,6 @@
    • get_status() (evennia.server.portal.amp_server.AMPServerProtocol method)
    • get_subscriptions() (evennia.comms.managers.ChannelDBManager method) -
    • -
    • get_success_url() (evennia.web.website.views.ObjectUpdateView method)
    • get_sync_data() (evennia.server.session.Session method)
    • @@ -6663,6 +6502,8 @@
    • get_time_and_season() (evennia.contrib.extended_room.ExtendedRoom method)
    • get_typeclass_totals() (evennia.typeclasses.managers.TypedObjectManager method) +
    • +
    • get_uptime() (evennia.server.portal.mssp.Mssp method)
    • get_username_validators() (evennia.accounts.accounts.DefaultAccount class method)
    • @@ -6694,6 +6535,12 @@
    • getKeyPair() (in module evennia.server.portal.ssh)
    • +
    • getSSLContext() (in module evennia.server.portal.ssl) + +
    • gidcounter() (in module evennia.server.profiling.dummyrunner)
    • GlobalScriptContainer (class in evennia.utils.containers) @@ -6743,17 +6590,17 @@
    • handle_QUIT() (evennia.server.portal.ssh.SshProtocol method)
    • handle_setup() (in module evennia.server.initial_setup) +
    • +
    • handshake_done() (evennia.server.portal.telnet.TelnetProtocol method)
    • has() (evennia.commands.cmdsethandler.CmdSetHandler method)
    • has_account() (evennia.objects.objects.DefaultObject property) @@ -6887,11 +6734,9 @@
    • (evennia.commands.default.comms.CmdCdestroy attribute)
    • -
    • (evennia.commands.default.comms.CmdCemit attribute) +
    • (evennia.commands.default.comms.CmdChannel attribute)
    • (evennia.commands.default.comms.CmdChannelCreate attribute) -
    • -
    • (evennia.commands.default.comms.CmdChannels attribute)
    • (evennia.commands.default.comms.CmdClock attribute)
    • @@ -6946,8 +6791,6 @@
    • (evennia.commands.default.syscommands.SystemNoInput attribute)
    • (evennia.commands.default.syscommands.SystemNoMatch attribute) -
    • -
    • (evennia.commands.default.syscommands.SystemSendToChannel attribute)
    • (evennia.commands.default.system.CmdAbout attribute)
    • @@ -6966,6 +6809,8 @@
    • (evennia.commands.default.system.CmdService attribute)
    • (evennia.commands.default.system.CmdShutdown attribute) +
    • +
    • (evennia.commands.default.system.CmdTasks attribute)
    • (evennia.commands.default.system.CmdTime attribute)
    • @@ -6980,8 +6825,6 @@
    • (evennia.commands.default.unloggedin.CmdUnconnectedLook attribute)
    • (evennia.commands.default.unloggedin.CmdUnconnectedQuit attribute) -
    • -
    • (evennia.comms.channelhandler.ChannelCommand attribute)
    • (evennia.contrib.barter.CmdAccept attribute)
    • @@ -7179,19 +7022,21 @@
    • (evennia.contrib.turnbattle.tb_range.CmdWithdraw attribute)
    • -
    • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdBlindHelp attribute) +
    • (evennia.contrib.tutorial_examples.red_button.CmdBlindHelp attribute)
    • -
    • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdBlindLook attribute) +
    • (evennia.contrib.tutorial_examples.red_button.CmdBlindLook attribute)
    • -
    • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdCloseLid attribute) +
    • (evennia.contrib.tutorial_examples.red_button.CmdCloseLid attribute)
    • -
    • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdNudge attribute) +
    • (evennia.contrib.tutorial_examples.red_button.CmdNudge attribute)
    • -
    • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdOpenLid attribute) +
    • (evennia.contrib.tutorial_examples.red_button.CmdOpenLid attribute)
    • -
    • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdPush attribute) +
    • (evennia.contrib.tutorial_examples.red_button.CmdPushLidClosed attribute)
    • -
    • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdSmashGlass attribute) +
    • (evennia.contrib.tutorial_examples.red_button.CmdPushLidOpen attribute) +
    • +
    • (evennia.contrib.tutorial_examples.red_button.CmdSmashGlass attribute)
    • (evennia.contrib.tutorial_world.mob.CmdMobOnOff attribute)
    • @@ -7236,6 +7081,8 @@
    • (evennia.contrib.unixcommand.UnixCommand attribute)
    • (evennia.objects.objects.ExitCommand attribute) +
    • +
    • (evennia.server.profiling.dummyrunner.CmdDummyRunnerEchoResponse attribute)
    • (evennia.utils.eveditor.CmdEditorBase attribute)
    • @@ -7248,6 +7095,8 @@
    • (evennia.utils.evmenu.CmdEvMenuNode attribute)
    • (evennia.utils.evmenu.CmdGetInput attribute) +
    • +
    • (evennia.utils.evmenu.CmdYesNoQuestion attribute)
    • (evennia.utils.evmore.CmdMore attribute)
    • @@ -7267,8 +7116,6 @@
    • help_more (evennia.commands.default.help.CmdHelp attribute)
    • HelpAction (class in evennia.contrib.unixcommand) -
    • -
    • HelpDetailView (class in evennia.web.website.views)
    • HelpEntry (class in evennia.help.models)
    • @@ -7277,20 +7124,8 @@
    • HelpEntry.MultipleObjectsReturned
    • helpentry_set (evennia.typeclasses.tags.Tag attribute) -
    • -
    • HelpEntryAdmin (class in evennia.help.admin) -
    • -
    • HelpEntryForm (class in evennia.help.admin) -
    • -
    • HelpEntryForm.Meta (class in evennia.help.admin)
    • HelpEntryManager (class in evennia.help.manager) -
    • -
    • HelpListView (class in evennia.web.website.views) -
    • -
    • HelpMixin (class in evennia.web.website.views) -
    • -
    • HelpTagInline (class in evennia.help.admin)
    • helptext_formatter() (evennia.prototypes.menus.OLCMenu method) @@ -7301,8 +7136,6 @@
    • hide_from() (evennia.comms.models.Msg property)
    • hide_from_accounts_set (evennia.accounts.models.AccountDB attribute) -
    • -
    • hide_from_channels_set (evennia.comms.models.ChannelDB attribute)
    • hide_from_objects_set (evennia.objects.models.ObjectDB attribute)
    • @@ -7326,6 +7159,10 @@

      I

    • initialize_for_combat() (evennia.contrib.turnbattle.tb_basic.TBBasicTurnHandler method) @@ -7452,30 +7301,16 @@
    • (evennia.contrib.turnbattle.tb_magic.TBMagicTurnHandler method)
    • (evennia.contrib.turnbattle.tb_range.TBRangeTurnHandler method) -
    • - -
    • initialize_nick_templates() (in module evennia.typeclasses.attributes) - -
    • -
    • InlinefuncError -
    • -
    • inlines (evennia.accounts.admin.AccountDBAdmin attribute) - -
    • -
    • key_mergetype (evennia.contrib.tutorial_examples.cmdset_red_button.LidClosedCmdSet attribute) - -
    • key_mergetypes (evennia.commands.cmdset.CmdSet attribute) @@ -8258,6 +8083,8 @@
    • (evennia.web.website.forms.ObjectForm.Meta attribute)
    • +
    • lamp_breaks_msg (evennia.contrib.tutorial_examples.red_button.RedButton attribute) +
    • LanguageError, [1]
    • LanguageExistsError @@ -8276,11 +8103,9 @@
    • leave() (evennia.contrib.building_menu.Choice method)
    • -
    • left_justify() (in module evennia.prototypes.protfuncs) +
    • LidClosedCmdSet (class in evennia.contrib.tutorial_examples.red_button)
    • -
    • LidClosedCmdSet (class in evennia.contrib.tutorial_examples.cmdset_red_button) -
    • -
    • LidOpenCmdSet (class in evennia.contrib.tutorial_examples.cmdset_red_button) +
    • LidOpenCmdSet (class in evennia.contrib.tutorial_examples.red_button)
    • light() (evennia.contrib.tutorial_world.objects.LightSource method)
    • @@ -8304,62 +8129,12 @@
    • list_callbacks() (evennia.contrib.ingame_python.commands.CmdCallback method)
    • -
    • list_display (evennia.accounts.admin.AccountDBAdmin attribute) - -
    • -
    • list_display_links (evennia.comms.admin.ChannelAdmin attribute) - -
    • -
    • list_filter (evennia.objects.admin.ObjectDBAdmin attribute) - -
    • list_node() (in module evennia.utils.evmenu)
    • list_prototypes() (in module evennia.prototypes.prototypes)
    • -
    • list_select_related (evennia.comms.admin.ChannelAdmin attribute) - -
    • list_settings() (in module evennia.server.evennia_launcher)
    • list_styles() (evennia.commands.default.account.CmdStyle method) @@ -8370,9 +8145,11 @@
    • ljust() (evennia.utils.ansi.ANSIString method)
    • -
    • load() (evennia.scripts.taskhandler.TaskHandler method) +
    • load() (evennia.objects.models.ContentsHandler method)
    • @@ -8521,11 +8298,9 @@
    • (evennia.commands.default.comms.CmdCdestroy attribute)
    • -
    • (evennia.commands.default.comms.CmdCemit attribute) +
    • (evennia.commands.default.comms.CmdChannel attribute)
    • (evennia.commands.default.comms.CmdChannelCreate attribute) -
    • -
    • (evennia.commands.default.comms.CmdChannels attribute)
    • (evennia.commands.default.comms.CmdClock attribute)
    • @@ -8580,8 +8355,6 @@
    • (evennia.commands.default.syscommands.SystemNoInput attribute)
    • (evennia.commands.default.syscommands.SystemNoMatch attribute) -
    • -
    • (evennia.commands.default.syscommands.SystemSendToChannel attribute)
    • (evennia.commands.default.system.CmdAbout attribute)
    • @@ -8600,6 +8373,8 @@
    • (evennia.commands.default.system.CmdService attribute)
    • (evennia.commands.default.system.CmdShutdown attribute) +
    • +
    • (evennia.commands.default.system.CmdTasks attribute)
    • (evennia.commands.default.system.CmdTime attribute)
    • @@ -8614,8 +8389,6 @@
    • (evennia.commands.default.unloggedin.CmdUnconnectedLook attribute)
    • (evennia.commands.default.unloggedin.CmdUnconnectedQuit attribute) -
    • -
    • (evennia.comms.channelhandler.ChannelCommand attribute)
    • (evennia.contrib.barter.CmdAccept attribute)
    • @@ -8813,19 +8586,21 @@
    • (evennia.contrib.turnbattle.tb_range.CmdWithdraw attribute)
    • -
    • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdBlindHelp attribute) +
    • (evennia.contrib.tutorial_examples.red_button.CmdBlindHelp attribute)
    • -
    • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdBlindLook attribute) +
    • (evennia.contrib.tutorial_examples.red_button.CmdBlindLook attribute)
    • -
    • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdCloseLid attribute) +
    • (evennia.contrib.tutorial_examples.red_button.CmdCloseLid attribute)
    • -
    • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdNudge attribute) +
    • (evennia.contrib.tutorial_examples.red_button.CmdNudge attribute)
    • -
    • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdOpenLid attribute) +
    • (evennia.contrib.tutorial_examples.red_button.CmdOpenLid attribute)
    • -
    • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdPush attribute) +
    • (evennia.contrib.tutorial_examples.red_button.CmdPushLidClosed attribute)
    • -
    • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdSmashGlass attribute) +
    • (evennia.contrib.tutorial_examples.red_button.CmdPushLidOpen attribute) +
    • +
    • (evennia.contrib.tutorial_examples.red_button.CmdSmashGlass attribute)
    • (evennia.contrib.tutorial_world.mob.CmdMobOnOff attribute)
    • @@ -8870,6 +8645,8 @@
    • (evennia.contrib.unixcommand.UnixCommand attribute)
    • (evennia.objects.objects.ExitCommand attribute) +
    • +
    • (evennia.server.profiling.dummyrunner.CmdDummyRunnerEchoResponse attribute)
    • (evennia.utils.eveditor.CmdEditorBase attribute)
    • @@ -8882,6 +8659,8 @@
    • (evennia.utils.evmenu.CmdEvMenuNode attribute)
    • (evennia.utils.evmenu.CmdGetInput attribute) +
    • +
    • (evennia.utils.evmenu.CmdYesNoQuestion attribute)
    • (evennia.utils.evmore.CmdMore attribute)
    • @@ -8896,6 +8675,8 @@
    • (evennia.help.models.HelpEntry property)
    • (evennia.typeclasses.attributes.Attribute property) +
    • +
    • (evennia.typeclasses.attributes.IAttribute property)
    • (evennia.typeclasses.models.TypedObject property)
    • @@ -9015,11 +8796,9 @@
    • (evennia.commands.default.comms.CmdCdestroy attribute)
    • -
    • (evennia.commands.default.comms.CmdCemit attribute) +
    • (evennia.commands.default.comms.CmdChannel attribute)
    • (evennia.commands.default.comms.CmdChannelCreate attribute) -
    • -
    • (evennia.commands.default.comms.CmdChannels attribute)
    • (evennia.commands.default.comms.CmdClock attribute)
    • @@ -9070,8 +8849,6 @@
    • (evennia.commands.default.syscommands.SystemNoInput attribute)
    • (evennia.commands.default.syscommands.SystemNoMatch attribute) -
    • -
    • (evennia.commands.default.syscommands.SystemSendToChannel attribute)
    • (evennia.commands.default.system.CmdAbout attribute)
    • @@ -9090,6 +8867,8 @@
    • (evennia.commands.default.system.CmdService attribute)
    • (evennia.commands.default.system.CmdShutdown attribute) +
    • +
    • (evennia.commands.default.system.CmdTasks attribute)
    • (evennia.commands.default.system.CmdTime attribute)
    • @@ -9181,19 +8960,21 @@
    • (evennia.contrib.talking_npc.CmdTalk attribute)
    • -
    • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdBlindHelp attribute) +
    • (evennia.contrib.tutorial_examples.red_button.CmdBlindHelp attribute)
    • -
    • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdBlindLook attribute) +
    • (evennia.contrib.tutorial_examples.red_button.CmdBlindLook attribute)
    • -
    • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdCloseLid attribute) +
    • (evennia.contrib.tutorial_examples.red_button.CmdCloseLid attribute)
    • -
    • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdNudge attribute) +
    • (evennia.contrib.tutorial_examples.red_button.CmdNudge attribute)
    • -
    • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdOpenLid attribute) +
    • (evennia.contrib.tutorial_examples.red_button.CmdOpenLid attribute)
    • -
    • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdPush attribute) +
    • (evennia.contrib.tutorial_examples.red_button.CmdPushLidClosed attribute)
    • -
    • (evennia.contrib.tutorial_examples.cmdset_red_button.CmdSmashGlass attribute) +
    • (evennia.contrib.tutorial_examples.red_button.CmdPushLidOpen attribute) +
    • +
    • (evennia.contrib.tutorial_examples.red_button.CmdSmashGlass attribute)
    • (evennia.contrib.tutorial_world.mob.CmdMobOnOff attribute)
    • @@ -9231,7 +9012,7 @@
    • (evennia.help.models.HelpEntry attribute)
    • -
    • (evennia.typeclasses.attributes.Attribute attribute) +
    • (evennia.typeclasses.attributes.IAttribute attribute)
    • (evennia.typeclasses.models.TypedObject attribute)
    • @@ -9265,8 +9046,12 @@
    • log_err() (in module evennia.utils.logger)
    • log_errmsg() (in module evennia.utils.logger) +
    • +
    • log_file (evennia.comms.comms.DefaultChannel attribute)
    • log_file() (in module evennia.utils.logger) +
    • +
    • log_file_exists() (in module evennia.utils.logger)
    • log_info() (in module evennia.utils.logger)
    • @@ -9310,6 +9095,8 @@ -
    • maxDiff (evennia.web.utils.tests.TestGeneralContext attribute) +
    • (evennia.server.profiling.dummyrunner.DummyFactory attribute)
    • -
    • media() (evennia.accounts.admin.AccountAttributeInline property) +
    • +
    • maxDiff (evennia.commands.default.tests.TestHelp attribute)
    • +
    • Mccp (class in evennia.server.portal.mccp)
    • -
    • (evennia.accounts.admin.AccountDBCreationForm property) -
    • -
    • (evennia.accounts.admin.AccountForm property) -
    • -
    • (evennia.accounts.admin.AccountInline property) -
    • -
    • (evennia.accounts.admin.AccountTagInline property) -
    • -
    • (evennia.comms.admin.ChannelAdmin property) -
    • -
    • (evennia.comms.admin.ChannelAttributeInline property) -
    • -
    • (evennia.comms.admin.ChannelTagInline property) -
    • -
    • (evennia.comms.admin.MsgAdmin property) -
    • -
    • (evennia.help.admin.HelpEntryAdmin property) -
    • -
    • (evennia.help.admin.HelpEntryForm property) -
    • -
    • (evennia.help.admin.HelpTagInline property) -
    • -
    • (evennia.objects.admin.ObjectAttributeInline property) -
    • -
    • (evennia.objects.admin.ObjectCreateForm property) -
    • -
    • (evennia.objects.admin.ObjectDBAdmin property) -
    • -
    • (evennia.objects.admin.ObjectEditForm property) -
    • -
    • (evennia.objects.admin.ObjectTagInline property) -
    • -
    • (evennia.scripts.admin.ScriptAttributeInline property) -
    • -
    • (evennia.scripts.admin.ScriptDBAdmin property) -
    • -
    • (evennia.scripts.admin.ScriptTagInline property) -
    • -
    • (evennia.server.admin.ServerConfigAdmin property) -
    • -
    • (evennia.typeclasses.admin.AttributeForm property) -
    • -
    • (evennia.typeclasses.admin.AttributeInline property) -
    • -
    • (evennia.typeclasses.admin.TagAdmin property) -
    • -
    • (evennia.typeclasses.admin.TagForm property) -
    • -
    • (evennia.typeclasses.admin.TagInline property) -
    • -
    • (evennia.utils.picklefield.PickledWidget property) +
    • mccp_compress() (in module evennia.server.portal.mccp)
    • +
    • media() (evennia.utils.picklefield.PickledWidget property) + +
    • -
    • mult() (in module evennia.prototypes.protfuncs) +
    • Mssp (class in evennia.server.portal.mssp)
    • mute() (evennia.comms.comms.DefaultChannel method) +
    • +
    • mute_channel() (evennia.commands.default.comms.CmdChannel method)
    • mutelist() (evennia.comms.comms.DefaultChannel property)
    • MuxAccountCommand (class in evennia.commands.default.muxcommand)
    • MuxCommand (class in evennia.commands.default.muxcommand) +
    • +
    • Mxp (class in evennia.server.portal.mxp) +
    • +
    • mxp_parse() (in module evennia.server.portal.mxp)
    • mxp_re (evennia.utils.ansi.ANSIParser attribute)
    • mxp_sub (evennia.utils.ansi.ANSIParser attribute) +
    • +
    • mxp_url_re (evennia.utils.ansi.ANSIParser attribute) +
    • +
    • mxp_url_sub (evennia.utils.ansi.ANSIParser attribute)
    • @@ -10103,12 +9804,6 @@ -
    • NAttributeHandler (class in evennia.server.serversession) - -
    • nattributes (evennia.server.serversession.ServerSession attribute) @@ -10117,6 +9812,8 @@
    • (evennia.typeclasses.models.TypedObject attribute)
    • +
    • Naws (class in evennia.server.portal.naws) +
    • ndb() (evennia.server.serversession.ServerSession property)
    • -
    • NickTemplateInvalid, [1] +
    • NickTemplateInvalid
    • no_channels (evennia.commands.cmdset.CmdSet attribute) @@ -10173,12 +9870,14 @@
    • (evennia.utils.evmenu.EvMenuCmdSet attribute)
    • (evennia.utils.evmenu.InputCmdSet attribute) +
    • +
    • (evennia.utils.evmenu.YesNoQuestionCmdSet attribute)
    • no_exits (evennia.commands.cmdset.CmdSet attribute)
    • +
    • no_gmcp() (evennia.server.portal.telnet_oob.TelnetOOB method) +
    • +
    • no_mccp() (evennia.server.portal.mccp.Mccp method) +
    • +
    • no_msdp() (evennia.server.portal.telnet_oob.TelnetOOB method) +
    • +
    • no_mssp() (evennia.server.portal.mssp.Mssp method) +
    • +
    • no_mxp() (evennia.server.portal.mxp.Mxp method) +
    • +
    • no_naws() (evennia.server.portal.naws.Naws method) +
    • +
    • nomatch() (evennia.contrib.building_menu.Choice method) - -
    • nonce (evennia.server.portal.webclient.WebSocketClient attribute)
    • none() (in module evennia.locks.lockfuncs)
    • normal (evennia.utils.text2html.TextToHTMLparser attribute) +
    • +
    • normalize_name() (evennia.objects.objects.DefaultCharacter class method)
    • normalize_username() (evennia.accounts.accounts.DefaultAccount class method)
    • not_found (evennia.commands.default.building.CmdSetAttribute attribute) -
    • -
    • null() (in module evennia.utils.inlinefuncs)
    • num_lines_to_append (evennia.utils.logger.EvenniaLogFile attribute)
    • @@ -10313,20 +10028,14 @@
    • obfuscate_whisper() (in module evennia.contrib.rplanguage)
    • -
    • obj (evennia.comms.channelhandler.ChannelCommand attribute) +
    • obj (evennia.contrib.ingame_python.callbackhandler.Callback attribute)
    • obj() (evennia.scripts.models.ScriptDB property) - -
    • objattr() (in module evennia.locks.lockfuncs)
    • object() (evennia.scripts.models.ScriptDB property) @@ -10345,14 +10054,6 @@
    • (evennia.web.website.tests.EvenniaWebTest attribute)
    • -
    • ObjectAttributeInline (class in evennia.objects.admin) -
    • -
    • ObjectCreateForm (class in evennia.objects.admin) -
    • -
    • ObjectCreateForm.Meta (class in evennia.objects.admin) -
    • -
    • ObjectCreateView (class in evennia.web.website.views) -
    • ObjectDB (class in evennia.objects.models)
    • ObjectDB.DoesNotExist @@ -10367,16 +10068,6 @@
    • (evennia.typeclasses.tags.Tag attribute)
    • -
    • ObjectDBAdmin (class in evennia.objects.admin) -
    • -
    • ObjectDeleteView (class in evennia.web.website.views) -
    • -
    • ObjectDetailView (class in evennia.web.website.views) -
    • -
    • ObjectEditForm (class in evennia.objects.admin) -
    • -
    • ObjectEditForm.Meta (class in evennia.objects.admin) -
    • ObjectForm (class in evennia.web.website.forms)
    • ObjectForm.Meta (class in evennia.web.website.forms) @@ -10418,12 +10109,6 @@
      • ObjectSessionHandler (class in evennia.objects.objects) -
      • -
      • ObjectTagInline (class in evennia.objects.admin) -
      • -
      • ObjectUpdateView (class in evennia.web.website.views) -
      • -
      • objlist() (in module evennia.prototypes.protfuncs)
      • objlocattr() (in module evennia.locks.lockfuncs)
      • @@ -10456,20 +10141,12 @@
      • OOCCmdSetCharGen (class in evennia.contrib.chargen)
      • open() (evennia.contrib.building_menu.BuildingMenu method) -
      • -
      • open_lid() (evennia.contrib.tutorial_examples.red_button.RedButton method)
      • open_parent_menu() (evennia.contrib.building_menu.BuildingMenu method)
      • open_submenu() (evennia.contrib.building_menu.BuildingMenu method)
      • open_wall() (evennia.contrib.tutorial_world.objects.CrumblingWall method) -
      • -
      • OpenLidState (class in evennia.contrib.tutorial_examples.red_button_scripts) -
      • -
      • OpenLidState.DoesNotExist -
      • -
      • OpenLidState.MultipleObjectsReturned
      • OptionContainer (class in evennia.utils.containers)
      • @@ -10495,22 +10172,8 @@
      • ordered_permutation_regex() (in module evennia.contrib.rpsystem)
      • -
      • ordering (evennia.comms.admin.ChannelAdmin attribute) - -
      • OutroRoom (class in evennia.contrib.tutorial_world.rooms)
      • OutroRoom.DoesNotExist @@ -10523,12 +10186,8 @@

        P

        - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - -
      • parse_html() (in module evennia.utils.text2html) -
      • -
      • parse_inlinefunc() (in module evennia.utils.inlinefuncs)
      • parse_input() (evennia.utils.evmenu.EvMenu method)
      • @@ -10656,18 +10277,12 @@
      • parse_menu_template() (in module evennia.utils.evmenu)
      • parse_nick_template() (in module evennia.typeclasses.attributes) - -
      • parse_opts() (in module evennia.contrib.tree_select)
      • parse_sdescs_and_recogs() (in module evennia.contrib.rpsystem)
      • ParseError -
      • -
      • ParseStack (class in evennia.utils.inlinefuncs)
      • partition() (evennia.utils.ansi.ANSIString method)
      • @@ -10678,6 +10293,8 @@
      • path (evennia.accounts.accounts.DefaultAccount attribute)
      • -
      • press_button() (evennia.contrib.tutorial_examples.red_button.RedButton method) -
      • print_debug_info() (evennia.utils.evmenu.EvMenu method)
      • print_help() (evennia.contrib.unixcommand.UnixCommandParser method) @@ -11089,6 +10696,8 @@
      • (evennia.utils.evmenu.EvMenuCmdSet attribute)
      • (evennia.utils.evmenu.InputCmdSet attribute) +
      • +
      • (evennia.utils.evmenu.YesNoQuestionCmdSet attribute)
      • (evennia.utils.evmore.CmdSetMore attribute)
      • @@ -11103,11 +10712,11 @@
      • process_sdesc() (evennia.contrib.rpsystem.ContribRPCharacter method)
      • -
      • produce_weapon() (evennia.contrib.tutorial_world.objects.WeaponRack method) +
      • produce_weapon() (evennia.contrib.tutorial_world.objects.TutorialWeaponRack method) +
      • +
      • protfunc_callable_protkey() (in module evennia.prototypes.protfuncs)
      • protfunc_parser() (in module evennia.prototypes.prototypes) -
      • -
      • protkey() (in module evennia.prototypes.protfuncs)
      • proto_def() (in module evennia.contrib.puzzles)
      • @@ -11149,12 +10758,36 @@
        -
        diff --git a/docs/0.9.5/index.html b/docs/0.9.5/index.html index 17554161b7..7abdb2281a 100644 --- a/docs/0.9.5/index.html +++ b/docs/0.9.5/index.html @@ -118,7 +118,6 @@ time.

      • 0.9.5 (v0.9.5 branch)
      • -
        diff --git a/docs/0.9.5/objects.inv b/docs/0.9.5/objects.inv index 0c5ce08423b1c356bee3f617dcce6a2b73e29575..9d0cf0a5da773931b4afb0530ac0a57774c51c92 100644 GIT binary patch delta 70960 zcmXVXV|XRa^LA|K#I|ko#I|kQ$%(nKjg5^BHqOS{*yhI8W`j4+|Mz~Wt7f`qu9~j9 z*gbibP!}~&NuHpo9$oK^vF7W)+lBkJOYeS5*4OS8S3LS&n!c@;_VV=y{)LSxqA8Mi zl4j{W}wTtf$J)Gv7iYVs<7;Y{K(e!t-ir$%UKh3Oj3~tiG03_ZWQ>!(8D`n?qLt z#!?eaf+C3i9OIozQ~d3h6=A30@?Bo$OQJ$CzY)%Ao>T_LObJtSz|0xZt0R|qWS;m^ zx7xGJukVupd};FS@}trj)qR<(nuAMB=dua<0R(cLc9K_dL5iJ?*=ygeOulnh%{J3! zupq~d?yevk6;%yzT0W*p|Lu7d7Y57n$WpZ0>kW__$C!_3QC2vOeSoepu?vOL3KJa~ zo+2rrdw=Yi14mY^+_1uEp$#jlsWV~Xm_?9eaZqrVT4xPrOh?mldX}^MdRF%?n;Xl2 z+Afmt8o|m5frw*_Ty9JGX{fr{q(@Xq$x_wzEnL-WO)8zR<2K5We#!EqX7Kkxs}1Vi z(kCcRxj5KQ`Pah_lb!TgL!OhY$VYz_c2=&5c34Yka6%dpQ^f#2%^iT*U@8dM$W zKau18B&y{^CP?lhBiAEy89P;-Z6MHxTA76SrfYI+D(U_`hj`Npy|1&%iu948Ki?71 zs_x9PAvM5S?yGp%>fm}sMGla1Gb4kwq?mx5eSF^uPL%{PeWW0+bpS!rpDx}T9ROpqc;k1H=k5Z78J z%;}W+2SrYxs%FpRY~cp$pNu$JPIka{MihKQPz47QY+XVHp&|3#)TSrVYryl>e-a<` zp|MO@4Q7BpGB2uku9WOwF=4`uv``4k)_w zv|-wVXvlED64>TD{h+gIT;h>)gC4Vvn}f$CI>=S$a1&ij(b+{oI6%~9X442^ZjAkA zQ?DPDwIauOJM|hB^inYq)%F?JXO>krl(5p{u)o)%(4Oo8>azL>S;Q(h7hb4-s}oo$ ze^=aCV!r&5fOL(Q?T2z^uksF}qI}+8a=YOXNu#Y2Q`8>E-zJtz{HcCz>gJlH7{CAS zHRLnUg&chfpnp!xHIZi=?-^}Y%efM zW6td9$NDrst)d0=G70SES@MEy$V|h!m%f6`bZQ@`7>9c;d-jsTV1WvR10v!T|qTbV?J0MJ;}f; zUWYBAe)>}jXThz~Gy4st`&?^%s(6{D4kod&N;`9G$EsOr!}1RQZ(NFJw?v3%gW(J+ zzhD35h8*96d!|(jq_a23ZyQ~1lW>)#0NL~JOh}kW+PFK?s688V;bqd)eP;7$Gt&kp zZTX5G#(C)j$!$x7u8FienbQ&NqBX{XM z(A{@CHe3i{oBKM2)M?wj)wSC}mJ@*nnnkWuJZM#j6Smr6$6rZn(*2FNWKd}uM^+zR4$S?RGOq~VEW+KCpv--h-4}w}rEZVT@ z3e>_5yVpL&j+;aKEd18N@GGBBFj3e+w!*+~ryrV^e4QYy{dp(t+h8GUX!@c9c8#T7 zT=MVMxd;+S-rd$WT>h3=WnLuQ(LHuSYZ*POKFv7wJOv|&nO*sOx^2cc)RkHnmj$iu z3sw*~#;3Y@BGx&>xswnBO*haI{yzqbvYfaaXmdby7_k?61mXL>E9hhcKga+&9ML17 z9R6fi%rMa2Z1naiHQ1!;N~ZYm)Qy#Sk#n2 zwJeiGK2wN=(r|d`JoJQ)(z#Sll1&fI?0biWjIO{!N3ZeO4XBgQ*1nX@7MO+YCa0|$ z<|@eZWcQ^^{Y|ywNhaUhk|d3zSPOIjZHl--iVTQc7M+~$hh-G>e7IEX{Qf_03!psM z&r+^bxdj9%Qo9H;tyb}rF})BQPa%w$eTwAfzIBQ|m8CjTI)GD0IQ@z!ewjU>XPqlU z?iOFF{xwDpmqT`O=bL;x+HeEj!+N_8`zZls>s-bk->_ zC^!_?%l$t_yVO|lqz&pe)SCF}tf7?UtV47PWU?4p5Od|J$ua;E58oQz)rHWl<&i4T zq>$Fg>Ew}6patG+%ax|fmZ{a5~ z9;Gs?;%Z28RCL6>X@Ce7d5Q#bQngCD>emazw*Xr7qng@MQQvEQXh*}d!vb09<68lw?6G_2)nG*5Kl6>T?Bh0;` zFR&dDfSw9%aKMX`?=hko&!}Qm*5w&H`!iYjvkTSW%_H?9p4o?Y$CY&}=JKh@5S2LK z(#w5MFctv(j*7go!7|0v^L{slk1#Df+PM|zjbdaBtDo66@Vt1f@Te(vU?_xBITLM(- zw*-EPy~j&J<3z>XxTbtep?|V}k;|atF@&Dw7m@4i{iVf_!(nb(qej~bNP_Zsw?(Le zKxW%<$K&15B4oF^#?(%bujMaEDOg8TqgBk{U<@=6*z1}5qd8bMQ5y-8D$uuPw4|5G zHvV4i9AeU^ZdXEE8Y6U=mBou4hz}<~PMsiC03)6l6?3rk#)p~P$3C4t|4h5Y{J*iph!KOs3qi#qe!g&?qse&|S=S3Y~|x$&oalrJGmS ziPa8O_|7^sE=A$4>MRf9s7gSv{mh^eRX^fKmQTLo%wj&UH3%)`ag}XNVSL2n4}4IF3^DOXD5co}vIVCDf=r{DrLI+) zvuvZX!tz~!9{y>zPU3A{wMPOU;_ys9GZS*lSM+mgZqx7%YvG{t+0-|9U8F#c2M>){ zH;3>`J_aB8Pqp#MS#$-BgaqE6@9Rk4{puEhFDddl@SjyrcIBu$oWm~)&N`ERIr<-p z+mv4D^|)zAmB-14x{Bn=UO94Ur<`&8I|?eDF0vH9Vbl$sAf|KU)e>zaxjB2{m=mrT zgNGbBO26q6>~|2Ii>G4wzrb-DbQK~3bvOxh@mQre#Z0{OAA0dzbxFw`ICC3AhgVrODfnka>h{%vH zm5~3gwGSbW$4j@ARkZgSPc#dg_oXao8)8|ASxUFR_8|J?7p^$HSIjhKgZZ%!|3Q0) zM>?3YS5B6d`(lm{wf#g$JJOiVFOjdlME0I8$@m9V7B|Bw58&iiEccz-Xg+Onk1tlS zB9Ny{?z2p$0h^?f1J97khr<5PeN~M>Exk)`gLIVYMHOKXv2Epa+@?bvQ?RD3JDQ`5 zhp|EAHNGqN;u#M6E3>onvMUZm$+mZ&DKf?gjHeow11YjbWFBj9aj2YRxCCgmDxLdfLPa z@5FEwf=r4HAX;#mmR2=ImG%t4!9FgYs^nsiXWusk{OLqakl$XS z1^r{9;2oe5Y9Ugk>zaMbQbtZO7gJ5cEwb|%%a45?Ft1?|4P3j+dojhZ6d5d;35=9a z|BDnacs>2!8m9#^<_SM{b8lJ@T|97v%5cm=m5swR3cWl_dTmqaC!;e~>Qf{aU&!9YgM?A#n|?g2u5$pNX=i3A%i7jtT{}%e-F%%U)w$ z%mw79;b|lYLUZ#M{^vn2$G6X$iMxV-w_)!avL*Hyx7}|{&XCVR9RIv~#MRsIH;uV# zX?o{F%Xn&cDu(_`F$<325B-;$yW8d21IUA3%e|*&cDji~B8J~%5LF$bPhcNuR3M9l z!|B17W8j3Kc*z;qw_ff7A58lG)J5LRiWX7-BGf>hMW|;qDCY}`#9r7 zc4Bl9WiC-(Cl!MF&WIl48b0^}k>cLfS;%kE$b-G;RFG$#!Y3d$6X611{*r^{e8H2`)B?gPnk=AJbroY7O%ByVSbD$|k<5|&5Bvq?py zYP!gY?U8%bq-doW@*1=nM3iIq+H+zP;1H6Q23?RJps78V(FYjASEfDU#tk)$=p_B- z4&Rg2vDZV3ksFj~r%-T=3gPr_eFWxb0NCXy(BInlP zq%|bEY4o#4EDnW|*!}tns(5T)VesVYMoSwsr=JItTC&BL0r?Y&Z#9J0p-0mu7>s@=JwSjftI-)qlwp$--bF^C2q`{(@p3=+QSr=a-kYd=ZMoB!b_v0(H+X`$%zOGlWPx2L&Sfh!EXko(V!IP z(NK4m(qQD*CMIc!i8Ec}ePg*LYVe(;e|}fLz}fUx!Rsr+j{L*-%$u_dcQgtoN1@tX z#Ib7@9aO~-2`K0`tL!~xh{Ve4H!Jo4$Il)Loh{Ux+pRW4Kl$Ng;~}>q2$64((lo)9 zDtVA2S#tv~ij&HsUwAi9Pi!FaI)`6P}6GdJN!i4kFrp_-{o zsJoORN^7r3vDmt=3a9T{nO>L0Ij==&=9nl`U4$eM&y|-+p8H0IGPWj(e$pIMJZFhH zO)*BDBax@bnM#>!gW<@X{qQRJx3v-n`dX8q^Lyy0mf44LORLk&v! zhJH$N$hyT)&mE_HEd+=X@KZ8O?Jz|;aubmh+@nN`6+)2#si_nzMRE>7lHugPd|g&! zG}pmiufTmkjW#i481D?9Wh9Z3TXlG>+>f|*9hbH0nFZrS$Gf> zMy1PFWOErxsdNdSt9Fs4`i94jRUPeGNZe5GRY=g#pe5mx0op6Q#M^TakeL_DD|P>;F>oYG_mUkQ$) z!weH)aHiLe19V#z8A5F{Q$LC(Ir*=+j>A1v;MF{?_8pomDn9vET-$#c!^K-*yJ{|* zk;JcQOAQ0{qKp_NOLDDxr1o9!9)PtA4^)LEHmyt#K^NB|!3`OU7>_QdSI!VjK^vNW zrikE%S6;jUx0l{G^=ayJcYdDPadm!Y>2>Gn4qzoX25tVfs0i>uK%pMFScN>16fKDS z9!0~?OA_EtLdeHU^y?>Dwi-Dh*`i^IPGMu0m;>2 z!zARnBIx>uI@wJm;Ws3DB(U2cT?{nB0s*l6n`yG(lU)Od3yJ2jI0crbf&fh8Gpmzv zN@ri$2jOPhVPUley1<8Ey<-ZV?2$~AQux-xvtA0OStgd`&T9<75d~LS=XDBTpMt0O z>l$l^B3o|@<8p~HX~n-4Zt>A>awz_$23>&=L?UXF0vG0M9l@%gfe$AEb0Ulcpm=a0 zR}C1FU(5U#c#kvl4@KP?TdeE{dQ^QYx@2`5x?E8^I~MAQ2-magNUHhtYz z-~QyqN4l2ja|2+%6GXMN^v)1pdS#qiNoOT24t5iw9g3BO!3{-^r;p#6#uTOTJ42Qf zWGi2i_6Q-1Mfq?Sv`cjDI=p;apkz;UO;`HG=-Coo+lGHJI@UzjRTj&)0OWzuZYF}w z$ReN$o#W7LW;Z^9(Fru(>vr>3-qNZ|s>sO(<~mw21Ak@Pmh%0<{mPZ$*=Hb>3ScJk%>RJJ z6e)lqNS6dblV|pZVw@TkR{}-8$_}ddO|ERM^MA!GL+Qz0smpDneNnGPNU(R+Uo@F;gl7>oRhukmdLeU!7p{p3T0*gYSaRwd?R`A4P7xQS=-d>~L zz~x;z_M{vQLmrW^`maD*!5%b-p&#+v#`Kf=%;{1t+K5&I3`*mGbeop#5jgnfDR@;~ zt+<>czH5H9>XYa0>F@%3IT&p63Jc40A-@Ee)fcV^3fK54wy({KvEWZaURf9-TPj0? ziC7&T?j4!n8UK(8dKAleT@1Q^$4cC_Qhk^b`>==6S*rST$9bUWqjm~;z!~08ga=io zw=U;loh&lo4h9EI@mUz(IuX=4c2qO{g#n;;qXo|0UVSU~;c28(`(92)qG5{o9>HG^ zg@~yI$FgVas|+lC=*4O{6xD5>u#?DF?_GA2hQril`aFuLw?jcD$|lMANav0GiV;jQon;zU$!wAsCO zxj-{~6S99jovWrVK*i&v03F*xsKJLq?^pC?)K{X;H3OhqNI?`Agr4{JlIPu*I{Tc7 z+_ySx(D^63TO9VDLSErQ0$KOH>~BpLx@tQR2NtI>WQ@`VuT;q8~$-Mtq^Bs93}U6M8}5UC~11 zW;6eULWv@AVwtxotPGDmcvhnmn05H2aHwaR&sJO($qXCrYX+xw2v;X7=I<}AMFD>D z1|W4>yi#8tfGkI;?^Uk#NcDIjNPz6NzSum3O=_M@pL*G{L^?KyHbn)zZ8A3Z; z&`$cNsliW7M{?MYKNq4;WA0?hN6H5=q|9 zKAm7J{*NW3M%YVc`@ac&ln(>Wu!K5ZFXg#Fy*?5SG4XEPc(WH2RKN6ZHRQe40LcP-ygs zQ)~2$RH*d8RA}{hk;k8L@i(2(kfZ>Ko6ox9wyL&<6Bd4thqmN{a+OD{qta!iwYH|V z0x-J&QNPZxc(nW&7%ejh=)$Z!hU1gz>*}G~=}-HJvi7viGRz*I zHRrH)5o!PHsEi2!G5GgHWRXDX3tI^dXy?Oj-nSV|u94Pe@L)~;4asGiYVu+K)^>!r z{+;94GJA(V4~GCMNBYjh*(C7PI9fMqdOd6^gJ?M{seIIM1Eo1nPhXfQRAr-?Rp_5e zY@DXfQ}WhzN9|JU4OOktTl1-8nbE+k7A=@=Lz<<-ur^OS2oC&0H*@V~sFL_wuX!mB z0f+8Rvz{{v)RmAFUT^0J^CGPrU2m2X%=@cFNRMP-Rav(-vxN23@V;xdb7L z{;5x}Hh!H|im2_Wt+vBp5Cts$Nu@S-cd#$6;Bxn} zx?ATSlxcJ%IX=rJtA1~!`0_!z))+`XJX<`dU<>_PlqXOsc-i?V<%>TY4}2bJOx^2p zf=wbW!}>N~gHA4|6)FbHIDOgfH!Tvdle! z30oUW7dMvPh#q3_u9n4@8m2?w&X_iU(Y(vAIERM9uPFK0_-8fJn+ujjqyMad-Mfu2 zwBw#GVi0f9+@;>osK9Egv)v%RfDUqZDpW{yw-jk};_m<|vV#1mUg!7&V2LrzC+NE( zs3UUB2A%zTJU99ecQbx9k=D*7#P{geYn)EB=^dWh%R0==sjNxDx+-Wm61OFrKoN|c z9M7gdZNW6NPZMW(qBX?w&Jgf5=XMa6ojj-%V7v|U-aq45jxlE#{6Dx9eDuS3Z-ww- zQEuiK&B7DmZqP`O4~Ab-f**vNzQ5gLf@&h;atFiphGOo=`CW>Xz0fHF&4Qy|E$~>D z6VY^7umsjYsa#u5s5s{%#7d?58~v_Mb>vb%se(s4TH|o`5W#-e3?*D$Z(Nq)35p%N zm~CXipg5WX*qV{S1RLXZyE_Ulzjp&KDuXU`MLb+g9WVBVT3e9`SC{F{Ec79KKsNea zK21GfyWMgZCm(ao5RG?r(|bd0Y{-P`BeZ4~1YkZU1T8+ULL1V)ag?g>$)2;xbqeHC z?c9k(-|#~*lh!%iRP3Y%*W;wq!u6?RrY1L3U~(nDDP%fQ4kDXJb#HJd?Ug4>Yp{Ivu=kpJCz58W;#n}HBS~;fF7Gf*%DMo z;@h^$dHB{zCaP6vNQr%fYG<@{je3L~k50}KpDF|pJ84_m2}OdXi;3dZ1UQcURgd!k z8Mh@DwlSZCGSR+N{IS;AsE!QwA08|Xv|Z($J|EnyF>lMwy%!7!+Y{J@Dp`F)EZbJ~ zip4g0P@Zc_76euag`+gppgNPz9-DswCo$3cG327*j1)1fx`Q6X*|91R7Ca8oE=&zC zn7Q*7(xDnc@&MKOTdArp3iv>-p<(}r&cp$zM-1@ds=KmbzLnNuA4j_N=FzUvjjBZ$ zRDe1DPd^8;?kmGrY;riSn&pDNhsr!QU=jF3eRyTKUTyvv!5}XHv@?|1iRaS1;Xo|l zVx2V8uSPlHm_&!MFR}}OA7X^U#=Q=q1tXT#fI?A$R=*y32&VYjI1}%Mkt8<`6VGS} zL7P|sn>(^+^|;ITrBoH8-P!S--e4!Oubzho;Pnj`)m$K9C_7r4a8?UIj%e)Q5yl|Q zxGcm#IRf^PV4GS%YVXeYa6aCU!#e$|*NHGEJ`G0vgcLh1Ue*F&EXX!%=UP$CBj<~N zx9j%yJDQBik;`?uYirW&<-imN%5l1ODfVu4JIWchR4KIpOj@w7jlf@bEi?~zy2At1 z=$;2|%Pt+J4iO#sScFdax`_4G?~w%334Uc9TgkPHPhE7NQc<(dMVB!&QQoOmoS=M_ zm>}oG%q|0;4a61s>)T)Yk0ChfIr@PQ(oif5+Y7yBI_L|1W{tla1ViV}{Ks_`WHg)C zP1z-ormgKXp++4kS@F@*z)Fhif%2Si3~vrsApu-xkY3^{BygA^ucQa|qy9HpY9wgJ z^;>jE!;VuRs1jkpNk+J{m*NgALQ6qjw+nB6=QfXjBW!!GB4lUQ0oZ|2U%%z35MEk2!kq&Guc5@-N!0_lu3B=Na* z2V!lPQNqQflBDgyMZd6x{H7QhetQxzq-FMI3`S@m%rbX93}ZOC@Mo?23wA44EKV^6 z7@4H>!WbLBnM$Y!X97VPMFhD5XuW{416LFK7D7W`I$G&VTFx(NnZKkh0xiNlL=%cw zRKs#DjGFQ(z}|sX1_BF!`qr;J)Z%-!aau$zW{TDaR-`UZ0)P8r!$b&GW4HwxpH^l) z&JXG)YgS+lVeyiq97apEoGw*0IN~AOj|D;T&7c$v6cs`)t8nA3%t{p z2HVUvmj+9mv6dD%A0`oMuK2;yJloeqj7G$*USGfs5Jh2Y>ME-pKvNJ5x<}1?K_-^z znr7Pd%8$kdT{$`#E9+LihLe8SEKbu=t(ng-*pj#7lA@9ojL<`OzfD99MlWC_@23NT zzcygtC$pMdDjs=A(d3x?YDYrEk{Rag9Z`_J=|vSVc$&C4bqx(RrqFI%lK6r_6|ZkS zXGejlGHh9s_`w01KojpzRZ+oIs`--`LSMsYo0&Ia!IheST82;|fVKR6RKaMCl-2*D z480O7`6Ea*@<&uFmBK1DD~dU*7ii6v6u){L0~%ZMGi7V!_7S|b&qPcOM%P08oq9xV z_Mlr*(8o|$faapJs~91Rr3Bm7Au{lOg%_}id+$sSI(Xa1JU&>OFel~(ELyZJ6 z`^Vt;5$3Ci2ysBBzpRNRpWKI)V_3mW%coIr=5os0nB@qv6<3AP8J4JUa0ji11Ud91 zFxm|(8L&?)4N+F-pM-bjXVInkLsg*Gc$|5j%|q;~)GU8@M~uyotTWm&Q0WHH$Df8F z46v-xlIwyXy8q0MU{YAkj11})!cTh^R%4KtPFx-&zeCx_gS9>G`mcVQ2aq~qHa!&-f`?DL!-8! zCI{g2LORGBVQn;5YyFF=V9@>-`G;Z2_OSchkQ-DY%y#XtQn8IUgrcpg7c)aX}&bH(#`dXMRI!F;j3ShAbVw>y4>OULrtN3V>X<(}O=EBeCHcx~D* zC@IN^rG$2(J1X)dRl}kup=UyYnt?nYnb9TkHSKgqELS_XBlo#mp*1O7iQ2E!`hIA` z?H?#7rjy>jpvq^T3CX-duA+^Ay9Rp3L?W;yL1iX@Fwdlq+R<&q?xhMT>r?VwJMA+Yw z!D>5{#vZ+-&KYj6mQ{J+Siq?rUUP>>tr%z=&6EC7iSEx-W~-iH4p#&F*~*GLkzvo- z>+KR>4ZY{cQ^68&SYLU0y!~L6r~T%3Owg|1ko<^B0)*cBA|)sIX+ zqP15Sj12xw4Cf%}4h})GpclMbBj;~3jUL+&k%>UOst*;yvqgvJtUpKH-}T!zgywwd zzPTxBw>}=nnJ!GcA{q5Mf2d(Z z==oUVf+gJvk*o~M?%cxX@Ol>(;{eMmEFv^M`n%yyJi*OVvB;h0z(M!EqHEeW$C(^G zn7b04cs;uk##+6t&hJDs>+OGkXLkN^6yQ8odM9W_Y-Vsf_#d}xpx1Lt?NkJ#v6KkXG2Lk3^>|XS|dKfEwT}4(@iaA~F2;}jcd3RrZBt$jG3GhR;wpm%R z+_57`U^vfov5j}{_}CMw3eC}CgA>qC5co&PWKVEI>xx0`oS{1X+H-~Zb&%UFZLsOH zO_q%Bc`E(G?q(#Kd^C(uYk6p_T<$Ot?{~>dq4NW-i(vPLNElKvI+y4$9)_c6Rz2p* zg7y{d5Z~V@LTA+Alz$!AuegtLu#hW6<+-DWL4poom)|iY3c2b|fCKF)spff(_PKaT za~Vq!yknr!^^8a6joX~|TAcH+#OnZOPuBgO>%gG37O~#s{pT`7``6x+2-FX;&kxnl z*Re2p@C1499W}Hy)J)r+G3G-oYezd81Fv!kuK`zBUJI7Z=b%B)AxAvM2-IyZGK>mx zdL_ya=vsZM+sRgL(fx1AmMFi;>d7NsM}|=f!@yKt*V_UB$vX)aXs)0yot3%ro@Ex!su-@^U)T^Wio5>Vlcl zMXZ5wf4I9X0qt&`*=@)kMy}s}vg5WM9f0o3!oSN|%eW6L{TfaF8kMwzk(0EW>_D$V zce3AxKvEBXg`62i;a+Z)?Ka^#MladI1xcZJLyE^ zBf8iV&@Ltz-6|QNE76w(2E zt+Q-Hyg`e(#)6vy4JnE2#IvV_5^-nl3E(Zl8#i?}zRTGumMzvon!UkLy``eD5`uob z5?R*TT5yFe@twVARU=VkB&>E*-?)~1jwW(O+UXmsB9&0$D zqRU&AJ)HeQaGY_hb~NBgG>tjd2Kn&Es$-vPa+!&lazi?7fYFW->>&$!1_4s3} z?``Rk9bi_@Q5hD&NDTVw9+9PL7Ak1(oACMl(Gpe~iEG=q4X~N~@bsMD^#Sdjl@6SW za|0}mmj%2R4tU=1c+5_62liMiy!-Hecb@{=m>4pjo5Y_-CffD0okS5D`9Pez=(#K~ zf~Nn5QO~TIYd~ie(%YVGvA$K`eqI1Mw+(*e*fjOf>daUa`w#_>(yv8 z?c)g$^3KQgZaG`91jx)@`d@inX_5ZwGNw;DSmnU7*=l#DN5fo>0KjzBNsfxdJVL)E zAKwo8NbxD2#6+M0ACM%GFYzQW4@L!3DoItBzJEj)Rjf5W>uB@RnSmM^2q#`0CM^bQ z#$GeV&vGTC0|8UsV1k5NE}k&#5JqSl|8K@wsiN5w4lILJPm za=DdkH5Ug%HO=2hYCy4}SQQi8e&6Wf!~%pTlnWjAVGw8MDnUX_(HQE|h!7L>ss6)^ z(Yprm@Xc46Zw;7!TJLKAUKSO5^*&hY4eP)e8`4u=$Up{&3p~d}m#>HOCXwpG$Zc2o z>S3}8zFe!l&Q9?Vd%bs!NLTUy-Y!!Ib+X&nNRC@JIBR&%$w2OPyN{&u^vh4W zOb95EHheSuMr&n4nG72Dt>;+P!>#N>fvM;D%ZHEU>-^xx?b_Ke44fBnQ( zRYki#(*iJo8l?^=r=DxKU3*68Cr5FO7s^>mO}2~*x8qF%Xqt=1C8rbjk#o$p!*X29 zKy48uf@K(0%{=M$TwZ!h_1zo(-%NQ`?yApfZ=5fKZKkARo*emk{Qf8|r5 zT88WIA8SqH(C~j#P<&z-Xp{zsth(_)arAg*^;t|!o@k*i-1_Y-G!<%^|f0+ z>uY?Fz6RzuJ#~&O1vL)#m=Y_&;vy>>1fl5%54YF4%}aj-I$N~XZ%Anh;xL(#!Z3=o zM34$(1QJR#+5S`jh+$fkRuj%t1(uu)N#-1dO6+NQGHhg}igehhGFKHsyE+@{Y%NZv z7%k3h6^5KlaR&T683qyIAdOFcXBkA4he9q8_?6g{0fLM5@w7v}SD=_{zke)j2d0J4 zwDXwJf>`j0$YCL&_q3QOwfgRS6vOQ9JW+YuysgDc>hK5r)^o4~BhQ5&l3N=-G>hf% znXzE%IP0V*jtPeH2Zm+7MCcXqS$wT&m8I#1q z2_^10Y#UTM(J2U z6*C`ON89K{vO-4ZO|n79Gkjzod!|04+F2Hx<(#qm;~QrwCN^hy_xsY8-yO z`b&QUN*)LgVh-(;aw&vv=ycTiK>((B4?wmWS8S#vD?*+c16RC;onP4^C{4Ud{j{_^ zT{d5a%2PZUYAP=tOcjyJ=hy*>IYx)v>h}nkIvkACu>0v-(4;X2w8DG)09PcYm|R1x0Mj?m6;Zg48CDt=Z?^6zH-^NJKz3s3pM6 zDY)1?0%8f6Ty)}tp>F)|Ha*tjgTdZq&+JJutnYR6JLa1hnYg@bn2vx1nUmcj87=UlY?HGXH@dcGZt`m_u@CXO8H*zYt z0ViLC-;)?d7ak!jQ4b#B5W-Ry(2Btsj?<0735NX>gEJVn34=39>iNt}D->q8L@PA% zHuQ@tBG(QDMWTgihr;xK-SoSiC?MgVNiTX8C}0qq_Wq@9#hgXf_>!L8gaU>9JS09? zO$NT$pPtQDdUHEYYu68E31D#xXOC6HYEfa}_&$pkmS&0)UO)A%OqGGw$mTp`>!`>&>89fM2L#Hr}yBzjzMZm#K&1%n$9R zjM12pDI&2(IP7B2hu^;A%!j*ILSuF&QHOpR`W~V!xewhCL|YOy(sf@Fb)H0B`fLOz z`VUGycw-sN0r_IA#t2T+7ZHIJ?)V`U1|ZpZc!`OuM@fG;yJ`o3UUgHF{O`lx_KSt* zLi3&GuIs{XuUsUPz`wVDui8cWwuH^Xf&$)3K9KX=;K07+-9YVuuX@nHSx=4i6R!CJc~gjpJQ$gUi2S8X1Dh{hei438W|(Y5hxAz$~-eEj+W6>Wx+h0Scjn>3!;#H>63 zcDJNFAnG>sixeGxVo^{ivvXuKf@EkcgntOmZC&xz&;}>F|CNXyaQ_QwqU!!P%=gTl zdzO+YX0Fghm)$(`=N~!fFQ<`?@Z~hDwU`>~yKmCblfQ6){vQq^hQ$Z*ss6(O`WFsV zH@WZbE ziVD`0L?^YwgKi*?9iU299-=S7H9=VGuOmk|0Hq(kHtlHwi*vK3mpRK-ogmzRB_0w@hRI17^>)mih2*bg3(};ur8m1BdsMu3^I2u8H z1&m)S$G{sk8)yedBixTB>vvJLW?YO`BgS+Ewv0?kjts?0e0hapf;gqpJQ9-Y#l8^x z4Y1&3%vCZ$u-q>tDJdT_T zp?)KOQcFAifhcCOkYe>erb%CSUMi_5MVVDHfT|4q;ywcm{17I|UnCmc zo&mzvqk-AV5eUX?=Lp1QvH9ZY-4KG{*nALzz-raQki&VbeePoWA~P1imq4NM&D-eU zgE(A1w|ZK+4*P7E#-LI6^}fGKi$6Z0m(y{CFGVo0MJ`2_LyDYQb!>Ei?7`Jm$~=k; zI=#}M21G3%Zx>3QA_?9U+%+mf*^1b0Dvo-6UJR5uHo_C}{<~~kjGvLAnKP2N^CvWB ze-!|1FJ1?ZtOjID5T zcm$`1@iSc6C}Fn@4RQ7Gh_(Ck@W=(FRZEHhAQCB4T>c~3)D}|617M2ES?k% z469r+E3$B7>!9>wvk@QoLeMa-oA@}?)N>+PavZf!F9^UA??8V1PZ~WH4%Vp`lm#g= z8D#w9B3oR5B2G^TGgCnXlPxBcn!h-b+6n0 zSq@fyB{T)csueyXi!qC4>K1dmOHrg_7JmVjk7Qr2qXzZMb=08lZJxllY@VJC4nw^F zURH+_|HDoY)X;gK(^q>~HUQ2r7+#`+IZ71U1s+ zAxM+tIHAFq{HyipuitH>w@t|y6l;I`YUMa7IT#I9FN@;m6PszZ!t9sR!*Da&!8?9o z4BqhzWAKh&82jQF{~rK|KzF}t!Dj&Pc`-T!%j!idE43MaVF%gN>KvAqo_xb$Vd?2N zHllbP?;?bF^!?}E({D>}F1NKEoQd`#p!rSWR#c0e#6zD(I+a8I?RFB++#4|@ z?sO`n%5+tT!?Lb+4NuCi!2#w{%Zp5sdK)r+IdcATK!RL+`D0bqh3ks^H78=|VN3K; zJ#rq_NA=>sTUl$BA$kSA)IwfT_T6>3A~t_rgD2sMHrjs;>4EmdZP6<#-fyxIt}Bl7 zk8qs`n39C+P`Y$>rBNmkLWq|PeZiEGL#+M)DW zMZ0lDS!MF)Dx&t9vdV2GI{vjR(j=9Uo<65co+L~ulMh#tQ6_(qCX~sG>&PcZ?p#B_ zUQ;&tHWYs@yON-x)8`T6M#3aw9JrDUVw_2uK8y?3kvnEzl1Jz@WsUC*uai|lEIfVY z7#&HNJ4P3-BzuhRB+VbA6W5VJmfl=JtX@+VxgWZ{^hwu?66KO37t&{xV|Nnfm19S) zB)c3tl{Cj3yK)_w=B-ax6UkSYbyPx3nsbx`SCfBnv@_}RjdtU@vW<4>8gh+x9|?oxffpaAIkdz9GO+>X z^84I3f|=zD+=vOwrRyL(*=|C;b^CH0878jkXCwsge(@W!W;XhWc+kjq3>%bByYxy zSLkKaJgumtGdfzX!Ih{bKw*ybyz4`jN9up?1+4lp-}@o|AGsuQ;XoAm#;%-G4?iFK zoBW?XoIAY#Go+jWbD)>)^iSfsPU}Obb{hy^W(n&F%(6jOpPof)H@tC@q`ur;iRSWB z{#M9)sRv)s{LOIY%_n{kx8iV+k5o3@)F<~0aNdn*epK5U%O~HqHI^SiOYRVz@m_y) zhvkcReG1Kywv<=*sl&x<4ImEw%7h%W>J7<_D~ML($8`kjgAj*=!K(0A7OdK(^uem# zxRNqw^yLbQ9PP>#XxR9XO2a?wUp_zG+3G8qevi>Nw%c~BM3ZUu#0{Z4(>t|c=s~^- zvzITOH-*S*(eKN8=d^JYAbBTrPm+J$>(6Ge6PQ6x1Nc20{WAJ zCSb)={ia&Q^TH=p#k0ezd@;n}iBd3V>R^hT{1oQEoyiM`DwTxrX$Rp*h{=Bi;dI$# z+m}6dYOthnvrz(6&7U*Yw&fG6h={>6F~X^`wmNSYO90ysb#JT21T@(=Yz4{N3v7ml zpj79GtO7i7iu>yHR?w^j#p!591r^a9294SW<2)y#MsfhU zC&SqUDaI5)op0;Oe$BT9HGY3h-rt9*4Dxu5N7xWvL`y239nzkPr^dFb;ynm!Tg7uD zTUam-qzN^U)>ecYw^e!A(1}~)(rDYDiKT6z36*UeAQ!g5rqlJzPZDLRRsB2fe{$A% ztnz?Ercw8dCsz0jPN?$P338>+=yYm7_90p1rB?md@d!j3#cNy|wHtplvC<7Rp~{T| zVBT z^wY>+(bDK%lZgednF*Dy`Q#GU)O6aO@F@Z;wVKsh2-Q)*HWjB+^^yuOTmt1u;NVFl zz8wx~-Tv+;t18-8uq1z{e+@_8kSC!x9;6S3nCaqiZV+Pc!CT(( zM6bWqxgcXrBl9$?^F$Jem=GW8fNu9cilNP^+TIIds&ZlJLi$o+=?!rbJV7T)flDu{ zvD1+nOq}|b=mdYV|Gwc>*->>pSXwH%kNEUbA3aH@wb29Oa38VB3fj?u1X>$6ouM9L zeZx(qzqgL0SK?cr(rNOoFU0D6>p()8n3y2eh=HaSi1p%n)L|V;FAeKRB3)QIX#@3y zolua(W3#8&)S{gHxE@(92d)zfGu6=b8-7B8kPe_9LsNf?!+LQ&(wJu!Bo;=RxdkWm zBqf$*Cl@5)+={p0>ky{) zRlOu9Quoq@l#2T*#4pplrqSEXqgUI4O{ld6HIdR59+2v6!A+yG69>|ST55HxnmC=d z6)k^_vNf4l*P5A7)tXPPX-!S1=n0=9z*4IDk@xf!qz; zXx{ipqfg@#nJ|q{%tUE?;*-YnL`{>%kMJo1EM*!Wo%p?c;(s=@nl{XI%C`Ij`nKf6 zDz{!F(Yj@)RlIfL8uX{?bhPSI#B|!z^aOv()7-?m(>^3oohGN%oOaF`XpPGHNz5hHZB~X3+V;)z}p>HD<|mDg#DUJD(ylrMJ8GXHllx0 zECQR@X_tUaZUkS($wf zPAKgePblpfN-XUkyyA^$dm?o&aVdWUe#B3!@grB#$ow4_2*q~f0ioWGxYUvxcLF4m z+ya+Ga!Y<<$t_(;B)Ri0P)cs;0j1=YT)VA$F^zwc-nHsNO@vOEYsk8+-$E00U7vA; zt_%ANJdxVc^eg`~dkqnlatm6DLT-sqTgELtNmIlvJs^zuC6+kLF43qvZ4G~Q`I3vn zfz`$8K9q}VSGS*BUaPhu`H+vna!Iyt2y3SA)p3@e+g7wLV(>Qqr~G_7KOIol7q)LQ zJ#v#}t1mZ-;xR)bisLjVBZ{z-#s1#z6op6ep6d}s(-EMLXKitB%dx@|#qgat5(RTR z(>4kbHZvp!c|S!0R@N~Dn%sY5SzFN_7=d(;aYJXL5Su6K!!_OA85-ctJ(pF%WyP{v z-;#R1bhRe1xb)}rQP!ka+l{9TFXP@-_BdKZ4LuGl!`u1HVlYyc3(*#3EsMqunR;MN z(~76Ea3~eyNUjZwIEqg@B93&TW|Rka$C~@a+d)zDf}vutX}K)#dDeg0UI6qPyW#R_ zX6n6}+rxZuORTEn%4(EuWM^Z@;NNZ8Wlyr9P|#?6Nmg%^=sCM|Aw?OdD}G`-h~mJ$ zgZWT2*U^nQ9*G1rNr}BEyQX5V$XeGpqP*hOVHZbH0|6}WWlUsrZ;hld*CdL<{4sCK z2Cr6b%+n=C%S(|OEn0u3E4J-i{mXL*me3R%P^b*f<5Q`t3I(T+m?5KWyxOB;Dl^QV#O1U+EJ{3>| zWa`>G*EhD;$1A+k8>atwU^Uy>NPpLYy~xRu9$NdXx})!A)8~Im@3)qnP2RAo%6f4$ z5OP*NF^p|l7a5bOpb;G&pchSwZu0$P8`R?Rcj`8t2(59jPF&w^MRl zjJYQigdN7Y*hBAPUlhFRR%EQNSy8dMW^(hgdKU&)Ejd@S155|hr~@c0&o8xhLM*Ni ze+O9Ab2ChFSwMe!TWqpZ(~w?o%qV8hUwU}c&I9LR=2r%=!;HF)Sch5f*$z7Jj@}0V{lWj3E)S%CDFRG%0G-#?!VAkrcEI7PHHE<1S zRS)FCCZT^?z=pW2e?hw_O(NX5v??n}kQN(oc{jX0K--fIKJf(l${ScQHsE)SbK4!S zwy^eEJ>9bJ%NjH;yFosH!A>uSG77Anz8!#G&Ysmpbz#)y&6N(-$??js^7H4Z)AK?P z=sS>g>wnDNpX(ZqwYxt3KbpXb0?~L?AsUy7qDFsoK4Bb~>Wt@~&$yA^fM>%Lnl+Rhnwx4K@iMcThq ztVMsCzMSJCjbF+@k)|(hKO1Sg5)AEmujEZn>qdc}J_5z{XwG>^Kh%D}xPB;V(V+zS z#MMMpGn8v)w>P5eI|lz|Z|u%9Ya?L6=52gtx`KFVcqNn|pVHzT;91Wuk7ULGMw1;9 z;O#p`fD~%pRz1zq#wFmrjJ-H;MALYVkEwqG**xA2biC`(jIWIu2b(^QdeGdtu-#?0 zH398^$V`?PR>*XgP~KjRQfymsu&Y+k9^#lYV7-?{(LBb{*)j!zK8w*X+Vil>nz~_Q z796QWhl)Z;Mr$*9Lhafms?+K(q$gt@y)FrG?DM+7zlo_7166>_1SMD7uKhl){Xc)> zzn}P)$%fbMp0zCR*Ly>b?E4t@Za;>TB3hE+&}p@$Q(HcYquP~OGc=7uS4uo+s7X*Q z$G@cw>-51}Dvt~eB1pENYp%x)v%WlFhJ&exAp**x;@CHFJaDs?D#JOo+K{U%|HUtF zJP;3ZE!4vaK4nWdWgM}bU5wI7H8aH5A!GhWbc?Wm$vNCv=KK zrReFu**FOhm!kTJ@DNky7EZ^<4f-=0Ct@O2@g_!x$-pZZk$Ot4b=+zSf8n{>=|~1D z9s*HdvN?;MC!Dt?2jJAhVZ&S5G{gj*>}Y_2D7(y#K=T5TakP#XgMokBxo;uJy_d4_ zhG-gHes#IBC03+;kC}CW1gzm3Yu+CGtk&wXmeo00-Y_%mFrSp!0SwK5v%eT}>eEyC z>`t^uj|p=`?b69GF*eah(?ZXIiQ*x*hs+@?IQ7f%92CUz&FT1)DB~zfP@~o>hu+56 zblHbD%KpXUXQM2uDk^_}>06eS^;Y08ocGR+qO5G88)e&dC*3HBJ;wpXw%=i|-YAot zA5A&wxCTDTxcgH0IE>4R_(;Nq-Cke_ZcFbY8L;)QvkcG?CtLbLXNx!Azuw--5AR9zykQrMH)FSo%K3j6ck+&4jJ7j#7;=B1 zvmk;}i-O}*L}S*op+M9vs8(e4nib{t(nfBf#!r^L0$b-V>`>NR6TJrUM4EA*Q-8W z-Yfgu#V&>4eDQzyNj6KWift`H-tit)1V+~orX z4Cwv=V|yGs3C3LOTY&>DV+Qx0T)K3kVE4Q|l)5JWxot&@797(peSW$VEsokw80!sP zP?}~nY^m{XA}>8kQ7kih?GN?!D^G&_HlHj@b4%P>!lS>)wekMQT% zqejp+Qc0d4|k%=~A z^(!b!=be8GTLHhl)TPlgUixQkCl;>MzK%?<*xaZybjLHa#Iy)?{fYQP>~T~vI`M&S zD^?+Jo=SA$Ilu+YxVM;fSDgL$JRx&m+z6-%uWo1eRF`*4<^k0kv#14YW;L zsYHJ;i=v;kA(ddeM+p)1X-pgK+VQ8AC5PddDdU2=Z#US*b^auwgWiD4h?TqTy6i=} zc4XiA%N^PRN0;B3A6KSeUSfGe)<>vdahIlK0+XtWiZq^4PQ<%BB@~vmGN}?8retc@zo~HIp&BnAWwgSdx8L9xnu_jj6-Swz^p742P9pZTn&iP zg*FZ7!ggOloX$~`oueA3WlzR&Hyw7XULITZ?#v6sMD*ze64eGdZ0KCY5n|s|j}ZZ` zv&+CpUil=5*!NJ@)|hMH(63Vaw%rcpxZvA-~bHOv}b=os@9VPi;`A!7*O z;bP2!hDy)6U#{)Z#kH&T-{rMGWLya z_NGQLoVqn*2tRCCVP$*uktXA7QfSsMi~sIP%3b;$&v5=DfP<_R%Lyw3%HqFyl7f?2 zS^V7-6`In@;(vIO$P(K`D~pi(`k$U8w~oCtpnnem5j?uktX&rW)sr;T!4H4$Z!0MC zZ^p;9Z12qe^?PV#{);=0jUQdT-pn|<`iK5$wbXe_a5e2w;6y;2YX1@TT_ZID;nWow z0~nX;U_xBmtkDFLu<~kK0$^NfF(8<6n`a7~W9u&-gs)NG=@bAcw?;=i$NVj8gs3v3 zT!*f*2=2WEA!Z3>o+L$R5ORNh&U}(P5-R8}QyZc-H={MOdw)=gajs5csKjRLO4}#eYWmV{XByv$9v&`>rr_j!chTIvg*_7$`26QfxQrsYEgCs7(Fq87h`{D)I0F7c+|f% z)TPECv&K2bO+JPD9VR}mb@x1?bn3BoF-KwBM)8Ikin=pPbGiOWJ}a;Al>m^)&4-=V8I(%AnEy4-CDV^ zymqa~IJ(yCj;BX09GriPakKx-+S={$I1%iRS;eHS{d$}K^!k6bC-mleS#S7iKRedJ z&m#j_&gCjB^|(4@cFl3CnZx?=%u2n_ykosA94;&3BYaU6M|sO{QL01!^Q6O-W-BbX z-3^EFNIOb!Zq8r%wl*ab0nL*<>6KG>Fpw?p8ktKuJy)LtO%u_NQ)0jpt0B;7bmUP< z)A9%vX^EWjaT0&%&yuKQH{qz%W-4^5qfVU#xL%=)B^_8w?NDu=QRgM^P|>2Q z)FKM`aLXJOWF{=@R#{QX3fDL&gbeJs{Lrr)3jzl-jU(C0tvCg5c}g-CtKe1EmAAg||%H{3SqfvV6E8J%&5xjqX!X)UH8J&QCm1cSnmVLcp zxqEj;I7lUSO#A;Fc>6k?+lfn=8>U#CmT!dU$AS=-q&JhNAPse9yTca4Bbc;eI2>N( zhZ?tRP^g1FK@f|fM-I!n>)Rpkk@K`n2Rg&a1c!>*i|4V}K^LysAdMi(?FnGD?j;_F zG;v|3lg@wa1UoOk!DZSZR5GS$XkMP=*jrPt5R=ujvdSv4)750u!sJYcDiKQU8Uy+i z7vouO)ArtcVQnzr?H58palD()=DOeI-@m9o-%f5^==8emMLgblXae1laRJV*$d;Wi zNqy3Vv}qe~CGU>Tqkjw~@BjGm9?L^h@dq0f4|e-lvL|sK zpFlb9IFfr!Y(;lR^)1>T3PNXOEY`dGR_5iLGB%E|DPrQ-0lhxb{Nym370nG@r@RI? zL__I?`olPn&8uo*zvy4L7{7R0fIZHhchVcO7R?B3PPBXkX%-ZYkRg58f0-e0X#zu z5$r^B^1h^)PSd(oKI#xNO>}J`>F} zw-M5MVRo2=Hp}z90Jr(l^R{MsA$Bg>BHMrSssg7d4dFg=z4^&eI6_-rJES+rFv`=e z#139DcAI=8v%CN|+!ak$*^Ms24YyqNaHE)3JvJzYhZ@K0c^hs>tKHBjXS?xu8c5r{ z%zDr^hZ;#C`n4fE;Ag%;NXe_`eI8x5RvDO1`!q}DM7=F{YiE9*0r*)~y;0k>7Q}z5 z{go3%mshPm1$+9@!qv6AfA7qrcMZDl4IE4e*&a9;R%|l2sg_~3r^*1l^_A1{g6-PJ zaWSaUpozJ({Ny)eu=roTT6Hyho+s_Mu*wyI8GxT-pap{sxD7{|$; zBATj>F}SKaWnrr7Rva36H+G|LFg49)Z`8W~kKzTkh&{1y=3Ss6dVzTZy})q)w0Z;f zYL|u)Q{*uQEjb=xFw^1@h!Z?Bj8u38Kudxr6wLJJy=6zNc|^rTZp{%5!&Fbq797ze z3?;>FwE@6FRux|J_tZG9qNsnGzHd;-Y9eX&zTqG#iKxkYhJ>slyyotyaauEc-tzUABUg_P>L zU=#%EJ;?!p6+8_9f<2zO;I`jBEL+X&cH7hymTNc2I6C{lT>N*p4Q^5088PxcEQwd{{D5j={B7Qi%n*z$)ZUDp0-ZWi-U9lk;nnN0SL~9%?3Z?i;9+;ru@wNH9$OV`?fXw%x~w40>+b3UAc9c{~9-a z0QX;h%pUH)W}kn*efs{}w-0xpA5k%q@bLNm>;Fc9R5E8g*j5O}%aHoAi}W$9tJhq6 z4Kw@MZ-jFO_B7mQD zDQG$|v^oFt;VY7Wy_%#UmVMitL5z?_We_N;)d)iLXcm74@qF8TL6ES9T@cE@brLMuDF1@p+9fD)B>|oM6 zIJ}Ij;23`&3AAl}6rD`zdYId8G>ZZmn!Y@66!SIw^LcR&z!&HElULroxJKWLi;v2l zcj&oWR&n>zz}u}6?8^T#U1GUsqIJVHd+r?LKwat>2>Q}**7SNP%$6NY`bLAFaTyTP zBZ0PE^PQ0OSapnP`7e&d0QcW(Uo)@m&FnuuE2w{#_8krT#!CpoY?8bcSy4Jy=|ec( ze&`GFTw@@n0TlQ*(aGwQ%vEMD_SP$uj=$;^SSMdKkMPm_@{idS*IPa334jY>;fdu8 zt7})!Iyt3>4*cJRZN%Gy-45a2@Z;dnk~~ zovVM5{EpYWHHXW~-xpWmQ_wVN5|^$lp5AzMHDP5vGgMcUYd2Ub$%s&=^wjH z?ckN=*Q7+;N7Qz%&0%?^V|7$r`SAGYJA5_)JS_XxCW9D0;|lJ82hIxD8o94kyvJhg z`&D=R&HE;KZ-SoV!=JIt4^81dGvC2_*X@5DWh$?9l&QM%gE@=r)5m)mg3qEYZueZa zi5zFOh-Z`6{Ptg&~Aemh97OTDG>mHgoCp{!XYQ$}?FeSGgyknZa7@sEFi z6&!)ay?1U1ulKBMo#$paT2@B@EozZ)rYq<6bLHHAu4JY0t8Z!xJ;6)|2oS7Be(@nqszNu5Wh!hU*(%eB;r6{{4gFi#~s)`C`1^ zdo=L5tg7tvxsrfo6ykz=Ue#u%heM#4iydRcUi?G<bF z{-@qWk^NekF{q&CCJfM{-5CQcXy2XR2thQ-y=5JRDm%8R_*aoT?;r?(d*BDra~hss z4?+x#*OZUa(8!*oYLa(*S(ks!3Q%+^0*mzYS)fc=fk@^efuD*Z&=<|wZlpiCk8W~Ir zDyhS1JQoGeb_eH$axlO{S5N^3<=qLwJL5I+yR$&LJFF?+U5)$h+}Vhg*~gkams#8&MT#t{a3*I`*U; zL`bP8!S%1$82S4$M}~hi6)Wp$D+_qgkE!1nJg$ss%(P+&`avCrqLLZA?_V2^L;J}$ zj~?qOL#<;zuo=>G)_!tdcpAZx@5Z;QG@1pS@u#42DC5<&u4TNw_Qz=5A*N>IPFB4u zc)s@ah?n@-3{)mp;h<$-4|HuNK%aUU0b;Pi9pmo_TSnpj?oZK_*<#ZU}#0^wq-T$ zjee;~HeR^e44W=2hQr~t9b|TB-K{Ua6hykYJrtkRj}Q9C&-q?F@U9Vcx7sWHz7GI! z*&r)f=eC0dt|KaZRwEYIg*~sDOdW>0b37Lc*PUPd3Y@4!{wwQx(c0d-wBB@_wfSCF zZ3_O9$t-_D_L{UqZoM_IG~YEPXmqCqCgAiz?Xg3R^;+Zt%;s$?$ZuG-R$OZ9z|@wj zN&z*s>v==Qbet#;jB{@RLxX+K9D?Ti97F`oc3w3A4Q>|mS*h5jY?dYUBPS~mmrT{i zk{^mrHL}$-RF~#8iXRQ@_e2kVR~Cx`aizHhz$1UgsZAS7GMe6wQ*E=G>EGI}nvMjX z$*@%ie|16a&*|Gi4bl1Axt+k>Wio7gqo06VKXE6<53%_xofAd5>(bHr3p<%=C2cM{(5_uTcT7fbwe;B9}&J?i?)Z-ue!*+vVpYbtxoUWIzznddE; z^(UX^4EwlfJ2@q@mDMM1w41!*tQ`mR)iL*-yYyf@Xn1S0S!S@={PYRka9cSA3^nT- z&oo#QI$>L@2|O5^stM4`c4`9r*ho!)cAL?K$d>KH%r+3yxZpKJ1Pr%L!vt*AB*}m3 zl<<^yo{D|c4kPDJy-`?XS>L_)X^;gI?7HnmOB42vN@=fUIrpdoj$iSp2Tor(;yKr8 zkBMhc-L&<`rF*ddthjCe`D}i>@`jftS8X{D>-t%hjmk!-T@dsPJ*U(3yaCfmkX4a6 z9fTH15DgZf<&|K_H!(5rZUfbSc*lRejtciPE%U#T)!wC&5oWtoy5ju+{8U^IHutpp z&#LVCe`HO|f&De-*^M*NVV?DJZvATRwimml@bO}^`;gn3mNOVX`<^*IhQ#vR;p`m% z&NNeF$9oc-`|1x6oKwpXgydc}$AN6etIMqLc$^K6#T;YY+jCqT1q5 z@M5epcEk?Y>pH(~a5xw0THbZe)rtf{Y_4uy@6V$KQz)OgUnvDfbT5CvK#;y=8!R+i z26h?`ioqQF$5Z%WMhy}Kw_}eW7|-S``dG8zBys+RO`JO|zva63avnjZrt5`lsrX|n zj<~oyrgy3E&f{-j=<7KSf~ zOGUjGr?B+0t3uDC^gJ#mNWTCGP{4z8?gPB=c1MJXi#jc zx#0+gdokpD1iM3x`8dpoRZNZD*Ry7EPQG-=~ z$N-eL>$*jy5BjUff3Z!)f9NQ`7ptcv#~DXa?HP<3=lXwAn_nQK)P}i`i2JsDl7-4+ z&-yY4&Y*8>-xQ^+D5+fqzm{D;?!OImCqEy5|DsNIaye%?*e*&$9TRj9jQU*W9Frm% z42b+x_K+#xT6CEo8EE#t<=gTF!?^37ofmEQ+1irCb6+wWiY&M4KVR!QzVO{zm)bc+ zzt9UijVynzaj|o<5Mb5he7UFfn-9~|e``P%UBZsT;u0wnMBfl@G6PH%ujxt`Gg z$yBGCRaCI9Z=YB-klh>|O!ZUM{H4z}ui2SE#Z`a4UaZsdr&0`E5(i2eHD2mq2ZNl7 z5SKQ|4;LeJt%b1YTia_83}p6EB)qd_4#RzEE}JNV!D#MjWhwwLX1xyq8pw)*j#X7; ztPSh)eMWhAdY?uz+NGgkXx5%}WUQ3|UU*zLj)r3~KW+XHRe_d5M)T;YV*(+{cw*SO zLs);DFWCJ)Uyk}hF70*#2tw`x`9jwR@`bib;tNTQ{R?fC{RGz`R?5B*H4nbfRcdF{ zN0$HMb%CBJEC)T0za^sAmEI!Frq(Cj{4`{pN@g@2Sqg(EB8$wtW8*>s@K(ljw@(1J zdp@Lj=m}#@WJ$v<-D5{=7@dXbDefr}nL2+f;gzP6e2k>4{2g;is%9gSpkeqHN~W6n zPBydKSM*lUDF?rD^M;69OFYFPR~FyF(LYw|0)CaBOgbrw`wKphmHHQaNd7MHi^j`j z^b+zi9Hz@H3OIr5pIOud(PFX z`%b!*eU(G&w9gN;8sFSkL*RcT@{M+`@M+z(nNB(7dIIgK=Uab|q%OO$7_Z3_ zx*~HVeDn_a6L{9HS=TO3^@}y-^}4+hHqKr<5--rUjZ-meM+SE(Vv~)Rg1<=7@1F9* z%P_q_w`bnxSuHY=r=yRgc_R2qICSw|!t%%wvm?{$ou@T4(g^T-D~$pLbqfU&>i`<0&X|lt$_Nir=zAH z{_lU=+_mNIq2GVp?N&-gGtmku%kU}u;ttz?J1m}M0CN>XhqhY9SioJ}V7B*L*6NE? zn{cm8dDu{!7sqV#r_GiQk-8<3hr7icKp{nGSQu86<^^HL3Szfx=2C!{&$$x(ezzL% zidOGdbM|gkZ|_!f_ij;t-^fi&C-&eN(4xId4oQ21WsiSHeU=0zwd+COBLLxX)g|$q zPaenP6$BcD1p!IDIAGB|m5z0>BOt#W=)kbg@45v+@5{Pa60T|Y`I0G3%_HBI#Ov~^ z9`*|(9v<>V5sPwHF6zauYMvIYAki-QA@SVM%bwSpV9TOIC~3uS2(F zGB2IT6?T8X7X+ju51PoXgEsM)ba=2N8rh6>*kWChbKk+}BM=v^x!a{{+IHd0-FAnn zTo!QQ+`Y7c_-ftKy@-w zj6vgM%gK1S3Uz23IA7#?8`~)DSw@&jzkyS<6haN;Wf7VJ~<|nvb|0bB+8pL0+Y_ z;C^vmHH|{PDw+w2n+dmaj@H?tsL(!4zL#`SOxSj~!F`8|!tQAU$q!5|hS|uw92SFQ zoApkFEZ|}6a$JM3=OabZlbKY>3BJ?P8H0ZhdZ^a}Z#IW=`?XpFc&OKb#NJsV6oGMo_eF&K^|BF;oIRbSBca(XN*kOWUN4c~wasu?x&$NWnnjosw7bxKh{u0Y zK>fRT@-pbvs|ZH3QUPY*YnNcgvUW-MKzsi0>%-75R}LiPI;CKQUpRw~z$<3Yk!11A zIYO_OHAjxMGv-bHNd5y3P%f7-CFD98bA(?wV~)TpW=sP~vnI>p*?)vyFZ=5ptL2|n z%hsF6H?se~K)Didp;Maizy*Q1g^quqKfGJ|j=?X6?Rx0^nx?zq{@%M9d^|i9+Qq@~ zuHkj;F6(s@6(@^Vvi-NAT;AZ0mj1O2#yep0p>I}lHour+CF{kt7j@ArjSaOf=@+gE z87SP^x!o6?xNpV30qt0#Wn0n-_@1=17VsSBKaIk7#Zx4@Y(^JN+zIN6sXKpVS~hv7 z=xe0!lw;ilK0mZ&)0X`rUV?p?-uYq>^3E2c(3{7%9MF{oM?4QucpobqlAi@#2(2a1 z@SX^`C-vY>1Q7Bj0t&&5%HtLN^%FmC;Yy1UHViLjC>f7Un{2lFD7txpl|eL9(19h`q2MX*kGJZ@MTM)QvJLDP_NXv>#QiM(Kmk(evxYKgyS zo|dTVb>Nki=a%EdZUAkzi*vpsf3Hp)+djh>+xmJ-EEY=$AvZY!ZIxSXQ45%v= z8xzxV#m9ucbTKk*jx%bacGyJ*p9ehwnX$ z!NKWpRoV487GDOA4PM~qrYHM@xF_OtV1f37nCUnTvT2Eb;fxCT7tTP4=A0{z=&VL1 zpbsf(Iy3@RER!va8#ehFju$`Y8IB#=RD>f&&v1rAA33oZOz@#;zAl$*0d1X}%aGT} zy@x$@^(Rd^4RBh6mNt+X{E(tYIv5 zuJ=~*XwcsV(mr>jUmAB=ze3bEclq|~(wL+!mWGU2LWzF^u7egA<1m9Zv`1q0&0$%{ z#j6yF$?L6EphIrBJPx_5%I%W1OURu!L3n(f);E&%1BqH`v(LYEA(wCXP{-E8H9$rw z?+BSm!EKMXv_yVxb8*?DtI=1W?U-*KFA2M}X(6ca9z+c2E}*%H#G}I?c*|mOSa@4^ zMd+up@LqqH8jrj@YDF&Q&76X@%W0g-y{|_i#5`RRDRzHL|92xVZL=3j9XALt_)Y8M8IE|? z`gk&$!D#zMyt(&CY<6{C=nUI2Bw-U`#~{PPu((cmA$0h$A%|xB;4L{(n4%0VgLr7# zKCd>zVOdz32dYg+woP4ho1vzGOJc()X?a()VCRy6-S&ZCJ+~YpX&*_ubgo(`@ylW_ zhlPKR3SNkLDtIZj&+B{_j>^R&(a&!l@|F}=gbt~nuSQ0DdtxR$jwzs@5>E$D-gm)X zL+N0rF=;I(@F~<|3fU1X=lan_;BOoj#!Kx#yle`!m+~o68&J6FRFGcCU_4r7p&m{l)GVQ04X}vboPPcwLYUWpL^h|# zP#n>G#?V|UC1v5-MnJzrbtAc6w!V?HIZLe#-$}P(LakSBB*P12w>3+SumsPgs& z(`Mzu`iVtoy$*s-@Dc@g!uYbqcS3)@a<9R{_QMO)t=Fuh!*nsp_ZoyrE;s$Y- z_4f>OS+9Ji8M%61t`^boLbrdTAA#IGG(%N7h zS|AI!re* zeO^|JCjp|a>wiYEo@3q){m?F7MKIVE?f%egzbr7`AFW^J@FnLJsp4D zj5#GVy>oORP4hn*+qP}n&c?>ZwylY+jcsGYjct23+}JiYx_O`P@BTG&&P@08oYJSN ztE;}x+H)WLq#D*$T%22W&s6-CH|X%7d87H-R}Ek`#D(2{fO>`-gy%Va zqvZKBnb*7Yw~EpyxYr>|e%xTnKDg3)&_E>K$Zzbd==Rcj&Mc&iGVJ^{>tZNSYZ4%6 z_sbM1<_jiwD7rOk>7p?Rx5DP>#*iGc@c;9T5Yd0wZQk4E3eu5UttKC{Q<(V%1> zM5neJwrSQJr zP9-vkNw4z(wjVPQncoFTy>&PrI)}M4`f46t> z8`|%@{o%I?UI4=N%U>jeUx9HC5s6c-aP#kqJ*U686q zX#?00<`G{(ECVBD!d3z(Lp2*l0dINyDm+b3w51scC8kD@L5v`SK=N?kxVQXWg zPNq~ZAj}TkW4HgWG;f!$wfK6pbhlB)?Yk7iEKUVsUFIq7vcFpVR2j-WMm6o%Ig-aNM6Jr{+;cV5)X^zoyZ)%(ld3&zpfHgV<8(d}phqYDCG~q#>SIUEVPkKe8*{S?+J?HjbcEWW)7Qk=@4J@Py+HR(S zmUP!;2|!+TAPk(t+Lh4|W7G0dx*Lqyd=*f4xbAyjgCD%{PE|t%2s?VZ3`<}uZu6)v zRkfQ91m+CjtzVClBf#+1g2@A`N+j*)_g9#I2VUOQnKkIi<5OME^L>FKxH zvA9oUUT`hYaqLuvoGqLP19qPfJ|grslDc&17}vU(tk~*<8{Cqb-QHTJwu=c*6*dKz z*D3q1mBUuBMc!e%OC;BfJm~2SW^^5}gY_tlc}_tM2FI!qFX$YJv8r%*-Lx(z>BHn3G-o*8z{qcLVJiIEf_iBjsGNgO=(eWn_PxYrvu{wG0hF1w`k?tF`pI=Y z-=enEK!^3Q@WIlR?Qe^$WS1F3Hquyr>UAg!rD`-xuLo<~@ZZ}1$Ry!8bjOSDss<OC8Bk?{hcT`vhyGYn$CvjQx3k$JHQx$~@ThD%iWLwJV zXTL10@Ca|sY;p$-D0&fU#Zh|mfxn?=i3Q{~+@=CB3}z4Ri@$RtfAlgZ+*e?IrkfqJ z_xDFub8|MlpkPDWg~yfzd0&hgB6v9^vaj~wF(2z+*sCY|V<5v}QDb^$HH~RRPP|n^ zcG0d_2;&#USr0>Ww7@|P=S|698iGW-Xck|K3-KoUGy1sMuZ#z`(VOR^4lK)|sB)x` z?ZT)=gIK)$9C#Vp18Y7@GFD!m+K2dq%*h7jcJ$HP=Un0}pQH7&+mFp(O{TDT0+i-e z`5PxrWQEl&+CcuQo*}_3{Y{RJ;x}IQ4VnY{XZLxLrO_mTuz?~wgrAqN(vWuhEP==0;p4@M7ZQPE&XAEh3PuLG4u#;C?KZFPJBH8vV03QmJu`x@T3MSVg{| zd4g`2nx#Rw#nbQ-<$?Tq6Y{!LyeQ5-+o^(tHRQzi!?wu&xd;`vQdCC3+6aQ)59;Txqe>rVG;jA3X zYPTLTZ0g8zHtwOd%&*l1miXoq zG~ny;)Bb}KPa@{sUSw~8ex*~lo_=LwkDsQ>*FZWuCj0Ihw%xjX4UC`ZlXPke>7{-z zz(!?KT`K=e*OsMA>obc?M0_W-59&a=>`&Ngztf%4B3$q32eg!(Et=+Bg*T3+ ze5s^|0hg4|16KzI!HkDOmy*wE`9K!SwV=U!Orl-$sg3`)KVD)74Gs-H4Hm8wotiN( zJxpV*!}xMh9eF!#32x4Vl&4kU+~U3AzyX1W;9^~6t&+lbKeFZyT>&We`*eDHsMBA5 z&r#lE)ou!|x^`(&c45@S?i0GH@$ z=y;yKUa!)37bR&_M1!Wn#uHJ3$AA7segb>=B<}1l+-0KVx)|1Z9tR&HrUuF7DgP)1 z`{-S(k`yBEuq2bH8F&i&VTn+R`w8AF-*n3qa)r3Xv!m_j*u9cdqLFuG)u>VOuAN9g zjtsb7{SB~BE?XH);byx%$mp+r!b#HJw6rbdfk+ z78S-Bl010u@*{l^V6#lyjZya<_D-5Il4{^QPzLh-!nyj9d{SD;hLVZ_fF$&Dvg&|v z9NPP1&`9puOuu#1;?U8KJhnI*jI3E?sOif@6c6gWsLr44-HF~#-ff(+uj9(I2Am4W zyt|1Xt`q#*c+m(S<-{KfFite6DQ~U=;20b>3>U2;2PtBq0Vg{he^ixld+$@MQ{?*4 zRWHwfD{DepTbhf$&-AZg18J`}$YW{CC4bY~-UPJrL+M!(qf!!4FOLd00?g~eGUi6M zVOMZiOb$-+=2FfPAEFd2g0rYmvLfeDeUwi72@DZ3`?gz~CL_xFEl!IR9RofRH@Bzh z=^}N4gQDv9ixjQ22L@)C8Ws~b5un@dX#Al)QL7^FjF3iWHm(C90I(UWRq)$ZY++lJ zTl(dpUi5#h%3jFnKQO@g+u4`ZLpWhLMU38qsS}P!ddKcY#PEA_qFjJg4h>KxXqzgZ z3}wsIpl3Q#gBUq@1eC9O>?nq_DQlL%u>uH#gqG!2$t~gue=?olGUm=?#iKm`t#2_| zxV-vJwldev_yo}hKxBiXpa9=W#5S?a**_%j*uqGPF0BX_rnBohAO!x+@Q*mVTcY#W zObQhhY}Du=8YO~g18p{k!Ko)D-tBsgW)5V0Gg_~sMD0w~x2$>HEYmyLvns!|CGll$ z-!XdsCVQ#_BeapI8(Xqom&jYsq}x?5@JPI>fxcgLyRWOZfD8Az2RbmGFtEGaOfR6` zZ5IIK+?&ep$frk)#ln)JT~4B)J(5g(UJz*ct zxPPc@3K+~wDW?ZAfAd;QlJy##wKL^OtH2mB%u0L{h@W+U$|_y6tPEl8(~(L(#hE~n zSRFpz@q{(AJ(l0$%lNYdd*jRJa3aO7zo$TmBYh*l>nnc4Is|IW8BQ^=pMcf3#JUx!Q~|3sizEH3sSg$O z$|4Ea`{Q{&$IF@K;S}{}FdM=d;*oWScy?1mVR@dckoMNGD73qH5aJf*N~uC@w>YIp zLpOhSsx|H3siyo;G5vI!uv=Wn?6-xQumM&A5wJ&W=-Sbo|JBQ5Hys9X+69UscaTesGfU#I;zUZI2 zdAweV6Az=5at$#^D>`byk|)#ddpr*?+AWHdvuh7SNRC?YWPtpOh0oES=c3v|?F!c% zCJ>%H=HhfS2q+OrH8{OTA^lu@FkchofHr++gE!N?cLmEI%{rjIP1)^M)lC_#(@XHc zU){14PEF<*L>{O}AU3QtzE{F!^E{XS9i?6ro*rp*%xi_2{V#XCkr_6Cw{r%#`6ZxB z+i)4Mc?m^x^*4XTmt7lVG&AE^Nck925v8qocVZAlf3{pMrosRLbTo#2XEYCJH zN{-o|*=c{Ev}I?@O)Y|QV1!M7Pg5IP*}5BQCf`yE!{y(CePSy_0()aMIiHe|n+Jp! zA?axbFB zlYF+4@tAHQhMoM9p}<@Q9bkbKhw#|%x7s}2kg`{OjrNIC9Ath2EUd1?FWB6h>iS(M z&rdgW(q{@vt7VKjOijt>Ru!m5v_Cl=8E;b*-dthG>Xw^`z4IOGfs_A$h{2#1p88&w zIyohANcc06g@xJP{J$yuYmX;-=gB2Dm#;bz`T_fW_ey_wdwKVjIOFj03D597N`F<^ zq-^srFznn}37jMFcQrH1+pa6QQRLfp2kVeT46Ir_=hV*zF07A^+$l#bDoKsBIt^*4 zbYoI$SGI1Ox7;gq52JoHgDMSU@qSJlbF2^mKiZ-Yg${Jws0=MgPh|nbs!nmj8CE| zQa*5=2$yGfb356B2UM{WFFbsak=OVK8*D17{iTe@s{{;|^ptiYkUymk)eie3(MSiC zQYx!AIl|>TDtik|4oLJY`NUCKE!5jbi-5d>+nq~FKs4eGSB=#?&emZUH60>?7Y`0k{g{U^;+Yi2m%SQC5`+F{Da zjY`JlV-$7OTaXf~0QK7>?qwBp(P!Yprzg7fj5sgEXI`J@l(J>75%a}q`X}|YwI_j# zk$#_%gd}^6lgxSLd>=)5_k#q4%f>nvz|hHy^ZJvlp4k$xbYv+_KiBosa77zRc^M4_ z1YYH>w(_|+$~Ip)Vo9&-Ot;?I+vN^U!cz3fc^J{Ta6!F+^szZJgj|uqOqiHLO;&VJ zqLKM2KyHtt*{4ObH-TmszG~GjGr8LCZAMsMy8S#cjrfJM+tzjEZ0^_}Tdj>^@7Z*0 z)pF&PEgO=k*F|FmbkM^8(^KtirVn|bL%@nzH4WNcTnwx0gTf_yk$7MV<}V^9US)7y zJn?N|h(8SgyM%CEMx|%(CuRoMLzU1rrxuYVvunU(Eglzv$)vX&Tud;Yhxnl+0~(YL zWE8YssXxrFB>*rGuweytUxMxK@ z`B&&wCPTs1m-mcJImwzDN)KOTGKI-QvaUR%Y4% z=37B2pi!_RI2DGdZn*_<6})uerD2B>+akl= z*cb-uw~gz0MB^IiJ>fx9_LoJ$T1bBWMp!WKOS@tkSYBJZZKxUR8a-eY>zBcdl_PJS z#4%sISA)GmO^e`>OJQ6ENd)VA<*k?u7t~wq54Bb$s_%_d+D0=ccCHr%i;E)Bg|h-G zMLHYjqozlZzUs^f_AtK~bd0&}{i`hcw1)B?aqZQ9M73|DF)@*qULUW{G7|K=hK6r^ zP!1kNqj6oxqB=n``@XqY)R%@6Hyse@uDn2LnhdAj(>Tr#j=h7WZ5m{XsT(4IvWAMa zT5OY5N2nMByAglS+F(>cTNEvyPDTgJjKk8SJgENKj#~t?W$4HwNV;m0KuWp|)j%%x zslNzJ4alEBRmo$c>5qO53_M?uI^?>GU|_Y(6`*}ClY9*KshJioIh;x^C*VG4y`3vp&u}%Jve}0oS-P9Awh-CFSCDjA~iu;mi z-~8eup_pOFKv%}H;;JYIt+Hw0P3}&qEf(-C7I@UCSHZ}}`Kovy4M_y7FD1Vbq7(l? zo@t1IaI$utU6ssVkvM2=+I!XfihmqG_VbIC_S{e{sK;l3ku^)858+c6Zf%QB1uZU_ zHC>(_rpSDU)TZm(S4=mw<5&X3F06Ft?Tqmp-lz_(z1HclWib|~EZ08@itA}fH?7Dg z!m@{LSIHUOOtAfPI0>e`{>=;P{F3yzN zi0BcHoN7McUzW#AO@#yT3jgK~GV`%_aq+98NgPfdVT}vACC+*aOmpc9~8!(K4r9{x{U{{D-29d*^H?3o7#d)7=iX5N4yaWx)A$ zXJlH`p6<7}L^Bmb@<~wfJk+2hERaDm#iW?Qc5d|vqp1DKO6)QI1iZN34)z9oUIB0< zyV112<$6Em;A{Y=oYWxw3L}r1c!GcX5nhUO#pJBHcT$kq&L3+6OAoFf(AaPJ&$9?+ zl*9Fu;~>@1D|d&|6g{SnqJy)}&OD8$U_GRmX}f2w_}K%|||dz={GK!c--98&24fw0cdF0i0rC zrXBs@I&9p%0{5Xv zUsnC>y(C`% z^W4UkPbh`G#*pc=2;mdk5Ycrp@HRkk;b6Q&R5WE8vP>O~$&~IiMt+Xb^h)HY%-Tus zWV87*qur~U2xaQ$G588hVLr-fCQ^V3AwP7$qI z73ufX_=R)SfP*JgL`;)n&Ga)t-vI;CcA+BNyfTEEvp08XB3#i-u$^mp*f^hUmi&%V zY*;nFL)s&+;~#Ra7&A~V$PWAS7T?^mhuwsRcO)ukq`S_S;8cN2HOWE7@qr7(yOSxC zI$KVlh_Z;mcM5gQR!*1CvEhk3s0)7Q?IH5GjsslF>2&Da6!1jN)|LGe9HiS6+1qsU-jzS z1FVnFY9gEh6Q5Nlg`3!BawBdP)fTPflDHSZn+p5XXR%+2@rQbb1Q{JE)jW&>e3(l^ z} z@?jGn`WCH~J-#l=b@-&03)s7i=CLy-2%-M-_iIMCN28y+&TBL{HsV+|mKpfeX+F6? zWnvCN|DlW0^7D~oi1cRl(9^->WRb5 zNtqz7lgR>=0w7-P{YWUBCm|9oK)J$R*Q+oQ6K^Gxnh^~bh*Os%$POIp3u znOR$WaTb^nV$~0G`Vj5N!0qC*cc){4$p8miJdaJ&$KU61ax|$cdHFZhnb!QOP1KZ?!$@h6a)HMM5NxxNyhss>y;6E9(zL|-2 zzobH>8=(?P?Oj#+x%>q8y{Inw8JGS0ar!(-tC|Isj(_nm$EHKZ&EFquN90Tvk4VUF zJC;la<@D+n+2|13DaIO$!T=BUkQ=Yul6OTinX5~uXI7v(VDje*~PQL;alhUwFJ-qmH_|GhPVIt)i0qsy*XoK-QO^& zs*SmN;)s&g>M;?)qsh!6pj^!j-VO;DbWeT*wQJS=+QYB3U=@{ZWjd+-B{zPKv7Xli zB9{FoXkX*Az7QbPyFwB9mZi@c?iYGyp zoBduC^^7|^TpPR@l?`$L5>rNZgJofH!u%74H+hAa@_SXMV0#;J7rYu%Z9y}ul6Qwh zcO@zd{TV0!+~*zc20D4vll;skb@V*^%|9AK^Q753^gV#wPncDB>J{#9@chN0qdf$D z*mGV?`1jqr4jZS?NsZ*eH^#`c=zL56`6{$s^TncEjhQ3ktD@rdC6+5iEmEcE)ECGg znqd;=gk5J%Z$Y6bk=QM26=f_oOdBaR3by#P9xbU@Y*9R-B&}3<~ zK{jr39ST4*?|Ep1f(J?3&DU7{Y7&gZRM8ctVZcI@$#R1-n{fgL-FO_-a`-*>S!DrB z2lbM4LV(Mws7{Bq8V{pJ8(dZ}R6##32}^0r30cJg4lb`HD}&V&5>aWoNka%eqKX-Q z!5-XYn8wC=gl2nh!q21aFKfe)t`NqYwkh)9RWG3Rft4APNjLzm|C|}Kd;*cWdI$oF zWvVR)Ej%5t_~7(98GbRDD{x3yXyFkn$up8S#qbmcACRei=~g=Fk!@@5z(-pZL09J) z(nhy=U{7o9T#xXCVorp=5wKWW-(eFP+p^e7te)P)JJ=SaiaeFGLB!3&?W?$5RC9*F zED3b%Pa&ZcDn{S=(M$*#>3fxJQ>B_1pC3)n5kq|{FIM4L#i1lL(Zw`vW!i7B)*q1b z?<}ZXS|D$a9EVYbw25$n@x?R>vLRxe4JHRJG7_v8&|=5vR=i#$V_>Z^j9kiWy;>UE znZ-zPz*m!zlVfAnqT4P`t;UDq5}7!f$pInEa~N^G?7ZJ}ZyWyK!hg=y*7KQ$#{O!u z$>Vw^%9$k=o7+V~J+~N_CpDA;-mXBQX*W})Z!|S?pr<0dO^}^+_!O5C@RXsA9d+0nhW~Nu-T4=%T7Ge=z@&^~ zg2th>qI=nX87cb#Qk;k7h-;+`rkR;NK}C*MX_ zGFSI|+sF=Oy?~|j_Wq0C?g9f>jn=Xa?fCyTd)?VU$T%PY%jnTHf~2Hf#X>ADFM5?Y zc_mjfOZd23PV>Ss!&JFSlZn-3SCr3&{>e|SX9#7tsu@0I2LFP*M@4#9Dh&supeIhZ{HJ>s)#}w7|m{-mg);JLK*^mwX|v?{H@mbsT5Z zx~tVJncer*|AiFiCevzfO$N6JC$qB0E|@zBN}8uY3diuy8*QE6RG#&cKDOg&p54|3uy+sh>ieO((( zT1NAw7O|Sr(JO$MK17N{t(_cjXbq#ogRlITWPh zPK&ABNz(E0?V$3O{lYz606LH4mvV41K#8>un+8t`D=E32Dhe7#gm&Vu)?Nw*)ECav zST_Li6mL7He`Y3O)0A*#Ik}l9nv_r07M-{=XK8xacQaQzxql5~$Y$uTq@s9Jb|%_y zTrGB3I*bR%pe3&TT~>2rR_@|+=}aTzPQrNpXGvH0_I;WZLtvYSyk|4XOrkg699R#0 zE%uy;rUQmE;m}MZxF%;kbn){A)3v4_tAXFvI2E1n!qceNpEKg4=&azUIL8CCdRBNNP3r@v(;|`}n?hWkj_o zZhtPa5>XeG=WR$cb7zk;c#CUJz2{0=p4N9N@2E`y>o}e{6Y%g^F^l8sU|N8 zO=r4W+jWh0h#O=jKX1T-J`w_?5P-4dz1b;8rO0%Q7y*afKIzQAgtz5uoBPw0wM@JJ zhpK1Ut1yvTVaBZZ+2!63nkMZN>KyJEeDSn66egX-=2kTpLt`_-nUb)QR$pQRve+kn z;vr|b{eJWC>aam)b!AWxEc*ZdStC1G68G@D>O?ioYPM6-M;SQWb{k#Y)W{Z*Tvbo^ zU-TJ?wXn_xSI-1lVCbVtFtyNJB`gsoHs*ijo-@pQ~W=)1oR3zU{5nN^2vh7bMdpg>*bX3#yUS)l=3h2*e0~WWwhQDJ`4wWW^(u-->|D#>L!JpEZaFUGmm<9F*d~Vo2DK>@4D-E~ zO55PW6m`T>^6CCBt%JxA~CKW&McxqsT6Oi z|DVVllxI?6VOtmc7`YYZ)(~1+hjuLGz~tt$qQe--&K&GL4sY)==a}AY(5Xp?1l?TI z`UClbr71VPAJ>yD3#pP%Y%Ll~dUW$>2G!0ie;w2BqIJq=-&)f6TOmdY6O2H~=J_5h z7nm(AmWOlhweipS)OZa+7nx(k+Y0m|Lha4)BGibM<2w#}S0_A)2%&zpY8+uGmi+?0 zuG`qdIO(m2huQ+AqpX|zgWCpZ8L+y39M?6`+vWuK!D77CC2RgUg_qYe}EYC`D*^DF;;=^pmS=vRnWlq`~RZ2V7M!8k|O5A2}?3e3zn z7JfV*dW>=-%N-sf-wd~sX!-FIn49DZyBp_$$fnbi{NI4<@aBOFq)>s0nT))o*1`QN z?grq?e*pcd0@OJ3M-1kfIZJo^w6ocANzhun63`b~sAph9>UZE8A{#nEpOD=B>k&lR zc98?wcEQK}zfWE3uZLl5ww%SYHJlL*5QswR#~1WFq)kl|Z^IY|t)qf?@iY_iSH1LYw<#K|5g@OfvIhoST!4#pevfw;ynLvXT0`L< z3pJZg`e(*}IsBaaKS9}EKG zK~>64MZRFk%Q=j5Z1d0_4us&$3bhM%a~VITC$9`#*tG?z2PBVN>(oU(s$UR{-L2uB zd$Vhw>b_L3>#A6Zo8-8fLC+#D#7 zcrKEr;p4rh87`TW=_(+8Gy^KKgm|3Wx~K*Jf9E$}rWB28-pGBo(MbWxRbN3>aFv@xz6w!Hi{frI=z9;dP_EjLLuhwg?^c9or1U^#ig2iepS^R zocyWP?+8tTL%S6pW^*6tqh;u?ScrFzNqvlzAN~}F)8s;~&);N~{n~5D*YpPD(!K3( zUd4WmoS=c?J340owt9*;L6%60t?*!Ej!`YMW%cgkfu%B^bUD8LtS)h^eme8rNjOFx z?bWVVo6=0?9*FR+fnV>JV`FH3zvoqNQ+O9&Z`=Hq9f@1a0QMh<$Fz-GMYD&+GF~w? zNQD$=zmPjunZtQu{m%o_XUfnvat;Q=G2caRhqnQ6OLOKC+5WRy`a*N7j7&H?WHplr z(Bk@OD=&YcrCvlTNuFMmd7-X5HkMX>zTDJoD8KnJMrV$>SyTQfxkPW4qn_H^pG^rL z7^s4q-vSXA{jof$tcJM>qH@D590H0hr?JMwJHB1-mpFvl3vTrB-5Vnjl@j(OvVoT9 z0D%et%g34uO?i<2WY%ABBS}1Abvm0u|Ib>wCtJi#%A!5;#N<+o9ws3jO(7dkg|H_e z2DGjuMBh1IG8jM5y^G1|(Sykl$*kFAZ&(BmV*S$r`xJt{>5|x`3Ko z9Ak&U_2NLbYdMv&JiNcW-xG>D==!(wkL`ujyD@}u<(zd0+V<&IgEc@YXEytiT`XjOtz|PcJEAYDf8JR1Z$zNiS8P$i^ed zep-+_LE!Xo+6sYc!2I1?2i3YX+BJ`_|z#o%kMB<+o=+k<8 zH%W;+6UzSu5+mD30Gs%h(CGS;9_y!`EhY6Wc>-=->-H@Hc9 zU@35F;vlx*!I&M9Y6eYx6;(H62T^R?fBig}=#i)Xw8Z^qIW9wS?*b|_WS9DODZv$8 z;F6uoBAR2CGOk?K916Xi#evJHUcJsDgi$c#$zA6JzBquvCXE_$KK6yya3_DvV<|vk z*dT4>fyH!PX28*^sY_;n3%EM*nN&Aq71I|6+tbDP2k@XMfs>ZVqhc8&Ic-srSy*Fd z-hd%D$zT~J51vU?f3;c=%{S_FJsqbx_gMBb8KwF06$!gd^{1LZ@M~V3nHHkbDbGI4 zHkSv>Tn5rmh*w*maf}n1d0a7`Q0U(uCDozbC8a55uMef7=EnJdAYvz^ozg<-plzl-^j0_8eJl7D7Q$<^SyMPJAV#g=Iw` zE0qU@V=J-)F$=ERy-p-1SCb3xZgqWT@q{rLV?SXR<4IQG-+y$_`hPHt^}p21Gw9ual~ninNby3KxoNQGaUcm`KB5k?7z5*3Q-R{_T_uL{moh z+Pp1-=5EEvb9)1>7@&9m!nLb8#=nBhv2|x(-q}>@+bzkkM)Gthztpl%js@HNWoIRH zeB5LYgO$<^ZR>1#mYMwrK4q6%<}y}7FV&wF{n9=n;|A9eQ!)$JNxwfvXldPDW| zZfhGLAt(o=tcVs{N#jPHjS+vDfyQ%acq-kR^BMj2>r8(UY{zX>rBcC{Cj9`pYU^O& zGwO;0z35D7>g@kxG12!GCw~a4(;(g{s)e_nl@{%UubJM%$!dS;Hn?utg)?f7%B;nG z$U0!9DT$jdV<*#8h0nClk^uRtD-{TK&fp02?!@mmUjFL}UOYPiuSCMFr7)IO{C(bW zmGoLhS2l@>Z6PT&(yTV8*nT@qFei&NiRILe0i=c#bjSoiC6b9ufG|mI;16{N&3dp` zVG8fFw6@A6;b)ReHCdr9yF>axZUXrm=A## zJ$(C@DU9Xf1u(qx zw+;xWX*g?q4()~46;3z;2SvYf)oHd>d9q1&9Kd*HZ!g<7qwffGkiNhBs#3VK^Rs&g zB`wP*X+h|HMgOp~9ucxWD3QV-Na#D{Np`@{H!kKLrhC3BjWC4@G%Nf?&|d%uhL}`| zGr@jTp`5@tpO|N6Xe81Bk8JF;Z=VvM0am_Vxs8{i$L`E^OAL$J9-_9{~d_i_VWfO<*%; zVihA)#|yOcust)*W^Dfz`xg9u^|(egiE)d_%(N*j{!@$T^zEysmO}~~>I_GqJlqFO zi*Ou=60&!GpR?hV?i>%*_ceeanF$DGV)*64u~+8+4g!Cr-1i2rO*{N;5~JSgUBaIg zFT;0-`=lX{3P$*Ao8Qf~?5e(1fI zmHZcqyijF{!y`UCxWBV~+UqvwS+&BtDZVKTfiH$XDpYz*ON^^I%Mu^)%|=3r|F}}) zoV%#k;q>$0>?g3t88ab|=qlM55gaKQ7)`=ZrE#Ez11&%uar6N?qcc52_qrR=r@g?# z5(5XaxOT~F-gjue8|ll%_d96HO{1OJ_k6>%=1lVJsOw5h z2h;se)7~jDRekz-=W2L|?6%0ea{6~Jw081$bW+Yqa!+8+6@jb5K^2kyKsz?s^c_RQ zitE?pmFy>h4MKWPKQI-@b|ihE)LmdKYy`pEv|+kU@B+tF#$M=}5M=MRS+zcPP~CmR zPy?24ForT{C6UI-E1suys3te??dN>x^#DI*99^%}rD@FdQc_}$9R~@;*Di?Qe#Qlw zN^x>lS_SYjL}%KSr+1NPilpdWnj7DNjdsttc~1g%ct6FlZck{jMhi2mTfBnnrr6mt zjeH^;!`mYtAosB`7ura&XVY6M!aE?<>CXfy^l znrJ}f?U6-+>7ymz*e0~AXt;3}?Q*EVU6AqLZES#?94TVLA@;9f2(9zIn#VT;VON&Q zd#$kKw0Lo~ykr%E-sih7vl;d7H8 zPV||#^pB1xTXRp!;Dn>2sfG=J_;ZW*cY^T|b>^Kb`&%!TcDYa2it7?TCJER}dQx@i}Y!Bd{(VN*z0@VXpkU0ml((&K|5K^33Kwj<^5} zi@Qga|A&V2gt1<8nD{R127*jzoCqzLK5P~}__P(FUJ$syTaDbwHX@S>m>{bN`+A6O zQOt~n+D|&>_0IaBnbl4-W}ECS1~Ut@-RHPQnhEy(q7^&hEEl;5IA|`8+d=I5ZAiY# zxy(WNC^OLk;dhFTf7VA8rP*?S5d`Gwe@P?$0SAmm&7dV2P~!%F<=Bd2(H@|an)3wp;+vd?<1gsoO=Nk zR`z@w4O3Z*E6L)U18KB-k`PqiLC7#stT#)+zAldb6l&EH{brebeNZYRVZZ=CVPAN{ zBSgA@Xz&e&?iGTvT1S=}OLrKV;kYXZ=Aw~&#mypw$+vj~CrhjKhoDr9R3(+X(s5}8 ze>kS3pM$lobM`f3t#b=xsm{ejT8B>D9@~|OJcL8S_H!0I$;)Y;0q{;@GVghCzrW)j zj|Gr4Hw7moZfoYdL`;TFXaVq_4>Y9If|-qQu&(*8GVGl-O7SGzpz*){{Yv=P8dN`R zJexQhzl{w-3t}bpW*5Ts9c;A#fBP$uIQysb`Uxp?fo8OBE8dvQ{kpP4?=BZ}Ln^oB ztH6nNxqnOIJ40%-eHX8Tpj_r*n8+*Y+-4s)cXh4!6@}Tiq_d{Yd@aDrOcAda(gk;J z#Et_FUuQJzCd)AwhJp}#!nOxfT!*19IpKL+rk%Xr18UvD=+k92qKx!+@rU}uCh5Y% z^YGZ{>r7%Qzv^G{M{6rAc(VgSi$X*lm|xynFTzqw#50pQd?>GWY-5(K4;)X9Bdx6i3sx;~A@*t0S9X;J|^BZR?BaSE32vCSaRYb3?+ zfi`7CPs5z?;NaG}=n;^%U?zZu) zFLiSfzSV|o)N(4dzm-^LyUjSimN_L8t*$;bIJ)D|~ZYaenm1r^O+)qC{7)-56QY zb8@AdrI@PZBl)oJC!|Sq0yKr9bSMP06(m1RRW8u{B4(V>UoiCP5-`CxP_y9<@)@=r zi5zc;T!!Pt;dvuo^fcL4;J3IF{NAH6>T#(ekg)j`Pg@*938qcoU7#|_DD1k%7g2%R ze>mbx8O{57%_W;?oBAR&Li=XfQ!kw$ex=(Rgz&KG@lJjalb&ttJna-W&mj^w{=&pP+0*myKKLp&o150x} zJXRbn@Q%w1kng@~yFV=6Cc?er!wdxj;7@2zqKosKG%Y@?Hj7! zmnUgPm@gnLaf>HF^ITfZAAg)$fc|QhuhfP6-n5+pQ$?8%desf8lvrh{z#af}Wlcx+ zRfD~eyyqLo5J8AEO=kC8UEe!HUo{Kh$EhLzq?6O(;NGr*?YnDwt!GE+5pQC~(}aAx zm8rH<2{o}1&OB=jh^E5Bzli-Ag~=`47v|)4FIwOms8-4$7PL{2ulkO0Uq~E`URLnA z7H-!Jo`#s}DT-!(XN#E?O&|`GrNrNavv;ww;@DToZ0=$pti1WU*<;pg#6&{sNtqpF*O9P-QjtNbHA+=wv)* z;h=q*Tc5Q~c%MsIY|7LG+i(>9tyY=G_V6A4=R8bC0pif({{y5z zTfe{&rCc2HUj6zqq zG^=Uz?x}IRz#NA6eueZ$zMR9i0cgPNQuY8Rj)FJhmyU#&y9VbPkXEwHt)@Hyh8z$M zOr=#|Q2xaN+-$nO{o|i->XQC(_uP|?{^?_A;8if39i=}}DX~E5eBy1w=6~QPVb6(x zY@(`}01Hyk&R{4clTLJ1Gb}B`;i#g(OGOjrJ?&J6LV|3fs+j=Gn)Y7GzT3b6G!$7V z;aE2@0-3lVXKi4Ma~|w$%#2JWF@T(j@z|EO4X`Sfi4mUoFr{JQmpoMN^wvP+2u_I2 zX(pE_#IWhABk50O$T|0syniOnYX@J!*PF8Z4!RvMaEZn%vKGkIO%SIum@qD3G2u5;bsf3$p>>F$*z?dljZx3H z{ebqv?gtkX)f&4~LMuhBAFY5RDXh4)yG=`WUCQJ>DoP3z-n2*y*8NcN z8I)(*diM`aG282*W8;;LOp#BfJf~cd?S!(Sj^x-^#I?DQ+{2_{Ek{aU&j1wgu~KJS z{s~OG;Cjxq-b(1$8~?TBaEy*yoJ+aRL~joUm>QrYC9Lur2o z0P6C($P|3v?fi%!bk*&qx=IGbN}Vm0^Z58tmCVM~vERbguZ`f`M`4x(#m#I5sG2P> z_yHb#2;vfgxAb3zLnFhEs&=$RAobYf=Z|?=;eSL6+((ERO~@upc1kCqZZKHy9;6Zv z$}P*&6K+`y=G-HA!oZD|A7|g(3Ii8y(gxUC2SJY?R~YMEM*}Y=%`-5=F&ognF2p=HB`F7N-g7;c%g?oe#feA8qus z=6@T$B|XXaTRi5%UjPWCN9|N-vmMpR2ZX$(A1?tCFaNjEA6j;zGs^F(()IY;#vvYX ziH)4l#yPL;-()6vrGJ z$*_?~Xuq=I`fM=x2s)RLf9F@igqSt=70xkIK;_;T4?8V6$nG*8=a=)Eji_K_LQ%GH z*5VX4M@R+2D;K`O9_!_r7IyUl%}eE;Obc>+?nMG!?Q(`>q#M7ehxUSVfd)CA)MKfB zIYAeD%3hmOSzJxR_XLH|i+fJE%6}UT!9cO2={wv(@r8R?>>D7BWK20_%IXHkcNSEG z0T1lGg)rwz;UD=A1K_xyD+FrFU#b7cq&3c^x_0VJla6SAMIEm{jLZ$#Y!@_(Xk`9yAR z?R8667UV7ut1pG@4g1%G)(q{Ihzm>GVT;{^AZ*m+_gqWO8xx+1_dvFAxKSQB2y+ux zOBJ=78Ipm{ycf+#!9{PywzC-&**?H4NY$X zt!VSsP78KG_780{>>l7=qNe>yilA1<)VMMnxcmrl^d0tLgbp*Y=fl5rQHEiUN@`xt zK>3%>M}B~deaR8rLUB%g%|dkMqN#m(SKegL1z(F_IudTxN20(Un}2B5s{^xKSNl=I zy|#ASX!R$aaN;*l6h1nsA?}+fXw5eTp(OPGB|IP~HyPlOALYA#hGW7irL>I(0Ff#X z+UXIo+rY`A8&)UeTaH^{JoI%c1TUnH2Bq@3u~bPV(2ACK$^6}47b+ZGMvcokipFwZ z)_n9yjEA}=6kI%o$A1V>{Ov^F2;RZ=9cUG)Ko`isbyBAD)`X;SbuxKa!(HrA#lmtQR|Fdh6i(&eY0&USy0&bM1G&ZGp%b8 zsvk_AK+1E-3{ol?xLrF9%#`jO2UCJ$Vl|7-r8ge5ktZcPdVdK|9R-j`4SY(8c6wES zIf2-dg~H8j&xesh?8?Hon(%7$3CNu0sbynNxnn>Ch469ZaYKSs{yc>hnrGr_Mj{Wf zXXA=J&FsH6W&LM4nL$6$5yvAjS)*cznNzXYO3MNO$te^1H^aH`bD2#XFFa(+Yyt*b zzK;IiP!m|q9DgrE#P8B6HbL%e7_A+sW2ugTu6JO z9cnl;19u_9Jt9pQA+DW0(f&D{1gE-qSxLjz%w~{h_?j7P&mAvp7X94;FIhQEFK~J- zG$t1}bAPoI)lyKqup%n7w7R7Bb`ON$p>!Jf-C>~0=It{Razz<$0W0oOP#!nbTzb$I zL*y?f<0vHqj2On+)P^OiPAMQO%n=)$$hHzb!i8A#$)pLolut+bH**Y)fouo4cD^0j z7Ixy#Z!n(`aW%FVgQ>Cm%HLQK721kFAIt35{04(Mc9TQljw{zr6>W@Z$1ZlD+8=!QiY@XAMrEeOc$@Xa3VHLQGL<9r zZtR$6lk*7d#qiB$sNqB{p{8!Crun)N72zMZ`+};nO)R89v>7>rD7tWAU;Jw6@P5;DQG1c6C04nxNt=aY*pqgVLH+`cfaD_ z;jsbfR98+oB#qDw=|A56dV!EO`bs(ye@0MO!jTL^K!GEx%I-*b`xf}&@AMo<5OMRKAKKl|*%jDB3Kq8^R1QxkSppYuc$$tpRxe?MrPxd8GWB3(L4AQAkOE?VhA&iAgOdcqS z99}I51to#IaUMfS+|Ewl>bb0q&0WPG<^nWleVf_GW zKENAGF~;z#rv)V30K67eRpl3;V$9*!Ex_4`d3T@oTj-DSz&}K=vo8~UIivGO+V#1D z0Iuq>qab}gyTQrNF4Qh{7&})?gNyReJPAb`ERL0?LpS~-!l5Xi8c`BSq7TpbX$Pxw z54w1?u@KA$2ybO zmr7mftS3iGHGPg{pJAwms448U3C^gY6X=g{BjAV{S4tQJME)~{Fw;yfPGGkj29lWo zg}5xXAa0|UBP90oPvOL3gv2of6pbrwh3q3F+2xArafuEWYRm4{YkzxhOYLmM_O+C* zmVi+^TCbh`tfJg8(sCD0Sng7$lAt<}P<0Cd+_;4d^hY=a6;8QQ!XSVJAj~wfyBO75 z6rDxXmR-d+_MRe}(`5yp{|+Z(^699WNH}2SaAsoIpMk9KBbX9|Q?8US2+9PzI&3rz z%#wgkTw#D<>i-@mDyJ&`4GFM1ci%32QN;-TnZ>T4n?PBisb8kSfZ_2nqb3E`NZLvV|Uw5%BR@ z9X=Wa;gl;S3|Ve!V9BmVrUvp(*R8)Xc{j~(`=7o z;(8<5$B&l|zJL9r?ESN!!Gugam5PagqMTQcj^2Nr^U@7Jg6Tjw2x3EB(-XaK@O!w>xNmM;eXK5L#e)7DOiE=_ zrjnpK%yH+ove9kZ^1!^weumSacq$bW0R?;v%6~=KDV$v-X*aTViG-89wicB?EXwv1 zz|W}s%2ZNKS-f@1_7lL*5B7WuvLzqP^WRbAB^%HS7zxL@OY5+nKiVU9Qm{WFsF^~l zC?_K%vU5lqeJ}QKKnD^IP{l;NPba#GD7QDHzmR}dZaHDdf5%XZX+r@c;TXGP{*X$_ z5q~`Y9YZVz?*c}`F=EGf9VEr@n*WX>=7VejBjGr)eYD*@3_adij?DazaB8lQD$2A%n6|J|76%`H!sPuW(|ak*ey6 z0t*&MShEpBE%vA3uZXR$e2*Ff;4s+7yt8(FhFVTAv7a$JZTTb<#}H7+=$L96cYobR zls08wFICbYEG)F;)`pHXd5RuAsvxP3k>~_4y+NKlW67tSkC5O;un{1fa;1bpP`1yx zb#V0bP<9921>?WN$(VdPswNT+SUH@HxZ$Kt1YyI-nnbL^+81G;$^)x;;72$G6;8QQ z!XSVJAS4aG4NKa#Y2}GI`Cc!4wSS%qVd`+mwb7VveI$w0V_n;aWRt>7l97 zR{qw4=?L#@seH+l#paC`k6Ceqls|7E4)nV44fe<{$z7Yn4ZKaeXIivi^nc_qe}vd# z)(EWtp>Yb(>i{;Vk^D=fMM7(&=Yj?mBEOa_GY-6%fqR93+(>w;mRQVNc{Ph#TZS zle@E`%xS-1Ao5r+yz!CTmu=U}vw-Y^JpOTfcv`2KKJk&0(mEO}V@>_B%K;E8T zod0}IiCVJ7#c6Seawb1nE@XZ!Rm3gJA}OX&qv&`cvw=`lv{gx48!F4rJ7;06qGsjF z;`HC@FXL!?SOZyz~CmehHV@KQB%7z_6ollS$P8($RwmM*}q0a@uCZ@gt2(hZ-M9rH2K8K`wMh(dw;U74iUbi9_A33J;&Ow~tZ<&8_f<;vTZT=;sbJ|bg0L}I|5$^{%L zn_W?$GoVMf65gX+z{)o$LDmzp8r+#OGGtfO4|EJP?F8`tL`sK@@{;;gNWzudH|)2D zW*(Expnv8sf9W9NCc@cWiv}cB_EP;z$7BZ_#MKC1Saw!o6u+G4Yv6FV*IkY;Yqs!8 zXn`m3pqs0|7z(@EhQoAPdqytcQk+m>aM-ujpDE>N$?HgV&GcQ>+`+5`Ek_mUX*K;o zlcOT7&p}Ktm3pbvduKz`c=0NCnt1o+&clQ^#D8gmGldZkPWHVXKiDYAeyG^*fK3O9Xb@n(k>9XI5gs+eO0xhKR1#FN8G-kL-P7(vRpu>R7B{;;-em$_3?{Twu8p^Xy%mtR_)(+Z z58VT&|JxzQ`+pw0Ri-=~honlG~5L1T89mgM(5r`Lo)K=4JJ@uIL*Ai)_?aLIlZjcyT zB?K)28pMSS+-A+TsVaDIo$0_0d~E!aCWq(#f&NWXrfcqdQ(wkzpoR($o8_#-%zrQ; zGf2!!s{z;2fEzAsjRe16P4>hg;=-whhb5e*k65gSK4OU%Coa8oHbdonZ3oeUF^scj znc6n0gA0ZFYYp_8eYIJjR&MawSGi41FvDt<8>kp6H^qpW-CIu%5yYUAGM%5Kx<=48 z6#<{H%Zb^}uW^1NS7)yAk~u5234drZXOWLn*Zj)5S0mA-PUJVze3fOGN%MCcL+H4D z`2IP6EbvHj?gS0#(nt_v*wHC8O_uny5LZjmoXjt@f}R9>rC^CXBrmh1QsVL~xO^H3 zX4&deG3R1t&atuU5O23%C1z~Ev)lV)#msnjbxMp1*lJ2cDpvz)w;9w^u7Cb|g!1#M z6{#XHZa_W47$2!t&6-I4X2ZM6)Z4oj-UEVD7Ul8g!fVSkjS(wVv3|6W_|4<}shnp* zTm>YLu%vv9fxH`+^J_5-#d8HnCIzNJCO8i_B#EN3NyGnv zwePNG{Qh_x_D2;NP`kbgCo5kU$mXlPEM1?stlvExRpSeNc3r*#=BJhmnftth z>K=rSF+nbDG8~i~mo~3P@Gz6c+A4V{NegpJ&&QfIVx=S2t%W4Oynm7yda<;g&25`9 z0!=N+ygv&SyYex)Me<7%x%?=jfay`z1^Fg#Il`I?AD$_H&s$3Y$5oQ|pr_w$gjFIw zWW$s%&7dZJ(M)4j!%tzN$%xZLvx?-mtife>Utp`I01lIf`D}<3Gm7W zZMI|!cL5}LYgtLFtY%N19!N|68fpmDPs_3$ienSTsxr&Q08N8Ro6%jFT>XV(kEYQ+M)X+On-;spHDd(gcQx6lDvKv zw|DQM?oVmz{5o`_5M1@mir;?=wHn@!tm7v!guG*w7xf&!(Kpp<;V zDS_8z>;L-C|D(qNKe%J@-Wm&=tB~L>?`TP4(_DW}C|jB2d%Vb>KZjb8ysg6>fi6H$ zF?UA&QKtDm<$sv`ZI%{tuVTUVXu*4v1n&0&+Fg>-^-IGR~wrh7b`jSyovaOBP zQj2tZlC7;2L_!i`l3)nZwo>`fKVwpr{JH)md(Z2A2Y*1ir^*&d;GE|!-^*Afk?3!l%^ zu5^*zX>3p`9VK`E`pO3sPV=UsTAfmLF0yb+NIo*B zg}9DAm}kF-i+yawhX|!F1moPnhzKCUShc-tcIX^BP*;TqB9y5TS6QWd6(dHh+j>)1 znxO;TfY*sdpqN<|OLa3wMPm*0i;Vw>{yo`M#qXQ zeq_p1-91~kP*AJQh)QR~4Oz+JO85tZ^1Yx09Np<4teW1PiZa#bYWuJ!CrI-wL0#&v zpr}-;61*&+hN9AC9?){;JK!!!&T*1qe18wR{%YlW&!Oy_NL_%#1}lpiGj;|(Q95U&B{ZxDjOQm1t@vJDWT^Ek(&p-Va95Vg)6fQKL<8ZO@^>N`) z2G{%<2Mf|Zs`-dOyCJNOLA3C;wHXnwix1Tj_K9F`X1KPKQb|hGE7ID2n+Ft5r++F@Px{#(%^e1|A ze5{`OF`@fJ?+Xx}g~~1}nmO=#mgbvZ#ejFEYA%@9es6o5almw{6pPPNATGmGQ!f|8 z1%P6D@v0<9<}1D=**SOkRR#*UB24bN`aXM?1_GXTTc6TL1Z$3I7aq>jA%9UKpZp5rF%!Q}!O5l2QT79S*YyomP{VrIErYlOwGQ@*C(R8x=oyBNLRz4>4F$piM z9BTqigk?r$g3Wz`RdbGWOvrJJntGhIUiv6WCVENnqES4q$x*3V$!fO&PLd2}cWIH& zl!cM&ngvz3IJbS4nK2NsWPglO)}V@6AH#`tFzi4dGkGo+W(W)mwPCP)&zzU2IYrG0 zYHFYYGr)%B*&y}ut*yO%}-fj9U8lW4vnLap-2=n8-gb>97++cDs&8n>jtk+ znD(byGL9G2`MN z5Bcf89HmbFJtXJ z6+{lGVV}tm4@#FJeTKTX^ee!4@b-EiQbVRkrhxdgWu&>as`}xN?B#`pM8C2?UXwa;Oj=bVyHL?pKw}f zHv$$oc_Xcx*Jl~42S${OOhF`xydZlc#Ay}QUkT33AdOdzaA%{LlV)4HH~G7o$%I@qsYiU zSPy&?&=;{@obvC2e+Ra+@RUw!G9MQ~gbEgl7?#a?|EYjTV=x~%jF0lA$iG4DOZt_; z4n`ECIYK?+3Pv9h=c<|?a5Y9+ujQ(mXRicM55EpT54C`0=zkjivTrc(lle7*1*J*1 z_yINXbcDLCjpVjYMCVAtdg8avj|lkif(bQ-3d9{wt)qF~B!xSQLKSxa1)Hv767w{+ zAG-r;4{K-*ddCR4S|kjI7nm@Gn!*?r;Ii$yYWs95yMBBMKIs zr^FKUVHNLjV!B6<1n{rbdT4rYFPt|2J^9D|-GB;6(1)YQUwTzVMh;u`RRbfv-og|S z{&aLjA69YGY=8Q+;I#Sg$di9YZ|SLwd~wwG zn@!zoCri+WRovE_wrk?xYQC}~WxrYwNj{MW@X}K_id^V@nj%7<=ZrtzFjzfD}gb&RYW_jxMhdu~L%6>gD)qYcdXx8;9MHkuQGMF9> z0Ohbwuz!d~X*DJejw(1jb$-!?Zroi13efEL710^{_(*$=<_~{NlUZn|6 zAOhpAT(%G9WqgW13i=UHqu3if!UupFCFPG5qwzL0_~lJ_j!=+y@-atiC?G zK?N#vzd!D2y-GlZbo^6-(|jdc!oD8n^pQ%@6n|N+6UA4uf9&g!n>#ePr3~|#+d3p> z4H{uF&@wAM3lWHLbypA`(FIxqA6z zx_u8dMZq01n>XBvM=ugkj1MFzEdj;gl?V*Kc8X#hX1< z6@T*gr83LXus(6zIJi%lroYcaZC8FIjrt1%5)sPlcXtFSx6rxQss&^Iu zrRjLxoEFpe+vQj~UWcbuG|-#4KyPo~4A8NUL47cvDo#SE0meAE>j*Yfnz#@>EVO>S zEvn7tAR=0b-j<*@34qdc7+4FviZLmJ8GjC?0&(PNMZZ*i4#e>~1Dr7fQ~2P)%zR;w z2?;%ZrWP9Rh=C)*Yh$hv^ zzQEZs*n$L$9gQ8g)Ki6wFt;CZAP5D^6+WPIdwA2DjwLj)3?^AwWD zHU661%W&El4-Fc3@ry=ey_9}z)?33Ve8f||A9IK&9Qr~wC_7Q=%;;#htGCb%z@2#D zU7zvldF_K-SdbZkXvY9I03wog@JZp1u*>Z+^0A|=ayzGj;|`oyc!Wh9l0bVAkQ1K!*5VJE<(`)?i)df!6+Ftm0Y(ob!8mAfi?&onAY?Qr> zC!M?i@4Am|(ALkp)9&p(Sn(L2jR zy2SHkW9<1;aywT@MzXrO$yaqj#m~1FO@#O}r9ZY5#5LHFKaU_>f_nbg_Culs{BhM_ z-^?Ke2Jg+F&|-*?VC+TfwjPr8RYOqR9yg3fVyfVxjDI!Dk-JQqgLCcu7$ky!UCmXy zjx!yEx+27%u0HMN?pJ3S`f!!w4Q8RL-DKvd?boBMwqp9tM;T+gO39ZKXBHkJ7q1uF zwppCcs}JU6bRS*OGZK|RLnJ?;&kQOhfJt=1dypyr3+cSH`WXftq14;e{?lj@9fFXW zj5lWZvwxq;4GDiBowJPKu5?JukU?4qA5BM(VYZkqxxr+G4F6_ZqvH=aag4uSRH=1Et7y$%D~jp`J0&QP>DF|@GNC&z z6ROsk<$)sGfxZpnG06a@%}5;_YeG^tC7z}>-G8uk7vxhI$?T}=J)SvmdY`v*Z}!Lh z4k&IX@!Sqbx$`t%-Cj(mhVlHm`2KoUyq#X0ESq_~hJPK#r}{0hLJo^JuSn^M6UY?b!8+xl3A-VX zIlj~NNIXBGPu4O6*;NhZ=M^21m->~}CCTt=kAcYdoL+g+bn|^Ge6#~AIfadCNvb$0 z=Bi3M;j6dj8FV%S|7Mx!EFMsK(_|)AYdj?td81!hy}iG0=8cnExu0LeOPk~q#DA{^ z<-$b~3S8tf_2+(1rR%0rHdV|FL!)FqE+ytHCUq=fH)FF^zaGWHCUGMGd7QJn{P>{^ zKd_hPJ0t8K8}rm`Dsak^qO+-tD39^bl{pw%o{GWAk_BVt@LlxtiG^*H7v1H?vorX6 zvTWz?JK9dQS=PI{aHjU;-G(yM^?yw6VtxbXosCooR60|8^2S3T>VwIC=CcEt+2HwO zJx8A!4r4`8AiAtwA}{f)M1GRS5f<9BQO!-sc7Fo5z8(hJ212qW$xdQ@MwYn@y1*Q! z%wUkzxvOJwXf|sQh~~f)$L1K-V1F_0Aw*IC8T>KQKA~XL%O}tOaNaK4tvvDgL%b}L3rbgl z;S3$j_obx1l&x}bM0_p27ZFewVy8|tOCzutl zEJz<0EO0E_YC&;yx`(g6E>^X9K_7T~1ct)&bP&c6L9TP~eKt8`K!4q3n{gQ*vdbA8 z>YiQ;HBAs{4n|`kXP*05HxG|H?CbL`bvKj%_7~#K<5zj@FvI|LPY_~~!0k1pS;LOV zXyd^kyVbjtZ@oM#NwY`iaJ-e=+CRwL!-C2gmR{?Qvm^{Turf_r^-yoB-6OBq6knO@ z(VG8(L->`I^cHPcx__7i+DYhkzdHn5#1&liJ#=)6bGm-2#zF&R=ws(}HATG?^_Kzu zwcs<9XN*p+53pJ}oo)AUobLljuB3C)N9!JjP>h86?`c7FZp_m_-H)*~gVZF0hSrc9 zLYszY2})%gTVXskTW^SR8lmMWIh*f+*Xk<=SIqRUL*x-g9DjBBVnw3n|eG-unoZ>KIU-3X1ip_|$jT$ikZdEWU-&F(zV-4J;V|pKcxeg$U zBJ^wgo7Le!B?IbmQ#N_HO6Z!7E-+QYPN-XI(;T47Y9EWvj1TI?sx~9NC%U7Y54)G% zJ{*yLf64mxF`1&s6^dLr6esHjr#2TKpaN0KiGa4T^Oh`yc`D4K;OH<8M^D2*MR+8O z#c|Ux?h#2&LS4q}$Dy;|ll*250i`!~+lI#6qGE1?)yD5{CZyo+*3gJsRJca#yAUVA z#n+yWftz9CQqVBC6CWeNvZ%Y}VSO->s#&h{e+Vf-XO2+0rT2wp*diPdBplri7IR^A zBpWu2;<6lcl^A}>#wbGsd%?3l{ER(la|5B+Yg&%HgU8Oieg9>&L3p_7N`SzYLLktf zJVBpD2bBmO))G+tlf<-#2YH>I*l=Sf3Pk-WT8;Fy>HG!!RUO&zLAx^5*OHe!5>uES zf1+$`pdFs-#7WvbtND7E;iPx6;ks{PK{TE0BAB9CXZ_oCF^p=paaKdMVF5_AZ+aL) zYZ8-I9-kZQP;|Qe9ZrrJ{7eX555kH&A$O-921na%*Gr5@Q1AAe)A_R9FMb=~lE4%M zWL^ZNCioEm&{h}G zc-zSzfJCpYnvb`wA0U3qR=Zr3Y{5yBx@flMv4|$2V?GDU=4kbDm0GCV6zxTlHnewH ze}FWMUAHVakOmeRxF0}{jL1nZWhh~k2BV}{5r|Q`7`H++oxUk3>IXugZvzX3reU>} ze}{9>2z(So`qoqSft@82eR-`a7+BOr)j@#EQ4giFT%zwuhAFEKf@%`XbR1pM#!hFC z#~IVfbhKu-6@UP~TMi-`5p%D6J=1uu>%oSCrDpiy1JLM9%K`i^_OSKrfO4k+nijc0 zcxC=}n8vs3V|~ZFM~3K)B=4Yr$SJH8lTY*rf2wrSws({i7~WdEP39S;Uf_;)*jQbE z=VStg_aN`PDFdzV`caYjVKv`qhkgxh$KO0*TzXhXNgdP%(AVL@nsO>zQ$QP!7O$=* zHz5zMXgs_2dC;oJg1;3mQO1^t+0%*G{)R@Cvg;Cf&HoHGoH0L0N->_<<(a<~t8THu ze`%y`DzTYGvi7NV3A&}LYwdh?>2O?4&u?4~w5O{nI|%t_&Fkg^{VKrdeZ!>a5C z#;WKv)!ymC)-;E2U<98G=^k@D=FD{Znxr(_E7<3xl1*!hG@4|kr-}kr=y7C7He3Q2 zv{zRAS6Ih-wXjC9s*#8K<0D`l=tV#Ye?@@%i3r&yNz~IV(WcsVvcE7vb(u3%fG;yR)`&TLlFceqt5NC{sLpj4>RFLz;Clk#~`f7Y=wrGroNA9+FT_PtIZbT!6n`0r?vn1?1cn8&@Y zUNe4)OH29d|8f_^=z46#`VNe zr0D?PH%rV?Wg7dZzsiyn9S^$yHzLeSlA?i=PNH#^!f|-=Ih+Idd>Us9f2QAhk*t)S za4>jd1?0Tg7LZ)9>jmTe87N+o_%uRr;4v&9MDl=5z|o!au`v#yBMWOr=k~XQN>e2B zF}I1PLR6GyJ?1xZW2~#nfDa3AGxA(ncpK6S*|QYvp5#4!FT6cVF9hj@s8et?_kL@? z_px3s+k%ofrJ!R~zjurJejKvuwB0f5h6ok$2lD&%sSE zk}ME2oVR!&a2Fogg-=-M}d0bE@D7*UE!G@+Z$&hv44OVxF z4Z0?LY!5fFpU%JE5#5ln?yc^iSv%Z5_x2LR%(%-|wJPrR4?V`Ba4Eti z3jaO^5bV{S98NW@5BYwW$EVp!uu^EiAwDYf?vg=nU48~EEg<&F5wNs?7#bA1fC6}R zoFQ@@(m+aLZpa5oTXa)?Ca%G(SxSy?NIL0hUdPb9`8ceWL3MuOn1)ip& z_$~u{#)+%8rrxir%_)ESM7MNM+=obl51wqh&Wk3q4V&QG=`@Ze15)nhNh5?vd2Ki& zQqHot`PmmuM%A4qaHEoqCS&A-Xfi?6B#8U5fE*NCe{?VB=}9cnJxy@j#~vCSX-Pwh z7>skou2xgLH=rLUTn_Wz2KmYX4-<_B?tFG7GW4k-GUwsp% ze|lV#-ie$&bwZ6FY+kCCIwhT&dzq4;G_5F2v)U|u?jl^!EQ>|wJx$OB;)A{Lye|rR zR3d)vVz9UpI2)-eoRM7=sWgBdi?chs!in7lbGc!@eKh5h_3pt-k@ag9cpVrE|ZZ*H(ZK88Gu-dMbqI3%W3nUEow6ue8~EG`7iYhKvB^S!JUx%Jq=`ogdiR63K%0&= zoxMtd67W)>p!NvVnG&+HM<~P8jFjCU1A!p>};SWd%&Lrk`qI3SN%dGH{)MzSWz zwa~aCe-Uo9v$fh9-_TLkyYbG}Iu?v7m=}Nf%qC8WNC)hdQa;o)(VIr4H9*KdI{2Ev zZsEqXNpY`Z&;a%T!lhXkXF5oA0z2U=h#8`lwkjmnh^einmZ3mk5-EibMO8|;8uK(% zC2OAbBU=kTRLzoNl+ckrPLVA|_AJy^++j44n2Kh54|xU`wT;UUqt6fmq#!R=5P~(I zL^bgK41PM08i5qz*qWpB_)YHvivmW<6@?22Wy%K~5*%)|%YEWW^TBbjCW7E6GUXo* zliU6of3EU)0&|l&7*C@w{>i)gKeXQEZ>oM;I!iHLgp3JODL{8-hB0jt$Mn`YMGqlCVY<)t!?xX<=P@yuPjgru8q>e@F%m5A z8;U0JmHE5>^lVkl%^-RC^z|q@RxVK&HpZ8rTl`)y-yr6dU?%9d^<64GQijh;-^#Zn zCVY&?6zN;}mc*1^_c%+%(-e_e?~ zk{7GZ=$54WT@o@yZg>BVWONnme&IB>jn)V@BqvdGEH(@zT$RkCT0kQyVU`li{JmH; z>n8H(%5f?HD_!~^X`TV%5gqQFOM0Fpx1}Zlzgbr6wR;;!QHYk*iQ>kExk_IN9fCCh zy5_NDF%*lMiz`4B33t_lL?nF%5nwP30e>9yNoMAV7lc$~OO&PPqt9*y0K^%(>nNfC z1Y^vDvQ$Y@XPy!Pxf9m+WZ_r1XAj(Yd41N&x$$+5%ALl(N9(caVi@X~xv4um+L_Xx zIkZlCkFUvCKX9kGn&Pm!!kp-9xPqLCe*8{xH^s4fg(=q8V0RGAGe<%O_1#fCXMgV) zbw)GAn!}*3Xs!^cYnmyt6G*QLL9sBzqz%8v>oRqrrvh?NyO48!@IBGBuo`nOh7AqC zoUaFv`syfBTzKI0B&@pzQ)KM72~g)*Fmk2Hoqa#O6eSBK$y-g0{M*0vVX>g8>5}M` zbR4KadBg>VIIOz2@PHqePAjhhpjp+NUxs%&;K>1mWZs@l>ZdviPV+` zJgFqsb#>S7cLf~_f$^Xh-x{S$kv>CR5({y?UxT>5v?mbYeta~|7i2`_O@9!F@qjkw zKIH8ezV^ESJFugjyBX!pPx8Wol7pwxc5=4rfnySl4(oL%aaeii8u zR5PnJA+0HD>E0JOq^c7iYLF9iXjMB*S(I=R9!0JgHWyL`Ja10@X;ZDW1DuS_)^Cdf z(1tt)xJbd~t#E^Sa{+MzFn{Po*OB{Hze#SSZ;z)`wCh2_ys=x{B1^NwhnR(Wyv4S- zbwKh|9O)R$OFwG8gdF7<4(lTx0rrra69vt3`$cq!2^nxyV{optq}FE+Z$i|{a*!Ro zXHJ!8A>4_|R1cW16^5FnUEB!KH{7 zFl)QNzb{H^C*j!Vw9W*t<-LIH1qNOZ2=!Jkj4}0M7>~K3u)hVv&~RIRj1`Pg3dYRG9AgFCHFFi4_G7*MtQtgan*^lQ zWtM^;W0rJZFlQwNMvDN60widH^e7XDcx|`I@&b_MwYEby%V?T9x5n5}eKVk<13fUS zGip*aL#G9Vy*)jC0B;7_76B+(WNS%s-tx3s8-pvFj=@bd=`bg1l1^)uFAa*9;K6~S zy*nD_+pNuETKCfb7~OJJeEeYwvzBLlG@! zr%N?t=I#+Y7Z?%-!S3558Vf?9s5Br16z0twLl2sxNw|`0Qip#V)=OvKM79VGgr*!) z?cK+^#%CH=Kw&}DF;z}Vuc68sIujUNV1-50(98spHB!`R(G}ILi6836X1=U7D`b<| z!m7sn$O_(SY-6{qo`pCGE*&vq{Ge^sr1w!}ICYSSp^HE}@&X8P6E@Uq&b9(A{j#n; z$moIe#uy?H_zr(z2ppFX#6>Sd$|Rjc9>uQGI{BQy%m=>6z@`FT;Ex12CnrnY zI40Iccc;?HP=_J8)3^y6RyGb975l3FP>xQyZ)s@g05(n})oOAg}@EslRl(#y~{6v^R}&iDS{BY|zY z3*?{}x(@KJR$uo(BLqBjF_68r0r(FG+0uJiTHgpc?_V@{4LvNjHlnichSX=>etle} zv3hUioAPwl|1AmH`HpVt+U5Xo>d}(pn_>hjJ==@Q2}mhaDu%_fdJ{o?iKtT#)ni{n zXt)6$l9_+dr>l*gBHD++*mAkxe<3KU>KF{e**U6{US!7v@!W*I)c>tv!&3eKFp5Aw zy?A0nmx;7k>B7akV7#{-uIei(d70I)VXB#TBX1YEn2C~euU=))TtZwhS$fW&BUwq) zi!b3&Gwyi`*Wovf!rU|y)w*u?olHB9Gr&`oMPGlbdew{Um@tmbO3e}&5WHd>4g|ok zlJ8u-6Q?4I&xj6&9Tz+w-s*VnBXYQO6wk7l9<_Kl_49}n`!@LqenRrx%s>R`XF0cO zlMJ3mx@hk2>un7Q(eG*)6s)~A1D^DB`w^O9fl3B)TM%qf1n7J;r)Mg<*|~D_-5#@i zLT7(-z&doZbIoC0?6s1oT@Kl^0hYpLf52ngz8@+TN4_Na>kz@ihnb5f8I0x|?~q2+ zumN?|e#qc?q}|7AGrGEguv5vVo~{Qw-h5YbmN9a_Sx{}RKQ**6V2!|jzYFOQv8xR`=TerehSoAx-(#amF~H8j5cxGIB5glQWJ z2HzH_d6osukvmJc7~GCCT-;Y(w2XUQh%li;bl%4o}GchSFpE8d&ysqH3NDKlv&yt zl6X*mY8ueK8lX)ZEPJR9y%Dk%D7qm6I7!|Z_@NKe0F|qVr-h>jl84~_0|6Uqm)#+B zrQmoEAmh9pNf?;f1rHuR8i{^g!m=)S>hPf>Rl8H0AGw*r`urcawD>sst;7n>%jjJQ zaiZNe4P0wRzz^#p7n z%B#2kNt#pEiE_h^Z5456x( zsy0brMTGa90CIfUvWAxDOGe0*;REyvnhnpvZ<~2I1(jrZfLFB9qKSRddUZK}3y~r= z9(PqV#df!?)}c>Hl8%RU70#}etag>aiU>FR?$NIwE$xRKCS_GyM@m+`$zUePcR_=H z-!9Eqy}$u}!Qusrk1}cJxA7$bmIzn|{Kn8j_#^Y3IDk+~hRt&V{(*uM-0xMhi{T%u ztzV3r{hevGmrrA;NZGkLsyuanaVHqnjZeiUz`EJDr!WwC?{;#Zt!TnvTW{K~iDMk6 zO@bx5Z(;oN-WzKYR_S0(nfB!%ZPsF0vmAM2$TUgifj5VNB!5Tp4uQ<`Q`0YR*Bm1K zKAIZO6Fx6dk?s*HP8o3G17?XS#yrLYe+Kaznx!*M0AtqiSO1)Y+fxWjasqSaCScGi zrDBNBW8$exoGq;vry9_+hFv$YmqFgd7aB9PE=6_9ppy_ZqSqG-MV=kz6a@;+4V?-{ zKZ5uB-k8we%Y?@%AFvr9J;rw|F6)`Hoauvz zm@a#sz=CIL*WM{4q5j~EOJI~dyif3*fzw@3rQPqxQ=p1T*AHXyow*)BG|_ zBp35)V`R(&!e0!*lb?t3$jhPWZJ1>)3Az*xm~(#evs1d4=NLCRyP3Q`m)s5kM1Nv< zHW>7YMIW+=0xTSE0;)L>13XY2=&x4Y?dbPnxpF^nNPiZw@&#vASGx?b(q?GH2mLFC!+qQ?UF1;@n`2A0E`O@c=13!|bqUIs9^Bbx)5o0imK-9@#bnD;VIzNh zS);mJ%vX#zs)RSq95P`Z^oXd=4S&hQ%lN0ggEV~@qkUJuub((~h-s^Kl)3MrZ6CsA z%YG|(kVMEB9UhT6zX%{x8bL;u0o1ivGBxtQPgwE_XSJzG5ihpYo^`eARSnHc@*ST;zjAEe#K=AVd0HVSk0%0T6nG&4qUbw*>DdIee9{2o7=HQNc%&>EHv<;x`(nI%b zEHgM+er}IC2acYY$v7gu24IF7az;$9Mfmc|4W3-1pqCbnqp~c4X+OFFZP2=VN&y__ zX@cZhk(&aT@{%>uNt#40%+BX&&x)1Mq zC~_M@dak45xdWH`5CJ-WsZtCkKgPhREC9;s7;;P{0wt7t#|kH|r}JsW`}WiEoB+;$ z9x9Fmpz>$zSR}!`e0ZCT#FV>v_n9(++wf(V2!j}t+59BtUZOVM#Iobqh%Wd`1c&=* z?k5Ej>@j88LLl^YVAetQ00a#7ecODa(lowZ_xmkQ%w(Tc-v$rV=wLlT1G$0Tt zjzLPq2pO(jh5@5~yLETY>*CuNht(G`#ORjak|AorwS$*tZWa)t3|0`T;(iYe zccF5{!@e171>)eUMO6|`Y5A9-5&;!|cJEQ4i0<7F^#&N!EhA3H6Kfy3&IcJueB#UEz)&neD zub0(RyYIg}p5QC|@dkf5U_@euo6F^01+EKl1NuNop;QGZY_{1!F-04btg3Ydi52ZV zR*^rM=WwtvnVMnjUG^S#C{i}(iuvq)j`$oSN7nglr`N)aL$M$+2D@qEstD}5mzviL z$=;s01_PV;Md@9L#x?BZWAnagDRJ8Jv?~7^fWx^uPG|9e YC!gC$6so#=h5jg-;-d8b0g&r!e*|AuRR910 delta 70493 zcmW(+V|Zpw53X(7wr$()*0znOcDuFRZf)DP?QU&v{q_C+#X_*0m;47S%|iIh;H9AA5}==Ik0yQ-`66y z%zh7ntam9dgn2Xt+?VBsb_RD4fluQ8H5-|Jo1ezwj6IG1r#KqMCPz0JOgE8FlKRF( zZ!s~20_NhQ&Yx}ZUc=>RRkH|HqZBDARGy1teSH*H4;AKS8V{nOUmwrvl-@GQV}w{7 zfO2b^$22vUFWf9Al<+DO@XA}l3=!y+@M-aIgNyTl7byA>Q)uad{)& z6f{}<^~Oqw4GOj2>c@lX%_*Pi8BJ9wvN#*5?&Qn|kxCgPZ@RBU4&bzwc2ajUBbC-Bo4a zBsflwY#18-hR;z5UiLpb?{Wsa0SGo~Ukh*a={5t1BV#;p1c7@Ljt=r=c=tib465!b7I+Bk~mc@lym zFWaod%kmrNf09Pkq%8>&ATp>{wlgP++N?wylF{gNa-jMK$KVRr=Jzp#KcQ8*R=Rimb7g= z;c$AepR z(g(&_S2)~r>#=SDzJ^ypGW{E1G0Zl|EF%hDNraamfzjI>&jVMvS$86v`;TT2zu@*# zK3Cx@37EqXC|q)ai;g?2+N?H*Lyah-zf>M1hp1-qI2bO`2WQyKmQ~b3N>UKhFQtC?uHu){Q!!8*0 zx#83;mn{#Y$Z-tSzw_zk5!|@4qs`|Jz$aU#yP$Rsm2T*3K0H@)A8ehxz z-gVZn^-Myo#YqZ+ok`a$n?r}yDw_C?0heuy`s7}>lZ~cct4=}@&MUT{ml!#I$S3x) zFO)=|J8N#hzbrzUw{)CNGm;hUe8b z@w@a@IHqd1AUW((k8M`>t1A<0uoWuITWWKK2xF%KGFgnO`X`SR%Wkcu_qpBc?N1fU zb}pP5J8zVeJ5%BXVT{$=P%Ye7`pw)_cu{R#k|Jfx&XzXab`!(Cc-DI6-KeO>MfG^r zp9>O3$Q(~!@b|45RZ~%N`lJBmqabLsbWaR^-m_ESRtKBIxmmr;X@x4@Q)o#lCzlC8 zqpc;N0)PPbQ6QIV!nNbr-BeMpmko8iuDWcpo(d0*wx}x~Vc6Ngk-=GYrX1seep5jp zE{xB62l;RA+Kc1JMXJ^BeDvX{<|+Kn*##9aO&7iqqKf}aALfBh8h5OG69HlNXB{R0 z%F`$sLMdJcXL&xK<9SfTaK4B2_k=3mX*w)`MXAMdKmXw)kqa!ELxe}-nJTTXCQ zM`!0Ldd<;Nw$teNIy=^R-q(=|`6@Izu5j|t-a=ipcpl5_=JQC)5_9Sa#+v(|kzMc7 z=VSglO1gJ<&UIN-J(6h;xal{d$`nbBRw=~NGFt86w2*VhOJ@5%5Q54ELE|-#j1e?| zkv=&sTxZ2Y|Cd5Z2>+<@Df*wX5N56dJKD|+Ygv5Hml(9qlsS5DvWppfp`BD4{SWsH zDAY);CcXqHEwc$WHX!_zGzx^#jAi^h23!mY!$&Oeuy60(V*Z;)Q+%?M&}%&RD_8^; zfE9>%%-NSVzG(f)$AZAZT>$B%tXcrTkR@p8YcL{4V0Rgd+1pAofvb|L`K?a*LjGZr z<8oLcsoSx0o=v}POLA+x;WLO+xLM!fx0eU+6)@l~r6=m)L~hX?Hlq}OQjDod@*Otn zOye%J@Ky6Uf2<~jjVjk;86HIrO@y#yNB5T*4nj2_U6K?*YN`-HsvHI4WKkMm6hsbL zr0aMak;2>5Ee7k&*oGo$+*w4W%sEIo+8Jcg(s=+`)_IsbmOxn(e9}GV9A?@*-1O8B z#5KdCH)*R8VsWS5-st>u?16w=*SBMM`XSGL9JNbC#ms%2MCvS2BzuxPfh#HX4Lbuh$$ts%O<=u+kU!z2p?L<=$U3KlG9>mvSeik=OK z^J(}wP2nL_g!J#wD}W6oeMk{we!`U`eu|MHeGQSMehrZ$e~T5Re8b2Bkhs2?nHsA= z6vJ?YYlLP0pyc->m(2!5{ISR<>tLnQnV*(Rlq&bO?N|2$=~n0evsIBRVW+Oh*iuot zptGDLTYXNQBB9^hZ7^j!ob*qMIPLXE(3==p{QHlfk0J7e&mTcwFtW&8*17ZzaOgow zFgTJ0pzwtlfnf_&LV%)2>3MIC79y|QA?HQ8(&1(#yaVIslY~PVU63(Y&FNwp3K)ra z8MH921S&FV9AzRM<=8Iu79nPC-&Ezo(jwfn=)7z7R z29p9B6j0wYLjZV>nZj6Cnc)P-nIf3GsBt7jRJ4`=PTr|FCc9h-S%^?N3Q%ITB;dly zal_L`wuktl1B+|cR;D2yc~=`0XGa?dBU>8+Z%Z2(JyS)l?0~iM?dOd+#rIhr_(Zzi zBLR(ux76#=RKeZ*g>K>RL|h2C1uU#BMR&tBNAjTdJpio&lVhE}FuxR<1M-s~7U41J z36#2htxTz_k2*~AZ^?h;8eQEqvFBInktw~mBt~#3=0I*NM$347=P1v(1WyrnxZXDD z&+Gj4RZ99Xb$lrO4|2H3#SwJK!cPh?$W^y^NYHaW|Fjgu7nl>?8wwP3v zVMYz4NG!&aCsE|elu5Q{i{@FEQ|bVcFMR4b1k8dtYhoD>+nDxe`I%94DG^`oHh@`H zgcKQ3JI6sR{=tuxjrXEpDAz#wn|B_N>r(-0wUfYwgD!*A4MLtQ0N{^PQe@U2kuezM?!K5|S^!9E_sfV;pVAhZkuP=!TDlEHlqE2ta&3;4Gek>GX z3mAZYRP&KI7TrbQ$4@C_!!|m$lz2;%(NByuEL^Z1I^&l$$6B`e!yuLRYeDXxVlz6C z-@h6Jyy37fWp;9R;tH%}@{HpIQ=XsIasI5%hAmp>4mFwK*QrfiUga@o%RO4KidUv& zA)h>nW^M@zwPIsg3a4=7fcT>~YoGp){*6TDVT?ym&Ws@_;z!{qRmWqBF()(SQI%0b z7%;|()FTh($3zoO-3rRof|Tf-$zzlf9bfN-m>m|CsLTu_$wcbtoT;@K60qoEbr4|b z%=YG5je3qL9~nG{^VJHD6D*aI#?Z^k#oiX_te@on8@$p0p$ifvObt9u`v}PHkKtGU zH;9TORmd$*vYK6jVx`bn#?C2xcECCNG`ag?Uj#tuEP;kB{^uu0*X*;erHr$)hfF*J_$043%C(nd9xM1V z$v%5?wOK8DZ0R*)^KD>%ricDS48V<)@)%@fD)5&5N~r@X0@>b{sJzXr z=~5`zV}8Y=rZAbGqW>e6G^nORPCj4cniv*^ks@&iCrRrFLV?yRC^Hja85c=X*{m|B zznKebb&MmtT~FA_Z+GWu8^aJo9O`nN{wc}WfQU=_d* z;sk!w`GdG|p~f7eaM6Qzs2*4$G4vFJzMlrB2g2RKt z-X*G9whaHvm~GOrf7tY!&o$+Gw%<+8>n>a+5A6xNC({$f4ePr{x3h$X-gX{a6=jbT zysX2+S31hBdRL`)CZ!VI0|TQsulO3}L8*iH=*P$O=AEk6R$e>Oa9D)D5&(o9=v=f6 z#V{vgPBehD0f0d~l6F%B`Ofda9<$rY`5jJe1ddoDVhJ>s)OQM57(T*}CO~q~t%sGF zNr)h)k<=yX|5f3!#Mtxp^2kj0Jlh>HBpLy<@kfYVs1un6)=`k;asMRxBXo3q?adjH z`gHP$znfNez0c|QJNBUoU<0IM%%+oK>T^Go1T^!g06^EPU!f%987!E5O8+IK;5aA% z5rL267F$VYm#3kPAzer}IG~YQphPo?beCer6*7?-I9A~Fp8G(csI|dYUPG54q5%tDEkqD)gQ1?`cm3*(x=lethQ{X9y z=Pr~i02mDk%P3t|!S<%GB7)JCH`{8@4;1p{Pf;!nl(>Z|9JpYbF$8I^2}1maD@87& zy+@jIq=+0ji0g?FHHL)dRZpkqHp|s836mmWiXG5M3saJj1-*0o!yHnW=}D$6yphOz zY;84Gy>o}5JShuTU9xJ5Vpki#hGWoA)!YMe2(a-FC0+W0WsrY_a%GM}<3TG%K@&Si zg$|({W1~DhqL50~c*mncGyjp{c6ufrNM-A`>|}uf4sz$FE}5f-)-M_tg$U=dw6#XL zycAK4lww9)IiUh&W)^wc(SXNeL?19#aA%R$dRbt-Ca4A-Sz5;)PH{P#KDG~#AWiNE zU}NhcSn%;^cY&0^6HgE%EABcZuydnWE^*DryKy-|p>r|MH*+SOskWR1+O}SA&LXT5tnBJn5xU;iI~aDxw^@d@q|{#s|kzbH-Xw{rLA61 zUR`2tVQ$45D8Z6P1$o(8w28bj2QA?Z!*2BRg`K7e8%ynTlZBmUi5qM6dy!$tAmtPC z>>S7_AfJL+Sh_kd@`2P_A=EFiC5c&PiqSSgOCu!%yf5>SVDgjF!{({w_MyN4B}_wa zZ>)y6k%mas9TFtsTpEaQ+IopXRE+YZOKAtnP;yRX=q2fFD5_+}v9VGW`Eb12q!A}> zB-TuU3QJ)Ul;;61nuFX!g$O)$?AcshA7Z8TsrtQ?O??384tUFHXb!F9%vk#oHw@LLY|qTRov5L30V~LGTfaBf|x$Ns>E!}B@ZKKMNWq}L7>*ZQeupfQIwncv9EQ)VCha~>8W|O#0FXSe@}xOtt=b0Aj6Zm6RZc|T_+sad zs2cJs&I&+6qMB$Rfbt;6>+hZJj|0s>?tTDCA}C-ZGa!Ze6e4BS`K>tbdLtmUn*7!3 z9l!O0$(IuBs)r`;c&C=HwyQ3S~ZP(<&FmSGQqU&}2 zrt@}xBLV2;IBNrnoE7>R$NIBsi*vB&>P-VhNO@ZT?cIt}FnbE4_>8_-pHvX!}VkIma#~H@qblPvNvfn>~>$ zTe;0<-b1$Xz9vQ5h|81IH$ygw=r%5n+g(96pRPQbF8Bb>BqoF&Z3Daq$>%EXsB2%W zJt{7i<3xF{H9>Q^1On!UkRcvskd4yIT#>@yl>D)%B>wJ;J^uUG@;)4;Z#dE^t|a~u zA^Q6jSq$fiG@0mH63y%{W5#KM^Ggi&v&XC>A13sNN>)@e)y9SEsiZ?I$TC@gJ%$EhLc9F#mL!eC#%}+aVnPcbbVSTwH-$ z0M>!4oIIh+GENfOqT(^z0lDHQQL{FU# zxW`>&{{qvumAx!O(mZ? zyt#DoWft%H5&T;Y778!1Pf|6fTqgOKX3nP>?6Brg-vVOPXoN_u+qrVM zU#pc%%}tvfa%!^?%Ed;NKJW2)q(k#vPD-?Ps>bWjwnlnf>UwlTt_A)HrHc3Nodv)- zpHADXxqzC=z{ZUzjS~(9&RO8K$`hub5Wt#lcIX?xh z_^1B@Mkvx2!V&PrWIokmITt$UI{=#0@^0+<{lc?D@%^{`yu%;|;9SSdfkdbNu&dPA zXmxu=YwhWq9HFz)e4OQ?2OJ%tbEnCa_yvVQsTyCEOz7#uu?)MV?3*o|kLXxLw$2L1 z56B`^)rYI%6L&JM)phPXFrmNhqJdVcna?#VB!Zu*IVdNr)V5uj6}+(=2GD_P+nx`L zk+2v#e(3v!f-!5u_`&p`F|R)=Fcj~qiT6o4mOSpt!2J6AvHn?XF3Og%hsu?)$0`=E!z)y?Uy0#VTe%un%L^1obbZ&^NI*50#6vfi+)+1` z^p`i6cNhvA92%dDT%Y&0=USO94zEr37(cNc zJufsqaO$zUEi-`)0=!EcwIhE{Ih?93?h*V=wgU~DV+__oYR%56_K7L6H(!TCP92gw z$S*EC2(=tKKbR{griMs^yeM>bpi+;_pg-iqzKEtt{#C(GPSr8lDA4$H#`W}g7B%?0*Q2)#LVaD}DF)cQ<3b(tc!C9Q+HMURF2xu>FL}H^ zXWTLg)%Jj50Zhq9sQK9V!gHaq;uQtK;1X{9=L1?eiJ}ib*eOM`@yviZGte}aEwI13 zw`^M<1E^%Vi5H`EFhanxK`*SR+=n@Vt4t`rgz^ir3g}xoZXF@GA4NMJB{Bhm>A8yG ztlpX$+f&=Vdvd-Ui?XSiF}3M;zH6Nb&^MkX)uNDqgq4!l2`=zG(%tkOnT z_BUW?#w$iA6GV+Eecnh5k8PpD(l9PI3Fc77vz@9n7hhF2_c)UR4evqhK*F~o9{w%Ia^QVi1JGMUvj zYV@X#FbMKM{)Qawf3RI;-6u zJ=Y~vy*sA7|LuQbK4eW^oi)25HmV*D!v)&%ML5Q!CU2OHnUQ8_#p@Epnf#MOgQ8py zq|U|#iKBZx9IZLrc2A3JoMt=#y7+6W)H_sv(Bm^xfpUJbPq>I5?Si82?xt`S z@zz~^#%@iu_P*Nm^sUZH&=y1Yi)ekz7f|+(XwFD7W30h%R8h4Vi9D3@VKYU0tEvVnE(t69iaVB*N7u!!zkMTEfpOz_vI-nE zbK*YXsHF$i(q$r~r3qc@Ijt6PP{7u_>G-om|5ZzWX=*1IoT60Z8l(0U`E} zv*^RsAoVdmA!?hTO12@fJv)NTZ9pIh+MqN4qXXu9tkUc1(*+7JIBNa;TIk9na^VuT zkOLjfW{$#gh5#aP8lltgn|==5J@CtW2@ZheGC`y~sIuFOZ`43GnL+6bp4k|V?f?h+ zr~Y+%k5cDfI=v5;!wiq-0vMq(9>WIm9Kvq&1m@fv^^Cr80mgTkAT!>wdRQ|mB<3n8 zlqU_3Hn+VxLN07Y5TOpXTDh)OPi`1egV}*O~U%`@B2Y zQ)+W-?!p+p9ogt|9Hev-@+I)SYzJ!XYF8rPdYlXB9U)wfTvwGSxDRJPV{YfnMrK>& z#7nD$7uD5%HtYg5+n)LaVcgY7moY_bP|+;J8l^gv*tAEb#JfUN*VC9L=B+nhBY-y0 z@8&1!>3Hk@Jc|a`10=7@#u4@v&BaM%_}zG_GpT5eOjMMTf4LA5W3XeQ%{E|l#If^l zPwHNx$cvKnHdocYWd^m@zv7@BV}4I}Of^%Z#U>FY;Cr@AM(?tTHM>M`-PbUNF^oEnj0KjZgI>4n*E91Wz&;D;}0cGUTI_;(ckaCqipEsialz$S3d|8XD=GUW8RTvz=)fvpOL zBjhj!>Uo)-48 zhM8{=s@Cz$>sRd%>S9*Q%SU$Y9gY;eh_imRE?PmS0S+v|?^>>tj!C2y*69=XbCyWF z;@asF53&Y;9I=4!ep2+l`6@Y*usV+4$gLYp?se8s3L(~uV@BM}hPzcTp4;E017C_O z0pfq#_v3Rn9n)=2&NvE=Kj#T%yxUzHG3_xO4ntedL1{~U8(&W~!59~J8r_VwkQ?2N z>t<^C073I-KI8W-X7`%0gIKO`(-snPV54?GlsHJqK!pW0(1JK2=>8lpLOnQ7z`Vp| zh#`?ee(`s1uUeCiixG?-?^_d&i|No}ex6;vTIId_s$P?XhO#0y3za%}hC9_iWUW^R z4@h_{vB>Jix*qdTbX0fEQW@heXjsdGSBD?4CLls*-8oiJhE0`FMt=xdDETlo`JA^5 z8Vv7jhRiq?>()iI`iva(Yf~J-d0GhC*$$g?j1o*_&e!@cq0jr&K8YVoH0CudnEuo( zQb=E3EUDx-oJc~SErBMa4T6Z2U)~0oqYM+rovGm!X-H{v3|>}h5K8(AhrQa@Hrg#9 zmeK}|(N+RTWGkj50n}nBUu?z_kJHtEBaH9Y7FD#Ta8Wg>SWHVa9z$jz3hf4qaefRT z%W`e<*&sfiIkG3v63MIN4tvH|EHob1MVD%4g6`saTLb<~PyF{1+{gZHrpG$|&dsQU?Nu?lVnXE&EsJ>^`&g%hItZ5DXpVsrp7xvG0cj`p~x5)HpNmcWIOXlDEd^`MZNH+(t%h6*9m zPCE?lNTp9MpaOvzU3N0c2LdUN_RKDzL!miczSG-9hJ1$W8AM{e!w6%&<47XEh?-}4%5Pcyd`h%Y6fljKD7t+=g}r3Pe4RQKrijsM*V4}B=fLp zs?g*WUXfxI>%}a~Lu?{BbEf^p65fC{U=iE)7&_~IxnC^fazkW=8K)r)8R^s^jX_DF zDXP05NZ~px1l@2-O=JL-yK{$tg9Is4Y4OMf@;;wqZ9Zn>8Ernk8`hfkYtqxZxx{5{ z?q$0KBgjpivHOxKuu1T7`VIxW2uioA>W82V4CQGbVMmWIAL{_-@dJrwmT^OY2b4oA zQQe6JYFtHp>WqvpX%hcdD^OR|b_!IJA%cbINv=1ts*^)33b-8gI*p9aUY8rhAJF9n)!{HBR^$r975TUdsn- zSk;Hzw06WqB2&PzxHku4Rps+6w!_kRX+{*~N>Wa$SVE1{!C6DEcsOBq&2)voR|8T{)6Zpy~2doe-%{!@24tG#S^j6NsJ9 zsv`(@+*6j&MNe}U6x>p@K*b-0QCka6i_YZb6Iss1w*$aJy$Wg3NI4NtX_tAA^-@D| zm0xOLTQ{1K+f&KKMP+nX&9ZXH=&Pd};>vpK;TmV_^GP+>!Ja7B2L<8ZUEZ|Q!Kb2l z^d{O{ky#N2R@5*nKPUQ@_--r(UU%?2;tPSZ980ri5lVrC9n8g74fD>Ei@PHnQ`Ve- z+@;vwV-Ns^wtcHW8)1z2fxLdI=7E%+K{)B~vgd&-5N{;qGv1W3vZTyS@+8KhTAV4O zm*x>~c+t2tpYzsu<`5>c9kZw^*zKaUzvw>>ipy1BUF5^nC5A~O`UrHc7|$fkib`6o zJR*iog#pqkj(V+wT9?zfBhtUU{#AJ z=hsHC0A}QA?skF{1ClA<)2cr7R;yA@@2PebLr)nA-J&3`tAqZCkCW^Q-y({g9|pE% zg-MUYg8$?Ld))3@Sr?pjaBZ8B(9NBcCn5<1^?pudC2f!=lD>M#fFg8g=2b5>X&kEG z&L2SAcfbrfl&#nk9tfc-Z}?uNjI*UYd{ixZ8Vtc2FK8g=HYWB3&klKCr@}=5<;7E1 zgLCd)iC;-Zz})fy!&Ts>{{+?)+j6!GrOK-7%%{_?J2q@yahu>vFdJ<4;P^7tW-ANW zGTE;z|E^56+__xno0a6RI1AkgUrG5VglmAcz9Fa=P5JlL<|;(MmG+L`-fwxBhEvu> zQyK6Vf`U+zNgWrGdrvYk7`B(1LdZhFIzNW!$xX9iJiVzCB^mKv!^Md=^e*4s%W@K! z=G&i2JE9{W{ncUV-8<||E{|Rj#z{HFK$!B6KriIE3y={CS~2}X(Bs*FhT6SpMhk!j zWnZ`}t9O5RPlcb&?i+7zv%^Dcml|VwjEU;E zj0m^~(-5t6uT$Xnb?0ou!-Kgh890C~fp%MoeWO($ov3iT(K8AHjL~O|I_bO&Y=V+) zj-eMOD$}PnF7t-$_v9E-Ph+9Au;}9-w<;~aP_o($&F#nlwal4^m^dhg zF-@$p3E$9gqIpfKbR9oXNCLnm;bcWPqoR4G7Kt8GAE>7hF1sTpUPyqR)+pQ(E8M^6 zuV0b+7{98zvM$t=jJ)k}X|)U-`$V6?f!Q4m=8y(nz(H9f3_=S+`dNyCNAD-N%$aJ1 zsph*R^1~l+!qH}JpxlLeivvdob_X<+ukULh;ZK^)s`vZILR2lpq3T8LrUb;+u!kt_!HaE;6Oq(XN67x*sE-H@W@wEm!x=uDl=^T6= z8na%iZ~T0Dj)Q$kkMaPrm@SWf^RR>;9-r?%pBE{RX&`uM*FBw>4TKD=U-5cW)~O!l zIgaaOFzeu>)9LZuj=N#dtH`bB&S(Ojt07X^QDs~S|1j%{V}}@5H-I8p1yZ=V!q*u6 z;-5U+4HdcW7FN7muxvZeoz+b`Tsz&F4c^xM9SNQUM%y+t6EOj6Xrs*pPAi{{T6hc; zg2M@V7z4v3Ac?wo^W1jBM&9La1qdbmJ%qJWC*dkKR;jNRMd(L1pTxD+&5}byNViBm zn}{NAO~gB6Q=WVpg>E{`dtpc&Pgn78)1e5FyZU8e7Ybb#n;Fhl>*K|Wh;|WPr8VnF zgFAi=#7LtvYe;~_p6&>j7JXn3G?Oo; zt6cdykOH}fT<$r<2U|XPMO65V=}49S3{zPRZT3}&sC7eHr$h}U@BMzdi`9F^A3Wio z(iDtFrb)vrm;l!|d^4|27VJCuKyN|wLnt|r7M)%f|AD!R2H8S2c#@TJbK{W)2%>K9 zZJQhB^J`l!!<~ReJMDms2WKD?w}!~2zU(U#4loNCUs=bN*fq3l;ypd%-5XzXJxE-H z3>SO^(J|f*NfhyxiMj{4Y@$YjBtKAKdsTf9yUr;j1VGaj+Xcr~i|sM~n(7Lo-Siw+ z&7%AE^o2cTjMi${zKNd|2KkC6(4LmTIz-&4%cj=dSZAVJ)s)UkPME%hN3e6|!ePvO zXx?rNnc`*#K-ly?GJ^mI7*?C_%XarpmEwXlqei>m`7zboHoF|nPP5MVwBpOlMPk`= z|2U@N3^3qJRoP>Wa9uL$@Q>C0-&||(ATgGMKWnzv;)AWhGQ*8Y@O5m8Lo0`$3z}hn z2V}VXhg|!&|9;hlR)*&G8?W;|9!mPnUV~!r|w_srO$PQLFpmaOHpF zvVSSO2RRO0P33U*U=o2pbbCBYHZQmLf^f93djJAANWnpZ38w=4R=b94mkQ*`J+wx6 z3_3m;PGrq+pLHi&TvjujI4cD{xdOqqdo1ivQou;Mc%y%Un{DyH6+hmX0j5@V%uCQ+ zeMdYi0>K9JWC(g5IPu(=PF*qt^IRe^dm}D#Nj3kYV@YP%Kr@BDM2ASl%5srOY(pN#^iy z$ExR%`?5{PLJYxHYm8l7K~9E8%Z0j37|T}FsM5vPkulYHvk+YKjULKdkoQgyWMWe! zj@X2N0uc4&zy2aBt-vDNB8chkkH`5EPC#85cI?}#c@Pyddj?T{l~$XkK@ikTs9(HW zt%!5h+{u$ev!cWzM%JId2OHDQ&R*4MgNUz(8tFYuH05=y$GmjGBA zV*NP5@RqHkdr%+)l|xU*YSX#jyb>MCVc&sf|9XwE1nSM1EH2F98L_bnP3TaoT5PBo zRvnLRT5Y(ZZOpviXh{F2u5NxtGhzvhbf5Dm6Scx9q7C$}poY587ZwujJP{h`I89}N zF2c$-7{|2I=lm0y_=WdWpMo`l$OpjPh~cz-x-OtrSFKoA-TJbHCGnK`vyrsOSjPnN zq+LE$sZ!IE#H}u3;<>rna9pGxMdGXniHt?YDyRsuS2ek@s1Vh@vqR?GpGA$~$+lq9W}6)&>*qU!Ht`B8 zfjSbb7_2XaGJ!8dFajlqH2?(5qI5vWW3@n}lbGJ9<)esI9VkIonI{fcmXJeh%2UK> zOv@ry?c!_r3OSVptFw*=sV^piRZ^frR30ZlUi^N!S^l2sL<|D`l(g^XkHDS<_b}gS zpR?iwMuY4M&*;w~x-jw)e#S|JDEy8GIB&%Q182wu$`aNH1Y z&|TGKt@z}PB6ZQq3O)ca(@t)+`^-*x9k-KB^VF|Z;B2ABz%{>@EKx|e3rh_ubAKH# zt>=Zo*{)n zhbecB2@Fzks85N=-$IFoE8Ir>QHFHf0{d-go+uQTvxh7%4?vy^MCBtfTH42B?7^oKWnX%^lLP#}?c)M&4 z=>aywg&u0MkS^wM=L(A>u2v>M9r1EoPcLQqGpBjk{K1j~b7 zETZNo$!MrLHL$+ zod`+>ojIg@5gZ=7kM@m2EK?f)`)Fr6S4?dM^UFX5P)jE^oDOMEcnec+U`v;5U}uQ5 zq$-r_Mi*n$ya_r&qX98R#;g*MX*_IXl#we5Ar#MTZa~YdSC3OKVRnJRfc>C}N;cnc z3tA5ZT;jJb2>6MFqFOJPg(zKM&>fj4G#Z?M>ks*XOz=-nza)Jih;v{AU6c+8`T(px z00bQ<`WFbgP>dD`x>S*m8?$Uah@-M>{(z_O52utMn=ca4|HB#n^mTcv&ngVKK>s8$ zCn!`8Ik)7}u;x&7{?aN{pu&Un^>cOBQb6pE(kgJ&zP?ORI7~uV!_j!eF~+LHbW4fF zOs=Pi#acLSK%?~1QRWoTf7i&R0rN{}!1!%s)F=}8Gs?1w#tG6v+|JS}bZp{OkaBsy zft14?Zy#T=ekIPurV9{)${{y=EuIW=F9GB7_z481lKmPiot3;*0jvCee04-{s|!=e z`<+h?y>ff@fZT=F|JF)WJ}(33Rz^dnT}-2uD5P#Uz@^T0&-8hF_xp0N)ilqbk#SeR z)9x0n@9pvMFzv@pdHei^f4loi`uY3~s6b5472qL|hN$#J*~}(!-o@(vwN)j-?~X~M zvVz7GdcfRBoM$j&(4RDqeLgr}b26W$p1`K0aExR7!5=`6glJF4t4Z{Hm;ei-AfhB_ z5Hk#l7~XMyCC(+q_Wd!LamD=tJpSIyo%g(;vd)#sHBK3LX4AGZgyoe>RO5U<+i(zCv?k$cLp9+k9yrlp?|X z2Gfxmm|5g=-&uibMfz;^ErNIOr3MVEiG>lyaq%82KDYbuCqP!GP zut=r<_tXk4i^ja**fhMr!DU`Gr25B?R+}e=R{i)v~%l(E&{K-}g4 zqRb462vSTWF;!JC*FBIRDJ(ZGNqV9PaSG_;F>tW@IkW=2x&R^&G5mr4pFxh&BAmv+ z!f;IDWB%q|t6QyAHPi?0CCZRDL2?-Vu;z(B2R%P7URWM^?u*uVfO|<8uY-i*2Oy4v znnPl@Du5q^M5X^9AvF<^|3?Tq^M45O-aYvgO4Nmq<>(Rhje`AYq{5VkOtMt#wU{ziRJLy;#J)Sc}8aaw%loL-Rce)+8|JOSmmd>!<*P>_A-TB7~DN?6&%!|1BOjDCbWhSTg9( zQvqe7T%G_3dpHK^Q;Dg*Sl|*U?QiJleZ2Dk_?$W{VOf-#eN+rmPwJp$z<@DVIFFVn zC7r}vBACs;kYOnOD8p_+X9bk%pUu@82pNo8h%_=o_)I2acqZvFh^hKm;si*$Tf9vw z{mi=9bQ4^0Ipj9M$}cVVS5ooQIJ)z_oHo;aUSvQL*sT~P+SG#!`JH2Pmlc%;G#oK zG7ZQVTDL{!H1C0kuRxJ~Sdy5=X zhZ}plq3bD4WB=(E`cd%wADbyC+1(n7gBysSt0^J*A8jqR`FqoZkc1!FBAPx}7e=kpE24wBgnAQ|R|VuUJ1JyC0kN&gsGAuJ)_{eZQhj zy$63Iu=z454=7I>!CY-Vz6;Xl`m*{1Z$0e2@W+g`m$Z%`jC!iMn|g^`@ML!CPV}uS z%$e9|h}KVO_is}BSdl7H_t@wN8e<7kW$|fKu~{o)Z$WVk)$^)u0EiQ06VbpeV!7>r zBf6;{dQY_VV%UXiOsnPzrkM5UEiBC_$lLQ~@%Qih_sQwKO-~j#n^A zI~$`m6P`A+HB{Tx0Q}C8Uz##EHGkwg-A}C>w=eg<5f`>EFVQJenv+%+TKuM)FD$on zz1-c(J>9Q1obN8zQ^*hh2XjD-zYk39{`DX|yRH`atA1T$YJT0(>(0=x`+QXu(>Gnb z!m{LTU$3P|dELV+N|LWTcxAcLt`oVIYU|RSYs`!*|E@bBu3Wv&B=dj5#cRneFCDv% z%IeCmYpSZQ9J`_%yz(n$>g|~b8iLo~3mA1b-}@o|jod?Z;XoAm#^xXO5{hvRkpEkN zbBFbRhiDqifu7~v2maWk^+BlZ$;0c&u%5u|GwSNoBk$}98BUVam%A&`TwclFa(OS! z;0v0+8P1ed&=bGqr;~qtr1z{>pWHLR>uyBzqvlX!`Q$rm8q1HMZ8Z^{@!m=k%NOq| z1)3vWC9m#Nhl|(lojCX_6LQeLlSpn{L9`k_t|M5#bACz~tO|c+!Kz(KAFSGqD=BkE zU#_6Y(XL#9hK(PoH2lN<<>SK_TYV+d?;35_R!o&>GR>a3!F7L!o=_(Yp5&V_hkw#} zQ}V3g{jq8ePAAO(k`KJ+=~(sH%Cw~Ma6kf7 z!ydD|>#B#mCL#u}*$$`5%Hn*yBLVCM1GvIKr$6!#_c z(XDw&!qTT=n{XtG5rZTQN&~FQn$gjW3TmP|3>rKS#(974{u9Xo=p77a6QmeZ014m5 zi~X8!17`f1yuWu-8RYRASJ)6~3&GL5cgJh8TBa6)~}PLOMC zMyJ!++6RB)$opI!jy;{uG%k(C44PP92AWV?#sP9&8EiUD&3xi0yHnfTd2Zkd2~DG| zr31tYTcQ){Z0QEM+LrKinmhM`I0nDl{!<#sDOwt>X)>|MG&7;PG@o2nnwm~e6P`H0 z)Z}W_^vicOqZ8DU3eW)zOPX8;T<_c?>3MKuzQ%F=x@KVojBNc7_n;l1^)* z2gKn%Vv`lLqXP-FHtrokJ+S$Ln@WE#9Z9dmmp-M_KQwsAc;pr&#|dRIr(utvRn=qCl+R^0pl0^1Og!)uC{+8 z#EHaU>FFgfkJl#({4^u=mP%RzS!Oa}5za_hjKC)qnD*dWL^e*%NGh}xvm%z{j+aBh zvd1aa6W=5Z2CnsHc(6P-0%sV z;p~9zrsH6-#YZF^uIPw#B)-@HbD)1_x&KC5VDyd^tRm-=i(FG9%Bo26(3W|xOX>dT zzZr7~TxK=H4>*1yninx|GM*hWX)>M~J7Y551G@5h&5fKZ3F81^sC~%0-*loHY4nns z$b^ELn2F>x@kzxrQPW6ig(nWMul!5i7e_iRSzsDDjc{T`jo5^u8eJgQ)d+u1C#|Ii zgz@$<7d?%v6p3C>no1}n%}b;p%_fzOCZ^HMgr*E8bKNI(&<2rc7Q_VNS<)#*wB)7| z)6xf8Q7y@7#Pyl;-=^tA6Xr9IKFAkr!Vq6j69xFf1Jdwba8n02b@`#ls;);TDn&~p zDNQC8lx8NBljf6)NmJ8FX~KUK2G~98>FZ)=&_si;uQ);)ap!QtF&ar9=gZN&@sUQK zK_@a{2A!CRGU&u7jpvD)CWEf<2?FfT>Vf^;(#pv&(}~LR6G+RF6AR3Gkwj*eomOnB z+Cm%hikL3oH9bMNYi{CT*FGc(bxlqi=(4i*f%SPsTwj{7=|X;XAwhrK&+x>-KRc2{ z0W5k4&1174X_Crod_rZ_-}Py~ZaivtNS~N_)l=N_&P9OZx|_SoBZ8g*Zkp{bqtomP&P9I=-sb<7pKs@<1M2$1_D!ZoZnA9iEuv^T0`!q`9qw&8R#>7KzVkMsU~cE|#USpc*MgM-41p#QSk|6*r<_1XYuq4g zNMQ41<+P!@J3|A!xyPz5nXKiB?cF@*OE-(<#ic)|kFtMSyV;04XLuR+u0O}oBC5-A zU>V-d$1j4BvV!xjtQuKP31sRiZ`+PPRHZ`^6-RQd<;PKcD)n)sGc}_;xG#Bow|F}! zYF;o@47MGUg)hrG+ayQ7u^T3zW~SboxjoDmx5TOnr>xWH7H>9&4F26#B72av_L4^9 zOR{>SM9+WOr9UUiI9>4*+glR{_8nP=qPY$=#PLWZph-&XWhL4=e@522#u4Qeuimpb zit3fmi(bY=M)%f83Uf`OD9rDRu4?gW<;FZ+Vzj&zsnMdRgW73Qq{K0=n<}u(&OiM zqtVw&?Q@$>#%}f%tJOS*i;b{A)4V&uTdkV9Y8ZmMwXCI#6?0tcnY@GFSa%>;ZCXvW z6hVIp4>_^2%HPbZVK${^Sywd&cyEQQhGn@xGAvtFJ#P_=v%D*gnb9Vs`9G{AA@YZ^ zb@PSwIk>?aoEtZ`WvXR0xanOk7}EQ?DOE37$4V^wV2b{cA3o{q3=k2MEd=*KV_>#w zQ?7YUQPxj+lOJp~`OWHsz36fUV!UX2<6nPf({H|^m1Sp>H+fylbhw(*@b)VUWbCV^ z%yQX|Xt}@x$fRBsr}0z_M23)+;{HhR$P8^b9GFn`VVq~DD&Z;!?Cn$x7h~=T1z`)| zi^Kaa_Enw{8#30{Y^c~=Gr4(Ly$gezmYn$z);XHzsw38Fih-6=q%Z`F<~J=rw}peSUxrk5z0yMY7J6JHcz|Vm5R& zr0o|G2W7Y_fgi06UMT<0!xqvmbX3{%oq?@xb$SMvT&or8ks|2Sr6V@L>?7M{TCJ*8 z04>$gxb5jhvMztkFs-ZQZ&=ptB8Y!r>yvh0t>@{#zFEUFe^vjg-s&wY({--)RI}_t zSNN+|FPf7<4{a}F{{%N_k~6Hy9^7ON?_~||WdrJEx$D>-(%?R?1*nI|Tx7Cc!G{L) zSsuCVzJoGos!Cwi8c~%D-lCep1!+~!Xo5{b4TlYJS?_{&QJO@!acNank|2LAw&3z^ znHjWzv?rTI`~mcpx3FSt!S5R9wgs#Au=YB=?x64Ocp#YJK|X-NuCszN3ap*J8-QNU zF>lKH!U)2PD;=tnA|C+sjt(!B}?)EykXhL3=h{o$0(YQ<$ z4Wjc!UL2X}``bOY`Gv0Ac$9zI#T41Rz7x@pvloy^HOo6Z^QPsFXaB%@JmVcZ@dt)! zzpe8E6(BI5kDgeX$GzS~H{z?MiT(SVWytvV%ah_(SGn1`F=I>b#*Vnl(+^$&cv{|= zi~s@HnwkK>aGt0Tz`E6ajF;vaMH#&~;V9m+!^|T92*x{JFdXM1#X)~OCMCszz!kT! z-Q|y2g>(xa-d~)p8*Wk6EiT@4qk+=q(G6~OurZQEh;bcA)+ z8Pq_C?P=7ppnX;MrWuMwaG$LmK>|;qqhXhM+Y#mo(zB|4x4e-B=A{;Ugnfqz=&{zP z>I91K+jHDw2(A;|0~miF%c=*ihmIzpYoRNghov358iaO;K>20X28&R>tQiRdm$ zgCbyFyCY?5cKg|Nn>_*Jb;j?F3GS~Nf7R;cxx4GjwtY00-SVbqO)oY&xL-5wZgsnR zJJP;OQ5k6Za!+TZ@k{-Xk)|&mjTUKpqleSe`d9!1#olPnc_M##sQrN14YjorC?YmRELc^jXZ9?Eek5PS*pDJ|Xsp7pFMu>hkr?qJjFs0YoR3)>>I<9^Wo zo4qie`fT^C${T+@v)N4jF2V0dvD%J3RD2K=yrY^=xbOJMZnT8<5XYPW>%BCJ<}r@W zmMIAIS&W9!o`>CuOAI@+N0v%-s3??Vw6)eI)UMrCaoVs9>B*Q!uS)_P`>ZMPZ(=IN zKo#J!l*rY#>kJLonHuB&AJ{&Z4X@i{-sMHV-D9z`?_+=1yZsnWifBoOL#GV_o!atI z9M!JO+M#V7x;x@QLqme<82&A(u5l$wl}Cma5hPpC4bwAxv%WfEhJ&exAp)whX4p5e zo?^L`D#JOhWo!$=>t=qpdH(D+59Lw-r`d* zY9lWp)dRr;Lw^63BJyWM2x1*^hLlVcnC5W<7rTFsyC7AanlhWCh86CsMphn5J76|n zbN(CA{7D=(Py2zPh)YXc;}NchSc8!^R&auGE+1Izc9e3WGkQlHQ{4wa&3v}WU+ zIb45=>LbEKOr2Xe9UnL7&uE;th*-s&7y^@lS1=;=lv?Y!)fD!`3boO#3{*S>qQGQx z7ClcmA3h1dX@=8|sbxTzptG&|Fc6is;KO#@A9l__8f=dd@M^8W#e>~DBG@wv_wJdNxfjUO~$-8g_nQh zTI(p|?n|!YFfJ>vBMEhlOmJJ`9m#;L6urs-?L~T(;JEPnO-S4Eo~u&j?R5e3C2uYX zSX^>q&ERB9U+8S{=G*7nFY?1%5`EpUi^ZFE6^Fh<*Y*DjgEF0|kyC=D+e zK83etO%@77-GXY`)z4X3?JsQ`9%_I5Z0RPjb@r5>s)ng^-0U1fV8FQO5ZG+hlxP;Si@dT_0%eI+{Vz{ zbvPmiq8N5KhI@|i$lV)?er?9Z#}B)^WtqRx)H}y`*>~=t2LlH5)`PLtEHFKuwLRq& zjJeen4hLGs4DLO-^uR~K?pS|!s&pUE$FAcYT5wFa^zq>f?{L(1#@Oxx1*K_Ln;)2< z;VG0~uLuBhYK%#`>ek>$;QusjGW4)CCnmL%2;9psPmWoW>)FEe=h!2U(K#mWviu>h z>U>ul;?yR^ARhUNA6QfUi{S3Gly!H5>Kqu*IC{hVbyWui!}BsTbs~QP+87BkMRb=B zH;l%ZRMhiK^k^Kt0c>A`&yaau(`{78Ai5<TA_f<;(&Jr@iJv3)LBEXe)T zt_Tvi+$iZJhdYF7lq;Z&_y>z7Z}inYFds#Xla^;E3@#^!$+NijCzW8UM8q$umq z#md$hNoUt>))>a?jNcn)B)w|p(dcoEaG zPRNYF&|{*(Y)!xjw!2D*pig5ubi~e9+1O7e95ZEHQ1|U&Be>3=C3Mgm zaGBrYZo8>^-W})FbsKGf<>d}-fz{<-%#RyO`7W`%A=`iRSzvLOmi7UY>Y9qw+aV+( z-sPo*u&j;6dC)Mm1ec0-afel3l=yv=Xy zC=_XZ&%1&l2X7_JqF5~Zt{nxz<_CfH{ADdWm$j_skhwPMgF)(?heB3>+=f=dF_>CI zHjbxab%J0fpL6ADAfc ziFGoK5~26~g|%Q|*6>2dn5PIEL&6LhLjVsKV-_@2`ds{W?W5j zf$*^H-aivXaUA1{V>tBwL;+O2CsTjK#x#Y)q`Ejp&GJUIXwP+ZhVa9N6;`%aA89haCWU7G zs{9|Gq{5|7{uR!D3*aDY#d5;RfU5lOo}}PpR+azoM1`ibs{B7aNo0v_qE%(cef>{Q zl3Q!}70`bT0TDd9(5zjR|A!~ZwX5M3)W3gkpv?an8+V0xV;!B}L#vA4%z56(>gw%g z#_H-H`lroO=Ow|_v`2vx0dcDRN7#3b)Ch!A*I^96dAu?L;@W17CXj@cSKAT*<5G(O z!7NuAV&fcJfAJuEjrvYC0zkPnI^sFzZ&}NEof+jibd^PL?<5E@ODOXsDMEvg^Mik8 z;77N{V3$G~VuKAV&h#XJx2s9|&u`a@%%3;*9#~xDWa;K!|8UEjeRa6J$pwPh4OLz09Tf{+BeTr!Z_Od0vU&VRUR~@< zLxFzgqDMyV_5Uv69LG@sQswmr=9u~8Xs7&%h}7^(5McByAXbi{(Hy|T!X`ZZ^HO7w zS>rXvO)-W0m%L;o_jOa|eXe$(YkAk_H4RfOHOq8SV*dP(J8JkBaY%x;b8CO~LcvTI zi{`oiV^I^PcH<-t>79_O?gs&Yo;8#`R{zSoa;sAD;tN}KiaRz@AL~{#hxOwzuk=}*j`gx|xU7he@I_S|Xrw%;buF%Dj)S}dE{F|&Ds*RzVqGAFS&1*GwsOlS4feJDU z4s@%mtYn32927zZ3MPL)^czPf!@*4BNValoM!_3e)(w}B=!s^Ptj^l1#6;-SnAwxO zo@Ir%v4U#Cj_o+_$AS=-q>ojjAPr4syTca4Bba}*ayXry<%b5hY)~k5 z+C3&ij~rHw=)0llk@K|LuR~=xncz?{NB%e#JLtkSn|~5SxdHJ;_Y#jonz%62NoRIB zpO??!GVKs58I!j(FHdspt*KXt$?Ef}&T4+p)nwGdPV`GI)5ff_%^!jG=lf!>(Rx~$so$?yo;4P&W>JQ^Q zHm|CM{i1)}V*KKH0d_xo;-!O?BM=@$NCMuM#%)}T!WFHM#al}KXp~gY+_9?^RKMiV zZmDB+@s=Xi7prZW&rz2fDzCscDW0QCK?pMvQpieiW6uplgDei-foG^8f&(v?hvmUT zY|{bpm79M(Z(aL;TnX*aD??&i5#yEHa+t2%@m>$}W-i_I=Y-3qjp{SrPIDU}t(RtZ zSZK4XIC5~CPd)3JTyLaM@UF~`tggW+N<+AhTyI{q3P)(`4|zQ>Xu~K^yXFUY#n>ZY zkj%0Y+^{IythO7~f*bCb>fuH)t$J)w3=a*C*Ykh&-H=wr&?;xec=Q^i?OtX*Xq!WW zq!9hu5FYR&+aaXn&9kgmmu*!Brjx7}Ywowsvwj8OXIb?|?YCMGoAx(O%U)i!`4sHQ zehXK(?*6Uw{N6O^zPEQUA!K{+U|6}!+@@NF*`6u`@Ybsm$F6-G7lYd0s>_+D!NxZ? zQ4fE%ys_<7uwAG9*@LZ5Q5WI$V)@L4#AL48N=){u{M0(ylUKUiR4Z|G&X|`+Ixc-W zr-fpid;Y+HyN>5&k#CQIfD!$MUJ$S@dpm$(eMWXbp|%f$gvYvWmlwauc&Gd~n}1D) z9Tx|Vb=J$9X9L6axcVQKd<#!jdtsP$O#gqlpZe_JQr-*mUh9hDVIGT$qG5h3ilT9h z>?yicaHBCE3yA<&eyfNAfG;+>fmPMYJhrONV7RJU!_ZZ=#xb&|h^DGF23J+*EKF71 z@>47C#%{C^rl#5Kjav8rox?b0w}id9 zS4h|@a@pP~&?>TS{I_umWne4CbGv`0Pym)TyticvM_{U<98RsnTp>TBYQqO;qnX=r zIxoK9K0-ZyVcOK&ZH40-#2{3_5H$eQ>%0w6a?KBS9ott=q*T`hqaaZ4Ne%$4;AsF5 z?D5P6xBd2E*=lCD+orCtT)RQW>g)q^@ju))xJ7km-1OiYe7T;dk|Iv#vq67ebcYZ- z@mh}zu?wbt^N-KVO}FVhSZp#wP3CP9@U(S`UL2$gh(r$94R8pYaNVxYn{nv!mOWGr zbF7d~*E`ln=j;C*KRNBs@;WYn<69L4Am)8GEq0}zm!qKVLTqB{VkImg^~hvVy|Zhk2)Sa|sgr(p)bDm^ z2*}@=t^rle;V0V(Ui@Z#K&J-+n4sL*bRnce1jCQ8!$}Dp^5|W_aL4&jQ$!y;4?IQm z#N#kjL@#9X8oPqC>BDqrS4zImDXzZ0R9)fN?vPhHwm8(4pT6I|=Z=3(jLEW#$(!6~ zHHoKbzh;A<@kK?;O;dj6{Td*iwtd?ge&+XcMFHc7k6wgZ}Z0RX=iT>yWets2DVgZ=`1YcoNJe-5%jft&0^b!b@m4X2hFJD(a|SU&8kIqys8%Bg(W6-y#Pe!2BneP-mW)Z75x*Ouc{hRmY~|t6w$4%lGD& zf6cCJr|`Eu0dT=L*W)@Pt9M+!dKqxedk!Ew)Sr#cy0_YK9rH_F*uD&n?sPb?vbv7P z610HIfgSjX~nlmA$(cUR~QOG#Tky(tvf!UYd#LrnnNn^p7G_ z8wF&A{;|9c&v1VqQ743BT~J=>SoKp^e!su>ZKY2D56iwaw;+a3^Ti$To#mx#?bp{T z-ea-${i+uJ=6#dAH$e|2utzNOLtDB}0CKP{#L-cv@=8aUsw>}_BM&~jzmp;O$h-1Z zodoR~mJ=%s;v1#0xT0gFnwyo^pVSGG`@CQti>G4go-2P$VsW+$`Q3w5YWJyxeZ(K1 z`Y!*}?D@N)Kl&`+54V4#X4Yk`y-W1lL3&;4Esd|_2kTB%lh-n3)F;r#_a+7DuI}&u z3YaJsXxw{&SSSbSS&5_H@-Kh8NO^Th@SI-}KnPl{7RB+{rZ#}%*#Qzl@U1ijFl4pK zOiO)NmTG@zGCYz!FX`jAKhPO};3GbL{ejN-kH0@5LiBVJzkQVhDCjv?kFS3o*XW?! zL%<}8P)ghJQ;Q85&r-ob^tOI-U;PXCos2af+oAHK%NwEooXI41$AD|BTQH?pKN!pr~mpa%{#*daD3wn zfaqBV1R(nLIza$^t5g8Y#YuX$E0>Pl@TTyXatT26TZjk(^jnAsg7jF32*C5K;s6mn zt2|ItuPP7})T2t|kIeF4`IB!srN87`SeY-qlmE!O3@Wb{*f3sjxfM^&>zY5Z@{5Lw zfUJK9;6h*#8c()=2`}K{T{ti3N_rP6@tNiOB(Gkzr|<1SptLuwjt`R$KA_YEVk^NX zL$^aJ_HV}8ysjQnJ$Adv5k0+=Va~ej?%Vwja`^pRg{CalEH+)~Had{3gc%(OY_q}g zc>>W-4x}q$M;GFolwhvJv=m^S2x~aN`VfE8jtKGKbN;XAk4?dyCmcc1ZU|rXFTtB? z@7`_b3hVg3s>d}Ymzrebg`3T=>B4e2ou0cvW{1w*`r=DLq?-@wvs-iTZDbeJYt+0Vynn#W>eL?t~32xTMrc^a9P{!)oM@?RJcyx4k~5mZx>n7vAky@ zlVRJNx_7{>pScs`2jBfl=R{c@L^?Wq%1>3p5_)iCb(@Y}m37LSpZX#a;$2G{ z3{35F+xDim;?h?MKyCB>=+(LiNA=GwbKTi205^&=J5^7%+uccc>+iYiuUCKjRQ+>c zUBx`A*~@Q*vFwHm3$kk}d&%B}dfu7mEs2{S^4|}0hP_`jTbz>F0vb-cDQcE?<3NGh zc1*ZS55|L*bvB!22Aj=KpU@4dg}+;Bs1D25+KLICunolo9*nKT1n6ZGF#&#TA0|M% zjT9rYWz#IPZL>5kc=a3u!)<@7ECE|JNwOv-JmsCIVz1g^gObUK26W5?4X9(P z?vKLyu=`6E(KsR+ZR3B6XQE)m@&r(&9umat=Hs>iAlg3a`&g6mqHx%G1%M+Psi#tw z=^2vxU*O!Q%7fsXy1PI~?hTGOkj-%}iy7l_HaKKWxN}%e9nW)INdg3N=m`WM?eH1w zi4`&ml$P;fI-Q#>329)(G4JxiVO}*5&aR?y=(U3ZwnN*po|1o+@s92l$`p(baX1Ys z9?}qJ--aT0NQi98)-)iJT807%3Xtsx*w^_%kkQ6{)$M$8FtB6)gJaLbcmr+~b0^`Hm+Mxjw@7sZJX|9V9y;-Q}R1N>FjDf zg6Acct*!qr0B(Qgoj5j2un^WNYq|C{LV-Nm=wL`&lgb?HQ*hk69#3y!)>W~n?@{_; zhA9&Sw_|S|7|-S``dG8zBys+NO`JO|zhk;*ah|e5P1k>mR#WkPPRBx{i&S{$0e>*^ z_`LPmU(Q`$IC!_6@DS+s@wYPYEBdP1nHOp3B5?$ar_Z@}X=8biDhe&%wbL68uk-zm z`}RISupjceDk&;+1a0nhJE&&4EW}t-di1!&ArE*_^P&>0+X0^aN%2(NASu;}^XjzF zlS;(f6OeyhDb=CL>&-=U_Oh-1vHsZczOOguV~^Ll+PnF&FnmEAYr8H6ojaZaOc(0B zHw3$S@21QSoo)052AFqHYJgR@V;46K+my_^&5)h1+={Zrm3FS^cw*mwj(^#RyK`0; z#5op$a4Ko3C2dZ79Re}OA{7PqxBQD*zy0nZuj+q%SJhSj4EPEk+0JdL#&qFUJGdD(JaA3yGHWwoPW_0Ot5{y%^4?lJF5R{pW6K`4wG;rL6R z_A7r}_gC~mf9A#Sd{?s{I?C_(=5dj6#!*!J3Puf%d}_=ukWn??t{C|s?z-wh7Ap6B z-d6>127O`srmQ-qcR&1GiGJLD7U)iX-v9YYoonK9aBr|(l!#grbhBN3t_p@p;VlM4 zeyV!Nly5D%OsWes>vryLh;i3*>Mq*uv#o!Hv#)*0YLJ}UY;)O<@4f7cbhlUx)@oay?F@r8vqZ>H(ywvBb&e3SFFB#kPiT9GphkG zcDY~~$=#SfIt9pN+hkyvcU7vtcC4hivlA<;9P@TW{($+o?pcqg7ik>R|4&VAkDq^o zci-5)VNWvE}^s+huA5}s2tT3vtXgUcU0+(2yUmPqdu{Y)ppQz)-r!|-Doz8<1<2iXtIh_6PoR#)PdIKF={_E0j=IM zBXC57TGyHFqt$X&3nI6BE~d-fx-aI-r)ry%!p<;0_MNx>1_K6c{0+w5*k=NgqvqSq z3p1VKFN!EXsf+OMP0i9j*rS?|NoJUe@G0s^Yi6h5694|>jV)gr{@v}e<;#Dg;GI8E z3g&M{c6(|(Zn;|s1=FwWjD(54n>tY`cyusTg=%C)Guu69uLLTt^7Ymf9eb$wAd)yx z(Wuc%5%*rsMTk!mBoA*AI_?c|T@NEHWVa3`0Rx#sR|xNHnJsZ&n#+kRU@)3{+L*=< zjPdMF0{~vytP`A7*JP|+-WPwzjPmX-ZxRYkJGl0-0I)7?6$;JT*ew(urzW!$d2vKz zekIB!U&)inSITVil`@@trB(M=N_l^!)c03nfq$)v-^enX3HSnAurQ^yz+eX60)rWH z3rr(FcdV`Rf+FGwV*7_Wd?i=&CiDsy#O`T()IjwwmZ_(h^_G0;1i*htWSe*5j0Oxl z<&A8PcW&b(nmbjwg_hW|?o?gg=>UaGmj@Kk=(Ee41LX^?N07+Mt=P&3fLCyB2@oqfO5;EpxtA_%clO$2(SN^rddq8FT64R-9@v3xK<2=LwJz z=5O+yP)nAad)#AKyenB}R}x~g9$2^Is@Ck$?H#b}3FK#$tJ3L| zw=#`q`+5*Z)LZJaZW?#NgShOv4*=5ptmyJjD)!QPTmY8$@OFPFXNPM&BYQi6vuDC- z9`k0xAt5tn!fCxdsQ{TW)j52Iwu5;UvVfdB8v+5WW<6>G)eZce;I%ppi-g_=o1P42_V#}!^E6N+(T8U|A zW8VZp**15@VBdd?o{ON1Y`r@xiS)%|-qMf=sy#33JZLxLIn^x?^T_mZU7215gk5VG zVRk5qh-PYDbhJLNYATvN=#PkI&nAPUjhfx;TT~Z1^(^WO->FU*k9iui^^0cjrc4cQ z`-kZphqD&6#?8Zg2KL%u3(69ziI8S6NbLJFtV)w`ev2S{55YxwP8SA;$Y?G z-Pik1mj-`|&#i5k*%qpY!8>8S+|8D$gPQ8VFr zN|GR1NG=lKHmvIqx-5UAtDQrOpEoeK|sD{ z=$BmU3OJxaefn^JX?2OeP1!tvw8pYIhk;c|Znjnf2UrBo+#PhL?SO;36K!3=8U&7R zXb1K2N6@th@SA?j+aec`q1|`#H}$3S9sPf8f|La7j*~YQh&$S{X)Df%=^%k|Xzpx@ zwx@?)+K#J5HJ1)qef8>%UitH@->aW*W##>D{N3gD->b9`%#CU>WbBC*8({@UH1W5u zHfu?7$kR!-Ge{oinuLCT>gd2s|8itp4DmopztgucPSZm|RJO$rVZPu^pH~grlysxPT6$6B%&86AKy4r~Zu*x%cP# zORlNf0yDriI05f`$Z*0`&rws`_YHqf_=r`)Sv>E``YtPPa2v)N*~W^$N*1y+Eu5X~ zBnxLPJIN~9%ua>9;3a83;vU2`^4AD?mC}Nnq(jv-3Wcg@E+lqci_Mh57Da~+VTuiu zi(=wa^SIe=QP@3eAjK)6#V~7ifx%*se23Z#A#-?PwHVeQ-1$h83}hxKbdkp`@BzCTn&nCmG`rZncE?gcrMQ2N&(|-voMxp`#lhDrRv%aw`F(ZhyXEqxf?OwO4)6Ux*=2xVIJ*qMD`po9Nxde^;+b-QK0&5j zyl3#{@r~+KE|A+LTub0M#ik5Z@ z*MuAt?myh_^H$zm5#H5wEYY&<+X#G58&(Sh4o1I>B6L~KOmx+9E}FO_)D=^A%(QIs zj?vdh-!aF!34DHNin@O(x<$MsUpx0sLV{3m3KE6hJiZlxzAQN41%TrFSn-hJyxu}+ z4TXmHg@Ain^}$2{p0IH@a7Eg=3}!an=fg}ZeC<%Fq&a53uec6w2PWcn}@c1u~C1>3ua}7xl(ph_={#X zg}Opk~&=o7Z3q#`txZ7^Ct64h|u@!X= zHefCYCmkz}S9B5M$awI5yIT+q5^8gY&ndtjmS)kS#nIPrg3Mp5fY-RSsa*w|Z~HA| zBeWE1Q&e#A;$45g^Is7?AG+zQrAwQH+;k7L+ALf4;>O7{;f@&~&!t$d)ihvd4TWS;Z%GrqTSb4r+ElPJa>@!>d z9D9L_m2M4frNXT@q6PCyu$b;OrRE)FzfVlx_2OcXAN zh$iO0X4S6V9I{561mN_?gKjm!D-+J0Sx3pUt zcUiwe)HipT=b7pwF=>@A4LM`>avpFMHLpJpGirYq+Dy!@J}e8lc$K0sMZL8Obj)2x z$04_6v0buui8=iog(sFsLSw)%kgSz9`|Nuga||h`=z6@~KEYCMh{nRcDyLeKWu$wInUJw$EeJg9# z1riIf7EddV3Q4t9Icr(m2b$#(eZASZENd+bx?ru%0hi9HChDRIc3+fbL?0pw>#5eW*tw#R6RtC3egHccZTFa2J0{6E_Ml`bodz8IE|>?|3qn!C3o6gSq!e zY<`JK>hL%A*)J>O_oBpsYEXxDsrls4u z%G*s}vA`v1O zwu?s<;xp0DZyvIS=2w&rsh_U~Mt6H+Cp?ZRqMtIK4xa;#_L}y1aD>yiv=I~ez-Wxe z94{3|vYdzCja!uJJiBXgJ8-yhSd5o7r&4HhU-s=oboO{5F+MWL1|)5lRly0j#aQ{H z;iqClhw|qX^OHxFljHqj{s$db;gx@}JuNprd0&=em$#?n|4&Nph*xzNW{m43FGdH) z?@#5-_+I)_l;QjDj%4~mvu~$qKdnsbwV`gh_1jT9_o@ZLPPuwUwbHJZS$U@*YEkM~ z1~yQ{2W;4|QT2D$Aky0Y6Hu7#%^GClj*qq3I@)&8g9#Ll9ZPWGi>52KWo&=$)d*sd zXU^rli0bG`y%({@?;l)*=BHEfuz}EtsMcp%onU68a}34I=JXhfBbv`SG?!XQS-7^5 z(5I+w6xV6%8%3M()Y^!hbSoy*dgVqjoFKccS#lIdLw9|dH787)l?&@99-;L*2qwWP z3hs#Uw8eKszH+a@!S>UM>DGU1*&U20BRmz)$x8SUGiFDSt=I(^F`TeM`A_N)jM>+3 zd&Z1w7lKpt62?>~Ee5CSHt3U9?JaG)6-wZQ3-XHW^q&!B{p-^FRasON=Fx&vUxQ?5-b<5wuYP|=-i$G!@#Fte zY`@)#!|Ly=$E+;!#W}9wl>JR7jwyKx^0Bb7+hdO>fSeFK5;YTkTZSJIoeSC2hov#W zv;2XnO~o>cx+tMtny9Mx@MP-ZuzkcH*O{0Hehurgko+Pp`DGn^BL$bHXtFA=_sgR` zEe+Wovh5R=nen)q29eMLNggUZX_Tp4Eqhls@-(;W~kKsow#F& z;JIfc3e=fLVb@*wf%;>BTS~vJ0^4;(wQCph^fhkBW#Aw0_+HNivdIMVobH1sV2?yT zH1xjszLqo2Vf*P@bpT@liW|gT*54D%Wxeu+W#saCxmv`)i|v1H9f90F)P0$MTC9AJ z(EEGg;$?B4nqnDq**}|{hI?>xz+%oGN8{0^SrlwhJ-^4ikn&=!sCqF^oE zE(*4=ak9=`1`oEE(S_j_jqp>}RLi0*W?q*S+wUh)Na{FY>F=xAsz#*hv4 z%uQL?KgXY%_cwp57KV7}*cSF>BygeTj^?X!3^G)^Dc%rU|dKpK=11~Ql zh}eq#LV}Z|Mfhf>m*L|?Xt)#lVv>FhhPp0kwnF{HaaS&Hl4P~QCJ0UthxIbiWnG5e z7(Ets-Q*P%Yb7p+U(fHa8LB)7yQu3W@VeetET`aDF%^IMCR?QkCV^K@1<7&>j`dRE z%|0v2#ghP0*Y!WASkEzU`>t=6uOc|?igtgfLkqM=g05)ub=?+S@krlS9St7Ge>wiT z8FNgwp4)DUT}AV?oMxb}>oSvSJ%`WVd1%5h4?KT13%!(PE9WX#p#K6;m*ArQn<;8a4Y@Oe=**#@NW*hTV;&I@# zS_2$zk=|_U>b_)7=~)S^RV(*WnwDk_KVIPJnQ@^&r%VX(e>T~6TlZDiL>)R3bJJzJ zMRCO=s%u~_ZY#ccN2`vXz+DV>KRg4x7-oNDCY=M>s{6_phFl<>;6&V}p>5qa+u&X+ zQ#eqvM#5qvefSKhjbsk`xhin1!RIu=Ui*tVS;2v;?r3vTR(R?7q=dY1oRqSuS<`w- zLRqvm zKVdyl`QO*uZ#f)b|B!VNd*WZfA+~2N58qd?$8{q*3`z{A0KH&M;CR9fm_;Y~I?{@IA4{U@##AKeA5Z&+8%Z6*y)T>A4BvCm*M9QN2wk`!` zFZo#P$}})F(5}r>J<_JbTljidB&x+Z%p&O|7*Np^{wCi)MUm;7D@KpRuS?b`j*9#f8@<76R6!~4L z?(JALP4c?GgZs@S*?LjBKS4e|MFrWw#Wg3WBNfl;C1(HqaFX(Widr957uA1y->Nh{ z^u^X^f#o^Lv|bkIs}mI+)~8&XV_!eAR)BT=u~KVSbsXoSY`s%_CC&Fe9AjeJwr$(C zHQ~fQv28n<*tTukHYV1a@ALa#zE|g>PghrUe`@W$)ABsx6)JtGKsRc zmiUXJGpSK2l>LCn%LWG;@lKL;!4E?U9%n3{^`|Rw{}{brejXg z>9Iv`OAEB{aqWRr3EBSHj6~#Mi+Jf@)+{zi7t3@SCx;Qs-yMkmu&oNKIXRS$#M#FA z*&g0GPYQ8gJ!&+g?(=-X>;Ttg0Bb2VKsoVe!aZtUq(gByOb0p~7_e`#%|TX`;@81I zY{wSe*XP}SmKUN8R`dP&d?HsD$}x~ie|I0Q*ficOdj(cof6RmWx}U~rSXEJMcsKRZ zX~}+HmX;d8Z%Q}t8=cx4!DYkt+*O5kf26=OPj2pR*aS;(xuxt>tuc`X{da^Lr>p-wP7`FHM_NtCN-RCPBX521>2AJ^;-n2K6RLyV<}gvq{zN zLqguCorDgM_GC+|eUJ5dLh-tNm#6VT@hl9&U(N7#uWNK>xQctSIM3zOp$0;?eV^l0 zka3X*oL?bBF zydZ6bG-g=7SHtbNj(ld|rdR6OM|1DLjc$17cr2=h`m>TzgUUYb=*$g2N=7-$1PMc{pGi?94 z>8F@(VR-1z|BY%P_iw}rB1w=#IkrFaDRmQbF}rh4chQ{6k0w1!ZoC0{n>+95tEqW?2YAhIW4Z7Q zr2m%CFIYA%A`d*!ayTZasO&>n8E?&>GgHPpq8-9Z8 z<*bY*ja)*`j+#!v%lBZqUp)FT0X<2O4j2p+5cl_FX1{vWkDC~i*YM~R`Wxkin8KH7 zsmT}CgNICY8d|-Fw>&S7b+L+qOF##8d+1=CbGpFT-#<#(dp3d$sXu8hN7#S zgG-50^5c%$+P6&blNWh&76_ja>_quKn2ZJedUGirc4=={CgJl@pZmF!+I!oftCD%Q zCRdHMdciE2>CB2sA(zMHzRB@#+QEnL4LSit`s@S!glmA{+Ve>+bq31~v3>ya z7yLfi>T>y{IP0FR34>XhQ}{hH!22$hf}xN7Wd2a>B_$Vt%@p=&vn3_TF7DFAPiD`X zf3Ml1nf-HI$3yj!ad(a5o6p^_a(=Z1=XJW?rbBRh`JT&8l~J3Y-poI1^9z-&!(7UW zYV_DXuutdWDdDaZ1c5odx%#iE{p%l(g5^7MGq=6<6XIUFDmmLE5rZxZfIYQBszW4Z z{3JxvSBf@Q$~PNm%3HE2#AR<~SGNsHE4335dz&*q4a3w? z2X*&D-@rU{P%p2o`D1zPL3$G?c}BnHvK}vm!t6})-PM~?-&`5zMS#RtDjlzD_nv<{ zTl&-5v)t0nom7a5yW>^>pqy^JCK-GQWLoMz$T-lMdoi?oGNY->)pyj@c>zsNNk)9@$X^Y4_C%t~3H{4DyP2p6XZCLJgJfF5mx z>27F?BV?yZ^(2$qmGi`?yA}Fem2NdJA(VDC>tN`O@cJF?uHd;4Ky0EZT%lXNqjYv@ z4j}m%Ti`og<3xyPIqTT1={EK|Dp|$e^>nR%rsJJXeDV6&5#Tlu!JP%$Q z!6n&C8aLcjBm{c0SdqG9zQ;z2egGgL%hrZiyFnQ7BA({)o8q)^-K#B%FirhDTw!)4 zc7&Sm3;J#St{40O&{UA$tC2IFF`Hc^S*=)uL@)L)sRpw{U*O2#xS;JP@Ajxof zz>KS6wpsLFxh#+MP`@a|5xt-ozyEX$Za0?j*wy?S%ez~XR{Y|Bm+UEQa+{1hWTk!% z9^I#rjg%30^y0MU%|pZ`S6-U7}H@8~n=)!Q9jDg`3+S%tE5M0K98YOpWx6%6CBj=njm7e}Y|Cao6Y6^Xu% zg0J&h9;m1I6^89ij@!vW`;tQDY^FZL+|DK=QD@(AOA)@;!9;ix)8|I zn@@ocFAC3|EXxo_bsurY2`LF3ca-YCaK=!?Q!X57dZNC}6RDKj-5_uZ_hJDU^izeQ zmViYxkLvf3(MW5GTXrfuf_{{g5X77?2ST6|{pELnkNVMJb7*M;_qb?FIHl!nC6ugb z-r&(AxKi-6#BLH>TB~Y7k+ZZq?&>MhHi}2lp-UGViXAqs|Dzum$TU6t+LM1hr^a(| zy8S<({McONud~a7*KRWxVyg1yiE(7&r(SVYh!8!|A4%I3N|x~U5=4KScttMSLdS)b zPtXvsOQW~Hur@RsyRfvVk)CK^R;id-Eb5I-+I|HZ$KjX z@{o-2htxRWzLH~D4bY;}OC&3S-JR1_egW?|=>LI&)Zh*g@$1W8;M0wYFwa!+ULhQ6 zb~ddpv^`)vTrh~=?RMJ3s6cN zgy|HuDChsRVn~Q$MFjd|2#w#P%`QqB3gG%kYKaVc$47JOlP+l=!)45aGRP1!MrVOD zn!LLBx-ppp`s^)I5nQ6D7RAKuzP|i7ci&yP!}J0I$7&A?q%}4B2d3%oPC?tw5N-k7 z#2zcPcI7dgaOe&nDb7f7g1uNYUV>jwKi$%T-l$pcZh}7P(6$E>?LB5PzspMSZ3It& zkuO-f(OAG=EA_+T*I$lgQ{E@q=^xJJ(nT=cO$u`*6nbSI{r>qkV*tXDcH2CNk1cgy`A zlG+ulxb4thKJP3y#i|J7|A{dLDzDypoXD;mY=roSbqXIT)ylu}fyw&ck58Tr% zfQssYC3^J0%-#A&E5kM;4Qb*xF~q(^lteOGA2~O0^J{czcCBBIv9Jt~xc_Xk`_}%l zoH#?r#?r3WA7p9-9Yls{?x*k5{kn$0Eh#HRGzqf4NXD16#hobfX&?Cl+^$**n3lh09@~{0c=V;xpakQ zEI}0!_QsuAA9n}9<8ta>XRzAPGO-fxw1|0l$Ub;ap(do3Wv?)lS7r6 zIf-tJDvWkdy38QWzS4HqlBCP&Gbm6;Qv{_hY-{)O@wlx0e>eUXTuk-}E4mY!@F5eG zj1#<*4o+_a+86(<pOZAkqB6XhzP9~@REO!8Cg51!uE2<<+w zzdWBkuc)_9Lo))n06iF~WDek0_|+Pvu^KG}L2(C88>^V{W}@{dyk#{zSWQ7@uq9W< zxT=!*J_!1Pp2{c+N|KJ5uE_nKx(e1~r6kEwe>Fa;)H8cLf#@J=*xOC;28Z^FK6 zY!@{Vl`eO07vz+M$ia1JJ)MuG+Nz7*{PrQ_> zgC9mnPL~p(?rf)x_B&xWwc(<&?=`aO^x9&oI`n?~E8Q6Z^{x5#5k4aV^sHeB*>1~InkeIFC&fa`j#KA%)?cWqmsQ>+LIfP1sYZK1*^i233@=g;=KSj zS>RFWO%?T}2UB=IQ}FocgF*Qpy|orWr^7$)Y+(ohCIp3NZ8-f&^QgZIn&h)84;6U= zIzHP91T%CZ*SnVit2z0RL6HXk*5;}Ir2?9=#p^b1N|=Il!H9fHxxgA`6r6K+df6%J zJ|(fHTBS|vaNx{K5ExCtaM1Lvn)aVSx3ne_qL(64&6P$f?n0!v9SE#ZX-%gL<8zi& z)HPH9KV!BP$H(xg9Vq<`!4u^2es9QA7Zo3TGHoa5m~_vJudB+X=7xpiokB!;_YFCo z>!T7-gMi1$$8j8=8trdm*UAc`?4_Ua45R(l{7vPGy6vAJBWWxmUHopca~x`g z-XRV#MM3uFMk8^*glinyQ`BRbXE!a2GxHA9pm18&zS*GAarjo7-O(Yt6~QOdE~DkQ z^kE)T(#BHt5JgLY4PfjqVzSLiR{R1kQSn~O*k8B~_L`73?|vw|KU22i{7fK0Crbn{ zVyzv+o3tbh4i6pCTlX8=tau=;LYUv2{x*kO#er;}$d(o~_ zVSZPW+%i~v8|qU#utPb<&%NS<|1rB`LL!*yR$P9zfQznr=7&Fk+P|1}`xXY=gmKf0 zzYNSAFz+SA$GL_7k_(wdVznuA#5_lBK-#6}8~A9UmG?0*xBh(hBksw|m`I^&nDMB-wkwOY2o@LnvMdjZYkEqj}M){5MAi3h9(G3)tZUCci6mNfya*xW$^9` zE8zVm4))qBj%LGGZ*|avp)Znu^1l5JK#g+;yAA8_Xq*?tfu=xlV7l`scOYZQT?DFR z_XxlVZaluSi2OdAh!V#Q;3R-s)ihZg?ECa^ z{n~iFTQ1d#@KTTcV0V7s&N0aP{``>TrR+Ut^f@^0EwbPG2uz62g?xl$s*0fqd-0W8 z^&#$0G@`xm^F?fUE}a29n=tzj|ASunUXypsPlP4M!@fnZL#s$8(uM=fk=7r<^>)S#1aJ4{<1A3H#TE`7+Ij=c#>DxW{wolW+23-vYM*A4K`5|` z*5yQ(07vK!1xzoic$~>T55a1nIzX4p&9jY^&r){XS<3ruZqPT4A4NP6Coq0R7 zPr(@=Log?NlOff|6o)=CO?RHj_5Pfk6M^8P&;OD)39%MzJgdG$ejRiR{kf7dEHR+j zT%ezu@+_i`9Qg+sBc^-BI>DzkcQu2T2oaK8g3O*MFWvw;kqgGiEyY_|nhvS~rOXRR zqC;F}cH00(=Vcl!e_fDk5iQt|)7?;a z{wcf7rOw0MKj;aW_}ux*-GR0sZT~OsPdTmi_(>7%wMn9|#4d}YpCIDiC*~(y0l?5m z-8u(wew=w8%l(!N&k{s^vn{>Ez@2l>d0!Z#vpJny-=1f#2GW2KOTpfnMz2u{u|9S; zDp30?gi5$>NF+9JKN$3n>}0HlUFcM?KD(ZqGwVXc`>YFOdU~_*Nk&zHqcX7HsNx_P z;-$dOw*CbVPg3t_o~_UBM%t5${-(eKR(L3&{VE{EkKCN9dhCQ<@nJsTH8xjZdo!lh z>e2cW_i#_ye)rqNCmqu00A@&t|FYrCyj}H)feTiNkz}Mh+!!a_eTSp995Ov-##I27 zu>qY`n$np4*y*e^tKQ`kwUlTwqA{X& z0X2#6MPe_qPGakJSWVza3E}+rOdVMe5majXuaT=z90ACNvRMSAx{O-MVaON=99j&r z52GN)Hcq3-T9Z!_PNUC}${jL+ucH~jn8Nq{LC+UefFvbyiG=S53@{t#^mre=Gb4wE z41(VMg17vv2?XH*!DB?%%%M4gazDG~76hcMB>I1q2sW0cEZ65%h z$FNNW@V4>-<>(%8yLyIkYwAb9eo}A&c+`aDb(l1RdtXf!&j{q^IITGVtY@hq&9!`J#| z{&}L4s78<{l`=z%z&3XW%Q-T@uEZsgg#e#PRv3*mj6A*Q;_++00CeqfyrK&1Us+K z5mdiJm>|B2dXTv)Tqs0f*3lete|8rw#j>Oh%7e>EIhpj zgmhjU2Pejw9QUjuT}FA%I?fKzUafR08N>VvuDg94znUjHk@FmMjc4sIk!<1ex`97U zUG;_h`GjX^K6BE*&w#UnyOg54r{Py;<3F=a5Oc_LiK#VWJX(}NxU_@&s|%d(#M$LK zn69Oy?nbKaiB0J`Y8k(Q|7P?%T}pvE8gM*ZC`FzL*~fM^n#zVwL9_VOpdNJA44!DA z$pf>1G|cx#3ENP^22BiW=_<2w;00;xQbX-=Jq4)JC=Vg#r`bJ`+CH4#NOu}nvk$OKL=O6ud5J+(#W@Hd}==~hUIXU2bRvqlcuIIl(vV zEe&=ypGSw!pjlbhVFJdpvhM)zctm1hmjR!#o))i+gNfgi!W6#&Rrf%I$U$WmnFIUa z_ZMGYffoR$?xl*R+9|iah1(v*R=;qC>?wGDcrUild|L>2@&QlZXD95SJ03yZ&%0X|y0DiGeX%G9@v{L32fxe(+MNU_FT=X&kzPLSvs-^`^>S_m$w4lJSLNz zMD_mPE`9phrEkb~IW7*F+vd4!J8vR5{{rYQ9fJQibXC3qT;NCb|Avl5S|GU`CUMBj z_D&`|q*2-2qf?;_;b;m4u)#gNPa0<|SQly%pakMp>%z4D^ta>>K%}twStr0#u&%8j znsF{=)<-=l6M5SmYDfj8NkRh!>QC`eZQqx7RLtCOQW$Q=lx1 z{g{218lT#O3b3mf#XjGZ#TmejOOTcS1QO^jFA9OBx+?2 znz;KG6Z60k0-Zh!oLM&J^0W>7NBO6p3an9w0cT~3W`|tskz9z zH$uLNqPP=@;hEdd(GSiWYiAhomTdlBq$<<{FCuJvsnLt}J{H~TOxzQDsYcZgkcw#e zWK4#Ql-n#vA_T}(!q1Xn54TS8*8qgl7?zun367z&Idt9F=LRaM;VbpjJyGa(ZwH z@Cv23KuW)1B66Cs)0terVJM!~%Hx84*3h_YTaem}5nVV<5TO8niivnWt}(UtX$i1T zbxjaHZ+cSq(6z$W@Q6WtUdm!uF2J(aj)0)qM`}ahe9u2iu6Cu<;C706JomgpGPaoD zf55EBwXH_@_F~krhQ_D4L-)dQA+o@evf=m2#QTBIwt50QWW~=^uxtBnI2L~Wt$-L^ za}99~&2Xf*(EL$wGyKa^d3GUgmS>PQX)m-V9^(1AIzUZJQ}=l<9tt8gF>)whq>?pp z-#xb6Liu?YovFpONrq0elBXMXGHpMY9F9mh_U4uBC~Een=OX1GJSxs%Pn}b)SQZ2u z`1zs1w)*R$GaUbv4z=&_N$thSoviXLJnv~?VyqP)$pH?^N7Lgo(W)?(OUhdC!dZBS zx6|q1_+=7T_NEUB&qhb6c?FXoY;HUH8~e|qfE}x|%|09ZB=&{B;sW5^MhyjIe#5+S zWA3_z7zHd~P>Vm+ZcmFs^QL2fd+dR(X3QHIP{$s`%Y(^1&=6Sm zC+CQCVzAusV8S)WLWyj+ffCbNWV9hLpM{qv4S;>3C0{RF`Lt$dXX{7Jlq1%si6fkY z2b;aO*0;zx3K zq>l6Hp@SO`Qbjp%;nrZov`9k7k{naV;xYz!6r+v1-79SaI0f!hT)2yF+APd^JFU3s zxnG!qiQ4>QDH zZiv`}@vaRAYyz+XnFPkzySE~lB3Ke{FUUQg&7Ff{r52*C?N0)xBecC7N{32{yrj2@ za1!<7BN6x)4i*NxUv3N1#0T%vR;MCXWZq{KemXtPr9&2jdO(;FOU}SNHN|j$T&qSg ziJ|0LBvW{>&8;rne{q5>cEmP=|PZuv4%l)TJm!Gv|KM&WBhhf`WN3j?Rwo}k@yG`9c34JWv^ z!0rJ93Rn#TS13qmbm`{^Pu9}c?O5+~NnJDdy3R-4#IFB|Z;r{;Q|@XL!m?ZO3&8`dWFPrIIl`T72@&kf^1-%!m2*2;=oOir%EyYkl0^jq4CePtv zUe|fdOU!|%&*!4?Csw)ocdtt*a#TQ(lkG(h3J@_!s6*P}`NOxouMo(`jc|R~_qGFb zXte*vFY>t2tggR|V8bNK{-IS5bl_c6aYUwo zp+;5+amn-J25$3lPS-eSRD1b65A5(Y5^HO0aibsn!!a|kW`oEyOKVwUF2E zJm32_vbGfwooBv^swL_zHl$-ZTVpLWYbBn#t)T`rxo6%me*V?i$ z78rE4v)2KNh@ddsTaX2l75bkW4p_2Pf2#W?cW|l-%-xQOky}24B10;Y32Y9^GS)u$ zGYRBXIW*VCkcC8Ye|XCRw}Em%HdWx433jVw-V%CQ=E&ipBK0>?^v71hts>q>*#(c# zAv-o_mlb~fT03f?P;CKUwyu(?YYrBnI=!mH5>}U$!5D**+VWNxki#0O1~B{YPeK1% z6*qnwUFQ}rtX&+rh_0_0VgGN%Bj(av1$~KrslyTL_Fu_x}hhW=&IkaMxjp5@r)+e z%_BDj;bQU>SiKEX^0uECHCFg0A9y%7`EDC?t`qTgM8`L{R?O^zItHRJlG(bhEm3Ra z-E&3-bZZ3c8})hDE%_7yPo?EQc+Cy>T8^_D-EI{?^Cbd^GGA-0s)*Q!c$`wX^IARx z4wXHu@=cc%Q~E3KU(^1F-(qdb>BR>7*`y$TK}4h_{kbSuZ1J2!k8m(KqL}<% zeMhdS;79+8Z8VG_I(fK~qH{E8+tr9X>RxqLvo`S{6N9yw6ad4iF%<5M##r40Wd;c&;B5P5PI28z`q(0St|M?U|{W#;lT;kG0QSjvvFE~Lr*q2dc=P#hq@d>3t*$3T)wfFA94Dl>> zpEV`CpWpYq{C-wH!nxP61G$4Bu?A2#Q?Si~5u85(h5FBtBHqlaba(--i(z(!$2#ka)hY?4#-eFYf?AYxXmOS&zG zqh+4CtYezl{Mbb)vLh$eRRxTs;K+t`uh zp`RMB&2tFo{G3BuBm@xbaRZVWp}=)H3ZJmkPu#LQ=p!3`Q+hs9O+>eXVBgIel9sn-ZhIv=NKQ!WZwya?ST`0wjAJGg8IqTx!@wSMgb0 zhmA#5b}))hUUTcR_>9c{=LFt7zn_%Ul;0w*l^pzCCM%qhEVO+jk6h5!pw_ZNkH(_i z?hhooV#-k;zoXZnexQqz4yrK^GN%Z|D&{(4Mr1e*<=Y|{Z;zD6B_fbSAVL$%7GFa@ zvDj+QvnKlhOc)bwb*^FT1a8>s{RVdXkJkq}{`5mS$g*MLJH3ccMGvR?C&JP5*hppR zeN;dL-dPH$}^6F*mIJ*&IfgZ8Li!t)T9`ZkCz8%T3xzauPWUSCZ4rBM$ zU>SrT z&^MT7r5XfpX#q5zjHNcEw>{wOPa>y-+tM3R2_2^YW_`3pwT|x5(LcLvbonPi-UjT?6 ztW-+z=l}S@{m7=i%dlpUOrup3b#yM?Dm>{+p;_!#qW?&o4?U*Vu0sF>=fog|C&m&p zHCF|WYH2F*qvN}`VLgv7WA9WgeN)!aKdt@a=iEC~(BiCZ3!gKr-b_ami_Coe2xr{e zB|^8sIbnh5D@uB$O^Y^-4`>i)^N`a((rt@*3)c|*);+JX(*P# z0x!dJVwf{WzDjKseJWlujcE!0L)jql9pvq0M(sq$$OY#y6ga7r5F}63uUpt(hT;Nt z;8pEuVk4#%_urc7N9)--b2;dpY|LFi2GwhyLMn`u_ypMl#it6_%`gD;f^ z2{{~p^zVmZM?+_^M9`rOPz;;i^#Xws<#BX1tYcsWzO0;8?8>K8>Qc+h2=81xc-C1# zNh+NnvouIv=b0eAbqVvXgFgBn(eUuDeTll`nPQfqc8h1p2<@rEnmgVwS#sb>^mUx? z!3dIn-R1@#C9`rxZh;S*-JjJ`CMtH5N2U@`E1{j`8Q~R`Z1irf3aK_GPP*;oMjo(y zh#l}rTb8?n@f{Bik74QOBujgtSId6L+YWbMSKx-Bl zIu&dGUh^$f!w04z!+ZHZBJIHA@H==Znf%a(=XKGj4dB0op*|D*$*k<~Q{(hw;ke0u za1|oUoMrB+qYg4AdZK$&OW}^nNugrhRPPIiG{E`C82j~zFSqIy_u(7Wx$T>f9y?Ar z-y5Q)yt#w=I?UKd{U~WE>oiS%O!_Ru=N-FB-XfOg_U~mbDpZSuX$ko7UZ92$e}Qqb zz8W@FvhP@sV&Ll&FOrZFTDSUkMMXu_*f3Xxg*;4bh>eNlHk@MmKssOKXZ>u(PX|s zh;|UAwEs{keX>R%tKtUhZDm8D%RUaUQYBBv=;ONclyd#`PXkuSz_rc=E^2mhhF}lR zU}gv`%idU&rRH$c&VenPn(@&Q(g*SPCS>c{@(}AqVBQA!w7Mgd+~ZjWV&^;C`gA8ogeZgt#$VS`9{I-j>;gC#Y6v;&?GfLLao5x zO1CS7F(19-1GPw)4q}Rfb+E>8#qKl^&oQG%5IaufnY39Ep2S>GL@+|!UE|&^p-r5Z zOZLJ`OO-zHB0Ymc);2GB_%%0k??l)FDLpa;vE&tn2H2!ou>7$t7Nglojc9rU4N+kO zS=+Ye_4{C&R+6Ef3+-EU2pt9Ct|l{#5m`*NgbCwm^fe^7FJstGHCz201r zS6=u(F%g7ET1N;$OrUsFC+*KEci6=I0a$~6?hLgI;;Td^ zgi}R#4O4!x%CDb(6sjhrRcuW4d22tvzz>8r#eO7CyS!aHV$PZRr?&NRl3!L3I4?XI6l#22 zb#DF%E4s?6V8U4rcQ7JeAX8rnC%D9MY+{&zN6g-6 ztV;qCbt3jHDcv0hT}PIop4onhWx?wY92%9$#7b1Y`by~*mqa=CMjcrH%^Ir&p@(H? z&k{T>7d(Y7OgxdLL;6OiVo*gb`yQiX!(i)o!6Ab9Q(>&g8dY*Y#yuoX>lS+1007ZOpc__AU7}9 zvF;PE*ozK>vu2n$cu&z&q_Sr#zfNW%7h`o2)~u$>2oc(zar;BWrzL^rWA~Lv&?@nkk-53H>1?|TNQ~7|?((NHdw)1Y993WL z5q+uu@fpztGN(<177X@?>BL*C*t~h{Y_OR+y!pqHJ&+;NV892AW{^>Q01$dbZW;pw zXd;8_@iTXW@yo@U-f%nP5jQ5ug&zytj92kt*8j!YD+?{t$%rl>YL1KDb^#DB=%d(`3hun`fYi#y&}e=62GPZn0_mCieo+%@@udfYkmjUxL7JUo?&!n*pVB#Umv zV25Ol(l0E4Z^!N0h^ccmM~3CE(IFJx`ijA;MXs(3Ej3Q8kXC4=z`SAW;!B{K3cz(j zf@?TtQSuC^EcUd z^l8n-xxm-wH^h`Nv&n#W{AC`YF_IxMROD~7JGfy0@XXj=o0p%8hM3gJ5Q2YQ5wsyb z8jyL@7Rz4mi;@_f>Exqf6ra4Oo1OgjtXG&9KR28IrL$Qb1NR*!k879aXO@dCZAHnn zm#gsS0Mt_gpk+gG2|A19rXoP#GiP(|I($CjB%bG#OB_daX|R_VB+}_ur2#S2RY~(2 z-&GF4BpPX+<0TeP@#sVAb%EA$6#-Ll8du_>i^Sld^eb&z0K#<+yuyw~qx31K{`Qx* z_ed|UI8A-|7}tFxGl34WhGP}^AjUS+S>?U;5q~pOEM556m^!F2bAv0MXvi9UJR5hF zW_X5trQ`6$+zYkO_N>jS8iw++(F8HR38IeWG^<%J5pPsr zjH_GKN9Jpc-|9u0>a!*Hi^rpoAqdu8`5`%k{4cC+rMsV7UJMx+8*`~1a0GG-vXC!T z!%4e^$&&^9=(dEDP{>|}sHJeuYj2(1ZDcZ1sE8QP;C0Ph66YJ0HeHATSeo)%#qbzF zdL+Nva_Np3yrbtA=AN|`cbMUsGBJH3z1--GvTxQl{ck!@-HgRw)bt>7{B7o>+tSq^ z5#KmND{gp;f+Kg(M;aeHnBBI^hZ6OFmSkQ4s49B$8D*N}s$D_fBTQxg_!H#M5CWJ6 zQ{WWpvUDHm>`WpIkv9NXD-Zw3uQlZXz`~@XJiwj<-!XLuE4}~?w<&jF{^bCnPr$eV zQ{@%W20os3nfJgqU&jTEW(&DTmszy!SDKp6^3p(!qwiCho%B_r6wRW+%DrLeAfYmF zl_2aRRa-5x4^x=z!XN?k2NJW8Mp7R%m=2*o4p07{QbYoxuW?n5y8N~a&$KvzDOUs! zBM`z=*5dAUzw7lf5Eo9C^i$F!bCGxkn^%^O5jCQrQG?~!&<&sb1|z8Aqp@GRF`$Dh zbnqaHx}RlKZ#U3OV%N@TadDeTUU9)^94?hRYX|AsXN4oHAzNhp5o*P2LdfsO_+K^H zXQ;pr6wqa%aZd|P^u{6V9g2}p$AB}o@D~&Gob#oF z%G*1x`@y-*>?8Rq>1A)Q>RBBBd<<){9zi?i*f%4%)R~C{gA!l|?>TASg5VLmlrWkQ ztHs^UFou`$qoRE{!NxS;{(H}#q@LKXgTtqwbB>-s8cZr!Pw~Nlt~LcQEX_dYHFNT< zaJ{WRk1D0guhs$EAkOi+A*5X~r!g6e0Z-!%b2-cot0nS`N2JgD9{A&D{@F>bWWTy` zH=okHJR`C;oJe})2g#%Z5+Vf~(K>rwPwt0j;t(7;}!DAAt!))WNMXd zM{k)HYN;#QF_DQ>9**`D*6Q7A^&es1b&h*!6w2JQ)K}RIrt5_!`s9f(Z=s*{{}j}+ z05|CGt>PboPlai!f&aP?5|;CHG{Zwa=KmY#>Z+EDD`W?X`}+}af%s_8ca%AhLzIix z#{dikgem^91#a5{Rxh+M5X|qxqkrJKAObH)7ogn&G5XVb*1)D`kDZ|{nd9J{cTMxJ zhilxY9u?MxJIki0c*`ajAMdVuUilwSNcDIZLX#VkbXq@70 zIxbm9dt2nGObb2I6b;Y33{DHGNlfE)2VyaIuVX1dWQV_W-Zb~paSldJU$pqVsTcI# zXnR65>;?^q`dpUt1ZA~s<&?W6BL{fU82}%kC4CH%O z0@fP8S_Aw}XV`NfWKrp))Iw~~+>^X7XG=La_Lc7AH+!;XxALt8?MeA92?SyyfX?-~yW zLY1ID_nPuP=ZKC11_8Qx zBc_US6j@W|Cv;`K-4D7!5-s_G5DKM|>>e{$tw*jO_jlZ;p=|7AW(Rw`(T(vk6a=jaXmL$%JM|^kd-6EA z@Qy9Um+PANa6z#gZG@2i^g*HfQ4I5m@0T1lg9uuISF1lce})K$J+6;{;6%vUM5B2{ z$E_9&0D-n0upkf+4}0Yr{vv}7>h~Ss=G$K5d!*+Z06H~F&94A`;Zo^O&_x9yrLLAp z<3Lw(=b;$VFDHz;R!I2ks9%TzXI_TLGHuoEF^BE1j`}k{#V66s;NtJ;w;+VZ06x#A zBk$osNxV==-0m%ChfzN#B)Kx2Uv-;C7rpDOZ(V+6vFObZ;GGnYP^__e5=q;DVw8Ep z;auoYwp3JD_$U2-CVQwmO58CS0+fl9Ta1(F`#Z6~* z>58p`5rXoo#Xs)4ha)Etip%6=9_WT|W=YoC=mSH&@C@UKhyN4(!XclyT>p7EM3gUi4=boS{V4V?hu;eWcwvCAhdG-yf^N$cH zLvQZir{CXL9rvcAwcl9)Uk5dvapN{%3ppVDtgX;&|69BapS9ZGyQvb|M-jxRD$irO zxsN8SYpa+R&bF1UufW&ACWQ#Uwm`F}&5$AvA$gB29&I5N+sgVp6-VI$zmGg~=(C;VhfhUmRsy#8nCppa*s-C<8d`YDfDm zEgr^f2cGRNpFz9)1Q1C4N9N_;#Xhj)RK5iL zUKxzz`Lk}TM7nwmVM6=7>GunXT0SK`=F-uND*n&6_@6{w z7D+QOX77jH6BGq}0LOi5c#vDC_z8C0a{XjgJ}*cJE+WEYk&B_?*CkLjhwaM8odT!J z*jKC9wdKSYEYsqxIOcRreQs$IXPzwotFn;~RAL@2@S3Pb1Mo4cMRuR2Bz<;TxvQpn z$bpiXzeWT*VA5;3EGii6zrUcPU38)9b@&5Y($=f?*V!3^*Z&ckUhhRepW1nW~vUPzt|zC z+(+`-IIlf?xma&XvpeW^z{trpRObq>g@S0$rPeS~znB17f64kT@fIKlThFUQS(GlO zKvT9mdAY}&m`SA}Vz0(9Qzn@&bNhm!m1qp2^5tu_6gZ~Q@&-maDneS$5K7l$m?;zQ z?y^3%+AROXypA)(n$u(GdC!-1;nkLThQw#1^#r|*BD5PSHn)NT8D)xsRHX28A~*vVwKrmtqFxnYG^CL!D3ddYIUF ze`OL@4r|P%hMg9Q%s6HW!n7xHPQgDCz47fCfHP>U_&Tg=rUD&l%TS2^)LE z@|JDJ(Xe1>LL?+~kD}>f8YrR zw_1LjeN!teT&zj!VQV3*hwkJw6F*dv)NH^D4+~8Aq|*CANe-(~lPJv#exfA#C_cC- zhtG-jIiA=KtEnWKiqi=FFgMG+)AKD}6ZFI3QrkEme$79+=vmFze@{A^?YDT$MZ5qI zNsrn@YV#e{$p?hIWgjmA5-sG>eBP8$k zvFEM7#X2zk2<709c*Y7O|i2Pe`8xvZQbop1qZyR#I!!0vS*Zy$Nf67pg!?@pi z+IDeF{f-EIBJ_#Wf91xuS|ZNI!PvN=CCyqIX@WSa1Ve49_{xIjBdsgglLoW98SARD zuzpXg&QVHzMgS1Mw}Jr?6X;b0o6ktRXCF5Fuq4GX$1Kb6;$+xJB(-0;a6>j&d<30K z$iLGoVPedh`U>Y58K8D=e@uX#l^kUE8ISYJS;a?GurVPont9gZ6t+Mh65*8(-(rvR za!m)jeu3ttc2A}Qd4BFi0#ogBf@Gx|zUYVcqH}=(Ih@qvseU;^mwU=y+f!LyO(OOL z#n8)pPK3%E1HnSEW9i%9LGguqS=<{Stz=x8aAkdi<2whc#efI?f8IizbCvMV;)exr z*v}P%I7q*jzigOYRuoiC><$0d zhF15@mdXoDn|_Pke}gD&)D-tzE6p1lo{jfFw{W;o9XN<{lTag?+RX&XLTBHLW~C6K zw{qLr1d47SU^rgJp(*KG`OAXIhKqNsa^EM@$HN`CQiGtzKXiRNKJKN*lR%VTdYMx; znsLkpxhQeZz5v0lfdTT50E@-2r>v*ax4ZmRvP;9fhsZLIo}PdJI2C-M-T z(vbH}NMWo<`(lMZPK0lT&sRcUGvNoB%`|Cr6qsypqIYlv8?u$x{KB@Ik*N8%h6L^de z#ovzft>7(e-+@+<3AB+6LWgjjw>Bh$tF8C21510ve-n36gy=wx7*BT!wHpVXLE6E~ z1#m}R9?Cr(JcJ-5ZwIY2ei%I{-xKwH1kbguWvF>Dc?7A>A#+HjWa0Mh zG_X_pcN~lfj)~PII+wwCutuI1{OBb-breCOH1H`U*6Gy&rUY_N77EvsJs(yIxho6b zYQn40e@7rwnx}@3J=Kl@85F}Ol!pxoO8LteR%)Kfs~M>}#GVc-_AImiS{K!y)no?y zz(yR8)Mky2A!knIVk;{P0Hmf&*xwxIBFtqsak%i1FSAJ)Z24ODe@ji^G;_EN5x*<5 zv3XTs7jdLkdvnoF7VShi&cR6*GY;Z_egI1F2W z;;5Jgo*hPwH=4Q)e%vbZ$(l%}aoZ@BZ|tBpeq7^4OXb@VF~qo%3tHk`3EZ!&!#Jr# ze<6VDT4zv+0*+d@BN!JITs=a?=9qXY)Drt`kV=QKQQ<<`6YEgJnHjhX5$+MG;|Ou> z?1}Zy;UqZI#mh=+zGgOoJj2(_V0-RxVYBS-_ISz4VSItpYpF51xLK$XR3o5v;Y8GE zS#`3FoI*#g{DThc;7UH&v2?bgE1kvEF7qvO?Xws7>Way&E^?+2}k1e=&Ts=_@!< zOPQ&gvaY{vWJUPL?LKF!d=m@JA?#0MyEvfSP5rZaIDEh)pf~J`oj@iY11|UZ=Rx`d z7+{Y?Mt+aA3`8%;|8e8oJtyXre{?J?xqBwslr*r6z#OD_HVnLtzoLE2Pnk)zM8Ghg z;bAkEr?&XgIkMr;csdj(N->d8z{sJTl&mCl=ZEJRRG>ka#-Qu~&vW)Sj}QKgj}M9y zrI<)4h)R*BAu4aj3$grWnsEHa)jE$!;NU-9qw*nl)Kl@kHUe)4>2@T%eG7c--)J%>OSlTYt_vKmn7WHVJ^;#T#9uSW zP_QXGLTyW5NNpDlV6v$ZW;c z9!SUg`TR>fEte-_fJ8xq2|R>fAmTD5r|p&-0>9!70BIuC5&;9G2;(N}n)+Gs!5_0I zL4jz>$p9(15z;|V_k~Df_!UnK(nP8y0tWaH#z7`0541#%uNI_&f0n@QFpr@nZtJFR z%v{#Y&0aCFu;f~4l-=Ec?N(XhWI<4l*yiSAK=Ufcw;HX7=CrEfW#Ys*P`mG z;sR8RIsCc>I2W<#f9|t>3;R(V#D^K|{L4sR&FK7*b$zZNK&S@n$Z3~NZg2{-OSMZA z#?3XS!9{s!o}{7+7RO5Cp_}+I!=WfotSE^hF^6a3w1d;R2T_@`A2SR&@JhVKs2@b- z4G<2RL)LX77vs-(DikM5F_BO}c(?#42c=eb&a5|wI#bk_e_CDXttSUcJ$;U4pJ3>Q z=qc>A3C^gY6WEV^*pGM$CQO7=qSdK{y?rZV*xv6WC&zs;zG@V2@9v_LiQs* zLa+=gloAdBE(8cWO~D(ABEFd@u#sST1#ckUU%H?xxFH_)ha!XgE1pPd5M4ddV1Zr1 zI*e$xe?P&nmfIlyh&Mqf5KTE5Ac6nW?T;zxrZOoURxA#f~KxkiF& z)H!R=DaV|stwx+5+yhQrc;Phl9GY6t)Id{9nmR~R*W06*gx)~*@#Ce3Z~v%z|NLh( zAr~h~F_BP=^Xk#l`>!%ly5UDO9S9SllyC?}fAmY{EZtQh@&){erzv>8Ky3~IG=(!? z@SA4&M1=SqO(x{YpqeN+NI3!LAg;GEqr?-|TaiZ+ROi{lMR1_J>VO~d6ik>1rG!HO z3qZJNa21vl!Os~~c-m1ZCK3t>5z0<^$aXvj!jEV=5GFz?;Sh}I8X#OWZHs%pITin7 ze+C^_AewSAKq9q(bkNg=553?=JS`I@LMh=8Km`yEnz|LvWIy6*>Xthbv^fOO0EB~v zH>ERXLijug(-U(b*RFOFUyVg{{1r`r(nP8y0){c+W3x^&G46pMGpP8u2eml_@;Jvm zibm_+9mP1(AIP=tp~nvXCK6i0e?}X?f5nMXOe7TJ{=}hNl&u&_;IA2kEgw#B00Dz+ zt#eS(wC&Kxl7GZg3I(DmCj%sK-`x26SZ&6O1^YLel*tmVlAt=wac8cw(QcdKz`ef56WV z?tBZfg&53>-?PXIKA@K{3Qlkr&SAZHv`6lw;D5}Z<_bhpP6kM17mzOcPVV7=4kR3) zniKJkjC2!OZf|IJp#YuSYQj+boqU;a5B{NE4}+ z2pHf)7zbJRTnZP%uXr+$CQ>aCFhGVd4l;frYy2FHxI+&Vq^cdc%lKR~`!_lYOqOt! z1l5`Gx0!3Mxud+_#s0;+ZsJ)ecD$rsf) z_UKUuAtpv*62SBZeF}^vf1ffjLV_RBMu0F8N(qNxY+o|x;OOb0Xb++bCVt10ad|SR zCJGK%1)Phx7NqqI!kUxSiCl$sFTy?*2VV2Qk9Z0uOoURxA%F!S6b-%&OPi){)QLIu zUN3xgo(tjXaN#d`gX+eiIRy_v+7lo?2B%Hp02IhgpMCUNB92rkf6a>l?NWTRvMK}N zd0hT2lGTEyR=hzt;lhmdk&Qwz$1y9KtW39XtsS%UP*-THcx%CSg!i>lzU0bs^G1Wm ztONoP&l|`Cy*_-4J?cwx*JN-5Z{6&<7AqJXJxm`Vc9=ClYd~n62J||D&1+>lgG?9SepxK9c*Q zX*+cmkYA7|J`N90n>14#dDsT^)R{wm7oYezfL%m!I?OHWY6s<*weRp+XtZTqk0`y1 zF_M)}eUnGAC&}$%w4e>b1Dcf;A0xuDBdvu?GUas}-{>=RqGAofr--mj2{62dQ{L#I zz;2^B?dJBZe;S61w(iff^WV;6?Gjq#o@J5Wl3NM#_Wa`f@8^uDp<7&>mUk$p>XYL_ z=GRI^-m)x{VhlBi4i_?82xUcE7Ob^lvi!Vr8pkSYR-r6UPrtEa+UOx0VC6SNJc=1o z9Ba`*4^sD?0d$0e`}=$3M2Lo=JZC%b$~nCBs4nzXnf0)=;;9eeNH3cikrodY_EZ12%Ex-zr z>A~r6u7~xbK>CE&S=spbMF}$2aa{b~1rgEYbF1a}GuA}paBp8Kf0&qW9^c?s)t+z} z`B_sJ9VupfkJW$=M)b{C)Vb`Nk@5grW_`uqA_jxQ7Akp+u8{v=0nsRMzblsvnvU1< ze{x}A`-idmfULc78Ma(|+foQ$kJSfcjE77NxKlZYBW05-3QPv{h)}|Nlyg}51|`UP zQr3Vw(?*8;iu#_7fySKx(Vrk}$fz!dPM0FrT5N-Xz=1y z?kw@{i(P;TZ-^I?SA&*;#;@&*PF*gprS8p0-vocCn{L~8K~yDoBYzn<`f%Tmf22!l z!*>JC@u2zyYmggWQI|N7r*hT{#AgayJ_DE+_x9_N-)Ks&LFqFnX)}MiCQkOf9zM7z z>Ao-d^DS~n1XsYp=1;tti8AW4_{K7E0!lwLEo3%VnQE^A$-PViy0oZ!z!}?7E}^caT$U4 zg59(3Ls?`EToyOEKi+2oUJNF+iO|Md!QM*9Tl{Fy@B8*a(Esg_;r&04ZSuEaDGogO zH?bV;GUe*?&Cj|i9Ed!&WLW9Lmpc(A#N)D0&J4lzI;`XMP28vl(d2Kuf5>P?+bO4{ z0FiJ+;W+W2j6}SMq;{Il>Z!*}yq3r^ZC4Q3xoL>s$wJ z;N#;Tk{q792lh8hnYO;~Y<(HGfd(o(Y?kp3GslF?pfE3;23#uxZiKKi65@U})f0z^ zOQ%{MmhhTBVDTRMfF)m?f4B_NxeQhFwJk&o#xUNRWo+A^4lb1HuMN;^{?%oHUb(^N zP~|o@!47LwZlGeR+%zL9es4WJ%pe9G!gYR8>IOkmmlS-$FDK?ZzlQmVOrN>NOXi%^ zHlWd*MK(-bi!1A14MdkFQP@cPRhDrkP2X{hp%eDu`{&}Zz$3|pe-jL(ODn+~!;Vg& zak9)$3wgC9%gN$GE9gn^R|=NML+Ub1CM7S=g3G6oV3MsaHFGW|<{TTl7V&obRbs{m zJiC23R@{ttS1*ZC4qHuGNa<@p-8O?d5$dl8s4%Zyk!k|N2Gk>r36UDrtc^5mHoU9M zyuEASJs>z`Q54kCOk6vPOOFEW z%0l$!@huBF)<}E_W;rW4oZU=(Z6<7IMW2$t?e;(Xt*>@_`vul<7BV0x&j6#YvHryd z9=3^}l*-C9QC?)Am{YVj4gvb0^+@P2oHRE;n7`E~gkSeRNZWbU&Ts(TPR#ssyn$#GC}SlYZAz~f9B zYOCa-pbg9|Js)ez5IXqS6-t z)4Qgi_iC-7zE8xY>L-^B_q_$zZpCo3QH9Gvk>tY$U9R@pgt2qU9PD1ibraeERX#RW zb*wuR1g1stF975hI^;C0#RKmPsynsLAn{#d+s#=_+) zB)H33R+9KM*Pj!{RwUUTFY*`9p_Vjjs(44B3lLP!oiTqDB-;~#Dc)vjAopq(Tn`q! zw^`tg#Qs@M{rnzEZ&u2_QlWVN$Yx0Z|TDIO3NuxqL0bVLa5uO#U90 ze{^P5?5GM>fhs|qFH8Gce8mLiBU)mEB!51GOJ7(Z26*>7 zT_&*abuIy>&u+tqgzvDPzFny!>(khvL^LIR{`$%Ul$@-k;*U>MbaAi)h-(}+1AXb{CF}Of7OVl zrr2+6s8eoUs_&Xi>{JS5Ny*J?2&G1NPF37C)G4>v){5`W-O=ue(n^$=umN0`KVm0z zd12J7aNV<^8!lo3ap24R)yZ7P*{e$JX*&o@D` zvIKd_pFvTHC?#ktAcvyTdpF>~f9dXk>m;s?lLE%vLFdm_=I%L^{V-9Nz~c(bi8`wE zl98gsL%%rpGU*$APW~B|O8@`bzP7n-BuVqTeg(ESF1mZCF`l;L zZg2EuMor1KZmgDCq}#i5aWMgrkc2Twa0t@2Cgwx`jGc&?Ki9wHD&MNIf8GF)?v1cT z63Bd>M4?cqm#oY$^LS1a*RBht`twi!1&2)kJ%tO6=Qvz!e0^Lvl)*KB#=(NLk7_<5 z&~6B;V-Q<-+uDqX*Tsiw3HwB_H#1z@NvR|y>J{1AewzmrPE|j|l@wlYuzmphX*X@x zH84ZXruIC=>h&t^gn9A+f2o9Rx`I^7#m^38PFM^#6W;-e+*=vb0+m?~EWsv*Q#Wc9 z8>?`yOtbl5nyuYZ*UNnNb!x0=DWbDb*`a>wHTTnwQpAh6sUp9Jp!I*kO0=lw;IU`ax z4(kc5enr4=-7^NJV5TW6Oy7JDPu^qO!d*Kp_M1gz6K{9*@_w8-0Zu6}rG=S=OmBth zKUpMc-^aRofA1#|xy19kcZOy!!p zx@y0$3Cw&pT(rAkc{lxAf=+2we*WnnFcoZW<;o0PfBtD55Cghuxp}N0azG9HOon(+ zx)kX%)V-x&0q$MBv#`%L^>$-g;A&am;UN|f5|YyDmZ7Eg6HY7JjerGC-bkzS zI%D;~h;orBh$N90WN(Bxt-|^%!Fd^^@v0H-Ol&lB(rjlJ2LPdU44AO3VU2C1xz-*D zH$pI_g*h8!8fTs?41TtO0@Q0_#Fj8pjubWm#~6zu94lypa3r|Ywr^)EI!+&1FlrmP zE0fmcB!AYExH7XCYa}D=(n zHj>*q5uGCm>xtj09})231rurv6^I^At)qF~B!wPDp^6?r!KSO2#5|4d$L@gI!y2{* zy<>!2EfR*q3rv_oO<{}*aM^ZUwS793T|YhrpY@X7%LXB(i}~ZbW>@#BJ1O^7fw+L; zJ%1Qh$bNGOyeX_tUqtxR(@o7YMA|ImVzW7fXxcSUrf`y5W$@z9W~kiuDX|27IK_LM znC{Ud0sQN<9-7|U3#ZM0PyTU#H=qI%^q~~_ORuWP$YH0xYG9<-TbLrkpGp^YrLw0t zhL-3>QNkFuqKMQTa%!s1hhqu)aEhB|(|@N0r_FyQPyQLbrDtX2i&EcjHg&I^EI}Vm zaa(WNu8D)I`N~SleRUv`d?F9vrKeDeThlX-bh!7j*jMu`-Y0rzZ~jV*BEA@Up^vz~Rj5>$4kFpfdOStRkGsT56-<$pR+d?owGz7Dy$LxWq&FrT@rLt@sT5e@@Aqjl{R zjLSR?BZh|YK0Efe{ib-_?KTu*qpRn8^CtdS-*v5N4R#cf0Fuwu%O}(Ad#EW2?vUBM z;Z8hyk$_@+AVKK}FlIqX1f?b5op={w;p^G#W{MV0$-;O27KT^6*;7?9Z+~&&M%o+H4LYqJ`*f z33`(NC{2ffwa}{=lQNj$P=6{AN1j&nORLX;I9_LfGiG24A3T_uFYGZP0f^!}7w#qw zlhn(4_a&rjf~_00JzylSQ7j=OD(n)$EeOS%diV2BfA_%BoN!B^c5fmFsyrRsS9nBF z=UM@zDZm+_zun0)fwNJf-c`-=;3pHNE=koro3j`$&wqQrhoL{+^aD6S zjq#9A!Q{DUQt+5dL{0w+eXtB^TQn>4diem398D+N6Gt<*C96X;sZRDi7PB<0w!wxX zsSIMNAJrVUA7I3)Ng+!tk+T5LBeek$Q2;{5M^5(BnY0oLRz0JgfI(4)KITU&sb!6{XIMj&{3x3*7+Ri3i^G8Lyt#KFEaw znGuNX7~lp#L~;&3Df|(3=^i5=JIX5EITai|aAM&R7I8=t*(t7~34V@!gS--@M0iz` z%<4OT4Lk!ok4*K26ZA|)+_SbcgT3<1sJ{Yrmz5|7jJD~Znxdf<1W}Jdl^qUc>&&aAKRd< zpLeJA?LFk4?jYqAZsyysR!>I|3qVN#GY{{?t-&waIbf>gcX?r+w{zSyM?wDluqz9H zea^S8iG!{9(m8xHPJ-=aHt8HXZ$dIwcPc0cd)!Mjht8Xj*;VPCWg#{3eAyU#{*>I# z6_Syx-Q47>YEbd>?L`wI{!HnQEd_B6R`TZ&geIuxk8M9BO28kj2K#0XDKL0%289+w zgal(R+HUJ1Szk2-#qDv!cqC>OG|E_ivy|Lr(j1&?@5dk!{Hrxr?K;kM5bBB$e`B;`V@*ivro_|KrW>|@?t**@Bbk+|y~i^JXYccN?#=#~-vPz#B%a#=DLt=a zgb*pO4QE73EpwZneGA-HT`g@JmF%Lnkq?%$F|d`)lYrB(o%4W+J#ZcVSUo`~yTyY{ z>OEAOAT{9|1i5h_GW{_#Ag=-BUG-#R+948e|Jy()J0E(aN%g0CJ8!ywx_JKLXk!GU zG#D2SZ=?kjL5wGmz=hgQ!okcZI8sOZg%7Z8lnn$ZTT|~brxn*_V*>!fR^gG?gUdpu zH-s_W>aHtFGZKNQN*F8b*z3S}SCCDeQ6Uta!Gx8!;@$P_ABxNGi<{f)SGO0_sbM_7 zF228>6>p~(C(CADuVIIO@u~e5SRseSn^&ali4({a-@!WNq6xbpkU74y>ydbVLZ7T< z2C}Of%+D(-k(c%>t4osM)gA+p?>W8lqUq-QRQPBGD>;RYYDua%DW+8=o$%G$^9(wh zfq%11bQTX-dDCPjR%<*ZEAqyEW%c&{zL_^Fw{kzfh?g$OCx~Bv3(AE?5ei)7Gxg_w zPo=9er)K*d%TQAdhpFmmfcr;Rp88d}oB+V`HA0 zO$APQQgkkr5#=!+x-x}f%hO_TvSh)SDZYz-KC!Tk@}g^QJUfHGC(CyJzN76_n`OPL z3pKST?>3a7u4i(87xNo9uQpO4P^qT&GKy+EV zL|)=oiTosuBP_IMqnewN?fwLAeLW1c4TNM%lAXl*j4X2*bb&ccnZY2bbFJfWXf|sQ zh~~g7lG0)*_?wG{q@X}d1w(q{X(_0F1X2`v3{ZjmWGHrjEp2S991dnJLUWu}X|*8E z1zDHCWL|TG+^xUtbja$|Y_Z}sETmO-Is!IpU9XFCJc}M15h^oh6B8&NEpwxC3=qO! z_B9RPa_Uy#2mZo}@@%1ZomBsdia&=X4=_6I$)i+Z;oB~20#6wC=28;gKbpXaOzl@z z|6qm#i*XNsA&UCX;E$2^2?e8GK6(C!^LE*8<%!21;$@j!P`VNfHFPlFmy-HYw#vZ~ z@wpVBNuH$7HaX?_L=wnBrsXNDsy84))n3DByMy`K9cT$W!K`@YK>D~~fn(WL3yP!D zJ$&_bv8v4r`oP;GFchYzgD{2&a-D>f)JAgZm%KD8g@iR8xIEAo!+H<>*ZNV znmsy)cm1)wdhk8@(9(l#4_{vm|*8C3~!mpg9w`jxC z#U#*wPC~c)-67Z_Zo#d-hmKBhs_SRfSZII@ee6_MQ`AdQe;MFk3qC`6#@NaA0ahnx zXWKm-^?d+IORAGTTK6!7VkFFePYa@RW1a@;evGXdq$U|OYz?^~v}uTzptOu*D~zY+ z>J3p&BeXmvXY)PqT7Bij>MkgXVw_z2lyiz5FR2?Z4jv z-`ETG3GI~zj3X}b(EFWIPG4~U{Z1Qk)a6I_J8ed~FvwrnZ!Sl)Ipi$tHIpT(%`$iq zY1BxMWDQ$qN1H@Ef$WNLkc7=sDJRHL<4Sx6AzT74lybqI`ac63=^U4`w^A(fzDNiV zPH`BquXrF0#b(6br?2_elZx^rf7RS}9|;NKQQ98Ao)56wtt7;cs-;z(^Z{!N?3@QW zv2afLUSd1_fgUleah`zDG}ed#aHoP%`K}@$7;E4z9n<^p%XI)*6ro?^->eP?Dj87C zP1)q(DxqsSy1=X&c0zTjO>=;n)jbxS86VV(Rc%IkPjp8)A9gRjdpIKff0FgxV=_gN zD-^j>6esHjr#2TKpaN0KiGa3o^Oh`yc`D4KpmZ3Aqo-k@B0Q4C;<#xT_lP7Xp)OubqN9*HSTe-BYMHqZ`F>%>Xg zJgfP7nBk;%vf;XKVnH-jb`ea`Y-j!3buoriyM z{T)t@8T?ELUJt^FtB|`>4}+uaw(BKEB&c`$&FOsE?iarea7kba0x~axQWN|L0B9=; zzE&kyfkamxLba+cld1G~f1_1>RQgfik0DU4$fpZD9YEshJy`xv(!e4E z_XEh05jp9l3?+=xV3ZUq0x?RBaVtdA>6?P0ejo(;Hn31=8dh6*e>ew?z(+x(Z#`un zSS^{@m)EL-fkj^-!wi68oNHn6m01s3yTo$I&Hi?Ck9EIAc1Qj<(rt1t5U$ zmV<~!#M~=i&orLvda$8jsTqFw05m$Y4Fub*Ro6Ivxy}%vqu(7)SPGtgy_aN`PDFdzV z`caYjVKv{_4*eS1j=y=rxb(1&k~&x$K;I4*)|6A(nF88)w0Lzjxe0l2MdR7E&x2M) z7W}QyL>XHmW=|(#`x_cn%C1Y`HUBf%aK`)~DU0#UEzkU|SapjHe@-K9Q;E$SlC#fh zm!Ml}U1#UBOT}?DJ-^W$XiryDb`bK>b1y+rW6U znb$DEw4N{babUcg9N7POKFPz`!GT~-?AN2sGwouKL2$ia-9>}z&omfV{2YeDGU+kl zxQntI5pY(s{sk{YI*AtfBA`0X;D=>l=^e zI8$vrJXg7XF>?jmDHYcd-En5Kl6{9erGk|3^#DqRRr=*FENgOJQTPtB__(t9%f5lv z%`aa25ZBedA3U1lOoap|zc!M;pp^hw5~P41Y1?kwY&OyG@3U;PkW=|~oNbs3zS`Dt zZTj6WXDz0Of3LQ6tW4?P)BHzXP`iC^ClIBt^%A?*EMl^OB@!;G~mioTYFSPdj<%jUb>82r|RuC^4lM#KW&!ne^#1Uw>R=`8|68;=|z$SVute;4+QSQ zBfId)hAcIghwJ8h&PH&bUX>kVr8$oa>ICIhKRejalqMOn&bz_ZU1Ec-2_M_TP3))h z?{`EuWURi`9W-l)+ox|YLCn-G#Uq1OK<-kBt*laz#2ZOQ8N_H9y4j*h8gWfE@u`N) ze@tdFJ>0&5q^27D1X2y57Z%T=L#KOH?aYvC0r3%V?iwQJG43~EWB z==)RGl8hC8;wp>=efb#{$yL2y!s8pY5HitTF>orO3=)sQYlK;c|hT$k32k|r$eFy ze-r7L2}*e_frD)_6_rMV33f^$thBG3imc`A_zGyO5T`hqdm25N_BOgSQ38E%J z+>Zt1pxB~&IZsbwiSB8F<39G#;7Ch0f24@PI7bZUZq8Gm0#sU{GsiL!mIm==21p)&`;OtK6;W-V&dk9*SAfXCw|)2SUWj=+>n=v=A5&Ij0f4W)EU z0An6;Y}oKjVRX`aod>P8h|r*56N{%ygJ>6e&&Tlg*bP3FocrLgN(kTgUL!JHuxssFNE0_F#+pFVBkwXBzk;3O|b<#)t#_^ASbvHjLm^p)U&~9^M8C zlPg&CpW%mx@NS1Wdn_hLa4AFde-zlSKc_a6-?f5Ltp)@jUAX-hWE+G8|M>NodA zV?@_qnnxa7*1muQ7TxZP-yLKwPTe>6Wn-|7nI%A#ghX@qhUU`T`1Q{}{oNb^qMv{I z$D6a+#dP-bPyhVgiD|Rydfh#?yHoeoH(_dz+oX3Q=T4na;|H6Us->Nhe@@N4Oi56h zR+Oe$ZI(XQ2p2TV;?Q|d6Lf+2U@tuHi-I1Nh@Wc=7PkayBXxx{vWp^>2GC`Rb0;RMG97goi<>)-jdw@S@x0phvJ*h*0ni(wqs9RNUXP)1e^$Y`o$lPSedxUn zAW1hKCI8?lIzai-2W4gCuvXtuXp{S9TYrqwEr&Qeijrc5r=hw-hDneL!are%(IsXC zOsw?z3^40bK}0E1DxK2X9NY|53S0t>J+D!Asx?n|pS=Wg zYwX&oge^!-*6{XwFSJ`@*J5qt0@9oWz*7&{88DEq*yoJ%6<Oz&c$Zc9Tv2DSu0H^90KRk{ib{@vvSom6oRz9vI3H zkL+GA&VB)7lZ60zdLC&>6OR=1?gwvyHXUm^dzAtu;H5x8?GdOmOUTL|p+uujSV~PW z-c=Y0tJyxWoQ4I5nCvidKpwO5;6ZYYWKEE3p>ak2B6PH~wY4?Ap`)zV@y^zEEErWV zFMslxOPmss4%jQDe5h%nH;qbbfRKH3@HK(m!i{N@;$Fv~0qg;UOS2khI!JW_JK-yc z8DcAKRYa%0CpCsWzruS3E`-WwWTTzn!Suct{Dm;af3? zZsqX=<|b1ZPoppX$-DahY`x3hR3Bk#6S_aRPX#y4yX>IuSU{olZmdj@CR8b($A5r1 zZt`4$HFGm;JBD8aXdAB5z&ShMYa*vlAG1@rk#BwI__cUnKOIPczf07+@nD9@Fm=&U zbgX$3K;xAtWeF_ql%9wtMqDCI<6q4yQw7`jCz8*!#$|dT;#`qF+i$4hF8^pX4%mn?mzDuP?%J4bqTltp6gpcu< zB7H00l9Dd5jJ=P^dHYF;Xl~>s|Fp*3TB?YO{oih3tBF zjvJA9ZLK7v5|F&5?dcdkuycoA$h4RXZbx2}Ht;U0wsjS^N1%4OE?E?xr?FkMMzA3{iJD_^VIbkEWERx{8c7MWlz(96@5QQFH<3qI zj?)6L(xnfQ=E=FF=Sgx~Y7+39Wwl=G+c=6sw4_cHHyY+DeI;}V)&%I9$CAZRENU*U z08u2|RSy!8^ch5e!7v1H&?lLhBVG_vku6b{qK`hi6#x)t=&qxP0uYQb56V&{Nu7C0 z1f(ad@5#ciaL*pN^MCUCtjf9Zb&g6;W8b6o*mN-r^~`kY4v%(bY0ng`O7HPC8S4k` z6jxImR#%u4eGONTGtrOVDek5?RaZZadj3EE*O*!&vbLuDhbT{^wlv^LC9$rn zyLP`T=vWAh2fg^#C|!#58S0W)i0l0t#Py{;fdKd8qiMb%BO-5tIE)9hG4~;Fzwou+ z1=xWd?ObP+H$TY>XV%W)+^L+m{37wMa0aFJ+ci()&D+&owc~&6Qm6E*NQa=BIjsq4 zO;OA4eSt$(b>c$}a$*jxYKJL{5>CRS$SsD;g_Hr$n^S+B09u`3^=MWI9FOy>obQpA==7vkR7~d&MMDB zxDzW=Jz&087`CoAkd|IV-H8HDga)wsnN$D%X3_-)1mMmNrv@>aJ7*4tg2tVHt9|!q zUiR;69750{anA(N86#v{X# z_PV{83drrjd}R-gG|Hf)CKe8`#vt(Y!bIbZ;qQCU#_@ZPS@>)X^TRv^Hr!@JSw*`; zMjIh8rNB%ghz8oy6u=8b=gJb!jw{JWGe#=DfCv#^ zKsfr3_B}LjxAk!~6Cg`KglP94?JI@=UjyIIKm7yF|NPTG6PzQAUeQKyDdGjp+V1b~ zi;~(&IQBWMGr`;PUO@H&18)xq_LVaOioVB;5!aXJ1_2L$S@%nJK|O}sI%6`%)Qe#} z=7z%l77RnfZTT@)Fh(gDGaqw|6>!(gRczXi_4c!B5V>s-ik)VVdrj_R8M6&>h-Ih|3Hq8U0{K-k-}#}DAm zAiE*}C5P-NEJ@B=o>psPa7EKGxQQkm=ERz0r!~u$2E|M8prB~)jtz5i7LdHOmz)Oy zXMf~i-lV{XEJE*pn3XWyQrabdggpXMDv+xfc*qv1mW?D!Kim?Az&)M>@q+^;M~fjV z+K`0cJ284jZyqRO@L33;puH>53;eUqp(z!R0D?$TdQw~|}-N(AdXBt;PVL?=x zDkr7aP-P9B2@EcZ7eI)cu%TXawiRgUmv!|)Mh~Pn#t?zPcYg>& z;JAb!E_xYKCfP~kQS4UQPCh3v^MNliu&IC-_#*)hd4H^nlgd&zj)}F=-KkU=>M$gC z8aH9X%Eck0Vqdi%>QVeF7v79&5o%tg@DjZCIhG@%I3pbQn2Mm|!YG)2*h6@}H_PfN zL-r0eE~7YyR_zsk=_Qf)C5Lf{7JtVi>1F5}isbM~=X-zfk-#?H1#(afT?cqqtFL>Y z5dt2%7|7n*0Q`r8Z0Wr$Ti*yd?_V@{4LvNbHlnichSX=>etle}ae8m%o8{@8|63BY z^Bvu+YnuY#)T1TGH^m56_G~XICm^LzsTdZ^=}iRnC8AC}RF8cPq2UI2NPlKRpIRF| zMQk4iW6R}&|AnBaYR6z0&Q7ULdXbe0;<*WZssCHUhNb%dVHAOWdhx`DE)!|7(uKym zV7#{-uIgJ-@-nMo!&EcxM&2%RF%uS{3FFwD)GUDk!7Ik$KmZIU`A+MdsEQ~)BX%&X zT=0B&r{lSg$l+2co@FsTYVmOD=MgFPZSoQPgygxIfe6yia_-b789a}4(cItH+Zqz0 z-_-Jn8B7BQ(PSl?kH!L-uTdrEu9F@YuHRhe}1smn453B6#>PbMYjD(R||_(uf*1pjz#R44y~YeXKU4 zs~ZTbN;dU$J=pQ)Ysp#0$o*zPwYmP((8_=_0{a2$`5=#Al!Bq2c!%+J4AaSey)bW~ z9eehGPusS1UXz|3Z+|_}35xpOljt=$0ExfJjksB-_f-rNDOBiy+6V*Sw2AWMFx=QZ z?|GwG_nQK(gNN3710Gn#DH<4jTcGAy7Bok$mT)n+ z9cQ?>uexX}jrM>##m zlCTzMDz#MS3`VIx(}eIcrwq?(pzsy!Ewa7jug97JJqF4wt%f8Xlz%l1XkQJ`rVW-o zREORO*$Nch5CNPdZw&mf57PjZR>af7(F4gtaQ}gT4YkYe5V}%uya$kR-i{;;%ffqx4kG7@G8FGzpM5LX_74XQE4vq_8EZC%j#lOdQOT1(9uWDrUk zh!R4n5UzUQQ|7oW#~8jOozx&_iB%>*t9+XVP4V0Ay7hnMFu3wUz;G*)8Df-Gmc=^V z5~O`g0HkE9aJ~4@fQy6yy;tBuAs=R@g>trFNEi@J6Pg>k(0?6@MZKv_XK_7m#+MOe z*h29z-dc)_1jPw80jvEdPOJ`n)M|?xOE57WISy~yWit=f6R?3OuipL#X--*_rv|io z$?E3`%&Y;_teNAS&7F@QU_%C(TQ;La$fCrS?6%d1#zwoqA1Tfmp7EMdk|lIHePRaw z7+nz?^LFWCL4RQdGq2I$dVXa23CRahp|IYd(j>x(smyD#p(ppg`9!H$lD*b6r`0Y| zTgRrGB#@=!+G7Qp8pmZCqQ{FywMl@5F`HsS{9N+gqb0&IgjTJzYLf(3M0n2$Ajg+2 zYuNI9$q2bJe1Kj-v*9`TZ8Hz2ppq;P@QOBCG_g-wuYWFQAyUM~Qb*gO^R4-`~zzgNvJhJUQKelc$Lcc#@|K8>Lw zWp#6`@_$t0PB5w)pNdU@b+d0zVIcBecXFStXu@DyZ`!VjV;rYVf+f0dVf^#n8*36) zsj#L@`*M&rYq6|Zj=V8snxyi;o5Mhozax2vK<4?W>6f=_4v~HzO^xRXpO>ge_XriI z3^?%tv&0l*9^-*OgZK^2QcV-Un05TsKj+}~6ikAgz|`CX3|ggB4DoqPJk`Y6(t2@f z1A5l5>n8Rx$eZ}W#tf}XQJpgABm|AzT5g>4S)vUG_YI1<%y3y;Dd+ z{XvaOV3a((Pw<_Av%8>5x8IMaKrJR+Ka9nbTL#ZYlJ}TT^UE-iT+FMDkueVle=!74 zejdsrFNdbLVV1ch=u$Xf&iTpDPN^?X88ow&NiDq=A5_W5NR$ZTb2qN`QytP)papnG2W;W-ZXQ_ zgn7^-Vs&o#OCDavKkXf)>BAW9yZU|o#JNLETeYLieGhH>5H4HxTfu`QLdNLuh|Kv# z0GZMVGO`SyuEmn6k^e)&l2<4{a7oYYkWPGcb?R1Jf0L*e&Afu$kGuuxz}m~BAg>ZH zN}c)@mo0>aH#%W8pB`%AxwUZMvdzebdvNGuPyM!CTX6Syb?^ng5N8DR=BGZ|t}VG2 zzOv(~GsnsuGR2xV+O^|HKVB9>KVmb5JL)mR&ehR2fVQTG?%7yoaI*Z|9(4{JJu#DU zM0^blUNxjfOxhxR`Q-*r+9>FyMdPR}OJLfMI-m_&cTXvR<2+4}Tq|-@08?JFMmkB8 zsD;^?-qCTN6Bi3j&n$LTkBM+uP-L%^q7SJ(6S>97bkKcx?V-qR2%gpo z>;VWE?EAL)Mx|+dyYBZ}oS4ZztG*2^e{LVwm%h4>t=->;fVCo47TuOnrG|ADc;lNF zA{3|j+AfP1+XV!0Yv;T6uHJrAJpawN{~mEg`nEt3q%67ZnO;# z=0@)3kA-RZisvu5JT`5&D@NPF5T$`ApTEG;C;_2-Uc6%T{}ZE+H|HDD`1Z5y`8H{f z!1o(u?sf6)i^J-R7-DqGZ^;mA!L`CmGdBweQ3fjrRdK(EhP$wG#lyZCYX#!qszp^2 zPU-lUa1;R*f7bV?u!#EZq{*Fq?%-JN6rdAVfQ~xVPs{ZI=y0~5CLMxF7E#g4!n~rZ zHcjyrHXM>V<x!@V%d>wQHjeXUGepUn_7e2Y1Xq})v4eqnvFgAYrA&2j)EO(&DwPA z8r%$o?Y5DPI*5M+ea|f{*b%2d@a@1LZx3K(Bk^yRozCI`Pd>MiC{)#Zh5jg-;-d8b I0jJis9+2`LGXMYp diff --git a/docs/0.9.5/py-modindex.html b/docs/0.9.5/py-modindex.html index fe561435b2..4062d5f193 100644 --- a/docs/0.9.5/py-modindex.html +++ b/docs/0.9.5/py-modindex.html @@ -66,11 +66,6 @@
            evennia.accounts.accounts
            - evennia.accounts.admin -
            @@ -201,16 +196,6 @@     evennia.comms
            - evennia.comms.admin -
            - evennia.comms.channelhandler -
            @@ -441,21 +426,11 @@     evennia.contrib.tutorial_examples.bodyfunctions
            - evennia.contrib.tutorial_examples.cmdset_red_button -
            evennia.contrib.tutorial_examples.red_button
            - evennia.contrib.tutorial_examples.red_button_scripts -
            @@ -501,11 +476,6 @@     evennia.help
            - evennia.help.admin -
            @@ -536,11 +506,6 @@     evennia.objects
            - evennia.objects.admin -
            @@ -586,11 +551,6 @@     evennia.scripts
            - evennia.scripts.admin -
            @@ -631,11 +591,6 @@     evennia.server
            - evennia.server.admin -
            @@ -716,6 +671,31 @@     evennia.server.portal.irc
            + evennia.server.portal.mccp +
            + evennia.server.portal.mssp +
            + evennia.server.portal.mxp +
            + evennia.server.portal.naws +
            + evennia.server.portal.portal +
            @@ -731,6 +711,41 @@     evennia.server.portal.ssh
            + evennia.server.portal.ssl +
            + evennia.server.portal.suppress_ga +
            + evennia.server.portal.telnet +
            + evennia.server.portal.telnet_oob +
            + evennia.server.portal.telnet_ssl +
            + evennia.server.portal.tests +
            + evennia.server.portal.ttype +
            @@ -831,11 +846,6 @@     evennia.typeclasses
            - evennia.typeclasses.admin -
            @@ -936,11 +946,6 @@     evennia.utils.idmapper.tests
            - evennia.utils.inlinefuncs -
            @@ -1051,11 +1056,6 @@     evennia.web.website.templatetags
            - evennia.web.website.templatetags.addclass -
            @@ -1109,7 +1109,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        diff --git a/docs/0.9.5/search.html b/docs/0.9.5/search.html index 81d912c9aa..13e7db178b 100644 --- a/docs/0.9.5/search.html +++ b/docs/0.9.5/search.html @@ -88,7 +88,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        diff --git a/docs/0.9.5/searchindex.js b/docs/0.9.5/searchindex.js index 67d4376429..0de7d8c73b 100644 --- a/docs/0.9.5/searchindex.js +++ b/docs/0.9.5/searchindex.js @@ -1 +1 @@ -Search.setIndex({docnames:["A-voice-operated-elevator-using-events","API-refactoring","Accounts","Add-a-simple-new-web-page","Add-a-wiki-on-your-website","Adding-Command-Tutorial","Adding-Object-Typeclass-Tutorial","Administrative-Docs","Apache-Config","Arxcode-installing-help","Async-Process","Attributes","Banning","Batch-Code-Processor","Batch-Command-Processor","Batch-Processors","Bootstrap-&-Evennia","Bootstrap-Components-and-Utilities","Builder-Docs","Building-Permissions","Building-Quickstart","Building-a-mech-tutorial","Building-menus","Choosing-An-SQL-Server","Client-Support-Grid","Coding-FAQ","Coding-Introduction","Coding-Utils","Command-Cooldown","Command-Duration","Command-Prompt","Command-Sets","Command-System","Commands","Communications","Connection-Screen","Continuous-Integration","Contributing","Contributing-Docs","Coordinates","Custom-Protocols","Customize-channels","Debugging","Default-Command-Help","Default-Exit-Errors","Developer-Central","Dialogues-in-events","Directory-Overview","Docs-refactoring","Dynamic-In-Game-Map","EvEditor","EvMenu","EvMore","Evennia-API","Evennia-Game-Index","Evennia-Introduction","Evennia-for-Diku-Users","Evennia-for-MUSH-Users","Evennia-for-roleplaying-sessions","Execute-Python-Code","First-Steps-Coding","Game-Planning","Gametime-Tutorial","Getting-Started","Glossary","Grapevine","Guest-Logins","HAProxy-Config","Help-System","Help-System-Tutorial","How-To-Get-And-Give-Help","How-to-connect-Evennia-to-Twitter","IRC","Implementing-a-game-rule-system","Inputfuncs","Installing-on-Android","Internationalization","Learn-Python-for-Evennia-The-Hard-Way","Licensing","Links","Locks","Manually-Configuring-Color","Mass-and-weight-for-objects","Messagepath","MonitorHandler","NPC-shop-Tutorial","New-Models","Nicks","OOB","Objects","Online-Setup","Parsing-command-arguments,-theory-and-best-practices","Portal-And-Server","Profiling","Python-3","Python-basic-introduction","Python-basic-tutorial-part-two","Quirks","RSS","Roadmap","Running-Evennia-in-Docker","Screenshot","Scripts","Security","Server-Conf","Sessions","Setting-up-PyCharm","Signals","Soft-Code","Spawner-and-Prototypes","Start-Stop-Reload","Static-In-Game-Map","Tags","Text-Encodings","TextTags","TickerHandler","Turn-based-Combat-System","Tutorial-Aggressive-NPCs","Tutorial-NPCs-listening","Tutorial-Searching-For-Objects","Tutorial-Tweeting-Game-Stats","Tutorial-Vehicles","Tutorial-World-Introduction","Tutorial-for-basic-MUSH-like-game","Tutorials","Typeclasses","Understanding-Color-Tags","Unit-Testing","Updating-Your-Game","Using-MUX-as-a-Standard","Using-Travis","Version-Control","Weather-Tutorial","Web-Character-Generation","Web-Character-View-Tutorial","Web-Features","Web-Tutorial","Webclient","Webclient-brainstorm","Wiki-Index","Zones","api/evennia","api/evennia-api","api/evennia.accounts","api/evennia.accounts.accounts","api/evennia.accounts.admin","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.admin","api/evennia.comms.channelhandler","api/evennia.comms.comms","api/evennia.comms.managers","api/evennia.comms.models","api/evennia.contrib","api/evennia.contrib.barter","api/evennia.contrib.building_menu","api/evennia.contrib.chargen","api/evennia.contrib.clothing","api/evennia.contrib.color_markups","api/evennia.contrib.custom_gametime","api/evennia.contrib.dice","api/evennia.contrib.email_login","api/evennia.contrib.extended_room","api/evennia.contrib.fieldfill","api/evennia.contrib.gendersub","api/evennia.contrib.health_bar","api/evennia.contrib.ingame_python","api/evennia.contrib.ingame_python.callbackhandler","api/evennia.contrib.ingame_python.commands","api/evennia.contrib.ingame_python.eventfuncs","api/evennia.contrib.ingame_python.scripts","api/evennia.contrib.ingame_python.tests","api/evennia.contrib.ingame_python.typeclasses","api/evennia.contrib.ingame_python.utils","api/evennia.contrib.mail","api/evennia.contrib.mapbuilder","api/evennia.contrib.menu_login","api/evennia.contrib.multidescer","api/evennia.contrib.puzzles","api/evennia.contrib.random_string_generator","api/evennia.contrib.rplanguage","api/evennia.contrib.rpsystem","api/evennia.contrib.security","api/evennia.contrib.security.auditing","api/evennia.contrib.security.auditing.outputs","api/evennia.contrib.security.auditing.server","api/evennia.contrib.security.auditing.tests","api/evennia.contrib.simpledoor","api/evennia.contrib.slow_exit","api/evennia.contrib.talking_npc","api/evennia.contrib.tree_select","api/evennia.contrib.turnbattle","api/evennia.contrib.turnbattle.tb_basic","api/evennia.contrib.turnbattle.tb_equip","api/evennia.contrib.turnbattle.tb_items","api/evennia.contrib.turnbattle.tb_magic","api/evennia.contrib.turnbattle.tb_range","api/evennia.contrib.tutorial_examples","api/evennia.contrib.tutorial_examples.bodyfunctions","api/evennia.contrib.tutorial_examples.cmdset_red_button","api/evennia.contrib.tutorial_examples.example_batch_code","api/evennia.contrib.tutorial_examples.red_button","api/evennia.contrib.tutorial_examples.red_button_scripts","api/evennia.contrib.tutorial_examples.tests","api/evennia.contrib.tutorial_world","api/evennia.contrib.tutorial_world.intro_menu","api/evennia.contrib.tutorial_world.mob","api/evennia.contrib.tutorial_world.objects","api/evennia.contrib.tutorial_world.rooms","api/evennia.contrib.unixcommand","api/evennia.contrib.wilderness","api/evennia.help","api/evennia.help.admin","api/evennia.help.manager","api/evennia.help.models","api/evennia.locks","api/evennia.locks.lockfuncs","api/evennia.locks.lockhandler","api/evennia.objects","api/evennia.objects.admin","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.admin","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.admin","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.admin","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.gametime","api/evennia.utils.idmapper","api/evennia.utils.idmapper.manager","api/evennia.utils.idmapper.models","api/evennia.utils.idmapper.tests","api/evennia.utils.inlinefuncs","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.web","api/evennia.web.urls","api/evennia.web.utils","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.templatetags","api/evennia.web.website.templatetags.addclass","api/evennia.web.website.tests","api/evennia.web.website.urls","api/evennia.web.website.views","index","toc"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":3,"sphinx.domains.index":1,"sphinx.domains.javascript":2,"sphinx.domains.math":2,"sphinx.domains.python":2,"sphinx.domains.rst":2,"sphinx.domains.std":1,"sphinx.ext.todo":2,"sphinx.ext.viewcode":1,sphinx:56},filenames:["A-voice-operated-elevator-using-events.md","API-refactoring.md","Accounts.md","Add-a-simple-new-web-page.md","Add-a-wiki-on-your-website.md","Adding-Command-Tutorial.md","Adding-Object-Typeclass-Tutorial.md","Administrative-Docs.md","Apache-Config.md","Arxcode-installing-help.md","Async-Process.md","Attributes.md","Banning.md","Batch-Code-Processor.md","Batch-Command-Processor.md","Batch-Processors.md","Bootstrap-&-Evennia.md","Bootstrap-Components-and-Utilities.md","Builder-Docs.md","Building-Permissions.md","Building-Quickstart.md","Building-a-mech-tutorial.md","Building-menus.md","Choosing-An-SQL-Server.md","Client-Support-Grid.md","Coding-FAQ.md","Coding-Introduction.md","Coding-Utils.md","Command-Cooldown.md","Command-Duration.md","Command-Prompt.md","Command-Sets.md","Command-System.md","Commands.md","Communications.md","Connection-Screen.md","Continuous-Integration.md","Contributing.md","Contributing-Docs.md","Coordinates.md","Custom-Protocols.md","Customize-channels.md","Debugging.md","Default-Command-Help.md","Default-Exit-Errors.md","Developer-Central.md","Dialogues-in-events.md","Directory-Overview.md","Docs-refactoring.md","Dynamic-In-Game-Map.md","EvEditor.md","EvMenu.md","EvMore.md","Evennia-API.md","Evennia-Game-Index.md","Evennia-Introduction.md","Evennia-for-Diku-Users.md","Evennia-for-MUSH-Users.md","Evennia-for-roleplaying-sessions.md","Execute-Python-Code.md","First-Steps-Coding.md","Game-Planning.md","Gametime-Tutorial.md","Getting-Started.md","Glossary.md","Grapevine.md","Guest-Logins.md","HAProxy-Config.md","Help-System.md","Help-System-Tutorial.md","How-To-Get-And-Give-Help.md","How-to-connect-Evennia-to-Twitter.md","IRC.md","Implementing-a-game-rule-system.md","Inputfuncs.md","Installing-on-Android.md","Internationalization.md","Learn-Python-for-Evennia-The-Hard-Way.md","Licensing.md","Links.md","Locks.md","Manually-Configuring-Color.md","Mass-and-weight-for-objects.md","Messagepath.md","MonitorHandler.md","NPC-shop-Tutorial.md","New-Models.md","Nicks.md","OOB.md","Objects.md","Online-Setup.md","Parsing-command-arguments,-theory-and-best-practices.md","Portal-And-Server.md","Profiling.md","Python-3.md","Python-basic-introduction.md","Python-basic-tutorial-part-two.md","Quirks.md","RSS.md","Roadmap.md","Running-Evennia-in-Docker.md","Screenshot.md","Scripts.md","Security.md","Server-Conf.md","Sessions.md","Setting-up-PyCharm.md","Signals.md","Soft-Code.md","Spawner-and-Prototypes.md","Start-Stop-Reload.md","Static-In-Game-Map.md","Tags.md","Text-Encodings.md","TextTags.md","TickerHandler.md","Turn-based-Combat-System.md","Tutorial-Aggressive-NPCs.md","Tutorial-NPCs-listening.md","Tutorial-Searching-For-Objects.md","Tutorial-Tweeting-Game-Stats.md","Tutorial-Vehicles.md","Tutorial-World-Introduction.md","Tutorial-for-basic-MUSH-like-game.md","Tutorials.md","Typeclasses.md","Understanding-Color-Tags.md","Unit-Testing.md","Updating-Your-Game.md","Using-MUX-as-a-Standard.md","Using-Travis.md","Version-Control.md","Weather-Tutorial.md","Web-Character-Generation.md","Web-Character-View-Tutorial.md","Web-Features.md","Web-Tutorial.md","Webclient.md","Webclient-brainstorm.md","Wiki-Index.md","Zones.md","api/evennia.rst","api/evennia-api.rst","api/evennia.accounts.rst","api/evennia.accounts.accounts.rst","api/evennia.accounts.admin.rst","api/evennia.accounts.bots.rst","api/evennia.accounts.manager.rst","api/evennia.accounts.models.rst","api/evennia.commands.rst","api/evennia.commands.cmdhandler.rst","api/evennia.commands.cmdparser.rst","api/evennia.commands.cmdset.rst","api/evennia.commands.cmdsethandler.rst","api/evennia.commands.command.rst","api/evennia.commands.default.rst","api/evennia.commands.default.account.rst","api/evennia.commands.default.admin.rst","api/evennia.commands.default.batchprocess.rst","api/evennia.commands.default.building.rst","api/evennia.commands.default.cmdset_account.rst","api/evennia.commands.default.cmdset_character.rst","api/evennia.commands.default.cmdset_session.rst","api/evennia.commands.default.cmdset_unloggedin.rst","api/evennia.commands.default.comms.rst","api/evennia.commands.default.general.rst","api/evennia.commands.default.help.rst","api/evennia.commands.default.muxcommand.rst","api/evennia.commands.default.syscommands.rst","api/evennia.commands.default.system.rst","api/evennia.commands.default.tests.rst","api/evennia.commands.default.unloggedin.rst","api/evennia.comms.rst","api/evennia.comms.admin.rst","api/evennia.comms.channelhandler.rst","api/evennia.comms.comms.rst","api/evennia.comms.managers.rst","api/evennia.comms.models.rst","api/evennia.contrib.rst","api/evennia.contrib.barter.rst","api/evennia.contrib.building_menu.rst","api/evennia.contrib.chargen.rst","api/evennia.contrib.clothing.rst","api/evennia.contrib.color_markups.rst","api/evennia.contrib.custom_gametime.rst","api/evennia.contrib.dice.rst","api/evennia.contrib.email_login.rst","api/evennia.contrib.extended_room.rst","api/evennia.contrib.fieldfill.rst","api/evennia.contrib.gendersub.rst","api/evennia.contrib.health_bar.rst","api/evennia.contrib.ingame_python.rst","api/evennia.contrib.ingame_python.callbackhandler.rst","api/evennia.contrib.ingame_python.commands.rst","api/evennia.contrib.ingame_python.eventfuncs.rst","api/evennia.contrib.ingame_python.scripts.rst","api/evennia.contrib.ingame_python.tests.rst","api/evennia.contrib.ingame_python.typeclasses.rst","api/evennia.contrib.ingame_python.utils.rst","api/evennia.contrib.mail.rst","api/evennia.contrib.mapbuilder.rst","api/evennia.contrib.menu_login.rst","api/evennia.contrib.multidescer.rst","api/evennia.contrib.puzzles.rst","api/evennia.contrib.random_string_generator.rst","api/evennia.contrib.rplanguage.rst","api/evennia.contrib.rpsystem.rst","api/evennia.contrib.security.rst","api/evennia.contrib.security.auditing.rst","api/evennia.contrib.security.auditing.outputs.rst","api/evennia.contrib.security.auditing.server.rst","api/evennia.contrib.security.auditing.tests.rst","api/evennia.contrib.simpledoor.rst","api/evennia.contrib.slow_exit.rst","api/evennia.contrib.talking_npc.rst","api/evennia.contrib.tree_select.rst","api/evennia.contrib.turnbattle.rst","api/evennia.contrib.turnbattle.tb_basic.rst","api/evennia.contrib.turnbattle.tb_equip.rst","api/evennia.contrib.turnbattle.tb_items.rst","api/evennia.contrib.turnbattle.tb_magic.rst","api/evennia.contrib.turnbattle.tb_range.rst","api/evennia.contrib.tutorial_examples.rst","api/evennia.contrib.tutorial_examples.bodyfunctions.rst","api/evennia.contrib.tutorial_examples.cmdset_red_button.rst","api/evennia.contrib.tutorial_examples.example_batch_code.rst","api/evennia.contrib.tutorial_examples.red_button.rst","api/evennia.contrib.tutorial_examples.red_button_scripts.rst","api/evennia.contrib.tutorial_examples.tests.rst","api/evennia.contrib.tutorial_world.rst","api/evennia.contrib.tutorial_world.intro_menu.rst","api/evennia.contrib.tutorial_world.mob.rst","api/evennia.contrib.tutorial_world.objects.rst","api/evennia.contrib.tutorial_world.rooms.rst","api/evennia.contrib.unixcommand.rst","api/evennia.contrib.wilderness.rst","api/evennia.help.rst","api/evennia.help.admin.rst","api/evennia.help.manager.rst","api/evennia.help.models.rst","api/evennia.locks.rst","api/evennia.locks.lockfuncs.rst","api/evennia.locks.lockhandler.rst","api/evennia.objects.rst","api/evennia.objects.admin.rst","api/evennia.objects.manager.rst","api/evennia.objects.models.rst","api/evennia.objects.objects.rst","api/evennia.prototypes.rst","api/evennia.prototypes.menus.rst","api/evennia.prototypes.protfuncs.rst","api/evennia.prototypes.prototypes.rst","api/evennia.prototypes.spawner.rst","api/evennia.scripts.rst","api/evennia.scripts.admin.rst","api/evennia.scripts.manager.rst","api/evennia.scripts.models.rst","api/evennia.scripts.monitorhandler.rst","api/evennia.scripts.scripthandler.rst","api/evennia.scripts.scripts.rst","api/evennia.scripts.taskhandler.rst","api/evennia.scripts.tickerhandler.rst","api/evennia.server.rst","api/evennia.server.admin.rst","api/evennia.server.amp_client.rst","api/evennia.server.connection_wizard.rst","api/evennia.server.deprecations.rst","api/evennia.server.evennia_launcher.rst","api/evennia.server.game_index_client.rst","api/evennia.server.game_index_client.client.rst","api/evennia.server.game_index_client.service.rst","api/evennia.server.initial_setup.rst","api/evennia.server.inputfuncs.rst","api/evennia.server.manager.rst","api/evennia.server.models.rst","api/evennia.server.portal.rst","api/evennia.server.portal.amp.rst","api/evennia.server.portal.amp_server.rst","api/evennia.server.portal.grapevine.rst","api/evennia.server.portal.irc.rst","api/evennia.server.portal.mccp.rst","api/evennia.server.portal.mssp.rst","api/evennia.server.portal.mxp.rst","api/evennia.server.portal.naws.rst","api/evennia.server.portal.portal.rst","api/evennia.server.portal.portalsessionhandler.rst","api/evennia.server.portal.rss.rst","api/evennia.server.portal.ssh.rst","api/evennia.server.portal.ssl.rst","api/evennia.server.portal.suppress_ga.rst","api/evennia.server.portal.telnet.rst","api/evennia.server.portal.telnet_oob.rst","api/evennia.server.portal.telnet_ssl.rst","api/evennia.server.portal.tests.rst","api/evennia.server.portal.ttype.rst","api/evennia.server.portal.webclient.rst","api/evennia.server.portal.webclient_ajax.rst","api/evennia.server.profiling.rst","api/evennia.server.profiling.dummyrunner.rst","api/evennia.server.profiling.dummyrunner_settings.rst","api/evennia.server.profiling.memplot.rst","api/evennia.server.profiling.settings_mixin.rst","api/evennia.server.profiling.test_queries.rst","api/evennia.server.profiling.tests.rst","api/evennia.server.profiling.timetrace.rst","api/evennia.server.server.rst","api/evennia.server.serversession.rst","api/evennia.server.session.rst","api/evennia.server.sessionhandler.rst","api/evennia.server.signals.rst","api/evennia.server.throttle.rst","api/evennia.server.validators.rst","api/evennia.server.webserver.rst","api/evennia.settings_default.rst","api/evennia.typeclasses.rst","api/evennia.typeclasses.admin.rst","api/evennia.typeclasses.attributes.rst","api/evennia.typeclasses.managers.rst","api/evennia.typeclasses.models.rst","api/evennia.typeclasses.tags.rst","api/evennia.utils.rst","api/evennia.utils.ansi.rst","api/evennia.utils.batchprocessors.rst","api/evennia.utils.containers.rst","api/evennia.utils.create.rst","api/evennia.utils.dbserialize.rst","api/evennia.utils.eveditor.rst","api/evennia.utils.evform.rst","api/evennia.utils.evmenu.rst","api/evennia.utils.evmore.rst","api/evennia.utils.evtable.rst","api/evennia.utils.gametime.rst","api/evennia.utils.idmapper.rst","api/evennia.utils.idmapper.manager.rst","api/evennia.utils.idmapper.models.rst","api/evennia.utils.idmapper.tests.rst","api/evennia.utils.inlinefuncs.rst","api/evennia.utils.logger.rst","api/evennia.utils.optionclasses.rst","api/evennia.utils.optionhandler.rst","api/evennia.utils.picklefield.rst","api/evennia.utils.search.rst","api/evennia.utils.test_resources.rst","api/evennia.utils.text2html.rst","api/evennia.utils.utils.rst","api/evennia.utils.validatorfuncs.rst","api/evennia.web.rst","api/evennia.web.urls.rst","api/evennia.web.utils.rst","api/evennia.web.utils.backends.rst","api/evennia.web.utils.general_context.rst","api/evennia.web.utils.middleware.rst","api/evennia.web.utils.tests.rst","api/evennia.web.webclient.rst","api/evennia.web.webclient.urls.rst","api/evennia.web.webclient.views.rst","api/evennia.web.website.rst","api/evennia.web.website.forms.rst","api/evennia.web.website.templatetags.rst","api/evennia.web.website.templatetags.addclass.rst","api/evennia.web.website.tests.rst","api/evennia.web.website.urls.rst","api/evennia.web.website.views.rst","index.md","toc.md"],objects:{"":{evennia:[141,0,0,"-"]},"evennia.accounts":{accounts:[144,0,0,"-"],admin:[145,0,0,"-"],bots:[146,0,0,"-"],manager:[147,0,0,"-"],models:[148,0,0,"-"]},"evennia.accounts.accounts":{DefaultAccount:[144,1,1,""]},"evennia.accounts.accounts.DefaultAccount":{"delete":[144,3,1,""],DoesNotExist:[144,2,1,""],MultipleObjectsReturned:[144,2,1,""],access:[144,3,1,""],at_access:[144,3,1,""],at_account_creation:[144,3,1,""],at_cmdset_get:[144,3,1,""],at_disconnect:[144,3,1,""],at_failed_login:[144,3,1,""],at_first_login:[144,3,1,""],at_first_save:[144,3,1,""],at_init:[144,3,1,""],at_look:[144,3,1,""],at_msg_receive:[144,3,1,""],at_msg_send:[144,3,1,""],at_password_change:[144,3,1,""],at_post_disconnect:[144,3,1,""],at_post_login:[144,3,1,""],at_pre_login:[144,3,1,""],at_server_reload:[144,3,1,""],at_server_shutdown:[144,3,1,""],authenticate:[144,3,1,""],basetype_setup:[144,3,1,""],character:[144,3,1,""],characters:[144,3,1,""],cmdset:[144,4,1,""],connection_time:[144,3,1,""],create:[144,3,1,""],create_character:[144,3,1,""],disconnect_session_from_account:[144,3,1,""],execute_cmd:[144,3,1,""],get_all_puppets:[144,3,1,""],get_puppet:[144,3,1,""],get_username_validators:[144,3,1,""],idle_time:[144,3,1,""],is_banned:[144,3,1,""],msg:[144,3,1,""],nicks:[144,4,1,""],normalize_username:[144,3,1,""],objects:[144,4,1,""],options:[144,4,1,""],path:[144,4,1,""],puppet:[144,3,1,""],puppet_object:[144,3,1,""],scripts:[144,4,1,""],search:[144,3,1,""],sessions:[144,4,1,""],set_password:[144,3,1,""],typename:[144,4,1,""],unpuppet_all:[144,3,1,""],unpuppet_object:[144,3,1,""],validate_password:[144,3,1,""],validate_username:[144,3,1,""]},"evennia.accounts.admin":{AccountAttributeInline:[145,1,1,""],AccountDBAdmin:[145,1,1,""],AccountDBChangeForm:[145,1,1,""],AccountDBCreationForm:[145,1,1,""],AccountForm:[145,1,1,""],AccountInline:[145,1,1,""],AccountTagInline:[145,1,1,""]},"evennia.accounts.admin.AccountAttributeInline":{media:[145,3,1,""],model:[145,4,1,""],related_field:[145,4,1,""]},"evennia.accounts.admin.AccountDBAdmin":{add_fieldsets:[145,4,1,""],add_form:[145,4,1,""],fieldsets:[145,4,1,""],form:[145,4,1,""],inlines:[145,4,1,""],list_display:[145,4,1,""],media:[145,3,1,""],response_add:[145,3,1,""],save_model:[145,3,1,""],user_change_password:[145,3,1,""]},"evennia.accounts.admin.AccountDBChangeForm":{Meta:[145,1,1,""],base_fields:[145,4,1,""],clean_username:[145,3,1,""],declared_fields:[145,4,1,""],media:[145,3,1,""]},"evennia.accounts.admin.AccountDBChangeForm.Meta":{fields:[145,4,1,""],model:[145,4,1,""]},"evennia.accounts.admin.AccountDBCreationForm":{Meta:[145,1,1,""],base_fields:[145,4,1,""],clean_username:[145,3,1,""],declared_fields:[145,4,1,""],media:[145,3,1,""]},"evennia.accounts.admin.AccountDBCreationForm.Meta":{fields:[145,4,1,""],model:[145,4,1,""]},"evennia.accounts.admin.AccountForm":{Meta:[145,1,1,""],base_fields:[145,4,1,""],declared_fields:[145,4,1,""],media:[145,3,1,""]},"evennia.accounts.admin.AccountForm.Meta":{app_label:[145,4,1,""],fields:[145,4,1,""],model:[145,4,1,""]},"evennia.accounts.admin.AccountInline":{extra:[145,4,1,""],fieldsets:[145,4,1,""],form:[145,4,1,""],max_num:[145,4,1,""],media:[145,3,1,""],model:[145,4,1,""],template:[145,4,1,""]},"evennia.accounts.admin.AccountTagInline":{media:[145,3,1,""],model:[145,4,1,""],related_field:[145,4,1,""]},"evennia.accounts.bots":{Bot:[146,1,1,""],BotStarter:[146,1,1,""],GrapevineBot:[146,1,1,""],IRCBot:[146,1,1,""],RSSBot:[146,1,1,""]},"evennia.accounts.bots.Bot":{DoesNotExist:[146,2,1,""],MultipleObjectsReturned:[146,2,1,""],at_server_shutdown:[146,3,1,""],basetype_setup:[146,3,1,""],execute_cmd:[146,3,1,""],msg:[146,3,1,""],path:[146,4,1,""],start:[146,3,1,""],typename:[146,4,1,""]},"evennia.accounts.bots.BotStarter":{DoesNotExist:[146,2,1,""],MultipleObjectsReturned:[146,2,1,""],at_repeat:[146,3,1,""],at_script_creation:[146,3,1,""],at_server_reload:[146,3,1,""],at_server_shutdown:[146,3,1,""],at_start:[146,3,1,""],path:[146,4,1,""],typename:[146,4,1,""]},"evennia.accounts.bots.GrapevineBot":{DoesNotExist:[146,2,1,""],MultipleObjectsReturned:[146,2,1,""],at_msg_send:[146,3,1,""],execute_cmd:[146,3,1,""],factory_path:[146,4,1,""],msg:[146,3,1,""],path:[146,4,1,""],start:[146,3,1,""],typename:[146,4,1,""]},"evennia.accounts.bots.IRCBot":{DoesNotExist:[146,2,1,""],MultipleObjectsReturned:[146,2,1,""],at_msg_send:[146,3,1,""],execute_cmd:[146,3,1,""],factory_path:[146,4,1,""],get_nicklist:[146,3,1,""],msg:[146,3,1,""],path:[146,4,1,""],ping:[146,3,1,""],reconnect:[146,3,1,""],start:[146,3,1,""],typename:[146,4,1,""]},"evennia.accounts.bots.RSSBot":{DoesNotExist:[146,2,1,""],MultipleObjectsReturned:[146,2,1,""],execute_cmd:[146,3,1,""],path:[146,4,1,""],start:[146,3,1,""],typename:[146,4,1,""]},"evennia.accounts.manager":{AccountManager:[147,1,1,""]},"evennia.accounts.models":{AccountDB:[148,1,1,""]},"evennia.accounts.models.AccountDB":{DoesNotExist:[148,2,1,""],MultipleObjectsReturned:[148,2,1,""],account_subscription_set:[148,4,1,""],cmdset_storage:[148,3,1,""],db_attributes:[148,4,1,""],db_cmdset_storage:[148,4,1,""],db_is_bot:[148,4,1,""],db_is_connected:[148,4,1,""],db_tags:[148,4,1,""],get_next_by_date_joined:[148,3,1,""],get_next_by_db_date_created:[148,3,1,""],get_previous_by_date_joined:[148,3,1,""],get_previous_by_db_date_created:[148,3,1,""],groups:[148,4,1,""],hide_from_accounts_set:[148,4,1,""],id:[148,4,1,""],is_bot:[148,3,1,""],is_connected:[148,3,1,""],key:[148,3,1,""],logentry_set:[148,4,1,""],name:[148,3,1,""],objectdb_set:[148,4,1,""],objects:[148,4,1,""],path:[148,4,1,""],receiver_account_set:[148,4,1,""],scriptdb_set:[148,4,1,""],sender_account_set:[148,4,1,""],typename:[148,4,1,""],uid:[148,3,1,""],user_permissions:[148,4,1,""]},"evennia.commands":{"default":[155,0,0,"-"],cmdhandler:[150,0,0,"-"],cmdparser:[151,0,0,"-"],cmdset:[152,0,0,"-"],cmdsethandler:[153,0,0,"-"],command:[154,0,0,"-"]},"evennia.commands.cmdhandler":{InterruptCommand:[150,2,1,""],cmdhandler:[150,5,1,""]},"evennia.commands.cmdparser":{build_matches:[151,5,1,""],cmdparser:[151,5,1,""],create_match:[151,5,1,""],try_num_prefixes:[151,5,1,""]},"evennia.commands.cmdset":{CmdSet:[152,1,1,""]},"evennia.commands.cmdset.CmdSet":{__init__:[152,3,1,""],add:[152,3,1,""],at_cmdset_creation:[152,3,1,""],count:[152,3,1,""],duplicates:[152,4,1,""],errmessage:[152,4,1,""],get:[152,3,1,""],get_all_cmd_keys_and_aliases:[152,3,1,""],get_system_cmds:[152,3,1,""],key:[152,4,1,""],key_mergetypes:[152,4,1,""],make_unique:[152,3,1,""],mergetype:[152,4,1,""],no_channels:[152,4,1,""],no_exits:[152,4,1,""],no_objs:[152,4,1,""],path:[152,4,1,""],permanent:[152,4,1,""],priority:[152,4,1,""],remove:[152,3,1,""],to_duplicate:[152,4,1,""]},"evennia.commands.cmdsethandler":{CmdSetHandler:[153,1,1,""],import_cmdset:[153,5,1,""]},"evennia.commands.cmdsethandler.CmdSetHandler":{"delete":[153,3,1,""],__init__:[153,3,1,""],add:[153,3,1,""],add_default:[153,3,1,""],all:[153,3,1,""],clear:[153,3,1,""],delete_default:[153,3,1,""],get:[153,3,1,""],has:[153,3,1,""],has_cmdset:[153,3,1,""],remove:[153,3,1,""],remove_default:[153,3,1,""],reset:[153,3,1,""],update:[153,3,1,""]},"evennia.commands.command":{Command:[154,1,1,""],CommandMeta:[154,1,1,""],InterruptCommand:[154,2,1,""]},"evennia.commands.command.Command":{__init__:[154,3,1,""],access:[154,3,1,""],aliases:[154,4,1,""],arg_regex:[154,4,1,""],at_post_cmd:[154,3,1,""],at_pre_cmd:[154,3,1,""],auto_help:[154,4,1,""],client_height:[154,3,1,""],client_width:[154,3,1,""],execute_cmd:[154,3,1,""],func:[154,3,1,""],get_command_info:[154,3,1,""],get_extra_info:[154,3,1,""],get_help:[154,3,1,""],help_category:[154,4,1,""],is_exit:[154,4,1,""],key:[154,4,1,""],lock_storage:[154,4,1,""],lockhandler:[154,4,1,""],locks:[154,4,1,""],match:[154,3,1,""],msg:[154,3,1,""],msg_all_sessions:[154,4,1,""],parse:[154,3,1,""],save_for_next:[154,4,1,""],set_aliases:[154,3,1,""],set_key:[154,3,1,""],styled_footer:[154,3,1,""],styled_header:[154,3,1,""],styled_separator:[154,3,1,""],styled_table:[154,3,1,""]},"evennia.commands.command.CommandMeta":{__init__:[154,3,1,""]},"evennia.commands.default":{account:[156,0,0,"-"],admin:[157,0,0,"-"],batchprocess:[158,0,0,"-"],building:[159,0,0,"-"],cmdset_account:[160,0,0,"-"],cmdset_character:[161,0,0,"-"],cmdset_session:[162,0,0,"-"],cmdset_unloggedin:[163,0,0,"-"],comms:[164,0,0,"-"],general:[165,0,0,"-"],help:[166,0,0,"-"],muxcommand:[167,0,0,"-"],syscommands:[168,0,0,"-"],system:[169,0,0,"-"],unloggedin:[171,0,0,"-"]},"evennia.commands.default.account":{CmdCharCreate:[156,1,1,""],CmdCharDelete:[156,1,1,""],CmdColorTest:[156,1,1,""],CmdIC:[156,1,1,""],CmdOOC:[156,1,1,""],CmdOOCLook:[156,1,1,""],CmdOption:[156,1,1,""],CmdPassword:[156,1,1,""],CmdQuell:[156,1,1,""],CmdQuit:[156,1,1,""],CmdSessions:[156,1,1,""],CmdStyle:[156,1,1,""],CmdWho:[156,1,1,""]},"evennia.commands.default.account.CmdCharCreate":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""]},"evennia.commands.default.account.CmdCharDelete":{aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""]},"evennia.commands.default.account.CmdColorTest":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""],slice_bright_bg:[156,4,1,""],slice_bright_fg:[156,4,1,""],slice_dark_bg:[156,4,1,""],slice_dark_fg:[156,4,1,""],table_format:[156,3,1,""]},"evennia.commands.default.account.CmdIC":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""]},"evennia.commands.default.account.CmdOOC":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""]},"evennia.commands.default.account.CmdOOCLook":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""]},"evennia.commands.default.account.CmdOption":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""],switch_options:[156,4,1,""]},"evennia.commands.default.account.CmdPassword":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""]},"evennia.commands.default.account.CmdQuell":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""]},"evennia.commands.default.account.CmdQuit":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""],switch_options:[156,4,1,""]},"evennia.commands.default.account.CmdSessions":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""]},"evennia.commands.default.account.CmdStyle":{aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],list_styles:[156,3,1,""],lock_storage:[156,4,1,""],set:[156,3,1,""],switch_options:[156,4,1,""]},"evennia.commands.default.account.CmdWho":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""]},"evennia.commands.default.admin":{CmdBan:[157,1,1,""],CmdBoot:[157,1,1,""],CmdEmit:[157,1,1,""],CmdForce:[157,1,1,""],CmdNewPassword:[157,1,1,""],CmdPerm:[157,1,1,""],CmdUnban:[157,1,1,""],CmdWall:[157,1,1,""]},"evennia.commands.default.admin.CmdBan":{aliases:[157,4,1,""],func:[157,3,1,""],help_category:[157,4,1,""],key:[157,4,1,""],lock_storage:[157,4,1,""],locks:[157,4,1,""]},"evennia.commands.default.admin.CmdBoot":{aliases:[157,4,1,""],func:[157,3,1,""],help_category:[157,4,1,""],key:[157,4,1,""],lock_storage:[157,4,1,""],locks:[157,4,1,""],switch_options:[157,4,1,""]},"evennia.commands.default.admin.CmdEmit":{aliases:[157,4,1,""],func:[157,3,1,""],help_category:[157,4,1,""],key:[157,4,1,""],lock_storage:[157,4,1,""],locks:[157,4,1,""],switch_options:[157,4,1,""]},"evennia.commands.default.admin.CmdForce":{aliases:[157,4,1,""],func:[157,3,1,""],help_category:[157,4,1,""],key:[157,4,1,""],lock_storage:[157,4,1,""],locks:[157,4,1,""],perm_used:[157,4,1,""]},"evennia.commands.default.admin.CmdNewPassword":{aliases:[157,4,1,""],func:[157,3,1,""],help_category:[157,4,1,""],key:[157,4,1,""],lock_storage:[157,4,1,""],locks:[157,4,1,""]},"evennia.commands.default.admin.CmdPerm":{aliases:[157,4,1,""],func:[157,3,1,""],help_category:[157,4,1,""],key:[157,4,1,""],lock_storage:[157,4,1,""],locks:[157,4,1,""],switch_options:[157,4,1,""]},"evennia.commands.default.admin.CmdUnban":{aliases:[157,4,1,""],func:[157,3,1,""],help_category:[157,4,1,""],key:[157,4,1,""],lock_storage:[157,4,1,""],locks:[157,4,1,""]},"evennia.commands.default.admin.CmdWall":{aliases:[157,4,1,""],func:[157,3,1,""],help_category:[157,4,1,""],key:[157,4,1,""],lock_storage:[157,4,1,""],locks:[157,4,1,""]},"evennia.commands.default.batchprocess":{CmdBatchCode:[158,1,1,""],CmdBatchCommands:[158,1,1,""]},"evennia.commands.default.batchprocess.CmdBatchCode":{aliases:[158,4,1,""],func:[158,3,1,""],help_category:[158,4,1,""],key:[158,4,1,""],lock_storage:[158,4,1,""],locks:[158,4,1,""],switch_options:[158,4,1,""]},"evennia.commands.default.batchprocess.CmdBatchCommands":{aliases:[158,4,1,""],func:[158,3,1,""],help_category:[158,4,1,""],key:[158,4,1,""],lock_storage:[158,4,1,""],locks:[158,4,1,""],switch_options:[158,4,1,""]},"evennia.commands.default.building":{CmdCopy:[159,1,1,""],CmdCpAttr:[159,1,1,""],CmdCreate:[159,1,1,""],CmdDesc:[159,1,1,""],CmdDestroy:[159,1,1,""],CmdDig:[159,1,1,""],CmdExamine:[159,1,1,""],CmdFind:[159,1,1,""],CmdLink:[159,1,1,""],CmdListCmdSets:[159,1,1,""],CmdLock:[159,1,1,""],CmdMvAttr:[159,1,1,""],CmdName:[159,1,1,""],CmdOpen:[159,1,1,""],CmdScript:[159,1,1,""],CmdSetAttribute:[159,1,1,""],CmdSetHome:[159,1,1,""],CmdSetObjAlias:[159,1,1,""],CmdSpawn:[159,1,1,""],CmdTag:[159,1,1,""],CmdTeleport:[159,1,1,""],CmdTunnel:[159,1,1,""],CmdTypeclass:[159,1,1,""],CmdUnLink:[159,1,1,""],CmdWipe:[159,1,1,""],ObjManipCommand:[159,1,1,""]},"evennia.commands.default.building.CmdCopy":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""]},"evennia.commands.default.building.CmdCpAttr":{aliases:[159,4,1,""],check_from_attr:[159,3,1,""],check_has_attr:[159,3,1,""],check_to_attr:[159,3,1,""],func:[159,3,1,""],get_attr:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdCreate":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],new_obj_lockstring:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdDesc":{aliases:[159,4,1,""],edit_handler:[159,3,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdDestroy":{aliases:[159,4,1,""],confirm:[159,4,1,""],default_confirm:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdDig":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],new_room_lockstring:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdExamine":{account_mode:[159,4,1,""],aliases:[159,4,1,""],arg_regex:[159,4,1,""],detail_color:[159,4,1,""],format_attributes:[159,3,1,""],format_output:[159,3,1,""],func:[159,3,1,""],header_color:[159,4,1,""],help_category:[159,4,1,""],key:[159,4,1,""],list_attribute:[159,3,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],quell_color:[159,4,1,""],separator:[159,4,1,""]},"evennia.commands.default.building.CmdFind":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdLink":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""]},"evennia.commands.default.building.CmdListCmdSets":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""]},"evennia.commands.default.building.CmdLock":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""]},"evennia.commands.default.building.CmdMvAttr":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdName":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""]},"evennia.commands.default.building.CmdOpen":{aliases:[159,4,1,""],create_exit:[159,3,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],new_obj_lockstring:[159,4,1,""]},"evennia.commands.default.building.CmdScript":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdSetAttribute":{aliases:[159,4,1,""],check_attr:[159,3,1,""],check_obj:[159,3,1,""],do_nested_lookup:[159,3,1,""],edit_handler:[159,3,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],nested_re:[159,4,1,""],not_found:[159,4,1,""],rm_attr:[159,3,1,""],search_for_obj:[159,3,1,""],set_attr:[159,3,1,""],split_nested_attr:[159,3,1,""],view_attr:[159,3,1,""]},"evennia.commands.default.building.CmdSetHome":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""]},"evennia.commands.default.building.CmdSetObjAlias":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdSpawn":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdTag":{aliases:[159,4,1,""],arg_regex:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],options:[159,4,1,""]},"evennia.commands.default.building.CmdTeleport":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],rhs_split:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdTunnel":{aliases:[159,4,1,""],directions:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdTypeclass":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdUnLink":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],help_key:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""]},"evennia.commands.default.building.CmdWipe":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""]},"evennia.commands.default.building.ObjManipCommand":{aliases:[159,4,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],parse:[159,3,1,""]},"evennia.commands.default.cmdset_account":{AccountCmdSet:[160,1,1,""]},"evennia.commands.default.cmdset_account.AccountCmdSet":{at_cmdset_creation:[160,3,1,""],key:[160,4,1,""],path:[160,4,1,""],priority:[160,4,1,""]},"evennia.commands.default.cmdset_character":{CharacterCmdSet:[161,1,1,""]},"evennia.commands.default.cmdset_character.CharacterCmdSet":{at_cmdset_creation:[161,3,1,""],key:[161,4,1,""],path:[161,4,1,""],priority:[161,4,1,""]},"evennia.commands.default.cmdset_session":{SessionCmdSet:[162,1,1,""]},"evennia.commands.default.cmdset_session.SessionCmdSet":{at_cmdset_creation:[162,3,1,""],key:[162,4,1,""],path:[162,4,1,""],priority:[162,4,1,""]},"evennia.commands.default.cmdset_unloggedin":{UnloggedinCmdSet:[163,1,1,""]},"evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet":{at_cmdset_creation:[163,3,1,""],key:[163,4,1,""],path:[163,4,1,""],priority:[163,4,1,""]},"evennia.commands.default.comms":{CmdAddCom:[164,1,1,""],CmdAllCom:[164,1,1,""],CmdCBoot:[164,1,1,""],CmdCWho:[164,1,1,""],CmdCdesc:[164,1,1,""],CmdCdestroy:[164,1,1,""],CmdCemit:[164,1,1,""],CmdChannelCreate:[164,1,1,""],CmdChannels:[164,1,1,""],CmdClock:[164,1,1,""],CmdDelCom:[164,1,1,""],CmdGrapevine2Chan:[164,1,1,""],CmdIRC2Chan:[164,1,1,""],CmdIRCStatus:[164,1,1,""],CmdPage:[164,1,1,""],CmdRSS2Chan:[164,1,1,""]},"evennia.commands.default.comms.CmdAddCom":{account_caller:[164,4,1,""],aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""]},"evennia.commands.default.comms.CmdAllCom":{account_caller:[164,4,1,""],aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""]},"evennia.commands.default.comms.CmdCBoot":{account_caller:[164,4,1,""],aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""],switch_options:[164,4,1,""]},"evennia.commands.default.comms.CmdCWho":{account_caller:[164,4,1,""],aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""]},"evennia.commands.default.comms.CmdCdesc":{account_caller:[164,4,1,""],aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""]},"evennia.commands.default.comms.CmdCdestroy":{account_caller:[164,4,1,""],aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""]},"evennia.commands.default.comms.CmdCemit":{account_caller:[164,4,1,""],aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""],switch_options:[164,4,1,""]},"evennia.commands.default.comms.CmdChannelCreate":{account_caller:[164,4,1,""],aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""]},"evennia.commands.default.comms.CmdChannels":{account_caller:[164,4,1,""],aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""]},"evennia.commands.default.comms.CmdClock":{account_caller:[164,4,1,""],aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""]},"evennia.commands.default.comms.CmdDelCom":{account_caller:[164,4,1,""],aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""]},"evennia.commands.default.comms.CmdGrapevine2Chan":{aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""],switch_options:[164,4,1,""]},"evennia.commands.default.comms.CmdIRC2Chan":{aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""],switch_options:[164,4,1,""]},"evennia.commands.default.comms.CmdIRCStatus":{aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""]},"evennia.commands.default.comms.CmdPage":{account_caller:[164,4,1,""],aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""],switch_options:[164,4,1,""]},"evennia.commands.default.comms.CmdRSS2Chan":{aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""],switch_options:[164,4,1,""]},"evennia.commands.default.general":{CmdAccess:[165,1,1,""],CmdDrop:[165,1,1,""],CmdGet:[165,1,1,""],CmdGive:[165,1,1,""],CmdHome:[165,1,1,""],CmdInventory:[165,1,1,""],CmdLook:[165,1,1,""],CmdNick:[165,1,1,""],CmdPose:[165,1,1,""],CmdSay:[165,1,1,""],CmdSetDesc:[165,1,1,""],CmdWhisper:[165,1,1,""]},"evennia.commands.default.general.CmdAccess":{aliases:[165,4,1,""],arg_regex:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""]},"evennia.commands.default.general.CmdDrop":{aliases:[165,4,1,""],arg_regex:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""]},"evennia.commands.default.general.CmdGet":{aliases:[165,4,1,""],arg_regex:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""]},"evennia.commands.default.general.CmdGive":{aliases:[165,4,1,""],arg_regex:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""],rhs_split:[165,4,1,""]},"evennia.commands.default.general.CmdHome":{aliases:[165,4,1,""],arg_regex:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""]},"evennia.commands.default.general.CmdInventory":{aliases:[165,4,1,""],arg_regex:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""]},"evennia.commands.default.general.CmdLook":{aliases:[165,4,1,""],arg_regex:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""]},"evennia.commands.default.general.CmdNick":{aliases:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""],parse:[165,3,1,""],switch_options:[165,4,1,""]},"evennia.commands.default.general.CmdPose":{aliases:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""],parse:[165,3,1,""]},"evennia.commands.default.general.CmdSay":{aliases:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""]},"evennia.commands.default.general.CmdSetDesc":{aliases:[165,4,1,""],arg_regex:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""]},"evennia.commands.default.general.CmdWhisper":{aliases:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""]},"evennia.commands.default.help":{CmdHelp:[166,1,1,""],CmdSetHelp:[166,1,1,""]},"evennia.commands.default.help.CmdHelp":{aliases:[166,4,1,""],arg_regex:[166,4,1,""],check_show_help:[166,3,1,""],format_help_entry:[166,3,1,""],format_help_list:[166,3,1,""],func:[166,3,1,""],help_category:[166,4,1,""],help_more:[166,4,1,""],key:[166,4,1,""],lock_storage:[166,4,1,""],locks:[166,4,1,""],msg_help:[166,3,1,""],parse:[166,3,1,""],return_cmdset:[166,4,1,""],should_list_cmd:[166,3,1,""],suggestion_cutoff:[166,4,1,""],suggestion_maxnum:[166,4,1,""]},"evennia.commands.default.help.CmdSetHelp":{aliases:[166,4,1,""],func:[166,3,1,""],help_category:[166,4,1,""],key:[166,4,1,""],lock_storage:[166,4,1,""],locks:[166,4,1,""],switch_options:[166,4,1,""]},"evennia.commands.default.muxcommand":{MuxAccountCommand:[167,1,1,""],MuxCommand:[167,1,1,""]},"evennia.commands.default.muxcommand.MuxAccountCommand":{account_caller:[167,4,1,""],aliases:[167,4,1,""],help_category:[167,4,1,""],key:[167,4,1,""],lock_storage:[167,4,1,""]},"evennia.commands.default.muxcommand.MuxCommand":{aliases:[167,4,1,""],at_post_cmd:[167,3,1,""],at_pre_cmd:[167,3,1,""],func:[167,3,1,""],get_command_info:[167,3,1,""],has_perm:[167,3,1,""],help_category:[167,4,1,""],key:[167,4,1,""],lock_storage:[167,4,1,""],parse:[167,3,1,""]},"evennia.commands.default.syscommands":{SystemMultimatch:[168,1,1,""],SystemNoInput:[168,1,1,""],SystemNoMatch:[168,1,1,""],SystemSendToChannel:[168,1,1,""]},"evennia.commands.default.syscommands.SystemMultimatch":{aliases:[168,4,1,""],func:[168,3,1,""],help_category:[168,4,1,""],key:[168,4,1,""],lock_storage:[168,4,1,""],locks:[168,4,1,""]},"evennia.commands.default.syscommands.SystemNoInput":{aliases:[168,4,1,""],func:[168,3,1,""],help_category:[168,4,1,""],key:[168,4,1,""],lock_storage:[168,4,1,""],locks:[168,4,1,""]},"evennia.commands.default.syscommands.SystemNoMatch":{aliases:[168,4,1,""],func:[168,3,1,""],help_category:[168,4,1,""],key:[168,4,1,""],lock_storage:[168,4,1,""],locks:[168,4,1,""]},"evennia.commands.default.syscommands.SystemSendToChannel":{aliases:[168,4,1,""],func:[168,3,1,""],help_category:[168,4,1,""],key:[168,4,1,""],lock_storage:[168,4,1,""],locks:[168,4,1,""],parse:[168,3,1,""]},"evennia.commands.default.system":{CmdAbout:[169,1,1,""],CmdObjects:[169,1,1,""],CmdPy:[169,1,1,""],CmdReload:[169,1,1,""],CmdReset:[169,1,1,""],CmdScripts:[169,1,1,""],CmdServerLoad:[169,1,1,""],CmdService:[169,1,1,""],CmdShutdown:[169,1,1,""],CmdTime:[169,1,1,""]},"evennia.commands.default.system.CmdAbout":{aliases:[169,4,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""]},"evennia.commands.default.system.CmdObjects":{aliases:[169,4,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""]},"evennia.commands.default.system.CmdPy":{aliases:[169,4,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""],switch_options:[169,4,1,""]},"evennia.commands.default.system.CmdReload":{aliases:[169,4,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""]},"evennia.commands.default.system.CmdReset":{aliases:[169,4,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""]},"evennia.commands.default.system.CmdScripts":{aliases:[169,4,1,""],excluded_typeclass_paths:[169,4,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""],switch_options:[169,4,1,""]},"evennia.commands.default.system.CmdServerLoad":{aliases:[169,4,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""],switch_options:[169,4,1,""]},"evennia.commands.default.system.CmdService":{aliases:[169,4,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""],switch_options:[169,4,1,""]},"evennia.commands.default.system.CmdShutdown":{aliases:[169,4,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""]},"evennia.commands.default.system.CmdTime":{aliases:[169,4,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""]},"evennia.commands.default.tests":{CmdInterrupt:[170,1,1,""],CommandTest:[170,1,1,""],TestAccount:[170,1,1,""],TestAdmin:[170,1,1,""],TestBatchProcess:[170,1,1,""],TestBuilding:[170,1,1,""],TestComms:[170,1,1,""],TestGeneral:[170,1,1,""],TestHelp:[170,1,1,""],TestInterruptCommand:[170,1,1,""],TestSystem:[170,1,1,""],TestSystemCommands:[170,1,1,""],TestUnconnectedCommand:[170,1,1,""]},"evennia.commands.default.tests.CmdInterrupt":{aliases:[170,4,1,""],func:[170,3,1,""],help_category:[170,4,1,""],key:[170,4,1,""],lock_storage:[170,4,1,""],parse:[170,3,1,""]},"evennia.commands.default.tests.CommandTest":{call:[170,3,1,""]},"evennia.commands.default.tests.TestAccount":{test_char_create:[170,3,1,""],test_char_delete:[170,3,1,""],test_color_test:[170,3,1,""],test_ic:[170,3,1,""],test_ic__nonaccess:[170,3,1,""],test_ic__other_object:[170,3,1,""],test_ooc:[170,3,1,""],test_ooc_look:[170,3,1,""],test_option:[170,3,1,""],test_password:[170,3,1,""],test_quell:[170,3,1,""],test_quit:[170,3,1,""],test_sessions:[170,3,1,""],test_who:[170,3,1,""]},"evennia.commands.default.tests.TestAdmin":{test_ban:[170,3,1,""],test_emit:[170,3,1,""],test_force:[170,3,1,""],test_perm:[170,3,1,""],test_wall:[170,3,1,""]},"evennia.commands.default.tests.TestBatchProcess":{test_batch_commands:[170,3,1,""]},"evennia.commands.default.tests.TestBuilding":{test_attribute_commands:[170,3,1,""],test_copy:[170,3,1,""],test_create:[170,3,1,""],test_desc:[170,3,1,""],test_desc_default_to_room:[170,3,1,""],test_destroy:[170,3,1,""],test_destroy_sequence:[170,3,1,""],test_dig:[170,3,1,""],test_do_nested_lookup:[170,3,1,""],test_empty_desc:[170,3,1,""],test_examine:[170,3,1,""],test_exit_commands:[170,3,1,""],test_find:[170,3,1,""],test_list_cmdsets:[170,3,1,""],test_lock:[170,3,1,""],test_name:[170,3,1,""],test_nested_attribute_commands:[170,3,1,""],test_script:[170,3,1,""],test_set_home:[170,3,1,""],test_set_obj_alias:[170,3,1,""],test_spawn:[170,3,1,""],test_split_nested_attr:[170,3,1,""],test_tag:[170,3,1,""],test_teleport:[170,3,1,""],test_tunnel:[170,3,1,""],test_tunnel_exit_typeclass:[170,3,1,""],test_typeclass:[170,3,1,""]},"evennia.commands.default.tests.TestComms":{setUp:[170,3,1,""],test_all_com:[170,3,1,""],test_cboot:[170,3,1,""],test_cdesc:[170,3,1,""],test_cdestroy:[170,3,1,""],test_cemit:[170,3,1,""],test_channels:[170,3,1,""],test_clock:[170,3,1,""],test_cwho:[170,3,1,""],test_page:[170,3,1,""],test_toggle_com:[170,3,1,""]},"evennia.commands.default.tests.TestGeneral":{test_access:[170,3,1,""],test_get_and_drop:[170,3,1,""],test_give:[170,3,1,""],test_home:[170,3,1,""],test_inventory:[170,3,1,""],test_look:[170,3,1,""],test_mux_command:[170,3,1,""],test_nick:[170,3,1,""],test_pose:[170,3,1,""],test_say:[170,3,1,""],test_whisper:[170,3,1,""]},"evennia.commands.default.tests.TestHelp":{test_help:[170,3,1,""],test_set_help:[170,3,1,""]},"evennia.commands.default.tests.TestInterruptCommand":{test_interrupt_command:[170,3,1,""]},"evennia.commands.default.tests.TestSystem":{test_about:[170,3,1,""],test_objects:[170,3,1,""],test_py:[170,3,1,""],test_scripts:[170,3,1,""],test_server_load:[170,3,1,""]},"evennia.commands.default.tests.TestSystemCommands":{test_channelcommand:[170,3,1,""],test_multimatch:[170,3,1,""],test_simple_defaults:[170,3,1,""]},"evennia.commands.default.tests.TestUnconnectedCommand":{test_info_command:[170,3,1,""]},"evennia.commands.default.unloggedin":{CmdUnconnectedConnect:[171,1,1,""],CmdUnconnectedCreate:[171,1,1,""],CmdUnconnectedHelp:[171,1,1,""],CmdUnconnectedLook:[171,1,1,""],CmdUnconnectedQuit:[171,1,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedConnect":{aliases:[171,4,1,""],arg_regex:[171,4,1,""],func:[171,3,1,""],help_category:[171,4,1,""],key:[171,4,1,""],lock_storage:[171,4,1,""],locks:[171,4,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedCreate":{aliases:[171,4,1,""],arg_regex:[171,4,1,""],func:[171,3,1,""],help_category:[171,4,1,""],key:[171,4,1,""],lock_storage:[171,4,1,""],locks:[171,4,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedHelp":{aliases:[171,4,1,""],func:[171,3,1,""],help_category:[171,4,1,""],key:[171,4,1,""],lock_storage:[171,4,1,""],locks:[171,4,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedLook":{aliases:[171,4,1,""],func:[171,3,1,""],help_category:[171,4,1,""],key:[171,4,1,""],lock_storage:[171,4,1,""],locks:[171,4,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedQuit":{aliases:[171,4,1,""],func:[171,3,1,""],help_category:[171,4,1,""],key:[171,4,1,""],lock_storage:[171,4,1,""],locks:[171,4,1,""]},"evennia.comms":{admin:[173,0,0,"-"],channelhandler:[174,0,0,"-"],comms:[175,0,0,"-"],managers:[176,0,0,"-"],models:[177,0,0,"-"]},"evennia.comms.admin":{ChannelAdmin:[173,1,1,""],ChannelAttributeInline:[173,1,1,""],ChannelTagInline:[173,1,1,""],MsgAdmin:[173,1,1,""]},"evennia.comms.admin.ChannelAdmin":{fieldsets:[173,4,1,""],inlines:[173,4,1,""],list_display:[173,4,1,""],list_display_links:[173,4,1,""],list_select_related:[173,4,1,""],media:[173,3,1,""],ordering:[173,4,1,""],raw_id_fields:[173,4,1,""],response_add:[173,3,1,""],save_as:[173,4,1,""],save_model:[173,3,1,""],save_on_top:[173,4,1,""],search_fields:[173,4,1,""],subscriptions:[173,3,1,""]},"evennia.comms.admin.ChannelAttributeInline":{media:[173,3,1,""],model:[173,4,1,""],related_field:[173,4,1,""]},"evennia.comms.admin.ChannelTagInline":{media:[173,3,1,""],model:[173,4,1,""],related_field:[173,4,1,""]},"evennia.comms.admin.MsgAdmin":{list_display:[173,4,1,""],list_display_links:[173,4,1,""],list_select_related:[173,4,1,""],media:[173,3,1,""],ordering:[173,4,1,""],save_as:[173,4,1,""],save_on_top:[173,4,1,""],search_fields:[173,4,1,""]},"evennia.comms.channelhandler":{ChannelCommand:[174,1,1,""],ChannelHandler:[174,1,1,""]},"evennia.comms.channelhandler.ChannelCommand":{aliases:[174,4,1,""],arg_regex:[174,4,1,""],func:[174,3,1,""],get_extra_info:[174,3,1,""],help_category:[174,4,1,""],is_channel:[174,4,1,""],key:[174,4,1,""],lock_storage:[174,4,1,""],obj:[174,4,1,""],parse:[174,3,1,""]},"evennia.comms.channelhandler.ChannelHandler":{__init__:[174,3,1,""],add:[174,3,1,""],add_channel:[174,3,1,""],clear:[174,3,1,""],get:[174,3,1,""],get_cmdset:[174,3,1,""],remove:[174,3,1,""],update:[174,3,1,""]},"evennia.comms.comms":{DefaultChannel:[175,1,1,""]},"evennia.comms.comms.DefaultChannel":{"delete":[175,3,1,""],DoesNotExist:[175,2,1,""],MultipleObjectsReturned:[175,2,1,""],access:[175,3,1,""],at_channel_creation:[175,3,1,""],at_first_save:[175,3,1,""],at_init:[175,3,1,""],basetype_setup:[175,3,1,""],channel_prefix:[175,3,1,""],connect:[175,3,1,""],create:[175,3,1,""],disconnect:[175,3,1,""],distribute_message:[175,3,1,""],format_external:[175,3,1,""],format_message:[175,3,1,""],format_senders:[175,3,1,""],get_absolute_url:[175,3,1,""],has_connection:[175,3,1,""],message_transform:[175,3,1,""],msg:[175,3,1,""],mute:[175,3,1,""],mutelist:[175,3,1,""],objects:[175,4,1,""],path:[175,4,1,""],pose_transform:[175,3,1,""],post_join_channel:[175,3,1,""],post_leave_channel:[175,3,1,""],post_send_message:[175,3,1,""],pre_join_channel:[175,3,1,""],pre_leave_channel:[175,3,1,""],pre_send_message:[175,3,1,""],tempmsg:[175,3,1,""],typename:[175,4,1,""],unmute:[175,3,1,""],web_get_admin_url:[175,3,1,""],web_get_create_url:[175,3,1,""],web_get_delete_url:[175,3,1,""],web_get_detail_url:[175,3,1,""],web_get_update_url:[175,3,1,""],wholist:[175,3,1,""]},"evennia.comms.managers":{ChannelDBManager:[176,1,1,""],ChannelManager:[176,1,1,""],CommError:[176,2,1,""],MsgManager:[176,1,1,""],identify_object:[176,5,1,""],to_object:[176,5,1,""]},"evennia.comms.managers.ChannelDBManager":{channel_search:[176,3,1,""],get_all_channels:[176,3,1,""],get_channel:[176,3,1,""],get_subscriptions:[176,3,1,""],search_channel:[176,3,1,""]},"evennia.comms.managers.MsgManager":{get_message_by_id:[176,3,1,""],get_messages_by_channel:[176,3,1,""],get_messages_by_receiver:[176,3,1,""],get_messages_by_sender:[176,3,1,""],identify_object:[176,3,1,""],message_search:[176,3,1,""],search_message:[176,3,1,""]},"evennia.comms.models":{ChannelDB:[177,1,1,""],Msg:[177,1,1,""],TempMsg:[177,1,1,""]},"evennia.comms.models.ChannelDB":{DoesNotExist:[177,2,1,""],MultipleObjectsReturned:[177,2,1,""],channel_set:[177,4,1,""],db_account_subscriptions:[177,4,1,""],db_attributes:[177,4,1,""],db_object_subscriptions:[177,4,1,""],db_tags:[177,4,1,""],get_next_by_db_date_created:[177,3,1,""],get_previous_by_db_date_created:[177,3,1,""],hide_from_channels_set:[177,4,1,""],id:[177,4,1,""],objects:[177,4,1,""],path:[177,4,1,""],subscriptions:[177,4,1,""],typename:[177,4,1,""]},"evennia.comms.models.Msg":{DoesNotExist:[177,2,1,""],MultipleObjectsReturned:[177,2,1,""],__init__:[177,3,1,""],access:[177,3,1,""],channels:[177,3,1,""],date_created:[177,3,1,""],db_date_created:[177,4,1,""],db_header:[177,4,1,""],db_hide_from_accounts:[177,4,1,""],db_hide_from_channels:[177,4,1,""],db_hide_from_objects:[177,4,1,""],db_lock_storage:[177,4,1,""],db_message:[177,4,1,""],db_receivers_accounts:[177,4,1,""],db_receivers_channels:[177,4,1,""],db_receivers_objects:[177,4,1,""],db_receivers_scripts:[177,4,1,""],db_sender_accounts:[177,4,1,""],db_sender_external:[177,4,1,""],db_sender_objects:[177,4,1,""],db_sender_scripts:[177,4,1,""],db_tags:[177,4,1,""],get_next_by_db_date_created:[177,3,1,""],get_previous_by_db_date_created:[177,3,1,""],header:[177,3,1,""],hide_from:[177,3,1,""],id:[177,4,1,""],lock_storage:[177,3,1,""],locks:[177,4,1,""],message:[177,3,1,""],objects:[177,4,1,""],path:[177,4,1,""],receivers:[177,3,1,""],remove_receiver:[177,3,1,""],remove_sender:[177,3,1,""],sender_external:[177,3,1,""],senders:[177,3,1,""],tags:[177,4,1,""],typename:[177,4,1,""]},"evennia.comms.models.TempMsg":{__init__:[177,3,1,""],access:[177,3,1,""],locks:[177,4,1,""],remove_receiver:[177,3,1,""],remove_sender:[177,3,1,""]},"evennia.contrib":{barter:[179,0,0,"-"],building_menu:[180,0,0,"-"],chargen:[181,0,0,"-"],clothing:[182,0,0,"-"],color_markups:[183,0,0,"-"],custom_gametime:[184,0,0,"-"],dice:[185,0,0,"-"],email_login:[186,0,0,"-"],extended_room:[187,0,0,"-"],fieldfill:[188,0,0,"-"],gendersub:[189,0,0,"-"],health_bar:[190,0,0,"-"],ingame_python:[191,0,0,"-"],mail:[199,0,0,"-"],multidescer:[202,0,0,"-"],puzzles:[203,0,0,"-"],random_string_generator:[204,0,0,"-"],rplanguage:[205,0,0,"-"],rpsystem:[206,0,0,"-"],security:[207,0,0,"-"],simpledoor:[212,0,0,"-"],slow_exit:[213,0,0,"-"],talking_npc:[214,0,0,"-"],tree_select:[215,0,0,"-"],turnbattle:[216,0,0,"-"],tutorial_examples:[222,0,0,"-"],tutorial_world:[229,0,0,"-"],unixcommand:[234,0,0,"-"],wilderness:[235,0,0,"-"]},"evennia.contrib.barter":{CmdAccept:[179,1,1,""],CmdDecline:[179,1,1,""],CmdEvaluate:[179,1,1,""],CmdFinish:[179,1,1,""],CmdOffer:[179,1,1,""],CmdStatus:[179,1,1,""],CmdTrade:[179,1,1,""],CmdTradeBase:[179,1,1,""],CmdTradeHelp:[179,1,1,""],CmdsetTrade:[179,1,1,""],TradeHandler:[179,1,1,""],TradeTimeout:[179,1,1,""]},"evennia.contrib.barter.CmdAccept":{aliases:[179,4,1,""],func:[179,3,1,""],help_category:[179,4,1,""],key:[179,4,1,""],lock_storage:[179,4,1,""],locks:[179,4,1,""]},"evennia.contrib.barter.CmdDecline":{aliases:[179,4,1,""],func:[179,3,1,""],help_category:[179,4,1,""],key:[179,4,1,""],lock_storage:[179,4,1,""],locks:[179,4,1,""]},"evennia.contrib.barter.CmdEvaluate":{aliases:[179,4,1,""],func:[179,3,1,""],help_category:[179,4,1,""],key:[179,4,1,""],lock_storage:[179,4,1,""],locks:[179,4,1,""]},"evennia.contrib.barter.CmdFinish":{aliases:[179,4,1,""],func:[179,3,1,""],help_category:[179,4,1,""],key:[179,4,1,""],lock_storage:[179,4,1,""],locks:[179,4,1,""]},"evennia.contrib.barter.CmdOffer":{aliases:[179,4,1,""],func:[179,3,1,""],help_category:[179,4,1,""],key:[179,4,1,""],lock_storage:[179,4,1,""],locks:[179,4,1,""]},"evennia.contrib.barter.CmdStatus":{aliases:[179,4,1,""],func:[179,3,1,""],help_category:[179,4,1,""],key:[179,4,1,""],lock_storage:[179,4,1,""],locks:[179,4,1,""]},"evennia.contrib.barter.CmdTrade":{aliases:[179,4,1,""],func:[179,3,1,""],help_category:[179,4,1,""],key:[179,4,1,""],lock_storage:[179,4,1,""],locks:[179,4,1,""]},"evennia.contrib.barter.CmdTradeBase":{aliases:[179,4,1,""],help_category:[179,4,1,""],key:[179,4,1,""],lock_storage:[179,4,1,""],parse:[179,3,1,""]},"evennia.contrib.barter.CmdTradeHelp":{aliases:[179,4,1,""],func:[179,3,1,""],help_category:[179,4,1,""],key:[179,4,1,""],lock_storage:[179,4,1,""],locks:[179,4,1,""]},"evennia.contrib.barter.CmdsetTrade":{at_cmdset_creation:[179,3,1,""],key:[179,4,1,""],path:[179,4,1,""]},"evennia.contrib.barter.TradeHandler":{__init__:[179,3,1,""],accept:[179,3,1,""],decline:[179,3,1,""],finish:[179,3,1,""],get_other:[179,3,1,""],join:[179,3,1,""],list:[179,3,1,""],msg_other:[179,3,1,""],offer:[179,3,1,""],search:[179,3,1,""],unjoin:[179,3,1,""]},"evennia.contrib.barter.TradeTimeout":{DoesNotExist:[179,2,1,""],MultipleObjectsReturned:[179,2,1,""],at_repeat:[179,3,1,""],at_script_creation:[179,3,1,""],is_valid:[179,3,1,""],path:[179,4,1,""],typename:[179,4,1,""]},"evennia.contrib.building_menu":{BuildingMenu:[180,1,1,""],BuildingMenuCmdSet:[180,1,1,""],Choice:[180,1,1,""],CmdNoInput:[180,1,1,""],CmdNoMatch:[180,1,1,""],GenericBuildingCmd:[180,1,1,""],GenericBuildingMenu:[180,1,1,""],menu_edit:[180,5,1,""],menu_quit:[180,5,1,""],menu_setattr:[180,5,1,""]},"evennia.contrib.building_menu.BuildingMenu":{__init__:[180,3,1,""],add_choice:[180,3,1,""],add_choice_edit:[180,3,1,""],add_choice_quit:[180,3,1,""],close:[180,3,1,""],current_choice:[180,3,1,""],display:[180,3,1,""],display_choice:[180,3,1,""],display_title:[180,3,1,""],init:[180,3,1,""],joker_key:[180,4,1,""],keys_go_back:[180,4,1,""],min_shortcut:[180,4,1,""],move:[180,3,1,""],open:[180,3,1,""],open_parent_menu:[180,3,1,""],open_submenu:[180,3,1,""],relevant_choices:[180,3,1,""],restore:[180,3,1,""],sep_keys:[180,4,1,""]},"evennia.contrib.building_menu.BuildingMenuCmdSet":{at_cmdset_creation:[180,3,1,""],key:[180,4,1,""],path:[180,4,1,""],priority:[180,4,1,""]},"evennia.contrib.building_menu.Choice":{__init__:[180,3,1,""],enter:[180,3,1,""],format_text:[180,3,1,""],keys:[180,3,1,""],leave:[180,3,1,""],nomatch:[180,3,1,""]},"evennia.contrib.building_menu.CmdNoInput":{__init__:[180,3,1,""],aliases:[180,4,1,""],func:[180,3,1,""],help_category:[180,4,1,""],key:[180,4,1,""],lock_storage:[180,4,1,""],locks:[180,4,1,""]},"evennia.contrib.building_menu.CmdNoMatch":{__init__:[180,3,1,""],aliases:[180,4,1,""],func:[180,3,1,""],help_category:[180,4,1,""],key:[180,4,1,""],lock_storage:[180,4,1,""],locks:[180,4,1,""]},"evennia.contrib.building_menu.GenericBuildingCmd":{aliases:[180,4,1,""],func:[180,3,1,""],help_category:[180,4,1,""],key:[180,4,1,""],lock_storage:[180,4,1,""]},"evennia.contrib.building_menu.GenericBuildingMenu":{init:[180,3,1,""]},"evennia.contrib.chargen":{CmdOOCCharacterCreate:[181,1,1,""],CmdOOCLook:[181,1,1,""],OOCCmdSetCharGen:[181,1,1,""]},"evennia.contrib.chargen.CmdOOCCharacterCreate":{aliases:[181,4,1,""],func:[181,3,1,""],help_category:[181,4,1,""],key:[181,4,1,""],lock_storage:[181,4,1,""],locks:[181,4,1,""]},"evennia.contrib.chargen.CmdOOCLook":{aliases:[181,4,1,""],func:[181,3,1,""],help_category:[181,4,1,""],key:[181,4,1,""],lock_storage:[181,4,1,""],locks:[181,4,1,""]},"evennia.contrib.chargen.OOCCmdSetCharGen":{at_cmdset_creation:[181,3,1,""],path:[181,4,1,""]},"evennia.contrib.clothing":{ClothedCharacter:[182,1,1,""],ClothedCharacterCmdSet:[182,1,1,""],Clothing:[182,1,1,""],CmdCover:[182,1,1,""],CmdDrop:[182,1,1,""],CmdGive:[182,1,1,""],CmdInventory:[182,1,1,""],CmdRemove:[182,1,1,""],CmdUncover:[182,1,1,""],CmdWear:[182,1,1,""],clothing_type_count:[182,5,1,""],get_worn_clothes:[182,5,1,""],order_clothes_list:[182,5,1,""],single_type_count:[182,5,1,""]},"evennia.contrib.clothing.ClothedCharacter":{DoesNotExist:[182,2,1,""],MultipleObjectsReturned:[182,2,1,""],path:[182,4,1,""],return_appearance:[182,3,1,""],typename:[182,4,1,""]},"evennia.contrib.clothing.ClothedCharacterCmdSet":{at_cmdset_creation:[182,3,1,""],key:[182,4,1,""],path:[182,4,1,""]},"evennia.contrib.clothing.Clothing":{DoesNotExist:[182,2,1,""],MultipleObjectsReturned:[182,2,1,""],at_get:[182,3,1,""],path:[182,4,1,""],remove:[182,3,1,""],typename:[182,4,1,""],wear:[182,3,1,""]},"evennia.contrib.clothing.CmdCover":{aliases:[182,4,1,""],func:[182,3,1,""],help_category:[182,4,1,""],key:[182,4,1,""],lock_storage:[182,4,1,""]},"evennia.contrib.clothing.CmdDrop":{aliases:[182,4,1,""],arg_regex:[182,4,1,""],func:[182,3,1,""],help_category:[182,4,1,""],key:[182,4,1,""],lock_storage:[182,4,1,""],locks:[182,4,1,""]},"evennia.contrib.clothing.CmdGive":{aliases:[182,4,1,""],arg_regex:[182,4,1,""],func:[182,3,1,""],help_category:[182,4,1,""],key:[182,4,1,""],lock_storage:[182,4,1,""],locks:[182,4,1,""]},"evennia.contrib.clothing.CmdInventory":{aliases:[182,4,1,""],arg_regex:[182,4,1,""],func:[182,3,1,""],help_category:[182,4,1,""],key:[182,4,1,""],lock_storage:[182,4,1,""],locks:[182,4,1,""]},"evennia.contrib.clothing.CmdRemove":{aliases:[182,4,1,""],func:[182,3,1,""],help_category:[182,4,1,""],key:[182,4,1,""],lock_storage:[182,4,1,""]},"evennia.contrib.clothing.CmdUncover":{aliases:[182,4,1,""],func:[182,3,1,""],help_category:[182,4,1,""],key:[182,4,1,""],lock_storage:[182,4,1,""]},"evennia.contrib.clothing.CmdWear":{aliases:[182,4,1,""],func:[182,3,1,""],help_category:[182,4,1,""],key:[182,4,1,""],lock_storage:[182,4,1,""]},"evennia.contrib.custom_gametime":{GametimeScript:[184,1,1,""],custom_gametime:[184,5,1,""],gametime_to_realtime:[184,5,1,""],real_seconds_until:[184,5,1,""],realtime_to_gametime:[184,5,1,""],schedule:[184,5,1,""],time_to_tuple:[184,5,1,""]},"evennia.contrib.custom_gametime.GametimeScript":{DoesNotExist:[184,2,1,""],MultipleObjectsReturned:[184,2,1,""],at_repeat:[184,3,1,""],at_script_creation:[184,3,1,""],path:[184,4,1,""],typename:[184,4,1,""]},"evennia.contrib.dice":{CmdDice:[185,1,1,""],DiceCmdSet:[185,1,1,""],roll_dice:[185,5,1,""]},"evennia.contrib.dice.CmdDice":{aliases:[185,4,1,""],func:[185,3,1,""],help_category:[185,4,1,""],key:[185,4,1,""],lock_storage:[185,4,1,""],locks:[185,4,1,""]},"evennia.contrib.dice.DiceCmdSet":{at_cmdset_creation:[185,3,1,""],path:[185,4,1,""]},"evennia.contrib.email_login":{CmdUnconnectedConnect:[186,1,1,""],CmdUnconnectedCreate:[186,1,1,""],CmdUnconnectedHelp:[186,1,1,""],CmdUnconnectedLook:[186,1,1,""],CmdUnconnectedQuit:[186,1,1,""]},"evennia.contrib.email_login.CmdUnconnectedConnect":{aliases:[186,4,1,""],func:[186,3,1,""],help_category:[186,4,1,""],key:[186,4,1,""],lock_storage:[186,4,1,""],locks:[186,4,1,""]},"evennia.contrib.email_login.CmdUnconnectedCreate":{aliases:[186,4,1,""],func:[186,3,1,""],help_category:[186,4,1,""],key:[186,4,1,""],lock_storage:[186,4,1,""],locks:[186,4,1,""],parse:[186,3,1,""]},"evennia.contrib.email_login.CmdUnconnectedHelp":{aliases:[186,4,1,""],func:[186,3,1,""],help_category:[186,4,1,""],key:[186,4,1,""],lock_storage:[186,4,1,""],locks:[186,4,1,""]},"evennia.contrib.email_login.CmdUnconnectedLook":{aliases:[186,4,1,""],func:[186,3,1,""],help_category:[186,4,1,""],key:[186,4,1,""],lock_storage:[186,4,1,""],locks:[186,4,1,""]},"evennia.contrib.email_login.CmdUnconnectedQuit":{aliases:[186,4,1,""],func:[186,3,1,""],help_category:[186,4,1,""],key:[186,4,1,""],lock_storage:[186,4,1,""],locks:[186,4,1,""]},"evennia.contrib.extended_room":{CmdExtendedRoomDesc:[187,1,1,""],CmdExtendedRoomDetail:[187,1,1,""],CmdExtendedRoomGameTime:[187,1,1,""],CmdExtendedRoomLook:[187,1,1,""],ExtendedRoom:[187,1,1,""],ExtendedRoomCmdSet:[187,1,1,""]},"evennia.contrib.extended_room.CmdExtendedRoomDesc":{aliases:[187,4,1,""],func:[187,3,1,""],help_category:[187,4,1,""],key:[187,4,1,""],lock_storage:[187,4,1,""],reset_times:[187,3,1,""],switch_options:[187,4,1,""]},"evennia.contrib.extended_room.CmdExtendedRoomDetail":{aliases:[187,4,1,""],func:[187,3,1,""],help_category:[187,4,1,""],key:[187,4,1,""],lock_storage:[187,4,1,""],locks:[187,4,1,""]},"evennia.contrib.extended_room.CmdExtendedRoomGameTime":{aliases:[187,4,1,""],func:[187,3,1,""],help_category:[187,4,1,""],key:[187,4,1,""],lock_storage:[187,4,1,""],locks:[187,4,1,""]},"evennia.contrib.extended_room.CmdExtendedRoomLook":{aliases:[187,4,1,""],func:[187,3,1,""],help_category:[187,4,1,""],key:[187,4,1,""],lock_storage:[187,4,1,""]},"evennia.contrib.extended_room.ExtendedRoom":{DoesNotExist:[187,2,1,""],MultipleObjectsReturned:[187,2,1,""],at_object_creation:[187,3,1,""],del_detail:[187,3,1,""],get_time_and_season:[187,3,1,""],path:[187,4,1,""],replace_timeslots:[187,3,1,""],return_appearance:[187,3,1,""],return_detail:[187,3,1,""],set_detail:[187,3,1,""],typename:[187,4,1,""],update_current_description:[187,3,1,""]},"evennia.contrib.extended_room.ExtendedRoomCmdSet":{at_cmdset_creation:[187,3,1,""],path:[187,4,1,""]},"evennia.contrib.fieldfill":{CmdTestMenu:[188,1,1,""],FieldEvMenu:[188,1,1,""],display_formdata:[188,5,1,""],form_template_to_dict:[188,5,1,""],init_delayed_message:[188,5,1,""],init_fill_field:[188,5,1,""],menunode_fieldfill:[188,5,1,""],sendmessage:[188,5,1,""],verify_online_player:[188,5,1,""]},"evennia.contrib.fieldfill.CmdTestMenu":{aliases:[188,4,1,""],func:[188,3,1,""],help_category:[188,4,1,""],key:[188,4,1,""],lock_storage:[188,4,1,""]},"evennia.contrib.fieldfill.FieldEvMenu":{node_formatter:[188,3,1,""]},"evennia.contrib.gendersub":{GenderCharacter:[189,1,1,""],SetGender:[189,1,1,""]},"evennia.contrib.gendersub.GenderCharacter":{DoesNotExist:[189,2,1,""],MultipleObjectsReturned:[189,2,1,""],at_object_creation:[189,3,1,""],msg:[189,3,1,""],path:[189,4,1,""],typename:[189,4,1,""]},"evennia.contrib.gendersub.SetGender":{aliases:[189,4,1,""],func:[189,3,1,""],help_category:[189,4,1,""],key:[189,4,1,""],lock_storage:[189,4,1,""],locks:[189,4,1,""]},"evennia.contrib.health_bar":{display_meter:[190,5,1,""]},"evennia.contrib.ingame_python":{callbackhandler:[192,0,0,"-"],commands:[193,0,0,"-"],eventfuncs:[194,0,0,"-"],scripts:[195,0,0,"-"],tests:[196,0,0,"-"],utils:[198,0,0,"-"]},"evennia.contrib.ingame_python.callbackhandler":{Callback:[192,1,1,""],CallbackHandler:[192,1,1,""]},"evennia.contrib.ingame_python.callbackhandler.Callback":{author:[192,4,1,""],code:[192,4,1,""],created_on:[192,4,1,""],name:[192,4,1,""],number:[192,4,1,""],obj:[192,4,1,""],parameters:[192,4,1,""],updated_by:[192,4,1,""],updated_on:[192,4,1,""],valid:[192,4,1,""]},"evennia.contrib.ingame_python.callbackhandler.CallbackHandler":{__init__:[192,3,1,""],add:[192,3,1,""],all:[192,3,1,""],call:[192,3,1,""],edit:[192,3,1,""],format_callback:[192,3,1,""],get:[192,3,1,""],get_variable:[192,3,1,""],remove:[192,3,1,""],script:[192,4,1,""]},"evennia.contrib.ingame_python.commands":{CmdCallback:[193,1,1,""]},"evennia.contrib.ingame_python.commands.CmdCallback":{accept_callback:[193,3,1,""],add_callback:[193,3,1,""],aliases:[193,4,1,""],del_callback:[193,3,1,""],edit_callback:[193,3,1,""],func:[193,3,1,""],get_help:[193,3,1,""],help_category:[193,4,1,""],key:[193,4,1,""],list_callbacks:[193,3,1,""],list_tasks:[193,3,1,""],lock_storage:[193,4,1,""],locks:[193,4,1,""]},"evennia.contrib.ingame_python.eventfuncs":{call_event:[194,5,1,""],deny:[194,5,1,""],get:[194,5,1,""]},"evennia.contrib.ingame_python.scripts":{EventHandler:[195,1,1,""],TimeEventScript:[195,1,1,""],complete_task:[195,5,1,""]},"evennia.contrib.ingame_python.scripts.EventHandler":{DoesNotExist:[195,2,1,""],MultipleObjectsReturned:[195,2,1,""],accept_callback:[195,3,1,""],add_callback:[195,3,1,""],add_event:[195,3,1,""],at_script_creation:[195,3,1,""],at_start:[195,3,1,""],call:[195,3,1,""],del_callback:[195,3,1,""],edit_callback:[195,3,1,""],get_callbacks:[195,3,1,""],get_events:[195,3,1,""],get_variable:[195,3,1,""],handle_error:[195,3,1,""],path:[195,4,1,""],set_task:[195,3,1,""],typename:[195,4,1,""]},"evennia.contrib.ingame_python.scripts.TimeEventScript":{DoesNotExist:[195,2,1,""],MultipleObjectsReturned:[195,2,1,""],at_repeat:[195,3,1,""],at_script_creation:[195,3,1,""],path:[195,4,1,""],typename:[195,4,1,""]},"evennia.contrib.ingame_python.tests":{TestCmdCallback:[196,1,1,""],TestDefaultCallbacks:[196,1,1,""],TestEventHandler:[196,1,1,""]},"evennia.contrib.ingame_python.tests.TestCmdCallback":{setUp:[196,3,1,""],tearDown:[196,3,1,""],test_accept:[196,3,1,""],test_add:[196,3,1,""],test_del:[196,3,1,""],test_list:[196,3,1,""],test_lock:[196,3,1,""]},"evennia.contrib.ingame_python.tests.TestDefaultCallbacks":{setUp:[196,3,1,""],tearDown:[196,3,1,""],test_exit:[196,3,1,""]},"evennia.contrib.ingame_python.tests.TestEventHandler":{setUp:[196,3,1,""],tearDown:[196,3,1,""],test_accept:[196,3,1,""],test_add_validation:[196,3,1,""],test_call:[196,3,1,""],test_del:[196,3,1,""],test_edit:[196,3,1,""],test_edit_validation:[196,3,1,""],test_handler:[196,3,1,""],test_start:[196,3,1,""]},"evennia.contrib.ingame_python.utils":{InterruptEvent:[198,2,1,""],get_event_handler:[198,5,1,""],get_next_wait:[198,5,1,""],keyword_event:[198,5,1,""],phrase_event:[198,5,1,""],register_events:[198,5,1,""],time_event:[198,5,1,""]},"evennia.contrib.mail":{CmdMail:[199,1,1,""],CmdMailCharacter:[199,1,1,""]},"evennia.contrib.mail.CmdMail":{aliases:[199,4,1,""],func:[199,3,1,""],get_all_mail:[199,3,1,""],help_category:[199,4,1,""],key:[199,4,1,""],lock:[199,4,1,""],lock_storage:[199,4,1,""],parse:[199,3,1,""],search_targets:[199,3,1,""],send_mail:[199,3,1,""]},"evennia.contrib.mail.CmdMailCharacter":{account_caller:[199,4,1,""],aliases:[199,4,1,""],help_category:[199,4,1,""],key:[199,4,1,""],lock_storage:[199,4,1,""]},"evennia.contrib.multidescer":{CmdMultiDesc:[202,1,1,""],DescValidateError:[202,2,1,""]},"evennia.contrib.multidescer.CmdMultiDesc":{aliases:[202,4,1,""],func:[202,3,1,""],help_category:[202,4,1,""],key:[202,4,1,""],lock_storage:[202,4,1,""],locks:[202,4,1,""]},"evennia.contrib.puzzles":{CmdArmPuzzle:[203,1,1,""],CmdCreatePuzzleRecipe:[203,1,1,""],CmdEditPuzzle:[203,1,1,""],CmdListArmedPuzzles:[203,1,1,""],CmdListPuzzleRecipes:[203,1,1,""],CmdUsePuzzleParts:[203,1,1,""],PuzzleRecipe:[203,1,1,""],PuzzleSystemCmdSet:[203,1,1,""],maskout_protodef:[203,5,1,""],proto_def:[203,5,1,""]},"evennia.contrib.puzzles.CmdArmPuzzle":{aliases:[203,4,1,""],func:[203,3,1,""],help_category:[203,4,1,""],key:[203,4,1,""],lock_storage:[203,4,1,""],locks:[203,4,1,""]},"evennia.contrib.puzzles.CmdCreatePuzzleRecipe":{aliases:[203,4,1,""],confirm:[203,4,1,""],default_confirm:[203,4,1,""],func:[203,3,1,""],help_category:[203,4,1,""],key:[203,4,1,""],lock_storage:[203,4,1,""],locks:[203,4,1,""]},"evennia.contrib.puzzles.CmdEditPuzzle":{aliases:[203,4,1,""],func:[203,3,1,""],help_category:[203,4,1,""],key:[203,4,1,""],lock_storage:[203,4,1,""],locks:[203,4,1,""]},"evennia.contrib.puzzles.CmdListArmedPuzzles":{aliases:[203,4,1,""],func:[203,3,1,""],help_category:[203,4,1,""],key:[203,4,1,""],lock_storage:[203,4,1,""],locks:[203,4,1,""]},"evennia.contrib.puzzles.CmdListPuzzleRecipes":{aliases:[203,4,1,""],func:[203,3,1,""],help_category:[203,4,1,""],key:[203,4,1,""],lock_storage:[203,4,1,""],locks:[203,4,1,""]},"evennia.contrib.puzzles.CmdUsePuzzleParts":{aliases:[203,4,1,""],func:[203,3,1,""],help_category:[203,4,1,""],key:[203,4,1,""],lock_storage:[203,4,1,""],locks:[203,4,1,""]},"evennia.contrib.puzzles.PuzzleRecipe":{DoesNotExist:[203,2,1,""],MultipleObjectsReturned:[203,2,1,""],path:[203,4,1,""],save_recipe:[203,3,1,""],typename:[203,4,1,""]},"evennia.contrib.puzzles.PuzzleSystemCmdSet":{at_cmdset_creation:[203,3,1,""],path:[203,4,1,""]},"evennia.contrib.random_string_generator":{ExhaustedGenerator:[204,2,1,""],RandomStringGenerator:[204,1,1,""],RandomStringGeneratorScript:[204,1,1,""],RejectedRegex:[204,2,1,""]},"evennia.contrib.random_string_generator.RandomStringGenerator":{__init__:[204,3,1,""],all:[204,3,1,""],clear:[204,3,1,""],get:[204,3,1,""],remove:[204,3,1,""],script:[204,4,1,""]},"evennia.contrib.random_string_generator.RandomStringGeneratorScript":{DoesNotExist:[204,2,1,""],MultipleObjectsReturned:[204,2,1,""],at_script_creation:[204,3,1,""],path:[204,4,1,""],typename:[204,4,1,""]},"evennia.contrib.rplanguage":{LanguageError:[205,2,1,""],LanguageExistsError:[205,2,1,""],LanguageHandler:[205,1,1,""],add_language:[205,5,1,""],available_languages:[205,5,1,""],obfuscate_language:[205,5,1,""],obfuscate_whisper:[205,5,1,""]},"evennia.contrib.rplanguage.LanguageHandler":{DoesNotExist:[205,2,1,""],MultipleObjectsReturned:[205,2,1,""],add:[205,3,1,""],at_script_creation:[205,3,1,""],path:[205,4,1,""],translate:[205,3,1,""],typename:[205,4,1,""]},"evennia.contrib.rpsystem":{CmdEmote:[206,1,1,""],CmdMask:[206,1,1,""],CmdPose:[206,1,1,""],CmdRecog:[206,1,1,""],CmdSay:[206,1,1,""],CmdSdesc:[206,1,1,""],ContribRPCharacter:[206,1,1,""],ContribRPObject:[206,1,1,""],ContribRPRoom:[206,1,1,""],EmoteError:[206,2,1,""],LanguageError:[206,2,1,""],RPCommand:[206,1,1,""],RPSystemCmdSet:[206,1,1,""],RecogError:[206,2,1,""],RecogHandler:[206,1,1,""],SdescError:[206,2,1,""],SdescHandler:[206,1,1,""],ordered_permutation_regex:[206,5,1,""],parse_language:[206,5,1,""],parse_sdescs_and_recogs:[206,5,1,""],regex_tuple_from_key_alias:[206,5,1,""],send_emote:[206,5,1,""]},"evennia.contrib.rpsystem.CmdEmote":{aliases:[206,4,1,""],func:[206,3,1,""],help_category:[206,4,1,""],key:[206,4,1,""],lock_storage:[206,4,1,""],locks:[206,4,1,""]},"evennia.contrib.rpsystem.CmdMask":{aliases:[206,4,1,""],func:[206,3,1,""],help_category:[206,4,1,""],key:[206,4,1,""],lock_storage:[206,4,1,""]},"evennia.contrib.rpsystem.CmdPose":{aliases:[206,4,1,""],func:[206,3,1,""],help_category:[206,4,1,""],key:[206,4,1,""],lock_storage:[206,4,1,""],parse:[206,3,1,""]},"evennia.contrib.rpsystem.CmdRecog":{aliases:[206,4,1,""],func:[206,3,1,""],help_category:[206,4,1,""],key:[206,4,1,""],lock_storage:[206,4,1,""],parse:[206,3,1,""]},"evennia.contrib.rpsystem.CmdSay":{aliases:[206,4,1,""],func:[206,3,1,""],help_category:[206,4,1,""],key:[206,4,1,""],lock_storage:[206,4,1,""],locks:[206,4,1,""]},"evennia.contrib.rpsystem.CmdSdesc":{aliases:[206,4,1,""],func:[206,3,1,""],help_category:[206,4,1,""],key:[206,4,1,""],lock_storage:[206,4,1,""],locks:[206,4,1,""]},"evennia.contrib.rpsystem.ContribRPCharacter":{DoesNotExist:[206,2,1,""],MultipleObjectsReturned:[206,2,1,""],at_before_say:[206,3,1,""],at_object_creation:[206,3,1,""],get_display_name:[206,3,1,""],path:[206,4,1,""],process_language:[206,3,1,""],process_recog:[206,3,1,""],process_sdesc:[206,3,1,""],recog:[206,4,1,""],sdesc:[206,4,1,""],typename:[206,4,1,""]},"evennia.contrib.rpsystem.ContribRPObject":{DoesNotExist:[206,2,1,""],MultipleObjectsReturned:[206,2,1,""],at_object_creation:[206,3,1,""],get_display_name:[206,3,1,""],path:[206,4,1,""],return_appearance:[206,3,1,""],search:[206,3,1,""],typename:[206,4,1,""]},"evennia.contrib.rpsystem.ContribRPRoom":{DoesNotExist:[206,2,1,""],MultipleObjectsReturned:[206,2,1,""],path:[206,4,1,""],typename:[206,4,1,""]},"evennia.contrib.rpsystem.RPCommand":{aliases:[206,4,1,""],help_category:[206,4,1,""],key:[206,4,1,""],lock_storage:[206,4,1,""],parse:[206,3,1,""]},"evennia.contrib.rpsystem.RPSystemCmdSet":{at_cmdset_creation:[206,3,1,""],path:[206,4,1,""]},"evennia.contrib.rpsystem.RecogHandler":{__init__:[206,3,1,""],add:[206,3,1,""],all:[206,3,1,""],get:[206,3,1,""],get_regex_tuple:[206,3,1,""],remove:[206,3,1,""]},"evennia.contrib.rpsystem.SdescHandler":{__init__:[206,3,1,""],add:[206,3,1,""],get:[206,3,1,""],get_regex_tuple:[206,3,1,""]},"evennia.contrib.security":{auditing:[208,0,0,"-"]},"evennia.contrib.security.auditing":{outputs:[209,0,0,"-"],server:[210,0,0,"-"],tests:[211,0,0,"-"]},"evennia.contrib.security.auditing.outputs":{to_file:[209,5,1,""],to_syslog:[209,5,1,""]},"evennia.contrib.security.auditing.server":{AuditedServerSession:[210,1,1,""]},"evennia.contrib.security.auditing.server.AuditedServerSession":{audit:[210,3,1,""],data_in:[210,3,1,""],data_out:[210,3,1,""],mask:[210,3,1,""]},"evennia.contrib.security.auditing.tests":{AuditingTest:[211,1,1,""]},"evennia.contrib.security.auditing.tests.AuditingTest":{test_audit:[211,3,1,""],test_mask:[211,3,1,""]},"evennia.contrib.simpledoor":{CmdOpen:[212,1,1,""],CmdOpenCloseDoor:[212,1,1,""],SimpleDoor:[212,1,1,""]},"evennia.contrib.simpledoor.CmdOpen":{aliases:[212,4,1,""],create_exit:[212,3,1,""],help_category:[212,4,1,""],key:[212,4,1,""],lock_storage:[212,4,1,""]},"evennia.contrib.simpledoor.CmdOpenCloseDoor":{aliases:[212,4,1,""],func:[212,3,1,""],help_category:[212,4,1,""],key:[212,4,1,""],lock_storage:[212,4,1,""],locks:[212,4,1,""]},"evennia.contrib.simpledoor.SimpleDoor":{"delete":[212,3,1,""],DoesNotExist:[212,2,1,""],MultipleObjectsReturned:[212,2,1,""],at_failed_traverse:[212,3,1,""],at_object_creation:[212,3,1,""],path:[212,4,1,""],setdesc:[212,3,1,""],setlock:[212,3,1,""],typename:[212,4,1,""]},"evennia.contrib.slow_exit":{CmdSetSpeed:[213,1,1,""],CmdStop:[213,1,1,""],SlowExit:[213,1,1,""]},"evennia.contrib.slow_exit.CmdSetSpeed":{aliases:[213,4,1,""],func:[213,3,1,""],help_category:[213,4,1,""],key:[213,4,1,""],lock_storage:[213,4,1,""]},"evennia.contrib.slow_exit.CmdStop":{aliases:[213,4,1,""],func:[213,3,1,""],help_category:[213,4,1,""],key:[213,4,1,""],lock_storage:[213,4,1,""]},"evennia.contrib.slow_exit.SlowExit":{DoesNotExist:[213,2,1,""],MultipleObjectsReturned:[213,2,1,""],at_traverse:[213,3,1,""],path:[213,4,1,""],typename:[213,4,1,""]},"evennia.contrib.talking_npc":{CmdTalk:[214,1,1,""],END:[214,5,1,""],TalkingCmdSet:[214,1,1,""],TalkingNPC:[214,1,1,""],info1:[214,5,1,""],info2:[214,5,1,""],info3:[214,5,1,""],menu_start_node:[214,5,1,""]},"evennia.contrib.talking_npc.CmdTalk":{aliases:[214,4,1,""],func:[214,3,1,""],help_category:[214,4,1,""],key:[214,4,1,""],lock_storage:[214,4,1,""],locks:[214,4,1,""]},"evennia.contrib.talking_npc.TalkingCmdSet":{at_cmdset_creation:[214,3,1,""],key:[214,4,1,""],path:[214,4,1,""]},"evennia.contrib.talking_npc.TalkingNPC":{DoesNotExist:[214,2,1,""],MultipleObjectsReturned:[214,2,1,""],at_object_creation:[214,3,1,""],path:[214,4,1,""],typename:[214,4,1,""]},"evennia.contrib.tree_select":{CmdNameColor:[215,1,1,""],change_name_color:[215,5,1,""],dashcount:[215,5,1,""],go_up_one_category:[215,5,1,""],index_to_selection:[215,5,1,""],init_tree_selection:[215,5,1,""],is_category:[215,5,1,""],menunode_treeselect:[215,5,1,""],optlist_to_menuoptions:[215,5,1,""],parse_opts:[215,5,1,""]},"evennia.contrib.tree_select.CmdNameColor":{aliases:[215,4,1,""],func:[215,3,1,""],help_category:[215,4,1,""],key:[215,4,1,""],lock_storage:[215,4,1,""]},"evennia.contrib.turnbattle":{tb_basic:[217,0,0,"-"],tb_equip:[218,0,0,"-"],tb_items:[219,0,0,"-"],tb_magic:[220,0,0,"-"],tb_range:[221,0,0,"-"]},"evennia.contrib.turnbattle.tb_basic":{ACTIONS_PER_TURN:[217,6,1,""],BattleCmdSet:[217,1,1,""],CmdAttack:[217,1,1,""],CmdCombatHelp:[217,1,1,""],CmdDisengage:[217,1,1,""],CmdFight:[217,1,1,""],CmdPass:[217,1,1,""],CmdRest:[217,1,1,""],TBBasicCharacter:[217,1,1,""],TBBasicTurnHandler:[217,1,1,""],apply_damage:[217,5,1,""],at_defeat:[217,5,1,""],combat_cleanup:[217,5,1,""],get_attack:[217,5,1,""],get_damage:[217,5,1,""],get_defense:[217,5,1,""],is_in_combat:[217,5,1,""],is_turn:[217,5,1,""],resolve_attack:[217,5,1,""],roll_init:[217,5,1,""],spend_action:[217,5,1,""]},"evennia.contrib.turnbattle.tb_basic.BattleCmdSet":{at_cmdset_creation:[217,3,1,""],key:[217,4,1,""],path:[217,4,1,""]},"evennia.contrib.turnbattle.tb_basic.CmdAttack":{aliases:[217,4,1,""],func:[217,3,1,""],help_category:[217,4,1,""],key:[217,4,1,""],lock_storage:[217,4,1,""]},"evennia.contrib.turnbattle.tb_basic.CmdCombatHelp":{aliases:[217,4,1,""],func:[217,3,1,""],help_category:[217,4,1,""],key:[217,4,1,""],lock_storage:[217,4,1,""]},"evennia.contrib.turnbattle.tb_basic.CmdDisengage":{aliases:[217,4,1,""],func:[217,3,1,""],help_category:[217,4,1,""],key:[217,4,1,""],lock_storage:[217,4,1,""]},"evennia.contrib.turnbattle.tb_basic.CmdFight":{aliases:[217,4,1,""],func:[217,3,1,""],help_category:[217,4,1,""],key:[217,4,1,""],lock_storage:[217,4,1,""]},"evennia.contrib.turnbattle.tb_basic.CmdPass":{aliases:[217,4,1,""],func:[217,3,1,""],help_category:[217,4,1,""],key:[217,4,1,""],lock_storage:[217,4,1,""]},"evennia.contrib.turnbattle.tb_basic.CmdRest":{aliases:[217,4,1,""],func:[217,3,1,""],help_category:[217,4,1,""],key:[217,4,1,""],lock_storage:[217,4,1,""]},"evennia.contrib.turnbattle.tb_basic.TBBasicCharacter":{DoesNotExist:[217,2,1,""],MultipleObjectsReturned:[217,2,1,""],at_before_move:[217,3,1,""],at_object_creation:[217,3,1,""],path:[217,4,1,""],typename:[217,4,1,""]},"evennia.contrib.turnbattle.tb_basic.TBBasicTurnHandler":{DoesNotExist:[217,2,1,""],MultipleObjectsReturned:[217,2,1,""],at_repeat:[217,3,1,""],at_script_creation:[217,3,1,""],at_stop:[217,3,1,""],initialize_for_combat:[217,3,1,""],join_fight:[217,3,1,""],next_turn:[217,3,1,""],path:[217,4,1,""],start_turn:[217,3,1,""],turn_end_check:[217,3,1,""],typename:[217,4,1,""]},"evennia.contrib.turnbattle.tb_equip":{ACTIONS_PER_TURN:[218,6,1,""],BattleCmdSet:[218,1,1,""],CmdAttack:[218,1,1,""],CmdCombatHelp:[218,1,1,""],CmdDisengage:[218,1,1,""],CmdDoff:[218,1,1,""],CmdDon:[218,1,1,""],CmdFight:[218,1,1,""],CmdPass:[218,1,1,""],CmdRest:[218,1,1,""],CmdUnwield:[218,1,1,""],CmdWield:[218,1,1,""],TBEArmor:[218,1,1,""],TBEWeapon:[218,1,1,""],TBEquipCharacter:[218,1,1,""],TBEquipTurnHandler:[218,1,1,""],apply_damage:[218,5,1,""],at_defeat:[218,5,1,""],combat_cleanup:[218,5,1,""],get_attack:[218,5,1,""],get_damage:[218,5,1,""],get_defense:[218,5,1,""],is_in_combat:[218,5,1,""],is_turn:[218,5,1,""],resolve_attack:[218,5,1,""],roll_init:[218,5,1,""],spend_action:[218,5,1,""]},"evennia.contrib.turnbattle.tb_equip.BattleCmdSet":{at_cmdset_creation:[218,3,1,""],key:[218,4,1,""],path:[218,4,1,""]},"evennia.contrib.turnbattle.tb_equip.CmdAttack":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""]},"evennia.contrib.turnbattle.tb_equip.CmdCombatHelp":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""]},"evennia.contrib.turnbattle.tb_equip.CmdDisengage":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""]},"evennia.contrib.turnbattle.tb_equip.CmdDoff":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""]},"evennia.contrib.turnbattle.tb_equip.CmdDon":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""]},"evennia.contrib.turnbattle.tb_equip.CmdFight":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""]},"evennia.contrib.turnbattle.tb_equip.CmdPass":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""]},"evennia.contrib.turnbattle.tb_equip.CmdRest":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""]},"evennia.contrib.turnbattle.tb_equip.CmdUnwield":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""]},"evennia.contrib.turnbattle.tb_equip.CmdWield":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""]},"evennia.contrib.turnbattle.tb_equip.TBEArmor":{DoesNotExist:[218,2,1,""],MultipleObjectsReturned:[218,2,1,""],at_before_drop:[218,3,1,""],at_before_give:[218,3,1,""],at_drop:[218,3,1,""],at_give:[218,3,1,""],at_object_creation:[218,3,1,""],path:[218,4,1,""],typename:[218,4,1,""]},"evennia.contrib.turnbattle.tb_equip.TBEWeapon":{DoesNotExist:[218,2,1,""],MultipleObjectsReturned:[218,2,1,""],at_drop:[218,3,1,""],at_give:[218,3,1,""],at_object_creation:[218,3,1,""],path:[218,4,1,""],typename:[218,4,1,""]},"evennia.contrib.turnbattle.tb_equip.TBEquipCharacter":{DoesNotExist:[218,2,1,""],MultipleObjectsReturned:[218,2,1,""],at_before_move:[218,3,1,""],at_object_creation:[218,3,1,""],path:[218,4,1,""],typename:[218,4,1,""]},"evennia.contrib.turnbattle.tb_equip.TBEquipTurnHandler":{DoesNotExist:[218,2,1,""],MultipleObjectsReturned:[218,2,1,""],at_repeat:[218,3,1,""],at_script_creation:[218,3,1,""],at_stop:[218,3,1,""],initialize_for_combat:[218,3,1,""],join_fight:[218,3,1,""],next_turn:[218,3,1,""],path:[218,4,1,""],start_turn:[218,3,1,""],turn_end_check:[218,3,1,""],typename:[218,4,1,""]},"evennia.contrib.turnbattle.tb_items":{BattleCmdSet:[219,1,1,""],CmdAttack:[219,1,1,""],CmdCombatHelp:[219,1,1,""],CmdDisengage:[219,1,1,""],CmdFight:[219,1,1,""],CmdPass:[219,1,1,""],CmdRest:[219,1,1,""],CmdUse:[219,1,1,""],DEF_DOWN_MOD:[219,6,1,""],ITEMFUNCS:[219,6,1,""],TBItemsCharacter:[219,1,1,""],TBItemsCharacterTest:[219,1,1,""],TBItemsTurnHandler:[219,1,1,""],add_condition:[219,5,1,""],apply_damage:[219,5,1,""],at_defeat:[219,5,1,""],combat_cleanup:[219,5,1,""],condition_tickdown:[219,5,1,""],get_attack:[219,5,1,""],get_damage:[219,5,1,""],get_defense:[219,5,1,""],is_in_combat:[219,5,1,""],is_turn:[219,5,1,""],itemfunc_add_condition:[219,5,1,""],itemfunc_attack:[219,5,1,""],itemfunc_cure_condition:[219,5,1,""],itemfunc_heal:[219,5,1,""],resolve_attack:[219,5,1,""],roll_init:[219,5,1,""],spend_action:[219,5,1,""],spend_item_use:[219,5,1,""],use_item:[219,5,1,""]},"evennia.contrib.turnbattle.tb_items.BattleCmdSet":{at_cmdset_creation:[219,3,1,""],key:[219,4,1,""],path:[219,4,1,""]},"evennia.contrib.turnbattle.tb_items.CmdAttack":{aliases:[219,4,1,""],func:[219,3,1,""],help_category:[219,4,1,""],key:[219,4,1,""],lock_storage:[219,4,1,""]},"evennia.contrib.turnbattle.tb_items.CmdCombatHelp":{aliases:[219,4,1,""],func:[219,3,1,""],help_category:[219,4,1,""],key:[219,4,1,""],lock_storage:[219,4,1,""]},"evennia.contrib.turnbattle.tb_items.CmdDisengage":{aliases:[219,4,1,""],func:[219,3,1,""],help_category:[219,4,1,""],key:[219,4,1,""],lock_storage:[219,4,1,""]},"evennia.contrib.turnbattle.tb_items.CmdFight":{aliases:[219,4,1,""],func:[219,3,1,""],help_category:[219,4,1,""],key:[219,4,1,""],lock_storage:[219,4,1,""]},"evennia.contrib.turnbattle.tb_items.CmdPass":{aliases:[219,4,1,""],func:[219,3,1,""],help_category:[219,4,1,""],key:[219,4,1,""],lock_storage:[219,4,1,""]},"evennia.contrib.turnbattle.tb_items.CmdRest":{aliases:[219,4,1,""],func:[219,3,1,""],help_category:[219,4,1,""],key:[219,4,1,""],lock_storage:[219,4,1,""]},"evennia.contrib.turnbattle.tb_items.CmdUse":{aliases:[219,4,1,""],func:[219,3,1,""],help_category:[219,4,1,""],key:[219,4,1,""],lock_storage:[219,4,1,""]},"evennia.contrib.turnbattle.tb_items.TBItemsCharacter":{DoesNotExist:[219,2,1,""],MultipleObjectsReturned:[219,2,1,""],apply_turn_conditions:[219,3,1,""],at_before_move:[219,3,1,""],at_object_creation:[219,3,1,""],at_turn_start:[219,3,1,""],at_update:[219,3,1,""],path:[219,4,1,""],typename:[219,4,1,""]},"evennia.contrib.turnbattle.tb_items.TBItemsCharacterTest":{DoesNotExist:[219,2,1,""],MultipleObjectsReturned:[219,2,1,""],at_object_creation:[219,3,1,""],path:[219,4,1,""],typename:[219,4,1,""]},"evennia.contrib.turnbattle.tb_items.TBItemsTurnHandler":{DoesNotExist:[219,2,1,""],MultipleObjectsReturned:[219,2,1,""],at_repeat:[219,3,1,""],at_script_creation:[219,3,1,""],at_stop:[219,3,1,""],initialize_for_combat:[219,3,1,""],join_fight:[219,3,1,""],next_turn:[219,3,1,""],path:[219,4,1,""],start_turn:[219,3,1,""],turn_end_check:[219,3,1,""],typename:[219,4,1,""]},"evennia.contrib.turnbattle.tb_magic":{ACTIONS_PER_TURN:[220,6,1,""],BattleCmdSet:[220,1,1,""],CmdAttack:[220,1,1,""],CmdCast:[220,1,1,""],CmdCombatHelp:[220,1,1,""],CmdDisengage:[220,1,1,""],CmdFight:[220,1,1,""],CmdLearnSpell:[220,1,1,""],CmdPass:[220,1,1,""],CmdRest:[220,1,1,""],CmdStatus:[220,1,1,""],TBMagicCharacter:[220,1,1,""],TBMagicTurnHandler:[220,1,1,""],apply_damage:[220,5,1,""],at_defeat:[220,5,1,""],combat_cleanup:[220,5,1,""],get_attack:[220,5,1,""],get_damage:[220,5,1,""],get_defense:[220,5,1,""],is_in_combat:[220,5,1,""],is_turn:[220,5,1,""],resolve_attack:[220,5,1,""],roll_init:[220,5,1,""],spell_attack:[220,5,1,""],spell_conjure:[220,5,1,""],spell_healing:[220,5,1,""],spend_action:[220,5,1,""]},"evennia.contrib.turnbattle.tb_magic.BattleCmdSet":{at_cmdset_creation:[220,3,1,""],key:[220,4,1,""],path:[220,4,1,""]},"evennia.contrib.turnbattle.tb_magic.CmdAttack":{aliases:[220,4,1,""],func:[220,3,1,""],help_category:[220,4,1,""],key:[220,4,1,""],lock_storage:[220,4,1,""]},"evennia.contrib.turnbattle.tb_magic.CmdCast":{aliases:[220,4,1,""],func:[220,3,1,""],help_category:[220,4,1,""],key:[220,4,1,""],lock_storage:[220,4,1,""]},"evennia.contrib.turnbattle.tb_magic.CmdCombatHelp":{aliases:[220,4,1,""],func:[220,3,1,""],help_category:[220,4,1,""],key:[220,4,1,""],lock_storage:[220,4,1,""]},"evennia.contrib.turnbattle.tb_magic.CmdDisengage":{aliases:[220,4,1,""],func:[220,3,1,""],help_category:[220,4,1,""],key:[220,4,1,""],lock_storage:[220,4,1,""]},"evennia.contrib.turnbattle.tb_magic.CmdFight":{aliases:[220,4,1,""],func:[220,3,1,""],help_category:[220,4,1,""],key:[220,4,1,""],lock_storage:[220,4,1,""]},"evennia.contrib.turnbattle.tb_magic.CmdLearnSpell":{aliases:[220,4,1,""],func:[220,3,1,""],help_category:[220,4,1,""],key:[220,4,1,""],lock_storage:[220,4,1,""]},"evennia.contrib.turnbattle.tb_magic.CmdPass":{aliases:[220,4,1,""],func:[220,3,1,""],help_category:[220,4,1,""],key:[220,4,1,""],lock_storage:[220,4,1,""]},"evennia.contrib.turnbattle.tb_magic.CmdRest":{aliases:[220,4,1,""],func:[220,3,1,""],help_category:[220,4,1,""],key:[220,4,1,""],lock_storage:[220,4,1,""]},"evennia.contrib.turnbattle.tb_magic.CmdStatus":{aliases:[220,4,1,""],func:[220,3,1,""],help_category:[220,4,1,""],key:[220,4,1,""],lock_storage:[220,4,1,""]},"evennia.contrib.turnbattle.tb_magic.TBMagicCharacter":{DoesNotExist:[220,2,1,""],MultipleObjectsReturned:[220,2,1,""],at_before_move:[220,3,1,""],at_object_creation:[220,3,1,""],path:[220,4,1,""],typename:[220,4,1,""]},"evennia.contrib.turnbattle.tb_magic.TBMagicTurnHandler":{DoesNotExist:[220,2,1,""],MultipleObjectsReturned:[220,2,1,""],at_repeat:[220,3,1,""],at_script_creation:[220,3,1,""],at_stop:[220,3,1,""],initialize_for_combat:[220,3,1,""],join_fight:[220,3,1,""],next_turn:[220,3,1,""],path:[220,4,1,""],start_turn:[220,3,1,""],turn_end_check:[220,3,1,""],typename:[220,4,1,""]},"evennia.contrib.turnbattle.tb_range":{ACTIONS_PER_TURN:[221,6,1,""],BattleCmdSet:[221,1,1,""],CmdApproach:[221,1,1,""],CmdAttack:[221,1,1,""],CmdCombatHelp:[221,1,1,""],CmdDisengage:[221,1,1,""],CmdFight:[221,1,1,""],CmdPass:[221,1,1,""],CmdRest:[221,1,1,""],CmdShoot:[221,1,1,""],CmdStatus:[221,1,1,""],CmdWithdraw:[221,1,1,""],TBRangeCharacter:[221,1,1,""],TBRangeObject:[221,1,1,""],TBRangeTurnHandler:[221,1,1,""],apply_damage:[221,5,1,""],approach:[221,5,1,""],at_defeat:[221,5,1,""],combat_cleanup:[221,5,1,""],combat_status_message:[221,5,1,""],distance_inc:[221,5,1,""],get_attack:[221,5,1,""],get_damage:[221,5,1,""],get_defense:[221,5,1,""],get_range:[221,5,1,""],is_in_combat:[221,5,1,""],is_turn:[221,5,1,""],resolve_attack:[221,5,1,""],roll_init:[221,5,1,""],spend_action:[221,5,1,""],withdraw:[221,5,1,""]},"evennia.contrib.turnbattle.tb_range.BattleCmdSet":{at_cmdset_creation:[221,3,1,""],key:[221,4,1,""],path:[221,4,1,""]},"evennia.contrib.turnbattle.tb_range.CmdApproach":{aliases:[221,4,1,""],func:[221,3,1,""],help_category:[221,4,1,""],key:[221,4,1,""],lock_storage:[221,4,1,""]},"evennia.contrib.turnbattle.tb_range.CmdAttack":{aliases:[221,4,1,""],func:[221,3,1,""],help_category:[221,4,1,""],key:[221,4,1,""],lock_storage:[221,4,1,""]},"evennia.contrib.turnbattle.tb_range.CmdCombatHelp":{aliases:[221,4,1,""],func:[221,3,1,""],help_category:[221,4,1,""],key:[221,4,1,""],lock_storage:[221,4,1,""]},"evennia.contrib.turnbattle.tb_range.CmdDisengage":{aliases:[221,4,1,""],func:[221,3,1,""],help_category:[221,4,1,""],key:[221,4,1,""],lock_storage:[221,4,1,""]},"evennia.contrib.turnbattle.tb_range.CmdFight":{aliases:[221,4,1,""],func:[221,3,1,""],help_category:[221,4,1,""],key:[221,4,1,""],lock_storage:[221,4,1,""]},"evennia.contrib.turnbattle.tb_range.CmdPass":{aliases:[221,4,1,""],func:[221,3,1,""],help_category:[221,4,1,""],key:[221,4,1,""],lock_storage:[221,4,1,""]},"evennia.contrib.turnbattle.tb_range.CmdRest":{aliases:[221,4,1,""],func:[221,3,1,""],help_category:[221,4,1,""],key:[221,4,1,""],lock_storage:[221,4,1,""]},"evennia.contrib.turnbattle.tb_range.CmdShoot":{aliases:[221,4,1,""],func:[221,3,1,""],help_category:[221,4,1,""],key:[221,4,1,""],lock_storage:[221,4,1,""]},"evennia.contrib.turnbattle.tb_range.CmdStatus":{aliases:[221,4,1,""],func:[221,3,1,""],help_category:[221,4,1,""],key:[221,4,1,""],lock_storage:[221,4,1,""]},"evennia.contrib.turnbattle.tb_range.CmdWithdraw":{aliases:[221,4,1,""],func:[221,3,1,""],help_category:[221,4,1,""],key:[221,4,1,""],lock_storage:[221,4,1,""]},"evennia.contrib.turnbattle.tb_range.TBRangeCharacter":{DoesNotExist:[221,2,1,""],MultipleObjectsReturned:[221,2,1,""],at_before_move:[221,3,1,""],at_object_creation:[221,3,1,""],path:[221,4,1,""],typename:[221,4,1,""]},"evennia.contrib.turnbattle.tb_range.TBRangeObject":{DoesNotExist:[221,2,1,""],MultipleObjectsReturned:[221,2,1,""],at_before_drop:[221,3,1,""],at_before_get:[221,3,1,""],at_before_give:[221,3,1,""],at_drop:[221,3,1,""],at_get:[221,3,1,""],at_give:[221,3,1,""],path:[221,4,1,""],typename:[221,4,1,""]},"evennia.contrib.turnbattle.tb_range.TBRangeTurnHandler":{DoesNotExist:[221,2,1,""],MultipleObjectsReturned:[221,2,1,""],at_repeat:[221,3,1,""],at_script_creation:[221,3,1,""],at_stop:[221,3,1,""],init_range:[221,3,1,""],initialize_for_combat:[221,3,1,""],join_fight:[221,3,1,""],join_rangefield:[221,3,1,""],next_turn:[221,3,1,""],path:[221,4,1,""],start_turn:[221,3,1,""],turn_end_check:[221,3,1,""],typename:[221,4,1,""]},"evennia.contrib.tutorial_examples":{bodyfunctions:[223,0,0,"-"],cmdset_red_button:[224,0,0,"-"],red_button:[226,0,0,"-"],red_button_scripts:[227,0,0,"-"],tests:[228,0,0,"-"]},"evennia.contrib.tutorial_examples.bodyfunctions":{BodyFunctions:[223,1,1,""]},"evennia.contrib.tutorial_examples.bodyfunctions.BodyFunctions":{DoesNotExist:[223,2,1,""],MultipleObjectsReturned:[223,2,1,""],at_repeat:[223,3,1,""],at_script_creation:[223,3,1,""],path:[223,4,1,""],send_random_message:[223,3,1,""],typename:[223,4,1,""]},"evennia.contrib.tutorial_examples.cmdset_red_button":{BlindCmdSet:[224,1,1,""],CmdBlindHelp:[224,1,1,""],CmdBlindLook:[224,1,1,""],CmdCloseLid:[224,1,1,""],CmdNudge:[224,1,1,""],CmdOpenLid:[224,1,1,""],CmdPush:[224,1,1,""],CmdSmashGlass:[224,1,1,""],DefaultCmdSet:[224,1,1,""],LidClosedCmdSet:[224,1,1,""],LidOpenCmdSet:[224,1,1,""]},"evennia.contrib.tutorial_examples.cmdset_red_button.BlindCmdSet":{at_cmdset_creation:[224,3,1,""],key:[224,4,1,""],mergetype:[224,4,1,""],no_exits:[224,4,1,""],no_objs:[224,4,1,""],path:[224,4,1,""]},"evennia.contrib.tutorial_examples.cmdset_red_button.CmdBlindHelp":{aliases:[224,4,1,""],func:[224,3,1,""],help_category:[224,4,1,""],key:[224,4,1,""],lock_storage:[224,4,1,""],locks:[224,4,1,""]},"evennia.contrib.tutorial_examples.cmdset_red_button.CmdBlindLook":{aliases:[224,4,1,""],func:[224,3,1,""],help_category:[224,4,1,""],key:[224,4,1,""],lock_storage:[224,4,1,""],locks:[224,4,1,""]},"evennia.contrib.tutorial_examples.cmdset_red_button.CmdCloseLid":{aliases:[224,4,1,""],func:[224,3,1,""],help_category:[224,4,1,""],key:[224,4,1,""],lock_storage:[224,4,1,""],locks:[224,4,1,""]},"evennia.contrib.tutorial_examples.cmdset_red_button.CmdNudge":{aliases:[224,4,1,""],func:[224,3,1,""],help_category:[224,4,1,""],key:[224,4,1,""],lock_storage:[224,4,1,""],locks:[224,4,1,""]},"evennia.contrib.tutorial_examples.cmdset_red_button.CmdOpenLid":{aliases:[224,4,1,""],func:[224,3,1,""],help_category:[224,4,1,""],key:[224,4,1,""],lock_storage:[224,4,1,""],locks:[224,4,1,""]},"evennia.contrib.tutorial_examples.cmdset_red_button.CmdPush":{aliases:[224,4,1,""],func:[224,3,1,""],help_category:[224,4,1,""],key:[224,4,1,""],lock_storage:[224,4,1,""],locks:[224,4,1,""]},"evennia.contrib.tutorial_examples.cmdset_red_button.CmdSmashGlass":{aliases:[224,4,1,""],func:[224,3,1,""],help_category:[224,4,1,""],key:[224,4,1,""],lock_storage:[224,4,1,""],locks:[224,4,1,""]},"evennia.contrib.tutorial_examples.cmdset_red_button.DefaultCmdSet":{at_cmdset_creation:[224,3,1,""],key:[224,4,1,""],mergetype:[224,4,1,""],path:[224,4,1,""]},"evennia.contrib.tutorial_examples.cmdset_red_button.LidClosedCmdSet":{at_cmdset_creation:[224,3,1,""],key:[224,4,1,""],key_mergetype:[224,4,1,""],path:[224,4,1,""]},"evennia.contrib.tutorial_examples.cmdset_red_button.LidOpenCmdSet":{at_cmdset_creation:[224,3,1,""],key:[224,4,1,""],key_mergetype:[224,4,1,""],path:[224,4,1,""]},"evennia.contrib.tutorial_examples.red_button":{RedButton:[226,1,1,""]},"evennia.contrib.tutorial_examples.red_button.RedButton":{DoesNotExist:[226,2,1,""],MultipleObjectsReturned:[226,2,1,""],at_object_creation:[226,3,1,""],blink:[226,3,1,""],break_lamp:[226,3,1,""],close_lid:[226,3,1,""],open_lid:[226,3,1,""],path:[226,4,1,""],press_button:[226,3,1,""],typename:[226,4,1,""]},"evennia.contrib.tutorial_examples.red_button_scripts":{BlindedState:[227,1,1,""],BlinkButtonEvent:[227,1,1,""],CloseLidEvent:[227,1,1,""],ClosedLidState:[227,1,1,""],DeactivateButtonEvent:[227,1,1,""],OpenLidState:[227,1,1,""]},"evennia.contrib.tutorial_examples.red_button_scripts.BlindedState":{DoesNotExist:[227,2,1,""],MultipleObjectsReturned:[227,2,1,""],at_script_creation:[227,3,1,""],at_start:[227,3,1,""],at_stop:[227,3,1,""],path:[227,4,1,""],typename:[227,4,1,""]},"evennia.contrib.tutorial_examples.red_button_scripts.BlinkButtonEvent":{DoesNotExist:[227,2,1,""],MultipleObjectsReturned:[227,2,1,""],at_repeat:[227,3,1,""],at_script_creation:[227,3,1,""],is_valid:[227,3,1,""],path:[227,4,1,""],typename:[227,4,1,""]},"evennia.contrib.tutorial_examples.red_button_scripts.CloseLidEvent":{DoesNotExist:[227,2,1,""],MultipleObjectsReturned:[227,2,1,""],at_repeat:[227,3,1,""],at_script_creation:[227,3,1,""],is_valid:[227,3,1,""],path:[227,4,1,""],typename:[227,4,1,""]},"evennia.contrib.tutorial_examples.red_button_scripts.ClosedLidState":{DoesNotExist:[227,2,1,""],MultipleObjectsReturned:[227,2,1,""],at_script_creation:[227,3,1,""],at_start:[227,3,1,""],at_stop:[227,3,1,""],is_valid:[227,3,1,""],path:[227,4,1,""],typename:[227,4,1,""]},"evennia.contrib.tutorial_examples.red_button_scripts.DeactivateButtonEvent":{DoesNotExist:[227,2,1,""],MultipleObjectsReturned:[227,2,1,""],at_repeat:[227,3,1,""],at_script_creation:[227,3,1,""],at_start:[227,3,1,""],path:[227,4,1,""],typename:[227,4,1,""]},"evennia.contrib.tutorial_examples.red_button_scripts.OpenLidState":{DoesNotExist:[227,2,1,""],MultipleObjectsReturned:[227,2,1,""],at_script_creation:[227,3,1,""],at_start:[227,3,1,""],at_stop:[227,3,1,""],is_valid:[227,3,1,""],path:[227,4,1,""],typename:[227,4,1,""]},"evennia.contrib.tutorial_examples.tests":{TestBodyFunctions:[228,1,1,""]},"evennia.contrib.tutorial_examples.tests.TestBodyFunctions":{script_typeclass:[228,4,1,""],setUp:[228,3,1,""],tearDown:[228,3,1,""],test_at_repeat:[228,3,1,""],test_send_random_message:[228,3,1,""]},"evennia.contrib.tutorial_world":{intro_menu:[230,0,0,"-"],mob:[231,0,0,"-"],objects:[232,0,0,"-"],rooms:[233,0,0,"-"]},"evennia.contrib.tutorial_world.intro_menu":{DemoCommandSetComms:[230,1,1,""],DemoCommandSetHelp:[230,1,1,""],DemoCommandSetRoom:[230,1,1,""],TutorialEvMenu:[230,1,1,""],do_nothing:[230,5,1,""],goto_cleanup_cmdsets:[230,5,1,""],goto_command_demo_comms:[230,5,1,""],goto_command_demo_help:[230,5,1,""],goto_command_demo_room:[230,5,1,""],init_menu:[230,5,1,""],send_testing_tagged:[230,5,1,""]},"evennia.contrib.tutorial_world.intro_menu.DemoCommandSetComms":{at_cmdset_creation:[230,3,1,""],key:[230,4,1,""],no_exits:[230,4,1,""],no_objs:[230,4,1,""],path:[230,4,1,""],priority:[230,4,1,""]},"evennia.contrib.tutorial_world.intro_menu.DemoCommandSetHelp":{at_cmdset_creation:[230,3,1,""],key:[230,4,1,""],path:[230,4,1,""],priority:[230,4,1,""]},"evennia.contrib.tutorial_world.intro_menu.DemoCommandSetRoom":{at_cmdset_creation:[230,3,1,""],key:[230,4,1,""],no_exits:[230,4,1,""],no_objs:[230,4,1,""],path:[230,4,1,""],priority:[230,4,1,""]},"evennia.contrib.tutorial_world.intro_menu.TutorialEvMenu":{close_menu:[230,3,1,""],options_formatter:[230,3,1,""]},"evennia.contrib.tutorial_world.mob":{CmdMobOnOff:[231,1,1,""],Mob:[231,1,1,""],MobCmdSet:[231,1,1,""]},"evennia.contrib.tutorial_world.mob.CmdMobOnOff":{aliases:[231,4,1,""],func:[231,3,1,""],help_category:[231,4,1,""],key:[231,4,1,""],lock_storage:[231,4,1,""],locks:[231,4,1,""]},"evennia.contrib.tutorial_world.mob.Mob":{DoesNotExist:[231,2,1,""],MultipleObjectsReturned:[231,2,1,""],at_hit:[231,3,1,""],at_init:[231,3,1,""],at_new_arrival:[231,3,1,""],at_object_creation:[231,3,1,""],do_attack:[231,3,1,""],do_hunting:[231,3,1,""],do_patrol:[231,3,1,""],path:[231,4,1,""],set_alive:[231,3,1,""],set_dead:[231,3,1,""],start_attacking:[231,3,1,""],start_hunting:[231,3,1,""],start_idle:[231,3,1,""],start_patrolling:[231,3,1,""],typename:[231,4,1,""]},"evennia.contrib.tutorial_world.mob.MobCmdSet":{at_cmdset_creation:[231,3,1,""],path:[231,4,1,""]},"evennia.contrib.tutorial_world.objects":{CmdAttack:[232,1,1,""],CmdClimb:[232,1,1,""],CmdGetWeapon:[232,1,1,""],CmdLight:[232,1,1,""],CmdPressButton:[232,1,1,""],CmdRead:[232,1,1,""],CmdSetClimbable:[232,1,1,""],CmdSetCrumblingWall:[232,1,1,""],CmdSetLight:[232,1,1,""],CmdSetReadable:[232,1,1,""],CmdSetWeapon:[232,1,1,""],CmdSetWeaponRack:[232,1,1,""],CmdShiftRoot:[232,1,1,""],CrumblingWall:[232,1,1,""],LightSource:[232,1,1,""],Obelisk:[232,1,1,""],TutorialClimbable:[232,1,1,""],TutorialObject:[232,1,1,""],TutorialReadable:[232,1,1,""],Weapon:[232,1,1,""],WeaponRack:[232,1,1,""]},"evennia.contrib.tutorial_world.objects.CmdAttack":{aliases:[232,4,1,""],func:[232,3,1,""],help_category:[232,4,1,""],key:[232,4,1,""],lock_storage:[232,4,1,""],locks:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.CmdClimb":{aliases:[232,4,1,""],func:[232,3,1,""],help_category:[232,4,1,""],key:[232,4,1,""],lock_storage:[232,4,1,""],locks:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.CmdGetWeapon":{aliases:[232,4,1,""],func:[232,3,1,""],help_category:[232,4,1,""],key:[232,4,1,""],lock_storage:[232,4,1,""],locks:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.CmdLight":{aliases:[232,4,1,""],func:[232,3,1,""],help_category:[232,4,1,""],key:[232,4,1,""],lock_storage:[232,4,1,""],locks:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.CmdPressButton":{aliases:[232,4,1,""],func:[232,3,1,""],help_category:[232,4,1,""],key:[232,4,1,""],lock_storage:[232,4,1,""],locks:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.CmdRead":{aliases:[232,4,1,""],func:[232,3,1,""],help_category:[232,4,1,""],key:[232,4,1,""],lock_storage:[232,4,1,""],locks:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.CmdSetClimbable":{at_cmdset_creation:[232,3,1,""],path:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.CmdSetCrumblingWall":{at_cmdset_creation:[232,3,1,""],key:[232,4,1,""],path:[232,4,1,""],priority:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.CmdSetLight":{at_cmdset_creation:[232,3,1,""],key:[232,4,1,""],path:[232,4,1,""],priority:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.CmdSetReadable":{at_cmdset_creation:[232,3,1,""],path:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.CmdSetWeapon":{at_cmdset_creation:[232,3,1,""],path:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.CmdSetWeaponRack":{at_cmdset_creation:[232,3,1,""],key:[232,4,1,""],path:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.CmdShiftRoot":{aliases:[232,4,1,""],func:[232,3,1,""],help_category:[232,4,1,""],key:[232,4,1,""],lock_storage:[232,4,1,""],locks:[232,4,1,""],parse:[232,3,1,""]},"evennia.contrib.tutorial_world.objects.CrumblingWall":{DoesNotExist:[232,2,1,""],MultipleObjectsReturned:[232,2,1,""],at_after_traverse:[232,3,1,""],at_failed_traverse:[232,3,1,""],at_init:[232,3,1,""],at_object_creation:[232,3,1,""],open_wall:[232,3,1,""],path:[232,4,1,""],reset:[232,3,1,""],return_appearance:[232,3,1,""],typename:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.LightSource":{DoesNotExist:[232,2,1,""],MultipleObjectsReturned:[232,2,1,""],at_init:[232,3,1,""],at_object_creation:[232,3,1,""],light:[232,3,1,""],path:[232,4,1,""],typename:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.Obelisk":{DoesNotExist:[232,2,1,""],MultipleObjectsReturned:[232,2,1,""],at_object_creation:[232,3,1,""],path:[232,4,1,""],return_appearance:[232,3,1,""],typename:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.TutorialClimbable":{DoesNotExist:[232,2,1,""],MultipleObjectsReturned:[232,2,1,""],at_object_creation:[232,3,1,""],path:[232,4,1,""],typename:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.TutorialObject":{DoesNotExist:[232,2,1,""],MultipleObjectsReturned:[232,2,1,""],at_object_creation:[232,3,1,""],path:[232,4,1,""],reset:[232,3,1,""],typename:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.TutorialReadable":{DoesNotExist:[232,2,1,""],MultipleObjectsReturned:[232,2,1,""],at_object_creation:[232,3,1,""],path:[232,4,1,""],typename:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.Weapon":{DoesNotExist:[232,2,1,""],MultipleObjectsReturned:[232,2,1,""],at_object_creation:[232,3,1,""],path:[232,4,1,""],reset:[232,3,1,""],typename:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.WeaponRack":{DoesNotExist:[232,2,1,""],MultipleObjectsReturned:[232,2,1,""],at_object_creation:[232,3,1,""],path:[232,4,1,""],produce_weapon:[232,3,1,""],typename:[232,4,1,""]},"evennia.contrib.tutorial_world.rooms":{BridgeCmdSet:[233,1,1,""],BridgeRoom:[233,1,1,""],CmdBridgeHelp:[233,1,1,""],CmdDarkHelp:[233,1,1,""],CmdDarkNoMatch:[233,1,1,""],CmdEast:[233,1,1,""],CmdEvenniaIntro:[233,1,1,""],CmdLookBridge:[233,1,1,""],CmdLookDark:[233,1,1,""],CmdSetEvenniaIntro:[233,1,1,""],CmdTutorial:[233,1,1,""],CmdTutorialGiveUp:[233,1,1,""],CmdTutorialLook:[233,1,1,""],CmdTutorialSetDetail:[233,1,1,""],CmdWest:[233,1,1,""],DarkCmdSet:[233,1,1,""],DarkRoom:[233,1,1,""],IntroRoom:[233,1,1,""],OutroRoom:[233,1,1,""],TeleportRoom:[233,1,1,""],TutorialRoom:[233,1,1,""],TutorialRoomCmdSet:[233,1,1,""],WeatherRoom:[233,1,1,""]},"evennia.contrib.tutorial_world.rooms.BridgeCmdSet":{at_cmdset_creation:[233,3,1,""],key:[233,4,1,""],path:[233,4,1,""],priority:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.BridgeRoom":{DoesNotExist:[233,2,1,""],MultipleObjectsReturned:[233,2,1,""],at_object_creation:[233,3,1,""],at_object_leave:[233,3,1,""],at_object_receive:[233,3,1,""],path:[233,4,1,""],typename:[233,4,1,""],update_weather:[233,3,1,""]},"evennia.contrib.tutorial_world.rooms.CmdBridgeHelp":{aliases:[233,4,1,""],func:[233,3,1,""],help_category:[233,4,1,""],key:[233,4,1,""],lock_storage:[233,4,1,""],locks:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.CmdDarkHelp":{aliases:[233,4,1,""],func:[233,3,1,""],help_category:[233,4,1,""],key:[233,4,1,""],lock_storage:[233,4,1,""],locks:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.CmdDarkNoMatch":{aliases:[233,4,1,""],func:[233,3,1,""],help_category:[233,4,1,""],key:[233,4,1,""],lock_storage:[233,4,1,""],locks:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.CmdEast":{aliases:[233,4,1,""],func:[233,3,1,""],help_category:[233,4,1,""],key:[233,4,1,""],lock_storage:[233,4,1,""],locks:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.CmdEvenniaIntro":{aliases:[233,4,1,""],func:[233,3,1,""],help_category:[233,4,1,""],key:[233,4,1,""],lock_storage:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.CmdLookBridge":{aliases:[233,4,1,""],func:[233,3,1,""],help_category:[233,4,1,""],key:[233,4,1,""],lock_storage:[233,4,1,""],locks:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.CmdLookDark":{aliases:[233,4,1,""],func:[233,3,1,""],help_category:[233,4,1,""],key:[233,4,1,""],lock_storage:[233,4,1,""],locks:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.CmdSetEvenniaIntro":{at_cmdset_creation:[233,3,1,""],key:[233,4,1,""],path:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.CmdTutorial":{aliases:[233,4,1,""],func:[233,3,1,""],help_category:[233,4,1,""],key:[233,4,1,""],lock_storage:[233,4,1,""],locks:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.CmdTutorialGiveUp":{aliases:[233,4,1,""],func:[233,3,1,""],help_category:[233,4,1,""],key:[233,4,1,""],lock_storage:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.CmdTutorialLook":{aliases:[233,4,1,""],func:[233,3,1,""],help_category:[233,4,1,""],key:[233,4,1,""],lock_storage:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.CmdTutorialSetDetail":{aliases:[233,4,1,""],func:[233,3,1,""],help_category:[233,4,1,""],key:[233,4,1,""],lock_storage:[233,4,1,""],locks:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.CmdWest":{aliases:[233,4,1,""],func:[233,3,1,""],help_category:[233,4,1,""],key:[233,4,1,""],lock_storage:[233,4,1,""],locks:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.DarkCmdSet":{at_cmdset_creation:[233,3,1,""],key:[233,4,1,""],mergetype:[233,4,1,""],path:[233,4,1,""],priority:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.DarkRoom":{DoesNotExist:[233,2,1,""],MultipleObjectsReturned:[233,2,1,""],at_init:[233,3,1,""],at_object_creation:[233,3,1,""],at_object_leave:[233,3,1,""],at_object_receive:[233,3,1,""],check_light_state:[233,3,1,""],path:[233,4,1,""],typename:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.IntroRoom":{DoesNotExist:[233,2,1,""],MultipleObjectsReturned:[233,2,1,""],at_object_creation:[233,3,1,""],at_object_receive:[233,3,1,""],path:[233,4,1,""],typename:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.OutroRoom":{DoesNotExist:[233,2,1,""],MultipleObjectsReturned:[233,2,1,""],at_object_creation:[233,3,1,""],at_object_leave:[233,3,1,""],at_object_receive:[233,3,1,""],path:[233,4,1,""],typename:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.TeleportRoom":{DoesNotExist:[233,2,1,""],MultipleObjectsReturned:[233,2,1,""],at_object_creation:[233,3,1,""],at_object_receive:[233,3,1,""],path:[233,4,1,""],typename:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.TutorialRoom":{DoesNotExist:[233,2,1,""],MultipleObjectsReturned:[233,2,1,""],at_object_creation:[233,3,1,""],at_object_receive:[233,3,1,""],path:[233,4,1,""],return_detail:[233,3,1,""],set_detail:[233,3,1,""],typename:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.TutorialRoomCmdSet":{at_cmdset_creation:[233,3,1,""],key:[233,4,1,""],path:[233,4,1,""],priority:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.WeatherRoom":{DoesNotExist:[233,2,1,""],MultipleObjectsReturned:[233,2,1,""],at_object_creation:[233,3,1,""],path:[233,4,1,""],typename:[233,4,1,""],update_weather:[233,3,1,""]},"evennia.contrib.unixcommand":{HelpAction:[234,1,1,""],ParseError:[234,2,1,""],UnixCommand:[234,1,1,""],UnixCommandParser:[234,1,1,""]},"evennia.contrib.unixcommand.UnixCommand":{__init__:[234,3,1,""],aliases:[234,4,1,""],func:[234,3,1,""],get_help:[234,3,1,""],help_category:[234,4,1,""],init_parser:[234,3,1,""],key:[234,4,1,""],lock_storage:[234,4,1,""],parse:[234,3,1,""]},"evennia.contrib.unixcommand.UnixCommandParser":{__init__:[234,3,1,""],format_help:[234,3,1,""],format_usage:[234,3,1,""],print_help:[234,3,1,""],print_usage:[234,3,1,""]},"evennia.contrib.wilderness":{WildernessExit:[235,1,1,""],WildernessMapProvider:[235,1,1,""],WildernessRoom:[235,1,1,""],WildernessScript:[235,1,1,""],create_wilderness:[235,5,1,""],enter_wilderness:[235,5,1,""],get_new_coordinates:[235,5,1,""]},"evennia.contrib.wilderness.WildernessExit":{DoesNotExist:[235,2,1,""],MultipleObjectsReturned:[235,2,1,""],at_traverse:[235,3,1,""],at_traverse_coordinates:[235,3,1,""],mapprovider:[235,3,1,""],path:[235,4,1,""],typename:[235,4,1,""],wilderness:[235,3,1,""]},"evennia.contrib.wilderness.WildernessMapProvider":{at_prepare_room:[235,3,1,""],exit_typeclass:[235,4,1,""],get_location_name:[235,3,1,""],is_valid_coordinates:[235,3,1,""],room_typeclass:[235,4,1,""]},"evennia.contrib.wilderness.WildernessRoom":{DoesNotExist:[235,2,1,""],MultipleObjectsReturned:[235,2,1,""],at_object_leave:[235,3,1,""],at_object_receive:[235,3,1,""],coordinates:[235,3,1,""],get_display_name:[235,3,1,""],location_name:[235,3,1,""],path:[235,4,1,""],set_active_coordinates:[235,3,1,""],typename:[235,4,1,""],wilderness:[235,3,1,""]},"evennia.contrib.wilderness.WildernessScript":{DoesNotExist:[235,2,1,""],MultipleObjectsReturned:[235,2,1,""],at_after_object_leave:[235,3,1,""],at_script_creation:[235,3,1,""],at_start:[235,3,1,""],get_obj_coordinates:[235,3,1,""],get_objs_at_coordinates:[235,3,1,""],is_valid_coordinates:[235,3,1,""],itemcoordinates:[235,3,1,""],mapprovider:[235,3,1,""],move_obj:[235,3,1,""],path:[235,4,1,""],typename:[235,4,1,""]},"evennia.help":{admin:[237,0,0,"-"],manager:[238,0,0,"-"],models:[239,0,0,"-"]},"evennia.help.admin":{HelpEntryAdmin:[237,1,1,""],HelpEntryForm:[237,1,1,""],HelpTagInline:[237,1,1,""]},"evennia.help.admin.HelpEntryAdmin":{fieldsets:[237,4,1,""],form:[237,4,1,""],inlines:[237,4,1,""],list_display:[237,4,1,""],list_display_links:[237,4,1,""],list_select_related:[237,4,1,""],media:[237,3,1,""],ordering:[237,4,1,""],save_as:[237,4,1,""],save_on_top:[237,4,1,""],search_fields:[237,4,1,""]},"evennia.help.admin.HelpEntryForm":{Meta:[237,1,1,""],base_fields:[237,4,1,""],declared_fields:[237,4,1,""],media:[237,3,1,""]},"evennia.help.admin.HelpEntryForm.Meta":{fields:[237,4,1,""],model:[237,4,1,""]},"evennia.help.admin.HelpTagInline":{media:[237,3,1,""],model:[237,4,1,""],related_field:[237,4,1,""]},"evennia.help.manager":{HelpEntryManager:[238,1,1,""]},"evennia.help.manager.HelpEntryManager":{all_to_category:[238,3,1,""],find_apropos:[238,3,1,""],find_topicmatch:[238,3,1,""],find_topics_with_category:[238,3,1,""],find_topicsuggestions:[238,3,1,""],get_all_categories:[238,3,1,""],get_all_topics:[238,3,1,""],search_help:[238,3,1,""]},"evennia.help.models":{HelpEntry:[239,1,1,""]},"evennia.help.models.HelpEntry":{DoesNotExist:[239,2,1,""],MultipleObjectsReturned:[239,2,1,""],access:[239,3,1,""],aliases:[239,4,1,""],db_entrytext:[239,4,1,""],db_help_category:[239,4,1,""],db_key:[239,4,1,""],db_lock_storage:[239,4,1,""],db_staff_only:[239,4,1,""],db_tags:[239,4,1,""],entrytext:[239,3,1,""],get_absolute_url:[239,3,1,""],help_category:[239,3,1,""],id:[239,4,1,""],key:[239,3,1,""],lock_storage:[239,3,1,""],locks:[239,4,1,""],objects:[239,4,1,""],path:[239,4,1,""],staff_only:[239,3,1,""],tags:[239,4,1,""],typename:[239,4,1,""],web_get_admin_url:[239,3,1,""],web_get_create_url:[239,3,1,""],web_get_delete_url:[239,3,1,""],web_get_detail_url:[239,3,1,""],web_get_update_url:[239,3,1,""]},"evennia.locks":{lockfuncs:[241,0,0,"-"],lockhandler:[242,0,0,"-"]},"evennia.locks.lockfuncs":{"false":[241,5,1,""],"true":[241,5,1,""],all:[241,5,1,""],attr:[241,5,1,""],attr_eq:[241,5,1,""],attr_ge:[241,5,1,""],attr_gt:[241,5,1,""],attr_le:[241,5,1,""],attr_lt:[241,5,1,""],attr_ne:[241,5,1,""],dbref:[241,5,1,""],has_account:[241,5,1,""],holds:[241,5,1,""],id:[241,5,1,""],inside:[241,5,1,""],inside_rec:[241,5,1,""],locattr:[241,5,1,""],none:[241,5,1,""],objattr:[241,5,1,""],objlocattr:[241,5,1,""],objtag:[241,5,1,""],pdbref:[241,5,1,""],perm:[241,5,1,""],perm_above:[241,5,1,""],pid:[241,5,1,""],pperm:[241,5,1,""],pperm_above:[241,5,1,""],self:[241,5,1,""],serversetting:[241,5,1,""],superuser:[241,5,1,""],tag:[241,5,1,""]},"evennia.locks.lockhandler":{LockException:[242,2,1,""],LockHandler:[242,1,1,""]},"evennia.locks.lockhandler.LockHandler":{"delete":[242,3,1,""],__init__:[242,3,1,""],add:[242,3,1,""],all:[242,3,1,""],append:[242,3,1,""],cache_lock_bypass:[242,3,1,""],check:[242,3,1,""],check_lockstring:[242,3,1,""],clear:[242,3,1,""],get:[242,3,1,""],remove:[242,3,1,""],replace:[242,3,1,""],reset:[242,3,1,""],validate:[242,3,1,""]},"evennia.objects":{admin:[244,0,0,"-"],manager:[245,0,0,"-"],models:[246,0,0,"-"],objects:[247,0,0,"-"]},"evennia.objects.admin":{ObjectAttributeInline:[244,1,1,""],ObjectCreateForm:[244,1,1,""],ObjectDBAdmin:[244,1,1,""],ObjectEditForm:[244,1,1,""],ObjectTagInline:[244,1,1,""]},"evennia.objects.admin.ObjectAttributeInline":{media:[244,3,1,""],model:[244,4,1,""],related_field:[244,4,1,""]},"evennia.objects.admin.ObjectCreateForm":{Meta:[244,1,1,""],base_fields:[244,4,1,""],declared_fields:[244,4,1,""],media:[244,3,1,""],raw_id_fields:[244,4,1,""]},"evennia.objects.admin.ObjectCreateForm.Meta":{fields:[244,4,1,""],model:[244,4,1,""]},"evennia.objects.admin.ObjectDBAdmin":{add_fieldsets:[244,4,1,""],add_form:[244,4,1,""],fieldsets:[244,4,1,""],form:[244,4,1,""],get_fieldsets:[244,3,1,""],get_form:[244,3,1,""],inlines:[244,4,1,""],list_display:[244,4,1,""],list_display_links:[244,4,1,""],list_filter:[244,4,1,""],list_select_related:[244,4,1,""],media:[244,3,1,""],ordering:[244,4,1,""],raw_id_fields:[244,4,1,""],response_add:[244,3,1,""],save_as:[244,4,1,""],save_model:[244,3,1,""],save_on_top:[244,4,1,""],search_fields:[244,4,1,""]},"evennia.objects.admin.ObjectEditForm":{Meta:[244,1,1,""],base_fields:[244,4,1,""],declared_fields:[244,4,1,""],media:[244,3,1,""]},"evennia.objects.admin.ObjectEditForm.Meta":{fields:[244,4,1,""]},"evennia.objects.admin.ObjectTagInline":{media:[244,3,1,""],model:[244,4,1,""],related_field:[244,4,1,""]},"evennia.objects.manager":{ObjectManager:[245,1,1,""]},"evennia.objects.models":{ContentsHandler:[246,1,1,""],ObjectDB:[246,1,1,""]},"evennia.objects.models.ContentsHandler":{__init__:[246,3,1,""],add:[246,3,1,""],clear:[246,3,1,""],get:[246,3,1,""],init:[246,3,1,""],remove:[246,3,1,""]},"evennia.objects.models.ObjectDB":{DoesNotExist:[246,2,1,""],MultipleObjectsReturned:[246,2,1,""],account:[246,3,1,""],at_db_location_postsave:[246,3,1,""],cmdset_storage:[246,3,1,""],contents_cache:[246,4,1,""],db_account:[246,4,1,""],db_account_id:[246,4,1,""],db_attributes:[246,4,1,""],db_cmdset_storage:[246,4,1,""],db_destination:[246,4,1,""],db_destination_id:[246,4,1,""],db_home:[246,4,1,""],db_home_id:[246,4,1,""],db_location:[246,4,1,""],db_location_id:[246,4,1,""],db_sessid:[246,4,1,""],db_tags:[246,4,1,""],destination:[246,3,1,""],destinations_set:[246,4,1,""],get_next_by_db_date_created:[246,3,1,""],get_previous_by_db_date_created:[246,3,1,""],hide_from_objects_set:[246,4,1,""],home:[246,3,1,""],homes_set:[246,4,1,""],id:[246,4,1,""],location:[246,3,1,""],locations_set:[246,4,1,""],object_subscription_set:[246,4,1,""],objects:[246,4,1,""],path:[246,4,1,""],receiver_object_set:[246,4,1,""],scriptdb_set:[246,4,1,""],sender_object_set:[246,4,1,""],sessid:[246,3,1,""],typename:[246,4,1,""]},"evennia.objects.objects":{DefaultCharacter:[247,1,1,""],DefaultExit:[247,1,1,""],DefaultObject:[247,1,1,""],DefaultRoom:[247,1,1,""],ExitCommand:[247,1,1,""],ObjectSessionHandler:[247,1,1,""]},"evennia.objects.objects.DefaultCharacter":{DoesNotExist:[247,2,1,""],MultipleObjectsReturned:[247,2,1,""],at_after_move:[247,3,1,""],at_post_puppet:[247,3,1,""],at_post_unpuppet:[247,3,1,""],at_pre_puppet:[247,3,1,""],basetype_setup:[247,3,1,""],connection_time:[247,3,1,""],create:[247,3,1,""],idle_time:[247,3,1,""],lockstring:[247,4,1,""],path:[247,4,1,""],typename:[247,4,1,""]},"evennia.objects.objects.DefaultExit":{DoesNotExist:[247,2,1,""],MultipleObjectsReturned:[247,2,1,""],at_cmdset_get:[247,3,1,""],at_failed_traverse:[247,3,1,""],at_init:[247,3,1,""],at_traverse:[247,3,1,""],basetype_setup:[247,3,1,""],create:[247,3,1,""],create_exit_cmdset:[247,3,1,""],exit_command:[247,4,1,""],lockstring:[247,4,1,""],path:[247,4,1,""],priority:[247,4,1,""],typename:[247,4,1,""]},"evennia.objects.objects.DefaultObject":{"delete":[247,3,1,""],DoesNotExist:[247,2,1,""],MultipleObjectsReturned:[247,2,1,""],access:[247,3,1,""],announce_move_from:[247,3,1,""],announce_move_to:[247,3,1,""],at_access:[247,3,1,""],at_after_move:[247,3,1,""],at_after_traverse:[247,3,1,""],at_before_drop:[247,3,1,""],at_before_get:[247,3,1,""],at_before_give:[247,3,1,""],at_before_move:[247,3,1,""],at_before_say:[247,3,1,""],at_cmdset_get:[247,3,1,""],at_desc:[247,3,1,""],at_drop:[247,3,1,""],at_failed_traverse:[247,3,1,""],at_first_save:[247,3,1,""],at_get:[247,3,1,""],at_give:[247,3,1,""],at_init:[247,3,1,""],at_look:[247,3,1,""],at_msg_receive:[247,3,1,""],at_msg_send:[247,3,1,""],at_object_creation:[247,3,1,""],at_object_delete:[247,3,1,""],at_object_leave:[247,3,1,""],at_object_post_copy:[247,3,1,""],at_object_receive:[247,3,1,""],at_post_puppet:[247,3,1,""],at_post_unpuppet:[247,3,1,""],at_pre_puppet:[247,3,1,""],at_pre_unpuppet:[247,3,1,""],at_say:[247,3,1,""],at_server_reload:[247,3,1,""],at_server_shutdown:[247,3,1,""],at_traverse:[247,3,1,""],basetype_posthook_setup:[247,3,1,""],basetype_setup:[247,3,1,""],clear_contents:[247,3,1,""],clear_exits:[247,3,1,""],cmdset:[247,4,1,""],contents:[247,3,1,""],contents_get:[247,3,1,""],contents_set:[247,3,1,""],copy:[247,3,1,""],create:[247,3,1,""],execute_cmd:[247,3,1,""],exits:[247,3,1,""],for_contents:[247,3,1,""],get_display_name:[247,3,1,""],get_numbered_name:[247,3,1,""],has_account:[247,3,1,""],is_connected:[247,3,1,""],is_superuser:[247,3,1,""],lockstring:[247,4,1,""],move_to:[247,3,1,""],msg:[247,3,1,""],msg_contents:[247,3,1,""],nicks:[247,4,1,""],objects:[247,4,1,""],path:[247,4,1,""],return_appearance:[247,3,1,""],scripts:[247,4,1,""],search:[247,3,1,""],search_account:[247,3,1,""],sessions:[247,4,1,""],typename:[247,4,1,""]},"evennia.objects.objects.DefaultRoom":{DoesNotExist:[247,2,1,""],MultipleObjectsReturned:[247,2,1,""],basetype_setup:[247,3,1,""],create:[247,3,1,""],lockstring:[247,4,1,""],path:[247,4,1,""],typename:[247,4,1,""]},"evennia.objects.objects.ExitCommand":{aliases:[247,4,1,""],func:[247,3,1,""],get_extra_info:[247,3,1,""],help_category:[247,4,1,""],key:[247,4,1,""],lock_storage:[247,4,1,""],obj:[247,4,1,""]},"evennia.objects.objects.ObjectSessionHandler":{__init__:[247,3,1,""],add:[247,3,1,""],all:[247,3,1,""],clear:[247,3,1,""],count:[247,3,1,""],get:[247,3,1,""],remove:[247,3,1,""]},"evennia.prototypes":{menus:[249,0,0,"-"],protfuncs:[250,0,0,"-"],prototypes:[251,0,0,"-"],spawner:[252,0,0,"-"]},"evennia.prototypes.menus":{OLCMenu:[249,1,1,""],node_apply_diff:[249,5,1,""],node_destination:[249,5,1,""],node_examine_entity:[249,5,1,""],node_home:[249,5,1,""],node_index:[249,5,1,""],node_key:[249,5,1,""],node_location:[249,5,1,""],node_prototype_desc:[249,5,1,""],node_prototype_key:[249,5,1,""],node_prototype_save:[249,5,1,""],node_prototype_spawn:[249,5,1,""],node_validate_prototype:[249,5,1,""],start_olc:[249,5,1,""]},"evennia.prototypes.menus.OLCMenu":{display_helptext:[249,3,1,""],helptext_formatter:[249,3,1,""],nodetext_formatter:[249,3,1,""],options_formatter:[249,3,1,""]},"evennia.prototypes.protfuncs":{add:[250,5,1,""],base_random:[250,5,1,""],center_justify:[250,5,1,""],choice:[250,5,1,""],dbref:[250,5,1,""],div:[250,5,1,""],eval:[250,5,1,""],full_justify:[250,5,1,""],left_justify:[250,5,1,""],mult:[250,5,1,""],obj:[250,5,1,""],objlist:[250,5,1,""],protkey:[250,5,1,""],randint:[250,5,1,""],random:[250,5,1,""],right_justify:[250,5,1,""],sub:[250,5,1,""],toint:[250,5,1,""]},"evennia.prototypes.prototypes":{DbPrototype:[251,1,1,""],PermissionError:[251,2,1,""],PrototypeEvMore:[251,1,1,""],ValidationError:[251,2,1,""],check_permission:[251,5,1,""],create_prototype:[251,5,1,""],delete_prototype:[251,5,1,""],format_available_protfuncs:[251,5,1,""],homogenize_prototype:[251,5,1,""],init_spawn_value:[251,5,1,""],list_prototypes:[251,5,1,""],load_module_prototypes:[251,5,1,""],protfunc_parser:[251,5,1,""],prototype_to_str:[251,5,1,""],save_prototype:[251,5,1,""],search_objects_with_prototype:[251,5,1,""],search_prototype:[251,5,1,""],validate_prototype:[251,5,1,""],value_to_obj:[251,5,1,""],value_to_obj_or_any:[251,5,1,""]},"evennia.prototypes.prototypes.DbPrototype":{DoesNotExist:[251,2,1,""],MultipleObjectsReturned:[251,2,1,""],at_script_creation:[251,3,1,""],path:[251,4,1,""],prototype:[251,3,1,""],typename:[251,4,1,""]},"evennia.prototypes.prototypes.PrototypeEvMore":{__init__:[251,3,1,""],init_pages:[251,3,1,""],page_formatter:[251,3,1,""],prototype_paginator:[251,3,1,""]},"evennia.prototypes.spawner":{Unset:[252,1,1,""],batch_create_object:[252,5,1,""],batch_update_objects_with_prototype:[252,5,1,""],flatten_diff:[252,5,1,""],flatten_prototype:[252,5,1,""],format_diff:[252,5,1,""],prototype_diff:[252,5,1,""],prototype_diff_from_object:[252,5,1,""],prototype_from_object:[252,5,1,""],spawn:[252,5,1,""]},"evennia.scripts":{admin:[254,0,0,"-"],manager:[255,0,0,"-"],models:[256,0,0,"-"],monitorhandler:[257,0,0,"-"],scripthandler:[258,0,0,"-"],scripts:[259,0,0,"-"],taskhandler:[260,0,0,"-"],tickerhandler:[261,0,0,"-"]},"evennia.scripts.admin":{ScriptAttributeInline:[254,1,1,""],ScriptDBAdmin:[254,1,1,""],ScriptTagInline:[254,1,1,""]},"evennia.scripts.admin.ScriptAttributeInline":{media:[254,3,1,""],model:[254,4,1,""],related_field:[254,4,1,""]},"evennia.scripts.admin.ScriptDBAdmin":{fieldsets:[254,4,1,""],inlines:[254,4,1,""],list_display:[254,4,1,""],list_display_links:[254,4,1,""],list_select_related:[254,4,1,""],media:[254,3,1,""],ordering:[254,4,1,""],raw_id_fields:[254,4,1,""],save_as:[254,4,1,""],save_model:[254,3,1,""],save_on_top:[254,4,1,""],search_fields:[254,4,1,""]},"evennia.scripts.admin.ScriptTagInline":{media:[254,3,1,""],model:[254,4,1,""],related_field:[254,4,1,""]},"evennia.scripts.manager":{ScriptManager:[255,1,1,""]},"evennia.scripts.models":{ScriptDB:[256,1,1,""]},"evennia.scripts.models.ScriptDB":{DoesNotExist:[256,2,1,""],MultipleObjectsReturned:[256,2,1,""],account:[256,3,1,""],db_account:[256,4,1,""],db_account_id:[256,4,1,""],db_attributes:[256,4,1,""],db_desc:[256,4,1,""],db_interval:[256,4,1,""],db_is_active:[256,4,1,""],db_obj:[256,4,1,""],db_obj_id:[256,4,1,""],db_persistent:[256,4,1,""],db_repeats:[256,4,1,""],db_start_delay:[256,4,1,""],db_tags:[256,4,1,""],desc:[256,3,1,""],get_next_by_db_date_created:[256,3,1,""],get_previous_by_db_date_created:[256,3,1,""],id:[256,4,1,""],interval:[256,3,1,""],is_active:[256,3,1,""],obj:[256,3,1,""],object:[256,3,1,""],objects:[256,4,1,""],path:[256,4,1,""],persistent:[256,3,1,""],receiver_script_set:[256,4,1,""],repeats:[256,3,1,""],sender_script_set:[256,4,1,""],start_delay:[256,3,1,""],typename:[256,4,1,""]},"evennia.scripts.monitorhandler":{MonitorHandler:[257,1,1,""]},"evennia.scripts.monitorhandler.MonitorHandler":{__init__:[257,3,1,""],add:[257,3,1,""],all:[257,3,1,""],at_update:[257,3,1,""],clear:[257,3,1,""],remove:[257,3,1,""],restore:[257,3,1,""],save:[257,3,1,""]},"evennia.scripts.scripthandler":{ScriptHandler:[258,1,1,""]},"evennia.scripts.scripthandler.ScriptHandler":{"delete":[258,3,1,""],__init__:[258,3,1,""],add:[258,3,1,""],all:[258,3,1,""],get:[258,3,1,""],start:[258,3,1,""],stop:[258,3,1,""],validate:[258,3,1,""]},"evennia.scripts.scripts":{DefaultScript:[259,1,1,""],DoNothing:[259,1,1,""],Store:[259,1,1,""]},"evennia.scripts.scripts.DefaultScript":{DoesNotExist:[259,2,1,""],MultipleObjectsReturned:[259,2,1,""],at_idmapper_flush:[259,3,1,""],at_repeat:[259,3,1,""],at_script_creation:[259,3,1,""],at_server_reload:[259,3,1,""],at_server_shutdown:[259,3,1,""],at_start:[259,3,1,""],at_stop:[259,3,1,""],create:[259,3,1,""],force_repeat:[259,3,1,""],is_valid:[259,3,1,""],path:[259,4,1,""],pause:[259,3,1,""],remaining_repeats:[259,3,1,""],reset_callcount:[259,3,1,""],restart:[259,3,1,""],start:[259,3,1,""],stop:[259,3,1,""],time_until_next_repeat:[259,3,1,""],typename:[259,4,1,""],unpause:[259,3,1,""]},"evennia.scripts.scripts.DoNothing":{DoesNotExist:[259,2,1,""],MultipleObjectsReturned:[259,2,1,""],at_script_creation:[259,3,1,""],path:[259,4,1,""],typename:[259,4,1,""]},"evennia.scripts.scripts.Store":{DoesNotExist:[259,2,1,""],MultipleObjectsReturned:[259,2,1,""],at_script_creation:[259,3,1,""],path:[259,4,1,""],typename:[259,4,1,""]},"evennia.scripts.taskhandler":{TaskHandler:[260,1,1,""],TaskHandlerTask:[260,1,1,""],handle_error:[260,5,1,""]},"evennia.scripts.taskhandler.TaskHandler":{__init__:[260,3,1,""],active:[260,3,1,""],add:[260,3,1,""],call_task:[260,3,1,""],cancel:[260,3,1,""],clean_stale_tasks:[260,3,1,""],clear:[260,3,1,""],create_delays:[260,3,1,""],do_task:[260,3,1,""],exists:[260,3,1,""],get_deferred:[260,3,1,""],load:[260,3,1,""],remove:[260,3,1,""],save:[260,3,1,""]},"evennia.scripts.taskhandler.TaskHandlerTask":{__init__:[260,3,1,""],active:[260,3,1,"id6"],call:[260,3,1,"id3"],called:[260,3,1,""],cancel:[260,3,1,"id5"],do_task:[260,3,1,"id2"],exists:[260,3,1,"id7"],get_deferred:[260,3,1,""],get_id:[260,3,1,"id8"],pause:[260,3,1,"id0"],paused:[260,3,1,""],remove:[260,3,1,"id4"],unpause:[260,3,1,"id1"]},"evennia.scripts.tickerhandler":{Ticker:[261,1,1,""],TickerHandler:[261,1,1,""],TickerPool:[261,1,1,""]},"evennia.scripts.tickerhandler.Ticker":{__init__:[261,3,1,""],add:[261,3,1,""],remove:[261,3,1,""],stop:[261,3,1,""],validate:[261,3,1,""]},"evennia.scripts.tickerhandler.TickerHandler":{__init__:[261,3,1,""],add:[261,3,1,""],all:[261,3,1,""],all_display:[261,3,1,""],clear:[261,3,1,""],remove:[261,3,1,""],restore:[261,3,1,""],save:[261,3,1,""],ticker_pool_class:[261,4,1,""]},"evennia.scripts.tickerhandler.TickerPool":{__init__:[261,3,1,""],add:[261,3,1,""],remove:[261,3,1,""],stop:[261,3,1,""],ticker_class:[261,4,1,""]},"evennia.server":{admin:[263,0,0,"-"],amp_client:[264,0,0,"-"],connection_wizard:[265,0,0,"-"],deprecations:[266,0,0,"-"],evennia_launcher:[267,0,0,"-"],game_index_client:[268,0,0,"-"],initial_setup:[271,0,0,"-"],inputfuncs:[272,0,0,"-"],manager:[273,0,0,"-"],models:[274,0,0,"-"],portal:[275,0,0,"-"],profiling:[297,0,0,"-"],server:[305,0,0,"-"],serversession:[306,0,0,"-"],session:[307,0,0,"-"],sessionhandler:[308,0,0,"-"],signals:[309,0,0,"-"],throttle:[310,0,0,"-"],validators:[311,0,0,"-"],webserver:[312,0,0,"-"]},"evennia.server.admin":{ServerConfigAdmin:[263,1,1,""]},"evennia.server.admin.ServerConfigAdmin":{list_display:[263,4,1,""],list_display_links:[263,4,1,""],list_select_related:[263,4,1,""],media:[263,3,1,""],ordering:[263,4,1,""],save_as:[263,4,1,""],save_on_top:[263,4,1,""],search_fields:[263,4,1,""]},"evennia.server.amp_client":{AMPClientFactory:[264,1,1,""],AMPServerClientProtocol:[264,1,1,""]},"evennia.server.amp_client.AMPClientFactory":{__init__:[264,3,1,""],buildProtocol:[264,3,1,""],clientConnectionFailed:[264,3,1,""],clientConnectionLost:[264,3,1,""],factor:[264,4,1,""],initialDelay:[264,4,1,""],maxDelay:[264,4,1,""],noisy:[264,4,1,""],startedConnecting:[264,3,1,""]},"evennia.server.amp_client.AMPServerClientProtocol":{connectionMade:[264,3,1,""],data_to_portal:[264,3,1,""],send_AdminServer2Portal:[264,3,1,""],send_MsgServer2Portal:[264,3,1,""],server_receive_adminportal2server:[264,3,1,""],server_receive_msgportal2server:[264,3,1,""],server_receive_status:[264,3,1,""]},"evennia.server.connection_wizard":{ConnectionWizard:[265,1,1,""],node_game_index_fields:[265,5,1,""],node_game_index_start:[265,5,1,""],node_mssp_start:[265,5,1,""],node_start:[265,5,1,""],node_view_and_apply_settings:[265,5,1,""]},"evennia.server.connection_wizard.ConnectionWizard":{__init__:[265,3,1,""],ask_choice:[265,3,1,""],ask_continue:[265,3,1,""],ask_input:[265,3,1,""],ask_node:[265,3,1,""],ask_yesno:[265,3,1,""],display:[265,3,1,""]},"evennia.server.deprecations":{check_errors:[266,5,1,""],check_warnings:[266,5,1,""]},"evennia.server.evennia_launcher":{AMPLauncherProtocol:[267,1,1,""],MsgLauncher2Portal:[267,1,1,""],MsgStatus:[267,1,1,""],check_database:[267,5,1,""],check_main_evennia_dependencies:[267,5,1,""],collectstatic:[267,5,1,""],create_game_directory:[267,5,1,""],create_secret_key:[267,5,1,""],create_settings_file:[267,5,1,""],create_superuser:[267,5,1,""],del_pid:[267,5,1,""],error_check_python_modules:[267,5,1,""],evennia_version:[267,5,1,""],get_pid:[267,5,1,""],getenv:[267,5,1,""],init_game_directory:[267,5,1,""],kill:[267,5,1,""],list_settings:[267,5,1,""],main:[267,5,1,""],query_info:[267,5,1,""],query_status:[267,5,1,""],reboot_evennia:[267,5,1,""],reload_evennia:[267,5,1,""],run_connect_wizard:[267,5,1,""],run_dummyrunner:[267,5,1,""],run_menu:[267,5,1,""],send_instruction:[267,5,1,""],set_gamedir:[267,5,1,""],show_version_info:[267,5,1,""],start_evennia:[267,5,1,""],start_only_server:[267,5,1,""],start_portal_interactive:[267,5,1,""],start_server_interactive:[267,5,1,""],stop_evennia:[267,5,1,""],stop_server_only:[267,5,1,""],tail_log_files:[267,5,1,""],wait_for_status:[267,5,1,""],wait_for_status_reply:[267,5,1,""]},"evennia.server.evennia_launcher.AMPLauncherProtocol":{__init__:[267,3,1,""],receive_status_from_portal:[267,3,1,""],wait_for_status:[267,3,1,""]},"evennia.server.evennia_launcher.MsgLauncher2Portal":{allErrors:[267,4,1,""],arguments:[267,4,1,""],commandName:[267,4,1,""],errors:[267,4,1,""],key:[267,4,1,""],response:[267,4,1,""],reverseErrors:[267,4,1,""]},"evennia.server.evennia_launcher.MsgStatus":{allErrors:[267,4,1,""],arguments:[267,4,1,""],commandName:[267,4,1,""],errors:[267,4,1,""],key:[267,4,1,""],response:[267,4,1,""],reverseErrors:[267,4,1,""]},"evennia.server.game_index_client":{client:[269,0,0,"-"],service:[270,0,0,"-"]},"evennia.server.game_index_client.client":{EvenniaGameIndexClient:[269,1,1,""],QuietHTTP11ClientFactory:[269,1,1,""],SimpleResponseReceiver:[269,1,1,""],StringProducer:[269,1,1,""]},"evennia.server.game_index_client.client.EvenniaGameIndexClient":{__init__:[269,3,1,""],handle_egd_response:[269,3,1,""],send_game_details:[269,3,1,""]},"evennia.server.game_index_client.client.QuietHTTP11ClientFactory":{noisy:[269,4,1,""]},"evennia.server.game_index_client.client.SimpleResponseReceiver":{__init__:[269,3,1,""],connectionLost:[269,3,1,""],dataReceived:[269,3,1,""]},"evennia.server.game_index_client.client.StringProducer":{__init__:[269,3,1,""],pauseProducing:[269,3,1,""],startProducing:[269,3,1,""],stopProducing:[269,3,1,""]},"evennia.server.game_index_client.service":{EvenniaGameIndexService:[270,1,1,""]},"evennia.server.game_index_client.service.EvenniaGameIndexService":{__init__:[270,3,1,""],name:[270,4,1,""],startService:[270,3,1,""],stopService:[270,3,1,""]},"evennia.server.initial_setup":{at_initial_setup:[271,5,1,""],collectstatic:[271,5,1,""],create_channels:[271,5,1,""],create_objects:[271,5,1,""],get_god_account:[271,5,1,""],handle_setup:[271,5,1,""],reset_server:[271,5,1,""]},"evennia.server.inputfuncs":{"default":[272,5,1,""],bot_data_in:[272,5,1,""],client_options:[272,5,1,""],echo:[272,5,1,""],external_discord_hello:[272,5,1,""],get_client_options:[272,5,1,""],get_inputfuncs:[272,5,1,""],get_value:[272,5,1,""],hello:[272,5,1,""],login:[272,5,1,""],monitor:[272,5,1,""],monitored:[272,5,1,""],msdp_list:[272,5,1,""],msdp_report:[272,5,1,""],msdp_send:[272,5,1,""],msdp_unreport:[272,5,1,""],repeat:[272,5,1,""],supports_set:[272,5,1,""],text:[272,5,1,""],unmonitor:[272,5,1,""],unrepeat:[272,5,1,""],webclient_options:[272,5,1,""]},"evennia.server.manager":{ServerConfigManager:[273,1,1,""]},"evennia.server.manager.ServerConfigManager":{conf:[273,3,1,""]},"evennia.server.models":{ServerConfig:[274,1,1,""]},"evennia.server.models.ServerConfig":{DoesNotExist:[274,2,1,""],MultipleObjectsReturned:[274,2,1,""],db_key:[274,4,1,""],db_value:[274,4,1,""],id:[274,4,1,""],key:[274,3,1,""],objects:[274,4,1,""],path:[274,4,1,""],store:[274,3,1,""],typename:[274,4,1,""],value:[274,3,1,""]},"evennia.server.portal":{amp:[276,0,0,"-"],amp_server:[277,0,0,"-"],grapevine:[278,0,0,"-"],irc:[279,0,0,"-"],portalsessionhandler:[285,0,0,"-"],rss:[286,0,0,"-"],ssh:[287,0,0,"-"],webclient:[295,0,0,"-"],webclient_ajax:[296,0,0,"-"]},"evennia.server.portal.amp":{AMPMultiConnectionProtocol:[276,1,1,""],AdminPortal2Server:[276,1,1,""],AdminServer2Portal:[276,1,1,""],Compressed:[276,1,1,""],FunctionCall:[276,1,1,""],MsgLauncher2Portal:[276,1,1,""],MsgPortal2Server:[276,1,1,""],MsgServer2Portal:[276,1,1,""],MsgStatus:[276,1,1,""],dumps:[276,5,1,""],loads:[276,5,1,""]},"evennia.server.portal.amp.AMPMultiConnectionProtocol":{__init__:[276,3,1,""],broadcast:[276,3,1,""],connectionLost:[276,3,1,""],connectionMade:[276,3,1,""],dataReceived:[276,3,1,""],data_in:[276,3,1,""],errback:[276,3,1,""],makeConnection:[276,3,1,""],receive_functioncall:[276,3,1,""],send_FunctionCall:[276,3,1,""]},"evennia.server.portal.amp.AdminPortal2Server":{allErrors:[276,4,1,""],arguments:[276,4,1,""],commandName:[276,4,1,""],errors:[276,4,1,""],key:[276,4,1,""],response:[276,4,1,""],reverseErrors:[276,4,1,""]},"evennia.server.portal.amp.AdminServer2Portal":{allErrors:[276,4,1,""],arguments:[276,4,1,""],commandName:[276,4,1,""],errors:[276,4,1,""],key:[276,4,1,""],response:[276,4,1,""],reverseErrors:[276,4,1,""]},"evennia.server.portal.amp.Compressed":{fromBox:[276,3,1,""],fromString:[276,3,1,""],toBox:[276,3,1,""],toString:[276,3,1,""]},"evennia.server.portal.amp.FunctionCall":{allErrors:[276,4,1,""],arguments:[276,4,1,""],commandName:[276,4,1,""],errors:[276,4,1,""],key:[276,4,1,""],response:[276,4,1,""],reverseErrors:[276,4,1,""]},"evennia.server.portal.amp.MsgLauncher2Portal":{allErrors:[276,4,1,""],arguments:[276,4,1,""],commandName:[276,4,1,""],errors:[276,4,1,""],key:[276,4,1,""],response:[276,4,1,""],reverseErrors:[276,4,1,""]},"evennia.server.portal.amp.MsgPortal2Server":{allErrors:[276,4,1,""],arguments:[276,4,1,""],commandName:[276,4,1,""],errors:[276,4,1,""],key:[276,4,1,""],response:[276,4,1,""],reverseErrors:[276,4,1,""]},"evennia.server.portal.amp.MsgServer2Portal":{allErrors:[276,4,1,""],arguments:[276,4,1,""],commandName:[276,4,1,""],errors:[276,4,1,""],key:[276,4,1,""],response:[276,4,1,""],reverseErrors:[276,4,1,""]},"evennia.server.portal.amp.MsgStatus":{allErrors:[276,4,1,""],arguments:[276,4,1,""],commandName:[276,4,1,""],errors:[276,4,1,""],key:[276,4,1,""],response:[276,4,1,""],reverseErrors:[276,4,1,""]},"evennia.server.portal.amp_server":{AMPServerFactory:[277,1,1,""],AMPServerProtocol:[277,1,1,""],getenv:[277,5,1,""]},"evennia.server.portal.amp_server.AMPServerFactory":{__init__:[277,3,1,""],buildProtocol:[277,3,1,""],logPrefix:[277,3,1,""],noisy:[277,4,1,""]},"evennia.server.portal.amp_server.AMPServerProtocol":{connectionLost:[277,3,1,""],data_to_server:[277,3,1,""],get_status:[277,3,1,""],portal_receive_adminserver2portal:[277,3,1,""],portal_receive_launcher2portal:[277,3,1,""],portal_receive_server2portal:[277,3,1,""],portal_receive_status:[277,3,1,""],send_AdminPortal2Server:[277,3,1,""],send_MsgPortal2Server:[277,3,1,""],send_Status2Launcher:[277,3,1,""],start_server:[277,3,1,""],stop_server:[277,3,1,""],wait_for_disconnect:[277,3,1,""],wait_for_server_connect:[277,3,1,""]},"evennia.server.portal.grapevine":{GrapevineClient:[278,1,1,""],RestartingWebsocketServerFactory:[278,1,1,""]},"evennia.server.portal.grapevine.GrapevineClient":{__init__:[278,3,1,""],at_login:[278,3,1,""],data_in:[278,3,1,""],disconnect:[278,3,1,""],onClose:[278,3,1,""],onMessage:[278,3,1,""],onOpen:[278,3,1,""],send_authenticate:[278,3,1,""],send_channel:[278,3,1,""],send_default:[278,3,1,""],send_heartbeat:[278,3,1,""],send_subscribe:[278,3,1,""],send_unsubscribe:[278,3,1,""]},"evennia.server.portal.grapevine.RestartingWebsocketServerFactory":{__init__:[278,3,1,""],buildProtocol:[278,3,1,""],clientConnectionFailed:[278,3,1,""],clientConnectionLost:[278,3,1,""],factor:[278,4,1,""],initialDelay:[278,4,1,""],maxDelay:[278,4,1,""],reconnect:[278,3,1,""],start:[278,3,1,""],startedConnecting:[278,3,1,""]},"evennia.server.portal.irc":{IRCBot:[279,1,1,""],IRCBotFactory:[279,1,1,""],parse_ansi_to_irc:[279,5,1,""],parse_irc_to_ansi:[279,5,1,""]},"evennia.server.portal.irc.IRCBot":{action:[279,3,1,""],at_login:[279,3,1,""],channel:[279,4,1,""],data_in:[279,3,1,""],disconnect:[279,3,1,""],factory:[279,4,1,""],get_nicklist:[279,3,1,""],irc_RPL_ENDOFNAMES:[279,3,1,""],irc_RPL_NAMREPLY:[279,3,1,""],lineRate:[279,4,1,""],logger:[279,4,1,""],nickname:[279,4,1,""],pong:[279,3,1,""],privmsg:[279,3,1,""],send_channel:[279,3,1,""],send_default:[279,3,1,""],send_ping:[279,3,1,""],send_privmsg:[279,3,1,""],send_reconnect:[279,3,1,""],send_request_nicklist:[279,3,1,""],signedOn:[279,3,1,""],sourceURL:[279,4,1,""]},"evennia.server.portal.irc.IRCBotFactory":{__init__:[279,3,1,""],buildProtocol:[279,3,1,""],clientConnectionFailed:[279,3,1,""],clientConnectionLost:[279,3,1,""],factor:[279,4,1,""],initialDelay:[279,4,1,""],maxDelay:[279,4,1,""],reconnect:[279,3,1,""],start:[279,3,1,""],startedConnecting:[279,3,1,""]},"evennia.server.portal.portalsessionhandler":{PortalSessionHandler:[285,1,1,""]},"evennia.server.portal.portalsessionhandler.PortalSessionHandler":{__init__:[285,3,1,""],announce_all:[285,3,1,""],at_server_connection:[285,3,1,""],connect:[285,3,1,""],count_loggedin:[285,3,1,""],data_in:[285,3,1,""],data_out:[285,3,1,""],disconnect:[285,3,1,""],disconnect_all:[285,3,1,""],server_connect:[285,3,1,""],server_disconnect:[285,3,1,""],server_disconnect_all:[285,3,1,""],server_logged_in:[285,3,1,""],server_session_sync:[285,3,1,""],sessions_from_csessid:[285,3,1,""],sync:[285,3,1,""]},"evennia.server.portal.rss":{RSSBotFactory:[286,1,1,""],RSSReader:[286,1,1,""]},"evennia.server.portal.rss.RSSBotFactory":{__init__:[286,3,1,""],start:[286,3,1,""]},"evennia.server.portal.rss.RSSReader":{__init__:[286,3,1,""],data_in:[286,3,1,""],disconnect:[286,3,1,""],get_new:[286,3,1,""],update:[286,3,1,""]},"evennia.server.portal.ssh":{AccountDBPasswordChecker:[287,1,1,""],ExtraInfoAuthServer:[287,1,1,""],PassAvatarIdTerminalRealm:[287,1,1,""],SSHServerFactory:[287,1,1,""],SshProtocol:[287,1,1,""],TerminalSessionTransport_getPeer:[287,1,1,""],getKeyPair:[287,5,1,""],makeFactory:[287,5,1,""]},"evennia.server.portal.ssh.AccountDBPasswordChecker":{__init__:[287,3,1,""],credentialInterfaces:[287,4,1,""],noisy:[287,4,1,""],requestAvatarId:[287,3,1,""]},"evennia.server.portal.ssh.ExtraInfoAuthServer":{auth_password:[287,3,1,""],noisy:[287,4,1,""]},"evennia.server.portal.ssh.PassAvatarIdTerminalRealm":{noisy:[287,4,1,""]},"evennia.server.portal.ssh.SSHServerFactory":{logPrefix:[287,3,1,""],noisy:[287,4,1,""]},"evennia.server.portal.ssh.SshProtocol":{__init__:[287,3,1,""],at_login:[287,3,1,""],connectionLost:[287,3,1,""],connectionMade:[287,3,1,""],data_out:[287,3,1,""],disconnect:[287,3,1,""],getClientAddress:[287,3,1,""],handle_EOF:[287,3,1,""],handle_FF:[287,3,1,""],handle_INT:[287,3,1,""],handle_QUIT:[287,3,1,""],lineReceived:[287,3,1,""],noisy:[287,4,1,""],sendLine:[287,3,1,""],send_default:[287,3,1,""],send_prompt:[287,3,1,""],send_text:[287,3,1,""],terminalSize:[287,3,1,""]},"evennia.server.portal.ssh.TerminalSessionTransport_getPeer":{__init__:[287,3,1,""],noisy:[287,4,1,""]},"evennia.server.portal.webclient":{WebSocketClient:[295,1,1,""]},"evennia.server.portal.webclient.WebSocketClient":{__init__:[295,3,1,""],at_login:[295,3,1,""],data_in:[295,3,1,""],disconnect:[295,3,1,""],get_client_session:[295,3,1,""],nonce:[295,4,1,""],onClose:[295,3,1,""],onMessage:[295,3,1,""],onOpen:[295,3,1,""],sendLine:[295,3,1,""],send_default:[295,3,1,""],send_prompt:[295,3,1,""],send_text:[295,3,1,""]},"evennia.server.portal.webclient_ajax":{AjaxWebClient:[296,1,1,""],AjaxWebClientSession:[296,1,1,""],LazyEncoder:[296,1,1,""],jsonify:[296,5,1,""]},"evennia.server.portal.webclient_ajax.AjaxWebClient":{__init__:[296,3,1,""],allowedMethods:[296,4,1,""],at_login:[296,3,1,""],client_disconnect:[296,3,1,""],get_client_sessid:[296,3,1,""],isLeaf:[296,4,1,""],lineSend:[296,3,1,""],mode_close:[296,3,1,""],mode_init:[296,3,1,""],mode_input:[296,3,1,""],mode_keepalive:[296,3,1,""],mode_receive:[296,3,1,""],render_POST:[296,3,1,""]},"evennia.server.portal.webclient_ajax.AjaxWebClientSession":{__init__:[296,3,1,""],at_login:[296,3,1,""],data_in:[296,3,1,""],data_out:[296,3,1,""],disconnect:[296,3,1,""],get_client_session:[296,3,1,""],send_default:[296,3,1,""],send_prompt:[296,3,1,""],send_text:[296,3,1,""]},"evennia.server.portal.webclient_ajax.LazyEncoder":{"default":[296,3,1,""]},"evennia.server.profiling":{dummyrunner:[298,0,0,"-"],dummyrunner_settings:[299,0,0,"-"],memplot:[300,0,0,"-"],settings_mixin:[301,0,0,"-"],test_queries:[302,0,0,"-"],tests:[303,0,0,"-"],timetrace:[304,0,0,"-"]},"evennia.server.profiling.dummyrunner":{DummyClient:[298,1,1,""],DummyFactory:[298,1,1,""],gidcounter:[298,5,1,""],idcounter:[298,5,1,""],makeiter:[298,5,1,""],start_all_dummy_clients:[298,5,1,""]},"evennia.server.profiling.dummyrunner.DummyClient":{connectionLost:[298,3,1,""],connectionMade:[298,3,1,""],counter:[298,3,1,""],dataReceived:[298,3,1,""],error:[298,3,1,""],logout:[298,3,1,""],step:[298,3,1,""]},"evennia.server.profiling.dummyrunner.DummyFactory":{__init__:[298,3,1,""],protocol:[298,4,1,""]},"evennia.server.profiling.dummyrunner_settings":{c_creates_button:[299,5,1,""],c_creates_obj:[299,5,1,""],c_digs:[299,5,1,""],c_examines:[299,5,1,""],c_help:[299,5,1,""],c_idles:[299,5,1,""],c_login:[299,5,1,""],c_login_nodig:[299,5,1,""],c_logout:[299,5,1,""],c_looks:[299,5,1,""],c_moves:[299,5,1,""],c_moves_n:[299,5,1,""],c_moves_s:[299,5,1,""],c_socialize:[299,5,1,""]},"evennia.server.profiling.memplot":{Memplot:[300,1,1,""]},"evennia.server.profiling.memplot.Memplot":{DoesNotExist:[300,2,1,""],MultipleObjectsReturned:[300,2,1,""],at_repeat:[300,3,1,""],at_script_creation:[300,3,1,""],path:[300,4,1,""],typename:[300,4,1,""]},"evennia.server.profiling.test_queries":{count_queries:[302,5,1,""]},"evennia.server.profiling.tests":{TestDummyrunnerSettings:[303,1,1,""],TestMemPlot:[303,1,1,""]},"evennia.server.profiling.tests.TestDummyrunnerSettings":{clear_client_lists:[303,3,1,""],perception_method_tests:[303,3,1,""],setUp:[303,3,1,""],test_c_creates_button:[303,3,1,""],test_c_creates_obj:[303,3,1,""],test_c_digs:[303,3,1,""],test_c_examines:[303,3,1,""],test_c_help:[303,3,1,""],test_c_login:[303,3,1,""],test_c_login_no_dig:[303,3,1,""],test_c_logout:[303,3,1,""],test_c_looks:[303,3,1,""],test_c_move_n:[303,3,1,""],test_c_move_s:[303,3,1,""],test_c_moves:[303,3,1,""],test_c_socialize:[303,3,1,""],test_idles:[303,3,1,""]},"evennia.server.profiling.tests.TestMemPlot":{test_memplot:[303,3,1,""]},"evennia.server.profiling.timetrace":{timetrace:[304,5,1,""]},"evennia.server.server":{Evennia:[305,1,1,""]},"evennia.server.server.Evennia":{__init__:[305,3,1,""],at_post_portal_sync:[305,3,1,""],at_server_cold_start:[305,3,1,""],at_server_cold_stop:[305,3,1,""],at_server_reload_start:[305,3,1,""],at_server_reload_stop:[305,3,1,""],at_server_start:[305,3,1,""],at_server_stop:[305,3,1,""],get_info_dict:[305,3,1,""],run_init_hooks:[305,3,1,""],run_initial_setup:[305,3,1,""],shutdown:[305,3,1,""],sqlite3_prep:[305,3,1,""],update_defaults:[305,3,1,""]},"evennia.server.serversession":{NAttributeHandler:[306,1,1,""],NDbHolder:[306,1,1,""],ServerSession:[306,1,1,""]},"evennia.server.serversession.NAttributeHandler":{__init__:[306,3,1,""],add:[306,3,1,""],all:[306,3,1,""],clear:[306,3,1,""],get:[306,3,1,""],has:[306,3,1,""],remove:[306,3,1,""]},"evennia.server.serversession.NDbHolder":{__init__:[306,3,1,""],all:[306,3,1,""],get_all:[306,3,1,""]},"evennia.server.serversession.ServerSession":{__init__:[306,3,1,""],access:[306,3,1,""],at_cmdset_get:[306,3,1,""],at_disconnect:[306,3,1,""],at_login:[306,3,1,""],at_sync:[306,3,1,""],attributes:[306,4,1,""],cmdset_storage:[306,3,1,""],data_in:[306,3,1,""],data_out:[306,3,1,""],db:[306,3,1,""],execute_cmd:[306,3,1,""],get_account:[306,3,1,""],get_character:[306,3,1,""],get_client_size:[306,3,1,""],get_puppet:[306,3,1,""],get_puppet_or_account:[306,3,1,""],log:[306,3,1,""],msg:[306,3,1,""],nattributes:[306,4,1,""],ndb:[306,3,1,""],ndb_del:[306,3,1,""],ndb_get:[306,3,1,""],ndb_set:[306,3,1,""],update_flags:[306,3,1,""],update_session_counters:[306,3,1,""]},"evennia.server.session":{Session:[307,1,1,""]},"evennia.server.session.Session":{at_sync:[307,3,1,""],data_in:[307,3,1,""],data_out:[307,3,1,""],disconnect:[307,3,1,""],get_sync_data:[307,3,1,""],init_session:[307,3,1,""],load_sync_data:[307,3,1,""]},"evennia.server.sessionhandler":{DummySession:[308,1,1,""],ServerSessionHandler:[308,1,1,""],SessionHandler:[308,1,1,""],delayed_import:[308,5,1,""]},"evennia.server.sessionhandler.DummySession":{sessid:[308,4,1,""]},"evennia.server.sessionhandler.ServerSessionHandler":{__init__:[308,3,1,""],account_count:[308,3,1,""],all_connected_accounts:[308,3,1,""],all_sessions_portal_sync:[308,3,1,""],announce_all:[308,3,1,""],call_inputfuncs:[308,3,1,""],data_in:[308,3,1,""],data_out:[308,3,1,""],disconnect:[308,3,1,""],disconnect_all_sessions:[308,3,1,""],disconnect_duplicate_sessions:[308,3,1,""],get_inputfuncs:[308,3,1,""],login:[308,3,1,""],portal_connect:[308,3,1,""],portal_disconnect:[308,3,1,""],portal_disconnect_all:[308,3,1,""],portal_reset_server:[308,3,1,""],portal_restart_server:[308,3,1,""],portal_session_sync:[308,3,1,""],portal_sessions_sync:[308,3,1,""],portal_shutdown:[308,3,1,""],session_from_account:[308,3,1,""],session_from_sessid:[308,3,1,""],session_portal_partial_sync:[308,3,1,""],session_portal_sync:[308,3,1,""],sessions_from_account:[308,3,1,""],sessions_from_character:[308,3,1,""],sessions_from_csessid:[308,3,1,""],sessions_from_puppet:[308,3,1,""],start_bot_session:[308,3,1,""],validate_sessions:[308,3,1,""]},"evennia.server.sessionhandler.SessionHandler":{clean_senddata:[308,3,1,""],get:[308,3,1,""],get_all_sync_data:[308,3,1,""],get_sessions:[308,3,1,""]},"evennia.server.throttle":{Throttle:[310,1,1,""]},"evennia.server.throttle.Throttle":{__init__:[310,3,1,""],check:[310,3,1,""],error_msg:[310,4,1,""],get:[310,3,1,""],update:[310,3,1,""]},"evennia.server.validators":{EvenniaPasswordValidator:[311,1,1,""],EvenniaUsernameAvailabilityValidator:[311,1,1,""]},"evennia.server.validators.EvenniaPasswordValidator":{__init__:[311,3,1,""],get_help_text:[311,3,1,""],validate:[311,3,1,""]},"evennia.server.webserver":{DjangoWebRoot:[312,1,1,""],EvenniaReverseProxyResource:[312,1,1,""],HTTPChannelWithXForwardedFor:[312,1,1,""],LockableThreadPool:[312,1,1,""],PrivateStaticRoot:[312,1,1,""],WSGIWebServer:[312,1,1,""],Website:[312,1,1,""]},"evennia.server.webserver.DjangoWebRoot":{__init__:[312,3,1,""],empty_threadpool:[312,3,1,""],getChild:[312,3,1,""]},"evennia.server.webserver.EvenniaReverseProxyResource":{getChild:[312,3,1,""],render:[312,3,1,""]},"evennia.server.webserver.HTTPChannelWithXForwardedFor":{allHeadersReceived:[312,3,1,""]},"evennia.server.webserver.LockableThreadPool":{__init__:[312,3,1,""],callInThread:[312,3,1,""],lock:[312,3,1,""]},"evennia.server.webserver.PrivateStaticRoot":{directoryListing:[312,3,1,""]},"evennia.server.webserver.WSGIWebServer":{__init__:[312,3,1,""],startService:[312,3,1,""],stopService:[312,3,1,""]},"evennia.server.webserver.Website":{log:[312,3,1,""],logPrefix:[312,3,1,""],noisy:[312,4,1,""]},"evennia.typeclasses":{admin:[315,0,0,"-"],attributes:[316,0,0,"-"],managers:[317,0,0,"-"],models:[318,0,0,"-"],tags:[319,0,0,"-"]},"evennia.typeclasses.admin":{AttributeForm:[315,1,1,""],AttributeFormSet:[315,1,1,""],AttributeInline:[315,1,1,""],TagAdmin:[315,1,1,""],TagForm:[315,1,1,""],TagFormSet:[315,1,1,""],TagInline:[315,1,1,""]},"evennia.typeclasses.admin.AttributeForm":{Meta:[315,1,1,""],__init__:[315,3,1,""],base_fields:[315,4,1,""],clean_attr_value:[315,3,1,""],declared_fields:[315,4,1,""],media:[315,3,1,""],save:[315,3,1,""]},"evennia.typeclasses.admin.AttributeForm.Meta":{fields:[315,4,1,""]},"evennia.typeclasses.admin.AttributeFormSet":{save:[315,3,1,""]},"evennia.typeclasses.admin.AttributeInline":{extra:[315,4,1,""],form:[315,4,1,""],formset:[315,4,1,""],get_formset:[315,3,1,""],media:[315,3,1,""],model:[315,4,1,""],related_field:[315,4,1,""]},"evennia.typeclasses.admin.TagAdmin":{fields:[315,4,1,""],list_display:[315,4,1,""],list_filter:[315,4,1,""],media:[315,3,1,""],search_fields:[315,4,1,""]},"evennia.typeclasses.admin.TagForm":{Meta:[315,1,1,""],__init__:[315,3,1,""],base_fields:[315,4,1,""],declared_fields:[315,4,1,""],media:[315,3,1,""],save:[315,3,1,""]},"evennia.typeclasses.admin.TagForm.Meta":{fields:[315,4,1,""]},"evennia.typeclasses.admin.TagFormSet":{save:[315,3,1,""]},"evennia.typeclasses.admin.TagInline":{extra:[315,4,1,""],form:[315,4,1,""],formset:[315,4,1,""],get_formset:[315,3,1,""],media:[315,3,1,""],model:[315,4,1,""],related_field:[315,4,1,""]},"evennia.typeclasses.attributes":{Attribute:[316,1,1,""],AttributeHandler:[316,1,1,""],NAttributeHandler:[316,1,1,""],NickHandler:[316,1,1,""],NickTemplateInvalid:[316,2,1,""],initialize_nick_templates:[316,5,1,""],parse_nick_template:[316,5,1,""]},"evennia.typeclasses.attributes.Attribute":{DoesNotExist:[316,2,1,""],MultipleObjectsReturned:[316,2,1,""],access:[316,3,1,""],accountdb_set:[316,4,1,""],attrtype:[316,3,1,""],category:[316,3,1,""],channeldb_set:[316,4,1,""],date_created:[316,3,1,""],db_attrtype:[316,4,1,""],db_category:[316,4,1,""],db_date_created:[316,4,1,""],db_key:[316,4,1,""],db_lock_storage:[316,4,1,""],db_model:[316,4,1,""],db_strvalue:[316,4,1,""],db_value:[316,4,1,""],get_next_by_db_date_created:[316,3,1,""],get_previous_by_db_date_created:[316,3,1,""],id:[316,4,1,""],key:[316,3,1,""],lock_storage:[316,3,1,""],locks:[316,4,1,""],model:[316,3,1,""],objectdb_set:[316,4,1,""],path:[316,4,1,""],scriptdb_set:[316,4,1,""],strvalue:[316,3,1,""],typename:[316,4,1,""],value:[316,3,1,""]},"evennia.typeclasses.attributes.AttributeHandler":{__init__:[316,3,1,""],add:[316,3,1,""],all:[316,3,1,""],batch_add:[316,3,1,""],clear:[316,3,1,""],get:[316,3,1,""],has:[316,3,1,""],remove:[316,3,1,""],reset_cache:[316,3,1,""]},"evennia.typeclasses.attributes.NAttributeHandler":{__init__:[316,3,1,""],add:[316,3,1,""],all:[316,3,1,""],clear:[316,3,1,""],get:[316,3,1,""],has:[316,3,1,""],remove:[316,3,1,""]},"evennia.typeclasses.attributes.NickHandler":{__init__:[316,3,1,""],add:[316,3,1,""],get:[316,3,1,""],has:[316,3,1,""],nickreplace:[316,3,1,""],remove:[316,3,1,""]},"evennia.typeclasses.managers":{TypedObjectManager:[317,1,1,""]},"evennia.typeclasses.managers.TypedObjectManager":{create_tag:[317,3,1,""],dbref:[317,3,1,""],dbref_search:[317,3,1,""],get_alias:[317,3,1,""],get_attribute:[317,3,1,""],get_by_alias:[317,3,1,""],get_by_attribute:[317,3,1,""],get_by_nick:[317,3,1,""],get_by_permission:[317,3,1,""],get_by_tag:[317,3,1,""],get_dbref_range:[317,3,1,""],get_id:[317,3,1,""],get_nick:[317,3,1,""],get_permission:[317,3,1,""],get_tag:[317,3,1,""],get_typeclass_totals:[317,3,1,""],object_totals:[317,3,1,""],typeclass_search:[317,3,1,""]},"evennia.typeclasses.models":{TypedObject:[318,1,1,""]},"evennia.typeclasses.models.TypedObject":{"delete":[318,3,1,""],Meta:[318,1,1,""],__init__:[318,3,1,""],access:[318,3,1,""],aliases:[318,4,1,""],at_idmapper_flush:[318,3,1,""],at_rename:[318,3,1,""],attributes:[318,4,1,""],check_permstring:[318,3,1,""],date_created:[318,3,1,""],db:[318,3,1,""],db_attributes:[318,4,1,""],db_date_created:[318,4,1,""],db_key:[318,4,1,""],db_lock_storage:[318,4,1,""],db_tags:[318,4,1,""],db_typeclass_path:[318,4,1,""],dbid:[318,3,1,""],dbref:[318,3,1,""],get_absolute_url:[318,3,1,""],get_display_name:[318,3,1,""],get_extra_info:[318,3,1,""],get_next_by_db_date_created:[318,3,1,""],get_previous_by_db_date_created:[318,3,1,""],is_typeclass:[318,3,1,""],key:[318,3,1,""],lock_storage:[318,3,1,""],locks:[318,4,1,""],name:[318,3,1,""],nattributes:[318,4,1,""],ndb:[318,3,1,""],objects:[318,4,1,""],path:[318,4,1,""],permissions:[318,4,1,""],set_class_from_typeclass:[318,3,1,""],swap_typeclass:[318,3,1,""],tags:[318,4,1,""],typeclass_path:[318,3,1,""],typename:[318,4,1,""],web_get_admin_url:[318,3,1,""],web_get_create_url:[318,3,1,""],web_get_delete_url:[318,3,1,""],web_get_detail_url:[318,3,1,""],web_get_puppet_url:[318,3,1,""],web_get_update_url:[318,3,1,""]},"evennia.typeclasses.models.TypedObject.Meta":{"abstract":[318,4,1,""],ordering:[318,4,1,""],verbose_name:[318,4,1,""]},"evennia.typeclasses.tags":{AliasHandler:[319,1,1,""],PermissionHandler:[319,1,1,""],Tag:[319,1,1,""],TagHandler:[319,1,1,""]},"evennia.typeclasses.tags.Tag":{DoesNotExist:[319,2,1,""],MultipleObjectsReturned:[319,2,1,""],accountdb_set:[319,4,1,""],channeldb_set:[319,4,1,""],db_category:[319,4,1,""],db_data:[319,4,1,""],db_key:[319,4,1,""],db_model:[319,4,1,""],db_tagtype:[319,4,1,""],helpentry_set:[319,4,1,""],id:[319,4,1,""],msg_set:[319,4,1,""],objectdb_set:[319,4,1,""],objects:[319,4,1,""],scriptdb_set:[319,4,1,""]},"evennia.typeclasses.tags.TagHandler":{__init__:[319,3,1,""],add:[319,3,1,""],all:[319,3,1,""],batch_add:[319,3,1,""],clear:[319,3,1,""],get:[319,3,1,""],remove:[319,3,1,""],reset_cache:[319,3,1,""]},"evennia.utils":{ansi:[321,0,0,"-"],batchprocessors:[322,0,0,"-"],containers:[323,0,0,"-"],create:[324,0,0,"-"],dbserialize:[325,0,0,"-"],eveditor:[326,0,0,"-"],evform:[327,0,0,"-"],evmenu:[328,0,0,"-"],evmore:[329,0,0,"-"],evtable:[330,0,0,"-"],gametime:[331,0,0,"-"],idmapper:[332,0,0,"-"],inlinefuncs:[336,0,0,"-"],logger:[337,0,0,"-"],optionclasses:[338,0,0,"-"],optionhandler:[339,0,0,"-"],picklefield:[340,0,0,"-"],search:[341,0,0,"-"],test_resources:[342,0,0,"-"],text2html:[343,0,0,"-"],utils:[344,0,0,"-"],validatorfuncs:[345,0,0,"-"]},"evennia.utils.ansi":{ANSIMeta:[321,1,1,""],ANSIParser:[321,1,1,""],ANSIString:[321,1,1,""],parse_ansi:[321,5,1,""],raw:[321,5,1,""],strip_ansi:[321,5,1,""],strip_raw_ansi:[321,5,1,""]},"evennia.utils.ansi.ANSIMeta":{__init__:[321,3,1,""]},"evennia.utils.ansi.ANSIParser":{ansi_escapes:[321,4,1,""],ansi_map:[321,4,1,""],ansi_map_dict:[321,4,1,""],ansi_re:[321,4,1,""],ansi_regex:[321,4,1,""],ansi_sub:[321,4,1,""],ansi_xterm256_bright_bg_map:[321,4,1,""],ansi_xterm256_bright_bg_map_dict:[321,4,1,""],brightbg_sub:[321,4,1,""],mxp_re:[321,4,1,""],mxp_sub:[321,4,1,""],parse_ansi:[321,3,1,""],strip_mxp:[321,3,1,""],strip_raw_codes:[321,3,1,""],sub_ansi:[321,3,1,""],sub_brightbg:[321,3,1,""],sub_xterm256:[321,3,1,""],xterm256_bg:[321,4,1,""],xterm256_bg_sub:[321,4,1,""],xterm256_fg:[321,4,1,""],xterm256_fg_sub:[321,4,1,""],xterm256_gbg:[321,4,1,""],xterm256_gbg_sub:[321,4,1,""],xterm256_gfg:[321,4,1,""],xterm256_gfg_sub:[321,4,1,""]},"evennia.utils.ansi.ANSIString":{__init__:[321,3,1,""],capitalize:[321,3,1,""],center:[321,3,1,""],clean:[321,3,1,""],count:[321,3,1,""],decode:[321,3,1,""],encode:[321,3,1,""],endswith:[321,3,1,""],expandtabs:[321,3,1,""],find:[321,3,1,""],format:[321,3,1,""],index:[321,3,1,""],isalnum:[321,3,1,""],isalpha:[321,3,1,""],isdigit:[321,3,1,""],islower:[321,3,1,""],isspace:[321,3,1,""],istitle:[321,3,1,""],isupper:[321,3,1,""],join:[321,3,1,""],ljust:[321,3,1,""],lower:[321,3,1,""],lstrip:[321,3,1,""],partition:[321,3,1,""],raw:[321,3,1,""],re_format:[321,4,1,""],replace:[321,3,1,""],rfind:[321,3,1,""],rindex:[321,3,1,""],rjust:[321,3,1,""],rsplit:[321,3,1,""],rstrip:[321,3,1,""],split:[321,3,1,""],startswith:[321,3,1,""],strip:[321,3,1,""],swapcase:[321,3,1,""],translate:[321,3,1,""],upper:[321,3,1,""]},"evennia.utils.batchprocessors":{BatchCodeProcessor:[322,1,1,""],BatchCommandProcessor:[322,1,1,""],read_batchfile:[322,5,1,""],tb_filename:[322,5,1,""],tb_iter:[322,5,1,""]},"evennia.utils.batchprocessors.BatchCodeProcessor":{code_exec:[322,3,1,""],parse_file:[322,3,1,""]},"evennia.utils.batchprocessors.BatchCommandProcessor":{parse_file:[322,3,1,""]},"evennia.utils.containers":{Container:[323,1,1,""],GlobalScriptContainer:[323,1,1,""],OptionContainer:[323,1,1,""]},"evennia.utils.containers.Container":{__init__:[323,3,1,""],all:[323,3,1,""],get:[323,3,1,""],load_data:[323,3,1,""],storage_modules:[323,4,1,""]},"evennia.utils.containers.GlobalScriptContainer":{__init__:[323,3,1,""],all:[323,3,1,""],get:[323,3,1,""],load_data:[323,3,1,""],start:[323,3,1,""]},"evennia.utils.containers.OptionContainer":{storage_modules:[323,4,1,""]},"evennia.utils.create":{create_account:[324,5,1,""],create_channel:[324,5,1,""],create_help_entry:[324,5,1,""],create_message:[324,5,1,""],create_object:[324,5,1,""],create_script:[324,5,1,""]},"evennia.utils.dbserialize":{dbserialize:[325,5,1,""],dbunserialize:[325,5,1,""],do_pickle:[325,5,1,""],do_unpickle:[325,5,1,""],from_pickle:[325,5,1,""],to_pickle:[325,5,1,""]},"evennia.utils.eveditor":{CmdEditorBase:[326,1,1,""],CmdEditorGroup:[326,1,1,""],CmdLineInput:[326,1,1,""],CmdSaveYesNo:[326,1,1,""],EvEditor:[326,1,1,""],EvEditorCmdSet:[326,1,1,""],SaveYesNoCmdSet:[326,1,1,""]},"evennia.utils.eveditor.CmdEditorBase":{aliases:[326,4,1,""],editor:[326,4,1,""],help_category:[326,4,1,""],help_entry:[326,4,1,""],key:[326,4,1,""],lock_storage:[326,4,1,""],locks:[326,4,1,""],parse:[326,3,1,""]},"evennia.utils.eveditor.CmdEditorGroup":{aliases:[326,4,1,""],arg_regex:[326,4,1,""],func:[326,3,1,""],help_category:[326,4,1,""],key:[326,4,1,""],lock_storage:[326,4,1,""]},"evennia.utils.eveditor.CmdLineInput":{aliases:[326,4,1,""],func:[326,3,1,""],help_category:[326,4,1,""],key:[326,4,1,""],lock_storage:[326,4,1,""]},"evennia.utils.eveditor.CmdSaveYesNo":{aliases:[326,4,1,""],func:[326,3,1,""],help_category:[326,4,1,""],help_cateogory:[326,4,1,""],key:[326,4,1,""],lock_storage:[326,4,1,""],locks:[326,4,1,""]},"evennia.utils.eveditor.EvEditor":{__init__:[326,3,1,""],decrease_indent:[326,3,1,""],deduce_indent:[326,3,1,""],display_buffer:[326,3,1,""],display_help:[326,3,1,""],get_buffer:[326,3,1,""],increase_indent:[326,3,1,""],load_buffer:[326,3,1,""],quit:[326,3,1,""],save_buffer:[326,3,1,""],swap_autoindent:[326,3,1,""],update_buffer:[326,3,1,""],update_undo:[326,3,1,""]},"evennia.utils.eveditor.EvEditorCmdSet":{at_cmdset_creation:[326,3,1,""],key:[326,4,1,""],mergetype:[326,4,1,""],path:[326,4,1,""]},"evennia.utils.eveditor.SaveYesNoCmdSet":{at_cmdset_creation:[326,3,1,""],key:[326,4,1,""],mergetype:[326,4,1,""],path:[326,4,1,""],priority:[326,4,1,""]},"evennia.utils.evform":{EvForm:[327,1,1,""]},"evennia.utils.evform.EvForm":{__init__:[327,3,1,""],map:[327,3,1,""],reload:[327,3,1,""]},"evennia.utils.evmenu":{CmdEvMenuNode:[328,1,1,""],CmdGetInput:[328,1,1,""],EvMenu:[328,1,1,""],EvMenuCmdSet:[328,1,1,""],EvMenuError:[328,2,1,""],EvMenuGotoAbortMessage:[328,2,1,""],InputCmdSet:[328,1,1,""],get_input:[328,5,1,""],list_node:[328,5,1,""],parse_menu_template:[328,5,1,""],template2menu:[328,5,1,""]},"evennia.utils.evmenu.CmdEvMenuNode":{aliases:[328,4,1,""],auto_help_display_key:[328,4,1,""],func:[328,3,1,""],get_help:[328,3,1,""],help_category:[328,4,1,""],key:[328,4,1,""],lock_storage:[328,4,1,""],locks:[328,4,1,""]},"evennia.utils.evmenu.CmdGetInput":{aliases:[328,4,1,""],func:[328,3,1,""],help_category:[328,4,1,""],key:[328,4,1,""],lock_storage:[328,4,1,""]},"evennia.utils.evmenu.EvMenu":{"goto":[328,3,1,""],__init__:[328,3,1,""],close_menu:[328,3,1,""],display_helptext:[328,3,1,""],display_nodetext:[328,3,1,""],extract_goto_exec:[328,3,1,""],helptext_formatter:[328,3,1,""],msg:[328,3,1,""],node_border_char:[328,4,1,""],node_formatter:[328,3,1,""],nodetext_formatter:[328,3,1,""],options_formatter:[328,3,1,""],parse_input:[328,3,1,""],print_debug_info:[328,3,1,""],run_exec:[328,3,1,""],run_exec_then_goto:[328,3,1,""]},"evennia.utils.evmenu.EvMenuCmdSet":{at_cmdset_creation:[328,3,1,""],key:[328,4,1,""],mergetype:[328,4,1,""],no_channels:[328,4,1,""],no_exits:[328,4,1,""],no_objs:[328,4,1,""],path:[328,4,1,""],priority:[328,4,1,""]},"evennia.utils.evmenu.InputCmdSet":{at_cmdset_creation:[328,3,1,""],key:[328,4,1,""],mergetype:[328,4,1,""],no_channels:[328,4,1,""],no_exits:[328,4,1,""],no_objs:[328,4,1,""],path:[328,4,1,""],priority:[328,4,1,""]},"evennia.utils.evmore":{CmdMore:[329,1,1,""],CmdMoreLook:[329,1,1,""],CmdSetMore:[329,1,1,""],EvMore:[329,1,1,""],msg:[329,5,1,""],queryset_maxsize:[329,5,1,""]},"evennia.utils.evmore.CmdMore":{aliases:[329,4,1,""],auto_help:[329,4,1,""],func:[329,3,1,""],help_category:[329,4,1,""],key:[329,4,1,""],lock_storage:[329,4,1,""]},"evennia.utils.evmore.CmdMoreLook":{aliases:[329,4,1,""],auto_help:[329,4,1,""],func:[329,3,1,""],help_category:[329,4,1,""],key:[329,4,1,""],lock_storage:[329,4,1,""]},"evennia.utils.evmore.CmdSetMore":{at_cmdset_creation:[329,3,1,""],key:[329,4,1,""],path:[329,4,1,""],priority:[329,4,1,""]},"evennia.utils.evmore.EvMore":{__init__:[329,3,1,""],display:[329,3,1,""],init_django_paginator:[329,3,1,""],init_evtable:[329,3,1,""],init_f_str:[329,3,1,""],init_iterable:[329,3,1,""],init_pages:[329,3,1,""],init_queryset:[329,3,1,""],init_str:[329,3,1,""],page_back:[329,3,1,""],page_end:[329,3,1,""],page_formatter:[329,3,1,""],page_next:[329,3,1,""],page_quit:[329,3,1,""],page_top:[329,3,1,""],paginator:[329,3,1,""],paginator_django:[329,3,1,""],paginator_index:[329,3,1,""],paginator_slice:[329,3,1,""],start:[329,3,1,""]},"evennia.utils.evtable":{ANSITextWrapper:[330,1,1,""],EvCell:[330,1,1,""],EvColumn:[330,1,1,""],EvTable:[330,1,1,""],fill:[330,5,1,""],wrap:[330,5,1,""]},"evennia.utils.evtable.EvCell":{__init__:[330,3,1,""],get:[330,3,1,""],get_height:[330,3,1,""],get_min_height:[330,3,1,""],get_min_width:[330,3,1,""],get_width:[330,3,1,""],reformat:[330,3,1,""],replace_data:[330,3,1,""]},"evennia.utils.evtable.EvColumn":{__init__:[330,3,1,""],add_rows:[330,3,1,""],reformat:[330,3,1,""],reformat_cell:[330,3,1,""]},"evennia.utils.evtable.EvTable":{__init__:[330,3,1,""],add_column:[330,3,1,""],add_header:[330,3,1,""],add_row:[330,3,1,""],get:[330,3,1,""],reformat:[330,3,1,""],reformat_column:[330,3,1,""]},"evennia.utils.gametime":{TimeScript:[331,1,1,""],game_epoch:[331,5,1,""],gametime:[331,5,1,""],portal_uptime:[331,5,1,""],real_seconds_until:[331,5,1,""],reset_gametime:[331,5,1,""],runtime:[331,5,1,""],schedule:[331,5,1,""],server_epoch:[331,5,1,""],uptime:[331,5,1,""]},"evennia.utils.gametime.TimeScript":{DoesNotExist:[331,2,1,""],MultipleObjectsReturned:[331,2,1,""],at_repeat:[331,3,1,""],at_script_creation:[331,3,1,""],path:[331,4,1,""],typename:[331,4,1,""]},"evennia.utils.idmapper":{manager:[333,0,0,"-"],models:[334,0,0,"-"],tests:[335,0,0,"-"]},"evennia.utils.idmapper.manager":{SharedMemoryManager:[333,1,1,""]},"evennia.utils.idmapper.manager.SharedMemoryManager":{get:[333,3,1,""]},"evennia.utils.idmapper.models":{SharedMemoryModel:[334,1,1,""],SharedMemoryModelBase:[334,1,1,""],WeakSharedMemoryModel:[334,1,1,""],WeakSharedMemoryModelBase:[334,1,1,""],cache_size:[334,5,1,""],conditional_flush:[334,5,1,""],flush_cache:[334,5,1,""],flush_cached_instance:[334,5,1,""],update_cached_instance:[334,5,1,""]},"evennia.utils.idmapper.models.SharedMemoryModel":{"delete":[334,3,1,""],Meta:[334,1,1,""],at_idmapper_flush:[334,3,1,""],cache_instance:[334,3,1,""],flush_cached_instance:[334,3,1,""],flush_from_cache:[334,3,1,""],flush_instance_cache:[334,3,1,""],get_all_cached_instances:[334,3,1,""],get_cached_instance:[334,3,1,""],objects:[334,4,1,""],path:[334,4,1,""],save:[334,3,1,""],typename:[334,4,1,""]},"evennia.utils.idmapper.models.SharedMemoryModel.Meta":{"abstract":[334,4,1,""]},"evennia.utils.idmapper.models.WeakSharedMemoryModel":{Meta:[334,1,1,""],path:[334,4,1,""],typename:[334,4,1,""]},"evennia.utils.idmapper.models.WeakSharedMemoryModel.Meta":{"abstract":[334,4,1,""]},"evennia.utils.idmapper.tests":{Article:[335,1,1,""],Category:[335,1,1,""],RegularArticle:[335,1,1,""],RegularCategory:[335,1,1,""],SharedMemorysTest:[335,1,1,""]},"evennia.utils.idmapper.tests.Article":{DoesNotExist:[335,2,1,""],MultipleObjectsReturned:[335,2,1,""],category2:[335,4,1,""],category2_id:[335,4,1,""],category:[335,4,1,""],category_id:[335,4,1,""],id:[335,4,1,""],name:[335,4,1,""],path:[335,4,1,""],typename:[335,4,1,""]},"evennia.utils.idmapper.tests.Category":{DoesNotExist:[335,2,1,""],MultipleObjectsReturned:[335,2,1,""],article_set:[335,4,1,""],id:[335,4,1,""],name:[335,4,1,""],path:[335,4,1,""],regulararticle_set:[335,4,1,""],typename:[335,4,1,""]},"evennia.utils.idmapper.tests.RegularArticle":{DoesNotExist:[335,2,1,""],MultipleObjectsReturned:[335,2,1,""],category2:[335,4,1,""],category2_id:[335,4,1,""],category:[335,4,1,""],category_id:[335,4,1,""],id:[335,4,1,""],name:[335,4,1,""],objects:[335,4,1,""]},"evennia.utils.idmapper.tests.RegularCategory":{DoesNotExist:[335,2,1,""],MultipleObjectsReturned:[335,2,1,""],article_set:[335,4,1,""],id:[335,4,1,""],name:[335,4,1,""],objects:[335,4,1,""],regulararticle_set:[335,4,1,""]},"evennia.utils.idmapper.tests.SharedMemorysTest":{setUp:[335,3,1,""],testMixedReferences:[335,3,1,""],testObjectDeletion:[335,3,1,""],testRegularReferences:[335,3,1,""],testSharedMemoryReferences:[335,3,1,""]},"evennia.utils.inlinefuncs":{"null":[336,5,1,""],InlinefuncError:[336,2,1,""],NickTemplateInvalid:[336,2,1,""],ParseStack:[336,1,1,""],clr:[336,5,1,""],crop:[336,5,1,""],initialize_nick_templates:[336,5,1,""],nomatch:[336,5,1,""],pad:[336,5,1,""],parse_inlinefunc:[336,5,1,""],parse_nick_template:[336,5,1,""],random:[336,5,1,""],raw:[336,5,1,""],space:[336,5,1,""]},"evennia.utils.inlinefuncs.ParseStack":{__init__:[336,3,1,""],append:[336,3,1,""]},"evennia.utils.logger":{EvenniaLogFile:[337,1,1,""],PortalLogObserver:[337,1,1,""],ServerLogObserver:[337,1,1,""],WeeklyLogFile:[337,1,1,""],log_dep:[337,5,1,""],log_depmsg:[337,5,1,""],log_err:[337,5,1,""],log_errmsg:[337,5,1,""],log_file:[337,5,1,""],log_info:[337,5,1,""],log_infomsg:[337,5,1,""],log_msg:[337,5,1,""],log_sec:[337,5,1,""],log_secmsg:[337,5,1,""],log_server:[337,5,1,""],log_trace:[337,5,1,""],log_tracemsg:[337,5,1,""],log_warn:[337,5,1,""],log_warnmsg:[337,5,1,""],tail_log_file:[337,5,1,""],timeformat:[337,5,1,""]},"evennia.utils.logger.EvenniaLogFile":{num_lines_to_append:[337,4,1,""],readlines:[337,3,1,""],rotate:[337,3,1,""],seek:[337,3,1,""],settings:[337,4,1,""]},"evennia.utils.logger.PortalLogObserver":{emit:[337,3,1,""],prefix:[337,4,1,""],timeFormat:[337,4,1,""]},"evennia.utils.logger.ServerLogObserver":{prefix:[337,4,1,""]},"evennia.utils.logger.WeeklyLogFile":{__init__:[337,3,1,""],shouldRotate:[337,3,1,""],suffix:[337,3,1,""],write:[337,3,1,""]},"evennia.utils.optionclasses":{BaseOption:[338,1,1,""],Boolean:[338,1,1,""],Color:[338,1,1,""],Datetime:[338,1,1,""],Duration:[338,1,1,""],Email:[338,1,1,""],Future:[338,1,1,""],Lock:[338,1,1,""],PositiveInteger:[338,1,1,""],SignedInteger:[338,1,1,""],Text:[338,1,1,""],Timezone:[338,1,1,""],UnsignedInteger:[338,1,1,""]},"evennia.utils.optionclasses.BaseOption":{"default":[338,3,1,""],__init__:[338,3,1,""],changed:[338,3,1,""],deserialize:[338,3,1,""],display:[338,3,1,""],load:[338,3,1,""],save:[338,3,1,""],serialize:[338,3,1,""],set:[338,3,1,""],validate:[338,3,1,""],value:[338,3,1,""]},"evennia.utils.optionclasses.Boolean":{deserialize:[338,3,1,""],display:[338,3,1,""],serialize:[338,3,1,""],validate:[338,3,1,""]},"evennia.utils.optionclasses.Color":{deserialize:[338,3,1,""],display:[338,3,1,""],validate:[338,3,1,""]},"evennia.utils.optionclasses.Datetime":{deserialize:[338,3,1,""],serialize:[338,3,1,""],validate:[338,3,1,""]},"evennia.utils.optionclasses.Duration":{deserialize:[338,3,1,""],serialize:[338,3,1,""],validate:[338,3,1,""]},"evennia.utils.optionclasses.Email":{deserialize:[338,3,1,""],validate:[338,3,1,""]},"evennia.utils.optionclasses.Future":{validate:[338,3,1,""]},"evennia.utils.optionclasses.Lock":{validate:[338,3,1,""]},"evennia.utils.optionclasses.PositiveInteger":{deserialize:[338,3,1,""],validate:[338,3,1,""]},"evennia.utils.optionclasses.SignedInteger":{deserialize:[338,3,1,""],validate:[338,3,1,""]},"evennia.utils.optionclasses.Text":{deserialize:[338,3,1,""]},"evennia.utils.optionclasses.Timezone":{"default":[338,3,1,""],deserialize:[338,3,1,""],serialize:[338,3,1,""],validate:[338,3,1,""]},"evennia.utils.optionclasses.UnsignedInteger":{deserialize:[338,3,1,""],validate:[338,3,1,""],validator_key:[338,4,1,""]},"evennia.utils.optionhandler":{InMemorySaveHandler:[339,1,1,""],OptionHandler:[339,1,1,""]},"evennia.utils.optionhandler.InMemorySaveHandler":{__init__:[339,3,1,""],add:[339,3,1,""],get:[339,3,1,""]},"evennia.utils.optionhandler.OptionHandler":{__init__:[339,3,1,""],all:[339,3,1,""],get:[339,3,1,""],set:[339,3,1,""]},"evennia.utils.picklefield":{PickledFormField:[340,1,1,""],PickledObject:[340,1,1,""],PickledObjectField:[340,1,1,""],PickledWidget:[340,1,1,""],dbsafe_decode:[340,5,1,""],dbsafe_encode:[340,5,1,""],wrap_conflictual_object:[340,5,1,""]},"evennia.utils.picklefield.PickledFormField":{__init__:[340,3,1,""],clean:[340,3,1,""],default_error_messages:[340,4,1,""],widget:[340,4,1,""]},"evennia.utils.picklefield.PickledObjectField":{__init__:[340,3,1,""],formfield:[340,3,1,""],from_db_value:[340,3,1,""],get_db_prep_lookup:[340,3,1,""],get_db_prep_value:[340,3,1,""],get_default:[340,3,1,""],get_internal_type:[340,3,1,""],pre_save:[340,3,1,""],value_to_string:[340,3,1,""]},"evennia.utils.picklefield.PickledWidget":{media:[340,3,1,""],render:[340,3,1,""],value_from_datadict:[340,3,1,""]},"evennia.utils.search":{search_account:[341,5,1,""],search_account_tag:[341,5,1,""],search_channel:[341,5,1,""],search_channel_tag:[341,5,1,""],search_help_entry:[341,5,1,""],search_message:[341,5,1,""],search_object:[341,5,1,""],search_script:[341,5,1,""],search_script_tag:[341,5,1,""]},"evennia.utils.test_resources":{EvenniaTest:[342,1,1,""],LocalEvenniaTest:[342,1,1,""],mockdeferLater:[342,5,1,""],mockdelay:[342,5,1,""],unload_module:[342,5,1,""]},"evennia.utils.test_resources.EvenniaTest":{account_typeclass:[342,4,1,""],character_typeclass:[342,4,1,""],exit_typeclass:[342,4,1,""],object_typeclass:[342,4,1,""],room_typeclass:[342,4,1,""],script_typeclass:[342,4,1,""],setUp:[342,3,1,""],tearDown:[342,3,1,""]},"evennia.utils.test_resources.LocalEvenniaTest":{account_typeclass:[342,4,1,""],character_typeclass:[342,4,1,""],exit_typeclass:[342,4,1,""],object_typeclass:[342,4,1,""],room_typeclass:[342,4,1,""],script_typeclass:[342,4,1,""]},"evennia.utils.text2html":{TextToHTMLparser:[343,1,1,""],parse_html:[343,5,1,""]},"evennia.utils.text2html.TextToHTMLparser":{bg_colormap:[343,4,1,""],bgfgstart:[343,4,1,""],bgfgstop:[343,4,1,""],bgstart:[343,4,1,""],bgstop:[343,4,1,""],blink:[343,4,1,""],colorback:[343,4,1,""],colorcodes:[343,4,1,""],convert_linebreaks:[343,3,1,""],convert_urls:[343,3,1,""],fg_colormap:[343,4,1,""],fgstart:[343,4,1,""],fgstop:[343,4,1,""],hilite:[343,4,1,""],inverse:[343,4,1,""],normal:[343,4,1,""],parse:[343,3,1,""],re_bgfg:[343,4,1,""],re_bgs:[343,4,1,""],re_blink:[343,4,1,""],re_blinking:[343,3,1,""],re_bold:[343,3,1,""],re_color:[343,3,1,""],re_dblspace:[343,4,1,""],re_double_space:[343,3,1,""],re_fgs:[343,4,1,""],re_hilite:[343,4,1,""],re_inverse:[343,4,1,""],re_inversing:[343,3,1,""],re_mxplink:[343,4,1,""],re_normal:[343,4,1,""],re_string:[343,4,1,""],re_uline:[343,4,1,""],re_underline:[343,3,1,""],re_unhilite:[343,4,1,""],re_url:[343,4,1,""],remove_backspaces:[343,3,1,""],remove_bells:[343,3,1,""],sub_dblspace:[343,3,1,""],sub_mxp_links:[343,3,1,""],sub_text:[343,3,1,""],tabstop:[343,4,1,""],underline:[343,4,1,""],unhilite:[343,4,1,""]},"evennia.utils.utils":{LimitedSizeOrderedDict:[344,1,1,""],all_from_module:[344,5,1,""],at_search_result:[344,5,1,""],callables_from_module:[344,5,1,""],calledby:[344,5,1,""],check_evennia_dependencies:[344,5,1,""],class_from_module:[344,5,1,""],columnize:[344,5,1,""],crop:[344,5,1,""],datetime_format:[344,5,1,""],dbid_to_obj:[344,5,1,""],dbref:[344,5,1,""],dbref_to_obj:[344,5,1,""],dedent:[344,5,1,""],deepsize:[344,5,1,""],delay:[344,5,1,""],display_len:[344,5,1,""],fill:[344,5,1,""],format_table:[344,5,1,""],fuzzy_import_from_module:[344,5,1,""],get_all_typeclasses:[344,5,1,""],get_evennia_pids:[344,5,1,""],get_evennia_version:[344,5,1,""],get_game_dir_path:[344,5,1,""],has_parent:[344,5,1,""],host_os_is:[344,5,1,""],inherits_from:[344,5,1,""],init_new_account:[344,5,1,""],interactive:[344,5,1,""],is_iter:[344,5,1,""],iter_to_string:[344,5,1,""],justify:[344,5,1,""],latinify:[344,5,1,""],lazy_property:[344,1,1,""],list_to_string:[344,5,1,""],m_len:[344,5,1,""],make_iter:[344,5,1,""],mod_import:[344,5,1,""],mod_import_from_path:[344,5,1,""],object_from_module:[344,5,1,""],pad:[344,5,1,""],pypath_to_realpath:[344,5,1,""],random_string_from_module:[344,5,1,""],run_async:[344,5,1,""],server_services:[344,5,1,""],string_from_module:[344,5,1,""],string_partial_matching:[344,5,1,""],string_similarity:[344,5,1,""],string_suggestions:[344,5,1,""],strip_control_sequences:[344,5,1,""],time_format:[344,5,1,""],to_bytes:[344,5,1,""],to_str:[344,5,1,""],uses_database:[344,5,1,""],validate_email_address:[344,5,1,""],variable_from_module:[344,5,1,""],wildcard_to_regexp:[344,5,1,""],wrap:[344,5,1,""]},"evennia.utils.utils.LimitedSizeOrderedDict":{__init__:[344,3,1,""],update:[344,3,1,""]},"evennia.utils.utils.lazy_property":{__init__:[344,3,1,""]},"evennia.utils.validatorfuncs":{"boolean":[345,5,1,""],color:[345,5,1,""],datetime:[345,5,1,""],duration:[345,5,1,""],email:[345,5,1,""],future:[345,5,1,""],lock:[345,5,1,""],positive_integer:[345,5,1,""],signed_integer:[345,5,1,""],text:[345,5,1,""],timezone:[345,5,1,""],unsigned_integer:[345,5,1,""]},"evennia.web":{urls:[347,0,0,"-"],utils:[348,0,0,"-"],webclient:[353,0,0,"-"],website:[356,0,0,"-"]},"evennia.web.utils":{backends:[349,0,0,"-"],general_context:[350,0,0,"-"],middleware:[351,0,0,"-"],tests:[352,0,0,"-"]},"evennia.web.utils.backends":{CaseInsensitiveModelBackend:[349,1,1,""]},"evennia.web.utils.backends.CaseInsensitiveModelBackend":{authenticate:[349,3,1,""]},"evennia.web.utils.general_context":{general_context:[350,5,1,""],set_game_name_and_slogan:[350,5,1,""],set_webclient_settings:[350,5,1,""]},"evennia.web.utils.middleware":{SharedLoginMiddleware:[351,1,1,""]},"evennia.web.utils.middleware.SharedLoginMiddleware":{__init__:[351,3,1,""],make_shared_login:[351,3,1,""]},"evennia.web.utils.tests":{TestGeneralContext:[352,1,1,""]},"evennia.web.utils.tests.TestGeneralContext":{maxDiff:[352,4,1,""],test_general_context:[352,3,1,""],test_set_game_name_and_slogan:[352,3,1,""],test_set_webclient_settings:[352,3,1,""]},"evennia.web.webclient":{urls:[354,0,0,"-"],views:[355,0,0,"-"]},"evennia.web.webclient.views":{webclient:[355,5,1,""]},"evennia.web.website":{forms:[357,0,0,"-"],templatetags:[358,0,0,"-"],tests:[360,0,0,"-"],urls:[361,0,0,"-"],views:[362,0,0,"-"]},"evennia.web.website.forms":{AccountForm:[357,1,1,""],CharacterForm:[357,1,1,""],CharacterUpdateForm:[357,1,1,""],EvenniaForm:[357,1,1,""],ObjectForm:[357,1,1,""]},"evennia.web.website.forms.AccountForm":{Meta:[357,1,1,""],base_fields:[357,4,1,""],declared_fields:[357,4,1,""],media:[357,3,1,""]},"evennia.web.website.forms.AccountForm.Meta":{field_classes:[357,4,1,""],fields:[357,4,1,""],model:[357,4,1,""]},"evennia.web.website.forms.CharacterForm":{Meta:[357,1,1,""],base_fields:[357,4,1,""],declared_fields:[357,4,1,""],media:[357,3,1,""]},"evennia.web.website.forms.CharacterForm.Meta":{fields:[357,4,1,""],labels:[357,4,1,""],model:[357,4,1,""]},"evennia.web.website.forms.CharacterUpdateForm":{base_fields:[357,4,1,""],declared_fields:[357,4,1,""],media:[357,3,1,""]},"evennia.web.website.forms.EvenniaForm":{base_fields:[357,4,1,""],clean:[357,3,1,""],declared_fields:[357,4,1,""],media:[357,3,1,""]},"evennia.web.website.forms.ObjectForm":{Meta:[357,1,1,""],base_fields:[357,4,1,""],declared_fields:[357,4,1,""],media:[357,3,1,""]},"evennia.web.website.forms.ObjectForm.Meta":{fields:[357,4,1,""],labels:[357,4,1,""],model:[357,4,1,""]},"evennia.web.website.templatetags":{addclass:[359,0,0,"-"]},"evennia.web.website.templatetags.addclass":{addclass:[359,5,1,""]},"evennia.web.website.tests":{AdminTest:[360,1,1,""],ChannelDetailTest:[360,1,1,""],ChannelListTest:[360,1,1,""],CharacterCreateView:[360,1,1,""],CharacterDeleteView:[360,1,1,""],CharacterListView:[360,1,1,""],CharacterManageView:[360,1,1,""],CharacterPuppetView:[360,1,1,""],CharacterUpdateView:[360,1,1,""],EvenniaWebTest:[360,1,1,""],IndexTest:[360,1,1,""],LoginTest:[360,1,1,""],LogoutTest:[360,1,1,""],PasswordResetTest:[360,1,1,""],RegisterTest:[360,1,1,""],WebclientTest:[360,1,1,""]},"evennia.web.website.tests.AdminTest":{unauthenticated_response:[360,4,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.ChannelDetailTest":{get_kwargs:[360,3,1,""],setUp:[360,3,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.ChannelListTest":{url_name:[360,4,1,""]},"evennia.web.website.tests.CharacterCreateView":{test_valid_access_multisession_0:[360,3,1,""],test_valid_access_multisession_2:[360,3,1,""],unauthenticated_response:[360,4,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.CharacterDeleteView":{get_kwargs:[360,3,1,""],test_invalid_access:[360,3,1,""],test_valid_access:[360,3,1,""],unauthenticated_response:[360,4,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.CharacterListView":{unauthenticated_response:[360,4,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.CharacterManageView":{unauthenticated_response:[360,4,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.CharacterPuppetView":{get_kwargs:[360,3,1,""],test_invalid_access:[360,3,1,""],unauthenticated_response:[360,4,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.CharacterUpdateView":{get_kwargs:[360,3,1,""],test_invalid_access:[360,3,1,""],test_valid_access:[360,3,1,""],unauthenticated_response:[360,4,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.EvenniaWebTest":{account_typeclass:[360,4,1,""],authenticated_response:[360,4,1,""],channel_typeclass:[360,4,1,""],character_typeclass:[360,4,1,""],exit_typeclass:[360,4,1,""],get_kwargs:[360,3,1,""],login:[360,3,1,""],object_typeclass:[360,4,1,""],room_typeclass:[360,4,1,""],script_typeclass:[360,4,1,""],setUp:[360,3,1,""],test_get:[360,3,1,""],test_get_authenticated:[360,3,1,""],test_valid_chars:[360,3,1,""],unauthenticated_response:[360,4,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.IndexTest":{url_name:[360,4,1,""]},"evennia.web.website.tests.LoginTest":{url_name:[360,4,1,""]},"evennia.web.website.tests.LogoutTest":{url_name:[360,4,1,""]},"evennia.web.website.tests.PasswordResetTest":{unauthenticated_response:[360,4,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.RegisterTest":{url_name:[360,4,1,""]},"evennia.web.website.tests.WebclientTest":{test_get:[360,3,1,""],test_get_disabled:[360,3,1,""],url_name:[360,4,1,""]},"evennia.web.website.views":{AccountCreateView:[362,1,1,""],AccountMixin:[362,1,1,""],ChannelDetailView:[362,1,1,""],ChannelListView:[362,1,1,""],ChannelMixin:[362,1,1,""],CharacterCreateView:[362,1,1,""],CharacterDeleteView:[362,1,1,""],CharacterDetailView:[362,1,1,""],CharacterListView:[362,1,1,""],CharacterManageView:[362,1,1,""],CharacterMixin:[362,1,1,""],CharacterPuppetView:[362,1,1,""],CharacterUpdateView:[362,1,1,""],EvenniaCreateView:[362,1,1,""],EvenniaDeleteView:[362,1,1,""],EvenniaDetailView:[362,1,1,""],EvenniaIndexView:[362,1,1,""],EvenniaUpdateView:[362,1,1,""],HelpDetailView:[362,1,1,""],HelpListView:[362,1,1,""],HelpMixin:[362,1,1,""],ObjectCreateView:[362,1,1,""],ObjectDeleteView:[362,1,1,""],ObjectDetailView:[362,1,1,""],ObjectUpdateView:[362,1,1,""],TypeclassMixin:[362,1,1,""],admin_wrapper:[362,5,1,""],evennia_admin:[362,5,1,""],to_be_implemented:[362,5,1,""]},"evennia.web.website.views.AccountCreateView":{form_valid:[362,3,1,""],success_url:[362,4,1,""],template_name:[362,4,1,""]},"evennia.web.website.views.AccountMixin":{form_class:[362,4,1,""],model:[362,4,1,""]},"evennia.web.website.views.ChannelDetailView":{attributes:[362,4,1,""],get_context_data:[362,3,1,""],get_object:[362,3,1,""],max_num_lines:[362,4,1,""],template_name:[362,4,1,""]},"evennia.web.website.views.ChannelListView":{get_context_data:[362,3,1,""],max_popular:[362,4,1,""],page_title:[362,4,1,""],paginate_by:[362,4,1,""],template_name:[362,4,1,""]},"evennia.web.website.views.ChannelMixin":{access_type:[362,4,1,""],get_queryset:[362,3,1,""],model:[362,4,1,""],page_title:[362,4,1,""]},"evennia.web.website.views.CharacterCreateView":{form_valid:[362,3,1,""],template_name:[362,4,1,""]},"evennia.web.website.views.CharacterDetailView":{access_type:[362,4,1,""],attributes:[362,4,1,""],get_queryset:[362,3,1,""],template_name:[362,4,1,""]},"evennia.web.website.views.CharacterListView":{access_type:[362,4,1,""],get_queryset:[362,3,1,""],page_title:[362,4,1,""],paginate_by:[362,4,1,""],template_name:[362,4,1,""]},"evennia.web.website.views.CharacterManageView":{page_title:[362,4,1,""],paginate_by:[362,4,1,""],template_name:[362,4,1,""]},"evennia.web.website.views.CharacterMixin":{form_class:[362,4,1,""],get_queryset:[362,3,1,""],model:[362,4,1,""],success_url:[362,4,1,""]},"evennia.web.website.views.CharacterPuppetView":{get_redirect_url:[362,3,1,""]},"evennia.web.website.views.CharacterUpdateView":{form_class:[362,4,1,""],template_name:[362,4,1,""]},"evennia.web.website.views.EvenniaCreateView":{page_title:[362,3,1,""]},"evennia.web.website.views.EvenniaDeleteView":{page_title:[362,3,1,""]},"evennia.web.website.views.EvenniaDetailView":{page_title:[362,3,1,""]},"evennia.web.website.views.EvenniaIndexView":{get_context_data:[362,3,1,""],template_name:[362,4,1,""]},"evennia.web.website.views.EvenniaUpdateView":{page_title:[362,3,1,""]},"evennia.web.website.views.HelpDetailView":{get_context_data:[362,3,1,""],get_object:[362,3,1,""],template_name:[362,4,1,""]},"evennia.web.website.views.HelpListView":{page_title:[362,4,1,""],paginate_by:[362,4,1,""],template_name:[362,4,1,""]},"evennia.web.website.views.HelpMixin":{get_queryset:[362,3,1,""],model:[362,4,1,""],page_title:[362,4,1,""]},"evennia.web.website.views.ObjectCreateView":{model:[362,4,1,""]},"evennia.web.website.views.ObjectDeleteView":{"delete":[362,3,1,""],access_type:[362,4,1,""],model:[362,4,1,""],template_name:[362,4,1,""]},"evennia.web.website.views.ObjectDetailView":{access_type:[362,4,1,""],attributes:[362,4,1,""],get_context_data:[362,3,1,""],get_object:[362,3,1,""],model:[362,4,1,""],template_name:[362,4,1,""]},"evennia.web.website.views.ObjectUpdateView":{access_type:[362,4,1,""],form_valid:[362,3,1,""],get_initial:[362,3,1,""],get_success_url:[362,3,1,""],model:[362,4,1,""]},"evennia.web.website.views.TypeclassMixin":{typeclass:[362,3,1,""]},evennia:{accounts:[143,0,0,"-"],commands:[149,0,0,"-"],comms:[172,0,0,"-"],contrib:[178,0,0,"-"],help:[236,0,0,"-"],locks:[240,0,0,"-"],objects:[243,0,0,"-"],prototypes:[248,0,0,"-"],scripts:[253,0,0,"-"],server:[262,0,0,"-"],set_trace:[141,5,1,""],settings_default:[313,0,0,"-"],typeclasses:[314,0,0,"-"],utils:[320,0,0,"-"],web:[346,0,0,"-"]}},objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","exception","Python exception"],"3":["py","method","Python method"],"4":["py","attribute","Python attribute"],"5":["py","function","Python function"],"6":["py","data","Python data"]},objtypes:{"0":"py:module","1":"py:class","2":"py:exception","3":"py:method","4":"py:attribute","5":"py:function","6":"py:data"},terms:{"000":[0,25,46,82,114,343],"0000":[0,46],"0004":22,"001":[22,127,343],"002":343,"003":343,"004":343,"005":[114,321,343],"006":343,"007":343,"008":343,"009":343,"00sc":124,"010":[25,343],"011":343,"012":343,"013":343,"014":343,"015":343,"015public":25,"016":343,"017":343,"018":343,"019":343,"020":343,"020t":25,"021":343,"022":343,"023":343,"024":343,"0247":22,"025":343,"026":343,"027":343,"028":343,"029":343,"030":343,"030a":25,"031":343,"032":343,"033":[321,343],"034":[22,343],"035":343,"036":343,"037":343,"038":343,"039":343,"040":343,"040f":25,"041":343,"042":343,"043":343,"044":343,"045":343,"046":343,"047":343,"048":343,"049":343,"050":[321,343],"050f":25,"051":343,"052":343,"053":343,"054":[114,343],"055":[321,343],"056":343,"057":343,"058":343,"059":343,"060":343,"061":343,"062":343,"062022":363,"063":343,"064":343,"065":343,"066":343,"067":343,"068":343,"069":343,"070":343,"071":343,"072":343,"073":343,"074":343,"075":343,"076":343,"077":343,"078":343,"079":343,"080":343,"081":343,"082":343,"083":343,"084":343,"085":343,"086":343,"087":343,"088":343,"089":343,"090":343,"091":343,"092":343,"093":343,"094":343,"095":343,"096":343,"097":343,"098":343,"099":343,"0b16":24,"0d0":56,"0x045a0990":42,"0x852be2c":59,"100":[31,43,56,73,85,93,111,125,169,185,188,217,220,221,343,362],"1000":[56,93,100,116,217,218,219,220,221,251],"10000":362,"1000000":[82,93,337],"100m":343,"100mb":90,"100x100":70,"101":[31,247,343],"101m":343,"102":343,"102m":343,"103":343,"103m":343,"104":343,"104m":343,"105":343,"105m":343,"106":343,"106m":343,"107":343,"107m":343,"108":343,"108m":343,"109":343,"1098":125,"109m":343,"10m":67,"110":[329,343],"110m":343,"111":[12,43,114,157,343],"111m":343,"112":343,"112m":343,"113":[90,343],"113m":343,"114":343,"114m":343,"115":343,"115600":56,"115m":343,"116":343,"116m":343,"117":343,"1172":138,"117m":343,"118":[115,343],"1184":23,"118m":343,"119":343,"119m":343,"120":[31,343],"1200":327,"120m":343,"121":343,"121m":343,"122":343,"122m":343,"123":[131,134,247,343],"1234":[54,109,203],"123dark":81,"123m":343,"124":343,"12400":82,"124m":343,"125":343,"125m":343,"126":343,"126m":343,"127":[8,9,24,63,67,90,287,343],"127m":343,"128":343,"128m":343,"129":343,"129m":343,"12s":27,"130":343,"130m":343,"131":343,"131m":343,"132":343,"132m":343,"133":343,"133m":343,"134":[12,43,157,343],"134m":343,"135":343,"135m":343,"136":343,"136m":343,"137":343,"137m":343,"138":343,"138m":343,"139":343,"139m":343,"140":[25,42,141,343],"1400":327,"140313967648552":33,"140m":343,"141":[139,343],"141m":343,"142":[22,180,343],"1424724909023":70,"142m":343,"143":343,"143m":343,"144":343,"144m":343,"145":343,"145m":343,"146":343,"146m":343,"147":343,"147m":343,"148":343,"148m":343,"149":343,"149m":343,"150":[326,343],"150m":343,"151":343,"151m":343,"152":343,"152m":343,"153":343,"153m":343,"154":343,"154m":343,"155":343,"155m":343,"156":[127,343],"156m":343,"157":343,"1577865600":62,"157m":343,"158":343,"158m":343,"159":343,"159m":343,"160":343,"160m":343,"161":343,"161m":343,"162":343,"162m":343,"163":343,"163m":343,"164":343,"164m":343,"165":343,"165m":343,"166":343,"166m":343,"167":343,"167m":343,"168":343,"168m":343,"169":343,"169m":343,"16m":343,"170":343,"170m":343,"171":343,"171m":343,"172":343,"172m":343,"173":343,"1730":79,"173m":343,"174":343,"174m":343,"175":343,"175m":343,"176":343,"1764":119,"176m":343,"177":343,"177m":343,"178":343,"178m":343,"179":343,"179m":343,"17m":343,"180":343,"180m":343,"181":343,"181m":343,"182":343,"182m":343,"183":343,"183m":343,"184":343,"184m":343,"185":343,"185m":343,"186":343,"186m":343,"187":343,"187m":343,"188":343,"188m":343,"189":343,"189m":343,"18m":343,"190":343,"1903":119,"190m":343,"191":343,"191m":343,"192":343,"192m":343,"193":343,"193m":343,"194":343,"194m":343,"195":343,"195m":343,"196":343,"196m":343,"197":343,"1970":62,"197m":343,"198":343,"198m":343,"199":343,"1996":79,"1998":79,"199m":343,"19m":343,"1_7":127,"1d100":[73,185],"1d2":56,"1d6":73,"1gb":90,"1st":62,"200":[343,360],"2001":79,"2003":79,"2004":79,"2008":344,"200m":343,"201":343,"2010":343,"2011":[124,181,214,232],"2012":[179,185,186,187],"2014":[21,213],"2015":[24,189,205,206],"2016":[99,199,202,212,214],"2017":[62,90,97,182,183,184,190,204,209,210,215,217,218,219,220,221,234,235],"2018":[9,180,188,198,203],"2019":[79,187],"201m":343,"202":343,"2020":[12,62,230,363],"2020_01_29":337,"2020_01_29__1":337,"2020_01_29__2":337,"202m":343,"203":[90,343],"203m":343,"204":343,"2048":67,"204m":343,"205":[327,343],"205m":343,"206":343,"206m":343,"207":343,"2076":119,"207m":343,"208":[91,343],"208m":343,"209":343,"209m":343,"20m":343,"210":343,"210m":343,"211":343,"211m":343,"212":[12,343],"2128":56,"212m":343,"213":343,"213m":343,"214":343,"214m":343,"215":343,"215m":343,"216":343,"216m":343,"217":343,"217m":343,"218":343,"218m":343,"219":[9,343],"219m":343,"21m":343,"220":343,"2207":204,"220m":343,"221":[322,343],"221m":343,"222":[114,321,343],"222m":343,"223":[12,343],"223m":343,"224":343,"224m":343,"225":[12,343],"225m":343,"226":343,"226m":343,"227":343,"227m":343,"228":343,"228m":343,"229":343,"229m":343,"22m":[321,343],"22nd":344,"230":[114,343],"230m":343,"231":343,"231m":343,"232":343,"232m":343,"233":[12,43,157,343],"233m":343,"234":[183,343],"234m":343,"235":343,"235m":343,"236":343,"236m":343,"237":[12,343],"237m":343,"238":343,"238m":343,"239":343,"239m":343,"23m":343,"240":343,"240m":343,"241":343,"241m":343,"242":343,"242m":343,"243":343,"243m":343,"244":343,"244m":343,"245":343,"245m":343,"246":343,"246m":343,"247":343,"247m":343,"248":343,"248m":343,"249":343,"249m":343,"24m":343,"250":343,"250m":343,"251":343,"251m":343,"252":343,"252m":343,"253":343,"253m":343,"254":343,"254m":343,"255":[24,343],"255fdonatecc":70,"255flg":70,"255fu":70,"255m":343,"256":[12,43,114,156,321],"25m":343,"26m":343,"27m":343,"280":71,"28comput":37,"28m":343,"29m":343,"2d6":[58,185],"2gb":90,"2pm6ywo":37,"300":[114,126,184,331],"3000000":82,"302":360,"30m":[321,343],"31m":[321,343],"31st":62,"32bit":[24,63],"32m":[321,343],"32nd":58,"333":[12,114],"33333":59,"33m":[321,343],"340":56,"34m":[321,343],"358283996582031":93,"35m":[321,343],"360":62,"3600":62,"36m":[321,343],"37m":[321,343],"3872":119,"38m":343,"39m":343,"3c3ccec30f037be174d3":344,"3d6":185,"3rd":62,"4000":[9,36,63,67,75,90,95,100,101,103],"4001":[3,4,8,9,36,63,67,69,75,90,95,100,101,103,133,134,135,137,296],"4002":[8,36,67,90,100],"4003":90,"4004":90,"4005":90,"4006":90,"403":131,"404":69,"40m":[321,343],"41917":287,"41m":[321,343],"4201":90,"4280":55,"42m":[321,343],"430000":62,"43m":[321,343],"443":[8,67,103],"444":114,"44m":[321,343],"45m":[27,321,343],"46m":[321,343],"47m":[321,343],"48m":343,"49m":343,"4er43233fwefwfw":9,"4th":[38,79],"500":[114,126,321,362],"50000":82,"505":321,"50m":343,"50mb":90,"516106":56,"51m":343,"520":114,"52m":343,"53m":343,"54m":343,"550":[321,327],"550n":25,"551e":25,"552w":25,"553b":25,"554i":25,"555":[114,204,321],"555e":25,"55m":343,"565000":62,"56m":343,"577349":343,"57m":343,"5885d80a13c0db1f8e263663d3faee8d66f31424b43e9a70645c907a6cbd8fb4":37,"58m":343,"593":344,"59m":343,"5d5":56,"5x5":111,"600":344,"60m":343,"614":138,"61m":343,"62m":343,"63m":343,"64m":343,"65m":343,"6666":40,"6667":[43,72,79,146,164,308],"66m":343,"67m":343,"68m":343,"69m":343,"6d6":56,"70982813835144":93,"70m":343,"71m":343,"72m":343,"73m":343,"74m":343,"75m":343,"760000":62,"76m":343,"775":36,"77m":343,"78m":343,"79m":343,"8080":90,"80m":343,"8111":36,"81m":343,"82m":343,"83m":343,"84m":343,"85000":82,"85m":343,"86400":120,"86m":343,"87m":343,"8859":[15,113],"88m":343,"89m":343,"8f64fec2670c":90,"900":[188,327],"9000":357,"90m":343,"90s":345,"91m":343,"92m":343,"93m":343,"94m":343,"95m":343,"96m":343,"97m":343,"981":204,"98m":343,"990":327,"99999":61,"99m":343,"\u6d4b\u8bd5":25,"abstract":[47,64,86,119,221,317,318,334,338,344],"boolean":[13,33,133,137,154,185,188,242,247,250,259,316,321,322,338,345],"break":[10,12,14,30,37,42,51,54,57,58,61,91,96,103,108,111,114,125,137,141,167,168,202,224,226,276,328,329,344],"byte":[15,27,113,269,276,278,287,295,344],"case":[1,6,8,10,11,12,13,14,15,21,22,25,27,28,29,31,33,34,37,38,40,41,42,43,44,46,49,51,55,58,59,60,61,62,64,69,74,79,80,81,82,83,86,88,89,91,95,96,100,102,103,105,107,108,109,110,111,113,114,116,119,120,121,123,125,127,128,131,133,137,144,146,151,153,156,159,165,167,168,174,175,176,179,180,182,185,187,188,196,204,206,211,233,238,239,241,242,247,251,256,258,272,276,298,305,308,316,317,318,319,321,323,334,341,344,349],"catch":[15,26,27,30,43,51,58,87,91,97,102,115,118,146,165,233,257,267,272,279,305,306,326,328,334,337,340,362],"char":[43,56,58,71,73,85,88,105,111,116,117,119,120,133,144,159,165,189,233,247,264,277,312,321,327,330],"class":[1,2,3,5,6,10,11,12,16,17,20,21,25,26,28,29,30,31,38,39,40,42,43,44,47,49,50,52,53,55,56,57,58,60,61,62,64,68,71,73,77,81,82,85,86,89,91,97,102,105,109,116,117,118,119,120,121,123,124,132,133,134,135,144,145,146,147,148,149,152,153,154,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,173,174,175,176,177,179,180,181,182,184,185,186,187,188,189,192,193,195,196,198,199,202,203,204,205,206,210,211,212,213,214,215,217,218,219,220,221,223,224,226,227,228,230,231,232,233,234,235,237,238,239,242,243,244,245,246,247,249,251,252,254,255,256,257,258,259,260,261,263,264,265,267,269,270,273,274,276,277,278,279,285,286,287,295,296,298,300,303,305,306,307,308,310,311,312,314,315,316,317,318,319,321,322,323,324,325,326,327,328,329,330,331,333,334,335,336,337,338,339,340,341,342,343,344,349,351,352,357,360,362],"const":234,"default":[0,1,2,3,4,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,27,29,31,32,33,34,35,36,38,39,40,41,42,45,46,47,49,50,51,53,56,57,58,59,62,63,64,65,66,67,68,69,71,72,75,76,77,81,82,83,85,86,87,88,89,90,91,93,95,96,97,100,101,102,103,104,105,106,107,109,111,112,113,114,116,117,118,119,121,123,124,125,126,127,128,129,131,133,134,135,136,138,139,140,141,142,144,145,146,148,149,150,151,152,153,154,174,175,177,179,180,181,182,183,184,185,186,187,188,189,190,193,195,196,199,202,203,205,206,209,210,212,213,214,215,217,218,219,220,221,224,231,233,234,235,236,238,239,240,242,247,251,252,256,257,259,260,261,265,267,269,271,272,273,277,296,298,299,305,306,307,308,312,313,316,317,318,319,321,323,324,326,328,329,330,333,334,336,337,338,339,340,341,344,345,349,357,362,364],"export":75,"final":[10,23,26,27,29,33,36,38,39,41,43,58,63,67,68,69,70,73,76,80,83,85,86,102,103,105,109,114,116,123,125,126,127,133,134,136,150,151,152,159,164,168,185,215,242,252,304,308,321,323,328,329,336],"float":[38,49,114,146,184,194,195,198,250,260,267,279,317,331,336,340,344],"function":[3,4,5,6,9,10,11,13,14,18,19,20,21,23,25,26,27,29,33,34,37,38,40,41,43,44,46,48,50,52,55,57,58,59,60,61,62,63,64,68,69,73,74,75,77,81,82,83,85,86,88,91,93,96,104,106,107,108,109,110,111,115,118,119,121,122,123,124,125,127,128,133,134,135,137,138,140,141,148,151,153,154,156,157,158,159,160,164,165,166,167,169,170,175,176,179,180,181,184,185,187,188,190,194,195,198,199,203,205,206,211,212,215,217,218,219,220,221,224,226,227,230,232,233,234,235,239,240,241,242,247,250,251,252,257,259,260,261,267,272,276,287,296,299,306,308,310,318,319,320,321,322,324,325,326,328,329,331,336,337,338,339,343,344,345,350,362],"g\u00e9n\u00e9ral":79,"goto":[85,230,328],"import":[0,2,3,4,5,6,9,10,11,13,14,15,16,19,20,21,22,25,27,28,29,30,31,33,39,40,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,68,69,71,72,73,74,76,77,80,81,82,83,84,85,86,89,90,91,93,96,97,102,103,104,105,106,107,110,111,112,113,114,115,116,117,118,119,120,121,123,125,126,127,132,133,134,135,136,137,138,140,141,153,159,169,174,179,180,181,182,183,184,185,187,188,198,199,202,204,205,206,212,213,215,217,218,219,220,221,227,232,233,235,238,242,251,252,261,267,271,279,301,305,308,309,318,322,323,326,327,328,329,330,341,342,344,362],"int":[11,25,31,39,49,51,56,58,74,85,91,114,123,125,134,144,146,151,152,154,176,179,182,184,185,188,190,192,194,195,198,206,215,217,218,219,220,221,234,247,252,258,259,260,261,264,265,267,271,272,276,277,278,279,285,286,287,295,296,298,308,310,312,317,321,324,326,327,328,329,330,331,334,336,337,341,344],"long":[9,10,15,20,22,23,25,26,27,29,33,37,38,40,43,44,46,49,51,52,55,58,60,62,64,68,71,72,73,78,79,80,81,85,86,87,90,105,108,111,113,115,118,121,125,126,127,129,131,133,135,138,139,156,159,164,179,186,195,203,213,220,227,234,276,296,321,322,329,330,344],"new":[0,2,5,9,11,12,13,14,16,19,20,21,22,23,24,25,26,27,29,31,33,34,35,36,37,38,39,40,41,43,44,45,49,50,51,54,55,57,61,62,63,64,65,67,68,70,71,72,73,75,76,77,78,79,80,81,82,83,84,85,88,89,90,91,92,93,95,96,98,100,101,104,105,106,107,108,109,111,112,116,117,118,121,122,123,124,128,129,131,132,134,135,136,137,138,139,144,145,146,152,153,154,156,157,159,164,167,168,170,171,173,174,175,180,181,182,186,187,188,192,195,199,202,203,204,205,206,212,213,215,217,218,219,220,221,231,232,233,235,239,242,244,246,247,249,251,252,254,256,259,260,261,264,267,276,277,278,279,285,286,287,299,306,307,308,312,316,317,318,319,321,322,324,327,328,329,330,334,336,337,338,360,362,363,364],"null":[8,86,315,336],"public":[25,34,41,43,58,65,67,72,90,93,100,103,131,134,164,247,312,330],"return":[3,4,6,10,11,15,20,21,22,25,27,28,29,30,33,36,38,39,40,41,42,43,44,48,49,50,52,58,60,62,64,68,69,71,73,74,76,77,80,81,82,83,85,89,91,93,95,96,97,100,102,103,107,108,109,110,111,112,114,116,117,118,119,121,123,125,127,129,133,134,137,138,144,145,146,148,150,151,152,153,154,156,159,164,166,169,170,174,175,176,177,179,180,182,184,185,187,188,190,192,193,194,195,198,199,203,204,205,206,210,211,212,215,217,218,219,220,221,223,230,231,232,233,234,235,237,238,239,241,242,244,246,247,249,250,251,252,257,258,259,260,261,264,265,267,272,273,276,277,279,285,286,287,295,296,298,299,305,306,308,310,311,312,315,316,317,318,319,321,322,323,324,325,326,328,329,330,331,334,336,337,338,339,340,341,343,344,345,350,357,362],"short":[20,22,29,38,39,42,46,51,54,57,58,61,62,70,71,83,87,89,95,96,103,110,112,114,123,129,137,140,180,182,195,202,205,206,227,234,252,322,344],"static":[38,49,58,83,124,127,135,136,137,139,166,180,192,206,214,312,324,355,362,364],"super":[5,22,25,31,40,41,49,57,58,60,62,81,89,96,118,121,123,125,180,182,206,329],"switch":[0,2,9,10,13,14,16,19,20,23,25,31,33,34,43,46,50,58,65,68,72,76,80,81,82,88,90,98,114,116,121,122,123,125,126,129,131,137,138,156,157,158,159,164,165,166,167,168,169,174,175,185,187,199,202,203,218,256,318,324,329,345],"th\u00ed":20,"throw":[11,22,43,66,75,109,131,133,153,166,260,344],"true":[1,2,4,5,10,11,13,20,21,22,25,26,27,29,31,33,34,38,40,41,49,50,51,54,56,58,62,65,66,68,69,72,74,76,80,81,83,84,85,86,87,90,91,96,98,100,102,105,114,115,116,117,120,121,122,123,125,126,127,133,135,137,138,144,148,150,152,153,154,156,159,164,166,167,170,173,174,175,176,177,179,180,182,183,184,185,188,190,192,195,203,204,205,206,212,215,217,218,219,220,221,224,226,230,231,235,237,241,242,244,246,247,249,251,252,254,256,257,258,259,260,261,263,265,267,272,273,276,278,285,295,296,306,308,310,312,315,316,317,318,321,324,326,328,329,330,331,334,336,339,340,341,344,345],"try":[0,4,5,6,8,9,10,11,12,13,15,16,20,21,22,23,25,26,27,29,30,38,39,42,43,44,46,48,49,50,51,54,55,56,57,58,60,61,63,64,65,66,67,68,69,73,74,75,77,80,81,86,90,91,93,95,96,97,102,103,108,109,110,111,113,118,119,120,121,123,124,126,127,133,134,135,136,137,138,140,144,148,152,154,159,175,177,179,180,186,196,204,205,206,212,213,217,218,219,220,221,224,227,231,232,233,235,239,247,251,259,264,267,276,296,310,315,316,318,321,323,324,326,327,340,344],"var":[67,83,88,137,209,322],"void":56,"while":[0,9,10,11,13,14,20,22,23,25,28,29,31,33,35,37,38,41,43,49,50,51,55,56,57,58,62,63,70,75,83,86,90,91,93,95,96,103,108,109,110,111,114,116,118,119,121,122,124,127,129,133,134,136,137,138,144,156,159,167,175,179,188,196,203,204,218,221,224,227,231,233,235,247,252,259,314,315,318,328,330,338,344,345,362,363],AIs:79,AND:[43,73,80,119,159,188,242],ARE:77,AWS:[90,100],Adding:[18,32,33,45,60,71,82,85,108,116,124,139,187,328,364],Age:[188,357],And:[0,4,9,10,11,21,22,25,26,29,33,36,41,42,46,51,57,61,62,69,73,80,86,91,96,105,111,126,133,138,153,182,215,217,218,219,220,221,364],Are:[33,61,79,82],Aye:46,BGs:126,Being:[58,81,122,123],But:[0,6,10,11,13,15,20,21,22,25,26,27,28,29,31,33,37,38,39,41,42,44,51,54,55,57,59,60,61,62,64,69,72,73,80,82,83,85,86,91,95,96,100,102,104,107,109,111,114,119,125,126,127,133,134,138,152,153,179,227,319,362],DNS:[67,90],DOING:188,DoS:285,Doing:[29,33,43,55,73,134,153,156],For:[0,2,5,6,8,9,12,13,14,16,17,19,20,21,22,23,25,27,29,31,33,36,37,38,39,41,42,43,46,49,51,55,56,57,58,59,62,63,64,69,72,73,76,79,80,81,83,85,86,88,90,91,93,95,96,98,100,102,103,105,109,110,111,113,114,116,121,123,126,127,129,131,132,133,134,135,136,138,139,140,152,153,159,169,174,175,176,177,180,182,185,187,188,189,198,206,212,214,215,218,231,239,242,252,260,287,296,316,318,321,325,328,329,338,340,344,357,362,364],GMs:58,Going:234,Has:[24,217,218,219,220,221],His:[57,189],IDE:[38,48,106],IDEs:57,IDs:[0,100,133,134,194,344],INTO:[43,159,188],IOS:24,IPs:[12,103,209,310],IRE:88,Its:[41,62,69,80,83,86,89,105,189,252,326,328,344],LTS:97,NOT:[11,25,33,43,80,90,103,119,137,159,242,252,259,310,364],Not:[8,24,30,41,54,57,61,74,90,108,112,115,127,131,132,133,137,146,153,167,168,247,264,277,278,279,316,317,338],OBS:[19,43],ONE:103,Obs:127,One:[0,8,12,20,22,25,29,34,36,38,46,49,51,57,58,60,63,64,69,76,79,80,87,91,95,102,105,110,115,117,121,123,126,128,130,131,132,138,141,148,150,179,185,205,215,231,232,251,252,277,305,315,316,317,321,329,344],PRs:131,Such:[6,13,28,33,37,43,48,51,57,64,73,127,159,252,321,328],THAT:91,THE:[188,227],THEN:[153,188],THERE:188,TLS:103,That:[0,3,4,9,10,15,21,22,25,26,31,33,39,41,42,46,49,55,57,62,64,68,69,73,74,77,91,93,95,96,98,102,105,111,112,115,119,122,125,127,131,134,136,138,140,179,180,186,215,242,252,308,328],The:[0,2,4,5,6,7,8,9,12,15,17,20,21,23,24,25,27,28,30,31,33,34,36,37,38,39,40,42,43,44,45,48,52,53,54,55,56,57,59,60,61,62,63,64,66,67,68,70,72,73,74,75,76,78,79,80,81,82,84,86,87,88,89,90,91,92,95,97,98,100,101,102,103,104,105,106,107,108,110,111,112,113,114,115,118,119,120,121,122,124,125,126,127,128,129,131,132,133,134,136,137,138,139,140,144,146,147,148,150,151,152,153,154,156,159,163,164,165,166,167,168,169,170,171,173,174,175,176,177,179,180,182,184,185,186,187,188,189,190,192,193,194,195,198,199,203,204,205,206,212,213,215,217,218,219,220,221,223,224,226,227,230,231,232,233,234,235,236,238,239,241,242,246,247,249,250,251,252,255,256,257,258,259,260,261,264,265,266,267,269,271,272,274,276,277,278,279,285,286,287,295,296,298,299,304,305,306,307,308,312,315,316,317,318,319,321,322,323,324,325,326,327,328,329,330,331,332,334,336,337,338,339,340,341,342,344,345,357,362,363,364],Their:[51,73,103,109,114,124,189],Theirs:189,Then:[0,9,15,22,38,39,41,42,46,56,61,63,69,91,93,100,107,127,131,137,187],There:[0,5,8,10,11,13,14,15,19,20,21,22,23,25,26,27,31,33,34,38,41,46,49,51,55,57,58,60,61,62,64,68,69,72,73,77,79,80,81,85,86,88,89,90,91,93,95,96,97,98,102,103,104,105,107,108,111,112,113,114,116,117,118,119,121,123,125,127,128,133,136,138,139,167,187,188,215,217,218,219,220,221,235,252,261,272,308,321,322,328,336,363],These:[0,4,5,9,11,13,17,22,25,33,34,35,38,39,40,43,47,49,51,59,61,65,68,69,73,74,83,86,88,90,91,95,96,100,102,103,105,107,109,110,111,112,114,119,121,122,124,125,127,131,133,137,138,139,143,144,145,150,152,154,156,158,160,168,176,180,184,198,199,203,205,206,210,227,233,238,242,247,251,252,261,266,273,295,296,298,307,308,309,316,318,321,325,328,329,330,337,338,339,344],USE:[241,364],Use:[1,2,4,5,8,9,12,13,14,20,22,23,24,25,31,38,43,48,51,54,58,60,63,65,69,70,89,90,93,95,96,100,105,109,114,116,122,123,125,127,131,137,144,151,156,157,159,164,165,169,171,179,180,184,186,199,202,203,204,206,218,219,220,221,226,234,244,246,247,269,273,278,295,296,298,299,302,316,318,321,327,328,330,334,341,344],Used:[33,43,121,139,150,153,159,175,188,202,215,235,259,269,287,318,329,330,350],Useful:[12,51,90],Uses:[114,159,171,186,209,231,267,330,334],Using:[18,22,27,43,46,51,55,58,60,62,68,80,91,96,115,121,123,139,159,206,218,234,247,287,314,328,364],VCS:36,VHS:188,VPS:90,WILL:[24,91,259],WIS:58,WITH:[23,188],Will:[31,38,74,110,114,144,184,204,206,247,250,252,265,267,276,277,318,328,330,331,336,339,344],With:[8,11,15,19,23,55,57,77,87,100,111,114,122,123,141,144,180,206,252,321,326],Yes:[33,138,188,326],__1:337,__2:337,_________________:125,_________________________:51,______________________________:51,________________________________:51,_________________________________:125,______________________________________:328,______________________________________________:51,_______________________________________________:51,____________________________________________________:51,_________________________________________________________:85,__________________________________________________________:85,__all__:[145,237,244],__defaultclasspath__:318,__doc__:[33,43,59,68,154,167,169,170,239,324,328],__example__:97,__ge__:97,__getitem__:321,__init_:330,__init__:[3,6,11,40,47,49,53,96,97,107,125,152,153,154,174,177,179,180,192,204,206,226,234,242,246,247,251,257,258,260,261,264,265,267,269,270,276,277,278,279,285,286,287,295,296,298,305,306,308,310,311,312,315,316,318,319,321,323,326,327,328,329,330,336,337,338,339,340,344,351],__iter__:11,__multimatch_command:168,__noinput_command:[152,168,180,326,328,329],__nomatch_command:[168,180,233,326,328],__send_to_channel_command:168,__settingsclasspath__:318,__unloggedin_look_command:[171,186],_action_thre:51,_action_two:51,_all_:152,_attrs_to_sync:307,_attrtyp:316,_cach:318,_cached_cmdset:153,_call_or_get:180,_callback:[27,261],_char_index:321,_character_dbref:181,_check_password:51,_check_usernam:51,_clean_str:321,_cleanup_charact:116,_code_index:321,_copi:[43,159,247],_creation:125,_data:329,_default:[51,328],_defend:51,_differ:321,_errorcmdset:153,_event:198,_evmenu:328,_famili:119,_file:337,_flag:251,_footer:33,_format_diff_text_and_opt:252,_get_a_random_goblin_nam:109,_get_db_hold:306,_get_top:69,_getinput:328,_gettabl:272,_http11clientfactori:269,_init_charact:116,_is_fight:29,_is_in_mage_guild:51,_ital:38,_italic_:54,_menutre:[25,51],_monitor:272,_monitor_callback:84,_nicklist_cal:146,_npage:329,_oob_at_:334,_option:51,_overrid:135,_page_formatt:329,_pagin:329,_pending_request:312,_permission_hierarchi:241,_ping_cal:146,_playable_charact:[69,133],_postsav:334,_prefix:206,_quell:241,_raw_str:321,_reactor_stop:305,_recog_obj2recog:206,_recog_obj2regex:206,_recog_ref2recog:206,_regex:206,_repeat:272,_safe_contents_upd:246,_saver:[11,325],_saverdict:[11,325],_saverlist:[11,325],_saverset:325,_sdesc:206,_select:51,_selectfunc:328,_sensitive_:349,_session:328,_set:119,_set_attribut:51,_set_nam:51,_some_other_monitor_callback:84,_start_delai:261,_static:38,_templat:38,_test:150,_validate_fieldnam:58,a2enmod:8,a8oc3d5b:100,a_off:179,a_python_func:38,aardwolf:88,abbrevi:[43,76,114,159,202,336],abcd:[43,165],abi:60,abid:126,abil:[6,10,20,31,33,52,55,56,57,58,60,73,77,80,90,100,102,108,109,123,127,134,137,138,139,205,206,213,217,218,219,220,221,247,259,267,316],abl:[0,3,4,5,8,11,13,14,19,20,21,22,23,26,27,28,29,31,33,36,41,42,43,47,49,51,52,55,57,58,59,60,61,63,64,69,71,73,75,76,81,83,85,86,87,89,90,91,93,95,96,100,103,104,106,109,111,112,114,116,121,122,123,130,131,133,134,138,140,153,156,157,159,160,174,177,180,184,190,199,206,212,217,218,219,220,221,227,259,316,318,325,340,344,360],abod:241,abort:[25,27,33,51,52,77,89,122,144,154,159,175,213,233,247,250,328,329],about:[0,3,9,10,11,12,13,14,15,16,17,20,21,22,23,24,25,26,30,31,33,36,37,38,39,41,42,44,45,46,48,51,54,55,57,59,60,61,63,64,68,69,70,71,73,75,76,77,78,79,81,83,85,86,90,91,93,95,96,97,100,101,103,104,108,109,110,112,113,114,116,118,119,120,123,124,126,127,131,134,135,136,138,139,144,159,169,174,179,180,182,185,214,219,220,221,226,227,232,233,239,247,267,269,272,285,296,306,308,315,317,319,321,329,334,336,344,363],abov:[2,4,8,9,10,11,12,13,14,21,23,24,27,28,29,30,31,33,36,37,40,43,44,46,49,50,51,56,57,58,59,60,62,63,64,67,68,69,74,80,81,84,85,86,90,91,93,95,96,100,102,105,106,109,110,111,112,114,116,118,119,121,123,125,127,131,132,133,135,137,138,140,152,153,159,180,185,188,190,199,204,206,213,214,215,217,219,220,221,242,247,272,315,328,339,350],abridg:41,absolut:[27,38,56,62,79,91,134,182,184,185,189,327,331,344],absorb:74,abspath:344,abstractus:148,abus:[7,103],academi:79,accept:[11,14,22,23,27,31,37,43,51,54,58,59,74,80,88,90,95,96,109,114,115,125,131,133,134,138,144,150,151,169,179,185,188,193,196,204,205,206,213,231,233,241,267,272,285,311,312,317,322,328,336,340,344],accept_callback:[193,195],accesing_obj:241,access:[0,4,7,8,11,12,13,14,19,21,22,23,25,27,29,31,33,34,38,39,40,41,47,49,51,52,53,56,57,58,59,60,63,64,66,68,69,71,73,74,80,83,84,85,86,87,89,90,91,95,96,100,101,102,103,104,105,107,108,109,111,112,114,116,119,121,123,124,125,126,127,128,131,133,134,135,137,139,144,145,148,152,153,154,156,157,159,164,165,166,167,168,169,174,175,176,177,180,187,190,192,194,203,205,206,217,218,219,220,221,233,234,239,240,241,242,246,247,250,251,252,256,258,260,261,264,267,276,277,306,308,314,315,316,318,319,322,323,324,337,343,344,357,362],access_obj:[241,316],access_opt:345,access_token_kei:[71,120],access_token_secret:[71,120],access_typ:[43,68,144,154,159,175,177,239,241,242,247,316,318,362],accessed_obj:[25,80,121,241,242],accessing_obj:[1,11,25,80,121,144,175,177,239,241,242,247,316,318],accessing_object:[11,241],accessor:[148,177,239,246,256,316,318,319,335],accessori:63,accident:[15,31,38,43,123,138,157,159,306],accommod:4,accomod:[101,330],accompani:123,accomplish:[12,25,41,49,55],accord:[31,33,111,116,126,180,182,204,205,218,260,321,322],accordingli:[49,58,90,106,175,234],account1:360,account2:360,account:[0,4,6,9,11,12,14,17,19,20,21,22,24,25,27,31,33,34,35,37,41,45,47,49,50,51,52,53,55,56,57,61,62,65,66,69,71,74,80,81,83,87,89,90,91,92,96,100,104,105,107,108,109,110,111,112,114,119,120,122,123,125,126,127,129,131,133,134,135,138,139,141,142,149,150,151,152,153,154,155,157,159,160,161,164,165,166,167,171,174,175,176,177,180,181,182,184,186,187,188,190,192,193,195,199,206,209,212,217,219,220,221,224,227,230,231,232,233,235,239,241,242,246,247,249,251,253,256,267,271,272,287,298,299,306,307,308,316,318,321,324,328,329,338,339,341,342,344,345,349,357,360,362,364],account_cal:[156,164,167,199],account_count:308,account_id:[133,247],account_mod:159,account_nam:56,account_search:[206,247],account_subscription_set:148,account_typeclass:[342,360],accountattributeinlin:145,accountcmdset:[2,22,31,41,43,57,58,62,156,160,164,181,199],accountcreateview:362,accountdb:[53,119,125,133,141,144,145,148,175,239,314,315,318,338,345],accountdb_db_attribut:145,accountdb_db_tag:145,accountdb_set:[316,319],accountdbadmin:145,accountdbchangeform:145,accountdbcreationform:145,accountdbmanag:[147,148],accountdbpasswordcheck:287,accountform:[145,357,362],accountid:133,accountinlin:145,accountlist:58,accountmanag:[144,147],accountmixin:362,accountnam:[43,58,159,171,176,186,324],accounttaginlin:145,accur:[22,154,177,192,218,221,252,260,265,267,269,270,278,287,295,296,306,321,336,339,340,351],accuraci:[46,91,218,219,220],accus:73,accustom:[87,124],acept:188,achiev:[0,22,27,33,57,114,124,126,138,220,267],ack:52,acquaint:57,acquir:323,across:[16,20,40,51,56,61,86,91,102,105,108,109,125,144,152,153,182,188,233,238,247,250,259,261,264,276,277,308,329,330],act:[2,8,13,23,29,31,34,37,43,49,51,56,58,61,70,77,95,102,105,110,111,123,139,141,159,177,188,215,241,264,276,277,296,316,319,323,328],action1:116,action2:116,action:[0,11,22,29,39,41,42,43,46,51,55,57,61,62,64,73,88,90,91,93,102,114,116,117,118,123,133,138,145,146,165,175,179,188,206,217,218,219,220,221,230,234,238,239,250,251,256,257,279,298,299,300,310,318,328,329,334],action_count:116,action_nam:[217,218,219,220,221],actiondict:116,actions_per_turn:[217,218,220,221],activ:[4,9,12,13,26,27,28,31,33,36,38,43,61,62,63,64,65,66,72,75,76,79,80,81,83,89,90,93,95,98,102,105,110,114,128,131,135,136,138,144,150,153,157,159,169,174,175,193,210,227,231,235,246,247,250,259,260,272,279,287,298,308,310,317,326,328,329,330,336,344],activest:343,actor:221,actual:[2,5,8,10,11,13,14,19,20,21,22,26,27,29,34,36,38,40,41,42,43,44,46,47,49,51,58,59,60,61,63,64,68,69,71,73,79,80,81,83,85,86,87,88,89,90,91,93,95,96,97,100,104,105,106,109,111,112,113,114,115,116,119,121,123,126,127,128,130,133,134,136,137,138,144,150,154,156,159,165,167,168,170,175,177,179,180,182,187,188,198,202,203,205,206,213,214,215,217,218,219,220,221,227,232,233,235,239,241,242,246,247,251,252,287,296,298,304,306,307,308,312,313,318,321,323,324,326,328,329,334,338,339,340,344,362],actual_return:127,adapt:[0,4,21,40,69,73,133],add:[0,2,5,6,8,9,10,11,13,14,15,16,17,19,20,21,22,24,26,29,30,31,33,34,35,36,37,38,39,40,41,42,43,44,46,47,48,49,50,51,54,55,57,58,61,62,64,65,66,67,68,69,71,73,74,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,93,95,96,98,100,102,104,105,106,109,111,112,113,114,115,116,117,118,119,120,121,123,124,125,127,128,131,132,133,134,135,137,138,139,140,141,144,148,152,153,159,164,165,166,168,174,175,179,180,181,182,183,185,186,187,192,193,195,196,198,199,202,203,205,206,209,212,213,215,217,218,219,220,221,223,224,226,227,230,231,232,233,234,241,242,246,247,250,252,256,257,258,260,261,267,272,273,277,285,296,298,299,301,306,309,316,319,322,326,327,328,329,330,334,336,337,339,340,362,364],add_:330,add_act:116,add_argu:234,add_callback:[193,195],add_channel:174,add_charact:116,add_choic:180,add_choice_:180,add_choice_edit:[22,180],add_choice_quit:[22,180],add_collumn:154,add_column:[58,330],add_condit:219,add_default:[21,31,85,96,121,153,224],add_dist:221,add_ev:195,add_fieldset:[145,244],add_form:[145,244],add_head:330,add_languag:205,add_row:[58,82,154,329,330],add_view:[145,173,244],add_xp:73,addblindedcmdset:227,addcallback:[33,247],addclass:[137,141,142,346,356,358],addcom:[58,164],added:[0,4,5,17,21,22,24,25,27,31,33,34,36,38,40,41,42,43,51,55,57,58,60,65,69,70,73,75,77,78,80,86,88,91,96,100,102,106,108,109,110,111,112,114,116,117,119,121,123,128,131,132,133,138,144,150,152,153,154,164,168,169,179,180,182,183,185,189,192,195,198,206,217,218,219,220,221,224,235,242,247,252,258,260,272,306,316,319,322,328,329,330,336,337,344,350],addendum:37,adding:[0,3,5,9,14,17,21,22,25,27,29,31,35,36,38,40,43,46,51,57,58,62,69,76,80,81,85,86,91,97,102,104,106,108,109,112,114,115,116,121,123,125,126,128,131,133,137,138,139,152,153,157,159,166,180,184,188,190,192,195,199,205,206,215,217,218,219,220,227,233,234,250,251,252,258,267,298,315,316,324,330,344],addit:[4,8,22,25,31,36,37,46,49,50,51,58,62,69,76,82,88,90,91,103,104,109,114,119,134,144,146,153,154,175,180,183,192,193,195,205,209,215,221,234,242,247,260,278,306,316,318,326,328,357],addition:[25,111,119,221],additionalcmdset:31,addpart:203,addquot:344,addr:[264,277,278,279,324],address:[3,9,12,23,33,40,43,49,67,87,90,91,103,105,131,135,144,157,175,186,189,247,264,277,279,287,307,310,344,345,363],address_and_port:287,addresult:203,addscript:[43,159],addservic:40,adjac:[221,231],adject:97,adjoin:206,adjust:[0,33,37,63,126,133,190,260,328,330],admin:[2,9,11,12,15,19,21,33,34,41,49,58,61,68,69,72,80,85,86,98,101,110,119,121,123,133,134,138,141,142,143,148,149,155,159,164,166,169,171,172,175,186,231,236,239,242,243,246,247,253,262,276,277,314,318,324,340,362,363],admin_sit:[145,173,237,244,254,263,315],admin_wrapp:362,administr:[10,23,33,36,41,55,58,63,64,68,80,103,129,139,264,276,277,364],adminportal2serv:276,adminserver2port:276,adminstr:264,admintest:360,admit:39,adopt:[21,22,26,57,64,177],advanc:[10,12,13,22,28,31,33,39,40,43,44,51,55,58,64,79,86,93,104,105,108,109,111,119,123,124,125,139,159,167,187,204,206,217,218,219,220,221,226,322,326,327,328,330,364],advantag:[3,14,15,28,36,39,46,51,55,56,58,59,62,68,69,73,90,103,104,109,116,118,123,133,179,180,209,215,217,218,219,220,221,319,322],advent:181,adventur:[20,41,77,111,122,124],advic:79,advis:[0,22,25,77],aeioui:119,aesthet:50,affair:323,affect:[11,13,14,19,25,31,33,43,61,62,73,80,81,105,112,114,116,126,127,128,131,138,141,142,144,152,169,183,198,205,212,219,240,247,251,318,322,330,338],affili:260,affliat:260,afford:[85,105],afraid:90,after:[0,5,8,9,10,11,14,15,20,21,22,25,27,28,29,30,31,33,36,38,39,41,43,44,46,49,50,51,55,58,60,63,67,68,76,77,79,80,83,85,86,90,91,96,100,102,103,107,114,116,117,121,122,123,126,127,128,130,131,133,136,138,139,144,152,153,154,155,156,159,167,169,170,174,175,179,180,182,184,185,186,187,188,190,195,203,205,206,215,217,218,219,220,221,227,228,231,232,233,234,235,246,247,250,252,257,259,260,267,305,306,307,308,310,312,316,321,322,323,326,328,329,334,336,339,342,343,344,362],after_mov:247,afternoon:187,afterthought:48,afterward:[20,29,69,86,91,119,131,180],again:[0,6,12,13,14,20,21,22,23,28,29,33,39,41,42,43,47,48,49,51,54,56,57,58,60,61,62,63,64,67,69,73,76,80,81,85,86,90,91,93,95,96,98,100,102,105,106,110,111,114,116,119,121,123,126,128,131,133,138,146,153,164,184,195,204,217,220,221,226,227,235,259,267,287,310,321,322,325,340,342],against:[6,11,21,31,33,37,57,58,83,90,103,116,119,125,127,144,151,152,174,206,217,218,219,220,221,242,247,251,252,285,310,316,318,336,341,344],age:[188,234,357],agenc:103,agent:36,agenta:114,ages:188,aggreg:79,aggress:[11,14,75,122,124,139,231,318,364],aggressive_pac:231,agi:[11,60,127],agil:[11,60],agnost:[37,64,175],ago:[25,100,344],agre:[1,73,113,179],agree:179,ahead:[14,22,24,36,49,61,90,108,121],aid:[113,166,167,168,179,312],aim:[7,55,58,61,73,85,86,90,95,108,126,176,251],ain:46,ainnev:[73,119],air:[20,21,111],ajax:[40,55,90,137,296,307],ajaxwebcli:296,ajaxwebclientsess:296,aka:[9,11,93,203,344],alarm:[20,82],alert:247,alexandrian:79,algebra:49,algorith:205,algorithm:344,alia:[2,6,9,20,21,22,31,33,41,44,48,51,57,58,59,60,63,87,89,90,95,105,111,112,119,125,127,129,131,145,148,151,154,156,159,164,165,166,167,168,170,173,174,187,192,206,212,228,231,233,235,237,241,244,246,247,250,252,254,256,261,272,298,315,317,318,319,324,340,341,342,357,362],alias1:[43,159,187],alias2:[43,159,187],alias3:187,alias:[2,13,20,21,22,25,27,29,31,33,34,41,43,44,45,48,51,58,60,74,81,82,85,87,89,109,111,116,119,123,129,131,140,144,152,154,156,157,158,159,164,165,166,167,168,169,170,171,174,175,176,179,180,181,182,185,186,187,188,189,193,199,202,203,206,212,213,214,215,217,218,219,220,221,224,231,232,233,234,235,238,239,246,247,252,317,318,319,324,326,328,329,337,341],aliaschan:[43,164],aliasdb:144,aliashandl:[315,319],aliasnam:252,aliasstr:324,align:[41,58,109,114,190,321,330,336,344],alik:68,alist:97,aliv:[55,231],alkarouri:343,all:[0,1,2,3,5,6,8,9,10,11,12,13,14,15,16,17,19,20,21,22,23,26,27,28,29,30,31,33,34,35,36,37,38,39,40,41,43,44,46,47,48,49,50,53,54,55,56,57,58,59,60,61,62,63,64,68,70,72,73,74,75,76,77,78,79,80,81,82,83,85,86,87,88,89,90,91,93,95,96,97,98,100,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,121,122,123,124,125,126,127,128,129,131,132,133,134,135,136,137,138,139,140,144,145,146,149,150,151,152,153,154,155,156,157,158,159,160,161,164,165,166,167,168,169,170,171,174,175,176,177,179,180,181,182,185,186,187,188,189,192,195,199,202,203,204,205,206,210,212,213,214,215,217,218,219,220,221,224,226,227,230,231,232,233,234,235,237,238,239,240,241,242,243,244,246,247,251,252,257,258,259,260,261,262,266,267,271,272,273,276,278,279,285,286,287,295,296,298,299,305,306,307,308,310,312,313,314,315,316,317,318,319,321,322,323,324,325,326,327,328,329,330,334,336,337,339,341,343,344,345,350,357,362,363],all_alias:112,all_attr:318,all_connected_account:308,all_displai:261,all_famili:119,all_from_modul:344,all_opt:339,all_receiv:247,all_room:13,all_script:102,all_sessions_portal_sync:308,all_to_categori:238,allcom:164,allerror:[267,276],allevi:[11,108,127,312],allheadersreceiv:312,alli:221,alloc:90,allow:[0,2,3,4,6,8,9,10,11,12,13,14,15,16,19,21,22,23,25,26,27,29,30,31,33,34,36,38,39,41,42,43,44,46,47,49,51,53,54,55,57,58,59,61,63,64,65,68,71,72,73,74,75,76,78,80,81,85,86,87,89,90,91,92,95,96,97,98,100,101,102,103,104,106,108,109,111,112,113,114,116,119,121,123,125,126,129,131,133,134,135,137,138,144,146,148,150,152,153,154,156,157,158,159,164,167,168,169,170,175,176,177,179,180,182,184,185,187,188,189,195,202,204,205,206,215,217,218,219,220,221,231,232,233,234,235,239,241,242,247,250,251,252,257,259,260,261,267,271,272,274,278,299,305,306,308,310,311,316,318,319,321,322,324,326,328,329,330,331,334,338,339,340,342,344,357,362],allow_dupl:152,allow_nan:296,allow_quit:328,allowed_attr:58,allowed_fieldnam:58,allowed_host:90,allowed_propnam:123,allowedmethod:296,allowext:312,almost:[19,33,41,95,115,119,125,180,182,269,276,314],alon:[13,29,49,51,56,58,73,80,86,87,116,127,138,152,261,272,298,306,316,322,324,330],alone_suffix:303,along:[5,12,33,43,48,51,60,64,70,74,78,88,91,93,96,100,104,107,114,121,122,139,144,156,179,185,205,209,215,220,242,247,296,314],alongsid:[5,38,67,188],alonw:256,alpha:[54,90,321],alphabet:[15,111,113,321],alreadi:[0,2,5,6,9,11,13,15,21,22,25,27,29,31,33,34,38,40,41,43,46,49,50,51,54,56,57,58,60,61,63,64,68,69,70,72,73,77,80,81,82,85,88,89,91,95,96,100,102,103,105,106,109,110,112,116,117,118,119,120,121,123,125,127,128,131,133,134,135,136,137,138,139,152,153,156,159,164,167,168,169,174,175,176,179,181,182,204,205,206,217,218,219,220,221,227,231,232,235,242,247,251,252,259,267,276,285,287,295,300,305,306,308,319,321,324,329,344,349],alredi:40,alright:179,also:[0,1,2,3,5,6,8,9,10,11,12,13,14,15,16,17,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,46,47,48,49,50,51,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,72,73,74,75,77,79,80,81,82,83,84,85,86,87,88,89,90,91,93,95,96,97,98,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,121,122,123,124,125,126,127,128,129,131,132,133,134,135,136,137,138,140,144,148,151,152,153,154,156,157,158,159,161,165,167,169,170,174,175,176,177,179,180,181,182,185,187,188,190,195,199,202,204,205,206,213,215,219,220,221,226,231,232,233,235,240,241,242,246,247,250,251,252,253,256,259,260,261,262,267,271,272,276,278,285,287,295,298,299,308,312,314,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,334,336,338,341,344,346,362,363],alt:321,alter:[0,4,23,41,64,111,137],altern:[23,29,33,34,38,51,55,57,63,64,68,72,76,81,87,90,111,112,114,118,119,122,131,133,138,140,167,168,175,203,206,221,224,241,242,285,324,336,344],although:[22,29,39,42,63,119,156,180,181,185,312,340,344],althougn:46,altogeth:[50,103,114],alu:33,alwai:[0,2,4,6,8,11,12,13,14,20,21,23,25,27,30,31,33,34,37,38,39,43,47,49,51,57,58,61,62,63,64,69,72,73,74,77,80,85,86,88,89,90,91,95,96,102,105,107,109,112,114,115,121,123,125,126,127,128,131,134,135,137,144,152,153,154,156,158,159,164,167,170,175,176,177,199,205,206,212,224,227,241,242,246,247,250,251,252,259,261,267,269,272,276,287,295,296,299,306,308,313,316,317,318,319,321,324,334,336,340,341,344,345,362],always_pag:329,always_return:267,amaz:75,amazon:[79,90],ambianc:108,ambigu:[41,154,174,189,247,318],ambiti:[108,129],amend:131,amfl:14,ammo:21,among:[2,35,36,43,62,64,79,89,104,111,123,127,165,182,224,232,242,341],amongst:77,amor:196,amount:[11,16,37,43,61,68,73,102,103,114,123,169,217,218,219,220,221,247,308,326],amp:[40,83,92,105,141,142,262,264,267,275,277,285,305,308],amp_client:[141,142,262],amp_port:90,amp_serv:[141,142,262,275],ampclientfactori:264,ampersand:108,amphack:276,ampl:124,amplauncherprotocol:267,ampmulticonnectionprotocol:[264,276,277],ampprotocol:264,ampserverclientprotocol:264,ampserverfactori:277,ampserverprotocol:277,amsterdam:90,anaconda:9,analog:[49,83],analys:51,analysi:210,analyz:[15,33,41,51,80,118,150,159,175,206,251,252,257,267,329,344],anchor:[175,221,239,318],anchor_obj:221,ancient:114,andr:24,android:[139,364],anew:[63,111,267],angl:129,angri:41,angular:[43,169],ani:[0,1,2,5,6,8,10,11,12,14,15,16,19,20,21,22,23,24,25,27,30,31,33,34,36,37,38,39,40,41,42,43,44,48,49,50,51,54,56,57,58,59,60,61,63,64,65,68,70,72,73,74,76,77,79,80,81,82,83,84,85,86,87,88,89,90,91,95,96,97,98,100,102,103,104,105,107,109,112,114,115,116,117,118,119,121,122,123,125,126,127,128,129,131,133,134,135,136,137,138,139,140,144,148,150,151,152,153,154,156,157,159,165,169,170,175,176,177,179,180,181,182,186,187,188,189,190,194,199,202,204,205,206,209,210,213,217,218,219,220,221,223,224,231,233,234,235,241,242,247,250,251,252,256,257,259,260,261,264,265,267,269,271,272,276,277,279,285,286,287,295,296,298,306,307,308,312,316,317,318,319,321,322,323,325,326,327,328,329,330,336,337,338,339,340,341,343,344,362],anim:[27,52],anna:[43,58,63,72,117,118,123,159],annoi:[12,85,91],annot:79,announc:[25,37,43,79,116,123,128,157,169,217,218,219,220,221,247],announce_al:[285,308],announce_move_from:[25,77,89,247],announce_move_to:[25,77,89,247],annoy:144,anonym:[4,66,69,206],anonymous_add:206,anoth:[0,8,10,11,13,14,16,21,22,29,31,33,36,39,42,43,46,49,51,56,57,58,62,63,64,67,69,77,78,80,89,90,91,96,97,98,102,105,106,108,109,111,112,113,114,116,121,123,127,131,132,136,137,138,139,140,144,152,153,156,159,164,165,175,179,180,182,188,194,199,204,206,215,217,218,219,220,221,232,235,239,247,250,308,316,318,322,326,328,329,336,344],another_batch_fil:322,another_nod:328,another_script:102,anotherscript:102,ansi:[24,43,53,55,74,81,137,141,142,156,183,190,202,272,279,287,295,296,320,330,336,343,364],ansi_escap:321,ansi_map:321,ansi_map_dict:321,ansi_pars:321,ansi_r:321,ansi_regex:321,ansi_sub:321,ansi_xterm256_bright_bg_map:321,ansi_xterm256_bright_bg_map_dict:321,ansimatch:321,ansimeta:321,ansipars:321,ansistr:[141,321,330],ansitextwrapp:330,answer:[0,11,21,25,26,33,46,51,61,63,67,69,70,73,95,96,103,127,265,271],anti:63,anul:8,anwer:44,anybodi:[59,103],anymor:[4,181,195,203,204,235,328,340],anyon:[1,4,12,21,25,29,41,42,54,58,60,76,80,85,90,116,118,119,123,138],anyth:[0,1,5,11,13,16,19,20,22,23,26,29,31,33,34,40,41,42,46,49,51,56,61,63,64,69,73,80,82,83,85,87,89,90,91,95,96,100,102,104,106,111,116,118,121,123,125,127,128,130,131,133,135,136,137,138,152,154,168,180,206,215,217,218,219,220,221,242,279,313,322,328],anywai:[0,4,14,20,51,55,75,76,91,95,108,114,140,179,181,186],anywher:[33,51,60,64,95,96,125,134,326],apach:[7,23,90,103,139,312,364],apache2:8,apache_wsgi:8,apart:[2,11,20,27,34,47,55,63,80,81,100,104,125,126,127,134,221],api:[13,15,26,27,33,34,42,43,47,48,52,59,60,71,73,89,96,105,109,111,120,125,133,138,139,141,144,158,169,171,177,186,306,316,318,322,323,329,363,364],api_kei:71,api_secret:71,apostroph:15,app:[4,40,71,80,86,134,135,136,138,139],app_id:133,app_label:145,appar:[48,58,126],apparit:233,appeal:[51,61,114],appear:[9,10,21,22,25,26,27,30,38,43,47,48,51,60,63,65,66,68,72,80,82,90,95,96,100,102,104,106,111,114,123,126,127,131,137,138,141,156,166,182,195,206,212,235,247,315,318,330,336,337],append:[20,22,25,27,31,39,40,43,49,50,51,68,69,80,85,88,89,90,91,93,96,97,116,123,127,133,138,154,159,166,182,199,206,242,300,322,336,337,344],appendix:241,appendto:137,appform:133,appl:[179,247],appli:[0,8,9,13,16,22,23,31,33,36,37,51,60,80,81,102,106,111,115,121,125,126,128,133,144,150,152,167,183,217,218,219,220,221,235,242,247,251,252,256,261,308,316,317,318,321,322,327,330,331,341,344],applic:[8,40,63,79,80,86,100,103,112,124,128,133,134,135,136,144,187,188,221,267,270,305,306,312,354,362],applied_d:133,apply_damag:[217,218,219,220,221],apply_turn_condit:219,appnam:[11,80],appreci:[22,37,70,78,334],approach:[22,25,39,56,77,91,106,115,133,180,221],appropri:[8,9,23,31,33,36,55,71,91,106,119,121,129,133,138,144,157,175,190,267,306,338,340,344],approrpri:40,approv:[133,134,138],approxim:[5,43,169,344],april:62,apt:[8,63,67,75,90,103,131],arbitr:61,arbitrari:[11,13,19,27,46,59,64,80,96,97,100,111,125,137,138,139,140,144,175,187,215,221,233,247,252,259,265,276,296,316,325,336,337,340],arcan:129,archer:252,architectur:[80,252],archiv:[79,103],archwizard:252,area:[2,22,24,48,49,51,58,61,79,117,122,127,138,231,235,241,327,328,330],aren:[0,4,29,39,69,103,127,131,133,136,138,144,182,188,195,203,219,337,340],arg1:[80,154,167,168,170,250,316,336],arg2:[154,167,168,170,250,316,336],arg:[1,5,10,21,22,25,29,30,33,38,39,40,41,42,43,51,58,59,68,71,73,74,80,81,83,85,88,96,109,114,115,116,119,121,123,129,132,137,144,145,146,147,148,151,154,159,167,168,170,175,176,177,179,182,184,187,189,192,195,203,204,205,206,212,213,214,215,217,218,219,220,221,223,226,227,231,232,233,234,235,238,239,241,242,245,246,247,250,251,252,255,256,259,260,261,264,272,273,274,276,277,278,279,285,287,295,296,300,306,308,312,315,316,317,318,319,321,328,329,330,331,333,334,336,337,340,342,344,345,357,362],arg_regex:[41,44,154,159,165,166,170,171,174,182,326],arglist:[167,168],argpars:234,argu:11,argument:[3,4,5,10,12,14,20,21,22,23,25,27,29,31,33,34,40,41,42,43,46,48,50,52,57,58,59,62,69,74,80,81,83,85,87,88,89,93,95,96,102,109,111,114,115,119,123,124,125,127,129,134,139,144,146,150,151,153,154,156,157,159,164,165,166,167,168,169,170,175,176,180,182,184,187,188,189,192,194,195,204,205,206,210,212,217,218,219,220,221,233,234,242,247,250,251,252,257,259,260,261,265,267,272,276,278,279,285,286,287,295,296,298,299,305,306,307,308,310,311,316,317,318,319,321,322,324,326,327,328,329,330,334,336,338,340,341,344,362,364],argumentpars:234,argumnet:330,argumu:336,aris:103,arm:[26,33,203],armi:85,armor:[29,82,182,218],armour:29,armouri:77,armpuzzl:203,armscii:[15,113],arnold:87,around:[0,4,10,13,14,15,21,23,29,31,34,38,39,42,43,49,55,58,61,63,64,69,70,71,73,77,79,80,85,89,90,91,96,109,111,113,114,116,117,119,121,123,129,136,138,139,159,167,168,182,184,194,203,206,221,224,231,232,233,235,247,321,322,330,337],arrai:[88,91,344],arrang:22,arrayclos:88,arrayopen:88,arriv:[0,25,29,43,73,77,83,105,159,279],arrow:[42,137],art:[114,327],articl:[4,15,21,39,41,48,57,79,113,127,131,335],article_set:335,artifact:330,artifici:73,arx:79,arxcod:[79,139,364],as_view:[175,239,318],ascii:[9,15,111,113,144,327,330,344],asciiusernamevalid:144,asdf:159,ashlei:[182,188,190,215,217,218,219,220,221],asian:344,asid:[9,227],ask:[1,10,21,23,26,34,37,42,43,46,48,50,54,58,63,67,68,69,70,73,84,90,91,93,97,119,124,131,133,152,154,159,179,184,193,204,234,265,267,328,331,344],ask_choic:265,ask_continu:265,ask_input:265,ask_nod:265,ask_yesno:265,asn:209,aspect:[48,51,57,60,64,68,73,86,109,127,190],assert:[116,127],assertequ:127,assertregex:127,asserttru:127,asset:[103,136,271],assetown:9,assign:[2,6,11,12,13,20,36,43,51,56,58,80,87,89,97,102,109,112,115,116,119,121,123,131,137,138,144,150,151,153,159,166,167,168,170,183,187,188,206,217,218,219,220,221,233,242,246,247,251,252,272,279,285,287,306,318,325],assist:90,associ:[4,11,29,43,51,79,83,90,105,122,135,138,144,149,159,175,192,195,206,247,306,308,317,362],assort:362,assum:[0,3,5,9,12,13,14,15,19,20,21,22,25,27,28,29,31,33,34,37,39,40,41,43,44,46,47,49,51,55,56,58,60,62,68,73,74,75,80,81,82,84,85,89,90,95,96,97,100,102,103,105,106,108,109,110,111,113,115,116,117,118,120,121,123,127,128,132,133,134,138,150,152,153,154,156,159,170,175,180,181,206,213,232,233,241,247,252,257,259,308,321,322,328,336,344,349,362],assumpt:151,assur:[49,125],asterisk:[2,12,38,43,157],astronaut:77,astronom:62,async:[133,139,344,364],asynccommand:10,asynchron:[27,28,29,33,45,55,64,92,93,139,146,247,276,277,337,344],at_:[125,334],at_access:[144,247],at_account_cr:[2,144],at_after_mov:[77,89,96,117,247],at_after_object_leav:235,at_after_travers:[89,232,247],at_befor:247,at_before_drop:[218,221,247],at_before_g:[218,221,247],at_before_get:[221,247],at_before_mov:[25,77,89,217,218,219,220,221,247],at_before_sai:[96,206,247],at_channel_cr:175,at_char_ent:117,at_cmdset_cr:[5,21,22,25,30,31,33,41,44,57,58,62,81,85,116,121,123,152,160,161,162,163,179,180,181,182,185,187,199,202,203,206,214,217,218,219,220,221,224,230,231,232,233,326,328,329],at_cmdset_get:[144,247,306],at_db_location_postsav:246,at_defeat:[217,218,219,220,221],at_desc:247,at_disconnect:[144,306],at_drop:[218,221,247],at_end:256,at_err:[10,344],at_err_funct:10,at_err_kwarg:[10,344],at_failed_login:144,at_failed_travers:[89,212,232,247],at_first_login:144,at_first_sav:[144,175,247],at_first_start:318,at_get:[182,221,247],at_giv:[218,221,247],at_heard_sai:118,at_hit:231,at_idmapper_flush:[259,318,334],at_init:[6,107,125,144,175,231,232,233,247],at_initial_setup:[104,271],at_initial_setup_hook_modul:271,at_login:[40,125,278,279,287,295,296,306],at_look:[96,144,247],at_message_rec:144,at_message_send:144,at_msg_rec:[144,189,247],at_msg_send:[144,146,189,247],at_new_arriv:231,at_now_add:86,at_object_cr:[5,6,21,25,31,39,43,58,60,73,80,81,85,89,96,121,123,125,132,159,187,189,206,212,214,217,218,219,220,221,226,231,232,233,247,318],at_object_delet:247,at_object_leav:[89,233,235,247],at_object_post_copi:247,at_object_rec:[89,117,233,235,247],at_password_chang:144,at_post_cmd:[30,33,150,154,167,170],at_post_command:33,at_post_disconnect:144,at_post_login:[25,144],at_post_portal_sync:305,at_post_puppet:[96,247],at_post_unpuppet:[96,247],at_pre_cmd:[33,150,154,167,170],at_pre_command:33,at_pre_login:144,at_pre_puppet:[96,247],at_pre_unpuppet:247,at_prepare_room:235,at_reload:[43,169,305],at_renam:318,at_repeat:[102,116,120,121,125,146,179,184,195,217,218,219,220,221,223,227,259,300,331],at_return:[10,344],at_return_funct:10,at_return_kwarg:[10,344],at_sai:[118,247],at_script_cr:[102,116,120,121,146,179,184,195,204,205,217,218,219,220,221,223,227,235,251,259,300,331],at_search_result:[168,344],at_server_cold_start:305,at_server_cold_stop:305,at_server_connect:285,at_server_reload:[102,110,144,146,247,259],at_server_reload_start:305,at_server_reload_stop:[25,305],at_server_shutdown:[102,110,144,146,247,259],at_server_start:305,at_server_startstop:[25,104],at_server_stop:305,at_shutdown:305,at_start:[102,116,146,195,227,235,256,259],at_startstop_modul:261,at_stop:[102,116,121,217,218,219,220,221,227,259],at_sunris:62,at_sync:[306,307],at_tick:[115,261],at_travers:[89,213,235,247],at_traverse_coordin:235,at_turn_start:219,at_upd:[219,257],at_weather_upd:132,atlanti:24,atom:98,atop:235,atribut:325,att:51,attach:[4,11,21,41,43,56,58,64,77,89,95,102,105,110,112,119,140,154,159,164,167,189,199,215,235,242,247,258,304,315,319],attachmentsconfig:4,attack:[14,28,29,30,46,51,77,90,103,116,119,122,134,139,153,206,215,217,218,219,220,221,231,232,247,252,285],attack_count:220,attack_messag:73,attack_nam:220,attack_skil:252,attack_summari:73,attack_typ:221,attack_valu:[217,218,219,220,221],attempt:[0,2,22,24,29,31,43,51,60,61,87,91,103,106,119,120,135,156,159,187,210,212,217,218,219,220,221,264,267,272,305,310,318,344,362],attent:[38,56,58,89,103,111],attitud:57,attr1:[43,159,203],attr2:[43,159,203],attr3:[43,159],attr:[11,22,43,49,51,58,80,109,119,136,137,159,166,180,233,241,251,252,306,334,340],attr_categori:315,attr_eq:241,attr_g:[80,241],attr_gt:[80,241],attr_kei:315,attr_l:[80,241],attr_lockstr:315,attr_lt:[80,241],attr_n:[80,241],attr_nam:159,attr_obj:318,attr_object:318,attr_typ:315,attr_valu:315,attract:37,attrcreat:[80,316],attread:11,attredit:[11,80,316],attrib:242,attribut:[0,2,6,12,20,22,25,27,28,30,39,41,42,43,45,46,49,50,51,56,57,58,60,61,69,73,74,77,80,81,82,84,85,86,87,89,91,95,102,105,108,109,112,115,116,119,123,125,127,133,134,138,139,141,142,144,145,148,153,159,168,169,173,175,180,181,187,194,195,202,203,206,213,217,218,219,220,221,226,231,232,233,241,244,246,247,250,251,252,254,256,257,260,272,306,314,315,317,318,319,324,325,337,338,341,344,357,362,364],attribute1:123,attribute2:123,attribute_nam:[144,206,247,341],attributeerror:[42,60,86,306,316],attributeform:315,attributeformset:315,attributehandl:[1,125,306,316,339,344],attributeinlin:[145,173,244,254,315],attributeobject:11,attrkei:252,attrnam:[11,43,51,80,109,125,159,241,318],attrread:[11,80,316],attrtyp:[11,316,317],attrvalu:51,attryp:317,atttribut:49,atyp:242,audibl:205,audio:137,audit:[141,142,175,178,207,247],audit_callback:209,auditedserversess:[209,210],auditingtest:211,aug:9,august:[9,344],aut:52,auth:[144,145,148,164,287,349,357,362],auth_password:287,auth_profile_modul:148,authent:[40,103,105,107,133,138,144,278,285,287,296,306,308,349,362],authenticated_respons:360,author:[41,90,126,144,192,195],auto:[0,5,12,14,21,31,32,33,34,38,42,43,45,51,63,67,71,89,95,96,105,122,131,133,138,141,144,148,150,154,158,159,166,169,170,205,206,227,236,239,242,247,252,256,259,261,264,267,278,295,296,305,308,318,323,329,330,349],auto_help:[33,41,44,51,68,69,154,170,188,230,249,328,329],auto_help_display_kei:[154,170,328],auto_id:[145,237,244,357],auto_look:[51,188,230,249,328],auto_now_add:86,auto_quit:[51,188,230,249,328],auto_transl:205,autobahn:[278,295],autodoc:38,autofield:133,autologin:349,autom:[14,36,57,58,67,79,86,100,103,110,362],automat:[0,6,10,14,19,22,23,27,30,31,34,37,38,41,43,46,47,50,51,55,58,60,62,64,65,66,67,68,71,72,80,81,84,85,86,90,96,97,100,102,104,105,109,111,116,117,118,119,121,122,123,124,125,126,128,131,135,136,139,140,144,152,153,154,159,164,165,167,174,179,180,181,182,194,195,196,203,204,205,206,214,221,226,227,234,242,246,247,258,259,260,261,272,287,305,308,322,326,328,329,330,344,350],automatical:261,autostart:[258,324],autumn:[97,99,187],avail:[0,5,7,8,10,11,13,16,21,22,23,25,26,31,33,36,38,39,40,41,42,43,44,46,48,49,51,53,57,58,60,62,63,64,65,72,74,75,76,77,78,79,80,81,82,85,88,89,90,91,95,96,98,100,102,104,105,106,108,109,110,111,113,114,116,119,121,122,123,125,127,128,130,131,133,134,137,138,139,141,144,150,151,152,153,154,156,159,161,164,165,166,167,168,169,170,171,179,180,181,185,187,189,195,199,202,204,205,206,214,215,217,218,219,220,221,224,232,233,241,242,247,250,251,252,256,272,296,299,310,321,322,323,328,329,330,336,344,362],available_choic:[51,328],available_func:336,available_funct:251,available_languag:205,available_weapon:232,avatar:[64,88,96,247,287],avatarid:287,avenu:182,averag:[13,43,90,93,169,195,205,234],avoid:[8,11,23,26,27,31,33,37,38,40,42,43,51,80,81,85,95,97,100,109,111,114,125,126,127,129,131,138,139,152,159,204,205,234,235,241,246,272,276,286,296,306,316,318,321,322,323,326,329,334],awai:[0,9,10,11,14,15,21,26,29,42,43,46,49,51,55,66,68,69,73,80,86,90,96,102,105,109,111,121,123,131,165,182,215,218,221,224,226,231,233,235,247,256,307,321,344],await:10,awar:[11,14,26,31,33,44,51,88,95,96,110,125,126,132,133,189,204,206,231,234,235,247,318,321],awesom:[63,135],aws:90,axhear:241,azur:100,b64decod:340,b64encod:340,b_offer:179,baaaad:127,babi:138,bacground:67,back:[0,3,5,10,11,12,13,14,20,21,22,23,25,26,27,29,31,33,34,36,38,43,46,49,50,51,56,58,60,61,63,64,67,69,73,74,81,83,85,86,87,90,91,95,96,97,100,102,105,106,110,111,113,116,118,119,121,122,123,125,126,131,133,135,137,141,144,153,156,159,164,168,179,180,206,212,215,220,224,249,259,267,272,276,279,285,287,305,318,325,328,329,337,344],back_exit:0,backbon:[133,322],backend:[23,36,109,127,135,141,142,344,346,348],background:[10,17,29,51,67,90,103,110,114,126,133,183,190,321,336,362],backpack:31,backslash:[114,329],backtick:[38,131],backtrack:131,backup:[10,89,90,105,131,168,322],backward:[50,51,58,121,337],bad:[0,22,24,37,41,58,64,70,76,85,119,127,210,269],bad_back:242,badg:130,bag:344,bake:100,balanc:[29,56,61,79,116,330],balk:95,ball:[31,59,104,151,152,252],ballon:203,balloon:203,ban:[7,25,80,139,144,157,242,364],band:[45,88,118,137,287],bandit:46,banid:[43,157],bank:61,bar:[51,82,83,84,88,112,135,137,190,206,215,328],bare:[33,55,58,73,104,190,218],barehandattack:56,bargain:86,barkeep:[42,206],barter:[61,63,102,117,141,142,178],bartl:79,bas:120,base:[3,4,6,9,13,16,17,20,21,22,23,30,33,34,36,38,39,41,42,43,49,51,53,55,56,57,58,60,61,63,64,67,69,72,73,75,77,79,80,83,85,86,89,90,96,100,102,103,105,108,111,113,115,119,120,123,124,125,126,127,129,130,133,134,136,137,138,139,141,144,145,146,147,148,150,152,153,154,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,173,174,175,176,177,179,180,181,182,184,185,186,187,188,189,192,193,195,196,198,199,202,203,204,205,206,210,211,212,213,214,215,217,218,219,220,221,223,224,226,227,228,230,231,232,233,234,235,237,238,239,242,244,245,246,247,249,251,252,254,255,256,257,258,259,260,261,263,264,265,267,269,270,273,274,276,277,278,279,285,286,287,295,296,298,299,300,303,305,306,307,308,310,311,312,315,316,317,318,319,321,322,323,326,327,328,329,330,331,333,334,335,336,337,338,339,340,341,342,343,344,349,351,352,357,360,362,364],base_account_typeclass:2,base_char_typeclass:120,base_character_typeclass:[43,81,120,133,134,144,159],base_field:[145,237,244,315,357],base_guest_typeclass:66,base_object_typeclass:[109,252,318],base_random:250,base_script_path:241,base_script_typeclass:102,base_set:9,baseclass:232,basecontain:323,baseinlineformset:315,baseline_index:344,baseobject:125,baseopt:338,basepath:344,basetyp:[247,322],basetype_posthook_setup:247,basetype_setup:[39,80,96,144,146,175,247],bash:[36,38,63,67,232],basi:[4,33,37,62,90,136,138,167,177,206,241,296,318,327],basic:[0,2,3,6,9,15,16,17,19,20,22,26,29,31,33,34,36,39,40,43,46,47,48,56,57,58,60,61,62,69,73,77,79,80,81,83,86,87,110,111,113,116,117,118,121,122,124,126,128,133,134,135,137,139,144,146,159,164,166,175,177,188,194,203,218,220,232,241,243,247,298,326,329,342,346,357,362,364],bat:[9,63],batch:[18,20,43,48,63,79,111,122,124,139,141,142,158,252,276,316,319,320,364],batch_add:[252,316,319],batch_cmd:14,batch_cod:[13,322],batch_code_insert:13,batch_create_object:252,batch_exampl:322,batch_import_path:[13,14],batch_insert_fil:14,batch_update_objects_with_prototyp:252,batchcmd:[43,158],batchcmdfil:[14,322],batchcod:[14,79,111,158],batchcode_map:111,batchcode_world:111,batchcodefil:13,batchcodeprocessor:322,batchcommand:[14,20,22,63,122,158,322],batchcommandprocessor:322,batchfil:[14,15,111,322],batchprocess:[141,142,149,155],batchprocessor:[13,141,142,158,320],batchscript:[13,322],batteri:144,battl:[79,103,116,122,217,218,219,220,221],battlecmdset:[217,218,219,220,221],baz:215,bazaar:108,beach:111,bear:[204,231],beat:[61,116],beaten:[116,233],beauti:[22,49,133],beazlei:79,becam:[29,126],becaus:[0,2,6,8,9,10,11,12,13,15,16,21,22,25,29,31,36,38,40,41,42,44,46,51,54,56,59,64,68,73,76,77,80,89,91,95,96,107,108,109,111,115,116,117,119,125,126,130,133,134,136,145,153,171,175,186,194,205,220,224,235,247,259,279,285,298,308,315,321,338,340],becom:[0,5,10,22,37,38,41,42,43,47,49,51,56,59,61,64,70,73,78,80,81,86,87,88,95,96,102,104,109,111,119,128,156,189,203,205,215,218,252,306,322,328],bed:61,been:[0,4,5,6,13,14,19,21,22,23,36,38,41,42,43,46,49,51,58,69,70,76,79,85,91,93,96,103,105,116,117,123,126,128,131,133,134,135,138,152,153,158,159,167,168,175,180,195,203,204,206,217,218,219,220,221,233,235,239,242,246,247,251,252,260,261,269,285,287,295,305,306,307,308,310,315,318,322,326,327,344,362],befit:125,befor:[1,4,10,11,12,13,14,15,20,21,22,25,27,28,29,31,33,37,41,42,43,46,48,49,51,56,57,58,60,61,67,69,71,75,77,79,80,81,84,85,86,90,91,93,96,97,100,102,103,104,106,107,108,109,111,112,113,114,115,116,117,118,119,121,123,124,125,126,127,131,132,133,134,135,137,138,139,144,150,151,154,159,164,167,171,175,184,186,187,188,189,190,194,198,205,206,209,210,215,217,218,219,220,221,226,227,230,232,233,235,241,242,246,247,250,252,259,260,261,267,276,285,287,301,303,305,306,310,312,316,321,322,323,324,328,329,330,331,335,337,340,344,362],beforehand:[11,131,323],beg:14,beggar:0,begin:[0,4,6,10,13,14,20,22,25,33,38,41,42,43,46,50,51,55,58,61,69,72,80,91,95,96,106,107,111,116,117,119,127,132,134,165,194,206,215,217,218,219,220,221,247,259,321,322,328,341],beginn:[55,60,77,79,91,95,124],behav:[11,13,20,22,29,69,91,95,107,110,127,251,344],behavior:[0,5,11,31,33,41,50,68,69,93,96,102,109,114,126,135,137,138,144,154,170,182,188,219,221,233,234,267,315,328],behaviour:[11,31,33,80,126,313,324,330,344],behind:[11,12,21,33,38,43,49,51,55,59,61,63,74,97,109,112,114,122,126,131,158,204,233,256,261,334],behvaior:329,being:[0,5,6,10,11,13,20,21,22,25,28,31,33,34,36,37,42,43,51,54,56,59,61,63,64,69,83,88,90,91,93,95,96,102,103,107,109,111,115,118,125,126,127,129,131,133,138,144,151,159,165,169,175,184,185,189,199,205,206,217,218,219,220,221,226,227,233,239,247,269,272,279,308,310,315,318,321,322,324,328,329,330,344,363],beipmu:24,belong:[4,14,43,64,83,95,103,112,119,133,140,153,206,215,235,239,250],below:[0,1,5,8,9,10,11,12,13,14,15,19,20,22,23,25,27,29,31,33,34,36,38,39,42,43,48,49,50,51,57,58,59,60,61,62,63,64,67,69,70,74,80,81,87,88,90,95,96,100,102,105,106,109,110,111,114,117,118,119,123,125,127,131,133,134,136,138,140,148,159,167,168,177,180,182,185,190,205,206,215,217,218,219,220,221,228,234,239,241,246,247,256,279,299,316,318,319,328,330,335,336],belt:77,beneath:27,benefici:[49,219],benefit:[78,90,100,103,108,127,153,316,322,328],besid:[0,14,31,106,111,190],best:[9,22,24,26,37,50,51,57,58,59,61,72,76,102,103,104,108,133,135,139,166,180,205,215,234,252,267,287,330,338,364],bet:[31,105,138,318],beta:[35,54,90],betray:51,better:[0,9,15,23,25,34,41,42,44,45,51,55,58,59,61,64,68,70,73,81,85,86,91,93,95,108,109,112,114,133,134,181,213,218,224,233,252,287,298,322],bettween:73,between:[0,2,10,14,22,25,28,31,33,36,38,39,40,41,43,46,49,56,57,58,64,67,69,73,76,83,85,87,88,90,91,100,102,105,109,112,113,114,116,120,121,122,123,124,126,131,137,138,140,151,154,159,164,166,169,170,177,179,182,183,194,195,198,199,202,204,205,206,215,217,218,219,220,221,247,252,261,267,276,279,286,287,298,299,306,319,321,322,324,328,330,331,336,344,351],bew:187,bewar:39,beyond:[1,2,9,22,25,33,37,52,57,64,88,89,90,102,127,134,154,159,170,177,180,206,215,233,251,318,328,330],bg_colormap:343,bgcolor:343,bgfgstart:343,bgfgstop:343,bgstart:343,bgstop:343,bias:159,bidirect:276,big:[9,11,13,14,20,25,28,29,33,37,45,57,73,80,96,122,138,140,151,168,322,329,341,344],bigger:[21,37,40,69,119,123],biggest:[72,138],biggui:33,bigmech:21,bigsw:29,bikesh:119,bill:[90,103],bin:[4,9,36,47,63,64,75,96,100],binari:[23,47,63,93,95,278,295],bind:67,birth:357,bit:[0,4,9,12,17,22,26,29,35,39,41,42,43,46,59,61,62,63,69,75,76,81,96,102,106,109,121,122,127,131,134,137,138,171,186,242,247,322],bitbucket:57,bite:[61,111],black:[73,114,126],blackbird:79,blackbox:138,blacklist:103,blade:232,blank:[51,86,117,134,144,188,321],blankmsg:188,blarg:83,blargh:109,blatant:12,blaufeuer:119,bleed:[114,131,330],blend:203,blender:203,bless:138,blind:[114,118,224,227],blindcmdset:224,blindedst:227,blindli:242,blink:[20,226,227,343],blinkbuttonev:227,blist:97,blob:[37,38,95,104,138],block:[3,12,25,28,43,50,51,55,58,64,69,80,90,91,97,102,103,110,114,123,129,133,134,139,157,158,159,187,221,230,231,232,235,249,286,322,328,336,344,362],blocking_cmdset:25,blockingcmdset:25,blockingroom:25,blocktitl:69,blog:[37,55,79,90,98],blowtorch:24,blue:[13,57,81,114,126,232],blueprint:[57,96,111,137],blurb:54,board:[34,49,61,79,80,121],boat:[31,121,153],bob:[33,43,81,138,157],bodi:[3,17,22,27,33,38,41,46,51,58,95,109,127,129,133,175,193,199,269,324],bodyfunct:[20,102,141,142,178,222,228],bog:21,boi:112,boiler:125,bold:54,bolt:252,bone:[55,73],bonu:[41,73,90,218,219,256],bonus:[29,218],book:[3,49,62,73,79,91,95,109,135],bool:[2,31,33,34,51,74,84,102,144,145,146,148,150,151,152,153,154,159,173,175,176,177,179,180,182,184,185,188,190,192,195,204,205,206,215,217,218,219,220,221,226,235,238,242,244,246,247,250,251,252,254,256,257,258,259,260,261,267,272,273,278,279,285,286,295,296,304,306,308,310,316,317,318,319,321,322,324,326,328,329,330,331,334,336,339,341,343,344],booleanfield:[133,145,237],boom:[21,51],boot:[80,100,110,157,261],bootstrap:[4,124,138,139,364],border:[43,58,111,156,188,327,330],border_bottom:330,border_bottom_char:330,border_char:330,border_left:330,border_left_char:330,border_right:330,border_right_char:330,border_top:330,border_top_char:330,border_width:330,borderless:58,borderstyl:188,bore:[12,55,103],borrow:[31,63,152,276],bort:52,boss:58,bot:[43,47,65,72,93,103,119,133,141,142,143,148,164,175,272,278,279,286,308,362],bot_data_in:[146,272],both:[0,11,15,19,22,23,25,26,27,31,33,34,36,37,38,40,43,44,49,51,56,57,58,62,65,69,71,74,79,84,85,86,87,88,90,91,95,97,103,104,105,106,110,111,116,119,121,124,125,127,128,131,133,134,136,138,150,152,159,164,169,177,179,183,190,199,203,212,215,220,221,233,242,247,251,252,253,256,259,261,276,285,295,296,305,307,310,316,317,321,324,328,330,339,344],bother:[29,103,128,174],botnam:[43,72,164,279,308],botnet:103,botstart:146,bottom:[4,39,41,52,54,57,58,60,69,85,95,101,106,111,125,127,133,137,153,199,220,235,252,322,329,330],bought:85,bouncer:[27,103,327],bound:[6,27,57,108,192,344],bounti:70,bountysourc:70,bow:252,box:[0,3,8,20,42,43,46,58,63,66,69,70,71,73,80,87,90,104,106,109,111,123,135,138,159,206,241,276,322,357],brace:[0,22,25,41,91,247,321],bracket:[38,43,96,129,169,183],brainstorm:[139,364],branch:[9,36,37,38,41,63,100,204,215],branchnam:131,brandymail:199,bread:16,breadth:221,break_lamp:226,break_long_word:330,break_on_hyphen:330,breakdown:[43,169],breakpoint:[16,106,141],breez:[102,132],breviti:58,bribe:51,brick:82,bridg:[22,23,53,79,83,105,233],bridgecmdset:233,bridgeroom:233,brief:[3,16,19,20,21,25,46,58,60,85,86,95,96,101,110,124,131,139,188,234,247,311],briefer:[89,110],briefli:[16,90,110],bright:[81,114,126,183,321],brightbg_sub:321,brighten:114,brighter:114,brilliant:131,bring:[23,49,96,100,103,121,123,133,136,215,221,224,231,309],broad:39,broadcast:[43,164,276],broader:[39,206,247],broken:[61,108,114,205,226,227,336],brought:102,brows:[3,9,25,39,55,58,62,69,85,90,91,103,106,123,131,136,137,138,362],browser:[3,8,9,16,38,55,63,64,67,69,70,75,77,90,95,96,101,103,133,134,135,136,137,138,295,296,362],brutal:234,bsd:78,btest:114,btn:[17,70],bucket:209,buf:326,buffer:[22,33,50,137,168,269,296,326],bug:[10,13,26,37,42,54,57,60,61,70,78,95,96,110,123,127,131,227,318],buggi:[11,328],bui:[85,138,179],build:[1,6,7,9,10,11,13,14,15,27,31,36,47,51,55,57,60,63,64,68,69,75,77,79,80,81,86,87,89,96,100,105,106,108,109,112,113,119,120,122,123,125,129,130,136,137,139,140,141,142,149,151,155,157,158,165,166,175,180,187,193,205,206,212,231,234,242,247,251,252,267,278,279,322,330,357,363,364],build_match:151,builder:[2,4,14,19,22,25,43,56,58,60,61,68,80,85,108,109,112,114,123,124,139,157,159,164,165,169,180,182,187,188,203,206,212,233,234,235,242,247,250,298,318,322,363,364],buildier:252,building_menu:[141,142,178],buildingmenu:[22,180],buildingmenucmdset:180,buildprotocol:[264,277,278,279],buildshop:85,built:[13,16,20,27,38,40,51,54,55,57,58,61,63,64,73,75,77,95,96,100,103,121,122,123,135,138,139,148,177,203,205,239,246,256,261,316,318,319,322,328,335],bulk:[96,103],bullet:[38,61],bulletin:[61,79,80],bulletpoint:38,bunch:[15,27,58,108,113],burden:82,buri:[108,122],burn:[61,73,90,232],busi:[64,70,90,179],butch:96,butt:138,butter:16,button:[9,13,14,31,33,43,80,83,87,88,106,131,133,134,135,137,138,159,224,226,227,232,299,329],button_expos:232,buy_ware_result:85,byngyri:205,bypass:[4,10,19,20,43,58,80,116,126,144,159,175,212,241,242,318,324,341,349],bypass_superus:80,bytecod:321,bytestr:[276,344],bytestream:344,c_creates_button:299,c_creates_obj:299,c_dig:299,c_examin:299,c_help:299,c_idl:299,c_login:299,c_login_nodig:299,c_logout:299,c_look:299,c_move:299,c_moves_:299,c_moves_n:299,c_social:299,cabl:82,cach:[6,8,11,12,28,33,39,43,86,119,125,127,130,137,144,154,169,174,175,187,231,232,242,246,247,271,315,316,318,319,320,332,334,344],cache_inst:334,cache_lock_bypass:242,cache_s:[310,334],cached_properti:344,cactu:220,cake:31,calcul:[10,25,27,39,73,116,119,123,139,153,184,187,198,205,217,218,220,221,252,331,334,344,362],calculated_node_to_go_to:51,calculu:56,calendar:[184,198,331],call:[0,2,3,4,5,6,10,11,13,14,16,20,21,22,23,25,26,27,28,29,30,31,36,38,39,40,41,42,43,46,47,48,49,50,51,55,56,57,58,59,60,61,62,63,64,65,69,71,72,73,74,75,80,81,83,84,85,86,88,89,90,91,93,95,96,100,102,104,105,107,108,109,110,111,114,115,116,117,118,119,120,121,122,123,125,126,127,128,131,132,133,134,135,137,138,144,146,150,151,152,153,154,156,159,164,167,168,169,170,171,174,175,179,180,182,184,185,186,187,188,189,192,193,194,195,196,198,203,204,205,206,212,214,215,217,218,219,220,221,223,224,226,227,230,231,232,233,234,235,241,242,246,247,250,251,252,257,258,259,260,261,264,267,269,271,272,276,277,278,279,285,286,287,295,296,298,299,300,305,306,307,308,309,312,315,316,318,319,321,322,323,324,326,328,329,330,331,334,336,337,339,340,341,344,357,362],call_async:10,call_command:127,call_ev:[0,194],call_inputfunc:[83,306,308],call_task:260,callabl:[49,50,84,109,115,123,180,188,195,215,219,247,250,251,252,257,261,265,267,269,277,323,326,328,329,337,339,340,344],callables_from_modul:344,callbac:22,callback1:328,callback:[4,10,22,27,29,33,50,51,62,74,84,115,138,146,180,184,188,192,193,194,195,196,198,210,215,230,247,257,259,260,261,265,267,269,272,276,277,278,295,298,309,328,331,337,342,344,364],callback_nam:[192,195],callbackhandl:[141,142,178,191],called_bi:150,calledbi:344,caller:[5,10,11,13,21,22,25,27,28,29,30,33,38,41,42,43,44,49,50,56,58,59,60,71,73,80,81,82,83,85,86,87,88,89,91,111,115,116,119,121,123,125,129,137,146,150,151,152,154,156,159,160,164,165,166,167,168,169,170,174,180,188,193,199,203,206,214,215,230,232,233,234,235,242,247,249,251,322,326,328,329,336,338,344],callerdepth:344,callertyp:150,callinthread:312,calllback:194,callsign:[51,272],calm:111,came:[9,21,25,55,79,111,132,138,231,235,247],camp:111,campfir:111,campsit:111,can:[0,1,2,3,4,5,6,9,10,12,13,14,15,17,19,20,21,23,24,25,26,27,28,29,30,31,33,34,35,36,37,38,39,40,41,42,43,44,46,48,49,50,51,54,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,95,96,97,98,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,130,131,133,134,135,136,137,138,139,140,143,144,146,148,151,152,153,154,156,157,159,164,165,166,167,168,169,170,174,175,176,177,179,180,182,183,184,185,187,188,189,190,194,195,198,199,203,204,205,206,209,212,215,217,218,219,220,221,224,226,227,231,232,233,234,235,239,241,242,246,247,250,251,252,253,256,257,258,259,261,267,278,285,287,295,296,298,299,305,306,307,308,309,312,313,314,316,317,318,319,321,322,323,324,326,327,328,329,330,336,338,339,340,341,342,344,345,357,362,363],can_:194,cancel:[27,29,74,194,217,218,219,220,221,247,260],candid:[22,33,119,133,151,203,206,247,341],candl:153,cannot:[5,9,10,11,13,14,19,21,22,25,27,28,29,31,33,39,43,44,46,50,51,56,60,61,63,69,70,73,76,80,85,90,104,109,112,114,122,123,127,128,133,139,144,146,153,156,159,175,180,187,188,192,195,212,215,221,227,231,232,238,241,242,247,251,261,316,323,325,327,330,334,344],cantanker:338,cantclear:188,cantillon:79,cantmov:25,canva:49,capabl:[6,36,43,49,58,64,80,83,88,105,156,214,272,357],cape:57,capfirst:69,capit:[9,12,25,29,43,64,88,95,123,159,189,204,205,321],captcha:133,caption:38,captur:[25,91,138,337,362],car:[87,121],card:103,cardin:[43,44,49,58,159],care:[0,4,10,12,23,33,38,44,49,51,56,57,62,64,78,86,91,110,116,121,126,132,144,152,175,187,203,206,230,231,233,241,247,250,318,322,326,328,329,330,344],carefulli:[55,93,105,111,133],carri:[20,31,61,80,82,85,116,117,177,182,218,231,241,306,317],cascad:334,caseinsensitivemodelbackend:349,cast:[28,109,112,215,220],caster:[28,220],castl:[13,111,122,187,233],cat:[67,75],catchi:4,categor:112,categori:[1,5,11,33,36,39,43,51,68,69,86,109,112,119,127,140,155,159,166,167,168,199,215,238,239,241,251,252,316,317,319,324,335,338,341,344,362],categoris:56,category2:335,category2_id:335,category_id:335,category_index:215,cater:29,caught:[42,51,97,176],caus:[11,12,29,30,31,42,60,61,64,77,80,90,96,114,116,117,119,123,127,137,140,153,186,224,226,235,247,298,330,344],caution:[62,137,328],cave:46,caveat:[5,10],caveman:56,cblue:131,cboot:[12,164],cc1:63,cccacccc:327,ccccc2ccccc:58,cccccccc:327,ccccccccccc:58,cccccccccccccccccbccccccccccccccccc:327,ccccccccccccccccccccccccccccccccccc:327,ccreat:[41,58,65,72,98,164],cdesc:[41,164],cdestroi:164,cdmset:31,cdn:103,ceas:[43,77,159],cel:327,celebr:61,cell:[58,69,111,188,327,330],celltext:327,cemit:164,censu:317,center:[4,16,39,49,109,111,114,190,250,321,330,344],center_justifi:[109,250],centos7:67,centr:111,central:[26,55,61,64,74,100,111,123,124,127,132,138,139,144,153,177,247,252,276,324,328,334,363,364],centre_east:111,centre_north:111,centre_south:111,centre_west:111,centric:[9,80,105,123,206],cert:8,certain:[13,14,16,19,25,29,31,33,37,38,43,48,64,75,80,88,90,97,102,105,107,108,114,115,121,138,159,176,179,205,209,227,232,235,241,259,267,273,309,315,316,317,326,330,341,344,357],certainli:[15,44,138],certbot:[67,90,103],certif:[8,90],certonli:67,cet:337,cfg:67,cflag:75,cgi:90,cha:[51,58],chain:[0,10,29,46,51,109,119,194,195,299,328],chain_1:0,chainedprotocol:287,chainsol:119,chair:[13,61,89,91,112,125],challeng:[73,79],chan:164,chanalia:[43,164],chanc:[21,22,28,31,54,61,66,73,115,116,122,131,152,217,218,219,220,221,224,232,233,299],chance_of_act:299,chance_of_login:299,chandler:116,chang:[2,3,4,7,8,9,11,12,13,14,15,16,19,20,21,22,23,26,29,30,31,33,34,35,36,37,39,41,42,43,45,47,49,50,51,53,54,57,61,62,63,64,66,67,68,71,73,74,75,77,78,80,81,83,84,85,86,87,89,90,91,95,96,100,102,104,105,107,109,110,111,112,114,115,116,118,121,123,125,126,127,132,133,134,135,137,138,139,144,145,153,154,156,157,159,164,165,170,173,175,179,180,182,186,187,189,190,192,195,202,205,206,212,213,215,217,218,219,220,221,231,232,233,234,235,239,244,247,252,254,256,257,259,260,261,267,272,298,305,306,313,315,318,322,325,326,329,330,337,338,339,340,362],change_name_color:215,changeabl:76,changelog:96,changepag:134,changepassword:12,chanlist:[43,164],channam:41,channel:[2,6,7,11,12,19,27,31,33,45,53,55,65,70,71,72,79,80,82,86,87,90,98,107,112,119,123,124,125,138,139,144,146,150,152,153,159,164,168,172,173,174,175,176,177,195,271,278,279,286,299,306,308,316,324,337,341,360,362,364],channel_:34,channel_ban:[41,164],channel_color:25,channel_command_class:[34,41],channel_connectinfo:306,channel_detail:362,channel_handl:[141,174],channel_list:362,channel_prefix:[25,175],channel_search:176,channel_set:177,channel_typeclass:360,channeladmin:173,channelam:174,channelattributeinlin:173,channelcmdset:31,channelcommand:[34,41,174],channelconnect:177,channelcr:[43,164],channelcreateview:175,channeldb:[41,53,125,141,173,175,177,314],channeldb_db_attribut:173,channeldb_db_tag:173,channeldb_set:[316,319],channeldbmanag:[176,177],channeldeleteview:175,channeldesc:[41,174],channeldetailtest:360,channeldetailview:[175,362],channelhandl:[34,41,141,142,150,172,175],channelkei:[41,174,176],channellist:[43,164],channellisttest:360,channellistview:362,channelmanag:[175,176],channelmixin:362,channelnam:[34,41,72,146,174,278],channeltaginlin:173,channelupdateview:175,char1:[43,73,127,165,360],char2:[43,73,127,165,360],char_health:233,char_nam:133,charac:84,charact:[0,2,5,9,11,14,15,17,19,20,21,22,23,27,28,29,30,31,33,34,36,39,40,41,42,43,45,47,49,50,51,53,55,56,57,62,68,69,71,74,76,77,80,81,83,85,86,87,88,91,95,97,102,105,111,113,114,116,117,118,119,120,121,122,124,125,127,129,135,136,138,139,141,143,144,151,152,154,156,159,160,161,165,166,167,174,175,180,181,182,187,188,189,190,192,194,195,199,202,204,205,206,209,214,215,217,218,219,220,221,223,231,232,233,235,239,242,247,259,272,306,311,316,318,321,322,327,328,330,336,342,344,345,357,360,362,364],character1:73,character2:73,character_cmdset:187,character_form:362,character_id:247,character_list:362,character_manage_list:362,character_typeclass:[127,144,342,360],charactercmdset:[5,21,22,25,30,31,41,43,44,57,58,60,62,81,123,161,180,182,187,199,202,212,217,218,219,220,221,233],charactercreateview:[360,362],characterdeleteview:[360,362],characterdetailview:362,characterform:[357,362],characterlistview:[360,362],charactermanageview:[360,362],charactermixin:362,characternam:114,characterpuppetview:[360,362],charactersheet:51,characterupdateform:[357,362],characterupdateview:[360,362],charapp:133,charat:188,charcreat:[0,46,69,156,181],chardata:58,chardelet:156,chardeleteview:[239,318],chardetailview:[239,318],charfield:[86,133,145,237,244,315,340,357],charg:90,chargen:[133,139,141,142,175,178,239,318],chargencmdset:123,chargenroom:123,chargenview:[239,318],charnam:[43,58,156],charpuppetview:318,charset:344,charsheet:58,charsheetform:58,charupdateview:[239,318],chase:122,chat:[1,2,9,26,34,37,48,55,58,60,63,65,70,72,79,80,98,123,131,139,296,337],chatroom:57,chatzilla:72,cheap:131,cheaper:[61,115],cheapest:90,cheapli:233,cheat:[23,38,73],cheatsheet:48,check:[0,4,5,12,13,14,19,22,25,26,27,28,29,31,33,36,37,38,39,40,41,42,43,44,46,49,51,54,56,58,60,63,65,67,68,69,70,71,73,77,81,82,85,86,87,89,90,91,95,97,98,100,102,103,106,109,110,111,112,114,115,116,117,118,119,121,123,125,127,128,130,131,133,136,138,139,144,145,150,151,152,153,154,156,158,159,164,165,166,167,169,171,175,177,179,181,182,186,187,188,195,199,217,218,219,220,221,223,224,227,231,233,234,235,241,242,246,247,251,252,256,258,259,260,266,267,271,276,287,306,308,310,311,312,315,316,318,319,321,322,324,338,339,344,345,362],check_attr:159,check_circular:296,check_databas:267,check_db:267,check_defeat:73,check_end_turn:116,check_error:266,check_evennia_depend:344,check_from_attr:159,check_grid:49,check_has_attr:159,check_light_st:233,check_lockstr:[4,80,242],check_main_evennia_depend:267,check_obj:159,check_permiss:251,check_permstr:[144,318],check_show_help:166,check_to_attr:159,check_warn:266,checkbox:133,checker:[15,49,241,287,345],checkout:[9,100,131],checkoutdir:36,chest:[80,91],child:[6,33,43,51,64,80,96,116,146,148,154,159,170,233,246,252,256,312,335],childhood:51,children:[21,33,64,96,112,117,119,125,148,246,247,256,267,317,335],chillout:[43,159],chime:27,chines:[25,79,113],chip:58,chmod:36,choci:180,chocol:60,choic:[4,15,23,33,43,51,55,60,78,90,91,95,105,107,109,113,116,119,124,127,129,132,156,159,179,180,188,217,234,250,265,326],choice1:129,choice2:129,choice3:129,choos:[7,9,10,13,38,49,51,57,62,64,67,72,73,85,101,106,116,120,123,126,133,135,138,139,140,214,215,217,218,219,220,221,224,231,328,343,364],chop:[33,232],chore:68,chose:[54,58,86,103,133,215],chosen:[22,51,88,106,116,132,138,188,190,328],chown:100,chractercmdset:233,christin:96,chrome:24,chronicl:188,chroot:67,chug:33,chunk:[13,69,111,269,322,336],church:27,church_clock:27,cid:299,cillum:52,circl:39,circuit:137,circular:[269,323],circumst:[46,51,57,85,119,152,220,357],circumv:[43,157],claim:83,clang:75,clank:0,clarif:[1,48],clarifi:25,clariti:[75,86,91,123],clash:[23,31,43,90,159,174,318],class_from_modul:344,classic:[3,13,79,105,112,115,116],classmethod:[39,144,175,239,247,259,318,334,351],classnam:11,classobj:318,claus:[78,118],clean:[1,4,17,25,28,43,48,51,76,110,111,114,116,122,131,145,152,154,159,175,179,206,217,218,219,220,221,227,232,233,235,247,256,267,271,285,295,308,315,318,321,326,328,334,340,343,344,357],clean_attr_valu:315,clean_attribut:[125,144,318],clean_cmdset:[125,318],clean_senddata:308,clean_stale_task:260,clean_str:321,clean_usernam:145,cleaned_data:133,cleaner:[91,123],cleanli:[64,102,105,110,150,154,164,174,188,269,278,295,308,326],cleanup:[1,11,22,33,40,43,45,50,51,102,127,145,169,179,230,233,328],clear:[1,4,11,12,15,22,29,33,37,38,40,43,48,50,59,61,64,69,70,73,81,104,110,111,112,113,115,125,128,129,131,132,137,138,153,156,157,159,165,174,188,204,206,227,233,242,246,247,257,260,261,269,306,316,318,319,328,334],clear_client_list:303,clear_cont:[89,247],clear_exit:[89,247],clearal:[43,129,165],clearli:[12,37,48,128,227,334],cleartext:[210,324],clemesha:312,clever:[10,31,51,95,242],cleverli:105,click:[36,38,69,90,101,106,114,128,131,133,135,137,138,328],clickabl:[18,38],client:[3,7,8,9,12,22,23,25,30,33,36,40,43,45,50,52,54,55,60,63,64,65,67,72,74,75,79,81,84,91,95,96,100,101,103,104,105,107,108,111,113,114,116,117,126,128,136,138,139,141,142,144,146,154,156,164,169,210,262,264,268,270,272,276,277,278,279,285,287,295,296,298,299,305,306,307,308,325,326,328,343,344,362,364],client_address:40,client_default_height:52,client_disconnect:296,client_encod:23,client_height:154,client_opt:272,client_secret:65,client_width:[33,154],clientconnectionfail:[264,278,279],clientconnectionlost:[264,278,279],clientfactori:298,clienthelp:137,clientraw:[43,169],clientsess:[295,296],cliff:[20,43,159],climat:112,climb:[33,43,55,77,93,159,232],climbabl:232,clipboard:[1,48],clist:[43,164],clock:[12,27,33,73,164],clone:[38,47,63,64,76,96,128,130],close:[0,14,22,25,38,39,40,41,43,46,48,50,51,64,69,76,90,96,100,103,105,106,110,125,131,133,137,169,171,179,180,186,190,212,221,224,226,227,230,269,277,278,285,287,295,296,308,316,322,328,336],close_lid:226,close_menu:[230,328],closedlidst:227,closelidev:227,closer:[205,221],closest:[39,114],cloth:[141,142,178,322],clothedcharact:182,clothedcharactercmdset:182,clothes_list:182,clothing_typ:182,clothing_type_count:182,clothing_type_ord:182,cloud:[90,100,102,103,132],cloudi:102,clr:[114,251,336],cls:39,clue:232,clunki:[131,221],clutter:[38,153],cma:131,cmd:[12,14,22,25,28,29,31,33,41,43,44,53,58,60,62,71,80,82,85,88,95,121,123,136,152,154,156,157,158,159,164,165,166,167,168,169,170,171,174,179,180,181,182,185,186,187,188,189,193,199,202,203,206,212,213,214,215,217,218,219,220,221,224,231,232,233,234,236,247,295,296,322,326,328,329],cmd_abil_result:127,cmd_arg:91,cmd_channel:[33,150],cmd_ignore_prefix:151,cmd_kei:91,cmd_last:105,cmd_last_vis:105,cmd_loginstart:33,cmd_multimatch:[33,150],cmd_na_m:88,cmd_name:88,cmd_noinput:[33,150,328],cmd_nomatch:[33,150,233,328],cmd_noperm:33,cmd_on_exit:[51,188,215,230,249,328],cmd_total:105,cmdabil:[60,127],cmdabout:169,cmdaccept:179,cmdaccess:165,cmdaddcom:164,cmdallcom:164,cmdapproach:221,cmdarmpuzzl:203,cmdasync:10,cmdattack:[29,73,116,123,217,218,219,220,221,232],cmdban:157,cmdbatchcod:158,cmdbatchcommand:158,cmdbigsw:29,cmdblindhelp:224,cmdblindlook:224,cmdblock:25,cmdboot:157,cmdbridgehelp:233,cmdbui:85,cmdbuildshop:85,cmdcallback:193,cmdcast:220,cmdcboot:164,cmdcdesc:164,cmdcdestroi:164,cmdcemit:164,cmdchannel:164,cmdchannelcr:164,cmdcharactercr:181,cmdcharcreat:156,cmdchardelet:156,cmdclimb:232,cmdclock:164,cmdcloselid:224,cmdcolortest:156,cmdcombathelp:[217,218,219,220,221],cmdconfigcolor:81,cmdconfirm:33,cmdconnect:41,cmdcopi:159,cmdcover:182,cmdcpattr:159,cmdcraftarmour:29,cmdcreat:159,cmdcreatenpc:123,cmdcreatepuzzlerecip:203,cmdcwho:164,cmddarkhelp:233,cmddarknomatch:233,cmddeclin:179,cmddefend:116,cmddelcom:164,cmddesc:[159,187],cmddestroi:159,cmddiagnos:30,cmddice:[58,185],cmddig:159,cmddisconnect:41,cmddisengag:[116,217,218,219,220,221],cmddoff:218,cmddon:218,cmddrop:[165,182],cmdeast:233,cmdecho:[5,29,33,38],cmdedit:180,cmdeditnpc:123,cmdeditorbas:326,cmdeditorgroup:326,cmdeditpuzzl:203,cmdemit:157,cmdemot:206,cmdentertrain:121,cmdevalu:179,cmdevenniaintro:233,cmdevmenunod:328,cmdexamin:159,cmdexiterror:44,cmdexiterroreast:44,cmdexiterrornorth:44,cmdexiterrorsouth:44,cmdexiterrorwest:44,cmdextendedroomdesc:187,cmdextendedroomdetail:187,cmdextendedroomgametim:187,cmdextendedroomlook:187,cmdfeint:116,cmdfight:[217,218,219,220,221],cmdfind:159,cmdfinish:179,cmdforc:157,cmdget:[25,165],cmdgetinput:328,cmdgetweapon:232,cmdgive:[165,182],cmdgmsheet:58,cmdgrapevine2chan:164,cmdhandler:[31,33,83,89,141,142,144,149,151,152,153,154,156,167,168,170,174,187,203,233,246,247,256,344],cmdhelp:[116,166,217,218,219,220,221],cmdhit:116,cmdhome:165,cmdic:156,cmdid:272,cmdinsid:121,cmdinterrupt:170,cmdinventori:[82,165,182],cmdirc2chan:164,cmdircstatu:164,cmdlaunch:21,cmdlearnspel:220,cmdleavetrain:121,cmdlen:[151,168],cmdlight:232,cmdline:267,cmdlineinput:326,cmdlink:159,cmdlistarmedpuzzl:203,cmdlistcmdset:159,cmdlisthangout:119,cmdlistpuzzlerecip:203,cmdlock:159,cmdlook:[30,127,165,181,187,233],cmdlookbridg:233,cmdlookdark:233,cmdmail:199,cmdmailcharact:199,cmdmakegm:58,cmdmask:206,cmdmobonoff:231,cmdmore:329,cmdmorelook:329,cmdmultidesc:[57,202],cmdmvattr:159,cmdmycmd:[56,68],cmdname2:151,cmdname3:151,cmdname:[40,59,74,83,88,123,137,150,151,154,159,167,168,170,272,295,296,308],cmdnamecolor:215,cmdnewpassword:157,cmdnick:165,cmdnoinput:180,cmdnomatch:180,cmdnpc:123,cmdnudg:224,cmdobj:[150,151,168,170],cmdobj_kei:150,cmdobject:[150,151,169],cmdoffer:179,cmdooc:156,cmdooccharactercr:181,cmdooclook:[156,181],cmdopen:[159,212],cmdopenclosedoor:212,cmdopenlid:224,cmdoption:156,cmdpage:164,cmdparri:116,cmdparser:[104,141,142,149],cmdpass:[217,218,219,220,221],cmdpassword:156,cmdperm:157,cmdplant:234,cmdpoke:119,cmdpose:[116,165,206],cmdpressbutton:232,cmdpush:224,cmdpy:169,cmdquell:156,cmdquit:156,cmdread:232,cmdrecog:206,cmdreload:169,cmdremov:182,cmdreset:169,cmdrest:[217,218,219,220,221],cmdroll:91,cmdrss2chan:164,cmdsai:[116,165,206],cmdsaveyesno:326,cmdscript:[159,169],cmdsdesc:206,cmdser:328,cmdserverload:169,cmdservic:169,cmdsession:156,cmdset:[2,7,14,21,22,25,31,33,34,40,41,42,44,47,51,53,57,60,62,68,69,81,82,85,89,96,97,105,116,121,123,141,142,144,149,150,151,153,154,159,160,161,162,163,166,167,168,169,170,174,179,180,181,182,185,187,189,193,199,203,206,213,214,217,218,219,220,221,224,227,230,231,232,233,234,241,246,247,256,298,305,306,318,326,328,329],cmdset_account:[2,141,142,149,155,181],cmdset_charact:[5,96,141,142,149,155,182,217,218,219,220,221],cmdset_mergetyp:[51,188,230,249,328],cmdset_prior:[51,188,230,249,328],cmdset_red_button:[141,142,178,222],cmdset_sess:[105,141,142,149,155],cmdset_stack:153,cmdset_storag:[148,246,306],cmdset_trad:179,cmdset_unloggedin:[33,141,142,149,155,186],cmdsetattribut:159,cmdsetclimb:232,cmdsetcrumblingwal:232,cmdsetdesc:165,cmdsetevenniaintro:233,cmdsethandl:[105,141,142,149],cmdsethelp:166,cmdsethom:159,cmdsetkei:31,cmdsetkeystr:152,cmdsetlight:232,cmdsetmor:329,cmdsetobj:[152,153,160,161,162,163,179,180,181,182,185,187,203,206,214,217,218,219,220,221,224,230,231,232,233,326,328,329],cmdsetobjalia:159,cmdsetpow:123,cmdsetread:232,cmdsetspe:213,cmdsettestattr:50,cmdsettrad:179,cmdsettrain:121,cmdsetweapon:232,cmdsetweaponrack:232,cmdsheet:58,cmdshiftroot:232,cmdshoot:[21,221],cmdshutdown:169,cmdsmashglass:224,cmdsmile:33,cmdspawn:159,cmdspellfirestorm:28,cmdstatu:[179,220,221],cmdstop:213,cmdstring:[33,58,150,154,167,168,170],cmdstyle:156,cmdtag:159,cmdtalk:214,cmdteleport:159,cmdtest:[29,42,91],cmdtestid:33,cmdtestinput:51,cmdtestmenu:[51,188,328],cmdtime:[62,169],cmdtrade:179,cmdtradebas:179,cmdtradehelp:179,cmdtunnel:159,cmdtutori:233,cmdtutorialgiveup:233,cmdtutoriallook:233,cmdtutorialsetdetail:233,cmdtweet:71,cmdtypeclass:159,cmdunban:157,cmdunconnectedconnect:[171,186],cmdunconnectedcr:[171,186],cmdunconnectedhelp:[171,186],cmdunconnectedlook:[171,186],cmdunconnectedquit:[171,186],cmduncov:182,cmdunlink:159,cmdunwield:218,cmduse:219,cmdusepuzzlepart:203,cmdwait:33,cmdwall:157,cmdwear:182,cmdwerewolf:25,cmdwest:233,cmdwhisper:165,cmdwho:156,cmdwield:218,cmdwipe:159,cmdwithdraw:221,cmset:153,cmsg:[43,164],cmud:24,cnf:[23,36],cnt:119,coast:[111,122],coastal:111,cockpit:21,code:[0,1,2,4,5,6,7,9,10,11,12,14,15,16,18,19,20,29,31,33,34,36,37,39,40,43,45,46,47,48,49,51,53,55,56,57,58,62,63,64,68,69,70,76,77,79,80,83,84,86,88,89,91,93,95,96,97,98,100,102,103,104,105,106,109,110,111,112,114,115,116,117,118,119,121,122,123,125,126,127,129,132,134,135,136,139,141,142,144,149,150,153,156,158,159,164,169,172,178,179,180,184,185,190,192,195,204,219,233,234,242,252,256,278,279,295,306,309,318,320,321,326,328,330,341,342,343,344,362,363,364],code_exec:322,codebas:[55,56,127,129,131,139,140,170],codeblock:[38,322],codec:321,codefunc:326,coder:[22,26,56,61,79,96,124,150,247,363],codestyl:37,coerc:339,coexist:126,coin:[61,70,179],col:[3,16,329,330],cold:[12,43,110,169,252,257,261,305],cole:344,collabor:[4,61,64,90,131,166],collat:[83,251],collect:[11,26,31,136,150,152,203,259,344],collector:136,collectstat:[136,137,267,271],collid:[31,54,90,328],collis:[31,131],colon:[27,41,60,80,95,242],color:[16,18,20,33,38,49,51,53,58,59,63,69,74,79,95,109,111,114,124,129,137,139,154,156,183,190,206,215,230,234,251,272,279,287,295,296,321,330,336,338,343,345,364],color_ansi_bright_bg_extra_map:183,color_ansi_bright_bgs_extra_map:183,color_ansi_extra_map:183,color_markup:[141,142,178],color_no_default:183,color_typ:321,color_xterm256_extra_bg:183,color_xterm256_extra_fg:183,color_xterm256_extra_gbg:183,color_xterm256_extra_gfg:183,colorablecharact:81,colorback:343,colorcod:343,colour:[27,43,55,139,159,321,330],column:[16,38,46,49,58,64,69,86,111,137,154,156,235,329,330,344],com:[8,9,22,23,37,38,43,45,54,55,63,67,70,75,79,90,95,98,100,103,104,108,128,130,131,133,135,138,141,164,180,186,279,295,312,330,343,344,357],comb:1,combat:[11,14,25,28,31,46,55,63,64,73,79,102,108,109,111,117,122,124,125,131,139,153,217,218,219,220,221,231,256,364],combat_:[217,218,219,220,221],combat_cleanup:[217,218,219,220,221],combat_cmdset:116,combat_handl:116,combat_handler_:116,combat_movesleft:[217,218,219,220],combat_scor:123,combat_status_messag:221,combatcmdset:116,combathandl:116,combatscor:123,combatt:11,combin:[8,11,12,20,27,28,30,31,33,34,41,43,55,57,58,84,90,109,112,114,115,118,119,121,127,150,151,152,159,175,202,203,205,226,242,251,261,267,317,319,324,338,344],combo:105,come:[0,2,3,4,6,10,11,15,16,20,21,23,25,27,29,33,34,40,46,49,51,52,55,57,58,61,62,64,69,73,80,83,85,88,91,93,100,105,111,114,116,118,119,121,123,124,126,129,131,133,134,135,137,144,152,187,204,217,218,219,220,221,251,252,285,295,296,298,304,321,329,362],comet:[40,55,137,296],comfort:[15,55,69,91,131],comlist:[43,164],comm:[33,34,41,47,53,64,68,71,141,142,149,155,324,362],comma:[20,43,46,86,95,114,134,159,167,168,198,199,242,247,336],command:[0,2,4,6,8,9,10,11,12,13,15,18,19,20,21,23,24,26,27,34,36,38,40,46,47,48,49,50,51,52,55,56,57,59,61,63,64,65,66,69,72,74,75,76,77,79,80,82,83,86,87,89,90,92,93,95,96,98,102,103,104,105,106,108,109,110,111,112,113,114,117,118,119,120,122,124,125,126,128,129,130,131,136,137,138,139,140,141,142,144,146,174,175,178,179,180,181,182,185,186,187,188,189,191,194,196,199,202,203,206,210,212,213,214,215,217,218,219,220,221,224,226,227,230,231,232,233,234,235,236,239,241,242,247,251,252,256,264,267,272,276,277,285,287,295,296,298,299,305,306,318,320,321,324,326,328,329,338,341,344,362,364],command_default_arg_regex:33,command_default_class:25,command_pars:151,commandhandl:[74,153,168],commandmeta:154,commandnam:[33,74,83,234,267,276,306,308],commandset:[5,80,89,153,181],commandtest:[127,170,196],comment:[8,9,13,14,24,25,37,41,48,51,60,90,96,118,125,138,322,328],commerc:79,commerci:[90,106],commerror:176,commit:[15,23,25,36,37,38,64,66,98,100,108,128,130,209,315],commmand:[212,217,218,219,220,221],common:[1,6,10,12,15,16,20,26,27,30,33,38,40,41,43,51,53,59,60,61,62,63,64,68,69,73,74,79,80,83,88,90,91,97,105,107,109,112,113,115,116,119,123,124,125,131,133,139,152,159,179,205,206,213,242,256,295,299,317,327,329,339,341,344,350,362],commonli:[23,63,64,83,86,87,96,104,105,107,115,119,128,247],commonmark:38,commun:[8,22,23,33,40,41,45,47,53,55,57,60,64,70,72,79,83,88,90,91,92,103,106,113,114,137,139,161,172,174,175,176,177,199,230,246,264,276,277,287,306,308,324,325,340,364],compact:[85,134],compani:[64,88],compar:[4,9,13,15,27,28,29,31,41,44,58,73,83,85,91,97,116,119,123,127,131,136,170,203,205,217,218,219,220,221,241,242,252,321,344],comparison:[13,93,241,252,328],compartment:58,compass:20,compat:[14,21,51,159,330,337],compet:[15,88],compil:[9,33,38,47,56,63,75,76,90,95,108,159,165,166,171,174,182,206,321,326,343],compilemessag:76,complain:[42,60,86,91,110,128],complement:[26,107],complementari:113,complet:[2,10,11,13,14,15,22,23,25,27,31,33,36,37,43,44,49,50,58,59,61,62,64,67,70,77,81,85,88,89,90,95,96,102,104,105,107,109,110,111,122,123,127,128,131,139,144,152,153,154,167,169,174,183,187,188,190,195,218,233,247,260,267,269,277,278,295,322,327,328,329,336,341,344,357],complete_task:195,completli:227,complex:[11,14,15,20,31,33,51,59,61,62,64,73,76,77,86,93,96,100,104,108,111,115,116,123,127,138,153,196,204,214,252,299],complianc:[24,187],compliant:39,complic:[0,10,22,29,41,43,49,69,90,91,111,133,134,171,186,188,215],compon:[29,33,40,43,49,58,90,93,96,102,110,114,116,124,127,135,137,138,139,159,169,175,176,177,184,203,205,252,253,256,259,267,296,324,327,341,344,364],componentid:137,componentnam:137,componentst:[137,138],compos:[100,188],composit:317,comprehens:[34,55,63,80,93,96,103,124,125,127],compress:[74,272,276,340],compress_object:340,compris:144,compromis:[103,209],comput:[10,12,43,49,56,60,63,64,72,73,100,113,115,124,131,132,157,169,206,344,345],computation:115,comsystem:[164,177],con:[43,58,79,171,186],concaten:[67,321,336],concept:[11,37,38,39,40,46,57,61,69,76,77,92,96,115,124,131,139,181,202],conceptu:[49,51],concern:[25,44,63,76,88,95,96,152,204,239],conch:[287,298],conclud:[96,179,328],concurr:23,conda:9,conder:322,condit:[8,46,49,55,61,73,85,91,93,96,123,124,150,185,206,219,242,247,259,266,267,312,344],condition:25,condition_result:185,condition_tickdown:219,conditional_flush:334,conduct:136,conductor:121,conect:308,conf:[4,8,9,23,25,35,36,38,40,41,47,54,62,65,67,69,74,76,80,81,86,90,93,102,103,109,114,120,121,127,130,131,133,134,135,139,144,183,267,273,274,313,322,364],confer:[79,344],confid:[37,39,42],config:[2,4,9,36,40,59,63,90,98,103,106,130,131,137,138,139,263,267,269,273,274,285,364],config_1:2,config_2:2,config_3:2,config_color:81,config_fil:67,configcmd:81,configdict:[287,308],configur:[0,2,7,25,36,38,43,45,47,54,59,62,63,64,69,90,100,103,114,120,124,127,136,138,139,144,148,151,156,209,210,234,269,274,285,308,312,313,317,357,364],configut:106,configvalu:59,confirm:[8,33,43,63,103,137,159,186,203,362],conflict:[41,42,126],confus:[10,22,26,31,44,58,59,60,64,77,80,87,90,91,93,97,114,119,126,131,136,137,140,186,362],conid:286,conjur:220,conn:[43,171,186],conn_tim:105,connect:[0,2,4,7,8,9,11,12,13,17,18,23,24,25,31,33,34,40,41,46,47,49,55,57,60,63,64,65,66,67,69,72,74,76,77,80,83,85,88,89,91,92,93,96,98,100,101,102,103,104,105,107,110,111,114,120,123,125,126,127,136,137,139,144,146,148,156,157,159,164,171,175,177,186,190,192,193,195,210,213,246,247,253,262,264,267,269,276,277,278,279,285,286,287,295,296,298,299,305,306,307,308,309,312,316,318,324,340,364],connection_cr:107,connection_screen:[35,104],connection_screen_modul:186,connection_set:54,connection_tim:[144,247],connection_wizard:[141,142,262],connectiondon:269,connectionlost:[269,276,277,287,298],connectionmad:[264,276,287,298],connectionwizard:265,connector:[264,278,279,285,308],consecut:51,consequ:[90,153],consid:[0,4,10,12,13,14,23,26,27,31,33,37,39,40,44,46,51,55,57,61,63,64,70,74,78,80,82,85,86,90,93,96,97,102,103,105,109,112,113,114,115,119,121,125,131,133,134,135,144,152,153,188,203,205,206,221,234,247,252,256,272,287,317,322,323,328,329],consider:[68,86,104,111,118,241,252],consist:[2,11,17,33,38,44,46,48,51,68,80,86,92,95,96,109,110,114,116,122,123,135,137,144,151,167,176,179,203,205,236,242,250,252,296,306,315,316,318,324,330,344,362],consol:[9,19,23,26,38,42,43,60,63,64,75,83,90,93,95,96,97,100,106,114,123,137,138,169,206,267],conson:205,constant:[0,88,276,342],constantli:[96,117,233],constitu:[153,167,168],constraint:[0,23],construct:[20,29,34,36,51,64,119,133,138,252,311,321,329,357],constructor:[22,33,180,278],consum:[10,269,344],consumer_kei:[71,120],consumer_secret:[71,120],consumpt:[23,310],contact:[89,90,100],contain:[0,5,7,9,10,11,13,14,16,17,18,20,21,22,25,26,31,33,34,37,38,39,40,41,43,46,47,51,53,55,56,57,62,63,64,68,69,70,75,79,80,86,89,91,95,96,97,101,102,104,105,114,118,119,122,123,124,126,127,128,129,133,134,136,137,138,139,141,142,144,146,149,150,151,152,153,155,158,159,166,172,180,188,189,192,193,194,195,196,198,203,204,205,206,210,211,213,215,219,224,232,234,235,238,240,247,249,250,251,252,260,262,266,270,272,298,311,312,316,317,318,319,320,321,322,325,327,328,329,330,341,343,344,345,355,362,363],container:100,contempl:56,content:[3,4,13,16,17,21,27,38,39,43,48,49,51,56,58,69,77,79,82,85,89,90,91,93,95,96,117,119,121,123,125,131,133,134,137,138,139,154,157,159,206,246,247,306,315,316,319,321,322,323,326,328,330,341,346,355],contentof:330,contents_cach:246,contents_get:[119,247],contents_set:247,contentshandl:246,context:[46,51,55,69,91,114,119,126,133,180,195,350,362],contextu:112,continu:[7,10,11,21,27,29,33,37,42,45,46,49,51,55,58,60,69,71,75,85,86,90,95,96,112,114,115,116,119,123,124,127,136,139,265,276,312,316,328,337,344,364],contrari:[0,38,41,43,62,169,319],contrast:[56,90,96,113,138],contrib:[4,13,14,20,38,47,53,57,58,62,63,64,73,78,102,116,122,141,142,144,145,148,173,237,244,254,263,309,315,322,349,357,362,364],contribrpcharact:206,contribrpobject:206,contribrproom:206,contribut:[1,4,22,26,45,55,70,78,82,124,127,131,136,139,178,179,181,182,183,185,187,199,203,204,206,209,210,212,213,214,234,363,364],contributor:[78,180],control:[2,5,7,9,11,12,13,14,19,20,21,31,33,34,36,37,38,42,43,47,50,51,52,53,55,57,58,61,63,64,67,68,73,74,80,81,83,86,89,90,92,93,96,102,103,105,108,109,110,114,118,121,123,124,128,135,138,139,144,146,156,158,159,164,179,181,194,206,227,231,233,235,241,247,256,267,306,308,318,328,357,364],convei:[206,247],convenei:107,conveni:[8,9,10,11,21,34,36,40,41,43,51,55,57,59,69,74,80,86,89,96,98,102,106,108,109,110,125,127,133,140,144,159,169,180,199,247,310,322,323,328,329,337,340,341],convent:[0,31,86,96,107,119,126],convention:[41,154,174,247,318],convers:[51,87,121,127,138,205,214,295,296,321,344,363],convert:[11,27,39,40,49,51,59,62,64,79,81,83,85,87,88,103,109,113,114,119,126,128,157,184,185,188,215,241,251,252,257,276,278,287,308,312,321,325,328,329,330,331,336,340,343,344,363],convert_linebreak:343,convert_url:343,convinc:[51,90],cool:[3,9,21,22,26,38,43,61,79,159],cool_gui:80,cooldown:[29,116,124,139,364],coord:39,coordi:39,coordin:[49,124,137,139,221,235,364],coordx:39,coordz:39,cope:220,copi:[0,1,4,13,14,20,25,26,33,36,47,48,50,51,62,64,81,90,93,96,100,104,105,109,111,123,128,131,133,135,136,137,138,158,159,182,195,217,218,219,220,221,233,247,267,276,313,321,337,362],copy_object:247,copyright:[78,90],cor:138,core:[19,37,43,47,49,76,78,88,89,96,104,106,125,127,131,139,144,148,169,177,178,199,239,241,246,247,256,262,274,305,316,318,319,322,329,335,357,362],corner:[17,39,57,79,138,235,330],corner_bottom_left_char:330,corner_bottom_right_char:330,corner_char:330,corner_top_left_char:330,corner_top_right_char:330,corpu:205,correct:[10,11,14,21,23,27,30,31,33,37,43,48,50,60,80,91,113,114,121,123,126,150,156,159,176,187,203,228,242,285,287,307,321,344],correctli:[4,8,9,27,29,33,36,38,42,44,49,50,51,61,62,72,77,80,85,90,91,97,110,112,115,121,122,123,126,144,148,153,156,257,276,312,340],correl:252,correspond:[20,33,80,83,85,105,135,184,203,215,315,357],correspondingli:128,corrupt:56,cosi:111,cosin:344,cosmet:235,cost:[28,85,90,220,235],cottag:[111,114],could:[0,1,2,3,4,5,6,9,10,11,12,13,14,15,19,20,21,22,25,28,29,30,31,33,34,36,37,38,39,40,41,42,43,44,46,47,48,49,51,55,57,58,60,61,62,63,64,65,68,69,71,72,73,79,80,81,82,83,84,85,86,87,88,89,90,91,93,95,96,98,102,106,108,109,111,112,113,114,115,116,117,118,119,120,121,123,125,126,127,128,129,132,133,135,136,138,140,144,153,159,166,176,177,179,180,185,190,198,204,206,213,215,233,235,241,242,247,272,296,312,318,321,322,326,330,331,334,339,344],couldn:[11,19,39,44,64,76,91,126,134,140,204],count:[64,102,104,116,119,120,152,182,215,219,247,259,285,298,302,308,310,317,321,328,337,344],count_loggedin:285,count_queri:302,countdown:[20,29],counter:[6,22,29,69,85,105,116,128,146,233,285,298,299,306,328],counterpart:[13,114,272,308,325],countless:95,countnod:51,countri:[43,157],coupl:[22,48,69,100,117,131,213],cours:[0,4,9,12,15,21,22,26,33,38,41,46,57,61,64,77,78,91,93,106,108,114,115,122,123,124,132,140,218,221,230],courtesi:12,cousin:[91,129],cover:[6,8,9,13,14,23,29,37,40,48,51,57,59,63,79,80,86,90,95,96,120,127,131,182,187,233,247,324,344,363],coverag:127,coveral:127,cpanel:90,cpattr:159,cpu:[12,43,90,103,169],cpython:93,crack:[61,86],craft:[29,80,111,188],crank:[115,258],crash:[26,60,61,79,103,111,271],crate:[20,87,124],crawl:103,cre:[43,171,186],creat:[4,9,11,13,14,15,16,19,22,23,25,26,29,31,34,35,37,38,39,40,41,42,44,46,47,49,50,54,55,56,57,58,60,61,62,63,64,65,66,67,68,70,71,72,73,75,76,77,78,79,80,81,83,85,87,90,91,93,95,96,102,103,104,105,106,107,108,109,112,116,117,118,119,120,122,124,127,129,130,131,132,134,135,136,137,138,139,140,141,142,144,145,146,148,150,151,152,153,154,156,159,164,165,166,167,168,170,171,174,175,177,179,180,181,182,184,185,186,187,188,189,194,195,196,198,199,202,203,204,205,206,210,212,214,215,217,218,219,220,221,223,224,226,227,230,231,232,233,234,235,239,242,244,246,247,249,250,251,252,256,259,260,261,264,267,271,272,277,279,285,287,299,307,308,312,316,317,318,319,320,322,323,326,327,328,330,331,336,337,344,360,362,363],create_:[89,125],create_account:[107,125,141,324],create_cal:144,create_channel:[34,141,174,175,271,324],create_charact:[144,247],create_delai:260,create_exit:[159,212],create_exit_cmdset:247,create_forward_many_to_many_manag:[148,177,239,246,256,316,318,319,335],create_game_directori:267,create_grid:49,create_help_entri:[68,141,324],create_kwarg:252,create_match:151,create_messag:[34,141,324],create_object:[13,27,80,85,89,111,123,125,133,141,247,252,271,322,324],create_prototyp:[251,252],create_script:[56,102,116,125,141,259,322,324],create_secret_kei:267,create_settings_fil:267,create_superus:267,create_tag:317,create_wild:235,created_on:192,creater:53,createview:362,creation:[11,14,20,21,38,43,47,49,51,58,60,61,79,80,81,86,89,97,105,111,123,125,131,133,139,140,141,144,145,148,159,166,175,181,203,206,210,212,217,218,219,220,221,232,233,239,244,246,252,256,261,300,315,318,324,326,327,328,330,357,362,363],creation_:324,creativ:[79,108],creator:[51,53,79,80,111,123,140,166,175,217,218,219,220,221,247,330],cred:[131,287],credenti:[90,103,131,144,287],credentialinterfac:287,credit:[90,103,131,343,344],creset:131,crew:119,criteria:[51,119,176,194,204,251,317,341],criterion:[119,131,144,179,206,238,247,258,341,344],critic:[19,26,31,60,63,67,97,102,105,114,128,242,266,267,337],critici:318,cron:67,crontab:67,crop:[58,114,159,327,330,336,344],crop_str:330,cross:[111,138,233,330],crossbario:295,crossbow:29,crossroad:111,crowd:[61,103],crt:[8,67],crucial:[91,115],crude:0,cruft:1,crumblingwal:232,crumblingwall_cmdset:232,crush:21,cryptic:138,cryptocurr:103,cscore:123,csessid:[285,295,296,308],csession:[295,296],csrf_token:133,css:[17,55,124,135,136,137,343],cssclass:137,ctrl:[48,63,67,90,93,95,100,110,298],culpa:52,cumbersom:[51,121,128,215],cumul:299,cup:70,cupidatat:52,cur_valu:190,cure:[219,220],cure_condit:219,curi:49,curiou:108,curli:[41,96,183],curly_color_ansi_bright_bg_extra_map:183,curly_color_ansi_bright_bgs_extra_map:183,curly_color_ansi_extra_map:183,curly_color_xterm256_extra_bg:183,curly_color_xterm256_extra_fg:183,curly_color_xterm256_extra_gbg:183,curly_color_xterm256_extra_gfg:183,curr_sess:308,curr_tim:187,currenc:[85,120],current:[0,2,9,11,12,13,14,19,20,21,22,25,27,28,29,31,33,38,41,43,46,48,49,50,51,58,59,60,64,68,74,76,77,79,80,85,86,89,97,100,102,104,105,106,112,114,115,116,119,120,121,123,124,127,128,131,133,137,138,144,148,150,151,153,154,156,157,159,164,165,166,168,169,175,179,180,182,187,188,190,195,198,202,204,206,212,213,215,217,218,219,220,221,230,232,233,235,238,246,247,252,256,260,261,267,272,277,287,299,306,308,310,317,318,326,328,330,331,337,338,341,344,362],current_choic:180,current_cmdset:159,current_coordin:235,current_kei:[250,251],current_us:133,current_weath:102,currentroom:121,curriculum:79,curs:42,curv:[55,56],curx:49,custom:[0,2,6,11,12,14,15,16,17,18,20,21,25,26,27,30,31,33,34,35,43,49,53,55,56,58,60,61,64,65,66,68,69,71,73,74,78,79,83,85,86,87,89,90,97,100,102,104,109,110,112,114,116,117,118,119,121,122,123,125,126,132,133,136,138,139,140,144,145,146,147,148,150,152,153,154,159,164,165,166,174,175,179,181,182,184,185,187,188,189,195,198,203,205,206,209,210,230,232,233,235,238,241,245,247,249,250,251,252,255,261,263,267,271,273,276,298,307,318,323,328,329,330,334,336,338,339,343,344,349,362,364],custom_add:195,custom_cal:[195,198],custom_gametim:[62,141,142,178],custom_kei:251,custom_pattern:[3,4,69,133,134],customfunc:83,customis:235,customiz:[17,41,180,188,190,206],customlog:8,cut:[20,40,49,50,55,91,111,123,252],cute:136,cutoff:344,cvcc:205,cvccv:205,cvccvcv:205,cvcvcc:205,cvcvccc:205,cvcvccvv:205,cvcvcvcvv:205,cvcvvcvvcc:205,cvv:205,cvvc:205,cwho:164,cyan:[114,126],cyberspac:79,cycl:[13,14,25,56,61,62,132,217,218,219,220,221],cyril:15,daemon:[8,67,93,100,103,110,312],dai:[25,27,36,56,61,62,100,103,108,120,126,131,132,139,184,187,331,337,344,345],daili:87,dailylogfil:337,dali:205,dalnet:[43,164],dam:56,damag:[14,21,28,61,73,85,103,116,122,217,218,219,220,221,231,232],damage_rang:220,damage_taken:56,damage_valu:[217,218,219,220,221],damnedscholar:48,dandi:140,danger:[13,31,38,82,97,105,152],dare:33,dark:[13,14,17,31,73,79,111,114,122,126,153,187,224,233,241,256,322],darkcmdset:233,darker:[114,126],darkgrai:126,darkroom:233,darkroom_cmdset:233,darkstat:233,dash:[38,119,204,215],dashcount:215,data:[2,10,13,15,22,23,25,27,43,56,57,58,59,61,64,75,83,86,87,88,90,93,96,97,100,102,104,109,112,113,119,125,128,133,134,135,137,138,139,144,145,146,154,159,169,175,188,190,194,195,206,209,210,237,244,246,247,249,253,259,261,264,265,269,273,274,276,277,278,279,285,286,287,295,296,298,299,300,305,306,307,308,314,315,316,317,318,319,321,322,323,324,325,327,328,329,330,333,337,338,339,340,357,362],data_in:[40,83,210,276,278,279,285,286,295,296,306,307,308],data_out:[40,210,285,287,296,306,307,308],data_to_port:264,data_to_serv:277,databa:267,databas:[0,4,5,6,7,11,12,13,15,17,19,20,21,23,25,27,28,29,31,34,36,38,39,43,45,47,55,56,57,58,59,60,61,63,64,74,77,80,84,87,89,91,93,100,101,102,104,105,107,110,111,112,115,116,119,123,124,125,127,131,133,134,135,136,138,139,140,144,148,152,153,159,166,169,173,174,175,176,177,187,194,195,206,220,233,236,238,239,241,244,246,247,250,251,253,254,256,257,260,261,267,271,273,298,305,306,314,315,316,317,318,319,322,324,325,326,329,332,334,340,341,344,346],datareceiv:[269,276,298],dataset:251,datastor:86,datbas:119,date:[7,11,12,23,34,49,62,68,75,76,86,126,128,131,133,138,145,153,157,209,331,337,345],date_appli:133,date_cr:[125,144,148,177,256,316,318],date_join:[145,148],date_s:34,datetim:[62,125,133,316,331,337,338,344,345],datetime_format:344,datetimefield:[86,133,145,148,177,246,256,316,318,344],david:79,day_rot:337,db3:[23,111,128,131],db_:[84,86,119,125,206,247,257,272,341],db_account:[182,244,246,256],db_account__db_kei:244,db_account_id:[246,256],db_account_subscript:[173,177],db_attribut:[107,119,145,148,177,244,246,256,318],db_attrtyp:316,db_attryp:87,db_categori:[86,315,316,319],db_category__iequ:86,db_channel:173,db_cmdset_storag:[145,148,182,244,246],db_data:[315,319],db_date_cr:[86,148,173,177,182,246,256,316,318],db_desc:256,db_destin:[182,244,246],db_destination__isnul:120,db_destination_id:246,db_entrytext:[237,239],db_header:177,db_help_categori:[237,239],db_hide_from_account:177,db_hide_from_channel:177,db_hide_from_object:177,db_hide_from_receiv:177,db_hide_from_send:177,db_home:[182,244,246],db_home_id:246,db_index:86,db_interv:[254,256],db_is_act:256,db_is_bot:[145,148],db_is_connect:[145,148],db_kei:[69,84,86,119,125,145,173,182,194,237,239,244,254,257,263,274,315,316,318,319,357],db_key__contain:125,db_key__icontain:86,db_key__istartswith:119,db_key__startswith:[119,125],db_locat:[84,119,182,244,246],db_location__db_tags__db_kei:119,db_location__isnul:120,db_location_id:246,db_lock_storag:[145,173,177,182,237,239,244,316,318],db_messag:[173,177],db_model:[316,319],db_obj:[254,256,325],db_obj_id:256,db_object_subscript:[173,177],db_permiss:[86,145],db_persist:[254,256],db_properti:272,db_protototyp:251,db_receiv:173,db_receivers_account:177,db_receivers_channel:177,db_receivers_object:177,db_receivers_script:177,db_repeat:[254,256],db_sender:173,db_sender_account:177,db_sender_extern:177,db_sender_object:177,db_sender_script:177,db_sessid:[182,244,246],db_staff_onli:[237,239],db_start_delai:[254,256],db_strvalu:316,db_tag:[119,145,148,177,237,239,244,246,256,318,319],db_tags__db_categori:[39,119],db_tags__db_kei:[39,119,173],db_tags__db_key__in:39,db_tagtyp:[315,319],db_text:86,db_typeclass_path:[86,120,145,182,244,246,254,318,344],db_valu:[84,263,274,316],dbef:341,dbhandler:357,dbid:[43,125,146,164,318],dbid_to_obj:344,dbmodel:317,dbobj:[11,316],dbobject:[11,317,318],dbprototyp:[169,251],dbref:[12,13,20,43,58,66,80,109,111,116,119,121,122,125,128,144,148,157,159,164,169,176,188,203,206,212,233,235,241,246,247,250,251,252,256,258,317,318,324,341,344],dbref_search:317,dbref_to_obj:344,dbrefmax:[43,159],dbrefmin:[43,159],dbsafe_decod:340,dbsafe_encod:340,dbserial:[11,97,141,142,257,320],dbshell:[23,86,110,128],dbunseri:325,ddesc:56,deactiv:[43,63,64,81,117,164,187,227,231,328],deactivatebuttonev:227,dead:[112,231,232,305,308,334],deadli:122,deal:[10,11,12,15,41,51,64,69,73,91,103,105,112,113,116,124,126,127,131,134,138,139,144,179,180,184,188,217,218,219,220,221,246,247,306,318,321,338,362],dealt:[167,168,219,220],dealth:219,death:[51,73,120],death_msg:231,death_pac:231,debat:91,debian:[8,23,63,67,131],debug:[14,27,43,45,51,59,72,74,91,95,102,106,135,139,150,154,158,169,188,230,249,267,272,278,279,312,322,328,337,344,364],debugg:[15,42,110,141],decemb:90,decend:[51,150],decent:[93,205],decic:205,decid:[4,14,15,25,33,41,46,58,61,69,73,85,86,88,90,103,105,112,114,116,126,138,150,179,217,242,329],deciph:48,decis:[73,115],declar:[114,340],declared_field:[145,237,244,315,357],declin:[51,179],decod:[15,321,344],decoded_text:344,decompos:133,decompress:[276,340],deconstruct:[122,228,342],decor:[0,29,33,46,107,131,148,246,256,264,276,277,318,324,328,329,344],decoupl:[9,251],decoupled_mut:11,decreas:[220,233,326],decrease_ind:326,dedent:[50,344],dedic:[73,90,127],deduc:326,deduce_ind:326,deduct:[73,85,217,218,219,220,221],deem:[37,57,129,131,178,362],deep:79,deeper:[41,215],deepest:159,deepli:11,deepsiz:344,def:[1,3,4,5,6,10,11,21,22,25,27,28,29,30,31,33,38,39,40,41,42,44,48,49,50,51,56,57,58,60,62,69,71,73,74,79,80,81,82,84,85,89,91,95,96,102,107,109,111,114,116,117,118,119,120,121,123,125,127,132,133,134,180,187,234,235,250,296,309,328,329,336,344],def_down_mod:219,defalt_cmdset:71,default_access:[1,11,316,324],default_categori:238,default_channel:34,default_charact:189,default_cmd:[5,21,22,25,28,29,30,41,44,53,57,58,62,81,116,119,141,180,182,187,199],default_cmdset:[5,22,25,30,35,41,44,57,58,60,62,81,105,123,153,180,181,182,187,188,202,212,215,217,218,219,220,221],default_command:25,default_confirm:[159,203],default_error_messag:340,default_hom:[59,109],default_in:137,default_out:137,default_pass:324,default_screen_width:33,default_set:[3,127],default_transaction_isol:23,default_unload:137,defaultaccount:[2,41,43,53,64,125,141,144,146,160,247,342,357,362],defaultchannel:[6,53,125,141,175,362],defaultcharact:[5,6,22,25,43,53,57,58,60,62,73,81,86,89,96,123,125,127,141,144,161,180,182,189,206,217,218,219,220,221,247,342,357,362],defaultcmdset:[185,224],defaultdict:257,defaultexit:[6,53,85,89,125,141,212,213,232,235,247,342],defaultguest:[53,141],defaultlock:241,defaultmod:337,defaultobject:[5,6,26,53,60,64,82,85,86,89,96,111,117,119,121,125,141,144,182,206,214,218,221,226,232,247,318,342,357,362],defaultpath:344,defaultroom:[6,39,49,53,56,85,89,125,132,141,187,206,233,235,247,342],defaultscript:[53,56,102,116,120,121,125,141,146,179,184,195,203,204,205,217,218,219,220,221,223,227,235,251,258,259,300,331,342],defaultsess:[43,162],defaulttyp:312,defaultunloggedin:[43,163],defeat:[73,116,122,217,218,219,220,221,231],defeat_msg:231,defeat_msg_room:231,defend:[51,116,122,217,218,219,220,221,232,247],defens:[116,217,218,219,220,221],defense_valu:[217,218,219,220,221],defer:[10,27,29,33,133,145,148,150,177,187,213,239,246,247,256,260,264,274,276,277,308,312,316,318,319,335,337],deferredlist:312,defin:[0,2,4,5,10,11,12,13,14,20,21,22,25,27,30,35,36,38,40,42,43,44,46,49,50,53,55,56,57,58,59,61,62,64,68,69,73,74,77,78,81,83,85,88,89,91,95,96,97,104,106,109,111,113,114,115,117,119,121,123,125,126,127,129,133,135,136,137,138,139,141,143,145,148,150,152,153,154,156,159,165,167,168,169,170,173,175,176,177,180,182,183,184,185,187,188,194,195,198,203,204,205,206,214,215,219,220,223,224,227,232,233,236,237,238,239,240,241,242,243,244,246,247,251,252,256,259,261,262,264,267,274,277,298,299,306,307,308,311,314,316,317,318,319,321,322,323,326,328,331,335,336,339,341,344,346,357,362],define_charact:51,definit:[0,2,5,10,12,14,20,33,34,39,41,42,43,55,60,61,68,69,82,83,87,88,89,109,114,115,124,127,152,154,159,164,167,168,192,203,226,232,240,242,246,251,252,258,322,324,328,336,340],defit:51,deflist:312,degrad:127,degre:38,deindent:344,del:[11,12,29,43,58,80,116,122,157,159,187,202,203,250,318],del_callback:[193,195],del_detail:187,del_pid:267,delai:[0,28,33,45,120,184,188,195,213,232,260,261,279,285,308,323,344],delaliaschan:[43,164],delayed_import:308,delchanalia:[43,164],delcom:[58,164],deleg:[148,177,239,246,256,316,318,319,335],delet:[2,4,7,11,12,13,20,22,23,31,43,50,51,63,66,68,80,87,89,98,100,102,105,107,111,112,116,122,128,131,144,153,156,157,158,159,164,165,166,169,174,175,177,187,192,193,195,196,199,202,203,212,227,232,239,242,247,251,257,258,259,260,261,273,285,306,315,316,318,321,322,328,334,360,362],delete_default:[31,153],delete_prototyp:251,deletet:187,deleteview:362,deliber:[11,42,129],delic:182,delimit:[91,167,168,322],delin:48,deliv:[90,199,206],delpart:203,delresult:203,deltatim:344,delux:90,demand:[30,58,61,73,90,115,117,144,175,187,247,309,323],demo:[22,55,79,138,229,230,328],democommandsetcomm:230,democommandsethelp:230,democommandsetroom:230,demon:109,demonin:344,demonstr:[0,4,22,126,133,180,188,209,219],demowiki:4,deni:[8,103,194,198],denot:[56,114,134,322],denounc:327,depart:49,depend:[0,4,10,11,12,14,15,16,22,27,31,33,34,37,40,43,46,49,51,55,57,58,61,63,64,69,72,73,74,75,83,85,88,90,93,95,97,100,102,103,104,105,106,111,114,115,116,118,123,125,131,133,134,137,138,143,150,152,154,156,169,175,180,181,185,187,193,205,235,242,247,251,259,261,267,287,296,298,306,308,316,318,319,326,328,329,344],deplet:219,deploi:[38,46,90,103],deploy:[36,38,79,90,100,106],depmsg:337,deprec:[27,51,94,109,141,142,252,262,328,337,344],deprecationwarn:266,depreci:321,depth:[16,17,36,95,114,122,124,215,252],dequ:[11,310],deriv:[23,56,63,67,100,108,119,125,127,234,321,345],desc:[14,20,21,22,34,41,57,58,60,69,74,80,84,85,89,102,109,111,116,120,134,153,156,159,170,180,182,187,202,203,212,215,220,235,256,265,322,324,327,328,357,362],desc_al:231,desc_dead:231,desc_lamp_broken:226,desc_lid_clos:226,desc_lid_open:226,descend:[119,357],describ:[5,9,11,13,14,20,21,22,30,31,33,37,43,46,51,55,58,62,63,64,68,69,71,75,76,79,80,85,86,88,90,92,96,102,109,110,111,113,114,116,124,125,127,128,131,133,135,137,139,152,159,163,164,165,177,182,184,187,204,206,220,226,244,252,259,264,285,287,300,328,343,344,363],descripion:231,descript:[0,14,15,20,21,22,34,39,41,43,46,49,51,54,55,57,58,60,61,68,74,77,85,90,96,102,109,111,112,126,129,131,133,134,135,139,145,156,159,164,165,175,179,180,182,187,202,204,206,212,215,226,230,231,232,233,234,235,237,241,244,247,256,322,324,328,338,339],description_str:111,descvalidateerror:202,deseri:[11,97,338],deserunt:52,design:[14,16,23,26,33,37,39,41,55,57,61,79,89,91,108,109,111,112,117,118,119,124,129,133,138,153,159,180,194,206,209,232,247,322,338,344],desir:[1,4,27,28,29,43,49,57,58,59,91,108,112,114,115,119,121,123,133,137,159,183,205,242,267,312,324,330,345],desired_perm:242,desktop:[15,16,138],despit:[11,13,57,63,64,79,81,105,233],dest:[234,247],destin:[0,22,25,33,43,49,74,77,85,89,91,109,111,119,121,159,209,212,213,217,218,219,220,221,232,233,241,246,247,252,324,362],destinations_set:246,destroi:[0,20,89,103,116,127,146,159,164,203,219,247],destroy:212,destruct:[31,152],detach:106,detail:[2,5,9,12,15,19,20,22,26,30,33,34,37,41,46,51,58,60,61,63,64,80,88,89,90,91,93,95,96,105,109,111,114,116,118,122,124,125,128,129,131,134,135,136,139,145,153,154,159,175,180,187,203,204,206,218,233,235,239,244,251,252,260,269,270,306,308,318,321,336,344,360,362],detail_color:159,detailkei:[187,233],detailview:362,detect:[31,33,36,38,61,81,88,89,103,105,118,151,154,168,175,279],determ:317,determin:[2,4,13,15,20,27,29,31,33,34,39,43,44,49,50,51,52,63,73,80,82,83,85,87,93,102,109,110,116,123,136,137,144,145,152,153,154,156,167,173,175,179,205,206,213,215,217,218,219,220,221,232,239,242,244,247,251,316,317,318,321,326,329,344],detour:[21,83,308],dev:[1,23,37,55,57,63,64,67,71,76,79,90,95,98,138],develop:[3,9,15,16,19,20,25,26,27,33,36,37,38,42,43,48,54,55,56,58,60,61,63,64,68,70,71,72,76,77,80,86,88,90,91,93,96,97,99,104,106,108,109,111,114,123,126,131,133,135,136,137,138,139,157,158,164,169,175,192,193,198,209,227,239,247,252,313,318,322,328,363,364],devoid:321,dex:[11,51,58,327],dexter:[217,218,219,220,221],diagnos:[30,97],diagram:125,dialog:137,dialogu:[0,124,139,364],dice:[63,73,91,116,141,142,178],dicecmdset:185,dicenum:185,dicetyp:185,dict:[0,11,13,25,31,43,46,51,53,88,107,109,119,127,144,146,152,154,159,175,182,184,187,188,192,195,198,205,206,209,210,215,219,221,233,247,249,250,251,252,259,261,264,265,267,272,277,278,285,287,295,296,307,308,310,317,322,323,325,327,328,329,336,339,344,357,362],dictat:[31,62,117],dictionari:[0,10,11,13,25,31,43,49,55,56,62,69,73,80,96,97,102,109,116,124,134,138,157,159,182,184,187,188,192,195,198,205,206,209,210,211,215,219,220,233,235,242,252,260,272,285,306,307,308,310,317,321,323,327,328,334,338,339,340,344,357,362],did:[2,21,22,29,57,60,64,68,91,95,96,104,111,123,131,144,179,247,260,319,340,344],did_declin:179,didn:[5,20,22,38,41,42,44,49,51,58,59,61,72,80,91,100,104,119,121,126,127,133,136,140],die:[73,91,106,114,117,185,205,308],dies:231,diff:[75,131,185,252],differ:[0,2,8,9,11,13,14,15,16,19,20,21,22,24,25,27,31,33,37,38,39,40,41,42,43,44,46,47,49,50,51,54,55,57,58,61,62,63,64,66,68,69,70,73,79,80,82,83,84,87,88,91,93,95,96,100,102,103,105,106,107,109,110,111,112,113,114,115,116,118,119,120,121,124,126,127,129,131,133,136,137,138,139,140,141,144,145,150,152,153,156,159,168,169,171,175,180,184,185,186,195,196,199,204,206,213,215,217,218,219,220,221,224,234,235,247,249,251,252,256,259,261,265,269,296,298,315,316,318,322,324,328,337,340,344,362],differenti:[56,57,58,182,206,215,247],differet:61,difficult:[4,39,93,103,133,220,221],difficulti:133,dig:[0,20,31,33,40,57,58,89,93,96,109,121,123,140,159,212,299],digit:[12,90,114,127,204,311,321,337],digitalocean:67,diku:[55,64,124,139,364],dikumud:129,dime:108,dimens:[49,55],dimension:58,diminish:114,dimli:111,dinner:46,dip:96,dir:[9,21,23,36,38,54,58,63,64,67,75,79,90,96,100,102,127,128,130,131,134,337,344],direct:[0,3,8,10,11,12,20,22,31,38,43,44,45,49,51,58,70,74,88,90,100,109,111,116,118,119,121,128,137,138,139,159,194,210,235,242,267,328,330,337,341,344,364],directli:[2,5,8,13,14,20,21,23,27,29,30,33,37,40,42,44,46,50,51,55,56,58,59,61,62,64,72,80,88,89,90,93,95,96,100,102,104,109,110,111,114,116,118,119,123,125,128,131,137,138,154,170,175,176,179,180,181,185,198,206,215,220,221,227,233,234,238,242,246,247,251,256,273,278,287,295,300,306,316,318,322,324,328,329,342,344],director:206,directori:[4,8,9,13,20,25,27,36,37,43,45,58,59,62,63,64,69,75,76,95,96,100,106,123,125,127,128,130,131,133,134,135,136,137,139,159,209,267,287,312,322,337,344,364],directorylist:312,dirnam:267,dirti:55,disabl:[0,4,24,25,50,63,80,81,106,114,127,137,154,170,188,206,215,234,242,329,334,345],disadvantag:[58,90,116,221],disambigu:[41,72,119,154,174,247,318],disappear:103,discard:[175,321],disconcert:41,disconnect:[2,11,12,40,41,43,55,57,60,92,97,105,107,110,112,116,123,128,137,144,156,159,164,167,169,175,247,277,278,279,285,286,287,295,296,299,305,306,307,308],disconnect_al:285,disconnect_all_sess:308,disconnect_duplicate_sess:308,disconnect_session_from_account:144,discontinu:24,discord:[9,63,72,79],discordia:108,discourag:[64,75],discov:[91,122],discoveri:210,discrimin:103,discuss:[1,4,25,26,33,37,45,48,55,63,69,70,116,138,139],discworld:88,disengag:[116,144,217,218,219,220,221],disk:[11,27,86,100,108,110,205,209,249],dislik:57,disonnect:11,dispatch:37,dispel:126,displai:[0,17,22,25,30,31,33,38,42,43,46,50,51,58,59,60,61,68,69,73,80,81,82,83,85,88,89,91,93,101,102,103,104,111,114,116,119,123,124,133,134,135,136,137,138,139,145,154,156,159,166,169,171,173,175,179,180,182,186,187,188,190,193,195,199,206,215,230,232,233,234,235,237,247,251,252,254,265,267,302,305,310,318,319,326,327,328,329,330,338,339,340,343,344,345,357,362],display:261,display_buff:326,display_choic:180,display_formdata:188,display_help:326,display_helptext:[249,328],display_len:344,display_met:190,display_nodetext:328,display_titl:180,dispos:[111,203],disput:116,disregard:33,dist:[63,130],distanc:[6,27,39,46,49,64,125,205,220,221,247,344],distance_inc:221,distance_to_room:39,distant:[49,138,187,233],distinct:[55,64,105,140,221],distinguish:[22,154,215,221],distribut:[8,9,15,23,31,34,42,63,64,78,96,97,124,127,128,175,177,206,321,324],distribute_messag:175,distributor:34,distro:[8,23,63,67,72],disturb:[27,140],distutil:63,distutilserror:63,ditto:63,div:[3,16,17,38,109,137,250],dive:[22,41,63],diverg:83,divid:[13,64,69,184,233,344],dividend:184,divisiblebi:69,divisor:184,django:[2,3,4,9,12,15,23,25,36,39,55,63,69,73,76,79,86,101,103,104,107,112,113,120,124,125,127,128,134,136,137,139,144,145,148,171,173,175,177,186,237,239,244,246,251,254,256,263,266,267,273,274,287,295,296,303,309,311,312,315,316,318,319,322,325,329,333,334,335,340,342,344,346,349,352,357,362],django_admin:360,django_nyt:4,djangonytconfig:4,djangoproject:[23,357],djangowebroot:312,dmg:73,dnf:[8,63,67],do_attack:231,do_flush:[318,334],do_hunt:231,do_nested_lookup:159,do_not_exce:25,do_noth:230,do_patrol:231,do_pickl:325,do_task:[260,344],do_unpickl:325,do_xterm256:321,doabl:[14,138],doc:[16,17,23,25,33,45,51,53,60,64,68,70,79,86,95,96,109,110,125,129,130,136,139,141,159,204,234,278,344,357,363,364],docker:[7,63,79,90,139,364],dockerfil:100,dockerhub:100,docstr:[1,5,25,38,41,43,68,74,96,154,159,170,180,193,205,206,215,233,234,328],documen:96,document:[0,3,5,6,9,16,17,20,22,23,24,25,26,29,41,43,46,47,48,52,55,57,58,60,64,68,70,76,79,83,86,90,96,103,104,106,111,114,118,121,122,123,124,125,127,131,133,135,136,139,153,167,180,204,234,316,319,327,334,362],dodg:218,doe:[2,4,5,9,11,20,21,23,24,25,26,29,31,33,37,38,39,40,41,43,49,51,54,55,56,57,58,60,61,63,64,68,69,73,78,80,85,88,89,91,95,96,100,102,104,109,110,111,112,113,114,116,117,118,119,121,123,125,126,127,129,131,132,133,136,137,138,140,144,146,156,164,167,169,171,174,181,182,183,186,187,202,203,215,217,218,219,220,221,232,233,234,235,247,251,252,259,260,266,267,271,272,273,276,279,287,306,316,318,323,328,336,337,340,344,349,357,362],doesn:[0,4,9,11,13,15,22,25,26,29,33,36,37,39,44,46,49,51,57,60,61,63,69,71,72,73,75,76,78,86,88,89,90,91,95,96,103,110,111,121,123,125,126,127,128,133,136,137,138,153,177,181,187,194,195,206,219,242,267,287,321,328,339,344],doesnotexist:[144,146,148,175,177,179,182,184,187,189,195,203,204,205,206,212,213,214,217,218,219,220,221,223,226,227,231,232,233,235,239,246,247,251,256,259,274,300,316,319,324,331,335],doff:218,dog:[27,96],doing:[2,4,10,11,27,29,31,33,36,38,39,43,46,49,51,57,58,59,60,61,64,69,70,79,80,89,90,95,96,97,105,110,114,115,119,125,126,127,133,134,137,138,144,156,179,182,194,206,215,217,218,219,220,221,226,231,232,235,241,247,261,298,328,334,340],dolor:52,dom:137,domain:[8,55,67,90,103,138,324],domexcept:90,dominion:9,dompc:9,don:[0,1,3,4,6,9,10,11,20,21,22,23,25,26,27,29,30,31,33,34,37,38,39,41,42,43,44,46,47,50,51,54,58,59,61,62,63,64,67,68,69,70,72,73,75,80,81,82,83,85,86,88,90,91,93,95,96,97,102,103,104,105,106,111,114,116,119,122,123,125,126,127,128,131,132,133,134,135,136,138,140,144,146,152,153,159,164,165,166,167,168,174,175,180,185,194,198,205,206,218,219,220,224,227,233,234,235,242,247,251,252,261,271,272,279,285,299,306,313,318,321,322,328,334,337,340,344,357,362],donald:93,donat:[70,90],done:[1,4,6,9,10,11,20,21,22,25,29,30,31,33,34,36,37,38,39,41,43,44,49,51,55,56,57,58,59,61,62,63,64,67,69,70,73,76,80,82,85,87,90,91,93,100,107,108,110,115,116,117,118,119,120,121,123,126,128,131,133,136,137,144,154,156,174,175,179,185,205,221,227,235,242,246,247,259,260,261,267,286,296,302,305,306,308,313,316,321,322,329,334,344,362],donoth:259,doom:252,door:[0,20,22,27,43,49,61,80,85,89,103,159,212],doorwai:212,dot:[22,43,119,153,159,322,344],dotal:[321,343],dotpath:344,doubl:[22,38,43,57,97,119,133,152,171,343,344],doublet:[152,153],doubt:[22,138,234],down:[0,4,6,11,12,21,22,29,31,33,36,38,39,41,43,49,50,51,55,57,58,61,63,73,81,85,86,90,91,93,96,100,102,103,104,106,108,111,114,119,122,123,136,137,144,159,169,195,209,215,218,219,232,235,241,247,252,259,261,267,269,276,277,285,305,306,308,321,329,330,344],download:[5,9,23,26,63,64,72,75,79,90,100,101,128,130,131,139],downtim:[29,103,331],downward:[43,156],dozen:[25,55,108],drag:137,draggabl:138,dragon:56,dramat:[11,61],drape:182,draw:[14,38,39,49,73,119,330],draw_room_on_map:49,drawback:[14,23,28,29,51,58,73,86,138,181,322],drawn:[49,58,111],drawtext:73,dream:[26,55,61,129],dress:182,drink:[316,318],drive:[9,19,21,61,63,64,96,100,121,131,133],driven:[25,79,123,214,249],driver:23,drizzl:[102,132],drop:[6,9,14,20,21,23,25,33,37,40,55,57,58,60,69,70,73,80,85,86,87,88,89,90,117,118,121,128,137,138,159,165,182,203,214,218,221,226,241,247,276,318,322,344],drop_whitespac:330,dropdown:[106,138],droplet:67,droplock:241,dropper:[218,221,247],drum:90,dry:67,dtobj:344,duck:[27,95],duckclient:24,due:[5,6,12,22,29,31,33,40,43,58,60,62,63,64,76,90,91,93,95,96,104,107,125,126,140,153,169,246,247,269,305,308,315,321,337],duh:108,dull:[20,26,111],dumb:[20,138,308,321],dummi:[9,33,54,59,80,93,127,206,242,267,285,298,299,306],dummycli:298,dummyfactori:298,dummyrunn:[141,142,262,267,285,297,299,301],dummyrunner_act:298,dummyrunner_actions_modul:298,dummyrunner_set:[93,141,142,262,267,297],dummyrunner_settings_modul:93,dummysess:308,dump:[34,209,276],dungeon:[55,77,112],dupic:31,duplic:[31,37,96,152,159,261,318,337],durat:[10,28,132,139,219,338,345,364],dure:[9,11,29,31,38,40,55,60,61,63,66,68,79,80,95,97,100,102,105,107,116,123,132,135,136,137,140,152,164,170,187,203,227,231,233,234,242,244,258,260,276,286,322,324,328,337,357],duti:64,dwarf:111,dying:[217,218,219,220,221],dynam:[2,3,34,43,68,82,86,90,111,114,115,124,133,137,138,139,144,148,154,166,169,170,174,177,188,206,215,217,218,219,220,221,239,246,247,256,261,316,318,319,324,326,328,335,338,362,364],dynamical:344,dyndns_system:90,e_char_typeclass:120,each:[0,1,2,4,5,10,11,13,19,20,22,27,29,31,33,34,36,38,39,40,42,43,48,49,51,55,56,57,58,59,61,62,64,69,73,77,80,82,83,85,86,95,96,97,100,102,104,105,108,109,111,112,114,115,116,119,121,123,124,125,126,127,132,133,136,137,138,140,144,151,152,153,157,159,168,175,179,181,182,183,187,188,203,205,206,215,217,219,220,221,228,235,239,242,246,247,252,258,261,269,272,285,287,299,306,307,308,316,318,319,321,322,324,326,327,328,329,330,334,336,344],eaoiui:205,earli:[36,138,217,218,219,220,221,269],earlier:[3,9,13,31,36,51,54,58,60,61,62,64,74,85,95,96,106,119,121,123,131,134,272],earn:124,earnest:124,earth:[82,103],eas:[31,33,39,86,90,100,126],easi:[0,5,10,13,17,22,23,26,29,33,38,39,43,46,51,55,56,61,62,67,68,69,72,73,76,79,81,82,85,88,89,90,100,102,106,108,111,113,116,118,123,125,126,127,128,131,133,134,138,140,153,157,164,182,188,215,328,334],easier:[1,4,10,11,12,22,25,37,38,39,47,51,55,56,57,58,61,62,69,73,86,90,91,95,96,102,109,126,136,205,215,217,218,219,220,221,232,309,319],easiest:[0,5,12,15,25,27,30,46,58,63,67,70,76,123,128,131,133,135,209,318],easili:[0,3,4,11,12,13,14,17,20,25,27,28,33,34,37,38,39,46,48,49,51,55,58,60,61,62,63,68,70,73,80,83,85,88,90,91,96,98,100,103,105,106,107,108,109,111,112,119,122,123,131,133,136,137,138,140,166,177,179,180,182,188,190,194,205,212,215,217,218,219,220,221,234,238,241,261,322,328,339],east:[25,44,49,111,159,233],east_exit:233,east_west:111,eastern:[62,111],eastward:233,eccel:330,echo1:29,echo2:29,echo3:29,echo:[5,10,12,20,26,27,28,29,33,36,38,43,44,49,50,55,59,65,71,90,95,96,98,100,104,109,110,116,118,123,132,140,144,146,157,159,164,169,182,185,206,226,231,232,233,247,265,272,287,326,344],echotest:5,econom:[55,79,86],economi:[61,73,102,108,120,179],ecosystem:100,ect:96,edg:[16,27,131,330,344],edgi:49,edit:[0,1,4,5,6,9,11,13,14,23,25,26,30,33,35,37,40,41,43,46,48,54,56,58,59,60,61,62,67,68,69,70,75,76,79,80,81,86,95,96,97,100,101,104,106,109,111,114,128,133,134,135,136,137,138,157,159,166,169,180,186,188,192,193,195,196,202,203,237,242,244,247,249,251,252,316,326,357,362,364],edit_callback:[193,195],edit_handl:159,editcmd:22,editor:[0,5,9,15,21,22,33,38,43,45,46,53,57,60,63,67,76,79,95,96,97,108,109,111,131,139,159,166,168,169,180,202,256,322,326],editor_command_group:326,editorcmdset:326,editsheet:58,edu:124,effect:[6,10,11,14,27,28,29,31,35,39,43,56,57,58,61,73,87,95,104,107,110,111,114,115,116,117,124,126,127,128,129,138,140,141,142,144,152,153,159,168,185,195,218,219,220,226,227,231,233,240,247,253,256,336,344],effici:[11,26,28,29,39,55,56,64,76,79,86,87,93,95,103,112,115,119,125,132,179,206,213,242,247,261,316,317,319,326,329],effort:[37,56,131,134,362],egg:75,egg_info:63,egi:269,either:[0,4,9,12,13,17,23,27,29,31,33,34,37,38,39,41,43,44,46,49,51,56,57,58,69,73,80,83,90,91,93,95,97,102,103,105,109,110,111,112,114,116,119,121,122,123,125,126,128,131,137,138,144,146,152,153,154,164,169,174,175,176,180,192,198,199,205,206,212,215,217,220,221,242,247,251,252,256,258,259,261,265,276,299,317,318,319,328,330,336,337,339,341,344],elabor:[4,22,85,91,123],electr:[90,124],eleg:37,element:[16,17,22,41,43,51,55,91,114,151,156,180,184,204,205,247,252,316,317,319,322,327,328,329,344],elev:[46,82,124,139,364],elif:[0,41,49,51,58,73,102,116,117,123],elimin:[96,100,321],ellipsi:96,ellow:114,els:[0,1,2,5,9,10,12,19,20,21,22,23,25,27,29,30,33,38,39,41,42,46,48,49,51,58,60,68,69,73,80,81,82,84,85,90,91,95,102,103,111,114,115,116,117,120,121,123,127,131,133,134,137,179,182,188,204,217,218,219,220,221,235,246,296,318,328,344],elsewher:[2,29,31,58,70,96,112,133,138,153,233,267,308,316],elvish:205,emac:[14,79],email:[63,64,67,131,144,145,186,324,338,344,345,357],email_login:[141,142,178],emailaddress:344,emailfield:[145,357],emb:[38,58,109,114,187,252],embark:121,embed:[109,114,125,138,250,327,336],emerg:[76,80,103],emi:205,emit:[25,34,108,137,153,157,175,189,247,306,337],emit_to_obj:[153,247],emitt:83,emo:21,emoji:24,emot:[33,41,43,55,68,116,165,179,205,206],emoteerror:206,emoteexcept:206,emphas:[38,61],emphasi:38,emploi:345,empti:[0,2,3,6,9,10,14,25,31,33,38,41,42,43,47,49,51,54,58,60,63,64,69,73,77,84,86,88,89,91,96,97,100,114,115,117,119,123,125,127,128,131,134,137,138,150,151,157,159,170,180,190,192,206,251,252,265,272,276,298,299,315,322,324,328,330,341,344],empty_color:190,empty_permit:[145,237,244,357],empty_threadpool:312,emptyset:31,emul:[43,64,75,105,123,129,169],enabl:[8,24,43,71,100,103,106,114,126,134,137,144,175,188,345],enable_recog:206,encamp:46,encapsul:338,encarnia:79,encas:326,enclos:[35,43,50,171,186,336],encod:[7,27,58,111,139,278,295,296,321,340,344,364],encoded_text:344,encompass:27,encount:[60,95,153,345],encourag:[3,22,24,39,70,91],encrypt:[7,8,43,83,103,164,287],end:[1,5,6,8,9,10,11,13,14,19,20,21,22,23,25,27,28,29,31,33,34,38,39,40,43,47,50,51,54,55,58,60,62,64,65,67,69,73,76,80,81,83,86,87,88,90,91,93,95,96,100,105,107,108,109,114,116,118,119,121,122,123,126,128,131,133,134,135,137,138,140,144,146,152,153,159,165,166,174,179,181,182,185,190,202,206,214,215,217,218,219,220,221,233,238,250,271,278,279,287,301,306,310,312,317,321,322,324,328,329,330,336,337,344,362],end_convers:51,end_turn:116,endblock:[3,69,133,134],endclr:[114,336],endfor:[69,133,134],endhour:25,endif:[69,133,134],endlessli:103,endpoint:103,endsep:344,endswith:321,enemi:[11,29,51,61,109,116,122,219,220,221,231,232,233],enemynam:51,enforc:[10,33,41,61,73,80,114,126,138,287,329,330,362],enforce_s:330,engag:[55,221,231],engin:[22,23,33,36,43,55,56,64,68,73,77,79,89,102,103,104,122,127,131,136,140,150,153,168,169,210,233,238,267,278,287,295,305,307,322,324],english:[15,76,79,97,113,139],enhanc:[59,81,114,209,321,362],enigmat:20,enjoi:[61,63,91,106],enough:[4,6,21,29,38,39,41,42,43,51,55,57,58,61,63,64,69,70,80,84,85,87,90,91,96,108,112,115,119,123,126,136,153,159,204,205,226,235,328,329,330],ensur:[49,69,100,106,117,126,127,215,342,362],ensure_ascii:296,enter:[0,1,3,5,9,12,13,14,15,20,21,22,23,25,26,27,29,31,33,35,36,41,42,43,44,46,51,58,62,63,64,66,69,75,77,80,83,85,87,89,91,95,96,100,109,111,114,116,117,119,122,123,124,128,129,131,133,135,138,139,141,144,151,153,158,167,168,169,174,179,180,182,187,188,198,215,217,218,219,220,221,231,233,235,241,247,252,256,265,306,326,328,357],enter_guild:51,enter_nam:51,enter_wild:235,enterlock:241,enterpris:36,entir:[10,11,13,14,19,22,27,29,33,46,49,50,51,60,61,69,80,86,90,91,108,111,114,115,123,125,127,136,180,205,206,215,234,241,242,247,251,252,318,322,328,330,334,336,344,362],entireti:[51,73,188,328],entit:324,entiti:[6,11,27,34,43,47,51,53,55,59,61,64,80,84,87,89,102,105,107,109,112,116,119,125,126,139,143,144,154,159,169,175,176,177,206,212,241,247,249,250,251,252,253,256,257,259,261,308,316,317,319,324,328,329,333,341,344],entitii:107,entitl:90,entranc:111,entri:[4,5,11,15,24,25,27,31,33,34,43,47,48,51,53,54,58,59,63,69,70,72,77,80,83,91,95,107,119,121,131,138,139,144,154,166,167,170,190,204,215,217,218,219,220,221,236,237,238,239,242,247,261,286,299,316,322,324,326,328,330,337,338,341,344,345,362],entriest:[43,156],entrust:59,entrypoint:100,entrytext:[69,239,324],enul:8,enumar:344,enumer:134,env:[267,277],environ:[4,7,9,13,25,36,38,43,45,59,61,63,64,65,82,90,95,100,103,128,169,170,228,230,267,277,302,322,328,342,360],environment:267,eof:287,epic:79,epilog:234,epoch:[27,62,331],epollreactor:312,epub:79,equal:[0,16,19,20,25,31,33,39,46,91,93,96,97,114,121,152,187,206,217,218,219,220,221,247,344],equip:[14,57,114,182,217,218,220,221],equival:[10,11,13,40,43,47,63,87,88,101,103,104,110,114,128,143,159,238,285,316,344,362],eras:[9,95,221],err:[58,80,298,322],err_travers:[89,247],errback:[10,264,267,276,277,344],errmessag:152,errmsg:[123,337],erron:[113,123,276,330],error:[1,5,6,8,9,10,11,14,15,20,22,23,24,26,27,31,33,37,38,42,43,51,56,57,58,59,60,63,64,67,71,74,75,76,80,83,86,87,89,90,91,97,103,104,105,109,111,113,114,118,119,120,122,123,125,127,128,131,133,135,139,144,150,152,153,159,175,195,204,206,215,227,232,234,242,247,250,251,259,260,264,266,267,269,271,276,298,318,321,322,324,327,328,336,337,340,344,345,364],error_check_python_modul:267,error_class:[145,237,244,357],error_cmd:44,error_msg:310,errorlist:[145,237,244,357],errorlog:8,escal:[2,19,43,80,156,241],escap:[43,69,114,165,169,234,250,321,336,343,357],escript:[22,180],especi:[1,8,15,22,23,29,60,61,63,67,80,105,111,112,124,190,205,322],ess:52,essai:79,essenti:[28,49,56,67,75,79,106,113,176,267,324],est:52,establish:[33,61,73,105,144,217,247,264,276,278,285,287,295,298,305,307],estim:[30,252,334],esult:247,etc:[2,5,6,8,11,12,20,22,23,25,27,29,30,33,35,38,40,41,43,47,48,49,51,53,55,56,57,58,61,62,63,64,67,73,79,80,83,84,86,87,88,89,95,96,100,102,103,105,107,108,109,110,112,116,119,120,125,126,127,131,132,137,138,144,148,150,151,152,153,156,158,159,167,168,169,175,179,183,184,188,190,203,205,206,212,218,220,224,227,234,247,250,251,252,285,287,295,296,306,307,315,316,318,321,322,324,325,326,327,328,336,337,344,362],etern:51,euro:90,ev_channel:146,eval:[109,179,250],eval_rst:38,evalstr:242,evalu:[33,38,51,119,151,179,242,250,328],evbot:[43,164,308],evcast:79,evcel:[327,330],evcolor:79,evcolum:330,evcolumn:330,eve:344,eveditor:[22,45,53,139,141,142,180,320,364],eveditorcmdset:326,even:[1,4,6,9,11,12,14,19,21,22,25,26,27,29,31,37,39,41,42,43,46,49,50,51,54,55,56,57,58,60,61,62,63,64,69,70,73,77,80,85,86,90,91,93,97,102,103,105,106,108,110,114,115,116,118,119,122,123,125,126,129,131,135,138,152,154,157,182,184,187,188,205,217,218,219,220,221,233,234,247,252,328,330,334,344],evenli:[27,184],evenn:100,evenna:9,evenni:4,evennia:[0,1,2,3,6,10,11,12,13,14,15,17,19,20,21,22,24,27,28,29,30,31,33,34,35,36,37,39,40,43,44,48,49,50,51,52,53,59,60,61,62,63,64,65,66,68,69,70,72,73,74,78,80,81,82,83,84,85,86,87,88,89,92,93,94,97,98,99,101,102,103,104,105,107,108,111,112,113,114,115,116,117,118,119,120,121,122,123,125,129,130,132,133,134,135,136,138,139,364],evennia_access:8,evennia_admin:362,evennia_channel:[43,65,72,98,164],evennia_dir:344,evennia_error:8,evennia_launch:[106,141,142,262,265],evennia_logo:136,evennia_vers:267,evennia_websocket_webcli:295,evennia_wsgi_apach:8,evenniacreateview:362,evenniadeleteview:362,evenniadetailview:362,evenniaform:357,evenniagameindexcli:269,evenniagameindexservic:270,evenniaindexview:362,evennialogfil:337,evenniapasswordvalid:311,evenniareverseproxyresourc:312,evenniatest:[170,196,211,228,342,360],evenniaupdateview:362,evenniausernameavailabilityvalid:[144,311],evenniawebtest:360,event:[51,64,73,103,107,137,139,141,146,179,184,194,195,196,198,206,209,227,256,259,309,364],event_nam:[194,198],eventdict:337,eventfunc:[0,141,142,178,191,195],eventhandl:195,eventi:[154,180,234],eventu:[4,11,12,19,25,29,33,41,58,61,70,76,80,83,88,90,110,116,119,123,133,136,144,150,151,168,170,185,205,206,233,242,247,251,252,264,272,298,306,307,319,323,324,328,330,355],evenv:[4,36,63,64,75,97,106],evenwidth:330,ever:[11,12,13,14,15,22,23,25,33,41,57,64,73,86,91,102,105,110,111,112,113,118,125,128,131,138,241,261,278,279,285,316,328],everi:[0,4,6,11,13,20,21,25,26,27,28,31,33,36,37,39,41,43,46,48,49,51,57,62,63,64,69,73,74,75,77,85,86,90,91,96,100,102,104,108,109,111,112,113,114,115,116,119,120,121,122,123,125,127,128,130,131,132,133,134,135,136,138,144,159,164,182,188,195,205,206,215,217,218,219,220,221,223,227,230,235,247,252,259,261,272,299,305,314,315,318,328,329,330],everror:195,everybodi:41,everyon:[19,21,24,33,34,43,51,58,61,64,71,73,77,78,80,87,98,102,110,112,114,116,121,123,127,128,131,132,159,165,166,185,217,218,219,220,221,247,285],everyth:[9,11,19,21,26,28,31,36,38,42,43,47,49,51,55,58,61,63,64,67,69,72,73,75,79,80,81,83,85,87,90,91,97,100,103,104,109,110,111,113,115,116,119,122,127,128,131,135,136,137,138,139,149,154,164,165,167,168,169,170,171,181,186,233,241,246,256,271,298,306,318,322,328,336],everywher:[9,56],evform:[27,45,53,141,142,320],evgam:[43,164],evgamedir:38,evid:72,evil:[14,93,226,252],evmenu:[22,27,33,45,53,58,85,124,139,141,142,180,188,214,215,230,249,320,364],evmenucmdset:328,evmenuerror:328,evmenugotoabortmessag:328,evmenugotomessag:328,evmor:[45,139,141,142,251,320,364],evtabl:[27,33,45,49,53,82,111,141,142,154,188,251,320,327,329,344],evtable_arg:329,evtable_kwarg:329,exact:[33,41,43,51,80,93,95,96,119,129,138,144,151,159,168,176,206,221,238,247,251,252,317,318,340,341,344],exactli:[2,10,19,20,38,40,42,46,58,62,63,64,69,73,76,83,86,91,95,96,100,102,110,111,114,115,123,128,131,136,138,206,247,267,318,341],exam:[43,159],examin:[2,11,12,20,22,33,58,60,73,80,83,85,91,96,106,115,122,123,131,137,140,144,159,179,224,232,233,299],exampl:[0,2,4,5,6,8,10,11,13,14,15,17,19,20,21,22,25,27,28,29,30,31,33,36,37,38,40,41,43,44,48,49,55,56,57,58,59,60,61,62,63,64,67,68,71,74,77,81,82,84,85,86,87,88,89,91,93,95,96,97,98,100,103,104,105,106,109,110,111,112,114,115,117,118,119,121,122,123,124,125,126,129,130,131,132,133,135,136,138,139,140,144,148,151,152,153,154,157,158,159,164,165,166,167,168,170,174,176,177,179,180,182,184,185,187,188,189,190,199,203,204,205,206,209,212,213,214,215,217,218,219,220,221,223,226,227,231,233,234,235,239,242,246,247,252,256,259,261,272,287,296,299,308,312,315,316,318,319,321,322,323,327,328,329,330,331,335,336,337,338,341,342,344,345,357,362,363,364],example_batch_cod:[13,141,142,178,222],exapmpl:5,excalibur:85,exce:[82,217,218,219,220,221,310,334],exceed:310,excel:[56,67,79,80,102,108],excempt:152,except:[4,9,10,11,14,19,20,21,22,27,28,29,31,33,38,39,41,46,50,58,63,64,75,80,83,89,90,91,95,97,102,109,111,114,116,118,119,120,121,123,126,133,134,144,146,148,150,153,154,167,168,175,176,177,179,182,184,187,189,194,195,198,202,203,204,205,206,212,213,214,217,218,219,220,221,223,226,227,231,232,233,234,235,239,241,242,246,247,251,256,259,260,267,272,274,276,296,300,312,316,319,321,324,327,328,329,330,331,335,336,337,339,344],excepteur:52,excerpt:50,excess:[22,80,109,167,168,246,322],exchang:[13,90,102,179,325],excit:[20,35,54],exclam:21,exclud:[64,119,120,123,182,203,233,246,247,326,328],exclude_channel_messag:176,exclude_cov:182,excluded_typeclass_path:169,exclus:[51,61,80,83,256,317,328],exclusiv:324,exe:[63,106,128],exec:[51,85,109,252,328],exec_kwarg:328,exec_str:302,execcgi:8,execut:[0,9,10,12,13,14,19,22,25,28,29,31,33,36,43,45,46,47,50,51,55,62,63,64,69,75,83,85,87,89,91,95,102,106,109,111,114,119,127,128,137,139,144,146,148,149,150,154,157,158,166,167,169,170,177,180,195,206,215,233,234,239,241,242,246,247,251,252,253,256,260,264,272,274,277,278,287,295,299,302,305,306,316,318,319,322,328,329,335,336,344,364],execute_cmd:[2,33,89,117,118,123,144,146,154,247,272,306],execute_command:33,executor:36,exemplifi:[28,40,122],exercis:[21,41,42,58,85,95,96,111,116,123,132,303,335],exhaust:22,exhaustedgener:204,exidbobj:247,exis:44,exist:[0,2,3,5,11,12,13,20,21,22,25,27,31,33,35,36,39,40,41,43,44,46,48,49,51,56,57,58,60,61,64,65,68,69,70,72,76,80,86,96,97,100,102,105,109,111,112,115,116,117,123,124,128,131,134,136,138,139,143,144,145,146,152,153,154,159,164,166,167,168,169,175,180,181,187,192,194,195,198,199,202,203,205,206,213,220,232,235,241,242,246,247,249,252,259,260,267,271,273,287,300,305,306,308,316,317,318,319,322,324,326,327,328,330,337,339,344],existen:306,exit:[20,21,22,23,31,39,41,43,45,49,50,51,53,55,58,63,80,85,86,91,100,106,109,111,119,121,122,123,124,125,128,139,141,150,152,153,159,169,179,180,196,212,213,215,221,231,232,233,234,235,241,246,247,252,287,299,316,324,326,328,329,342,360,364],exit_alias:[159,212],exit_back:58,exit_cmd:[51,329],exit_command:247,exit_nam:[49,159,212],exit_on_lastpag:329,exit_ther:58,exit_to_her:[43,159],exit_to_ther:[43,159],exit_typeclass:[235,342,360],exitbuildingmenu:22,exitcmdset:[31,247],exitcommand:247,exitnam:212,exitobject:44,exixt:285,exot:33,exp:327,expand:[0,1,4,5,6,20,21,23,49,55,57,58,61,64,70,74,81,85,89,90,104,111,114,117,120,123,124,131,132,135,139,140,159,186,212,217,218,219,220,221,247,321,330],expand_tab:330,expandtab:[321,330],expans:[44,61],expect:[0,1,6,9,10,33,34,37,38,47,56,58,61,67,75,80,83,87,88,89,90,91,95,96,97,107,113,114,115,122,123,124,126,127,128,134,138,159,167,168,180,192,194,204,227,235,241,247,251,252,265,315,318,328,329,334,349,362],expected_return:127,expedit:96,expens:[90,115,119,341],experi:[26,42,51,57,60,61,62,63,73,77,81,90,95,100,111,122,131,135,139,164],experienc:[51,61,64,79,95],experienced_betray:51,experienced_viol:51,experiment:[43,74,169,173,244],explain:[20,22,33,39,48,51,55,58,64,71,79,86,119,121,124,126,127,129,131,134,136,139],explan:[25,31,33,39,64,69,77,114,124,139,311],explicit:[0,1,22,31,38,40,48,69,71,88,91,104,129,136,204,267,316],explicitli:[4,9,21,30,31,38,43,58,59,63,68,80,83,84,85,86,87,96,97,109,112,114,115,124,125,153,154,159,204,247,252,261,318,321,324,340],explor:[0,2,10,20,42,43,59,63,69,83,95,104,111,116,122,125,169],expos:[103,134],express:[3,33,38,43,51,56,80,109,119,127,134,135,140,159,184,204,221,250,344],ext:51,extend:[1,3,5,27,34,39,43,55,56,69,73,79,85,86,108,109,111,117,118,125,133,134,148,154,166,170,175,181,183,187,195,198,235,244,246,247,318,321,338,357,362],extended_room:[141,142,178],extendedloopingcal:261,extendedroom:187,extendedroomcmdset:187,extens:[1,3,9,23,38,51,55,56,61,63,64,88,96,97,104,111,114,127,138,148,210,217,324,333,343],extent:[22,56,73],exter:164,extern:[8,15,23,34,38,40,41,43,54,55,57,63,65,72,90,98,106,108,109,111,124,139,141,153,164,172,175,177,209,251,265,267,269],external_discord_hello:272,extra:[1,6,8,14,16,21,23,25,29,31,33,37,41,51,57,58,80,89,90,93,95,96,107,114,119,123,125,126,127,134,136,137,138,144,145,148,154,166,179,187,189,202,206,233,247,250,251,261,264,315,317,321,322,326,328,329,330,337,338,339,343,344],extra_environ:322,extra_spac:344,extract:[11,41,56,91,96,97,107,138,154,206,210,242,295,344],extract_goto_exec:328,extrainfoauthserv:287,extran:188,extrem:[26,56,91,110,128,217,218,220,221,338],eye:[60,97,111,114,252,329],eyed:136,eyes:[33,37,57],eyesight:[58,80,114],f6d4ca9b2b22:100,face:[90,103,122,189,311,328],facil:337,fact:[10,11,14,21,29,33,55,57,58,61,76,83,89,103,106,114,117,123,125,126,134,138,140,308,336],facter:138,factor:[0,62,82,114,218,220,264,278,279],factori:[40,96,264,269,277,278,279,285,286,287,298],factory_path:146,fade:[108,205],fail:[4,9,10,11,12,13,14,24,27,31,41,51,60,61,63,89,91,103,107,109,110,113,116,117,121,127,153,168,175,185,206,212,232,241,242,247,251,259,264,265,267,271,278,279,310,315,316,318,338,340,344,362],failmsg:310,failtext:73,failur:[10,14,63,73,119,127,144,233,269,276,278,279,298,310,321,344],failure_teleport_msg:233,failure_teleport_to:233,faint:102,fair:[73,185],fairli:[39,69,75,182,188,215,218],fake:[183,298,308],fall:[26,31,38,60,62,64,73,97,102,111,113,141,144,168,189,206,233,328,344,357,362],fall_exit:233,fallback:[44,49,55,150,154,177,187,242,259,267,296,316,328,339,344],fals:[1,2,4,6,11,20,21,22,25,27,29,31,33,38,41,44,49,50,51,58,62,68,74,77,80,81,84,86,89,96,102,103,115,116,118,120,121,123,125,127,133,137,144,145,148,150,151,152,153,154,159,166,175,176,177,179,180,182,183,184,185,188,192,195,199,205,206,212,215,217,218,219,220,221,230,234,235,237,238,239,241,242,244,246,247,249,251,252,256,257,258,259,260,261,264,267,269,273,276,277,285,286,287,296,304,305,306,308,310,312,315,316,317,318,319,321,322,324,326,328,329,330,331,334,336,339,340,341,343,344,345,357],falsestr:188,falter:61,fame:122,famili:[9,51,57],familiar:[3,9,20,29,31,33,39,58,60,63,85,90,91,95,96,111,119,124,125,133],famou:[52,326],fan:79,fanci:[15,17,36,73,138,182],fanclub:119,faq:[45,124,139,364],far:[0,13,20,21,22,31,33,39,41,44,46,49,51,54,55,57,59,61,75,88,90,91,95,96,100,106,111,114,119,131,138,152,221,235,241,269,326,334],fashion:111,fast:[11,15,23,26,27,29,56,62,64,82,89,108,115,131,157],faster:[23,62,93,119,175,177,179,316],fastest:[5,38],fatal:267,faulti:95,favor:27,favorit:[21,37],fear:27,featur:[0,4,12,15,17,20,22,25,26,27,31,33,34,36,37,42,45,46,47,48,49,50,56,57,59,61,62,63,64,70,72,78,81,85,91,96,103,107,109,111,114,119,122,123,124,125,128,129,131,138,139,144,153,154,187,195,206,215,234,261,305,309,318,326,344,362,364],februari:62,fed:[10,33,80,285,325,327],fedora:[8,63,67,131],feed:[7,15,43,49,51,55,73,98,109,128,139,146,164,269,286,287,318,329],feedback:[37,42,61,70,89,118,176,226,326],feedpars:[98,286],feedread:146,feel:[0,10,17,22,37,38,39,46,55,57,60,61,63,64,69,70,71,73,77,90,91,108,118,122,123,125,131,133,138,205,215,218,224,233],feend78:199,feint:116,felin:27,fellow:327,felt:[102,132],femal:189,fetch:[11,63,90,100,128,131,133,329,362],few:[0,4,6,9,10,11,15,17,20,23,31,33,34,36,38,41,42,43,49,50,55,59,60,61,64,66,73,74,79,80,86,88,89,91,103,110,114,116,119,121,122,123,126,127,131,138,169,184,205,227,246,310,321,330,344,362],fewer:[108,308,317],fg_colormap:343,fgstart:343,fgstop:343,fiction:[51,55,62,77,328],fictional_word:205,fictiv:205,fiddl:233,fido:96,fie:102,field:[3,11,23,34,54,56,58,74,84,86,87,89,102,106,107,112,119,125,128,133,135,145,148,173,177,188,192,206,221,231,237,239,241,244,246,247,251,252,254,256,257,261,274,315,316,317,318,319,327,335,340,341,357,359,362],field_class:357,field_or_argnam:74,field_ord:357,fieldevmenu:188,fieldfil:[141,142,178],fieldnam:[58,84,188,257,318,334,357],fieldset:[145,173,237,244,254],fieldtyp:188,fifi:96,fifo:344,fifth:49,fight:[29,31,61,116,122,217,218,219,220,221,232],fighter:[217,218,219,220,221],figur:[3,12,26,33,37,38,42,49,80,83,90,91,93,96,97,119,121,131,133,138,179,181,184,206,251,267],file:[2,3,4,5,6,8,9,19,20,21,22,23,25,26,27,31,34,36,37,40,41,42,44,47,48,54,56,57,58,59,60,62,63,64,65,66,67,68,69,72,75,76,79,80,81,82,83,85,86,90,93,95,96,97,98,100,102,103,106,109,110,111,114,117,119,120,121,123,128,130,133,134,135,136,137,138,139,141,142,144,145,158,166,175,180,182,183,184,186,205,209,234,235,237,241,244,252,266,267,287,299,300,301,305,312,313,315,320,327,328,337,340,341,344,357,362],file_end:[322,344],filelogobserv:337,filenam:[27,60,131,322,327,337],filename1:267,filename2:267,filesystem:[63,100,103],fill:[36,41,49,50,58,61,65,70,106,111,114,119,133,135,188,250,315,316,321,327,329,330,344],fill_char:330,fill_color:190,fillabl:188,fillchar:[114,321,336,344],filo:344,filter:[31,34,39,43,69,86,106,114,119,120,125,133,138,152,157,175,180,187,206,247,344,362],filter_famili:[119,125],filthi:78,final_valu:10,find:[0,3,4,6,10,11,12,13,14,17,20,21,22,23,24,25,26,27,29,31,33,34,37,38,40,41,42,46,47,48,49,50,55,56,57,58,60,61,62,63,67,68,69,70,73,74,75,76,78,79,80,84,86,87,89,90,91,93,95,96,97,100,102,103,108,109,110,112,114,119,122,123,124,125,127,128,131,133,134,135,136,139,140,144,151,159,176,184,187,206,212,215,233,234,247,251,252,258,267,316,317,321,323,341],find_apropo:238,find_topicmatch:238,find_topics_with_categori:238,find_topicsuggest:238,fine:[12,15,20,33,41,44,46,64,85,86,89,95,105,112,115,118,122,123,138,146,233,324,344],finer:12,finish:[10,14,29,33,38,58,59,61,100,107,122,123,124,128,133,136,141,144,154,156,167,179,187,203,232,233,247,267,271,279,305,312,323,328,344],finish_chargen:51,finit:91,fire:[2,20,21,27,28,29,33,46,51,58,61,96,102,106,107,111,115,118,120,132,139,146,150,195,219,220,247,250,252,259,267,276,278,295,328,329,334],firebreath:58,firefox:72,firestorm:28,firestorm_lastcast:28,firewal:[67,90],first:[2,3,4,5,6,7,9,10,11,12,13,14,15,16,19,20,21,23,24,26,27,29,31,33,35,38,39,40,41,42,43,45,48,49,50,51,55,56,58,59,61,62,63,65,68,69,70,71,73,75,76,77,80,81,83,85,86,89,90,91,93,96,97,98,100,102,103,104,105,106,107,108,109,110,113,114,116,118,119,120,121,122,123,125,126,127,128,131,132,133,134,135,136,137,138,139,144,146,148,151,152,159,167,168,171,175,177,179,180,182,183,184,186,187,204,205,206,212,214,217,218,219,220,221,223,227,231,232,233,234,235,239,241,246,247,251,252,256,259,267,271,272,274,285,287,295,296,298,299,305,308,316,318,319,321,322,324,326,327,328,330,331,334,335,336,343,344,363,364],first_lin:123,first_nam:145,firsthand:80,firstli:[9,89,90,96,97],fish:[73,153,203],fist:252,fit:[11,23,39,47,51,58,80,88,121,129,130,133,218,221,327,329,330,344],five:[28,33,90,111,119,153,215,344,345],fix:[13,14,16,26,27,33,37,42,43,51,57,60,61,63,64,70,75,78,83,85,90,95,96,97,109,110,121,123,125,127,138,205,267,327,329,330,340,363],fix_sentence_end:330,fixer:119,fixing_strange_bug:131,fixtur:[228,303,335,342],flag:[9,13,14,20,28,29,30,31,33,40,41,43,51,58,61,74,76,83,86,108,115,123,131,144,150,152,154,159,231,241,242,247,267,274,278,287,295,306,326,328,344],flame:[28,220],flash:[14,227],flat:[22,26,27,45,47,48,53,56,59,60,96,125,141,252],flatfil:56,flaticon:79,flatten:252,flatten_diff:252,flatten_prototyp:252,flattened_diff:252,flatul:102,flavor:[20,90,220],flavour:[87,126],flaw:121,fled:[116,231],fledg:[15,90,108,123,133,158,185],flee:[116,117,221,231],fleevalu:116,flesh:[20,58],flexibl:[1,13,21,22,29,39,43,51,57,59,73,88,90,102,108,109,111,116,134,138,148,159,179,180,188,215,241,316,328,362],flick:345,flip:[51,81],flood:[27,50],floor:[0,82,206],flow:[17,36,40,55,61,83,86,115,131,137,324,328,336],flower:[12,20,43,61,87,89,119,159],flowerpot:[12,57],fluent:79,fluid:[16,17],flurri:206,flush:[23,33,43,111,128,169,259,318,334],flush_cach:334,flush_cached_inst:334,flush_from_cach:334,flush_instance_cach:334,flusher:334,flushmem:[43,169],fly:[3,12,21,27,31,33,34,43,51,55,64,85,102,109,119,138,144,165,167,168,175,177,239,247,261,274,285,316,322,331,344,362],focu:[4,61,70,116,124],focus:[56,57,77,79,106,123,124,221],foe:218,fold:215,folder:[3,5,8,13,14,21,27,30,38,47,49,55,57,58,60,63,64,69,73,75,76,86,95,96,100,103,106,110,111,116,117,118,123,127,128,130,133,134,135,136,137,217,218,219,220,221,267],folder_nam:64,foldernam:60,follow:[0,2,4,5,7,8,9,10,11,13,14,16,17,19,20,22,23,25,31,33,34,37,38,39,40,41,42,43,46,47,48,49,50,51,54,58,60,61,62,63,65,67,68,69,71,73,74,75,76,79,80,82,85,86,88,89,90,91,93,95,96,97,100,102,103,106,110,112,114,116,117,119,120,121,123,125,127,128,131,133,134,135,137,144,146,148,150,151,154,159,167,168,170,175,177,180,182,183,185,189,195,199,206,215,219,220,226,233,239,241,242,246,247,250,251,252,256,257,271,272,295,296,299,309,316,318,321,322,324,327,328,329,330,336,337,344],follwo:242,follwow:51,fond:62,font:[25,38,111,137],foo:[33,40,51,83,84,88,95,107,112,119,127,215,328,342],foo_bar:88,foobarfoo:12,foolish:226,footer:[69,133,154,329],footnot:[15,38],footprint:[43,169],footwear:57,for_cont:247,forai:96,forbid:41,forbidden:131,forc:[0,6,8,10,31,33,58,60,63,73,81,82,91,100,103,110,116,121,123,125,127,138,146,153,157,159,164,179,187,189,203,205,206,242,247,251,258,278,279,285,308,329,330,334],force_init:247,force_repeat:[102,116,259],force_restart:259,force_str:340,forcibl:[102,258],fore:305,forebod:187,foreground:[42,100,114,126,183,267,336],foreign:125,foreignkei:[148,246,256,315,318,335],forens:210,forest:[13,111,112,140,187],forest_meadow:112,forest_room:112,forestobj:140,forev:[61,102],forget:[3,9,10,13,25,27,33,41,54,62,72,82,85,86,95,96,100,123,131,206,322],forgo:232,forgotten:[28,49,77,85],fork:[9,79],forloop:69,form:[11,13,27,31,33,34,38,43,45,51,53,55,58,59,61,64,68,70,74,76,77,80,83,88,89,93,96,97,109,112,113,114,115,116,118,123,124,125,127,129,135,141,142,144,145,146,151,153,154,157,159,167,168,170,173,175,176,177,179,188,189,205,206,210,237,239,241,242,244,247,251,252,254,257,259,261,265,285,287,295,306,308,315,316,317,318,321,322,324,325,327,328,330,336,337,340,341,344,345,346,356,362],form_char:327,form_class:362,form_template_to_dict:188,form_url:145,form_valid:362,formal:[61,80,96,138,247],format:[0,14,17,19,22,23,27,31,33,37,38,41,42,46,48,55,58,62,68,69,76,79,81,83,88,96,98,103,108,109,111,113,114,119,124,129,131,133,138,152,154,156,159,166,168,170,174,175,180,182,183,184,188,198,206,209,215,219,230,234,235,239,247,249,251,252,257,267,272,287,307,309,316,318,321,322,324,326,328,329,330,331,336,337,339,344,345,363],format_attribut:159,format_available_protfunc:251,format_callback:192,format_diff:252,format_extern:175,format_help:234,format_help_entri:166,format_help_list:166,format_messag:175,format_output:159,format_send:175,format_t:344,format_text:180,format_usag:234,formatt:[188,251,328,329],formatted_list:175,formcallback:188,formchar:[58,327],formdata:188,former:[17,23,64,126,328],formfield:340,formhelptext:188,formset:315,formstr:58,formtempl:188,formul:134,forth:[27,43,131,159,220],fortress:111,fortun:[4,33,39,48,69,122,128],forum:[1,9,37,48,55,57,63,90,98,128],forward:[13,14,20,38,42,45,50,51,62,69,90,121,126,148,177,199,209,239,246,256,312,316,318,319,327,329,335],forwardfor:67,forwardmanytoonedescriptor:[246,256,335],forwardonetoonedescriptor:[246,256,335],foul:109,found:[2,4,6,9,10,13,14,15,20,22,23,25,27,31,33,38,39,40,41,42,43,49,51,55,57,58,59,63,68,73,74,76,78,80,83,85,89,90,91,97,103,104,109,112,116,119,122,123,125,127,128,134,135,137,138,141,144,149,150,151,152,154,159,167,168,175,179,180,192,194,195,206,233,239,242,247,250,251,252,258,261,266,267,273,285,296,306,308,316,317,318,321,322,323,328,330,334,336,339,341,344,346],foundat:[49,55,77,79,217],four:[4,14,27,38,39,40,68,73,82,86,87,111,114,119,153,177,187,242],fourth:39,fqdn:90,fractal:56,fraction:127,frame:[137,138],framework:[3,16,64,124,133,136,137,170,217,220,340],frankli:129,free:[0,22,29,37,48,55,57,60,61,64,76,77,79,90,106,112,116,123,124,126,130,133,139,179,206,215,218,251],freedn:90,freedom:[14,26,44,63],freeform:[73,116,182],freeli:[55,77,100,103,322],freenod:[9,43,63,70,72,79,90,146,164,308],freepik:79,freetext:[176,341],freez:[29,33,42,194],frequenc:205,frequent:[91,180],fresh:[11,31,58,128,267],freshli:111,fri:12,friarzen:138,friend:[37,58,61,82,103],friendli:[22,38,78,95,133,138,148],friendlier:[175,247],frighten:219,from:[0,2,3,5,6,8,9,10,11,12,13,14,15,16,17,19,21,22,23,26,27,28,29,30,31,33,34,35,36,37,38,39,40,41,42,43,44,46,47,48,49,50,52,54,56,57,58,59,61,62,63,64,66,67,68,69,70,71,72,73,74,75,76,79,80,81,82,83,84,85,86,87,89,91,92,93,95,97,98,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,134,135,136,139,140,141,142,144,146,148,149,150,151,152,153,154,156,157,158,159,164,165,166,167,168,169,170,171,173,174,175,176,177,179,180,181,182,183,184,185,186,187,188,189,194,195,198,199,202,203,204,205,206,209,210,211,212,213,215,217,218,219,220,221,224,226,227,231,232,233,234,235,238,239,241,242,243,246,247,251,252,256,257,258,259,260,261,264,267,272,273,274,276,277,278,279,285,286,287,295,296,299,301,305,306,307,308,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,329,330,331,334,335,336,337,338,340,341,343,344,345,357,362,363,364],from_channel:146,from_db_valu:340,from_nod:[51,328],from_obj:[81,83,118,144,146,154,189,247],from_pickl:325,from_tz:345,frombox:276,fromstr:276,fromtimestamp:331,front:[8,13,20,73,80,85,96,103,109,131,137,139],frontend:215,frozen:[29,33,122,195],fruit:203,ftabl:344,ftp:343,fuel:[21,220],fugiat:52,fulfil:267,full:[4,9,13,14,15,16,17,20,21,23,24,25,26,27,33,37,38,43,51,55,57,58,59,60,61,64,73,75,80,84,88,89,90,95,96,97,100,101,102,105,108,109,110,111,115,116,117,119,121,123,124,125,127,128,131,133,134,135,136,146,151,153,154,158,159,164,168,169,170,179,180,185,187,190,202,205,206,215,220,230,234,242,252,257,279,285,298,308,309,316,318,322,326,328,330,344],full_justifi:[109,250],full_nam:87,full_result:185,fullchain:67,fuller:58,fullhost:67,fulli:[4,11,19,33,51,55,58,59,61,63,85,86,90,93,103,110,122,144,205,242,247,259,295,307,324,344],fun:[20,26,61,79,81,111,136],func1:[43,159,242,299],func2:[43,159,242,299],func:[5,10,21,22,25,28,29,30,33,38,42,44,50,51,56,58,60,62,71,73,80,81,82,83,85,91,116,119,121,123,150,154,156,157,158,159,164,165,166,167,168,169,170,171,174,179,180,181,182,184,185,186,187,188,189,193,199,202,203,206,212,213,214,215,217,218,219,220,221,224,231,232,233,234,241,242,247,278,299,303,312,326,328,329,331,344,362],funciton:220,funcnam:[74,114,242,250,261,328,336],functioncal:276,functionnam:[276,336],functool:63,fund:70,fundament:[33,57,77,89,95,96,112,247],furnitur:[13,112,125],further:[0,9,11,27,31,34,38,42,43,44,49,57,83,85,86,90,91,96,100,102,104,105,106,109,110,111,119,124,125,130,131,138,153,159,181,205,219,221,252,267,344],furthermor:[37,38,124,126],fuss:100,futur:[9,10,11,20,23,38,43,45,50,55,58,60,61,62,63,76,87,95,100,123,139,156,195,232,235,272,317,338,345,364],futurist:62,fuzzi:[76,238,341,344],fuzzy_import_from_modul:344,gadget:70,gag:24,gain:[11,29,61,73,93,154,177,206,242,247],galosch:205,gambl:185,game:[0,2,3,4,5,6,8,9,10,11,13,14,15,17,18,19,20,21,22,23,24,25,28,29,30,31,33,34,35,36,37,38,41,42,43,44,46,50,51,52,53,56,60,63,64,65,66,67,68,69,71,72,75,76,77,78,79,80,81,83,85,86,87,88,89,91,92,93,95,96,97,98,101,102,103,104,105,106,107,108,109,110,112,113,114,115,116,117,118,119,121,122,125,129,130,132,133,134,135,136,137,138,139,140,143,144,145,146,148,150,152,153,154,156,157,158,159,163,164,165,166,169,170,171,172,174,175,176,177,178,179,180,181,182,184,185,186,187,188,190,193,194,195,196,199,204,205,206,213,215,217,218,219,220,221,229,230,233,234,239,241,243,246,247,256,258,259,262,267,269,270,271,272,278,279,286,287,298,299,300,305,306,308,315,317,318,319,322,323,324,326,327,328,331,334,336,337,344,363,364],game_dir:[337,344],game_epoch:[27,331],game_index_cli:[141,142,262],game_index_en:54,game_index_list:54,game_nam:[54,350],game_slogan:[9,350],game_statu:54,game_templ:47,game_websit:54,gamedir:[51,100,109,267,313],gamedirnam:58,gameindexcli:270,gameplai:[90,145],gamer:[65,72],gamesrc:27,gametim:[27,53,59,139,141,142,184,187,195,320,364],gametime_to_realtim:184,gametimescript:184,gammon:79,gandalf:51,garden:79,garment:182,gatewai:[110,296],gather:[24,33,48,83,119,127,132,136,150,151,233,265,269,324,341],gave:[5,21,60,64,91,102,126],gbg:321,gcc:63,gear:[43,90,106,136,146,153,171,186],gemer:204,gen:17,gender:189,gendercharact:189,gendersub:[141,142,178],gener:[0,1,5,9,10,11,12,20,23,25,29,31,33,34,36,37,38,48,49,51,55,57,58,59,60,62,63,64,68,70,73,76,80,83,86,87,88,90,93,96,104,105,106,109,111,112,114,116,126,127,134,137,138,139,141,142,144,146,149,154,155,156,159,166,167,168,170,171,174,175,179,180,181,182,185,186,187,188,189,195,199,202,204,205,206,209,210,212,213,214,215,217,218,219,220,221,224,230,231,233,234,239,242,247,249,252,278,287,295,306,307,308,312,319,320,321,323,324,326,329,330,337,338,339,340,344,349,357,362,364],general_context:[141,142,346,348],genericbuildingcmd:180,genericbuildingmenu:180,genesi:90,geniu:203,genr:[37,64],geoff:234,geograph:140,geographi:39,geoip:209,geometr:111,geometri:111,get:[0,1,2,3,5,6,7,8,9,10,11,12,13,15,17,21,22,23,25,26,28,29,30,31,33,38,39,40,41,42,44,45,46,47,48,49,50,54,55,56,57,58,59,60,61,62,64,65,68,69,71,72,73,74,75,76,77,80,81,82,83,84,85,86,87,88,90,91,92,93,95,96,97,100,102,103,104,105,106,107,110,111,112,114,116,118,121,122,123,125,126,127,128,130,131,133,134,135,136,137,138,139,144,146,148,152,153,154,156,157,159,160,164,165,171,173,174,176,177,180,182,185,192,194,195,198,199,203,204,206,213,214,215,217,218,219,220,221,223,224,232,233,235,238,239,241,242,246,247,249,251,252,256,258,259,261,265,267,272,276,277,285,287,295,296,304,306,307,308,310,316,317,318,319,321,322,323,326,328,330,331,333,334,336,337,338,339,341,344,357,362,363,364],get_abl:60,get_absolute_url:[134,175,239,318],get_account:[242,306],get_al:306,get_alia:317,get_all_cached_inst:334,get_all_categori:238,get_all_channel:176,get_all_cmd_keys_and_alias:152,get_all_mail:199,get_all_puppet:144,get_all_sync_data:308,get_all_top:238,get_all_typeclass:344,get_and_merge_cmdset:153,get_attack:[217,218,219,220,221],get_attr:159,get_attribut:317,get_buff:326,get_by_alia:317,get_by_attribut:317,get_by_nick:317,get_by_permiss:317,get_by_tag:317,get_cached_inst:334,get_callback:195,get_channel:[41,176],get_charact:306,get_client_opt:272,get_client_s:306,get_client_sess:[295,296],get_client_sessid:296,get_cmdset:174,get_command_info:[154,167],get_context_data:362,get_damag:[217,218,219,220,221],get_db_prep_lookup:340,get_db_prep_valu:340,get_dbref_rang:317,get_def:260,get_default:340,get_defens:[217,218,219,220,221],get_display_nam:[22,42,46,58,206,235,247,318],get_err_msg:[6,20,80],get_ev:195,get_evennia_pid:344,get_evennia_vers:344,get_event_handl:198,get_extra_info:[41,154,174,247,318],get_famili:[119,125],get_fieldset:244,get_form:244,get_formset:315,get_game_dir_path:344,get_god_account:271,get_height:330,get_help:[33,68,69,154,170,193,234,328],get_help_text:311,get_id:[133,260,317],get_info_dict:305,get_initi:362,get_input:328,get_inputfunc:[272,308],get_internal_typ:340,get_kwarg:360,get_location_nam:235,get_mass:82,get_message_by_id:176,get_messages_by_channel:176,get_messages_by_receiv:176,get_messages_by_send:176,get_min_height:330,get_min_width:330,get_new:286,get_new_coordin:235,get_next_by_date_join:148,get_next_by_db_date_cr:[148,177,246,256,316,318],get_next_wait:198,get_nick:317,get_nicklist:[146,279],get_numbered_nam:247,get_obj_coordin:235,get_object:362,get_object_with_account:341,get_objs_at_coordin:235,get_oth:179,get_permiss:317,get_pid:267,get_previous_by_date_join:148,get_previous_by_db_date_cr:[148,177,246,256,316,318],get_puppet:[2,144,306],get_puppet_or_account:306,get_queryset:362,get_rang:221,get_redirect_url:362,get_regex_tupl:206,get_respons:351,get_room_at:39,get_rooms_around:39,get_sess:308,get_statu:277,get_subscript:176,get_success_url:362,get_sync_data:307,get_system_cmd:152,get_tag:317,get_time_and_season:187,get_typeclass_tot:317,get_username_valid:144,get_valu:272,get_vari:[192,195],get_width:330,get_worn_cloth:182,getattr:84,getchild:312,getclientaddress:[40,287],getel:137,getenv:[267,277],getfromlock:241,getgl:137,getinput:328,getkeypair:287,getloadavg:75,getpeer:287,getpid:344,getsizof:334,getston:33,getter:[148,177,182,206,218,221,246,247,274,316],gettext:76,gfg:321,ghostli:233,giant:[21,124],gid:[45,100,299],gidcount:298,gif:70,gift:69,gist:[205,344],git:[9,23,25,36,38,45,47,63,75,76,79,86,90,100,108,124,128,130],github:[9,25,37,41,43,45,57,63,70,75,76,79,95,96,98,104,130,131,138,180,295,312,344],gitignor:131,give:[0,1,2,3,4,5,9,10,11,12,13,15,18,19,20,21,22,23,25,26,27,30,33,38,39,41,46,48,51,52,55,57,58,59,60,61,62,63,64,68,69,73,75,77,79,80,82,85,88,89,90,91,93,96,98,100,102,103,105,107,109,110,111,112,113,114,115,116,117,118,119,122,123,124,125,127,128,133,134,136,138,139,140,150,152,153,156,165,167,168,169,174,176,180,181,182,187,204,205,214,215,217,218,219,220,221,224,233,235,241,247,256,306,312,318,321,330,341,342,344,363,364],givelock:241,given:[0,2,4,10,11,12,13,14,20,21,22,25,27,31,33,34,38,39,42,43,46,49,50,51,58,62,64,70,73,74,80,83,84,85,86,88,89,90,93,97,100,102,105,109,110,113,114,115,116,117,119,122,123,125,126,127,131,133,134,135,138,140,144,150,151,152,153,154,156,157,159,164,166,168,169,170,175,176,177,180,181,182,184,185,186,187,188,189,190,192,194,198,203,204,205,206,212,215,217,218,219,220,221,232,233,234,241,242,247,249,250,251,252,257,258,259,261,265,267,272,273,276,285,296,299,302,306,307,308,309,311,312,316,317,318,319,321,322,324,325,326,327,328,329,330,331,334,336,337,339,340,341,342,344,349,362],given_class:359,giver:[218,221,247],glad:91,glanc:[22,27,31,33,39,48,58,61,91,96,180,206],glance_exit:22,glass:[203,224,226,227],glob:[43,51,165,328],global:[13,22,33,34,35,43,45,51,56,61,64,67,74,85,89,100,104,105,108,109,114,115,120,125,131,132,137,138,140,159,187,195,204,206,212,241,247,250,252,253,256,260,264,267,272,274,277,298,299,322,323,324,328,331,336,341,342,344,350],global_script:[102,141,323],global_search:[13,22,27,58,91,144,206,247,317],globalscript:[43,169],globalscriptcontain:323,globalth:342,globe:[90,136],gloss:61,glossari:[63,139,364],glow:111,glu:92,glyph:276,gmcp:[55,74,83],gmsheet:58,gmud:24,gno:22,gnome:24,gnu:14,go_back:[51,215,328],go_back_func:51,go_up_one_categori:215,goal:[61,76,79,91,102,103,122,124,205],goals_of_input_valid:357,goblin:[43,51,109,159,252],goblin_arch:252,goblin_archwizard:252,goblin_shaman:109,goblin_wizard:252,goblinwieldingclub:109,god:[20,80,271],godlik:206,goe:[0,5,9,22,26,29,33,37,40,42,49,64,69,73,75,86,90,95,96,118,121,122,123,139,152,153,221,235,247,287,305,306,343,344,362],goff:204,going:[0,3,20,25,26,40,45,46,49,51,58,61,62,65,69,70,82,88,90,91,95,96,100,111,116,121,127,133,138,139,180,206,217,218,219,220,221,230,233,235,247,264,269,321,328],goings:269,gold:[51,82,85,109,322],gold_valu:85,golden:138,goldenlayout:138,goldenlayout_config:[137,138],goldenlayout_default_config:[137,138],gone:[5,12,77,80,85,100,102,131,259],good:[0,2,4,5,9,11,12,14,20,21,22,25,26,27,31,33,37,38,39,40,41,46,48,49,51,54,55,56,57,60,61,63,69,70,72,73,79,80,85,87,90,91,93,95,96,97,100,102,103,104,106,109,110,111,114,119,121,123,125,126,127,131,133,134,138,144,152,153,154,170,179,194,206,328],goodby:287,goodgui:242,googl:[38,43,75,79,90,164,330],googleusercont:70,googli:136,gossip:[65,79,164],got:[10,13,95,96,116,128,138,215,232],goto_cal:[51,328],goto_cleanup_cmdset:230,goto_command_demo_comm:230,goto_command_demo_help:230,goto_command_demo_room:230,goto_kwarg:328,goto_next_room:121,goto_node2:51,goto_str_or_cal:51,gotostr_or_func:328,gotten:[55,95,131,221,232,247],graaah:117,grab:[20,33,43,73,133,165,175,232,362],gracefulli:[26,43,156,169,206,247,267],gradual:[13,14,29,61,79,96,205],grai:[114,126],grain:[115,324],gram:82,grammar:205,grammat:205,grand:11,grant:[19,23,80,131,177,217,218,219,220,221,241,242,251,316],granular:221,grapevin:[7,139,141,142,146,164,262,275,364],grapevine2chan:[65,164],grapevine_:164,grapevine_channel:[65,146,164],grapevine_client_id:65,grapevine_client_secret:65,grapevine_en:[65,164],grapevinebot:146,grapevinecli:278,graph:[49,131],graphic:[42,58,80,83,84,93,111,128,135,141,186,190],grasp:[126,133],grave:60,grayscal:183,great:[0,4,14,16,21,22,29,37,39,51,57,61,69,70,73,77,79,91,95,107,108,123,127,131,134,180,188,312],greater:[22,31,73,80,97,105,119,241,328],greatli:78,greek:15,green:[31,43,80,109,114,126,131,159,169,232],greenskin:252,greet:[9,35,46,95,104,105,117,272],greetjack:87,greg:79,grei:[109,126],grenad:89,grep:[75,131],greyscal:114,greyskinnedgoblin:109,griatch:[21,70,86,119,179,181,183,184,185,186,187,189,199,202,205,206,212,213,214,230,232,327,334,340,343],grid:[7,16,111,123,139,221,235,364],grief:12,griefer:134,grin:[33,41],grip:38,gritti:33,ground:[20,21,55,111],group:[4,9,10,12,19,21,26,33,37,41,43,46,55,68,70,79,91,100,102,109,112,125,127,139,140,145,148,155,159,165,176,187,203,232,233,247,251,252,276,315,316,319,321,324],grow:[13,25,26,61,63,79,110,278,279,330,344],grown:[9,25,51,129],grudg:73,grumbl:60,grungies1138:[199,214],grunt:[43,159,252],gthi:81,guarante:[11,37,61,67,80,86,90,102,185,195,251,306,318],guard:51,guess:[15,22,46,50,69,91,103,113,138,180,252],guest1:66,guest9:66,guest:[7,53,80,139,144,364],guest_en:[66,80],guest_hom:[66,133],guest_list:66,guest_start_loc:66,guestaccount:112,gui:[45,57,83,137,199,364],guid:[36,37,45,81,95,96,128,133,136],guidelin:[37,38,79],guild:[79,86,112,118],guild_memb:51,gun:[21,77],guru:55,habit:56,habitu:115,hack:[55,73,116,276],hacker:[79,103],had:[8,9,14,15,19,20,21,29,31,37,55,61,90,95,96,100,102,119,123,128,135,138,158,182,232,251,252,256,259,267,318,322,329,357],hadn:[61,62,131],half:[108,138,239],hall:49,hallwai:49,halt:[102,111],hand:[1,15,37,38,40,43,51,55,56,57,58,61,70,73,87,89,96,105,108,119,134,154,165,167,168,169,179],handi:[42,75,119,133,219],handl:[0,2,4,5,7,8,9,11,13,15,22,24,27,33,34,37,40,41,43,44,47,49,50,51,53,55,56,60,61,62,64,67,68,74,75,80,83,85,86,87,88,89,91,93,95,97,100,104,105,108,115,116,117,124,125,126,128,129,131,132,137,138,139,144,146,149,150,152,153,159,160,164,165,168,174,179,186,187,195,198,206,210,212,214,215,217,218,219,220,221,226,232,233,234,236,246,247,250,251,252,256,257,260,264,267,271,272,276,277,279,287,296,298,307,308,315,316,318,321,322,324,325,326,328,329,330,331,334,343,344,351],handle_egd_respons:269,handle_eof:287,handle_error:[195,260],handle_ff:287,handle_foo_messag:[51,328],handle_int:287,handle_messag:[51,328],handle_message2:51,handle_numb:[51,328],handle_quit:287,handle_setup:271,handler:[2,11,31,33,41,47,64,73,80,83,84,86,87,89,102,104,105,112,115,125,139,144,150,153,168,172,174,177,179,192,195,196,198,206,231,235,241,242,246,247,252,257,258,260,261,272,285,305,306,308,314,315,316,318,319,323,327,328,329,338,339,344],handlertyp:319,handshak:[24,52,83,277,285],hang:[3,61,70,124],hangout:119,happen:[0,6,12,19,20,26,27,31,33,37,39,41,42,44,51,54,55,57,58,60,61,62,64,72,73,77,80,83,86,88,90,91,95,96,97,102,105,107,108,110,111,114,115,116,119,122,123,126,127,128,131,133,138,144,152,153,164,175,184,213,217,218,219,220,221,227,231,233,235,247,250,252,260,269,276,279,299,304,306,307,308,318,328,329,334,336,337,344],happend:252,happi:[13,119],happier:91,happili:96,haproxi:[90,139,364],hard:[9,10,11,13,15,19,26,27,31,33,38,40,41,58,61,63,64,76,79,88,90,93,96,97,100,102,109,112,115,119,121,127,131,133,138,139,168,188,215,256,267,316,318,328,364],hardcod:[57,58,77,100,111,140,316],harden:63,harder:[12,56,61,93,119,127,232],hardwar:90,hare:79,harm:[11,29,219],harri:59,harvest:362,has:[0,2,4,8,9,10,11,12,13,14,15,16,19,20,21,22,23,25,27,28,29,31,33,34,36,37,39,40,41,42,43,44,46,47,49,50,51,53,54,56,57,58,59,60,61,62,63,64,65,67,68,69,70,71,74,75,76,77,78,79,80,83,85,86,87,88,89,90,91,93,95,96,97,100,101,102,103,104,105,107,109,110,112,113,114,115,116,117,118,119,121,122,123,125,126,127,128,129,131,132,133,134,135,136,137,138,139,143,144,145,146,151,152,153,154,156,158,159,164,167,168,169,170,171,174,175,176,179,180,184,185,186,187,188,195,199,203,204,206,215,217,218,219,220,221,223,231,232,233,234,235,239,241,242,246,247,251,252,256,259,260,261,267,269,271,272,276,279,285,295,299,305,306,307,308,310,315,316,317,318,324,326,327,328,330,334,336,337,338,341,344,357,360,362],has_account:[89,231,241,246,247],has_attribut:316,has_cmdset:153,has_connect:[41,175],has_drawn:49,has_nattribut:[306,316],has_nick:316,has_par:344,has_perm:[167,242],has_sub:175,has_thorn:11,hasattr:[28,33],hash:[14,90,109,252,261,295,299,308,317],hasn:[22,49,204,232,315,362],hassl:62,hast:219,hat:[37,70,182],hau:[65,146,164,278],have:[0,1,2,3,4,5,6,9,10,11,12,13,14,15,16,19,20,21,22,23,25,26,27,28,29,30,31,33,34,35,36,37,38,39,40,41,42,43,44,46,47,48,49,50,51,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,80,81,82,83,84,85,86,87,88,89,90,91,92,93,95,96,97,98,100,102,103,104,105,106,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,144,146,150,152,153,154,156,159,161,164,167,168,169,170,171,175,176,177,179,180,181,182,184,186,187,188,189,194,195,198,202,204,205,206,209,210,215,217,218,219,220,221,224,227,233,234,238,239,241,246,247,250,251,252,253,256,258,259,260,261,272,277,285,287,305,306,307,308,310,313,314,315,316,317,318,319,321,322,323,324,325,327,328,330,336,337,340,341,342,344,345,357,362,363],haven:[4,22,29,42,62,67,77,109,111,117,118,120,127,128,133,134,138,310],hdict_cmd:166,hdict_db:166,head:[20,21,31,46,69,76,77,96,106,119,121,123,138,139],headach:[61,138],header:[9,13,14,27,34,37,38,63,89,95,103,129,138,154,175,177,199,206,247,322,324,329,330],header_color:159,header_line_char:330,headi:330,heading1:330,heading2:330,headless:[96,247],headlong:63,heal:[219,220,233],healing_rang:220,health:[30,61,73,84,88,90,109,116,190,252],health_bar:[141,142,178],hear:[29,46,61],heard:[111,122,241],heart:126,heartbeat:[115,278],heavi:[6,11,20,23,27,33,64,73,80,82,96,116,123,179,206,218,344],heavier:218,heavili:[9,27,37,40,57,75,86,104,180,217,218,219,220,221,318],heed:[105,242],heh:138,hei:[20,179,199],height:[52,74,137,141,154,272,287,306,327,330],held:[1,31,48,116,241],hello:[0,29,34,41,43,46,51,72,74,83,87,88,91,96,105,108,123,129,165,174,206,272,321],hello_funct:95,hello_valu:108,hello_world:[95,96,108],helmet:[29,77],help:[0,1,4,5,12,13,14,15,19,22,23,27,29,32,33,35,38,39,41,42,44,45,46,47,48,49,50,51,53,57,58,60,61,63,64,67,71,72,76,77,79,80,86,90,91,93,96,105,107,108,109,110,111,112,113,116,119,122,123,124,126,127,131,133,137,138,139,141,142,149,150,152,154,155,156,167,168,170,171,177,179,184,186,188,192,193,195,199,205,209,217,218,219,220,221,224,230,233,234,241,249,260,265,267,269,270,278,285,287,295,296,298,299,306,317,321,324,325,326,328,329,336,339,340,341,342,351,357,362,363,364],help_categori:[22,33,41,43,58,60,68,69,71,85,116,123,154,156,157,158,159,164,165,166,167,168,169,170,171,174,179,180,181,182,185,186,187,188,189,193,199,202,203,206,212,213,214,215,217,218,219,220,221,224,231,232,233,234,238,239,247,326,328,329,341],help_cateogori:326,help_detail:362,help_entri:326,help_kei:159,help_list:362,help_mor:166,help_system:69,help_text:[166,195,357],helpact:234,helpdetailview:362,helpentri:[69,80,237,238,239,324,362],helpentry_db_tag:237,helpentry_set:319,helpentryadmin:237,helpentryform:237,helpentrymanag:[238,239],helper:[19,41,43,51,58,67,80,109,119,141,144,153,156,159,166,173,176,180,184,205,247,251,252,264,276,277,296,308,322,328,329,337,342,343,344],helpfil:166,helplistview:362,helpmixin:362,helptaginlin:237,helptext:[51,249,328],helptext_formatt:[51,249,328],henc:[0,22,46,76,95,106,233,234,241,322],henceforth:[13,44,60,66,80,90,95,97,102,105,111,123,131,132,140,308],henddher:203,her:[122,127,182,189],herbal:327,herd:23,here:[0,2,3,4,5,9,10,11,13,14,15,16,17,19,20,21,22,23,24,25,27,29,30,33,36,37,38,39,40,41,42,43,44,46,47,48,49,51,53,56,57,58,59,61,62,63,64,65,67,69,70,71,72,73,74,75,76,77,79,80,81,83,84,85,86,87,88,89,91,92,95,98,100,101,102,103,104,105,106,107,108,109,110,111,113,114,115,116,117,118,119,120,121,123,125,126,127,128,129,130,131,133,134,135,136,137,144,146,152,153,154,159,167,168,169,171,175,179,180,181,182,184,185,186,194,195,204,205,206,213,217,218,219,220,223,224,227,231,232,233,234,235,239,242,247,251,252,259,267,269,272,276,278,285,287,305,306,308,314,315,316,318,321,324,328,330,334,336,346,362],hesit:[22,39],hfill_char:330,hidden:[11,49,61,64,96,122,131,137,177,182,185,234],hide:[9,11,20,31,33,34,41,61,73,80,96,111,138,166,177,185,206,224,232],hide_from:[34,177],hide_from_accounts_set:148,hide_from_channels_set:177,hide_from_objects_set:246,hieararci:241,hierarch:[2,19,43,80,156],hierarchi:[4,19,22,43,61,66,69,80,119,139,165,182,241],high:[4,8,20,31,55,63,80,122,152,220,247,309],higher:[7,19,25,31,41,43,44,51,56,58,62,63,73,80,90,105,108,119,123,128,144,152,156,169,205,217,218,219,220,221,233,241,269,328,344],highest:[31,58,321,344],highest_protocol:340,highli:[9,17,51,55,56,64,80,86,107,115,117,190,322,334],highlight:[14,38,57,58,114,126],hijack:134,hilight:343,hilit:343,hill:87,him:[41,46,51,189,206],hint:[1,25,55,63,79,93,95,109,110,123,124,128,136,139,184,313],hire:[85,103],his:[46,51,58,77,96,109,127,182,189,206,329,343],histogram:344,histor:[62,129,266,337],histori:[4,23,34,41,50,58,64,95,100,131,137,138,139,153,174,188,337],hit:[6,9,21,29,52,61,73,116,119,122,131,146,217,218,219,220,221,231,232,265,306,337,340],hit_msg:231,hite:114,hmm:138,hnow:114,hobbi:[61,90],hobbit:62,hoc:55,hold:[2,6,9,13,14,16,21,26,31,34,36,38,41,47,49,51,58,61,63,64,66,73,77,80,85,89,96,97,100,102,104,105,106,109,111,112,114,116,119,123,125,131,133,136,140,152,153,178,180,182,185,204,214,215,217,218,219,220,221,229,231,232,236,241,242,251,252,253,257,262,274,276,285,295,296,298,308,318,319,320,324,327,328,330,332,337,344,346],holder:[9,69,90,306],home:[8,16,26,63,64,66,70,79,89,90,103,109,131,133,139,153,159,165,231,241,246,247,252,324,344],home_loc:[43,159],homepag:[27,63,79,90,93],homes_set:246,homogen:[27,164,251,252,256],homogenize_prototyp:251,honor:206,hood:[20,33,38,51,57,60,61,64,86,87,119,122,125,128,206,234],hook:[2,25,30,33,43,49,55,60,61,73,74,76,80,81,89,96,102,107,110,115,116,117,118,120,121,123,127,132,144,150,152,154,156,159,165,167,169,173,175,182,187,195,203,204,206,210,217,218,219,220,221,228,230,231,232,233,235,244,247,254,256,259,261,271,278,295,303,305,306,307,309,318,326,329,334,335,338,342,344,357,362],hooligan:12,hop:55,hope:[42,58,91],hopefulli:[8,26,41,49,90,111,133,137],horizon:62,horizont:[138,232,330],hors:27,host1plu:90,host:[7,12,23,26,27,61,64,67,89,98,100,102,103,131,135,205,312,344],host_os_i:344,hostnam:67,hotbutton:137,hotel:90,hotspot:103,hour:[27,62,132,184,331,344],hous:[43,90,109,159],housecat:27,hover:138,how:[0,1,3,4,5,6,7,8,10,11,12,13,14,15,17,19,20,21,22,25,26,27,28,29,30,31,35,37,38,39,40,41,42,43,44,45,46,48,49,51,55,56,57,60,61,62,63,64,66,68,69,72,73,75,77,80,81,82,83,84,85,86,87,88,90,91,93,95,96,97,102,103,104,105,106,108,109,110,111,112,116,117,118,119,120,123,124,126,127,128,130,131,132,133,134,135,136,137,138,139,140,145,146,151,153,154,168,169,170,173,174,175,180,182,184,185,189,204,205,206,213,215,219,220,221,226,231,235,237,241,246,247,252,256,261,267,272,277,286,298,305,306,307,308,312,315,318,322,326,328,329,330,337,338,343,344,357,363,364],howev:[0,2,4,5,10,11,12,13,14,15,17,20,22,23,29,30,31,33,37,38,40,41,43,44,46,50,55,58,59,60,62,70,73,77,80,85,88,90,91,108,109,110,111,113,114,115,120,123,125,128,129,131,132,135,153,154,159,166,169,170,180,188,190,195,204,215,220,227,241,321],hpad_char:330,href:[17,69,133],hrs:184,html5:55,html:[24,38,43,55,64,69,79,83,96,103,114,134,135,136,137,138,145,169,175,204,234,239,295,296,312,318,340,343,362],htmlchar:343,htop:110,http404:[69,134],http:[3,4,9,22,23,36,37,38,43,45,54,55,63,65,69,70,75,83,90,95,98,103,104,107,108,124,128,130,131,133,134,135,137,138,141,146,164,180,204,234,269,276,278,279,295,296,312,321,330,343,344,357],http_request:[103,135],httpchannel:312,httpchannelwithxforwardedfor:312,httpd:8,httprequest:144,httprespons:[145,173,244],httpresponseredirect:133,hub:[79,100,139,324],hue:114,huge:[3,16,21,29,39,61,62,86,127,235,329],huh:[22,33],human:[4,12,40,51,57,61,64,73,85,93,96,117,133,362],humanizeconfig:4,hundr:[72,113,133],hungri:86,hunt:[73,231],hunting_pac:231,hunting_skil:73,hurdl:49,hurt:30,huzzah:9,hwejfpoiwjrpw09:9,hybrid:73,i18n:[47,76],iac:88,icon:[79,106,138],id_:[145,237,244,357],id_str:84,idcount:298,idea:[0,9,12,26,33,37,38,39,45,49,55,56,60,61,63,69,71,72,73,77,80,85,106,107,108,119,121,123,127,131,133,134,139,154,166,167,170,179,205,252,334,343,362,364],ideal:[1,6,33,37,46,48,90,129,138,148,242],idenfi:152,ident:[9,31,33,44,57,61,83,96,97,110,114,144,167,168,206,212,242,247,321,322],identif:[27,115,308],identifi:[0,8,23,28,30,31,33,38,39,41,42,43,49,50,51,58,61,69,74,83,84,88,93,97,102,109,115,116,119,125,134,138,151,154,159,164,167,168,170,174,176,180,187,205,206,215,233,242,247,251,258,261,264,267,272,274,277,295,304,306,308,316,317,321,326,327,328,336],identify_object:176,idl:[12,105,144,146,231,247,299,306,308],idle_command:33,idle_tim:[144,247],idle_timeout:146,idmap:334,idmapp:[43,86,125,141,142,169,177,239,274,300,316,317,318,320],idnum:176,ids:[12,58,121,187,298,308,327],idstr:[84,115,257,261,304],idtifi:176,idx:121,ifconfig:67,ifram:[137,138],ignor:[6,14,20,23,27,29,31,33,34,38,42,43,51,58,73,74,80,83,86,90,91,95,96,105,114,117,121,122,125,131,144,151,152,153,154,159,175,187,206,241,246,247,261,267,272,278,279,295,296,318,321,322,327,328,336,339,344,345],ignore_error:144,ignorecas:[159,165,166,171,174,182,321,326,343],ignoredext:312,illumin:111,illus:[10,96],imag:[4,17,63,69,70,90,101,106,133,135,136,137,138],imagesconfig:4,imagin:[14,29,31,46,48,51,61,77,116,117,122,132,138,322],imaginari:[21,79],imc2:34,imeplement:235,img:[17,70],immedi:[0,5,15,27,29,33,43,48,49,51,64,70,74,83,90,95,100,102,109,116,120,133,134,150,157,169,231,278,322,324,328,329],immobil:25,immort:231,immut:[11,261],imo:1,impact:126,impati:63,imper:102,implement:[1,6,11,21,25,26,28,29,31,33,34,37,40,41,49,51,55,56,57,58,60,61,78,79,80,81,86,88,89,96,97,108,111,112,114,115,116,117,118,119,120,123,124,125,127,128,131,135,137,138,139,140,145,148,152,153,156,157,158,159,160,161,164,165,166,167,168,169,176,177,179,181,182,184,185,187,189,202,205,206,210,212,213,214,215,217,218,221,224,231,232,233,235,238,239,241,242,246,247,256,258,261,273,278,285,287,295,296,298,305,312,316,317,318,319,321,322,325,326,328,329,335,336,339,340,343,344,362,364],impli:[22,112],implicit:[91,114,126],implicit_keep:252,impmement:242,import_cmdset:153,importantli:[51,133,242],importerror:[4,9,344],impos:[55,79,310],imposs:[15,19,38,49,51,90,111,113,121,133,138,330],impract:[33,109,252],imprecis:334,impress:[42,111],improv:[0,11,37,61,70,76,91,128],in_game_error:[26,103],in_templ:[316,336],inabl:[63,103],inaccess:[0,80],inact:[102,231],inactiv:[43,169],inadvert:221,inadyn:90,inarticul:108,inbuilt:[67,112,123],incant:75,incarn:357,incid:210,includ:[2,4,6,9,12,13,16,20,21,22,27,30,31,33,36,37,38,39,41,43,44,48,51,53,55,58,60,61,62,63,64,69,73,74,75,78,79,80,84,85,88,89,91,93,95,96,100,101,102,104,105,106,107,108,109,111,112,114,115,116,119,121,125,127,131,133,134,135,136,137,138,144,150,151,152,154,157,158,159,167,168,170,174,179,182,187,188,189,195,205,206,210,215,217,218,219,220,221,224,227,233,234,235,241,247,267,285,287,304,307,316,317,318,319,322,323,324,325,327,328,330,331,337,344],include_account:316,include_children:317,include_par:317,include_prefix:151,include_unloggedin:[285,308],inclus:[317,336],incoher:126,incol:[58,327,330],incom:[33,40,88,90,96,104,139,145,146,151,168,173,210,218,244,254,276,286,295,296,298,306,307,308,312,328,329,336],incomplet:[154,213],inconsist:[10,97,204],incorpor:[43,156,330],incorrect:176,increas:[25,62,73,80,103,114,119,125,179,218,220,221,233,279,285,299,326,328],increase_ind:326,incred:[215,269],increment:63,incur:27,indata:[40,316],inde:[9,55,90,91],indefinit:[102,219,232,324],indent:[0,9,13,14,27,38,50,51,57,60,95,129,137,296,322,326,328,344],independ:[0,56,64,102,126,179,209],indetermin:269,index:[7,38,43,49,56,61,68,79,85,86,90,108,121,135,136,151,165,179,215,232,265,269,270,312,319,321,329,330,357,360,362,364],index_to_select:215,indexerror:[134,235,317],indextest:360,indic:[0,8,22,38,43,49,51,62,85,91,95,111,119,146,159,166,167,168,189,210,215,256,278,279,287,295,308,310,312,322,328,329,344],individu:[0,11,13,14,18,21,22,33,34,41,43,46,48,49,55,57,58,59,71,73,78,85,88,90,96,109,111,132,153,157,174,185,192,195,220,227,241,249,250,252,306,319,321,330,336,338,339],ineffici:[115,117,321],infact:33,infinit:[0,61,63,146,235,251],inflict:[102,219],inflict_condit:219,influenc:[10,16,22,46,51,102,123,179,344],influenti:79,info1:214,info2:214,info3:214,info:[3,5,11,13,16,17,20,23,24,25,26,27,33,35,37,43,52,55,58,59,63,64,68,78,86,88,89,95,100,101,102,104,105,106,112,124,125,131,138,139,144,146,148,156,157,159,169,171,175,178,179,181,186,187,190,199,233,239,247,267,272,276,285,305,306,308,317,318,319,324,327,337,344],infomsg:337,inforamt:[206,235,247,318],inform:[0,2,3,6,8,9,18,20,22,23,25,27,28,33,34,36,38,41,43,46,48,51,55,60,65,66,68,69,73,83,84,85,86,91,95,96,100,102,103,104,105,109,112,114,116,117,119,120,123,124,127,131,132,133,134,135,136,137,138,139,144,146,154,157,159,164,165,169,174,177,180,185,204,206,210,211,219,220,221,239,247,259,267,272,285,307,308,317,318,321,324,326,337,344,357],infrastructur:[64,83,90,103,150,277],infrequ:46,ing:[9,14,58,185],ingame_python:[141,142,178],ingame_tim:62,ingo:[31,51,58,74,114,152,279,336],inher:[4,10,87,108],inherit:[2,5,6,22,27,30,31,33,36,40,42,43,57,60,64,69,81,86,89,96,102,109,114,117,119,123,125,127,148,152,154,159,167,169,170,175,177,179,180,182,187,189,203,206,213,217,218,219,220,221,230,231,233,234,243,246,247,252,256,258,307,314,317,318,326,329,330,334,342,344,362],inheritng:252,inherits_from:[43,117,134,169,344],inifinit:251,init:[6,9,22,38,40,47,49,58,60,63,75,83,95,104,106,131,137,138,179,180,188,224,246,258,267,285,286,296,308,344],init_delayed_messag:188,init_django_pagin:329,init_evt:329,init_f_str:329,init_fill_field:188,init_game_directori:267,init_iter:329,init_menu:230,init_mod:[153,258],init_new_account:344,init_pag:[251,329],init_pars:234,init_queryset:329,init_rang:221,init_sess:[40,307],init_spawn_valu:251,init_str:329,init_tree_select:215,init_tru:153,initi:[5,9,11,21,29,33,38,47,49,50,51,58,60,61,64,68,73,85,97,105,107,110,120,123,127,130,131,133,137,138,144,145,146,153,154,170,174,175,177,179,186,188,192,196,198,205,206,215,217,218,219,220,221,230,231,232,237,244,246,247,251,257,260,261,264,265,267,269,270,271,276,277,278,285,286,287,295,296,298,306,307,308,315,316,321,323,326,327,328,329,336,339,340,344,351,357,362],initial_formdata:188,initial_ind:330,initial_setup:[141,142,262,305],initialdelai:[264,278,279],initialize_for_combat:[217,218,219,220,221],initialize_nick_templ:[316,336],initil:295,inject:[96,103,306,328],inlin:[18,57,85,104,137,145,173,237,244,254,265,315,336],inlinefunc:[45,83,104,109,141,142,250,308,320],inlinefunc_en:[114,336],inlinefunc_modul:[114,336],inlinefunc_stack_maxs:114,inlinefuncerror:336,inlinefunct:[114,336],inmemorysavehandl:339,inner:77,innoc:[12,43,157],innocu:103,inobject:276,inp:[51,159,176,251,265,329,344],inpect:51,input:[1,5,9,10,14,15,17,20,22,27,30,31,40,41,43,50,53,55,57,58,70,74,79,83,87,91,95,96,104,105,109,110,111,113,114,115,118,127,131,133,135,137,138,144,149,150,151,154,159,164,166,167,168,169,170,174,176,180,185,188,205,206,210,215,220,232,238,247,250,251,252,265,272,276,287,295,306,308,316,317,319,326,327,328,329,330,336,338,340,344,345,357],input_cmdset:328,input_func_modul:[74,272],input_str:328,input_validation_cheat_sheet:357,inputcmdset:328,inputcommand:[74,83,88],inputcompon:137,inputdebug:[74,272],inputfunc:[40,45,104,139,141,142,146,262,295,306,308,364],inputfunc_nam:295,inputfunct:74,inputhandl:141,inputlin:[43,87,165,316,317],insecur:90,insensit:[51,174,187,206,233,317,349],insert:[13,14,25,50,51,58,64,71,87,96,109,114,138,153,189,202,250,322,328,330,336,344],insid:[0,5,10,11,13,15,19,20,21,23,25,27,28,31,33,38,42,43,46,47,51,57,59,64,67,68,69,71,72,73,80,82,83,85,86,88,89,91,92,93,95,96,100,102,105,106,108,109,110,111,114,117,121,123,125,127,132,133,134,135,136,139,141,146,169,180,187,190,194,195,206,231,233,235,241,246,247,250,267,305,312,322,323,326,336,344],inside_rec:241,insiderecurs:241,insight:[20,41,42,122,136],insist:[90,91],inspect:[12,23,43,51,85,144,159,179,265,267,328],inspectdb:86,inspir:[33,41,73,116,127,129,181,189,330,344],instac:[154,247,306],instal:[0,3,5,14,20,26,37,38,41,42,46,47,54,55,57,58,59,60,64,65,76,77,79,95,96,97,98,101,103,106,108,110,124,127,128,130,134,138,139,141,179,181,182,183,185,186,187,199,202,203,206,210,212,213,217,218,219,220,221,363,364],installed_app:[4,69,86,127,133,134],instanc:[0,2,3,8,11,16,17,22,25,27,28,29,39,41,42,43,46,50,51,56,57,58,59,60,61,62,64,69,76,84,85,91,95,96,97,102,103,105,107,109,116,119,121,126,127,131,136,137,144,145,148,150,151,152,153,154,163,166,168,169,173,175,177,180,195,198,204,215,234,235,237,239,244,246,247,251,252,254,256,260,261,264,267,276,277,278,279,285,298,299,307,308,312,315,316,318,319,321,324,325,328,330,334,335,340,344,345,357],instanci:180,instant:136,instanti:[33,86,127,144,153,170,224,258,261,305,308,327],instantli:315,instead:[0,3,6,9,10,11,12,14,16,19,20,21,22,23,25,26,27,29,30,31,33,34,37,39,41,43,46,48,49,51,57,58,60,62,63,64,67,79,80,83,84,85,86,89,90,91,93,95,96,100,102,103,104,105,106,109,110,111,112,114,116,117,118,119,121,123,125,126,127,128,131,132,133,134,135,136,138,139,144,146,153,154,156,157,159,161,164,168,169,171,180,185,186,188,198,206,213,215,217,218,219,220,221,226,230,232,234,235,241,242,247,252,261,267,295,296,306,310,315,316,318,319,324,328,329,334,337,339,340,341,344,357,362],instig:157,instil:[140,219],instnac:260,instr:[276,344],instruct:[0,8,9,13,14,23,27,30,37,38,42,43,46,47,55,57,58,60,61,63,67,74,75,77,79,83,85,90,93,96,97,100,106,119,124,131,139,144,154,169,206,210,252,261,264,267,277,279,285,295,296,298,306,308,328,338],integ:[25,31,33,39,85,91,105,109,114,123,125,151,182,184,185,188,217,218,219,220,221,233,241,247,250,317,336,340,344,345],integerfield:[133,357],integr:[4,7,41,45,61,64,76,79,103,134,137,139,170,206,270,272,328,364],intellig:[73,83,91,103,134,153,298],intend:[13,17,20,22,27,31,33,34,37,42,55,61,90,103,108,109,111,112,114,122,126,131,136,137,144,164,179,180,206,227,239,247,252,285,317,319,324,325,327,330,336,341,342,344,345,362],intens:[79,93,114],intent:[51,76,96,103,205,344],inter:13,interact:[2,20,23,29,33,40,42,43,51,55,56,59,61,77,79,100,106,108,110,116,122,133,138,141,158,221,226,267,322,337,344],intercept:308,interchang:[116,328,362],interest:[0,1,4,11,14,20,21,22,26,33,37,40,42,46,49,55,57,60,61,70,79,86,90,91,93,96,103,109,114,119,120,121,123,136,153,168,179,184,233,235],interf:63,interfac:[9,21,22,23,25,36,40,42,43,63,64,69,70,79,80,90,96,97,101,104,119,133,135,137,138,139,156,159,173,175,247,259,278,307,312,319,321,362],interfaceclass:287,interfer:[23,97,251],interim:[29,115],interlink:305,intermediari:[206,242,257,328],intern:[10,11,15,27,34,38,40,51,63,76,80,87,88,90,100,102,103,104,105,107,109,110,112,113,116,128,144,146,174,177,186,189,206,235,247,251,258,295,296,316,318,319,321,325,328,330,336,344],internal:328,internal_port:90,internation:[7,113,139,364],internet:[10,12,16,33,40,43,63,67,72,90,103,124,157,264,269,277,278,279,287,298,312],interpret:[33,42,43,56,59,60,91,93,96,102,103,104,109,134,154,158,159,251,252,295,321,336,340],interrupt:[63,150,154,170,192,195,198,287],interruptcommand:[33,91,141,150,154],interruptev:198,intersect:[31,152],interv:[64,74,102,115,116,120,121,132,146,184,195,217,218,219,220,221,223,226,227,231,233,250,256,259,261,272,324,331],interval1:261,intim:[31,33],intimid:58,intoexit:[43,159],intpropv:123,intricaci:62,intrigu:54,intro:[4,69,122,124,134,230,233],intro_menu:[141,142,178,229],introduc:[26,29,31,57,73,97,123,124,127,131,139,206],introduct:[3,13,14,15,18,19,20,45,60,61,63,124,127,131,139,180,363,364],introductori:[55,63],introroom:233,introspect:203,intrus:126,intuit:[22,51,61,86,91,131,139,152],intxt:27,inv:[31,43,82,165,182],invalid:[11,41,60,91,109,144,188,206,227,251,330,340,344,345],invalid_formchar:327,inventori:[20,21,25,27,31,80,85,91,97,119,138,165,182,206,241,247,318],invers:[80,114,126,206,343],invert:[114,126],investig:90,invis:24,invit:[0,10,61,77],invitingli:20,invok:[11,13,14,102,209,241],involv:[40,56,61,68,75,80,89,105,107,116,123,188,221,318,319,321],ioerror:322,ipregex:157,ipstart:[63,100,110],iptabl:103,ipython:[26,58,59,96],irc2chan:[72,164],irc:[7,9,26,34,43,55,60,63,70,79,98,131,138,139,141,142,146,164,172,262,272,275,285,308,363,364],irc_botnam:146,irc_channel:146,irc_en:[72,164,241],irc_network:146,irc_port:146,irc_rpl_endofnam:279,irc_rpl_namrepli:279,irc_ssl:146,ircbot:[146,279],ircbotfactori:[146,279],ircclient:[279,308],ircclientfactori:285,irchannel:[43,72,164],ircnetwork:[43,72,164],ircstatu:164,iron:179,irregular:[223,231,233],irregular_echo:231,irrelev:[103,276],irur:52,is_account_object:56,is_act:[145,256],is_aggress:117,is_anonym:[4,69],is_anyon:4,is_authent:133,is_ban:144,is_bot:148,is_build:4,is_categori:215,is_channel:[33,41,174],is_connect:[148,247],is_craft:29,is_exit:[33,154],is_fight:29,is_full_moon:25,is_giving_light:232,is_gm:58,is_in_chargen:123,is_in_combat:[217,218,219,220,221],is_inst:27,is_it:344,is_iter:344,is_lit:[232,233],is_next:[148,177,246,256,316,318],is_o:344,is_ouch:11,is_prototype_bas:251,is_sai:118,is_staff:145,is_subprocess:344,is_superus:[2,4,144,145,148,242,247,324],is_thief:[43,166],is_turn:[217,218,219,220,221],is_typeclass:[144,318],is_valid:[102,121,133,179,227,256,259],is_valid_coordin:235,isalnum:321,isalpha:321,isbinari:[278,295],isclos:137,isconnect:137,isdigit:[58,114,321],isfiremag:28,isinst:[39,344],isleaf:296,islow:321,isn:[0,4,17,22,41,42,46,50,56,62,63,69,91,119,138,180,192,196,221,233,234,269,315,321,338,349],isnul:340,iso:[15,113],isol:[13,37,61,63,64,91,95,100,127],isp:[90,103],isspac:321,issu:[7,8,10,11,13,14,21,22,23,29,31,33,37,38,42,43,45,48,54,58,60,63,70,79,85,89,90,93,103,108,123,125,126,127,131,138,140,164,251,267,298,299,330,363],istart:[42,110,141],istep:299,istitl:321,isub:116,isupp:321,itch:[61,63],item:[20,43,47,51,59,63,68,69,82,85,86,116,117,138,165,179,182,188,206,219,224,235,247,286,316,336,344],item_consum:219,item_func:219,item_kwarg:219,item_selfonli:219,item_us:219,itemcoordin:235,itemfunc:219,itemfunc_add_condit:219,itemfunc_attack:219,itemfunc_cure_condit:219,itemfunc_h:219,itend:344,iter:[11,49,51,59,97,112,119,138,144,206,235,247,252,259,296,298,316,318,321,322,325,329,344],iter_cal:329,iter_to_str:344,itl:[22,180],its:[0,2,3,5,9,11,12,14,15,16,20,21,22,23,25,27,29,31,33,37,38,39,40,41,42,43,44,49,50,51,52,55,56,57,58,60,61,62,63,64,65,68,69,70,72,73,75,80,81,82,83,84,85,86,88,89,90,91,93,95,96,98,100,101,102,103,104,105,109,111,114,115,117,118,119,121,122,123,124,125,126,127,128,129,130,131,133,134,135,136,137,138,139,144,145,146,148,150,151,152,153,154,157,159,167,168,169,175,176,179,180,188,189,195,203,205,206,213,215,217,218,219,220,221,226,227,231,232,234,235,241,246,247,252,259,260,261,267,272,276,295,296,299,307,308,312,313,315,316,317,318,319,322,327,328,330,334,336,337,338,339,340,341,344,357,362],itself:[0,4,9,11,15,17,20,21,22,23,25,27,29,33,36,37,40,41,44,45,46,47,49,51,55,60,63,64,68,75,77,78,80,82,85,86,89,96,104,105,106,111,114,115,116,118,119,122,123,125,127,131,133,134,135,136,144,146,174,175,180,185,188,198,204,206,215,220,223,232,233,235,236,241,247,249,252,260,267,296,308,312,315,316,319,321,324,326,328,339,341,344,346,357,362],iusernamepassword:287,iwar:85,iweb:90,iwebsocketclientchannelfactori:278,iwth:261,jack:87,jail:[12,13],jamochamud:24,jan:[12,62],januari:62,jarin:90,javascript:[55,83,88,103,135,136,137,138,295,296],jenkin:[123,182,188,190,215,217,218,219,220,221],jet:220,jetbrain:[79,106],jnwidufhjw4545_oifej:9,job:[33,41,67,69,80,144],jobfusc:205,john:[58,214],johnni:[209,210],johnsson:87,join:[9,22,34,43,49,58,61,63,65,72,96,112,116,119,123,133,144,164,175,179,205,321,344],join_fight:[217,218,219,220,221],join_rangefield:221,joiner:175,jointli:[64,153],joke:59,joker_kei:[22,180],jqueri:138,json:[83,88,137,138,209,278,295,296,325],jsondata:88,jsonencod:296,jsonifi:296,judgement:73,jump:[13,14,21,41,44,49,51,52,55,61,63,77,89,108,131,139,215,265],junk:276,just:[0,1,3,4,5,6,9,10,11,12,13,14,15,17,19,20,21,22,23,25,26,27,28,29,30,31,33,34,37,38,39,40,41,42,43,44,46,47,48,49,51,52,54,56,57,58,59,60,61,62,63,64,68,69,70,73,74,76,77,79,80,81,83,85,86,87,88,89,90,91,93,95,96,97,100,101,102,105,106,107,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,125,126,127,128,131,132,133,134,135,136,137,138,140,144,152,153,154,157,159,167,168,169,170,174,179,180,182,185,187,192,194,195,206,214,215,217,218,219,220,221,224,227,231,233,235,241,242,247,251,252,257,272,285,295,305,312,316,317,318,321,322,325,326,328,330,339,340,344,345,362],justif:[329,344],justifi:[96,109,250,321,329,344],justifii:329,justify_kwarg:329,kcachegrind:93,keen:37,keep:[0,1,4,7,9,11,13,14,15,16,20,25,26,29,30,33,34,42,45,48,51,56,57,58,60,61,62,63,64,68,69,73,75,76,77,78,81,82,85,91,92,95,96,97,100,105,109,116,118,121,122,126,128,131,132,133,134,138,146,153,187,190,195,204,209,227,232,233,251,252,258,269,310,328,330,344],keep_log:[34,175,324],keepal:[105,296],keeper:85,keepint:64,kei:[0,1,5,8,9,10,11,13,21,25,26,27,28,29,30,31,33,34,38,39,41,42,43,44,49,50,52,56,57,58,60,62,69,71,74,80,81,82,84,85,86,88,89,91,95,96,97,102,107,111,112,114,115,116,119,120,121,123,125,127,129,131,133,137,138,144,146,148,150,152,153,154,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,174,175,176,179,180,181,182,184,185,186,187,188,189,193,194,199,202,203,205,206,212,213,214,215,217,218,219,220,221,224,230,231,232,233,234,235,239,241,246,247,250,251,252,256,257,258,259,260,261,265,267,272,273,274,276,285,295,296,299,306,307,308,310,316,317,318,319,323,324,326,327,328,329,337,338,339,341,344,357,362],kept:[33,43,57,80,91,119,127,159,194,195,252],kept_opt:215,key1:202,key2:[51,202,247],key_mergetyp:[31,152,224],keyboard:138,keydown:137,keyerror:[251,261,339],keynam:[175,252,324],keypair:287,keys_go_back:[22,180],keystr:319,keystrok:287,keywod:330,keyword:[0,1,5,10,11,22,25,27,29,30,33,34,43,50,51,52,58,62,74,80,81,83,86,91,93,95,102,107,109,114,115,119,123,125,127,134,144,146,150,154,159,165,175,182,184,187,192,194,195,198,205,206,210,217,218,219,220,221,233,234,242,247,250,251,252,257,260,261,265,267,272,276,278,279,285,286,287,295,296,305,306,307,308,310,316,317,318,324,327,328,329,330,334,336,338,340,341,344,362],keyword_ev:198,kick:[12,31,43,51,58,90,146,152,157,164,171,186,247,329],kildclient:24,kill:[20,27,43,51,61,75,93,100,102,105,116,169,179,231,232,257,258,259,261,267,305,312],killsign:267,kilogram:82,kind:[0,11,37,38,40,80,91,97,104,116,118,119,121,133,138,217,218,219,220,242,318,345],kinda:138,kindli:126,kitchen:[43,44,159],knew:95,knock:51,knot:182,know:[0,2,5,6,8,10,11,13,14,15,16,20,21,22,23,26,29,31,33,37,38,39,40,41,42,43,44,48,49,51,54,56,57,58,60,61,64,67,69,70,72,73,74,79,80,81,82,83,84,85,86,89,90,91,93,95,96,97,98,100,102,104,105,110,111,113,114,116,117,118,119,121,125,126,127,128,131,132,133,134,136,138,139,154,158,159,167,168,170,174,179,194,199,205,215,220,232,246,247,272,306,308,315,322,323,328,344,362,363],knowledg:[13,15,33,55,77,308],known:[7,20,24,33,50,73,79,80,87,92,96,109,114,115,125,134,137,143,168,220,329],knuth:93,kobold:61,koster:79,kovash:51,kwarg:[1,10,25,29,33,40,41,51,58,59,74,80,81,83,84,88,96,107,109,114,115,118,121,125,132,134,137,144,145,146,147,148,150,154,156,157,158,159,164,165,166,167,168,169,170,171,174,175,176,177,179,180,181,182,184,185,186,187,188,189,192,193,194,195,199,202,203,204,205,206,210,212,213,214,215,217,218,219,220,221,223,224,226,227,230,231,232,233,234,235,238,239,241,242,244,245,246,247,249,250,251,252,255,256,257,259,260,261,264,265,272,273,274,276,277,278,279,285,286,287,295,296,300,306,307,308,309,310,312,315,316,317,318,319,321,326,327,328,329,330,331,333,334,336,337,338,339,340,341,342,344,345,357,362],label:[48,70,86,112,133,140,357],label_suffix:[145,237,244,357],laborum:52,lack:[13,38,56,61,70,129,206,247,344],ladder:58,lag:[49,63],lai:[1,48],lair:14,lambda:[10,39,51,69,109,195,252],lamp:[111,224,226,227],land:[91,116,231,232],landscap:[103,111],lang:205,langcod:206,langnam:206,languag:[7,15,38,40,47,55,56,57,58,64,79,91,95,103,108,113,114,118,124,125,127,129,130,137,139,205,206],language_cod:76,languageerror:[205,206],languageexistserror:205,languagehandl:205,larg:[10,11,13,14,16,20,23,37,51,55,56,61,86,90,96,97,108,109,122,127,205,235,251,285,322,327,329,334],larger:[14,20,49,57,61,68,80,82,86,108,187,321,334,344],largesword:86,laser:77,last:[4,11,13,14,22,26,29,31,33,34,36,42,43,48,51,54,58,60,69,74,76,86,87,89,90,91,95,96,105,107,110,116,121,122,126,127,131,134,136,137,150,151,153,159,164,165,179,184,187,195,206,215,217,218,219,220,221,227,247,271,321,322,323,328,329,330,331,337,344],last_cmd:33,last_initial_setup_step:305,last_login:145,last_nam:145,last_step:271,lastcast:28,lastli:[81,83,111,133,150],lastsit:25,late:[251,323],later:[0,2,9,11,12,13,22,23,33,34,38,40,43,46,55,58,60,61,63,64,69,73,74,76,81,83,84,86,90,95,97,109,111,114,115,117,120,121,123,125,131,133,138,139,140,152,156,157,159,167,168,184,203,206,252,261,287,319,344],latest:[20,21,27,31,36,38,43,58,63,64,75,83,98,131,159,164,169,247,252,286,310,328,337,363],latin:[15,113,344],latinifi:344,latter:[6,27,29,34,64,77,80,89,91,95,115,126,206,256,258,319],launch:[14,21,54,63,75,85,90,93,102,106,110,122,127,138,153,224,266,267,277,279,298,326,344],launcher:[93,106,266,267,276,277,298],law:79,layer:[22,31,246,318],layout:[27,49,56,58,96,119,125,128,137,138,235],lazi:344,lazy_properti:344,lazyencod:296,lazyset:337,lc_messag:76,lcnorth:114,ldesc:56,ldflag:75,lead:[0,11,13,17,20,22,23,31,37,43,49,51,56,60,61,64,69,79,83,86,102,103,111,121,144,151,152,159,169,195,198,204,212,247,252,306,318,328,330,336,344],leak:135,lean:206,leap:[62,118],learn:[0,15,16,17,20,22,29,31,33,42,46,49,56,57,60,63,68,69,79,80,81,95,96,106,108,118,122,124,126,127,131,134,136,139,205,220,364],learnspel:220,least:[3,8,33,39,42,47,49,51,55,57,58,61,67,73,80,86,90,96,102,106,121,138,144,153,176,179,205,238,247,252,259,321,327,330,341,344],leasur:231,leather:85,leav:[0,2,20,21,22,25,43,58,60,73,74,77,85,93,95,102,103,116,123,137,138,156,158,159,164,175,179,180,233,235,241,247,260,295,296,328,334],leavelock:241,leaver:175,left:[22,27,33,36,39,41,43,57,69,74,80,85,86,91,101,102,109,111,114,137,138,144,159,165,167,168,190,217,218,219,220,221,232,235,242,250,252,318,321,330,344,363],left_justifi:[109,250],leg:304,legaci:[88,109,144,206],legal:[90,103],legend:[49,50],leisur:345,len:[25,49,58,71,85,109,114,116,119,120,121,151,168,184,344],lend:50,length:[22,23,25,49,62,66,68,71,83,86,90,91,95,122,151,184,188,190,198,205,206,269,310,316,321,330,344,362],lengthi:[1,25],lengthier:363,lenient:109,less:[22,34,44,51,56,61,64,73,86,90,91,106,108,116,119,132,133,139,184,218,220,316],let:[0,3,5,7,8,9,11,12,14,15,20,21,22,25,28,31,33,37,39,40,41,43,44,46,48,49,51,56,57,58,60,61,62,63,64,65,70,72,73,74,75,77,80,81,82,83,85,89,91,93,95,96,98,103,106,111,114,115,117,118,119,121,123,124,126,127,131,133,134,136,137,140,144,154,159,165,166,170,174,179,182,185,188,190,215,227,235,242,247,277,296,308,324,328,338,343,357,362,363],letsencrypt:[67,90],letter:[15,22,39,43,76,90,95,111,113,114,119,123,133,156,165,180,204,311,344],level:[2,11,13,19,20,22,26,27,30,36,38,40,41,43,47,50,51,55,57,58,61,66,69,71,73,79,80,85,90,95,96,104,105,108,111,112,119,122,125,130,133,138,139,140,144,156,161,162,180,181,184,199,205,215,241,247,251,252,269,306,316,318,324,326,331,336,344,362],lever:[33,125],leverag:[3,38],levi:86,lhs:[25,58,167,168],lhslist:[167,168],lib:[63,67,75,97],libapache2:8,libcrypt:75,libjpeg:75,librari:[6,13,26,45,53,56,57,63,64,75,76,78,79,91,95,100,103,108,109,125,127,128,133,136,137,138,178,204,234,251,252,318,330,344],licenc:321,licens:[37,45,79,106,139,204,321,364],lid:[224,226,227],lidclosedcmdset:224,lidopencmdset:224,lie:111,lies:[33,131],life:[11,37,62,87,95,126,184,231],lift:[20,73,80,96,123,221,242],lifter:80,light:[14,23,27,38,61,102,108,122,153,218,232,233,241,252,260,321],lightabl:232,lighter:[114,218],lightest:27,lightli:[16,218],lightsail:90,lightsourc:232,lightsource_cmdset:232,like:[0,2,3,5,6,8,9,10,11,12,14,15,16,17,19,20,21,22,23,25,26,27,28,29,30,31,33,34,35,36,37,38,39,40,41,42,43,44,45,46,48,49,51,52,53,54,55,57,58,59,60,61,62,63,64,65,67,68,69,70,71,72,73,74,75,76,77,79,80,81,83,84,85,86,88,89,90,91,93,95,96,97,100,102,103,104,105,106,107,108,109,111,112,114,115,116,117,118,119,120,121,125,126,127,128,129,131,132,133,134,135,136,137,138,139,140,144,146,148,149,151,152,153,156,158,159,164,167,168,171,172,175,176,179,180,182,186,187,188,189,190,198,204,205,206,212,213,215,217,218,219,220,221,224,227,233,234,235,239,241,242,246,247,250,251,252,272,296,301,305,307,308,316,317,318,321,322,324,327,328,329,330,331,334,338,340,341,344,357,362,364],limbo:[0,9,13,14,20,22,27,43,59,63,66,104,111,121,122,134,159,180,233,271],limbo_exit:111,limit:[0,2,6,11,16,19,20,25,26,27,28,31,33,34,37,43,46,51,53,55,58,61,64,68,71,80,86,90,91,95,102,104,109,112,116,123,125,126,127,138,140,144,156,157,158,159,175,176,182,195,206,215,217,219,220,227,238,239,242,247,252,256,259,261,272,285,310,316,317,318,319,322,324,326,337,341,344,362],limit_valu:144,limitedsizeordereddict:344,line:[0,4,5,9,10,13,14,15,19,22,23,25,26,27,29,30,31,33,34,36,38,39,41,43,45,46,48,51,53,54,56,57,58,59,60,61,62,63,67,69,74,76,81,83,86,87,89,90,91,92,93,95,96,97,98,100,104,108,109,110,111,114,119,121,123,125,127,128,133,134,137,138,139,141,144,150,153,159,166,168,169,180,185,186,188,202,205,206,215,234,235,251,267,272,287,295,306,318,322,326,327,328,329,330,337,344,357,362],linear:49,linebreak:[69,343],lineeditor:326,lineend:343,lineno:38,linenum:326,liner:279,linereceiv:287,linesend:296,lingo:[57,86,105,135],linguist:344,link:[2,3,4,9,14,17,18,20,22,25,29,31,33,37,39,40,46,48,49,51,54,55,57,63,64,69,70,72,85,89,90,96,98,105,111,119,121,123,124,128,131,133,134,139,144,148,159,164,192,224,227,234,241,242,247,256,265,267,278,287,318,343,344,364],link_ok:241,linklock:241,linknam:54,linkref:38,linktext:38,linod:90,linux:[4,8,9,23,25,38,64,67,72,75,87,90,93,97,100,106,131,209,344],liquid:318,list:[0,1,2,3,4,6,7,11,12,13,14,15,20,22,23,25,27,31,33,34,37,39,40,41,43,45,46,48,49,51,54,55,57,58,59,60,61,63,66,68,69,70,72,73,74,76,77,79,80,82,85,86,88,89,90,91,93,95,96,97,98,102,103,105,106,109,110,111,112,113,114,116,118,119,121,123,124,125,128,129,131,133,134,135,137,138,139,144,146,148,151,152,153,154,156,157,158,159,164,165,166,167,168,169,170,174,175,176,177,179,180,181,182,183,187,188,189,190,192,193,195,196,198,199,202,203,204,205,206,209,210,215,217,218,219,220,221,230,231,232,235,238,241,242,246,247,250,251,252,257,258,259,261,265,267,272,273,277,279,285,286,296,299,306,308,310,312,315,316,317,318,319,321,322,323,324,325,328,329,330,336,337,338,341,344,362,363],list_attribut:159,list_callback:193,list_displai:[145,173,237,244,254,263,315],list_display_link:[173,237,244,254,263],list_filt:[244,315],list_nod:328,list_of_all_rose_attribut:11,list_of_all_rose_ndb_attr:11,list_of_lycanthrop:119,list_of_myscript:102,list_prototyp:251,list_select_rel:[173,237,244,254,263],list_set:267,list_styl:156,list_task:193,list_to_str:344,listabl:[43,159],listcmdset:[43,159],listcmset:[43,159],listen:[2,12,34,41,43,67,80,103,105,124,137,139,164,175,205,206,224,241,362,364],listing_contact:54,listobj:[43,169],listobject:[43,169],listscript:[43,169],liststr:344,listview:362,lit:[232,233],liter:[13,20,38,43,57,66,109,165,250,321,340,344],literal_ev:[51,251,315,328],littl:[0,4,9,10,15,20,21,25,28,33,34,38,41,42,57,58,60,64,69,70,71,85,90,91,96,100,102,109,110,111,117,118,119,125,131,134,136,138,139,218,230,233,302,328,344,357],live:[8,23,38,60,63,67,70,79,90,100,106],ljust:321,lne:215,load:[6,11,12,13,15,26,29,31,33,43,44,50,51,56,57,58,60,61,69,73,82,83,97,103,106,109,111,121,123,127,136,137,138,148,153,165,166,169,177,187,195,205,239,242,246,247,256,260,271,274,276,307,316,318,319,322,323,326,335,338,339,342,344,355],load_buff:326,load_data:323,load_kwarg:339,load_module_prototyp:251,load_sync_data:307,loader:[51,318,344],loadfunc:[50,326,339],loc:[43,159],local0:67,local:[23,25,36,37,47,59,62,64,67,72,76,97,100,103,106,114,131,133,138,192,195,206,252],localecho:90,localevenniatest:342,localhost:[3,4,9,23,24,63,67,69,75,90,95,133,134,135,137,296],localstorag:138,locat:[0,2,4,6,8,9,11,12,13,20,21,25,27,30,31,33,35,38,39,43,46,47,48,49,51,57,58,59,63,64,66,73,74,77,80,85,89,90,91,96,100,102,103,109,111,112,114,117,118,119,121,122,123,125,127,128,131,133,135,136,137,140,144,150,159,165,169,176,180,181,182,187,203,206,212,231,233,235,241,246,247,252,296,305,317,318,319,322,324,328,330,337,341],location_nam:235,location_set:119,locations_set:[119,246],locattr:[232,241],lock:[4,6,10,12,19,20,21,22,23,25,28,29,31,33,34,39,41,44,45,47,48,53,58,60,62,68,71,82,85,89,90,96,104,109,110,112,123,125,133,138,139,141,142,144,145,154,156,157,158,159,164,165,166,168,169,170,171,175,177,179,180,181,182,185,186,187,189,192,193,195,196,199,202,203,206,212,214,224,231,232,233,235,237,239,246,247,251,252,312,316,318,324,326,328,338,345,364],lock_definit:242,lock_func_modul:[80,242],lock_storag:[154,156,157,158,159,164,165,166,167,168,169,170,171,174,177,179,180,181,182,185,186,187,188,189,193,199,202,203,206,212,213,214,215,217,218,219,220,221,224,231,232,233,234,239,247,316,318,326,328,329],lockabl:[58,212],lockablethreadpool:312,lockdown:[80,316],lockdown_mod:90,lockexcept:242,lockfunc1:80,lockfunc2:80,lockfunc:[25,33,43,53,80,104,121,141,142,159,240],lockhandl:[11,48,80,125,141,142,154,180,234,240,241],lockset:247,lockstr:[4,11,33,43,80,97,109,159,164,166,175,177,212,241,242,247,252,316,324],locktest:136,locktyp:[152,252],log:[2,4,5,6,8,10,11,12,20,21,23,24,25,33,34,35,36,39,43,44,45,47,51,53,55,57,58,59,60,63,64,65,66,67,71,72,73,74,75,76,83,86,89,90,93,100,101,102,105,106,107,110,111,114,121,122,123,128,130,131,133,134,135,137,138,144,153,157,171,175,181,186,188,209,210,247,256,260,267,272,276,277,285,287,298,299,300,306,308,310,312,318,324,336,337,344,362,364],log_dep:[27,337],log_depmsg:337,log_dir:209,log_err:[27,337],log_errmsg:337,log_fil:[27,337],log_info:[27,337],log_infomsg:337,log_msg:337,log_sec:337,log_secmsg:337,log_serv:337,log_trac:[27,102,118,120,337],log_tracemsg:337,log_typ:337,log_typemsg:337,log_warn:[27,337],log_warnmsg:337,logdir:36,logentry_set:148,logfil:[267,337,362],logged_in:105,loggedin:285,logger:[27,53,102,118,120,141,142,209,279,320],logic:[0,4,10,39,41,42,44,49,69,97,111,134,205,246,250,271,328,345],login:[2,4,7,9,25,33,35,43,51,55,69,70,80,90,97,101,105,107,131,133,139,144,156,171,186,242,271,272,287,295,296,299,308,344,349,351,360,364],login_func:299,loginrequiredmixin:362,logintest:360,logout:[298,299,360],logout_func:299,logouttest:360,logprefix:[277,287,312],lone:[43,61,111,159],long_descript:54,long_running_funct:10,long_text:52,longer:[0,21,25,29,33,41,43,50,52,54,58,69,79,86,91,102,115,124,125,126,129,152,157,175,182,205,206,213,217,218,219,220,221,257,260,326,330],longest:[27,206],longrun:33,loo:[154,170],look:[0,3,4,6,9,10,11,12,13,14,15,16,17,19,20,21,22,23,25,26,27,29,30,31,33,35,36,37,38,39,40,41,42,44,46,48,49,51,55,57,58,60,61,62,63,64,67,68,69,70,71,73,74,75,76,77,80,81,82,83,85,86,87,88,89,90,91,96,97,100,103,105,108,109,110,111,112,114,116,117,118,119,121,122,124,125,126,127,131,133,134,135,136,138,139,144,146,151,153,154,156,159,165,167,168,170,171,174,181,182,186,187,188,194,202,203,205,206,215,219,224,230,232,233,235,238,241,242,244,246,247,249,252,272,287,295,299,316,318,322,328,329,330,338,341,343,357,364],look_str:144,lookaccount:58,lookat:33,looker:[49,58,60,123,182,187,206,235,241,247,318],lookm:33,lookstr:247,lookup:[11,33,43,80,86,97,112,119,150,165,209,246,286,319,321,333,334,340,341,344,345],lookup_typ:340,lookup_usernam:51,lookuperror:321,loom:111,loop:[0,5,6,11,21,46,49,55,60,64,69,85,93,96,116,118,119,124,125,141,146,217,252,285],loopingcal:[259,270],loos:[14,37,144,182,221,238,287,298,322],loot:61,lop:119,lore:58,lose:[11,56,61,100,105,110,116,123,138,209,219,278,279,287],lost:[0,38,39,43,56,79,91,110,111,125,135,139,164,213,264,277,278,279,287,295,321],lot:[0,4,10,13,15,22,26,27,28,34,37,39,41,42,46,53,55,57,58,59,61,62,63,67,69,70,73,79,80,86,90,91,93,95,96,108,109,111,112,114,119,121,123,125,127,131,133,135,138,180,184,186,188,206,214,218,232,235,312],loud:21,love:137,low:[31,40,46,66,90,95,152],lower:[2,10,19,25,29,31,33,41,43,49,51,58,62,80,85,86,90,93,114,122,137,151,152,156,167,169,206,272,321],lower_channelkei:[41,174],lowercas:[95,154,321],lowest:[66,90,241,321],lpmud:129,lpthw:77,lsarmedpuzzl:203,lspuzzlerecip:203,lst:[49,324],lstart:50,lstrip:[91,119,321],ltto:114,luc:327,luciano:79,luck:[8,51,91,96],luckili:[60,80,111,127,131],lue:114,lug:55,lunch:46,luxuri:[112,314],lycanthrop:119,lying:111,m2m:319,m2m_chang:107,m_len:344,mac:[9,23,24,38,64,93,100,106,131,344],machin:[13,25,100,106,131,231],macport:[63,131],macro:[4,116],macrosconfig:4,mad:131,made:[3,11,19,20,21,25,26,35,36,38,43,51,56,58,59,61,79,80,90,96,98,103,104,109,111,121,123,131,134,150,152,164,169,179,182,188,215,219,220,221,242,260,269,313,321,322,328,344],mag:[60,127,327],magazin:79,mage:51,mage_guild_block:51,mage_guild_welcom:51,magenta:126,magic:[30,60,61,80,112,121,122,140,179,190,220,269],magic_meadow:112,magicalforest:140,magnific:51,mai:[0,4,6,8,9,10,11,13,19,20,21,23,25,27,28,29,31,33,34,37,38,40,41,42,43,48,51,54,56,57,60,62,63,64,66,67,69,70,71,73,75,77,79,80,81,83,84,86,87,88,89,90,93,95,96,97,100,102,103,104,105,106,108,109,110,111,114,115,116,118,119,120,123,125,127,128,130,131,133,134,135,136,144,146,150,151,152,154,156,157,159,164,169,175,176,178,179,181,182,184,188,190,205,206,217,218,219,220,221,224,232,233,241,242,247,250,251,252,253,269,299,306,308,309,313,315,318,319,321,323,324,325,326,328,330,331,336,338,341,344,362],mail:[9,34,37,51,55,57,60,61,70,79,93,116,128,141,142,176,177,178,241,363],mailbox:[34,199],maillock:241,main:[13,14,15,20,21,22,30,31,33,34,37,40,43,49,51,54,56,64,68,69,76,79,80,81,83,84,85,86,89,90,91,92,100,104,105,109,110,112,115,116,119,122,124,125,131,133,134,135,137,138,139,144,145,148,150,156,159,170,177,180,188,195,199,205,206,235,239,246,252,254,256,267,271,272,274,279,286,305,307,312,318,319,328,329,332,341,343,344],mainli:[10,12,33,34,43,51,57,79,83,89,93,96,105,156,236,316,322,336,344],maintain:[4,19,23,37,41,43,53,56,68,90,93,100,108,115,119,169,171,186,261,363],mainten:[90,103],major:[14,15,23,45,57,60,63,64,119,121,133],make:[0,1,2,4,5,6,7,8,9,10,11,12,13,14,15,16,19,22,23,24,25,26,28,29,30,31,33,36,37,38,39,40,41,42,43,44,46,47,48,49,50,51,54,55,56,59,61,62,63,64,68,70,71,72,73,74,75,77,78,79,80,81,83,85,86,87,89,90,91,93,95,96,97,100,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,122,124,125,126,128,130,132,133,134,136,137,138,139,140,144,146,148,151,152,153,154,156,157,159,164,167,170,174,175,176,179,180,182,187,188,190,196,199,205,206,211,212,213,215,217,218,219,220,223,224,226,227,231,232,233,238,241,242,247,251,252,258,259,261,267,271,279,298,299,305,306,308,309,311,312,315,316,317,318,319,321,322,323,324,325,326,328,330,331,334,336,341,343,344,360,362,363],make_it:344,make_shared_login:351,make_uniqu:152,makeconnect:276,makefactori:287,makefil:38,makeit:298,makemessag:76,makemigr:[36,86,133],male:189,malevol:14,malform:345,malici:103,malign:242,man2x1:108,man:[43,87,90,108,129,165,199,206],mana:[28,30],manaag:237,manag:[2,7,9,11,31,39,40,43,53,56,57,59,80,83,85,86,89,93,96,100,102,105,110,115,119,125,127,128,131,133,138,141,142,143,144,148,169,170,172,174,175,177,202,206,221,227,233,236,239,243,246,247,251,253,256,261,262,267,274,306,314,316,318,319,320,323,324,332,335,337,341,344,360,362,364],manager_nam:306,manchest:344,mandat:357,mandatori:[0,22,107,109,129],maneuv:215,mango:203,manhol:287,manhole_ssh:287,mani:[0,1,2,4,5,9,10,11,12,14,15,17,20,26,27,30,31,33,34,38,40,43,44,49,51,55,56,57,58,61,62,63,64,66,68,70,72,73,76,77,85,86,88,89,90,91,93,95,96,98,102,103,104,105,107,108,109,110,111,113,114,115,116,118,119,120,121,122,123,124,125,126,127,128,129,131,133,134,135,140,148,152,154,159,170,177,179,182,186,188,206,213,214,215,219,220,224,231,234,239,241,242,246,252,256,261,267,310,316,318,319,321,328,329,334,335,337,362],manifest:97,manipul:[0,11,22,31,41,43,44,51,64,86,102,109,123,159,166,176,187,192,238,247,273,324,329],manner:[14,175,206,235,247,285,318],manpow:37,manual:[4,6,14,20,21,23,30,33,34,38,40,55,58,60,61,63,68,79,80,85,86,89,90,97,102,109,110,111,114,117,119,121,122,124,125,128,131,134,139,140,141,146,159,215,224,227,230,234,247,252,259,267,328,363,364],manual_paus:259,manual_transl:205,manual_unpaus:259,manytomanydescriptor:[148,177,239,246,256,316,318,319],manytomanyfield:[148,177,239,246,256,316,318,319],map:[0,15,25,39,43,46,51,57,58,61,64,67,87,88,97,100,124,135,138,139,156,164,183,184,205,206,235,247,251,252,316,318,321,327,328,336,344,364],map_modul:111,map_str:[49,111,235],mapbuild:[141,142,178],mapper:334,mapprovid:235,march:[79,337],margin:17,mark:[13,14,20,21,33,38,43,49,51,58,63,72,76,80,90,95,114,119,131,135,137,138,140,151,158,187,195,204,215,308,318,322,327,328,336,340],mark_categori:215,markdown:[1,4,38,48,54],marker:[13,20,33,43,51,64,87,114,138,165,187,189,206,215,247,279,287,295,296,316,319,321,327,329,336],market:90,markup:[38,81,114,136,139,183,321,343],mask:[203,206,210,211],maskout_protodef:203,mass:[61,124,139,364],massiv:[28,55],master:[7,9,37,38,43,57,61,63,73,95,98,100,104,116,118,134,313],match:[9,11,20,22,27,31,33,39,41,43,44,49,51,57,58,62,68,74,76,80,83,86,87,88,89,91,102,104,105,109,111,112,114,118,119,125,128,131,133,134,135,136,137,138,144,150,151,152,153,154,157,159,165,166,168,170,174,176,180,183,184,187,188,198,199,202,203,206,220,235,238,241,242,247,251,252,258,261,272,273,285,298,308,316,317,318,319,321,326,328,330,336,339,341,343,344,345,362],match_index:151,matched_charact:188,matcher:51,matches2:86,matchobject:[321,343],mate:64,math:39,mathemat:152,matplotlib:300,matrix:330,matt:102,matter:[0,4,9,11,25,31,36,41,51,57,61,62,63,69,73,76,84,91,95,103,105,107,108,116,117,127,136,152,221,231,246,272,316],matur:[108,128,129],maverick:64,max:[16,25,49,71,114,116,188,206,310,337,344],max_damag:219,max_dbref:317,max_depth:344,max_dist:49,max_heal:219,max_l:49,max_length:[49,86,133,206],max_lin:330,max_num:145,max_num_lin:362,max_popular:362,max_rmem:334,max_siz:337,max_valu:[190,357],max_w:49,max_width:49,maxconn:67,maxdelai:[264,278,279],maxdepth:252,maxdiff:352,maximum:[16,39,71,86,91,111,114,144,188,190,217,218,219,220,221,247,252,312,321,328,330,336,344],maxlengthvalid:144,maxnum:344,maxrotatedfil:337,maxsplit:321,maxthread:312,maxval:336,maxvalu:336,maxwidth:330,may_use_red_door:109,mayb:[6,9,11,13,14,21,22,25,27,31,33,38,44,48,49,54,61,63,68,69,70,73,82,85,86,90,109,116,119,122,138,140,153,179,198,285],mccp:[24,55,74,141,142,262,272,275],meadow:[22,112,140],mean:[0,5,10,11,12,13,14,15,20,22,23,27,28,31,33,34,37,40,41,42,43,46,49,51,55,57,58,60,61,62,64,68,73,74,77,78,80,81,83,84,85,86,87,88,90,93,95,96,97,100,102,103,104,105,110,111,112,113,114,116,117,119,121,122,123,125,126,127,128,131,134,135,136,138,144,146,153,159,175,185,195,205,226,227,232,234,241,247,251,252,257,261,267,307,316,318,321,326,328,330,334,337,340,341],meaning:[154,170],meaningless:123,meant:[16,20,22,31,34,44,54,62,68,76,83,96,102,125,126,137,138,140,152,180,189,206,214,217,218,219,220,221,227,233,235,247,272,322],meantim:1,meanwhil:96,measur:[90,93,123,151,168,344],meat:133,mech:[124,139,364],mechan:[27,28,33,39,50,51,55,58,61,67,69,73,91,102,109,116,122,123,125,126,139,144,146,150,187,206,220,240,252,259,261,267,271,277,285,296,307,318,326,329,332,339,362],mechcmdset:21,mechcommand:21,mechcommandset:21,meck:21,media:[16,145,173,237,244,254,263,295,312,315,340,357],median:49,mediat:73,medium:16,mediumbox:276,meet:[25,36,61,122,194,235,311],mele:221,mem:[43,169],member:[9,11,43,70,86,165,167,168,247,344],membership:[4,9,119],memori:[6,12,23,28,31,33,43,56,75,86,90,93,113,125,135,144,169,175,227,247,260,261,300,310,320,329,334,339,344],memoryerror:63,memoryusag:300,memplot:[141,142,262,297],meni:180,mental:126,mention:[6,9,10,11,13,14,15,21,29,33,40,41,49,56,57,61,63,70,74,80,90,102,108,113,115,126,127,153,186],menu:[11,25,31,43,45,46,47,53,54,55,63,65,69,105,106,109,110,123,128,138,139,141,142,159,180,188,214,215,230,248,252,265,267,320,338,364],menu_cmdset:328,menu_data:51,menu_edit:180,menu_login:[141,142,178],menu_modul:328,menu_module_path:328,menu_quit:180,menu_setattr:180,menu_start_nod:214,menu_templ:328,menuchoic:[51,328],menudata:[188,230,249,328],menudebug:[51,328],menufil:328,menunode_fieldfil:188,menunode_inspect_and_bui:85,menunode_shopfront:85,menunode_treeselect:215,menunodename1:51,menunodename2:51,menunodename3:51,menuopt:215,menutre:[51,328],merchant:46,mercuri:108,mere:[117,190],merg:[3,5,22,33,37,43,44,51,57,62,64,97,131,139,150,151,152,153,166,224,233,235,252,256,328,336],merge_prior:328,merger:[5,31,37,111,152,153],mergetyp:[31,51,116,152,224,233,326,328],mess:[11,19,27,38,90,93,131,138,215],messag:[5,6,8,10,13,15,20,21,22,27,28,29,33,34,40,41,43,44,45,46,50,51,52,53,55,58,59,60,61,62,63,64,65,70,71,73,74,76,80,81,82,85,89,90,91,92,95,96,101,102,103,104,105,110,111,113,116,118,119,123,124,127,128,131,132,137,138,139,140,144,146,150,153,154,157,159,164,165,166,168,170,172,174,175,176,177,179,180,182,188,189,193,195,199,203,204,206,210,217,218,219,220,221,223,224,226,228,230,231,232,233,234,241,247,267,269,276,278,279,285,286,287,295,304,306,308,310,312,324,326,328,329,336,337,341,344],message_rout:137,message_search:176,message_transform:175,messagepath:[139,364],messagewindow:137,meta:[104,125,145,237,244,315,318,334,357],metaclass:[86,96,125,154,318],metadata:[210,269],metavar:234,meteor:82,meter:190,metho:174,method:[1,2,5,6,9,10,11,22,25,27,28,29,30,31,34,38,39,40,42,46,48,49,51,55,58,59,60,62,64,68,69,73,77,80,83,86,88,89,91,95,96,102,104,105,107,109,111,112,114,115,116,117,118,119,120,121,123,125,127,131,132,133,134,137,139,144,148,150,152,153,154,156,159,160,164,166,167,168,169,170,173,174,175,176,177,179,180,184,187,192,195,202,203,204,205,206,209,210,212,217,218,219,220,221,227,228,230,231,232,233,234,235,238,239,241,242,247,259,260,261,264,269,272,273,274,276,277,278,279,285,287,295,296,299,303,305,306,307,308,310,315,316,318,321,322,324,326,328,329,330,331,334,335,336,337,338,339,341,342,343,344,362],methodnam:[170,196,211,228,261,303,335,342,352,360],metric:82,microsecond:11,microsoft:[63,111],mid:[29,108,121],middl:[29,33,49,90,218,321],middlewar:[141,142,346,348],midnight:[25,62],midst:122,midwai:114,mighht:91,might:[0,4,8,10,11,12,14,15,17,20,22,23,25,26,27,28,29,30,31,33,34,39,40,41,42,43,46,51,52,55,58,60,61,62,63,69,70,73,75,76,77,80,81,82,85,89,90,91,95,96,97,98,100,102,103,104,105,110,111,114,115,116,119,120,122,123,124,126,127,131,132,133,136,138,153,157,159,179,204,210,213,217,218,219,220,234,247,296,318,321,326,337,338,344,357,363],mighti:[29,111],migrat:[9,23,36,38,63,75,86,107,110,111,127,131,133,252],mike:[43,159],mileston:139,million:[23,25,133],mime:324,mimic:[23,34,50,55,73,93,177,306,326],mimick:[50,64,73,138,298,326,329],mimim:319,min:[49,62,102,114,184,188,331,336],min_damag:219,min_dbref:317,min_heal:219,min_height:330,min_shortcut:[22,180],min_valu:357,min_width:330,mind:[10,12,13,14,37,41,45,51,54,55,56,57,60,61,122,126,134,138,179,190,195,204,269,344],mindex:151,mine:[46,103,138],mini:[55,111,124],miniatur:[61,122],minim:[61,103,105,116,138,205,252],minimalist:[33,58,108],minimum:[22,58,64,73,105,188,217,218,219,220,221,272,312,318,330,336,339,344],mininum:330,minlengthvalid:144,minor:[41,153,363],mint:[63,67,131],minthread:312,minu:[86,331],minut:[25,27,28,43,62,79,91,100,102,116,164,179,184,310,331,344],minval:336,mirc:279,mirror:[72,79,105],mis:57,misanthrop:119,misc:138,miscelan:320,miscellan:47,mislead:41,mismatch:[74,344],miss:[49,57,60,63,70,90,95,97,217,218,219,220,221,251,272],missil:[21,220],mission:[41,69],mistak:[38,60,363],misus:90,mit:[79,124,321],mitig:[57,103,362],mix:[11,30,33,34,51,53,114,126,133,144,179,206,251,252,311,319,322,330],mixin:[251,301,362],mixtur:81,mkdir:[9,36,63],mktime:62,mob0:56,mob:[14,43,55,56,61,80,105,122,141,142,153,159,178,229,233,252,322],mob_data:56,mob_db:56,mob_vnum_1:56,mobcmdset:231,mobdb:56,mobil:[14,71,109,122,138,231,241],moboff:231,mobon:231,mock:[127,260,342],mock_channeldb:170,mock_get_vers:352,mock_random:228,mock_set:352,mock_tim:303,mockdeferlat:342,mockdelai:342,mocked_idmapp:303,mocked_o:303,mocked_open:303,mockup:138,mockval:342,mod:[8,103,251],mod_import:344,mod_import_from_path:344,mod_prototype_list:251,mod_proxy_http:8,mod_proxy_wstunnel:8,mod_sslj:8,mode:[2,8,31,41,42,43,50,51,67,69,74,79,93,100,103,106,116,117,123,133,135,138,141,158,169,175,181,199,231,247,251,258,267,272,277,295,296,305,322,326,328,337,344],mode_clos:296,mode_init:296,mode_input:296,mode_keepal:296,mode_rec:296,model:[9,11,34,41,45,59,64,69,73,80,87,96,104,112,115,119,125,132,135,136,139,141,142,143,144,145,172,173,175,176,236,237,243,244,247,253,254,257,261,262,263,273,314,315,316,317,319,320,324,325,332,333,335,340,341,344,357,362,364],model_inst:340,modeladmin:[173,237,244,254,263,315],modelbackend:349,modelbas:334,modelchoicefield:244,modelclass:[11,112],modelform:[145,237,244,315,357],modelmultiplechoicefield:[145,237,244],modelnam:[175,239,318],moder:[4,39,179],modern:[10,11,15,30,79,103,108,126,138],modif:[0,8,25,33,37,46,83,91,100,123,131,138,313,357],modifi:[0,2,4,11,20,22,25,26,31,33,34,38,39,40,43,44,46,51,53,55,56,57,58,60,68,73,78,85,89,93,96,100,104,105,109,110,111,114,118,119,122,123,125,128,131,135,137,138,139,140,144,145,153,175,180,185,187,189,195,203,206,213,217,218,219,220,221,232,234,239,247,252,261,318,322,328,334,340,343,357,362],modified_text:114,modul:[3,5,6,11,13,15,20,21,26,27,29,31,33,35,37,38,40,43,45,47,50,51,55,56,57,58,59,60,62,65,68,74,75,80,81,82,83,85,89,93,96,97,98,102,103,104,105,107,108,110,111,114,117,119,121,122,123,124,125,127,135,138,139,150,151,153,154,159,161,162,163,164,168,170,174,179,180,181,182,183,184,185,186,187,188,190,192,193,194,196,204,205,206,211,212,213,215,217,218,219,220,221,224,231,232,233,234,241,242,246,247,250,251,252,257,259,260,261,264,266,267,271,272,276,286,287,296,298,299,300,305,307,308,309,316,318,319,320,322,323,324,325,326,327,328,329,331,336,342,344],modular:55,modulepath:276,moifi:187,mollit:52,moment:[21,31,46,57,76,85,91,96,115,135,139,144,250,256],monei:[9,61,70,86,90,241],monetari:[37,179],monitor:[53,84,88,93,139,257,272,334],monitor_handl:[84,141,257],monitorhandl:[45,74,139,141,142,253,364],mono:25,monster:[29,43,57,61,64,89,109,159,252],month:[37,62,67,90,184,331,337,344],monthli:62,montorhandl:84,moo:[55,57,79,108,129],mood:[46,122],moon:[25,61,62,82],moor:122,moral:97,more:[0,1,2,3,4,5,9,10,11,12,13,14,15,17,19,20,21,22,23,25,26,27,28,31,33,34,35,36,37,39,40,41,42,43,44,46,49,50,51,52,55,56,58,59,60,61,62,63,64,66,67,68,69,70,71,72,73,74,75,76,77,79,83,85,86,87,88,89,90,91,93,95,96,97,100,102,103,104,105,108,109,110,111,112,113,114,115,116,118,119,121,122,123,124,125,126,127,131,132,133,134,136,137,138,141,143,144,145,148,151,152,153,158,159,165,169,171,174,178,179,180,181,182,184,186,187,190,195,198,204,205,206,213,214,215,217,218,219,220,221,226,231,232,233,234,235,241,244,247,250,251,252,277,279,298,299,308,313,316,317,321,322,324,325,326,327,328,329,330,334,341,344,345,357,362],more_command:329,moreov:[90,102],morn:[187,188],most:[0,4,6,8,9,10,11,13,17,22,23,25,27,30,31,33,35,37,38,39,40,41,42,43,46,47,48,49,51,56,57,58,59,60,61,62,63,64,69,73,74,77,80,82,83,86,88,89,90,91,93,95,96,97,100,103,104,105,107,108,111,113,114,115,116,117,119,121,123,125,126,128,129,133,137,138,140,144,148,152,153,156,159,167,177,180,190,205,206,213,217,218,219,220,221,239,241,242,246,247,251,252,256,260,295,305,316,317,318,319,328,329,334,335,344,362],mostli:[40,51,57,69,73,90,91,95,114,123,125,137,138,145,152,185,205,219,235,287,321],motiv:[13,14,37,55,61,70,89,278,279,285,286,287,295,296,307,308],mount:100,mountain:[108,111],mous:[114,137,328],move:[0,4,9,14,15,21,22,23,29,33,34,41,43,44,46,49,50,51,52,54,58,61,63,69,77,79,82,85,89,91,95,96,111,116,117,122,126,133,134,138,153,159,165,179,180,188,194,213,217,218,219,220,221,231,232,233,235,238,241,247,299,318,322,329],move_hook:247,move_obj:235,move_to:[0,85,89,121,213,247],movecommand:44,moved_obj:[233,235,247],moved_object:247,movement:[58,109,121,213,217,218,219,220,221,247],mover:221,mptt:4,mratio:[151,168],msdp:[55,83,272],msdp_list:272,msdp_report:272,msdp_send:272,msdp_unreport:272,msg:[0,2,5,10,11,13,22,25,27,28,29,30,33,38,40,41,42,44,46,50,51,52,53,56,58,59,60,62,71,73,80,82,84,85,86,88,89,91,95,96,105,111,112,114,116,118,119,121,123,127,129,137,138,141,144,146,154,156,160,164,170,173,175,176,177,189,199,210,234,242,247,278,279,306,315,322,324,328,329,337,341,344],msg_all:116,msg_all_sess:[33,154],msg_arriv:0,msg_content:[0,21,27,33,46,62,73,89,102,118,121,123,132,247],msg_help:166,msg_leav:0,msg_locat:247,msg_other:179,msg_receiv:247,msg_self:247,msg_set:319,msgadmin:173,msglauncher2port:[267,276],msgmanag:[176,177],msgobj:[34,175],msgportal2serv:276,msgreturn:170,msgserver2port:276,msgstatu:[267,276],mssp:[55,104,141,142,262,275],much:[0,4,10,11,13,14,15,20,22,23,25,26,29,37,38,39,41,42,49,51,56,59,61,62,63,64,67,69,73,76,79,80,82,89,90,91,93,96,109,111,113,115,116,119,120,121,125,127,132,133,134,138,148,153,158,167,180,184,185,206,215,221,224,232,307,321,322,323,330,344],muck:57,mud:[8,15,21,22,23,24,30,40,43,49,55,56,60,61,63,64,72,73,74,80,87,88,90,91,92,95,97,98,100,101,104,105,108,110,111,114,115,116,117,122,124,126,128,132,135,137,138,140,148,153,156,221,230,264,287,322,331],mudbyt:79,mudconnector:79,mudderi:79,muddev:63,mudform:327,mudinfo:34,mudlab:79,mudlet:[24,96,101,272],mudmast:24,mudramm:24,muhammad:343,mukluk:24,mul:250,mult:[109,250],multi:[10,22,31,38,43,51,55,61,95,96,100,104,105,119,122,123,151,169,206,215,308,328],multiaccount_mod:97,multidesc:[141,142,178],multilin:343,multimatch:[31,151,206,247,344],multimatch_str:[144,206,247,344],multimedia:137,multipl:[6,12,14,22,23,27,30,31,33,40,43,51,55,58,61,62,64,73,79,84,88,89,90,95,96,104,105,107,108,109,114,115,122,123,125,131,138,144,150,152,157,158,159,164,168,169,183,185,186,187,189,190,196,202,206,215,217,218,219,220,233,242,247,250,251,252,261,265,269,272,276,299,315,316,317,322,328,329,330,341,344],multiplay:[55,57,79],multipleobjectsreturn:[144,146,148,175,177,179,182,184,187,189,195,203,204,205,206,212,213,214,217,218,219,220,221,223,226,227,231,232,233,235,239,246,247,251,256,259,274,300,316,319,331,335],multipli:250,multisess:[2,41,69,328],multisession_mod:[24,33,64,105,123,133,144,156,160,181,189,247,308],multisession_modd:51,multitud:[57,111,114],multumatch:247,mundan:21,murri:344,muse:79,mush:[9,36,55,60,73,79,108,116,124,139,183,202,364],mushclient:[24,74,96,272],musher:79,mushman:108,musoapbox:[57,79],must:[0,1,2,4,5,8,10,11,15,24,25,29,31,33,37,38,40,43,48,49,50,51,56,58,61,62,63,64,65,67,71,72,74,76,80,81,83,84,85,87,89,90,93,95,96,97,100,103,104,109,110,112,113,114,115,116,117,119,123,125,127,128,131,133,135,136,137,140,146,151,152,154,159,164,169,170,174,175,176,179,182,183,184,186,203,205,206,210,215,217,218,219,220,221,226,227,230,232,233,239,241,247,250,251,257,261,267,272,285,287,307,309,310,315,316,317,318,321,322,323,324,325,326,327,328,329,331,336,338,339,340,341,343,344,345,362],must_be_default:153,mutabl:325,mute:[17,41,174,175],mutelist:[41,175],mutltidesc:202,mutual:317,mux2:129,mux:[20,21,33,34,41,45,55,58,103,108,139,141,142,149,167,168,183,240,364],mux_color_ansi_extra_map:183,mux_color_xterm256_extra_bg:183,mux_color_xterm256_extra_fg:183,mux_color_xterm256_extra_gbg:183,mux_color_xterm256_extra_gfg:183,muxaccountcommand:[167,199],muxaccountlookcommand:156,muxcommand:[5,25,28,29,30,33,44,53,58,119,123,141,142,149,155,156,157,158,159,164,165,166,168,169,171,174,182,185,186,187,193,199,202,203,212,214,219,220,233,247,326],mvattr:159,mxp:[24,55,74,114,141,142,262,272,275,287,321,328,343,344],mxp_re:321,mxp_sub:321,my_callback:309,my_datastor:86,my_funct:29,my_github_password:131,my_github_usernam:131,my_identsystem:87,my_number_handl:51,my_object:29,my_port:40,my_portal_plugin:40,my_script:102,my_server_plugin:40,my_servic:40,my_word_fil:205,myaccount:112,myapp:86,myarx:9,myattr:[11,144],myawesomegam:67,mybot:[43,164],mycallable1:51,mycar2:87,mychair:112,mychan:34,mychannel:[12,43,164],mycharact:81,mychargen:51,myclass:60,mycmd:[33,68],mycmdset:[5,31,33],mycommand1:31,mycommand2:31,mycommand3:31,mycommand:[30,31,33,83],mycompon:137,myconf:36,mycontrib:127,mycss:137,mycssdiv:137,mycustom_protocol:40,mycustomcli:40,mycustomview:135,mydatastor:86,mydhaccount:100,mydhaccountt:100,mydhacct:100,myevennia:72,myevilcmdset:[31,152],myevmenu:51,myfix:131,myfunc:[10,115,127,344],myfunct:51,mygam:[2,3,5,6,9,13,14,21,23,25,26,27,30,31,35,40,42,44,47,49,51,53,54,56,57,58,60,62,63,65,67,69,71,73,74,75,76,80,81,82,85,86,89,90,93,95,96,100,102,104,106,109,110,111,114,116,118,119,120,121,123,125,127,128,131,133,134,135,136,137,180,181,183,187,199,202,212,213,342,344],mygamedir:38,mygamegam:81,myglobaleconomi:102,mygotocal:51,mygrapevin:164,myhandl:107,myhdaccount:100,myhousetypeclass:[43,159],myinstanc:86,myircchan:[43,164],mykwarg:51,mylayout:137,mylink:38,mylist2:11,mylist:[6,11,97,318],mylog:27,mymenu:51,mymethod:56,mymodul:115,mymud:[8,106],mymudgam:90,mynam:100,mynestedlist:325,mynod:51,mynoinputcommand:33,mynpc:123,myobj1:112,myobj2:112,myobj:[11,27,80,102,261],myobject:[5,11],myobjectcommand:25,myothercmdset:31,myownfactori:40,myownprototyp:109,mypassw:186,mypath:127,myplugin:137,myproc:40,myproc_en:40,myprotfunc:109,myroom:[43,56,102,112,159],myros:89,myscript:[102,112,125],myscriptpath:102,myserv:186,myservic:40,mysess:105,mysql:[36,55,64,128,344],mysqlclient:23,mysteri:[75,87],mytag1:137,mytag2:137,mythic:122,mytick:261,mytickerhandl:261,mytickerpool:261,mytop:20,mytup1:11,mytup:11,myvar:33,myview:135,naccount:308,naiv:[175,235,239,318],nake:33,name1:[43,159],name2:[43,159],name:[0,2,3,4,5,6,9,10,11,13,14,15,19,20,22,23,24,25,29,31,33,34,36,38,40,41,42,44,46,47,49,51,52,53,54,55,56,57,58,59,60,61,62,64,65,66,67,68,69,71,72,73,74,75,76,79,80,81,82,83,84,85,86,87,89,90,91,93,95,96,100,102,103,104,105,106,107,109,110,111,112,113,114,116,117,119,121,123,125,126,127,128,130,131,132,133,134,135,136,137,138,139,140,141,142,144,146,148,150,151,152,153,154,156,157,159,164,165,166,167,168,169,170,171,174,175,176,177,180,181,182,184,186,188,192,194,195,198,203,204,205,206,212,215,219,220,231,233,234,235,238,239,240,246,247,251,252,256,257,259,261,267,270,272,273,274,276,277,279,287,295,296,299,306,308,312,315,316,317,318,319,321,322,323,324,326,327,328,329,334,335,336,337,338,340,341,343,344,345,349,357,362],namecolor:215,namedtupl:192,nameerror:[42,95],namelist:199,namesak:97,namespac:[69,125,137,195,234,252,322],napoleon:38,narg:[114,234],narr:221,narrow:91,nativ:[34,38,42,51,88,102,209,312,362],nattempt:51,nattribut:[11,43,51,116,125,159,252,306,316,318,324,328],nattributehandl:[306,316],natur:[11,15,27,55,79,88,112,146,330],natural_height:330,natural_kei:316,natural_width:330,navig:[9,48,49,51,106,111,128,133,134,221,362],naw:[24,52,141,142,262,275],nbsp:343,nchar:120,nclient:298,ncolumn:330,ncurs:141,ndb:[6,13,22,25,29,33,43,51,102,105,116,125,144,148,169,246,256,306,316,318,328],ndb_:[43,109,159,252],ndb_del:306,ndb_get:306,ndb_set:306,ndbholder:306,ndk:75,nearbi:[119,152,153,154,221],nearli:321,neat:[0,3,138,357],neatli:[108,344],necess:[40,95],necessari:[0,4,22,36,39,40,51,57,58,59,61,77,91,108,110,114,118,121,125,131,138,153,154,177,181,195,210,233,234,252,296,315,322,328,330,338,340,344],necessarili:[38,41,57,88,90,109,344],necessit:309,neck:[109,182],necklac:182,need:[1,2,3,4,5,6,8,9,10,11,13,14,15,19,20,21,22,23,25,26,27,28,29,30,31,33,34,35,36,37,38,39,40,41,42,43,44,45,46,48,49,50,51,54,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,79,80,81,82,83,84,85,86,87,88,89,90,91,93,95,96,97,98,100,102,103,104,105,106,109,110,111,112,113,114,115,116,117,118,119,121,122,123,124,125,126,127,128,130,131,133,134,135,136,137,138,140,144,146,148,152,154,156,159,164,165,167,170,174,175,179,180,186,187,189,193,194,195,196,203,204,205,206,215,217,218,219,220,221,227,231,232,233,234,235,241,242,246,247,251,252,259,267,269,271,272,276,296,298,306,307,308,312,315,316,318,321,322,324,328,329,330,331,336,338,339,341,344,362],need_gamedir:267,needl:203,neg:[62,126,152,326],negat:[114,119,242],negoti:[55,179,285,308],neighbor:39,neither:[11,54,61,73,97,110,185,251,316,319,345],nenter:51,nest:[11,14,33,43,51,114,144,159,206,215,241,247,250,252,325,336],nested_mut:11,nested_r:159,nestl:111,net:[9,43,57,63,72,79,90,146,164,308],netrc:131,network:[40,43,53,55,64,65,70,71,72,79,90,103,113,139,146,164,278,279,305,308],neu:180,neutral:189,never:[12,14,26,27,31,33,51,54,56,60,61,62,64,80,86,88,91,95,96,104,114,115,118,119,121,125,127,131,133,144,194,205,206,220,221,231,242,247,306,325,336,344],nevertheless:[26,43,51,86,126,156,180],new_alias:154,new_arriv:233,new_channel:58,new_charact:231,new_coordin:235,new_datastor:86,new_goto:328,new_kei:[107,154,247],new_loc:[43,159],new_menu:180,new_nam:[43,107,159],new_name2:[43,159],new_obj:[80,247,252],new_obj_lockstr:159,new_object:[109,252],new_raw_str:151,new_room_lockstr:159,new_ros:89,new_script:102,new_typeclass:[144,318],new_typeclass_path:125,new_valu:84,newbi:[25,48,55,124,174],newcom:[96,117],newer:9,newindex:215,newli:[43,46,58,60,66,131,133,159,175,180,199,204,234,247,252,259,324],newlin:[33,43,137,166,322,330],newnam:[33,43,159,318],newpassword:[43,157],newstr:137,nexist:22,nexit:[120,127],next:[0,4,5,6,9,10,11,12,13,14,20,21,22,23,25,28,29,30,31,33,36,38,39,41,42,46,49,50,51,52,56,58,60,61,62,64,65,68,72,73,75,76,77,79,80,81,83,85,86,89,90,95,96,98,100,102,103,106,110,111,114,116,119,121,122,123,127,131,133,134,137,138,180,184,202,215,217,218,219,220,221,232,242,259,267,322,328,329,331,336,344,362],next_nod:51,next_turn:[217,218,219,220,221],nextrpi:79,nexu:45,nfkc:144,ng2:330,nginx:8,nice:[0,12,22,27,49,54,58,61,62,68,70,81,90,96,100,111,119,127,138,140,159,179,182,206,251],nicer:[20,60,96],niceti:[43,159],nick:[2,11,45,57,74,79,89,129,139,144,146,159,165,206,241,246,247,279,316,317,336,364],nick_typ:87,nickhandl:[11,87,316],nicklist:[146,164,279],nicknam:[43,87,89,129,131,165,206,246,247,279,316,317],nickreplac:316,nicktemplateinvalid:[316,336],nicktyp:[206,247],nifti:8,night:[58,61,132,138,187],nine:66,nineti:345,nit:[60,62],nline:337,no_channel:[31,33,152,328],no_default:[125,144,318],no_exit:[31,33,116,152,224,230,328],no_log:153,no_match:180,no_more_weapons_msg:232,no_obj:[31,152,224,230,328],no_superuser_bypass:[144,175,242,247,318],no_tel:80,noansi:170,nobj:120,nocaptcha:133,nocaptcha_recaptcha:133,nocolor:[81,272,287,295,296],nodaemon:106,node1:[51,328],node2:[51,328],node3:[51,328],node:[13,85,109,188,215,230,249,265,328],node_abort:51,node_apply_diff:249,node_attack:51,node_background:51,node_betrayal_background:51,node_border_char:328,node_destin:249,node_examine_ent:249,node_exit:51,node_formatt:[51,188,328],node_four:51,node_game_index_field:265,node_game_index_start:265,node_hom:249,node_index:[249,328],node_kei:249,node_loc:249,node_login:51,node_matching_the_choic:51,node_mssp_start:265,node_mylist:51,node_on:51,node_parse_input:51,node_password:51,node_prototype_desc:249,node_prototype_kei:249,node_prototype_sav:249,node_prototype_spawn:249,node_readus:51,node_select:51,node_set_nam:51,node_start:265,node_test:51,node_text:51,node_usernam:51,node_validate_prototyp:249,node_view_and_apply_set:265,node_view_sheet:51,node_violent_background:51,node_with_other_nam:328,nodefunc1:51,nodefunc2:51,nodefunc:328,nodekei:328,nodenam:[51,328],nodename_to_goto:51,nodestartfunc:51,nodetext:[51,188,249,328],nodetext_formatt:[51,188,249,328],noecho:[43,169],noerror:247,nofound_str:[144,206,247,344],nohom:324,nois:21,noisi:[90,264,269,277,287,312],noloc:[43,159],nomarkup:[74,81],nomatch:[22,168,180,326,336,344],nomatch_exit:22,nomatch_single_exit:22,nomigr:127,nomin:362,non:[4,6,14,15,20,22,27,29,31,33,38,43,44,49,50,52,55,58,61,62,63,64,65,68,70,74,82,86,88,102,105,109,110,114,122,124,125,126,131,137,139,140,144,146,148,150,152,159,169,175,177,185,195,204,212,214,215,232,238,246,247,251,252,256,257,258,259,261,267,276,305,306,308,316,318,321,324,325,326,328,330,336,341,344],nonc:295,nondatabas:[11,306,318],none:[0,1,2,10,11,13,14,15,22,25,30,31,33,34,39,40,41,42,43,44,49,50,51,56,58,60,62,64,69,74,77,80,81,83,84,85,86,87,88,91,96,102,105,111,112,114,116,118,119,121,123,144,145,146,150,151,152,153,154,156,159,160,161,162,163,166,167,168,170,173,174,175,176,177,179,180,181,182,185,187,188,189,192,194,195,198,203,204,205,206,212,214,215,217,218,219,220,221,224,230,231,232,233,234,235,237,238,241,242,244,246,247,249,250,251,252,254,257,258,259,260,261,264,265,267,269,273,276,277,278,279,286,287,295,296,306,307,308,310,311,312,315,316,317,318,319,321,322,323,324,325,326,327,328,329,330,331,334,336,337,339,340,341,344,345,349,352,357,362],nonpc:123,nonsens:205,noon:[20,60,73,76,80,96],nopkeepal:24,nor:[11,13,29,31,42,54,106,108,116,126,185,186,234,251,316,319],norecapcha:133,norecaptcha_secret_kei:133,norecaptcha_site_kei:133,norecaptchafield:133,normal:[2,3,5,6,9,10,11,13,14,15,19,20,21,23,25,27,29,30,31,33,34,38,43,44,46,49,51,55,56,57,58,60,62,64,66,68,69,72,74,75,76,80,81,82,83,85,86,87,88,90,93,96,97,100,102,104,105,109,110,111,112,113,114,116,119,121,122,123,125,126,127,128,134,135,137,138,140,144,146,148,150,151,152,153,154,156,159,166,169,174,175,179,184,185,217,218,219,220,221,231,234,235,246,247,249,252,259,261,267,276,279,285,299,306,308,314,316,317,318,321,322,325,328,329,334,336,341,343,344,346],normal_turn_end:116,normalize_usernam:144,north:[0,20,22,43,44,46,49,89,111,114,121,159,180,213,299],north_south:111,northeast:[20,43,159,235],northern:[22,111],northwest:159,not_don:312,not_error:267,not_found:159,notabl:[6,9,10,40,43,63,97,131,154,159,170,179,318,325,326,336,344],notat:[43,119,159,321,344],notdatabas:125,note:[0,1,2,4,5,6,9,11,12,13,19,20,21,23,24,25,27,29,41,42,43,48,49,57,58,59,60,61,62,63,64,69,70,73,74,75,76,80,83,85,86,88,89,90,93,95,96,100,102,103,105,106,107,109,110,113,114,115,116,117,119,121,123,124,125,126,128,130,131,133,134,135,136,137,141,144,146,151,152,153,154,156,159,160,161,165,166,167,169,170,171,174,175,176,179,181,182,183,184,185,186,187,189,194,195,198,202,203,204,205,206,212,213,215,217,218,219,220,221,224,226,227,233,234,235,241,242,246,247,251,252,259,261,264,267,272,276,277,279,285,286,287,295,298,300,301,306,308,312,313,316,317,318,319,321,322,323,324,325,326,327,328,329,330,331,334,336,337,339,340,341,342,344,350,364],notepad:63,notfound:344,notgm:58,noth:[0,10,11,14,20,22,27,29,33,34,42,56,57,60,62,83,85,89,95,108,111,115,116,127,144,159,168,215,217,220,221,231,235,247,259,279,318,328],nother:120,notic:[0,10,12,13,20,22,23,29,33,36,37,39,41,42,46,62,69,70,91,96,117,121,126,127,131,180,223,362],notif:[4,75,131,137,138,199],notifi:[43,98,164,217,218,219,220,221,233,251],notificationsconfig:4,notion:[62,115,116],noun:[205,206],noun_postfix:205,noun_prefix:205,noun_transl:205,now:[0,2,3,5,6,9,10,11,12,14,20,21,22,23,25,27,28,29,31,33,36,39,41,46,48,49,51,55,56,57,58,60,61,62,63,64,65,67,69,71,72,73,75,76,77,79,80,81,82,83,85,86,89,90,91,95,96,97,98,100,102,103,105,106,108,109,110,111,114,115,117,118,119,121,123,125,126,127,128,131,133,134,135,136,137,138,140,153,179,184,188,195,215,226,235,242,247,279,287,308,340,342,344],nowher:[95,111],npc:[9,33,46,51,61,64,73,111,119,124,139,179,214,241,247,364],npcname:118,npcshop:85,nprot:120,nr_start:258,nroom:[22,120],nroom_desc:127,nrow:330,ntf:63,nuanc:114,nudg:[78,224,227,312],nuisanc:103,nulla:52,num:[49,80,206,247],num_lines_to_append:337,num_object:119,num_objects__gt:119,num_tag:119,number:[0,6,10,11,12,13,20,21,23,25,26,27,31,33,34,36,38,41,43,49,50,51,57,58,60,61,62,64,71,73,77,81,85,87,90,93,95,96,97,98,100,102,104,105,107,111,112,114,115,116,119,120,122,123,125,127,131,134,135,140,141,144,146,151,152,153,157,159,164,165,174,176,177,182,184,185,188,190,192,194,195,198,204,205,206,215,217,218,219,220,221,247,250,251,252,258,259,265,267,272,278,279,285,298,308,310,312,316,317,319,321,322,324,326,328,329,330,331,334,336,337,341,344,357],number_of_dummi:267,number_tweet_output:120,numbertweetoutput:120,numer:[61,73,97,190,321],numpi:300,o_o:138,obelisk:232,obfusc:[205,206],obfuscate_languag:[205,206],obfuscate_whisp:[205,206],obj1:[11,43,80,97,109,159,203,221],obj2:[11,43,80,97,109,127,159,203,221,322],obj3:[11,43,109,159],obj4:11,obj5:11,obj:[2,6,10,11,22,25,27,31,33,41,42,43,48,56,58,59,60,80,82,84,86,87,89,91,96,102,109,112,115,117,119,121,125,127,139,144,145,152,153,154,157,159,165,167,168,169,170,173,174,176,180,182,187,188,189,192,194,195,198,199,203,206,215,217,218,219,220,221,224,227,232,233,235,241,242,244,246,247,250,252,254,256,257,258,259,296,298,299,306,315,316,317,318,319,322,324,325,329,339,340,341,344],obj_desc:220,obj_detail:233,obj_kei:220,obj_prototyp:252,obj_to_chang:125,obj_typeclass:220,objattr:[232,241],objclass:[334,344],object1:33,object2:[33,179,247],object:[0,2,9,10,12,13,14,15,18,19,21,22,23,26,29,30,31,33,34,36,38,39,40,41,42,44,45,46,47,49,50,51,52,53,55,56,57,58,62,69,73,74,77,79,81,83,84,85,86,87,88,91,93,95,102,103,104,107,108,109,110,114,115,116,117,118,120,122,123,125,127,129,132,133,134,135,137,138,139,140,141,142,143,144,145,146,147,148,150,151,152,153,154,156,157,158,159,160,161,164,165,167,168,169,170,171,173,174,175,176,177,178,179,180,181,182,186,187,188,189,192,193,194,195,196,198,199,203,204,206,209,210,211,212,213,214,215,217,218,219,220,221,223,224,226,227,229,230,231,233,234,235,237,238,239,241,242,249,250,251,252,253,254,256,257,258,259,260,261,265,267,269,271,272,273,274,276,277,285,286,287,296,298,299,305,306,307,308,310,311,312,315,316,317,318,319,321,322,323,324,325,326,327,328,329,330,334,335,336,338,339,340,341,342,343,344,345,349,351,357,360,362,364],object_confirm_delet:362,object_detail:362,object_from_modul:344,object_id:134,object_search:134,object_subscription_set:246,object_tot:317,object_typeclass:[342,360],objectattributeinlin:244,objectcr:357,objectcreateform:244,objectcreateview:362,objectdb:[11,53,59,96,112,119,120,125,133,141,244,246,247,252,314,315,316,324,329,341],objectdb_db_attribut:244,objectdb_db_tag:[244,315],objectdb_set:[148,316,319],objectdbadmin:244,objectdbmanag:[245,246],objectdeleteview:362,objectdetailview:362,objectdoesnotexist:[148,177,239,246,256,274,316,319,335],objecteditform:244,objectform:357,objectmanag:[245,247,317],objectnam:[6,58],objects_objectdb:86,objectsessionhandl:[2,247],objecttaginlin:244,objectupd:357,objectupdateview:362,objid:80,objlist:[109,250],objlocattr:[232,241],objmanip:[43,159],objmanipcommand:159,objnam:[27,43,125,159],objparam:252,objs2:112,objsparam:252,objtag:241,objtyp:176,obnoxi:269,obs:318,obscur:[48,72,82,205,206],observ:[13,14,20,43,81,88,159,165,187,206,223,227,233,322,344],obtain:[0,33,39,63,77,90,91,93,100,180,232],obviou:[0,59,61,103,121,128,138,190,362],obvious:[0,4,14,49,55,105,108,121,319],occaecat:52,occas:128,occasion:[90,119],occation:330,occur:[9,10,25,33,42,57,60,102,137,168,175,204,219,234,242,247,260,299,328,337],occurr:[46,91,123,321],ocean:[90,122],ocw:124,odd:[22,49,61,103,126],odor:58,off:[0,11,14,20,23,24,29,31,33,36,40,41,43,49,50,51,55,61,64,66,74,80,81,86,88,90,100,103,107,108,110,114,115,123,126,135,138,139,144,154,164,169,170,174,175,182,188,206,227,231,233,242,247,272,287,306,318,321,322,324,326,328,329,330,336,337,345],off_bal:29,offend:12,offer:[1,4,11,14,22,26,28,31,33,34,37,39,40,43,44,50,51,55,56,57,59,62,64,72,73,74,76,83,86,87,89,90,91,96,102,106,108,109,111,114,115,116,123,124,127,128,129,131,132,137,138,152,153,158,159,169,179,180,187,205,233,249,257,308,326,328],offernam:179,offici:[38,72,100,103,127,131,337],officia:52,offlin:[9,15,79,90,109,158,175,322],offscreen:9,offset:[206,326,337],often:[2,5,10,11,15,22,26,28,31,33,40,41,42,43,46,48,49,51,57,59,61,62,64,76,86,88,90,91,93,95,96,97,102,103,104,105,112,114,115,116,119,128,131,146,152,157,167,168,169,175,180,215,217,218,219,220,221,224,226,242,246,256,258,267,272,286,306,316,318,322,324,330,337],ohloh:37,okai:[41,42,48,49,51,58,75,77,111,123,128,198],olc:[43,47,159,249,252],olcmenu:249,old:[0,1,5,9,21,25,27,31,38,39,43,50,51,55,56,58,60,63,80,81,85,88,90,105,106,111,114,122,123,125,126,128,138,144,152,153,156,159,174,179,206,242,247,252,276,317,318,321,324,363],old_default_set:127,old_kei:[107,247],old_nam:107,older:[2,9,24,55,63,64,79,105,159],oldnam:318,oliv:114,omiss:60,omit:[91,100,109],ommand:150,on_:180,on_bad_request:269,on_ent:[22,180],on_leav:[22,180],on_nomatch:[22,180],onbeforeunload:[83,137],onbuild:100,onc:[0,2,5,6,9,10,13,16,21,22,23,25,33,34,37,38,39,40,41,42,43,46,47,49,51,55,57,58,60,61,62,63,64,67,72,79,80,83,85,89,90,93,95,96,97,100,102,105,108,114,116,119,121,122,125,126,128,131,133,137,144,146,151,154,159,164,167,168,170,175,179,180,188,189,195,199,203,205,212,215,217,218,219,220,221,223,227,231,232,233,234,235,247,251,256,259,272,277,305,321,328,329,337,342,344],onclos:[40,278,295],onconnectionclos:[83,137],oncustomfunc:83,ond:319,ondefault:83,one:[0,1,2,3,4,5,9,10,11,12,13,14,15,16,19,20,21,22,23,25,26,27,28,29,31,33,34,35,36,37,38,41,42,43,44,46,47,48,49,50,51,52,54,55,56,57,58,59,60,61,62,63,64,65,67,68,69,70,72,73,74,76,77,79,80,81,82,83,85,86,87,88,89,90,91,92,93,95,96,97,98,100,102,103,104,105,106,108,109,111,112,113,114,115,116,118,119,121,122,123,125,126,127,128,131,132,133,134,135,136,137,138,140,143,144,148,151,152,153,154,156,157,159,165,168,170,174,175,176,177,179,180,182,185,187,189,195,198,199,204,205,206,214,215,217,218,219,220,221,224,227,230,232,233,234,235,238,239,241,242,244,246,247,249,250,251,252,256,261,267,269,271,272,277,278,279,287,306,307,308,312,314,316,317,318,321,322,324,325,326,327,328,329,330,331,334,335,336,337,339,340,341,342,344,345,357,360,362],ones:[4,9,14,20,22,27,31,33,57,58,65,72,74,80,81,83,90,95,100,103,109,114,116,126,127,135,152,153,154,177,180,195,217,218,219,220,221,241,251,252,271,276,308,321,330,338],onewai:[43,159],ongo:[28,91,116,179,213],ongotopt:[83,137],onkeydown:[83,137],onli:[0,2,4,5,6,9,10,11,12,13,14,15,19,20,21,22,24,25,26,27,28,29,31,33,34,37,39,40,41,42,43,44,46,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,67,68,69,71,72,73,74,77,79,80,81,82,83,85,86,87,88,89,90,91,93,95,96,100,102,103,104,105,106,107,109,111,112,114,116,117,118,119,121,122,123,124,125,126,127,130,131,132,133,134,135,136,137,138,140,141,144,145,146,150,151,152,153,154,156,157,158,159,164,165,166,167,168,169,170,175,176,177,179,180,181,182,185,187,188,190,195,199,205,206,214,215,217,218,219,220,221,223,226,227,232,233,234,235,239,241,242,247,250,251,252,256,258,259,260,261,267,271,272,279,285,287,299,305,306,308,310,311,312,315,316,317,318,319,321,322,323,324,326,328,329,330,334,336,337,339,340,341,342,344,357,362],onlin:[7,12,15,21,37,41,43,55,57,58,60,61,64,65,68,69,70,71,73,77,79,89,96,98,101,104,108,116,123,128,129,139,141,156,164,175,180,188,322,364],onloggedin:[83,137],onlook:247,only_tim:341,only_valid:252,onmessag:[40,278,295],onopen:[40,278,295],onoptionsui:137,onprompt:[83,137],onsend:[83,137],onset:[5,11],onsil:83,ontabcr:137,ontext:[83,137],onto:[25,31,33,44,55,60,61,72,90,95,121,137,153,224,233,246,279,325,328],onunknowncmd:137,onward:107,oob:[24,30,33,45,83,104,137,138,139,144,146,166,189,247,272,295,296,308,328,364],oobfunc:104,oobhandl:334,oobobject:102,ooc:[2,53,58,102,105,114,123,144,148,156,159,160,164,167,177,181,199,247],ooccmdsetchargen:181,ooclook:[105,181,329],opaqu:[15,103],open:[0,3,4,5,9,20,22,23,26,31,34,37,38,42,46,50,55,57,58,60,63,64,65,67,69,70,71,72,73,75,79,80,90,95,96,103,105,106,111,114,116,123,130,131,133,134,138,159,166,169,179,180,188,212,213,221,224,226,227,232,241,310,316,324,337,363],open_lid:226,open_parent_menu:180,open_submenu:[22,180],open_wal:232,openhatch:79,openlidst:227,openlock:241,opensoci:70,opensourc:321,oper:[9,11,12,14,22,27,33,41,42,43,46,51,57,59,60,61,63,64,67,72,74,80,82,88,89,90,95,96,97,102,109,110,112,115,119,124,126,131,137,139,144,150,152,154,156,159,164,169,175,180,185,206,227,232,242,247,250,252,261,264,267,276,277,287,296,298,299,306,307,317,318,321,324,328,329,330,334,344,364],opinion:[1,48],oppon:[11,73,218,220,231],opportun:[0,4,22,91,133,221],oppos:[27,89,103,110,114,306,319],opposit:[41,43,58,111,121,159,224],opt:[58,137,234],optim:[23,27,33,34,39,56,64,86,93,115,119,154,251,252,302,305,316,329],option100:51,option10:51,option11:51,option12:51,option13:51,option14:51,option1:51,option2:51,option3:51,option4:51,option5:51,option6:51,option7:51,option8:51,option9:51,option:[2,4,7,8,10,11,17,20,23,24,25,27,29,31,33,34,36,38,41,42,47,50,54,55,57,62,63,64,74,76,79,80,81,83,85,86,88,96,100,102,104,106,108,109,111,112,113,114,116,117,123,127,129,133,134,135,137,138,139,141,144,145,146,150,151,152,153,154,156,157,159,164,167,168,170,173,174,175,176,177,179,180,181,182,184,185,187,188,189,190,192,194,195,199,203,204,205,206,214,215,219,221,230,233,234,235,237,238,241,242,244,246,247,249,251,252,254,256,257,258,259,260,261,263,264,265,267,269,272,273,276,277,285,286,287,295,296,298,299,306,308,310,315,316,317,318,319,321,322,323,324,326,327,328,329,330,331,334,336,337,338,339,340,341,343,344,345,349],option_class:[141,323],option_dict:328,option_gener:328,option_kei:345,option_str:234,option_typ:339,option_valu:339,optiona:[144,264,318],optionalposit:1,optionclass:[141,142,320,323],optioncontain:323,optionhandl:[141,142,320,338],optionlist:[51,230,249,328],options2:137,options_dict:339,options_formatt:[51,188,230,249,328],optionsl:251,optionslist:230,optionstext:[51,188,328],optlist:215,optlist_to_menuopt:215,optuon:205,oracl:[23,344],orang:[114,203,234],orc:[57,61,109,117],orc_shaman:109,orchestr:100,order:[0,2,5,6,9,10,11,13,14,22,27,31,33,36,37,39,43,44,49,50,51,58,60,61,62,63,64,68,69,70,71,80,84,87,89,93,100,102,104,109,111,113,114,116,119,121,122,123,126,127,128,131,133,134,136,137,138,144,150,153,154,160,165,166,169,170,173,179,180,181,182,183,185,188,203,204,206,217,218,219,220,221,227,231,232,233,234,237,241,242,244,247,252,254,263,278,295,299,306,316,318,321,322,328,329,330,337,341,344,362],order_bi:119,order_clothes_list:182,ordered_clothes_list:182,ordered_permutation_regex:206,ordered_plugin:83,ordereddict:[11,344],ordin:321,org:[37,38,90,204,234,295,321,344,357],organ:[5,6,9,22,69,73,80,89,102,108,111,112,119,124,129,131,132,154,170],organiz:102,orient:[55,57,64,96,124],origin:[0,4,9,21,25,29,41,43,49,51,55,57,60,75,76,79,81,89,91,96,102,103,105,106,119,131,136,138,146,152,159,180,199,205,206,234,247,251,252,276,318,321,328,336,340,343,363],oscar:[175,239,318],osnam:344,oss:106,ostr:[144,176,238,341],osx:[63,131],other:[0,1,2,4,5,6,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,25,27,28,29,31,34,36,37,38,39,40,41,43,44,46,47,48,49,50,51,53,55,57,58,59,60,61,62,63,64,65,68,69,70,71,73,74,76,80,81,82,83,85,86,87,88,89,91,95,96,97,100,102,103,105,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,123,124,125,126,127,128,131,133,134,135,136,137,138,139,140,144,150,151,152,153,154,159,165,166,167,170,171,176,179,182,184,186,188,194,199,205,206,210,212,215,217,218,219,220,221,224,227,233,234,235,239,242,246,247,251,252,257,259,261,265,271,272,276,278,279,285,287,299,306,307,309,316,318,320,321,322,324,326,327,328,329,330,336,338,339,341,344,345,362],otherroom:212,otherwis:[0,4,11,15,23,25,27,29,31,33,37,39,41,42,43,51,59,62,68,69,76,78,83,86,89,90,91,95,97,100,102,103,105,109,114,121,123,131,135,141,151,152,156,159,175,179,183,187,188,192,195,206,217,218,219,220,221,235,242,247,250,251,252,259,260,267,278,279,287,306,310,311,315,321,328,329,336,337,341,342,344,362],our:[2,3,4,8,9,11,14,16,20,21,23,25,26,30,31,33,36,37,38,39,40,41,42,43,44,46,49,55,57,58,59,60,61,62,63,64,67,70,72,73,75,77,78,79,80,81,82,83,85,88,90,91,98,100,101,103,111,115,116,117,119,123,124,127,128,129,131,132,134,135,136,137,138,140,148,153,167,168,187,215,231,232,235,242,257,312,315,337,363],ourself:123,ourselv:[0,20,58,80,87,118,132,138,144,181],out:[0,1,3,6,8,9,10,12,13,14,15,16,17,19,20,21,22,23,26,28,29,33,34,37,38,39,41,42,43,44,45,46,47,48,49,51,53,54,55,56,57,59,60,61,62,63,64,66,69,70,71,77,79,80,86,88,89,90,91,93,95,96,97,100,102,104,105,108,109,111,114,116,117,118,119,121,122,123,126,127,129,131,133,135,137,138,139,143,144,151,152,156,158,159,179,181,184,186,188,199,205,206,209,210,212,213,217,218,219,220,221,227,230,232,241,251,252,259,267,269,295,296,298,307,308,315,316,325,327,328,330,336,343,344,357],out_templ:[316,336],outcom:[38,73,86,152,185,242,247,251],outdat:8,outdata:[40,308],outdoor:[112,119,122,132,233],outer:330,outermost:[11,29,74],outerwear:182,outfunc_nam:40,outgo:[67,88,90,96,105,146,247,279,307,344],outgoing_port:90,outlet:90,outlin:[36,43,111,133,278],outmessag:247,output:[4,14,20,22,26,27,34,40,43,51,52,58,74,79,88,91,95,96,100,105,106,108,110,111,113,114,116,120,121,123,126,128,129,135,137,138,141,142,154,159,166,169,170,178,180,184,189,207,208,210,217,218,219,220,221,251,267,272,287,299,306,321,328,329,337,340,344],outputcommand:[74,83],outputfunc:[40,59,83,247,272,278],outputfunc_nam:[40,272],outputfunct:83,outrank:317,outright:[12,90,363],outro:[122,233],outroroom:233,outsid:[0,13,15,20,21,38,39,57,64,67,73,88,96,100,104,108,109,110,112,121,134,204,220,231,241,306,307,316,319,330],outtempl:[316,336],outtxt:27,outward:[49,90],over:[1,6,8,11,13,14,15,16,17,27,28,31,33,34,36,37,38,39,40,43,45,48,49,51,54,57,58,59,60,61,73,77,81,83,85,88,90,93,96,97,100,103,105,108,111,112,113,114,115,116,118,119,125,126,127,128,129,133,136,137,138,144,153,164,174,176,188,212,215,217,218,219,220,221,227,233,261,271,285,287,296,298,300,313,318,322,329,334,340,362,363],overal:[10,56,57,68,71,86,90,152,167,168,218],overcom:111,overhead:[23,27,34,113,132,206,235,316],overhear:205,overlap:[31,62,205,321,330],overload:[5,22,30,31,33,40,44,47,51,55,57,60,74,76,89,96,97,104,114,115,117,123,136,144,152,154,168,175,180,181,187,189,203,206,212,213,217,218,219,220,221,230,231,232,233,234,247,252,261,271,307,326,328,329,330,338],overrid:[1,3,4,9,20,21,22,25,31,36,43,51,53,54,68,69,80,83,91,96,102,105,107,109,117,118,121,135,136,137,144,154,159,166,170,175,176,180,187,195,205,219,221,233,234,242,247,252,259,308,312,315,328,329,334,337,338,341,362],overridden:[4,40,96,136,138,144,159,180,234,329,362],override_set:107,overriden:[144,166,206],overrod:16,overrul:[2,80,144,153,206,247,330],overseen:73,overshadow:61,overshoot:344,oversight:57,overview:[15,16,18,23,45,46,57,68,77,96,103,139,364],overwhelm:[46,61],overwrit:[5,43,76,136,138,159,166,285,317,362],overwritten:[33,134,233,319],owasp:357,own:[1,3,4,5,6,8,9,10,11,13,17,19,20,21,22,25,26,27,29,30,31,34,37,38,41,43,45,47,51,55,57,61,62,63,64,67,68,71,72,75,76,77,78,80,81,83,85,86,87,88,91,93,95,96,98,101,102,103,104,105,107,108,109,111,112,114,119,121,122,123,124,125,127,128,129,131,132,133,134,135,136,138,139,148,150,151,152,153,159,164,167,182,184,187,188,199,205,206,210,217,218,219,220,221,232,234,235,241,242,247,252,272,299,307,318,321,322,323,329,330,334,337,338,342,344,362,364],owner:[4,19,80,85,144,242,338],owner_object:80,ownership:[90,100],p_id:133,pace:[122,231],pack:[83,276],packag:[8,9,23,41,47,63,64,72,75,78,88,90,93,96,97,100,108,127,128,135,141,143,149,155,172,178,229,236,240,243,253,262,267,276,295,314,320,346],package_nam:64,packagenam:64,packed_data:276,packeddict:[97,318],packedlist:[97,318],packet:[83,287],pad:[17,114,321,330,336,344],pad_bottom:330,pad_char:330,pad_left:330,pad_right:330,pad_top:330,pad_width:330,page:[7,8,9,12,13,14,16,17,20,21,23,25,26,28,31,33,36,37,38,40,45,48,51,52,55,57,58,59,60,61,64,67,70,72,73,75,76,77,79,80,81,88,89,90,94,96,99,100,101,103,104,106,108,110,124,125,126,127,129,130,131,133,134,137,138,139,164,165,175,239,241,244,251,254,296,315,318,328,329,344,346,355,362,363,364],page_back:329,page_ban:164,page_end:329,page_formatt:[251,329],page_next:329,page_quit:329,page_titl:362,page_top:329,pagelock:241,pageno:[251,329],pager:[52,139,329],pages:[51,328],pagin:[251,329],paginag:329,paginate_bi:362,paginated_db_queri:251,paginator_django:329,paginator_index:329,paginator_slic:329,pai:[56,85,90,103,232,241],paid:90,pain:[90,138],painstakingli:13,pair:[31,83,116,137,138,144,152,182,241,247,306,308,357,362],pal:87,palett:126,pallet:111,palm:188,pane:[43,88,137,138,171,186,230],panel:[67,106],panic:109,paper:[61,79,116],paperback:73,par:23,paradigm:[9,61,118,218],paragraph:[14,27,38,202,322,330,344],parallel:[57,62,69,317],paralyz:219,param:[67,159,247,259,261,269,279,312,337,345],paramat:[144,154,247,306],paramet:[0,22,24,31,36,39,42,46,49,62,91,100,106,119,127,141,144,145,146,150,151,152,153,154,159,166,173,174,175,176,177,179,180,182,184,185,187,188,189,190,192,193,194,195,198,199,204,205,206,209,210,212,215,217,218,219,220,221,226,230,233,234,235,238,242,244,246,247,249,251,252,254,257,258,259,260,261,264,265,266,267,269,271,272,273,274,276,277,278,279,285,286,287,295,296,298,304,305,306,307,308,310,311,312,316,317,318,319,321,322,323,324,325,326,327,328,329,330,331,334,336,337,338,339,341,342,343,344,345,349],paramount:127,paramt:345,paremt:252,parent1:109,parent2:109,parent:[2,6,22,25,27,31,33,38,40,43,44,60,64,81,89,96,109,114,118,121,123,125,140,148,156,159,167,169,180,206,215,234,241,246,247,251,252,256,317,318,326,335,337,344,362],parent_categori:215,parent_kei:[22,180],parent_model:[145,173,237,244,254,315],parentesi:336,parenthes:95,parentlock:241,pari:[79,90],pariatur:52,paricular:33,park:180,parlanc:3,parri:[116,232],parrot:118,pars:[3,15,31,33,38,40,43,50,51,63,81,83,88,97,104,108,109,114,123,124,129,134,139,149,150,151,154,159,165,166,167,168,169,170,174,179,180,185,186,187,199,206,209,210,211,215,232,233,234,242,247,250,251,252,272,279,295,296,316,321,322,326,327,328,336,343,344,364],parse_ansi:321,parse_ansi_to_irc:279,parse_fil:322,parse_html:343,parse_inlinefunc:336,parse_input:328,parse_irc_to_ansi:279,parse_languag:206,parse_menu_templ:[51,328],parse_nick_templ:[316,336],parse_opt:215,parse_sdescs_and_recog:206,parseabl:251,parsed_str:279,parseerror:234,parser:[33,41,47,79,104,108,109,134,150,151,156,159,167,168,174,186,187,203,205,206,232,233,234,250,251,286,321,336,343],parsestack:336,part1:203,part2:203,part:[1,4,5,9,11,13,14,15,16,20,22,23,26,29,33,36,37,38,39,40,41,42,44,45,46,48,49,51,57,58,60,61,68,69,70,73,76,80,85,86,88,90,91,92,95,102,105,106,111,114,116,117,119,122,123,124,125,127,131,135,136,137,138,139,140,151,152,154,167,168,170,175,179,180,185,203,206,215,220,233,238,241,242,250,251,267,271,296,307,310,312,317,321,322,326,328,336,344,364],part_a:179,part_b:179,parti:[8,9,13,23,27,37,42,64,72,75,90,101,114,128,134,177,179,185],partial:[25,68,205,251,269,308,339,341,344,345],particip:[41,103,217,218,219,220,221],particular:[5,8,12,13,14,20,22,28,31,38,40,41,43,44,48,58,59,64,68,70,72,74,75,79,80,83,85,88,89,93,96,97,104,105,107,112,113,114,118,119,121,124,125,131,132,135,139,144,151,152,159,176,187,210,219,220,227,238,241,242,247,256,308,310,318,334,341,362],particularli:[0,4,12,38,39,51,55,127,154,167,170,206,252,271],partit:321,partli:[11,31,47,86,129,152],party_oth:179,pass:[4,10,21,23,25,27,28,29,30,33,36,40,43,49,51,52,62,69,74,80,82,83,85,88,90,91,95,96,100,102,105,107,109,110,111,115,117,119,121,125,127,130,134,138,139,144,146,152,171,182,184,185,188,189,194,209,210,212,215,217,218,219,220,221,232,241,242,247,251,257,260,261,265,277,285,287,295,296,306,312,316,318,327,328,329,330,336,337,338,339,340,343,344,362],passag:[83,116,182,232,233,331],passant:126,passavataridterminalrealm:287,passiv:[29,116,133],passthrough:[1,31,259],password1:[145,357],password2:[145,357],password:[4,9,12,23,35,36,51,64,74,80,103,131,139,144,145,156,157,171,186,204,210,272,287,311,324,349,357],password_chang:360,passwordresettest:360,past:[0,13,20,26,37,46,50,58,62,69,96,104,108,111,116,123,133,137,219,313,322,331,362],pastebin:37,patch:[125,342],path:[0,2,4,8,14,20,21,22,27,29,38,39,40,43,45,48,51,59,60,63,64,66,67,69,74,80,85,86,88,89,90,95,96,100,102,105,106,109,114,117,118,119,121,123,124,125,134,135,136,138,139,144,146,148,151,152,153,158,159,160,161,162,163,164,169,175,177,179,180,181,182,184,185,187,189,195,198,203,204,205,206,212,213,214,217,218,219,220,221,223,224,226,227,230,231,232,233,235,239,246,247,251,252,256,258,259,261,267,274,276,285,298,300,304,308,312,316,317,318,322,324,326,327,328,329,331,334,335,341,344,362],path_or_typeclass:198,pathnam:342,patient:[20,70],patreon:70,patrol:231,patrolling_pac:231,patron:[37,70],pattern:[3,4,16,51,69,87,127,133,134,135,140,157,206,311,344],paul:125,paus:[10,39,46,51,100,102,110,116,194,259,260],pausabl:344,pauseproduc:269,paxboard:79,payload:[278,295],paypal:[37,70],paypalobject:70,pdb:[139,141],pdbref:[80,241],pdf:79,peac:117,peek:[20,26,51,91],peer:[278,295],peform:272,peg:103,pem:67,pemit:[43,108,157],penalti:[86,219],pend:312,pennmush:[57,108,129],pentagon:103,peopl:[2,20,21,26,37,43,54,55,58,61,64,68,71,72,73,79,80,81,85,90,95,96,97,103,108,114,116,119,139,165,186,206,232,233,315,324],pep8:26,per:[2,4,11,19,33,38,41,47,51,58,60,62,64,69,83,86,89,93,100,105,109,112,116,119,123,138,144,175,187,205,217,218,219,220,221,231,251,310,328,329,330,334,337,338],perceiv:62,percent:33,percentag:[116,317],perception_method_test:303,perfect:[50,55,61,75,100,131],perfectli:[4,69,96,112,129,138,321],perform:[11,13,14,22,23,25,39,41,42,43,51,52,55,59,71,74,75,80,89,91,93,97,102,103,114,116,117,123,133,134,150,152,156,159,164,175,180,182,188,194,195,206,209,215,217,218,219,220,221,227,247,250,256,257,276,298,299,316,317,318,325,328,329,336,338,341,344,345,357],perhap:[16,22,42,46,62,69,77,91,97,108,138],period:[90,95,96,100,103,127,128,130,344],perist:[34,125],perm:[4,11,12,19,22,25,33,58,68,71,80,85,109,112,123,133,148,157,158,159,164,165,166,169,187,193,203,212,233,239,241,242,246,247,256,316,318],perm_abov:[80,241],perm_us:157,perman:[4,5,12,21,24,25,31,43,51,85,90,96,122,123,138,144,152,153,156,159,164,165,169,205,247,260,318],permiss:[2,4,7,8,9,11,12,18,20,21,23,25,31,41,43,45,66,68,70,71,75,93,108,109,123,133,139,144,145,147,148,152,154,156,157,158,159,165,167,168,175,193,206,221,239,241,242,246,247,251,252,256,316,317,318,319,322,324,337,341,362,364],permission_account_default:[80,298],permission_func_modul:241,permission_guest_default:66,permission_hierarchi:[19,80,241,242],permissionerror:251,permissionhandl:[133,319],permissionshandl:315,permit:[41,78,159,311],permstr:[80,144,318,324],permut:206,perpetu:93,persis:29,persist:[0,6,21,22,27,31,33,34,43,51,55,56,57,60,64,79,84,86,89,102,104,105,109,110,115,116,121,123,125,144,148,159,169,175,176,177,180,184,188,195,205,206,213,215,217,218,219,220,221,227,230,232,239,246,247,249,250,251,256,257,258,259,260,261,272,273,274,305,306,314,318,324,326,328,330,331,344],person:[12,21,43,61,63,70,73,90,102,105,118,129,139,144,159,165,179,185,206,226],persona:96,perspect:[73,76,77,105],pertain:[103,126,136,350],pertin:[68,133],perus:137,peski:85,pester:[57,61],phase:[49,61],philosophi:80,phone:[16,64,75,139,204],phone_gener:204,phonem:205,php:[108,357],phrase:[46,198],phrase_ev:198,physic:[2,49,220,231],pick:[6,9,13,15,20,21,31,33,35,37,39,43,51,55,62,68,72,73,80,85,90,95,96,100,102,104,106,111,119,132,151,156,159,165,167,168,174,182,190,206,221,224,232,233,247,251,299],pickl:[11,29,83,115,257,261,264,274,276,277,316,317,325,326,328,340],pickle_protocol:340,pickledfield:340,pickledformfield:[315,340],pickledobject:340,pickledobjectfield:340,pickledwidget:340,picklefield:[141,142,315,320],pickpocket:[43,166],pickup:[221,247],pictur:[21,40,57,106,138],pid:[36,80,100,110,131,133,241,247,267,277,344],piddir:36,pidfil:267,piec:[10,13,59,61,64,93,122,203,322,329],pierc:232,piggyback:144,pile:[153,322],pillow:75,ping:[146,164,267,279],pink:119,pip:[9,23,26,38,42,47,59,63,65,71,75,93,96,97,98,100,127,128,130,133,141],pipe:[105,279,325],pitfal:[14,26,114,126],pixel:24,pizza:[148,177,239,246,256,316,318,319],pkg:75,pki:8,place:[0,2,3,4,5,8,9,11,14,15,20,21,25,26,30,37,38,41,43,46,49,51,55,62,63,64,69,71,73,75,76,80,83,89,90,91,95,96,100,102,103,104,105,109,111,121,123,124,126,128,129,131,132,133,135,136,138,144,157,159,165,179,180,182,184,188,203,206,209,217,218,219,220,221,232,233,235,247,259,276,285,306,307,308,322,323,325,328,344],placehold:[134,242,247,330],plai:[0,2,11,14,19,22,29,39,46,55,58,61,64,68,73,75,81,83,90,91,95,105,111,114,116,121,122,123,124,132,133,138,144,217,221,308,324],plain:[13,14,38,58,86,88,123,179,180,202,252,272,298,325,362],plaintext:210,plan:[9,14,15,40,41,42,45,55,56,90,96,100,124,125,127,139,322,364],plane:121,planet:[62,79],plant:234,plate:[82,125,204],platform:[9,16,56,63,90,102,106,131],playabl:[133,360],player:[9,10,11,12,19,20,21,22,25,29,31,34,40,41,43,51,53,54,55,58,60,61,64,65,68,71,73,77,80,81,83,85,90,91,93,95,97,98,105,108,110,111,112,113,116,117,118,119,120,121,122,123,124,133,138,139,153,156,159,164,169,176,179,180,188,190,198,199,203,205,206,210,214,215,220,221,233,234,235,238,256,307,322,327,344,357,362],playernam:71,playerornpc:9,pleas:[4,5,8,16,17,26,31,37,43,51,63,70,71,72,75,78,90,93,109,111,114,117,118,120,124,125,127,131,133,169,269,298,334,340,357,363],pleasur:16,plenti:[14,55,60,129],plot:300,plu:[22,27,43,64,73,106,169],pluck:33,plug:[96,103,107,136,235],plugin:[4,40,45,47,53,55,72,79,83,104,108,138,206,265,364],plugin_handl:[83,137],plugin_manag:137,plural:[19,58,80,220,247],png:[70,136],po1x1jbkiv:37,pobject:226,pocoo:344,point:[0,2,4,5,8,13,14,15,20,21,22,25,27,29,31,33,34,36,37,38,39,42,43,49,51,55,56,60,61,62,63,67,69,73,75,81,83,85,86,88,89,90,91,93,95,97,100,102,104,105,106,112,113,115,116,121,123,125,127,130,131,133,134,135,136,138,139,144,150,154,159,167,168,169,179,189,206,212,217,233,234,235,247,249,251,261,267,271,285,287,295,306,308,315,316,318,322,328,336,344,362],pointer:[26,49,56,91],pointless:[6,10,89,115],poison:[219,252],poke:119,pole:203,polici:[43,45,90,103,139,210,239,311,316],polit:103,poll:[40,136,156,231,267,296],pong:279,pool:[23,31,115,261,312,325],poor:[48,58],poorli:103,pop:[10,23,25,38,48,58,85,106,138],popen:277,popul:[22,23,36,41,57,61,62,81,124,135,138,152,160,161,162,163,180,182,187,203,206,214,217,218,219,220,221,224,230,231,232,233,260,261,315,322,326,327,329,336],popular:[9,57,64,79,103,108,362],popup:[137,138],port:[0,8,9,23,36,43,54,55,63,67,72,100,101,110,146,164,276,279,287,299,308,312],portal:[40,43,45,47,53,79,88,89,90,93,103,104,106,110,121,128,137,139,141,142,146,169,183,262,264,267,305,306,307,308,331,337,344,364],portal_connect:308,portal_disconnect:308,portal_disconnect_al:308,portal_l:277,portal_pid:[277,344],portal_receive_adminserver2port:277,portal_receive_launcher2port:277,portal_receive_server2port:277,portal_receive_statu:277,portal_reset_serv:308,portal_restart_serv:308,portal_run:267,portal_service_plugin_modul:40,portal_services_plugin:[40,104],portal_services_plugin_modul:40,portal_sess:40,portal_session_sync:308,portal_sessions_sync:308,portal_shutdown:308,portal_st:267,portal_uptim:331,portallogobserv:337,portalsess:[40,105,285],portalsessiondata:308,portalsessionhandl:[40,141,142,262,275,286,308],portalsessionsdata:308,portion:[77,180,190],pose:[29,58,116,165,175,195,206],pose_transform:175,poser:175,posgresql:23,posit:[13,20,22,39,49,51,91,111,116,126,127,137,138,139,153,171,180,186,202,221,232,233,234,235,260,321,322,325,326,330,344,345],positive_integ:345,positiveinteg:338,posix:[337,344],possess:[7,77,189],possibl:[0,5,9,10,11,22,23,25,26,31,33,34,37,38,39,43,46,50,55,57,58,63,64,66,73,74,75,76,80,91,93,100,102,104,105,109,111,112,114,116,123,126,127,128,131,134,136,138,141,144,148,150,152,159,167,168,179,187,194,203,205,206,214,227,231,233,235,241,242,247,250,251,252,257,261,272,296,306,308,317,319,321,324,326,327,328,330,340,341,344],post:[5,31,34,37,55,57,58,61,63,69,70,71,80,98,107,111,120,133,136,210,296,362],post_delet:107,post_init:107,post_join_channel:175,post_leave_channel:175,post_migr:107,post_sav:107,post_send_messag:175,post_text:190,post_url_continu:[145,173,244],postfix:205,postgr:[23,64],postgresql:[55,344],postgresql_psycopg2:23,postinit:[83,137],posttext:188,postupd:[71,120],pot:12,potato:[24,234],potenti:[10,11,13,26,41,82,83,90,98,111,114,116,123,154,176,210,211,241,242,247,251,338,341,344],potion:[77,318],power:[15,19,20,29,30,31,33,42,43,46,50,51,55,56,58,61,64,80,89,96,109,111,116,122,123,137,138,152,153,158,159,215,220,234,322,328,344],powerfulli:0,pperm:[12,41,43,71,80,133,156,164,203,241,247],pperm_abov:241,pprofil:267,pprogram:267,practial:15,practic:[0,13,14,22,26,29,33,34,36,37,57,58,63,64,70,80,89,90,96,105,109,119,124,126,131,139,322,364],pre:[33,43,47,49,54,61,63,71,89,90,111,114,138,144,159,166,205,242,247,251,252,295,296,326,340],pre_delet:107,pre_init:107,pre_join_channel:175,pre_leave_channel:175,pre_migr:107,pre_sav:[107,340],pre_send_messag:175,pre_text:190,preced:[19,31,41,96,109,114,119,152,154,174,215,247,252,317,330],precend:150,precis:[11,96,126,321],predefin:[121,311],predict:[125,133],prefac:119,prefer:[21,22,23,31,37,43,47,55,57,71,80,90,91,96,106,109,111,123,131,137,138,152,154,157,175,180,206,218,231,238,247,318],prefix:[20,22,23,42,76,86,97,103,125,145,151,168,175,190,205,237,244,272,279,315,321,336,337,341,344,357],prefix_str:25,prematur:[27,93,179,259],prepai:90,prepar:[3,49,57,87,109,127,136,144,206,217,218,219,220,221,231,256,325,340,363],prepars:38,prepend:[199,206,247,321,322,328,344],prepopul:[315,362],preprocess:159,prerequisit:[9,36],prescrib:[55,57],preselect:138,presenc:[9,17,23,55,56,90,122,124,126,136,144,247,312,346],present:[1,4,8,22,42,46,48,49,51,62,69,77,85,91,96,97,104,105,116,123,131,138,180,188,190,204,205,214,215,234,252,326,344],preserv:[126,167,168,318,321,322,337,344],press:[9,14,15,22,26,31,33,42,51,63,80,83,88,95,96,100,106,110,180,224,226,227,232,265,328],press_button:226,pressabl:227,pressur:82,presto:20,presum:[62,73,153,337,338],pretend:75,pretext:188,pretti:[0,22,25,26,37,38,39,41,60,64,67,72,85,88,89,90,116,121,123,126,131,133,138,154,182,204,236,242,251,327,329,338,344],prettier:[0,357],prettifi:[57,344],prettili:62,pretty_corn:330,prettyt:[27,330],prev:[51,329],prev_entri:51,prevent:[11,20,33,38,46,62,95,194,221,234,315,329,362],preview:38,previou:[0,10,11,14,16,22,29,31,33,41,42,51,52,58,60,62,69,80,85,86,87,91,95,96,100,104,107,114,119,123,126,174,215,233,249,259,328,337,362],previous:[20,31,34,43,49,50,67,72,74,91,102,104,114,119,127,133,136,154,157,159,179,272,299,308,319],prgmr:90,price:[90,232],primari:[17,100,125,133,206,247,316,341],primarili:[2,12,34,36,37,55,61,108,144,179,206,238,285,325,344],primarli:38,primary_kei:133,prime:[150,179],primit:[43,61,159,251],princess:[111,122],principl:[2,9,19,26,30,33,37,38,40,43,51,55,57,60,80,85,89,90,96,98,119,123,132,138,153,156,179,233],print:[4,9,10,11,21,25,26,27,40,42,43,50,51,58,59,83,86,91,95,96,97,110,113,125,156,185,205,234,251,266,267,327,328,329,330,336,337,344],print_debug_info:328,print_help:234,print_usag:234,prio:[25,31,33,150,233],prior:[117,194],priorit:205,prioriti:[4,25,31,33,44,51,97,116,152,156,160,161,162,163,167,168,180,230,232,233,247,326,328,329],privat:[4,8,38,43,57,61,69,90,131,164,165,176,279],private_set:9,privatestaticroot:312,privileg:[21,23,43,60,63,65,72,98,123,165,206,235,247,318],privkei:67,privkeyfil:287,privmsg:279,prize:122,proactiv:115,probabl:[4,5,11,16,21,22,23,25,29,33,37,46,48,51,55,57,61,64,67,69,85,86,89,90,96,108,116,119,121,128,133,134,136,138,180,198,204,233,269,279,287,334,344,345],problem:[11,13,15,21,22,23,24,25,26,27,36,38,43,56,61,64,69,70,75,77,80,90,95,97,100,103,110,111,113,127,138,140,144,153,195,247,276,322],problemat:[25,344],proce:[14,15,100,121,126,362],procedud:51,procedur:[138,215,287],proceed:[131,344],process:[0,4,8,9,11,13,14,15,22,23,25,29,33,36,38,39,41,42,43,49,51,55,59,61,64,67,73,75,76,83,88,89,90,91,92,93,100,106,122,131,133,138,139,144,150,152,159,169,179,206,215,234,240,242,247,251,257,260,267,272,276,277,287,295,296,305,306,308,321,322,325,328,338,343,344,345,362,364],process_languag:206,process_recog:206,process_sdesc:206,processed_result:344,processj:[316,336],processor:[18,43,93,110,111,124,139,141,142,158,169,320,364],procpool:344,produc:[33,43,51,96,114,123,131,156,159,203,205,232,235,247,251,252,266,298,316,318,327,328,336,344],produce_weapon:232,producion:27,product:[23,26,36,90,93,103,106,128,131,135,298,301,328],production_set:9,prof:93,profession:[3,57,64,108],profil:[45,65,139,141,142,145,148,188,262,364],profile_templ:188,profit:138,profunc:109,prog:234,progmat:56,program:[2,10,15,23,43,53,56,57,63,64,67,70,75,77,79,86,90,92,93,95,96,100,103,106,108,110,114,124,127,128,169,234,262,267,296,298],programm:[91,95],programmat:[114,138],progress:[70,73,79,85,131,217,218,219,220,221,326,364],proident:52,project:[4,15,25,37,49,64,70,72,77,79,91,99,108,111,124,127,131,135,136,338],projectil:220,promis:26,promisqu:126,prompt:[9,12,23,24,26,42,54,63,64,75,83,88,96,100,111,124,125,137,139,154,215,265,279,295,296,322,328,364],promptli:14,prone:[1,128,153,318],pronoun:189,prop:61,propag:[8,152,271,340],proper:[15,21,23,27,36,39,43,44,56,57,61,64,85,91,96,100,103,116,123,127,131,133,135,137,138,159,179,180,196,205,327],properli:[9,29,58,62,69,84,106,108,117,125,126,127,128,131,133,140,154,179,211,233,241,260,261,287,344,362],properti:[5,6,13,22,25,39,43,53,55,56,57,59,61,68,73,80,81,84,86,87,96,97,104,109,110,111,115,116,119,121,123,126,127,144,145,146,148,154,156,159,167,169,170,173,175,177,180,188,194,203,206,215,217,219,220,221,231,232,233,234,235,237,239,241,242,244,246,247,251,252,254,256,258,259,260,263,272,274,279,285,299,306,307,308,315,316,318,319,323,325,328,338,339,340,341,344,357,362],propnam:123,propos:[50,138],proprietari:23,propval:123,propvalu:123,prosimii:[133,134],prospect:61,prot:252,prot_func_modul:[109,250],protect:[6,31,43,90,159,306],protfunc:[141,142,248,251],protfunc_modul:251,protfunc_pars:251,protfunct:251,protkei:[109,250,251],proto:[276,287],proto_def:203,protocol:[24,27,33,43,47,53,64,72,74,79,83,90,92,101,103,104,105,110,137,139,144,146,154,157,189,210,247,262,264,267,269,272,276,277,278,279,285,286,287,295,296,298,305,306,307,308,326,340,344,364],protocol_flag:306,protocol_kei:307,protocol_path:[285,308],protodef:203,prototocol:[43,169],protototyp:[249,251,252],protototype_tag:109,prototoyp:250,prototyp:[43,45,46,47,53,55,120,139,141,142,159,169,203,218,219,232,364],prototype1:252,prototype2:252,prototype_:109,prototype_desc:[109,252],prototype_dict:[43,159],prototype_diff:252,prototype_diff_from_object:252,prototype_from_object:252,prototype_kei:[43,109,159,251,252],prototype_keykei:[43,159],prototype_lock:[109,252],prototype_modul:[43,109,159,251,252],prototype_pagin:251,prototype_par:[43,109,159,252],prototype_tag:252,prototype_to_str:251,prototypeevmor:251,prototypefunc:252,protpar:[251,252],protpart:251,provid:[0,3,4,11,12,16,17,22,25,29,33,36,38,41,43,47,55,69,75,77,90,91,96,97,100,102,103,108,109,119,124,125,126,127,131,133,134,136,137,138,144,154,159,164,175,180,182,188,190,193,203,204,215,217,218,219,220,221,234,235,241,247,259,287,310,317,328,338,339,340,344,345,357,362],provok:[42,79],proxi:[47,60,67,70,103,125,312,315],proxypass:8,proxypassrevers:8,prudent:36,prune:31,pseudo:[40,49,91,108,204,205],psionic:220,psql:23,psycopg2:23,pty:9,pub:41,pubkeyfil:287,publicli:[54,61,79],publish:[21,36,79,100],pudb:141,puff:56,pull:[25,31,33,36,37,38,64,100,128,131,136,198,227,232,269],pullrequest:37,punch:31,punish:221,puppet:[2,9,19,21,22,31,33,39,40,41,43,55,57,58,62,74,80,96,97,105,107,114,118,123,133,143,144,150,156,159,167,181,199,241,247,306,308,318,336,360,362],puppet_object:[2,144],purchas:[67,85],pure:[46,56,88,114,125,126,256,267,316,321],pure_ascii:344,purg:[11,43,110,125,169],purpos:[4,11,67,83,90,92,95,112,119,123,126,133,146,150,154,185,194,287,316,325,328,344],pursu:[122,231],push:[22,38,76,100,103,126,198,224,226,227,232],pushd:63,put:[0,2,3,5,6,10,12,13,14,19,20,21,23,25,33,37,38,42,43,46,49,50,51,57,58,60,61,64,70,73,77,79,80,83,85,86,87,89,90,95,96,102,103,104,105,106,109,111,114,116,121,122,123,125,127,129,133,135,136,138,153,156,157,159,161,165,181,182,188,190,206,215,217,218,219,220,221,223,227,242,276,329,330],putti:90,puzzl:[79,122,141,142,178,232,233],puzzle_desc:232,puzzle_kei:233,puzzle_nam:203,puzzle_valu:233,puzzleedit:203,puzzlerecip:203,puzzlesystemcmdset:203,pwd:100,py3:276,pyc:[47,95],pycharm:[38,45,139,364],pyflak:26,pylint:26,pyopenssl:65,pypath:344,pypath_prefix:344,pypath_to_realpath:344,pypi:[64,79,90,93,321],pypiwin32:[9,63],pyprof2calltre:93,pyramid:235,pyramidmapprovid:235,python2:[9,63,97],python37:63,python3:[63,75],python:[0,2,3,4,9,10,11,12,14,15,19,20,21,22,23,27,29,31,33,37,38,39,42,43,45,46,47,49,50,51,53,56,58,60,62,63,64,65,66,69,72,73,75,76,80,82,83,85,86,89,90,91,93,97,98,100,102,103,104,106,108,109,110,111,113,114,116,118,119,123,124,125,127,128,130,133,134,135,139,151,153,158,159,163,169,170,180,185,192,193,194,195,196,198,204,234,235,242,246,250,251,252,258,261,267,269,276,285,295,306,308,312,314,317,318,321,322,324,325,326,327,328,330,331,334,337,340,344,363,364],python_execut:64,python_path:[153,344],pythonista:79,pythonpath:[153,267,277,322],pytz:345,qualiti:[61,151],quell:[2,6,20,121,156,212],quell_color:159,queri:[11,16,34,39,56,64,83,86,109,112,131,148,177,206,238,239,246,247,250,251,252,256,274,287,302,316,317,318,319,329,335,341,344,345],quersyet:119,query_info:267,query_statu:267,queryset:[64,102,112,119,176,199,238,251,273,315,317,329,362],queryset_maxs:329,quest:[55,57,61,63,117,122,139,233],question:[8,10,22,26,33,34,43,50,51,57,61,63,67,70,73,90,96,124,131,135,159,246,264,265,316,326,328,344],queu:267,queue:[36,116,312],qui:52,quick:[5,18,22,31,33,38,39,43,48,55,61,70,79,90,91,95,97,108,112,116,119,124,138,140,146,159,180,205,252,272,316,319,330],quicker:[0,37,86,87],quickli:[10,11,15,25,33,34,39,43,48,51,86,89,96,112,114,120,128,136,139,159,180,205,319,322],quickstart:[95,139,364],quiescentcallback:269,quiet:[25,43,85,144,157,159,164,180,182,206,247,329,344],quiethttp11clientfactori:269,quietli:[29,83,88,316],quirk:[24,45,139,153,364],quit:[0,2,4,10,17,21,22,23,30,33,38,39,40,42,46,50,51,54,55,57,60,67,75,85,93,96,105,119,127,128,133,156,171,180,186,188,194,220,287,326,328,329],quitfunc:[50,326],quitfunc_arg:326,quitsave_yesno:326,quo:115,quot:[23,27,35,43,50,51,80,95,96,109,114,118,159,171,186,206,326,328,336,340,344],qux:215,ra4d24e8a3cab:35,race:[8,55,56,61,73,79,117,133,344],rack:232,radiu:[39,49,111],rage:122,rail:[64,121],railroad:121,rain:[102,119,122,132],raini:233,rais:[10,15,27,33,69,73,77,83,91,109,119,134,144,146,176,180,185,187,192,194,195,204,205,206,242,250,251,259,261,266,267,285,296,311,316,317,321,322,324,327,328,330,336,337,338,339,340,344,345],raise_error:[339,344],raise_except:[1,316],ram:[11,90],ramalho:79,ran:[13,36,42,90,127],rand:102,randint:[73,91,109,116,120,123,217,218,219,220,221,250,252],random:[9,20,35,46,60,73,90,91,102,104,109,114,116,120,123,132,204,205,217,218,219,220,221,223,224,226,228,232,233,235,250,252,298,299,336,344],random_string_from_modul:344,random_string_gener:[141,142,178],randomli:[86,93,102,120,132,217,218,219,220,221,231,232,250,267,299],randomstringgener:204,randomstringgeneratorscript:204,rang:[24,31,39,42,43,49,50,56,59,63,88,91,93,103,109,111,116,118,120,122,127,159,184,188,218,221,317,326,336,357,362],rank:[19,241],raph:79,rapidli:153,rare:[10,22,33,34,38,63,86,104,106,115,128,242,324],rascal:112,rate:[33,37,43,64,90,164,261,267,286,344],rather:[2,3,11,13,20,22,25,26,29,33,37,38,39,41,43,47,55,57,60,61,64,71,86,89,91,93,95,97,102,104,110,111,112,115,116,127,128,129,131,134,135,138,144,148,152,156,159,160,164,167,169,179,190,194,202,206,217,218,219,220,221,236,241,247,249,251,252,315,316,318,321,330,336,339,340,343,362],ration:179,raw:[3,12,20,33,38,41,51,56,64,74,83,86,95,109,114,119,144,151,154,159,167,168,170,206,210,234,247,272,287,295,296,306,321,326,328,329,336,338],raw_cmdnam:[151,168],raw_desc:187,raw_id_field:[173,244,254],raw_input:[85,328],raw_nick:87,raw_str:[33,51,85,144,146,150,151,154,170,188,215,230,247,249,306,316,328],raw_templ:87,rawstr:[154,170],rcannot:22,re_bg:343,re_bgfg:343,re_blink:343,re_bold:343,re_color:343,re_dblspac:343,re_double_spac:343,re_fg:343,re_format:321,re_hilit:343,re_invers:343,re_mxplink:343,re_norm:343,re_str:343,re_ulin:343,re_underlin:343,re_unhilit:343,re_url:343,reach:[20,22,39,51,73,87,88,90,95,101,121,122,141,154,188,192,221,241,287,310,328,329,336,341],reachabl:[64,115],react:[51,115,117,118,231,247],reactiv:[43,169],reactor:[278,305,312,342],read:[0,1,4,5,8,9,11,13,15,16,17,20,22,23,25,27,29,31,33,34,37,38,39,41,43,46,51,55,56,58,59,60,64,69,70,71,72,76,77,79,80,85,86,88,90,91,93,95,96,102,103,104,105,109,114,119,122,123,124,126,127,128,131,133,134,138,139,144,148,158,166,177,180,187,190,198,199,204,206,232,233,239,246,247,251,252,256,274,276,299,316,318,319,322,323,327,329,335,337,362,363],read_batchfil:322,read_default_fil:36,readabl:[1,27,38,49,51,93,96,108,114,115,125,232,321,328],readable_text:232,reader:[38,43,48,58,74,79,81,98,133,164,190,221,272,286],readi:[2,10,12,15,20,25,29,36,37,40,42,54,63,75,77,80,83,89,93,106,121,131,136,138,144,154,166,206,217,218,219,220,221,247,296,329,338],readili:[23,111],readin:327,readlin:337,readm:[14,37,47,53,130,131,178,210],readonlypasswordhashfield:145,readthedoc:[79,83],real:[2,10,21,22,27,31,38,39,42,46,55,58,59,62,63,66,67,72,73,89,90,93,95,100,108,109,110,111,116,119,123,125,126,131,148,153,177,179,184,205,206,219,241,298,322,331],real_address:2,real_nam:2,real_seconds_until:[184,331],real_word:205,realis:77,realist:[127,132],realiti:[21,55,56,61,77,79,126],realiz:[48,96,126,131],realli:[4,10,11,12,13,14,19,20,22,25,26,31,33,38,39,42,51,58,62,64,67,72,77,80,85,89,91,96,98,104,108,110,111,112,115,118,119,121,127,128,138,139,154,170,179,180,181,215,234,242,276,321,322,328,340],realm:287,realnam:89,realtim:[58,184],realtime_to_gametim:184,reason:[8,9,11,12,13,22,25,29,34,37,38,39,40,41,43,44,49,51,56,57,58,60,61,63,64,69,73,80,82,83,86,87,89,93,97,102,103,104,106,109,114,115,116,119,122,126,129,131,138,144,157,159,164,169,186,204,205,247,251,257,264,269,276,277,278,279,285,286,287,295,296,298,306,307,308,318,326,337,344,362],reasourc:109,reassign:49,reattach:[106,278,279],rebas:131,reboot:[11,27,28,43,50,55,67,84,86,90,100,102,105,115,116,128,144,153,164,169,183,188,231,232,247,256,257,258,259,261,267,307,308,326,328],reboot_evennia:267,rebuild:[58,63,100,128,279],rebuilt:33,rec:206,recach:[233,306],recal:[95,138,232,362],recaptcha:133,receipt:[103,269],receiv:[31,33,34,37,41,42,51,52,58,77,83,87,91,105,113,114,117,127,133,137,138,144,152,153,170,171,175,176,177,186,199,206,210,247,269,272,276,278,279,285,295,296,305,306,324,329,341,344],receive_functioncal:276,receive_status_from_port:267,receivelock:241,receiver_account_set:148,receiver_object_set:246,receiver_script_set:256,recent:[4,17,25,60,67,123,310],recev:296,recip:[0,28,115,203],recipi:[34,58,144,176,199,276],reckon:9,reclaim:102,recog:[87,206],recog_regex:206,recogerror:206,recoghandl:206,recogn:[16,20,63,74,83,89,90,96,110,127,134,206,312],recognit:[206,316,336],recommend:[9,12,23,24,25,26,36,37,38,43,51,55,58,59,60,61,63,69,73,79,86,88,89,90,93,95,108,109,122,124,125,127,131,135,169,190,194,209,234,242,247,269,322,328,341],recommonmark:38,reconfigur:90,reconnect:[144,146,164,264,267,276,278,279,305,308],reconnectingclientfactori:[264,278,279],record:[15,23,90,123,210,221,310,357],recours:12,recov:[27,28,29,56,217,218,219,220,221,242,344],recoveri:116,recreat:[23,63,102,111,128,146,153,322,323],rectangl:327,rectangular:[58,327],recur:64,recurs:[11,241,251],red:[13,14,20,31,43,59,80,87,95,109,114,126,159,169,224,226,227,232,336,345],red_bal:59,red_button:[13,14,20,43,87,141,142,159,178,222,224,227],red_button_script:[141,142,178,222,226],red_kei:80,redbutton:[13,14,20,43,87,159,224,226,227],redbuttonblind:227,redbuttonclos:227,redbuttondefault:224,redbuttonopen:227,redd:103,reddit:103,redefin:[22,33,55,89,247,357],redhat:[63,67],redirect:[8,22,40,69,96,105,133,135,180,328,362],redirectview:362,redistribut:34,redit:180,redo:[50,61,326],redon:271,redraw:287,reduc:[116,217,218,219,220,221],redund:321,reel:153,reen:114,ref:[23,38,125,206,344,357],refactor:[45,57,139,363,364],refer:[0,8,9,13,19,20,22,31,33,34,37,40,43,46,48,49,51,56,57,62,64,69,73,79,80,86,87,88,89,90,95,96,100,104,105,106,109,110,111,116,118,119,124,125,126,127,129,130,131,133,134,144,153,159,164,168,179,188,204,206,217,218,219,220,221,241,247,258,260,261,269,279,299,307,315,317,328,334,340,341,344,362],referenc:[43,56,89,104,109,159,175,206,239,318,344],referenti:344,referr:90,refin:[49,119],reflect:[96,362],reflow:16,reformat:[252,330,337],reformat_cel:330,reformat_column:[111,330],refresh:[26,134,287],refus:12,regain:29,regard:[48,126,127,138,204],regardless:[12,19,31,33,58,73,80,81,83,102,105,114,119,121,125,127,138,152,179,189,206,224,227,247,259,261,287,305,307,316,319,322,334,337],regener:219,regex:[5,33,50,51,87,127,137,154,157,170,183,204,206,311,316,328,336,344],regex_nick:87,regex_tupl:206,regex_tuple_from_key_alia:206,regexfield:145,region:[43,58,90,140,157],regist:[65,71,83,103,104,116,120,131,133,135,137,138,144,164,198,231,232,257,267,278,279,285,308,312,321,336,360,362],register_error:321,register_ev:198,registercompon:137,registertest:360,registr:[65,362],registrar:67,registri:[204,312],regress:251,regul:242,regular:[3,17,33,38,51,69,79,90,96,105,115,127,132,134,135,146,152,182,203,204,226,227,233,242,261,319,334,344,363],regulararticl:335,regulararticle_set:335,regularcategori:335,regularli:[67,85,98,102,120,128,132,184,226,231,233,258,259,261,270,300,331],reilli:79,reinforc:79,reiniti:110,reinstal:63,reinvent:57,reject:[188,204],rejectedregex:204,rel:[10,13,14,19,22,31,49,51,82,104,123,131,133,184,221,322,328],relai:[27,33,43,72,105,144,164,179,189,247,285,308,328,329,344],relat:[28,31,33,34,43,47,51,56,57,72,79,96,102,103,104,110,125,132,137,138,139,145,148,149,152,166,167,172,176,177,184,198,210,217,218,219,220,221,230,233,239,246,247,256,259,261,272,308,315,316,318,319,321,328,335,337,346,350,357],related_field:[145,173,237,244,254,315],related_nam:[148,177,239,246,256,316,318,319,335],relationship:[34,49,119,125],relay:146,releas:[9,28,37,43,55,63,78,79,90,96,169],releg:1,relev:[3,9,11,14,22,30,33,37,38,47,58,62,79,80,89,96,107,112,114,116,119,123,124,125,133,135,140,144,145,150,152,179,180,241,242,258,259,299,306,307,308,315,321,326,328,338],relevant_choic:180,reli:[9,34,41,51,62,70,81,85,86,88,91,114,115,119,126,127,135,189,206,227,233,267,318,328],reliabl:[13,23,25,29,125,334],reload:[0,2,3,5,6,7,12,13,14,19,21,22,26,27,28,29,31,33,35,36,39,40,41,42,44,48,50,51,55,57,58,60,62,63,65,66,68,69,71,73,74,81,92,95,96,98,102,104,105,106,115,116,117,118,121,123,125,128,133,134,135,136,139,144,146,153,158,159,169,175,180,181,185,186,187,195,202,206,212,213,232,233,235,242,247,257,258,259,261,267,276,277,279,305,308,312,322,324,326,327,328,331,344,364],reload_evennia:267,remain:[13,19,30,31,33,43,50,51,58,77,90,91,96,97,107,109,110,113,151,153,159,161,165,175,181,184,187,217,218,219,220,221,231,247,259,267,295,296,328,329,336,344],remaind:[21,33,184],remaining_repeat:[102,259],remap:[38,316,336],remedi:60,rememb:[0,1,4,5,11,12,13,21,22,28,29,31,33,39,41,43,48,49,51,54,56,58,61,62,63,69,77,80,86,88,90,91,93,95,96,97,111,112,114,115,119,123,126,128,131,137,139,157,159,181,194,247,257,322,341],remind:[0,4,38,50],remit:[43,157],remnisc:57,remot:[25,100,103,164,276,278],remov:[0,1,4,9,11,12,21,22,27,31,36,39,41,43,48,50,51,55,58,69,80,81,84,85,87,89,91,93,98,102,115,116,122,127,128,131,133,136,138,141,152,153,157,159,164,165,166,169,174,175,177,180,182,187,188,192,196,203,204,205,206,215,217,218,219,220,221,224,242,246,247,252,257,260,261,267,285,296,306,308,310,316,319,321,325,328,334,340,342,343,344],remove_backspac:343,remove_bel:343,remove_charact:116,remove_default:[31,153],remove_receiv:177,remove_send:177,removeth:316,renam:[9,20,43,58,81,136,159,165,247,318],render:[3,22,38,69,81,102,107,133,134,136,145,166,190,237,244,312,315,329,338,340,355,357,362],render_post:296,renew:[29,58,67],reorgan:[45,47],repair:[21,61],repeat:[0,42,61,62,75,88,93,102,110,111,116,118,121,136,139,146,179,184,204,215,256,259,267,272,316,324,328,331],repeatedli:[14,42,62,74,102,139,231,256,259,261,267,272,298],repeatlist:74,repetit:[62,116,204],replac:[5,6,9,22,23,25,29,30,31,33,36,38,41,43,50,51,57,69,74,80,87,89,95,96,100,104,105,109,111,114,116,119,134,135,136,137,138,144,151,152,153,154,157,165,166,170,179,181,183,186,187,188,192,195,202,203,205,206,224,227,230,233,234,242,247,249,251,252,279,295,296,306,316,321,326,327,328,330,336,343,344],replace_data:330,replace_timeslot:187,replace_whitespac:330,replacement_str:[43,165],replacement_templ:[43,165],replenish:[217,218,219,220,221],repli:[33,51,65,70,139,146,179,199,265,296,308,328],replic:[22,114,136],repo:[38,47,57,79,106,131,139,344],report:[22,24,26,33,37,43,61,63,70,73,75,84,91,93,97,102,103,104,115,116,127,131,136,138,159,192,195,206,234,267,272,279,295,306,308,321,324,328,344],report_to:324,repositori:[8,9,23,25,36,76,78,96,100,130,252],repositri:76,repr:[91,329,344],reprehenderit:52,repres:[0,2,9,20,21,22,25,31,33,40,46,49,53,56,61,62,64,69,77,86,89,95,96,105,107,113,116,119,125,126,127,133,136,144,150,174,176,182,188,190,192,198,204,206,210,212,215,219,232,233,234,247,252,260,261,264,278,279,295,296,306,307,308,312,316,317,321,323,324,328,329,330,340,344],represent:[2,11,28,40,58,64,73,77,86,87,88,105,113,119,126,176,192,195,206,251,256,276,295,296,319,325,331],reprocess:103,reproduc:[10,96,247],reput:209,reqhash:[317,344],reqiur:188,request:[3,8,26,37,40,43,51,63,69,80,90,103,107,119,123,131,133,134,135,139,144,145,146,157,173,179,195,244,247,251,254,267,269,276,279,286,287,296,312,315,319,328,349,350,351,355,362],request_finish:107,request_start:107,requestavatarid:287,requestfactori:312,requestor:310,requir:[1,4,8,9,10,11,14,15,22,23,33,36,37,38,43,46,47,49,50,51,54,58,60,61,67,68,69,70,71,75,77,78,79,80,84,85,86,89,90,93,102,109,110,111,114,115,116,118,119,125,126,127,129,132,133,134,136,137,145,158,159,164,169,176,177,185,186,187,188,202,204,206,215,219,220,233,234,237,238,241,244,247,251,260,267,278,279,300,311,315,317,322,327,328,329,330,334,339,340,341,344,357,362],require_singl:251,requr:109,rerout:[138,156,160,279],rerun:[13,14,51,122],resart:259,research:[79,194],resembl:[25,55,129],resend:33,reserv:[1,10,33,95,96,111,251,311,317,336,344],reset:[0,7,12,15,17,23,27,29,31,33,44,50,60,66,73,81,102,104,105,111,114,116,121,123,125,126,139,144,146,153,159,169,174,184,195,206,227,232,242,258,259,267,271,277,287,305,316,319,322,330,331,336,342,344],reset_cach:[316,319],reset_callcount:[102,259],reset_gametim:[27,331],reset_serv:271,reset_tim:187,resid:[47,96,108,227,242],residu:[43,169,219],resist:[252,344],resiz:[58,138,327,330],resolut:[114,116],resolv:[26,29,42,60,70,90,95,104,116,131,203,217,218,219,220,221],resolve_attack:[217,218,219,220,221],resolve_combat:116,resort:[33,54,58,164,206,344],resourc:[9,23,26,28,38,41,47,48,53,56,90,95,96,103,108,115,124,127,135,136,139,220,257,265,296,312,323,342],respect:[0,6,23,33,43,48,58,80,104,105,123,125,157,159,166,179,199,203,206,213,224,242,247,306,307,318,319,322,324,330,341,344,357],respond:[0,46,51,61,83,84,107,110,117,118,126,298],respons:[7,10,16,17,37,49,51,60,63,64,70,85,88,90,91,118,120,121,144,146,153,164,175,233,235,239,247,265,267,269,276,299,308,318,338,340,344],response_add:[145,173,244],resport:344,rest:[17,29,33,51,56,63,73,82,85,86,87,104,106,111,122,123,151,167,168,217,218,219,220,221,321,330],restart:[12,42,43,58,60,76,90,92,93,102,103,104,106,110,116,128,131,135,138,141,144,169,175,180,183,195,227,247,257,259,260,261,271,305,306,307,344],restartingwebsocketserverfactori:[146,278],restock:85,restor:[0,31,102,126,180,220,227,257,261],restrain:[43,159,241,327,344],restrict:[4,8,11,19,20,43,47,59,68,73,80,90,109,111,115,125,134,137,159,164,182,204,220,221,237,242,252,324,326,328,330,341],restructur:[38,56],result1:203,result2:[51,203],result:[10,11,23,27,30,31,33,38,43,44,48,51,58,59,73,80,88,90,91,95,96,97,104,105,109,114,115,116,118,119,123,124,126,127,131,134,135,136,144,151,152,154,159,166,175,177,179,185,188,203,204,205,206,209,217,218,219,220,221,233,238,242,247,250,251,252,259,267,276,299,316,318,321,326,327,328,330,334,336,337,338,341,344,345],result_nam:203,resum:[29,33,102,260],resurrect:231,resync:[146,276,306],ret:33,ret_index:344,retain:[10,27,31,51,97,111,138,189,252,313,318,322,324,337,344],retext:38,retract:179,retreat:221,retri:267,retriev:[0,33,43,69,74,86,96,97,108,112,119,123,139,140,144,148,150,153,159,169,174,176,187,194,238,241,251,265,272,273,279,285,316,319,325,334,339,341,344,362],retriv:[146,323],retroact:[58,125],retur:52,return_appear:[49,60,122,123,182,187,206,232,247],return_cmdset:166,return_detail:[187,233],return_iter:251,return_key_and_categori:319,return_list:[1,316,319],return_map:111,return_minimap:111,return_obj:[1,11,87,316,319,339],return_par:252,return_prototyp:120,return_puppet:144,return_tagobj:319,return_tupl:[87,185,306,316],returnv:33,returnvalu:10,reus:[25,334],reusabl:122,rev342453534:344,reveal:182,revers:[29,31,33,39,111,114,121,126,134,148,177,235,239,246,256,312,316,318,319,321,335],reverseerror:[267,276],reversemanytoonedescriptor:[148,246,335],reverseproxyresourc:312,revert:[43,90,126,131,156,238],review:[0,31,37,41,64,70,128,135],revis:61,revisit:[36,328],reviu:51,revok:58,revolutionari:131,rework:[29,61],rewritemim:70,rfind:321,rgb:114,rgbmatch:321,rhel:8,rhostmush:[57,108,129],rhs:[25,58,167,168,170],rhs_split:[159,165,167,168],rhslist:[167,168],ricardo:344,riccardomurri:344,rich:[22,57,78,79,325],richard:79,rick:109,rid:[56,119,139],riddanc:12,ridden:[1,96],riddick:188,ride:121,right:[0,5,8,10,14,20,21,23,25,28,29,33,38,39,41,42,43,46,51,55,56,57,58,60,61,63,68,74,75,76,80,85,87,90,91,96,101,102,109,111,114,117,119,121,123,126,127,128,133,134,137,138,145,153,156,159,167,168,175,181,187,188,190,195,196,203,221,224,227,231,232,233,235,242,250,252,256,307,321,322,326,330,344,345],right_justifi:[109,250],rigid:57,rindex:321,ring:205,ripe:96,rise:[31,62],risen:62,risk:[38,43,57,63,90,123,138,158,169],rival:111,rjust:321,rm_attr:159,rnormal:114,rnote:[43,169],road:[31,46,111,121,152],roadmap:[45,139,364],roam:[122,153,231],roar:111,robot:[77,133],robust:[85,91,103],rock:[6,60,86,116,124,153],rocki:122,rod:153,role:[17,23,55,57,61,73,91,217],roleplai:[9,11,57,61,68,73,79,116,123,139,185,206,364],roll1:73,roll2:73,roll:[11,58,61,63,73,91,114,116,123,185,217,218,219,220,221,310],roll_challeng:73,roll_dic:185,roll_dmg:73,roll_hit:73,roll_init:[217,218,219,220,221],roll_result:185,roll_skil:73,roller:[73,116,185],rom:79,roof:[43,159],room1:127,room56:13,room:[9,12,13,14,15,20,21,22,27,31,33,42,43,44,45,46,53,55,56,57,59,62,63,64,73,77,80,85,91,96,102,104,108,109,111,112,116,117,118,119,120,121,122,123,124,125,127,129,132,133,140,141,142,150,151,152,153,157,159,165,170,178,180,182,185,187,194,206,212,213,214,217,218,219,220,221,229,230,231,232,234,235,241,247,256,271,299,322,342,360,364],room_count:119,room_flag:56,room_lava:56,room_typeclass:[235,342,360],roombuildingmenu:[22,180],roomnam:[43,58,159],roomobj:119,roomref:121,root:[9,13,22,23,36,47,53,63,64,69,75,78,80,81,86,89,90,93,96,97,100,106,128,130,134,135,136,232,247,252,267,312,325,344,364],rose:[11,87,89,125],roster:[9,217,218,219,220,221],rosterentri:9,rot:127,rotat:337,rotatelength:337,roughli:[58,61,96,344],round:[17,205,221,330],rounder:205,rout:[5,20,49,56,121,137,144],router:90,routin:[206,302,341,344],row:[0,3,16,25,38,49,58,64,69,86,111,114,116,126,137,330,344],rpcharact:206,rpcommand:206,rpg:[58,60,73,124,185,221],rpi:79,rplanguag:[141,142,178,206],rpm:63,rpobject:206,rpsystem:[38,141,142,178,202,205],rpsystemcmdset:206,rred:321,rsa:287,rspli8t:91,rsplit:[123,321],rsrc:70,rss2chan:[98,164],rss:[7,43,55,79,128,139,141,142,146,164,172,262,272,275,285,364],rss_enabl:[98,164],rss_rate:146,rss_update_interv:[43,164],rss_url:[43,98,146,164],rssbot:146,rssbotfactori:286,rsschan:[43,164],rssfactori:286,rssreader:286,rst:38,rstrip:[91,321],rsyslog:209,rtest2:114,rtext:85,rthe:22,rthi:114,rtype:312,rubbish:[43,156],rubi:64,rudimentari:231,ruin:[122,187,233],rule:[12,13,14,21,33,47,55,58,61,68,77,79,80,96,114,124,126,127,131,139,180,204,205,217,218,221,239,322,364],rulebook:116,rumour:122,run:[0,2,3,5,6,8,9,10,11,13,14,15,20,21,23,24,26,27,28,29,31,35,36,38,40,43,45,46,47,51,53,54,56,57,59,60,61,62,63,64,67,68,69,72,73,76,79,80,81,83,85,86,90,91,92,93,95,96,97,101,102,103,104,109,110,111,115,119,121,122,123,124,125,126,128,130,131,132,133,134,136,137,138,139,141,144,146,150,151,153,154,158,159,164,165,166,169,170,174,175,195,196,206,209,213,215,217,218,219,220,221,227,230,235,241,242,247,251,252,256,258,259,260,261,267,271,273,277,296,298,301,305,306,310,312,318,321,322,326,328,329,331,337,341,342,344,362,363,364],run_async:[10,344],run_connect_wizard:267,run_dummyrunn:267,run_exec:328,run_exec_then_goto:328,run_init_hook:305,run_initial_setup:305,run_menu:267,run_start_hook:[60,125,318],runexec:328,runexec_kwarg:328,runnabl:109,runner:[36,106,232,298],runsnak:93,runtest:[170,196,211,228,303,335,342,352,360],runtim:[12,27,33,62,154,180,234,331,344],runtimeerror:[73,144,146,192,195,198,204,205,251,259,285,316,328,336,344],runtimewarn:251,rusernam:51,rush:29,rusti:85,ruv:36,ryou:22,sad:133,safe:[11,26,30,31,43,46,56,60,64,82,89,97,104,131,133,156,179,227,242,261,276,308,312,318,322,325,334,344],safefunc:326,safer:[12,13],safest:[0,90,105,318],safeti:[2,43,56,89,90,123,125,139,159,179,246,322],sai:[0,5,6,10,12,14,17,20,22,25,26,27,29,31,33,39,40,41,44,46,51,56,57,58,60,61,62,63,64,69,73,77,78,80,89,90,91,93,96,109,114,116,117,118,119,123,125,126,127,128,129,131,137,138,139,140,153,165,179,181,185,188,198,205,206,215,227,233,247,328],said:[0,4,10,22,26,43,44,46,49,51,57,83,91,96,111,112,118,127,134,151,164,168,206,235,247,279,318,328],sake:[13,43,57,126,135,171,186,362],sale:85,same:[0,2,5,6,9,10,11,12,13,14,15,16,19,20,21,22,23,26,27,28,29,31,33,34,37,38,40,41,42,43,44,50,55,57,58,59,60,61,62,63,64,66,69,73,74,78,80,81,83,84,85,86,88,89,90,91,95,96,97,98,100,102,104,105,106,108,109,110,111,112,113,114,115,116,119,121,123,125,126,127,128,131,133,134,136,138,144,150,151,152,153,154,157,159,167,168,169,170,175,180,182,184,187,190,194,195,199,204,205,206,212,214,215,217,218,219,220,221,224,231,233,234,235,241,247,251,252,256,257,261,271,276,306,307,308,310,312,315,316,317,318,319,321,322,324,328,329,330,331,337,338,344,357,362],sampl:[8,36,56,100,215],san:190,sand:62,sandi:111,sane:[61,79,96,362],sanit:[357,362],saniti:[9,49,111,127,139,338],sarah:[43,129,165],sat:[21,140],satisfi:[108,167],satur:103,save:[0,1,9,15,21,22,24,27,29,33,34,36,41,42,43,46,48,50,51,54,56,64,67,84,86,87,89,95,97,100,102,103,105,107,109,110,112,115,116,123,125,127,131,133,138,144,145,156,159,169,173,175,176,177,180,195,242,244,246,247,249,251,252,254,257,259,260,261,265,272,285,299,300,305,306,312,315,316,318,325,326,334,338,339,340,344],save_a:[173,237,244,254,263],save_as_new:315,save_buff:326,save_data:338,save_for_next:[33,154],save_handl:338,save_kwarg:339,save_model:[145,173,244,254],save_nam:261,save_on_top:[173,237,244,254,263],save_prototyp:251,save_recip:203,savefunc:[50,326,339],savehandl:339,saver:325,saverdict:325,saverlist:325,saverset:325,saveyesnocmdset:326,saw:[10,46,69],say_text:118,saytext:206,scale:[23,57,61,73,106,114,205],scalewai:90,scan:[8,150,231,233],scarf:182,scatter:[219,322],scedul:331,scenario:58,scene:[11,21,38,55,59,61,73,74,97,109,112,114,116,122,126,204,233,256,261,334],schedul:[27,62,184,195,260,331],schema:[4,64,86,125,131,344],scheme:[28,33,43,63,86,114,159,169,321],scienc:[49,124],scientif:79,scissor:116,scm:9,scope:[29,55,64,74,124,134,138,204,324],score:[58,60,344],scraper:362,scratch:[40,46,57,58,61,63,123,124,128,136,139],scream:122,screen:[7,16,18,33,43,51,52,61,66,74,81,85,97,100,101,104,105,109,114,127,133,138,139,145,171,186,190,221,250,272,287,329,344,364],screenheight:[74,154,272],screenread:[74,272,295,296],screenshot:[55,133,139,364],screenwidth:[74,154,272],script:[6,11,13,14,20,27,36,45,47,53,55,56,57,59,61,62,63,71,80,84,85,86,89,90,93,103,104,105,106,107,108,109,110,112,115,116,117,119,120,122,125,130,132,133,137,138,139,141,142,144,146,158,159,169,177,178,179,184,187,191,192,198,203,204,205,213,217,218,219,220,221,223,224,226,227,233,235,241,246,247,251,252,267,300,305,322,323,324,331,339,341,342,344,360,364],script_path:[43,159],script_search:59,script_typeclass:[228,342,360],scriptattributeinlin:254,scriptbas:259,scriptclass:258,scriptdb:[53,119,125,141,254,256,314],scriptdb_db_attribut:254,scriptdb_db_tag:254,scriptdb_set:[148,246,316,319],scriptdbadmin:254,scriptdbmanag:[255,256],scripthandl:[141,142,253],scriptkei:[43,159],scriptmanag:255,scriptnam:323,scripttaginlin:254,scroll:[20,45,52,63,77,95,96,97,123,138,329],scrub:308,scrypt:102,sdesc:[56,202,206],sdesc_regex:206,sdescerror:206,sdeschandl:206,sdk:63,sea:[111,122],seamless:206,seamlessli:[92,102],search:[0,2,9,13,21,22,30,33,41,42,43,48,50,55,58,59,60,64,68,70,73,76,87,89,96,102,104,109,116,123,124,125,127,131,134,136,139,140,141,142,144,150,152,154,159,166,169,176,179,194,199,203,206,217,218,219,220,221,233,235,238,241,247,250,251,258,273,316,317,318,319,320,321,324,326,344,363,364],search_:[27,59],search_account:[58,107,119,141,247,341],search_account_attribut:119,search_account_tag:[119,341],search_at_multimatch_input:247,search_at_result:[206,247],search_attribute_object:119,search_channel:[41,119,141,176,341],search_channel_tag:[119,341],search_field:[173,237,244,254,263,315],search_for_obj:159,search_help:[119,141,238],search_help_entri:341,search_helpentri:238,search_messag:[119,141,176,341],search_mod:206,search_multimatch_regex:247,search_object:[11,13,27,111,119,121,125,141,144,341],search_object_attribut:119,search_objects_with_prototyp:251,search_prototyp:251,search_script:[59,102,119,141,341],search_script_tag:[119,341],search_tag:[48,112,119,140,141],search_tag_account:112,search_tag_script:112,search_target:199,searchabl:194,searchdata:[144,206,247,341],searchstr:68,season:[61,187],sec:[10,29,62,74,184,279,331],secmsg:337,second:[0,10,11,14,16,21,22,25,27,29,31,33,38,39,41,43,51,62,63,69,80,85,86,88,90,91,95,100,102,103,104,109,110,114,115,116,119,120,121,123,126,127,132,134,144,146,151,159,184,194,195,198,206,213,217,218,219,220,221,223,227,231,241,247,252,259,260,261,267,272,286,299,310,321,324,328,331,337,344,345],secondari:[81,307],secondli:89,secreci:131,secret:[9,23,65,71,185,267],secret_kei:9,secret_set:[4,9,23,65,267],sect_insid:49,section:[1,4,9,11,15,18,21,22,23,25,26,29,31,33,35,36,38,39,40,48,51,58,60,62,63,68,69,75,77,80,86,89,90,93,95,96,100,111,113,119,124,125,127,133,137,138,139,187,205,252,321,322,328,345],sector:49,sector_typ:49,secur:[7,11,13,22,26,37,41,43,57,63,80,85,90,96,108,109,114,123,133,134,139,141,142,158,169,175,178,239,247,287,318,337,357,364],secure_attr:80,sed:36,see:[0,1,2,3,4,5,8,9,10,11,12,13,14,19,20,21,22,23,25,26,27,28,29,30,31,32,33,34,35,37,38,39,40,41,42,43,44,46,48,49,50,51,52,53,55,56,57,58,59,60,61,62,63,64,65,68,70,71,72,74,75,76,80,81,82,83,86,87,88,89,90,91,93,95,96,98,100,101,102,103,104,105,106,108,109,110,111,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,130,131,132,133,134,135,136,137,138,139,144,154,156,158,159,164,165,166,167,168,170,175,177,178,179,180,186,190,192,199,203,204,205,206,210,213,214,215,217,218,219,220,221,223,224,226,231,233,234,235,241,246,247,260,265,267,269,270,278,279,287,295,296,298,299,306,307,308,312,316,321,324,325,326,327,330,336,339,340,344,351,357,362],seek:[122,242,337],seem:[4,22,24,31,39,41,56,61,63,75,109,110,119,121,122,123,137,138,316,322],seen:[0,22,29,31,34,40,46,49,51,57,58,69,81,91,95,96,102,105,111,119,120,121,126,127,131,180,251,279,330],sefsefiwwj3:9,segment:[121,312],seldomli:[154,170],select:[2,20,22,27,31,38,43,51,54,63,69,77,80,85,86,104,105,106,111,119,120,123,131,133,137,138,140,151,152,157,166,215,218,318,326,328],selet:328,self:[0,1,2,5,6,9,10,11,13,20,21,22,25,27,28,29,30,31,33,38,39,40,41,42,43,44,49,50,51,56,57,58,59,60,62,63,71,72,73,76,77,80,81,82,85,86,87,89,95,96,102,109,115,116,117,118,119,120,121,123,125,127,129,132,134,144,146,148,150,152,153,154,156,159,160,164,167,168,169,170,174,175,177,179,180,181,182,185,187,188,192,199,202,203,206,215,217,218,219,220,221,223,224,227,230,231,232,233,234,235,241,247,259,260,265,267,269,270,274,278,279,285,287,295,296,306,307,308,316,318,319,321,326,328,329,334,336,338,339,340,344,351],self_pid:344,selfaccount:58,sell:[78,85,179],semi:[93,132,138,205],semicolon:[80,242,324],send:[2,12,22,25,27,29,33,34,41,43,51,52,58,59,61,64,67,70,71,73,74,76,80,81,83,89,91,93,95,96,102,103,105,107,110,113,114,115,116,118,120,123,126,133,137,138,139,140,144,146,150,153,154,157,164,168,174,175,176,177,179,188,189,199,206,210,221,223,230,231,241,247,260,261,264,267,269,270,272,276,277,278,279,285,286,287,295,296,298,306,307,308,309,321,324,325,328,330,344],send_:[40,83,285],send_adminportal2serv:277,send_adminserver2port:264,send_authent:278,send_channel:[278,279],send_default:[40,83,278,279,285,287,295,296],send_defeated_to:231,send_emot:206,send_functioncal:276,send_game_detail:269,send_heartbeat:278,send_instruct:267,send_mail:199,send_msgportal2serv:277,send_msgserver2port:264,send_p:279,send_privmsg:279,send_prompt:[287,295,296],send_random_messag:223,send_reconnect:279,send_request_nicklist:279,send_status2launch:277,send_subscrib:278,send_testing_tag:230,send_text:[40,83,287,295,296],send_unsubscrib:278,sender:[34,41,43,107,144,146,164,175,176,177,179,206,247,278,309,334,341],sender_account_set:148,sender_extern:177,sender_object:309,sender_object_set:246,sender_script_set:256,sender_str:175,sendernam:[43,164],senderobj:324,sendlin:[287,295],sendmessag:[40,188],sens:[1,10,22,31,37,56,58,80,86,89,96,102,121,138,152,224,324,325,328],sensibl:[90,271],sensit:[11,51,58,80,176,180,184,187,195,210,211,238,317,331,341],sensivit:204,sent:[25,34,51,58,69,74,83,88,91,105,107,113,114,119,137,138,144,146,150,164,166,170,175,176,177,180,186,188,195,199,210,228,234,247,264,267,269,272,276,277,278,279,287,295,306,308,316,328,336,341],sentenc:[46,91,198,205,206],sep:321,sep_kei:[22,180],separ:[8,11,13,14,20,23,29,31,33,37,40,43,46,48,51,57,58,61,62,64,71,72,75,77,80,84,85,86,87,89,91,92,93,95,96,98,101,102,103,105,106,112,114,115,119,121,123,126,129,131,133,136,137,138,140,151,153,154,159,165,166,167,168,169,175,180,195,198,199,205,206,215,217,218,219,220,221,224,233,235,238,242,246,247,251,257,261,286,296,308,321,322,324,327,329,336,341,344],separatli:29,seq:87,sequenc:[10,13,14,15,33,64,80,81,87,89,113,126,154,158,184,206,242,265,271,321,322,328,330,343,344],seri:[51,61,79,114,131,136,138,226,330],serial:[11,83,138,250,260,261,285,325,338,340,344],serializ:296,seriou:[39,110],serious:63,serv:[45,49,55,64,83,101,103,104,111,135,152,219,296,312,322,324,355],server:[0,2,4,9,10,11,12,13,15,19,21,25,26,27,28,29,31,33,34,35,36,37,38,40,41,45,47,51,53,54,55,56,57,58,59,60,62,63,64,65,66,67,69,70,71,72,73,74,75,78,79,80,81,83,84,86,88,89,91,93,95,96,97,100,101,102,103,106,107,109,110,111,113,114,115,116,118,121,122,124,125,127,128,130,131,133,134,135,136,137,138,139,141,142,144,146,153,157,159,164,169,171,175,178,180,183,186,187,195,202,206,207,208,209,212,213,227,231,232,233,235,247,256,257,258,259,261,313,318,322,324,325,326,328,331,334,337,338,344,346,363,364],server_connect:285,server_disconnect:285,server_disconnect_al:285,server_epoch:[27,331],server_l:277,server_logged_in:285,server_nam:104,server_pid:[277,344],server_receive_adminportal2serv:264,server_receive_msgportal2serv:264,server_receive_statu:264,server_reload:[257,261],server_run:267,server_runn:305,server_servic:344,server_services_plugin:[40,104],server_services_plugin_modul:40,server_session_class:105,server_session_sync:285,server_st:267,server_twistd_cmd:277,server_twisted_cmd:277,serverconf:[157,261],serverconfig:[260,261,273,274],serverconfigadmin:263,serverconfigmanag:[273,274],serverfactori:[277,287],serverload:[43,169],serverlogobserv:337,servermsg:337,servernam:[4,8,9,54,74,90,104],serverprocess:[43,169],serversess:[40,105,114,141,142,210,242,262,285,308],serversessionhandl:[40,105,308],serverset:[43,80,164,241],servic:[12,23,40,45,67,71,90,100,103,104,110,131,133,141,142,169,262,264,267,268,276,277,305,312,344],sessdata:[307,308],sessid:[2,33,105,123,246,247,264,276,277,285,308],session:[2,12,15,24,31,33,40,45,47,51,53,57,74,81,84,88,89,91,96,100,107,114,123,127,138,139,141,142,144,146,148,150,151,152,154,156,157,160,162,166,167,171,186,188,189,209,210,211,230,246,247,249,250,251,257,262,264,272,276,277,278,279,285,286,287,295,296,305,306,308,310,326,328,329,336,344,345,364],session_data:308,session_from_account:308,session_from_sessid:308,session_handl:[105,141],session_portal_partial_sync:308,session_portal_sync:308,sessioncmdset:[31,43,162],sessionhandl:[40,83,141,142,144,247,262,272,278,279,285,286,306,307],sessionid:285,sessionobject:336,sessions_from_account:308,sessions_from_charact:308,sessions_from_csessid:[285,308],sessions_from_puppet:308,sesslen:247,set:[0,2,3,6,7,8,10,11,12,13,14,15,16,17,19,20,21,22,23,24,25,26,27,29,30,32,33,34,35,36,37,38,39,40,41,42,44,45,46,47,50,52,53,55,56,57,58,59,60,61,63,64,66,67,68,69,71,74,75,76,82,83,85,86,87,89,91,93,95,96,97,100,102,105,107,108,109,110,111,112,113,114,116,117,119,120,121,124,125,126,128,129,130,133,134,135,136,137,138,139,141,143,144,146,148,150,151,152,153,154,156,157,159,160,161,162,163,164,166,167,168,170,172,174,180,181,182,183,184,185,186,187,188,189,193,195,198,202,203,205,206,209,212,213,215,217,218,219,220,221,224,226,227,228,230,231,232,233,234,235,237,241,242,246,247,250,251,252,258,259,260,261,264,266,267,271,272,273,274,277,278,287,298,299,301,303,305,306,307,308,310,312,313,315,316,317,318,319,321,322,323,324,325,326,327,328,329,330,331,334,335,336,337,338,339,340,341,342,343,344,345,350,357,360,364],set_active_coordin:235,set_al:231,set_alias:154,set_attr:159,set_class_from_typeclass:318,set_dead:231,set_descript:51,set_detail:[187,233],set_game_name_and_slogan:350,set_gamedir:267,set_kei:154,set_nam:51,set_password:144,set_task:195,set_trac:[42,141],set_webclient_set:350,setcolor:81,setdesc:[57,165,212],setgend:189,sethelp:[20,68,166],sethom:159,setlock:212,setnam:40,setobjalia:[43,159],setperm:[43,157],setspe:213,sett:98,settabl:[74,86],setter:39,settestattr:50,settingnam:80,settings_chang:107,settings_default:[4,5,34,47,104,127,141,142,337,344],settings_ful:104,settings_mixin:[141,142,262,297],settl:[111,116],setup:[5,15,18,26,40,47,61,63,67,71,85,93,96,100,116,120,127,129,131,138,139,144,156,164,170,184,196,224,228,230,233,247,259,271,298,302,303,305,312,318,334,335,342,360,364],setup_str:302,setuptool:[63,75],sever:[0,11,14,19,22,29,31,33,36,41,42,43,48,50,52,55,56,57,59,62,69,79,80,102,104,109,113,116,119,125,137,158,159,167,168,169,187,194,195,231,233,247,319,324],sex:189,shall:[126,134],shaman:[57,109],shape:[20,22,39,58,61,111,235,330],sharabl:109,share:[9,25,31,36,37,42,46,57,59,63,64,65,80,86,90,102,103,105,112,116,119,125,133,135,145,194,195,252,261,298,317,319,330,344,351],sharedloginmiddlewar:351,sharedmemorymanag:[317,333],sharedmemorymodel:[177,239,316,318,334,335],sharedmemorymodelbas:[148,177,239,246,256,316,318,334,335],sharedmemorystest:335,shaw:[77,79],she:[0,22,33,56,91,126,180,189,205],sheer:[43,159],sheet:[23,38,51,133,134,137,327],sheet_lock:58,shell:[7,23,25,26,36,57,58,59,60,63,75,86,87,90,100,103,108,110,125,128,287],shield:[29,77,86],shift:[14,15,27,108,195,232,238,344],shiftroot:232,shine:[21,233],shini:344,ship:[55,64,75,111],shire:62,shirt:182,shoe:182,shoot:[21,220,221,327],shop:[51,57,108,124,139,364],shop_exit:85,shopcmdset:85,shopnam:85,shopper:85,short_descript:54,shortcom:85,shortcut:[0,3,22,23,27,29,31,33,38,43,47,59,69,91,96,100,107,116,119,125,129,133,134,141,146,153,154,159,180,192,235,242,247,338,344],shorten:[42,46,125,252],shorter:[40,61,104,108,117,118,125,132,175,205,317,324,337],shortest:[39,206],shorthand:[43,89,126,159],shortli:[0,22,77],shot:220,should:[0,1,2,3,4,5,6,8,9,10,11,12,13,14,15,16,19,20,22,23,24,25,26,27,29,31,33,34,37,38,39,40,41,42,43,46,47,48,51,55,57,58,59,60,61,62,63,64,65,66,67,68,69,72,73,74,75,76,77,80,81,82,83,85,86,88,89,90,91,93,95,96,97,98,100,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,119,121,122,123,124,125,126,127,128,129,130,131,133,134,135,136,137,138,139,140,144,146,148,150,152,153,154,156,158,159,160,163,166,167,169,170,174,175,177,180,182,184,187,192,195,198,199,202,203,204,205,206,209,217,218,219,220,221,224,227,230,231,233,234,241,242,246,247,249,250,251,252,256,258,259,260,261,265,266,267,271,274,278,287,295,296,299,305,306,307,308,311,313,315,316,318,319,321,322,324,325,326,328,329,330,331,336,337,338,339,340,342,344,345,357,360,362],should_join:175,should_leav:175,should_list_cmd:166,shoulddrop:[221,247],shoulder:[58,182],shouldget:[221,247],shouldgiv:[221,247],shouldmov:[217,218,219,220,221,247],shouldn:[0,13,21,22,29,41,48,58,93,126,166,180,195,198,220,298],shouldrot:337,shout:29,shove:21,show:[0,12,13,14,20,22,24,26,27,30,33,35,37,38,39,40,42,43,46,48,49,52,54,55,57,58,60,61,62,63,64,68,69,70,71,73,81,82,85,86,90,91,95,96,97,98,101,102,103,104,105,106,110,111,114,116,117,118,119,120,122,124,126,127,128,129,131,133,134,136,137,138,139,144,156,157,159,164,165,167,169,171,179,181,182,185,186,187,188,190,202,215,220,221,226,233,234,235,247,249,251,252,265,267,276,326,328,337,338,339,344,357],show_foot:329,show_map:49,show_non_edit:251,show_non_us:251,show_valu:190,show_version_info:267,show_warn:267,showcas:[31,111],shown:[0,4,9,22,25,29,35,41,43,49,51,54,57,62,68,109,114,121,133,138,154,157,164,166,168,170,180,182,204,206,232,247,267,328,329],showtim:62,shrink:330,shrug:46,shrunk:101,shuffl:27,shun:[26,90,108],shut:[0,4,29,43,93,100,102,104,137,144,169,247,259,261,267,269,276,277,285,305,308],shutdown:[12,19,31,58,93,102,105,110,144,146,169,261,267,276,277,305,306,318,324,328],shy:[26,61,129],sibl:[10,57,96,102],sid:[43,157],side:[0,1,11,24,36,38,43,48,49,58,73,74,83,91,105,112,119,126,127,133,137,138,146,148,165,167,168,177,179,185,212,239,246,256,264,276,277,285,295,306,307,308,316,318,319,321,330,335],sidestep:19,sidewai:330,sigint:267,sign:[0,14,20,46,83,90,91,106,115,123,132,187,247,261,321,345],signal:[45,93,110,139,141,142,217,218,219,220,221,262,267,296,298,334,364],signal_acccount_post_first_login:107,signal_account_:107,signal_account_post_connect:107,signal_account_post_cr:107,signal_account_post_last_logout:107,signal_account_post_login:107,signal_account_post_login_fail:107,signal_account_post_logout:107,signal_account_post_renam:107,signal_channel_post_cr:107,signal_helpentry_post_cr:107,signal_object_:107,signal_object_post_cr:107,signal_object_post_puppet:107,signal_object_post_unpuppet:107,signal_script_post_cr:107,signal_typed_object_post_renam:107,signatur:[33,73,154,177,192,260,265,267,269,270,278,287,295,296,306,321,328,336,339,340,351],signed_integ:345,signedinteg:338,signedon:279,signifi:[14,241],signific:97,significantli:50,signup:4,silenc:269,silenced_system_check:127,silent:[10,43,62,118,157,164,271,279],silli:[60,89,96,109],silvren:[55,90],similar:[0,11,13,20,21,22,25,33,41,48,51,55,58,64,67,68,73,77,86,89,90,96,102,106,121,125,129,136,137,140,144,154,156,170,180,188,205,217,218,219,220,221,235,239,247,306,308,316,319,324,328,344,362],similarli:[58,62,90,112,218,234,315],simpl:[0,2,4,5,6,9,10,13,14,15,17,25,26,28,30,31,33,35,38,39,40,41,43,46,49,50,55,56,57,58,59,60,61,64,67,69,70,73,74,76,77,81,85,86,88,89,90,91,95,96,98,100,103,105,108,109,111,112,116,117,118,119,120,122,123,124,126,132,133,135,139,159,174,179,180,181,186,187,188,189,194,199,203,204,206,212,213,214,215,217,218,219,220,221,223,224,231,232,233,235,236,246,247,250,252,259,277,286,322,323,354,355,357,364],simpledoor:[141,142,178],simplemu:24,simpler:[10,15,38,43,51,56,158,159,325,362],simpleresponsereceiv:269,simplest:[6,29,58,73,90,116,153,322,345],simpli:[5,8,11,12,13,17,20,21,22,23,25,29,31,37,38,39,40,41,47,49,51,55,58,59,61,63,71,72,73,80,81,83,85,96,102,103,104,109,112,114,118,121,123,125,127,128,131,132,138,140,144,152,153,154,170,171,174,175,180,186,187,196,206,213,215,217,218,219,220,221,224,232,239,247,318,322,323,327,329,344],simplic:[22,39,43,55,126,171,186,232],simplif:[45,116],simplifi:[10,69,100,111,116,118,192],simplist:[116,123,132,137,205,214],simul:[33,73,93,213],simultan:[58,88,116,344],sinc:[0,1,3,4,5,6,9,10,11,13,14,19,21,22,23,25,26,27,28,29,31,33,34,35,38,39,40,41,42,43,44,47,48,49,50,51,54,55,56,57,58,59,60,61,62,64,69,74,76,80,83,84,85,86,88,89,90,91,94,96,97,100,102,104,110,111,114,115,116,118,119,121,122,123,125,126,127,131,133,134,135,138,144,146,148,152,153,154,159,167,168,169,175,176,179,180,181,184,187,199,206,215,217,218,219,220,221,227,232,233,241,247,251,252,257,260,261,267,269,272,299,305,306,308,315,316,317,318,322,323,324,326,328,331,334,337,340,341,342,344,357],singl:[0,5,10,14,16,22,23,31,33,37,38,43,44,48,51,55,57,58,59,61,64,67,73,77,83,87,88,90,95,96,105,108,111,112,114,119,122,125,127,128,129,139,144,150,157,159,165,176,177,180,204,209,215,217,218,219,220,221,233,234,235,247,251,252,260,261,299,306,308,317,319,321,322,327,328,330,336,341,344,357],single_type_count:182,singleton:[84,105,115,174,257,260,323],singular:[58,61,247],sink:26,sint:52,sir:46,sit:[11,14,29,33,47,55,63,80,83,90,95,96,119,121,123,125,167,198,199,206,224,232,233,242,258,261,324,339,342],sitabl:125,sitat:233,site:[8,16,17,23,37,69,71,79,80,90,97,98,100,101,103,111,133,134,145,312,362],site_nam:59,situ:[11,318,325],situat:[0,6,11,22,33,37,42,43,46,62,76,83,86,102,105,119,125,131,153,154,159,194,334],six:[73,91,185,215],sixti:62,size:[16,24,42,49,58,97,101,108,111,137,138,141,235,269,321,327,329,330,334,337,344],size_limit:344,skeleton:123,sketch:[116,138],skill:[28,29,30,55,60,61,70,73,79,110,116,121,127,133,134,205,206,327],skill_combat:73,skillnam:73,skin:109,skip:[31,33,41,43,49,51,61,62,75,88,100,106,109,115,131,144,158,159,247,316,325],skipkei:296,skippabl:129,skull:109,sky:[102,132],slack:79,slam:188,slash:[20,38,41,55,73,116,122,232],slate:111,sleep:[10,29,33,73],slew:[61,73,75,322],slice:[119,156,321,329],slice_bright_bg:156,slice_bright_fg:156,slice_dark_bg:156,slice_dark_fg:156,slight:[8,91,184,195],slightli:[42,62,63,79,116,123,145,177,187,218,234,362],slightly_smiling_fac:138,slip:343,slogan:9,slot:[58,134,187,188,218,220,252],slow:[27,116,176,213,231,235,251,286,321,341,344],slow_exit:[141,142,178],slower:[62,77,90,93],slowexit:213,slowli:79,slug:[175,239,318,362],slugifi:362,small:[4,14,15,16,25,30,33,37,55,57,58,61,63,69,70,79,81,85,90,91,93,96,97,98,108,111,122,123,124,127,128,139,185,220,224,235,326,327,330,344],smaller:[13,14,16,38,101,330],smallest:[58,62,80,90,184,327],smallshield:86,smart:[41,77,91,235],smarter:109,smash:[61,224,227],smell:61,smelli:109,smile:[33,43,165],smith:327,smithi:29,smoothi:203,smoothli:134,smush:48,snake:136,snap:82,snapshot:131,snazzi:78,sneak:242,snippet:[10,13,21,31,43,55,64,80,109,114,139,169,276,343,344],snoop:103,snuff:26,social:[55,71],socializechat:299,soft:[4,64,139,205,364],softcod:[129,139],softli:78,softwar:[36,63,90,131],solar:62,soldier:85,sole:[57,69,146],solid:[49,55,114],solo:[20,63,124],solut:[0,9,14,25,27,29,39,56,69,73,85,90,91,103,111,115,118,121,122,125,127,138,168,242],solv:[21,27,44,49,61,63,77,97,111,203,232],some:[0,3,4,5,6,8,9,11,12,13,14,15,16,20,21,22,23,24,25,26,27,28,29,31,33,36,37,38,40,42,43,45,46,48,49,50,51,55,57,58,60,61,62,63,64,67,69,70,72,73,74,75,77,78,79,80,82,83,85,86,87,89,90,91,95,96,97,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,121,122,123,124,125,126,127,128,131,133,134,136,137,138,139,144,153,154,159,161,165,168,169,175,176,179,180,181,186,195,198,204,205,212,215,218,219,220,221,226,227,230,232,233,234,235,242,247,251,252,256,269,271,276,279,305,318,321,322,327,328,331,334,337,338,344,357,362],some_long_text_output:329,somebodi:[0,138],somehow:[33,40,73,80,87,90,113,140,182,326],someon:[0,1,29,33,43,46,48,49,58,60,80,85,90,96,103,107,115,117,118,119,138,144,165,182,226,231,232,247],somepassword:23,someplac:231,someth:[0,3,4,6,8,9,10,11,12,14,20,22,23,25,27,29,30,33,38,39,40,41,43,44,46,49,51,52,56,57,58,59,60,61,62,64,65,67,68,69,70,71,72,73,75,80,82,83,85,86,89,90,91,93,95,96,102,104,107,108,109,111,114,115,119,123,125,127,128,129,133,134,135,137,138,139,144,152,154,159,165,166,167,179,180,182,189,198,204,206,213,217,218,219,220,221,232,233,234,235,242,247,252,306,318,322,328,329,338,344,362],sometim:[6,22,27,33,40,42,50,51,60,62,64,80,86,91,93,95,96,102,109,110,119,136,138,166],somewhat:[4,22,41,57,127,138,180],somewher:[0,12,37,43,73,80,90,109,121,125,131,159,175,239,318,344],soon:[42,61,69,72,96,100,105,127,226,296,344],sophist:[10,27,55,108,116],sorl:4,sorri:[80,242],sort:[3,6,11,31,39,49,59,61,64,69,73,83,84,90,105,110,112,116,117,135,140,179,190,217,218,219,220,221,233,247,252,256,317,318,328,357,362],sort_kei:296,sought:[144,151,175,239,247,316,318],soul:111,sound:[22,29,37,58,61,80,82,83,102,104,111,115,131,138,205],sourc:[0,4,9,10,12,15,16,17,20,21,22,23,27,31,36,37,46,47,55,57,60,63,64,67,68,72,75,76,79,88,89,96,97,108,122,127,128,130,131,134,139,141,144,145,146,147,148,150,151,152,153,154,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,173,174,175,176,177,179,180,181,182,184,185,186,187,188,189,190,192,193,194,195,196,198,199,202,203,204,205,206,209,210,211,212,213,214,215,217,218,219,220,221,223,224,226,227,228,230,231,232,233,234,235,237,238,239,241,242,244,245,246,247,249,250,251,252,254,255,256,257,258,259,260,261,263,264,265,266,267,269,270,271,272,273,274,276,277,278,279,285,286,287,295,296,298,299,300,302,303,304,305,306,307,308,310,311,312,315,316,317,318,319,321,322,323,324,325,326,327,328,329,330,331,333,334,335,336,337,338,339,340,341,342,343,344,345,349,350,351,352,355,357,359,360,362,363],source_loc:[25,77,96,117,232,233,235,247],source_object:[171,174,186],sourceurl:279,south:[0,22,43,44,49,111,121,159,299],south_north:111,southeast:159,southern:111,southwest:[20,43,159],space:[9,20,21,22,25,33,35,38,41,43,46,48,49,51,57,68,80,87,91,95,102,109,111,114,116,118,126,129,137,138,151,154,159,165,167,168,170,171,174,202,205,206,221,232,247,250,311,318,321,322,327,328,330,336,343,344],spaceship:121,spacestart:343,spaghetti:[13,328],spam:[12,28,103,116,138,310],spammi:[12,116],span:[16,17,108],spanish:76,spare:[217,218,219,220,221],spars:310,spatial:111,spawen:203,spawn:[47,53,55,93,120,122,137,138,141,157,159,203,218,219,249,250,251,252],spawner:[18,45,89,120,139,141,142,159,219,220,248,364],spd:134,speak:[0,15,19,41,43,46,60,96,113,117,118,126,133,165,206,241,247],speaker:[46,205,206],spear:109,special:[2,10,11,13,14,15,19,20,25,26,27,30,31,33,35,37,41,42,51,58,60,61,64,69,76,77,80,81,83,85,86,88,89,95,102,103,104,107,111,112,113,114,116,119,122,123,125,127,131,134,137,146,148,150,153,165,168,187,189,206,215,219,220,232,233,235,242,244,247,271,272,295,316,318,322,328,343],specif:[0,2,4,9,11,12,22,23,24,25,26,27,31,33,36,37,38,39,40,41,42,43,46,47,50,51,53,55,56,59,61,62,64,67,69,77,78,79,80,82,87,88,89,90,91,95,96,100,105,107,110,111,112,115,116,119,121,122,123,124,125,126,127,131,132,133,134,135,137,138,144,145,150,157,159,169,175,177,178,179,180,192,193,194,195,199,204,206,238,241,247,257,267,272,279,295,296,306,316,318,321,322,326,328,329,330,362],specifi:[3,11,12,16,19,21,22,27,29,31,38,39,43,46,49,51,54,58,62,63,68,83,84,86,88,90,91,98,100,102,103,105,109,111,112,114,115,119,123,127,134,136,150,151,159,166,175,180,182,183,185,187,188,192,194,195,199,203,204,206,215,218,219,220,235,241,242,247,250,251,252,257,278,304,319,321,322,324,327,328,331,338,339,340,344,357,362],spectacular:42,speech:247,speechlock:241,speed:[11,47,62,82,86,87,93,116,134,213,252,285,319,341],spell:[15,19,28,57,60,109,112,215,220,252],spell_attack:220,spell_conjur:220,spell_heal:220,spell_nam:220,spellnam:220,spend:[39,89,91,119,217,218,219,220,221],spend_act:[217,218,219,220,221],spend_item_us:219,spent:220,sphinx:38,spin:[62,90],spit:[3,60,116],splashscreen:186,split:[9,25,31,33,41,58,91,104,105,111,118,121,123,131,136,138,151,167,168,184,232,235,249,308,321,322,329,331],split_2:138,split_nested_attr:159,splithandl:138,spoken:[0,46,72,205,206,247],spoof:315,spool:63,sport:87,spot:[57,64,144],spread:[70,73,109],spring:[82,124,187],sprint:213,sprofil:267,spunki:77,spyrit:24,sql:[7,36,56,57,64,86,125,139,302,364],sqlite3:[25,55,64,86,123,127,128,131,344],sqlite3_prep:305,sqlite:[23,86,128,305],sqllite:36,sqrt:39,squar:[38,39,129],squeez:86,src:[10,17,20,59,75,80,89,100,102,133,137,139,210],srcobj:[154,167],srun:271,srv:36,ssessionhandl:83,ssh:[9,25,40,55,64,83,90,105,110,141,142,262,275,306,307],ssh_interfac:90,ssh_port:90,sshd:103,sshfactori:287,sshprotocol:287,sshserverfactori:287,sshuserauthserv:287,ssl:[7,8,43,55,64,67,83,88,141,142,146,164,262,275,279,307],ssl_interfac:90,ssl_port:90,sslcertificatefil:8,sslcertificatekeyfil:8,sslciphersuit:8,sslengin:8,ssllab:8,sslprotocol:8,ssltest:8,sslv3:67,sta:327,stab:[29,122,232],stabil:[61,170,205],stabl:[37,40,56,60,100],stabli:[97,261],stack:[13,31,61,121,137,145,152,153,227,251,308,328,336],stackedinlin:145,stackexchang:127,stackful:336,stacktrac:[251,336],staf:108,staff:[9,19,25,57,61,68,73,80,108,109,111,123,133,152,252,322],staff_onli:239,staffer:9,staffernam:9,stage:[2,36,56,61,77,111,123,131,133,145,173,244],stagger:279,stai:[1,31,49,51,63,90,91,121,125,126,138,235],stale:[100,125,260],stale_timeout:260,stalker:362,stamina:[30,190,220],stamp:[27,43,96,105,125,137,144,148,157,169,246,256,299,304,318],stanc:[116,206],stand:[13,17,20,21,22,25,29,38,43,49,56,61,63,72,73,80,86,90,95,96,111,116,121,122,123,127,131,133,138,165,179,206,231,247,256,261,298,306,316,319,322,324,330],standalon:[67,103],standard:[0,1,6,8,9,15,21,27,30,41,43,50,57,58,59,63,64,79,83,88,91,95,103,113,114,116,120,126,131,136,139,141,144,156,185,186,206,234,241,247,287,311,316,321,330,331,336,345,364],stanza:277,star:[43,159],stare:131,start:[0,1,2,3,4,5,7,12,13,14,15,16,18,20,21,23,25,26,27,29,31,33,34,38,39,40,41,42,43,44,45,47,48,49,50,51,54,55,57,59,60,61,62,64,65,66,67,69,70,72,73,74,75,76,77,79,80,83,84,86,87,90,91,93,95,96,97,98,101,102,103,104,105,106,107,108,109,111,114,116,119,120,121,123,124,125,127,128,130,131,132,133,136,137,138,139,144,146,151,152,158,159,164,165,167,168,169,170,174,179,180,185,187,188,189,190,195,205,206,215,217,218,219,220,221,226,227,230,231,233,235,247,249,250,251,256,258,259,260,261,264,267,269,271,272,277,278,279,285,286,298,304,305,308,312,317,321,322,323,324,326,328,329,330,331,336,337,344,363,364],start_all_dummy_cli:298,start_attack:231,start_bot_sess:308,start_delai:[102,116,120,121,227,256,259,261,324],start_driv:121,start_evennia:267,start_hunt:231,start_idl:231,start_lines1:267,start_lines2:267,start_loc_on_grid:49,start_olc:249,start_only_serv:267,start_ov:51,start_patrol:231,start_plugin_servic:40,start_portal_interact:267,start_serv:277,start_server_interact:267,start_sunrise_ev:62,start_text:215,start_turn:[217,218,219,220,221],startapp:[69,86,133,134],startclr:[114,336],startedconnect:[264,278,279],starter:[9,136],starthour:25,startnod:[51,85,188,230,249,328],startnode_input:[51,188,230,249,328],startproduc:269,startservic:[270,312],startset:233,startswith:[41,43,84,159,321],starttupl:287,startup:[11,35,40,60,62,90,102,104,136,247,256,296,305,337,344],stat:[17,43,60,61,71,85,116,123,133,134,136,139,169,179,217,218,219,220,221,364],state:[11,13,14,31,33,42,43,50,51,55,56,64,80,95,100,102,105,110,114,116,121,122,126,127,131,137,138,144,150,152,153,156,163,171,174,212,217,218,219,220,221,224,227,231,233,252,256,258,259,261,267,287,316,326,328],state_unlog:163,statefultelnetprotocol:298,statement:[10,13,14,27,31,42,49,51,55,58,59,83,86,95,96,118,119,124,247,322,343],static_overrid:[135,136,137],static_root:136,statict:[43,169],station:121,stationari:231,statist:[3,12,43,104,105,120,124,135,169,190,300,317,334],statu:[20,29,51,58,61,88,90,104,105,115,131,175,179,219,220,221,231,261,265,267,276,277,278,295],status:61,status_cod:269,stderr:234,stdin_open:100,stdout:[59,100,234,267,337],steadi:64,steal:[43,85,166],steer:121,step1:29,step2:29,step3:29,step:[0,4,7,8,13,14,21,23,29,31,33,36,38,39,41,43,45,46,50,51,58,63,69,73,77,82,85,86,91,97,100,102,106,108,121,122,123,126,127,128,134,138,139,158,180,233,259,261,271,298,299,308,318,322,325,326,328,329,363,364],stick:[15,33,38,43,51,63,113,157],still:[0,1,4,6,9,11,13,14,15,19,20,22,25,26,29,31,33,37,38,39,40,41,43,49,55,57,58,60,62,63,64,77,78,79,83,91,95,96,102,103,105,106,107,108,110,114,121,122,123,125,126,128,131,134,138,152,159,164,166,186,215,217,218,219,220,221,230,233,235,247,251,258,299,328,330,331,340,344],sting:111,stock:[34,55,85,101,210,357],stolen:[103,321],stone:[20,33,60],stoni:60,stop:[7,9,10,12,14,20,25,27,29,34,41,42,43,49,51,57,58,62,63,67,74,77,80,82,89,90,93,95,96,100,102,104,105,106,108,115,116,120,121,123,128,137,139,156,159,164,169,179,184,194,196,206,212,213,218,221,226,227,247,258,259,260,261,266,267,269,272,285,305,306,312,321,322,324,344,364],stop_driv:121,stop_evennia:267,stop_serv:277,stop_server_onli:267,stopproduc:269,stopservic:[270,312],storag:[11,13,23,28,29,33,43,47,56,64,73,85,86,96,102,125,133,138,148,169,174,177,198,205,235,242,246,247,251,252,256,259,261,274,306,310,314,316,318,323,338,339],storage_modul:323,storagecontain:102,storagescript:102,store:[0,2,9,13,15,21,23,27,28,29,31,33,34,37,39,40,41,43,44,46,47,49,50,55,56,57,58,60,61,64,69,73,75,80,82,85,86,87,89,91,95,97,100,102,104,105,112,113,115,116,119,121,123,125,127,128,131,133,134,135,136,137,138,139,144,146,148,153,156,157,159,160,162,167,168,174,177,179,187,188,195,202,204,205,206,210,213,214,219,223,232,233,235,241,242,246,250,251,252,253,257,258,259,260,261,267,271,272,273,274,277,279,299,305,306,307,308,310,312,316,317,318,319,321,323,324,325,326,327,328,329,334,336,338,339,340,344,357,362],store_kei:261,store_result:48,store_tru:234,stored_obj:25,storekei:[85,261],storenam:85,storeroom:85,storeroom_exit:85,storeroom_kei:85,storeroom_key_nam:85,stori:[3,9,97,133],storm:[28,119],storypag:3,storytel:123,stove:247,str:[0,10,11,22,25,27,39,40,50,51,58,59,60,73,74,84,91,96,113,114,119,125,127,133,134,141,144,146,150,151,152,153,154,159,166,170,174,175,176,177,179,180,182,184,187,188,189,190,192,193,194,195,198,199,204,205,206,210,212,215,217,218,219,220,221,230,233,234,235,238,239,242,247,250,251,252,257,258,259,261,264,265,267,272,273,274,276,277,278,279,285,286,287,295,296,298,304,305,306,307,308,310,311,312,315,316,317,318,319,321,322,323,324,326,327,328,329,330,336,337,338,339,340,341,342,343,344,345,349,362],straight:[49,68,126],straightforward:[25,41,85,91,121,123],strang:[6,8,14,29,41,56,131,153],strangl:90,strategi:[42,221],strattr:[1,11,316],strawberri:234,stream:[106,276,306],streamlin:[36,179],strength:[11,57,58,60,61,73,80,116,134],stress:[93,298],stretch:111,stribg:344,strict:[10,251,321],stricter:251,strictli:[19,51,59,77,133,186,220,330],strike:[43,51,82,116,165,214,220,221],string1:344,string2:344,string:[5,9,11,12,13,15,19,20,22,23,25,27,29,31,33,34,35,38,41,42,43,49,50,54,55,57,58,59,60,62,68,71,76,82,83,84,86,87,88,89,90,93,95,96,97,104,109,111,112,113,114,115,116,119,124,125,127,129,133,134,137,138,139,141,142,144,146,148,150,151,154,157,159,165,166,167,168,169,170,174,175,176,177,179,180,182,186,188,198,199,203,204,205,206,210,211,215,217,218,219,220,221,230,231,235,238,239,240,241,242,246,247,250,251,252,256,259,261,267,269,272,276,279,287,299,304,306,308,311,315,316,317,318,319,320,321,324,325,326,327,329,330,336,337,338,340,341,342,343,344,345,362],string_from_modul:344,string_partial_match:344,string_similar:344,string_suggest:344,stringproduc:269,strip:[21,22,33,38,41,43,51,58,74,81,85,108,109,114,118,123,151,159,167,168,206,252,272,287,321,322,328,336,344],strip_ansi:[81,321,343],strip_control_sequ:344,strip_mxp:321,strip_raw_ansi:321,strip_raw_cod:321,strippabl:328,stroll:213,strong:[80,114,123,343],strongest:80,strongli:[64,73,95,124,205],strr:204,struct:56,structur:[9,11,33,37,41,43,45,47,48,49,51,55,56,59,63,64,68,69,80,83,88,95,96,109,119,133,134,136,138,159,206,247,250,251,252,296,319,325,328,354,361,362],strvalu:[11,316,317],stuck:[51,63],studi:59,stuff:[3,9,11,21,29,31,37,38,47,49,51,57,61,67,73,80,85,96,102,105,107,109,119,138,153,159,189,234,261,305,350],stumbl:97,stupidli:34,sturdi:327,stutter:108,style:[3,16,20,21,27,33,37,38,40,41,45,51,55,57,58,61,79,87,95,106,111,114,116,122,124,129,138,148,154,156,167,182,183,188,199,217,234,247,251,326,330,344],styled_foot:154,styled_head:[33,154],styled_separ:154,styled_t:[33,154],sub:[9,11,36,37,38,57,65,69,88,90,108,109,116,119,137,138,143,149,172,173,178,180,206,234,236,238,240,243,250,252,253,262,314,320,321,343,346],sub_ansi:321,sub_app:133,sub_brightbg:321,sub_dblspac:343,sub_mxp_link:343,sub_text:343,sub_xterm256:321,subclass:[27,64,105,109,118,119,125,159,180,235,246,251,256,277,296,315,318,335,340,344],subdir:127,subdirectori:[37,127],subdomain:[8,90,103],subfold:[47,86,95,96,134,135],subhead:38,subject:[36,39,81,86,90,124,189,199],submarin:121,submenu:[106,180,249],submenu_class:180,submenu_obj:180,submiss:[188,357],submit:[17,37,103,133,188,357,362],submitcmd:188,subnet:[12,43,157],subpackag:[88,127],subprocess:[25,344],subreddit:79,subscrib:[12,33,34,41,43,53,58,64,80,115,128,132,146,164,174,175,176,219,261,278,309],subscript:[33,43,58,79,115,132,164,173,176,177,261],subsequ:[10,11,33,43,95,116,164,322,344],subsequent_ind:330,subset:[56,112,127],subsid:125,substitut:[51,71,87,106,247,321,343],substr:321,subsubhead:38,subsubsubhead:38,subsystem:[9,63,86,242],subtitl:17,subtract:[85,250],subturn:116,subword:344,succ:241,succe:[61,116,185],succeed:[185,234],success:[73,116,123,134,144,175,179,185,217,218,219,220,221,224,232,233,242,251,260,267,271,318,326,338,344,362],success_teleport_msg:233,success_teleport_to:233,success_url:362,successfuli:203,successfulli:[10,28,33,36,60,77,110,111,130,144,203,232,235,247,259,260,267,279,311,318,362],suddenli:[26,97,318],sudo:[63,67,100,103],suffic:[17,57,61],suffici:[86,90,119],suffix:[27,97,114,321,336,337,344],suggest:[1,23,25,37,38,48,51,52,55,61,68,70,90,95,97,125,138,140,151,166,179,206,233,247,344],suggestion_cutoff:166,suggestion_maxnum:166,suit:[29,34,55,64,117,139,170,344,362],suitabl:[21,25,33,37,55,63,64,80,83,87,88,90,112,131,152,242,301,308,324,328],sum:[37,82,91,139,153],summar:[0,79,139],summari:[0,7,46,79,96,110,123,180],summer:187,sun:62,sunris:62,sunt:52,super_long_text:329,superclass:145,superfici:205,superflu:343,supersus:242,superus:[2,4,5,6,9,12,13,14,19,20,21,23,25,41,43,58,60,63,81,95,96,111,122,134,144,148,158,169,175,182,212,231,241,242,247,252,267,318,322,324],supplement:51,suppli:[10,11,27,34,37,43,51,58,59,63,68,72,74,84,88,93,102,105,109,112,114,115,116,123,127,148,153,154,157,159,164,169,170,176,180,184,186,187,190,246,247,251,256,261,278,308,318,326,329,331,341,344],support:[2,4,7,8,9,11,23,26,33,37,38,40,42,43,44,47,49,50,51,56,57,58,61,63,64,65,66,70,74,75,76,81,83,86,87,90,91,94,98,100,103,109,110,113,114,123,126,139,156,165,183,184,185,187,198,234,241,247,250,251,252,261,272,287,296,307,316,321,325,328,329,330,336,341,344,349,364],supports_set:[74,272],suppos:[0,33,51,61,76,83,109,119,138,144,180],supposedli:[67,205],suppress:24,suppress_ga:[141,142,262,275],sur:79,sure:[0,2,4,5,8,9,11,12,13,14,15,19,20,21,23,25,28,29,30,31,33,36,37,38,41,42,43,44,49,51,57,58,60,61,62,63,67,71,72,73,75,78,80,81,86,87,89,90,91,93,95,96,97,100,102,105,106,109,110,111,112,113,115,116,118,123,125,126,127,128,131,133,134,136,137,138,140,144,146,152,153,154,156,159,164,167,174,176,180,182,196,204,205,206,211,215,220,223,227,231,232,233,238,241,242,247,251,252,258,259,267,271,277,279,305,311,312,313,315,317,318,321,323,325,328,334,340,341,343,344,360,362],surfac:[58,82,103],surpris:[22,39,69,80,91],surround:[31,33,43,111,116,119,129,157,231,340,344],surviv:[5,11,27,28,31,43,50,51,84,102,105,115,116,126,146,153,169,180,256,257,261,324,326,328],suscept:[27,56,242],suspect:133,suspend:[100,103,106],suspens:102,suspici:51,suspicion:133,svn:[36,108],swallow:[96,118,276,343],swap:[43,114,127,137,138,159,187,202,318,326],swap_autoind:326,swap_object:318,swap_typeclass:[60,125,144,318],swapcas:321,swapcont:138,swapper:318,swedish:76,sweep:102,swiftli:10,swing:[28,29,33,82],switch1:129,switch2:129,switch_opt:[156,157,158,159,164,165,166,167,168,169,187],sword:[20,28,33,61,73,77,85,86,119,179,206,252,341,344],symbol:[14,15,33,49,75,106,108,119,215,235,329],symlink:[38,63],symmetr:330,sync:[64,83,105,131,174,285,305,306,307,308,316,325],sync_port:308,syncdata:[307,308],syncdb:127,synchron:337,syntact:[242,344],syntax:[5,6,13,14,15,21,22,23,29,33,41,43,46,48,51,55,58,60,62,76,80,91,97,114,119,123,129,134,141,142,154,158,159,167,168,170,180,185,187,188,234,242,247,267,279,306,318,320,321,336,364],syntaxerror:60,sys_cmd:152,sys_game_tim:59,syscmdkei:[33,53,141],syscommand:[141,142,149,155,247],syslog:209,sysroot:75,system:[0,2,4,5,9,10,11,19,21,22,23,26,27,28,29,31,34,36,37,38,39,40,41,44,46,47,49,53,55,56,59,60,62,63,64,67,74,75,76,77,79,81,83,84,85,86,87,90,93,95,97,102,103,104,105,107,108,109,110,111,112,114,115,119,121,122,125,126,127,128,129,131,132,134,136,138,139,140,141,142,145,146,148,149,150,152,154,155,156,158,166,168,170,172,175,176,177,179,180,182,186,193,194,195,196,198,199,202,203,205,206,209,210,211,215,217,218,219,220,221,226,230,233,235,236,239,241,242,246,247,249,252,253,259,267,296,304,314,318,322,324,327,328,337,363,364],system_command:33,systemat:39,systemctl:8,systemd:67,systemmultimatch:168,systemnoinput:168,systemnomatch:168,systemsendtochannel:168,tab:[9,14,26,30,36,59,69,95,96,106,114,137,138,321,330,343],tabl:[0,4,13,15,43,45,46,48,53,58,59,64,69,82,88,97,111,113,114,119,125,128,134,154,156,166,169,188,310,321,327,329,330,341,344],table_char:327,table_format:156,table_lin:330,table_str:58,tablea:327,tableb:327,tablechar:[58,327],tableclos:88,tablecol:330,tabledata:329,tableevmor:329,tableopen:88,tablet:16,tabletop:[58,73,79,124,217,221],tabsiz:[321,330],tabstop:343,tabularinlin:315,tack:[20,119,153],tackl:37,tactic:[73,116],taction:116,tag:[9,12,13,18,20,24,27,33,45,48,51,53,55,57,58,64,73,74,86,87,88,95,96,100,109,114,119,124,125,134,136,137,138,139,140,141,142,145,159,173,177,183,187,189,199,204,206,209,230,232,239,241,244,251,252,254,296,304,314,315,317,318,321,324,327,330,341,364],tag_categori:315,tag_data:315,tag_kei:315,tag_typ:315,tagadmin:315,tagform:315,tagformset:315,taghandl:[112,125,315,319],taginlin:[145,173,237,244,254,315],tagkei:[241,319,324],taglin:17,tagnam:252,tagstr:[252,319],tagtyp:[112,317,319,341],tail:[76,90,100,267,337],tail_log_fil:[267,337],tail_log_funct:337,tailor:[4,69,357],take:[0,3,4,9,10,11,13,14,15,16,17,19,20,21,22,25,26,27,28,29,31,33,37,40,42,46,49,51,52,55,56,57,58,62,64,69,70,74,75,76,77,79,80,83,85,90,91,95,96,103,104,105,106,108,109,111,114,116,119,121,122,123,124,125,126,127,133,134,136,138,139,144,146,151,152,156,168,174,177,179,182,184,187,188,203,204,206,209,213,215,217,218,219,220,221,230,231,233,242,250,252,271,287,295,307,308,317,318,321,326,327,328,329,338,344,345],taken:[31,43,56,64,103,116,120,121,123,165,186,209,217,218,219,220,221,287,311,321,324],takeov:309,taladan:48,tale:3,talk:[23,27,33,34,37,40,41,43,46,58,60,90,91,131,138,165,179,205,206,214,233,264],talker:[55,61],talki:64,talking_npc:[141,142,178],talkingcmdset:214,talkingnpc:214,tall:[43,129,165,206],tallman:[43,165],tandem:61,tantal:14,target1:220,target2:220,target:[21,25,28,29,30,33,34,40,43,58,73,88,103,114,116,119,123,127,136,138,144,154,159,164,165,169,177,182,185,187,199,215,217,218,219,220,221,231,235,247,317,321,324,328,344],target_loc:[213,233,235,247],target_obj:242,targetlist:199,task:[0,27,36,40,41,91,93,102,110,112,138,193,195,215,260,261,344],task_handl:[141,260,344],task_id:[195,260],taskhandl:[141,142,253,344],taskhandlertask:[260,344],tast:[22,34,133],tavern:206,tax:[75,93],taylor:79,tb_basic:[141,142,178,216],tb_equip:[141,142,178,216],tb_filenam:322,tb_item:[141,142,178,216],tb_iter:322,tb_magic:[141,142,178,216],tb_rang:[141,142,178,216],tbbasiccharact:217,tbbasicturnhandl:217,tbearmor:218,tbequipcharact:218,tbequipturnhandl:218,tbeweapon:218,tbitemscharact:219,tbitemscharactertest:219,tbitemsturnhandl:219,tbmagiccharact:220,tbmagicturnhandl:220,tbodi:134,tbrangecharact:221,tbrangeobject:221,tbrangeturnhandl:221,tchar:116,tcp:[55,103],tcpserver:[40,312],teach:124,team:[33,36,61,64,70,108,131],teardown:[127,196,228,342],teaser:90,tech:79,technic:[4,6,9,10,11,19,20,23,39,40,51,64,70,83,90,108,112,114,119,125,139,179],techniqu:[29,139,321],tediou:[1,106,111],teenag:[21,103],tehom:[9,119],tehomcd:9,tel:[0,12,58,63,91,121,159],teleport:[12,14,20,43,58,85,122,140,159,165,233,241,322],teleportroom:233,televis:31,tell:[0,3,5,8,10,12,13,19,21,22,23,26,29,31,33,41,42,43,46,49,51,58,59,60,61,69,73,74,75,76,77,80,83,86,87,90,91,93,95,96,100,102,103,109,110,116,117,121,127,128,130,131,132,134,135,139,146,156,164,165,176,177,185,206,233,247,267,285,296,308,326,362],telnet:[9,15,25,30,40,43,55,63,64,75,79,83,100,101,103,105,110,114,137,138,141,142,169,262,275,287,298,306,307,343],telnet_:90,telnet_hostnam:54,telnet_interfac:90,telnet_oob:[88,141,142,262,275],telnet_port:[9,36,54,90,299],telnet_ssl:[141,142,262,275],teloutlock:241,temp:177,tempat:188,templat:[2,3,4,5,27,31,43,47,64,81,87,104,107,109,123,125,131,134,135,136,137,138,141,142,145,165,167,188,230,267,296,306,307,316,320,327,336,355,362],template2menu:[51,328],template_nam:362,template_overrid:[4,135,136,137],template_regex:[316,336],template_rend:107,template_str:[51,87],templates_overrid:135,templatestr:327,templatetag:[141,142,346,356],templateview:362,tempmsg:[175,177],temporari:[6,11,110,122,127,131,153,177,198,217,218,219,220,221,261,328],temporarili:[20,26,31,43,51,60,90,97,102,127,164,169,175,195,203],tempt:[43,61,95,104,157],ten:[29,90,111],tend:[41,43,57,61,64,73,76,86,90,97,103,119,121,124,129,138,159,205,209],tent:[45,111,139],terabyt:25,term:[0,10,31,62,63,64,69,90,91,96,126,139,154,204],term_siz:[42,141],termin:[4,23,26,27,38,42,47,59,60,63,64,75,90,93,95,96,97,100,103,106,110,114,123,126,131,138,139,141,194,215,217,218,219,220,221,266,267,287,310,362],terminalrealm:287,terminals:287,terminalsessiontransport:287,terminalsessiontransport_getp:287,terrain:49,ters:102,test1:[11,74,330],test2:[11,33,74,114],test3:[11,330],test4:[11,330],test5:11,test6:11,test7:11,test8:11,test:[0,5,10,11,13,14,15,17,19,20,21,22,23,24,25,29,31,33,36,37,38,41,42,43,45,46,50,51,56,58,60,61,62,63,65,67,68,69,72,73,74,79,80,81,85,89,90,91,95,96,98,106,107,109,111,115,116,120,124,130,131,132,133,137,138,139,141,142,149,151,155,156,158,166,169,178,182,185,187,188,191,207,208,215,217,218,219,220,221,222,223,230,250,251,262,269,272,275,296,297,298,302,318,320,321,322,324,328,332,342,344,346,348,350,356,364],test_:127,test_about:170,test_accept:196,test_access:170,test_add:196,test_add_valid:196,test_all_com:170,test_alternative_cal:127,test_at_repeat:228,test_attribute_command:170,test_audit:211,test_ban:170,test_batch_command:170,test_c_creates_button:303,test_c_creates_obj:303,test_c_dig:303,test_c_examin:303,test_c_help:303,test_c_login:303,test_c_login_no_dig:303,test_c_logout:303,test_c_look:303,test_c_mov:303,test_c_move_:303,test_c_move_n:303,test_c_soci:303,test_cal:196,test_cas:127,test_cboot:170,test_cdesc:170,test_cdestroi:170,test_cemit:170,test_channel:170,test_channelcommand:170,test_char_cr:170,test_char_delet:170,test_clock:170,test_color_test:170,test_copi:170,test_creat:170,test_cwho:170,test_del:196,test_desc:170,test_desc_default_to_room:170,test_destroi:170,test_destroy_sequ:170,test_dig:170,test_do_nested_lookup:170,test_edit:196,test_edit_valid:196,test_emit:170,test_empty_desc:170,test_examin:170,test_exit:196,test_exit_command:170,test_find:170,test_forc:170,test_general_context:352,test_get:360,test_get_and_drop:170,test_get_authent:360,test_get_dis:360,test_giv:170,test_handl:196,test_help:170,test_hom:170,test_ic:170,test_ic__nonaccess:170,test_ic__other_object:170,test_idl:303,test_info_command:170,test_interrupt_command:170,test_invalid_access:360,test_inventori:170,test_list:196,test_list_cmdset:170,test_lock:[170,196],test_look:170,test_mask:211,test_memplot:303,test_menu:215,test_messag:304,test_multimatch:170,test_mux_command:170,test_mycmd_char:127,test_mycmd_room:127,test_nam:170,test_nested_attribute_command:170,test_nick:170,test_object:170,test_object_search:127,test_ooc:170,test_ooc_look:170,test_opt:170,test_pag:170,test_password:170,test_perm:170,test_pi:170,test_pos:170,test_quel:170,test_queri:[141,142,262,297],test_quit:170,test_resourc:[127,141,142,170,196,211,228,320,360],test_return_valu:127,test_sai:170,test_script:170,test_send_random_messag:228,test_server_load:170,test_sess:170,test_set_game_name_and_slogan:352,test_set_help:170,test_set_hom:170,test_set_obj_alia:170,test_set_webclient_set:352,test_simpl:127,test_simple_default:170,test_spawn:170,test_split_nested_attr:170,test_start:196,test_tag:170,test_teleport:170,test_toggle_com:170,test_tunnel:170,test_tunnel_exit_typeclass:170,test_typeclass:170,test_upp:127,test_valid_access:360,test_valid_access_multisession_0:360,test_valid_access_multisession_2:360,test_valid_char:360,test_wal:170,test_whisp:170,test_who:170,test_without_migr:127,testabl:127,testaccount:170,testadmin:170,testapp:133,testbatchprocess:170,testbodyfunct:228,testbuild:170,testcas:[127,303,335,342,352],testcmdcallback:196,testcomm:170,testcommand:51,testdefaultcallback:196,testdummyrunnerset:303,testdynamic:127,tester:[90,119,285],testeventhandl:196,testform:327,testgener:170,testgeneralcontext:352,testhelp:170,testid:33,testinterruptcommand:170,testmemplot:303,testmenu:[188,328],testmixedrefer:335,testmod:308,testmymodel:127,testnod:51,testobj:127,testobject:127,testobjectdelet:335,testok:91,testregularrefer:335,testresult:251,testset:127,testsharedmemoryrefer:335,teststr:127,testsystem:170,testsystemcommand:170,testunconnectedcommand:170,testvalu:11,text2html:[141,142,320],text:[0,1,2,5,7,9,10,13,14,15,17,18,21,22,24,26,30,33,34,35,37,40,43,45,46,48,50,52,53,55,56,57,58,59,60,63,68,72,73,76,77,78,79,80,81,83,85,86,87,88,90,91,95,96,97,98,100,108,109,110,111,112,118,121,123,124,126,127,131,133,137,138,139,144,146,151,154,156,158,165,166,167,175,176,177,179,180,187,188,189,190,193,195,199,202,205,206,210,215,221,232,233,234,239,242,247,249,250,252,256,264,265,272,278,279,285,286,287,295,296,306,307,308,311,312,316,317,319,321,322,324,326,327,328,329,330,336,338,341,343,344,345,357,364],text_:38,text_color:190,text_exit:[22,180],text_single_exit:22,textarea:[340,357],textbook:40,textbox:357,textfield:[86,133],textstr:74,texttag:[81,126,139,364],texttohtmlpars:343,textual:39,textwrap:330,textwrapp:330,than:[0,2,4,6,8,11,13,14,16,19,23,25,26,29,31,33,35,37,38,39,42,43,46,47,49,51,52,54,55,57,58,60,61,62,64,68,69,71,73,76,80,82,86,89,90,91,93,95,97,103,104,105,106,109,110,112,113,114,115,116,119,122,123,125,126,127,128,129,131,134,135,137,138,139,144,148,151,152,153,156,157,158,159,160,164,167,169,179,180,181,184,190,195,204,205,206,213,215,217,218,219,220,221,232,234,241,247,249,250,251,267,308,313,315,316,317,318,321,322,328,329,330,334,336,337,339,340,341,343,344,362],thank:[4,102,134,138,199,312],thankfulli:133,the_next_node_to_go_to:328,thead:134,thei:[0,1,2,4,5,6,8,9,10,11,12,13,14,15,16,17,19,20,21,22,23,25,27,29,30,31,33,34,37,38,39,40,41,42,43,44,46,48,51,55,56,57,58,61,63,64,66,68,69,73,75,77,78,80,81,83,85,86,88,89,90,91,92,93,95,96,97,102,103,105,106,107,108,109,110,111,112,113,114,116,118,119,121,122,123,124,125,126,127,131,132,134,136,137,138,139,140,144,145,152,153,156,158,159,164,165,167,168,169,174,179,180,182,185,187,189,194,205,206,217,218,219,220,221,232,233,234,235,241,242,246,247,250,251,252,253,256,258,259,261,267,287,296,299,305,306,307,308,310,315,316,321,322,323,325,328,330,336,344,345,357,362],theirs:[116,181,189],them:[0,2,4,5,6,9,10,11,12,13,14,15,16,21,22,23,25,26,27,28,29,30,31,33,34,35,37,38,39,40,41,43,46,48,50,51,54,55,57,58,59,60,61,62,64,66,68,69,71,73,74,75,76,77,80,82,83,85,86,87,88,89,90,91,95,96,97,98,102,103,104,105,106,109,110,111,112,113,114,115,116,118,119,121,122,123,124,125,126,127,128,131,133,134,135,136,137,138,139,140,144,150,151,152,154,156,158,159,164,166,167,168,170,175,181,182,183,187,188,189,190,192,194,203,204,206,215,217,218,219,220,221,224,231,233,234,238,242,247,252,258,261,267,285,287,298,302,305,306,308,315,316,318,319,321,322,324,328,336,340,343,362],themat:61,theme:[61,134],themself:219,themselv:[0,11,19,21,28,31,33,43,49,51,55,58,69,72,73,80,81,85,89,97,102,107,113,119,121,123,125,127,132,138,140,159,206,247,256,259,267,317,319,340],theoret:[31,108],theori:[31,42,57,79,123,139,152,364],thereaft:87,therefor:[0,49,62,68,91,102,122,127,158,180,192],therein:[15,33,156,167,187,203,233],thereof:[206,247],thi:[0,1,2,3,4,5,6,8,9,10,11,12,13,14,15,16,18,19,20,21,22,23,24,25,26,27,28,29,30,31,33,34,35,36,37,38,39,40,42,43,44,45,46,47,48,49,50,51,52,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,70,71,72,73,74,75,76,77,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,143,144,145,146,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,192,193,194,195,198,199,202,203,204,205,206,209,210,212,213,214,215,217,218,219,220,221,223,224,226,227,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,246,247,250,251,252,253,254,256,257,258,259,260,261,262,264,265,266,267,269,271,272,273,274,276,277,278,279,285,286,287,295,296,298,299,300,301,302,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,334,335,336,337,338,339,340,341,342,343,344,345,346,349,350,354,355,357,361,362,363],thie:51,thief:61,thieveri:[43,166],thin:[10,22,29,111,182,337],thing:[0,1,3,4,5,6,8,9,10,11,12,13,15,19,20,21,22,25,26,27,28,29,30,31,33,34,37,39,40,41,43,46,47,48,49,50,51,55,58,59,60,61,63,64,67,69,70,71,73,74,75,76,79,80,82,83,85,86,89,90,91,93,95,96,97,100,102,103,104,105,107,108,109,110,111,114,115,116,118,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,144,152,153,159,175,179,180,187,195,205,206,215,221,227,230,233,234,241,242,246,247,250,271,276,312,315,316,318,321,322,336,340,362],think:[1,20,29,31,34,37,46,48,51,55,59,61,62,67,70,73,79,81,91,95,96,97,109,111,112,114,115,135,138,139,308,362],third:[0,8,9,23,27,37,38,39,42,43,51,64,69,72,75,90,96,101,114,121,127,128,134,159,321],thirdnod:51,this_sign:309,thoma:[12,43,87,157],thorn:[11,89],thorough:26,those:[2,3,4,6,9,11,13,14,15,19,20,21,23,28,30,31,33,35,36,43,44,47,48,51,55,56,57,58,60,61,62,64,68,71,73,77,78,79,80,81,85,86,88,89,90,95,96,103,105,109,110,111,112,114,118,119,121,123,124,125,127,128,130,131,135,136,138,153,154,156,159,165,166,170,176,180,206,210,215,217,232,233,242,250,251,252,260,295,317,318,328,329,330,338,339,342,344,357,362],though:[2,10,11,12,13,14,15,22,23,26,27,30,31,37,39,41,51,57,59,60,62,63,64,69,72,75,79,81,89,90,91,96,97,100,102,103,104,110,116,119,121,122,123,126,127,128,129,130,131,138,144,154,180,181,190,217,218,220,221,226,233,234,247,252,321,328,344],thought:[23,39,61,79,80,84,138],thousand:[39,90,111,133],thread:[23,27,55,79,110,286,312,337,344],threadpool:312,threadsaf:315,threat:103,three:[0,4,12,13,16,22,25,31,33,38,46,51,69,80,83,85,87,89,90,114,133,134,135,151,215,220,242,258,321,328],threshold:[228,310,322],thrill:85,throttl:[141,142,262,272,285],through:[0,1,2,5,9,13,14,17,23,25,27,30,31,33,34,38,39,40,41,44,46,48,51,52,55,56,57,58,59,60,61,62,64,68,69,70,71,76,77,80,83,85,87,88,89,90,91,93,96,97,98,99,103,104,105,106,107,108,109,110,114,116,117,119,121,122,124,136,138,139,140,141,144,153,159,166,174,179,187,192,210,212,217,218,219,220,221,235,240,242,246,247,251,257,258,261,267,269,274,287,296,299,304,306,307,315,317,318,322,324,327,328,329,336,343,344,357,362],throughout:[11,20,49,51,55,104,219],throughput:[175,324],thrown:116,thrust:232,thu:[14,19,31,33,39,43,44,51,54,57,58,73,80,83,86,96,108,111,114,121,122,123,125,134,135,136,156,160,181,205,242,247,261,299,313,316,317,324],thub:43,thud:189,thumb:[114,131],thumbnail:4,thunder:23,thunderstorm:122,thusli:75,tick:[23,33,38,51,64,115,131,132,139,219,231,233,261,299],ticker1:[115,261],ticker2:[115,261],ticker:[53,55,74,102,132,139,146,231,233,257,261,272],ticker_class:261,ticker_handl:[115,132,141,261],ticker_pool_class:261,ticker_storag:261,tickerhandl:[27,45,102,116,132,139,141,142,213,219,233,253,364],tickerpool:261,tickerpool_layout:261,tidbit:55,tidi:100,tie:[83,116,138],tied:[64,119,153,166,182,224,227,239],tier:90,ties:[49,135,161],tight:182,tightli:103,tim:[182,188,190,215,217,218,219,220,221],time:[0,1,2,4,5,6,8,9,10,11,12,13,14,17,20,21,22,23,25,26,28,29,30,31,34,36,37,39,40,41,42,45,49,51,52,53,54,55,56,58,59,60,61,63,64,65,66,67,69,70,72,73,75,80,83,86,88,89,90,91,93,95,96,100,104,105,106,109,110,113,114,115,116,117,119,121,122,123,124,125,127,128,129,131,132,133,135,138,139,144,146,148,150,151,153,154,157,164,169,175,177,179,184,185,187,194,195,198,203,204,212,213,215,217,218,219,220,221,223,227,231,232,233,239,246,247,250,252,253,256,259,260,261,267,269,271,273,274,279,285,299,300,304,305,306,308,310,315,316,318,319,321,322,323,324,329,331,334,335,337,340,344,363],time_ev:198,time_factor:[27,62,184,331],time_format:[59,344],time_game_epoch:[27,62,331],time_to_tupl:184,time_unit:[62,184],time_until_next_repeat:[102,259],timedelai:[29,260,342,344],timedelta:[338,345],timeeventscript:195,timefactor:62,timeformat:[337,344],timeit:93,timeout:[63,67,116,120,310,334],timer:[20,27,33,47,56,64,83,102,115,116,187,219,223,226,232,253,259,260,261,298,306,341],timerobject:102,timescript:331,timeslot:187,timestamp:[25,27,310,331],timestep:299,timestr:337,timetrac:[141,142,262,297],timetupl:62,timezon:[23,337,338,345],tini:[23,39,81],tinker:97,tintin:24,tinyfugu:24,tinymud:[57,108],tinymush:[57,108,129],tinymux:[57,108],tip:[12,37,70,79,103,112],tire:[20,153],titeuf87:235,titl:[17,22,34,43,48,69,98,137,164,166,180,238,321,324,362],titlebar:137,titleblock:69,tlen:71,tls:8,tlsv10:67,tlsv1:8,tmp:[36,63],to_be_impl:362,to_byt:344,to_cur:219,to_displai:180,to_dupl:152,to_execut:344,to_exit:0,to_fil:209,to_init:221,to_non:247,to_obj:[144,154,247],to_object:176,to_pickl:325,to_str:344,to_syslog:209,tobox:276,toc:363,todai:[138,190],todo:58,toe:108,togeth:[0,3,8,9,14,22,29,31,33,38,43,48,49,57,58,61,64,68,71,73,83,89,90,92,116,119,122,123,124,125,126,127,131,138,150,159,161,175,187,202,203,205,206,232,233,246,252,276,295,308,315,321,322,336,341],toggl:81,togglecolor:81,toint:[109,250],token:[71,247,287,322,336],told:[44,59,90,91,95,113,114,123,128,340],tolkien:62,tom:[43,58,87,123,129,159,165,189,206,327],tommi:[19,80,87],ton:[57,82],tone:114,tonon:[43,159],too:[0,4,6,9,11,12,13,14,17,20,21,22,25,27,29,33,38,39,41,42,43,46,47,48,49,51,57,58,59,60,61,63,69,73,80,83,84,85,91,93,96,106,114,116,121,122,123,125,128,131,133,138,157,159,178,215,220,224,241,259,272,276,310,312,322,327,328,329,330,341,344],took:[127,344],tool:[4,6,7,8,23,29,53,57,62,63,64,86,90,96,100,108,109,111,112,114,119,136,139],toolbox:79,tooltip:137,top:[5,9,13,22,26,29,31,33,38,39,47,48,50,52,57,58,59,60,63,68,69,75,79,85,93,95,96,101,102,104,110,111,112,117,123,125,130,131,133,134,138,139,148,153,177,180,182,184,202,206,215,234,235,239,246,256,267,309,316,318,319,322,329,330,337],topcistr:238,topic:[4,10,20,31,33,40,42,43,55,68,69,86,93,105,119,126,166,217,218,219,220,221,238,341,357,362],topicstr:238,tos:241,tostr:276,total:[27,43,62,80,82,91,93,102,104,105,114,118,139,169,185,304,329,330,331],total_num:334,touch:[8,38,54,60,96,97,103,104,114],tour:91,toward:[22,33,40,42,91,102,111,190,221,231],tower:[111,187,233],tportlock:241,trace:[83,96,195,304,328],traceback:[6,13,27,57,60,95,97,102,110,114,123,127,133,135,195,202,250,276,318,322,337,344],tracemessag:304,track:[11,27,30,49,57,61,64,73,77,82,86,95,98,99,100,102,105,116,121,128,132,133,138,144,153,221,257,278,279,287,305,310,318,325,326,338],tracker:[43,61,70,131],trade:[46,179],tradehandl:179,trader:46,tradetimeout:179,tradit:[10,15,36,73,74,83,90,103,114,116,138,235,306,329],tradition:[57,83],traffic:[8,103],train:79,traindriv:121,traindrivingscript:121,training_dummi:73,trainobject:121,trainscript:121,trainstop:121,trainstoppedscript:121,trait:[27,38,73,252],transact:179,transfer:[85,133,153,278,330],transform:[36,175],transit:[89,124],translat:[14,40,45,79,87,88,113,114,126,205,206,252,269,321],transmiss:209,transmit:113,transpar:[67,105,126,137,138,246,261],transport:[276,287,296],transportfactori:287,transpos:126,trap:[14,82,122],traumat:51,travel:[49,82,83,88,96,213,235],travers:[11,44,49,80,85,89,121,212,213,231,232,235,241,247],traverse_:33,traversing_object:[212,213,235,247],travi:[45,139,364],treasur:[9,235],treat:[10,14,33,64,95,96,105,111,112,119,125,138,144,150,153,175,189,247,252,308,328,330,341],tree:[3,11,33,38,43,47,51,61,63,64,77,80,96,131,140,180,206,215,234,247,252,267,296,312,328,344],tree_select:[141,142,178],treestr:215,treshold:334,tri:[11,12,14,24,29,33,43,51,58,61,80,83,87,90,91,105,107,113,116,119,133,138,151,169,179,181,188,224,232,233,271,310,344,345],trial:106,tribal:111,trick:[8,22,51,79,138,318,357],tricki:[109,126,127,138],trickier:[9,69],trigger:[21,24,31,33,36,42,46,49,51,56,57,69,74,83,84,89,100,105,107,114,115,116,117,118,121,134,135,138,144,146,150,151,154,156,170,175,180,198,231,233,246,247,252,259,261,269,272,276,298,305,309,324,336],trim:321,trip:96,tripl:[27,38,96,114,336,344],trivial:[27,33,40,42,91,93,138],troll:12,troubl:[5,8,9,23,41,46,58,63,70,75,91,105,131,139,363],troubleshoot:9,troublesom:[12,13,14],trove:9,truestr:188,truli:[0,12,39,41,105,187],trust:[19,43,51,57,169,322],truth:42,truthfulli:33,truthi:260,try_num_prefix:151,ttarget:116,tty:[9,100],ttype:[55,141,142,262,275,287],tuck:[111,224],tun:[43,159],tune:[67,126],tunnel:[0,20,22,44,49,58,121,159],tup:[39,206],tupl:[11,39,41,42,43,51,59,60,80,86,87,88,90,109,116,119,134,141,144,151,157,159,167,168,176,179,180,184,185,189,192,206,219,220,230,235,241,242,247,250,251,252,261,264,276,277,287,299,306,316,319,321,323,324,326,328,329,331,336,337,339,344],tupled:337,turbo:75,turkish:144,turn:[0,10,12,27,31,33,38,41,43,50,51,57,58,64,66,77,79,80,81,83,88,90,96,102,105,107,110,111,114,117,118,121,122,126,127,131,133,135,138,139,144,154,164,169,170,175,198,206,215,217,218,219,220,221,231,233,247,252,267,272,287,298,308,314,315,318,322,324,328,329,330,336,344,364],turn_act:116,turn_end_check:[217,218,219,220,221],turnbattl:[141,142,178],turnchar:219,tut:[122,233],tutor:230,tutori:[3,4,10,16,17,20,22,25,26,28,29,31,32,33,35,37,39,41,42,45,48,49,51,55,57,58,60,61,63,64,70,71,77,79,81,82,91,95,102,111,112,114,115,126,133,135,139,180,213,218,232,233,363,364],tutorial_bridge_posist:233,tutorial_cmdset:233,tutorial_exampl:[13,14,20,102,141,142,178],tutorial_info:233,tutorial_world:[20,22,63,122,141,142,178],tutorialclimb:232,tutorialevmenu:230,tutorialobject:[231,232],tutorialread:232,tutorialroom:[231,233],tutorialroomcmdset:233,tutorialroomlook:233,tutorialworld:[232,233],tweak:[8,9,25,57,58,67,97,102,109,117,119,125,138,312,321],tweet:[124,139,364],tweet_output:120,tweet_stat:120,tweetstat:120,twenti:58,twice:[25,51,62,116,195,221,328],twist:[10,27,29,33,40,63,72,75,79,97,103,247,260,264,267,269,270,276,277,278,279,287,295,296,298,305,308,312,337],twistd:[63,106,110,305],twistedcli:40,twistedweb:103,twitch:[41,116],twitter:[7,55,120,139,364],twitter_api:71,two:[0,4,11,13,14,15,16,19,22,23,25,26,27,28,29,31,33,34,38,39,40,41,43,44,46,47,49,50,51,57,58,64,65,67,68,69,73,74,76,80,83,84,85,86,88,89,90,91,92,95,97,100,102,103,104,105,108,109,110,111,112,113,116,119,121,122,123,125,126,127,129,131,133,134,135,137,138,139,140,152,159,177,179,180,185,199,204,212,213,215,219,221,224,233,234,247,249,267,296,307,308,317,319,322,328,330,336,337,344,345,364],twowai:[43,159],txt:[9,38,40,50,75,78,90,96,146,205,326,328],tying:90,typclass:206,type:[0,8,12,14,16,17,19,20,21,22,24,25,26,27,28,29,31,33,34,35,37,38,41,42,43,44,46,47,49,50,51,55,56,57,58,59,61,62,64,73,75,77,79,80,81,82,83,86,87,88,90,91,95,96,97,102,103,105,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,125,126,128,133,137,138,139,144,146,154,159,166,169,170,171,175,176,177,180,182,186,188,192,195,198,199,206,213,217,218,219,220,221,227,232,233,234,239,241,242,246,247,251,252,260,261,265,267,269,270,278,279,285,287,295,296,298,306,308,312,315,316,317,318,319,321,322,324,325,328,329,330,336,339,340,341,344,345,351,357],type_count:182,typecalss:195,typeclass:[0,2,5,9,11,12,13,20,21,22,25,26,27,33,34,39,44,47,48,49,56,58,60,61,62,66,69,73,76,77,80,82,83,84,85,89,91,96,102,105,107,109,111,112,116,117,118,120,121,122,123,127,132,133,134,139,141,142,144,145,146,147,148,153,159,164,173,175,176,177,178,182,187,191,194,195,198,203,206,212,213,214,217,218,219,220,221,226,233,235,237,238,241,242,244,245,246,247,251,252,254,255,256,257,259,261,305,323,324,341,342,344,360,362,364],typeclass_path:[43,102,119,125,148,159,256,317,318],typeclass_search:317,typeclassbas:96,typeclassmanag:[147,176,245,255],typeclassmixin:362,typedobject:[41,125,148,154,174,177,206,235,246,247,256,317,318,319,339,344],typedobjectmanag:[176,238,317],typeerror:[42,185,296],typenam:[22,144,146,148,175,177,179,182,184,187,189,195,203,204,205,206,212,213,214,217,218,219,220,221,223,226,227,231,232,233,235,239,246,247,251,256,259,274,300,316,318,331,334,335],typeobject:319,types_count:182,typic:[27,55,91,127,220,221,362],typo:[37,38,70,103,363],ubbfwiuvdezxc0m:37,ubuntu:[8,63,67,97,103,131],ufw:103,ugli:[56,109,137,338],uid:[100,148,279,286,307,308],uit:[22,180],ulrik:58,ultima:79,umlaut:15,unabl:[71,190],unaccept:33,unaffect:[51,116,219,260],unarm:218,unarmor:218,unassign:138,unauthenticated_respons:360,unavoid:115,unban:[12,157],unbias:185,unbroken:327,uncal:260,uncas:321,uncategor:341,unchang:[87,97,127,205,252,344],unclear:[30,363],uncolor:[81,114],uncom:[67,90],uncommit:131,unconnect:[43,171,186],uncov:182,undefin:[36,86,112],under:[6,9,20,24,33,36,38,41,42,43,46,48,51,57,60,61,63,64,73,75,77,78,79,86,93,100,106,108,110,119,122,123,125,128,133,134,135,136,137,154,156,159,188,215,234,242,259,267,321,328,329,330,344,346,362],undergar:182,undergon:195,underli:[57,61,64,80,119,124,131],underlin:[330,343],underneath:[9,318],underscor:[0,38,51,74,88,95,97,114,119,152,344],underscror:152,understand:[4,10,15,24,25,26,29,30,31,33,37,38,39,41,42,44,48,49,55,60,61,63,79,81,83,91,95,96,103,104,105,109,111,113,114,123,124,127,131,133,134,136,139,151,152,204,205,206,312,321,364],understood:[83,91,111,127,295,296],undestand:25,undo:[50,103,326],undon:[43,156],undoubtedli:57,unexpect:[91,126,127,328],unexpectedli:334,unfamiliar:[63,74,80,88,90,118,124],unformat:[51,328,331],unfortun:[4,41,61],unhandl:60,unhappi:9,unhilit:343,unicod:[15,83,113,144,321,344],unicodeencodeerror:321,unicorn:119,unifi:[133,307],uniform:105,uninform:8,uninstal:63,uninstati:344,unintent:234,union:[31,51,152,224,328],uniqu:[2,12,13,20,31,33,35,36,38,40,43,46,51,55,57,60,61,64,71,80,83,84,90,95,96,102,105,109,112,119,123,125,127,137,138,144,150,152,154,159,164,169,171,175,176,181,184,186,194,204,205,206,212,215,218,219,231,233,238,247,251,252,261,264,276,277,285,298,299,307,308,317,318,319,324,326,338,341],unit:[27,31,34,36,37,45,47,55,62,64,79,82,107,124,130,139,176,184,198,219,269,324,331,344,350,364],unittest:[25,127,170,308,324,342],univers:[14,15,43,62,164],unix:[24,38,43,52,63,87,165,234,329,337,344],unixcommand:[141,142,178],unixcommandpars:234,unixtim:337,unjoin:179,unknown:[41,43,56,69,137,251,336,344],unleash:28,unless:[4,5,11,12,21,22,23,27,29,33,38,43,51,72,78,80,84,88,89,90,96,102,110,115,123,138,140,144,152,153,157,159,164,167,174,175,194,204,205,206,221,227,232,237,241,242,247,252,265,296,308,316,318,341,345],unlik:[37,51,64,73,90,107,127,180,219,318],unlimit:[235,259],unlink:159,unload:342,unload_modul:342,unlock:[58,77,80,316],unlocks_red_chest:80,unlog:[43,157,162,163,171,175,186,308],unloggedin:[105,141,142,149,155,308],unloggedincmdset:[35,43,105,163,186],unlucki:12,unmask:206,unmodifi:[151,168,187,328],unmonitor:272,unmut:[174,175],unnam:[112,152],unneccesari:113,unnecessari:[36,61],unneed:235,unpaced_data:276,unpack:[91,241],unpars:[74,87,151,295,296,336],unpaus:[100,102,259,260],unpickl:[83,276,316,325,340],unplay:[25,105],unpredict:344,unprivileg:252,unprogram:73,unpuppet:[43,96,107,123,156],unpuppet_al:144,unpuppet_object:[2,144],unquel:[20,43,80,122,156],unreal:79,unregist:135,unrel:[51,131,145],unrepeat:272,unreport:272,unsaf:[110,152,233],unsatisfactori:111,unsav:326,unsel:85,unset:[33,49,58,89,116,157,206,231,242,247,251,252,259,261,324,328,329,330,336,337],unsign:345,unsigned_integ:[338,345],unsignedinteg:338,unstabl:100,unstrip:151,unsubscrib:[43,58,115,164,261,278],unsuit:[19,251,319],unsur:[15,37,63,71,76,90,116,138,213],untag:137,untest:[24,61,63,127],until:[5,8,10,11,12,13,20,26,29,30,31,33,36,48,51,61,63,64,86,87,93,95,97,102,114,115,119,123,126,131,136,137,138,139,179,182,184,198,217,218,219,220,221,231,232,233,247,259,260,267,296,298,321,322,329,331,344],untouch:321,untrust:13,unus:[33,81,144,150,154,175,187,215,221,233,247,259,306,311,317,326],unusu:[103,119],unwant:139,unwield:218,unwieldli:153,upcom:54,updat:[2,4,5,8,9,11,13,14,20,23,24,28,29,30,33,36,38,39,43,45,49,51,55,57,58,61,62,63,64,68,71,73,75,76,79,81,83,84,86,88,89,90,91,95,97,98,100,102,115,116,123,127,133,134,135,136,137,138,139,145,146,153,154,159,164,167,169,170,174,175,183,187,195,206,220,233,239,242,246,247,249,250,252,257,285,286,305,306,308,310,315,318,325,326,327,328,329,330,334,344,357,360,362,364],update_buff:326,update_cached_inst:334,update_charsheet:58,update_current_descript:187,update_default:305,update_flag:306,update_po:49,update_session_count:306,update_undo:326,update_weath:233,updated_bi:192,updated_on:192,updatemethod:[137,138],updateview:362,upfir:106,upgrad:[63,64,75],upload:[4,63,64,90,100],upon:[14,29,61,80,86,90,96,100,103,113,117,123,188,210,217,218,219,220,221,258,269,278,310,329,362],upp:233,upper:[29,39,43,86,101,114,127,138,156,321],uppercas:[114,321],upping:114,ups:7,upsel:90,upsid:[41,235],upstart:[40,258],upstream:[26,64,104,128],upt:153,uptim:[12,27,43,62,169,331],urfgar:109,uri:[175,239,318],url:[8,38,43,64,70,90,98,131,134,135,136,138,141,142,146,164,175,239,286,296,312,318,343,346,353,356,362],url_nam:360,url_or_ref:38,url_to_online_repo:131,urlencod:69,urlpattern:[3,4,69,133,134,135],usabl:[4,43,66,114,123,159,180,190,219,241,310,328],usag:[0,5,12,21,22,23,28,29,30,33,38,41,42,43,51,58,60,64,68,71,73,81,82,85,90,91,93,109,115,116,119,121,123,124,129,154,156,157,158,159,164,165,166,169,170,171,174,179,180,181,182,184,185,186,187,188,189,199,202,203,205,206,210,212,213,214,217,218,219,220,221,224,230,231,232,233,234,235,241,250,260,267,326,328,330,334],use:[0,2,3,4,5,6,8,9,10,11,12,13,14,15,16,17,19,20,21,22,23,24,25,26,27,28,29,31,33,34,35,36,37,38,39,40,41,42,43,46,47,48,49,50,51,52,54,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,76,79,80,81,82,83,84,85,86,87,88,89,90,91,93,95,96,98,100,102,103,104,105,106,107,108,109,111,112,113,114,116,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,144,145,146,148,150,151,152,153,154,156,159,160,164,165,167,168,169,170,174,175,177,179,180,181,182,185,187,189,190,194,198,199,202,203,204,205,206,212,214,215,217,218,219,220,221,223,224,226,230,231,232,233,234,235,241,242,246,247,251,252,259,260,261,265,272,276,295,298,299,306,307,308,315,316,317,318,319,321,322,323,324,326,327,328,329,330,334,336,337,338,340,344,345,362],use_dbref:[206,247,341],use_destin:247,use_evt:329,use_i18n:76,use_item:219,use_nick:[144,206,247],use_required_attribut:[145,237,244,357],use_success_location_messag:203,use_success_messag:203,use_xterm256:321,useabl:235,used:[0,2,3,7,9,10,11,13,15,16,17,19,20,22,23,24,27,29,30,31,34,35,38,40,41,43,46,47,48,50,51,52,54,55,56,57,58,59,60,62,63,64,67,68,69,72,73,74,79,80,82,83,84,85,86,87,88,89,90,91,93,95,96,100,102,103,104,105,107,108,109,110,111,112,113,114,115,116,118,119,120,121,122,123,124,125,126,127,128,129,131,133,134,135,136,137,139,141,144,145,146,150,152,153,154,156,159,164,166,167,168,169,170,175,179,180,182,184,186,187,188,189,190,192,194,195,198,199,204,205,206,213,215,217,218,219,220,221,231,232,233,234,235,238,240,241,242,244,247,250,251,252,258,259,260,261,262,264,265,269,272,273,276,277,278,279,285,287,295,296,299,306,308,309,315,316,317,318,319,320,321,322,324,325,326,328,329,330,336,337,338,339,340,341,344,345,350,357,362,363],used_kei:80,useful:[0,1,4,5,10,11,12,13,14,15,16,17,18,19,20,22,23,25,26,27,28,29,30,31,34,36,37,38,39,41,42,43,46,47,48,50,51,53,57,58,59,60,63,64,66,69,70,80,81,87,89,90,91,93,95,96,102,104,107,109,110,111,112,114,115,116,119,120,123,124,125,127,131,132,133,138,139,150,152,153,154,156,158,159,166,167,168,170,178,179,180,194,195,199,205,206,210,233,234,235,241,247,251,252,259,267,287,316,318,322,328,331,340,344],useless:231,uselock:241,user:[2,4,7,8,10,11,12,13,14,20,22,23,25,28,29,30,31,35,36,37,38,40,41,42,43,49,50,51,52,55,60,63,64,65,66,67,68,70,71,72,74,75,76,77,79,80,81,85,87,88,90,91,93,95,97,98,100,101,104,105,107,109,113,114,119,121,122,123,125,126,127,133,134,135,136,137,138,139,144,145,146,148,151,154,157,159,164,169,174,175,176,177,180,182,187,189,193,195,206,209,210,215,219,221,227,233,235,239,241,242,247,252,259,262,265,271,279,286,287,295,296,306,308,311,316,318,321,326,328,329,330,336,338,344,345,349,357,362,364],user_change_password:145,user_input:51,user_permiss:[145,148],useradmin:145,userauth:287,userchangeform:145,usercreationform:[145,357],usernam:[2,4,12,35,51,74,100,107,119,131,134,144,145,148,186,287,311,349,357],username__contain:119,usernamefield:357,userpassword:[12,157],uses:[0,5,9,13,15,16,17,22,23,29,30,31,33,34,38,39,40,44,57,64,68,69,80,81,86,88,90,98,107,109,112,113,114,115,119,124,125,127,130,131,136,137,152,179,185,187,199,206,219,226,227,233,234,235,242,256,261,276,296,319,336,337,338,344],uses_databas:344,using:[2,4,5,6,8,9,10,11,12,13,14,15,19,20,21,22,23,24,25,26,27,28,29,30,31,33,34,36,37,38,39,41,43,45,46,47,49,50,51,53,55,56,57,58,59,60,61,62,63,64,67,68,70,71,72,73,74,77,78,79,80,81,83,85,86,87,88,89,90,91,93,95,96,97,100,101,102,103,105,107,108,109,110,111,112,114,115,116,117,118,120,121,122,123,124,125,126,128,129,131,132,133,134,137,138,139,140,144,148,150,153,154,156,158,159,164,167,168,169,174,179,180,181,184,185,187,188,190,194,203,205,206,212,213,214,215,217,218,219,220,221,224,230,231,233,234,235,242,247,250,251,252,256,259,260,261,278,279,285,286,296,299,309,310,312,316,318,319,321,322,326,328,329,331,336,337,338,339,340,341,342,344,346,357,362,363,364],usr:[63,64,75,100],usual:[0,2,4,5,6,8,9,11,19,20,21,22,23,25,26,27,29,30,31,33,34,37,38,40,41,43,46,47,50,51,52,57,59,60,62,63,64,67,72,74,80,81,87,89,90,91,93,95,96,97,100,102,105,106,109,110,112,114,115,119,124,125,126,127,131,133,136,144,146,151,152,153,154,156,159,165,169,170,174,175,177,184,194,195,198,204,205,206,233,234,242,246,247,252,259,267,269,274,299,306,315,316,318,323,324,328,329,337,339,341,344],utc:[23,345],utf8:[23,36],utf:[15,24,58,74,111,113,272,278,295,330,344],util:[8,10,11,13,14,16,34,41,45,47,48,49,50,51,52,57,58,59,62,63,81,82,85,86,89,96,97,102,103,111,114,117,124,127,133,134,137,139,141,142,145,158,170,175,177,178,184,187,188,191,195,196,211,213,220,228,230,237,239,244,247,249,251,259,260,274,298,315,316,317,318,346,357,360,364],utilis:328,uyi:205,v19:63,vagu:21,val1:250,val2:250,val:[11,88,144,156,250,344],valid:[1,11,13,26,30,31,33,42,43,44,51,58,60,67,69,88,89,90,91,95,96,97,102,103,109,110,114,119,123,133,134,141,142,144,151,153,159,167,168,169,176,179,180,188,192,195,196,204,206,215,220,226,227,232,233,234,235,242,247,249,250,251,252,257,258,259,260,261,262,265,267,295,306,317,319,322,324,328,329,338,339,340,341,343,344,345,357,362],valid_handl:338,validate_email_address:344,validate_onli:242,validate_password:[51,144],validate_prototyp:251,validate_sess:308,validate_usernam:144,validationerror:[144,251,311,338,340],validator_config:144,validator_kei:338,validatorfunc:[141,142,320],valign:330,valu:[0,2,4,6,10,11,12,17,20,22,25,27,28,31,33,39,41,42,43,49,50,58,59,60,61,62,64,67,69,73,74,77,80,81,82,84,85,86,87,88,90,97,102,111,114,115,116,123,125,126,127,128,133,134,137,138,139,144,148,150,152,154,156,157,159,170,175,177,180,182,185,188,189,190,192,195,196,203,204,205,206,211,217,218,219,220,221,227,228,233,235,239,241,242,246,247,250,251,252,256,258,259,260,261,265,272,273,274,276,285,306,307,308,313,316,317,318,319,321,323,324,325,326,327,328,334,335,336,338,339,340,341,344,345,350,357,362],valuabl:122,value1:109,value2:109,value_from_datadict:340,value_to_obj:251,value_to_obj_or_ani:251,value_to_str:340,valueerror:[41,91,109,123,180,202,204,316,321,324,336,345],valuei:111,values_list:119,valuex:111,vanilla:[9,26,49,56,58,86,101,125],vaniti:51,vari:[30,40,60,64,82,108,114,125,131,193,205,221,306,316,318],variabl:[0,3,5,11,13,28,31,33,38,41,43,46,49,51,55,56,58,64,66,69,80,83,88,91,95,96,97,100,103,104,106,109,113,121,124,133,134,135,137,138,144,148,150,154,156,159,164,167,168,169,170,183,187,188,192,194,195,198,203,233,241,246,247,251,252,264,267,277,287,299,306,313,321,322,328,344,350],variable_from_modul:344,variable_nam:[192,195],variablenam:344,varianc:205,variant:[11,55,112,153,180,186,213,278],variat:[62,73,116,152,187,205,227],varieti:[55,82,116,120,219,220],variou:[5,6,11,15,33,37,40,41,46,47,48,53,57,62,67,69,73,77,81,88,89,90,93,97,102,103,105,109,110,112,114,115,116,123,124,125,127,137,139,152,168,184,205,206,215,219,220,231,232,242,246,247,252,253,261,299,324,330,341,342],vast:[23,60,86,108,111,119],vastli:64,vcc:205,vccv:205,vccvccvc:205,vcpython27:9,vcv:205,vcvccv:205,vcvcvcc:205,vcvcvvccvcvv:205,vcvvccvvc:205,vector:344,vehicl:[21,124,139,364],velit:52,venu:[131,176],venv:[63,75],verb:[25,303],verbal:247,verbos:[26,38,116,127,206],verbose_nam:[133,318],veri:[0,2,4,5,6,8,9,10,11,13,14,17,20,21,22,23,26,27,28,29,31,33,35,37,38,39,40,41,42,46,49,50,51,52,55,56,57,58,60,61,64,67,68,70,72,73,74,77,78,79,80,85,86,88,90,91,93,95,96,97,104,107,108,109,110,111,112,114,115,116,119,121,122,123,125,127,128,129,131,132,134,137,138,139,140,144,146,152,154,170,175,177,180,182,194,195,204,205,206,212,213,214,215,220,227,231,234,235,238,246,251,271,317,319,324,326,328,329,344,362],verif:90,verifi:[36,51,63,90,131,159,188,220],verify_online_play:188,verifyfunc:188,versa:[40,43,61,88,105,116,164,276],version:[2,4,7,11,13,14,20,21,23,24,29,30,31,33,35,36,37,41,43,47,51,54,57,60,61,63,64,74,75,76,79,81,86,87,90,91,95,96,100,108,111,114,123,124,125,126,128,136,137,139,159,167,169,171,181,182,186,187,206,218,219,220,221,224,232,247,252,267,272,286,306,310,315,316,321,329,344,357,363,364],version_info:267,versionad:38,versionchang:38,versu:55,vertic:[138,232,330,344],very_strong:242,very_weak:80,vest:103,vet:109,veteran:79,vfill_char:330,via:[10,11,27,37,40,51,52,55,56,57,63,70,73,74,83,85,86,90,92,93,101,103,108,109,114,119,123,125,126,131,137,172,176,177,209,246,256,316,319,321,335],viabl:231,vice:[40,43,61,88,105,116,164,276],vicin:[33,43,165,187,233],video:[79,95,114,137],vienv:9,view:[1,4,17,27,34,38,41,42,43,50,51,52,55,58,60,63,64,72,80,82,86,90,96,101,102,110,111,115,116,123,124,131,136,139,141,142,144,156,157,159,164,165,166,169,174,175,182,206,217,218,219,220,221,235,237,239,247,249,302,318,329,346,350,353,356,357,364],view_attr:159,viewabl:[53,55,166],viewer:[25,38,69,206,235,241,247,318],viewport:42,vim:[14,50,79,326],vincent:[180,187,204,234],violent:51,virtual:[4,41,43,55,57,59,63,79,90,124,169,187,331],virtual_env:75,virtualenv:[9,23,26,36,38,63,75,76,90,93,95,96,97,100,106,110,128],virtualhost:8,viru:63,visibl:[13,25,31,36,38,43,48,54,61,63,67,69,81,90,96,105,114,123,125,131,139,165,206,241,247,279,312,328,344],visiblelock:241,vision:[11,58,61],visit:[22,49,90,111,133,134,234,328],visitor:[103,134,135],vista:63,visual:[25,57,63,93,114,137,144,166,190,363],vital:91,vlgeoff:184,vniftg:63,vnum:56,vocabulari:[46,344],voic:[33,46,124,139,364],volatil:251,volum:[21,61,100],volund:119,voluntari:37,volupt:52,vowel:[119,205],vpad_char:330,vulner:[29,103],vvc:205,vvcc:205,vvccv:205,vvccvvcc:205,w001:127,wai:[0,2,5,6,9,10,11,12,13,14,15,19,20,21,22,23,27,28,30,31,33,37,38,39,40,41,42,43,44,46,48,49,54,55,56,57,58,61,62,63,64,68,69,70,72,73,74,75,79,80,82,83,84,85,86,87,88,89,90,91,92,93,95,96,97,98,102,103,104,105,106,107,109,110,111,112,113,114,115,116,117,118,119,121,122,123,124,125,126,127,128,129,131,132,133,136,138,139,140,144,151,152,159,166,175,179,184,185,187,188,190,194,198,205,212,213,215,217,218,219,220,221,224,230,231,232,234,242,247,251,259,261,267,272,276,287,306,308,312,313,314,316,317,319,322,327,328,330,334,337,338,340,362,364],wail:49,waist:182,wait:[0,10,20,25,27,28,29,33,42,51,102,121,138,146,194,198,217,218,219,220,221,259,267,277,296,298,310,324,344],wait_for_disconnect:277,wait_for_server_connect:277,wait_for_statu:267,wait_for_status_repli:267,waiter:267,wake:188,walias:[43,159],walk:[0,14,21,31,39,46,49,60,62,85,139,213,214,215,235,322],walki:64,wall:[111,157,165,187,232,233],wanna:[37,179],want:[0,2,3,4,5,6,8,9,10,11,12,13,14,15,19,20,21,22,23,24,25,26,27,28,29,30,31,33,34,35,37,38,39,40,41,42,43,44,46,48,49,50,51,54,57,58,60,61,62,63,64,66,67,68,69,70,71,72,73,74,75,76,77,78,80,81,82,83,84,85,86,87,88,89,90,91,93,95,96,97,98,102,103,104,105,106,107,108,109,110,111,113,114,115,118,119,121,122,123,125,126,127,128,131,132,133,134,135,136,137,138,140,144,152,153,154,156,165,170,174,179,180,186,187,188,190,204,206,209,215,217,218,219,220,221,227,233,235,237,241,242,247,252,259,261,285,298,308,313,315,316,318,326,328,329,334,340,344,357,362,363],wanted_id:80,ware:85,warehous:[209,322],wari:[114,235,247,318],warm:[102,110,271],warn:[8,23,27,31,59,60,63,64,90,91,93,104,105,111,128,134,138,140,152,174,210,266,267,337],warnmsg:337,warrior:[28,57,58,61,122,123],wasclean:[278,295],wasn:[0,42,134],wast:[6,14,115],watch:[14,84,106,139],water:[153,203],waterballon:203,wave:111,wcach:[43,169],wcactu:220,wcommandnam:234,wcure:220,wdestin:[43,159],weak:252,weakref:334,weaksharedmemorymodel:[274,334],weaksharedmemorymodelbas:[274,334],weakvalu:334,wealth:85,weapon:[29,51,61,64,73,77,82,85,86,109,116,122,218,231,232,252],weapon_ineffective_msg:231,weapon_prototyp:232,weaponrack:232,weaponrack_cmdset:232,wear:[82,182,206,218],wearabl:182,wearer:182,wearstyl:182,weather:[30,61,73,102,111,112,115,122,124,139,140,233,364],weather_script:102,weatherroom:[132,233],web:[4,8,9,16,17,23,25,30,38,47,53,55,61,63,64,67,69,72,75,76,79,80,83,95,101,109,110,119,139,141,142,173,269,271,285,295,296,306,310,312,319,325,364],web_client_url:54,web_get_admin_url:[175,239,318],web_get_create_url:[175,239,318],web_get_delete_url:[175,239,318],web_get_detail_url:[175,239,318],web_get_puppet_url:318,web_get_update_url:[175,239,318],webclient:[24,30,40,43,45,53,54,64,67,69,83,88,95,103,105,110,114,135,139,141,142,169,230,262,272,275,296,307,328,346,350,351,360,364],webclient_ajax:[137,141,142,262,275],webclient_en:103,webclient_opt:272,webclientdata:296,webclienttest:360,webpag:[8,17,77,90,354],webport:36,webserv:[3,7,8,9,23,36,40,47,55,67,90,100,101,104,135,139,141,142,262,346],webserver_en:103,webserver_interfac:[67,90],webserver_port:90,webservic:103,websit:[3,9,17,53,55,57,64,67,69,79,90,98,101,103,124,133,136,137,138,139,141,142,145,296,312,346,351,364],websocket:[40,55,64,90,100,137,278,295,307],websocket_client_interfac:[67,90],websocket_client_port:[67,90],websocket_client_url:[8,67,90],websocket_clos:295,websocketcli:295,websocketclientfactori:278,websocketclientprotocol:278,websocketserverprotocol:295,weed:[26,119,152],week:[62,184,337,345],weeklylogfil:337,weigh:[82,298],weight:[23,38,61,108,124,139,190,205,317,364],weirdli:96,welcom:[3,4,22,35,37,63,72,76,85],well:[2,4,6,9,11,12,16,17,19,21,22,23,25,26,33,37,38,39,40,41,43,44,45,46,49,50,51,52,55,57,58,61,62,64,66,68,69,71,74,75,81,85,88,89,91,96,98,103,104,105,106,108,109,113,116,118,119,120,123,124,125,127,128,131,133,134,135,136,138,148,152,153,154,159,164,169,172,179,182,187,194,202,205,206,215,219,220,221,226,231,247,256,262,267,276,278,279,285,302,310,315,316,317,321,325,328,331,340],went:[57,110,127,131,257,261],were:[1,10,11,13,24,31,33,37,38,42,44,51,58,59,64,69,77,82,85,86,91,100,102,104,108,109,119,123,125,126,127,137,144,151,152,153,204,215,247,251,314,318,322,341,344],weren:62,werewolf:25,werewolv:119,werkzeug:344,west:[20,25,44,49,111,159,233],west_east:111,west_exit:233,western:111,westward:233,wether:[179,324],wevennia:22,wflame:220,wflushmem:[43,169],wfull:220,what:[0,1,2,4,8,9,10,12,13,14,19,20,21,22,23,25,26,27,29,31,33,38,39,40,42,43,44,45,46,48,49,51,56,57,58,60,61,62,63,64,67,68,69,70,72,73,74,77,78,79,80,81,83,85,86,88,89,90,93,95,96,97,98,102,103,104,105,108,109,110,111,113,114,115,116,117,118,119,121,122,123,124,125,126,127,128,129,131,132,133,134,136,138,139,140,144,150,152,153,154,156,159,166,170,175,195,203,204,206,209,214,219,220,224,227,231,233,239,242,247,251,252,267,269,272,279,296,311,313,316,318,319,321,322,328,338,339,344,345,349,357,362,364],whatev:[2,11,14,21,22,23,27,33,40,43,46,48,51,56,58,61,64,67,78,82,89,91,100,102,111,123,127,131,133,134,138,144,146,153,159,188,220,231,232,247,252,256,257,278,287,295,308,329,338,362],whatnot:138,wheel:[57,63,75,115,258],whelp:234,when:[0,2,3,4,5,6,8,9,10,11,12,13,14,15,17,19,20,21,22,23,24,26,27,29,30,31,33,34,35,36,37,38,39,40,41,42,43,44,46,47,49,50,51,52,56,57,58,59,60,61,62,63,64,65,66,67,68,69,73,74,75,76,77,78,79,80,82,83,84,85,86,87,88,89,90,91,93,95,96,97,98,100,102,103,104,105,106,107,108,109,110,111,112,113,114,116,117,118,119,120,121,122,123,124,125,126,127,128,129,131,132,133,136,137,138,139,141,144,146,148,150,152,153,154,156,158,159,164,165,167,168,169,171,175,176,177,179,180,181,182,184,185,186,187,188,189,190,195,196,198,199,202,203,204,205,206,212,214,215,217,218,219,220,221,223,224,226,227,228,230,231,232,233,234,235,238,239,241,242,246,247,249,251,252,256,257,259,260,261,264,267,269,273,274,276,277,278,279,285,287,295,296,298,299,305,306,307,308,309,310,316,318,319,321,322,324,325,326,327,328,329,330,334,335,336,337,339,344,357,362],when_stop:267,whenev:[6,10,11,22,25,33,46,64,66,74,76,80,84,87,90,95,98,100,102,106,107,109,111,113,117,119,128,144,153,174,175,231,232,233,247,257,259,269,286,306,307,308],where:[0,1,3,6,9,10,11,12,13,14,20,21,22,25,26,29,31,33,36,38,39,40,41,42,43,46,48,49,50,51,52,56,57,58,59,61,62,64,69,73,75,76,80,83,85,86,88,90,91,95,100,102,103,104,105,108,109,111,113,114,117,118,119,121,122,123,124,125,127,131,133,134,135,136,137,138,139,151,152,157,159,165,168,175,176,181,185,199,205,206,210,219,232,233,235,241,242,247,250,251,252,257,267,269,272,276,299,304,308,315,318,321,322,326,328,329,330,336,338,339,344,362],wherea:[11,12,13,19,21,26,31,33,34,40,42,55,56,61,80,81,85,86,93,97,103,105,109,113,114,116,125,128,205,224,227,261,296,316,334],whereabout:122,wherebi:220,wherev:[11,63,64,67,100,111,127,180,209,219],whether:[0,12,39,43,46,51,55,62,69,77,121,144,146,153,159,164,166,175,188,215,217,218,219,220,221,241,247,261,278,295,310,317,321,336,338,340,344],whewiu:9,which:[0,1,3,4,5,6,9,10,11,12,13,14,15,19,20,22,24,25,26,27,28,29,30,31,33,34,36,37,38,39,40,41,42,43,44,46,49,51,52,56,57,58,59,60,61,62,63,64,65,66,67,69,71,72,73,74,76,77,80,81,82,83,85,86,87,88,89,90,91,93,95,96,97,100,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,125,126,127,131,132,133,134,135,136,137,138,139,140,146,150,152,153,154,156,157,159,165,167,168,169,170,174,175,176,177,179,180,181,182,183,184,187,188,190,198,199,202,206,209,210,212,214,215,217,218,219,220,221,226,227,231,232,233,234,235,239,242,246,247,251,252,256,257,259,261,264,266,267,271,272,279,285,287,295,296,298,299,306,307,308,310,313,315,316,317,318,319,321,322,324,325,328,329,330,331,334,336,337,338,340,341,342,344,349,350,357,362],whichev:[27,90,103,233],whilst:[77,111,328],whim:139,whisp:205,whisper:[46,165,198,205,206,247],white:[48,74,114,126,344],whitelist:74,whitepag:[1,48,138],whitespac:[14,27,33,58,81,119,123,167,168,202,206,321,322,330,344],who:[4,10,11,12,21,34,41,46,49,51,55,56,58,61,73,80,87,95,103,109,114,116,119,121,123,124,125,127,132,133,138,146,154,156,159,164,174,175,179,188,195,206,217,218,219,220,221,232,239,241,242,247,252,318,326,328],whoever:133,whole:[4,16,43,49,51,55,57,60,61,67,87,96,111,112,122,123,129,138,152,159,169,221,330],wholist:175,whome:[43,159],whomev:[73,114,121],whose:[88,114,119,125,144,154,170,195,206,215,217,218,219,220,221,272,323,328,344],whould:328,why:[0,11,12,20,22,25,38,39,41,43,44,46,51,55,60,63,64,82,91,95,96,103,111,123,125,126,139,157,204,217,220,221,264,265],wide:[16,25,27,39,43,58,61,73,86,91,138,157,219,220,235,327,330,344],widen:12,wider:[12,25,39,43,157,330],widest:344,widget:[145,237,244,315,340,357],width:[16,17,25,27,33,49,74,109,111,114,141,154,250,272,287,306,321,326,327,329,330,336,344],wield:[61,82,109,218],wifi:[90,103],wiki:[1,9,33,37,45,48,55,58,70,79,108,111,124,125,138,180,295,363,364],wiki_account_handl:4,wiki_account_signup_allow:4,wiki_can:4,wiki_can_admin:4,wiki_can_assign:4,wiki_can_assign_own:4,wiki_can_change_permiss:4,wiki_can_delet:4,wiki_can_moder:4,wiki_can_read:4,wiki_can_writ:4,wikiconfig:4,wikimedia:37,wikipedia:[15,37,55,113,127,131,295],wild:[108,126,131],wildcard:[12,43,57,87,157,159,344],wildcard_to_regexp:344,wilder:[141,142,178],wildernessexit:235,wildernessmap:235,wildernessmapprovid:235,wildernessroom:235,wildernessscript:235,wildli:205,willing:[58,61,79],win10:63,win7:63,win8:63,win:[9,24,91,116,122],wind:[122,132],window:[4,23,25,31,38,44,45,49,52,64,72,76,83,88,89,93,95,96,97,101,105,106,110,128,131,137,138,154,166,267,306,310,329,344],windowid:306,windows10:63,wingd:111,winpti:9,winter:187,wintext:73,wip:38,wipe:[9,13,23,111,138,152,159,169,219,318],wire:[27,40,64,83,88,90,113,138,168,264,276,277,308,321],wis:58,wisdom:[60,93],wise:[6,11,13,14,15,26,58,60,80,96,118,131,135],wise_text:60,wiseobject:60,wiser:20,wiseword:60,wish:[33,36,39,75,120,131,136,180,221,321,343,357],with_metaclass:96,with_tag:203,withdraw:[116,221],withdrawl:221,within:[1,8,9,10,11,22,24,26,31,33,37,38,39,43,47,49,51,56,58,64,90,95,97,100,114,115,116,117,118,119,120,124,126,131,134,136,137,138,144,148,150,159,179,187,190,192,210,238,247,252,260,310,316,317,321,336,337,344,357,362],without:[0,8,11,12,13,14,16,20,21,22,23,25,27,29,30,31,33,35,37,38,40,42,43,44,46,49,50,51,55,57,58,59,60,61,63,64,66,67,76,80,86,88,90,91,92,93,96,97,100,101,104,107,108,109,114,115,118,119,121,123,125,126,127,128,129,131,133,136,138,139,144,146,151,154,156,157,159,164,165,167,168,169,170,177,179,181,182,187,192,195,205,206,212,215,217,220,221,231,233,242,247,250,251,252,259,260,276,287,298,306,308,309,316,318,321,322,324,325,326,328,329,336,340,341],withstand:80,wiz:58,wizard:[109,233,252,265,267],wkei:[43,159],wlocat:[43,159],wlock:[43,159],wmagic:220,wmass:220,wndb_:[43,159],won:[0,2,4,10,11,12,13,15,21,22,23,29,31,38,41,42,46,57,61,63,69,73,78,81,83,85,86,91,95,96,100,111,114,119,123,125,127,134,137,138,153,188,204,223,224,226,227,312,321,336,340],wonder:[9,16,56,82,119,138],wooden:109,woosh:21,word:[14,27,33,43,46,49,50,62,69,70,72,76,88,89,91,93,95,96,97,111,119,122,126,131,136,151,167,168,171,186,198,205,206,279,326,341,344],word_fil:205,word_length_vari:205,wordi:205,work:[0,2,4,5,8,9,10,11,13,14,15,16,20,21,22,23,24,25,26,27,28,29,31,34,36,37,38,41,42,43,44,48,49,51,56,57,58,59,60,61,62,63,64,66,67,70,71,72,75,80,81,83,84,85,86,89,90,93,95,96,97,102,103,105,106,108,109,111,112,114,115,116,117,119,122,123,124,126,127,128,129,132,133,134,136,138,139,150,153,154,156,159,164,165,167,169,174,175,179,180,181,187,202,203,206,212,215,219,220,221,233,234,235,239,241,242,247,251,252,267,271,272,299,312,314,318,322,327,328,329,330,338,344,362,363,364],workaround:[63,100,131],workflow:[61,145],world:[9,10,11,13,14,15,21,27,31,33,34,39,41,47,49,51,55,57,58,60,62,63,64,68,72,73,78,79,80,82,86,90,96,104,108,109,111,113,116,117,121,123,124,127,131,139,144,158,159,166,174,179,184,202,206,217,218,219,220,221,232,233,235,239,256,306,308,321,322,331,363,364],world_map:111,worm:49,worm_has_map:49,worn:[182,218],worri:[0,11,15,36,39,41,51,55,104,113,114,123,127,138,179,227],worst:61,worth:[0,8,21,29,51,61,70,79,91,93,124,125,133,179],worthi:61,worthless:90,would:[0,1,4,6,8,9,10,11,13,14,15,16,19,20,21,22,25,27,29,31,33,36,38,39,41,42,43,44,46,48,49,51,55,56,57,58,60,61,62,63,64,68,69,73,77,80,81,82,85,86,88,89,90,91,93,95,96,100,102,105,106,109,111,112,114,115,116,117,118,119,121,123,125,126,127,128,133,134,135,136,138,140,144,151,152,153,159,168,175,179,184,195,205,215,224,227,234,235,239,241,242,251,252,279,315,318,321,322,325,328,336,339,340,342,344],wouldn:[39,126,138],wound:220,wow:[69,138],wpermiss:[43,159],wprototype_desc:[43,159],wprototype_kei:[43,159],wprototype_lock:[43,159],wprototype_par:[43,159],wprototype_tag:[43,159],wrap:[10,30,49,51,59,96,102,109,119,136,182,188,206,274,314,330,344],wrap_conflictual_object:340,wrapper:[10,27,29,51,74,86,93,105,119,125,144,148,175,176,177,212,239,246,247,256,260,272,274,306,315,316,318,319,321,330,334,335,337,344,362],wresid:[43,169],write:[0,4,10,11,14,15,16,20,22,23,25,27,31,33,34,37,38,41,43,44,46,48,51,56,58,62,63,65,68,69,71,72,87,88,91,93,96,108,123,124,125,129,131,138,159,166,174,180,209,210,234,247,337,342,362,363,364],writeabl:75,written:[15,27,38,54,56,57,58,79,103,109,127,133,134,166,209,322,362],wrong:[26,41,42,43,60,63,81,85,95,110,127,152,159,169,206],wserver:[43,169],wservic:[43,164],wsgi:[8,312],wsgi_resourc:312,wsgiwebserv:312,wsl:[38,63],wss:[8,67,90],wtypeclass:[43,159],wwhere:247,www:[8,9,22,38,55,70,108,128,133,141,343,357],wyou:82,x1b:[321,343],x2x:58,x4x:327,x5x:327,x6x:327,x7x:327,x8x:327,x9x:327,x_r:39,xcode:63,xenial:130,xforward:312,xgettext:76,xit:[22,180],xmlcharrefreplac:321,xp_gain:73,xpo:330,xterm256:[43,55,74,81,83,137,156,183,190,272,287,321,364],xterm256_bg:321,xterm256_bg_sub:321,xterm256_fg:321,xterm256_fg_sub:321,xterm256_gbg:321,xterm256_gbg_sub:321,xterm256_gfg:321,xterm256_gfg_sub:321,xterm:[114,126],xterms256:114,xval:33,xxx:[25,42,204],xxxx:204,xxxxx1xxxxx:327,xxxxx3xxxxx:327,xxxxxxx2xxxxxxx:327,xxxxxxxxxx3xxxxxxxxxxx:58,xxxxxxxxxx4xxxxxxxxxxx:58,xxxxxxxxxxx:327,xxxxxxxxxxxxxx1xxxxxxxxxxxxxxx:58,xxxxxxxxxxxxxxxxxxxxxx:58,xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx:58,xyz:87,y_r:39,yan:114,yank:50,yeah:138,year:[25,55,61,62,88,90,108,184,331,337,344,357],yearli:[62,90],yellow:[114,126,131,232],yep:138,yes:[10,33,39,46,51,126,138,159,198,265,326,344],yesno:[51,326],yet:[0,2,4,12,14,22,25,28,35,36,41,42,46,49,51,54,60,63,64,67,76,79,86,90,96,105,109,111,119,121,128,130,131,133,134,138,144,171,179,186,195,242,246,260,285,308,312,321,362],yield:[10,23,33,80,108,159,210,330,344],yml:[100,130],yogurt:203,you:[0,1,2,3,4,5,6,8,9,10,11,12,13,14,15,16,17,19,20,21,22,23,24,25,27,28,29,30,31,33,34,35,36,37,38,39,40,41,42,43,44,46,47,48,49,50,51,54,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,95,96,97,98,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,144,153,154,156,159,164,165,166,167,168,169,170,171,174,179,180,181,182,183,184,187,188,190,193,194,195,198,199,202,203,204,205,206,209,210,212,213,214,215,217,218,219,220,221,223,224,226,227,232,233,234,235,237,241,242,247,252,258,259,260,261,269,278,279,296,298,308,310,312,313,316,318,321,322,324,327,328,330,331,340,341,344,357,362,363],young:77,your:[0,1,3,5,6,7,8,9,10,11,12,13,14,15,16,17,21,22,23,25,27,29,30,31,34,35,36,37,38,41,42,43,44,45,46,47,48,49,50,51,54,55,56,57,58,59,61,62,63,64,65,66,67,68,69,70,71,72,73,75,76,77,78,79,80,81,82,83,85,87,88,91,93,95,96,98,101,102,104,105,106,107,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,129,130,132,134,135,136,138,139,140,144,148,151,153,154,156,157,159,164,165,169,170,171,179,180,182,183,184,185,186,187,188,190,194,204,205,206,209,210,213,215,217,218,219,220,221,223,232,233,234,235,241,242,246,298,315,318,321,326,328,330,340,341,342,344,345,357,362,364],your_email:131,yourgam:209,yourhostnam:67,yournam:8,yourpassword:23,yourrepo:106,yourself:[0,2,5,6,14,16,19,22,23,26,31,37,42,43,51,55,58,63,69,70,73,78,80,86,89,90,91,96,102,108,111,119,123,125,130,131,135,159,165,179,189,206,212,220,223,328],yoursit:133,yourusernam:131,yourwebsit:133,yousuck:12,yousuckmor:12,youth:188,youtub:131,ypo:330,yrs:184,ythi:114,yum:[8,67,131],yvonn:58,z_r:39,zed:[77,79],zero:[20,27,109,206,247,321],zip:103,zlib:[75,276],zmud:24,zone:[18,46,55,56,70,79,112,119,122,124,139,319,337,364],zope:97,zopeinterfac:63,zy1rozgc6mq:45},titles:["A voice operated elevator using events","API refactoring","Accounts","Add a simple new web page","Add a wiki on your website","Adding Command Tutorial","Adding Object Typeclass Tutorial","Administrative Docs","Apache Config","Arxcode installing help","Async Process","Attributes","Banning","Batch Code Processor","Batch Command Processor","Batch Processors","Bootstrap & Evennia","Bootstrap Components and Utilities","Builder Docs","Building Permissions","Building Quickstart","Building a mech tutorial","Building menus","Choosing An SQL Server","Client Support Grid","Coding FAQ","Coding Introduction","Coding Utils","Command Cooldown","Command Duration","Command Prompt","Command Sets","Command System","Commands","Communications","Connection Screen","Continuous Integration","Contributing","Contributing to Evennia Docs","Coordinates","Custom Protocols","Customize channels","Debugging","Default Command Help","Default Exit Errors","Developer Central","Dialogues in events","Directory Overview","Docs refactoring","Dynamic In Game Map","EvEditor","EvMenu","EvMore","API Summary","Evennia Game Index","Evennia Introduction","Evennia for Diku Users","Evennia for MUSH Users","Evennia for roleplaying sessions","Execute Python Code","First Steps Coding","Game Planning","Gametime Tutorial","Getting Started","Glossary","Grapevine","Guest Logins","HAProxy Config (Optional)","Help System","Help System Tutorial","How To Get And Give Help","How to connect Evennia to Twitter","IRC","Implementing a game rule system","Inputfuncs","Installing on Android","Internationalization","Learn Python for Evennia The Hard Way","Licensing","Links","Locks","Manually Configuring Color","Mass and weight for objects","Messagepath","MonitorHandler","NPC shop Tutorial","New Models","Nicks","OOB","Objects","Online Setup","Parsing command arguments, theory and best practices","Portal And Server","Profiling","Python 3","Python basic introduction","Python basic tutorial part two","Quirks","RSS","Roadmap","Running Evennia in Docker","Screenshot","Scripts","Security","Server Conf","Sessions","Setting up PyCharm","Signals","Soft Code","Spawner and Prototypes","Start Stop Reload","Static In Game Map","Tags","Text Encodings","TextTags","TickerHandler","Turn based Combat System","Tutorial Aggressive NPCs","Tutorial NPCs listening","Tutorial Searching For Objects","Tutorial Tweeting Game Stats","Tutorial Vehicles","Tutorial World Introduction","Tutorial for basic MUSH like game","Tutorials","Typeclasses","Understanding Color Tags","Unit Testing","Updating Your Game","Using MUX as a Standard","Using Travis","Version Control","Weather Tutorial","Web Character Generation","Web Character View Tutorial","Web Features","Web Tutorial","Webclient","Webclient brainstorm","Wiki Index","Zones","evennia","evennia","evennia.accounts","evennia.accounts.accounts","evennia.accounts.admin","evennia.accounts.bots","evennia.accounts.manager","evennia.accounts.models","evennia.commands","evennia.commands.cmdhandler","evennia.commands.cmdparser","evennia.commands.cmdset","evennia.commands.cmdsethandler","evennia.commands.command","evennia.commands.default","evennia.commands.default.account","evennia.commands.default.admin","evennia.commands.default.batchprocess","evennia.commands.default.building","evennia.commands.default.cmdset_account","evennia.commands.default.cmdset_character","evennia.commands.default.cmdset_session","evennia.commands.default.cmdset_unloggedin","evennia.commands.default.comms","evennia.commands.default.general","evennia.commands.default.help","evennia.commands.default.muxcommand","evennia.commands.default.syscommands","evennia.commands.default.system","evennia.commands.default.tests","evennia.commands.default.unloggedin","evennia.comms","evennia.comms.admin","evennia.comms.channelhandler","evennia.comms.comms","evennia.comms.managers","evennia.comms.models","evennia.contrib","evennia.contrib.barter","evennia.contrib.building_menu","evennia.contrib.chargen","evennia.contrib.clothing","evennia.contrib.color_markups","evennia.contrib.custom_gametime","evennia.contrib.dice","evennia.contrib.email_login","evennia.contrib.extended_room","evennia.contrib.fieldfill","evennia.contrib.gendersub","evennia.contrib.health_bar","evennia.contrib.ingame_python","evennia.contrib.ingame_python.callbackhandler","evennia.contrib.ingame_python.commands","evennia.contrib.ingame_python.eventfuncs","evennia.contrib.ingame_python.scripts","evennia.contrib.ingame_python.tests","evennia.contrib.ingame_python.typeclasses","evennia.contrib.ingame_python.utils","evennia.contrib.mail","evennia.contrib.mapbuilder","evennia.contrib.menu_login","evennia.contrib.multidescer","evennia.contrib.puzzles","evennia.contrib.random_string_generator","evennia.contrib.rplanguage","evennia.contrib.rpsystem","evennia.contrib.security","evennia.contrib.security.auditing","evennia.contrib.security.auditing.outputs","evennia.contrib.security.auditing.server","evennia.contrib.security.auditing.tests","evennia.contrib.simpledoor","evennia.contrib.slow_exit","evennia.contrib.talking_npc","evennia.contrib.tree_select","evennia.contrib.turnbattle","evennia.contrib.turnbattle.tb_basic","evennia.contrib.turnbattle.tb_equip","evennia.contrib.turnbattle.tb_items","evennia.contrib.turnbattle.tb_magic","evennia.contrib.turnbattle.tb_range","evennia.contrib.tutorial_examples","evennia.contrib.tutorial_examples.bodyfunctions","evennia.contrib.tutorial_examples.cmdset_red_button","evennia.contrib.tutorial_examples.example_batch_code","evennia.contrib.tutorial_examples.red_button","evennia.contrib.tutorial_examples.red_button_scripts","evennia.contrib.tutorial_examples.tests","evennia.contrib.tutorial_world","evennia.contrib.tutorial_world.intro_menu","evennia.contrib.tutorial_world.mob","evennia.contrib.tutorial_world.objects","evennia.contrib.tutorial_world.rooms","evennia.contrib.unixcommand","evennia.contrib.wilderness","evennia.help","evennia.help.admin","evennia.help.manager","evennia.help.models","evennia.locks","evennia.locks.lockfuncs","evennia.locks.lockhandler","evennia.objects","evennia.objects.admin","evennia.objects.manager","evennia.objects.models","evennia.objects.objects","evennia.prototypes","evennia.prototypes.menus","evennia.prototypes.protfuncs","evennia.prototypes.prototypes","evennia.prototypes.spawner","evennia.scripts","evennia.scripts.admin","evennia.scripts.manager","evennia.scripts.models","evennia.scripts.monitorhandler","evennia.scripts.scripthandler","evennia.scripts.scripts","evennia.scripts.taskhandler","evennia.scripts.tickerhandler","evennia.server","evennia.server.admin","evennia.server.amp_client","evennia.server.connection_wizard","evennia.server.deprecations","evennia.server.evennia_launcher","evennia.server.game_index_client","evennia.server.game_index_client.client","evennia.server.game_index_client.service","evennia.server.initial_setup","evennia.server.inputfuncs","evennia.server.manager","evennia.server.models","evennia.server.portal","evennia.server.portal.amp","evennia.server.portal.amp_server","evennia.server.portal.grapevine","evennia.server.portal.irc","evennia.server.portal.mccp","evennia.server.portal.mssp","evennia.server.portal.mxp","evennia.server.portal.naws","evennia.server.portal.portal","evennia.server.portal.portalsessionhandler","evennia.server.portal.rss","evennia.server.portal.ssh","evennia.server.portal.ssl","evennia.server.portal.suppress_ga","evennia.server.portal.telnet","evennia.server.portal.telnet_oob","evennia.server.portal.telnet_ssl","evennia.server.portal.tests","evennia.server.portal.ttype","evennia.server.portal.webclient","evennia.server.portal.webclient_ajax","evennia.server.profiling","evennia.server.profiling.dummyrunner","evennia.server.profiling.dummyrunner_settings","evennia.server.profiling.memplot","evennia.server.profiling.settings_mixin","evennia.server.profiling.test_queries","evennia.server.profiling.tests","evennia.server.profiling.timetrace","evennia.server.server","evennia.server.serversession","evennia.server.session","evennia.server.sessionhandler","evennia.server.signals","evennia.server.throttle","evennia.server.validators","evennia.server.webserver","evennia.settings_default","evennia.typeclasses","evennia.typeclasses.admin","evennia.typeclasses.attributes","evennia.typeclasses.managers","evennia.typeclasses.models","evennia.typeclasses.tags","evennia.utils","evennia.utils.ansi","evennia.utils.batchprocessors","evennia.utils.containers","evennia.utils.create","evennia.utils.dbserialize","evennia.utils.eveditor","evennia.utils.evform","evennia.utils.evmenu","evennia.utils.evmore","evennia.utils.evtable","evennia.utils.gametime","evennia.utils.idmapper","evennia.utils.idmapper.manager","evennia.utils.idmapper.models","evennia.utils.idmapper.tests","evennia.utils.inlinefuncs","evennia.utils.logger","evennia.utils.optionclasses","evennia.utils.optionhandler","evennia.utils.picklefield","evennia.utils.search","evennia.utils.test_resources","evennia.utils.text2html","evennia.utils.utils","evennia.utils.validatorfuncs","evennia.web","evennia.web.urls","evennia.web.utils","evennia.web.utils.backends","evennia.web.utils.general_context","evennia.web.utils.middleware","evennia.web.utils.tests","evennia.web.webclient","evennia.web.webclient.urls","evennia.web.webclient.views","evennia.web.website","evennia.web.website.forms","evennia.web.website.templatetags","evennia.web.website.templatetags.addclass","evennia.web.website.tests","evennia.web.website.urls","evennia.web.website.views","Evennia Documentation","Toc"],titleterms:{"2017":138,"2019":[1,48,138],"3rd":138,"9th":138,"case":0,"class":[22,27,33,41,51,96,125,127],"default":[5,6,25,30,43,44,55,60,74,80,137,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171],"final":[49,75],"function":[22,42,51,53,80,89,95,102,114],"goto":51,"import":[26,38,41,95],"new":[3,4,6,58,60,69,86,97,102,114,125,127,133],"public":54,"return":[51,59,105],"static":111,"super":19,"switch":41,"try":41,Adding:[0,4,5,6,9,20,25,31,39,40,41,44,74,86,112,121,133],And:[70,92],For:119,NOT:77,PMs:58,TLS:8,The:[3,10,11,13,14,16,18,19,22,26,29,41,46,47,49,50,51,58,69,77,83,85,93,96,109,116,123,135],USE:77,Use:[26,103],Using:[49,52,84,86,90,93,109,112,127,129,130,140],Will:25,Yes:51,__unloggedin_look_command:43,abort:29,about:[29,43,115,125,128],abus:12,access:43,access_typ:80,account:[2,43,58,64,97,143,144,145,146,147,148,156],activ:[57,133],actual:[33,125],add:[3,4,23,25,60],add_choic:22,addclass:359,addcom:43,adding:127,addit:[9,39,41,44,100],address:25,admin:[43,64,97,135,145,157,173,237,244,254,263,315],administr:7,advanc:[18,29,53,87,110],affect:241,aggress:117,alia:[43,97],alias:112,all:[25,51,67,69],allcom:43,alpha:61,altern:[9,106],amp:276,amp_client:264,amp_serv:277,analyz:93,android:75,ani:[13,55],annot:119,anoth:[38,41,119],ansi:[27,114,126,321],apach:8,api:[1,38,45,53,137],app:[69,133],arbitrari:51,area:[111,123],arg:91,arg_regex:33,argument:[1,51,91],arm:21,arx:9,arxcod:9,ascii:27,ask:[33,51],assign:[19,33],assort:[10,14,31,33,40,51,112,118],async:10,asynchron:10,attach:[106,107],attack:[73,123],attribut:[11,64,97,316],attributehandl:11,audit:[208,209,210,211],aug:[1,48],auto:68,automat:25,avail:[35,59,107],backend:349,ban:[12,43],barter:179,base:[25,109,116],basic:[4,13,14,18,55,71,95,96,123,127,136],batch:[13,14,15,322],batchcod:[13,43],batchcommand:43,batchprocess:[43,158],batchprocessor:322,befor:26,best:91,beta:61,between:[13,51,125],block:[13,29,38],blockquot:38,bodyfunct:223,bold:38,boot:[12,43],bootstrap:[16,17],border:17,bot:146,brainstorm:[45,138],branch:[51,131],bridg:77,brief:[55,69],briefli:88,bug:[38,97],build:[18,19,20,21,22,38,43,49,58,61,85,111,124,159],builder:18,building_menu:[22,180],busi:85,button:[17,20],calendar:62,call:33,callabl:51,callback:[0,46,137],callbackhandl:192,caller:51,can:[11,22,55],capcha:133,card:17,care:103,caveat:[13,14,75,114,125],cboot:43,ccreat:43,cdesc:43,cdestroi:43,cemit:43,central:45,certif:67,chainsol:138,chang:[0,5,6,25,38,58,60,76,97,103,108,128,131,136],channel:[25,34,41,43,58,64],channelhandl:174,charact:[6,24,25,46,58,60,61,64,73,82,89,96,123,133,134],charcreat:43,chardelet:43,chargen:[123,181],chat:138,cheat:42,check:[11,80],checker:26,checkpoint:133,choic:22,choos:23,clean:9,clickabl:114,client:[24,83,88,90,135,137,269],client_opt:74,clock:43,clone:[9,131],cloth:182,cloud9:90,cmdabout:43,cmdaccess:43,cmdaddcom:43,cmdallcom:43,cmdban:43,cmdbatchcod:43,cmdbatchcommand:43,cmdboot:43,cmdcboot:43,cmdcdesc:43,cmdcdestroi:43,cmdcemit:43,cmdchannel:43,cmdchannelcr:43,cmdcharcreat:43,cmdchardelet:43,cmdclock:43,cmdcolortest:43,cmdcopi:43,cmdcpattr:43,cmdcreat:43,cmdcwho:43,cmddelcom:43,cmddesc:43,cmddestroi:43,cmddig:43,cmddrop:43,cmdemit:43,cmdexamin:43,cmdfind:43,cmdforc:43,cmdget:43,cmdgive:43,cmdhandler:150,cmdhelp:43,cmdhome:43,cmdic:43,cmdinventori:43,cmdirc2chan:43,cmdlink:43,cmdlistcmdset:43,cmdlock:43,cmdlook:43,cmdmvattr:43,cmdname:43,cmdnewpassword:43,cmdnick:43,cmdobject:43,cmdooc:43,cmdooclook:43,cmdopen:43,cmdoption:43,cmdpage:43,cmdparser:151,cmdpassword:43,cmdperm:43,cmdpose:43,cmdpy:43,cmdquell:43,cmdquit:43,cmdreload:43,cmdreset:43,cmdrss2chan:43,cmdsai:43,cmdscript:43,cmdserverload:43,cmdservic:43,cmdsession:43,cmdset:[5,43,152],cmdset_account:160,cmdset_charact:161,cmdset_red_button:224,cmdset_sess:162,cmdset_unloggedin:163,cmdsetattribut:43,cmdsetdesc:43,cmdsethandl:153,cmdsethelp:43,cmdsethom:43,cmdsetobjalia:43,cmdshutdown:43,cmdspawn:43,cmdstyle:43,cmdtag:43,cmdteleport:43,cmdtime:43,cmdtunnel:43,cmdtypeclass:43,cmdunban:43,cmdunconnectedconnect:43,cmdunconnectedcr:43,cmdunconnectedhelp:43,cmdunconnectedlook:43,cmdunconnectedquit:43,cmdunlink:43,cmdwall:43,cmdwhisper:43,cmdwho:43,cmdwipe:43,code:[8,13,22,25,26,27,38,41,42,50,59,60,61,73,85,87,108,124,128,131,322],collabor:57,color:[17,25,27,43,81,126],color_markup:183,colour:114,combat:[116,123],comfort:100,comm:[43,164,172,173,174,175,176,177],command:[5,14,22,25,28,29,30,31,32,33,35,41,42,43,44,45,53,58,60,62,68,71,73,81,85,88,91,97,100,116,121,123,127,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,193,322],comment:[44,49],commit:131,commun:[13,34],complet:80,complex:[22,119],compon:[17,45],comput:90,concept:[45,49,116],conclud:[39,123],conclus:[22,41,91,111],condit:[25,119],conf:104,config:[8,53,67,81],configur:[8,23,65,67,71,72,81,98,106,131,133],congratul:61,connect:[35,43,54,71,90,97],connection_wizard:265,contain:[100,323],content:[25,55],continu:36,contrib:[22,37,124,127,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235],contribut:[37,38,53],control:131,convert:91,cooldown:28,coordin:39,copi:[8,43],core:[45,53,56,64],cpattr:43,cprofil:93,creat:[0,2,3,5,6,12,20,21,27,33,36,43,51,53,69,86,89,97,100,111,121,123,125,133,324],createnpc:123,creatur:100,credit:79,crop:27,current:[42,62],custom:[4,5,7,10,22,40,41,51,57,62,80,81,105,113,124,127,135,137],custom_gametim:184,cwho:43,data:[6,11,40,51,105,106],databas:[9,53,68,86,97,109,128],dbref:25,dbserial:325,deal:102,debug:[13,42,103],debugg:106,decor:[10,51],dedent:27,dedic:133,defaultobject:97,defin:[31,33,34,51,80,86,102,131],definit:80,delai:[10,27,29],delcom:43,delimit:25,demo:61,depend:[9,128],deploi:100,deprec:[38,266],desc:[43,51],descer:57,descript:100,design:85,destroi:43,detail:[43,69,133],develop:[45,57,79,100,103,110,124,127],dialogu:46,dice:[58,185],dictionari:51,differ:[56,125],dig:43,diku:56,direct:106,directori:[47,90,104],disabl:103,discuss:79,displai:[24,27,49,62],django:[64,80,110,119,133,135],doc:[7,18,26,38,48],docker:100,document:[37,38,129,363],don:[13,55,100],donat:37,down:[20,110,121],drop:43,dummi:73,dummyrunn:[93,298],dummyrunner_set:299,durat:29,dure:110,dynam:[33,49,51,127],earli:7,echo:74,edit:[22,38,50,123],editnpc:123,editor:50,effect:241,elev:0,email_login:186,emit:43,emul:56,encod:[15,113],encrypt:90,end:41,engin:124,enjoi:8,enter:121,entir:0,entri:[20,68],error:[44,95,102,110],eveditor:[50,326],evennia:[4,5,7,8,9,16,23,25,26,38,41,42,45,47,54,55,56,57,58,67,71,75,76,77,79,90,91,95,96,100,106,109,110,124,126,127,128,131,137,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363],evennia_launch:267,evenniatest:127,event:[0,46,62],eventfunc:194,everi:30,everyth:22,evform:[58,327],evmenu:[25,51,328],evmor:[52,329],evtabl:[25,58,330],examin:[42,43],exampl:[39,42,46,50,51,73,80,83,90,102,108,116,127,137],example_batch_cod:225,execut:[42,59],exercis:77,exist:[6,125],exit:[0,6,25,33,44,89],expand:[116,121],explan:22,explor:[26,96],extended_room:187,extern:103,familiar:[56,57],faq:25,faster:127,featur:[38,55,69,135],feel:56,field:64,fieldfil:188,file:[13,14,15,38,43,104,127,131,322],fill:27,find:[39,43,59],firewal:103,first:[0,22,46,57,60,95,124],fix:131,flexibl:38,folder:[9,26,131],forc:43,foreground:110,forget:97,fork:[37,131],form:[17,133,357],format:51,forum:79,framework:79,from:[4,20,25,51,55,60,90,96,100,133,137,138,328],front:136,full:[22,41,69,83],func:41,further:[8,10,136],futur:[21,138],game:[7,26,27,39,45,47,49,54,55,57,58,59,61,62,73,90,100,111,120,123,124,127,128,131],game_index_cli:[268,269,270],gamedir:38,gameplai:122,gametim:[62,331],gap:77,gendersub:189,gener:[17,22,41,43,45,79,123,124,133,165,328],general_context:350,get:[20,43,51,63,67,70,119],get_client_opt:74,get_input:51,get_inputfunc:74,get_valu:74,git:[64,131],github:[38,64],give:[43,70],given:112,global:[53,91,102],glossari:64,gmcp:88,godhood:20,goldenlayout:137,googl:133,grant:58,grapevin:[65,278],griatch:[1,48,138],grid:[24,49],group:119,guest:66,gui:138,guid:9,handl:[12,69,103,110],handler:[53,107,116],haproxi:67,hard:77,have:123,head:38,health_bar:190,hello:95,help:[9,20,26,37,43,68,69,70,166,236,237,238,239],here:[26,55,60,96],hierarchi:58,hint:8,home:43,hook:125,host:90,hous:20,how:[2,33,58,70,71,89,100,113,121,125],html:[3,133],http:[8,67],idea:138,idmapp:[332,333,334,335],imag:[100,103],implement:73,improv:69,index:[54,69,133,139],info:[79,110],inform:[45,90],infrastructur:73,ingame_python:[191,192,193,194,195,196,197,198],ingo:83,inherit:140,inherits_from:27,initi:[6,23,25,116],initial_setup:271,inlin:114,inlinefunc:[114,336],input:[33,51,88],inputfunc:[74,83,88,272],insid:119,instal:[4,7,8,9,23,63,67,71,75,90,100,122,131,133],instanc:[33,86,125],instruct:88,integr:36,interact:[10,13,14,26],interfac:103,internation:76,interpret:106,intro_menu:230,introduct:[9,26,49,51,55,93,95,111,122,133],inventori:[43,82],irc2chan:43,irc:[72,279],issu:24,ital:38,jan:138,johnni:1,join:41,jumbotron:17,just:55,kei:[22,51,109],keyword:46,kill:110,know:[55,103],known:97,kovitiku:48,languag:[51,76],last:25,latest:[100,128],latin:25,launch:[50,51],layout:[16,41,47],learn:[26,55,77],leav:[41,121],legend:24,let:[13,42,69,90],librari:[47,96],licens:78,life:7,lift:12,like:[13,56,123],limit:[13,14,119],line:[21,42,50],link:[38,43,79,114],linux:[36,63,110],list:[38,42],list_nod:51,listen:118,literatur:79,live:110,local:[38,90,91],lock:[11,43,80,121,240,241,242],lockdown:90,lockfunc:241,lockhandl:242,log:[9,27,69,95,103],logfil:106,logger:337,login:[66,74],logo:136,longer:46,look:[5,43,56,95,123],lookup:53,mac:[63,110],machin:90,magic:97,mail:[131,199],main:[38,53],make:[20,21,27,57,58,60,67,121,123,127,131],manag:[4,137,147,176,238,245,255,273,317,333],manual:[54,81],map:[49,111],mapbuild:200,mapper:49,mariadb:23,mass:82,master:[58,131],match:97,mccp:280,mech:21,mechan:124,memplot:300,menu:[22,27,51,85,249,328],menu_login:201,merg:31,messag:[0,25,83,88],messagepath:83,method:[33,41,81,97],middlewar:351,migrat:[4,64,128],mind:131,mini:127,minimap:111,miscellan:124,mob:231,mod_proxi:8,mod_ssl:8,mod_wsgi:8,mode:[13,14,64,90,105,110],model:[53,86,127,133,148,177,239,246,256,274,318,334],modif:58,modifi:[8,30],modul:[71,73,95,109,116],monitor:74,monitorhandl:[84,257],more:[16,29,38,53,57,80,81,128,135],most:26,move:[25,121],msdp:88,msg:[34,81,83],mssp:281,mud:79,multi:57,multidesc:[57,202],multipl:[11,119],multisess:[64,105],mush:[57,123],mutabl:[11,97],mux:[129,241],muxcommand:167,mvattr:43,mxp:282,mysql:23,name:[12,43,88,97,241],naw:283,ndb:11,need:[0,55],nest:22,next:[57,63,71],nice:67,nick:[43,87],node:51,non:[11,25,28,54],nop:24,note:[8,10,14,15,31,33,38,40,51,87,112,118,122,127],npc:[85,117,118,123],number:91,object:[5,6,11,20,25,27,43,59,60,61,64,80,82,89,96,97,105,111,112,119,121,124,232,243,244,245,246,247],objmanipcommand:43,obtain:133,oct:138,octob:138,off:25,offici:79,olc:109,one:39,onli:[38,110],onlin:[38,90,131],oob:88,ooc:43,open:[43,85],oper:[0,10],option:[1,22,43,51,58,67,90,91,103,110],optionclass:338,optionhandl:339,other:[23,33,45,79,90,104],our:[0,22,69,95,96,108,121,133],out:[25,40,58],outgo:83,output:[59,127,209],outputcommand:88,outputfunc:88,outsid:[59,90],overal:73,overload:[81,125,135],overrid:97,overview:[36,47,86,116,136],own:[2,33,40,74,89,90,100,137],page:[3,4,43,69,135,136],parent:[57,86],pars:[25,41,91,95],part:96,parti:79,password:43,patch:37,path:[13,83],paus:[0,29,33],pax:9,pdb:42,perm:43,permiss:[19,58,80,112,122],perpetu:61,persist:[11,28,29,50],person:20,picklefield:340,pictur:133,pip:[4,64],plai:67,plan:[26,61,111],player:57,plugin:137,point:26,polici:129,port:[90,103],portal:[83,92,105,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296],portalsess:83,portalsessionhandl:[83,285],pose:43,posit:1,possibl:51,post:138,postgresql:23,practic:91,prepar:36,prerequisit:75,prevent:25,privileg:4,problem:108,process:[10,110],processor:[13,14,15,322],product:[21,100],profil:[93,297,298,299,300,301,302,303,304],program:[42,55],progress:77,project:[36,106],prompt:[30,51],properti:[2,11,31,33,34,51,64,89,102,105,112,125],protfunc:[109,250],protocol:[40,45,55,88],prototyp:[109,248,249,250,251,252],proxi:[8,90],publicli:131,pudb:42,puppet:64,push:[20,131],put:[67,69,131],puzzl:203,pycharm:106,python:[13,26,55,57,59,71,77,79,94,95,96],quell:[19,43,80,122],queri:[119,125],quick:[36,63],quickstart:20,quiet:91,quirk:97,quit:43,random_string_gener:204,read:[10,26,135,136],real:13,reboot:110,recapcha:133,receiv:[40,88],red_button:226,red_button_script:227,reduc:1,refactor:[1,48],refer:[25,38],regist:90,relat:[45,62],releas:[38,61],relev:90,reli:13,reload:[8,25,43,97,110],remark:123,rememb:38,remind:69,remot:[90,131],remov:[25,112],repeat:[51,74],repo:9,report:38,repositori:[26,37,38,64,131],request:38,requir:63,reset:[43,110,128],reshuffl:20,resourc:79,rest:38,restart:8,retriev:11,roadmap:99,role:58,roleplai:58,roller:58,rom:56,room:[0,6,25,39,49,58,61,82,89,233],rplanguag:205,rpsystem:206,rss2chan:43,rss:[98,286],rule:[31,73,116],run:[4,7,25,33,42,55,75,100,106,127],runner:127,safeti:13,sage:48,sai:43,same:[46,51],save:11,schema:128,score:123,screen:35,screenshot:101,script:[43,64,102,121,195,253,254,255,256,257,258,259,260,261],scripthandl:258,search:[27,31,39,53,86,91,112,119,341],secret:133,secur:[8,67,103,207,208,209,210,211],see:[69,97],select:25,self:91,send:[30,40,88],sent:30,separ:22,sept:[1,48],server:[7,8,23,43,76,90,92,104,105,123,210,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312],serverconf:104,serversess:[83,306],serversessionhandl:83,servic:[43,270],session:[25,43,58,64,83,105,307],sessionhandl:[105,308],set:[4,5,9,31,43,49,51,54,62,65,72,80,81,90,98,103,104,106,123,127,131],setdesc:43,sethelp:43,sethom:43,setpow:123,settings_default:313,settings_mixin:301,setup:[8,9,23,36,90],sever:[39,46,91],share:131,sharedmemorymodel:86,sheet:[42,58],shell:96,shop:85,shortcut:[11,53],show:[51,123],shut:110,shutdown:43,sidebar:38,signal:[107,309],simpl:[3,22,29,42,51,80,93,127],simpledoor:212,singl:11,singleton:53,site:[64,135],sitekei:133,slow_exit:213,soft:108,softcod:[57,108],solut:108,some:[39,41,56],somewher:55,sourc:[38,43,106],space:17,spawn:[43,57,109],spawner:[109,252],special:38,specif:5,spread:37,spuriou:24,sql:23,sqlite3:23,ssh:[88,103,287],ssl:[90,288],standard:[55,62,129],start:[9,58,63,85,100,110],stat:120,statu:110,step:[5,9,20,42,57,60,61,65,71,72,75,98,124,131,133],stop:110,storag:51,store:[6,11,25,51,109],string:[51,80,91,328],strip:91,structur:38,studi:0,stuff:[55,123],style:[17,43],sub:22,subclass:89,subject:96,suit:127,summari:[12,53,55],superus:80,support:[24,55,88],suppress_ga:289,surround:42,swap:125,synchron:10,syntax:[26,38,57,110,322],syscommand:168,system:[16,32,33,43,45,61,68,69,73,80,116,123,124,169],tabl:[25,27,38,86],tag:[39,43,112,126,319],talking_npc:214,taskhandl:260,tb_basic:217,tb_equip:218,tb_item:219,tb_magic:220,tb_rang:221,teamciti:36,tech:61,technic:[38,55],tel:43,telnet:[24,88,90,290],telnet_oob:291,telnet_ssl:292,templat:[36,51,69,133,328],templatetag:[358,359],tempmsg:34,temporari:51,termux:75,test:[55,59,93,123,127,170,196,211,228,293,303,335,352,360],test_queri:302,test_resourc:342,text2html:343,text:[27,38,51,74,113,114,136],texttag:114,theori:91,thi:[41,69],thing:[38,56,57,119],third:79,throttl:310,through:[37,42,100],ticker:[64,115],tickerhandl:[115,261],tie:58,time:[27,33,43,62,102,108],time_format:27,timer:93,timetrac:304,tip:131,titeuf87:138,to_byt:27,to_str:27,toc:364,togeth:[67,69],tool:[12,27,79],traceback:26,track:131,train:[73,121],translat:76,travi:130,treat:13,tree_select:215,trick:131,troubleshoot:[60,63,75],ttype:294,tunnel:43,turn:[25,97,116],turnbattl:[216,217,218,219,220,221],tutori:[0,5,6,18,21,46,62,69,85,96,116,117,118,119,120,121,122,123,124,127,132,134,136],tutorial_exampl:[222,223,224,225,226,227,228],tutorial_world:[229,230,231,232,233],tweak:[60,96],tweet:[71,120],twist:64,twitter:71,two:96,type:[2,5,6,11,60,89],typeclass:[6,43,45,53,57,64,81,97,119,124,125,140,197,314,315,316,317,318,319],unban:43,under:131,understand:126,ungm:58,uninstal:122,unit:127,unixcommand:234,unlink:43,unloggedin:[43,171],unmonitor:74,unrepeat:74,updat:[6,25,60,125,128,131],upgrad:128,upload:103,upstream:[97,131],url:[3,4,69,133,347,354,361],usag:[1,13,14,50],use:[55,97,115],used:[25,33],useful:[33,79],user:[19,33,56,57,69,103,124,131],userpassword:43,using:[0,42,119,127],util:[17,27,29,33,53,79,106,119,198,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,348,349,350,351,352],valid:[80,311],validatorfunc:345,valu:[51,109,119],variabl:[42,59],vehicl:121,verbatim:38,version:[38,131],versu:10,vhost:8,view:[3,68,69,133,134,135,355,362],virtualenv:64,voic:0,wai:[29,51,77],wall:43,want:[55,100],warn:38,weather:132,web:[3,45,88,90,97,103,124,133,134,135,136,137,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362],webclient:[137,138,295,353,354,355],webclient_ajax:296,webclient_gui:137,webserv:[103,312],websit:[4,135,356,357,358,359,360,361,362],websocket:[8,67],weight:82,what:[11,16,36,41,55,91,100],when:[25,115],where:[5,55,60,63,96],whisper:43,whitepag:45,who:[33,43],wiki:[4,139],wilder:235,willing:55,window:[9,63],wipe:43,wizard:54,word:37,work:[7,33,55,69,77,91,100,121,125,131],workaround:24,world:[18,20,61,95,122],write:[40,127,137],xterm256:[114,126],yield:[29,51],you:[26,55],your:[2,4,19,20,26,33,39,40,60,74,86,89,90,97,100,103,108,128,131,133,137],yourself:[20,60,61],zone:140}}) \ No newline at end of file +Search.setIndex({docnames:["A-voice-operated-elevator-using-events","API-refactoring","Accounts","Add-a-simple-new-web-page","Add-a-wiki-on-your-website","Adding-Command-Tutorial","Adding-Object-Typeclass-Tutorial","Administrative-Docs","Apache-Config","Arxcode-installing-help","Async-Process","Attributes","Banning","Batch-Code-Processor","Batch-Command-Processor","Batch-Processors","Bootstrap-&-Evennia","Bootstrap-Components-and-Utilities","Builder-Docs","Building-Permissions","Building-Quickstart","Building-a-mech-tutorial","Building-menus","Choosing-An-SQL-Server","Client-Support-Grid","Coding-FAQ","Coding-Introduction","Coding-Utils","Command-Cooldown","Command-Duration","Command-Prompt","Command-Sets","Command-System","Commands","Communications","Connection-Screen","Continuous-Integration","Contributing","Contributing-Docs","Coordinates","Custom-Protocols","Customize-channels","Debugging","Default-Command-Help","Default-Exit-Errors","Developer-Central","Dialogues-in-events","Directory-Overview","Docs-refactoring","Dynamic-In-Game-Map","EvEditor","EvMenu","EvMore","Evennia-API","Evennia-Game-Index","Evennia-Introduction","Evennia-for-Diku-Users","Evennia-for-MUSH-Users","Evennia-for-roleplaying-sessions","Execute-Python-Code","First-Steps-Coding","Game-Planning","Gametime-Tutorial","Getting-Started","Glossary","Grapevine","Guest-Logins","HAProxy-Config","Help-System","Help-System-Tutorial","How-To-Get-And-Give-Help","How-to-connect-Evennia-to-Twitter","IRC","Implementing-a-game-rule-system","Inputfuncs","Installing-on-Android","Internationalization","Learn-Python-for-Evennia-The-Hard-Way","Licensing","Links","Locks","Manually-Configuring-Color","Mass-and-weight-for-objects","Messagepath","MonitorHandler","NPC-shop-Tutorial","New-Models","Nicks","OOB","Objects","Online-Setup","Parsing-command-arguments,-theory-and-best-practices","Portal-And-Server","Profiling","Python-3","Python-basic-introduction","Python-basic-tutorial-part-two","Quirks","RSS","Roadmap","Running-Evennia-in-Docker","Screenshot","Scripts","Security","Server-Conf","Sessions","Setting-up-PyCharm","Signals","Soft-Code","Spawner-and-Prototypes","Start-Stop-Reload","Static-In-Game-Map","Tags","Text-Encodings","TextTags","TickerHandler","Turn-based-Combat-System","Tutorial-Aggressive-NPCs","Tutorial-NPCs-listening","Tutorial-Searching-For-Objects","Tutorial-Tweeting-Game-Stats","Tutorial-Vehicles","Tutorial-World-Introduction","Tutorial-for-basic-MUSH-like-game","Tutorials","Typeclasses","Understanding-Color-Tags","Unit-Testing","Updating-Your-Game","Using-MUX-as-a-Standard","Using-Travis","Version-Control","Weather-Tutorial","Web-Character-Generation","Web-Character-View-Tutorial","Web-Features","Web-Tutorial","Webclient","Webclient-brainstorm","Wiki-Index","Zones","api/evennia","api/evennia-api","api/evennia.accounts","api/evennia.accounts.accounts","api/evennia.accounts.admin","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.admin","api/evennia.comms.channelhandler","api/evennia.comms.comms","api/evennia.comms.managers","api/evennia.comms.models","api/evennia.contrib","api/evennia.contrib.barter","api/evennia.contrib.building_menu","api/evennia.contrib.chargen","api/evennia.contrib.clothing","api/evennia.contrib.color_markups","api/evennia.contrib.custom_gametime","api/evennia.contrib.dice","api/evennia.contrib.email_login","api/evennia.contrib.extended_room","api/evennia.contrib.fieldfill","api/evennia.contrib.gendersub","api/evennia.contrib.health_bar","api/evennia.contrib.ingame_python","api/evennia.contrib.ingame_python.callbackhandler","api/evennia.contrib.ingame_python.commands","api/evennia.contrib.ingame_python.eventfuncs","api/evennia.contrib.ingame_python.scripts","api/evennia.contrib.ingame_python.tests","api/evennia.contrib.ingame_python.typeclasses","api/evennia.contrib.ingame_python.utils","api/evennia.contrib.mail","api/evennia.contrib.mapbuilder","api/evennia.contrib.menu_login","api/evennia.contrib.multidescer","api/evennia.contrib.puzzles","api/evennia.contrib.random_string_generator","api/evennia.contrib.rplanguage","api/evennia.contrib.rpsystem","api/evennia.contrib.security","api/evennia.contrib.security.auditing","api/evennia.contrib.security.auditing.outputs","api/evennia.contrib.security.auditing.server","api/evennia.contrib.security.auditing.tests","api/evennia.contrib.simpledoor","api/evennia.contrib.slow_exit","api/evennia.contrib.talking_npc","api/evennia.contrib.tree_select","api/evennia.contrib.turnbattle","api/evennia.contrib.turnbattle.tb_basic","api/evennia.contrib.turnbattle.tb_equip","api/evennia.contrib.turnbattle.tb_items","api/evennia.contrib.turnbattle.tb_magic","api/evennia.contrib.turnbattle.tb_range","api/evennia.contrib.tutorial_examples","api/evennia.contrib.tutorial_examples.bodyfunctions","api/evennia.contrib.tutorial_examples.cmdset_red_button","api/evennia.contrib.tutorial_examples.example_batch_code","api/evennia.contrib.tutorial_examples.red_button","api/evennia.contrib.tutorial_examples.red_button_scripts","api/evennia.contrib.tutorial_examples.tests","api/evennia.contrib.tutorial_world","api/evennia.contrib.tutorial_world.intro_menu","api/evennia.contrib.tutorial_world.mob","api/evennia.contrib.tutorial_world.objects","api/evennia.contrib.tutorial_world.rooms","api/evennia.contrib.unixcommand","api/evennia.contrib.wilderness","api/evennia.help","api/evennia.help.admin","api/evennia.help.manager","api/evennia.help.models","api/evennia.locks","api/evennia.locks.lockfuncs","api/evennia.locks.lockhandler","api/evennia.objects","api/evennia.objects.admin","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.admin","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.admin","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.admin","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.gametime","api/evennia.utils.idmapper","api/evennia.utils.idmapper.manager","api/evennia.utils.idmapper.models","api/evennia.utils.idmapper.tests","api/evennia.utils.inlinefuncs","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.web","api/evennia.web.urls","api/evennia.web.utils","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.templatetags","api/evennia.web.website.templatetags.addclass","api/evennia.web.website.tests","api/evennia.web.website.urls","api/evennia.web.website.views","index","toc"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":3,"sphinx.domains.index":1,"sphinx.domains.javascript":2,"sphinx.domains.math":2,"sphinx.domains.python":2,"sphinx.domains.rst":2,"sphinx.domains.std":1,"sphinx.ext.todo":2,"sphinx.ext.viewcode":1,sphinx:56},filenames:["A-voice-operated-elevator-using-events.md","API-refactoring.md","Accounts.md","Add-a-simple-new-web-page.md","Add-a-wiki-on-your-website.md","Adding-Command-Tutorial.md","Adding-Object-Typeclass-Tutorial.md","Administrative-Docs.md","Apache-Config.md","Arxcode-installing-help.md","Async-Process.md","Attributes.md","Banning.md","Batch-Code-Processor.md","Batch-Command-Processor.md","Batch-Processors.md","Bootstrap-&-Evennia.md","Bootstrap-Components-and-Utilities.md","Builder-Docs.md","Building-Permissions.md","Building-Quickstart.md","Building-a-mech-tutorial.md","Building-menus.md","Choosing-An-SQL-Server.md","Client-Support-Grid.md","Coding-FAQ.md","Coding-Introduction.md","Coding-Utils.md","Command-Cooldown.md","Command-Duration.md","Command-Prompt.md","Command-Sets.md","Command-System.md","Commands.md","Communications.md","Connection-Screen.md","Continuous-Integration.md","Contributing.md","Contributing-Docs.md","Coordinates.md","Custom-Protocols.md","Customize-channels.md","Debugging.md","Default-Command-Help.md","Default-Exit-Errors.md","Developer-Central.md","Dialogues-in-events.md","Directory-Overview.md","Docs-refactoring.md","Dynamic-In-Game-Map.md","EvEditor.md","EvMenu.md","EvMore.md","Evennia-API.md","Evennia-Game-Index.md","Evennia-Introduction.md","Evennia-for-Diku-Users.md","Evennia-for-MUSH-Users.md","Evennia-for-roleplaying-sessions.md","Execute-Python-Code.md","First-Steps-Coding.md","Game-Planning.md","Gametime-Tutorial.md","Getting-Started.md","Glossary.md","Grapevine.md","Guest-Logins.md","HAProxy-Config.md","Help-System.md","Help-System-Tutorial.md","How-To-Get-And-Give-Help.md","How-to-connect-Evennia-to-Twitter.md","IRC.md","Implementing-a-game-rule-system.md","Inputfuncs.md","Installing-on-Android.md","Internationalization.md","Learn-Python-for-Evennia-The-Hard-Way.md","Licensing.md","Links.md","Locks.md","Manually-Configuring-Color.md","Mass-and-weight-for-objects.md","Messagepath.md","MonitorHandler.md","NPC-shop-Tutorial.md","New-Models.md","Nicks.md","OOB.md","Objects.md","Online-Setup.md","Parsing-command-arguments,-theory-and-best-practices.md","Portal-And-Server.md","Profiling.md","Python-3.md","Python-basic-introduction.md","Python-basic-tutorial-part-two.md","Quirks.md","RSS.md","Roadmap.md","Running-Evennia-in-Docker.md","Screenshot.md","Scripts.md","Security.md","Server-Conf.md","Sessions.md","Setting-up-PyCharm.md","Signals.md","Soft-Code.md","Spawner-and-Prototypes.md","Start-Stop-Reload.md","Static-In-Game-Map.md","Tags.md","Text-Encodings.md","TextTags.md","TickerHandler.md","Turn-based-Combat-System.md","Tutorial-Aggressive-NPCs.md","Tutorial-NPCs-listening.md","Tutorial-Searching-For-Objects.md","Tutorial-Tweeting-Game-Stats.md","Tutorial-Vehicles.md","Tutorial-World-Introduction.md","Tutorial-for-basic-MUSH-like-game.md","Tutorials.md","Typeclasses.md","Understanding-Color-Tags.md","Unit-Testing.md","Updating-Your-Game.md","Using-MUX-as-a-Standard.md","Using-Travis.md","Version-Control.md","Weather-Tutorial.md","Web-Character-Generation.md","Web-Character-View-Tutorial.md","Web-Features.md","Web-Tutorial.md","Webclient.md","Webclient-brainstorm.md","Wiki-Index.md","Zones.md","api/evennia.rst","api/evennia-api.rst","api/evennia.accounts.rst","api/evennia.accounts.accounts.rst","api/evennia.accounts.admin.rst","api/evennia.accounts.bots.rst","api/evennia.accounts.manager.rst","api/evennia.accounts.models.rst","api/evennia.commands.rst","api/evennia.commands.cmdhandler.rst","api/evennia.commands.cmdparser.rst","api/evennia.commands.cmdset.rst","api/evennia.commands.cmdsethandler.rst","api/evennia.commands.command.rst","api/evennia.commands.default.rst","api/evennia.commands.default.account.rst","api/evennia.commands.default.admin.rst","api/evennia.commands.default.batchprocess.rst","api/evennia.commands.default.building.rst","api/evennia.commands.default.cmdset_account.rst","api/evennia.commands.default.cmdset_character.rst","api/evennia.commands.default.cmdset_session.rst","api/evennia.commands.default.cmdset_unloggedin.rst","api/evennia.commands.default.comms.rst","api/evennia.commands.default.general.rst","api/evennia.commands.default.help.rst","api/evennia.commands.default.muxcommand.rst","api/evennia.commands.default.syscommands.rst","api/evennia.commands.default.system.rst","api/evennia.commands.default.tests.rst","api/evennia.commands.default.unloggedin.rst","api/evennia.comms.rst","api/evennia.comms.admin.rst","api/evennia.comms.channelhandler.rst","api/evennia.comms.comms.rst","api/evennia.comms.managers.rst","api/evennia.comms.models.rst","api/evennia.contrib.rst","api/evennia.contrib.barter.rst","api/evennia.contrib.building_menu.rst","api/evennia.contrib.chargen.rst","api/evennia.contrib.clothing.rst","api/evennia.contrib.color_markups.rst","api/evennia.contrib.custom_gametime.rst","api/evennia.contrib.dice.rst","api/evennia.contrib.email_login.rst","api/evennia.contrib.extended_room.rst","api/evennia.contrib.fieldfill.rst","api/evennia.contrib.gendersub.rst","api/evennia.contrib.health_bar.rst","api/evennia.contrib.ingame_python.rst","api/evennia.contrib.ingame_python.callbackhandler.rst","api/evennia.contrib.ingame_python.commands.rst","api/evennia.contrib.ingame_python.eventfuncs.rst","api/evennia.contrib.ingame_python.scripts.rst","api/evennia.contrib.ingame_python.tests.rst","api/evennia.contrib.ingame_python.typeclasses.rst","api/evennia.contrib.ingame_python.utils.rst","api/evennia.contrib.mail.rst","api/evennia.contrib.mapbuilder.rst","api/evennia.contrib.menu_login.rst","api/evennia.contrib.multidescer.rst","api/evennia.contrib.puzzles.rst","api/evennia.contrib.random_string_generator.rst","api/evennia.contrib.rplanguage.rst","api/evennia.contrib.rpsystem.rst","api/evennia.contrib.security.rst","api/evennia.contrib.security.auditing.rst","api/evennia.contrib.security.auditing.outputs.rst","api/evennia.contrib.security.auditing.server.rst","api/evennia.contrib.security.auditing.tests.rst","api/evennia.contrib.simpledoor.rst","api/evennia.contrib.slow_exit.rst","api/evennia.contrib.talking_npc.rst","api/evennia.contrib.tree_select.rst","api/evennia.contrib.turnbattle.rst","api/evennia.contrib.turnbattle.tb_basic.rst","api/evennia.contrib.turnbattle.tb_equip.rst","api/evennia.contrib.turnbattle.tb_items.rst","api/evennia.contrib.turnbattle.tb_magic.rst","api/evennia.contrib.turnbattle.tb_range.rst","api/evennia.contrib.tutorial_examples.rst","api/evennia.contrib.tutorial_examples.bodyfunctions.rst","api/evennia.contrib.tutorial_examples.cmdset_red_button.rst","api/evennia.contrib.tutorial_examples.example_batch_code.rst","api/evennia.contrib.tutorial_examples.red_button.rst","api/evennia.contrib.tutorial_examples.red_button_scripts.rst","api/evennia.contrib.tutorial_examples.tests.rst","api/evennia.contrib.tutorial_world.rst","api/evennia.contrib.tutorial_world.intro_menu.rst","api/evennia.contrib.tutorial_world.mob.rst","api/evennia.contrib.tutorial_world.objects.rst","api/evennia.contrib.tutorial_world.rooms.rst","api/evennia.contrib.unixcommand.rst","api/evennia.contrib.wilderness.rst","api/evennia.help.rst","api/evennia.help.admin.rst","api/evennia.help.manager.rst","api/evennia.help.models.rst","api/evennia.locks.rst","api/evennia.locks.lockfuncs.rst","api/evennia.locks.lockhandler.rst","api/evennia.objects.rst","api/evennia.objects.admin.rst","api/evennia.objects.manager.rst","api/evennia.objects.models.rst","api/evennia.objects.objects.rst","api/evennia.prototypes.rst","api/evennia.prototypes.menus.rst","api/evennia.prototypes.protfuncs.rst","api/evennia.prototypes.prototypes.rst","api/evennia.prototypes.spawner.rst","api/evennia.scripts.rst","api/evennia.scripts.admin.rst","api/evennia.scripts.manager.rst","api/evennia.scripts.models.rst","api/evennia.scripts.monitorhandler.rst","api/evennia.scripts.scripthandler.rst","api/evennia.scripts.scripts.rst","api/evennia.scripts.taskhandler.rst","api/evennia.scripts.tickerhandler.rst","api/evennia.server.rst","api/evennia.server.admin.rst","api/evennia.server.amp_client.rst","api/evennia.server.connection_wizard.rst","api/evennia.server.deprecations.rst","api/evennia.server.evennia_launcher.rst","api/evennia.server.game_index_client.rst","api/evennia.server.game_index_client.client.rst","api/evennia.server.game_index_client.service.rst","api/evennia.server.initial_setup.rst","api/evennia.server.inputfuncs.rst","api/evennia.server.manager.rst","api/evennia.server.models.rst","api/evennia.server.portal.rst","api/evennia.server.portal.amp.rst","api/evennia.server.portal.amp_server.rst","api/evennia.server.portal.grapevine.rst","api/evennia.server.portal.irc.rst","api/evennia.server.portal.mccp.rst","api/evennia.server.portal.mssp.rst","api/evennia.server.portal.mxp.rst","api/evennia.server.portal.naws.rst","api/evennia.server.portal.portal.rst","api/evennia.server.portal.portalsessionhandler.rst","api/evennia.server.portal.rss.rst","api/evennia.server.portal.ssh.rst","api/evennia.server.portal.ssl.rst","api/evennia.server.portal.suppress_ga.rst","api/evennia.server.portal.telnet.rst","api/evennia.server.portal.telnet_oob.rst","api/evennia.server.portal.telnet_ssl.rst","api/evennia.server.portal.tests.rst","api/evennia.server.portal.ttype.rst","api/evennia.server.portal.webclient.rst","api/evennia.server.portal.webclient_ajax.rst","api/evennia.server.profiling.rst","api/evennia.server.profiling.dummyrunner.rst","api/evennia.server.profiling.dummyrunner_settings.rst","api/evennia.server.profiling.memplot.rst","api/evennia.server.profiling.settings_mixin.rst","api/evennia.server.profiling.test_queries.rst","api/evennia.server.profiling.tests.rst","api/evennia.server.profiling.timetrace.rst","api/evennia.server.server.rst","api/evennia.server.serversession.rst","api/evennia.server.session.rst","api/evennia.server.sessionhandler.rst","api/evennia.server.signals.rst","api/evennia.server.throttle.rst","api/evennia.server.validators.rst","api/evennia.server.webserver.rst","api/evennia.settings_default.rst","api/evennia.typeclasses.rst","api/evennia.typeclasses.admin.rst","api/evennia.typeclasses.attributes.rst","api/evennia.typeclasses.managers.rst","api/evennia.typeclasses.models.rst","api/evennia.typeclasses.tags.rst","api/evennia.utils.rst","api/evennia.utils.ansi.rst","api/evennia.utils.batchprocessors.rst","api/evennia.utils.containers.rst","api/evennia.utils.create.rst","api/evennia.utils.dbserialize.rst","api/evennia.utils.eveditor.rst","api/evennia.utils.evform.rst","api/evennia.utils.evmenu.rst","api/evennia.utils.evmore.rst","api/evennia.utils.evtable.rst","api/evennia.utils.gametime.rst","api/evennia.utils.idmapper.rst","api/evennia.utils.idmapper.manager.rst","api/evennia.utils.idmapper.models.rst","api/evennia.utils.idmapper.tests.rst","api/evennia.utils.inlinefuncs.rst","api/evennia.utils.logger.rst","api/evennia.utils.optionclasses.rst","api/evennia.utils.optionhandler.rst","api/evennia.utils.picklefield.rst","api/evennia.utils.search.rst","api/evennia.utils.test_resources.rst","api/evennia.utils.text2html.rst","api/evennia.utils.utils.rst","api/evennia.utils.validatorfuncs.rst","api/evennia.web.rst","api/evennia.web.urls.rst","api/evennia.web.utils.rst","api/evennia.web.utils.backends.rst","api/evennia.web.utils.general_context.rst","api/evennia.web.utils.middleware.rst","api/evennia.web.utils.tests.rst","api/evennia.web.webclient.rst","api/evennia.web.webclient.urls.rst","api/evennia.web.webclient.views.rst","api/evennia.web.website.rst","api/evennia.web.website.forms.rst","api/evennia.web.website.templatetags.rst","api/evennia.web.website.templatetags.addclass.rst","api/evennia.web.website.tests.rst","api/evennia.web.website.urls.rst","api/evennia.web.website.views.rst","index.md","toc.md"],objects:{"":{evennia:[141,0,0,"-"]},"evennia.accounts":{accounts:[144,0,0,"-"],bots:[146,0,0,"-"],manager:[147,0,0,"-"],models:[148,0,0,"-"]},"evennia.accounts.accounts":{DefaultAccount:[144,1,1,""],DefaultGuest:[144,1,1,""]},"evennia.accounts.accounts.DefaultAccount":{"delete":[144,3,1,""],DoesNotExist:[144,2,1,""],MultipleObjectsReturned:[144,2,1,""],access:[144,3,1,""],at_access:[144,3,1,""],at_account_creation:[144,3,1,""],at_cmdset_get:[144,3,1,""],at_disconnect:[144,3,1,""],at_failed_login:[144,3,1,""],at_first_login:[144,3,1,""],at_first_save:[144,3,1,""],at_init:[144,3,1,""],at_look:[144,3,1,""],at_msg_receive:[144,3,1,""],at_msg_send:[144,3,1,""],at_password_change:[144,3,1,""],at_post_channel_msg:[144,3,1,""],at_post_disconnect:[144,3,1,""],at_post_login:[144,3,1,""],at_pre_channel_msg:[144,3,1,""],at_pre_login:[144,3,1,""],at_server_reload:[144,3,1,""],at_server_shutdown:[144,3,1,""],authenticate:[144,3,1,""],basetype_setup:[144,3,1,""],channel_msg:[144,3,1,""],character:[144,3,1,""],characters:[144,3,1,""],cmdset:[144,4,1,""],connection_time:[144,3,1,""],create:[144,3,1,""],create_character:[144,3,1,""],disconnect_session_from_account:[144,3,1,""],execute_cmd:[144,3,1,""],get_all_puppets:[144,3,1,""],get_display_name:[144,3,1,""],get_puppet:[144,3,1,""],get_username_validators:[144,3,1,""],idle_time:[144,3,1,""],is_banned:[144,3,1,""],msg:[144,3,1,""],nicks:[144,4,1,""],normalize_username:[144,3,1,""],objects:[144,4,1,""],options:[144,4,1,""],path:[144,4,1,""],puppet:[144,3,1,""],puppet_object:[144,3,1,""],scripts:[144,4,1,""],search:[144,3,1,""],sessions:[144,4,1,""],set_password:[144,3,1,""],typename:[144,4,1,""],unpuppet_all:[144,3,1,""],unpuppet_object:[144,3,1,""],validate_password:[144,3,1,""],validate_username:[144,3,1,""]},"evennia.accounts.accounts.DefaultGuest":{DoesNotExist:[144,2,1,""],MultipleObjectsReturned:[144,2,1,""],at_post_disconnect:[144,3,1,""],at_post_login:[144,3,1,""],at_server_shutdown:[144,3,1,""],authenticate:[144,3,1,""],create:[144,3,1,""],path:[144,4,1,""],typename:[144,4,1,""]},"evennia.accounts.bots":{Bot:[146,1,1,""],BotStarter:[146,1,1,""],GrapevineBot:[146,1,1,""],IRCBot:[146,1,1,""],RSSBot:[146,1,1,""]},"evennia.accounts.bots.Bot":{DoesNotExist:[146,2,1,""],MultipleObjectsReturned:[146,2,1,""],at_server_shutdown:[146,3,1,""],basetype_setup:[146,3,1,""],execute_cmd:[146,3,1,""],msg:[146,3,1,""],path:[146,4,1,""],start:[146,3,1,""],typename:[146,4,1,""]},"evennia.accounts.bots.BotStarter":{DoesNotExist:[146,2,1,""],MultipleObjectsReturned:[146,2,1,""],at_repeat:[146,3,1,""],at_script_creation:[146,3,1,""],at_server_reload:[146,3,1,""],at_server_shutdown:[146,3,1,""],at_start:[146,3,1,""],path:[146,4,1,""],typename:[146,4,1,""]},"evennia.accounts.bots.GrapevineBot":{DoesNotExist:[146,2,1,""],MultipleObjectsReturned:[146,2,1,""],at_msg_send:[146,3,1,""],execute_cmd:[146,3,1,""],factory_path:[146,4,1,""],msg:[146,3,1,""],path:[146,4,1,""],start:[146,3,1,""],typename:[146,4,1,""]},"evennia.accounts.bots.IRCBot":{DoesNotExist:[146,2,1,""],MultipleObjectsReturned:[146,2,1,""],at_msg_send:[146,3,1,""],execute_cmd:[146,3,1,""],factory_path:[146,4,1,""],get_nicklist:[146,3,1,""],msg:[146,3,1,""],path:[146,4,1,""],ping:[146,3,1,""],reconnect:[146,3,1,""],start:[146,3,1,""],typename:[146,4,1,""]},"evennia.accounts.bots.RSSBot":{DoesNotExist:[146,2,1,""],MultipleObjectsReturned:[146,2,1,""],execute_cmd:[146,3,1,""],path:[146,4,1,""],start:[146,3,1,""],typename:[146,4,1,""]},"evennia.accounts.manager":{AccountManager:[147,1,1,""]},"evennia.accounts.models":{AccountDB:[148,1,1,""]},"evennia.accounts.models.AccountDB":{DoesNotExist:[148,2,1,""],MultipleObjectsReturned:[148,2,1,""],account_subscription_set:[148,4,1,""],cmdset_storage:[148,3,1,""],db_attributes:[148,4,1,""],db_cmdset_storage:[148,4,1,""],db_is_bot:[148,4,1,""],db_is_connected:[148,4,1,""],db_tags:[148,4,1,""],get_next_by_date_joined:[148,3,1,""],get_next_by_db_date_created:[148,3,1,""],get_previous_by_date_joined:[148,3,1,""],get_previous_by_db_date_created:[148,3,1,""],groups:[148,4,1,""],hide_from_accounts_set:[148,4,1,""],id:[148,4,1,""],is_bot:[148,3,1,""],is_connected:[148,3,1,""],key:[148,3,1,""],logentry_set:[148,4,1,""],name:[148,3,1,""],objectdb_set:[148,4,1,""],objects:[148,4,1,""],path:[148,4,1,""],receiver_account_set:[148,4,1,""],scriptdb_set:[148,4,1,""],sender_account_set:[148,4,1,""],typename:[148,4,1,""],uid:[148,3,1,""],user_permissions:[148,4,1,""]},"evennia.commands":{"default":[155,0,0,"-"],cmdhandler:[150,0,0,"-"],cmdparser:[151,0,0,"-"],cmdset:[152,0,0,"-"],cmdsethandler:[153,0,0,"-"],command:[154,0,0,"-"]},"evennia.commands.cmdhandler":{InterruptCommand:[150,2,1,""],cmdhandler:[150,5,1,""]},"evennia.commands.cmdparser":{build_matches:[151,5,1,""],cmdparser:[151,5,1,""],create_match:[151,5,1,""],try_num_differentiators:[151,5,1,""]},"evennia.commands.cmdset":{CmdSet:[152,1,1,""]},"evennia.commands.cmdset.CmdSet":{__init__:[152,3,1,""],add:[152,3,1,""],at_cmdset_creation:[152,3,1,""],count:[152,3,1,""],duplicates:[152,4,1,""],errmessage:[152,4,1,""],get:[152,3,1,""],get_all_cmd_keys_and_aliases:[152,3,1,""],get_system_cmds:[152,3,1,""],key:[152,4,1,""],key_mergetypes:[152,4,1,""],make_unique:[152,3,1,""],mergetype:[152,4,1,""],no_channels:[152,4,1,""],no_exits:[152,4,1,""],no_objs:[152,4,1,""],path:[152,4,1,""],permanent:[152,4,1,""],priority:[152,4,1,""],remove:[152,3,1,""],to_duplicate:[152,4,1,""]},"evennia.commands.cmdsethandler":{CmdSetHandler:[153,1,1,""],import_cmdset:[153,5,1,""]},"evennia.commands.cmdsethandler.CmdSetHandler":{"delete":[153,3,1,""],__init__:[153,3,1,""],add:[153,3,1,""],add_default:[153,3,1,""],all:[153,3,1,""],clear:[153,3,1,""],delete_default:[153,3,1,""],get:[153,3,1,""],has:[153,3,1,""],has_cmdset:[153,3,1,""],remove:[153,3,1,""],remove_default:[153,3,1,""],reset:[153,3,1,""],update:[153,3,1,""]},"evennia.commands.command":{Command:[154,1,1,""],CommandMeta:[154,1,1,""],InterruptCommand:[154,2,1,""]},"evennia.commands.command.Command":{__init__:[154,3,1,""],access:[154,3,1,""],aliases:[154,4,1,""],arg_regex:[154,4,1,""],at_post_cmd:[154,3,1,""],at_pre_cmd:[154,3,1,""],auto_help:[154,4,1,""],client_width:[154,3,1,""],execute_cmd:[154,3,1,""],func:[154,3,1,""],get_command_info:[154,3,1,""],get_extra_info:[154,3,1,""],get_help:[154,3,1,""],help_category:[154,4,1,""],is_exit:[154,4,1,""],key:[154,4,1,""],lock_storage:[154,4,1,""],lockhandler:[154,4,1,""],locks:[154,4,1,""],match:[154,3,1,""],msg:[154,3,1,""],msg_all_sessions:[154,4,1,""],parse:[154,3,1,""],save_for_next:[154,4,1,""],search_index_entry:[154,4,1,""],set_aliases:[154,3,1,""],set_key:[154,3,1,""],styled_footer:[154,3,1,""],styled_header:[154,3,1,""],styled_separator:[154,3,1,""],styled_table:[154,3,1,""]},"evennia.commands.command.CommandMeta":{__init__:[154,3,1,""]},"evennia.commands.default":{account:[156,0,0,"-"],admin:[157,0,0,"-"],batchprocess:[158,0,0,"-"],building:[159,0,0,"-"],cmdset_account:[160,0,0,"-"],cmdset_character:[161,0,0,"-"],cmdset_session:[162,0,0,"-"],cmdset_unloggedin:[163,0,0,"-"],comms:[164,0,0,"-"],general:[165,0,0,"-"],help:[166,0,0,"-"],muxcommand:[167,0,0,"-"],syscommands:[168,0,0,"-"],system:[169,0,0,"-"],unloggedin:[171,0,0,"-"]},"evennia.commands.default.account":{CmdCharCreate:[156,1,1,""],CmdCharDelete:[156,1,1,""],CmdColorTest:[156,1,1,""],CmdIC:[156,1,1,""],CmdOOC:[156,1,1,""],CmdOOCLook:[156,1,1,""],CmdOption:[156,1,1,""],CmdPassword:[156,1,1,""],CmdQuell:[156,1,1,""],CmdQuit:[156,1,1,""],CmdSessions:[156,1,1,""],CmdStyle:[156,1,1,""],CmdWho:[156,1,1,""]},"evennia.commands.default.account.CmdCharCreate":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""],search_index_entry:[156,4,1,""]},"evennia.commands.default.account.CmdCharDelete":{aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""],search_index_entry:[156,4,1,""]},"evennia.commands.default.account.CmdColorTest":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""],search_index_entry:[156,4,1,""],slice_bright_bg:[156,4,1,""],slice_bright_fg:[156,4,1,""],slice_dark_bg:[156,4,1,""],slice_dark_fg:[156,4,1,""],table_format:[156,3,1,""]},"evennia.commands.default.account.CmdIC":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""],search_index_entry:[156,4,1,""]},"evennia.commands.default.account.CmdOOC":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""],search_index_entry:[156,4,1,""]},"evennia.commands.default.account.CmdOOCLook":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""],search_index_entry:[156,4,1,""]},"evennia.commands.default.account.CmdOption":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""],search_index_entry:[156,4,1,""],switch_options:[156,4,1,""]},"evennia.commands.default.account.CmdPassword":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""],search_index_entry:[156,4,1,""]},"evennia.commands.default.account.CmdQuell":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""],search_index_entry:[156,4,1,""]},"evennia.commands.default.account.CmdQuit":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""],search_index_entry:[156,4,1,""],switch_options:[156,4,1,""]},"evennia.commands.default.account.CmdSessions":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""],search_index_entry:[156,4,1,""]},"evennia.commands.default.account.CmdStyle":{aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],list_styles:[156,3,1,""],lock_storage:[156,4,1,""],search_index_entry:[156,4,1,""],set:[156,3,1,""],switch_options:[156,4,1,""]},"evennia.commands.default.account.CmdWho":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""],search_index_entry:[156,4,1,""]},"evennia.commands.default.admin":{CmdBan:[157,1,1,""],CmdBoot:[157,1,1,""],CmdEmit:[157,1,1,""],CmdForce:[157,1,1,""],CmdNewPassword:[157,1,1,""],CmdPerm:[157,1,1,""],CmdUnban:[157,1,1,""],CmdWall:[157,1,1,""]},"evennia.commands.default.admin.CmdBan":{aliases:[157,4,1,""],func:[157,3,1,""],help_category:[157,4,1,""],key:[157,4,1,""],lock_storage:[157,4,1,""],locks:[157,4,1,""],search_index_entry:[157,4,1,""]},"evennia.commands.default.admin.CmdBoot":{aliases:[157,4,1,""],func:[157,3,1,""],help_category:[157,4,1,""],key:[157,4,1,""],lock_storage:[157,4,1,""],locks:[157,4,1,""],search_index_entry:[157,4,1,""],switch_options:[157,4,1,""]},"evennia.commands.default.admin.CmdEmit":{aliases:[157,4,1,""],func:[157,3,1,""],help_category:[157,4,1,""],key:[157,4,1,""],lock_storage:[157,4,1,""],locks:[157,4,1,""],search_index_entry:[157,4,1,""],switch_options:[157,4,1,""]},"evennia.commands.default.admin.CmdForce":{aliases:[157,4,1,""],func:[157,3,1,""],help_category:[157,4,1,""],key:[157,4,1,""],lock_storage:[157,4,1,""],locks:[157,4,1,""],perm_used:[157,4,1,""],search_index_entry:[157,4,1,""]},"evennia.commands.default.admin.CmdNewPassword":{aliases:[157,4,1,""],func:[157,3,1,""],help_category:[157,4,1,""],key:[157,4,1,""],lock_storage:[157,4,1,""],locks:[157,4,1,""],search_index_entry:[157,4,1,""]},"evennia.commands.default.admin.CmdPerm":{aliases:[157,4,1,""],func:[157,3,1,""],help_category:[157,4,1,""],key:[157,4,1,""],lock_storage:[157,4,1,""],locks:[157,4,1,""],search_index_entry:[157,4,1,""],switch_options:[157,4,1,""]},"evennia.commands.default.admin.CmdUnban":{aliases:[157,4,1,""],func:[157,3,1,""],help_category:[157,4,1,""],key:[157,4,1,""],lock_storage:[157,4,1,""],locks:[157,4,1,""],search_index_entry:[157,4,1,""]},"evennia.commands.default.admin.CmdWall":{aliases:[157,4,1,""],func:[157,3,1,""],help_category:[157,4,1,""],key:[157,4,1,""],lock_storage:[157,4,1,""],locks:[157,4,1,""],search_index_entry:[157,4,1,""]},"evennia.commands.default.batchprocess":{CmdBatchCode:[158,1,1,""],CmdBatchCommands:[158,1,1,""]},"evennia.commands.default.batchprocess.CmdBatchCode":{aliases:[158,4,1,""],func:[158,3,1,""],help_category:[158,4,1,""],key:[158,4,1,""],lock_storage:[158,4,1,""],locks:[158,4,1,""],search_index_entry:[158,4,1,""],switch_options:[158,4,1,""]},"evennia.commands.default.batchprocess.CmdBatchCommands":{aliases:[158,4,1,""],func:[158,3,1,""],help_category:[158,4,1,""],key:[158,4,1,""],lock_storage:[158,4,1,""],locks:[158,4,1,""],search_index_entry:[158,4,1,""],switch_options:[158,4,1,""]},"evennia.commands.default.building":{CmdCopy:[159,1,1,""],CmdCpAttr:[159,1,1,""],CmdCreate:[159,1,1,""],CmdDesc:[159,1,1,""],CmdDestroy:[159,1,1,""],CmdDig:[159,1,1,""],CmdExamine:[159,1,1,""],CmdFind:[159,1,1,""],CmdLink:[159,1,1,""],CmdListCmdSets:[159,1,1,""],CmdLock:[159,1,1,""],CmdMvAttr:[159,1,1,""],CmdName:[159,1,1,""],CmdOpen:[159,1,1,""],CmdScript:[159,1,1,""],CmdSetAttribute:[159,1,1,""],CmdSetHome:[159,1,1,""],CmdSetObjAlias:[159,1,1,""],CmdSpawn:[159,1,1,""],CmdTag:[159,1,1,""],CmdTeleport:[159,1,1,""],CmdTunnel:[159,1,1,""],CmdTypeclass:[159,1,1,""],CmdUnLink:[159,1,1,""],CmdWipe:[159,1,1,""],ObjManipCommand:[159,1,1,""]},"evennia.commands.default.building.CmdCopy":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""]},"evennia.commands.default.building.CmdCpAttr":{aliases:[159,4,1,""],check_from_attr:[159,3,1,""],check_has_attr:[159,3,1,""],check_to_attr:[159,3,1,""],func:[159,3,1,""],get_attr:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdCreate":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],new_obj_lockstring:[159,4,1,""],search_index_entry:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdDesc":{aliases:[159,4,1,""],edit_handler:[159,3,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdDestroy":{aliases:[159,4,1,""],confirm:[159,4,1,""],default_confirm:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdDig":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],new_room_lockstring:[159,4,1,""],search_index_entry:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdExamine":{account_mode:[159,4,1,""],aliases:[159,4,1,""],arg_regex:[159,4,1,""],detail_color:[159,4,1,""],format_attributes:[159,3,1,""],format_output:[159,3,1,""],func:[159,3,1,""],header_color:[159,4,1,""],help_category:[159,4,1,""],key:[159,4,1,""],list_attribute:[159,3,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],quell_color:[159,4,1,""],search_index_entry:[159,4,1,""],separator:[159,4,1,""]},"evennia.commands.default.building.CmdFind":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdLink":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""]},"evennia.commands.default.building.CmdListCmdSets":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""]},"evennia.commands.default.building.CmdLock":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""]},"evennia.commands.default.building.CmdMvAttr":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdName":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""]},"evennia.commands.default.building.CmdOpen":{aliases:[159,4,1,""],create_exit:[159,3,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],new_obj_lockstring:[159,4,1,""],search_index_entry:[159,4,1,""]},"evennia.commands.default.building.CmdScript":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdSetAttribute":{aliases:[159,4,1,""],check_attr:[159,3,1,""],check_obj:[159,3,1,""],do_nested_lookup:[159,3,1,""],edit_handler:[159,3,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],nested_re:[159,4,1,""],not_found:[159,4,1,""],rm_attr:[159,3,1,""],search_for_obj:[159,3,1,""],search_index_entry:[159,4,1,""],set_attr:[159,3,1,""],split_nested_attr:[159,3,1,""],view_attr:[159,3,1,""]},"evennia.commands.default.building.CmdSetHome":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""]},"evennia.commands.default.building.CmdSetObjAlias":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdSpawn":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdTag":{aliases:[159,4,1,""],arg_regex:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],options:[159,4,1,""],search_index_entry:[159,4,1,""]},"evennia.commands.default.building.CmdTeleport":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],rhs_split:[159,4,1,""],search_index_entry:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdTunnel":{aliases:[159,4,1,""],directions:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdTypeclass":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdUnLink":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],help_key:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""]},"evennia.commands.default.building.CmdWipe":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""]},"evennia.commands.default.building.ObjManipCommand":{aliases:[159,4,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],parse:[159,3,1,""],search_index_entry:[159,4,1,""]},"evennia.commands.default.cmdset_account":{AccountCmdSet:[160,1,1,""]},"evennia.commands.default.cmdset_account.AccountCmdSet":{at_cmdset_creation:[160,3,1,""],key:[160,4,1,""],path:[160,4,1,""],priority:[160,4,1,""]},"evennia.commands.default.cmdset_character":{CharacterCmdSet:[161,1,1,""]},"evennia.commands.default.cmdset_character.CharacterCmdSet":{at_cmdset_creation:[161,3,1,""],key:[161,4,1,""],path:[161,4,1,""],priority:[161,4,1,""]},"evennia.commands.default.cmdset_session":{SessionCmdSet:[162,1,1,""]},"evennia.commands.default.cmdset_session.SessionCmdSet":{at_cmdset_creation:[162,3,1,""],key:[162,4,1,""],path:[162,4,1,""],priority:[162,4,1,""]},"evennia.commands.default.cmdset_unloggedin":{UnloggedinCmdSet:[163,1,1,""]},"evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet":{at_cmdset_creation:[163,3,1,""],key:[163,4,1,""],path:[163,4,1,""],priority:[163,4,1,""]},"evennia.commands.default.comms":{CmdAddCom:[164,1,1,""],CmdAllCom:[164,1,1,""],CmdCBoot:[164,1,1,""],CmdCWho:[164,1,1,""],CmdCdesc:[164,1,1,""],CmdCdestroy:[164,1,1,""],CmdChannel:[164,1,1,""],CmdChannelCreate:[164,1,1,""],CmdClock:[164,1,1,""],CmdDelCom:[164,1,1,""],CmdGrapevine2Chan:[164,1,1,""],CmdIRC2Chan:[164,1,1,""],CmdIRCStatus:[164,1,1,""],CmdPage:[164,1,1,""],CmdRSS2Chan:[164,1,1,""]},"evennia.commands.default.comms.CmdAddCom":{account_caller:[164,4,1,""],aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""],search_index_entry:[164,4,1,""]},"evennia.commands.default.comms.CmdAllCom":{account_caller:[164,4,1,""],aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""],search_index_entry:[164,4,1,""]},"evennia.commands.default.comms.CmdCBoot":{account_caller:[164,4,1,""],aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""],search_index_entry:[164,4,1,""],switch_options:[164,4,1,""]},"evennia.commands.default.comms.CmdCWho":{account_caller:[164,4,1,""],aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""],search_index_entry:[164,4,1,""]},"evennia.commands.default.comms.CmdCdesc":{account_caller:[164,4,1,""],aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""],search_index_entry:[164,4,1,""]},"evennia.commands.default.comms.CmdCdestroy":{account_caller:[164,4,1,""],aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""],search_index_entry:[164,4,1,""]},"evennia.commands.default.comms.CmdChannel":{account_caller:[164,4,1,""],add_alias:[164,3,1,""],aliases:[164,4,1,""],ban_user:[164,3,1,""],boot_user:[164,3,1,""],channel_list_bans:[164,3,1,""],channel_list_who:[164,3,1,""],create_channel:[164,3,1,""],destroy_channel:[164,3,1,""],display_all_channels:[164,3,1,""],display_subbed_channels:[164,3,1,""],func:[164,3,1,""],get_channel_aliases:[164,3,1,""],get_channel_history:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],list_channels:[164,3,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""],msg_channel:[164,3,1,""],mute_channel:[164,3,1,""],remove_alias:[164,3,1,""],search_channel:[164,3,1,""],search_index_entry:[164,4,1,""],set_desc:[164,3,1,""],set_lock:[164,3,1,""],sub_to_channel:[164,3,1,""],switch_options:[164,4,1,""],unban_user:[164,3,1,""],unmute_channel:[164,3,1,""],unset_lock:[164,3,1,""],unsub_from_channel:[164,3,1,""]},"evennia.commands.default.comms.CmdChannelCreate":{account_caller:[164,4,1,""],aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""],search_index_entry:[164,4,1,""]},"evennia.commands.default.comms.CmdClock":{account_caller:[164,4,1,""],aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""],search_index_entry:[164,4,1,""]},"evennia.commands.default.comms.CmdDelCom":{account_caller:[164,4,1,""],aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""],search_index_entry:[164,4,1,""]},"evennia.commands.default.comms.CmdGrapevine2Chan":{aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""],search_index_entry:[164,4,1,""],switch_options:[164,4,1,""]},"evennia.commands.default.comms.CmdIRC2Chan":{aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""],search_index_entry:[164,4,1,""],switch_options:[164,4,1,""]},"evennia.commands.default.comms.CmdIRCStatus":{aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""],search_index_entry:[164,4,1,""]},"evennia.commands.default.comms.CmdPage":{account_caller:[164,4,1,""],aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""],search_index_entry:[164,4,1,""],switch_options:[164,4,1,""]},"evennia.commands.default.comms.CmdRSS2Chan":{aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""],search_index_entry:[164,4,1,""],switch_options:[164,4,1,""]},"evennia.commands.default.general":{CmdAccess:[165,1,1,""],CmdDrop:[165,1,1,""],CmdGet:[165,1,1,""],CmdGive:[165,1,1,""],CmdHome:[165,1,1,""],CmdInventory:[165,1,1,""],CmdLook:[165,1,1,""],CmdNick:[165,1,1,""],CmdPose:[165,1,1,""],CmdSay:[165,1,1,""],CmdSetDesc:[165,1,1,""],CmdWhisper:[165,1,1,""]},"evennia.commands.default.general.CmdAccess":{aliases:[165,4,1,""],arg_regex:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""],search_index_entry:[165,4,1,""]},"evennia.commands.default.general.CmdDrop":{aliases:[165,4,1,""],arg_regex:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""],search_index_entry:[165,4,1,""]},"evennia.commands.default.general.CmdGet":{aliases:[165,4,1,""],arg_regex:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""],search_index_entry:[165,4,1,""]},"evennia.commands.default.general.CmdGive":{aliases:[165,4,1,""],arg_regex:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""],rhs_split:[165,4,1,""],search_index_entry:[165,4,1,""]},"evennia.commands.default.general.CmdHome":{aliases:[165,4,1,""],arg_regex:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""],search_index_entry:[165,4,1,""]},"evennia.commands.default.general.CmdInventory":{aliases:[165,4,1,""],arg_regex:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""],search_index_entry:[165,4,1,""]},"evennia.commands.default.general.CmdLook":{aliases:[165,4,1,""],arg_regex:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""],search_index_entry:[165,4,1,""]},"evennia.commands.default.general.CmdNick":{aliases:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""],parse:[165,3,1,""],search_index_entry:[165,4,1,""],switch_options:[165,4,1,""]},"evennia.commands.default.general.CmdPose":{aliases:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""],parse:[165,3,1,""],search_index_entry:[165,4,1,""]},"evennia.commands.default.general.CmdSay":{aliases:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""],search_index_entry:[165,4,1,""]},"evennia.commands.default.general.CmdSetDesc":{aliases:[165,4,1,""],arg_regex:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""],search_index_entry:[165,4,1,""]},"evennia.commands.default.general.CmdWhisper":{aliases:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""],search_index_entry:[165,4,1,""]},"evennia.commands.default.help":{CmdHelp:[166,1,1,""],CmdSetHelp:[166,1,1,""]},"evennia.commands.default.help.CmdHelp":{aliases:[166,4,1,""],arg_regex:[166,4,1,""],can_list_topic:[166,3,1,""],can_read_topic:[166,3,1,""],clickable_topics:[166,4,1,""],collect_topics:[166,3,1,""],do_search:[166,3,1,""],format_help_entry:[166,3,1,""],format_help_index:[166,3,1,""],func:[166,3,1,""],help_category:[166,4,1,""],help_more:[166,4,1,""],index_category_clr:[166,4,1,""],index_topic_clr:[166,4,1,""],index_type_separator_clr:[166,4,1,""],key:[166,4,1,""],lock_storage:[166,4,1,""],locks:[166,4,1,""],msg_help:[166,3,1,""],parse:[166,3,1,""],return_cmdset:[166,4,1,""],search_index_entry:[166,4,1,""],subtopic_separator_char:[166,4,1,""],suggestion_cutoff:[166,4,1,""],suggestion_maxnum:[166,4,1,""]},"evennia.commands.default.help.CmdSetHelp":{aliases:[166,4,1,""],arg_regex:[166,4,1,""],func:[166,3,1,""],help_category:[166,4,1,""],key:[166,4,1,""],lock_storage:[166,4,1,""],locks:[166,4,1,""],parse:[166,3,1,""],search_index_entry:[166,4,1,""],switch_options:[166,4,1,""]},"evennia.commands.default.muxcommand":{MuxAccountCommand:[167,1,1,""],MuxCommand:[167,1,1,""]},"evennia.commands.default.muxcommand.MuxAccountCommand":{account_caller:[167,4,1,""],aliases:[167,4,1,""],help_category:[167,4,1,""],key:[167,4,1,""],lock_storage:[167,4,1,""],search_index_entry:[167,4,1,""]},"evennia.commands.default.muxcommand.MuxCommand":{aliases:[167,4,1,""],at_post_cmd:[167,3,1,""],at_pre_cmd:[167,3,1,""],func:[167,3,1,""],get_command_info:[167,3,1,""],has_perm:[167,3,1,""],help_category:[167,4,1,""],key:[167,4,1,""],lock_storage:[167,4,1,""],parse:[167,3,1,""],search_index_entry:[167,4,1,""]},"evennia.commands.default.syscommands":{SystemMultimatch:[168,1,1,""],SystemNoInput:[168,1,1,""],SystemNoMatch:[168,1,1,""]},"evennia.commands.default.syscommands.SystemMultimatch":{aliases:[168,4,1,""],func:[168,3,1,""],help_category:[168,4,1,""],key:[168,4,1,""],lock_storage:[168,4,1,""],locks:[168,4,1,""],search_index_entry:[168,4,1,""]},"evennia.commands.default.syscommands.SystemNoInput":{aliases:[168,4,1,""],func:[168,3,1,""],help_category:[168,4,1,""],key:[168,4,1,""],lock_storage:[168,4,1,""],locks:[168,4,1,""],search_index_entry:[168,4,1,""]},"evennia.commands.default.syscommands.SystemNoMatch":{aliases:[168,4,1,""],func:[168,3,1,""],help_category:[168,4,1,""],key:[168,4,1,""],lock_storage:[168,4,1,""],locks:[168,4,1,""],search_index_entry:[168,4,1,""]},"evennia.commands.default.system":{CmdAbout:[169,1,1,""],CmdObjects:[169,1,1,""],CmdPy:[169,1,1,""],CmdReload:[169,1,1,""],CmdReset:[169,1,1,""],CmdScripts:[169,1,1,""],CmdServerLoad:[169,1,1,""],CmdService:[169,1,1,""],CmdShutdown:[169,1,1,""],CmdTasks:[169,1,1,""],CmdTime:[169,1,1,""]},"evennia.commands.default.system.CmdAbout":{aliases:[169,4,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""],search_index_entry:[169,4,1,""]},"evennia.commands.default.system.CmdObjects":{aliases:[169,4,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""],search_index_entry:[169,4,1,""]},"evennia.commands.default.system.CmdPy":{aliases:[169,4,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""],search_index_entry:[169,4,1,""],switch_options:[169,4,1,""]},"evennia.commands.default.system.CmdReload":{aliases:[169,4,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""],search_index_entry:[169,4,1,""]},"evennia.commands.default.system.CmdReset":{aliases:[169,4,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""],search_index_entry:[169,4,1,""]},"evennia.commands.default.system.CmdScripts":{aliases:[169,4,1,""],excluded_typeclass_paths:[169,4,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""],search_index_entry:[169,4,1,""],switch_mapping:[169,4,1,""],switch_options:[169,4,1,""]},"evennia.commands.default.system.CmdServerLoad":{aliases:[169,4,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""],search_index_entry:[169,4,1,""],switch_options:[169,4,1,""]},"evennia.commands.default.system.CmdService":{aliases:[169,4,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""],search_index_entry:[169,4,1,""],switch_options:[169,4,1,""]},"evennia.commands.default.system.CmdShutdown":{aliases:[169,4,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""],search_index_entry:[169,4,1,""]},"evennia.commands.default.system.CmdTasks":{aliases:[169,4,1,""],coll_date_func:[169,3,1,""],do_task_action:[169,3,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""],search_index_entry:[169,4,1,""],switch_options:[169,4,1,""]},"evennia.commands.default.system.CmdTime":{aliases:[169,4,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""],search_index_entry:[169,4,1,""]},"evennia.commands.default.tests":{CmdInterrupt:[170,1,1,""],CommandTest:[170,1,1,""],TestAccount:[170,1,1,""],TestAdmin:[170,1,1,""],TestBatchProcess:[170,1,1,""],TestBuilding:[170,1,1,""],TestCmdTasks:[170,1,1,""],TestComms:[170,1,1,""],TestCommsChannel:[170,1,1,""],TestGeneral:[170,1,1,""],TestHelp:[170,1,1,""],TestInterruptCommand:[170,1,1,""],TestSystem:[170,1,1,""],TestSystemCommands:[170,1,1,""],TestUnconnectedCommand:[170,1,1,""],func_test_cmd_tasks:[170,5,1,""]},"evennia.commands.default.tests.CmdInterrupt":{aliases:[170,4,1,""],func:[170,3,1,""],help_category:[170,4,1,""],key:[170,4,1,""],lock_storage:[170,4,1,""],parse:[170,3,1,""],search_index_entry:[170,4,1,""]},"evennia.commands.default.tests.CommandTest":{call:[170,3,1,""]},"evennia.commands.default.tests.TestAccount":{test_char_create:[170,3,1,""],test_char_delete:[170,3,1,""],test_color_test:[170,3,1,""],test_ic:[170,3,1,""],test_ic__nonaccess:[170,3,1,""],test_ic__other_object:[170,3,1,""],test_ooc:[170,3,1,""],test_ooc_look:[170,3,1,""],test_option:[170,3,1,""],test_password:[170,3,1,""],test_quell:[170,3,1,""],test_quit:[170,3,1,""],test_sessions:[170,3,1,""],test_who:[170,3,1,""]},"evennia.commands.default.tests.TestAdmin":{test_ban:[170,3,1,""],test_emit:[170,3,1,""],test_force:[170,3,1,""],test_perm:[170,3,1,""],test_wall:[170,3,1,""]},"evennia.commands.default.tests.TestBatchProcess":{test_batch_commands:[170,3,1,""]},"evennia.commands.default.tests.TestBuilding":{test_attribute_commands:[170,3,1,""],test_copy:[170,3,1,""],test_create:[170,3,1,""],test_desc:[170,3,1,""],test_desc_default_to_room:[170,3,1,""],test_destroy:[170,3,1,""],test_destroy_sequence:[170,3,1,""],test_dig:[170,3,1,""],test_do_nested_lookup:[170,3,1,""],test_empty_desc:[170,3,1,""],test_examine:[170,3,1,""],test_exit_commands:[170,3,1,""],test_find:[170,3,1,""],test_list_cmdsets:[170,3,1,""],test_lock:[170,3,1,""],test_name:[170,3,1,""],test_nested_attribute_commands:[170,3,1,""],test_script:[170,3,1,""],test_set_home:[170,3,1,""],test_set_obj_alias:[170,3,1,""],test_spawn:[170,3,1,""],test_split_nested_attr:[170,3,1,""],test_tag:[170,3,1,""],test_teleport:[170,3,1,""],test_tunnel:[170,3,1,""],test_tunnel_exit_typeclass:[170,3,1,""],test_typeclass:[170,3,1,""]},"evennia.commands.default.tests.TestCmdTasks":{setUp:[170,3,1,""],tearDown:[170,3,1,""],test_active_task:[170,3,1,""],test_call:[170,3,1,""],test_cancel:[170,3,1,""],test_do_task:[170,3,1,""],test_func_name_manipulation:[170,3,1,""],test_misformed_command:[170,3,1,""],test_new_task_waiting_input:[170,3,1,""],test_no_input:[170,3,1,""],test_no_tasks:[170,3,1,""],test_pause_unpause:[170,3,1,""],test_persistent_task:[170,3,1,""],test_remove:[170,3,1,""],test_responce_of_yes:[170,3,1,""],test_task_complete_waiting_input:[170,3,1,""],test_wrong_func_name:[170,3,1,""]},"evennia.commands.default.tests.TestComms":{setUp:[170,3,1,""],test_all_com:[170,3,1,""],test_cboot:[170,3,1,""],test_cdesc:[170,3,1,""],test_cdestroy:[170,3,1,""],test_clock:[170,3,1,""],test_cwho:[170,3,1,""],test_page:[170,3,1,""],test_toggle_com:[170,3,1,""]},"evennia.commands.default.tests.TestCommsChannel":{setUp:[170,3,1,""],tearDown:[170,3,1,""],test_channel__alias__unalias:[170,3,1,""],test_channel__all:[170,3,1,""],test_channel__ban__unban:[170,3,1,""],test_channel__boot:[170,3,1,""],test_channel__create:[170,3,1,""],test_channel__desc:[170,3,1,""],test_channel__destroy:[170,3,1,""],test_channel__history:[170,3,1,""],test_channel__list:[170,3,1,""],test_channel__lock:[170,3,1,""],test_channel__msg:[170,3,1,""],test_channel__mute:[170,3,1,""],test_channel__noarg:[170,3,1,""],test_channel__sub:[170,3,1,""],test_channel__unlock:[170,3,1,""],test_channel__unmute:[170,3,1,""],test_channel__unsub:[170,3,1,""],test_channel__who:[170,3,1,""]},"evennia.commands.default.tests.TestGeneral":{test_access:[170,3,1,""],test_get_and_drop:[170,3,1,""],test_give:[170,3,1,""],test_home:[170,3,1,""],test_inventory:[170,3,1,""],test_look:[170,3,1,""],test_mux_command:[170,3,1,""],test_nick:[170,3,1,""],test_pose:[170,3,1,""],test_say:[170,3,1,""],test_whisper:[170,3,1,""]},"evennia.commands.default.tests.TestHelp":{maxDiff:[170,4,1,""],setUp:[170,3,1,""],tearDown:[170,3,1,""],test_help:[170,3,1,""],test_set_help:[170,3,1,""],test_subtopic_fetch:[170,4,1,""],test_subtopic_fetch_00_test:[170,3,1,""],test_subtopic_fetch_01_test_creating_extra_stuff:[170,3,1,""],test_subtopic_fetch_02_test_creating:[170,3,1,""],test_subtopic_fetch_03_test_extra:[170,3,1,""],test_subtopic_fetch_04_test_extra_subsubtopic:[170,3,1,""],test_subtopic_fetch_05_test_creating_extra_subsub:[170,3,1,""],test_subtopic_fetch_06_test_Something_else:[170,3,1,""],test_subtopic_fetch_07_test_More:[170,3,1,""],test_subtopic_fetch_08_test_More_Second_more:[170,3,1,""],test_subtopic_fetch_09_test_More_more:[170,3,1,""],test_subtopic_fetch_10_test_more_second_more_again:[170,3,1,""],test_subtopic_fetch_11_test_more_second_third:[170,3,1,""]},"evennia.commands.default.tests.TestInterruptCommand":{test_interrupt_command:[170,3,1,""]},"evennia.commands.default.tests.TestSystem":{test_about:[170,3,1,""],test_objects:[170,3,1,""],test_py:[170,3,1,""],test_scripts:[170,3,1,""],test_server_load:[170,3,1,""]},"evennia.commands.default.tests.TestSystemCommands":{test_multimatch:[170,3,1,""],test_simple_defaults:[170,3,1,""]},"evennia.commands.default.tests.TestUnconnectedCommand":{test_info_command:[170,3,1,""]},"evennia.commands.default.unloggedin":{CmdUnconnectedConnect:[171,1,1,""],CmdUnconnectedCreate:[171,1,1,""],CmdUnconnectedHelp:[171,1,1,""],CmdUnconnectedLook:[171,1,1,""],CmdUnconnectedQuit:[171,1,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedConnect":{aliases:[171,4,1,""],arg_regex:[171,4,1,""],func:[171,3,1,""],help_category:[171,4,1,""],key:[171,4,1,""],lock_storage:[171,4,1,""],locks:[171,4,1,""],search_index_entry:[171,4,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedCreate":{aliases:[171,4,1,""],arg_regex:[171,4,1,""],func:[171,3,1,""],help_category:[171,4,1,""],key:[171,4,1,""],lock_storage:[171,4,1,""],locks:[171,4,1,""],search_index_entry:[171,4,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedHelp":{aliases:[171,4,1,""],func:[171,3,1,""],help_category:[171,4,1,""],key:[171,4,1,""],lock_storage:[171,4,1,""],locks:[171,4,1,""],search_index_entry:[171,4,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedLook":{aliases:[171,4,1,""],func:[171,3,1,""],help_category:[171,4,1,""],key:[171,4,1,""],lock_storage:[171,4,1,""],locks:[171,4,1,""],search_index_entry:[171,4,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedQuit":{aliases:[171,4,1,""],func:[171,3,1,""],help_category:[171,4,1,""],key:[171,4,1,""],lock_storage:[171,4,1,""],locks:[171,4,1,""],search_index_entry:[171,4,1,""]},"evennia.comms":{comms:[175,0,0,"-"],managers:[176,0,0,"-"],models:[177,0,0,"-"]},"evennia.comms.comms":{DefaultChannel:[175,1,1,""]},"evennia.comms.comms.DefaultChannel":{"delete":[175,3,1,""],DoesNotExist:[175,2,1,""],MultipleObjectsReturned:[175,2,1,""],access:[175,3,1,""],add_user_channel_alias:[175,3,1,""],at_channel_creation:[175,3,1,""],at_first_save:[175,3,1,""],at_init:[175,3,1,""],at_post_msg:[175,3,1,""],at_pre_msg:[175,3,1,""],ban:[175,3,1,""],banlist:[175,3,1,""],basetype_setup:[175,3,1,""],channel_msg_nick_pattern:[175,4,1,""],channel_msg_nick_replacement:[175,4,1,""],channel_prefix:[175,3,1,""],channel_prefix_string:[175,4,1,""],connect:[175,3,1,""],create:[175,3,1,""],disconnect:[175,3,1,""],distribute_message:[175,3,1,""],format_external:[175,3,1,""],format_message:[175,3,1,""],format_senders:[175,3,1,""],get_absolute_url:[175,3,1,""],get_log_filename:[175,3,1,""],has_connection:[175,3,1,""],log_file:[175,4,1,""],message_transform:[175,3,1,""],msg:[175,3,1,""],mute:[175,3,1,""],mutelist:[175,3,1,""],objects:[175,4,1,""],path:[175,4,1,""],pose_transform:[175,3,1,""],post_join_channel:[175,3,1,""],post_leave_channel:[175,3,1,""],post_send_message:[175,3,1,""],pre_join_channel:[175,3,1,""],pre_leave_channel:[175,3,1,""],pre_send_message:[175,3,1,""],remove_user_channel_alias:[175,3,1,""],send_to_online_only:[175,4,1,""],set_log_filename:[175,3,1,""],typename:[175,4,1,""],unban:[175,3,1,""],unmute:[175,3,1,""],web_get_admin_url:[175,3,1,""],web_get_create_url:[175,3,1,""],web_get_delete_url:[175,3,1,""],web_get_detail_url:[175,3,1,""],web_get_update_url:[175,3,1,""],wholist:[175,3,1,""]},"evennia.comms.managers":{ChannelDBManager:[176,1,1,""],ChannelManager:[176,1,1,""],CommError:[176,2,1,""],MsgManager:[176,1,1,""],identify_object:[176,5,1,""],to_object:[176,5,1,""]},"evennia.comms.managers.ChannelDBManager":{channel_search:[176,3,1,""],get_all_channels:[176,3,1,""],get_channel:[176,3,1,""],get_subscriptions:[176,3,1,""],search_channel:[176,3,1,""]},"evennia.comms.managers.MsgManager":{get_message_by_id:[176,3,1,""],get_messages_by_receiver:[176,3,1,""],get_messages_by_sender:[176,3,1,""],identify_object:[176,3,1,""],message_search:[176,3,1,""],search_message:[176,3,1,""]},"evennia.comms.models":{ChannelDB:[177,1,1,""],Msg:[177,1,1,""],TempMsg:[177,1,1,""]},"evennia.comms.models.ChannelDB":{DoesNotExist:[177,2,1,""],MultipleObjectsReturned:[177,2,1,""],db_account_subscriptions:[177,4,1,""],db_attributes:[177,4,1,""],db_object_subscriptions:[177,4,1,""],db_tags:[177,4,1,""],get_next_by_db_date_created:[177,3,1,""],get_previous_by_db_date_created:[177,3,1,""],id:[177,4,1,""],objects:[177,4,1,""],path:[177,4,1,""],subscriptions:[177,4,1,""],typename:[177,4,1,""]},"evennia.comms.models.Msg":{DoesNotExist:[177,2,1,""],MultipleObjectsReturned:[177,2,1,""],access:[177,3,1,""],date_created:[177,3,1,""],db_date_created:[177,4,1,""],db_header:[177,4,1,""],db_hide_from_accounts:[177,4,1,""],db_hide_from_objects:[177,4,1,""],db_lock_storage:[177,4,1,""],db_message:[177,4,1,""],db_receiver_external:[177,4,1,""],db_receivers_accounts:[177,4,1,""],db_receivers_objects:[177,4,1,""],db_receivers_scripts:[177,4,1,""],db_sender_accounts:[177,4,1,""],db_sender_external:[177,4,1,""],db_sender_objects:[177,4,1,""],db_sender_scripts:[177,4,1,""],db_tags:[177,4,1,""],get_next_by_db_date_created:[177,3,1,""],get_previous_by_db_date_created:[177,3,1,""],header:[177,3,1,""],hide_from:[177,3,1,""],id:[177,4,1,""],lock_storage:[177,3,1,""],locks:[177,4,1,""],message:[177,3,1,""],objects:[177,4,1,""],path:[177,4,1,""],receiver_external:[177,3,1,""],receivers:[177,3,1,""],remove_receiver:[177,3,1,""],remove_sender:[177,3,1,""],sender_external:[177,3,1,""],senders:[177,3,1,""],tags:[177,4,1,""],typename:[177,4,1,""]},"evennia.comms.models.TempMsg":{__init__:[177,3,1,""],access:[177,3,1,""],locks:[177,4,1,""],remove_receiver:[177,3,1,""],remove_sender:[177,3,1,""]},"evennia.contrib":{barter:[179,0,0,"-"],building_menu:[180,0,0,"-"],chargen:[181,0,0,"-"],clothing:[182,0,0,"-"],color_markups:[183,0,0,"-"],custom_gametime:[184,0,0,"-"],dice:[185,0,0,"-"],email_login:[186,0,0,"-"],extended_room:[187,0,0,"-"],fieldfill:[188,0,0,"-"],gendersub:[189,0,0,"-"],health_bar:[190,0,0,"-"],ingame_python:[191,0,0,"-"],mail:[199,0,0,"-"],multidescer:[202,0,0,"-"],puzzles:[203,0,0,"-"],random_string_generator:[204,0,0,"-"],rplanguage:[205,0,0,"-"],rpsystem:[206,0,0,"-"],security:[207,0,0,"-"],simpledoor:[212,0,0,"-"],slow_exit:[213,0,0,"-"],talking_npc:[214,0,0,"-"],tree_select:[215,0,0,"-"],turnbattle:[216,0,0,"-"],tutorial_examples:[222,0,0,"-"],tutorial_world:[229,0,0,"-"],unixcommand:[234,0,0,"-"],wilderness:[235,0,0,"-"]},"evennia.contrib.barter":{CmdAccept:[179,1,1,""],CmdDecline:[179,1,1,""],CmdEvaluate:[179,1,1,""],CmdFinish:[179,1,1,""],CmdOffer:[179,1,1,""],CmdStatus:[179,1,1,""],CmdTrade:[179,1,1,""],CmdTradeBase:[179,1,1,""],CmdTradeHelp:[179,1,1,""],CmdsetTrade:[179,1,1,""],TradeHandler:[179,1,1,""],TradeTimeout:[179,1,1,""]},"evennia.contrib.barter.CmdAccept":{aliases:[179,4,1,""],func:[179,3,1,""],help_category:[179,4,1,""],key:[179,4,1,""],lock_storage:[179,4,1,""],locks:[179,4,1,""],search_index_entry:[179,4,1,""]},"evennia.contrib.barter.CmdDecline":{aliases:[179,4,1,""],func:[179,3,1,""],help_category:[179,4,1,""],key:[179,4,1,""],lock_storage:[179,4,1,""],locks:[179,4,1,""],search_index_entry:[179,4,1,""]},"evennia.contrib.barter.CmdEvaluate":{aliases:[179,4,1,""],func:[179,3,1,""],help_category:[179,4,1,""],key:[179,4,1,""],lock_storage:[179,4,1,""],locks:[179,4,1,""],search_index_entry:[179,4,1,""]},"evennia.contrib.barter.CmdFinish":{aliases:[179,4,1,""],func:[179,3,1,""],help_category:[179,4,1,""],key:[179,4,1,""],lock_storage:[179,4,1,""],locks:[179,4,1,""],search_index_entry:[179,4,1,""]},"evennia.contrib.barter.CmdOffer":{aliases:[179,4,1,""],func:[179,3,1,""],help_category:[179,4,1,""],key:[179,4,1,""],lock_storage:[179,4,1,""],locks:[179,4,1,""],search_index_entry:[179,4,1,""]},"evennia.contrib.barter.CmdStatus":{aliases:[179,4,1,""],func:[179,3,1,""],help_category:[179,4,1,""],key:[179,4,1,""],lock_storage:[179,4,1,""],locks:[179,4,1,""],search_index_entry:[179,4,1,""]},"evennia.contrib.barter.CmdTrade":{aliases:[179,4,1,""],func:[179,3,1,""],help_category:[179,4,1,""],key:[179,4,1,""],lock_storage:[179,4,1,""],locks:[179,4,1,""],search_index_entry:[179,4,1,""]},"evennia.contrib.barter.CmdTradeBase":{aliases:[179,4,1,""],help_category:[179,4,1,""],key:[179,4,1,""],lock_storage:[179,4,1,""],parse:[179,3,1,""],search_index_entry:[179,4,1,""]},"evennia.contrib.barter.CmdTradeHelp":{aliases:[179,4,1,""],func:[179,3,1,""],help_category:[179,4,1,""],key:[179,4,1,""],lock_storage:[179,4,1,""],locks:[179,4,1,""],search_index_entry:[179,4,1,""]},"evennia.contrib.barter.CmdsetTrade":{at_cmdset_creation:[179,3,1,""],key:[179,4,1,""],path:[179,4,1,""]},"evennia.contrib.barter.TradeHandler":{__init__:[179,3,1,""],accept:[179,3,1,""],decline:[179,3,1,""],finish:[179,3,1,""],get_other:[179,3,1,""],join:[179,3,1,""],list:[179,3,1,""],msg_other:[179,3,1,""],offer:[179,3,1,""],search:[179,3,1,""],unjoin:[179,3,1,""]},"evennia.contrib.barter.TradeTimeout":{DoesNotExist:[179,2,1,""],MultipleObjectsReturned:[179,2,1,""],at_repeat:[179,3,1,""],at_script_creation:[179,3,1,""],is_valid:[179,3,1,""],path:[179,4,1,""],typename:[179,4,1,""]},"evennia.contrib.building_menu":{BuildingMenu:[180,1,1,""],BuildingMenuCmdSet:[180,1,1,""],Choice:[180,1,1,""],CmdNoInput:[180,1,1,""],CmdNoMatch:[180,1,1,""],GenericBuildingCmd:[180,1,1,""],GenericBuildingMenu:[180,1,1,""],menu_edit:[180,5,1,""],menu_quit:[180,5,1,""],menu_setattr:[180,5,1,""]},"evennia.contrib.building_menu.BuildingMenu":{__init__:[180,3,1,""],add_choice:[180,3,1,""],add_choice_edit:[180,3,1,""],add_choice_quit:[180,3,1,""],close:[180,3,1,""],current_choice:[180,3,1,""],display:[180,3,1,""],display_choice:[180,3,1,""],display_title:[180,3,1,""],init:[180,3,1,""],joker_key:[180,4,1,""],keys_go_back:[180,4,1,""],min_shortcut:[180,4,1,""],move:[180,3,1,""],open:[180,3,1,""],open_parent_menu:[180,3,1,""],open_submenu:[180,3,1,""],relevant_choices:[180,3,1,""],restore:[180,3,1,""],sep_keys:[180,4,1,""]},"evennia.contrib.building_menu.BuildingMenuCmdSet":{at_cmdset_creation:[180,3,1,""],key:[180,4,1,""],path:[180,4,1,""],priority:[180,4,1,""]},"evennia.contrib.building_menu.Choice":{__init__:[180,3,1,""],enter:[180,3,1,""],format_text:[180,3,1,""],keys:[180,3,1,""],leave:[180,3,1,""],nomatch:[180,3,1,""]},"evennia.contrib.building_menu.CmdNoInput":{__init__:[180,3,1,""],aliases:[180,4,1,""],func:[180,3,1,""],help_category:[180,4,1,""],key:[180,4,1,""],lock_storage:[180,4,1,""],locks:[180,4,1,""],search_index_entry:[180,4,1,""]},"evennia.contrib.building_menu.CmdNoMatch":{__init__:[180,3,1,""],aliases:[180,4,1,""],func:[180,3,1,""],help_category:[180,4,1,""],key:[180,4,1,""],lock_storage:[180,4,1,""],locks:[180,4,1,""],search_index_entry:[180,4,1,""]},"evennia.contrib.building_menu.GenericBuildingCmd":{aliases:[180,4,1,""],func:[180,3,1,""],help_category:[180,4,1,""],key:[180,4,1,""],lock_storage:[180,4,1,""],search_index_entry:[180,4,1,""]},"evennia.contrib.building_menu.GenericBuildingMenu":{init:[180,3,1,""]},"evennia.contrib.chargen":{CmdOOCCharacterCreate:[181,1,1,""],CmdOOCLook:[181,1,1,""],OOCCmdSetCharGen:[181,1,1,""]},"evennia.contrib.chargen.CmdOOCCharacterCreate":{aliases:[181,4,1,""],func:[181,3,1,""],help_category:[181,4,1,""],key:[181,4,1,""],lock_storage:[181,4,1,""],locks:[181,4,1,""],search_index_entry:[181,4,1,""]},"evennia.contrib.chargen.CmdOOCLook":{aliases:[181,4,1,""],func:[181,3,1,""],help_category:[181,4,1,""],key:[181,4,1,""],lock_storage:[181,4,1,""],locks:[181,4,1,""],search_index_entry:[181,4,1,""]},"evennia.contrib.chargen.OOCCmdSetCharGen":{at_cmdset_creation:[181,3,1,""],path:[181,4,1,""]},"evennia.contrib.clothing":{ClothedCharacter:[182,1,1,""],ClothedCharacterCmdSet:[182,1,1,""],Clothing:[182,1,1,""],CmdCover:[182,1,1,""],CmdDrop:[182,1,1,""],CmdGive:[182,1,1,""],CmdInventory:[182,1,1,""],CmdRemove:[182,1,1,""],CmdUncover:[182,1,1,""],CmdWear:[182,1,1,""],clothing_type_count:[182,5,1,""],get_worn_clothes:[182,5,1,""],order_clothes_list:[182,5,1,""],single_type_count:[182,5,1,""]},"evennia.contrib.clothing.ClothedCharacter":{DoesNotExist:[182,2,1,""],MultipleObjectsReturned:[182,2,1,""],path:[182,4,1,""],return_appearance:[182,3,1,""],typename:[182,4,1,""]},"evennia.contrib.clothing.ClothedCharacterCmdSet":{at_cmdset_creation:[182,3,1,""],key:[182,4,1,""],path:[182,4,1,""]},"evennia.contrib.clothing.Clothing":{DoesNotExist:[182,2,1,""],MultipleObjectsReturned:[182,2,1,""],at_get:[182,3,1,""],path:[182,4,1,""],remove:[182,3,1,""],typename:[182,4,1,""],wear:[182,3,1,""]},"evennia.contrib.clothing.CmdCover":{aliases:[182,4,1,""],func:[182,3,1,""],help_category:[182,4,1,""],key:[182,4,1,""],lock_storage:[182,4,1,""],search_index_entry:[182,4,1,""]},"evennia.contrib.clothing.CmdDrop":{aliases:[182,4,1,""],arg_regex:[182,4,1,""],func:[182,3,1,""],help_category:[182,4,1,""],key:[182,4,1,""],lock_storage:[182,4,1,""],locks:[182,4,1,""],search_index_entry:[182,4,1,""]},"evennia.contrib.clothing.CmdGive":{aliases:[182,4,1,""],arg_regex:[182,4,1,""],func:[182,3,1,""],help_category:[182,4,1,""],key:[182,4,1,""],lock_storage:[182,4,1,""],locks:[182,4,1,""],search_index_entry:[182,4,1,""]},"evennia.contrib.clothing.CmdInventory":{aliases:[182,4,1,""],arg_regex:[182,4,1,""],func:[182,3,1,""],help_category:[182,4,1,""],key:[182,4,1,""],lock_storage:[182,4,1,""],locks:[182,4,1,""],search_index_entry:[182,4,1,""]},"evennia.contrib.clothing.CmdRemove":{aliases:[182,4,1,""],func:[182,3,1,""],help_category:[182,4,1,""],key:[182,4,1,""],lock_storage:[182,4,1,""],search_index_entry:[182,4,1,""]},"evennia.contrib.clothing.CmdUncover":{aliases:[182,4,1,""],func:[182,3,1,""],help_category:[182,4,1,""],key:[182,4,1,""],lock_storage:[182,4,1,""],search_index_entry:[182,4,1,""]},"evennia.contrib.clothing.CmdWear":{aliases:[182,4,1,""],func:[182,3,1,""],help_category:[182,4,1,""],key:[182,4,1,""],lock_storage:[182,4,1,""],search_index_entry:[182,4,1,""]},"evennia.contrib.custom_gametime":{GametimeScript:[184,1,1,""],custom_gametime:[184,5,1,""],gametime_to_realtime:[184,5,1,""],real_seconds_until:[184,5,1,""],realtime_to_gametime:[184,5,1,""],schedule:[184,5,1,""],time_to_tuple:[184,5,1,""]},"evennia.contrib.custom_gametime.GametimeScript":{DoesNotExist:[184,2,1,""],MultipleObjectsReturned:[184,2,1,""],at_repeat:[184,3,1,""],at_script_creation:[184,3,1,""],path:[184,4,1,""],typename:[184,4,1,""]},"evennia.contrib.dice":{CmdDice:[185,1,1,""],DiceCmdSet:[185,1,1,""],roll_dice:[185,5,1,""]},"evennia.contrib.dice.CmdDice":{aliases:[185,4,1,""],func:[185,3,1,""],help_category:[185,4,1,""],key:[185,4,1,""],lock_storage:[185,4,1,""],locks:[185,4,1,""],search_index_entry:[185,4,1,""]},"evennia.contrib.dice.DiceCmdSet":{at_cmdset_creation:[185,3,1,""],path:[185,4,1,""]},"evennia.contrib.email_login":{CmdUnconnectedConnect:[186,1,1,""],CmdUnconnectedCreate:[186,1,1,""],CmdUnconnectedHelp:[186,1,1,""],CmdUnconnectedLook:[186,1,1,""],CmdUnconnectedQuit:[186,1,1,""]},"evennia.contrib.email_login.CmdUnconnectedConnect":{aliases:[186,4,1,""],func:[186,3,1,""],help_category:[186,4,1,""],key:[186,4,1,""],lock_storage:[186,4,1,""],locks:[186,4,1,""],search_index_entry:[186,4,1,""]},"evennia.contrib.email_login.CmdUnconnectedCreate":{aliases:[186,4,1,""],func:[186,3,1,""],help_category:[186,4,1,""],key:[186,4,1,""],lock_storage:[186,4,1,""],locks:[186,4,1,""],parse:[186,3,1,""],search_index_entry:[186,4,1,""]},"evennia.contrib.email_login.CmdUnconnectedHelp":{aliases:[186,4,1,""],func:[186,3,1,""],help_category:[186,4,1,""],key:[186,4,1,""],lock_storage:[186,4,1,""],locks:[186,4,1,""],search_index_entry:[186,4,1,""]},"evennia.contrib.email_login.CmdUnconnectedLook":{aliases:[186,4,1,""],func:[186,3,1,""],help_category:[186,4,1,""],key:[186,4,1,""],lock_storage:[186,4,1,""],locks:[186,4,1,""],search_index_entry:[186,4,1,""]},"evennia.contrib.email_login.CmdUnconnectedQuit":{aliases:[186,4,1,""],func:[186,3,1,""],help_category:[186,4,1,""],key:[186,4,1,""],lock_storage:[186,4,1,""],locks:[186,4,1,""],search_index_entry:[186,4,1,""]},"evennia.contrib.extended_room":{CmdExtendedRoomDesc:[187,1,1,""],CmdExtendedRoomDetail:[187,1,1,""],CmdExtendedRoomGameTime:[187,1,1,""],CmdExtendedRoomLook:[187,1,1,""],ExtendedRoom:[187,1,1,""],ExtendedRoomCmdSet:[187,1,1,""]},"evennia.contrib.extended_room.CmdExtendedRoomDesc":{aliases:[187,4,1,""],func:[187,3,1,""],help_category:[187,4,1,""],key:[187,4,1,""],lock_storage:[187,4,1,""],reset_times:[187,3,1,""],search_index_entry:[187,4,1,""],switch_options:[187,4,1,""]},"evennia.contrib.extended_room.CmdExtendedRoomDetail":{aliases:[187,4,1,""],func:[187,3,1,""],help_category:[187,4,1,""],key:[187,4,1,""],lock_storage:[187,4,1,""],locks:[187,4,1,""],search_index_entry:[187,4,1,""]},"evennia.contrib.extended_room.CmdExtendedRoomGameTime":{aliases:[187,4,1,""],func:[187,3,1,""],help_category:[187,4,1,""],key:[187,4,1,""],lock_storage:[187,4,1,""],locks:[187,4,1,""],search_index_entry:[187,4,1,""]},"evennia.contrib.extended_room.CmdExtendedRoomLook":{aliases:[187,4,1,""],func:[187,3,1,""],help_category:[187,4,1,""],key:[187,4,1,""],lock_storage:[187,4,1,""],search_index_entry:[187,4,1,""]},"evennia.contrib.extended_room.ExtendedRoom":{DoesNotExist:[187,2,1,""],MultipleObjectsReturned:[187,2,1,""],at_object_creation:[187,3,1,""],del_detail:[187,3,1,""],get_time_and_season:[187,3,1,""],path:[187,4,1,""],replace_timeslots:[187,3,1,""],return_appearance:[187,3,1,""],return_detail:[187,3,1,""],set_detail:[187,3,1,""],typename:[187,4,1,""],update_current_description:[187,3,1,""]},"evennia.contrib.extended_room.ExtendedRoomCmdSet":{at_cmdset_creation:[187,3,1,""],path:[187,4,1,""]},"evennia.contrib.fieldfill":{CmdTestMenu:[188,1,1,""],FieldEvMenu:[188,1,1,""],display_formdata:[188,5,1,""],form_template_to_dict:[188,5,1,""],init_delayed_message:[188,5,1,""],init_fill_field:[188,5,1,""],menunode_fieldfill:[188,5,1,""],sendmessage:[188,5,1,""],verify_online_player:[188,5,1,""]},"evennia.contrib.fieldfill.CmdTestMenu":{aliases:[188,4,1,""],func:[188,3,1,""],help_category:[188,4,1,""],key:[188,4,1,""],lock_storage:[188,4,1,""],search_index_entry:[188,4,1,""]},"evennia.contrib.fieldfill.FieldEvMenu":{node_formatter:[188,3,1,""]},"evennia.contrib.gendersub":{GenderCharacter:[189,1,1,""],SetGender:[189,1,1,""]},"evennia.contrib.gendersub.GenderCharacter":{DoesNotExist:[189,2,1,""],MultipleObjectsReturned:[189,2,1,""],at_object_creation:[189,3,1,""],msg:[189,3,1,""],path:[189,4,1,""],typename:[189,4,1,""]},"evennia.contrib.gendersub.SetGender":{aliases:[189,4,1,""],func:[189,3,1,""],help_category:[189,4,1,""],key:[189,4,1,""],lock_storage:[189,4,1,""],locks:[189,4,1,""],search_index_entry:[189,4,1,""]},"evennia.contrib.health_bar":{display_meter:[190,5,1,""]},"evennia.contrib.ingame_python":{callbackhandler:[192,0,0,"-"],commands:[193,0,0,"-"],eventfuncs:[194,0,0,"-"],scripts:[195,0,0,"-"],tests:[196,0,0,"-"],utils:[198,0,0,"-"]},"evennia.contrib.ingame_python.callbackhandler":{Callback:[192,1,1,""],CallbackHandler:[192,1,1,""]},"evennia.contrib.ingame_python.callbackhandler.Callback":{author:[192,4,1,""],code:[192,4,1,""],created_on:[192,4,1,""],name:[192,4,1,""],number:[192,4,1,""],obj:[192,4,1,""],parameters:[192,4,1,""],updated_by:[192,4,1,""],updated_on:[192,4,1,""],valid:[192,4,1,""]},"evennia.contrib.ingame_python.callbackhandler.CallbackHandler":{__init__:[192,3,1,""],add:[192,3,1,""],all:[192,3,1,""],call:[192,3,1,""],edit:[192,3,1,""],format_callback:[192,3,1,""],get:[192,3,1,""],get_variable:[192,3,1,""],remove:[192,3,1,""],script:[192,4,1,""]},"evennia.contrib.ingame_python.commands":{CmdCallback:[193,1,1,""]},"evennia.contrib.ingame_python.commands.CmdCallback":{accept_callback:[193,3,1,""],add_callback:[193,3,1,""],aliases:[193,4,1,""],del_callback:[193,3,1,""],edit_callback:[193,3,1,""],func:[193,3,1,""],get_help:[193,3,1,""],help_category:[193,4,1,""],key:[193,4,1,""],list_callbacks:[193,3,1,""],list_tasks:[193,3,1,""],lock_storage:[193,4,1,""],locks:[193,4,1,""],search_index_entry:[193,4,1,""]},"evennia.contrib.ingame_python.eventfuncs":{call_event:[194,5,1,""],deny:[194,5,1,""],get:[194,5,1,""]},"evennia.contrib.ingame_python.scripts":{EventHandler:[195,1,1,""],TimeEventScript:[195,1,1,""],complete_task:[195,5,1,""]},"evennia.contrib.ingame_python.scripts.EventHandler":{DoesNotExist:[195,2,1,""],MultipleObjectsReturned:[195,2,1,""],accept_callback:[195,3,1,""],add_callback:[195,3,1,""],add_event:[195,3,1,""],at_script_creation:[195,3,1,""],at_server_start:[195,3,1,""],call:[195,3,1,""],del_callback:[195,3,1,""],edit_callback:[195,3,1,""],get_callbacks:[195,3,1,""],get_events:[195,3,1,""],get_variable:[195,3,1,""],handle_error:[195,3,1,""],path:[195,4,1,""],set_task:[195,3,1,""],typename:[195,4,1,""]},"evennia.contrib.ingame_python.scripts.TimeEventScript":{DoesNotExist:[195,2,1,""],MultipleObjectsReturned:[195,2,1,""],at_repeat:[195,3,1,""],at_script_creation:[195,3,1,""],path:[195,4,1,""],typename:[195,4,1,""]},"evennia.contrib.ingame_python.tests":{TestCmdCallback:[196,1,1,""],TestDefaultCallbacks:[196,1,1,""],TestEventHandler:[196,1,1,""]},"evennia.contrib.ingame_python.tests.TestCmdCallback":{setUp:[196,3,1,""],tearDown:[196,3,1,""],test_accept:[196,3,1,""],test_add:[196,3,1,""],test_del:[196,3,1,""],test_list:[196,3,1,""],test_lock:[196,3,1,""]},"evennia.contrib.ingame_python.tests.TestDefaultCallbacks":{setUp:[196,3,1,""],tearDown:[196,3,1,""],test_exit:[196,3,1,""]},"evennia.contrib.ingame_python.tests.TestEventHandler":{setUp:[196,3,1,""],tearDown:[196,3,1,""],test_accept:[196,3,1,""],test_add_validation:[196,3,1,""],test_call:[196,3,1,""],test_del:[196,3,1,""],test_edit:[196,3,1,""],test_edit_validation:[196,3,1,""],test_handler:[196,3,1,""],test_start:[196,3,1,""]},"evennia.contrib.ingame_python.utils":{InterruptEvent:[198,2,1,""],get_event_handler:[198,5,1,""],get_next_wait:[198,5,1,""],keyword_event:[198,5,1,""],phrase_event:[198,5,1,""],register_events:[198,5,1,""],time_event:[198,5,1,""]},"evennia.contrib.mail":{CmdMail:[199,1,1,""],CmdMailCharacter:[199,1,1,""]},"evennia.contrib.mail.CmdMail":{aliases:[199,4,1,""],func:[199,3,1,""],get_all_mail:[199,3,1,""],help_category:[199,4,1,""],key:[199,4,1,""],lock:[199,4,1,""],lock_storage:[199,4,1,""],parse:[199,3,1,""],search_index_entry:[199,4,1,""],search_targets:[199,3,1,""],send_mail:[199,3,1,""]},"evennia.contrib.mail.CmdMailCharacter":{account_caller:[199,4,1,""],aliases:[199,4,1,""],help_category:[199,4,1,""],key:[199,4,1,""],lock_storage:[199,4,1,""],search_index_entry:[199,4,1,""]},"evennia.contrib.multidescer":{CmdMultiDesc:[202,1,1,""],DescValidateError:[202,2,1,""]},"evennia.contrib.multidescer.CmdMultiDesc":{aliases:[202,4,1,""],func:[202,3,1,""],help_category:[202,4,1,""],key:[202,4,1,""],lock_storage:[202,4,1,""],locks:[202,4,1,""],search_index_entry:[202,4,1,""]},"evennia.contrib.puzzles":{CmdArmPuzzle:[203,1,1,""],CmdCreatePuzzleRecipe:[203,1,1,""],CmdEditPuzzle:[203,1,1,""],CmdListArmedPuzzles:[203,1,1,""],CmdListPuzzleRecipes:[203,1,1,""],CmdUsePuzzleParts:[203,1,1,""],PuzzleRecipe:[203,1,1,""],PuzzleSystemCmdSet:[203,1,1,""],maskout_protodef:[203,5,1,""],proto_def:[203,5,1,""]},"evennia.contrib.puzzles.CmdArmPuzzle":{aliases:[203,4,1,""],func:[203,3,1,""],help_category:[203,4,1,""],key:[203,4,1,""],lock_storage:[203,4,1,""],locks:[203,4,1,""],search_index_entry:[203,4,1,""]},"evennia.contrib.puzzles.CmdCreatePuzzleRecipe":{aliases:[203,4,1,""],confirm:[203,4,1,""],default_confirm:[203,4,1,""],func:[203,3,1,""],help_category:[203,4,1,""],key:[203,4,1,""],lock_storage:[203,4,1,""],locks:[203,4,1,""],search_index_entry:[203,4,1,""]},"evennia.contrib.puzzles.CmdEditPuzzle":{aliases:[203,4,1,""],func:[203,3,1,""],help_category:[203,4,1,""],key:[203,4,1,""],lock_storage:[203,4,1,""],locks:[203,4,1,""],search_index_entry:[203,4,1,""]},"evennia.contrib.puzzles.CmdListArmedPuzzles":{aliases:[203,4,1,""],func:[203,3,1,""],help_category:[203,4,1,""],key:[203,4,1,""],lock_storage:[203,4,1,""],locks:[203,4,1,""],search_index_entry:[203,4,1,""]},"evennia.contrib.puzzles.CmdListPuzzleRecipes":{aliases:[203,4,1,""],func:[203,3,1,""],help_category:[203,4,1,""],key:[203,4,1,""],lock_storage:[203,4,1,""],locks:[203,4,1,""],search_index_entry:[203,4,1,""]},"evennia.contrib.puzzles.CmdUsePuzzleParts":{aliases:[203,4,1,""],func:[203,3,1,""],help_category:[203,4,1,""],key:[203,4,1,""],lock_storage:[203,4,1,""],locks:[203,4,1,""],search_index_entry:[203,4,1,""]},"evennia.contrib.puzzles.PuzzleRecipe":{DoesNotExist:[203,2,1,""],MultipleObjectsReturned:[203,2,1,""],path:[203,4,1,""],save_recipe:[203,3,1,""],typename:[203,4,1,""]},"evennia.contrib.puzzles.PuzzleSystemCmdSet":{at_cmdset_creation:[203,3,1,""],path:[203,4,1,""]},"evennia.contrib.random_string_generator":{ExhaustedGenerator:[204,2,1,""],RandomStringGenerator:[204,1,1,""],RandomStringGeneratorScript:[204,1,1,""],RejectedRegex:[204,2,1,""]},"evennia.contrib.random_string_generator.RandomStringGenerator":{__init__:[204,3,1,""],all:[204,3,1,""],clear:[204,3,1,""],get:[204,3,1,""],remove:[204,3,1,""],script:[204,4,1,""]},"evennia.contrib.random_string_generator.RandomStringGeneratorScript":{DoesNotExist:[204,2,1,""],MultipleObjectsReturned:[204,2,1,""],at_script_creation:[204,3,1,""],path:[204,4,1,""],typename:[204,4,1,""]},"evennia.contrib.rplanguage":{LanguageError:[205,2,1,""],LanguageExistsError:[205,2,1,""],LanguageHandler:[205,1,1,""],add_language:[205,5,1,""],available_languages:[205,5,1,""],obfuscate_language:[205,5,1,""],obfuscate_whisper:[205,5,1,""]},"evennia.contrib.rplanguage.LanguageHandler":{DoesNotExist:[205,2,1,""],MultipleObjectsReturned:[205,2,1,""],add:[205,3,1,""],at_script_creation:[205,3,1,""],path:[205,4,1,""],translate:[205,3,1,""],typename:[205,4,1,""]},"evennia.contrib.rpsystem":{CmdEmote:[206,1,1,""],CmdMask:[206,1,1,""],CmdPose:[206,1,1,""],CmdRecog:[206,1,1,""],CmdSay:[206,1,1,""],CmdSdesc:[206,1,1,""],ContribRPCharacter:[206,1,1,""],ContribRPObject:[206,1,1,""],ContribRPRoom:[206,1,1,""],EmoteError:[206,2,1,""],LanguageError:[206,2,1,""],RPCommand:[206,1,1,""],RPSystemCmdSet:[206,1,1,""],RecogError:[206,2,1,""],RecogHandler:[206,1,1,""],SdescError:[206,2,1,""],SdescHandler:[206,1,1,""],ordered_permutation_regex:[206,5,1,""],parse_language:[206,5,1,""],parse_sdescs_and_recogs:[206,5,1,""],regex_tuple_from_key_alias:[206,5,1,""],send_emote:[206,5,1,""]},"evennia.contrib.rpsystem.CmdEmote":{aliases:[206,4,1,""],func:[206,3,1,""],help_category:[206,4,1,""],key:[206,4,1,""],lock_storage:[206,4,1,""],locks:[206,4,1,""],search_index_entry:[206,4,1,""]},"evennia.contrib.rpsystem.CmdMask":{aliases:[206,4,1,""],func:[206,3,1,""],help_category:[206,4,1,""],key:[206,4,1,""],lock_storage:[206,4,1,""],search_index_entry:[206,4,1,""]},"evennia.contrib.rpsystem.CmdPose":{aliases:[206,4,1,""],func:[206,3,1,""],help_category:[206,4,1,""],key:[206,4,1,""],lock_storage:[206,4,1,""],parse:[206,3,1,""],search_index_entry:[206,4,1,""]},"evennia.contrib.rpsystem.CmdRecog":{aliases:[206,4,1,""],func:[206,3,1,""],help_category:[206,4,1,""],key:[206,4,1,""],lock_storage:[206,4,1,""],parse:[206,3,1,""],search_index_entry:[206,4,1,""]},"evennia.contrib.rpsystem.CmdSay":{aliases:[206,4,1,""],func:[206,3,1,""],help_category:[206,4,1,""],key:[206,4,1,""],lock_storage:[206,4,1,""],locks:[206,4,1,""],search_index_entry:[206,4,1,""]},"evennia.contrib.rpsystem.CmdSdesc":{aliases:[206,4,1,""],func:[206,3,1,""],help_category:[206,4,1,""],key:[206,4,1,""],lock_storage:[206,4,1,""],locks:[206,4,1,""],search_index_entry:[206,4,1,""]},"evennia.contrib.rpsystem.ContribRPCharacter":{DoesNotExist:[206,2,1,""],MultipleObjectsReturned:[206,2,1,""],at_before_say:[206,3,1,""],at_object_creation:[206,3,1,""],get_display_name:[206,3,1,""],path:[206,4,1,""],process_language:[206,3,1,""],process_recog:[206,3,1,""],process_sdesc:[206,3,1,""],recog:[206,4,1,""],sdesc:[206,4,1,""],typename:[206,4,1,""]},"evennia.contrib.rpsystem.ContribRPObject":{DoesNotExist:[206,2,1,""],MultipleObjectsReturned:[206,2,1,""],at_object_creation:[206,3,1,""],get_display_name:[206,3,1,""],path:[206,4,1,""],return_appearance:[206,3,1,""],search:[206,3,1,""],typename:[206,4,1,""]},"evennia.contrib.rpsystem.ContribRPRoom":{DoesNotExist:[206,2,1,""],MultipleObjectsReturned:[206,2,1,""],path:[206,4,1,""],typename:[206,4,1,""]},"evennia.contrib.rpsystem.RPCommand":{aliases:[206,4,1,""],help_category:[206,4,1,""],key:[206,4,1,""],lock_storage:[206,4,1,""],parse:[206,3,1,""],search_index_entry:[206,4,1,""]},"evennia.contrib.rpsystem.RPSystemCmdSet":{at_cmdset_creation:[206,3,1,""],path:[206,4,1,""]},"evennia.contrib.rpsystem.RecogHandler":{__init__:[206,3,1,""],add:[206,3,1,""],all:[206,3,1,""],get:[206,3,1,""],get_regex_tuple:[206,3,1,""],remove:[206,3,1,""]},"evennia.contrib.rpsystem.SdescHandler":{__init__:[206,3,1,""],add:[206,3,1,""],get:[206,3,1,""],get_regex_tuple:[206,3,1,""]},"evennia.contrib.security":{auditing:[208,0,0,"-"]},"evennia.contrib.security.auditing":{outputs:[209,0,0,"-"],server:[210,0,0,"-"],tests:[211,0,0,"-"]},"evennia.contrib.security.auditing.outputs":{to_file:[209,5,1,""],to_syslog:[209,5,1,""]},"evennia.contrib.security.auditing.server":{AuditedServerSession:[210,1,1,""]},"evennia.contrib.security.auditing.server.AuditedServerSession":{audit:[210,3,1,""],data_in:[210,3,1,""],data_out:[210,3,1,""],mask:[210,3,1,""]},"evennia.contrib.security.auditing.tests":{AuditingTest:[211,1,1,""]},"evennia.contrib.security.auditing.tests.AuditingTest":{test_audit:[211,3,1,""],test_mask:[211,3,1,""]},"evennia.contrib.simpledoor":{CmdOpen:[212,1,1,""],CmdOpenCloseDoor:[212,1,1,""],SimpleDoor:[212,1,1,""]},"evennia.contrib.simpledoor.CmdOpen":{aliases:[212,4,1,""],create_exit:[212,3,1,""],help_category:[212,4,1,""],key:[212,4,1,""],lock_storage:[212,4,1,""],search_index_entry:[212,4,1,""]},"evennia.contrib.simpledoor.CmdOpenCloseDoor":{aliases:[212,4,1,""],func:[212,3,1,""],help_category:[212,4,1,""],key:[212,4,1,""],lock_storage:[212,4,1,""],locks:[212,4,1,""],search_index_entry:[212,4,1,""]},"evennia.contrib.simpledoor.SimpleDoor":{"delete":[212,3,1,""],DoesNotExist:[212,2,1,""],MultipleObjectsReturned:[212,2,1,""],at_failed_traverse:[212,3,1,""],at_object_creation:[212,3,1,""],path:[212,4,1,""],setdesc:[212,3,1,""],setlock:[212,3,1,""],typename:[212,4,1,""]},"evennia.contrib.slow_exit":{CmdSetSpeed:[213,1,1,""],CmdStop:[213,1,1,""],SlowExit:[213,1,1,""]},"evennia.contrib.slow_exit.CmdSetSpeed":{aliases:[213,4,1,""],func:[213,3,1,""],help_category:[213,4,1,""],key:[213,4,1,""],lock_storage:[213,4,1,""],search_index_entry:[213,4,1,""]},"evennia.contrib.slow_exit.CmdStop":{aliases:[213,4,1,""],func:[213,3,1,""],help_category:[213,4,1,""],key:[213,4,1,""],lock_storage:[213,4,1,""],search_index_entry:[213,4,1,""]},"evennia.contrib.slow_exit.SlowExit":{DoesNotExist:[213,2,1,""],MultipleObjectsReturned:[213,2,1,""],at_traverse:[213,3,1,""],path:[213,4,1,""],typename:[213,4,1,""]},"evennia.contrib.talking_npc":{CmdTalk:[214,1,1,""],END:[214,5,1,""],TalkingCmdSet:[214,1,1,""],TalkingNPC:[214,1,1,""],info1:[214,5,1,""],info2:[214,5,1,""],info3:[214,5,1,""],menu_start_node:[214,5,1,""]},"evennia.contrib.talking_npc.CmdTalk":{aliases:[214,4,1,""],func:[214,3,1,""],help_category:[214,4,1,""],key:[214,4,1,""],lock_storage:[214,4,1,""],locks:[214,4,1,""],search_index_entry:[214,4,1,""]},"evennia.contrib.talking_npc.TalkingCmdSet":{at_cmdset_creation:[214,3,1,""],key:[214,4,1,""],path:[214,4,1,""]},"evennia.contrib.talking_npc.TalkingNPC":{DoesNotExist:[214,2,1,""],MultipleObjectsReturned:[214,2,1,""],at_object_creation:[214,3,1,""],path:[214,4,1,""],typename:[214,4,1,""]},"evennia.contrib.tree_select":{CmdNameColor:[215,1,1,""],change_name_color:[215,5,1,""],dashcount:[215,5,1,""],go_up_one_category:[215,5,1,""],index_to_selection:[215,5,1,""],init_tree_selection:[215,5,1,""],is_category:[215,5,1,""],menunode_treeselect:[215,5,1,""],optlist_to_menuoptions:[215,5,1,""],parse_opts:[215,5,1,""]},"evennia.contrib.tree_select.CmdNameColor":{aliases:[215,4,1,""],func:[215,3,1,""],help_category:[215,4,1,""],key:[215,4,1,""],lock_storage:[215,4,1,""],search_index_entry:[215,4,1,""]},"evennia.contrib.turnbattle":{tb_basic:[217,0,0,"-"],tb_equip:[218,0,0,"-"],tb_items:[219,0,0,"-"],tb_magic:[220,0,0,"-"],tb_range:[221,0,0,"-"]},"evennia.contrib.turnbattle.tb_basic":{ACTIONS_PER_TURN:[217,6,1,""],BattleCmdSet:[217,1,1,""],CmdAttack:[217,1,1,""],CmdCombatHelp:[217,1,1,""],CmdDisengage:[217,1,1,""],CmdFight:[217,1,1,""],CmdPass:[217,1,1,""],CmdRest:[217,1,1,""],TBBasicCharacter:[217,1,1,""],TBBasicTurnHandler:[217,1,1,""],apply_damage:[217,5,1,""],at_defeat:[217,5,1,""],combat_cleanup:[217,5,1,""],get_attack:[217,5,1,""],get_damage:[217,5,1,""],get_defense:[217,5,1,""],is_in_combat:[217,5,1,""],is_turn:[217,5,1,""],resolve_attack:[217,5,1,""],roll_init:[217,5,1,""],spend_action:[217,5,1,""]},"evennia.contrib.turnbattle.tb_basic.BattleCmdSet":{at_cmdset_creation:[217,3,1,""],key:[217,4,1,""],path:[217,4,1,""]},"evennia.contrib.turnbattle.tb_basic.CmdAttack":{aliases:[217,4,1,""],func:[217,3,1,""],help_category:[217,4,1,""],key:[217,4,1,""],lock_storage:[217,4,1,""],search_index_entry:[217,4,1,""]},"evennia.contrib.turnbattle.tb_basic.CmdCombatHelp":{aliases:[217,4,1,""],func:[217,3,1,""],help_category:[217,4,1,""],key:[217,4,1,""],lock_storage:[217,4,1,""],search_index_entry:[217,4,1,""]},"evennia.contrib.turnbattle.tb_basic.CmdDisengage":{aliases:[217,4,1,""],func:[217,3,1,""],help_category:[217,4,1,""],key:[217,4,1,""],lock_storage:[217,4,1,""],search_index_entry:[217,4,1,""]},"evennia.contrib.turnbattle.tb_basic.CmdFight":{aliases:[217,4,1,""],func:[217,3,1,""],help_category:[217,4,1,""],key:[217,4,1,""],lock_storage:[217,4,1,""],search_index_entry:[217,4,1,""]},"evennia.contrib.turnbattle.tb_basic.CmdPass":{aliases:[217,4,1,""],func:[217,3,1,""],help_category:[217,4,1,""],key:[217,4,1,""],lock_storage:[217,4,1,""],search_index_entry:[217,4,1,""]},"evennia.contrib.turnbattle.tb_basic.CmdRest":{aliases:[217,4,1,""],func:[217,3,1,""],help_category:[217,4,1,""],key:[217,4,1,""],lock_storage:[217,4,1,""],search_index_entry:[217,4,1,""]},"evennia.contrib.turnbattle.tb_basic.TBBasicCharacter":{DoesNotExist:[217,2,1,""],MultipleObjectsReturned:[217,2,1,""],at_before_move:[217,3,1,""],at_object_creation:[217,3,1,""],path:[217,4,1,""],typename:[217,4,1,""]},"evennia.contrib.turnbattle.tb_basic.TBBasicTurnHandler":{DoesNotExist:[217,2,1,""],MultipleObjectsReturned:[217,2,1,""],at_repeat:[217,3,1,""],at_script_creation:[217,3,1,""],at_stop:[217,3,1,""],initialize_for_combat:[217,3,1,""],join_fight:[217,3,1,""],next_turn:[217,3,1,""],path:[217,4,1,""],start_turn:[217,3,1,""],turn_end_check:[217,3,1,""],typename:[217,4,1,""]},"evennia.contrib.turnbattle.tb_equip":{ACTIONS_PER_TURN:[218,6,1,""],BattleCmdSet:[218,1,1,""],CmdAttack:[218,1,1,""],CmdCombatHelp:[218,1,1,""],CmdDisengage:[218,1,1,""],CmdDoff:[218,1,1,""],CmdDon:[218,1,1,""],CmdFight:[218,1,1,""],CmdPass:[218,1,1,""],CmdRest:[218,1,1,""],CmdUnwield:[218,1,1,""],CmdWield:[218,1,1,""],TBEArmor:[218,1,1,""],TBEWeapon:[218,1,1,""],TBEquipCharacter:[218,1,1,""],TBEquipTurnHandler:[218,1,1,""],apply_damage:[218,5,1,""],at_defeat:[218,5,1,""],combat_cleanup:[218,5,1,""],get_attack:[218,5,1,""],get_damage:[218,5,1,""],get_defense:[218,5,1,""],is_in_combat:[218,5,1,""],is_turn:[218,5,1,""],resolve_attack:[218,5,1,""],roll_init:[218,5,1,""],spend_action:[218,5,1,""]},"evennia.contrib.turnbattle.tb_equip.BattleCmdSet":{at_cmdset_creation:[218,3,1,""],key:[218,4,1,""],path:[218,4,1,""]},"evennia.contrib.turnbattle.tb_equip.CmdAttack":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],search_index_entry:[218,4,1,""]},"evennia.contrib.turnbattle.tb_equip.CmdCombatHelp":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],search_index_entry:[218,4,1,""]},"evennia.contrib.turnbattle.tb_equip.CmdDisengage":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],search_index_entry:[218,4,1,""]},"evennia.contrib.turnbattle.tb_equip.CmdDoff":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],search_index_entry:[218,4,1,""]},"evennia.contrib.turnbattle.tb_equip.CmdDon":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],search_index_entry:[218,4,1,""]},"evennia.contrib.turnbattle.tb_equip.CmdFight":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],search_index_entry:[218,4,1,""]},"evennia.contrib.turnbattle.tb_equip.CmdPass":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],search_index_entry:[218,4,1,""]},"evennia.contrib.turnbattle.tb_equip.CmdRest":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],search_index_entry:[218,4,1,""]},"evennia.contrib.turnbattle.tb_equip.CmdUnwield":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],search_index_entry:[218,4,1,""]},"evennia.contrib.turnbattle.tb_equip.CmdWield":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],search_index_entry:[218,4,1,""]},"evennia.contrib.turnbattle.tb_equip.TBEArmor":{DoesNotExist:[218,2,1,""],MultipleObjectsReturned:[218,2,1,""],at_before_drop:[218,3,1,""],at_before_give:[218,3,1,""],at_drop:[218,3,1,""],at_give:[218,3,1,""],at_object_creation:[218,3,1,""],path:[218,4,1,""],typename:[218,4,1,""]},"evennia.contrib.turnbattle.tb_equip.TBEWeapon":{DoesNotExist:[218,2,1,""],MultipleObjectsReturned:[218,2,1,""],at_drop:[218,3,1,""],at_give:[218,3,1,""],at_object_creation:[218,3,1,""],path:[218,4,1,""],typename:[218,4,1,""]},"evennia.contrib.turnbattle.tb_equip.TBEquipCharacter":{DoesNotExist:[218,2,1,""],MultipleObjectsReturned:[218,2,1,""],at_before_move:[218,3,1,""],at_object_creation:[218,3,1,""],path:[218,4,1,""],typename:[218,4,1,""]},"evennia.contrib.turnbattle.tb_equip.TBEquipTurnHandler":{DoesNotExist:[218,2,1,""],MultipleObjectsReturned:[218,2,1,""],at_repeat:[218,3,1,""],at_script_creation:[218,3,1,""],at_stop:[218,3,1,""],initialize_for_combat:[218,3,1,""],join_fight:[218,3,1,""],next_turn:[218,3,1,""],path:[218,4,1,""],start_turn:[218,3,1,""],turn_end_check:[218,3,1,""],typename:[218,4,1,""]},"evennia.contrib.turnbattle.tb_items":{BattleCmdSet:[219,1,1,""],CmdAttack:[219,1,1,""],CmdCombatHelp:[219,1,1,""],CmdDisengage:[219,1,1,""],CmdFight:[219,1,1,""],CmdPass:[219,1,1,""],CmdRest:[219,1,1,""],CmdUse:[219,1,1,""],DEF_DOWN_MOD:[219,6,1,""],ITEMFUNCS:[219,6,1,""],TBItemsCharacter:[219,1,1,""],TBItemsCharacterTest:[219,1,1,""],TBItemsTurnHandler:[219,1,1,""],add_condition:[219,5,1,""],apply_damage:[219,5,1,""],at_defeat:[219,5,1,""],combat_cleanup:[219,5,1,""],condition_tickdown:[219,5,1,""],get_attack:[219,5,1,""],get_damage:[219,5,1,""],get_defense:[219,5,1,""],is_in_combat:[219,5,1,""],is_turn:[219,5,1,""],itemfunc_add_condition:[219,5,1,""],itemfunc_attack:[219,5,1,""],itemfunc_cure_condition:[219,5,1,""],itemfunc_heal:[219,5,1,""],resolve_attack:[219,5,1,""],roll_init:[219,5,1,""],spend_action:[219,5,1,""],spend_item_use:[219,5,1,""],use_item:[219,5,1,""]},"evennia.contrib.turnbattle.tb_items.BattleCmdSet":{at_cmdset_creation:[219,3,1,""],key:[219,4,1,""],path:[219,4,1,""]},"evennia.contrib.turnbattle.tb_items.CmdAttack":{aliases:[219,4,1,""],func:[219,3,1,""],help_category:[219,4,1,""],key:[219,4,1,""],lock_storage:[219,4,1,""],search_index_entry:[219,4,1,""]},"evennia.contrib.turnbattle.tb_items.CmdCombatHelp":{aliases:[219,4,1,""],func:[219,3,1,""],help_category:[219,4,1,""],key:[219,4,1,""],lock_storage:[219,4,1,""],search_index_entry:[219,4,1,""]},"evennia.contrib.turnbattle.tb_items.CmdDisengage":{aliases:[219,4,1,""],func:[219,3,1,""],help_category:[219,4,1,""],key:[219,4,1,""],lock_storage:[219,4,1,""],search_index_entry:[219,4,1,""]},"evennia.contrib.turnbattle.tb_items.CmdFight":{aliases:[219,4,1,""],func:[219,3,1,""],help_category:[219,4,1,""],key:[219,4,1,""],lock_storage:[219,4,1,""],search_index_entry:[219,4,1,""]},"evennia.contrib.turnbattle.tb_items.CmdPass":{aliases:[219,4,1,""],func:[219,3,1,""],help_category:[219,4,1,""],key:[219,4,1,""],lock_storage:[219,4,1,""],search_index_entry:[219,4,1,""]},"evennia.contrib.turnbattle.tb_items.CmdRest":{aliases:[219,4,1,""],func:[219,3,1,""],help_category:[219,4,1,""],key:[219,4,1,""],lock_storage:[219,4,1,""],search_index_entry:[219,4,1,""]},"evennia.contrib.turnbattle.tb_items.CmdUse":{aliases:[219,4,1,""],func:[219,3,1,""],help_category:[219,4,1,""],key:[219,4,1,""],lock_storage:[219,4,1,""],search_index_entry:[219,4,1,""]},"evennia.contrib.turnbattle.tb_items.TBItemsCharacter":{DoesNotExist:[219,2,1,""],MultipleObjectsReturned:[219,2,1,""],apply_turn_conditions:[219,3,1,""],at_before_move:[219,3,1,""],at_object_creation:[219,3,1,""],at_turn_start:[219,3,1,""],at_update:[219,3,1,""],path:[219,4,1,""],typename:[219,4,1,""]},"evennia.contrib.turnbattle.tb_items.TBItemsCharacterTest":{DoesNotExist:[219,2,1,""],MultipleObjectsReturned:[219,2,1,""],at_object_creation:[219,3,1,""],path:[219,4,1,""],typename:[219,4,1,""]},"evennia.contrib.turnbattle.tb_items.TBItemsTurnHandler":{DoesNotExist:[219,2,1,""],MultipleObjectsReturned:[219,2,1,""],at_repeat:[219,3,1,""],at_script_creation:[219,3,1,""],at_stop:[219,3,1,""],initialize_for_combat:[219,3,1,""],join_fight:[219,3,1,""],next_turn:[219,3,1,""],path:[219,4,1,""],start_turn:[219,3,1,""],turn_end_check:[219,3,1,""],typename:[219,4,1,""]},"evennia.contrib.turnbattle.tb_magic":{ACTIONS_PER_TURN:[220,6,1,""],BattleCmdSet:[220,1,1,""],CmdAttack:[220,1,1,""],CmdCast:[220,1,1,""],CmdCombatHelp:[220,1,1,""],CmdDisengage:[220,1,1,""],CmdFight:[220,1,1,""],CmdLearnSpell:[220,1,1,""],CmdPass:[220,1,1,""],CmdRest:[220,1,1,""],CmdStatus:[220,1,1,""],TBMagicCharacter:[220,1,1,""],TBMagicTurnHandler:[220,1,1,""],apply_damage:[220,5,1,""],at_defeat:[220,5,1,""],combat_cleanup:[220,5,1,""],get_attack:[220,5,1,""],get_damage:[220,5,1,""],get_defense:[220,5,1,""],is_in_combat:[220,5,1,""],is_turn:[220,5,1,""],resolve_attack:[220,5,1,""],roll_init:[220,5,1,""],spell_attack:[220,5,1,""],spell_conjure:[220,5,1,""],spell_healing:[220,5,1,""],spend_action:[220,5,1,""]},"evennia.contrib.turnbattle.tb_magic.BattleCmdSet":{at_cmdset_creation:[220,3,1,""],key:[220,4,1,""],path:[220,4,1,""]},"evennia.contrib.turnbattle.tb_magic.CmdAttack":{aliases:[220,4,1,""],func:[220,3,1,""],help_category:[220,4,1,""],key:[220,4,1,""],lock_storage:[220,4,1,""],search_index_entry:[220,4,1,""]},"evennia.contrib.turnbattle.tb_magic.CmdCast":{aliases:[220,4,1,""],func:[220,3,1,""],help_category:[220,4,1,""],key:[220,4,1,""],lock_storage:[220,4,1,""],search_index_entry:[220,4,1,""]},"evennia.contrib.turnbattle.tb_magic.CmdCombatHelp":{aliases:[220,4,1,""],func:[220,3,1,""],help_category:[220,4,1,""],key:[220,4,1,""],lock_storage:[220,4,1,""],search_index_entry:[220,4,1,""]},"evennia.contrib.turnbattle.tb_magic.CmdDisengage":{aliases:[220,4,1,""],func:[220,3,1,""],help_category:[220,4,1,""],key:[220,4,1,""],lock_storage:[220,4,1,""],search_index_entry:[220,4,1,""]},"evennia.contrib.turnbattle.tb_magic.CmdFight":{aliases:[220,4,1,""],func:[220,3,1,""],help_category:[220,4,1,""],key:[220,4,1,""],lock_storage:[220,4,1,""],search_index_entry:[220,4,1,""]},"evennia.contrib.turnbattle.tb_magic.CmdLearnSpell":{aliases:[220,4,1,""],func:[220,3,1,""],help_category:[220,4,1,""],key:[220,4,1,""],lock_storage:[220,4,1,""],search_index_entry:[220,4,1,""]},"evennia.contrib.turnbattle.tb_magic.CmdPass":{aliases:[220,4,1,""],func:[220,3,1,""],help_category:[220,4,1,""],key:[220,4,1,""],lock_storage:[220,4,1,""],search_index_entry:[220,4,1,""]},"evennia.contrib.turnbattle.tb_magic.CmdRest":{aliases:[220,4,1,""],func:[220,3,1,""],help_category:[220,4,1,""],key:[220,4,1,""],lock_storage:[220,4,1,""],search_index_entry:[220,4,1,""]},"evennia.contrib.turnbattle.tb_magic.CmdStatus":{aliases:[220,4,1,""],func:[220,3,1,""],help_category:[220,4,1,""],key:[220,4,1,""],lock_storage:[220,4,1,""],search_index_entry:[220,4,1,""]},"evennia.contrib.turnbattle.tb_magic.TBMagicCharacter":{DoesNotExist:[220,2,1,""],MultipleObjectsReturned:[220,2,1,""],at_before_move:[220,3,1,""],at_object_creation:[220,3,1,""],path:[220,4,1,""],typename:[220,4,1,""]},"evennia.contrib.turnbattle.tb_magic.TBMagicTurnHandler":{DoesNotExist:[220,2,1,""],MultipleObjectsReturned:[220,2,1,""],at_repeat:[220,3,1,""],at_script_creation:[220,3,1,""],at_stop:[220,3,1,""],initialize_for_combat:[220,3,1,""],join_fight:[220,3,1,""],next_turn:[220,3,1,""],path:[220,4,1,""],start_turn:[220,3,1,""],turn_end_check:[220,3,1,""],typename:[220,4,1,""]},"evennia.contrib.turnbattle.tb_range":{ACTIONS_PER_TURN:[221,6,1,""],BattleCmdSet:[221,1,1,""],CmdApproach:[221,1,1,""],CmdAttack:[221,1,1,""],CmdCombatHelp:[221,1,1,""],CmdDisengage:[221,1,1,""],CmdFight:[221,1,1,""],CmdPass:[221,1,1,""],CmdRest:[221,1,1,""],CmdShoot:[221,1,1,""],CmdStatus:[221,1,1,""],CmdWithdraw:[221,1,1,""],TBRangeCharacter:[221,1,1,""],TBRangeObject:[221,1,1,""],TBRangeTurnHandler:[221,1,1,""],apply_damage:[221,5,1,""],approach:[221,5,1,""],at_defeat:[221,5,1,""],combat_cleanup:[221,5,1,""],combat_status_message:[221,5,1,""],distance_inc:[221,5,1,""],get_attack:[221,5,1,""],get_damage:[221,5,1,""],get_defense:[221,5,1,""],get_range:[221,5,1,""],is_in_combat:[221,5,1,""],is_turn:[221,5,1,""],resolve_attack:[221,5,1,""],roll_init:[221,5,1,""],spend_action:[221,5,1,""],withdraw:[221,5,1,""]},"evennia.contrib.turnbattle.tb_range.BattleCmdSet":{at_cmdset_creation:[221,3,1,""],key:[221,4,1,""],path:[221,4,1,""]},"evennia.contrib.turnbattle.tb_range.CmdApproach":{aliases:[221,4,1,""],func:[221,3,1,""],help_category:[221,4,1,""],key:[221,4,1,""],lock_storage:[221,4,1,""],search_index_entry:[221,4,1,""]},"evennia.contrib.turnbattle.tb_range.CmdAttack":{aliases:[221,4,1,""],func:[221,3,1,""],help_category:[221,4,1,""],key:[221,4,1,""],lock_storage:[221,4,1,""],search_index_entry:[221,4,1,""]},"evennia.contrib.turnbattle.tb_range.CmdCombatHelp":{aliases:[221,4,1,""],func:[221,3,1,""],help_category:[221,4,1,""],key:[221,4,1,""],lock_storage:[221,4,1,""],search_index_entry:[221,4,1,""]},"evennia.contrib.turnbattle.tb_range.CmdDisengage":{aliases:[221,4,1,""],func:[221,3,1,""],help_category:[221,4,1,""],key:[221,4,1,""],lock_storage:[221,4,1,""],search_index_entry:[221,4,1,""]},"evennia.contrib.turnbattle.tb_range.CmdFight":{aliases:[221,4,1,""],func:[221,3,1,""],help_category:[221,4,1,""],key:[221,4,1,""],lock_storage:[221,4,1,""],search_index_entry:[221,4,1,""]},"evennia.contrib.turnbattle.tb_range.CmdPass":{aliases:[221,4,1,""],func:[221,3,1,""],help_category:[221,4,1,""],key:[221,4,1,""],lock_storage:[221,4,1,""],search_index_entry:[221,4,1,""]},"evennia.contrib.turnbattle.tb_range.CmdRest":{aliases:[221,4,1,""],func:[221,3,1,""],help_category:[221,4,1,""],key:[221,4,1,""],lock_storage:[221,4,1,""],search_index_entry:[221,4,1,""]},"evennia.contrib.turnbattle.tb_range.CmdShoot":{aliases:[221,4,1,""],func:[221,3,1,""],help_category:[221,4,1,""],key:[221,4,1,""],lock_storage:[221,4,1,""],search_index_entry:[221,4,1,""]},"evennia.contrib.turnbattle.tb_range.CmdStatus":{aliases:[221,4,1,""],func:[221,3,1,""],help_category:[221,4,1,""],key:[221,4,1,""],lock_storage:[221,4,1,""],search_index_entry:[221,4,1,""]},"evennia.contrib.turnbattle.tb_range.CmdWithdraw":{aliases:[221,4,1,""],func:[221,3,1,""],help_category:[221,4,1,""],key:[221,4,1,""],lock_storage:[221,4,1,""],search_index_entry:[221,4,1,""]},"evennia.contrib.turnbattle.tb_range.TBRangeCharacter":{DoesNotExist:[221,2,1,""],MultipleObjectsReturned:[221,2,1,""],at_before_move:[221,3,1,""],at_object_creation:[221,3,1,""],path:[221,4,1,""],typename:[221,4,1,""]},"evennia.contrib.turnbattle.tb_range.TBRangeObject":{DoesNotExist:[221,2,1,""],MultipleObjectsReturned:[221,2,1,""],at_before_drop:[221,3,1,""],at_before_get:[221,3,1,""],at_before_give:[221,3,1,""],at_drop:[221,3,1,""],at_get:[221,3,1,""],at_give:[221,3,1,""],path:[221,4,1,""],typename:[221,4,1,""]},"evennia.contrib.turnbattle.tb_range.TBRangeTurnHandler":{DoesNotExist:[221,2,1,""],MultipleObjectsReturned:[221,2,1,""],at_repeat:[221,3,1,""],at_script_creation:[221,3,1,""],at_stop:[221,3,1,""],init_range:[221,3,1,""],initialize_for_combat:[221,3,1,""],join_fight:[221,3,1,""],join_rangefield:[221,3,1,""],next_turn:[221,3,1,""],path:[221,4,1,""],start_turn:[221,3,1,""],turn_end_check:[221,3,1,""],typename:[221,4,1,""]},"evennia.contrib.tutorial_examples":{bodyfunctions:[223,0,0,"-"],red_button:[226,0,0,"-"],tests:[228,0,0,"-"]},"evennia.contrib.tutorial_examples.bodyfunctions":{BodyFunctions:[223,1,1,""]},"evennia.contrib.tutorial_examples.bodyfunctions.BodyFunctions":{DoesNotExist:[223,2,1,""],MultipleObjectsReturned:[223,2,1,""],at_repeat:[223,3,1,""],at_script_creation:[223,3,1,""],path:[223,4,1,""],send_random_message:[223,3,1,""],typename:[223,4,1,""]},"evennia.contrib.tutorial_examples.red_button":{BlindCmdSet:[226,1,1,""],CmdBlindHelp:[226,1,1,""],CmdBlindLook:[226,1,1,""],CmdCloseLid:[226,1,1,""],CmdNudge:[226,1,1,""],CmdOpenLid:[226,1,1,""],CmdPushLidClosed:[226,1,1,""],CmdPushLidOpen:[226,1,1,""],CmdSmashGlass:[226,1,1,""],LidClosedCmdSet:[226,1,1,""],LidOpenCmdSet:[226,1,1,""],RedButton:[226,1,1,""]},"evennia.contrib.tutorial_examples.red_button.BlindCmdSet":{at_cmdset_creation:[226,3,1,""],key:[226,4,1,""],mergetype:[226,4,1,""],no_exits:[226,4,1,""],no_objs:[226,4,1,""],path:[226,4,1,""]},"evennia.contrib.tutorial_examples.red_button.CmdBlindHelp":{aliases:[226,4,1,""],func:[226,3,1,""],help_category:[226,4,1,""],key:[226,4,1,""],lock_storage:[226,4,1,""],locks:[226,4,1,""],search_index_entry:[226,4,1,""]},"evennia.contrib.tutorial_examples.red_button.CmdBlindLook":{aliases:[226,4,1,""],func:[226,3,1,""],help_category:[226,4,1,""],key:[226,4,1,""],lock_storage:[226,4,1,""],locks:[226,4,1,""],search_index_entry:[226,4,1,""]},"evennia.contrib.tutorial_examples.red_button.CmdCloseLid":{aliases:[226,4,1,""],func:[226,3,1,""],help_category:[226,4,1,""],key:[226,4,1,""],lock_storage:[226,4,1,""],locks:[226,4,1,""],search_index_entry:[226,4,1,""]},"evennia.contrib.tutorial_examples.red_button.CmdNudge":{aliases:[226,4,1,""],func:[226,3,1,""],help_category:[226,4,1,""],key:[226,4,1,""],lock_storage:[226,4,1,""],locks:[226,4,1,""],search_index_entry:[226,4,1,""]},"evennia.contrib.tutorial_examples.red_button.CmdOpenLid":{aliases:[226,4,1,""],func:[226,3,1,""],help_category:[226,4,1,""],key:[226,4,1,""],lock_storage:[226,4,1,""],locks:[226,4,1,""],search_index_entry:[226,4,1,""]},"evennia.contrib.tutorial_examples.red_button.CmdPushLidClosed":{aliases:[226,4,1,""],func:[226,3,1,""],help_category:[226,4,1,""],key:[226,4,1,""],lock_storage:[226,4,1,""],locks:[226,4,1,""],search_index_entry:[226,4,1,""]},"evennia.contrib.tutorial_examples.red_button.CmdPushLidOpen":{aliases:[226,4,1,""],func:[226,3,1,""],help_category:[226,4,1,""],key:[226,4,1,""],lock_storage:[226,4,1,""],locks:[226,4,1,""],search_index_entry:[226,4,1,""]},"evennia.contrib.tutorial_examples.red_button.CmdSmashGlass":{aliases:[226,4,1,""],func:[226,3,1,""],help_category:[226,4,1,""],key:[226,4,1,""],lock_storage:[226,4,1,""],locks:[226,4,1,""],search_index_entry:[226,4,1,""]},"evennia.contrib.tutorial_examples.red_button.LidClosedCmdSet":{at_cmdset_creation:[226,3,1,""],key:[226,4,1,""],path:[226,4,1,""]},"evennia.contrib.tutorial_examples.red_button.LidOpenCmdSet":{at_cmdset_creation:[226,3,1,""],key:[226,4,1,""],path:[226,4,1,""]},"evennia.contrib.tutorial_examples.red_button.RedButton":{DoesNotExist:[226,2,1,""],MultipleObjectsReturned:[226,2,1,""],at_object_creation:[226,3,1,""],auto_close_msg:[226,4,1,""],blind_target:[226,3,1,""],blink_msgs:[226,4,1,""],break_lamp:[226,3,1,""],desc_add_lamp_broken:[226,4,1,""],desc_closed_lid:[226,4,1,""],desc_open_lid:[226,4,1,""],lamp_breaks_msg:[226,4,1,""],path:[226,4,1,""],to_closed_state:[226,3,1,""],to_open_state:[226,3,1,""],typename:[226,4,1,""]},"evennia.contrib.tutorial_examples.tests":{TestBodyFunctions:[228,1,1,""]},"evennia.contrib.tutorial_examples.tests.TestBodyFunctions":{script_typeclass:[228,4,1,""],setUp:[228,3,1,""],tearDown:[228,3,1,""],test_at_repeat:[228,3,1,""],test_send_random_message:[228,3,1,""]},"evennia.contrib.tutorial_world":{intro_menu:[230,0,0,"-"],mob:[231,0,0,"-"],objects:[232,0,0,"-"],rooms:[233,0,0,"-"]},"evennia.contrib.tutorial_world.intro_menu":{DemoCommandSetComms:[230,1,1,""],DemoCommandSetHelp:[230,1,1,""],DemoCommandSetRoom:[230,1,1,""],TutorialEvMenu:[230,1,1,""],do_nothing:[230,5,1,""],goto_cleanup_cmdsets:[230,5,1,""],goto_command_demo_comms:[230,5,1,""],goto_command_demo_help:[230,5,1,""],goto_command_demo_room:[230,5,1,""],init_menu:[230,5,1,""],send_testing_tagged:[230,5,1,""]},"evennia.contrib.tutorial_world.intro_menu.DemoCommandSetComms":{at_cmdset_creation:[230,3,1,""],key:[230,4,1,""],no_exits:[230,4,1,""],no_objs:[230,4,1,""],path:[230,4,1,""],priority:[230,4,1,""]},"evennia.contrib.tutorial_world.intro_menu.DemoCommandSetHelp":{at_cmdset_creation:[230,3,1,""],key:[230,4,1,""],path:[230,4,1,""],priority:[230,4,1,""]},"evennia.contrib.tutorial_world.intro_menu.DemoCommandSetRoom":{at_cmdset_creation:[230,3,1,""],key:[230,4,1,""],no_exits:[230,4,1,""],no_objs:[230,4,1,""],path:[230,4,1,""],priority:[230,4,1,""]},"evennia.contrib.tutorial_world.intro_menu.TutorialEvMenu":{close_menu:[230,3,1,""],options_formatter:[230,3,1,""]},"evennia.contrib.tutorial_world.mob":{CmdMobOnOff:[231,1,1,""],Mob:[231,1,1,""],MobCmdSet:[231,1,1,""]},"evennia.contrib.tutorial_world.mob.CmdMobOnOff":{aliases:[231,4,1,""],func:[231,3,1,""],help_category:[231,4,1,""],key:[231,4,1,""],lock_storage:[231,4,1,""],locks:[231,4,1,""],search_index_entry:[231,4,1,""]},"evennia.contrib.tutorial_world.mob.Mob":{DoesNotExist:[231,2,1,""],MultipleObjectsReturned:[231,2,1,""],at_hit:[231,3,1,""],at_init:[231,3,1,""],at_new_arrival:[231,3,1,""],at_object_creation:[231,3,1,""],do_attack:[231,3,1,""],do_hunting:[231,3,1,""],do_patrol:[231,3,1,""],path:[231,4,1,""],set_alive:[231,3,1,""],set_dead:[231,3,1,""],start_attacking:[231,3,1,""],start_hunting:[231,3,1,""],start_idle:[231,3,1,""],start_patrolling:[231,3,1,""],typename:[231,4,1,""]},"evennia.contrib.tutorial_world.mob.MobCmdSet":{at_cmdset_creation:[231,3,1,""],path:[231,4,1,""]},"evennia.contrib.tutorial_world.objects":{CmdAttack:[232,1,1,""],CmdClimb:[232,1,1,""],CmdGetWeapon:[232,1,1,""],CmdLight:[232,1,1,""],CmdPressButton:[232,1,1,""],CmdRead:[232,1,1,""],CmdSetClimbable:[232,1,1,""],CmdSetCrumblingWall:[232,1,1,""],CmdSetLight:[232,1,1,""],CmdSetReadable:[232,1,1,""],CmdSetWeapon:[232,1,1,""],CmdSetWeaponRack:[232,1,1,""],CmdShiftRoot:[232,1,1,""],CrumblingWall:[232,1,1,""],LightSource:[232,1,1,""],Obelisk:[232,1,1,""],TutorialClimbable:[232,1,1,""],TutorialObject:[232,1,1,""],TutorialReadable:[232,1,1,""],TutorialWeapon:[232,1,1,""],TutorialWeaponRack:[232,1,1,""]},"evennia.contrib.tutorial_world.objects.CmdAttack":{aliases:[232,4,1,""],func:[232,3,1,""],help_category:[232,4,1,""],key:[232,4,1,""],lock_storage:[232,4,1,""],locks:[232,4,1,""],search_index_entry:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.CmdClimb":{aliases:[232,4,1,""],func:[232,3,1,""],help_category:[232,4,1,""],key:[232,4,1,""],lock_storage:[232,4,1,""],locks:[232,4,1,""],search_index_entry:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.CmdGetWeapon":{aliases:[232,4,1,""],func:[232,3,1,""],help_category:[232,4,1,""],key:[232,4,1,""],lock_storage:[232,4,1,""],locks:[232,4,1,""],search_index_entry:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.CmdLight":{aliases:[232,4,1,""],func:[232,3,1,""],help_category:[232,4,1,""],key:[232,4,1,""],lock_storage:[232,4,1,""],locks:[232,4,1,""],search_index_entry:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.CmdPressButton":{aliases:[232,4,1,""],func:[232,3,1,""],help_category:[232,4,1,""],key:[232,4,1,""],lock_storage:[232,4,1,""],locks:[232,4,1,""],search_index_entry:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.CmdRead":{aliases:[232,4,1,""],func:[232,3,1,""],help_category:[232,4,1,""],key:[232,4,1,""],lock_storage:[232,4,1,""],locks:[232,4,1,""],search_index_entry:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.CmdSetClimbable":{at_cmdset_creation:[232,3,1,""],path:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.CmdSetCrumblingWall":{at_cmdset_creation:[232,3,1,""],key:[232,4,1,""],path:[232,4,1,""],priority:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.CmdSetLight":{at_cmdset_creation:[232,3,1,""],key:[232,4,1,""],path:[232,4,1,""],priority:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.CmdSetReadable":{at_cmdset_creation:[232,3,1,""],path:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.CmdSetWeapon":{at_cmdset_creation:[232,3,1,""],path:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.CmdSetWeaponRack":{at_cmdset_creation:[232,3,1,""],key:[232,4,1,""],path:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.CmdShiftRoot":{aliases:[232,4,1,""],func:[232,3,1,""],help_category:[232,4,1,""],key:[232,4,1,""],lock_storage:[232,4,1,""],locks:[232,4,1,""],parse:[232,3,1,""],search_index_entry:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.CrumblingWall":{DoesNotExist:[232,2,1,""],MultipleObjectsReturned:[232,2,1,""],at_after_traverse:[232,3,1,""],at_failed_traverse:[232,3,1,""],at_init:[232,3,1,""],at_object_creation:[232,3,1,""],open_wall:[232,3,1,""],path:[232,4,1,""],reset:[232,3,1,""],return_appearance:[232,3,1,""],typename:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.LightSource":{DoesNotExist:[232,2,1,""],MultipleObjectsReturned:[232,2,1,""],at_init:[232,3,1,""],at_object_creation:[232,3,1,""],light:[232,3,1,""],path:[232,4,1,""],typename:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.Obelisk":{DoesNotExist:[232,2,1,""],MultipleObjectsReturned:[232,2,1,""],at_object_creation:[232,3,1,""],path:[232,4,1,""],return_appearance:[232,3,1,""],typename:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.TutorialClimbable":{DoesNotExist:[232,2,1,""],MultipleObjectsReturned:[232,2,1,""],at_object_creation:[232,3,1,""],path:[232,4,1,""],typename:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.TutorialObject":{DoesNotExist:[232,2,1,""],MultipleObjectsReturned:[232,2,1,""],at_object_creation:[232,3,1,""],path:[232,4,1,""],reset:[232,3,1,""],typename:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.TutorialReadable":{DoesNotExist:[232,2,1,""],MultipleObjectsReturned:[232,2,1,""],at_object_creation:[232,3,1,""],path:[232,4,1,""],typename:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.TutorialWeapon":{DoesNotExist:[232,2,1,""],MultipleObjectsReturned:[232,2,1,""],at_object_creation:[232,3,1,""],path:[232,4,1,""],reset:[232,3,1,""],typename:[232,4,1,""]},"evennia.contrib.tutorial_world.objects.TutorialWeaponRack":{DoesNotExist:[232,2,1,""],MultipleObjectsReturned:[232,2,1,""],at_object_creation:[232,3,1,""],path:[232,4,1,""],produce_weapon:[232,3,1,""],typename:[232,4,1,""]},"evennia.contrib.tutorial_world.rooms":{BridgeCmdSet:[233,1,1,""],BridgeRoom:[233,1,1,""],CmdBridgeHelp:[233,1,1,""],CmdDarkHelp:[233,1,1,""],CmdDarkNoMatch:[233,1,1,""],CmdEast:[233,1,1,""],CmdEvenniaIntro:[233,1,1,""],CmdLookBridge:[233,1,1,""],CmdLookDark:[233,1,1,""],CmdSetEvenniaIntro:[233,1,1,""],CmdTutorial:[233,1,1,""],CmdTutorialGiveUp:[233,1,1,""],CmdTutorialLook:[233,1,1,""],CmdTutorialSetDetail:[233,1,1,""],CmdWest:[233,1,1,""],DarkCmdSet:[233,1,1,""],DarkRoom:[233,1,1,""],IntroRoom:[233,1,1,""],OutroRoom:[233,1,1,""],TeleportRoom:[233,1,1,""],TutorialRoom:[233,1,1,""],TutorialRoomCmdSet:[233,1,1,""],WeatherRoom:[233,1,1,""]},"evennia.contrib.tutorial_world.rooms.BridgeCmdSet":{at_cmdset_creation:[233,3,1,""],key:[233,4,1,""],path:[233,4,1,""],priority:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.BridgeRoom":{DoesNotExist:[233,2,1,""],MultipleObjectsReturned:[233,2,1,""],at_object_creation:[233,3,1,""],at_object_leave:[233,3,1,""],at_object_receive:[233,3,1,""],path:[233,4,1,""],typename:[233,4,1,""],update_weather:[233,3,1,""]},"evennia.contrib.tutorial_world.rooms.CmdBridgeHelp":{aliases:[233,4,1,""],func:[233,3,1,""],help_category:[233,4,1,""],key:[233,4,1,""],lock_storage:[233,4,1,""],locks:[233,4,1,""],search_index_entry:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.CmdDarkHelp":{aliases:[233,4,1,""],func:[233,3,1,""],help_category:[233,4,1,""],key:[233,4,1,""],lock_storage:[233,4,1,""],locks:[233,4,1,""],search_index_entry:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.CmdDarkNoMatch":{aliases:[233,4,1,""],func:[233,3,1,""],help_category:[233,4,1,""],key:[233,4,1,""],lock_storage:[233,4,1,""],locks:[233,4,1,""],search_index_entry:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.CmdEast":{aliases:[233,4,1,""],func:[233,3,1,""],help_category:[233,4,1,""],key:[233,4,1,""],lock_storage:[233,4,1,""],locks:[233,4,1,""],search_index_entry:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.CmdEvenniaIntro":{aliases:[233,4,1,""],func:[233,3,1,""],help_category:[233,4,1,""],key:[233,4,1,""],lock_storage:[233,4,1,""],search_index_entry:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.CmdLookBridge":{aliases:[233,4,1,""],func:[233,3,1,""],help_category:[233,4,1,""],key:[233,4,1,""],lock_storage:[233,4,1,""],locks:[233,4,1,""],search_index_entry:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.CmdLookDark":{aliases:[233,4,1,""],func:[233,3,1,""],help_category:[233,4,1,""],key:[233,4,1,""],lock_storage:[233,4,1,""],locks:[233,4,1,""],search_index_entry:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.CmdSetEvenniaIntro":{at_cmdset_creation:[233,3,1,""],key:[233,4,1,""],path:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.CmdTutorial":{aliases:[233,4,1,""],func:[233,3,1,""],help_category:[233,4,1,""],key:[233,4,1,""],lock_storage:[233,4,1,""],locks:[233,4,1,""],search_index_entry:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.CmdTutorialGiveUp":{aliases:[233,4,1,""],func:[233,3,1,""],help_category:[233,4,1,""],key:[233,4,1,""],lock_storage:[233,4,1,""],search_index_entry:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.CmdTutorialLook":{aliases:[233,4,1,""],func:[233,3,1,""],help_category:[233,4,1,""],key:[233,4,1,""],lock_storage:[233,4,1,""],search_index_entry:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.CmdTutorialSetDetail":{aliases:[233,4,1,""],func:[233,3,1,""],help_category:[233,4,1,""],key:[233,4,1,""],lock_storage:[233,4,1,""],locks:[233,4,1,""],search_index_entry:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.CmdWest":{aliases:[233,4,1,""],func:[233,3,1,""],help_category:[233,4,1,""],key:[233,4,1,""],lock_storage:[233,4,1,""],locks:[233,4,1,""],search_index_entry:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.DarkCmdSet":{at_cmdset_creation:[233,3,1,""],key:[233,4,1,""],mergetype:[233,4,1,""],path:[233,4,1,""],priority:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.DarkRoom":{DoesNotExist:[233,2,1,""],MultipleObjectsReturned:[233,2,1,""],at_init:[233,3,1,""],at_object_creation:[233,3,1,""],at_object_leave:[233,3,1,""],at_object_receive:[233,3,1,""],check_light_state:[233,3,1,""],path:[233,4,1,""],typename:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.IntroRoom":{DoesNotExist:[233,2,1,""],MultipleObjectsReturned:[233,2,1,""],at_object_creation:[233,3,1,""],at_object_receive:[233,3,1,""],path:[233,4,1,""],typename:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.OutroRoom":{DoesNotExist:[233,2,1,""],MultipleObjectsReturned:[233,2,1,""],at_object_creation:[233,3,1,""],at_object_leave:[233,3,1,""],at_object_receive:[233,3,1,""],path:[233,4,1,""],typename:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.TeleportRoom":{DoesNotExist:[233,2,1,""],MultipleObjectsReturned:[233,2,1,""],at_object_creation:[233,3,1,""],at_object_receive:[233,3,1,""],path:[233,4,1,""],typename:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.TutorialRoom":{DoesNotExist:[233,2,1,""],MultipleObjectsReturned:[233,2,1,""],at_object_creation:[233,3,1,""],at_object_receive:[233,3,1,""],path:[233,4,1,""],return_detail:[233,3,1,""],set_detail:[233,3,1,""],typename:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.TutorialRoomCmdSet":{at_cmdset_creation:[233,3,1,""],key:[233,4,1,""],path:[233,4,1,""],priority:[233,4,1,""]},"evennia.contrib.tutorial_world.rooms.WeatherRoom":{DoesNotExist:[233,2,1,""],MultipleObjectsReturned:[233,2,1,""],at_object_creation:[233,3,1,""],path:[233,4,1,""],typename:[233,4,1,""],update_weather:[233,3,1,""]},"evennia.contrib.unixcommand":{HelpAction:[234,1,1,""],ParseError:[234,2,1,""],UnixCommand:[234,1,1,""],UnixCommandParser:[234,1,1,""]},"evennia.contrib.unixcommand.UnixCommand":{__init__:[234,3,1,""],aliases:[234,4,1,""],func:[234,3,1,""],get_help:[234,3,1,""],help_category:[234,4,1,""],init_parser:[234,3,1,""],key:[234,4,1,""],lock_storage:[234,4,1,""],parse:[234,3,1,""],search_index_entry:[234,4,1,""]},"evennia.contrib.unixcommand.UnixCommandParser":{__init__:[234,3,1,""],format_help:[234,3,1,""],format_usage:[234,3,1,""],print_help:[234,3,1,""],print_usage:[234,3,1,""]},"evennia.contrib.wilderness":{WildernessExit:[235,1,1,""],WildernessMapProvider:[235,1,1,""],WildernessRoom:[235,1,1,""],WildernessScript:[235,1,1,""],create_wilderness:[235,5,1,""],enter_wilderness:[235,5,1,""],get_new_coordinates:[235,5,1,""]},"evennia.contrib.wilderness.WildernessExit":{DoesNotExist:[235,2,1,""],MultipleObjectsReturned:[235,2,1,""],at_traverse:[235,3,1,""],at_traverse_coordinates:[235,3,1,""],mapprovider:[235,3,1,""],path:[235,4,1,""],typename:[235,4,1,""],wilderness:[235,3,1,""]},"evennia.contrib.wilderness.WildernessMapProvider":{at_prepare_room:[235,3,1,""],exit_typeclass:[235,4,1,""],get_location_name:[235,3,1,""],is_valid_coordinates:[235,3,1,""],room_typeclass:[235,4,1,""]},"evennia.contrib.wilderness.WildernessRoom":{DoesNotExist:[235,2,1,""],MultipleObjectsReturned:[235,2,1,""],at_object_leave:[235,3,1,""],at_object_receive:[235,3,1,""],coordinates:[235,3,1,""],get_display_name:[235,3,1,""],location_name:[235,3,1,""],path:[235,4,1,""],set_active_coordinates:[235,3,1,""],typename:[235,4,1,""],wilderness:[235,3,1,""]},"evennia.contrib.wilderness.WildernessScript":{DoesNotExist:[235,2,1,""],MultipleObjectsReturned:[235,2,1,""],at_after_object_leave:[235,3,1,""],at_script_creation:[235,3,1,""],at_start:[235,3,1,""],get_obj_coordinates:[235,3,1,""],get_objs_at_coordinates:[235,3,1,""],is_valid_coordinates:[235,3,1,""],itemcoordinates:[235,3,1,""],mapprovider:[235,3,1,""],move_obj:[235,3,1,""],path:[235,4,1,""],typename:[235,4,1,""]},"evennia.help":{manager:[238,0,0,"-"],models:[239,0,0,"-"]},"evennia.help.manager":{HelpEntryManager:[238,1,1,""]},"evennia.help.manager.HelpEntryManager":{all_to_category:[238,3,1,""],find_apropos:[238,3,1,""],find_topicmatch:[238,3,1,""],find_topics_with_category:[238,3,1,""],find_topicsuggestions:[238,3,1,""],get_all_categories:[238,3,1,""],get_all_topics:[238,3,1,""],search_help:[238,3,1,""]},"evennia.help.models":{HelpEntry:[239,1,1,""]},"evennia.help.models.HelpEntry":{DoesNotExist:[239,2,1,""],MultipleObjectsReturned:[239,2,1,""],access:[239,3,1,""],aliases:[239,4,1,""],date_created:[239,3,1,""],db_date_created:[239,4,1,""],db_entrytext:[239,4,1,""],db_help_category:[239,4,1,""],db_key:[239,4,1,""],db_lock_storage:[239,4,1,""],db_tags:[239,4,1,""],entrytext:[239,3,1,""],get_absolute_url:[239,3,1,""],get_next_by_db_date_created:[239,3,1,""],get_previous_by_db_date_created:[239,3,1,""],help_category:[239,3,1,""],id:[239,4,1,""],key:[239,3,1,""],lock_storage:[239,3,1,""],locks:[239,4,1,""],objects:[239,4,1,""],path:[239,4,1,""],search_index_entry:[239,3,1,""],tags:[239,4,1,""],typename:[239,4,1,""],web_get_admin_url:[239,3,1,""],web_get_create_url:[239,3,1,""],web_get_delete_url:[239,3,1,""],web_get_detail_url:[239,3,1,""],web_get_update_url:[239,3,1,""]},"evennia.locks":{lockfuncs:[241,0,0,"-"],lockhandler:[242,0,0,"-"]},"evennia.locks.lockfuncs":{"false":[241,5,1,""],"true":[241,5,1,""],all:[241,5,1,""],attr:[241,5,1,""],attr_eq:[241,5,1,""],attr_ge:[241,5,1,""],attr_gt:[241,5,1,""],attr_le:[241,5,1,""],attr_lt:[241,5,1,""],attr_ne:[241,5,1,""],dbref:[241,5,1,""],has_account:[241,5,1,""],holds:[241,5,1,""],id:[241,5,1,""],inside:[241,5,1,""],inside_rec:[241,5,1,""],locattr:[241,5,1,""],none:[241,5,1,""],objattr:[241,5,1,""],objlocattr:[241,5,1,""],objtag:[241,5,1,""],pdbref:[241,5,1,""],perm:[241,5,1,""],perm_above:[241,5,1,""],pid:[241,5,1,""],pperm:[241,5,1,""],pperm_above:[241,5,1,""],self:[241,5,1,""],serversetting:[241,5,1,""],superuser:[241,5,1,""],tag:[241,5,1,""]},"evennia.locks.lockhandler":{LockException:[242,2,1,""],LockHandler:[242,1,1,""]},"evennia.locks.lockhandler.LockHandler":{"delete":[242,3,1,""],__init__:[242,3,1,""],add:[242,3,1,""],all:[242,3,1,""],append:[242,3,1,""],cache_lock_bypass:[242,3,1,""],check:[242,3,1,""],check_lockstring:[242,3,1,""],clear:[242,3,1,""],get:[242,3,1,""],remove:[242,3,1,""],replace:[242,3,1,""],reset:[242,3,1,""],validate:[242,3,1,""]},"evennia.objects":{manager:[245,0,0,"-"],models:[246,0,0,"-"],objects:[247,0,0,"-"]},"evennia.objects.manager":{ObjectManager:[245,1,1,""]},"evennia.objects.models":{ContentsHandler:[246,1,1,""],ObjectDB:[246,1,1,""]},"evennia.objects.models.ContentsHandler":{__init__:[246,3,1,""],add:[246,3,1,""],clear:[246,3,1,""],get:[246,3,1,""],init:[246,3,1,""],load:[246,3,1,""],remove:[246,3,1,""]},"evennia.objects.models.ObjectDB":{DoesNotExist:[246,2,1,""],MultipleObjectsReturned:[246,2,1,""],account:[246,3,1,""],at_db_location_postsave:[246,3,1,""],cmdset_storage:[246,3,1,""],contents_cache:[246,4,1,""],db_account:[246,4,1,""],db_account_id:[246,4,1,""],db_attributes:[246,4,1,""],db_cmdset_storage:[246,4,1,""],db_destination:[246,4,1,""],db_destination_id:[246,4,1,""],db_home:[246,4,1,""],db_home_id:[246,4,1,""],db_location:[246,4,1,""],db_location_id:[246,4,1,""],db_sessid:[246,4,1,""],db_tags:[246,4,1,""],destination:[246,3,1,""],destinations_set:[246,4,1,""],get_next_by_db_date_created:[246,3,1,""],get_previous_by_db_date_created:[246,3,1,""],hide_from_objects_set:[246,4,1,""],home:[246,3,1,""],homes_set:[246,4,1,""],id:[246,4,1,""],location:[246,3,1,""],locations_set:[246,4,1,""],object_subscription_set:[246,4,1,""],objects:[246,4,1,""],path:[246,4,1,""],receiver_object_set:[246,4,1,""],scriptdb_set:[246,4,1,""],sender_object_set:[246,4,1,""],sessid:[246,3,1,""],typename:[246,4,1,""]},"evennia.objects.objects":{DefaultCharacter:[247,1,1,""],DefaultExit:[247,1,1,""],DefaultObject:[247,1,1,""],DefaultRoom:[247,1,1,""],ExitCommand:[247,1,1,""],ObjectSessionHandler:[247,1,1,""]},"evennia.objects.objects.DefaultCharacter":{DoesNotExist:[247,2,1,""],MultipleObjectsReturned:[247,2,1,""],at_after_move:[247,3,1,""],at_post_puppet:[247,3,1,""],at_post_unpuppet:[247,3,1,""],at_pre_puppet:[247,3,1,""],basetype_setup:[247,3,1,""],connection_time:[247,3,1,""],create:[247,3,1,""],idle_time:[247,3,1,""],lockstring:[247,4,1,""],normalize_name:[247,3,1,""],path:[247,4,1,""],typename:[247,4,1,""],validate_name:[247,3,1,""]},"evennia.objects.objects.DefaultExit":{DoesNotExist:[247,2,1,""],MultipleObjectsReturned:[247,2,1,""],at_cmdset_get:[247,3,1,""],at_failed_traverse:[247,3,1,""],at_init:[247,3,1,""],at_traverse:[247,3,1,""],basetype_setup:[247,3,1,""],create:[247,3,1,""],create_exit_cmdset:[247,3,1,""],exit_command:[247,4,1,""],lockstring:[247,4,1,""],path:[247,4,1,""],priority:[247,4,1,""],typename:[247,4,1,""]},"evennia.objects.objects.DefaultObject":{"delete":[247,3,1,""],DoesNotExist:[247,2,1,""],MultipleObjectsReturned:[247,2,1,""],access:[247,3,1,""],announce_move_from:[247,3,1,""],announce_move_to:[247,3,1,""],at_access:[247,3,1,""],at_after_move:[247,3,1,""],at_after_traverse:[247,3,1,""],at_before_drop:[247,3,1,""],at_before_get:[247,3,1,""],at_before_give:[247,3,1,""],at_before_move:[247,3,1,""],at_before_say:[247,3,1,""],at_cmdset_get:[247,3,1,""],at_desc:[247,3,1,""],at_drop:[247,3,1,""],at_failed_traverse:[247,3,1,""],at_first_save:[247,3,1,""],at_get:[247,3,1,""],at_give:[247,3,1,""],at_init:[247,3,1,""],at_look:[247,3,1,""],at_msg_receive:[247,3,1,""],at_msg_send:[247,3,1,""],at_object_creation:[247,3,1,""],at_object_delete:[247,3,1,""],at_object_leave:[247,3,1,""],at_object_post_copy:[247,3,1,""],at_object_receive:[247,3,1,""],at_post_puppet:[247,3,1,""],at_post_unpuppet:[247,3,1,""],at_pre_puppet:[247,3,1,""],at_pre_unpuppet:[247,3,1,""],at_say:[247,3,1,""],at_server_reload:[247,3,1,""],at_server_shutdown:[247,3,1,""],at_traverse:[247,3,1,""],basetype_posthook_setup:[247,3,1,""],basetype_setup:[247,3,1,""],clear_contents:[247,3,1,""],clear_exits:[247,3,1,""],cmdset:[247,4,1,""],contents:[247,3,1,""],contents_get:[247,3,1,""],contents_set:[247,3,1,""],copy:[247,3,1,""],create:[247,3,1,""],execute_cmd:[247,3,1,""],exits:[247,3,1,""],for_contents:[247,3,1,""],get_display_name:[247,3,1,""],get_numbered_name:[247,3,1,""],has_account:[247,3,1,""],is_connected:[247,3,1,""],is_superuser:[247,3,1,""],lockstring:[247,4,1,""],move_to:[247,3,1,""],msg:[247,3,1,""],msg_contents:[247,3,1,""],nicks:[247,4,1,""],objects:[247,4,1,""],path:[247,4,1,""],return_appearance:[247,3,1,""],scripts:[247,4,1,""],search:[247,3,1,""],search_account:[247,3,1,""],sessions:[247,4,1,""],typename:[247,4,1,""]},"evennia.objects.objects.DefaultRoom":{DoesNotExist:[247,2,1,""],MultipleObjectsReturned:[247,2,1,""],basetype_setup:[247,3,1,""],create:[247,3,1,""],lockstring:[247,4,1,""],path:[247,4,1,""],typename:[247,4,1,""]},"evennia.objects.objects.ExitCommand":{aliases:[247,4,1,""],func:[247,3,1,""],get_extra_info:[247,3,1,""],help_category:[247,4,1,""],key:[247,4,1,""],lock_storage:[247,4,1,""],obj:[247,4,1,""],search_index_entry:[247,4,1,""]},"evennia.objects.objects.ObjectSessionHandler":{__init__:[247,3,1,""],add:[247,3,1,""],all:[247,3,1,""],clear:[247,3,1,""],count:[247,3,1,""],get:[247,3,1,""],remove:[247,3,1,""]},"evennia.prototypes":{menus:[249,0,0,"-"],protfuncs:[250,0,0,"-"],prototypes:[251,0,0,"-"],spawner:[252,0,0,"-"]},"evennia.prototypes.menus":{OLCMenu:[249,1,1,""],node_apply_diff:[249,5,1,""],node_destination:[249,5,1,""],node_examine_entity:[249,5,1,""],node_home:[249,5,1,""],node_index:[249,5,1,""],node_key:[249,5,1,""],node_location:[249,5,1,""],node_prototype_desc:[249,5,1,""],node_prototype_key:[249,5,1,""],node_prototype_save:[249,5,1,""],node_prototype_spawn:[249,5,1,""],node_validate_prototype:[249,5,1,""],start_olc:[249,5,1,""]},"evennia.prototypes.menus.OLCMenu":{display_helptext:[249,3,1,""],helptext_formatter:[249,3,1,""],nodetext_formatter:[249,3,1,""],options_formatter:[249,3,1,""]},"evennia.prototypes.protfuncs":{protfunc_callable_protkey:[250,5,1,""]},"evennia.prototypes.prototypes":{DbPrototype:[251,1,1,""],PermissionError:[251,2,1,""],PrototypeEvMore:[251,1,1,""],ValidationError:[251,2,1,""],check_permission:[251,5,1,""],create_prototype:[251,5,1,""],delete_prototype:[251,5,1,""],format_available_protfuncs:[251,5,1,""],homogenize_prototype:[251,5,1,""],init_spawn_value:[251,5,1,""],list_prototypes:[251,5,1,""],load_module_prototypes:[251,5,1,""],protfunc_parser:[251,5,1,""],prototype_to_str:[251,5,1,""],save_prototype:[251,5,1,""],search_objects_with_prototype:[251,5,1,""],search_prototype:[251,5,1,""],validate_prototype:[251,5,1,""],value_to_obj:[251,5,1,""],value_to_obj_or_any:[251,5,1,""]},"evennia.prototypes.prototypes.DbPrototype":{DoesNotExist:[251,2,1,""],MultipleObjectsReturned:[251,2,1,""],at_script_creation:[251,3,1,""],path:[251,4,1,""],prototype:[251,3,1,""],typename:[251,4,1,""]},"evennia.prototypes.prototypes.PrototypeEvMore":{__init__:[251,3,1,""],init_pages:[251,3,1,""],page_formatter:[251,3,1,""],prototype_paginator:[251,3,1,""]},"evennia.prototypes.spawner":{Unset:[252,1,1,""],batch_create_object:[252,5,1,""],batch_update_objects_with_prototype:[252,5,1,""],flatten_diff:[252,5,1,""],flatten_prototype:[252,5,1,""],format_diff:[252,5,1,""],prototype_diff:[252,5,1,""],prototype_diff_from_object:[252,5,1,""],prototype_from_object:[252,5,1,""],spawn:[252,5,1,""]},"evennia.scripts":{manager:[255,0,0,"-"],models:[256,0,0,"-"],monitorhandler:[257,0,0,"-"],scripthandler:[258,0,0,"-"],scripts:[259,0,0,"-"],taskhandler:[260,0,0,"-"],tickerhandler:[261,0,0,"-"]},"evennia.scripts.manager":{ScriptManager:[255,1,1,""]},"evennia.scripts.models":{ScriptDB:[256,1,1,""]},"evennia.scripts.models.ScriptDB":{DoesNotExist:[256,2,1,""],MultipleObjectsReturned:[256,2,1,""],account:[256,3,1,""],db_account:[256,4,1,""],db_account_id:[256,4,1,""],db_attributes:[256,4,1,""],db_desc:[256,4,1,""],db_interval:[256,4,1,""],db_is_active:[256,4,1,""],db_obj:[256,4,1,""],db_obj_id:[256,4,1,""],db_persistent:[256,4,1,""],db_repeats:[256,4,1,""],db_start_delay:[256,4,1,""],db_tags:[256,4,1,""],desc:[256,3,1,""],get_next_by_db_date_created:[256,3,1,""],get_previous_by_db_date_created:[256,3,1,""],id:[256,4,1,""],interval:[256,3,1,""],is_active:[256,3,1,""],obj:[256,3,1,""],object:[256,3,1,""],objects:[256,4,1,""],path:[256,4,1,""],persistent:[256,3,1,""],receiver_script_set:[256,4,1,""],repeats:[256,3,1,""],sender_script_set:[256,4,1,""],start_delay:[256,3,1,""],typename:[256,4,1,""]},"evennia.scripts.monitorhandler":{MonitorHandler:[257,1,1,""]},"evennia.scripts.monitorhandler.MonitorHandler":{__init__:[257,3,1,""],add:[257,3,1,""],all:[257,3,1,""],at_update:[257,3,1,""],clear:[257,3,1,""],remove:[257,3,1,""],restore:[257,3,1,""],save:[257,3,1,""]},"evennia.scripts.scripthandler":{ScriptHandler:[258,1,1,""]},"evennia.scripts.scripthandler.ScriptHandler":{"delete":[258,3,1,""],__init__:[258,3,1,""],add:[258,3,1,""],all:[258,3,1,""],get:[258,3,1,""],start:[258,3,1,""],stop:[258,3,1,""]},"evennia.scripts.scripts":{DefaultScript:[259,1,1,""],DoNothing:[259,1,1,""],Store:[259,1,1,""]},"evennia.scripts.scripts.DefaultScript":{DoesNotExist:[259,2,1,""],MultipleObjectsReturned:[259,2,1,""],at_pause:[259,3,1,""],at_repeat:[259,3,1,""],at_script_creation:[259,3,1,""],at_script_delete:[259,3,1,""],at_server_reload:[259,3,1,""],at_server_shutdown:[259,3,1,""],at_server_start:[259,3,1,""],at_start:[259,3,1,""],at_stop:[259,3,1,""],create:[259,3,1,""],is_valid:[259,3,1,""],path:[259,4,1,""],typename:[259,4,1,""]},"evennia.scripts.scripts.DoNothing":{DoesNotExist:[259,2,1,""],MultipleObjectsReturned:[259,2,1,""],at_script_creation:[259,3,1,""],path:[259,4,1,""],typename:[259,4,1,""]},"evennia.scripts.scripts.Store":{DoesNotExist:[259,2,1,""],MultipleObjectsReturned:[259,2,1,""],at_script_creation:[259,3,1,""],path:[259,4,1,""],typename:[259,4,1,""]},"evennia.scripts.taskhandler":{TaskHandler:[260,1,1,""],TaskHandlerTask:[260,1,1,""],handle_error:[260,5,1,""]},"evennia.scripts.taskhandler.TaskHandler":{__init__:[260,3,1,""],active:[260,3,1,""],add:[260,3,1,""],call_task:[260,3,1,""],cancel:[260,3,1,""],clean_stale_tasks:[260,3,1,""],clear:[260,3,1,""],create_delays:[260,3,1,""],do_task:[260,3,1,""],exists:[260,3,1,""],get_deferred:[260,3,1,""],load:[260,3,1,""],remove:[260,3,1,""],save:[260,3,1,""]},"evennia.scripts.taskhandler.TaskHandlerTask":{__init__:[260,3,1,""],active:[260,3,1,"id6"],call:[260,3,1,"id3"],called:[260,3,1,""],cancel:[260,3,1,"id5"],do_task:[260,3,1,"id2"],exists:[260,3,1,"id7"],get_deferred:[260,3,1,""],get_id:[260,3,1,"id8"],pause:[260,3,1,"id0"],paused:[260,3,1,""],remove:[260,3,1,"id4"],unpause:[260,3,1,"id1"]},"evennia.scripts.tickerhandler":{Ticker:[261,1,1,""],TickerHandler:[261,1,1,""],TickerPool:[261,1,1,""]},"evennia.scripts.tickerhandler.Ticker":{__init__:[261,3,1,""],add:[261,3,1,""],remove:[261,3,1,""],stop:[261,3,1,""],validate:[261,3,1,""]},"evennia.scripts.tickerhandler.TickerHandler":{__init__:[261,3,1,""],add:[261,3,1,""],all:[261,3,1,""],all_display:[261,3,1,""],clear:[261,3,1,""],remove:[261,3,1,""],restore:[261,3,1,""],save:[261,3,1,""],ticker_pool_class:[261,4,1,""]},"evennia.scripts.tickerhandler.TickerPool":{__init__:[261,3,1,""],add:[261,3,1,""],remove:[261,3,1,""],stop:[261,3,1,""],ticker_class:[261,4,1,""]},"evennia.server":{amp_client:[264,0,0,"-"],connection_wizard:[265,0,0,"-"],deprecations:[266,0,0,"-"],evennia_launcher:[267,0,0,"-"],game_index_client:[268,0,0,"-"],initial_setup:[271,0,0,"-"],inputfuncs:[272,0,0,"-"],manager:[273,0,0,"-"],models:[274,0,0,"-"],portal:[275,0,0,"-"],profiling:[297,0,0,"-"],server:[305,0,0,"-"],serversession:[306,0,0,"-"],session:[307,0,0,"-"],sessionhandler:[308,0,0,"-"],signals:[309,0,0,"-"],throttle:[310,0,0,"-"],validators:[311,0,0,"-"],webserver:[312,0,0,"-"]},"evennia.server.amp_client":{AMPClientFactory:[264,1,1,""],AMPServerClientProtocol:[264,1,1,""]},"evennia.server.amp_client.AMPClientFactory":{__init__:[264,3,1,""],buildProtocol:[264,3,1,""],clientConnectionFailed:[264,3,1,""],clientConnectionLost:[264,3,1,""],factor:[264,4,1,""],initialDelay:[264,4,1,""],maxDelay:[264,4,1,""],noisy:[264,4,1,""],startedConnecting:[264,3,1,""]},"evennia.server.amp_client.AMPServerClientProtocol":{connectionMade:[264,3,1,""],data_to_portal:[264,3,1,""],send_AdminServer2Portal:[264,3,1,""],send_MsgServer2Portal:[264,3,1,""],server_receive_adminportal2server:[264,3,1,""],server_receive_msgportal2server:[264,3,1,""],server_receive_status:[264,3,1,""]},"evennia.server.connection_wizard":{ConnectionWizard:[265,1,1,""],node_game_index_fields:[265,5,1,""],node_game_index_start:[265,5,1,""],node_mssp_start:[265,5,1,""],node_start:[265,5,1,""],node_view_and_apply_settings:[265,5,1,""]},"evennia.server.connection_wizard.ConnectionWizard":{__init__:[265,3,1,""],ask_choice:[265,3,1,""],ask_continue:[265,3,1,""],ask_input:[265,3,1,""],ask_node:[265,3,1,""],ask_yesno:[265,3,1,""],display:[265,3,1,""]},"evennia.server.deprecations":{check_errors:[266,5,1,""],check_warnings:[266,5,1,""]},"evennia.server.evennia_launcher":{AMPLauncherProtocol:[267,1,1,""],MsgLauncher2Portal:[267,1,1,""],MsgStatus:[267,1,1,""],check_database:[267,5,1,""],check_main_evennia_dependencies:[267,5,1,""],collectstatic:[267,5,1,""],create_game_directory:[267,5,1,""],create_secret_key:[267,5,1,""],create_settings_file:[267,5,1,""],create_superuser:[267,5,1,""],del_pid:[267,5,1,""],error_check_python_modules:[267,5,1,""],evennia_version:[267,5,1,""],get_pid:[267,5,1,""],getenv:[267,5,1,""],init_game_directory:[267,5,1,""],kill:[267,5,1,""],list_settings:[267,5,1,""],main:[267,5,1,""],query_info:[267,5,1,""],query_status:[267,5,1,""],reboot_evennia:[267,5,1,""],reload_evennia:[267,5,1,""],run_connect_wizard:[267,5,1,""],run_dummyrunner:[267,5,1,""],run_menu:[267,5,1,""],send_instruction:[267,5,1,""],set_gamedir:[267,5,1,""],show_version_info:[267,5,1,""],start_evennia:[267,5,1,""],start_only_server:[267,5,1,""],start_portal_interactive:[267,5,1,""],start_server_interactive:[267,5,1,""],stop_evennia:[267,5,1,""],stop_server_only:[267,5,1,""],tail_log_files:[267,5,1,""],wait_for_status:[267,5,1,""],wait_for_status_reply:[267,5,1,""]},"evennia.server.evennia_launcher.AMPLauncherProtocol":{__init__:[267,3,1,""],receive_status_from_portal:[267,3,1,""],wait_for_status:[267,3,1,""]},"evennia.server.evennia_launcher.MsgLauncher2Portal":{allErrors:[267,4,1,""],arguments:[267,4,1,""],commandName:[267,4,1,""],errors:[267,4,1,""],key:[267,4,1,""],response:[267,4,1,""],reverseErrors:[267,4,1,""]},"evennia.server.evennia_launcher.MsgStatus":{allErrors:[267,4,1,""],arguments:[267,4,1,""],commandName:[267,4,1,""],errors:[267,4,1,""],key:[267,4,1,""],response:[267,4,1,""],reverseErrors:[267,4,1,""]},"evennia.server.game_index_client":{client:[269,0,0,"-"],service:[270,0,0,"-"]},"evennia.server.game_index_client.client":{EvenniaGameIndexClient:[269,1,1,""],QuietHTTP11ClientFactory:[269,1,1,""],SimpleResponseReceiver:[269,1,1,""],StringProducer:[269,1,1,""]},"evennia.server.game_index_client.client.EvenniaGameIndexClient":{__init__:[269,3,1,""],handle_egd_response:[269,3,1,""],send_game_details:[269,3,1,""]},"evennia.server.game_index_client.client.QuietHTTP11ClientFactory":{noisy:[269,4,1,""]},"evennia.server.game_index_client.client.SimpleResponseReceiver":{__init__:[269,3,1,""],connectionLost:[269,3,1,""],dataReceived:[269,3,1,""]},"evennia.server.game_index_client.client.StringProducer":{__init__:[269,3,1,""],pauseProducing:[269,3,1,""],startProducing:[269,3,1,""],stopProducing:[269,3,1,""]},"evennia.server.game_index_client.service":{EvenniaGameIndexService:[270,1,1,""]},"evennia.server.game_index_client.service.EvenniaGameIndexService":{__init__:[270,3,1,""],name:[270,4,1,""],startService:[270,3,1,""],stopService:[270,3,1,""]},"evennia.server.initial_setup":{at_initial_setup:[271,5,1,""],collectstatic:[271,5,1,""],create_channels:[271,5,1,""],create_objects:[271,5,1,""],get_god_account:[271,5,1,""],handle_setup:[271,5,1,""],reset_server:[271,5,1,""]},"evennia.server.inputfuncs":{"default":[272,5,1,""],bot_data_in:[272,5,1,""],client_options:[272,5,1,""],echo:[272,5,1,""],external_discord_hello:[272,5,1,""],get_client_options:[272,5,1,""],get_inputfuncs:[272,5,1,""],get_value:[272,5,1,""],hello:[272,5,1,""],login:[272,5,1,""],monitor:[272,5,1,""],monitored:[272,5,1,""],msdp_list:[272,5,1,""],msdp_report:[272,5,1,""],msdp_send:[272,5,1,""],msdp_unreport:[272,5,1,""],repeat:[272,5,1,""],supports_set:[272,5,1,""],text:[272,5,1,""],unmonitor:[272,5,1,""],unrepeat:[272,5,1,""],webclient_options:[272,5,1,""]},"evennia.server.manager":{ServerConfigManager:[273,1,1,""]},"evennia.server.manager.ServerConfigManager":{conf:[273,3,1,""]},"evennia.server.models":{ServerConfig:[274,1,1,""]},"evennia.server.models.ServerConfig":{DoesNotExist:[274,2,1,""],MultipleObjectsReturned:[274,2,1,""],db_key:[274,4,1,""],db_value:[274,4,1,""],id:[274,4,1,""],key:[274,3,1,""],objects:[274,4,1,""],path:[274,4,1,""],store:[274,3,1,""],typename:[274,4,1,""],value:[274,3,1,""]},"evennia.server.portal":{amp:[276,0,0,"-"],amp_server:[277,0,0,"-"],grapevine:[278,0,0,"-"],irc:[279,0,0,"-"],mccp:[280,0,0,"-"],mssp:[281,0,0,"-"],mxp:[282,0,0,"-"],naws:[283,0,0,"-"],portal:[284,0,0,"-"],portalsessionhandler:[285,0,0,"-"],rss:[286,0,0,"-"],ssh:[287,0,0,"-"],ssl:[288,0,0,"-"],suppress_ga:[289,0,0,"-"],telnet:[290,0,0,"-"],telnet_oob:[291,0,0,"-"],telnet_ssl:[292,0,0,"-"],tests:[293,0,0,"-"],ttype:[294,0,0,"-"],webclient:[295,0,0,"-"],webclient_ajax:[296,0,0,"-"]},"evennia.server.portal.amp":{AMPMultiConnectionProtocol:[276,1,1,""],AdminPortal2Server:[276,1,1,""],AdminServer2Portal:[276,1,1,""],Compressed:[276,1,1,""],FunctionCall:[276,1,1,""],MsgLauncher2Portal:[276,1,1,""],MsgPortal2Server:[276,1,1,""],MsgServer2Portal:[276,1,1,""],MsgStatus:[276,1,1,""],dumps:[276,5,1,""],loads:[276,5,1,""]},"evennia.server.portal.amp.AMPMultiConnectionProtocol":{__init__:[276,3,1,""],broadcast:[276,3,1,""],connectionLost:[276,3,1,""],connectionMade:[276,3,1,""],dataReceived:[276,3,1,""],data_in:[276,3,1,""],errback:[276,3,1,""],makeConnection:[276,3,1,""],receive_functioncall:[276,3,1,""],send_FunctionCall:[276,3,1,""]},"evennia.server.portal.amp.AdminPortal2Server":{allErrors:[276,4,1,""],arguments:[276,4,1,""],commandName:[276,4,1,""],errors:[276,4,1,""],key:[276,4,1,""],response:[276,4,1,""],reverseErrors:[276,4,1,""]},"evennia.server.portal.amp.AdminServer2Portal":{allErrors:[276,4,1,""],arguments:[276,4,1,""],commandName:[276,4,1,""],errors:[276,4,1,""],key:[276,4,1,""],response:[276,4,1,""],reverseErrors:[276,4,1,""]},"evennia.server.portal.amp.Compressed":{fromBox:[276,3,1,""],fromString:[276,3,1,""],toBox:[276,3,1,""],toString:[276,3,1,""]},"evennia.server.portal.amp.FunctionCall":{allErrors:[276,4,1,""],arguments:[276,4,1,""],commandName:[276,4,1,""],errors:[276,4,1,""],key:[276,4,1,""],response:[276,4,1,""],reverseErrors:[276,4,1,""]},"evennia.server.portal.amp.MsgLauncher2Portal":{allErrors:[276,4,1,""],arguments:[276,4,1,""],commandName:[276,4,1,""],errors:[276,4,1,""],key:[276,4,1,""],response:[276,4,1,""],reverseErrors:[276,4,1,""]},"evennia.server.portal.amp.MsgPortal2Server":{allErrors:[276,4,1,""],arguments:[276,4,1,""],commandName:[276,4,1,""],errors:[276,4,1,""],key:[276,4,1,""],response:[276,4,1,""],reverseErrors:[276,4,1,""]},"evennia.server.portal.amp.MsgServer2Portal":{allErrors:[276,4,1,""],arguments:[276,4,1,""],commandName:[276,4,1,""],errors:[276,4,1,""],key:[276,4,1,""],response:[276,4,1,""],reverseErrors:[276,4,1,""]},"evennia.server.portal.amp.MsgStatus":{allErrors:[276,4,1,""],arguments:[276,4,1,""],commandName:[276,4,1,""],errors:[276,4,1,""],key:[276,4,1,""],response:[276,4,1,""],reverseErrors:[276,4,1,""]},"evennia.server.portal.amp_server":{AMPServerFactory:[277,1,1,""],AMPServerProtocol:[277,1,1,""],getenv:[277,5,1,""]},"evennia.server.portal.amp_server.AMPServerFactory":{__init__:[277,3,1,""],buildProtocol:[277,3,1,""],logPrefix:[277,3,1,""],noisy:[277,4,1,""]},"evennia.server.portal.amp_server.AMPServerProtocol":{connectionLost:[277,3,1,""],data_to_server:[277,3,1,""],get_status:[277,3,1,""],portal_receive_adminserver2portal:[277,3,1,""],portal_receive_launcher2portal:[277,3,1,""],portal_receive_server2portal:[277,3,1,""],portal_receive_status:[277,3,1,""],send_AdminPortal2Server:[277,3,1,""],send_MsgPortal2Server:[277,3,1,""],send_Status2Launcher:[277,3,1,""],start_server:[277,3,1,""],stop_server:[277,3,1,""],wait_for_disconnect:[277,3,1,""],wait_for_server_connect:[277,3,1,""]},"evennia.server.portal.grapevine":{GrapevineClient:[278,1,1,""],RestartingWebsocketServerFactory:[278,1,1,""]},"evennia.server.portal.grapevine.GrapevineClient":{__init__:[278,3,1,""],at_login:[278,3,1,""],data_in:[278,3,1,""],disconnect:[278,3,1,""],onClose:[278,3,1,""],onMessage:[278,3,1,""],onOpen:[278,3,1,""],send_authenticate:[278,3,1,""],send_channel:[278,3,1,""],send_default:[278,3,1,""],send_heartbeat:[278,3,1,""],send_subscribe:[278,3,1,""],send_unsubscribe:[278,3,1,""]},"evennia.server.portal.grapevine.RestartingWebsocketServerFactory":{__init__:[278,3,1,""],buildProtocol:[278,3,1,""],clientConnectionFailed:[278,3,1,""],clientConnectionLost:[278,3,1,""],factor:[278,4,1,""],initialDelay:[278,4,1,""],maxDelay:[278,4,1,""],reconnect:[278,3,1,""],start:[278,3,1,""],startedConnecting:[278,3,1,""]},"evennia.server.portal.irc":{IRCBot:[279,1,1,""],IRCBotFactory:[279,1,1,""],parse_ansi_to_irc:[279,5,1,""],parse_irc_to_ansi:[279,5,1,""]},"evennia.server.portal.irc.IRCBot":{action:[279,3,1,""],at_login:[279,3,1,""],channel:[279,4,1,""],data_in:[279,3,1,""],disconnect:[279,3,1,""],factory:[279,4,1,""],get_nicklist:[279,3,1,""],irc_RPL_ENDOFNAMES:[279,3,1,""],irc_RPL_NAMREPLY:[279,3,1,""],lineRate:[279,4,1,""],logger:[279,4,1,""],nickname:[279,4,1,""],pong:[279,3,1,""],privmsg:[279,3,1,""],send_channel:[279,3,1,""],send_default:[279,3,1,""],send_ping:[279,3,1,""],send_privmsg:[279,3,1,""],send_reconnect:[279,3,1,""],send_request_nicklist:[279,3,1,""],signedOn:[279,3,1,""],sourceURL:[279,4,1,""]},"evennia.server.portal.irc.IRCBotFactory":{__init__:[279,3,1,""],buildProtocol:[279,3,1,""],clientConnectionFailed:[279,3,1,""],clientConnectionLost:[279,3,1,""],factor:[279,4,1,""],initialDelay:[279,4,1,""],maxDelay:[279,4,1,""],reconnect:[279,3,1,""],start:[279,3,1,""],startedConnecting:[279,3,1,""]},"evennia.server.portal.mccp":{Mccp:[280,1,1,""],mccp_compress:[280,5,1,""]},"evennia.server.portal.mccp.Mccp":{__init__:[280,3,1,""],do_mccp:[280,3,1,""],no_mccp:[280,3,1,""]},"evennia.server.portal.mssp":{Mssp:[281,1,1,""]},"evennia.server.portal.mssp.Mssp":{__init__:[281,3,1,""],do_mssp:[281,3,1,""],get_player_count:[281,3,1,""],get_uptime:[281,3,1,""],no_mssp:[281,3,1,""]},"evennia.server.portal.mxp":{Mxp:[282,1,1,""],mxp_parse:[282,5,1,""]},"evennia.server.portal.mxp.Mxp":{__init__:[282,3,1,""],do_mxp:[282,3,1,""],no_mxp:[282,3,1,""]},"evennia.server.portal.naws":{Naws:[283,1,1,""]},"evennia.server.portal.naws.Naws":{__init__:[283,3,1,""],do_naws:[283,3,1,""],negotiate_sizes:[283,3,1,""],no_naws:[283,3,1,""]},"evennia.server.portal.portal":{Portal:[284,1,1,""],Websocket:[284,1,1,""]},"evennia.server.portal.portal.Portal":{__init__:[284,3,1,""],get_info_dict:[284,3,1,""],shutdown:[284,3,1,""]},"evennia.server.portal.portalsessionhandler":{PortalSessionHandler:[285,1,1,""]},"evennia.server.portal.portalsessionhandler.PortalSessionHandler":{__init__:[285,3,1,""],announce_all:[285,3,1,""],at_server_connection:[285,3,1,""],connect:[285,3,1,""],count_loggedin:[285,3,1,""],data_in:[285,3,1,""],data_out:[285,3,1,""],disconnect:[285,3,1,""],disconnect_all:[285,3,1,""],generate_sessid:[285,3,1,""],server_connect:[285,3,1,""],server_disconnect:[285,3,1,""],server_disconnect_all:[285,3,1,""],server_logged_in:[285,3,1,""],server_session_sync:[285,3,1,""],sessions_from_csessid:[285,3,1,""],sync:[285,3,1,""]},"evennia.server.portal.rss":{RSSBotFactory:[286,1,1,""],RSSReader:[286,1,1,""]},"evennia.server.portal.rss.RSSBotFactory":{__init__:[286,3,1,""],start:[286,3,1,""]},"evennia.server.portal.rss.RSSReader":{__init__:[286,3,1,""],data_in:[286,3,1,""],disconnect:[286,3,1,""],get_new:[286,3,1,""],update:[286,3,1,""]},"evennia.server.portal.ssh":{AccountDBPasswordChecker:[287,1,1,""],ExtraInfoAuthServer:[287,1,1,""],PassAvatarIdTerminalRealm:[287,1,1,""],SSHServerFactory:[287,1,1,""],SshProtocol:[287,1,1,""],TerminalSessionTransport_getPeer:[287,1,1,""],getKeyPair:[287,5,1,""],makeFactory:[287,5,1,""]},"evennia.server.portal.ssh.AccountDBPasswordChecker":{__init__:[287,3,1,""],credentialInterfaces:[287,4,1,""],noisy:[287,4,1,""],requestAvatarId:[287,3,1,""]},"evennia.server.portal.ssh.ExtraInfoAuthServer":{auth_password:[287,3,1,""],noisy:[287,4,1,""]},"evennia.server.portal.ssh.PassAvatarIdTerminalRealm":{noisy:[287,4,1,""]},"evennia.server.portal.ssh.SSHServerFactory":{logPrefix:[287,3,1,""],noisy:[287,4,1,""]},"evennia.server.portal.ssh.SshProtocol":{__init__:[287,3,1,""],at_login:[287,3,1,""],connectionLost:[287,3,1,""],connectionMade:[287,3,1,""],data_out:[287,3,1,""],disconnect:[287,3,1,""],getClientAddress:[287,3,1,""],handle_EOF:[287,3,1,""],handle_FF:[287,3,1,""],handle_INT:[287,3,1,""],handle_QUIT:[287,3,1,""],lineReceived:[287,3,1,""],noisy:[287,4,1,""],sendLine:[287,3,1,""],send_default:[287,3,1,""],send_prompt:[287,3,1,""],send_text:[287,3,1,""],terminalSize:[287,3,1,""]},"evennia.server.portal.ssh.TerminalSessionTransport_getPeer":{__init__:[287,3,1,""],noisy:[287,4,1,""]},"evennia.server.portal.ssl":{SSLProtocol:[288,1,1,""],getSSLContext:[288,5,1,""],verify_SSL_key_and_cert:[288,5,1,""]},"evennia.server.portal.ssl.SSLProtocol":{__init__:[288,3,1,""]},"evennia.server.portal.suppress_ga":{SuppressGA:[289,1,1,""]},"evennia.server.portal.suppress_ga.SuppressGA":{__init__:[289,3,1,""],will_suppress_ga:[289,3,1,""],wont_suppress_ga:[289,3,1,""]},"evennia.server.portal.telnet":{TelnetProtocol:[290,1,1,""],TelnetServerFactory:[290,1,1,""]},"evennia.server.portal.telnet.TelnetProtocol":{__init__:[290,3,1,""],applicationDataReceived:[290,3,1,""],at_login:[290,3,1,""],connectionLost:[290,3,1,""],connectionMade:[290,3,1,""],dataReceived:[290,3,1,""],data_in:[290,3,1,""],data_out:[290,3,1,""],disableLocal:[290,3,1,""],disableRemote:[290,3,1,""],disconnect:[290,3,1,""],enableLocal:[290,3,1,""],enableRemote:[290,3,1,""],handshake_done:[290,3,1,""],sendLine:[290,3,1,""],send_default:[290,3,1,""],send_prompt:[290,3,1,""],send_text:[290,3,1,""],toggle_nop_keepalive:[290,3,1,""]},"evennia.server.portal.telnet.TelnetServerFactory":{logPrefix:[290,3,1,""],noisy:[290,4,1,""]},"evennia.server.portal.telnet_oob":{TelnetOOB:[291,1,1,""]},"evennia.server.portal.telnet_oob.TelnetOOB":{__init__:[291,3,1,""],data_out:[291,3,1,""],decode_gmcp:[291,3,1,""],decode_msdp:[291,3,1,""],do_gmcp:[291,3,1,""],do_msdp:[291,3,1,""],encode_gmcp:[291,3,1,""],encode_msdp:[291,3,1,""],no_gmcp:[291,3,1,""],no_msdp:[291,3,1,""]},"evennia.server.portal.telnet_ssl":{SSLProtocol:[292,1,1,""],getSSLContext:[292,5,1,""],verify_or_create_SSL_key_and_cert:[292,5,1,""]},"evennia.server.portal.telnet_ssl.SSLProtocol":{__init__:[292,3,1,""]},"evennia.server.portal.tests":{TestAMPServer:[293,1,1,""],TestIRC:[293,1,1,""],TestTelnet:[293,1,1,""],TestWebSocket:[293,1,1,""]},"evennia.server.portal.tests.TestAMPServer":{setUp:[293,3,1,""],test_amp_in:[293,3,1,""],test_amp_out:[293,3,1,""],test_large_msg:[293,3,1,""]},"evennia.server.portal.tests.TestIRC":{test_bold:[293,3,1,""],test_colors:[293,3,1,""],test_identity:[293,3,1,""],test_italic:[293,3,1,""],test_plain_ansi:[293,3,1,""]},"evennia.server.portal.tests.TestTelnet":{setUp:[293,3,1,""],test_mudlet_ttype:[293,3,1,""]},"evennia.server.portal.tests.TestWebSocket":{setUp:[293,3,1,""],tearDown:[293,3,1,""],test_data_in:[293,3,1,""],test_data_out:[293,3,1,""]},"evennia.server.portal.ttype":{Ttype:[294,1,1,""]},"evennia.server.portal.ttype.Ttype":{__init__:[294,3,1,""],will_ttype:[294,3,1,""],wont_ttype:[294,3,1,""]},"evennia.server.portal.webclient":{WebSocketClient:[295,1,1,""]},"evennia.server.portal.webclient.WebSocketClient":{__init__:[295,3,1,""],at_login:[295,3,1,""],data_in:[295,3,1,""],disconnect:[295,3,1,""],get_client_session:[295,3,1,""],nonce:[295,4,1,""],onClose:[295,3,1,""],onMessage:[295,3,1,""],onOpen:[295,3,1,""],sendLine:[295,3,1,""],send_default:[295,3,1,""],send_prompt:[295,3,1,""],send_text:[295,3,1,""]},"evennia.server.portal.webclient_ajax":{AjaxWebClient:[296,1,1,""],AjaxWebClientSession:[296,1,1,""],LazyEncoder:[296,1,1,""],jsonify:[296,5,1,""]},"evennia.server.portal.webclient_ajax.AjaxWebClient":{__init__:[296,3,1,""],allowedMethods:[296,4,1,""],at_login:[296,3,1,""],client_disconnect:[296,3,1,""],get_client_sessid:[296,3,1,""],isLeaf:[296,4,1,""],lineSend:[296,3,1,""],mode_close:[296,3,1,""],mode_init:[296,3,1,""],mode_input:[296,3,1,""],mode_keepalive:[296,3,1,""],mode_receive:[296,3,1,""],render_POST:[296,3,1,""]},"evennia.server.portal.webclient_ajax.AjaxWebClientSession":{__init__:[296,3,1,""],at_login:[296,3,1,""],data_in:[296,3,1,""],data_out:[296,3,1,""],disconnect:[296,3,1,""],get_client_session:[296,3,1,""],send_default:[296,3,1,""],send_prompt:[296,3,1,""],send_text:[296,3,1,""]},"evennia.server.portal.webclient_ajax.LazyEncoder":{"default":[296,3,1,""]},"evennia.server.profiling":{dummyrunner:[298,0,0,"-"],dummyrunner_settings:[299,0,0,"-"],memplot:[300,0,0,"-"],settings_mixin:[301,0,0,"-"],test_queries:[302,0,0,"-"],tests:[303,0,0,"-"],timetrace:[304,0,0,"-"]},"evennia.server.profiling.dummyrunner":{CmdDummyRunnerEchoResponse:[298,1,1,""],DummyClient:[298,1,1,""],DummyFactory:[298,1,1,""],DummyRunnerCmdSet:[298,1,1,""],gidcounter:[298,5,1,""],idcounter:[298,5,1,""],makeiter:[298,5,1,""],start_all_dummy_clients:[298,5,1,""]},"evennia.server.profiling.dummyrunner.CmdDummyRunnerEchoResponse":{aliases:[298,4,1,""],func:[298,3,1,""],help_category:[298,4,1,""],key:[298,4,1,""],lock_storage:[298,4,1,""],search_index_entry:[298,4,1,""]},"evennia.server.profiling.dummyrunner.DummyClient":{connectionLost:[298,3,1,""],connectionMade:[298,3,1,""],counter:[298,3,1,""],dataReceived:[298,3,1,""],error:[298,3,1,""],logout:[298,3,1,""],report:[298,3,1,""],step:[298,3,1,""]},"evennia.server.profiling.dummyrunner.DummyFactory":{__init__:[298,3,1,""],initialDelay:[298,4,1,""],maxDelay:[298,4,1,""],noisy:[298,4,1,""],protocol:[298,4,1,""]},"evennia.server.profiling.dummyrunner.DummyRunnerCmdSet":{at_cmdset_creation:[298,3,1,""],path:[298,4,1,""]},"evennia.server.profiling.dummyrunner_settings":{c_creates_button:[299,5,1,""],c_creates_obj:[299,5,1,""],c_digs:[299,5,1,""],c_examines:[299,5,1,""],c_help:[299,5,1,""],c_idles:[299,5,1,""],c_login:[299,5,1,""],c_login_nodig:[299,5,1,""],c_logout:[299,5,1,""],c_looks:[299,5,1,""],c_measure_lag:[299,5,1,""],c_moves:[299,5,1,""],c_moves_n:[299,5,1,""],c_moves_s:[299,5,1,""],c_socialize:[299,5,1,""]},"evennia.server.profiling.memplot":{Memplot:[300,1,1,""]},"evennia.server.profiling.memplot.Memplot":{DoesNotExist:[300,2,1,""],MultipleObjectsReturned:[300,2,1,""],at_repeat:[300,3,1,""],at_script_creation:[300,3,1,""],path:[300,4,1,""],typename:[300,4,1,""]},"evennia.server.profiling.test_queries":{count_queries:[302,5,1,""]},"evennia.server.profiling.tests":{TestDummyrunnerSettings:[303,1,1,""],TestMemPlot:[303,1,1,""]},"evennia.server.profiling.tests.TestDummyrunnerSettings":{clear_client_lists:[303,3,1,""],perception_method_tests:[303,3,1,""],setUp:[303,3,1,""],test_c_creates_button:[303,3,1,""],test_c_creates_obj:[303,3,1,""],test_c_digs:[303,3,1,""],test_c_examines:[303,3,1,""],test_c_help:[303,3,1,""],test_c_login:[303,3,1,""],test_c_login_no_dig:[303,3,1,""],test_c_logout:[303,3,1,""],test_c_looks:[303,3,1,""],test_c_move_n:[303,3,1,""],test_c_move_s:[303,3,1,""],test_c_moves:[303,3,1,""],test_c_socialize:[303,3,1,""],test_idles:[303,3,1,""]},"evennia.server.profiling.tests.TestMemPlot":{test_memplot:[303,3,1,""]},"evennia.server.profiling.timetrace":{timetrace:[304,5,1,""]},"evennia.server.server":{Evennia:[305,1,1,""]},"evennia.server.server.Evennia":{__init__:[305,3,1,""],at_post_portal_sync:[305,3,1,""],at_server_cold_start:[305,3,1,""],at_server_cold_stop:[305,3,1,""],at_server_reload_start:[305,3,1,""],at_server_reload_stop:[305,3,1,""],at_server_start:[305,3,1,""],at_server_stop:[305,3,1,""],get_info_dict:[305,3,1,""],run_init_hooks:[305,3,1,""],run_initial_setup:[305,3,1,""],shutdown:[305,3,1,""],sqlite3_prep:[305,3,1,""],update_defaults:[305,3,1,""]},"evennia.server.serversession":{ServerSession:[306,1,1,""]},"evennia.server.serversession.ServerSession":{__init__:[306,3,1,""],access:[306,3,1,""],at_cmdset_get:[306,3,1,""],at_disconnect:[306,3,1,""],at_login:[306,3,1,""],at_sync:[306,3,1,""],attributes:[306,4,1,""],cmdset_storage:[306,3,1,""],data_in:[306,3,1,""],data_out:[306,3,1,""],db:[306,3,1,""],execute_cmd:[306,3,1,""],get_account:[306,3,1,""],get_character:[306,3,1,""],get_client_size:[306,3,1,""],get_puppet:[306,3,1,""],get_puppet_or_account:[306,3,1,""],id:[306,3,1,""],log:[306,3,1,""],msg:[306,3,1,""],nattributes:[306,4,1,""],ndb:[306,3,1,""],ndb_del:[306,3,1,""],ndb_get:[306,3,1,""],ndb_set:[306,3,1,""],update_flags:[306,3,1,""],update_session_counters:[306,3,1,""]},"evennia.server.session":{Session:[307,1,1,""]},"evennia.server.session.Session":{at_sync:[307,3,1,""],data_in:[307,3,1,""],data_out:[307,3,1,""],disconnect:[307,3,1,""],get_sync_data:[307,3,1,""],init_session:[307,3,1,""],load_sync_data:[307,3,1,""]},"evennia.server.sessionhandler":{DummySession:[308,1,1,""],ServerSessionHandler:[308,1,1,""],SessionHandler:[308,1,1,""],delayed_import:[308,5,1,""]},"evennia.server.sessionhandler.DummySession":{sessid:[308,4,1,""]},"evennia.server.sessionhandler.ServerSessionHandler":{__init__:[308,3,1,""],account_count:[308,3,1,""],all_connected_accounts:[308,3,1,""],all_sessions_portal_sync:[308,3,1,""],announce_all:[308,3,1,""],call_inputfuncs:[308,3,1,""],data_in:[308,3,1,""],data_out:[308,3,1,""],disconnect:[308,3,1,""],disconnect_all_sessions:[308,3,1,""],disconnect_duplicate_sessions:[308,3,1,""],get_inputfuncs:[308,3,1,""],login:[308,3,1,""],portal_connect:[308,3,1,""],portal_disconnect:[308,3,1,""],portal_disconnect_all:[308,3,1,""],portal_reset_server:[308,3,1,""],portal_restart_server:[308,3,1,""],portal_session_sync:[308,3,1,""],portal_sessions_sync:[308,3,1,""],portal_shutdown:[308,3,1,""],session_from_account:[308,3,1,""],session_from_sessid:[308,3,1,""],session_portal_partial_sync:[308,3,1,""],session_portal_sync:[308,3,1,""],sessions_from_account:[308,3,1,""],sessions_from_character:[308,3,1,""],sessions_from_csessid:[308,3,1,""],sessions_from_puppet:[308,3,1,""],start_bot_session:[308,3,1,""],validate_sessions:[308,3,1,""]},"evennia.server.sessionhandler.SessionHandler":{clean_senddata:[308,3,1,""],get:[308,3,1,""],get_all_sync_data:[308,3,1,""],get_sessions:[308,3,1,""]},"evennia.server.throttle":{Throttle:[310,1,1,""]},"evennia.server.throttle.Throttle":{__init__:[310,3,1,""],check:[310,3,1,""],error_msg:[310,4,1,""],get:[310,3,1,""],get_cache_key:[310,3,1,""],record_ip:[310,3,1,""],remove:[310,3,1,""],touch:[310,3,1,""],unrecord_ip:[310,3,1,""],update:[310,3,1,""]},"evennia.server.validators":{EvenniaPasswordValidator:[311,1,1,""],EvenniaUsernameAvailabilityValidator:[311,1,1,""]},"evennia.server.validators.EvenniaPasswordValidator":{__init__:[311,3,1,""],get_help_text:[311,3,1,""],validate:[311,3,1,""]},"evennia.server.webserver":{DjangoWebRoot:[312,1,1,""],EvenniaReverseProxyResource:[312,1,1,""],HTTPChannelWithXForwardedFor:[312,1,1,""],LockableThreadPool:[312,1,1,""],PrivateStaticRoot:[312,1,1,""],WSGIWebServer:[312,1,1,""],Website:[312,1,1,""]},"evennia.server.webserver.DjangoWebRoot":{__init__:[312,3,1,""],empty_threadpool:[312,3,1,""],getChild:[312,3,1,""]},"evennia.server.webserver.EvenniaReverseProxyResource":{getChild:[312,3,1,""],render:[312,3,1,""]},"evennia.server.webserver.HTTPChannelWithXForwardedFor":{allHeadersReceived:[312,3,1,""]},"evennia.server.webserver.LockableThreadPool":{__init__:[312,3,1,""],callInThread:[312,3,1,""],lock:[312,3,1,""]},"evennia.server.webserver.PrivateStaticRoot":{directoryListing:[312,3,1,""]},"evennia.server.webserver.WSGIWebServer":{__init__:[312,3,1,""],startService:[312,3,1,""],stopService:[312,3,1,""]},"evennia.server.webserver.Website":{log:[312,3,1,""],logPrefix:[312,3,1,""],noisy:[312,4,1,""]},"evennia.typeclasses":{attributes:[316,0,0,"-"],managers:[317,0,0,"-"],models:[318,0,0,"-"],tags:[319,0,0,"-"]},"evennia.typeclasses.attributes":{Attribute:[316,1,1,""],AttributeHandler:[316,1,1,""],DbHolder:[316,1,1,""],IAttribute:[316,1,1,""],IAttributeBackend:[316,1,1,""],InMemoryAttribute:[316,1,1,""],InMemoryAttributeBackend:[316,1,1,""],ModelAttributeBackend:[316,1,1,""],NickHandler:[316,1,1,""],NickTemplateInvalid:[316,2,1,""],initialize_nick_templates:[316,5,1,""],parse_nick_template:[316,5,1,""]},"evennia.typeclasses.attributes.Attribute":{DoesNotExist:[316,2,1,""],MultipleObjectsReturned:[316,2,1,""],accountdb_set:[316,4,1,""],attrtype:[316,3,1,""],category:[316,3,1,""],channeldb_set:[316,4,1,""],date_created:[316,3,1,""],db_attrtype:[316,4,1,""],db_category:[316,4,1,""],db_date_created:[316,4,1,""],db_key:[316,4,1,""],db_lock_storage:[316,4,1,""],db_model:[316,4,1,""],db_strvalue:[316,4,1,""],db_value:[316,4,1,""],get_next_by_db_date_created:[316,3,1,""],get_previous_by_db_date_created:[316,3,1,""],id:[316,4,1,""],key:[316,3,1,""],lock_storage:[316,3,1,""],model:[316,3,1,""],objectdb_set:[316,4,1,""],path:[316,4,1,""],scriptdb_set:[316,4,1,""],strvalue:[316,3,1,""],typename:[316,4,1,""],value:[316,3,1,""]},"evennia.typeclasses.attributes.AttributeHandler":{__init__:[316,3,1,""],add:[316,3,1,""],all:[316,3,1,""],batch_add:[316,3,1,""],clear:[316,3,1,""],get:[316,3,1,""],has:[316,3,1,""],remove:[316,3,1,""],reset_cache:[316,3,1,""]},"evennia.typeclasses.attributes.DbHolder":{__init__:[316,3,1,""],all:[316,3,1,""],get_all:[316,3,1,""]},"evennia.typeclasses.attributes.IAttribute":{access:[316,3,1,""],attrtype:[316,3,1,""],category:[316,3,1,""],date_created:[316,3,1,""],key:[316,3,1,""],lock_storage:[316,3,1,""],locks:[316,4,1,""],model:[316,3,1,""],strvalue:[316,3,1,""]},"evennia.typeclasses.attributes.IAttributeBackend":{__init__:[316,3,1,""],batch_add:[316,3,1,""],clear_attributes:[316,3,1,""],create_attribute:[316,3,1,""],delete_attribute:[316,3,1,""],do_batch_delete:[316,3,1,""],do_batch_finish:[316,3,1,""],do_batch_update_attribute:[316,3,1,""],do_create_attribute:[316,3,1,""],do_delete_attribute:[316,3,1,""],do_update_attribute:[316,3,1,""],get:[316,3,1,""],get_all_attributes:[316,3,1,""],query_all:[316,3,1,""],query_category:[316,3,1,""],query_key:[316,3,1,""],reset_cache:[316,3,1,""],update_attribute:[316,3,1,""]},"evennia.typeclasses.attributes.InMemoryAttribute":{__init__:[316,3,1,""],value:[316,3,1,""]},"evennia.typeclasses.attributes.InMemoryAttributeBackend":{__init__:[316,3,1,""],do_batch_finish:[316,3,1,""],do_batch_update_attribute:[316,3,1,""],do_create_attribute:[316,3,1,""],do_delete_attribute:[316,3,1,""],do_update_attribute:[316,3,1,""],query_all:[316,3,1,""],query_category:[316,3,1,""],query_key:[316,3,1,""]},"evennia.typeclasses.attributes.ModelAttributeBackend":{__init__:[316,3,1,""],do_batch_finish:[316,3,1,""],do_batch_update_attribute:[316,3,1,""],do_create_attribute:[316,3,1,""],do_delete_attribute:[316,3,1,""],do_update_attribute:[316,3,1,""],query_all:[316,3,1,""],query_category:[316,3,1,""],query_key:[316,3,1,""]},"evennia.typeclasses.attributes.NickHandler":{__init__:[316,3,1,""],add:[316,3,1,""],get:[316,3,1,""],has:[316,3,1,""],nickreplace:[316,3,1,""],remove:[316,3,1,""]},"evennia.typeclasses.managers":{TypedObjectManager:[317,1,1,""]},"evennia.typeclasses.managers.TypedObjectManager":{create_tag:[317,3,1,""],dbref:[317,3,1,""],dbref_search:[317,3,1,""],get_alias:[317,3,1,""],get_attribute:[317,3,1,""],get_by_alias:[317,3,1,""],get_by_attribute:[317,3,1,""],get_by_nick:[317,3,1,""],get_by_permission:[317,3,1,""],get_by_tag:[317,3,1,""],get_dbref_range:[317,3,1,""],get_id:[317,3,1,""],get_nick:[317,3,1,""],get_permission:[317,3,1,""],get_tag:[317,3,1,""],get_typeclass_totals:[317,3,1,""],object_totals:[317,3,1,""],typeclass_search:[317,3,1,""]},"evennia.typeclasses.models":{TypedObject:[318,1,1,""]},"evennia.typeclasses.models.TypedObject":{"delete":[318,3,1,""],Meta:[318,1,1,""],__init__:[318,3,1,""],access:[318,3,1,""],aliases:[318,4,1,""],at_idmapper_flush:[318,3,1,""],at_rename:[318,3,1,""],attributes:[318,4,1,""],check_permstring:[318,3,1,""],date_created:[318,3,1,""],db:[318,3,1,""],db_attributes:[318,4,1,""],db_date_created:[318,4,1,""],db_key:[318,4,1,""],db_lock_storage:[318,4,1,""],db_tags:[318,4,1,""],db_typeclass_path:[318,4,1,""],dbid:[318,3,1,""],dbref:[318,3,1,""],get_absolute_url:[318,3,1,""],get_display_name:[318,3,1,""],get_extra_info:[318,3,1,""],get_next_by_db_date_created:[318,3,1,""],get_previous_by_db_date_created:[318,3,1,""],is_typeclass:[318,3,1,""],key:[318,3,1,""],lock_storage:[318,3,1,""],locks:[318,4,1,""],name:[318,3,1,""],nattributes:[318,4,1,""],ndb:[318,3,1,""],objects:[318,4,1,""],path:[318,4,1,""],permissions:[318,4,1,""],set_class_from_typeclass:[318,3,1,""],swap_typeclass:[318,3,1,""],tags:[318,4,1,""],typeclass_path:[318,3,1,""],typename:[318,4,1,""],web_get_admin_url:[318,3,1,""],web_get_create_url:[318,3,1,""],web_get_delete_url:[318,3,1,""],web_get_detail_url:[318,3,1,""],web_get_puppet_url:[318,3,1,""],web_get_update_url:[318,3,1,""]},"evennia.typeclasses.models.TypedObject.Meta":{"abstract":[318,4,1,""],ordering:[318,4,1,""],verbose_name:[318,4,1,""]},"evennia.typeclasses.tags":{AliasHandler:[319,1,1,""],PermissionHandler:[319,1,1,""],Tag:[319,1,1,""],TagHandler:[319,1,1,""]},"evennia.typeclasses.tags.Tag":{DoesNotExist:[319,2,1,""],MultipleObjectsReturned:[319,2,1,""],accountdb_set:[319,4,1,""],channeldb_set:[319,4,1,""],db_category:[319,4,1,""],db_data:[319,4,1,""],db_key:[319,4,1,""],db_model:[319,4,1,""],db_tagtype:[319,4,1,""],helpentry_set:[319,4,1,""],id:[319,4,1,""],msg_set:[319,4,1,""],objectdb_set:[319,4,1,""],objects:[319,4,1,""],scriptdb_set:[319,4,1,""]},"evennia.typeclasses.tags.TagHandler":{__init__:[319,3,1,""],add:[319,3,1,""],all:[319,3,1,""],batch_add:[319,3,1,""],clear:[319,3,1,""],get:[319,3,1,""],has:[319,3,1,""],remove:[319,3,1,""],reset_cache:[319,3,1,""]},"evennia.utils":{ansi:[321,0,0,"-"],batchprocessors:[322,0,0,"-"],containers:[323,0,0,"-"],create:[324,0,0,"-"],dbserialize:[325,0,0,"-"],eveditor:[326,0,0,"-"],evform:[327,0,0,"-"],evmenu:[328,0,0,"-"],evmore:[329,0,0,"-"],evtable:[330,0,0,"-"],gametime:[331,0,0,"-"],idmapper:[332,0,0,"-"],logger:[337,0,0,"-"],optionclasses:[338,0,0,"-"],optionhandler:[339,0,0,"-"],picklefield:[340,0,0,"-"],search:[341,0,0,"-"],test_resources:[342,0,0,"-"],text2html:[343,0,0,"-"],utils:[344,0,0,"-"],validatorfuncs:[345,0,0,"-"]},"evennia.utils.ansi":{ANSIMeta:[321,1,1,""],ANSIParser:[321,1,1,""],ANSIString:[321,1,1,""],parse_ansi:[321,5,1,""],raw:[321,5,1,""],strip_ansi:[321,5,1,""],strip_raw_ansi:[321,5,1,""]},"evennia.utils.ansi.ANSIMeta":{__init__:[321,3,1,""]},"evennia.utils.ansi.ANSIParser":{ansi_escapes:[321,4,1,""],ansi_map:[321,4,1,""],ansi_map_dict:[321,4,1,""],ansi_re:[321,4,1,""],ansi_regex:[321,4,1,""],ansi_sub:[321,4,1,""],ansi_xterm256_bright_bg_map:[321,4,1,""],ansi_xterm256_bright_bg_map_dict:[321,4,1,""],brightbg_sub:[321,4,1,""],mxp_re:[321,4,1,""],mxp_sub:[321,4,1,""],mxp_url_re:[321,4,1,""],mxp_url_sub:[321,4,1,""],parse_ansi:[321,3,1,""],strip_mxp:[321,3,1,""],strip_raw_codes:[321,3,1,""],sub_ansi:[321,3,1,""],sub_brightbg:[321,3,1,""],sub_xterm256:[321,3,1,""],xterm256_bg:[321,4,1,""],xterm256_bg_sub:[321,4,1,""],xterm256_fg:[321,4,1,""],xterm256_fg_sub:[321,4,1,""],xterm256_gbg:[321,4,1,""],xterm256_gbg_sub:[321,4,1,""],xterm256_gfg:[321,4,1,""],xterm256_gfg_sub:[321,4,1,""]},"evennia.utils.ansi.ANSIString":{__init__:[321,3,1,""],capitalize:[321,3,1,""],center:[321,3,1,""],clean:[321,3,1,""],count:[321,3,1,""],decode:[321,3,1,""],encode:[321,3,1,""],endswith:[321,3,1,""],expandtabs:[321,3,1,""],find:[321,3,1,""],format:[321,3,1,""],index:[321,3,1,""],isalnum:[321,3,1,""],isalpha:[321,3,1,""],isdigit:[321,3,1,""],islower:[321,3,1,""],isspace:[321,3,1,""],istitle:[321,3,1,""],isupper:[321,3,1,""],join:[321,3,1,""],ljust:[321,3,1,""],lower:[321,3,1,""],lstrip:[321,3,1,""],partition:[321,3,1,""],raw:[321,3,1,""],re_format:[321,4,1,""],replace:[321,3,1,""],rfind:[321,3,1,""],rindex:[321,3,1,""],rjust:[321,3,1,""],rsplit:[321,3,1,""],rstrip:[321,3,1,""],split:[321,3,1,""],startswith:[321,3,1,""],strip:[321,3,1,""],swapcase:[321,3,1,""],translate:[321,3,1,""],upper:[321,3,1,""]},"evennia.utils.batchprocessors":{BatchCodeProcessor:[322,1,1,""],BatchCommandProcessor:[322,1,1,""],read_batchfile:[322,5,1,""],tb_filename:[322,5,1,""],tb_iter:[322,5,1,""]},"evennia.utils.batchprocessors.BatchCodeProcessor":{code_exec:[322,3,1,""],parse_file:[322,3,1,""]},"evennia.utils.batchprocessors.BatchCommandProcessor":{parse_file:[322,3,1,""]},"evennia.utils.containers":{Container:[323,1,1,""],GlobalScriptContainer:[323,1,1,""],OptionContainer:[323,1,1,""]},"evennia.utils.containers.Container":{__init__:[323,3,1,""],all:[323,3,1,""],get:[323,3,1,""],load_data:[323,3,1,""],storage_modules:[323,4,1,""]},"evennia.utils.containers.GlobalScriptContainer":{__init__:[323,3,1,""],all:[323,3,1,""],get:[323,3,1,""],load_data:[323,3,1,""],start:[323,3,1,""]},"evennia.utils.containers.OptionContainer":{storage_modules:[323,4,1,""]},"evennia.utils.create":{create_account:[324,5,1,""],create_channel:[324,5,1,""],create_help_entry:[324,5,1,""],create_message:[324,5,1,""],create_object:[324,5,1,""],create_script:[324,5,1,""]},"evennia.utils.dbserialize":{dbserialize:[325,5,1,""],dbunserialize:[325,5,1,""],do_pickle:[325,5,1,""],do_unpickle:[325,5,1,""],from_pickle:[325,5,1,""],to_pickle:[325,5,1,""]},"evennia.utils.eveditor":{CmdEditorBase:[326,1,1,""],CmdEditorGroup:[326,1,1,""],CmdLineInput:[326,1,1,""],CmdSaveYesNo:[326,1,1,""],EvEditor:[326,1,1,""],EvEditorCmdSet:[326,1,1,""],SaveYesNoCmdSet:[326,1,1,""]},"evennia.utils.eveditor.CmdEditorBase":{aliases:[326,4,1,""],editor:[326,4,1,""],help_category:[326,4,1,""],help_entry:[326,4,1,""],key:[326,4,1,""],lock_storage:[326,4,1,""],locks:[326,4,1,""],parse:[326,3,1,""],search_index_entry:[326,4,1,""]},"evennia.utils.eveditor.CmdEditorGroup":{aliases:[326,4,1,""],arg_regex:[326,4,1,""],func:[326,3,1,""],help_category:[326,4,1,""],key:[326,4,1,""],lock_storage:[326,4,1,""],search_index_entry:[326,4,1,""]},"evennia.utils.eveditor.CmdLineInput":{aliases:[326,4,1,""],func:[326,3,1,""],help_category:[326,4,1,""],key:[326,4,1,""],lock_storage:[326,4,1,""],search_index_entry:[326,4,1,""]},"evennia.utils.eveditor.CmdSaveYesNo":{aliases:[326,4,1,""],func:[326,3,1,""],help_category:[326,4,1,""],help_cateogory:[326,4,1,""],key:[326,4,1,""],lock_storage:[326,4,1,""],locks:[326,4,1,""],search_index_entry:[326,4,1,""]},"evennia.utils.eveditor.EvEditor":{__init__:[326,3,1,""],decrease_indent:[326,3,1,""],deduce_indent:[326,3,1,""],display_buffer:[326,3,1,""],display_help:[326,3,1,""],get_buffer:[326,3,1,""],increase_indent:[326,3,1,""],load_buffer:[326,3,1,""],quit:[326,3,1,""],save_buffer:[326,3,1,""],swap_autoindent:[326,3,1,""],update_buffer:[326,3,1,""],update_undo:[326,3,1,""]},"evennia.utils.eveditor.EvEditorCmdSet":{at_cmdset_creation:[326,3,1,""],key:[326,4,1,""],mergetype:[326,4,1,""],path:[326,4,1,""]},"evennia.utils.eveditor.SaveYesNoCmdSet":{at_cmdset_creation:[326,3,1,""],key:[326,4,1,""],mergetype:[326,4,1,""],path:[326,4,1,""],priority:[326,4,1,""]},"evennia.utils.evform":{EvForm:[327,1,1,""]},"evennia.utils.evform.EvForm":{__init__:[327,3,1,""],map:[327,3,1,""],reload:[327,3,1,""]},"evennia.utils.evmenu":{CmdEvMenuNode:[328,1,1,""],CmdGetInput:[328,1,1,""],CmdYesNoQuestion:[328,1,1,""],EvMenu:[328,1,1,""],EvMenuCmdSet:[328,1,1,""],EvMenuError:[328,2,1,""],EvMenuGotoAbortMessage:[328,2,1,""],InputCmdSet:[328,1,1,""],YesNoQuestionCmdSet:[328,1,1,""],ask_yes_no:[328,5,1,""],get_input:[328,5,1,""],list_node:[328,5,1,""],parse_menu_template:[328,5,1,""],template2menu:[328,5,1,""]},"evennia.utils.evmenu.CmdEvMenuNode":{aliases:[328,4,1,""],auto_help_display_key:[328,4,1,""],func:[328,3,1,""],get_help:[328,3,1,""],help_category:[328,4,1,""],key:[328,4,1,""],lock_storage:[328,4,1,""],locks:[328,4,1,""],search_index_entry:[328,4,1,""]},"evennia.utils.evmenu.CmdGetInput":{aliases:[328,4,1,""],func:[328,3,1,""],help_category:[328,4,1,""],key:[328,4,1,""],lock_storage:[328,4,1,""],search_index_entry:[328,4,1,""]},"evennia.utils.evmenu.CmdYesNoQuestion":{aliases:[328,4,1,""],arg_regex:[328,4,1,""],func:[328,3,1,""],help_category:[328,4,1,""],key:[328,4,1,""],lock_storage:[328,4,1,""],search_index_entry:[328,4,1,""]},"evennia.utils.evmenu.EvMenu":{"goto":[328,3,1,""],__init__:[328,3,1,""],close_menu:[328,3,1,""],display_helptext:[328,3,1,""],display_nodetext:[328,3,1,""],extract_goto_exec:[328,3,1,""],helptext_formatter:[328,3,1,""],msg:[328,3,1,""],node_border_char:[328,4,1,""],node_formatter:[328,3,1,""],nodetext_formatter:[328,3,1,""],options_formatter:[328,3,1,""],parse_input:[328,3,1,""],print_debug_info:[328,3,1,""],run_exec:[328,3,1,""],run_exec_then_goto:[328,3,1,""]},"evennia.utils.evmenu.EvMenuCmdSet":{at_cmdset_creation:[328,3,1,""],key:[328,4,1,""],mergetype:[328,4,1,""],no_channels:[328,4,1,""],no_exits:[328,4,1,""],no_objs:[328,4,1,""],path:[328,4,1,""],priority:[328,4,1,""]},"evennia.utils.evmenu.InputCmdSet":{at_cmdset_creation:[328,3,1,""],key:[328,4,1,""],mergetype:[328,4,1,""],no_channels:[328,4,1,""],no_exits:[328,4,1,""],no_objs:[328,4,1,""],path:[328,4,1,""],priority:[328,4,1,""]},"evennia.utils.evmenu.YesNoQuestionCmdSet":{at_cmdset_creation:[328,3,1,""],key:[328,4,1,""],mergetype:[328,4,1,""],no_channels:[328,4,1,""],no_exits:[328,4,1,""],no_objs:[328,4,1,""],path:[328,4,1,""],priority:[328,4,1,""]},"evennia.utils.evmore":{CmdMore:[329,1,1,""],CmdMoreLook:[329,1,1,""],CmdSetMore:[329,1,1,""],EvMore:[329,1,1,""],msg:[329,5,1,""],queryset_maxsize:[329,5,1,""]},"evennia.utils.evmore.CmdMore":{aliases:[329,4,1,""],auto_help:[329,4,1,""],func:[329,3,1,""],help_category:[329,4,1,""],key:[329,4,1,""],lock_storage:[329,4,1,""],search_index_entry:[329,4,1,""]},"evennia.utils.evmore.CmdMoreLook":{aliases:[329,4,1,""],auto_help:[329,4,1,""],func:[329,3,1,""],help_category:[329,4,1,""],key:[329,4,1,""],lock_storage:[329,4,1,""],search_index_entry:[329,4,1,""]},"evennia.utils.evmore.CmdSetMore":{at_cmdset_creation:[329,3,1,""],key:[329,4,1,""],path:[329,4,1,""],priority:[329,4,1,""]},"evennia.utils.evmore.EvMore":{__init__:[329,3,1,""],display:[329,3,1,""],init_django_paginator:[329,3,1,""],init_evtable:[329,3,1,""],init_f_str:[329,3,1,""],init_iterable:[329,3,1,""],init_pages:[329,3,1,""],init_queryset:[329,3,1,""],init_str:[329,3,1,""],page_back:[329,3,1,""],page_end:[329,3,1,""],page_formatter:[329,3,1,""],page_next:[329,3,1,""],page_quit:[329,3,1,""],page_top:[329,3,1,""],paginator:[329,3,1,""],paginator_django:[329,3,1,""],paginator_index:[329,3,1,""],paginator_slice:[329,3,1,""],start:[329,3,1,""]},"evennia.utils.evtable":{ANSITextWrapper:[330,1,1,""],EvCell:[330,1,1,""],EvColumn:[330,1,1,""],EvTable:[330,1,1,""],fill:[330,5,1,""],wrap:[330,5,1,""]},"evennia.utils.evtable.EvCell":{__init__:[330,3,1,""],get:[330,3,1,""],get_height:[330,3,1,""],get_min_height:[330,3,1,""],get_min_width:[330,3,1,""],get_width:[330,3,1,""],reformat:[330,3,1,""],replace_data:[330,3,1,""]},"evennia.utils.evtable.EvColumn":{__init__:[330,3,1,""],add_rows:[330,3,1,""],reformat:[330,3,1,""],reformat_cell:[330,3,1,""]},"evennia.utils.evtable.EvTable":{__init__:[330,3,1,""],add_column:[330,3,1,""],add_header:[330,3,1,""],add_row:[330,3,1,""],get:[330,3,1,""],reformat:[330,3,1,""],reformat_column:[330,3,1,""]},"evennia.utils.gametime":{TimeScript:[331,1,1,""],game_epoch:[331,5,1,""],gametime:[331,5,1,""],portal_uptime:[331,5,1,""],real_seconds_until:[331,5,1,""],reset_gametime:[331,5,1,""],runtime:[331,5,1,""],schedule:[331,5,1,""],server_epoch:[331,5,1,""],uptime:[331,5,1,""]},"evennia.utils.gametime.TimeScript":{DoesNotExist:[331,2,1,""],MultipleObjectsReturned:[331,2,1,""],at_repeat:[331,3,1,""],at_script_creation:[331,3,1,""],path:[331,4,1,""],typename:[331,4,1,""]},"evennia.utils.idmapper":{manager:[333,0,0,"-"],models:[334,0,0,"-"],tests:[335,0,0,"-"]},"evennia.utils.idmapper.manager":{SharedMemoryManager:[333,1,1,""]},"evennia.utils.idmapper.manager.SharedMemoryManager":{get:[333,3,1,""]},"evennia.utils.idmapper.models":{SharedMemoryModel:[334,1,1,""],SharedMemoryModelBase:[334,1,1,""],WeakSharedMemoryModel:[334,1,1,""],WeakSharedMemoryModelBase:[334,1,1,""],cache_size:[334,5,1,""],conditional_flush:[334,5,1,""],flush_cache:[334,5,1,""],flush_cached_instance:[334,5,1,""],update_cached_instance:[334,5,1,""]},"evennia.utils.idmapper.models.SharedMemoryModel":{"delete":[334,3,1,""],Meta:[334,1,1,""],at_idmapper_flush:[334,3,1,""],cache_instance:[334,3,1,""],flush_cached_instance:[334,3,1,""],flush_from_cache:[334,3,1,""],flush_instance_cache:[334,3,1,""],get_all_cached_instances:[334,3,1,""],get_cached_instance:[334,3,1,""],objects:[334,4,1,""],path:[334,4,1,""],save:[334,3,1,""],typename:[334,4,1,""]},"evennia.utils.idmapper.models.SharedMemoryModel.Meta":{"abstract":[334,4,1,""]},"evennia.utils.idmapper.models.WeakSharedMemoryModel":{Meta:[334,1,1,""],path:[334,4,1,""],typename:[334,4,1,""]},"evennia.utils.idmapper.models.WeakSharedMemoryModel.Meta":{"abstract":[334,4,1,""]},"evennia.utils.idmapper.tests":{Article:[335,1,1,""],Category:[335,1,1,""],RegularArticle:[335,1,1,""],RegularCategory:[335,1,1,""],SharedMemorysTest:[335,1,1,""]},"evennia.utils.idmapper.tests.Article":{DoesNotExist:[335,2,1,""],MultipleObjectsReturned:[335,2,1,""],category2:[335,4,1,""],category2_id:[335,4,1,""],category:[335,4,1,""],category_id:[335,4,1,""],id:[335,4,1,""],name:[335,4,1,""],path:[335,4,1,""],typename:[335,4,1,""]},"evennia.utils.idmapper.tests.Category":{DoesNotExist:[335,2,1,""],MultipleObjectsReturned:[335,2,1,""],article_set:[335,4,1,""],id:[335,4,1,""],name:[335,4,1,""],path:[335,4,1,""],regulararticle_set:[335,4,1,""],typename:[335,4,1,""]},"evennia.utils.idmapper.tests.RegularArticle":{DoesNotExist:[335,2,1,""],MultipleObjectsReturned:[335,2,1,""],category2:[335,4,1,""],category2_id:[335,4,1,""],category:[335,4,1,""],category_id:[335,4,1,""],id:[335,4,1,""],name:[335,4,1,""],objects:[335,4,1,""]},"evennia.utils.idmapper.tests.RegularCategory":{DoesNotExist:[335,2,1,""],MultipleObjectsReturned:[335,2,1,""],article_set:[335,4,1,""],id:[335,4,1,""],name:[335,4,1,""],objects:[335,4,1,""],regulararticle_set:[335,4,1,""]},"evennia.utils.idmapper.tests.SharedMemorysTest":{setUp:[335,3,1,""],testMixedReferences:[335,3,1,""],testObjectDeletion:[335,3,1,""],testRegularReferences:[335,3,1,""],testSharedMemoryReferences:[335,3,1,""]},"evennia.utils.logger":{EvenniaLogFile:[337,1,1,""],PortalLogObserver:[337,1,1,""],ServerLogObserver:[337,1,1,""],WeeklyLogFile:[337,1,1,""],log_dep:[337,5,1,""],log_depmsg:[337,5,1,""],log_err:[337,5,1,""],log_errmsg:[337,5,1,""],log_file:[337,5,1,""],log_file_exists:[337,5,1,""],log_info:[337,5,1,""],log_infomsg:[337,5,1,""],log_msg:[337,5,1,""],log_sec:[337,5,1,""],log_secmsg:[337,5,1,""],log_server:[337,5,1,""],log_trace:[337,5,1,""],log_tracemsg:[337,5,1,""],log_warn:[337,5,1,""],log_warnmsg:[337,5,1,""],rotate_log_file:[337,5,1,""],tail_log_file:[337,5,1,""],timeformat:[337,5,1,""]},"evennia.utils.logger.EvenniaLogFile":{num_lines_to_append:[337,4,1,""],readlines:[337,3,1,""],rotate:[337,3,1,""],seek:[337,3,1,""],settings:[337,4,1,""]},"evennia.utils.logger.PortalLogObserver":{emit:[337,3,1,""],prefix:[337,4,1,""],timeFormat:[337,4,1,""]},"evennia.utils.logger.ServerLogObserver":{prefix:[337,4,1,""]},"evennia.utils.logger.WeeklyLogFile":{__init__:[337,3,1,""],shouldRotate:[337,3,1,""],suffix:[337,3,1,""],write:[337,3,1,""]},"evennia.utils.optionclasses":{BaseOption:[338,1,1,""],Boolean:[338,1,1,""],Color:[338,1,1,""],Datetime:[338,1,1,""],Duration:[338,1,1,""],Email:[338,1,1,""],Future:[338,1,1,""],Lock:[338,1,1,""],PositiveInteger:[338,1,1,""],SignedInteger:[338,1,1,""],Text:[338,1,1,""],Timezone:[338,1,1,""],UnsignedInteger:[338,1,1,""]},"evennia.utils.optionclasses.BaseOption":{"default":[338,3,1,""],__init__:[338,3,1,""],changed:[338,3,1,""],deserialize:[338,3,1,""],display:[338,3,1,""],load:[338,3,1,""],save:[338,3,1,""],serialize:[338,3,1,""],set:[338,3,1,""],validate:[338,3,1,""],value:[338,3,1,""]},"evennia.utils.optionclasses.Boolean":{deserialize:[338,3,1,""],display:[338,3,1,""],serialize:[338,3,1,""],validate:[338,3,1,""]},"evennia.utils.optionclasses.Color":{deserialize:[338,3,1,""],display:[338,3,1,""],validate:[338,3,1,""]},"evennia.utils.optionclasses.Datetime":{deserialize:[338,3,1,""],serialize:[338,3,1,""],validate:[338,3,1,""]},"evennia.utils.optionclasses.Duration":{deserialize:[338,3,1,""],serialize:[338,3,1,""],validate:[338,3,1,""]},"evennia.utils.optionclasses.Email":{deserialize:[338,3,1,""],validate:[338,3,1,""]},"evennia.utils.optionclasses.Future":{validate:[338,3,1,""]},"evennia.utils.optionclasses.Lock":{validate:[338,3,1,""]},"evennia.utils.optionclasses.PositiveInteger":{deserialize:[338,3,1,""],validate:[338,3,1,""]},"evennia.utils.optionclasses.SignedInteger":{deserialize:[338,3,1,""],validate:[338,3,1,""]},"evennia.utils.optionclasses.Text":{deserialize:[338,3,1,""]},"evennia.utils.optionclasses.Timezone":{"default":[338,3,1,""],deserialize:[338,3,1,""],serialize:[338,3,1,""],validate:[338,3,1,""]},"evennia.utils.optionclasses.UnsignedInteger":{deserialize:[338,3,1,""],validate:[338,3,1,""],validator_key:[338,4,1,""]},"evennia.utils.optionhandler":{InMemorySaveHandler:[339,1,1,""],OptionHandler:[339,1,1,""]},"evennia.utils.optionhandler.InMemorySaveHandler":{__init__:[339,3,1,""],add:[339,3,1,""],get:[339,3,1,""]},"evennia.utils.optionhandler.OptionHandler":{__init__:[339,3,1,""],all:[339,3,1,""],get:[339,3,1,""],set:[339,3,1,""]},"evennia.utils.picklefield":{PickledFormField:[340,1,1,""],PickledObject:[340,1,1,""],PickledObjectField:[340,1,1,""],PickledWidget:[340,1,1,""],dbsafe_decode:[340,5,1,""],dbsafe_encode:[340,5,1,""],wrap_conflictual_object:[340,5,1,""]},"evennia.utils.picklefield.PickledFormField":{__init__:[340,3,1,""],clean:[340,3,1,""],default_error_messages:[340,4,1,""],widget:[340,4,1,""]},"evennia.utils.picklefield.PickledObjectField":{__init__:[340,3,1,""],formfield:[340,3,1,""],from_db_value:[340,3,1,""],get_db_prep_lookup:[340,3,1,""],get_db_prep_value:[340,3,1,""],get_default:[340,3,1,""],get_internal_type:[340,3,1,""],pre_save:[340,3,1,""],value_to_string:[340,3,1,""]},"evennia.utils.picklefield.PickledWidget":{media:[340,3,1,""],render:[340,3,1,""],value_from_datadict:[340,3,1,""]},"evennia.utils.search":{search_account:[341,5,1,""],search_account_tag:[341,5,1,""],search_channel:[341,5,1,""],search_channel_tag:[341,5,1,""],search_help_entry:[341,5,1,""],search_message:[341,5,1,""],search_object:[341,5,1,""],search_script:[341,5,1,""],search_script_tag:[341,5,1,""],search_tag:[341,5,1,""]},"evennia.utils.test_resources":{EvenniaTest:[342,1,1,""],LocalEvenniaTest:[342,1,1,""],mockdeferLater:[342,5,1,""],mockdelay:[342,5,1,""],unload_module:[342,5,1,""]},"evennia.utils.test_resources.EvenniaTest":{account_typeclass:[342,4,1,""],character_typeclass:[342,4,1,""],exit_typeclass:[342,4,1,""],object_typeclass:[342,4,1,""],room_typeclass:[342,4,1,""],script_typeclass:[342,4,1,""],setUp:[342,3,1,""],tearDown:[342,3,1,""]},"evennia.utils.test_resources.LocalEvenniaTest":{account_typeclass:[342,4,1,""],character_typeclass:[342,4,1,""],exit_typeclass:[342,4,1,""],object_typeclass:[342,4,1,""],room_typeclass:[342,4,1,""],script_typeclass:[342,4,1,""]},"evennia.utils.text2html":{TextToHTMLparser:[343,1,1,""],parse_html:[343,5,1,""]},"evennia.utils.text2html.TextToHTMLparser":{bg_colormap:[343,4,1,""],bgfgstart:[343,4,1,""],bgfgstop:[343,4,1,""],bgstart:[343,4,1,""],bgstop:[343,4,1,""],blink:[343,4,1,""],colorback:[343,4,1,""],colorcodes:[343,4,1,""],convert_linebreaks:[343,3,1,""],convert_urls:[343,3,1,""],fg_colormap:[343,4,1,""],fgstart:[343,4,1,""],fgstop:[343,4,1,""],hilite:[343,4,1,""],inverse:[343,4,1,""],normal:[343,4,1,""],parse:[343,3,1,""],re_bgfg:[343,4,1,""],re_bgs:[343,4,1,""],re_blink:[343,4,1,""],re_blinking:[343,3,1,""],re_bold:[343,3,1,""],re_color:[343,3,1,""],re_dblspace:[343,4,1,""],re_double_space:[343,3,1,""],re_fgs:[343,4,1,""],re_hilite:[343,4,1,""],re_inverse:[343,4,1,""],re_inversing:[343,3,1,""],re_mxplink:[343,4,1,""],re_mxpurl:[343,4,1,""],re_normal:[343,4,1,""],re_string:[343,4,1,""],re_uline:[343,4,1,""],re_underline:[343,3,1,""],re_unhilite:[343,4,1,""],re_url:[343,4,1,""],remove_backspaces:[343,3,1,""],remove_bells:[343,3,1,""],sub_dblspace:[343,3,1,""],sub_mxp_links:[343,3,1,""],sub_mxp_urls:[343,3,1,""],sub_text:[343,3,1,""],tabstop:[343,4,1,""],underline:[343,4,1,""],unhilite:[343,4,1,""]},"evennia.utils.utils":{LimitedSizeOrderedDict:[344,1,1,""],all_from_module:[344,5,1,""],at_search_result:[344,5,1,""],callables_from_module:[344,5,1,""],calledby:[344,5,1,""],check_evennia_dependencies:[344,5,1,""],class_from_module:[344,5,1,""],columnize:[344,5,1,""],crop:[344,5,1,""],datetime_format:[344,5,1,""],dbid_to_obj:[344,5,1,""],dbref:[344,5,1,""],dbref_to_obj:[344,5,1,""],dedent:[344,5,1,""],deepsize:[344,5,1,""],delay:[344,5,1,""],display_len:[344,5,1,""],fill:[344,5,1,""],format_grid:[344,5,1,""],format_table:[344,5,1,""],fuzzy_import_from_module:[344,5,1,""],get_all_cmdsets:[344,5,1,""],get_all_typeclasses:[344,5,1,""],get_evennia_pids:[344,5,1,""],get_evennia_version:[344,5,1,""],get_game_dir_path:[344,5,1,""],has_parent:[344,5,1,""],host_os_is:[344,5,1,""],inherits_from:[344,5,1,""],init_new_account:[344,5,1,""],interactive:[344,5,1,""],is_iter:[344,5,1,""],iter_to_str:[344,5,1,""],iter_to_string:[344,5,1,""],justify:[344,5,1,""],latinify:[344,5,1,""],lazy_property:[344,1,1,""],list_to_string:[344,5,1,""],m_len:[344,5,1,""],make_iter:[344,5,1,""],mod_import:[344,5,1,""],mod_import_from_path:[344,5,1,""],object_from_module:[344,5,1,""],pad:[344,5,1,""],percent:[344,5,1,""],percentile:[344,5,1,""],pypath_to_realpath:[344,5,1,""],random_string_from_module:[344,5,1,""],repeat:[344,5,1,""],run_async:[344,5,1,""],safe_convert_to_types:[344,5,1,""],server_services:[344,5,1,""],string_from_module:[344,5,1,""],string_partial_matching:[344,5,1,""],string_similarity:[344,5,1,""],string_suggestions:[344,5,1,""],strip_control_sequences:[344,5,1,""],time_format:[344,5,1,""],to_bytes:[344,5,1,""],to_str:[344,5,1,""],unrepeat:[344,5,1,""],uses_database:[344,5,1,""],validate_email_address:[344,5,1,""],variable_from_module:[344,5,1,""],wildcard_to_regexp:[344,5,1,""],wrap:[344,5,1,""]},"evennia.utils.utils.LimitedSizeOrderedDict":{__init__:[344,3,1,""],update:[344,3,1,""]},"evennia.utils.utils.lazy_property":{__init__:[344,3,1,""]},"evennia.utils.validatorfuncs":{"boolean":[345,5,1,""],color:[345,5,1,""],datetime:[345,5,1,""],duration:[345,5,1,""],email:[345,5,1,""],future:[345,5,1,""],lock:[345,5,1,""],positive_integer:[345,5,1,""],signed_integer:[345,5,1,""],text:[345,5,1,""],timezone:[345,5,1,""],unsigned_integer:[345,5,1,""]},"evennia.web":{urls:[347,0,0,"-"],utils:[348,0,0,"-"],webclient:[353,0,0,"-"],website:[356,0,0,"-"]},"evennia.web.utils":{backends:[349,0,0,"-"],general_context:[350,0,0,"-"],middleware:[351,0,0,"-"],tests:[352,0,0,"-"]},"evennia.web.utils.backends":{CaseInsensitiveModelBackend:[349,1,1,""]},"evennia.web.utils.backends.CaseInsensitiveModelBackend":{authenticate:[349,3,1,""]},"evennia.web.utils.general_context":{general_context:[350,5,1,""],set_game_name_and_slogan:[350,5,1,""],set_webclient_settings:[350,5,1,""]},"evennia.web.utils.middleware":{SharedLoginMiddleware:[351,1,1,""]},"evennia.web.utils.middleware.SharedLoginMiddleware":{__init__:[351,3,1,""],make_shared_login:[351,3,1,""]},"evennia.web.utils.tests":{TestGeneralContext:[352,1,1,""]},"evennia.web.utils.tests.TestGeneralContext":{maxDiff:[352,4,1,""],test_general_context:[352,3,1,""],test_set_game_name_and_slogan:[352,3,1,""],test_set_webclient_settings:[352,3,1,""]},"evennia.web.webclient":{urls:[354,0,0,"-"],views:[355,0,0,"-"]},"evennia.web.webclient.views":{webclient:[355,5,1,""]},"evennia.web.website":{forms:[357,0,0,"-"],templatetags:[358,0,0,"-"],tests:[360,0,0,"-"],urls:[361,0,0,"-"],views:[362,0,0,"-"]},"evennia.web.website.forms":{AccountForm:[357,1,1,""],CharacterForm:[357,1,1,""],CharacterUpdateForm:[357,1,1,""],EvenniaForm:[357,1,1,""],ObjectForm:[357,1,1,""]},"evennia.web.website.forms.AccountForm":{Meta:[357,1,1,""],base_fields:[357,4,1,""],declared_fields:[357,4,1,""],media:[357,3,1,""]},"evennia.web.website.forms.AccountForm.Meta":{field_classes:[357,4,1,""],fields:[357,4,1,""],model:[357,4,1,""]},"evennia.web.website.forms.CharacterForm":{Meta:[357,1,1,""],base_fields:[357,4,1,""],declared_fields:[357,4,1,""],media:[357,3,1,""]},"evennia.web.website.forms.CharacterForm.Meta":{fields:[357,4,1,""],labels:[357,4,1,""],model:[357,4,1,""]},"evennia.web.website.forms.CharacterUpdateForm":{base_fields:[357,4,1,""],declared_fields:[357,4,1,""],media:[357,3,1,""]},"evennia.web.website.forms.EvenniaForm":{base_fields:[357,4,1,""],clean:[357,3,1,""],declared_fields:[357,4,1,""],media:[357,3,1,""]},"evennia.web.website.forms.ObjectForm":{Meta:[357,1,1,""],base_fields:[357,4,1,""],declared_fields:[357,4,1,""],media:[357,3,1,""]},"evennia.web.website.forms.ObjectForm.Meta":{fields:[357,4,1,""],labels:[357,4,1,""],model:[357,4,1,""]},"evennia.web.website.tests":{AdminTest:[360,1,1,""],ChannelDetailTest:[360,1,1,""],ChannelListTest:[360,1,1,""],CharacterCreateView:[360,1,1,""],CharacterDeleteView:[360,1,1,""],CharacterListView:[360,1,1,""],CharacterManageView:[360,1,1,""],CharacterPuppetView:[360,1,1,""],CharacterUpdateView:[360,1,1,""],EvenniaWebTest:[360,1,1,""],IndexTest:[360,1,1,""],LoginTest:[360,1,1,""],LogoutTest:[360,1,1,""],PasswordResetTest:[360,1,1,""],RegisterTest:[360,1,1,""],WebclientTest:[360,1,1,""]},"evennia.web.website.tests.AdminTest":{unauthenticated_response:[360,4,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.ChannelDetailTest":{get_kwargs:[360,3,1,""],setUp:[360,3,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.ChannelListTest":{url_name:[360,4,1,""]},"evennia.web.website.tests.CharacterCreateView":{test_valid_access_multisession_0:[360,3,1,""],test_valid_access_multisession_2:[360,3,1,""],unauthenticated_response:[360,4,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.CharacterDeleteView":{get_kwargs:[360,3,1,""],test_invalid_access:[360,3,1,""],test_valid_access:[360,3,1,""],unauthenticated_response:[360,4,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.CharacterListView":{unauthenticated_response:[360,4,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.CharacterManageView":{unauthenticated_response:[360,4,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.CharacterPuppetView":{get_kwargs:[360,3,1,""],test_invalid_access:[360,3,1,""],unauthenticated_response:[360,4,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.CharacterUpdateView":{get_kwargs:[360,3,1,""],test_invalid_access:[360,3,1,""],test_valid_access:[360,3,1,""],unauthenticated_response:[360,4,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.EvenniaWebTest":{account_typeclass:[360,4,1,""],authenticated_response:[360,4,1,""],channel_typeclass:[360,4,1,""],character_typeclass:[360,4,1,""],exit_typeclass:[360,4,1,""],get_kwargs:[360,3,1,""],login:[360,3,1,""],object_typeclass:[360,4,1,""],room_typeclass:[360,4,1,""],script_typeclass:[360,4,1,""],setUp:[360,3,1,""],test_get:[360,3,1,""],test_get_authenticated:[360,3,1,""],test_valid_chars:[360,3,1,""],unauthenticated_response:[360,4,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.IndexTest":{url_name:[360,4,1,""]},"evennia.web.website.tests.LoginTest":{url_name:[360,4,1,""]},"evennia.web.website.tests.LogoutTest":{url_name:[360,4,1,""]},"evennia.web.website.tests.PasswordResetTest":{unauthenticated_response:[360,4,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.RegisterTest":{url_name:[360,4,1,""]},"evennia.web.website.tests.WebclientTest":{test_get:[360,3,1,""],test_get_disabled:[360,3,1,""],url_name:[360,4,1,""]},evennia:{accounts:[143,0,0,"-"],commands:[149,0,0,"-"],comms:[172,0,0,"-"],contrib:[178,0,0,"-"],help:[236,0,0,"-"],locks:[240,0,0,"-"],objects:[243,0,0,"-"],prototypes:[248,0,0,"-"],scripts:[253,0,0,"-"],server:[262,0,0,"-"],set_trace:[141,5,1,""],settings_default:[313,0,0,"-"],typeclasses:[314,0,0,"-"],utils:[320,0,0,"-"],web:[346,0,0,"-"]}},objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","exception","Python exception"],"3":["py","method","Python method"],"4":["py","attribute","Python attribute"],"5":["py","function","Python function"],"6":["py","data","Python data"]},objtypes:{"0":"py:module","1":"py:class","2":"py:exception","3":"py:method","4":"py:attribute","5":"py:function","6":"py:data"},terms:{"000":[0,25,46,82,114,343],"0000":[0,46],"0004":22,"001":[22,127,343],"002":343,"003":343,"004":343,"005":[114,321,343],"006":343,"007":343,"008":343,"009":343,"00sc":124,"010":[25,343],"011":343,"012":343,"013":343,"014":343,"015":343,"015public":25,"016":343,"017":343,"018":343,"019":343,"020":343,"020t":25,"021":343,"022":343,"023":343,"024":343,"0247":22,"025":343,"026":343,"027":343,"028":343,"029":343,"030":343,"030a":25,"031":343,"032":343,"033":[321,343],"034":[22,343],"035":343,"036":343,"037":343,"038":343,"039":343,"040":343,"040f":25,"041":343,"042":343,"043":343,"044":343,"045":343,"046":343,"047":343,"048":343,"049":343,"050":[321,343],"050f":25,"051":343,"052":343,"053":343,"054":[114,343],"055":[321,343],"056":343,"057":343,"058":343,"059":343,"060":343,"061":343,"062":343,"062022":363,"063":343,"064":343,"065":343,"066":343,"067":343,"068":343,"069":343,"070":343,"071":343,"072":343,"073":343,"074":343,"075":343,"076":343,"077":343,"078":343,"079":343,"080":343,"081":343,"082":343,"083":343,"084":343,"085":343,"086":343,"087":343,"088":343,"089":343,"090":343,"091":343,"092":343,"093":343,"094":343,"095":343,"096":343,"097":343,"098":343,"099":343,"0b16":24,"0d0":56,"0x045a0990":42,"0x852be2c":59,"100":[31,43,56,73,85,93,111,125,169,185,188,217,220,221,343,344],"1000":[56,93,100,116,217,218,219,220,221,251],"1000000":[82,93,337],"100m":343,"100mb":90,"100x100":70,"101":[31,247,343],"101m":343,"102":343,"102m":343,"103":343,"103m":343,"104":343,"104m":343,"105":343,"105m":343,"106":343,"106m":343,"107":343,"107m":343,"108":343,"108m":343,"109":343,"1098":125,"109m":343,"10m":67,"110":[321,329,343],"110m":343,"111":[12,43,114,157,343],"111m":343,"112":343,"112m":343,"113":[90,343],"113m":343,"114":343,"114m":343,"115":343,"115600":56,"115m":343,"116":343,"116m":343,"117":343,"1172":138,"117m":343,"118":[115,343],"1184":23,"118m":343,"119":343,"119m":343,"120":[31,343],"1200":327,"120m":343,"121":343,"121m":343,"122":343,"122m":343,"123":[131,134,247,343],"1234":[54,109,203],"123dark":81,"123m":343,"124":343,"12400":82,"124m":343,"125":343,"125m":343,"126":343,"126m":343,"127":[8,9,24,63,67,90,287,343],"127m":343,"128":343,"128m":343,"129":343,"129m":343,"12s":27,"130":343,"130m":343,"131":343,"131m":343,"132":343,"132m":343,"133":343,"133m":343,"134":[12,43,157,343],"134m":343,"135":343,"135m":343,"136":343,"136m":343,"137":343,"137m":343,"138":343,"138m":343,"139":343,"139m":343,"140":[25,42,141,343],"1400":327,"140313967648552":33,"140m":343,"141":[139,343],"141m":343,"142":[22,180,343],"1424724909023":70,"142m":343,"143":343,"143m":343,"144":343,"144m":343,"145":343,"145m":343,"146":343,"146m":343,"147":343,"147m":343,"148":343,"148m":343,"149":343,"149m":343,"150":[326,343],"150m":343,"151":343,"151m":343,"152":343,"152m":343,"153":343,"153m":343,"154":343,"154m":343,"155":343,"155m":343,"156":[127,343],"156m":343,"157":343,"1577865600":62,"157m":343,"158":343,"158m":343,"159":343,"159m":343,"160":343,"160m":343,"161":343,"161m":343,"162":343,"162m":343,"163":343,"163m":343,"164":343,"164m":343,"165":343,"165m":343,"166":343,"166m":343,"167":343,"167m":343,"168":343,"168m":343,"169":343,"169m":343,"16m":343,"170":343,"170m":343,"171":343,"171m":343,"172":343,"172m":343,"173":343,"1730":79,"173m":343,"174":343,"174m":343,"175":343,"175m":343,"176":343,"1764":119,"176m":343,"177":343,"177m":343,"178":343,"178m":343,"179":343,"179m":343,"17m":343,"180":343,"180m":343,"181":343,"181m":343,"182":343,"182m":343,"183":343,"183m":343,"184":343,"184m":343,"185":343,"185m":343,"186":343,"186m":343,"187":343,"187m":343,"188":343,"188m":343,"189":343,"189m":343,"18m":343,"190":343,"1903":119,"190m":343,"191":343,"191m":343,"192":343,"192m":343,"193":343,"193m":343,"194":343,"194m":343,"195":343,"195m":343,"196":343,"196m":343,"197":343,"1970":62,"197m":343,"198":343,"198m":343,"199":343,"1996":79,"1998":79,"199m":343,"19m":343,"1_7":127,"1d100":[73,185],"1d2":56,"1d6":73,"1gb":90,"1st":62,"200":[343,360],"2001":79,"2003":79,"2004":79,"2008":344,"200m":343,"201":343,"2010":343,"2011":[124,181,214,232],"2012":[179,185,186,187],"2014":[21,213],"2015":[24,189,205,206],"2016":[99,199,202,212,214],"2017":[62,90,97,182,183,184,190,204,209,210,215,217,218,219,220,221,234,235],"2018":[9,180,188,198,203],"2019":[79,187],"201m":343,"202":343,"2020":[12,62,230,363],"2020_01_29":337,"2020_01_29__1":337,"2020_01_29__2":337,"202m":343,"203":[90,343],"203m":343,"204":343,"2048":67,"204m":343,"205":[327,343],"205m":343,"206":343,"206m":343,"207":343,"2076":119,"207m":343,"208":[91,343],"208m":343,"209":343,"209m":343,"20m":343,"210":343,"210m":343,"211":343,"211m":343,"212":[12,343],"2128":56,"212m":343,"213":343,"213m":343,"214":343,"214m":343,"215":343,"215m":343,"216":343,"216m":343,"217":343,"217m":343,"218":343,"218m":343,"219":[9,343],"219m":343,"21m":343,"220":343,"2207":204,"220m":343,"221":[322,343],"221m":343,"222":[114,321,343],"222m":343,"223":[12,343],"223m":343,"224":343,"224m":343,"225":[12,343],"225m":343,"226":343,"226m":343,"227":343,"227m":343,"228":343,"228m":343,"229":343,"229m":343,"22m":[321,343],"22nd":344,"230":[114,343],"230m":343,"231":343,"231m":343,"232":343,"232m":343,"233":[12,43,157,343],"233m":343,"234":[183,343],"234m":343,"235":343,"235m":343,"236":343,"236m":343,"237":[12,343],"237m":343,"238":343,"238m":343,"239":343,"239m":343,"23m":343,"240":343,"240m":343,"241":343,"241m":343,"242":343,"242m":343,"243":343,"243m":343,"244":343,"244m":343,"245":343,"245m":343,"246":343,"246m":343,"247":343,"247m":343,"248":343,"248m":343,"249":343,"249m":343,"24m":343,"250":343,"250m":343,"251":343,"251m":343,"252":343,"252m":343,"253":343,"253m":343,"254":343,"254m":343,"255":[24,321,343],"255fdonatecc":70,"255flg":70,"255fu":70,"255m":343,"256":[12,43,114,156,321],"25m":343,"26m":343,"27m":343,"280":71,"28comput":37,"28gmcp":291,"28m":343,"29m":343,"2d6":[58,185],"2gb":90,"2pm6ywo":37,"300":[114,126,184,331],"3000000":82,"302":360,"30m":[321,343],"31m":[321,343],"31st":62,"32bit":[24,63],"32m":[321,343],"32nd":58,"333":[12,114],"33333":59,"33m":[321,343],"340":56,"34m":[321,343],"358283996582031":93,"35m":[321,343],"360":62,"3600":62,"36m":[321,343],"37m":[321,343],"3872":119,"38m":343,"39m":343,"3c3ccec30f037be174d3":344,"3d6":185,"3rd":62,"4000":[9,36,63,67,75,90,95,100,101,103],"4001":[3,4,8,9,36,63,67,69,75,90,95,100,101,103,133,134,135,137,296],"4002":[8,36,67,90,100],"4003":90,"4004":90,"4005":90,"4006":90,"403":131,"404":69,"40m":[321,343],"41917":287,"41m":[321,343],"4201":90,"425":321,"4280":55,"42m":[321,343],"430000":62,"431":321,"43m":[321,343],"443":[8,67,103],"444":114,"44m":[321,343],"45m":[27,321,343],"46m":[321,343],"47m":[321,343],"48m":343,"49m":343,"4er43233fwefwfw":9,"4th":[38,79],"500":[114,126,321],"50000":82,"500red":321,"505":321,"50m":343,"50mb":90,"516106":56,"51m":343,"520":114,"52m":343,"53m":343,"54m":343,"550":[321,327],"550n":25,"551e":25,"552w":25,"553b":25,"554i":25,"555":[114,204,321],"555e":25,"55m":343,"565000":62,"56m":343,"577349":343,"57m":343,"5885d80a13c0db1f8e263663d3faee8d66f31424b43e9a70645c907a6cbd8fb4":37,"58m":343,"593":344,"59m":343,"5d5":56,"5x5":111,"600":344,"60m":343,"614":138,"61m":343,"62m":343,"63m":343,"64m":343,"65m":343,"6666":40,"6667":[43,72,79,146,164,308],"66m":343,"67m":343,"68m":343,"69m":343,"6d6":56,"70982813835144":93,"70m":343,"71m":343,"72m":343,"73m":343,"74m":343,"75m":343,"760000":62,"76m":343,"775":36,"77m":343,"78m":343,"79m":343,"8080":90,"80m":343,"8111":36,"81m":343,"82m":343,"83m":343,"84m":343,"85000":82,"85m":343,"86400":120,"86m":343,"87m":343,"8859":[15,113],"88m":343,"89m":343,"8f64fec2670c":90,"900":[188,327],"9000":357,"90m":343,"90s":345,"91m":343,"92m":343,"93m":343,"94m":343,"95m":343,"96m":343,"97m":343,"981":204,"98m":343,"990":327,"99999":61,"99m":343,"\u6d4b\u8bd5":25,"abstract":[47,64,86,119,221,316,317,318,334,338,344],"boolean":[13,33,133,137,154,185,188,242,247,259,287,316,319,321,322,338,345],"break":[10,12,14,30,37,42,51,54,57,58,61,91,96,103,108,111,114,125,137,141,166,167,202,226,276,328,329,344],"byte":[15,27,113,269,276,278,287,295,344],"case":[1,6,8,10,11,12,13,14,15,21,22,25,27,28,29,31,33,34,37,38,40,41,42,43,44,46,49,51,55,58,59,60,61,62,64,69,74,79,80,81,82,83,86,88,89,91,95,96,100,102,103,105,107,108,109,110,111,113,114,116,119,120,121,123,125,127,128,131,133,137,144,146,151,153,156,159,165,166,167,170,175,176,179,180,182,185,187,188,196,204,206,211,226,233,238,239,241,242,247,251,256,258,272,276,280,284,298,305,308,316,317,318,319,321,323,334,341,344,349],"catch":[15,26,27,30,43,51,58,87,91,97,102,115,118,146,165,233,257,267,272,279,305,306,316,326,328,334,337,340],"char":[43,56,58,71,73,85,88,105,111,116,117,119,120,133,144,159,165,189,233,247,264,277,290,291,312,321,327,330],"class":[1,2,3,5,6,10,11,12,16,17,20,21,25,26,28,29,30,31,38,39,40,42,43,44,47,49,50,52,53,55,56,57,58,60,61,62,64,68,71,73,77,81,82,85,86,89,91,97,102,105,109,116,117,118,119,120,121,123,124,132,133,134,135,144,146,147,148,149,152,153,154,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,175,176,177,179,180,181,182,184,185,186,187,188,189,192,193,195,196,198,199,202,203,204,205,206,210,211,212,213,214,215,217,218,219,220,221,223,226,228,230,231,232,233,234,235,238,239,242,243,245,246,247,249,251,252,255,256,257,258,259,260,261,264,265,267,269,270,273,274,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,298,300,303,305,306,307,308,310,311,312,314,316,317,318,319,321,322,323,324,325,326,327,328,329,330,331,333,334,335,337,338,339,340,341,342,343,344,347,349,351,352,357,360],"const":234,"default":[0,1,2,3,4,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,27,29,31,32,33,34,35,36,38,39,40,41,42,45,46,47,49,50,51,53,56,57,58,59,62,63,64,65,66,67,68,69,71,72,75,76,77,81,82,83,85,86,87,88,89,90,91,93,95,96,97,100,101,102,103,104,105,106,107,109,111,112,113,114,116,117,118,119,121,123,124,125,126,127,128,129,131,133,134,135,136,138,139,140,141,142,144,146,148,149,150,151,152,153,154,175,177,179,180,181,182,183,184,185,186,187,188,189,190,193,195,196,199,202,203,205,206,209,210,212,213,214,215,217,218,219,220,221,226,231,233,234,235,236,238,239,240,242,247,251,252,256,257,259,260,261,265,267,269,271,272,273,277,289,290,291,296,298,299,305,306,307,308,312,313,316,317,318,319,321,323,324,326,328,329,330,333,334,337,338,339,340,341,344,345,349,357,364],"export":75,"final":[10,23,26,27,29,33,36,38,39,41,43,58,63,67,68,69,70,73,76,80,83,85,86,102,103,105,109,114,116,123,125,126,127,133,134,136,150,151,152,159,164,168,185,215,242,252,304,308,321,323,328,329],"float":[38,49,114,146,184,194,195,198,260,267,279,317,331,340,344],"function":[3,4,5,6,9,10,11,13,14,18,19,20,21,23,25,26,27,29,33,34,37,38,40,41,43,44,46,48,50,52,55,57,58,59,60,61,62,63,64,68,69,73,74,75,77,81,82,83,85,86,88,91,93,96,104,106,107,108,109,110,111,115,118,119,121,122,123,124,125,127,128,133,134,135,137,138,140,141,144,148,151,153,154,156,157,158,159,160,164,165,166,167,169,170,175,176,179,180,181,184,185,187,188,190,194,195,198,199,203,205,206,211,212,215,217,218,219,220,221,226,230,232,233,234,235,239,240,241,242,247,250,251,252,257,259,260,261,267,272,276,287,288,293,296,299,306,308,310,318,319,320,321,322,324,325,326,328,329,331,337,338,339,343,344,345,347,350],"g\u00e9n\u00e9ral":79,"goto":[85,230,328],"import":[0,2,3,4,5,6,9,10,11,13,14,15,16,19,20,21,22,25,27,28,29,30,31,33,39,40,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,68,69,71,72,73,74,76,77,80,81,82,83,84,85,86,89,90,91,93,96,97,102,103,104,105,106,107,110,111,112,113,114,115,116,117,118,119,120,121,123,125,126,127,132,133,134,135,136,137,138,140,141,153,159,169,170,179,180,181,182,183,184,185,187,188,198,199,202,204,205,206,212,213,215,217,218,219,220,221,226,232,233,235,238,242,251,252,261,267,271,279,280,301,305,308,309,316,318,322,323,326,327,328,329,330,341,342,344],"int":[11,25,31,39,49,51,56,58,74,85,91,114,123,125,134,144,146,151,152,154,176,179,182,184,185,188,190,192,194,195,198,206,215,217,218,219,220,221,234,247,252,258,260,261,264,265,267,271,272,276,277,278,279,281,285,286,287,295,296,298,308,310,312,316,317,321,324,326,327,328,329,330,331,334,337,341,344],"long":[9,10,15,20,22,23,25,26,27,29,33,37,38,40,43,44,46,49,51,52,55,58,60,62,64,68,71,72,73,78,79,80,81,85,86,87,90,105,108,111,113,115,118,121,125,126,127,129,131,133,135,138,139,156,159,166,179,186,195,203,213,220,234,276,281,296,321,322,329,330,344],"new":[0,2,5,9,11,12,13,14,16,19,20,21,22,23,24,25,26,27,29,31,33,34,35,36,37,38,39,40,41,43,44,45,49,50,51,54,55,57,61,62,63,64,65,67,68,70,71,72,73,75,76,77,78,79,80,81,82,83,84,85,88,89,90,91,92,93,95,96,98,100,101,104,105,106,107,108,109,111,112,116,117,118,121,122,123,124,128,129,131,132,134,135,136,137,138,139,144,146,152,153,154,156,157,159,164,166,167,169,170,171,175,180,181,182,186,187,188,192,195,199,202,203,204,205,206,212,213,215,217,218,219,220,221,231,232,233,235,239,242,246,247,249,251,252,256,259,260,261,264,267,276,277,278,279,285,286,287,292,299,307,308,312,316,317,318,319,321,322,324,327,328,329,330,334,337,338,344,360,363,364],"null":[8,86],"public":[25,34,41,43,58,65,67,72,90,93,100,103,131,134,164,247,312,330],"return":[3,4,6,10,11,15,20,21,22,25,27,28,29,30,33,36,38,39,40,41,42,43,44,48,49,50,52,58,60,62,64,68,69,71,73,74,76,77,80,81,82,83,85,89,91,93,95,96,97,100,102,103,107,108,109,110,111,112,114,116,117,118,119,121,123,125,127,129,133,134,137,138,144,146,148,150,151,152,153,154,156,159,164,166,169,170,175,176,177,179,180,182,184,185,187,188,190,192,193,194,195,198,199,203,204,205,206,210,211,212,215,217,218,219,220,221,223,226,230,231,232,233,234,235,238,239,241,242,246,247,249,250,251,252,257,258,259,260,261,264,265,267,272,273,276,277,279,280,281,282,284,285,286,287,288,290,291,292,294,295,296,298,299,305,306,308,310,311,312,316,317,318,319,321,322,323,324,325,326,328,329,330,331,334,337,338,339,340,341,343,344,345,347,350,357],"short":[20,22,29,38,39,42,46,51,54,57,58,61,62,70,71,83,87,89,95,96,103,110,112,114,123,129,137,140,164,180,182,195,202,205,206,234,252,322,344],"static":[38,49,58,83,124,127,135,136,137,139,169,180,192,206,214,312,324,347,355,364],"super":[5,22,25,31,40,41,49,57,58,60,62,81,89,96,118,121,123,125,180,182,206],"switch":[0,2,9,10,13,14,16,19,20,23,25,31,33,34,43,46,50,58,65,68,72,76,80,81,82,88,90,98,114,116,121,122,123,125,126,129,131,137,138,156,157,158,159,164,165,166,167,169,185,187,199,202,203,218,226,256,318,324,329,345],"th\u00ed":20,"throw":[11,22,43,66,75,109,131,133,153,260,344],"true":[1,2,4,5,10,11,13,20,21,22,25,26,27,29,31,33,34,38,40,41,49,50,51,54,56,58,62,65,66,68,69,72,74,76,80,81,83,84,85,86,87,90,91,96,98,100,102,105,114,115,116,117,120,121,122,123,125,126,127,133,135,137,138,144,148,150,152,153,154,156,159,164,166,167,170,175,176,177,179,180,182,183,184,185,188,190,192,195,203,204,205,206,212,215,217,218,219,220,221,226,230,231,235,239,241,242,246,247,249,251,252,256,257,258,259,260,261,265,267,272,273,276,278,285,290,295,296,306,308,310,312,316,317,318,321,324,326,328,329,330,331,334,339,340,341,344,345],"try":[0,4,5,6,8,9,10,11,12,13,15,16,20,21,22,23,25,26,27,29,30,38,39,42,43,44,46,48,49,50,51,54,55,56,57,58,60,61,63,64,65,66,67,68,69,73,74,75,77,80,81,86,90,91,93,95,96,97,102,103,108,109,110,111,113,118,119,120,121,123,124,126,127,133,134,135,136,137,138,140,144,148,152,154,159,175,177,179,180,186,196,204,205,206,212,213,217,218,219,220,221,226,231,232,233,235,239,247,251,264,267,276,291,292,296,310,316,318,321,323,324,326,327,340,344],"var":[67,83,88,137,209,291,322],"void":56,"while":[0,9,10,11,13,14,20,22,23,25,28,29,31,33,35,37,38,41,43,49,50,51,55,56,57,58,62,63,70,75,83,86,90,91,93,95,96,103,108,109,110,111,114,116,118,119,121,122,124,127,129,133,134,136,137,138,144,156,159,166,167,170,179,188,196,203,204,218,221,226,231,233,235,247,252,259,291,314,318,328,330,344,345,363],AIs:79,AND:[43,73,80,119,159,188,242,316],ARE:77,AWS:[90,100],Adding:[18,32,33,45,60,71,82,85,108,116,124,139,166,187,328,364],Age:[188,357],And:[0,4,9,10,11,21,22,25,26,29,33,36,41,42,46,51,57,61,62,69,73,80,86,91,96,105,111,126,133,138,153,182,215,217,218,219,220,221,364],Are:[33,61,79,82,328],Aye:46,BGs:126,Being:[58,81,122,123],But:[0,6,10,11,13,15,20,21,22,25,26,27,28,29,31,33,37,38,39,41,42,44,51,54,55,57,59,60,61,62,64,69,72,73,80,82,83,85,86,91,95,96,100,102,104,107,109,111,114,119,125,126,127,133,134,138,152,153,179,319],DNS:[67,90],DOING:188,DoS:285,Doing:[29,33,43,55,73,134,153,156],For:[0,2,5,6,8,9,12,13,14,16,17,19,20,21,22,23,25,27,29,31,33,36,37,38,39,41,42,43,46,49,51,55,56,57,58,59,62,63,64,69,72,73,76,79,80,81,83,85,86,88,90,91,93,95,96,98,100,102,103,105,109,110,111,113,114,116,121,123,126,127,129,131,132,133,134,135,136,138,139,140,144,152,153,159,164,166,169,175,176,177,180,182,185,187,188,189,198,206,212,214,215,218,231,239,242,247,252,260,287,296,316,318,321,325,328,338,340,344,350,357,364],GMs:58,Going:234,Has:[24,217,218,219,220,221],His:[57,189],IDE:[38,48,106],IDEs:57,IDs:[0,100,133,134,194,316,344],INTO:[43,159,188],IOS:24,IPs:[12,103,209,310],IRE:[88,291],Its:[41,62,69,80,83,86,89,105,164,189,226,252,326,328,344],LTS:97,NOT:[11,25,33,43,80,90,103,119,137,159,242,252,310,364],Not:[8,24,30,41,54,57,61,74,90,108,112,115,127,131,132,133,137,146,153,167,247,264,277,278,279,281,282,283,289,291,294,316,317,338],OBS:[19,43],ONE:103,Obs:127,One:[0,8,12,20,22,25,29,34,36,38,46,49,51,57,58,60,63,64,69,76,79,80,87,91,95,102,105,110,115,117,121,123,126,128,130,131,132,138,141,148,150,166,179,185,205,215,231,232,251,252,277,305,316,317,321,322,328,329,344],PRs:131,Such:[6,13,28,33,37,43,48,51,57,64,73,127,159,252,321,328],THAT:91,THE:188,THEN:[153,188],THERE:188,TLS:103,That:[0,3,4,9,10,15,21,22,25,26,31,33,39,41,42,46,49,55,57,62,64,68,69,73,74,77,91,93,95,96,98,102,105,111,112,115,119,122,125,127,131,134,136,138,140,179,180,186,215,242,252,308,328],The:[0,2,4,5,6,7,8,9,12,15,17,20,21,23,24,25,27,28,30,31,33,34,36,37,38,39,40,42,43,44,45,48,52,53,54,55,56,57,59,60,61,62,63,64,66,67,68,70,72,73,74,75,76,78,79,80,81,82,84,86,87,88,89,90,91,92,95,97,98,100,101,102,103,104,105,106,107,108,110,111,112,113,114,115,118,119,120,121,122,124,125,126,127,128,129,131,132,133,134,136,137,138,139,140,144,146,147,148,150,151,152,153,154,156,159,163,164,165,166,167,168,169,170,171,175,176,177,179,180,182,184,185,186,187,188,189,190,192,193,194,195,198,199,203,204,205,206,212,213,215,217,218,219,220,221,223,226,230,231,232,233,234,235,236,238,239,241,242,246,247,249,250,251,252,255,256,257,258,259,260,261,264,265,266,267,269,271,272,274,276,277,278,279,280,281,282,283,284,285,286,287,289,290,291,292,294,295,296,298,299,304,305,306,307,308,312,316,317,318,319,321,322,323,324,325,326,327,328,329,330,331,332,334,337,338,339,340,341,342,344,345,347,357,363,364],Their:[51,73,103,109,114,124,189],Theirs:189,Then:[0,9,15,22,38,39,41,42,46,56,61,63,69,91,93,100,107,127,131,137,187],There:[0,5,8,10,11,13,14,15,19,20,21,22,23,25,26,27,31,33,34,38,41,46,49,51,55,57,58,60,61,62,64,68,69,72,73,77,79,80,81,85,86,88,89,90,91,93,95,96,97,98,102,103,104,105,107,108,111,112,113,114,116,117,118,119,121,123,125,127,128,133,136,138,139,167,187,188,215,217,218,219,220,221,235,252,261,272,291,308,321,322,328,363],These:[0,4,5,9,11,13,17,22,25,33,34,35,38,39,40,43,47,49,51,59,61,65,68,69,73,74,83,86,88,90,91,95,96,100,102,103,105,107,109,110,111,112,114,119,121,122,124,125,127,131,133,137,138,139,143,144,150,152,154,156,158,160,164,168,176,180,184,198,199,203,205,206,210,226,233,238,242,247,251,252,261,266,273,292,295,296,298,307,308,309,316,318,321,325,328,329,330,337,338,339,344],USE:364,Use:[1,2,4,5,8,9,12,13,14,20,22,23,24,25,31,38,43,48,51,54,58,60,63,65,69,70,89,90,93,95,96,100,105,109,114,116,122,123,125,127,131,137,144,151,156,157,159,164,165,166,169,171,175,179,180,184,186,199,202,203,204,206,218,219,220,221,234,246,247,269,273,278,295,296,298,302,316,318,321,327,328,330,334,341,344],Used:[33,43,121,139,150,153,159,188,202,215,235,246,259,269,287,316,318,329,330,344,350],Useful:[12,51,90],Uses:[114,159,171,186,209,231,267,316,330,334],Using:[18,22,27,43,46,51,55,58,60,62,68,80,91,96,115,121,123,139,159,206,218,226,234,247,287,314,328,364],VCS:36,VHS:188,VPS:90,WILL:[24,91],WIS:58,WITH:[23,188],Was:164,Will:[31,38,74,110,114,144,164,184,204,206,247,250,252,265,267,276,277,318,328,330,331,339,344],With:[8,11,15,19,23,55,57,77,87,100,111,114,122,123,141,144,180,206,247,252,316,321],Yes:[33,138,188,326,328],__1:337,__2:337,_________________:125,_________________________:51,______________________________:51,________________________________:51,_________________________________:125,______________________________________:328,______________________________________________:51,_______________________________________________:51,____________________________________________________:51,_________________________________________________________:85,__________________________________________________________:85,__defaultclasspath__:318,__doc__:[33,43,59,68,154,167,169,170,239,324,328],__example__:97,__ge__:97,__getitem__:321,__init_:330,__init__:[3,6,11,40,47,49,53,96,97,107,125,152,153,154,177,179,180,192,204,206,234,242,246,247,251,257,258,260,261,264,265,267,269,270,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,294,295,296,298,305,306,308,310,311,312,316,318,319,321,323,326,327,328,329,330,337,338,339,340,344,351],__iter__:11,__multimatch_command:168,__noinput_command:[152,168,180,326,328,329],__nomatch_command:[168,180,233,326,328],__settingsclasspath__:318,__unloggedin_look_command:[171,186],_action_thre:51,_action_two:51,_all_:152,_asynctest:293,_attrs_to_sync:307,_attrtyp:316,_cach:318,_cached_cmdset:153,_call_or_get:180,_callable_no:328,_callable_y:328,_callback:[27,261],_char_index:321,_character_dbref:181,_check_password:51,_check_usernam:51,_clean_str:321,_cleanup_charact:116,_code_index:321,_copi:[43,159,247],_creation:125,_data:329,_default:[51,328],_defend:51,_differ:321,_errorcmdset:153,_event:198,_evmenu:328,_famili:119,_file:337,_flag:251,_footer:33,_format_diff_text_and_opt:252,_funcnam:344,_get_a_random_goblin_nam:109,_get_db_hold:[306,318],_get_top:69,_getinput:328,_gettabl:272,_http11clientfactori:269,_init_charact:116,_is_fight:29,_is_in_mage_guild:51,_ital:38,_italic_:54,_loadfunc:326,_menutre:[25,51,328],_monitor:272,_monitor_callback:84,_nicklist_cal:146,_npage:329,_oob_at_:334,_option:51,_overrid:135,_page_formatt:329,_pagin:329,_pending_request:312,_permission_hierarchi:241,_ping_cal:146,_playable_charact:[69,133],_postsav:334,_prefix:206,_quell:241,_quitfunc:326,_raw_str:321,_reactor_stop:[284,305],_recog_obj2recog:206,_recog_obj2regex:206,_recog_ref2recog:206,_regex:206,_repeat:272,_safe_contents_upd:246,_savefunc:326,_saver:[11,325],_saverdict:[11,325],_saverlist:[11,325],_saverset:325,_sdesc:206,_select:51,_sensitive_:349,_session:328,_set:119,_set_attribut:51,_set_nam:51,_some_other_monitor_callback:84,_start_delai:261,_static:38,_stop_:344,_stop_serv:284,_templat:38,_test:150,_to_evt:329,_validate_fieldnam:58,_yes_no_quest:328,a2enmod:8,a8oc3d5b:100,a_off:179,a_python_func:38,aardwolf:88,abbrevi:[43,76,114,159,202],abcd:[43,165],abi:60,abid:126,abil:[6,10,20,31,33,52,55,56,57,58,60,73,77,80,90,100,102,108,109,123,127,134,137,138,139,205,206,213,217,218,219,220,221,247,259,267,316],abl:[0,3,4,5,8,11,13,14,19,20,21,22,23,26,27,28,29,31,33,36,41,42,43,47,49,51,52,55,57,58,59,60,61,63,64,69,71,73,75,76,81,83,85,86,87,89,90,91,93,95,96,100,103,104,106,109,111,112,114,116,121,122,123,130,131,133,134,138,140,153,156,157,159,160,164,166,175,177,180,184,190,199,206,212,217,218,219,220,221,316,318,325,340,344,360],abort:[25,27,33,51,52,77,89,122,144,154,159,175,213,233,247,250,328,329,344],about:[0,3,9,10,11,12,13,14,15,16,17,20,21,22,23,24,25,26,30,31,33,36,37,38,39,41,42,44,45,46,48,51,54,55,57,59,60,61,63,64,68,69,70,71,73,75,76,77,78,79,81,83,85,86,90,91,93,95,96,97,100,101,103,104,108,109,110,112,113,114,116,118,119,120,123,124,126,127,131,134,135,136,138,139,144,159,166,169,179,180,182,185,214,219,220,221,232,233,239,247,267,269,272,281,283,285,294,296,298,299,306,308,317,319,321,329,334,344,363],abov:[2,4,8,9,10,11,12,13,14,21,23,24,27,28,29,30,31,33,36,37,40,43,44,46,49,50,51,56,57,58,59,60,62,63,64,67,68,69,74,80,81,84,85,86,90,91,93,95,96,100,102,105,106,109,110,111,112,114,116,118,119,121,123,125,127,131,132,133,135,137,138,140,152,153,159,180,185,188,190,199,204,206,213,214,215,217,219,220,221,242,247,272,328,339,350],abridg:41,absolut:[27,38,56,62,79,91,134,182,184,185,189,327,331,344],absorb:74,abspath:344,abstractus:148,abus:[7,103],academi:79,accept:[11,14,22,23,27,31,37,43,51,54,58,59,74,80,88,90,95,96,109,114,115,125,131,133,134,138,144,150,151,169,179,185,188,193,196,204,205,206,213,231,233,247,267,272,285,311,312,317,322,328,340,344],accept_callback:[193,195],access:[0,4,7,8,11,12,13,14,19,21,22,23,25,27,29,31,33,34,38,39,40,41,47,49,51,52,53,56,57,58,59,60,63,64,66,68,69,71,73,74,80,83,84,85,86,87,89,90,91,95,96,100,101,102,103,104,105,107,108,109,111,112,114,116,119,121,123,124,125,126,127,128,131,133,134,135,137,139,144,148,152,153,154,156,157,159,164,165,166,167,169,175,176,177,180,187,190,192,194,203,205,206,217,218,219,220,221,233,234,239,240,241,242,246,247,250,251,252,256,258,260,261,264,267,276,277,306,308,314,316,318,319,322,323,324,337,343,344,357],access_obj:[241,316],access_opt:345,access_token_kei:[71,120],access_token_secret:[71,120],access_typ:[43,68,144,154,159,175,177,239,241,242,247,316,318],accessed_obj:[25,80,121,241,242],accessing_obj:[1,11,25,80,121,144,175,177,239,241,242,247,316,318],accessing_object:[11,241],accessor:[148,177,239,246,256,316,318,319,335],accessori:63,accident:[15,31,38,43,123,138,157,159,306],accommod:4,accomod:[101,330],accompani:123,accomplish:[12,25,41,49,55],accord:[31,33,111,116,126,180,182,204,205,218,260,321,322],accordingli:[49,58,90,106,234],account1:360,account2:360,account:[0,4,6,9,11,12,14,17,19,20,21,22,24,25,27,31,33,34,35,37,41,45,47,49,50,51,52,53,55,56,57,61,62,65,66,69,71,74,80,81,83,87,89,90,91,92,96,100,104,105,107,108,109,110,111,112,114,119,120,122,123,125,126,127,129,131,133,134,135,138,139,141,142,149,150,151,152,153,154,155,157,159,160,161,164,165,166,167,170,171,175,176,177,180,181,182,184,186,187,188,190,192,193,195,199,206,209,212,217,219,220,221,226,230,231,232,233,235,239,241,242,246,247,249,251,252,253,256,267,271,272,287,298,299,306,307,308,316,318,321,324,328,329,338,339,341,342,344,345,349,357,360,364],account_cal:[156,164,167,199],account_count:308,account_id:[133,247],account_mod:159,account_nam:56,account_search:[206,247],account_subscription_set:148,account_typeclass:[342,360],accountcmdset:[2,22,31,41,43,57,58,62,156,160,181,199],accountdb:[53,119,125,133,141,144,148,175,239,314,318,338,345],accountdb_set:[316,319],accountdbmanag:[147,148],accountdbpasswordcheck:287,accountform:357,accountid:133,accountlist:58,accountmanag:[144,147],accountnam:[43,58,159,171,176,186],accru:144,accur:[22,154,192,218,221,252,260,265,267,269,270,278,287,288,290,292,295,296,316,321,339,340,351],accuraci:[46,91,218,219,220],accus:73,accustom:[87,124],acept:188,achiev:[0,22,27,33,57,114,124,126,138,220,267],ack:52,acquaint:57,acquir:323,across:[16,20,40,51,56,61,86,91,102,105,108,109,125,144,152,153,182,188,205,233,238,247,259,261,264,276,277,291,308,329,330],act:[2,8,13,23,29,31,34,37,43,49,51,56,58,61,70,77,95,102,105,110,111,123,139,141,144,159,164,177,188,215,264,276,277,296,316,319,323,328],action1:116,action2:116,action:[0,11,22,29,39,41,42,43,46,51,55,57,61,62,64,73,88,90,91,93,102,114,116,117,118,123,133,138,144,146,164,165,169,175,179,188,206,217,218,219,220,221,226,230,234,238,239,251,256,257,279,298,299,300,310,318,328,329,334],action_count:116,action_nam:[217,218,219,220,221],actiondict:116,actions_per_turn:[217,218,220,221],activ:[4,9,12,13,26,27,28,31,33,36,38,43,61,62,63,64,65,66,72,75,76,79,80,81,83,89,90,93,95,98,102,105,110,114,128,131,135,136,138,144,150,153,157,159,169,175,193,210,226,231,235,246,247,250,260,272,279,280,281,282,283,287,289,290,291,298,308,310,316,317,328,329,330,344],activest:343,actor:[221,247],actual:[2,5,8,10,11,13,14,19,20,21,22,26,27,29,34,36,38,40,41,42,43,44,46,47,49,51,58,59,60,61,63,64,68,69,71,73,79,80,81,83,85,86,87,88,89,90,91,93,95,96,97,100,104,105,106,109,111,112,113,114,115,116,119,121,123,126,127,128,130,133,134,136,137,138,144,150,154,156,159,164,165,167,169,170,175,177,179,180,182,187,188,198,202,203,205,206,213,214,215,217,218,219,220,221,226,232,233,235,239,241,242,246,247,252,287,290,296,298,304,306,307,308,312,313,316,318,321,323,326,328,334,338,339,340,344],actual_return:127,adapt:[0,4,21,40,69,73,133],add:[0,2,5,6,8,9,10,11,13,14,15,16,17,19,20,21,22,24,26,29,30,31,33,34,35,36,37,38,39,40,41,42,43,44,46,47,48,49,50,51,54,55,57,58,61,62,64,65,66,67,68,69,71,73,74,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,93,95,96,98,100,102,104,105,106,109,111,112,113,114,115,116,117,118,119,120,121,123,124,125,127,128,131,132,133,134,135,137,138,139,140,141,144,148,152,153,159,164,165,166,168,170,175,179,180,181,182,183,185,186,187,192,193,195,196,198,199,202,203,205,206,209,212,213,215,217,218,219,220,221,223,226,230,231,232,233,234,241,242,246,247,252,256,257,258,259,260,261,267,272,273,277,280,281,283,285,289,296,298,299,301,309,316,319,322,326,327,328,329,330,334,337,339,340,364],add_:330,add_act:116,add_alia:164,add_argu:234,add_callback:[193,195],add_charact:116,add_choic:180,add_choice_:180,add_choice_edit:[22,180],add_choice_quit:[22,180],add_collumn:154,add_column:[58,330],add_condit:219,add_default:[21,31,85,96,121,153],add_dist:221,add_ev:195,add_head:330,add_languag:205,add_row:[58,82,154,330],add_user_channel_alia:175,add_xp:73,addcallback:[33,247],addclass:[137,141,142,346,356,358],addcom:[58,164],added:[0,4,5,17,21,22,24,25,27,31,33,34,36,38,40,41,42,43,51,55,57,58,60,65,69,70,73,75,77,78,80,86,88,91,96,100,102,106,108,109,110,111,112,114,116,117,119,121,123,128,131,132,133,138,144,150,152,153,154,164,168,169,179,180,182,183,185,189,192,195,198,205,206,217,218,219,220,221,226,235,242,247,250,252,258,260,272,306,310,316,319,322,328,329,330,337,344,350],addendum:37,adding:[0,3,5,9,14,17,21,22,25,27,29,31,35,36,38,40,43,46,51,57,58,62,69,76,80,81,85,86,91,97,102,104,106,108,109,112,114,115,116,121,123,125,126,128,131,133,137,138,139,152,153,157,159,166,180,184,188,190,192,195,199,205,206,215,217,218,219,220,233,234,251,252,258,267,298,316,324,330,344],addingservermxp:282,addit:[4,8,22,25,31,36,37,46,49,50,51,58,62,69,76,82,88,90,91,103,104,109,114,119,134,144,146,153,154,166,175,180,183,192,193,195,205,209,215,221,234,242,247,250,260,278,306,316,318,328,357],addition:[25,111,119,221],additionalcmdset:31,addpart:203,addquot:344,addr:[264,277,278,279,324],address:[3,9,12,23,33,40,43,49,67,87,90,91,103,105,131,135,144,157,175,186,189,247,264,277,279,287,307,310,344,345,363],address_and_port:287,addresult:203,addscript:[43,159],addservic:40,adjac:[221,231],adject:97,adjoin:206,adjust:[0,33,37,63,126,133,190,260,328,330],admin:[2,9,11,12,15,19,21,33,34,41,49,58,61,68,69,72,80,85,86,98,101,110,119,121,123,133,134,138,141,142,143,148,149,155,159,164,169,171,172,175,186,231,236,239,242,243,246,247,253,262,276,277,314,318,324,340,363],administr:[10,23,33,36,41,55,58,63,64,68,80,103,129,139,264,276,277,364],adminportal2serv:276,adminserver2port:276,adminstr:264,admintest:360,admit:39,adopt:[21,22,26,57,64,177,291],advanc:[10,12,13,22,28,31,33,39,40,43,44,51,55,58,64,79,86,93,104,105,108,109,111,119,123,124,125,139,159,167,187,204,206,217,218,219,220,221,226,282,322,326,327,328,330,364],advantag:[3,14,15,28,36,39,46,51,55,56,58,59,62,68,69,73,90,103,104,109,116,118,123,133,179,180,209,215,217,218,219,220,221,319,322],advent:181,adventur:[20,41,77,111,122,124],advic:79,advis:[0,22,25,77],aeioui:119,aesthet:50,affair:323,affect:[11,13,14,19,25,31,33,43,61,62,73,80,81,105,112,114,116,126,127,128,131,138,144,152,169,183,198,205,212,219,226,247,251,318,322,330,338],affili:260,affliat:260,afford:[85,105],afraid:90,after:[0,5,8,9,10,11,14,15,20,21,22,25,27,28,29,30,31,33,36,38,39,41,43,44,46,49,50,51,55,58,60,63,67,68,76,77,79,80,83,85,86,90,91,96,100,102,103,107,114,116,117,121,122,123,126,127,128,130,131,133,136,138,139,144,152,153,154,155,156,159,166,167,169,170,175,179,180,182,184,185,186,187,188,190,195,203,205,206,215,217,218,219,220,221,226,228,231,232,233,234,235,246,247,252,257,259,260,267,289,290,293,298,305,306,307,308,310,312,316,321,322,323,326,328,329,334,339,342,343,344],after_mov:247,afternoon:187,afterthought:48,afterward:[20,29,69,86,91,119,131,180],again:[0,6,12,13,14,20,21,22,23,28,29,33,39,41,42,43,47,48,49,51,54,56,57,58,60,61,62,63,64,67,69,73,76,80,81,85,86,90,91,93,95,96,98,100,102,105,106,110,111,114,116,119,121,123,126,128,131,133,138,146,153,164,170,184,195,204,217,220,221,226,235,259,267,284,287,290,310,321,322,325,340,342],againnneven:170,against:[6,11,21,31,33,37,57,58,83,90,103,116,119,125,127,144,151,152,206,217,218,219,220,221,242,247,251,252,285,310,316,318,341,344],age:[188,234,357],agenc:103,agent:36,agenta:[114,321],ages:188,aggreg:79,aggress:[11,14,75,122,124,139,231,318,364],aggressive_pac:231,agi:[11,60,127],agil:[11,60],agnost:[37,64],ago:[25,100,344],agre:[1,73,113,179],agree:179,ahead:[14,22,24,36,49,61,90,108,121,289],aid:[113,166,167,179,312],aim:[7,55,58,61,73,85,86,90,95,108,126,251],ain:46,ainnev:[73,119],air:[20,21,111],ajax:[40,55,90,137,296,307],ajaxwebcli:296,ajaxwebclientsess:296,aka:[9,11,93,203,344],alarm:[20,82],alert:[175,247],alexandrian:79,algebra:49,algorith:205,algorithm:344,alia:[2,6,9,20,21,22,31,33,41,44,48,51,57,58,59,60,63,87,89,90,95,105,111,112,119,125,127,129,131,148,151,154,156,159,164,165,166,167,170,175,187,192,206,212,228,231,233,235,241,246,247,252,256,261,272,298,317,318,319,324,340,341,342,357],alias1:[43,159,187],alias2:[43,159,187],alias3:187,alias:[2,13,20,21,22,25,27,29,31,33,34,41,43,44,45,48,51,58,60,74,81,82,85,87,89,109,111,116,119,123,129,131,140,144,152,154,156,157,158,159,164,165,166,167,168,169,170,171,175,176,179,180,181,182,185,186,187,188,189,193,199,202,203,206,212,213,214,215,217,218,219,220,221,226,231,232,233,234,235,238,239,246,247,252,298,317,318,319,324,326,328,329,337,341],aliaschan:[43,164],aliasdb:144,aliashandl:319,aliasnam:252,aliasstr:324,align:[41,58,109,114,190,321,330,344],alik:68,alist:97,aliv:[55,231],alkarouri:343,all:[0,1,2,3,5,6,8,9,10,11,12,13,14,15,16,17,19,20,21,22,23,26,27,28,29,30,31,33,34,35,36,37,38,39,40,41,43,44,46,47,48,49,50,53,54,55,56,57,58,59,60,61,62,63,64,68,70,72,73,74,75,76,77,78,79,80,81,82,83,85,86,87,88,89,90,91,93,95,96,97,98,100,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,121,122,123,124,125,126,127,128,129,131,132,133,134,135,136,137,138,139,140,144,146,149,150,151,152,153,154,155,156,157,158,159,160,161,164,165,166,167,168,169,170,171,175,176,177,179,180,181,182,185,186,187,188,189,192,195,199,202,203,204,205,206,210,212,213,214,215,217,218,219,220,221,226,230,231,232,233,234,235,238,239,240,241,242,243,246,247,250,251,252,257,258,259,260,261,262,266,267,271,272,273,276,278,279,281,283,284,285,286,287,290,291,294,295,296,298,299,305,306,307,308,310,312,313,314,316,317,318,319,321,322,323,324,325,326,327,328,329,330,334,337,339,341,343,344,345,347,350,357,363],all_alias:112,all_attr:318,all_connected_account:308,all_displai:261,all_famili:119,all_from_modul:344,all_opt:339,all_receiv:247,all_room:13,all_script:102,all_sessions_portal_sync:308,all_to_categori:238,allcom:164,allerror:[267,276],allevi:[11,108,127,312],allheadersreceiv:312,alli:221,alloc:90,allow:[0,2,3,4,6,8,9,10,11,12,13,14,15,16,19,21,22,23,25,26,27,29,30,31,33,34,36,38,39,41,42,43,44,46,47,49,51,53,54,55,57,58,59,61,63,64,65,68,71,72,73,74,75,76,78,80,81,85,86,87,89,90,91,92,95,96,97,98,100,101,102,103,104,106,108,109,111,112,113,114,116,119,121,123,125,126,129,131,133,134,135,137,138,144,146,148,150,152,153,154,156,157,158,159,164,166,167,169,170,175,176,177,179,180,182,184,185,187,188,189,195,202,204,205,206,215,217,218,219,220,221,226,231,232,233,234,235,239,241,242,247,251,252,257,260,261,267,271,272,274,278,280,281,282,283,290,291,292,294,299,305,306,308,310,311,316,318,319,321,322,324,326,328,329,330,331,334,338,339,340,342,344,357],allow_abort:328,allow_dupl:152,allow_nan:296,allow_quit:328,allowed_attr:58,allowed_fieldnam:58,allowed_host:90,allowed_propnam:123,allowedmethod:296,allowext:312,almost:[19,33,41,95,115,119,125,180,182,269,276,314],alon:[13,29,49,51,56,58,73,80,86,87,116,127,138,152,166,261,272,298,322,324,330],alone_suffix:303,along:[5,12,33,43,48,51,60,64,70,74,78,88,91,93,96,100,104,107,114,121,122,139,144,156,179,185,205,209,215,220,242,247,296,314],alongsid:[5,38,67,188],alonw:256,alpha:[54,90,321],alphabet:[15,111,113,321],alreadi:[0,2,5,6,9,11,13,15,21,22,25,27,29,31,33,34,38,40,41,43,46,49,50,51,54,56,57,58,60,61,63,64,68,69,70,72,73,77,80,81,82,85,88,89,91,95,96,100,102,103,105,106,109,110,112,116,117,118,119,120,121,123,125,127,128,131,133,134,135,136,137,138,139,152,153,156,159,164,167,169,170,175,176,179,181,182,204,205,206,217,218,219,220,221,231,232,235,242,247,251,252,267,276,284,285,287,292,295,300,305,306,308,316,319,321,324,329,337,344,349],alredi:40,alright:179,also:[0,1,2,3,5,6,8,9,10,11,12,13,14,15,16,17,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,46,47,48,49,50,51,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,72,73,74,75,77,79,80,81,82,83,84,85,86,87,88,89,90,91,93,95,96,97,98,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,121,122,123,124,125,126,127,128,129,131,132,133,134,135,136,137,138,140,144,148,151,152,153,154,156,157,158,159,161,164,165,166,167,169,170,175,176,177,179,180,181,182,185,187,188,190,195,199,202,204,205,206,213,215,219,220,221,226,231,232,233,235,240,241,242,246,247,251,252,253,256,259,261,262,267,271,272,276,278,285,287,290,291,294,295,298,299,308,312,314,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,334,341,344,363],alt:321,alter:[0,4,23,41,64,111,137,316],altern:[23,29,33,34,38,51,55,57,63,64,68,72,76,81,87,90,111,112,114,118,119,122,131,133,138,140,164,167,175,203,206,221,226,241,242,285,321,324,344],although:[22,29,39,42,63,119,156,180,181,185,312,340,344],althougn:46,altogeth:[50,103,114],alu:33,alwai:[0,2,4,6,8,11,12,13,14,20,21,23,25,27,30,31,33,34,37,38,39,43,47,49,51,57,58,61,62,63,64,69,72,73,74,77,80,85,86,88,89,90,91,95,96,102,105,107,109,112,114,115,121,123,125,126,127,128,131,134,135,137,144,152,153,154,156,158,159,164,166,167,170,175,176,177,199,205,206,212,226,241,242,246,247,251,252,261,267,269,272,276,284,287,290,291,295,296,299,306,308,313,316,317,318,319,321,324,334,340,341,344,345,350],always_pag:329,always_return:267,amaz:75,amazon:[79,90],ambianc:108,ambigu:[41,154,189,247,318],ambiti:[108,129],amend:131,amfl:14,ammo:21,among:[2,35,36,43,62,64,79,89,104,111,123,127,165,182,232,242,330,341],amongst:77,amor:196,amount:[11,16,37,43,61,68,73,102,103,114,123,169,217,218,219,220,221,247,308,326],amp:[40,83,92,105,141,142,262,264,267,275,277,285,293,305,308],amp_client:[141,142,262],amp_maxlen:293,amp_port:90,amp_serv:[141,142,262,275],ampclientfactori:264,ampersand:108,amphack:276,ampl:124,amplauncherprotocol:267,ampmulticonnectionprotocol:[264,276,277],ampprotocol:264,ampserverclientprotocol:264,ampserverfactori:277,ampserverprotocol:277,amsterdam:90,anaconda:9,analog:[49,83],analys:51,analysi:210,analyz:[15,33,41,51,80,118,150,159,206,247,251,252,257,267,329,344],anchor:[175,221,239,318],anchor_obj:221,ancient:114,andr:24,android:[139,364],anew:[63,111,175,267],angl:129,angri:41,angular:[43,169],ani:[0,1,2,5,6,8,10,11,12,14,15,16,19,20,21,22,23,24,25,27,30,31,33,34,36,37,38,39,40,41,42,43,44,48,49,50,51,54,56,57,58,59,60,61,63,64,65,68,70,72,73,74,76,77,79,80,81,82,83,84,85,86,87,88,89,90,91,95,96,97,98,100,102,103,104,105,107,109,112,114,115,116,117,118,119,121,122,123,125,126,127,128,129,131,133,134,135,136,137,138,139,140,144,148,150,151,152,153,154,156,157,159,165,166,169,170,175,176,177,179,180,181,182,186,187,188,189,190,194,199,202,204,205,206,209,210,213,217,218,219,220,221,223,226,231,233,234,235,241,242,247,250,251,252,256,257,259,260,261,264,265,267,269,271,272,276,277,279,285,286,287,290,291,295,296,298,306,307,308,312,316,317,318,319,321,322,323,325,326,327,328,329,330,337,338,339,340,341,343,344],anim:[27,52],anna:[43,58,63,72,117,118,123,159],annoi:[12,85,91],annot:79,announc:[25,37,43,79,116,123,128,157,164,169,175,217,218,219,220,221,247],announce_al:[285,308],announce_move_from:[25,77,89,247],announce_move_to:[25,77,89,247],annoy:144,anonym:[4,66,69,206],anonymous_add:206,anoth:[0,8,10,11,13,14,16,21,22,29,31,33,36,39,42,43,46,49,51,56,57,58,62,63,64,67,69,77,78,80,89,90,91,96,97,98,102,105,106,108,109,111,112,113,114,116,121,123,127,131,132,136,137,138,139,140,144,152,153,156,159,164,165,170,175,179,180,182,188,194,199,204,206,215,217,218,219,220,221,232,235,239,247,250,308,316,318,322,326,328,329,344],another_batch_fil:322,another_nod:328,another_script:102,anotherscript:102,ansi:[24,43,53,55,74,81,137,141,142,156,183,190,202,272,279,287,290,295,296,320,330,343,344,364],ansi_escap:321,ansi_map:321,ansi_map_dict:321,ansi_pars:321,ansi_r:321,ansi_regex:321,ansi_sub:321,ansi_xterm256_bright_bg_map:321,ansi_xterm256_bright_bg_map_dict:321,ansimatch:321,ansimeta:321,ansipars:321,ansistr:[141,321,330],ansitextwrapp:330,answer:[0,11,21,25,26,33,46,51,61,63,67,69,70,73,95,96,103,127,265,271,328],anti:63,anul:8,anwer:44,anybodi:[59,103],anymor:[4,181,195,203,204,235,328,340],anyon:[1,4,12,21,25,29,41,42,54,58,60,76,80,85,90,116,118,119,123,138],anyth:[0,1,5,11,13,16,19,20,22,23,26,29,31,33,34,40,41,42,46,49,51,56,61,63,64,69,73,80,82,83,85,87,89,90,91,95,96,100,102,104,106,111,116,118,121,123,125,127,128,130,131,133,135,136,137,138,152,154,168,180,206,215,217,218,219,220,221,242,279,313,316,322,328],anywai:[0,4,14,20,51,55,75,76,91,95,108,114,140,179,181,186],anywher:[33,51,60,64,95,96,125,134,326],apach:[7,23,90,103,139,312,364],apache2:8,apache_wsgi:8,apart:[2,11,20,27,34,47,55,63,80,81,100,104,125,126,127,134,221],api:[13,15,26,27,33,34,42,43,47,48,52,59,60,71,73,89,96,105,109,111,120,125,133,138,139,141,144,158,169,171,177,186,306,316,318,322,323,329,363,364],api_kei:71,api_secret:71,apostroph:15,app:[4,40,71,80,86,134,135,136,138,139],app_id:133,appar:[48,58,126],apparit:233,appeal:[51,61,114],appear:[9,10,21,22,25,26,27,30,38,43,47,48,51,60,63,65,66,68,72,80,82,90,95,96,100,102,104,106,111,114,123,126,127,131,137,138,141,156,166,182,195,206,212,235,247,291,292,318,330,337],append:[20,22,25,27,31,39,40,43,49,50,51,68,69,80,85,88,89,90,91,93,96,97,116,123,127,133,138,154,159,166,182,199,206,242,300,322,337,344],appendto:137,appform:133,appl:[179,247],appli:[0,8,9,13,16,22,23,31,33,36,37,51,60,80,81,102,106,111,115,121,125,126,128,133,144,150,152,167,183,217,218,219,220,221,235,242,247,251,252,256,261,308,316,317,318,321,322,327,330,331,341,344],applic:[8,40,63,79,80,86,100,103,112,124,128,133,134,135,136,144,187,188,221,267,270,280,284,305,306,312,354],applicationdatareceiv:290,applied_d:133,apply_damag:[217,218,219,220,221],apply_turn_condit:219,appnam:[11,80],appreci:[22,37,70,78,334],approach:[22,25,39,56,77,91,106,115,133,180,221],appropri:[8,9,23,31,33,36,55,71,91,106,119,121,129,133,138,144,157,190,267,306,338,340,344,347],approrpri:40,approv:[133,134,138],approxim:[5,43,169,344],april:62,apt:[8,63,67,75,90,103,131],arbitr:61,arbitrari:[11,13,19,27,46,59,64,80,96,97,100,111,125,137,138,139,140,144,175,187,215,221,233,247,252,259,265,276,296,310,316,325,337,340,344],arcan:129,archer:252,architectur:[80,252],archiv:[79,103],archwizard:252,area:[2,22,24,48,49,51,58,61,79,117,122,127,138,231,235,241,327,328,330,344],aren:[0,4,29,39,69,103,127,131,133,136,138,144,182,188,195,203,219,337,340],arg1:[80,154,167,170,175,316],arg2:[154,167,170,316],arg:[1,5,10,21,22,25,29,30,33,38,39,40,41,42,43,51,58,59,68,71,73,74,80,81,83,85,88,96,109,114,115,116,119,121,123,129,132,137,144,146,147,148,151,154,159,167,168,169,170,175,176,177,179,182,184,187,189,192,195,203,204,205,206,212,213,214,215,217,218,219,220,221,223,226,231,232,233,234,235,238,239,241,242,245,246,247,250,251,252,255,256,259,260,261,264,272,273,274,276,277,278,279,284,285,287,288,290,291,292,295,296,300,306,308,310,312,316,317,318,319,321,328,330,331,333,334,337,340,342,344,345,357],arg_regex:[41,44,154,159,165,166,170,171,182,326,328],arglist:167,argn:316,argpars:234,argtyp:344,argu:11,argument:[3,4,5,10,12,14,20,21,22,23,25,27,29,31,33,34,40,41,42,43,46,48,50,52,57,58,59,62,69,74,80,81,83,85,87,88,89,93,95,96,102,109,111,114,115,119,123,124,125,127,129,134,139,144,146,150,151,153,154,156,157,159,164,165,166,167,169,170,175,176,180,182,184,187,188,189,192,194,195,204,205,206,210,212,217,218,219,220,221,233,234,242,247,251,252,257,259,260,261,265,267,272,276,278,279,285,286,287,290,291,295,296,298,299,306,307,308,310,311,316,317,318,319,321,322,324,326,327,328,329,330,334,338,340,341,344,364],argumentpars:234,argumnet:330,aribtrarili:344,aris:103,arm:[26,33,203],armi:85,armor:[29,82,182,218],armour:29,armouri:77,armpuzzl:203,armscii:[15,113],arnold:87,around:[0,4,10,13,14,15,21,23,29,31,34,38,39,42,43,49,55,58,61,63,64,69,70,71,73,77,79,80,85,89,90,91,96,109,111,113,114,116,117,119,121,123,129,136,138,139,159,167,182,184,194,203,206,221,226,231,232,233,235,247,321,322,330,337],arrai:[88,91,291,344],arrang:22,arrayclos:[88,291],arrayopen:[88,291],arriv:[0,25,29,43,73,77,83,105,159,279],arrow:[42,137],art:[114,327],articl:[4,15,21,39,41,48,57,79,113,127,131,335],article_set:335,artifact:330,artifici:73,arx:79,arxcod:[79,139,364],as_view:[175,239,318],ascii:[9,15,111,113,144,327,330,344],asciiusernamevalid:144,asdf:159,ashlei:[182,188,190,215,217,218,219,220,221],asian:344,asid:9,ask:[1,10,21,23,26,34,37,42,43,46,48,50,54,58,63,67,68,69,70,73,84,90,91,93,97,119,124,131,133,152,154,159,179,184,193,204,234,265,267,294,328,331,344],ask_choic:265,ask_continu:265,ask_input:265,ask_nod:265,ask_yes_no:328,ask_yesno:265,asn:209,aspect:[48,51,57,60,64,68,73,86,109,127,190],assert:[116,127],assertequ:127,assertionerror:170,assertregex:127,asserttru:127,asset:[103,136,271,347],assetown:9,assign:[2,6,11,12,13,20,36,43,51,56,58,80,87,89,97,102,109,112,115,116,119,121,123,131,137,138,144,150,151,153,159,164,166,167,170,183,187,188,206,217,218,219,220,221,233,242,246,247,251,252,272,279,285,287,290,306,325],assist:90,associ:[4,11,29,43,51,79,83,90,105,122,135,138,144,149,159,175,192,195,206,247,306,308,317],assum:[0,3,5,9,12,13,14,15,19,20,21,22,25,27,28,29,31,33,34,37,39,40,41,43,44,46,47,49,51,55,56,58,60,62,68,73,74,75,80,81,82,84,85,89,90,95,96,97,100,102,103,105,106,108,109,110,111,113,115,116,117,118,120,121,123,127,128,132,133,134,138,150,152,153,154,156,159,164,166,170,175,180,181,206,213,232,233,241,247,252,257,291,308,321,322,328,344,349],assumpt:151,assur:[49,125],asterisk:[2,12,38,43,157],astronaut:77,astronom:62,async:[133,139,344,364],asynccommand:10,asynchron:[27,28,29,33,45,55,64,92,93,139,146,247,276,277,291,337,344],at_:[125,334],at_access:[144,247],at_account_cr:[2,144],at_after_mov:[77,89,96,117,247],at_after_object_leav:235,at_after_travers:[89,232,247],at_befor:247,at_before_drop:[218,221,247],at_before_g:[218,221,247],at_before_get:[221,247],at_before_mov:[25,77,89,217,218,219,220,221,247],at_before_sai:[96,206,247],at_channel_cr:175,at_channel_msg:175,at_char_ent:117,at_cmdset_cr:[5,21,22,25,30,31,33,41,44,57,58,62,81,85,116,121,123,152,160,161,162,163,179,180,181,182,185,187,199,202,203,206,214,217,218,219,220,221,226,230,231,232,233,298,326,328,329],at_cmdset_get:[144,247,306],at_db_location_postsav:246,at_defeat:[217,218,219,220,221],at_desc:247,at_disconnect:[144,306],at_drop:[218,221,247],at_end:256,at_err:[10,344],at_err_funct:10,at_err_kwarg:[10,344],at_failed_login:144,at_failed_travers:[89,212,232,247],at_first_login:144,at_first_sav:[144,175,247],at_first_start:318,at_get:[182,221,247],at_giv:[218,221,247],at_heard_sai:118,at_hit:231,at_idmapper_flush:[318,334],at_init:[6,107,125,144,175,231,232,233,247],at_initial_setup:[104,271],at_initial_setup_hook_modul:271,at_login:[40,125,278,279,287,290,295,296,306],at_look:[96,144,247],at_message_rec:144,at_message_send:144,at_msg_rec:[144,189,247],at_msg_send:[144,146,189,247],at_new_arriv:231,at_now_add:86,at_object_cr:[5,6,21,25,31,39,43,58,60,73,80,81,85,89,96,121,123,125,132,159,187,189,206,212,214,217,218,219,220,221,226,231,232,233,247,318],at_object_delet:247,at_object_leav:[89,233,235,247],at_object_post_copi:247,at_object_rec:[89,117,233,235,247],at_password_chang:144,at_paus:259,at_post_all_msg:175,at_post_channel_msg:[144,175],at_post_cmd:[30,33,150,154,167,170],at_post_command:33,at_post_disconnect:144,at_post_login:[25,144],at_post_msg:175,at_post_portal_sync:305,at_post_puppet:[96,247],at_post_unpuppet:[96,247],at_pre_channel_msg:[144,175],at_pre_cmd:[33,150,154,167,170],at_pre_command:33,at_pre_login:144,at_pre_msg:175,at_pre_puppet:[96,247],at_pre_unpuppet:247,at_prepare_room:235,at_reload:[43,169,305],at_renam:318,at_repeat:[102,116,120,121,125,146,179,184,195,217,218,219,220,221,223,259,300,331],at_return:[10,344],at_return_funct:10,at_return_kwarg:[10,344],at_sai:[118,247],at_script_cr:[102,116,120,121,146,179,184,195,204,205,217,218,219,220,221,223,235,251,259,300,331],at_script_delet:259,at_search_result:[168,344],at_server_cold_start:305,at_server_cold_stop:305,at_server_connect:285,at_server_reload:[102,110,144,146,247,259],at_server_reload_start:305,at_server_reload_stop:[25,305],at_server_shutdown:[102,110,144,146,247,259],at_server_start:[195,259,305],at_server_startstop:[25,104],at_server_stop:305,at_shutdown:305,at_start:[102,116,146,235,256,259],at_startstop_modul:261,at_stop:[102,116,121,217,218,219,220,221,259],at_sunris:62,at_sync:[306,307],at_tick:[115,261],at_travers:[89,213,235,247],at_traverse_coordin:235,at_turn_start:219,at_upd:[219,257],at_weather_upd:132,ating:170,atlanti:24,atleast:205,atom:98,atop:235,atribut:325,att:51,attach:[4,11,21,41,43,56,58,64,77,89,95,102,105,110,112,119,140,154,159,167,169,189,199,215,235,242,247,258,304,319],attachmentsconfig:4,attachscript:159,attack:[14,28,29,30,46,51,77,90,103,116,119,122,134,139,153,206,215,217,218,219,220,221,231,232,247,252,285],attack_count:220,attack_messag:73,attack_nam:220,attack_skil:252,attack_summari:73,attack_typ:221,attack_valu:[217,218,219,220,221],attempt:[0,2,22,24,29,31,43,51,60,61,87,91,103,106,119,120,135,156,159,187,210,212,217,218,219,220,221,264,267,272,305,310,318,344],attent:[38,56,58,89,103,111],attitud:57,attr1:[43,159,203],attr2:[43,159,203],attr3:[43,159],attr:[11,22,43,49,51,58,80,109,119,136,137,159,166,180,233,241,251,252,306,316,318,334,340],attr_eq:241,attr_g:[80,241],attr_gt:[80,241],attr_l:[80,241],attr_lt:[80,241],attr_n:[80,241],attr_nam:159,attr_obj:[316,318],attr_object:318,attract:37,attrcreat:[80,316],attread:11,attredit:[11,80,316],attrib:242,attribiut:316,attribut:[0,2,6,12,20,22,25,27,28,30,39,41,42,43,45,46,49,50,51,56,57,58,60,61,69,73,74,77,80,81,82,84,85,86,87,89,91,95,102,105,108,109,112,115,116,119,123,125,127,133,134,138,139,141,142,144,148,153,159,168,169,175,180,181,187,194,195,202,203,206,213,217,218,219,220,221,226,231,232,233,241,246,247,250,251,252,256,257,260,272,306,314,317,318,319,324,325,326,337,338,341,344,357,364],attribute1:123,attribute2:123,attribute_list:316,attribute_nam:[144,206,247,341],attributeerror:[42,60,86,306,316],attributehandl:[1,125,316,339,344],attributeobject:11,attrkei:252,attrlist:316,attrnam:[11,43,51,80,109,125,159,241,318],attrread:[11,80,316],attrtyp:[11,316,317],attrvalu:51,attryp:317,atttribut:49,atyp:242,audibl:205,audio:137,audit:[141,142,175,178,207,247],audit_callback:209,auditedserversess:[209,210],auditingtest:211,aug:9,august:[9,344],aut:52,auth:[144,148,164,287,349,357],auth_password:287,auth_profile_modul:148,authent:[40,103,105,107,133,138,144,278,285,287,290,296,306,308,349],authenticated_respons:360,author:[41,90,126,144,192,195],auto:[0,5,12,14,21,31,32,33,34,38,42,43,45,51,63,67,71,89,95,96,105,122,131,133,138,141,144,148,154,158,159,166,169,170,205,206,226,236,239,242,247,252,256,261,264,267,278,288,295,296,305,308,318,323,329,330,349],auto_close_msg:226,auto_help:[33,41,44,51,68,69,154,170,188,230,249,328,329],auto_help_display_kei:[154,170,328],auto_id:357,auto_look:[51,188,230,249,328],auto_now_add:86,auto_quit:[51,188,230,249,328],auto_transl:205,autobahn:[278,284,295],autodoc:38,autofield:133,autologin:349,autom:[14,36,57,58,67,79,86,100,103,110],automat:[0,6,10,14,19,22,23,27,30,31,34,37,38,41,43,46,47,50,51,55,58,60,62,64,65,66,67,68,71,72,80,81,84,85,86,90,96,97,100,102,104,105,109,111,116,117,118,119,121,122,123,124,125,126,128,131,135,136,139,140,144,152,153,154,159,164,165,167,169,170,179,180,181,182,194,195,196,203,204,205,206,214,221,234,242,246,247,258,260,261,272,281,284,287,292,305,308,310,322,326,328,329,330,344,350],automatical:261,autostart:[258,324],autumn:[97,99,187],avail:[0,5,7,8,10,11,13,16,21,22,23,25,26,31,33,36,38,39,40,41,42,43,44,46,48,49,51,53,57,58,60,62,63,64,65,72,74,75,76,77,78,79,80,81,82,85,88,89,90,91,95,96,98,100,102,104,105,106,108,109,110,111,113,114,116,119,121,122,123,125,127,128,130,131,133,134,137,138,139,141,144,150,151,152,153,154,156,159,161,164,165,166,167,169,170,171,179,180,181,185,187,189,195,199,202,204,205,206,214,215,217,218,219,220,221,226,232,233,242,247,250,251,252,256,272,296,298,299,310,322,323,328,329,330,344,350],available_chan:164,available_choic:[51,328],available_funct:251,available_languag:205,available_weapon:232,avatar:[64,88,96,247,287],avatarid:287,avenu:182,averag:[13,43,90,93,169,195,205,234],avoid:[8,11,23,26,27,31,33,37,38,40,42,43,51,80,81,85,95,97,100,109,111,114,125,126,127,129,131,138,139,152,159,204,205,226,234,235,241,246,272,276,286,296,306,316,318,321,322,323,326,329,334],awai:[0,9,10,11,14,15,21,26,29,42,43,46,49,51,55,66,68,69,73,80,86,90,96,102,105,109,111,121,123,131,165,182,215,218,221,226,231,233,235,247,256,307,321,344],await:10,awar:[11,14,26,31,33,44,51,88,95,96,110,125,126,132,133,189,204,206,231,234,235,247,318,321],awesom:[63,135],aws:90,azur:100,b64decod:340,b64encod:340,b_offer:179,baaaad:127,babi:138,bacground:67,back:[0,3,5,10,11,12,13,14,20,21,22,23,25,26,27,29,31,33,34,36,38,43,46,49,50,51,56,58,60,61,63,64,67,69,73,74,81,83,85,86,87,90,91,95,96,97,100,102,105,106,110,111,113,116,118,119,121,122,123,125,126,131,133,135,137,141,144,153,156,159,164,168,179,180,206,212,215,220,226,249,267,272,276,279,285,287,290,305,318,325,328,329,337,344],back_exit:0,backbon:[133,322],backend:[23,36,109,127,135,141,142,316,344,346,348],backend_class:316,background:[10,17,29,51,67,90,103,110,114,126,133,183,190,321],backpack:31,backslash:114,backtick:[38,131],backtrack:131,backup:[10,89,90,105,131,168,322],backward:[50,51,58,121,337],bad:[0,22,24,37,41,58,64,70,76,85,119,127,210,269],bad_back:242,badg:130,bag:344,bake:100,balanc:[29,56,61,79,116,330],balk:95,ball:[31,59,104,151,152,252],ballon:203,balloon:203,ban:[7,25,80,139,144,157,164,170,175,242,364],ban_us:164,band:[45,88,118,137,287,290,291],bandit:46,bandwidth:280,banid:[43,157],bank:61,banlist:175,bar:[51,82,83,84,88,112,135,137,190,206,215,291,328,344],bare:[33,55,58,73,104,190,218],barehandattack:56,bargain:86,barkeep:[42,206],barter:[61,63,102,117,141,142,178],bartl:79,bas:120,base:[3,4,6,9,13,16,17,20,21,22,23,30,33,34,36,38,39,41,42,43,49,51,53,55,56,57,58,60,61,63,64,67,69,72,73,75,77,79,80,83,85,86,89,90,96,100,102,103,105,108,111,113,115,119,120,123,124,125,126,127,129,130,133,134,136,137,138,139,141,144,146,147,148,150,152,153,154,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,175,176,177,179,180,181,182,184,185,186,187,188,189,192,193,195,196,198,199,202,203,204,205,206,210,211,212,213,214,215,217,218,219,220,221,223,226,228,230,231,232,233,234,235,238,239,242,245,246,247,249,251,252,255,256,257,258,259,260,261,264,265,267,269,270,273,274,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,298,299,300,303,305,306,307,308,310,311,312,316,317,318,319,321,322,323,326,327,328,329,330,331,333,334,335,337,338,339,340,341,342,343,344,349,351,352,357,360,364],base_account_typeclass:2,base_char_typeclass:120,base_character_typeclass:[43,81,120,133,134,144,159],base_field:357,base_guest_typeclass:66,base_object_typeclass:[109,252,318],base_script_path:241,base_script_typeclass:102,base_set:9,baseclass:232,basecontain:323,baseline_index:344,baseobject:125,baseopt:338,basepath:344,basetyp:[247,322],basetype_posthook_setup:247,basetype_setup:[39,80,96,144,146,175,247],bash:[36,38,63,67,232],basi:[4,33,37,62,90,136,138,167,177,206,296,318,327],basic:[0,2,3,6,9,15,16,17,19,20,22,26,29,31,33,34,36,39,40,43,46,47,48,56,57,58,60,61,62,69,73,77,79,80,81,83,86,87,110,111,113,116,117,118,121,122,124,126,128,133,134,135,137,139,144,146,159,164,166,175,177,188,194,203,218,220,232,241,243,247,298,342,357,364],bat:[9,63],batch:[18,20,43,48,63,79,111,122,124,139,141,142,158,252,276,316,319,320,364],batch_add:[252,316,319],batch_cmd:14,batch_cod:[13,322],batch_code_insert:13,batch_create_object:252,batch_exampl:322,batch_import_path:[13,14],batch_insert_fil:14,batch_update_objects_with_prototyp:252,batchcmd:[43,158],batchcmdfil:[14,322],batchcod:[14,79,111,158],batchcode_map:111,batchcode_world:111,batchcodefil:13,batchcodeprocessor:322,batchcommand:[14,20,22,63,122,158,322],batchcommandprocessor:322,batchfil:[14,15,111,322],batchprocess:[141,142,149,155],batchprocessor:[13,141,142,158,320],batchscript:[13,322],batteri:144,battl:[79,103,116,122,217,218,219,220,221],battlecmdset:[217,218,219,220,221],baz:215,bazaar:108,beach:111,bear:[204,231],beat:[61,116],beaten:[116,233],beauti:[22,49,133],beazlei:79,becam:[29,126],becaus:[0,2,6,8,9,10,11,12,13,15,16,21,22,25,29,31,36,38,40,41,42,44,46,51,54,56,59,64,68,73,76,77,80,89,91,95,96,107,108,109,111,115,116,117,119,125,126,130,133,134,136,153,166,171,175,186,194,205,220,235,247,259,279,285,298,308,321,338,340,344],becom:[0,5,10,22,37,38,41,42,43,47,49,51,56,59,61,64,70,73,78,80,81,86,87,88,95,96,102,104,109,111,119,128,156,170,189,203,205,215,218,247,252,306,322,328],bed:61,been:[0,4,5,6,13,14,19,21,22,23,36,38,41,42,43,46,49,51,58,69,70,76,79,85,91,93,96,103,105,116,117,123,126,128,131,133,134,135,138,152,153,158,159,164,167,175,180,195,203,204,206,217,218,219,220,221,233,235,239,242,246,247,251,252,260,261,269,281,285,287,295,305,306,307,308,310,316,318,322,326,327,344],befit:125,befor:[1,4,10,11,12,13,14,15,20,21,22,25,27,28,29,31,33,37,41,42,43,46,48,49,51,56,57,58,60,61,67,69,71,75,77,79,80,81,84,85,86,90,91,93,96,97,100,102,103,104,106,107,108,109,111,112,113,114,115,116,117,118,119,121,123,124,125,126,127,131,132,133,134,135,137,138,139,144,150,151,154,159,164,166,167,171,175,184,186,187,188,189,190,194,198,205,206,209,210,215,217,218,219,220,221,226,230,232,233,235,241,242,246,247,250,252,260,261,267,276,285,287,293,299,301,303,305,306,310,312,316,321,322,323,324,328,329,330,331,335,337,340,344],beforehand:[11,131,323],beg:14,beggar:0,begin:[0,4,6,10,13,14,20,22,25,33,38,41,42,43,46,50,51,55,58,61,69,72,80,91,95,96,106,107,111,116,117,119,127,132,134,165,166,194,205,206,215,217,218,219,220,221,247,321,322,328,341],beginn:[55,60,77,79,91,95,124],behav:[11,13,20,22,29,69,91,95,107,110,127,344],behavior:[0,5,11,31,33,41,50,68,69,93,96,102,109,114,126,135,137,138,144,154,170,182,188,219,221,233,234,267,316,328],behaviour:[11,31,33,80,126,313,324,330,344],behind:[11,12,21,33,38,43,49,51,55,59,61,63,74,97,109,112,114,122,126,131,158,204,233,256,261,334],behvaior:329,being:[0,5,6,10,11,13,20,21,22,25,28,31,33,34,36,37,42,43,51,54,56,59,61,63,64,69,83,88,90,91,93,95,96,102,103,107,109,111,115,118,125,126,127,129,131,133,138,144,151,159,165,169,170,175,184,185,189,199,205,206,217,218,219,220,221,226,233,239,247,269,272,279,299,308,310,316,318,321,322,324,328,329,330,344,363],beipmu:24,belong:[4,14,43,64,83,95,103,112,119,133,140,153,206,215,235,239,250],below:[0,1,5,8,9,10,11,12,13,14,15,19,20,22,23,25,27,29,31,33,34,36,38,39,42,43,48,49,50,51,57,58,59,60,61,62,63,64,67,69,70,74,80,81,87,88,90,95,96,100,102,105,106,109,110,111,114,117,118,119,123,125,127,131,133,134,136,138,140,148,159,167,177,180,182,185,190,205,206,215,217,218,219,220,221,228,234,239,246,247,256,279,299,316,318,319,328,330,335],belt:77,beneath:27,benefici:[49,219],benefit:[78,90,100,103,108,127,153,316,322,328],besid:[0,14,31,106,111,190],best:[9,22,24,26,37,50,51,57,58,59,61,72,76,102,103,104,108,133,135,139,166,180,205,215,234,252,267,287,330,338,364],bet:[31,105,138,318],beta:[35,54,90],betray:51,better:[0,9,15,23,25,34,41,42,44,45,51,55,58,59,61,64,68,70,73,81,85,86,91,93,95,108,109,112,114,133,134,181,213,218,233,247,252,284,287,290,298,316,322],bettween:73,between:[0,2,10,14,22,25,28,31,33,36,38,39,40,41,43,46,49,56,57,58,64,67,69,73,76,83,85,87,88,90,91,100,102,105,109,112,113,114,116,120,121,122,123,124,126,131,137,138,140,151,154,159,164,166,169,170,177,179,182,183,194,195,198,199,202,204,205,206,215,217,218,219,220,221,247,252,261,267,276,279,286,287,290,291,298,299,306,319,321,322,324,328,330,331,344,351],bew:187,bewar:39,beyond:[1,2,9,22,25,33,37,52,57,64,88,89,90,102,127,134,154,159,170,177,180,206,215,226,233,251,298,316,318,328,330],bg_colormap:343,bgcolor:343,bgfgstart:343,bgfgstop:343,bgstart:343,bgstop:343,bias:159,bidirect:276,big:[9,11,13,14,20,25,28,29,33,37,45,57,73,80,96,122,138,140,151,166,168,226,322,329,341,344],bigger:[21,37,40,69,119,123,205],biggest:[72,138,344],biggui:33,bigmech:21,bigsw:29,bikesh:119,bill:[90,103],bin:[4,9,36,47,63,64,75,96,100],binari:[23,47,63,93,95,278,280,295],bind:67,birth:357,bit:[0,4,9,12,17,22,26,29,35,39,41,42,43,46,59,61,62,63,69,75,76,81,96,102,106,109,121,122,127,131,134,137,138,164,171,186,242,247,322],bitbucket:57,bite:[61,111],black:[73,114,126,321],blackbird:79,blackbox:138,blacklist:[103,164],blade:232,blank:[51,86,117,134,144,188,321],blankmsg:188,blarg:83,blargh:109,blatant:12,blaufeuer:119,bleed:[114,131,330],blend:203,blender:203,bless:138,blind:[114,118,226],blind_target:226,blindcmdset:226,blindli:242,blink:[20,226,343],blink_msg:226,blist:97,blob:[37,38,95,104,138],block:[3,12,25,28,43,50,51,55,58,64,69,80,90,91,97,102,103,110,114,123,129,133,134,139,157,158,159,187,221,230,231,232,235,249,286,322,328,344],blocking_cmdset:25,blockingcmdset:25,blockingroom:25,blocktitl:69,blog:[37,55,79,90,98],blowtorch:24,blue:[13,57,81,114,126,232,321],blueprint:[57,96,111,137],blurb:54,board:[34,49,61,79,80,121],boat:[31,121,153],bob:[33,43,81,138,157],bodi:[3,17,22,27,33,38,41,46,51,58,95,109,127,129,133,193,199,269,324],bodyfunct:[20,102,141,142,178,222,228],bog:21,boi:112,boiler:125,bold:54,bolt:252,bone:[55,73],bonu:[41,73,90,218,219,256],bonus:[29,218],book:[3,49,62,73,79,91,95,109,135],bool:[2,31,33,34,51,74,84,102,144,146,148,150,151,152,153,154,159,164,166,175,176,177,179,180,182,184,185,188,190,192,195,204,205,206,215,217,218,219,220,221,235,238,239,242,246,247,251,252,256,257,258,259,260,261,267,272,273,278,279,284,285,286,290,295,296,304,306,308,310,316,317,318,319,321,322,324,326,328,329,330,331,334,337,339,341,343,344],booleanfield:133,boom:[21,51],boot:[80,100,110,157,164,175,261],boot_us:164,bootstrap:[4,124,138,139,364],border:[43,58,111,156,170,188,327,330],border_bottom:330,border_bottom_char:330,border_char:330,border_left:330,border_left_char:330,border_right:330,border_right_char:330,border_top:330,border_top_char:330,border_width:330,borderless:58,borderstyl:188,bore:[12,55,103],borrow:[31,63,152,276],bort:[52,328],boss:58,bot:[43,47,65,72,93,103,119,133,141,142,143,148,164,272,278,279,286,308],bot_data_in:[146,272],both:[0,11,15,19,22,23,25,26,27,31,33,34,36,37,38,40,43,44,49,51,56,57,58,62,65,69,71,74,79,84,85,86,87,88,90,91,95,97,103,104,105,106,110,111,116,119,121,124,125,127,128,131,133,134,136,138,150,152,159,164,169,177,179,183,190,199,203,212,215,220,221,233,242,247,251,252,253,256,259,261,276,285,295,296,298,305,307,310,316,317,321,324,328,330,339,344],bother:[29,103,128,316],botnam:[43,72,164,279,308],botnet:103,botstart:146,bottom:[4,39,41,52,54,57,58,60,69,85,95,101,106,111,125,127,133,137,153,199,220,235,252,322,329,330],bought:85,bouncer:[27,103,327],bound:[6,27,57,108,192,344],boundari:344,bounti:70,bountysourc:70,bow:252,box:[0,3,8,20,42,43,46,58,63,66,69,70,71,73,80,87,90,104,106,109,111,123,135,138,159,206,241,276,322,357],brace:[0,22,25,41,91,247,321],bracket:[38,43,96,129,169,183],brainstorm:[139,364],branch:[9,36,37,38,41,63,100,204,215],branchnam:131,brandymail:199,bread:16,breadth:221,break_lamp:226,break_long_word:330,break_on_hyphen:330,breakdown:[43,169],breakpoint:[16,106,141],breez:[102,132],breviti:58,bribe:51,brick:82,bridg:[22,23,53,79,83,105,233],bridgecmdset:233,bridgeroom:233,brief:[3,16,19,20,21,25,46,58,60,85,86,95,96,101,110,124,131,139,188,234,247,311],briefer:[89,110],briefli:[16,90,110,226],bright:[81,114,126,183,226,321],brightbg_sub:321,brighten:114,brighter:114,brilliant:131,bring:[23,49,96,100,103,121,123,133,136,215,221,231,309],broad:39,broadcast:[43,144,175,276],broader:[39,206,247],broken:[61,108,114,205,226],brought:102,brown:321,brows:[3,9,25,39,55,58,62,69,85,90,91,103,106,123,131,136,137,138],browser:[3,8,9,16,38,55,63,64,67,69,70,75,77,90,95,96,101,103,133,134,135,136,137,138,295,296],brutal:234,bsd:78,bsubtopicnna:170,btest:114,btn:[17,70],bucket:209,buf:326,buffer:[22,33,50,137,168,269,296,326],bug:[10,13,26,37,42,54,57,60,61,70,78,95,96,110,123,127,131,247,318],buggi:[11,328],bui:[85,138,179],build:[1,6,7,9,10,11,13,14,15,27,31,36,47,51,55,57,60,63,64,68,69,75,77,79,80,81,86,87,89,96,100,105,106,108,109,112,113,119,120,122,123,125,129,130,136,137,139,140,141,142,149,151,155,157,158,165,166,169,180,187,193,205,206,212,231,234,242,247,251,252,267,278,279,322,330,357,363,364],build_match:151,builder:[2,4,14,19,22,25,43,56,58,60,61,68,80,85,108,109,112,114,123,124,139,157,159,164,165,169,180,182,187,188,203,206,212,226,233,234,235,242,247,298,318,322,363,364],buildier:252,building_menu:[141,142,178],buildingmenu:[22,180],buildingmenucmdset:180,buildprotocol:[264,277,278,279],buildshop:85,built:[13,16,20,27,38,40,51,54,55,57,58,61,63,64,73,75,77,95,96,100,103,121,122,123,135,138,139,148,177,203,205,239,246,256,261,316,318,319,322,326,328,335],builtin:280,bulk:[96,103],bullet:[38,61],bulletin:[61,79,80],bulletpoint:38,bunch:[15,27,58,108,113],burden:82,buri:[108,122],burn:[61,73,90,232],busi:[64,70,90,179],butch:96,butt:138,butter:16,button:[9,13,14,31,33,43,80,83,87,88,106,131,133,134,135,137,138,159,226,232,299,329],button_expos:232,buy_ware_result:85,byngyri:205,bypass:[4,10,19,20,43,58,80,116,126,144,159,175,212,242,318,324,341,344,349],bypass_mut:175,bypass_superus:80,bytecod:321,bytestr:[276,344],bytestream:344,c20:164,c_creates_button:299,c_creates_obj:299,c_dig:299,c_examin:299,c_help:299,c_idl:299,c_login:299,c_login_nodig:299,c_logout:299,c_look:299,c_measure_lag:299,c_move:299,c_moves_:299,c_moves_n:299,c_social:299,cabl:82,cach:[6,8,11,12,28,33,39,43,86,119,125,127,130,137,144,154,169,175,187,231,232,242,246,247,271,310,316,318,319,320,332,334,344],cache_inst:334,cache_lock_bypass:242,cache_s:[310,334],cached_properti:344,cactu:220,cake:31,calcul:[10,25,27,39,73,116,119,123,139,153,184,187,198,205,217,218,220,221,252,331,334,344],calculated_node_to_go_to:51,calculu:56,calendar:[184,198,331],call:[0,2,3,4,5,6,10,11,13,14,16,20,21,22,23,25,26,27,28,29,30,31,36,38,39,40,41,42,43,46,47,48,49,50,51,55,56,57,58,59,60,61,62,63,64,65,69,71,72,73,74,75,80,81,83,84,85,86,88,89,90,91,93,95,96,100,102,104,105,107,108,109,110,111,114,115,116,117,118,119,120,121,122,123,125,126,127,128,131,132,133,134,135,137,138,144,146,150,151,152,153,154,156,159,164,167,168,169,170,171,175,179,180,182,184,185,186,187,188,189,192,193,194,195,196,198,203,204,205,206,212,214,215,217,218,219,220,221,223,226,230,231,232,233,234,235,241,242,246,247,250,251,252,257,259,260,261,264,267,269,271,272,276,277,278,279,280,281,282,283,285,286,287,288,289,290,291,292,294,295,296,298,299,300,305,306,307,308,309,312,316,318,319,321,322,323,324,326,328,329,330,331,334,337,339,340,341,344,357],call_async:10,call_command:127,call_ev:[0,194],call_inputfunc:[83,306,308],call_task:260,callabl:[49,50,84,109,115,123,180,188,195,215,219,247,250,251,252,257,261,265,267,269,277,308,323,326,328,329,337,339,340,344],callables_from_modul:344,callbac:22,callback1:328,callback:[4,10,22,27,29,33,50,51,62,74,84,115,138,146,169,180,184,188,192,193,194,195,196,198,210,215,230,247,257,260,261,265,267,269,272,276,277,278,280,294,295,298,309,328,331,337,342,344,364],callback_nam:[192,195],callbackhandl:[141,142,178,191],called_bi:150,calledbi:344,caller:[5,10,11,13,21,22,25,27,28,29,30,33,38,41,42,43,44,49,50,56,58,59,60,71,73,80,81,82,83,85,86,87,88,89,91,111,115,116,119,121,123,125,129,137,146,150,151,152,154,156,159,160,164,165,166,167,169,170,180,188,193,199,203,206,214,215,226,230,232,233,234,235,242,247,249,251,252,322,326,328,329,338,344],callerdepth:344,callertyp:150,callinthread:312,calllback:194,callsign:[51,272],calm:111,came:[9,21,25,55,79,111,132,138,231,235,247],camp:111,campfir:111,campsit:111,can:[0,1,2,3,4,5,6,9,10,12,13,14,15,17,19,20,21,23,24,25,26,27,28,29,30,31,33,34,35,36,37,38,39,40,41,42,43,44,46,48,49,50,51,54,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,95,96,97,98,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,130,131,133,134,135,136,137,138,139,140,143,144,146,148,151,152,153,154,156,157,159,164,165,166,167,168,169,170,175,176,177,179,180,182,183,184,185,187,188,189,190,194,195,198,199,203,204,205,206,209,212,215,217,218,219,220,221,226,231,232,233,234,235,239,241,242,246,247,250,251,252,253,256,257,259,261,267,278,282,285,287,290,291,295,296,298,299,305,306,307,308,309,312,313,314,316,317,318,319,321,322,323,324,326,327,328,329,330,338,339,340,341,342,344,345,357,363],can_:194,can_list_top:166,can_read_top:166,cancel:[27,29,74,169,194,217,218,219,220,221,247,260],candid:[22,33,119,133,151,203,206,247,341],candl:153,cannot:[5,9,10,11,13,14,19,21,22,25,27,28,29,31,33,39,43,44,46,50,51,56,60,61,63,69,70,73,76,80,85,90,104,109,112,114,122,123,127,128,133,139,144,146,153,156,159,166,180,187,188,192,195,212,215,221,231,232,238,242,247,251,261,316,323,325,327,330,334,344],cantanker:338,cantclear:188,cantillon:79,cantmov:25,canva:49,capabl:[6,36,43,49,58,64,80,83,88,105,156,214,272,294,357],cape:57,capfirst:69,capit:[9,12,25,29,43,64,88,95,123,159,189,204,205,321],captcha:133,caption:38,captur:[25,91,138,337],car:[87,121],card:103,cardin:[43,44,49,58,159],care:[0,4,10,12,23,33,38,44,49,51,56,57,62,64,78,86,91,110,116,121,126,132,144,152,175,187,203,206,230,231,233,241,247,298,318,322,326,328,329,330,344],carefulli:[55,93,105,111,133],carri:[20,31,61,80,82,85,116,117,177,182,218,231,241,306,317],cascad:334,caseinsensitivemodelbackend:349,cast:[28,109,112,215,220],caster:[28,220],castl:[13,111,122,187,233],cat:[67,75],catchi:4,categor:112,categori:[1,5,11,33,36,39,43,51,68,69,86,109,112,119,127,140,154,155,156,157,158,159,164,165,166,167,168,169,170,171,179,180,181,182,185,186,187,188,189,193,199,202,203,206,212,213,214,215,217,218,219,220,221,226,231,232,233,234,238,239,241,247,251,252,298,316,317,319,324,326,328,329,335,338,341,344],categoris:56,category2:335,category2_id:335,category_id:335,category_index:215,cater:29,caught:[42,51,97,176],caus:[11,12,29,30,31,42,60,61,64,77,80,90,96,114,116,117,119,123,127,137,140,153,175,186,226,235,247,298,328,330,344],caution:[62,137,328],cave:46,caveat:[5,10],caveman:56,cblue:131,cboot:[12,164],cc1:63,cccacccc:327,ccccc2ccccc:58,cccccccc:327,ccccccccccc:58,cccccccccccccccccbccccccccccccccccc:327,ccccccccccccccccccccccccccccccccccc:327,ccreat:[41,58,65,72,98,164],cdesc:[41,164],cdestroi:164,cdmset:31,cdn:103,ceas:[43,77,159],cel:327,celebr:61,cell:[58,69,111,188,327,330],celltext:327,censu:317,center:[4,16,39,49,109,111,114,190,321,330,344],center_justifi:109,centos7:67,centr:111,central:[26,55,61,64,74,100,111,123,124,127,132,138,139,144,153,170,175,177,247,252,276,324,328,334,347,363,364],centre_east:111,centre_north:111,centre_south:111,centre_west:111,centric:[9,80,105,123,206],cert:[8,288,292],certain:[13,14,16,19,25,29,31,33,37,38,43,48,64,75,80,88,90,97,102,105,107,108,114,115,121,138,159,176,179,205,209,226,232,235,241,251,259,267,273,290,294,309,316,317,326,330,341,344,357],certainli:[15,44,138],certbot:[67,90,103],certfil:[288,292],certif:[8,90,288,292],certonli:67,cet:337,cfg:67,cflag:75,cgi:90,cha:[51,58],chain:[0,10,29,46,51,109,119,194,195,299,328],chain_1:0,chainedprotocol:287,chainsol:119,chair:[13,61,89,91,112,125],challeng:[73,79],chan:164,chanalia:[43,164],chanc:[21,22,28,31,54,61,66,73,115,116,122,131,152,217,218,219,220,221,226,232,233,299],chance_of_act:299,chance_of_login:299,chandler:116,chang:[2,3,4,7,8,9,11,12,13,14,15,16,19,20,21,22,23,26,29,30,31,33,34,35,36,37,39,41,42,43,45,47,49,50,51,53,54,57,61,62,63,64,66,67,68,71,73,74,75,77,78,80,81,83,84,85,86,87,89,90,91,95,96,100,102,104,105,107,109,110,111,112,114,115,116,118,121,123,125,126,127,132,133,134,135,137,138,139,144,153,154,156,157,159,164,165,170,175,179,180,182,186,187,189,190,192,195,202,205,206,212,213,215,217,218,219,220,221,231,232,233,234,235,239,247,252,256,257,259,260,261,267,272,283,298,305,306,313,316,318,322,325,326,329,330,337,338,339,340],change_name_color:215,changeabl:76,changelock:164,changelog:96,changepag:134,changepassword:12,chanlist:43,channam:41,channel:[2,6,7,11,12,19,27,31,33,45,53,55,65,70,71,72,79,80,82,86,87,90,98,107,112,119,123,124,125,138,139,144,146,152,153,159,164,170,172,175,176,177,195,226,271,278,279,286,299,306,308,316,324,337,341,360,364],channel_:[34,175],channel_ban:[41,164],channel_color:25,channel_command_class:[34,41],channel_connectinfo:306,channel_list_ban:164,channel_list_who:164,channel_msg:144,channel_msg_nick_pattern:175,channel_msg_nick_replac:[164,175],channel_msg_pattern:164,channel_prefix:[25,175],channel_prefix_str:175,channel_search:176,channel_typeclass:360,channelalia:[164,175],channelcl:164,channelcmdset:31,channelcommand:[34,41],channelconnect:177,channelcr:[43,164],channelcreateview:175,channeldb:[41,53,125,141,175,177,314],channeldb_set:[316,319],channeldbmanag:[176,177],channeldeleteview:175,channeldesc:41,channeldetailtest:360,channeldetailview:175,channelhandl:[34,41,141,142,172],channelkei:[41,176],channellist:43,channellisttest:360,channelmanag:[175,176],channelnam:[34,41,72,144,146,164,175,278],channelupdateview:175,char1:[43,73,127,165,170,360],char2:[43,73,127,165,360],char_health:233,char_nam:133,charac:84,charact:[0,2,5,9,11,14,15,17,19,20,21,22,23,27,28,29,30,31,33,34,36,39,40,41,42,43,45,47,49,50,51,53,55,56,57,62,68,69,71,74,76,77,80,81,83,85,86,87,88,91,95,97,102,105,111,113,114,116,117,118,119,120,121,122,124,125,127,129,135,136,138,139,141,143,144,151,152,154,156,159,160,161,165,166,167,169,175,180,181,182,187,188,189,190,192,194,195,199,202,204,205,206,209,214,215,217,218,219,220,221,223,226,231,232,233,235,239,242,247,259,272,293,306,311,316,318,321,322,327,328,330,342,344,345,357,360,364],character1:73,character2:73,character_cmdset:187,character_id:247,character_typeclass:[127,144,342,360],charactercmdset:[5,21,22,25,30,31,41,43,44,57,58,60,62,81,123,161,180,182,187,199,202,212,217,218,219,220,221,233],charactercreateview:360,characterdeleteview:360,characterform:357,characterlistview:360,charactermanageview:360,characternam:114,characterpuppetview:360,charactersheet:51,characterupdateform:357,characterupdateview:360,charapp:133,charat:188,charcreat:[0,46,69,156,181],chardata:58,chardelet:156,chardeleteview:[239,318],chardetailview:[239,318],charfield:[86,133,340,357],charg:90,chargen:[133,139,141,142,175,178,239,318],chargencmdset:123,chargenroom:123,chargenview:[239,318],charnam:[43,58,156],charpuppetview:318,charset:344,charsheet:58,charsheetform:58,charupdateview:[239,318],chase:122,chat:[1,2,9,26,34,37,48,55,58,60,63,65,70,72,79,80,98,123,131,139,296,337],chatroom:57,chatzilla:72,cheap:131,cheaper:[61,115],cheapest:90,cheapli:233,cheat:[23,38,73],cheatsheet:48,chec:170,check:[0,4,5,12,13,14,19,22,25,26,27,28,29,31,33,36,37,38,39,40,41,42,43,44,46,49,51,54,56,58,60,63,65,67,68,69,70,71,73,77,81,82,85,86,87,89,90,91,95,97,98,100,102,103,106,109,110,111,112,114,115,116,117,118,119,121,123,125,127,128,130,131,133,136,138,139,144,150,151,152,153,154,156,158,159,164,165,166,167,169,170,171,175,177,179,181,182,186,187,188,195,199,217,218,219,220,221,223,226,231,233,234,235,241,242,246,247,251,252,256,258,259,260,266,267,271,276,282,287,306,308,310,311,312,316,318,319,321,322,324,338,339,344,345],check_attr:159,check_circular:296,check_databas:267,check_db:267,check_defeat:73,check_end_turn:116,check_error:266,check_evennia_depend:344,check_from_attr:159,check_grid:49,check_has_attr:159,check_light_st:233,check_lockstr:[4,80,242],check_main_evennia_depend:267,check_obj:159,check_permiss:251,check_permstr:[144,318],check_to_attr:159,check_warn:266,checkbox:133,checker:[15,49,241,287,345],checkout:[9,100,131],checkoutdir:36,chest:[80,91],child:[6,33,43,51,64,80,96,116,146,148,154,159,170,233,246,252,256,312,335],childhood:51,children:[21,33,64,96,112,117,119,125,148,246,247,256,267,317,335],chillout:[43,159],chime:27,chines:[25,79,113],chip:58,chmod:36,choci:180,chocol:60,choic:[4,15,23,33,43,51,55,60,78,90,91,95,105,107,109,113,116,119,124,127,129,132,144,156,159,179,180,188,217,234,265,326,328],choice1:129,choice2:129,choice3:129,choos:[7,9,10,13,38,49,51,57,62,64,67,72,73,85,101,106,116,120,123,126,133,135,138,139,140,170,214,215,217,218,219,220,221,226,231,280,328,343,364],chop:[33,232],chore:68,chose:[54,58,86,103,133,215,328],chosen:[22,51,88,106,116,132,138,188,190,328],chown:100,chractercmdset:233,christin:96,chrome:24,chronicl:188,chroot:67,chug:33,chunk:[13,69,111,269,322],church:27,church_clock:27,cid:299,cillum:52,circl:39,circuit:137,circular:[269,323],circumst:[46,51,57,85,119,152,220,357],circumv:[43,157],claim:83,clang:75,clank:0,clarif:[1,48],clarifi:25,clariti:[75,86,91,123],clash:[23,31,43,90,159,318,328],class_from_modul:344,classic:[3,13,79,105,112,115,116],classmethod:[39,144,175,239,247,259,318,334,351],classnam:11,classobj:318,claus:[78,118],clean:[1,4,17,25,28,43,48,51,76,110,111,114,116,122,131,152,154,159,169,179,206,217,218,219,220,221,232,233,235,247,256,267,271,285,295,308,318,321,326,328,334,340,343,344,357],clean_attribut:[125,144,318],clean_cmdset:[125,318],clean_senddata:308,clean_stale_task:260,clean_str:321,cleaned_data:133,cleaner:[91,123],cleanli:[64,102,105,110,150,154,164,188,269,278,284,295,308,326],cleanup:[1,11,22,33,40,43,45,50,51,102,127,179,230,233,328],clear:[1,4,11,12,15,22,29,33,37,38,40,43,48,50,59,61,64,69,70,73,81,104,110,111,112,113,115,125,128,129,131,132,137,138,153,156,157,159,165,188,204,206,233,242,246,247,257,260,261,269,306,310,316,318,319,328,334],clear_attribut:316,clear_client_list:303,clear_cont:[89,247],clear_exit:[89,247],clearal:[43,129,165],clearli:[12,37,48,128,334],cleartext:[210,324],clemesha:312,clever:[10,31,51,95,242],cleverli:105,click:[36,38,69,90,101,106,114,128,131,133,135,137,138,328],click_top:166,clickabl:[18,38,166],clickable_top:166,client:[3,7,8,9,12,22,23,25,30,33,36,40,43,45,50,52,54,55,60,63,64,65,67,72,74,75,79,81,84,91,95,96,100,101,103,104,105,107,108,111,113,114,116,117,126,128,136,138,139,141,142,144,146,154,156,164,166,169,210,262,264,268,270,272,276,277,278,279,280,281,282,283,285,287,289,290,291,292,294,295,296,298,299,305,306,307,308,325,326,328,343,344,364],client_address:40,client_default_height:52,client_disconnect:296,client_encod:23,client_opt:[272,291],client_secret:65,client_width:[33,154],clientconnectionfail:[264,278,279],clientconnectionlost:[264,278,279],clienthelp:137,clientkei:298,clientraw:[43,169],clientsess:[295,296],cliff:[20,43,159],climat:112,climb:[33,43,55,77,93,159,232],climbabl:232,clipboard:[1,48],clist:43,clock:[12,27,33,73,164],clone:[38,47,63,64,76,96,128,130],close:[0,14,22,25,38,39,40,41,43,46,48,50,51,64,69,76,90,96,100,103,105,106,110,125,131,133,137,169,171,179,180,186,190,212,221,226,230,269,277,278,285,287,295,296,308,316,322,328],close_menu:[230,328],closer:[205,221],closest:[39,114,344],cloth:[141,142,178,322],clothedcharact:182,clothedcharactercmdset:182,clothes_list:182,clothing_typ:182,clothing_type_count:182,clothing_type_ord:182,cloud:[90,100,102,103,132],cloudi:102,clr:[114,251],cls:[39,144],clue:232,clunki:[131,221],clutter:[38,153],cma:131,cmd:[12,14,22,25,28,29,31,33,41,43,44,53,58,60,62,71,80,82,85,88,95,121,123,136,152,154,156,157,158,159,164,165,166,167,168,169,170,171,179,180,181,182,185,186,187,188,189,193,199,202,203,206,212,213,214,215,217,218,219,220,221,226,231,232,233,234,236,247,291,295,296,298,322,326,328,329],cmd_abil_result:127,cmd_arg:91,cmd_channel:33,cmd_help_dict:166,cmd_ignore_prefix:151,cmd_kei:91,cmd_last:105,cmd_last_vis:105,cmd_loginstart:33,cmd_multimatch:[33,150],cmd_na_m:88,cmd_name:88,cmd_noinput:[33,150,328],cmd_nomatch:[33,150,233,328],cmd_noperm:33,cmd_on_exit:[51,188,215,230,249,328],cmd_or_top:166,cmd_total:105,cmdabil:[60,127],cmdabout:169,cmdaccept:179,cmdaccess:165,cmdaddcom:164,cmdallcom:164,cmdapproach:221,cmdarmpuzzl:203,cmdasync:10,cmdattack:[29,73,116,123,217,218,219,220,221,232],cmdban:157,cmdbatchcod:158,cmdbatchcommand:158,cmdbigsw:29,cmdblindhelp:226,cmdblindlook:226,cmdblock:25,cmdboot:157,cmdbridgehelp:233,cmdbui:85,cmdbuildshop:85,cmdcallback:193,cmdcast:220,cmdcboot:164,cmdcdesc:164,cmdcdestroi:164,cmdchannel:164,cmdchannelcr:164,cmdcharactercr:181,cmdcharcreat:156,cmdchardelet:156,cmdclimb:232,cmdclock:164,cmdcloselid:226,cmdcolortest:156,cmdcombathelp:[217,218,219,220,221],cmdconfigcolor:81,cmdconfirm:33,cmdconnect:41,cmdcopi:159,cmdcover:182,cmdcpattr:159,cmdcraftarmour:29,cmdcreat:159,cmdcreatenpc:123,cmdcreatepuzzlerecip:203,cmdcwho:164,cmddarkhelp:233,cmddarknomatch:233,cmddeclin:179,cmddefend:116,cmddelcom:164,cmddesc:[159,187],cmddestroi:159,cmddiagnos:30,cmddice:[58,185],cmddig:159,cmddisconnect:41,cmddisengag:[116,217,218,219,220,221],cmddoff:218,cmddon:218,cmddrop:[165,182],cmddummyrunnerechorespons:298,cmdeast:233,cmdecho:[5,29,33,38,170],cmdedit:180,cmdeditnpc:123,cmdeditorbas:326,cmdeditorgroup:326,cmdeditpuzzl:203,cmdemit:157,cmdemot:206,cmdentertrain:121,cmdevalu:179,cmdevenniaintro:233,cmdevmenunod:328,cmdexamin:159,cmdexiterror:44,cmdexiterroreast:44,cmdexiterrornorth:44,cmdexiterrorsouth:44,cmdexiterrorwest:44,cmdextendedroomdesc:187,cmdextendedroomdetail:187,cmdextendedroomgametim:187,cmdextendedroomlook:187,cmdfeint:116,cmdfight:[217,218,219,220,221],cmdfind:159,cmdfinish:179,cmdforc:157,cmdget:[25,165],cmdgetinput:328,cmdgetweapon:232,cmdgive:[165,182],cmdgmsheet:58,cmdgrapevine2chan:164,cmdhandler:[31,33,83,89,141,142,144,149,151,152,153,154,156,167,168,169,170,187,203,233,246,247,256,344],cmdhelp:[116,166,217,218,219,220,221],cmdhit:116,cmdhome:165,cmdic:156,cmdid:272,cmdinsid:121,cmdinterrupt:170,cmdinventori:[82,165,182],cmdirc2chan:164,cmdircstatu:164,cmdlaunch:21,cmdlearnspel:220,cmdleavetrain:121,cmdlen:[151,168],cmdlight:232,cmdline:267,cmdlineinput:326,cmdlink:159,cmdlistarmedpuzzl:203,cmdlistcmdset:159,cmdlisthangout:119,cmdlistpuzzlerecip:203,cmdlock:159,cmdlook:[30,127,165,181,187,233],cmdlookbridg:233,cmdlookdark:233,cmdmail:199,cmdmailcharact:199,cmdmakegm:58,cmdmask:206,cmdmobonoff:231,cmdmore:329,cmdmorelook:329,cmdmultidesc:[57,202],cmdmvattr:159,cmdmycmd:[56,68],cmdname2:151,cmdname3:151,cmdname:[40,59,74,83,88,123,137,150,151,154,159,167,168,170,272,290,291,295,296,308],cmdnamecolor:215,cmdnewpassword:157,cmdnick:165,cmdnoinput:180,cmdnomatch:180,cmdnpc:123,cmdnudg:226,cmdobj:[150,151,168,170],cmdobj_kei:150,cmdobject:[150,151,169],cmdoffer:179,cmdooc:156,cmdooccharactercr:181,cmdooclook:[156,181],cmdopen:[159,212],cmdopenclosedoor:212,cmdopenlid:226,cmdoption:156,cmdpage:164,cmdparri:116,cmdparser:[104,141,142,149],cmdpass:[217,218,219,220,221],cmdpassword:156,cmdperm:157,cmdplant:234,cmdpoke:119,cmdpose:[116,165,206],cmdpressbutton:232,cmdpushlidclos:226,cmdpushlidopen:226,cmdpy:169,cmdquell:156,cmdquit:156,cmdread:232,cmdrecog:206,cmdreload:169,cmdremov:182,cmdreset:169,cmdrest:[217,218,219,220,221],cmdroll:91,cmdrss2chan:164,cmdsai:[116,165,206],cmdsaveyesno:326,cmdscript:[159,169],cmdsdesc:206,cmdser:328,cmdserverload:169,cmdservic:169,cmdsession:156,cmdset:[2,7,14,21,22,25,31,33,34,40,41,42,44,47,51,53,57,60,62,68,69,81,82,85,89,96,97,105,116,121,123,141,142,144,149,150,151,153,154,159,160,161,162,163,167,168,169,170,179,180,181,182,185,187,189,193,199,203,206,213,214,217,218,219,220,221,226,230,231,232,233,234,246,247,256,298,305,306,318,326,328,329,344],cmdset_account:[2,141,142,149,155,181],cmdset_charact:[5,96,141,142,149,155,182,217,218,219,220,221],cmdset_mergetyp:[51,188,230,249,328],cmdset_prior:[51,188,230,249,328],cmdset_red_button:[141,142,178,222],cmdset_sess:[105,141,142,149,155],cmdset_stack:153,cmdset_storag:[148,246,306],cmdset_trad:179,cmdset_unloggedin:[33,141,142,149,155,186],cmdsetattribut:159,cmdsetclimb:232,cmdsetcrumblingwal:232,cmdsetdesc:165,cmdsetevenniaintro:233,cmdsethandl:[105,141,142,149],cmdsethelp:166,cmdsethom:159,cmdsetkei:31,cmdsetkeystr:152,cmdsetlight:232,cmdsetmor:329,cmdsetobj:[152,153,160,161,162,163,179,180,181,182,185,187,203,206,214,217,218,219,220,221,226,230,231,232,233,298,326,328,329],cmdsetobjalia:159,cmdsetpow:123,cmdsetread:232,cmdsetspe:213,cmdsettestattr:50,cmdsettrad:179,cmdsettrain:121,cmdsetweapon:232,cmdsetweaponrack:232,cmdsheet:58,cmdshiftroot:232,cmdshoot:[21,221],cmdshutdown:169,cmdsmashglass:226,cmdsmile:33,cmdspawn:159,cmdspellfirestorm:28,cmdstatu:[179,220,221],cmdstop:213,cmdstring:[33,58,150,154,167,170],cmdstyle:156,cmdtag:159,cmdtalk:214,cmdtask:169,cmdteleport:159,cmdtest:[29,42,91],cmdtestid:33,cmdtestinput:51,cmdtestmenu:[51,188,328],cmdtime:[62,169],cmdtrade:179,cmdtradebas:179,cmdtradehelp:179,cmdtunnel:159,cmdtutori:233,cmdtutorialgiveup:233,cmdtutoriallook:233,cmdtutorialsetdetail:233,cmdtweet:71,cmdtypeclass:159,cmdunban:157,cmdunconnectedconnect:[171,186],cmdunconnectedcr:[171,186],cmdunconnectedhelp:[171,186],cmdunconnectedlook:[171,186],cmdunconnectedquit:[171,186],cmduncov:182,cmdunlink:159,cmdunwield:218,cmduse:219,cmdusepuzzlepart:203,cmdwait:33,cmdwall:157,cmdwear:182,cmdwerewolf:25,cmdwest:233,cmdwhisper:165,cmdwho:156,cmdwield:218,cmdwipe:159,cmdwithdraw:221,cmdyesnoquest:328,cmset:153,cmsg:43,cmud:24,cnf:[23,36],cnt:119,coast:[111,122],coastal:111,cockpit:21,code:[0,1,2,4,5,6,7,9,10,11,12,14,15,16,18,19,20,29,31,33,34,36,37,39,40,43,45,46,47,48,49,51,53,55,56,57,58,62,63,64,68,69,70,76,77,79,80,83,84,86,88,89,91,93,95,96,97,98,100,102,103,104,105,106,109,110,111,112,114,115,116,117,118,119,121,122,123,125,126,127,129,132,134,135,136,139,141,142,144,149,150,153,156,158,159,164,166,169,172,178,179,180,184,185,190,192,195,204,219,233,234,242,252,256,278,279,295,306,309,318,320,321,326,328,330,341,342,343,344,363,364],code_exec:322,codebas:[55,56,127,129,131,139,140,170],codeblock:38,codec:321,codefunc:326,coder:[22,26,56,61,79,96,124,150,247,363],codestyl:37,coerc:339,coexist:126,coin:[61,70,179],col:[3,16,330],cold:[12,43,110,169,252,257,261,305],cole:344,coll_date_func:169,collabor:[4,61,64,90,131,166],collat:[83,251],collect:[11,26,31,136,150,152,166,169,203,316,344],collect_top:166,collector:136,collectstat:[136,137,267,271],collid:[31,54,90,328],collis:[31,131,310],colon:[27,41,60,80,95,242],color:[16,18,20,33,38,49,51,53,58,59,63,69,74,79,95,109,111,114,124,129,137,139,154,156,170,183,190,206,215,230,234,251,272,279,287,290,295,296,321,330,338,343,345,364],color_ansi_bright_bg_extra_map:183,color_ansi_bright_bgs_extra_map:183,color_ansi_extra_map:183,color_markup:[141,142,178],color_no_default:183,color_typ:321,color_xterm256_extra_bg:183,color_xterm256_extra_fg:183,color_xterm256_extra_gbg:183,color_xterm256_extra_gfg:183,colorablecharact:81,colorback:343,colorcod:343,colour:[27,43,55,139,159,294,321,330],column:[16,38,46,49,58,64,69,86,111,137,154,156,235,330,344],com:[8,9,22,23,37,38,43,45,54,55,63,67,70,75,79,90,95,98,100,103,104,108,128,130,131,133,135,138,141,164,169,180,186,279,282,291,295,312,330,343,344,357],comb:1,combat:[11,14,25,28,31,46,55,63,64,73,79,102,108,109,111,117,122,124,125,131,139,153,217,218,219,220,221,231,256,364],combat_:[217,218,219,220,221],combat_cleanup:[217,218,219,220,221],combat_cmdset:116,combat_handl:116,combat_handler_:116,combat_movesleft:[217,218,219,220],combat_scor:123,combat_status_messag:221,combatcmdset:116,combathandl:116,combatscor:123,combatt:11,combin:[8,11,12,20,27,28,30,31,33,34,41,43,55,57,58,84,90,109,112,114,115,118,119,121,127,150,151,152,159,170,202,203,205,226,242,251,261,267,317,319,324,338,344],combo:105,come:[0,2,3,4,6,10,11,15,16,20,21,23,25,27,29,33,34,40,46,49,51,52,55,57,58,61,62,64,69,73,80,83,85,88,91,93,100,105,111,114,116,118,119,121,123,124,126,129,131,133,134,135,137,144,152,187,204,217,218,219,220,221,251,252,285,290,295,296,298,304,321,329],comet:[40,55,137,296],comfort:[15,55,69,91,131],comlist:[43,164],comm:[33,34,41,47,53,64,68,71,141,142,149,155,324],comma:[20,43,46,86,95,114,134,159,167,198,199,242,247],command:[0,2,4,6,8,9,10,11,12,13,15,18,19,20,21,23,24,26,27,34,36,38,40,46,47,48,49,50,51,52,55,56,57,59,61,63,64,65,66,69,72,74,75,76,77,79,80,82,83,86,87,89,90,92,93,95,96,98,102,103,104,105,106,108,109,110,111,112,113,114,117,118,119,120,122,124,125,126,128,129,130,131,136,137,138,139,140,141,142,144,146,175,178,179,180,181,182,185,186,187,188,189,191,194,196,199,202,203,206,210,212,213,214,215,217,218,219,220,221,226,230,231,232,233,234,235,236,239,241,242,247,251,252,256,264,267,272,276,277,285,287,290,291,295,296,298,299,305,306,318,320,321,324,326,328,329,338,341,344,364],command_default_arg_regex:33,command_default_class:25,command_pars:151,commandhandl:[74,153,168],commandmeta:154,commandnam:[33,74,83,234,267,276,306,308],commandset:[5,80,89,153,181],commandtest:[127,170,196],comment:[8,9,13,14,24,25,37,41,48,51,60,90,96,118,125,138,322,328],commerc:79,commerci:[90,106],commerror:176,commit:[15,23,25,36,37,38,64,66,98,100,108,128,130,209],commmand:[212,217,218,219,220,221],common:[1,6,10,12,15,16,20,26,27,30,33,38,40,41,43,51,53,59,60,61,62,63,64,68,69,73,74,79,80,83,88,90,91,97,105,107,109,112,113,115,116,119,123,124,125,131,133,139,152,159,164,179,205,206,213,242,256,295,299,317,327,329,339,341,344,350],commonli:[23,63,64,83,86,87,96,104,105,107,115,119,128,170,247],commonmark:38,commun:[8,22,23,33,40,41,45,47,53,55,57,60,64,70,72,79,83,88,90,91,92,103,106,113,114,137,139,144,161,164,172,175,176,177,199,230,246,264,276,277,287,288,290,291,292,293,306,308,324,325,340,364],compact:[85,134,226],compani:[64,88],compar:[4,9,13,15,27,28,29,31,41,44,58,73,83,85,91,97,116,119,123,127,131,136,170,203,205,217,218,219,220,221,241,242,252,298,321,344],comparison:[13,93,170,241,252,328],compartment:58,compass:20,compat:[14,21,51,159,330,337,344],compet:[15,88],compil:[9,33,38,47,56,63,75,76,90,95,108,159,165,166,171,182,206,321,326,328,343],compilemessag:76,complain:[42,60,86,91,110,128],complement:[26,107],complementari:113,complet:[2,10,11,13,14,15,22,23,25,27,31,33,36,37,43,44,49,50,58,59,61,62,64,67,70,77,81,85,88,89,90,95,96,102,104,105,107,109,110,111,122,123,127,128,131,139,144,152,153,154,167,169,170,183,187,188,190,195,218,226,233,247,260,267,269,277,278,295,316,322,327,328,329,341,344,357],complete_task:195,complex:[11,14,15,20,31,33,51,59,61,62,64,73,76,77,86,93,96,100,104,108,111,115,116,123,127,138,153,175,196,204,214,226,252,299,316],complianc:[24,187],compliant:[39,291],complic:[0,10,22,29,41,43,49,69,90,91,111,133,134,171,186,188,215,316],compon:[29,33,40,43,49,58,90,93,96,102,110,114,116,124,127,135,137,138,139,159,169,176,177,184,203,205,252,253,256,259,267,296,324,327,341,344,347,364],componentid:137,componentnam:137,componentst:[137,138],compos:[100,188],composit:[293,317],comprehens:[34,55,63,80,93,96,103,124,125,127],compress:[74,272,276,280,340],compress_object:340,compris:144,compromis:[103,209],comput:[10,12,43,49,56,60,63,64,72,73,100,113,115,124,131,132,157,169,206,344,345],computation:115,comsystem:177,con:[43,58,79,171,186],concaten:[67,321],concept:[11,37,38,39,40,46,57,61,69,76,77,92,96,115,124,131,139,181,202],conceptu:[49,51],concern:[25,44,63,76,88,95,96,152,204,239],conch:[287,290,298],conclud:[96,179,328],concurr:23,conda:9,conder:322,condit:[8,46,49,55,61,73,85,91,93,96,123,124,150,185,206,219,242,247,259,266,267,312,344],condition:25,condition_result:185,condition_tickdown:219,conditional_flush:334,conduct:136,conductor:121,conect:308,conf:[4,8,9,23,25,35,36,38,40,41,47,54,62,65,67,69,74,76,80,81,86,90,93,102,103,109,114,120,121,127,130,131,133,134,135,139,144,183,267,273,274,313,322,364],confer:[79,344],confid:[37,39,42],config:[2,4,9,36,40,59,63,90,98,103,106,130,131,137,138,139,267,269,273,274,285,364],config_1:2,config_2:2,config_3:2,config_color:81,config_fil:67,configcmd:81,configdict:[287,308],configur:[0,2,7,25,36,38,43,45,47,54,59,62,63,64,69,90,100,103,114,120,124,127,136,138,139,144,148,151,156,209,210,234,269,274,285,308,310,312,313,317,357,364],configut:106,configvalu:59,confirm:[8,33,43,63,103,137,159,186,203,291,294],conflict:[41,42,126],confus:[10,22,26,31,44,58,59,60,64,77,80,87,90,91,93,97,114,119,126,131,136,137,140,164,186],conid:286,conj:247,conjug:247,conjur:220,conn:[43,171,186],conn_tim:105,connect:[0,2,4,7,8,9,11,12,13,17,18,23,24,25,31,33,34,40,41,46,47,49,55,57,60,63,64,65,66,67,69,72,74,76,77,80,83,85,88,89,91,92,93,96,98,100,101,102,103,104,105,107,110,111,114,120,123,125,126,127,136,137,139,144,146,148,156,157,159,164,171,175,177,186,190,192,193,195,210,213,246,247,253,262,264,267,269,276,277,278,279,280,285,286,287,290,295,296,298,299,305,306,307,308,309,312,316,318,324,340,364],connection_cr:107,connection_screen:[35,104],connection_screen_modul:186,connection_set:54,connection_tim:[144,247],connection_wizard:[141,142,262],connectiondon:269,connectionlost:[269,276,277,287,290,298],connectionmad:[264,276,287,290,298],connectionwizard:265,connector:[264,278,279,285,308],consecut:51,consequ:[90,153],consid:[0,4,10,12,13,14,23,26,27,31,33,37,39,40,44,46,51,55,57,61,63,64,70,74,78,80,82,85,86,90,93,96,97,102,103,105,109,112,113,114,115,119,121,125,131,133,134,135,144,152,153,188,203,205,206,221,234,247,252,256,272,287,290,317,322,323,328,329],consider:[68,86,104,111,118,252,330],consist:[2,11,17,33,38,44,46,48,51,68,80,86,92,95,96,109,110,114,116,122,123,135,137,144,151,166,167,175,176,179,203,205,236,242,252,291,296,306,316,318,324,330,344],consol:[9,19,23,26,38,42,43,60,63,64,75,83,90,93,95,96,97,100,106,114,123,137,138,166,169,206,267],conson:205,constant:[0,88,276,342],constantli:[96,117,233],constitu:[153,167],constraint:[0,23],construct:[20,29,34,36,51,64,119,133,138,252,311,316,321,329,357],constructor:[22,33,180,278],consum:[10,269,344],consumer_kei:[71,120],consumer_secret:[71,120],consumpt:[23,310],contact:[89,90,100],contain:[0,5,7,9,10,11,13,14,16,17,18,20,21,22,25,26,31,33,34,37,38,39,40,41,43,46,47,51,53,55,56,57,62,63,64,68,69,70,75,79,80,86,89,91,95,96,97,101,102,104,105,114,118,119,122,123,124,126,127,128,129,133,134,136,137,138,139,141,142,144,146,149,150,151,152,153,155,158,159,164,166,170,172,180,188,189,192,193,194,195,196,198,203,204,205,206,210,211,213,215,219,226,232,234,235,238,240,247,249,251,252,260,262,266,270,272,298,310,311,312,316,317,318,319,320,321,322,325,327,328,329,330,341,343,344,345,347,355,363],container:100,contempl:56,content:[3,4,13,16,17,21,27,38,39,43,48,49,51,56,58,69,77,79,82,85,89,90,91,93,95,96,117,119,121,123,125,131,133,134,137,138,139,154,157,159,206,246,247,319,321,322,323,326,328,330,341,346,347,355],content_typ:[246,247],contentof:330,contents_cach:246,contents_get:[119,247],contents_set:247,contentshandl:246,context:[46,51,55,69,91,114,119,126,133,180,195,288,292,350],context_processor:350,contextu:112,continu:[7,10,11,21,27,29,33,37,42,45,46,49,51,55,58,60,69,71,75,85,86,90,95,96,112,114,115,116,119,123,124,127,136,139,247,265,276,312,316,328,337,344,364],contrari:[0,38,41,43,62,169,319],contrast:[56,90,96,113,138,291],contrib:[4,13,14,20,38,47,53,57,58,62,63,64,73,78,102,116,122,141,142,144,148,169,309,321,322,349,357,364],contribrpcharact:206,contribrpobject:206,contribrproom:206,contribut:[1,4,22,26,45,55,70,78,82,124,127,131,136,139,178,179,181,182,183,185,187,199,203,204,206,209,210,212,213,214,234,363,364],contributor:[78,180],control:[2,5,7,9,11,12,13,14,19,20,21,31,33,34,36,37,38,42,43,47,50,51,52,53,55,57,58,61,63,64,67,68,73,74,80,81,83,86,89,90,92,93,96,102,103,105,108,109,110,114,118,121,123,124,128,135,138,139,144,146,156,158,159,164,170,179,181,194,206,226,231,233,235,241,247,256,267,306,308,318,328,357,364],convei:[206,247],convenei:107,conveni:[8,9,10,11,21,34,36,40,41,43,51,55,57,59,69,74,80,86,89,96,98,102,106,108,109,110,125,127,133,140,144,159,169,180,199,247,299,310,322,323,328,329,337,340,341],convent:[0,31,86,96,107,119,126],convention:[41,154,247,318],convers:[51,87,121,127,138,205,214,295,296,321,344,363],convert:[11,27,39,40,49,51,59,62,64,79,81,83,85,87,88,103,109,113,114,119,126,128,157,184,185,188,215,241,251,252,257,276,278,287,290,291,308,312,321,325,328,329,330,331,340,343,344,363],convert_linebreak:343,convert_url:343,convinc:[51,90],cool:[3,9,21,22,26,38,43,61,79,159,164],cool_gui:80,cooldown:[29,116,124,139,364],coord:39,coordi:39,coordin:[49,124,137,139,221,235,364],coordx:39,coordz:39,cope:220,copi:[0,1,4,13,14,20,25,26,33,36,47,48,50,51,62,64,81,90,93,96,100,104,105,109,111,123,128,131,133,135,136,137,138,158,159,182,195,217,218,219,220,221,233,247,267,276,313,321,337],copy_object:247,copyright:[78,90],cor:138,core:[19,37,43,47,49,76,78,88,89,96,104,106,125,127,131,139,144,148,169,177,178,199,239,246,247,256,262,274,284,291,305,316,318,319,322,329,335,357],corner:[17,39,57,79,138,235,330],corner_bottom_left_char:330,corner_bottom_right_char:330,corner_char:330,corner_top_left_char:330,corner_top_right_char:330,corpu:205,correct:[10,11,14,21,23,27,30,31,33,37,43,48,50,60,80,91,113,114,121,123,126,150,156,159,170,176,187,203,228,242,282,285,287,293,307,321,344],correctli:[4,8,9,27,29,33,36,38,42,44,49,50,51,61,62,72,77,80,85,90,91,97,110,112,115,121,122,123,126,144,148,153,156,257,276,312,340],correl:252,correspond:[20,33,80,83,85,105,135,184,203,215,357],correspondingli:128,corrupt:56,cosi:111,cosin:344,cosmet:235,cost:[28,85,90,220,235],cottag:[111,114],could:[0,1,2,3,4,5,6,9,10,11,12,13,14,15,19,20,21,22,25,28,29,30,31,33,34,36,37,38,39,40,41,42,43,44,46,47,48,49,51,55,57,58,60,61,62,63,64,65,68,69,71,72,73,79,80,81,82,83,84,85,86,87,88,89,90,91,93,95,96,98,102,106,108,109,111,112,113,114,115,116,117,118,119,120,121,123,125,126,127,128,129,132,133,135,136,138,140,144,153,159,166,176,177,179,180,185,190,198,204,206,213,215,226,233,235,242,247,259,272,291,296,312,318,321,322,326,330,331,334,339,344],couldn:[11,19,39,44,64,76,91,126,134,140,204],count:[64,102,104,116,119,120,152,182,215,219,247,281,285,298,302,308,310,317,321,328,337],count_loggedin:285,count_queri:302,countdown:[20,29],counter:[6,22,29,69,85,105,116,128,146,233,285,298,299,306,328],counterpart:[13,114,272,308,325],countless:95,countnod:51,countri:[43,157],coupl:[22,48,69,100,117,131,175,213],cours:[0,4,9,12,15,21,22,26,33,38,41,46,57,61,64,77,78,91,93,106,108,114,115,122,123,124,132,140,218,221,230],courtesi:12,cousin:[91,129],cover:[6,8,9,13,14,23,29,37,40,48,51,57,59,63,79,80,86,90,95,96,120,127,131,182,187,226,233,247,344,363],coverag:127,coveral:127,cpanel:90,cpattr:159,cpu:[12,43,90,103,169],cpython:93,crack:[61,86],craft:[29,80,111,188],crank:115,crash:[26,60,61,79,103,111,271,316],crate:[20,87,124],crawl:103,crawler:281,cre:[43,171,186],creat:[4,9,11,13,14,15,16,19,22,23,25,26,29,31,34,35,37,38,39,40,41,42,44,46,47,49,50,54,55,56,57,58,60,61,62,63,64,65,66,67,68,70,71,72,73,75,76,77,78,79,80,81,83,85,87,90,91,93,95,96,102,103,104,105,106,107,108,109,112,116,117,118,119,120,122,124,127,129,130,131,132,134,135,136,137,138,139,140,141,142,144,146,148,151,152,153,154,156,159,164,165,166,167,168,169,170,171,175,177,179,180,181,182,184,185,186,187,188,189,194,195,196,198,199,202,203,204,205,206,210,212,214,215,217,218,219,220,221,223,226,230,231,232,233,234,235,239,242,246,247,249,250,251,252,256,259,260,261,264,267,271,272,277,279,280,285,287,288,292,299,307,308,310,312,316,317,318,319,320,322,323,326,327,328,330,331,337,344,360,363],create_:[89,125],create_account:[107,125,141,324],create_attribut:316,create_cal:144,create_channel:[34,141,164,175,271,324],create_charact:[144,247],create_delai:260,create_exit:[159,212],create_exit_cmdset:247,create_forward_many_to_many_manag:[148,177,239,246,256,316,318,319,335],create_game_directori:267,create_grid:49,create_help_entri:[68,141,324],create_kwarg:252,create_match:151,create_messag:[34,141,324],create_object:[13,27,80,85,89,111,123,125,133,141,226,247,252,271,322,324],create_prototyp:[251,252],create_script:[56,102,116,125,141,259,322,324],create_secret_kei:267,create_settings_fil:267,create_superus:267,create_tag:317,create_wild:235,created_on:192,creater:53,creation:[11,14,20,21,38,43,47,49,51,58,60,61,79,80,81,86,89,97,105,111,123,125,131,133,139,140,141,144,148,159,164,166,175,181,203,206,210,212,217,218,219,220,221,232,233,239,246,247,252,256,261,300,318,324,326,327,328,330,357,363],creation_:324,creativ:[79,108],creator:[51,53,79,80,111,123,140,166,175,217,218,219,220,221,247,330],cred:[131,287],credenti:[90,103,131,144,287],credentialinterfac:287,credit:[90,103,131,343,344],creset:131,crew:119,criteria:[51,119,176,194,204,251,317,341],criterion:[119,131,144,179,206,238,247,258,341,344],critic:[19,26,31,60,63,67,97,102,105,114,128,242,266,267,337],critici:318,cron:67,crontab:67,crop:[58,114,159,327,330,344],crop_str:330,cross:[111,138,233,330],crossbario:295,crossbow:29,crossroad:111,crowd:[61,103],crt:[8,67],crucial:[91,115],crude:0,cruft:1,crumblingwal:232,crumblingwall_cmdset:232,crush:21,cryptic:138,cryptocurr:103,cscore:123,csessid:[285,295,296,308],csession:[295,296],csrf_token:133,css:[17,55,124,135,136,137,343,347],cssclass:137,ctrl:[48,63,67,90,93,95,100,110,298],culpa:52,cumbersom:[51,121,128,215],cumul:299,cup:70,cupidatat:52,cur_valu:190,cure:[219,220],cure_condit:219,curi:49,curiou:108,curli:[41,96,183],curly_color_ansi_bright_bg_extra_map:183,curly_color_ansi_bright_bgs_extra_map:183,curly_color_ansi_extra_map:183,curly_color_xterm256_extra_bg:183,curly_color_xterm256_extra_fg:183,curly_color_xterm256_extra_gbg:183,curly_color_xterm256_extra_gfg:183,curr_sess:308,curr_tim:187,currenc:[85,120],current:[0,2,9,11,12,13,14,19,20,21,22,25,27,28,29,31,33,38,41,43,46,48,49,50,51,58,59,60,64,68,74,76,77,79,80,85,86,89,97,100,102,104,105,106,112,114,115,116,119,120,121,123,124,127,128,131,133,137,138,144,148,150,151,153,154,156,157,159,164,165,166,168,169,179,180,182,187,188,190,195,198,202,204,206,212,213,215,217,218,219,220,221,230,232,233,235,238,246,247,252,256,260,261,267,272,277,283,284,287,288,299,306,308,310,317,318,326,328,330,331,337,338,341,344],current_choic:180,current_cmdset:159,current_coordin:235,current_kei:[250,251],current_tim:298,current_us:133,current_weath:102,currentroom:121,curriculum:79,curs:42,curv:[55,56],curx:49,custom:[0,2,6,11,12,14,15,16,17,18,20,21,25,26,27,30,31,33,34,35,43,49,53,55,56,58,60,61,64,65,66,68,69,71,73,74,78,79,83,85,86,87,89,90,97,100,102,104,109,110,112,114,116,117,118,119,121,122,123,125,126,132,133,136,138,139,140,144,146,147,148,150,152,153,154,159,164,165,166,175,179,181,182,184,185,187,188,189,195,198,203,205,206,209,210,226,230,232,233,235,238,245,247,249,250,251,252,255,261,267,271,273,276,298,307,318,323,326,328,329,330,334,338,339,343,344,349,364],custom_add:195,custom_cal:[195,198],custom_gametim:[62,141,142,178],custom_kei:251,custom_pattern:[3,4,69,133,134],customfunc:83,customis:235,customiz:[17,41,180,188,190,206,226],customlog:8,cut:[20,40,49,50,55,91,111,123,252],cute:136,cutoff:344,cvcc:205,cvccv:205,cvccvcv:205,cvcvcc:205,cvcvccc:205,cvcvccvv:205,cvcvcvcvv:205,cvcvvcvvcc:205,cvv:205,cvvc:205,cwho:164,cyan:[114,126],cyberspac:79,cycl:[13,14,25,56,61,62,132,217,218,219,220,221],cyril:15,daemon:[8,67,93,100,103,110,284,312],dai:[25,27,36,56,61,62,100,103,108,120,126,131,132,139,184,187,331,337,344,345],daili:87,dailylogfil:337,dali:205,dalnet:[43,164],dam:56,damag:[14,21,28,61,73,85,103,116,122,217,218,219,220,221,231,232],damage_rang:220,damage_taken:56,damage_valu:[217,218,219,220,221],damnedscholar:48,dandi:140,danger:[13,31,38,82,97,105,152],dare:33,dark:[13,14,17,31,73,79,111,114,122,126,153,187,226,233,256,321,322],darkcmdset:233,darker:[114,126],darkgrai:126,darkroom:233,darkroom_cmdset:233,darkstat:233,dash:[38,119,204,215],dashcount:215,data:[2,10,13,15,22,23,25,27,43,56,57,58,59,61,64,75,83,86,87,88,90,93,96,97,100,102,104,109,112,113,119,125,128,133,134,135,137,138,139,144,146,154,159,166,169,188,190,194,195,206,209,210,246,247,249,251,253,259,261,264,265,269,273,274,276,277,278,279,280,285,286,287,288,290,291,292,294,295,296,298,300,305,306,307,308,310,314,316,317,318,319,321,322,323,324,325,327,328,329,330,333,337,338,339,340,344,357],data_in:[40,83,210,276,278,279,285,286,290,295,296,306,307,308],data_out:[40,210,285,287,290,291,296,306,307,308],data_to_port:264,data_to_serv:277,databa:267,databas:[0,4,5,6,7,11,12,13,15,17,19,20,21,23,25,27,28,29,31,34,36,38,39,43,45,47,55,56,57,58,59,60,61,63,64,74,77,80,84,87,89,91,93,100,101,102,104,105,107,110,111,112,115,116,119,123,124,125,127,131,133,134,135,136,138,139,140,144,148,152,153,159,166,169,175,176,177,187,194,195,206,220,233,236,238,239,241,246,247,251,253,256,257,260,261,267,271,273,284,298,305,314,316,317,318,319,322,324,325,332,334,340,341,344,346],datareceiv:[269,276,290,298],dataset:251,datastor:86,datbas:119,date:[7,11,12,23,34,49,62,68,75,76,86,126,128,131,133,138,153,157,169,209,331,337,345],date_appli:133,date_cr:[125,144,148,177,239,256,316,318],date_join:148,date_s:34,datetim:[62,125,133,316,331,337,338,344,345],datetime_format:344,datetimefield:[86,133,148,177,239,246,256,316,318,344],david:79,day_rot:337,db3:[23,111,128,131],db_:[84,86,119,125,206,247,257,272,341],db_account:[182,246,256],db_account_id:[246,256],db_account_subscript:177,db_attribut:[107,119,148,177,246,256,318],db_attrtyp:316,db_attryp:87,db_categori:[86,316,319],db_category__iequ:86,db_cmdset_storag:[148,182,246],db_data:319,db_date_cr:[86,148,177,182,239,246,256,316,318],db_desc:256,db_destin:[182,246],db_destination__isnul:120,db_destination_id:246,db_entrytext:239,db_header:177,db_help_categori:239,db_help_dict:166,db_hide_from_account:177,db_hide_from_object:177,db_hide_from_receiv:177,db_hide_from_send:177,db_home:[182,246],db_home_id:246,db_index:86,db_interv:256,db_is_act:256,db_is_bot:148,db_is_connect:148,db_kei:[69,84,86,119,125,182,194,239,257,274,316,318,319,357],db_key__contain:125,db_key__icontain:86,db_key__istartswith:119,db_key__startswith:[119,125],db_locat:[84,119,182,246],db_location__db_tags__db_kei:119,db_location__isnul:120,db_location_id:246,db_lock_storag:[177,182,239,316,318],db_messag:177,db_model:[316,319],db_obj:[256,325],db_obj_id:256,db_object_subscript:177,db_permiss:86,db_persist:256,db_properti:272,db_protototyp:251,db_receiver_extern:177,db_receivers_account:177,db_receivers_object:177,db_receivers_script:177,db_repeat:256,db_sender_account:177,db_sender_extern:177,db_sender_object:177,db_sender_script:177,db_sessid:[182,246],db_start_delai:256,db_strvalu:316,db_tag:[119,148,177,239,246,256,318,319],db_tags__db_categori:[39,119],db_tags__db_kei:[39,119],db_tags__db_key__in:39,db_tagtyp:319,db_text:86,db_typeclass_path:[86,120,182,246,318,344],db_valu:[84,274,316],dbef:341,dbentri:166,dbhandler:357,dbholder:316,dbid:[43,125,146,164,318],dbid_to_obj:344,dbmodel:317,dbobj:[11,316],dbobject:[11,317,318],dbprototyp:[169,251],dbref:[12,13,20,43,58,66,80,109,111,116,119,121,122,125,128,144,148,157,159,164,169,176,188,203,206,212,233,235,241,246,247,252,256,258,317,318,324,341,344],dbref_search:317,dbref_to_obj:344,dbrefmax:[43,159],dbrefmin:[43,159],dbsafe_decod:340,dbsafe_encod:340,dbserial:[11,97,141,142,257,320],dbshell:[23,86,110,128],dbunseri:325,ddesc:56,deactiv:[43,63,64,81,117,164,187,231,328],dead:[112,231,232,305,308,334],deadli:122,deal:[10,11,12,15,41,51,64,69,73,91,103,105,112,113,116,124,126,127,131,134,138,139,144,179,180,184,188,217,218,219,220,221,246,247,306,318,321,338],dealt:[167,219,220],dealth:219,death:[51,73,120],death_msg:231,death_pac:231,debat:91,debian:[8,23,63,67,131],debug:[14,27,43,45,51,59,72,74,91,95,102,106,135,139,150,154,158,169,188,230,249,267,272,278,279,290,312,322,328,337,344,364],debugg:[15,42,110,141],decemb:90,decend:[51,150],decent:[93,205],decic:205,decid:[4,14,15,25,33,41,46,58,61,69,73,85,86,88,90,103,105,112,114,116,126,138,150,179,217,242,329],deciph:48,decis:[73,115],declar:[114,340],declared_field:357,declin:[51,179],decod:[15,291,321,344],decode_gmcp:291,decode_msdp:291,decoded_text:344,decompos:133,decompress:[276,340],deconstruct:[122,170,228,293,342],decor:[0,29,33,46,107,131,148,170,246,256,264,276,277,318,324,328,329,344],decoupl:[9,251],decoupled_mut:11,decreas:[220,233,326],decrease_ind:326,dedent:[50,344],dedic:[73,90,127],deduc:326,deduce_ind:326,deduct:[73,85,217,218,219,220,221],deem:[37,57,129,131,178],deep:79,deeper:[41,215],deepest:159,deepli:11,deepsiz:344,def:[1,3,4,5,6,10,11,21,22,25,27,28,29,30,31,33,38,39,40,41,42,44,48,49,50,51,56,57,58,60,62,69,71,73,74,79,80,81,82,84,85,89,91,95,96,102,107,109,111,114,116,117,118,119,120,121,123,125,127,132,133,134,170,180,187,234,235,250,296,309,326,328,329,344],def_down_mod:219,defalt_cmdset:71,default_access:[1,11,316,324],default_categori:238,default_channel:34,default_charact:189,default_cmd:[5,21,22,25,28,29,30,41,44,53,57,58,62,81,116,119,141,180,182,187,199],default_cmdset:[5,22,25,30,35,41,44,57,58,60,62,81,105,123,153,180,181,182,187,188,202,212,215,217,218,219,220,221],default_command:25,default_confirm:[159,203],default_error_messag:340,default_help_categori:166,default_hom:[59,109],default_in:137,default_out:137,default_pass:324,default_screen_width:33,default_set:[3,127],default_transaction_isol:23,default_unload:137,defaultaccount:[2,41,43,53,64,125,141,144,146,160,247,342,357],defaultchannel:[6,53,125,141,164,175],defaultcharact:[5,6,22,25,43,53,57,58,60,62,73,81,86,89,96,123,125,127,141,144,161,180,182,189,206,217,218,219,220,221,247,342,357],defaultcmdset:185,defaultdict:257,defaultexit:[6,53,85,89,125,141,212,213,232,235,247,342],defaultguest:[53,141,144],defaultmod:337,defaultobject:[5,6,26,53,60,64,82,85,86,89,96,111,117,119,121,125,141,144,182,206,214,218,221,226,232,247,318,342,357],defaultpath:344,defaultroom:[6,39,49,53,56,85,89,125,132,141,187,206,233,235,247,342],defaultscript:[53,56,102,116,120,121,125,141,146,179,184,195,203,204,205,217,218,219,220,221,223,235,251,258,259,300,331,342],defaultsess:[43,162],defaulttyp:312,defaultunloggedin:[43,163],defeat:[73,116,122,217,218,219,220,221,231],defeat_msg:231,defeat_msg_room:231,defend:[51,116,122,217,218,219,220,221,232,247],defens:[116,217,218,219,220,221],defense_valu:[217,218,219,220,221],defer:[10,27,29,33,133,148,150,169,177,187,213,239,246,247,256,260,264,274,276,277,308,312,316,318,319,335,337],deferredlist:312,defin:[0,2,4,5,10,11,12,13,14,20,21,22,25,27,30,35,36,38,40,42,43,44,46,49,50,53,55,56,57,58,59,61,62,64,68,69,73,74,77,78,81,83,85,88,89,91,95,96,97,104,106,109,111,113,114,115,117,119,121,123,125,126,127,129,133,135,136,137,138,139,141,143,148,150,152,153,154,156,159,165,166,167,169,170,175,176,177,180,182,183,184,185,187,188,194,195,198,203,204,205,206,214,215,219,220,223,232,233,236,238,239,240,241,242,243,246,247,251,252,256,259,261,262,264,267,274,277,298,299,306,307,308,311,314,316,317,318,319,321,322,323,326,328,331,335,339,341,344,350,357],define_charact:51,definit:[0,2,5,10,12,14,20,33,34,39,41,42,43,55,60,61,68,69,82,83,87,88,89,109,114,115,124,127,152,154,159,164,167,192,203,232,240,242,246,251,252,258,322,324,328,340],defit:51,deflist:312,degrad:127,degre:38,deindent:344,del:[11,12,29,43,58,80,116,122,157,159,187,202,203,318],del_callback:[193,195],del_detail:187,del_pid:267,delai:[0,28,33,45,120,169,184,188,195,213,226,232,260,261,279,285,308,323,344],delaliaschan:[43,164],delayed_import:308,delchanalia:[43,164],delcom:[58,164],deleg:[148,177,239,246,256,316,318,319,335],delet:[2,4,7,11,12,13,20,22,23,31,43,50,51,63,66,68,80,87,89,98,100,102,105,107,111,112,116,122,128,131,144,153,156,157,158,159,164,165,166,169,175,177,187,192,193,195,196,199,202,203,212,232,239,242,247,251,257,258,259,260,261,273,285,306,316,318,321,322,328,334,360],delete_attribut:316,delete_default:[31,153],delete_prototyp:251,deletet:187,deliber:[11,42,129,344],delic:182,delimit:[91,167,322],delin:48,deliv:[90,199,206],delpart:203,delresult:203,deltatim:344,delux:90,demand:[30,58,61,73,90,115,117,144,175,187,247,309,323],demo:[22,55,79,138,229,230,328],democommandsetcomm:230,democommandsethelp:230,democommandsetroom:230,demon:109,demonin:344,demonstr:[0,4,22,126,133,180,188,209,219],demowiki:4,deni:[8,103,194,198],denot:[56,114,134,322],denounc:327,depart:49,depend:[0,4,10,11,12,14,15,16,22,27,31,33,34,37,40,43,46,49,51,55,57,58,61,63,64,69,72,73,74,75,83,85,88,90,93,95,97,100,102,103,104,105,106,111,114,115,116,118,123,125,131,133,134,137,138,143,150,152,154,156,169,180,181,185,187,193,205,226,235,242,247,251,261,267,287,290,296,298,308,318,319,326,328,329,344],deplet:219,deploi:[38,46,90,103],deploy:[36,38,79,90,100,106],depmsg:337,deprec:[27,51,94,109,141,142,252,262,321,328,337,344],deprecationwarn:266,depth:[16,17,36,95,114,122,124,166,215,252],dequ:[11,310],deriv:[23,56,63,67,100,108,119,125,127,234,321,345],desc:[14,20,21,22,34,41,57,58,60,69,74,80,84,85,89,102,109,111,116,120,134,153,156,159,164,170,180,182,187,202,203,212,215,220,226,235,256,265,322,324,326,327,328,357],desc_add_lamp_broken:226,desc_al:231,desc_closed_lid:226,desc_dead:231,desc_open_lid:226,descend:[119,357],describ:[5,9,11,13,14,20,21,22,30,31,33,37,43,46,51,55,58,62,63,64,68,69,71,75,76,79,80,85,86,88,90,92,96,102,109,110,111,113,114,116,124,125,127,128,131,133,135,137,139,152,159,163,164,165,177,182,184,187,204,206,220,226,252,259,264,285,287,290,300,328,343,344,363],descripion:231,descript:[0,14,15,20,21,22,34,39,41,43,46,49,51,54,55,57,58,60,61,68,74,77,85,90,96,102,109,111,112,126,129,131,133,134,135,139,156,159,164,165,175,179,180,182,187,202,204,206,212,215,226,230,231,232,233,234,235,247,256,322,324,328,338,339],description_str:111,descvalidateerror:202,deseri:[11,97,338],deserunt:52,design:[14,16,23,26,33,37,39,41,55,57,61,79,89,91,108,109,111,112,117,118,119,124,129,133,138,153,159,180,194,206,209,232,247,322,338,344],desir:[1,4,27,28,29,43,49,57,58,59,91,108,112,114,115,119,121,123,133,137,159,175,183,205,242,267,312,316,324,330,345],desired_perm:242,desktop:[15,16,138],despit:[11,13,57,63,64,79,81,105,233],dest:[234,247],destin:[0,22,25,33,43,49,74,77,85,89,91,109,111,119,121,159,209,212,213,217,218,219,220,221,232,233,246,247,252,324],destinations_set:246,destroi:[0,20,89,103,116,127,144,146,159,164,203,219,247],destroy:212,destroy_channel:164,destruct:[31,152],detach:106,detail:[2,5,9,12,15,19,20,22,26,30,33,34,37,41,46,51,58,60,61,63,64,80,88,89,90,91,93,95,96,105,109,111,114,116,118,122,124,125,128,129,131,134,135,136,139,153,154,159,175,180,187,203,204,206,218,233,235,239,252,260,269,270,306,308,318,321,326,344,360],detail_color:159,detailkei:[187,233],detect:[31,33,36,38,61,81,88,89,103,105,118,151,154,279],determ:317,determin:[2,4,13,15,20,27,29,31,33,34,39,43,44,49,50,51,52,63,73,80,82,83,85,87,93,102,109,110,116,123,136,137,144,152,153,154,156,164,166,167,170,175,179,205,206,213,215,217,218,219,220,221,232,239,242,247,251,291,316,317,318,321,326,329,337,344,347],detour:[21,83,308],dev:[1,23,37,55,57,63,64,67,71,76,79,90,95,98,138],develop:[3,9,15,16,19,20,25,26,27,33,36,37,38,42,43,48,54,55,56,58,60,61,63,64,68,70,71,72,76,77,80,86,88,90,91,93,96,97,99,104,106,108,109,111,114,123,126,131,133,135,136,137,138,139,157,158,164,165,166,169,175,192,193,198,209,239,247,252,313,318,322,328,363,364],devoid:321,dex:[11,51,58,327],dexter:[217,218,219,220,221],diagnos:[30,97],diagram:125,dialog:137,dialogu:[0,124,139,364],dice:[63,73,91,116,141,142,178],dicecmdset:185,dicenum:185,dicetyp:185,dict:[0,11,13,25,31,43,46,51,53,88,107,109,119,127,144,146,152,154,159,166,170,175,182,184,187,188,192,195,198,205,206,209,210,215,219,221,233,247,249,250,251,252,259,261,264,265,267,272,277,278,280,285,287,290,295,296,307,308,310,317,322,323,325,327,328,329,339,344,357],dictat:[31,62,117],dictionari:[0,10,11,13,25,31,43,49,55,56,62,69,73,80,96,97,102,109,116,124,134,138,157,159,182,184,187,188,192,195,198,205,206,209,210,211,215,219,220,233,235,242,252,260,272,285,294,306,307,308,310,317,321,323,327,328,334,338,339,340,344,357],did:[2,21,22,29,57,60,64,68,91,95,96,104,111,123,131,144,179,247,260,319,340,344],did_declin:179,didn:[5,20,22,38,41,42,44,49,51,58,59,61,72,80,91,100,104,119,121,126,127,133,136,140],die:[73,91,106,114,117,185,205,308],dies:231,diff:[75,131,185,252],differ:[0,2,8,9,11,13,14,15,16,19,20,21,22,24,25,27,31,33,37,38,39,40,41,42,43,44,46,47,49,50,51,54,55,57,58,61,62,63,64,66,68,69,70,73,79,80,82,83,84,87,88,91,93,95,96,100,102,103,105,106,107,109,110,111,112,113,114,115,116,118,119,120,121,124,126,127,129,131,133,136,137,138,139,140,141,144,150,152,153,156,159,166,168,169,171,175,180,184,185,186,195,196,199,204,206,213,215,217,218,219,220,221,234,235,249,252,256,261,265,269,291,296,298,316,318,322,324,328,337,340,344],differenti:[56,57,58,182,206,215,247,344],differet:61,difficult:[4,39,93,103,133,220,221],difficulti:133,dig:[0,20,31,33,40,57,58,89,93,96,109,121,123,140,159,212,299],digit:[12,90,114,127,204,311,321,337],digitalocean:67,diku:[55,64,124,139,364],dikumud:129,dime:108,dimens:[49,55],dimension:58,diminish:114,dimli:111,dinner:46,dip:96,dir:[9,21,23,36,38,54,58,63,64,67,75,79,90,96,100,102,127,128,130,131,134,337,344,347],direct:[0,3,8,10,11,12,20,22,31,38,43,44,45,49,51,58,70,74,88,90,100,109,111,116,118,119,121,128,137,138,139,159,170,194,210,235,242,259,267,328,330,337,341,344,364],directli:[2,5,8,13,14,20,21,23,27,29,30,33,37,40,42,44,46,50,51,55,56,58,59,61,62,64,72,80,88,89,90,93,95,96,100,102,104,109,110,111,114,116,118,119,123,125,128,131,137,138,154,170,176,179,180,181,185,198,206,215,220,221,226,233,234,238,242,246,247,256,273,278,287,290,295,298,300,306,316,318,322,324,328,329,342,344],director:[206,247],directori:[4,8,9,13,20,25,27,36,37,43,45,58,59,62,63,64,69,75,76,95,96,100,106,123,125,127,128,130,131,133,134,135,136,137,139,159,209,267,287,288,312,322,337,344,364],directorylist:312,dirnam:267,dirti:55,disabl:[0,4,24,25,50,63,80,81,106,114,127,137,154,170,188,206,215,226,234,242,290,310,329,334,345],disableloc:290,disableremot:290,disadvantag:[58,90,116,221],disambigu:[41,72,119,154,247,318],disappear:103,discard:321,disconcert:41,disconnect:[2,11,12,40,41,43,55,57,60,92,97,105,107,110,112,116,123,128,137,144,156,159,164,167,169,175,247,277,278,279,285,286,287,290,295,296,299,305,306,307,308],disconnect_al:285,disconnect_all_sess:308,disconnect_duplicate_sess:308,disconnect_session_from_account:144,discontinu:24,discord:[9,63,72,79],discordia:108,discourag:[64,75],discov:[91,122,316],discoveri:210,discrimin:103,discuss:[1,4,25,26,33,37,45,48,55,63,69,70,116,138,139],discworld:88,disengag:[116,144,217,218,219,220,221],disk:[11,27,86,100,108,110,205,209,249],dislik:57,disonnect:11,dispatch:37,dispel:126,displai:[0,17,22,25,30,31,33,38,42,43,46,50,51,58,59,60,61,68,69,73,80,81,82,83,85,88,89,91,93,101,102,103,104,111,114,116,119,123,124,133,134,135,136,137,138,139,144,154,156,159,164,166,169,170,171,179,180,182,186,187,188,190,193,195,199,206,215,226,230,232,233,234,235,247,251,252,265,267,284,302,305,310,318,319,326,327,328,329,330,338,339,340,343,344,345,357],display:261,display_all_channel:164,display_buff:326,display_choic:180,display_formdata:188,display_help:326,display_helptext:[249,328],display_len:344,display_met:190,display_nodetext:328,display_subbed_channel:164,display_titl:180,dispos:[111,203],disput:116,disregard:33,dist:[63,130],distanc:[6,27,39,46,49,64,125,205,220,221,247,344],distance_inc:221,distance_to_room:39,distant:[49,138,187,233],distinct:[55,64,105,140,221],distinguish:[22,154,215,221],distribut:[8,9,15,23,31,34,42,63,64,78,96,97,124,127,128,175,177,206,321,324,344],distribute_messag:175,distributor:34,distro:[8,23,63,67,72],disturb:[27,140],distutil:63,distutilserror:63,ditto:63,div:[3,16,17,38,109,137],dive:[22,41,63],diverg:83,divid:[13,64,69,184,233,344],dividend:184,divisiblebi:69,divisor:184,django:[2,3,4,9,12,15,23,25,36,39,55,63,69,73,76,79,86,101,103,104,107,112,113,120,124,125,127,128,134,136,137,139,144,148,171,175,177,186,239,246,251,256,266,267,273,274,287,293,295,296,303,309,310,311,312,316,318,319,322,325,329,333,334,335,340,342,344,346,349,352,357],django_admin:360,django_nyt:4,djangonytconfig:4,djangoproject:[23,357],djangowebroot:312,dmg:73,dnf:[8,63,67],do_attack:231,do_batch_delet:316,do_batch_finish:316,do_batch_update_attribut:316,do_create_attribut:316,do_delete_attribut:316,do_flush:[318,334],do_gmcp:291,do_hunt:231,do_mccp:280,do_msdp:291,do_mssp:281,do_mxp:282,do_naw:283,do_nested_lookup:159,do_not_exce:25,do_noth:230,do_patrol:231,do_pickl:325,do_search:166,do_task:[169,260,344],do_task_act:169,do_unpickl:325,do_update_attribut:316,do_xterm256:321,doabl:[14,138],doc:[16,17,23,25,33,45,51,53,60,64,68,70,79,86,95,96,109,110,125,129,130,136,139,141,159,169,204,234,247,278,344,357,363,364],docker:[7,63,79,90,139,364],dockerfil:100,dockerhub:100,docstr:[1,5,25,38,41,43,68,74,96,154,159,170,180,193,205,206,215,226,233,234,298,328],documen:96,document:[0,3,5,6,9,16,17,20,22,23,24,25,26,29,41,43,46,47,48,52,55,57,58,60,64,68,70,76,79,83,86,90,96,103,104,106,111,114,118,121,122,123,124,125,127,131,133,135,136,139,153,167,180,204,234,316,319,327,334],dodg:218,doe:[2,4,5,9,11,20,21,23,24,25,26,29,31,33,37,38,39,40,41,43,49,51,54,55,56,57,58,60,61,63,64,68,69,73,78,80,85,88,89,91,95,96,100,102,104,109,110,111,112,113,114,116,117,118,119,121,123,125,126,127,129,131,132,133,136,137,138,140,144,146,156,167,169,170,171,181,182,183,186,187,202,203,215,217,218,219,220,221,232,233,234,235,247,251,252,259,260,266,267,271,272,273,276,279,287,288,294,316,318,323,328,337,340,344,349,357],doesn:[0,4,9,11,13,15,22,25,26,29,33,36,37,39,44,46,49,51,57,60,61,63,69,71,72,73,75,76,78,86,88,89,90,91,95,96,103,110,111,121,123,125,126,127,128,133,136,137,138,153,164,175,177,181,187,194,195,206,219,242,247,267,280,287,291,316,321,328,339,344],doesnotexist:[144,146,148,175,177,179,182,184,187,189,195,203,204,205,206,212,213,214,217,218,219,220,221,223,226,231,232,233,235,239,246,247,251,256,259,274,300,316,319,324,331,335],doff:218,dog:[27,96],doing:[2,4,10,11,27,29,31,33,36,38,39,43,46,49,51,57,58,59,60,61,64,69,70,79,80,89,90,95,96,97,105,110,114,115,119,125,126,127,133,134,137,138,144,156,175,179,182,194,206,215,217,218,219,220,221,231,232,235,241,247,261,298,328,334,340],dolor:52,dom:137,domain:[8,55,67,90,103,138,324],domexcept:90,dominion:9,dompc:9,don:[0,1,3,4,6,9,10,11,20,21,22,23,25,26,27,29,30,31,33,34,37,38,39,41,42,43,44,46,47,50,51,54,58,59,61,62,63,64,67,68,69,70,72,73,75,80,81,82,83,85,86,88,90,91,93,95,96,97,102,103,104,105,106,111,114,116,119,122,123,125,126,127,128,131,132,133,134,135,136,138,140,144,146,152,153,159,164,165,166,167,168,175,180,185,194,198,205,206,218,219,220,226,233,234,235,242,246,247,251,252,261,271,272,279,284,285,290,292,299,306,313,318,321,322,328,334,337,340,344,357],donald:93,donat:[70,90],done:[1,4,6,9,10,11,20,21,22,25,29,30,31,33,34,36,37,38,39,41,43,44,49,51,55,56,57,58,59,61,62,63,64,67,69,70,73,76,80,82,85,87,90,91,93,100,107,108,110,115,116,117,118,119,120,121,123,126,128,131,133,136,137,144,154,156,164,170,179,185,205,221,235,242,246,247,259,260,261,267,280,284,286,288,292,296,302,305,306,308,313,316,321,322,329,334,344],donoth:259,dont:289,doom:252,door:[0,20,22,27,43,49,61,80,85,89,103,159,212],doorwai:212,dot:[22,43,119,153,159,322,344],dotal:[321,343],dotpath:344,doubl:[22,38,43,57,97,119,133,152,171,343,344],doublet:[152,153],doubt:[22,138,234],down:[0,4,6,11,12,21,22,29,31,33,36,38,39,41,43,49,50,51,55,57,58,61,63,73,81,85,86,90,91,93,96,100,102,103,104,106,108,111,114,119,122,123,136,137,144,159,164,169,195,209,215,218,219,232,235,241,247,252,259,261,267,269,276,277,284,285,305,306,308,321,329,330,344],download:[5,9,23,26,63,64,72,75,79,90,100,101,128,130,131,139],downtim:[29,103,331],downward:[43,156],dozen:[25,55,108],drag:137,draggabl:138,dragon:56,dramat:[11,61],drape:182,draw:[14,38,39,49,73,119,330],draw_room_on_map:49,drawback:[14,23,28,29,51,58,73,86,138,181,322],drawn:[49,58,111],drawtext:73,dream:[26,55,61,129],dress:182,drink:[316,318],drive:[9,19,21,61,63,64,96,100,121,131,133],driven:[25,79,123,214,249],driver:23,drizzl:[102,132],drop:[6,9,14,20,21,23,25,33,37,40,55,57,58,60,69,70,73,80,85,86,87,88,89,90,117,118,121,128,137,138,159,165,182,203,214,218,221,226,247,276,318,322,344],drop_whitespac:330,dropdown:[106,138],droplet:67,dropper:[218,221,247],drum:90,dry:67,dtobj:344,duck:[27,95],duckclient:24,due:[5,6,12,22,29,31,33,40,43,58,60,62,63,64,76,90,91,93,95,96,104,107,125,126,140,153,169,246,247,269,305,308,321,337],duh:108,dull:[20,26,111],dumb:[20,138,308,321],dummi:[9,33,54,59,80,93,127,206,242,267,285,298,299,306],dummycli:298,dummyfactori:298,dummyrunn:[141,142,262,267,285,297,299,301],dummyrunner_act:298,dummyrunner_actions_modul:298,dummyrunner_echo_respons:298,dummyrunner_set:[93,141,142,262,267,297],dummyrunner_settings_modul:93,dummyrunnercmdset:298,dummysess:308,dump:[34,209,276],dungeon:[55,77,112],dupic:31,duplic:[31,37,96,152,159,261,318,337],durat:[10,28,132,139,169,219,338,345,364],dure:[9,11,29,31,38,40,55,60,61,63,66,68,79,80,95,97,100,102,105,107,116,123,132,135,136,137,140,144,152,164,170,187,203,231,233,234,242,260,276,286,322,324,328,337,357],duti:64,dwarf:111,dying:[217,218,219,220,221],dynam:[2,3,34,43,68,82,86,90,111,114,115,124,133,137,138,139,144,148,154,166,169,170,177,188,206,215,217,218,219,220,221,239,246,247,256,261,316,318,319,324,326,328,335,338,344,347,364],dyndns_system:90,e_char_typeclass:120,each:[0,1,2,4,5,10,11,13,19,20,22,27,29,31,33,34,36,38,39,40,42,43,48,49,51,55,56,57,58,59,61,62,64,69,73,77,80,82,83,85,86,95,96,97,100,102,104,105,108,109,111,112,114,115,116,119,121,123,124,125,126,127,132,133,136,137,138,140,144,151,152,153,157,159,164,166,168,170,175,179,181,182,183,187,188,203,205,206,215,217,219,220,221,226,228,235,239,242,246,247,250,252,258,261,269,272,285,287,290,294,299,306,307,308,316,318,319,321,322,324,326,327,328,329,330,334,344,347],eaoiui:205,earli:[36,138,217,218,219,220,221,269],earlier:[3,9,13,31,36,51,54,58,60,61,62,64,74,85,95,96,106,119,121,123,131,134,272],earn:124,earnest:124,earth:[82,103],eas:[31,33,39,86,90,100,126],easi:[0,5,10,13,17,22,23,26,29,33,38,39,43,46,51,55,56,61,62,67,68,69,72,73,76,79,81,82,85,88,89,90,100,102,106,108,111,113,116,118,123,125,126,127,128,131,133,134,138,140,153,157,182,188,215,328,334],easier:[1,4,10,11,12,22,25,37,38,39,47,51,55,56,57,58,61,62,69,73,86,90,91,95,96,102,109,126,136,205,215,217,218,219,220,221,232,309,316,319,344],easiest:[0,5,12,15,25,27,30,46,58,63,67,70,76,123,128,131,133,135,209,318],easili:[0,3,4,11,12,13,14,17,20,25,27,28,33,34,37,38,39,46,48,49,51,55,58,60,61,62,63,68,70,73,80,83,85,88,90,91,96,98,100,103,105,106,107,108,109,111,112,119,122,123,131,133,136,137,138,140,164,175,177,179,180,182,188,190,194,205,212,215,217,218,219,220,221,234,238,239,261,322,328,339],east:[25,44,49,111,159,233],east_exit:233,east_west:111,eastern:[62,111],eastward:233,eccel:330,echo1:29,echo2:29,echo3:29,echo:[5,10,12,20,26,27,28,29,33,36,38,43,44,49,50,55,59,65,71,90,95,96,98,100,104,109,110,116,118,123,132,140,144,146,157,159,164,169,170,182,185,206,231,232,233,247,265,272,287,290,326,328,344],echotest:5,econom:[55,79,86],economi:[61,73,102,108,120,179],ecosystem:100,ect:96,edg:[16,27,131,170,330,344],edgi:49,edit:[0,1,4,5,6,9,11,13,14,23,25,26,30,33,35,37,40,41,43,46,48,54,56,58,59,60,61,62,67,68,69,70,75,76,79,80,81,86,95,96,97,100,101,104,106,109,111,114,128,133,134,135,136,137,138,157,159,166,169,180,186,188,192,193,195,196,202,203,242,247,249,251,252,316,326,357,364],edit_callback:[193,195],edit_handl:159,editcmd:22,editor:[0,5,9,15,21,22,33,38,43,45,46,53,57,60,63,67,76,79,95,96,97,108,109,111,131,139,159,166,168,169,180,202,256,322,326],editor_command_group:326,editorcmdset:326,editsheet:58,edu:124,effect:[6,10,11,14,27,28,29,31,35,39,43,56,57,58,61,73,87,95,104,107,110,111,114,115,116,117,124,126,127,128,129,138,140,144,152,153,159,168,175,185,195,218,219,220,231,233,247,253,256,280,344],effici:[11,26,28,29,39,55,56,64,76,79,86,87,93,95,103,112,115,119,125,132,179,206,213,242,247,261,316,317,319,326,329],effort:[37,56,131,134],egg:75,egg_info:63,egi:269,either:[0,4,9,12,13,17,23,27,29,31,33,34,37,38,39,41,43,44,46,49,51,56,57,58,69,73,80,83,90,91,93,95,97,102,103,105,109,110,111,112,114,116,119,121,122,123,125,126,128,131,137,138,144,146,152,153,154,164,169,176,180,192,198,199,205,206,212,215,217,220,221,226,242,247,250,252,256,258,259,261,265,276,288,292,299,317,318,319,328,330,337,339,341,344],elabor:[4,22,85,91,123],electr:[90,124],eleg:37,element:[16,17,22,41,43,51,55,91,114,151,156,166,170,180,184,204,205,247,252,316,317,319,322,327,328,329,344],elev:[46,82,124,139,364],elif:[0,41,49,51,58,73,102,116,117,123],elimin:[96,100,321],ellipsi:96,ellow:[114,321],els:[0,1,2,5,9,10,12,19,20,21,22,23,25,27,29,30,33,38,39,41,42,46,48,49,51,58,60,68,69,73,80,81,82,84,85,90,91,95,102,103,111,114,115,116,117,120,121,123,127,131,133,134,137,164,170,179,182,188,204,217,218,219,220,221,235,246,296,318,328,344],elsennsometh:170,elsewher:[2,29,31,58,70,96,112,133,138,153,233,267,308,316],elvish:205,emac:[14,79],email:[63,64,67,131,144,186,324,338,344,345,357],email_login:[141,142,178],emailaddress:344,emailfield:357,emb:[38,58,109,114,187,252],embark:121,embed:[109,114,125,138,166,175,250,327,344],emerg:[76,80,103],emi:205,emit:[25,34,108,137,144,153,157,175,189,247,306,337],emit_to_obj:[153,247],emitt:83,emo:21,emoji:24,emot:[33,41,43,55,68,116,144,165,179,205,206,316],emoteerror:206,emoteexcept:206,emphas:[38,61],emphasi:38,emploi:345,empti:[0,2,3,6,9,10,14,25,31,33,38,41,42,43,47,49,51,54,58,60,63,64,69,73,77,84,86,88,89,91,96,97,100,114,115,117,119,123,125,127,128,131,134,137,138,150,151,157,159,164,170,180,190,192,206,251,252,265,272,276,298,299,316,322,324,328,330,341,344],empty_color:190,empty_permit:357,empty_threadpool:312,emptyset:31,emul:[43,64,75,105,123,129,169],enabl:[8,24,43,71,100,103,106,114,126,134,137,144,188,290,345],enable_recog:206,enableloc:290,enableremot:290,encamp:46,encapsul:338,encarnia:79,encas:326,enclos:[35,43,50,171,186],encod:[7,27,58,111,139,278,291,295,296,321,340,344,364],encode_gmcp:291,encode_msdp:291,encoded_text:344,encompass:27,encount:[60,95,153,345],encourag:[3,22,24,39,70,91],encrypt:[7,8,43,83,103,164,287,288,292],end:[1,5,6,8,9,10,11,13,14,19,20,21,22,23,25,27,28,29,31,33,34,38,39,40,43,47,50,51,54,55,58,60,62,64,65,67,69,73,76,80,81,83,86,87,88,90,91,93,95,96,100,105,107,108,109,114,116,118,119,121,122,123,126,128,131,133,134,135,137,138,140,144,146,152,153,159,165,166,179,181,182,185,190,202,206,214,215,217,218,219,220,221,233,238,271,278,279,287,290,291,298,301,306,310,312,317,321,322,324,328,329,330,337,344],end_convers:51,end_turn:116,endblock:[3,69,133,134],endclr:114,endfor:[69,133,134],endhour:25,endif:[69,133,134],endlessli:103,endpoint:103,endsep:344,endswith:321,enemi:[11,29,51,61,109,116,122,219,220,221,231,232,233],enemynam:51,enforc:[10,33,41,61,73,80,114,126,138,287,290,329,330],enforce_s:330,engag:[55,221,231],engin:[22,23,33,36,43,55,56,64,68,73,77,79,89,102,103,104,122,127,131,136,140,150,153,166,168,169,210,233,238,267,278,284,287,290,295,305,307,322,324],english:[15,76,79,97,113,139],enhanc:[59,81,114,209,321],enigmat:20,enjoi:[61,63,91,106],enough:[4,6,21,29,38,39,41,42,43,51,55,57,58,61,63,64,69,70,80,84,85,87,90,91,96,108,112,115,119,123,126,136,153,159,170,204,205,226,235,328,329,330],ensdep:344,ensur:[49,69,100,106,117,126,127,215,310,342],ensure_ascii:296,enter:[0,1,3,5,9,12,13,14,15,20,21,22,23,25,26,27,29,31,33,35,36,41,42,43,44,46,51,58,62,63,64,66,69,75,77,80,83,85,87,89,91,95,96,100,109,111,114,116,117,119,122,123,124,128,129,131,133,135,138,139,141,144,151,153,158,166,167,169,179,180,182,187,188,198,215,217,218,219,220,221,231,233,235,241,247,252,256,265,306,328,347,357],enter_guild:51,enter_nam:51,enter_wild:235,enterpris:36,entir:[10,11,13,14,19,22,27,29,33,46,49,50,51,60,61,69,80,86,90,91,108,111,114,115,123,125,127,136,180,205,206,215,234,242,247,251,252,318,322,328,330,334,344],entireti:[51,73,188,328],entit:324,entiti:[6,11,27,34,43,47,51,53,55,59,61,64,80,84,87,89,102,105,107,109,112,116,119,125,126,139,143,144,154,159,164,169,175,176,177,206,212,239,241,247,249,250,251,252,253,256,257,259,261,308,316,317,319,324,328,329,333,341,344],entitii:107,entitl:90,entranc:111,entri:[4,5,11,15,24,25,27,31,33,34,43,47,48,51,53,54,58,59,63,69,70,72,77,80,83,91,95,107,119,121,131,138,139,144,154,166,167,170,190,204,215,217,218,219,220,221,236,238,239,242,247,261,286,299,310,316,322,324,326,328,330,337,338,341,344,345],entriest:[43,156],entrust:59,entrypoint:100,entrytext:[69,239,324],enul:8,enumar:344,enumer:134,env:[267,277],environ:[4,7,9,13,25,36,38,43,45,59,61,63,64,65,82,90,95,100,103,128,169,170,228,230,267,277,293,302,322,328,342,360],environment:267,eof:287,epic:79,epilog:234,epoch:[27,62,331],epollreactor:312,epub:79,equal:[0,16,19,20,25,31,33,39,46,91,93,96,97,114,121,152,164,187,206,217,218,219,220,221,247,344],equip:[14,57,114,182,217,218,220,221],equival:[10,11,13,40,43,47,63,87,88,101,103,104,110,114,128,143,159,238,285,291,316,344],eras:[9,95,221],err:[58,80,276,298,322],err_travers:[89,247],errback:[10,264,267,276,277,344],errmessag:152,errmsg:[123,337],erron:[113,123,276,330],error:[1,5,6,8,9,10,11,14,15,20,22,23,24,26,27,31,33,37,38,42,43,51,56,57,58,59,60,63,64,67,71,74,75,76,80,83,86,87,89,90,91,97,103,104,105,109,111,113,114,118,119,120,122,123,125,127,128,131,133,135,139,144,150,152,153,159,164,175,195,204,206,215,232,234,242,247,250,251,259,260,264,266,267,269,271,276,290,298,318,321,322,324,327,328,337,340,344,345,364],error_check_python_modul:267,error_class:357,error_cmd:44,error_msg:310,errorlist:357,errorlog:8,escal:[2,19,43,80,156,241],escap:[43,69,114,165,169,234,321,343,357],escript:[22,180],esom:166,especi:[1,8,15,22,23,29,60,61,63,67,80,105,111,112,124,190,205,322],ess:52,essai:79,essenti:[28,49,56,67,75,79,106,113,176,267,324],est:[52,170],establish:[33,61,73,105,144,217,247,264,276,278,285,287,290,295,298,305,307],estim:[30,252,334],esult:247,etc:[2,5,6,8,11,12,20,22,23,25,27,29,30,33,35,38,40,41,43,47,48,49,51,53,55,56,57,58,61,62,63,64,67,73,79,80,83,84,86,87,88,89,95,96,100,102,103,105,107,108,109,110,112,116,119,120,125,126,127,131,132,137,138,144,148,150,151,152,153,156,158,159,164,167,169,179,183,184,188,190,203,205,206,212,218,220,226,234,247,251,252,285,287,290,294,295,296,306,307,316,318,321,322,324,325,326,327,328,337,344,347],etern:51,euro:90,ev_channel:146,eval:[109,179,344],eval_rst:38,evalstr:242,evalu:[33,38,51,119,151,179,242,328],evbot:[43,164,308],evcast:79,evcel:[327,330],evcolor:79,evcolum:330,evcolumn:330,eve:344,eveditor:[22,45,53,139,141,142,180,320,364],eveditorcmdset:326,even:[1,4,6,9,11,12,14,19,21,22,25,26,27,29,31,37,39,41,42,43,46,49,50,51,54,55,56,57,58,60,61,62,63,64,69,70,73,77,80,85,86,90,91,93,97,102,103,105,106,108,110,114,115,116,118,119,122,123,125,126,129,131,135,138,152,154,157,164,166,182,184,187,188,205,217,218,219,220,221,233,234,247,252,290,328,330,334,344],evenli:[27,184,344],evenn:100,evenna:9,evenni:4,evennia:[0,1,2,3,6,10,11,12,13,14,15,17,19,20,21,22,24,27,28,29,30,31,33,34,35,36,37,39,40,43,44,48,49,50,51,52,53,59,60,61,62,63,64,65,66,68,69,70,72,73,74,78,80,81,82,83,84,85,86,87,88,89,92,93,94,97,98,99,101,102,103,104,105,107,108,111,112,113,114,115,116,117,118,119,120,121,122,123,125,129,130,132,133,134,135,136,138,139,364],evennia_access:8,evennia_channel:[43,65,72,98,164],evennia_dir:344,evennia_error:8,evennia_launch:[106,141,142,262,265],evennia_logo:136,evennia_vers:267,evennia_websocket_webcli:295,evennia_wsgi_apach:8,evenniaform:357,evenniagameindexcli:269,evenniagameindexservic:270,evennialogfil:337,evenniapasswordvalid:311,evenniareverseproxyresourc:312,evenniatest:[170,196,211,228,293,342,360],evenniausernameavailabilityvalid:[144,311],evenniawebtest:360,event:[51,64,73,103,107,137,139,141,146,179,184,194,195,196,198,206,209,226,256,259,309,364],event_nam:[194,198],eventdict:337,eventfunc:[0,141,142,178,191,195],eventhandl:195,eventi:[154,180,234],eventu:[4,11,12,19,25,29,33,41,58,61,70,76,80,83,88,90,110,116,119,123,133,136,144,150,151,168,185,205,206,226,233,242,247,252,264,272,298,306,307,319,323,324,328,330,355],evenv:[4,36,63,64,75,97,106],evenwidth:330,ever:[11,12,13,14,15,22,23,25,33,41,57,64,73,86,91,102,105,110,111,112,113,118,125,128,131,138,205,261,278,279,285,316,328],everi:[0,4,6,11,13,20,21,25,26,27,28,31,33,36,37,39,41,43,46,48,49,51,57,62,63,64,69,73,74,75,77,85,86,90,91,96,100,102,104,108,109,111,112,113,114,115,116,119,120,121,122,123,125,127,128,130,131,132,133,134,135,136,138,144,159,164,170,182,188,195,205,206,215,217,218,219,220,221,223,230,235,247,252,259,261,272,289,299,305,314,316,318,328,329,330,344],everror:195,everybodi:41,everyon:[19,21,24,33,34,43,51,58,61,64,71,73,77,78,80,87,98,102,110,112,114,116,121,123,127,128,131,132,159,164,165,166,185,217,218,219,220,221,285],everyth:[9,11,19,21,26,28,31,36,38,42,43,47,49,51,55,58,61,63,64,67,69,72,73,75,79,80,81,83,85,87,90,91,97,100,103,104,109,110,111,113,115,116,119,122,127,128,131,135,136,137,138,139,149,154,164,165,167,169,170,171,181,186,233,241,246,256,271,298,306,316,318,322,328],everywher:[9,56],evform:[27,45,53,141,142,320],evgam:[43,164],evgamedir:38,evict:310,evid:72,evil:[14,93,226,252],evilus:164,evmenu:[22,27,33,45,53,58,85,124,139,141,142,169,170,180,188,214,215,230,249,320,329,364],evmenucmdset:328,evmenuerror:328,evmenugotoabortmessag:328,evmenugotomessag:328,evmor:[45,139,141,142,251,320,364],evtabl:[27,33,45,49,53,82,111,141,142,154,164,188,251,320,327,329,344],exact:[33,41,43,51,80,93,95,96,119,129,138,144,151,159,164,168,176,206,221,238,247,251,252,317,318,340,341,344],exactli:[2,10,19,20,38,40,42,46,58,62,63,64,69,73,76,83,86,91,95,96,100,102,110,111,114,115,123,128,131,136,138,164,206,247,267,318,341],exam:[43,159],examin:[2,11,12,20,22,33,58,60,73,80,83,85,91,96,106,115,122,123,131,137,140,144,159,170,179,226,232,233,299],exampl:[0,2,4,5,6,8,10,11,13,14,15,17,19,20,21,22,25,27,28,29,30,31,33,36,37,38,40,41,43,44,48,49,55,56,57,58,59,60,61,62,63,64,67,68,71,74,77,81,82,84,85,86,87,88,89,91,93,95,96,97,98,100,103,104,105,106,109,110,111,112,114,115,117,118,119,121,122,123,124,125,126,129,130,131,132,133,135,136,138,139,140,141,142,144,148,151,152,153,154,157,158,159,164,165,166,167,168,169,170,175,177,179,180,182,184,185,187,188,189,190,199,203,204,205,206,209,212,213,214,215,217,218,219,220,221,223,226,231,233,234,235,239,242,246,247,252,256,259,261,272,287,290,291,296,299,308,312,316,318,319,320,321,323,327,328,329,330,331,335,337,338,341,342,344,345,357,363,364],example_batch_cod:[13,141,142,178,222],exapmpl:5,excalibur:85,exce:[82,217,218,219,220,221,310,334],exceed:310,excel:[56,67,79,80,102,108],excempt:152,except:[4,9,10,11,14,19,20,21,22,27,28,29,31,33,38,39,41,46,50,58,63,64,75,80,83,89,90,91,95,97,102,109,111,114,116,118,119,120,121,123,126,133,134,144,146,148,150,153,154,167,168,175,176,177,179,182,184,187,189,194,195,198,202,203,204,205,206,212,213,214,217,218,219,220,221,223,226,231,232,233,234,235,239,241,242,246,247,251,256,259,260,267,272,274,276,288,290,292,296,300,312,316,319,321,324,327,328,330,331,335,337,339,344],excepteur:52,excerpt:50,excess:[22,80,109,167,246,322],exchang:[13,90,102,179,325],excit:[20,35,54],exclam:21,exclud:[64,119,120,123,175,182,203,233,246,247,326,328],exclude_cov:182,excluded_typeclass_path:169,exclus:[51,61,80,83,226,247,256,317,328],exclusiv:324,exe:[63,106,128],exec:[51,85,109,252,328,344],exec_kwarg:328,exec_str:302,execcgi:8,execut:[0,9,10,12,13,14,19,22,25,28,29,31,33,36,43,45,46,47,50,51,55,62,63,64,69,75,83,85,87,89,91,95,102,106,109,111,114,119,127,128,137,139,144,146,148,149,150,154,157,158,167,169,170,177,180,195,206,215,226,233,234,239,241,242,246,247,252,253,256,260,264,272,274,277,278,284,287,290,295,298,299,302,305,306,316,318,319,322,328,329,335,344,347,364],execute_cmd:[2,33,89,117,118,123,144,146,154,247,272,306],execute_command:33,executor:36,exemplifi:[28,40,122],exercis:[21,41,42,58,85,95,96,111,116,123,132,293,303,335],exhaust:22,exhaustedgener:204,exidbobj:247,exis:44,exist:[0,2,3,5,11,12,13,20,21,22,25,27,31,33,35,36,39,40,41,43,44,46,48,49,51,56,57,58,60,61,64,65,68,69,70,72,76,80,86,96,97,100,102,105,109,111,112,115,116,117,123,124,128,131,134,136,138,139,143,144,146,152,153,154,159,164,166,167,169,180,181,187,192,194,195,198,199,202,203,205,206,213,220,232,235,241,242,246,247,249,252,260,267,271,273,287,288,290,292,300,305,306,308,316,317,318,319,322,324,326,327,328,330,337,339,344],existen:306,exit:[20,21,22,23,31,39,41,43,45,49,50,51,53,55,58,63,80,85,86,91,100,106,109,111,119,121,122,123,124,125,128,139,141,150,152,153,159,169,179,180,196,212,213,215,221,226,231,232,233,234,235,241,246,247,252,287,299,316,324,326,328,329,342,360,364],exit_alias:[159,212],exit_back:58,exit_cmd:[51,329],exit_command:247,exit_nam:[49,159,212],exit_on_lastpag:329,exit_ther:58,exit_to_her:[43,159],exit_to_ther:[43,159],exit_typeclass:[235,342,360],exitbuildingmenu:22,exitcmdset:[31,247],exitcommand:247,exitnam:212,exitobject:44,exixt:285,exot:33,exp:327,expand:[0,1,4,5,6,20,21,23,49,55,57,58,61,64,70,74,81,85,89,90,104,111,114,117,120,123,124,131,132,135,139,140,159,186,212,217,218,219,220,221,247,321,330],expand_tab:330,expandtab:[321,330],expans:[44,61],expect:[0,1,6,9,10,33,34,37,38,47,56,58,61,67,75,80,83,87,88,89,90,91,95,96,97,107,113,114,115,122,123,124,126,127,128,134,138,159,167,170,180,192,194,204,235,241,247,251,252,265,318,328,329,334,344,349],expected1:170,expected2:170,expected_input:170,expected_return:127,expedit:96,expens:[90,115,119,341],experi:[26,42,51,57,60,61,62,63,73,77,81,90,95,100,111,122,131,135,139,164],experienc:[51,61,64,79,95],experienced_betray:51,experienced_viol:51,experiment:[43,74,169],explain:[20,22,33,39,48,51,55,58,64,71,79,86,119,121,124,126,127,129,131,134,136,139],explan:[25,31,33,39,64,69,77,114,124,139,311],explicit:[0,1,22,31,38,40,48,69,71,88,91,104,129,136,204,267,289,316,328],explicitli:[4,9,21,30,31,38,43,58,59,63,68,80,83,84,85,86,87,96,97,109,112,114,115,124,125,153,154,159,166,170,204,247,252,261,318,321,324,340],explor:[0,2,10,20,42,43,59,63,69,83,95,104,111,116,122,125,169],expos:[103,134,226],express:[3,33,38,43,51,56,80,109,119,127,134,135,140,159,184,204,221,316,344,347],ext:51,extend:[1,3,5,27,34,39,43,55,56,69,73,79,85,86,108,109,111,117,118,125,133,134,148,154,166,170,175,181,183,187,195,198,235,246,247,318,338,357],extended_room:[141,142,178],extendedloopingcal:261,extendedroom:187,extendedroomcmdset:187,extens:[1,3,9,23,38,51,55,56,61,63,64,88,96,97,104,111,114,127,138,148,210,217,282,290,324,333,343],extent:[22,56,73],exter:164,extern:[8,15,23,34,38,40,41,43,54,55,57,63,65,72,90,98,106,108,109,111,124,139,141,153,164,170,172,177,209,251,265,267,269,324],external_discord_hello:272,external_receiv:177,extra:[1,6,8,14,16,21,23,25,29,31,33,37,41,51,57,58,80,89,90,93,95,96,107,114,119,123,125,126,127,134,136,137,138,144,148,154,166,170,175,179,187,189,202,206,226,233,247,250,251,261,264,317,321,322,326,328,329,330,337,338,339,343,344],extra_environ:322,extra_opt:328,extra_spac:344,extract:[11,41,56,91,96,97,107,138,154,206,210,242,281,295,344],extract_goto_exec:328,extrainfoauthserv:287,extral:177,extran:188,extrem:[26,56,91,110,128,217,218,220,221,280,338],eye:[60,97,111,114,252,329],eyed:136,eyes:[33,37,57],eyesight:[58,80,114],f6d4ca9b2b22:100,face:[90,103,122,189,311,328],facil:337,fact:[10,11,14,21,29,33,55,57,58,61,76,83,89,103,106,114,117,123,125,126,134,138,140,308,310],facter:138,factor:[0,62,82,114,218,220,264,278,279],factori:[40,96,264,269,277,278,279,285,286,287,288,290,298],factory_path:146,fade:[108,205],fail:[4,9,10,11,12,13,14,24,27,31,41,51,60,61,63,89,91,103,107,109,110,113,116,117,121,127,153,164,168,175,185,206,212,226,232,241,242,247,251,264,265,267,271,278,279,289,310,316,318,338,340,344],failmsg:310,failtext:73,failur:[10,14,63,73,119,127,144,233,269,276,278,279,298,310,321,344],failure_teleport_msg:233,failure_teleport_to:233,faint:102,fair:[73,185],fairli:[39,69,75,182,188,215,218],fake:[183,298,308,316,321],fall:[26,31,38,60,62,64,73,97,102,111,113,141,144,168,189,206,226,233,344,357],fall_exit:233,fallback:[44,49,55,150,154,177,187,242,259,267,296,316,328,339,344],fals:[1,2,4,6,11,20,21,22,25,27,29,31,33,38,41,44,49,50,51,58,62,68,74,77,80,81,84,86,89,96,102,103,115,116,118,120,121,123,125,127,133,137,144,148,150,151,152,153,154,159,164,166,170,175,177,179,180,182,183,184,185,188,192,195,199,205,206,212,215,217,218,219,220,221,230,234,235,238,239,241,242,246,247,249,251,252,256,257,259,260,261,264,267,269,273,276,277,284,285,286,287,290,296,298,304,305,306,308,310,312,316,317,318,319,321,322,324,326,328,329,330,331,334,339,340,341,343,344,345,357],falsestr:188,falsi:175,falter:61,fame:122,famili:[9,51,57],familiar:[3,9,20,29,31,33,39,58,60,63,85,90,91,95,96,111,119,124,125,133],famou:[52,326],fan:79,fanci:[15,17,36,73,138,182],fanclub:119,fantasi:205,faq:[45,124,139,289,364],far:[0,13,20,21,22,31,33,39,41,44,46,49,51,54,55,57,59,61,75,88,90,91,95,96,100,106,111,114,119,131,138,152,221,235,269,294,316,326,334],fashion:111,fast:[11,15,23,26,27,29,56,62,64,82,89,108,115,131,157,299],faster:[23,62,93,119,177,179,316],fastest:[5,38],fatal:267,faulti:95,favor:27,favorit:[21,37],fear:27,featgmcp:291,featur:[0,4,12,15,17,20,22,25,26,27,31,33,34,36,37,42,45,46,47,48,49,50,56,57,59,61,62,63,64,70,72,78,81,85,91,96,103,107,109,111,114,119,122,123,124,125,128,129,131,138,139,144,153,154,187,195,206,215,234,261,284,305,309,318,326,344,364],februari:62,fed:[10,33,80,285,316,325,327],fedora:[8,63,67,131],feed:[7,15,43,49,51,55,73,98,109,128,139,146,164,269,286,287,318,329],feedback:[37,42,61,70,89,118,176,326],feedpars:[98,286],feedread:146,feel:[0,10,17,22,37,38,39,46,55,57,60,61,63,64,69,70,71,73,77,90,91,108,118,122,123,125,131,133,138,205,215,218,226,233],feend78:199,feint:116,felin:27,fellow:327,felt:[102,132],femal:189,fetch:[11,63,90,100,128,131,133,316,329],few:[0,4,6,9,10,11,15,17,20,23,31,33,34,36,38,41,42,43,49,50,55,59,60,61,64,66,73,74,79,80,86,88,89,91,103,110,114,116,119,121,122,123,126,127,131,138,169,184,205,226,246,282,291,310,321,330,344],fewer:[108,308,317],fg_colormap:343,fgstart:343,fgstop:343,fiction:[51,55,62,77,328],fictional_word:205,fictiv:205,fiddl:233,fido:96,fie:102,field:[3,11,23,34,54,56,58,74,84,86,87,89,102,106,107,112,119,125,128,133,135,148,177,188,192,206,221,231,239,241,246,247,251,252,256,257,261,274,316,317,318,319,327,335,340,341,357],field_class:357,field_or_argnam:74,field_ord:357,fieldevmenu:188,fieldfil:[141,142,178],fieldnam:[58,84,188,257,318,334,357],fieldtyp:188,fifi:96,fifo:344,fifth:49,fight:[29,31,61,116,122,217,218,219,220,221,232],fighter:[217,218,219,220,221],figur:[3,12,26,33,37,38,42,49,80,83,90,91,93,96,97,119,121,131,133,138,179,181,184,206,251,267],file:[2,3,4,5,6,8,9,19,20,21,22,23,25,26,27,31,34,36,37,40,41,42,44,47,48,54,56,57,58,59,60,62,63,64,65,66,67,68,69,72,75,76,79,80,81,82,83,85,86,90,93,95,96,97,98,100,102,103,106,109,110,111,114,117,119,120,121,123,128,130,133,134,135,136,137,138,139,141,142,144,158,166,175,180,182,183,184,186,205,209,234,235,252,266,267,287,288,291,292,299,300,301,305,312,313,320,327,328,337,340,341,344,347,350,357],file_end:[322,344],file_help_entry_modul:166,fileentri:166,filehelpentri:166,filelogobserv:337,filenam:[27,60,131,175,205,322,327,337],filename1:267,filename2:267,filesystem:[63,100,103],fill:[36,41,49,50,58,61,65,70,106,111,114,119,133,135,188,316,321,327,328,329,330,344],fill_char:330,fill_color:190,fillabl:188,fillchar:[114,321,344],filo:344,filter:[31,34,39,43,69,86,106,114,119,120,125,133,138,152,157,180,187,206,246,247,344],filter_famili:[119,125],filthi:78,final_valu:10,find:[0,3,4,6,10,11,12,13,14,17,20,21,22,23,24,25,26,27,29,31,33,34,37,38,40,41,42,46,47,48,49,50,55,56,57,58,60,61,62,63,67,68,69,70,73,74,75,76,78,79,80,84,86,87,89,90,91,93,95,96,97,100,102,103,108,109,110,112,114,119,122,123,124,125,127,128,131,133,134,135,136,139,140,144,151,159,166,184,187,206,212,215,233,234,247,251,252,258,267,281,316,317,321,323,341,344],find_apropo:238,find_topicmatch:238,find_topics_with_categori:238,find_topicsuggest:238,fine:[12,15,20,33,41,44,46,64,85,86,89,95,105,112,115,118,122,123,138,146,233,316,324,344],finer:12,finish:[10,14,29,33,38,58,59,61,100,107,122,123,124,128,133,136,141,144,154,156,167,169,179,187,203,232,233,247,267,271,279,290,305,312,323,328,344,347],finish_chargen:51,finit:91,fire:[2,20,21,27,28,29,33,46,51,58,61,96,102,106,107,111,115,118,120,132,139,144,146,150,195,219,220,247,252,267,276,278,295,328,329,334],firebreath:58,firefox:72,firestorm:28,firestorm_lastcast:28,firewal:[67,90],first:[2,3,4,5,6,7,9,10,11,12,13,14,15,16,19,20,21,23,24,26,27,29,31,33,35,38,39,40,41,42,43,45,48,49,50,51,55,56,58,59,61,62,63,65,68,69,70,71,73,75,76,77,80,81,83,85,86,89,90,91,93,96,97,98,100,102,103,104,105,106,107,108,109,110,113,114,116,118,119,120,121,122,123,125,126,127,128,131,132,133,134,135,136,137,138,139,144,146,148,151,152,159,166,167,170,171,175,177,179,180,182,183,184,186,187,204,205,206,212,214,217,218,219,220,221,223,226,231,232,233,234,235,239,241,246,247,251,252,256,259,267,271,272,274,285,287,290,295,296,298,299,305,308,316,318,319,321,322,324,326,327,328,330,331,334,335,343,344,363,364],first_lin:123,firsthand:80,firstli:[9,89,90,96,97],fish:[73,153,203],fist:252,fit:[11,23,39,47,51,58,80,88,121,129,130,133,218,221,327,329,330,344],five:[28,33,90,111,119,153,215,344,345],fix:[13,14,16,26,27,33,37,42,43,51,57,60,61,63,64,70,75,78,83,85,90,95,96,97,109,110,121,123,125,127,138,205,267,327,329,330,340,363],fix_sentence_end:330,fixer:119,fixing_strange_bug:131,fixtur:[170,228,293,303,335,342],flag:[9,13,14,20,28,29,30,31,33,40,41,43,51,58,61,74,76,83,86,108,115,123,131,144,150,152,154,159,226,231,241,242,247,267,274,278,287,290,295,306,326,328,344],flame:[28,220],flash:[14,226],flat:[22,26,27,45,47,48,53,56,59,60,96,125,141,252],flatfil:56,flaticon:79,flatten:252,flatten_diff:252,flatten_prototyp:252,flattened_diff:252,flatul:102,flavor:[20,90,220],flavour:[87,126],flaw:121,fled:[116,231],fledg:[15,90,108,123,133,158,185],flee:[116,117,221,231],fleevalu:116,flesh:[20,58],flexibl:[1,13,21,22,29,39,43,51,57,59,73,88,90,102,108,109,111,116,134,138,148,159,179,180,188,215,316,328,344],flick:345,flicker:226,flip:[51,81],flood:[27,50],floor:[0,82,206],flourish:316,flow:[17,36,40,55,61,83,86,115,131,137,324,328],flower:[12,20,43,61,87,89,119,159],flowerpot:[12,57],fluent:79,fluid:[16,17],flurri:206,flush:[23,33,43,111,128,169,316,318,334],flush_cach:334,flush_cached_inst:334,flush_from_cach:334,flush_instance_cach:334,flusher:334,flushmem:[43,169],fly:[3,12,21,27,31,33,34,43,51,55,64,85,102,109,119,138,144,165,167,177,239,247,261,274,285,288,292,316,322,331,344],fnmatch:316,focu:[4,61,70,116,124],focus:[56,57,77,79,106,123,124,221],foe:218,fold:215,folder:[3,5,8,13,14,21,27,30,38,47,49,55,57,58,60,63,64,69,73,75,76,86,95,96,100,103,106,110,111,116,117,118,123,127,128,130,133,134,135,136,137,217,218,219,220,221,267],folder_nam:64,foldernam:60,follow:[0,2,4,5,7,8,9,10,11,13,14,16,17,19,20,22,23,25,31,33,34,37,38,39,40,41,42,43,46,47,48,49,50,51,54,58,60,61,62,63,65,67,68,69,71,73,74,75,76,79,80,82,85,86,88,89,90,91,93,95,96,97,100,102,103,106,110,112,114,116,117,119,120,121,123,125,127,128,131,133,134,135,137,144,146,148,150,151,154,159,166,167,170,175,177,180,182,183,185,189,195,199,206,215,219,220,233,239,242,246,247,250,251,252,256,257,271,272,282,291,295,296,299,309,316,318,321,322,324,327,328,329,330,337,344],follwo:242,follwow:51,fond:62,font:[25,38,111,137],foo:[33,40,51,83,84,88,95,107,112,119,127,215,328,342],foo_bar:88,foobarfoo:12,fooerror:328,foolish:226,footer:[69,133,154,329],footnot:[15,38],footprint:[43,169],footwear:57,for_cont:247,forai:96,forbid:41,forbidden:131,forc:[0,6,8,10,31,33,58,60,63,73,81,82,91,100,103,110,116,121,123,125,127,138,146,153,157,159,164,179,187,189,203,205,206,242,247,251,258,278,279,285,290,308,310,329,330,334,337,344],force_init:247,force_repeat:[102,116],force_str:340,forcibl:[102,258],fore:305,forebod:187,foreground:[42,100,114,126,183,267,321],foreign:125,foreignkei:[148,246,256,318,335],forens:210,forest:[13,111,112,140,187],forest_meadow:112,forest_room:112,forestobj:140,forev:[61,102],forget:[3,9,10,13,25,27,33,41,54,62,72,82,85,86,95,96,100,123,131,206,322],forgo:232,forgotten:[28,49,77,85],fork:[9,79],forloop:69,form:[11,13,27,31,33,34,38,43,45,51,53,55,58,59,61,64,68,70,74,76,77,80,83,88,89,93,96,97,109,112,113,114,115,116,118,123,124,125,127,129,135,141,142,144,146,151,153,154,157,159,164,167,170,175,176,177,179,188,189,205,206,210,239,241,242,247,251,252,257,259,261,265,285,287,291,295,306,308,316,317,318,321,322,324,325,326,327,328,330,337,340,341,344,345,346,356],form_char:327,form_template_to_dict:188,formal:[61,80,96,138,247,291],format:[0,14,17,19,22,23,27,31,33,37,38,41,42,46,48,55,58,62,68,69,76,79,81,83,88,96,98,103,108,109,111,113,114,119,124,129,131,133,138,152,154,156,159,166,170,175,180,182,183,184,188,198,206,209,215,219,230,234,235,239,247,249,251,252,257,267,272,282,287,307,309,316,318,321,322,324,326,328,329,330,331,337,339,344,345,363],format_attribut:159,format_available_protfunc:251,format_callback:192,format_diff:252,format_extern:175,format_grid:344,format_help:234,format_help_entri:166,format_help_index:166,format_messag:175,format_output:159,format_send:175,format_t:344,format_text:180,format_usag:234,formatt:[188,251,328,329],formcallback:188,formchar:[58,327],formdata:188,former:[17,23,64,126,328],formfield:340,formhelptext:188,formstr:58,formtempl:188,formul:134,forth:[27,43,131,159,220],fortress:111,fortun:[4,33,39,48,69,122,128],forum:[1,9,37,48,55,57,63,90,98,128],forward:[13,14,20,38,42,45,50,51,62,69,90,121,126,144,148,177,199,209,239,246,256,312,316,318,319,327,329,335],forwardfor:67,forwardmanytoonedescriptor:[246,256,335],forwardonetoonedescriptor:[246,256,335],foul:109,found:[2,4,6,9,10,13,14,15,20,22,23,25,27,31,33,38,39,40,41,42,43,49,51,55,57,58,59,63,68,73,74,76,78,80,83,85,89,90,91,97,103,104,109,112,116,119,122,123,125,127,128,134,135,137,138,141,144,149,150,151,152,154,159,164,167,168,175,179,180,192,194,195,206,233,239,242,247,250,251,252,258,261,266,267,273,282,285,296,306,308,316,317,318,321,322,323,324,328,330,334,339,341,344,347],foundat:[49,55,77,79,217],four:[4,14,27,38,39,40,68,73,82,86,87,111,114,119,153,177,187,242],fourth:39,fqdn:90,fractal:56,fraction:127,frame:[137,138],framework:[3,16,64,124,133,136,137,170,217,220,340],frankli:129,free:[0,22,29,37,48,55,57,60,61,64,76,77,79,90,106,112,116,123,124,126,130,133,139,179,206,215,218,251],freedn:90,freedom:[14,26,44,63],freeform:[73,116,182],freeli:[55,77,100,103,322],freenod:[9,43,63,70,72,79,90,146,164,308],freepik:79,freetext:[176,341],freez:[29,33,42,194],frequenc:205,frequent:[91,180],fresh:[11,31,58,128,267],freshli:111,fri:12,friarzen:138,friend:[37,58,61,82,103],friendli:[22,38,78,95,133,138,148],friendlier:[175,247],frighten:219,from:[0,2,3,5,6,8,9,10,11,12,13,14,15,16,17,19,21,22,23,26,27,28,29,30,31,33,34,35,36,37,38,39,40,41,42,43,44,46,47,48,49,50,52,54,56,57,58,59,61,62,63,64,66,67,68,69,70,71,72,73,74,75,76,79,80,81,82,83,84,85,86,87,89,91,92,93,95,97,98,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,134,135,136,139,140,141,142,144,146,148,149,150,151,152,153,154,156,157,158,159,164,165,166,167,168,169,170,171,175,176,177,179,180,181,182,183,184,185,186,187,188,189,194,195,198,199,202,203,204,205,206,209,210,211,212,213,215,217,218,219,220,221,226,231,232,233,234,235,238,239,241,242,243,246,247,251,252,256,257,258,260,261,264,267,272,273,274,276,277,278,279,280,284,285,286,287,290,295,296,298,299,301,305,306,307,308,310,312,313,314,316,317,318,319,320,321,322,323,324,325,326,327,329,330,331,334,335,337,338,340,341,343,344,345,347,357,363,364],from_channel:146,from_db_valu:340,from_nod:[51,328],from_obj:[81,83,118,144,146,154,189,247],from_pickl:325,from_tz:345,frombox:276,fromstr:276,fromtimestamp:331,front:[8,13,20,73,80,85,96,103,109,131,137,139],frontend:[215,316],frozen:[29,33,122,195],fruit:203,ftabl:344,ftp:343,fuel:[21,220],fugiat:52,fulfil:267,full:[4,9,13,14,15,16,17,20,21,23,24,25,26,27,33,37,38,43,51,55,57,58,59,60,61,64,73,75,80,84,88,89,90,95,96,97,100,101,102,105,108,109,110,111,115,116,117,119,121,123,124,125,127,128,131,133,134,135,136,146,151,153,154,158,159,164,168,169,170,175,179,180,185,187,190,202,205,206,215,220,230,234,242,252,257,279,285,298,308,309,316,318,322,326,328,330,344],full_justifi:109,full_nam:87,full_result:185,fullchain:67,fuller:58,fullhost:67,fulli:[4,11,19,33,51,55,58,59,61,63,85,86,90,93,103,110,122,144,205,242,247,259,295,307,324,344],fun:[20,26,61,79,81,111,136],func1:[43,159,242,299],func2:[43,159,242,299],func:[5,10,21,22,25,28,29,30,33,38,42,44,50,51,56,58,60,62,71,73,80,81,82,83,85,91,116,119,121,123,150,154,156,157,158,159,164,165,166,167,168,169,170,171,179,180,181,182,184,185,186,187,188,189,193,199,202,203,206,212,213,214,215,217,218,219,220,221,226,231,232,233,234,241,242,247,278,298,299,303,312,326,328,329,331,344],func_test_cmd_task:170,funciton:220,funcnam:[74,114,242,250,251,261,328,344],funcpars:[250,308,344],funcparser_cal:250,funcparser_outgoing_messages_modul:308,function_nam:169,functioncal:276,functionnam:276,functionpars:251,functool:63,fund:70,fundament:[33,57,77,89,95,96,112,247],furnitur:[13,112,125],further:[0,9,11,27,31,34,38,42,43,44,49,57,83,85,86,90,91,96,100,102,104,105,106,109,110,111,119,124,125,130,131,138,153,159,181,205,219,221,252,267,291,344],furthermor:[37,38,124,126],fuss:100,futur:[9,10,11,20,23,38,43,45,50,55,58,60,61,62,63,76,87,95,100,123,139,156,195,232,235,272,317,338,345,364],futurist:62,fuzzi:[76,164,238,341,344],fuzzy_import_from_modul:344,gadget:70,gag:24,gain:[11,29,61,73,93,154,169,177,206,242,247],galosch:205,gambl:185,game:[0,2,3,4,5,6,8,9,10,11,13,14,15,17,18,19,20,21,22,23,24,25,28,29,30,31,33,34,35,36,37,38,41,42,43,44,46,50,51,52,53,56,60,63,64,65,66,67,68,69,71,72,75,76,77,78,79,80,81,83,85,86,87,88,89,91,92,93,95,96,97,98,101,102,103,104,105,106,107,108,109,110,112,113,114,115,116,117,118,119,121,122,125,129,130,132,133,134,135,136,137,138,139,140,143,144,146,148,150,152,153,154,156,157,158,159,163,164,165,166,169,170,171,172,175,176,177,178,179,180,181,182,184,185,186,187,188,190,193,194,195,196,199,204,205,206,213,215,217,218,219,220,221,226,229,230,233,234,239,243,246,247,256,258,259,262,267,269,270,271,272,278,279,284,286,287,290,291,298,299,300,305,306,308,317,318,319,322,323,324,326,327,331,334,337,344,363,364],game_dir:[337,344],game_epoch:[27,331],game_index_cli:[141,142,262],game_index_en:54,game_index_list:54,game_nam:[54,350],game_slogan:[9,350],game_statu:54,game_templ:47,game_websit:54,gamedir:[51,100,109,267,313],gamedirnam:58,gameindexcli:270,gameplai:90,gamer:[65,72],gamesrc:27,gametim:[27,53,59,139,141,142,184,187,195,320,364],gametime_to_realtim:184,gametimescript:184,gammon:[79,282],gandalf:51,garbag:316,garden:79,garment:182,gatewai:[110,296],gather:[24,33,48,83,119,127,132,136,150,151,233,265,269,324,341],gave:[5,21,60,64,91,102,126],gbg:321,gcc:63,gcreat:169,gear:[43,90,106,136,146,153,171,186],gemer:204,gen:17,gender:189,gendercharact:189,gendersub:[141,142,178],gener:[0,1,5,9,10,11,12,20,23,25,29,31,33,34,36,37,38,48,49,51,55,57,58,59,60,62,63,64,68,70,73,76,80,83,86,87,88,90,93,96,104,105,106,109,111,112,114,116,126,127,134,137,138,139,141,142,144,146,149,154,155,156,159,166,167,168,170,171,175,179,180,181,182,185,186,187,188,189,195,199,202,204,205,206,209,210,212,213,214,215,217,218,219,220,221,226,230,231,233,234,239,242,247,249,252,278,285,287,290,291,295,298,306,307,308,312,316,319,320,321,323,324,326,329,330,337,339,340,344,349,357,364],general_context:[141,142,346,348],generate_sessid:285,generic_mud_communication_protocol:291,genericbuildingcmd:180,genericbuildingmenu:180,genesi:90,geniu:203,genr:[37,64,281],geoff:234,geograph:140,geographi:39,geoip:209,geometr:111,geometri:111,get:[0,1,2,3,5,6,7,8,9,10,11,12,13,15,17,21,22,23,25,26,28,29,30,31,33,38,39,40,41,42,44,45,46,47,48,49,50,54,55,56,57,58,59,60,61,62,64,65,68,69,71,72,73,74,75,76,77,80,81,82,83,84,85,86,87,88,90,91,92,93,95,96,97,100,102,103,104,105,106,107,110,111,112,114,116,118,121,122,123,125,126,127,128,130,131,133,134,135,136,137,138,139,144,146,148,152,153,154,156,157,159,160,164,165,166,171,175,176,177,180,182,185,192,194,195,198,199,203,204,206,213,214,215,217,218,219,220,221,223,226,232,233,235,238,239,242,246,247,249,251,252,256,258,261,265,267,272,276,277,281,285,287,290,291,293,295,296,304,306,307,308,310,316,317,318,319,321,322,323,326,328,330,331,333,334,337,338,339,341,344,357,363,364],get_abl:60,get_absolute_url:[134,175,239,318],get_account:[242,306],get_al:316,get_alia:317,get_all_attribut:316,get_all_cached_inst:334,get_all_categori:238,get_all_channel:176,get_all_cmd_keys_and_alias:152,get_all_cmdset:344,get_all_mail:199,get_all_puppet:144,get_all_sync_data:308,get_all_top:238,get_all_typeclass:344,get_and_merge_cmdset:153,get_attack:[217,218,219,220,221],get_attr:159,get_attribut:317,get_buff:326,get_by_alia:317,get_by_attribut:317,get_by_nick:317,get_by_permiss:317,get_by_tag:317,get_cach:316,get_cache_kei:310,get_cached_inst:334,get_callback:195,get_channel:[41,176],get_channel_alias:164,get_channel_histori:164,get_charact:306,get_client_opt:272,get_client_s:306,get_client_sess:[295,296],get_client_sessid:296,get_command_info:[154,167],get_damag:[217,218,219,220,221],get_db_prep_lookup:340,get_db_prep_valu:340,get_dbref_rang:317,get_def:260,get_default:340,get_defens:[217,218,219,220,221],get_display_nam:[22,42,46,58,144,206,235,247,318],get_err_msg:[6,20,80],get_ev:195,get_evennia_pid:344,get_evennia_vers:344,get_event_handl:198,get_extra_info:[41,154,247,318],get_famili:[119,125],get_game_dir_path:344,get_god_account:271,get_height:330,get_help:[33,68,69,154,170,193,234,328],get_help_text:311,get_id:[133,260,317],get_info_dict:[284,305],get_input:[170,328],get_inputfunc:[272,291,308],get_internal_typ:340,get_kwarg:360,get_location_nam:235,get_log_filenam:175,get_mass:82,get_message_by_id:176,get_messages_by_receiv:176,get_messages_by_send:176,get_min_height:330,get_min_width:330,get_new:286,get_new_coordin:235,get_next_by_date_join:148,get_next_by_db_date_cr:[148,177,239,246,256,316,318],get_next_wait:198,get_nick:317,get_nicklist:[146,279],get_numbered_nam:247,get_obj_coordin:235,get_object_with_account:341,get_objs_at_coordin:235,get_oth:179,get_permiss:317,get_pid:267,get_player_count:281,get_previous_by_date_join:148,get_previous_by_db_date_cr:[148,177,239,246,256,316,318],get_puppet:[2,144,306],get_puppet_or_account:306,get_rang:221,get_regex_tupl:206,get_respons:351,get_room_at:39,get_rooms_around:39,get_sess:308,get_statu:277,get_subscript:176,get_sync_data:307,get_system_cmd:152,get_tag:317,get_time_and_season:187,get_typeclass_tot:317,get_uptim:281,get_username_valid:144,get_valu:[272,291],get_vari:[192,195],get_width:330,get_worn_cloth:182,getattr:84,getchild:312,getclientaddress:[40,287],getel:137,getenv:[267,277],getgl:137,getinput:328,getkeypair:287,getloadavg:75,getpeer:287,getpid:344,getsizof:334,getsslcontext:[288,292],getston:33,getter:[148,177,182,206,218,221,246,247,274,316],gettext:76,gfg:321,ghostli:233,giant:[21,124],gid:[45,100,299],gidcount:298,gif:70,gift:69,girl:247,gist:[205,344],git:[9,23,25,36,38,45,47,63,75,76,79,86,90,100,108,124,128,130],github:[9,25,37,41,43,45,57,63,70,75,76,79,95,96,98,104,130,131,138,180,295,312,344],gitignor:131,give:[0,1,2,3,4,5,9,10,11,12,13,15,18,19,20,21,22,23,25,26,27,30,33,38,39,41,46,48,51,52,55,57,58,59,60,61,62,63,64,68,69,73,75,77,79,80,82,85,88,89,90,91,93,96,98,100,102,103,105,107,109,110,111,112,113,114,115,116,117,118,119,122,123,124,125,127,128,133,134,136,138,139,140,144,150,152,153,156,164,165,167,169,175,176,180,181,182,187,204,205,214,215,217,218,219,220,221,226,233,235,247,256,293,299,306,312,316,318,321,328,330,341,342,344,363,364],given:[0,2,4,10,11,12,13,14,20,21,22,25,27,31,33,34,38,39,42,43,46,49,50,51,58,62,64,70,73,74,80,83,84,85,86,88,89,90,93,97,100,102,105,109,110,113,114,115,116,117,119,122,123,125,126,127,131,133,134,135,138,140,144,150,151,152,153,154,156,157,159,164,166,168,169,170,175,176,177,180,181,182,184,185,186,187,188,189,190,192,194,198,203,204,205,206,212,215,217,218,219,220,221,226,232,233,234,241,242,247,249,251,252,257,258,259,261,265,267,272,273,276,285,290,291,296,299,302,306,307,308,309,310,311,312,316,317,318,319,321,322,324,325,326,327,328,329,330,331,334,337,339,340,341,342,344,347,349],giver:[218,221,247],glad:91,glanc:[22,27,31,33,39,48,58,61,91,96,180,206],glance_exit:22,glass:[203,226],glob:[43,51,165,328],global:[13,22,33,34,35,43,45,51,56,61,64,67,74,85,89,100,104,105,108,109,114,115,120,125,131,132,137,138,140,159,169,175,187,195,204,206,212,247,252,253,256,260,264,267,272,274,277,298,299,322,323,324,328,331,341,342,344,350],global_script:[102,141,323],global_search:[13,22,27,58,91,144,206,247,317],globalscript:43,globalscriptcontain:323,globalth:342,globe:[90,136],gloss:61,glossari:[63,139,364],glow:111,glu:92,glyph:276,gmcp:[55,74,83,291],gmsheet:58,gmud:24,gno:22,gnome:24,gnu:14,go_back:[51,215,328],go_back_func:51,go_up_one_categori:215,goal:[61,76,79,91,102,103,122,124,205],goals_of_input_valid:357,goblin:[43,51,109,159,252],goblin_arch:252,goblin_archwizard:252,goblin_shaman:109,goblin_wizard:252,goblinwieldingclub:109,god:[20,80,271],godlik:206,goe:[0,5,9,22,26,29,33,37,40,42,49,64,69,73,75,86,90,95,96,118,121,122,123,139,152,153,221,235,247,287,290,305,306,343,344],goff:204,going:[0,3,20,25,26,40,45,46,49,51,58,61,62,65,69,70,82,88,90,91,95,96,100,111,116,121,127,133,138,139,180,206,217,218,219,220,221,226,230,233,235,247,264,269,321,328],goings:269,gold:[51,82,85,109,322],gold_valu:85,golden:138,goldenlayout:138,goldenlayout_config:[137,138],goldenlayout_default_config:[137,138],gone:[5,12,77,80,85,100,102,131],good:[0,2,4,5,9,11,12,14,20,21,22,25,26,27,31,33,37,38,39,40,41,46,48,49,51,54,55,56,57,60,61,63,69,70,72,73,79,80,85,87,90,91,93,95,96,97,100,102,103,104,106,109,110,111,114,119,121,123,125,126,127,131,133,134,138,144,152,153,154,170,179,194,206,290,299,328],goodby:287,goodgui:242,googl:[38,43,75,79,90,164,330],googleusercont:70,googli:136,gossip:[65,79,164],got:[10,13,95,96,116,128,138,215,232],goto_cal:[51,328],goto_cleanup_cmdset:230,goto_command_demo_comm:230,goto_command_demo_help:230,goto_command_demo_room:230,goto_kwarg:328,goto_next_room:121,goto_node2:51,goto_str_or_cal:51,gotostr_or_func:328,gotten:[55,95,131,221,232,247,294],graaah:117,grab:[20,33,43,73,133,165,232],gracefulli:[26,43,156,169,206,247,267,344],gradual:[13,14,29,61,79,96,205],grai:[114,126],grain:[115,324],gram:82,grammar:205,grammat:205,grand:11,grant:[19,23,80,131,177,217,218,219,220,221,241,242,251,316],granular:221,grapevin:[7,139,141,142,146,164,262,275,364],grapevine2chan:[65,164],grapevine_:164,grapevine_channel:[65,146,164],grapevine_client_id:65,grapevine_client_secret:65,grapevine_en:[65,164],grapevinebot:146,grapevinecli:278,graph:[49,131],graphic:[42,58,80,83,84,93,111,128,135,141,186,190,291],grasp:[126,133],grave:60,grayscal:183,great:[0,4,14,16,21,22,29,37,39,51,57,61,69,70,73,77,79,91,95,107,108,123,127,131,134,180,188,312],greater:[22,31,73,80,97,105,119,241,328],greatli:78,greek:15,green:[31,43,80,109,114,126,131,159,169,232,321],greenskin:252,greet:[9,35,46,95,104,105,117,272],greetjack:87,greg:79,grei:[109,126,321],grenad:89,grep:[75,131],greyscal:[114,321],greyskinnedgoblin:109,griatch:[21,70,86,119,179,181,183,184,185,186,187,189,199,202,205,206,212,213,214,230,232,327,334,340,343],grid:[7,16,111,123,139,166,221,235,344,364],grief:12,griefer:134,grin:[33,41,316],grip:38,gritti:33,ground:[20,21,55,111],group:[4,9,10,12,19,21,26,33,37,41,43,46,55,68,70,79,91,100,102,109,112,125,127,139,140,148,155,159,165,166,176,187,203,205,232,233,247,251,252,276,299,316,319,321,324],groupd:316,grow:[13,25,26,61,63,79,110,278,279,330,344],grown:[9,25,51,129],grudg:73,grumbl:60,grungies1138:[199,214],grunt:[43,159,252],gstart:169,gthi:81,guarante:[11,37,61,67,80,86,90,102,185,195,251,285,306,318],guard:51,guess:[15,22,46,50,69,91,103,113,138,180,252],guest1:66,guest9:66,guest:[7,53,80,139,144,364],guest_en:[66,80],guest_hom:[66,133],guest_list:66,guest_start_loc:66,guestaccount:112,gui:[45,57,83,137,199,364],guid:[36,37,45,81,95,96,128,133,136],guidelin:[37,38,79],guild:[79,86,112,118,164],guild_memb:51,gun:[21,77],guru:55,habit:56,habitu:115,hack:[55,73,116,276],hacker:[79,103],had:[8,9,14,15,19,20,21,29,31,37,55,61,90,95,96,100,102,119,123,128,135,138,154,158,170,182,232,252,256,267,318,322,329,357],hadn:[61,62,131],half:[108,138,239],hall:49,hallwai:49,halt:[102,111],hand:[1,15,37,38,40,43,51,55,56,57,58,61,70,73,87,89,96,105,108,119,134,154,165,167,169,179],handi:[42,75,119,133,219],handl:[0,2,4,5,7,8,9,11,13,15,22,24,27,33,34,37,40,41,43,44,47,49,50,51,53,55,56,60,61,62,64,67,68,74,75,80,83,85,86,87,88,89,91,93,95,97,100,104,105,108,115,116,117,124,125,126,128,129,131,132,137,138,139,144,146,149,150,152,153,159,160,164,165,168,179,186,187,195,198,206,210,212,214,215,217,218,219,220,221,226,232,233,234,236,246,247,250,251,252,256,257,260,264,267,271,272,276,277,279,280,287,290,291,294,296,298,307,308,316,318,321,322,324,325,326,328,329,330,331,334,343,344,351],handle_egd_respons:269,handle_eof:287,handle_error:[164,195,260],handle_ff:287,handle_foo_messag:[51,328],handle_int:287,handle_messag:[51,328],handle_message2:51,handle_numb:[51,328],handle_quit:287,handle_setup:271,handler:[2,11,31,33,41,47,64,73,80,83,84,86,87,89,102,104,105,112,115,125,139,144,150,153,168,172,177,179,192,195,196,198,206,231,235,241,242,246,247,252,257,258,260,261,272,284,285,305,308,314,316,318,319,323,324,327,328,338,339,344],handlertyp:319,handshak:[24,52,83,277,283,285,290],handshake_don:290,hang:[3,61,70,124],hangout:119,happen:[0,6,12,19,20,26,27,31,33,37,39,41,42,44,51,54,55,57,58,60,61,62,64,72,73,77,80,83,86,88,90,91,95,96,97,102,105,107,108,110,111,114,115,116,119,122,123,126,127,128,131,133,138,144,152,153,164,175,184,213,217,218,219,220,221,231,233,235,247,252,260,269,276,279,299,304,306,307,308,318,328,329,334,337,344],happend:252,happi:[13,119,328],happier:91,happili:96,haproxi:[90,139,364],hard:[9,10,11,13,15,19,26,27,31,33,38,40,41,58,61,63,64,76,79,88,90,93,96,97,100,102,109,112,115,119,121,127,131,133,138,139,168,188,215,256,267,316,318,328,364],hardcod:[57,58,77,100,111,140,316],harden:63,harder:[12,56,61,93,119,127,232],hardwar:[90,280],hare:79,harm:[11,29,219],harri:59,has:[0,2,4,8,9,10,11,12,13,14,15,16,19,20,21,22,23,25,27,28,29,31,33,34,36,37,39,40,41,42,43,44,46,47,49,50,51,53,54,56,57,58,59,60,61,62,63,64,65,67,68,69,70,71,74,75,76,77,78,79,80,83,85,86,87,88,89,90,91,93,95,96,97,100,101,102,103,104,105,107,109,110,112,113,114,115,116,117,118,119,121,122,123,125,126,127,128,129,131,132,133,134,135,136,137,138,139,143,144,146,151,152,153,154,156,158,159,164,166,167,169,170,171,175,176,179,180,184,185,186,187,188,195,199,203,204,206,215,217,218,219,220,221,223,226,231,232,233,234,235,239,241,242,246,247,251,252,256,259,260,261,267,269,271,272,276,279,281,285,289,294,295,299,305,306,307,308,310,316,317,318,319,324,326,327,328,330,334,337,338,341,344,357,360],has_account:[89,231,241,246,247],has_attribut:316,has_cmdset:153,has_connect:[41,175],has_drawn:49,has_nick:316,has_par:344,has_perm:[167,242],has_sub:175,has_tag:319,has_thorn:11,hasattr:[28,33],hash:[14,90,109,252,261,295,299,308,317],hasn:[22,49,204,232,316],hassl:62,hast:219,hat:[37,70,182],hau:[65,146,164,278],have:[0,1,2,3,4,5,6,9,10,11,12,13,14,15,16,19,20,21,22,23,25,26,27,28,29,30,31,33,34,35,36,37,38,39,40,41,42,43,44,46,47,48,49,50,51,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,80,81,82,83,84,85,86,87,88,89,90,91,92,93,95,96,97,98,100,102,103,104,105,106,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,144,146,150,152,153,154,156,159,161,164,167,168,169,170,171,175,176,177,179,180,181,182,184,186,187,188,189,194,195,198,202,204,205,206,209,210,215,217,218,219,220,221,226,233,234,238,239,241,246,247,250,251,252,253,256,259,260,261,272,277,280,281,285,287,290,291,305,306,307,308,313,314,316,317,318,319,321,322,323,324,325,327,328,329,330,337,340,341,342,344,345,350,357,363],haven:[4,22,29,42,62,67,77,109,111,117,118,120,127,128,133,134,138,310],head:[20,21,31,46,69,76,77,96,106,119,121,123,138,139],headach:[61,138],header:[9,13,14,27,34,37,38,63,89,95,103,129,138,154,166,177,199,206,247,322,324,329,330],header_color:159,header_line_char:330,headi:330,heading1:330,heading2:330,headless:[96,247],headlong:63,heal:[219,220,233],healing_rang:220,health:[30,61,73,84,88,90,109,116,190,252,291],health_bar:[141,142,178],hear:[29,46,61,170],heard:[111,122],heart:126,heartbeat:[115,278],heavi:[6,11,20,23,27,33,64,73,80,82,96,116,123,179,206,218,280,344],heavier:218,heavili:[9,27,37,40,57,75,86,104,180,217,218,219,220,221,318],heed:[105,242],heh:138,hei:[20,179,199,205],height:[52,74,137,141,272,287,306,327,330],held:[1,31,48,116,241],hello:[0,29,34,41,43,46,51,72,74,83,87,88,91,96,105,108,123,129,164,165,170,175,206,272,321],hello_funct:95,hello_valu:108,hello_world:[95,96,108],helmet:[29,77],help:[0,1,4,5,12,13,14,15,19,22,23,27,29,32,33,35,38,39,41,42,44,45,46,47,48,49,50,51,53,57,58,60,61,63,64,67,71,72,76,77,79,80,86,90,91,93,96,105,107,108,109,110,111,112,113,116,119,122,123,124,126,127,131,133,137,138,139,141,142,149,150,152,154,155,156,164,167,169,170,171,179,184,186,188,192,193,195,199,205,209,217,218,219,220,221,226,230,233,234,249,260,265,267,269,270,278,285,287,288,290,292,295,296,298,299,316,317,321,324,325,326,328,329,339,340,341,342,351,357,363,364],help_categori:[22,33,41,43,58,60,68,69,71,85,116,123,154,156,157,158,159,164,165,166,167,168,169,170,171,179,180,181,182,185,186,187,188,189,193,199,202,203,206,212,213,214,215,217,218,219,220,221,226,231,232,233,234,238,239,247,298,326,328,329,341],help_cateogori:326,help_entri:326,help_kei:159,help_messag:166,help_mor:166,help_system:69,help_text:[166,195,357],helpact:234,helparg:170,helpentri:[69,80,166,238,239,324],helpentry_set:319,helpentrymanag:[238,239],helper:[19,41,43,51,58,67,80,109,119,141,144,153,156,159,164,166,176,180,184,205,247,251,252,264,276,277,296,308,322,328,329,337,342,343,344],helpfil:166,helptext:[51,249,328],helptext_formatt:[51,249,328],henc:[0,22,46,76,95,106,233,234,322],henceforth:[13,44,60,66,80,90,95,97,102,105,111,123,131,132,140,308],henddher:203,her:[122,127,182,189],herbal:327,herd:23,here:[0,2,3,4,5,9,10,11,13,14,15,16,17,19,20,21,22,23,24,25,27,29,30,33,36,37,38,39,40,41,42,43,44,46,47,48,49,51,53,56,57,58,59,61,62,63,64,65,67,69,70,71,72,73,74,75,76,77,79,80,81,83,84,85,86,87,88,89,91,92,95,98,100,101,102,103,104,105,106,107,108,109,110,111,113,114,115,116,117,118,119,120,121,123,125,126,127,128,129,130,131,133,134,135,136,137,144,146,152,153,154,159,167,168,169,170,171,179,180,181,182,184,185,186,194,195,204,205,206,213,217,218,219,220,223,231,232,233,234,235,239,242,247,251,252,267,269,272,276,278,284,285,287,290,299,305,306,308,314,316,318,321,324,328,330,334,347],hesit:[22,39],hfill_char:330,hidden:[11,49,61,64,96,122,131,137,177,182,185,234],hide:[9,11,20,31,33,34,41,61,73,80,96,111,138,166,177,185,206,232],hide_from:[34,177],hide_from_accounts_set:148,hide_from_objects_set:246,hieararci:241,hierarch:[2,19,43,80,156],hierarchi:[4,19,22,43,61,66,69,80,119,139,165,182,241],high:[4,8,20,31,55,63,80,122,152,220,247,309],higher:[7,19,25,31,41,43,44,51,56,58,62,63,73,80,90,105,108,119,123,128,144,152,156,169,205,217,218,219,220,221,233,241,269,328,344],highest:[31,58,321,344],highest_protocol:340,highli:[9,17,51,55,56,64,80,86,107,115,117,190,322,334],highlight:[14,38,57,58,114,126],hijack:134,hilight:343,hilit:343,hill:87,him:[41,46,51,189,206],hint:[1,25,55,63,79,93,95,109,110,123,124,128,136,139,184,313],hire:[85,103],his:[46,51,58,77,96,109,127,182,189,206,329,343],histogram:344,histor:[62,129,266,337],histori:[4,23,34,41,50,58,64,95,100,131,137,138,139,153,164,175,188,337],hit:[6,9,21,29,52,61,73,116,119,122,131,146,217,218,219,220,221,231,232,265,306,337,340],hit_msg:231,hite:114,hmm:138,hnow:114,hobbi:[61,90],hobbit:62,hoc:55,hold:[2,6,9,13,14,16,21,26,31,34,36,38,41,47,49,51,58,61,63,64,66,73,77,80,85,89,96,97,100,102,104,105,106,109,111,112,114,116,119,123,125,131,133,136,140,152,153,178,180,182,185,204,214,215,217,218,219,220,221,229,231,232,236,241,242,251,252,253,257,262,274,276,285,295,296,298,308,318,319,320,324,327,328,330,332,337,344,346],holder:[9,69,90,316],home:[8,16,26,63,64,66,70,79,89,90,103,109,131,133,139,153,159,165,231,246,247,252,324,344],home_loc:[43,159],homepag:[27,63,79,90,93],homes_set:246,homogen:[27,251,252,256],homogenize_prototyp:251,honor:206,hood:[20,33,38,51,57,60,61,64,86,87,119,122,125,128,206,234],hook:[2,25,30,33,43,49,55,60,61,73,74,76,80,81,89,96,102,107,110,115,116,117,118,120,121,123,127,132,144,150,152,154,156,159,164,165,167,169,170,175,182,187,195,203,204,206,210,217,218,219,220,221,228,230,231,232,233,235,247,256,259,261,271,278,290,293,295,298,303,305,306,307,309,318,326,329,334,335,338,342,344,357],hooligan:12,hop:55,hope:[42,58,91],hopefulli:[8,26,41,49,90,111,133,137],horizon:62,horizont:[138,232,330,344],hors:27,host1plu:90,host:[7,12,23,26,27,61,64,67,89,98,100,102,103,131,135,205,312,344],host_os_i:344,hostnam:67,hotbutton:137,hotel:90,hotspot:103,hour:[27,62,132,184,331,344],hous:[43,90,109,159],housecat:27,hover:138,how:[0,1,3,4,5,6,7,8,10,11,12,13,14,15,17,19,20,21,22,25,26,27,28,29,30,31,35,37,38,39,40,41,42,43,44,45,46,48,49,51,55,56,57,60,61,62,63,64,66,68,69,72,73,75,77,80,81,82,83,84,85,86,87,88,90,91,93,95,96,97,102,103,104,105,106,108,109,110,111,112,116,117,118,119,120,123,124,126,127,128,130,131,132,133,134,135,136,137,138,139,140,146,151,153,154,166,168,169,170,175,180,182,184,185,189,204,205,206,213,215,219,220,221,226,231,235,241,246,247,252,256,261,267,272,277,281,286,291,294,298,299,305,306,307,308,312,318,322,326,328,329,330,337,338,343,344,357,363,364],howev:[0,2,4,5,10,11,12,13,14,15,17,20,22,23,29,30,31,33,37,38,40,41,43,44,46,50,55,58,59,60,62,70,73,77,80,85,88,90,91,108,109,110,111,113,114,115,120,123,125,128,129,131,132,135,153,154,159,166,169,170,180,188,190,195,204,215,220,226,241,321],hpad_char:330,href:[17,69,133],hrs:184,htm:282,html5:55,html:[24,38,43,55,64,69,79,83,96,103,114,134,135,136,137,138,169,175,204,234,239,289,291,295,296,312,318,340,343,347],htmlchar:343,htop:110,http404:[69,134],http:[3,4,9,22,23,36,37,38,43,45,54,55,63,65,69,70,75,83,90,95,98,103,104,107,108,124,128,130,131,133,134,135,137,138,141,146,164,180,204,234,269,276,278,279,280,281,282,283,289,291,294,295,296,312,321,330,343,344,357],http_request:[103,135],httpchannel:312,httpchannelwithxforwardedfor:312,httpd:8,httprequest:144,httpresponseredirect:133,hub:[79,100,139,324],hue:114,huge:[3,16,21,29,39,61,62,86,127,235,329],huh:[22,33],human:[4,12,40,51,57,61,64,73,85,93,96,117,133],humanizeconfig:4,hundr:[72,113,133],hungri:86,hunt:[73,231],hunting_pac:231,hunting_skil:73,hurdl:49,hurt:30,huzzah:9,hwejfpoiwjrpw09:9,hybrid:73,i18n:[47,76,247],iac:88,iattribut:316,iattributebackend:316,icon:[79,106,138],id_:357,id_str:84,idcount:298,idea:[0,9,12,26,33,37,38,39,45,49,55,56,60,61,63,69,71,72,73,77,80,85,106,107,108,119,121,123,127,131,133,134,139,154,166,167,170,179,205,252,334,343,364],ideal:[1,6,33,37,46,48,90,129,138,148,242],idenfi:152,ident:[9,31,33,44,57,61,83,96,97,110,114,144,167,206,212,242,247,321,322],identif:[27,115,308],identifi:[0,8,23,28,30,31,33,38,39,41,42,43,49,50,51,58,61,69,74,83,84,88,93,97,102,109,115,116,119,125,134,138,151,154,159,164,167,170,176,180,187,205,206,215,233,242,247,251,258,261,264,267,272,274,277,291,295,304,306,308,316,317,321,324,327,328,344],identify_object:176,idl:[12,105,144,146,231,247,299,306,308],idle_command:33,idle_tim:[144,247],idle_timeout:146,idmap:334,idmapp:[43,86,125,141,142,169,177,239,274,300,316,317,318,320],idnum:176,ids:[12,58,121,187,298,308,327],idstr:[84,115,257,261,304,344],idtifi:176,idx:121,ietf:283,ifconfig:67,ifram:[137,138],ignor:[6,14,20,23,27,29,31,33,34,38,42,43,51,58,73,74,80,83,86,90,91,95,96,105,114,117,121,122,125,131,144,151,152,153,154,159,170,187,206,241,246,247,261,267,272,278,279,294,295,296,316,318,321,322,327,328,339,344,345],ignore_ansi:344,ignore_error:144,ignorecas:[159,165,166,171,182,321,326,328,343],ignoredext:312,illumin:111,illus:[10,96],imag:[4,17,63,69,70,90,101,106,133,135,136,137,138,347],imagesconfig:4,imagin:[14,29,31,46,48,51,61,77,116,117,122,132,138,226,322],imaginari:[21,79],imc2:34,imeplement:235,img:[17,70],immedi:[0,5,15,27,29,33,43,48,49,51,64,70,74,83,90,95,100,102,109,116,120,133,134,157,169,231,278,322,324,328,329],immobil:25,immort:231,immut:[11,261],imo:1,impact:126,impati:63,imper:102,implement:[1,6,11,21,25,26,28,29,31,33,34,37,40,41,49,51,55,56,57,58,60,61,78,79,80,81,86,88,89,96,97,108,111,112,114,115,116,117,118,119,120,123,124,125,127,128,131,135,137,138,139,140,148,152,153,156,157,158,159,160,161,164,165,166,167,168,169,175,176,177,179,181,182,184,185,187,189,202,205,206,210,212,213,214,215,217,218,221,231,232,233,235,238,239,242,246,247,256,258,261,273,278,280,281,282,283,284,285,287,289,290,291,294,295,296,298,305,312,316,317,318,319,321,322,325,326,328,329,335,339,340,343,344,364],impli:[22,112],implicit:[91,114,126],implicit_keep:252,impmement:242,import_cmdset:153,importantli:[51,133,242],importerror:[4,9,344],impos:[55,79,310],imposs:[15,19,38,49,51,90,111,113,121,133,138,330],impract:[33,109,252],imprecis:334,impress:[42,111],improv:[0,11,37,61,70,76,91,128],in_game_error:[26,103],inabl:[63,103],inaccess:[0,80],inact:[102,231],inactiv:[43,169],inadvert:221,inadyn:90,inarticul:108,inbuilt:[67,112,123],incant:75,incarn:357,incid:210,includ:[2,4,6,9,12,13,16,20,21,22,27,30,31,33,36,37,38,39,41,43,44,48,51,53,55,58,60,61,62,63,64,69,73,74,75,78,79,80,84,85,88,89,91,93,95,96,100,101,102,104,105,106,107,108,109,111,112,114,115,116,119,121,125,127,131,133,134,135,136,137,138,144,150,151,152,154,157,158,159,167,170,175,179,182,187,188,189,195,205,206,210,215,217,218,219,220,221,233,234,235,241,247,259,267,285,287,290,291,299,304,307,316,317,318,319,321,322,323,324,325,327,328,330,331,337,344,347,350],include_account:316,include_children:317,include_par:317,include_prefix:151,include_unloggedin:[285,308],inclus:317,incoher:126,incol:[58,327,330],incom:[33,40,88,90,96,104,139,146,151,168,210,218,276,280,283,286,290,291,295,296,298,306,307,308,312,328,329],incomplet:[154,213,330],inconsist:[10,97,204],incorpor:[43,156,330],incorrect:176,increas:[25,62,73,80,103,114,119,125,179,218,220,221,233,279,285,299,326,328],increase_ind:326,incred:[215,269],increment:[63,316],incur:27,indata:[40,316],inde:[9,55,90,91],indefinit:[102,219,232,324],indent:[0,9,13,14,27,38,50,51,57,60,95,129,137,296,322,326,328,344],independ:[0,56,64,102,126,179,209],indetermin:269,index:[7,38,43,49,56,61,68,79,85,86,90,108,121,135,136,151,164,165,166,179,215,232,239,265,269,270,312,319,321,329,330,344,357,360,364],index_category_clr:166,index_to_select:215,index_topic_clr:166,index_type_separator_clr:166,indexerror:[134,235,317],indextest:360,indic:[0,8,22,38,43,49,51,62,85,91,95,111,119,146,159,166,167,189,210,215,256,259,278,279,287,294,295,308,310,312,316,321,322,328,329,344],individu:[0,11,13,14,18,21,22,33,34,41,43,46,48,49,55,57,58,59,71,73,78,85,88,90,96,109,111,132,153,157,175,185,192,195,220,249,252,306,319,321,330,338,339],ineffici:[115,117,321],infact:33,infinit:[0,61,63,146,235,251],inflict:[102,219],inflict_condit:219,influenc:[10,16,22,46,51,102,123,179,344],influenti:79,info1:214,info2:214,info3:214,info:[3,5,11,13,16,17,20,23,24,25,26,27,33,35,37,43,52,55,58,59,63,64,68,78,86,88,89,95,100,101,102,104,105,106,112,124,125,131,138,139,144,146,148,156,157,159,166,169,171,178,179,181,186,187,190,199,233,239,247,267,272,276,284,285,305,306,308,317,318,319,324,327,337,344],infomsg:337,inforamt:[206,235,247,318],inform:[0,2,3,6,8,9,18,20,22,23,25,27,28,33,34,36,38,41,43,46,48,51,55,60,65,66,68,69,73,83,84,85,86,91,95,96,100,102,103,104,105,109,112,114,116,117,119,120,123,124,127,131,132,133,134,135,136,137,138,139,144,146,154,157,159,164,165,169,177,180,185,204,206,210,211,219,220,221,239,247,267,272,281,282,283,285,294,307,308,317,318,321,324,326,337,344,357],infrastructur:[64,83,90,103,150,277],infrequ:46,ing:[9,14,58,185],ingame_python:[141,142,178],ingame_tim:62,ingo:[31,51,58,74,114,152,279],inher:[4,10,87,108],inherit:[2,5,6,22,27,30,31,33,36,40,42,43,57,60,64,69,81,86,89,96,102,109,114,117,119,123,125,127,148,152,154,159,167,169,170,175,177,179,180,182,187,189,203,206,213,217,218,219,220,221,230,231,233,234,243,246,247,252,256,258,298,307,314,317,318,326,329,330,334,342,344],inheritng:252,inherits_from:[43,117,134,169,344],inifinit:251,init:[6,9,22,38,40,47,49,58,60,63,75,83,95,104,106,131,137,138,179,180,188,246,267,285,286,296,308,344],init_delayed_messag:188,init_django_pagin:329,init_evt:329,init_f_str:329,init_fill_field:188,init_game_directori:267,init_iter:329,init_menu:230,init_mod:153,init_new_account:344,init_pag:[251,329],init_pars:234,init_queryset:329,init_rang:221,init_sess:[40,307],init_spawn_valu:251,init_str:329,init_tree_select:215,init_tru:153,initi:[5,9,11,21,29,33,38,47,49,50,51,58,60,61,64,68,73,85,97,105,107,110,120,123,127,130,131,133,137,138,144,146,153,154,170,175,179,186,188,192,196,198,205,206,215,217,218,219,220,221,226,230,231,232,246,247,251,257,260,261,264,265,267,269,270,271,276,277,278,280,281,282,283,285,286,287,288,289,290,291,292,294,295,296,298,306,307,308,316,321,323,326,327,328,329,339,340,344,351,357],initial_formdata:188,initial_ind:330,initial_setup:[141,142,262,305],initialdelai:[264,278,279,298],initialize_for_combat:[217,218,219,220,221],initialize_nick_templ:316,initil:295,inject:[96,103,298,299,306,322,328],inlin:[18,57,85,104,137,247,265],inlinefunc:[45,83,104,109,141,142,320],inlinefunc_en:114,inlinefunc_modul:114,inlinefunc_stack_maxs:114,inlinefunct:114,inmemori:316,inmemoryattribut:316,inmemoryattributebackend:316,inmemorybackend:316,inmemorysavehandl:339,inner:77,innoc:[12,43,157],innocu:103,inobject:276,inp:[51,159,176,251,265,329,344],inpect:51,input:[1,5,9,10,14,15,17,20,22,27,30,31,40,41,43,50,53,55,57,58,70,74,79,83,87,91,95,96,104,105,109,110,111,113,114,115,118,127,131,133,135,137,138,144,149,150,151,154,159,164,166,167,168,169,170,176,180,185,188,205,206,210,215,220,232,238,247,250,251,252,265,272,276,287,295,306,308,316,317,319,326,327,328,329,330,338,340,344,345,357],input_arg:170,input_cmdset:328,input_func_modul:[74,272],input_str:328,input_validation_cheat_sheet:357,inputcmdset:328,inputcommand:[74,83,88],inputcompon:137,inputdebug:[74,272],inputfunc:[40,45,104,139,141,142,146,262,295,306,308,364],inputfunc_nam:295,inputfunct:74,inputhandl:141,inputlin:[43,87,165,175,316,317],insecur:90,insensit:[51,166,187,206,233,317,349],insert:[13,14,25,50,51,58,64,71,87,96,109,114,138,153,189,202,251,322,328,330,344],insid:[0,5,10,11,13,15,19,20,21,23,25,27,28,31,33,38,42,43,46,47,51,57,59,64,67,68,69,71,72,73,80,82,83,85,86,88,89,91,92,93,95,96,100,102,105,106,108,109,110,111,114,117,121,123,125,127,132,133,134,135,136,139,141,146,169,175,180,187,190,194,195,206,231,233,235,241,246,247,250,267,284,305,312,322,323,344],inside_rec:241,insiderecurs:241,insight:[20,41,42,122,136],insist:[90,91],inspect:[12,23,43,51,85,144,159,179,265,267,328],inspectdb:86,inspir:[33,41,73,116,127,129,181,189,330,344],instac:[154,247,306],instal:[0,3,5,14,20,26,37,38,41,42,46,47,54,55,57,58,59,60,64,65,76,77,79,95,96,97,98,101,103,106,108,110,124,127,128,130,134,138,139,141,179,181,182,183,185,186,187,199,202,203,206,210,212,213,217,218,219,220,221,363,364],installed_app:[4,69,86,127,133,134],instanc:[0,2,3,8,11,16,17,22,25,27,28,29,39,41,42,43,46,50,51,56,57,58,59,60,61,62,64,69,76,84,85,91,95,96,97,102,103,105,107,109,116,119,121,126,127,131,136,137,144,148,150,151,152,153,154,163,166,168,169,170,175,177,180,195,198,204,215,234,235,239,246,247,251,252,256,260,261,264,267,276,277,278,279,280,281,282,283,285,289,290,294,298,299,307,308,312,316,318,319,321,324,325,328,330,334,335,340,344,345,357],instanci:180,instant:136,instanti:[33,86,127,144,153,170,226,258,261,284,305,308,316,327],instead:[0,3,6,9,10,11,12,14,16,19,20,21,22,23,25,26,27,29,30,31,33,34,37,39,41,43,46,48,49,51,57,58,60,62,63,64,67,79,80,83,84,85,86,89,90,91,93,95,96,100,102,103,104,105,106,109,110,111,112,114,116,117,118,119,121,123,125,126,127,128,131,132,133,134,135,136,138,139,144,146,153,154,156,157,159,161,164,168,169,171,175,180,185,186,188,198,205,206,213,215,217,218,219,220,221,230,232,234,235,241,242,247,252,261,267,295,296,306,310,316,318,319,324,328,329,334,337,339,340,341,344,357],instig:157,instil:[140,219],instnac:260,instr:[276,344],instruct:[0,8,9,13,14,23,27,30,37,38,42,43,46,47,55,57,58,60,61,63,67,74,75,77,79,83,85,90,93,96,97,100,106,119,124,131,139,144,154,169,206,210,252,261,264,267,277,279,285,290,291,295,296,298,306,308,328,338],integ:[25,31,33,39,85,91,105,109,114,123,125,151,182,184,185,188,217,218,219,220,221,233,241,247,317,340,344,345],integerfield:[133,357],integr:[4,7,41,45,61,64,76,79,103,134,137,139,170,206,270,272,328,364],intellig:[73,83,91,103,134,153,298],intend:[13,17,20,22,27,31,33,34,37,42,55,61,90,103,108,109,111,112,114,122,126,131,136,137,144,179,180,206,239,247,252,285,317,319,324,325,327,330,341,342,344,345],intens:[79,93,114],intent:[51,76,96,103,205,344],inter:13,interact:[2,20,23,29,33,40,42,43,51,55,56,59,61,77,79,100,106,108,110,116,122,133,138,141,158,170,221,226,267,284,322,337,344],intercept:308,interchang:[116,328],interest:[0,1,4,11,14,20,21,22,26,33,37,40,42,46,49,55,57,60,61,70,79,86,90,91,93,96,103,109,114,119,120,121,123,136,153,168,179,184,233,235],interf:[63,226],interfac:[9,21,22,23,25,36,40,42,43,63,64,69,70,79,80,90,96,97,101,104,119,133,135,137,138,139,156,159,175,247,259,278,307,312,316,319,321,344],interfaceclass:287,interfer:[23,97,251],interim:[29,115],interlink:[284,305],intermediari:[206,242,257,328],intern:[10,11,15,27,34,38,40,51,63,76,80,87,88,90,100,102,103,104,105,107,109,110,112,113,116,128,144,146,177,186,189,206,235,247,251,258,295,296,316,318,319,321,325,328,330,344],internal:328,internal_port:90,internation:[7,113,139,364],internet:[10,12,16,33,40,43,63,67,72,90,103,124,157,264,269,277,278,279,287,290,298,312],interpret:[33,42,43,56,59,60,91,93,96,102,103,104,109,134,154,158,159,251,252,295,321,340],interrupt:[63,150,154,170,192,195,198,287],interruptcommand:[33,91,141,150,154],interruptev:198,intersect:[31,152],interv:[64,74,102,115,116,120,121,132,146,184,195,217,218,219,220,221,223,231,233,256,261,272,324,331,344],interval1:261,intim:[31,33],intimid:58,intoexit:[43,159],intpropv:123,intricaci:62,intrigu:54,intro:[4,69,122,124,134,230,233],intro_menu:[141,142,178,229],introduc:[26,29,31,57,73,97,123,124,127,131,139,206],introduct:[3,13,14,15,18,19,20,45,60,61,63,124,127,131,139,180,363,364],introductori:[55,63],introroom:233,introspect:203,intrus:126,intuit:[22,51,61,86,91,131,139,152],intxt:27,inv:[31,43,82,165,182],invalid:[11,41,60,91,109,144,188,206,251,330,340,344,345],invalid_formchar:327,inventori:[20,21,25,27,31,80,85,91,97,119,138,165,182,206,241,247,318],invers:[80,114,126,206,293,343],invert:[114,126],investig:90,invis:24,invit:[0,10,61,77,226],invitingli:[20,226],invok:[11,13,14,102,209],involv:[40,56,61,68,75,80,89,105,107,116,123,188,221,318,319,321],ioerror:322,ipregex:157,ipstart:[63,100,110],iptabl:103,ipython:[26,58,59,96],irc2chan:[72,164],irc:[7,9,26,34,43,55,60,63,70,79,98,131,138,139,141,142,146,164,172,262,272,275,285,308,363,364],irc_botnam:146,irc_channel:146,irc_en:[72,164,241],irc_network:146,irc_port:146,irc_rpl_endofnam:279,irc_rpl_namrepli:279,irc_ssl:146,ircbot:[146,279],ircbotfactori:[146,279],ircclient:[279,308],ircclientfactori:285,irchannel:[43,72,164],ircnetwork:[43,72,164],ircstatu:164,iron:179,ironrealm:291,irregular:[223,231,233],irregular_echo:231,irrelev:[103,276],irur:52,is_account_object:56,is_act:256,is_aggress:117,is_anonym:[4,69],is_anyon:4,is_authent:133,is_ban:144,is_bot:148,is_build:4,is_categori:215,is_channel:[33,41],is_connect:[148,247],is_craft:29,is_exit:[33,154],is_fight:29,is_full_moon:25,is_giving_light:232,is_gm:58,is_in_chargen:123,is_in_combat:[217,218,219,220,221],is_inst:27,is_it:344,is_iter:344,is_lit:[232,233],is_next:[148,177,239,246,256,316,318],is_o:344,is_ouch:11,is_prototype_bas:251,is_sai:118,is_subprocess:344,is_superus:[2,4,144,148,242,247,324],is_thief:[43,166],is_turn:[217,218,219,220,221],is_typeclass:[144,318],is_valid:[102,121,133,179,256,259],is_valid_coordin:235,isalnum:321,isalpha:321,isb:170,isbinari:[278,295],isclos:137,isconnect:137,isdigit:[58,114,321],isfiremag:28,isinst:[39,344],isleaf:296,islow:321,isn:[0,4,17,22,41,42,46,50,56,62,63,69,91,119,138,180,192,196,221,233,234,269,321,338,349],isnul:340,iso:[15,113],isol:[13,37,61,63,64,91,95,100,127],isp:[90,103],isspac:321,issu:[7,8,10,11,13,14,21,22,23,29,31,33,37,38,42,43,45,48,54,58,60,63,70,79,85,89,90,93,103,108,123,125,126,127,131,138,140,164,251,267,298,299,330,363],istart:[42,110,141],istep:299,istitl:321,isub:116,isupp:321,itch:[61,63],item:[20,43,47,51,59,63,68,69,82,85,86,116,117,138,165,179,182,188,206,219,226,235,286,316,344],item_consum:219,item_func:219,item_kwarg:219,item_selfonli:219,item_us:219,itemcoordin:235,itemfunc:219,itemfunc_add_condit:219,itemfunc_attack:219,itemfunc_cure_condit:219,itemfunc_h:219,itend:344,iter:[11,49,51,59,97,112,119,138,144,206,235,247,252,259,296,298,299,316,318,319,321,322,325,329,344],iter_cal:329,iter_to_str:344,itl:[22,180],its:[0,2,3,5,9,11,12,14,15,16,20,21,22,23,25,27,29,31,33,37,38,39,40,41,42,43,44,49,50,51,52,55,56,57,58,60,61,62,63,64,65,68,69,70,72,73,75,80,81,82,83,84,85,86,88,89,90,91,93,95,96,98,100,101,102,103,104,105,109,111,114,115,117,118,119,121,122,123,124,125,126,127,128,129,130,131,133,134,135,136,137,138,139,144,146,148,150,151,152,153,154,157,159,167,169,170,175,176,179,180,188,189,195,203,205,206,213,215,217,218,219,220,221,226,231,232,234,235,246,247,252,260,261,267,272,276,280,293,294,295,296,299,307,308,312,313,316,317,318,319,322,327,328,330,334,337,338,339,340,341,344,347,357],itself:[0,4,9,11,15,17,20,21,22,23,25,27,29,33,36,37,40,41,44,45,46,47,49,51,55,60,63,64,68,75,77,78,80,82,85,86,89,96,104,105,106,111,114,115,116,118,119,122,123,125,127,131,133,134,135,136,144,146,166,175,180,185,188,198,204,206,215,220,223,232,233,235,236,239,241,247,249,250,252,260,267,291,296,308,312,316,319,321,324,326,328,339,341,344,357],iusernamepassword:287,iwar:85,iweb:90,iwebsocketclientchannelfactori:278,iwth:261,jack:87,jail:[12,13],jamochamud:24,jan:[12,62],januari:62,jarin:90,javascript:[55,83,88,103,135,136,137,138,295,296],jenkin:[123,182,188,190,215,217,218,219,220,221],jet:220,jetbrain:[79,106],jnwidufhjw4545_oifej:9,job:[33,41,67,69,80,144],jobfusc:205,john:[58,214],johnni:[209,210],johnsson:87,join:[9,22,34,43,49,58,61,63,65,72,96,112,116,119,123,133,144,164,175,179,205,321,344],join_fight:[217,218,219,220,221],join_rangefield:221,joiner:175,jointli:[64,153],joke:59,joker_kei:[22,180],jqueri:138,json:[83,88,137,138,209,278,291,295,296,325],jsondata:88,jsonencod:296,jsonifi:296,jtext:321,judgement:73,jump:[13,14,21,41,44,49,51,52,55,61,63,77,89,108,131,139,215,265],junk:276,just:[0,1,3,4,5,6,9,10,11,12,13,14,15,17,19,20,21,22,23,25,26,27,28,29,30,31,33,34,37,38,39,40,41,42,43,44,46,47,48,49,51,52,54,56,57,58,59,60,61,62,63,64,68,69,70,73,74,76,77,79,80,81,83,85,86,87,88,89,90,91,93,95,96,97,100,101,102,105,106,107,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,125,126,127,128,131,132,133,134,135,136,137,138,140,144,152,153,154,157,159,164,167,168,169,170,175,179,180,182,185,187,192,194,195,205,206,214,215,217,218,219,220,221,226,231,233,235,242,247,252,257,272,285,295,299,305,312,316,317,318,321,325,326,328,330,339,340,344,345],justif:[329,344],justifi:[96,109,321,329,344],justifii:329,justify_kwarg:329,kcachegrind:93,keen:37,keep:[0,1,4,7,9,11,13,14,15,16,20,25,26,29,30,33,34,42,45,48,51,56,57,58,60,61,62,63,64,68,69,73,75,76,77,78,81,82,85,91,92,95,96,97,100,105,109,116,118,121,122,126,128,131,132,133,134,138,146,153,187,190,195,204,209,226,232,233,251,252,269,310,328,330,344],keep_log:[34,175,324],keepal:[105,290,296],keeper:85,keepint:64,kei:[0,1,5,8,9,10,11,13,21,25,26,27,28,29,30,31,33,34,38,39,41,42,43,44,49,50,52,56,57,58,60,62,69,71,74,80,81,82,84,85,86,88,89,91,95,96,97,102,107,111,112,114,115,116,119,120,121,123,125,127,129,131,133,137,138,144,146,148,150,152,153,154,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,175,176,179,180,181,182,184,185,186,187,188,189,193,194,199,202,203,205,206,212,213,214,215,217,218,219,220,221,226,230,231,232,233,234,235,239,241,246,247,250,251,252,256,257,258,259,260,261,265,267,272,273,274,276,285,288,291,292,294,295,296,298,299,306,307,308,310,316,317,318,319,323,324,326,327,328,329,337,338,339,341,344,357],kept:[33,43,57,80,91,119,127,159,194,195,252,316],kept_opt:215,key1:202,key2:[51,202,247],key_mergetyp:[31,152,226],keyboard:138,keydown:137,keyerror:[251,261,339,344],keyfil:[288,292],keynam:[175,250,252,324],keypair:287,keys_go_back:[22,180],keystr:319,keystrok:287,keywod:330,keyword:[0,1,5,10,11,22,25,27,29,30,33,34,43,50,51,52,58,62,74,80,81,83,86,91,93,95,102,107,109,114,115,119,123,125,127,134,144,146,150,154,159,165,175,182,184,187,192,194,195,198,205,206,210,217,218,219,220,221,233,234,242,247,251,252,257,260,261,265,267,272,276,278,279,285,286,287,290,295,296,306,307,308,310,316,317,318,324,327,328,329,330,334,338,340,341,344],keyword_ev:198,kick:[12,31,43,51,58,90,146,152,157,164,171,186,329],kildclient:24,kill:[20,27,43,51,61,75,93,100,102,105,116,179,231,232,257,261,267,305,312],killsign:267,kilogram:82,kind:[0,11,37,38,40,80,91,97,104,116,118,119,121,133,138,217,218,219,220,242,318,345],kinda:138,kindli:126,kitchen:[43,44,159],knew:95,knock:51,knot:182,know:[0,2,5,6,8,10,11,13,14,15,16,20,21,22,23,26,29,31,33,37,38,39,40,41,42,43,44,48,49,51,54,56,57,58,60,61,64,67,69,70,72,73,74,79,80,81,82,83,84,85,86,89,90,91,93,95,96,97,98,100,102,104,105,110,111,113,114,116,117,118,119,121,125,126,127,128,131,132,133,134,136,138,139,154,158,159,167,170,179,194,199,205,215,220,226,232,246,247,272,306,308,316,322,323,328,344,363],knowledg:[13,15,33,55,77,289,308],known:[7,20,24,33,50,73,79,80,87,92,96,109,114,115,125,134,137,143,168,220,329],knuth:93,kobold:61,koster:79,kovash:51,kwar:318,kwarg:[1,10,25,29,33,40,41,51,58,59,74,80,81,83,84,88,96,107,109,114,115,118,121,125,132,134,137,144,146,147,148,150,153,154,156,157,158,159,164,165,166,167,168,169,170,171,175,176,177,179,180,181,182,184,185,186,187,188,189,192,193,194,195,199,202,203,204,205,206,210,212,213,214,215,217,218,219,220,221,223,226,230,231,232,233,234,235,238,239,241,242,245,246,247,249,250,251,252,255,256,257,259,260,261,264,265,272,273,274,276,277,278,279,284,285,286,287,288,290,291,292,295,296,298,300,306,307,308,309,310,312,316,317,318,319,321,324,326,327,328,329,330,331,333,334,337,338,339,340,341,342,344,345,357],kwargtyp:344,label:[48,70,86,112,133,140,357],label_suffix:357,laborum:52,lack:[13,38,56,61,70,129,206,226,247,316,344],ladder:58,lag:[49,63],lai:[1,48],lair:14,lambda:[10,39,51,69,109,195,252,344],lamp:[111,226],lamp_breaks_msg:226,land:[91,116,231,232],landscap:[103,111],lang:205,langcod:206,langnam:206,languag:[7,15,38,40,47,55,56,57,58,64,79,91,95,103,108,113,114,118,124,125,127,129,130,137,139,205,206],language_cod:76,languageerror:[205,206],languageexistserror:205,languagehandl:205,larg:[10,11,13,14,16,20,23,37,51,55,56,61,86,90,96,97,108,109,122,127,205,226,235,251,285,322,327,334],larger:[14,20,49,57,61,68,80,82,86,108,187,247,293,321,334,344,347],largesword:86,laser:77,last:[4,11,13,14,22,26,29,31,33,34,36,42,43,48,51,54,58,60,69,74,76,86,87,89,90,91,95,96,105,107,110,116,121,122,126,127,131,134,136,137,150,151,153,159,164,165,179,184,187,195,206,215,217,218,219,220,221,247,271,321,322,323,328,329,330,331,337,344],last_cmd:33,last_initial_setup_step:305,last_step:271,lastcast:28,lastli:[81,83,111,133,150],lastsit:25,late:[251,323],later:[0,2,9,11,12,13,22,23,33,34,38,40,43,46,55,58,60,61,63,64,69,73,74,76,81,83,84,86,90,95,97,109,111,114,115,117,120,121,123,125,131,133,138,139,140,152,156,157,159,167,175,184,203,206,252,261,287,319,344],latest:[20,21,27,31,36,38,43,58,63,64,75,83,98,131,159,164,169,247,252,286,310,328,337,363],latin:[15,113,247,344],latin_nam:247,latinifi:[247,344],latter:[6,27,29,34,64,77,80,89,91,95,115,126,206,256,258,319],launch:[14,21,54,63,75,85,90,93,102,106,110,122,127,138,153,226,266,267,277,279,298,326,344],launcher:[93,106,266,267,276,277,298],law:79,layer:[22,31,246,318],layout:[27,49,56,58,96,119,125,128,137,138,235],lazi:344,lazy_properti:344,lazyencod:296,lazyset:337,lc_messag:76,lcnorth:114,ldesc:56,ldflag:75,lead:[0,11,13,17,20,22,23,31,37,43,49,51,56,60,61,64,69,79,83,86,102,103,111,121,144,151,152,159,169,195,198,204,212,247,252,306,316,318,328,330,344],leak:135,lean:206,leap:[62,118],learn:[0,15,16,17,20,22,29,31,33,42,46,49,56,57,60,63,68,69,79,80,81,95,96,106,108,118,122,124,126,127,131,134,136,139,205,220,364],learnspel:220,least:[3,8,33,39,42,47,49,51,55,57,58,61,67,73,80,86,90,96,102,106,121,138,144,153,176,179,205,238,247,252,259,321,327,330,341,344],leasur:231,leather:85,leav:[0,2,20,21,22,25,43,58,60,73,74,77,85,93,95,102,103,116,123,137,138,156,158,159,175,179,180,233,235,247,260,295,296,328,334],leaver:175,left:[22,27,33,36,39,41,43,57,69,74,80,85,86,91,101,102,109,111,114,137,138,144,159,165,167,190,217,218,219,220,221,226,232,235,242,252,318,321,330,344,363],left_justifi:109,leg:304,legaci:[88,109,144,206],legal:[90,103],legend:[49,50],leisur:345,len:[25,49,58,71,85,109,114,116,119,120,121,151,168,184,344],lend:50,length:[22,23,25,49,62,66,68,71,83,86,90,91,95,122,151,184,188,190,198,205,206,269,310,316,321,330,344],lengthi:[1,25],lengthier:363,lenient:109,less:[22,34,44,51,56,61,64,73,86,90,91,106,108,116,119,132,133,139,184,218,220,316],let:[0,3,5,7,8,9,11,12,14,15,20,21,22,25,28,31,33,37,39,40,41,43,44,46,48,49,51,56,57,58,60,61,62,63,64,65,70,72,73,74,75,77,80,81,82,83,85,89,91,93,95,96,98,103,106,111,114,115,117,118,119,121,123,124,126,127,131,133,134,136,137,140,144,153,154,159,165,170,179,182,185,188,190,215,235,242,247,277,296,308,324,328,338,343,357,363],letsencrypt:[67,90],letter:[15,22,39,43,76,90,95,111,113,114,119,123,133,156,165,180,204,205,311,321,344],leve:251,level:[2,11,13,19,20,22,26,27,30,36,38,40,41,43,47,50,51,55,57,58,61,66,69,71,73,79,80,85,90,95,96,104,105,108,111,112,119,122,125,130,133,138,139,140,144,156,161,162,169,175,180,181,184,199,205,215,226,241,247,252,269,306,316,318,324,326,331,344],lever:[33,125],leverag:[3,38],levi:86,lhs:[25,58,167],lhslist:167,lib:[63,67,75,97],libapache2:8,libcrypt:75,libjpeg:75,librari:[6,13,26,45,53,56,57,63,64,75,76,78,79,91,95,100,103,108,109,125,127,128,133,136,137,138,178,204,234,251,252,280,316,318,330,344],licenc:321,licens:[37,45,79,106,139,204,321,364],lid:226,lidclosedcmdset:226,lidopencmdset:226,lie:111,lies:[33,131],life:[11,37,62,87,95,126,184,231],lift:[20,73,80,96,123,221,242],lifter:80,light:[14,23,27,38,61,102,108,122,153,218,232,233,252,260,321],lightabl:232,lighter:[114,218],lightest:27,lightli:[16,218],lightsail:90,lightsourc:232,lightsource_cmdset:232,like:[0,2,3,5,6,8,9,10,11,12,14,15,16,17,19,20,21,22,23,25,26,27,28,29,30,31,33,34,35,36,37,38,39,40,41,42,43,44,45,46,48,49,51,52,53,54,55,57,58,59,60,61,62,63,64,65,67,68,69,70,71,72,73,74,75,76,77,79,80,81,83,84,85,86,88,89,90,91,93,95,96,97,100,102,103,104,105,106,107,108,109,111,112,114,115,116,117,118,119,120,121,125,126,127,128,129,131,132,133,134,135,136,137,138,139,140,144,146,148,149,151,152,153,156,158,159,164,167,170,171,172,175,176,179,180,182,186,187,188,189,190,198,204,205,206,212,213,215,217,218,219,220,221,226,233,234,235,239,241,242,246,247,251,252,272,280,296,299,301,305,307,308,316,317,318,321,322,324,327,328,329,330,331,334,338,340,341,344,357,364],limbo:[0,9,13,14,20,22,27,43,59,63,66,104,111,121,122,134,159,180,233,271],limbo_exit:111,limit:[0,2,6,11,16,19,20,25,26,27,28,31,33,34,37,43,46,51,53,55,58,61,64,68,71,80,86,90,91,95,102,104,109,112,116,123,125,126,127,138,140,144,156,157,158,159,175,176,182,195,206,215,217,219,220,226,238,239,242,247,252,256,261,272,285,310,316,317,318,319,322,324,326,337,341,344],limit_valu:144,limitedsizeordereddict:344,line:[0,4,5,9,10,13,14,15,19,22,23,25,26,27,29,30,31,33,34,36,38,39,41,43,45,46,48,51,53,54,56,57,58,59,60,61,62,63,67,69,74,76,81,83,86,87,89,90,91,92,93,95,96,97,98,100,104,108,109,110,111,114,119,121,123,125,127,128,133,134,137,138,139,141,144,150,153,159,164,166,168,169,180,185,186,188,202,205,206,215,226,234,235,251,267,272,287,290,295,306,318,322,326,327,328,329,330,337,344,357],linear:49,linebreak:[69,343],lineeditor:326,lineend:343,lineno:38,linenum:326,liner:279,linereceiv:[287,290],linesend:296,lingo:[57,86,105,135],linguist:344,link:[2,3,4,9,14,17,18,20,22,25,29,31,33,37,39,40,46,48,49,51,54,55,57,63,64,69,70,72,85,89,90,96,98,105,111,119,121,123,124,128,131,133,134,139,144,148,159,164,192,234,242,247,256,265,267,278,282,287,290,318,343,344,364],linknam:54,linkref:38,linktext:38,linod:90,linux:[4,8,9,23,25,38,64,67,72,75,87,90,93,97,100,106,131,209,344],liquid:318,list:[0,1,2,3,4,6,7,11,12,13,14,15,20,22,23,25,27,31,33,34,37,39,40,41,43,45,46,48,49,51,54,55,57,58,59,60,61,63,66,68,69,70,72,73,74,76,77,79,80,82,85,86,88,89,90,91,93,95,96,97,98,102,103,105,106,109,110,111,112,113,114,116,118,119,121,123,124,125,128,129,131,133,134,135,137,138,139,144,146,148,151,152,153,154,156,157,158,159,164,165,166,167,169,170,175,176,177,179,180,181,182,183,187,188,189,190,192,193,195,196,198,199,202,203,204,205,206,209,210,215,217,218,219,220,221,226,230,231,232,235,238,242,246,247,251,252,257,258,259,261,265,267,272,273,277,279,281,283,285,286,291,296,299,308,310,312,316,317,318,319,321,322,323,324,325,328,330,337,338,341,344,350,363],list_attribut:159,list_callback:193,list_channel:164,list_nod:328,list_of_all_rose_attribut:11,list_of_all_rose_ndb_attr:11,list_of_lycanthrop:119,list_of_myscript:102,list_prototyp:251,list_set:267,list_styl:156,list_task:193,list_to_str:344,listabl:[43,159],listcmdset:[43,159],listcmset:[43,159],listen:[2,12,34,41,43,67,80,103,105,124,137,139,164,175,205,206,226,364],listing_contact:54,listnod:328,listobj:[43,169],listobject:[43,169],listscript:[43,169],lit:[232,233],liter:[13,20,38,43,57,66,109,165,321,340,344],literal_ev:[51,328,344],littl:[0,4,9,10,15,20,21,25,28,33,34,38,41,42,57,58,60,64,69,70,71,85,90,91,96,100,102,109,110,111,117,118,119,125,131,134,136,138,139,218,230,233,302,316,328,344,357],live:[8,23,38,60,63,67,70,79,90,100,106],ljust:321,lne:215,load:[6,11,12,13,15,26,29,31,33,43,44,50,51,56,57,58,60,61,69,73,82,83,97,103,106,109,111,121,123,127,136,137,138,148,153,165,166,169,177,187,195,205,239,242,246,247,256,260,271,274,276,307,316,318,319,322,323,326,335,338,339,342,344,355],load_buff:326,load_data:323,load_kwarg:339,load_module_prototyp:251,load_sync_data:307,loader:[51,318,344],loadfunc:[50,326,339],loc:[43,159],local0:67,local:[23,25,36,37,47,59,62,64,67,72,76,97,100,103,106,114,131,133,138,192,195,206,252,290,316],localecho:90,localevenniatest:342,localhost:[3,4,9,23,24,63,67,69,75,90,95,133,134,135,137,296],localstorag:138,locat:[0,2,4,6,8,9,11,12,13,20,21,25,27,30,31,33,35,38,39,43,46,47,48,49,51,57,58,59,63,64,66,73,74,77,80,85,89,90,91,96,100,102,103,109,111,112,114,117,118,119,121,122,123,125,127,128,131,133,135,136,137,140,144,150,159,165,169,175,176,180,181,182,187,203,206,212,231,233,235,241,246,247,252,296,305,316,317,318,319,322,324,328,330,337,341,347],location_nam:235,location_set:119,locations_set:[119,246],locattr:[232,241],lock:[4,6,10,12,19,20,21,22,23,25,28,29,31,33,34,39,41,44,45,47,48,53,58,60,62,68,71,82,85,89,90,96,104,109,110,112,123,125,133,138,139,141,142,144,154,156,157,158,159,164,165,166,168,169,170,171,175,177,179,180,181,182,185,186,187,189,192,193,195,196,199,202,203,206,212,214,226,231,232,233,235,239,246,247,251,252,312,316,318,324,326,328,338,345,364],lock_definit:242,lock_func_modul:[80,242],lock_storag:[154,156,157,158,159,164,165,166,167,168,169,170,171,177,179,180,181,182,185,186,187,188,189,193,199,202,203,206,212,213,214,215,217,218,219,220,221,226,231,232,233,234,239,247,298,316,318,326,328,329],lockabl:[58,212],lockablethreadpool:312,lockdown:[80,316],lockdown_mod:90,lockexcept:242,lockfunc1:80,lockfunc2:80,lockfunc:[25,33,43,53,80,104,121,141,142,159,164,240],lockhandl:[11,48,80,125,141,142,154,180,234,240,241],lockset:247,lockstr:[4,11,33,43,80,97,109,159,164,166,175,177,212,242,247,252,316,324],locktest:136,locktyp:[152,164,252],log:[2,4,5,6,8,10,11,12,20,21,23,24,25,33,34,35,36,39,43,44,45,47,51,53,55,57,58,59,60,63,64,65,66,67,71,72,73,74,75,76,83,86,89,90,93,100,101,102,105,106,107,110,111,114,121,122,123,128,130,131,133,134,135,137,138,144,153,157,171,175,181,186,188,209,210,247,256,260,267,272,276,277,281,284,285,287,290,298,299,300,306,308,310,312,318,324,337,344,364],log_dep:[27,337],log_depmsg:337,log_dir:[175,209,337],log_err:[27,337],log_errmsg:337,log_fil:[27,175,337],log_file_exist:337,log_info:[27,337],log_infomsg:337,log_msg:337,log_sec:337,log_secmsg:337,log_serv:337,log_trac:[27,102,118,120,337],log_tracemsg:337,log_typ:337,log_typemsg:337,log_warn:[27,337],log_warnmsg:337,logdir:36,logentry_set:148,logfil:[267,337],logged_in:105,loggedin:285,logger:[27,53,102,118,120,141,142,209,279,320],logic:[0,4,10,39,41,42,44,49,69,97,111,134,205,246,250,271,316,328,345],login:[2,4,7,9,25,33,35,43,51,55,69,70,80,90,97,101,105,107,131,133,139,144,156,171,186,242,271,272,287,290,295,296,299,308,344,349,351,360,364],login_func:299,logintest:360,logout:[298,299,360],logout_func:299,logouttest:360,logprefix:[277,287,290,312],lone:[43,61,111,159,166],long_descript:54,long_running_funct:10,long_text:52,longer:[0,21,25,29,33,41,43,50,52,54,58,69,79,86,91,102,115,124,125,126,129,152,157,175,182,205,206,213,217,218,219,220,221,257,260,326,330],longest:[27,206],longrun:33,loo:[154,170],look:[0,3,4,6,9,10,11,12,13,14,15,16,17,19,20,21,22,23,25,26,27,29,30,31,33,35,36,37,38,39,40,41,42,44,46,48,49,51,55,57,58,60,61,62,63,64,67,68,69,70,71,73,74,75,76,77,80,81,82,83,85,86,87,88,89,90,91,96,97,100,103,105,108,109,110,111,112,114,116,117,118,119,121,122,124,125,126,127,131,133,134,135,136,138,139,144,146,151,153,154,156,159,165,167,170,171,181,182,186,187,188,194,202,203,205,206,215,219,226,230,232,233,235,238,241,242,246,247,249,252,272,287,288,295,299,316,318,322,328,329,330,338,341,343,344,357,364],look_str:144,lookaccount:58,lookat:33,looker:[49,58,60,123,144,182,187,206,235,247,318],lookm:33,lookstr:247,lookup:[11,33,43,80,86,97,112,119,150,165,209,246,286,319,321,333,334,340,341,344,345],lookup_typ:340,lookup_usernam:51,lookuperror:321,loom:111,loop:[0,5,6,11,21,46,49,55,60,64,69,85,93,96,116,118,119,124,125,141,146,217,252,285],loopingcal:270,loos:[14,37,144,164,182,221,238,287,298,322],loot:61,lop:119,lore:[58,166],lose:[11,56,61,100,105,110,116,123,138,209,219,278,279,287,290],lost:[0,38,39,43,56,79,91,110,111,125,135,139,164,213,264,277,278,279,287,290,295,316,321],lot:[0,4,10,13,15,22,26,27,28,34,37,39,41,42,46,53,55,57,58,59,61,62,63,67,69,70,73,79,80,86,90,91,93,95,96,108,109,111,112,114,119,121,123,125,127,131,133,135,138,180,184,186,188,206,214,218,232,235,312],loud:21,love:137,low:[31,40,46,66,90,95,152],lower:[2,10,19,25,29,31,33,41,43,49,51,58,62,80,85,86,90,93,114,122,137,151,152,156,167,169,206,272,321],lower_channelkei:41,lowercas:[95,154,321],lowest:[66,90,241,321],lpmud:129,lpthw:77,lsarmedpuzzl:203,lspuzzlerecip:203,lst:[49,324],lstart:50,lstrip:[91,119,321],ltthe:169,ltto:114,luc:327,luciano:79,luck:[8,51,91,96],luckili:[60,80,111,127,131],lue:[114,321],lug:55,luhttp:169,lunch:46,lunr:166,luxuri:[112,314],lycanthrop:119,lying:111,m2m:319,m2m_chang:107,m_len:344,mac:[9,23,24,38,64,93,100,106,131,344],machin:[13,25,100,106,131,231],macport:[63,131],macro:[4,116],macrosconfig:4,mad:131,made:[3,11,19,20,21,25,26,35,36,38,43,51,56,58,59,61,79,80,90,96,98,103,104,109,111,121,123,131,134,150,152,169,170,175,179,182,188,215,219,220,221,242,260,269,299,313,321,322,326,328,344],mag:[60,127,327],magazin:79,mage:51,mage_guild_block:51,mage_guild_welcom:51,magenta:126,magic:[30,60,61,80,112,121,122,140,179,190,220,269],magic_meadow:112,magicalforest:140,magnific:51,mai:[0,4,6,8,9,10,11,13,19,20,21,23,25,27,28,29,31,33,34,37,38,40,41,42,43,48,51,54,56,57,60,62,63,64,66,67,69,70,71,73,75,77,79,80,81,83,84,86,87,88,89,90,93,95,96,97,100,102,103,104,105,106,108,109,110,111,114,115,116,118,119,120,123,125,127,128,130,131,133,134,135,136,144,146,150,151,152,154,156,157,159,164,166,169,170,175,176,178,179,181,182,184,188,190,205,206,217,218,219,220,221,232,233,242,247,251,252,253,269,306,308,309,313,316,318,319,321,323,324,325,326,328,330,331,338,341,344,347],mail:[9,34,37,51,55,57,60,61,70,79,93,116,128,141,142,176,177,178,363],mailbox:[34,199],main:[13,14,15,20,21,22,30,31,33,34,37,40,43,49,51,54,56,64,68,69,76,79,80,81,83,84,85,86,89,90,91,92,100,104,105,109,110,112,115,116,119,122,124,125,131,133,134,135,137,138,139,144,148,150,156,159,164,166,170,175,177,180,188,195,199,205,206,235,239,246,252,256,267,271,272,274,279,284,286,291,305,307,312,318,319,328,329,332,341,343,344],mainli:[10,12,33,34,43,51,57,79,83,89,93,96,105,156,236,316,322,344],maintain:[4,19,23,37,41,43,53,56,68,90,93,100,108,115,119,169,171,186,261,363],mainten:[90,103],major:[14,15,23,45,57,60,63,64,119,121,133],make:[0,1,2,4,5,6,7,8,9,10,11,12,13,14,15,16,19,22,23,24,25,26,28,29,30,31,33,36,37,38,39,40,41,42,43,44,46,47,48,49,50,51,54,55,56,59,61,62,63,64,68,70,71,72,73,74,75,77,78,79,80,81,83,85,86,87,89,90,91,93,95,96,97,100,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,122,124,125,126,128,130,132,133,134,136,137,138,139,140,144,146,148,151,152,153,154,156,157,159,164,167,170,176,179,180,182,187,188,190,196,199,205,206,211,212,213,215,217,218,219,220,223,226,231,232,233,238,241,242,247,251,252,258,261,267,271,279,284,298,299,305,306,308,309,311,312,316,317,318,319,321,322,323,324,325,326,328,330,331,334,341,343,344,360,363],make_it:344,make_shared_login:351,make_uniqu:152,makeconnect:276,makefactori:287,makefil:38,makeit:298,makemessag:76,makemigr:[36,86,133],male:189,malevol:14,malform:[170,345],malici:103,malign:242,man2x1:108,man:[43,87,90,108,129,165,199,206],mana:[28,30],manag:[2,7,9,11,31,39,40,43,53,56,57,59,80,83,85,86,89,93,96,100,102,105,110,115,119,125,127,128,131,133,138,141,142,143,144,148,164,169,170,172,175,177,202,206,221,233,236,239,243,246,247,251,253,256,261,262,267,274,314,316,318,319,320,323,324,332,335,337,341,344,360,364],manager_nam:316,manchest:344,mandat:357,mandatori:[0,22,107,109,129],maneuv:215,mangl:293,mango:203,manhol:287,manhole_ssh:287,mani:[0,1,2,4,5,9,10,11,12,14,15,17,20,26,27,30,31,33,34,38,40,43,44,49,51,55,56,57,58,61,62,63,64,66,68,70,72,73,76,77,85,86,88,89,90,91,93,95,96,98,102,103,104,105,107,108,109,110,111,113,114,115,116,118,119,120,121,122,123,124,125,126,127,128,129,131,133,134,135,140,148,152,154,159,164,170,177,179,182,186,188,206,213,214,215,219,220,231,234,239,242,246,252,256,261,267,281,289,291,310,316,318,319,321,328,329,334,335,337],manifest:97,manipul:[0,11,22,31,41,43,44,51,64,86,102,109,123,159,176,187,192,238,247,273,324,329],manner:[14,206,235,247,285,318],manpow:37,manual:[4,6,14,20,21,23,30,33,34,38,40,55,58,60,61,63,68,79,80,85,86,89,90,97,102,109,110,111,114,117,119,121,122,124,125,128,131,134,139,140,141,146,159,215,226,230,234,247,252,259,267,284,291,328,329,363,364],manual_paus:259,manual_transl:205,manytomanydescriptor:[148,177,239,246,256,316,318,319],manytomanyfield:[148,177,239,246,256,316,318,319],map:[0,15,25,39,43,46,51,57,58,61,64,67,87,88,97,100,124,135,138,139,156,164,170,175,183,184,205,206,235,247,251,252,291,316,318,321,327,328,344,364],map_modul:111,map_str:[49,111,235],mapbuild:[141,142,178],mapper:334,mapprovid:235,march:[79,337],margin:17,mark:[13,14,20,21,33,38,43,49,51,58,63,72,76,80,90,95,114,119,131,135,137,138,140,151,158,187,195,204,215,308,316,318,322,327,328,340],mark_categori:215,markdown:[1,4,38,48,54],marker:[13,20,33,43,51,64,87,114,138,164,165,187,189,206,215,247,279,287,290,295,296,316,319,321,327,328,329,347],market:90,markup:[38,81,114,136,139,141,142,183,320,343,344],mask:[203,206,210,211],maskout_protodef:203,mass:[61,124,139,364],massiv:[28,55],master:[7,9,37,38,43,57,61,63,73,95,98,100,104,116,118,134,313],match:[9,11,20,22,27,31,33,39,41,43,44,49,51,57,58,62,68,74,76,80,83,86,87,88,89,91,102,104,105,109,111,112,114,118,119,125,128,131,133,134,135,136,137,138,144,150,151,152,153,154,157,159,164,165,166,168,170,176,180,183,184,187,188,198,199,202,203,206,220,235,238,241,242,247,251,252,258,261,272,273,285,298,308,316,317,318,319,321,326,328,330,339,341,343,344,345,347],match_index:151,matched_charact:188,matcher:51,matches2:86,matchobject:[321,343],mate:64,math:39,mathemat:152,matplotlib:300,matrix:330,matt:102,matter:[0,4,9,11,25,31,36,41,51,57,61,62,63,69,73,76,84,91,95,103,105,107,108,116,117,127,136,152,221,231,246,272,316],matur:[108,128,129],maverick:64,max:[16,25,49,71,114,116,166,188,206,310,337,344],max_damag:219,max_dbref:317,max_depth:344,max_dist:49,max_heal:219,max_l:49,max_length:[49,86,133,206],max_lin:330,max_rmem:334,max_siz:337,max_valu:[190,357],max_w:49,max_width:49,maxconn:67,maxdelai:[264,278,279,298],maxdepth:252,maxdiff:[170,352],maximum:[16,39,71,86,91,111,114,144,188,190,217,218,219,220,221,247,252,312,321,328,330,344],maxlengthvalid:144,maxnum:344,maxrotatedfil:337,maxsplit:321,maxthread:312,maxval:344,maxwidth:330,may_use_red_door:109,mayb:[6,9,11,13,14,21,22,25,27,31,33,38,44,48,49,54,61,63,68,69,70,73,82,85,86,90,109,116,119,122,138,140,153,179,198,205,285],mccp:[24,55,74,141,142,262,272,275],mccp_compress:280,meadow:[22,112,140],mean:[0,5,10,11,12,13,14,15,20,22,23,27,28,31,33,34,37,40,41,42,43,46,49,51,55,57,58,60,61,62,64,68,73,74,77,78,80,81,83,84,85,86,87,88,90,93,95,96,97,100,102,103,104,105,110,111,112,113,114,116,117,119,121,122,123,125,126,127,128,131,134,135,136,138,144,146,153,159,166,185,195,205,232,234,241,247,251,252,257,261,267,291,307,316,318,321,328,330,334,337,340,341],meaning:[154,170],meaningless:123,meant:[16,20,22,31,34,44,54,62,68,76,83,96,102,125,126,137,138,140,152,180,189,206,214,217,218,219,220,221,233,235,247,272,322],meantim:1,meanwhil:96,measur:[90,93,123,151,168,298,299,344],meat:133,mech:[124,139,364],mechan:[27,28,33,39,50,51,55,58,61,67,69,73,91,102,109,116,122,123,125,126,139,144,146,150,187,206,220,240,252,261,267,271,277,285,296,307,318,326,329,332,339],mechcmdset:21,mechcommand:21,mechcommandset:21,meck:21,media:[16,295,312,340,357],median:49,mediat:73,medium:16,mediumbox:276,meet:[25,36,61,122,194,235,311],mele:221,mem:[43,169],member:[9,11,43,70,86,164,165,167,247,344],membership:[4,9,119],memori:[6,12,23,28,31,33,43,56,75,86,90,93,113,125,135,144,169,175,247,260,261,300,310,316,320,329,334,339,344],memoryerror:63,memoryusag:300,memplot:[141,142,262,297],meni:180,mental:126,mention:[6,9,10,11,13,14,15,21,29,33,40,41,49,56,57,61,63,70,74,80,90,102,108,113,115,126,127,153,186],menu:[11,25,31,43,45,46,47,53,54,55,63,65,69,105,106,109,110,123,128,138,139,141,142,159,180,188,214,215,230,248,252,265,267,320,338,364],menu_cmdset:328,menu_data:51,menu_edit:180,menu_login:[141,142,178],menu_modul:328,menu_module_path:328,menu_quit:180,menu_setattr:180,menu_start_nod:214,menu_templ:328,menuchoic:[51,328],menudata:[188,230,249,328],menudebug:[51,328],menufil:328,menunode_fieldfil:188,menunode_inspect_and_bui:85,menunode_shopfront:85,menunode_treeselect:215,menunodename1:51,menunodename2:51,menunodename3:51,menuopt:215,menutre:[51,328],merchant:46,mercuri:108,mere:[117,190],merg:[3,5,22,33,37,43,44,51,57,62,64,97,131,139,150,151,152,153,226,233,235,252,256,291,328],merge_prior:328,merger:[5,31,37,111,152,153],mergetyp:[31,51,116,152,226,233,326,328],mess:[11,19,27,38,90,93,131,138,215],messag:[5,6,8,10,13,15,20,21,22,27,28,29,33,34,40,41,43,44,45,46,50,51,52,53,55,58,59,60,61,62,63,64,65,70,71,73,74,76,80,81,82,85,89,90,91,92,95,96,101,102,103,104,105,110,111,113,116,118,119,123,124,127,128,131,132,137,138,139,140,144,146,150,153,154,157,159,164,165,166,170,172,175,176,177,179,180,182,188,189,193,195,199,203,204,206,210,217,218,219,220,221,223,226,228,230,231,232,233,234,247,267,269,276,278,279,285,286,287,290,291,293,295,304,306,308,310,312,324,326,328,329,337,341,344],message_rout:137,message_search:176,message_transform:175,messagepath:[139,364],messagewindow:137,meta:[104,125,318,334,357],metaclass:[86,96,125,154,318],metadata:[210,269],metavar:234,meteor:82,meter:190,method:[1,2,5,6,9,10,11,22,25,27,28,29,30,31,34,38,39,40,42,46,48,49,51,55,58,59,60,62,64,68,69,73,77,80,83,86,88,89,91,95,96,102,104,105,107,109,111,112,114,115,116,117,118,119,120,121,123,125,127,131,132,133,134,137,139,144,148,150,152,153,154,156,159,160,164,166,167,169,170,175,176,177,179,180,184,187,192,195,202,203,204,205,206,209,210,212,217,218,219,220,221,226,228,230,231,232,233,234,235,238,239,241,242,247,260,261,264,269,272,273,274,276,277,278,279,280,285,287,290,293,295,296,298,299,303,305,306,307,308,310,316,318,321,322,324,326,328,329,330,331,334,335,337,338,339,341,342,343,344],methodnam:[170,196,211,228,261,293,303,335,342,352,360],metric:[82,205],microsecond:11,microsoft:[63,111],mid:[29,108,121],middl:[29,33,49,90,218,321],middlewar:[141,142,346,348],midnight:[25,62],midst:122,midwai:114,mighht:91,might:[0,4,8,10,11,12,14,15,17,20,22,23,25,26,27,28,29,30,31,33,34,39,40,41,42,43,46,51,52,55,58,60,61,62,63,69,70,73,75,76,77,80,81,82,85,89,90,91,95,96,97,98,100,102,103,104,105,110,111,114,115,116,119,120,122,123,124,126,127,131,132,133,136,138,153,157,159,179,204,210,213,217,218,219,220,234,247,296,318,321,326,337,338,344,357,363],mighti:[29,111],migrat:[9,23,36,38,63,75,86,107,110,111,127,131,133,252],mike:[43,159],mileston:139,million:[23,25,133],mime:324,mimic:[23,34,50,55,73,93,177,306,326],mimick:[50,64,73,138,298,326,329],mimim:319,min:[49,62,102,114,184,188,331],min_damag:219,min_dbref:317,min_heal:219,min_height:330,min_shortcut:[22,180],min_valu:357,min_width:330,mind:[10,12,13,14,37,41,45,51,54,55,56,57,60,61,122,126,134,138,179,190,195,204,269,344],mindex:151,mine:[46,103,138],mini:[55,111,124],miniatur:[61,122],minim:[61,103,105,116,138,205,252],minimalist:[33,58,108],minimum:[22,58,64,73,105,188,217,218,219,220,221,272,312,318,330,339,344],mininum:330,minlengthvalid:144,minor:[41,153,363],mint:[63,67,131],minthread:312,minu:[86,247,331],minut:[25,27,28,43,62,79,91,100,102,116,164,169,179,184,310,331,344],minval:344,mirc:279,mirror:[72,79,105],mis:57,misanthrop:119,misc:138,miscelan:320,miscellan:47,mislead:41,mismatch:[74,344],miss:[49,57,60,63,70,90,95,97,217,218,219,220,221,251,272],missil:[21,220],mission:[41,69],mistak:[38,60,363],misus:90,mit:[79,124,321],mitig:[57,103],mix:[11,30,33,34,51,53,114,126,133,144,166,179,206,247,251,252,311,319,322,330],mixin:[251,301],mixtur:81,mkdir:[9,36,63],mktime:62,mob0:56,mob:[14,43,55,56,61,80,105,122,141,142,153,159,178,229,233,252,322],mob_data:56,mob_db:56,mob_vnum_1:56,mobcmdset:231,mobdb:56,mobil:[14,71,109,122,138,231,241],moboff:231,mobon:231,mock:[127,170,260,342],mock_delai:170,mock_get_vers:352,mock_random:228,mock_repeat:170,mock_set:352,mock_tim:303,mockdeferlat:342,mockdelai:342,mocked_idmapp:303,mocked_o:303,mocked_open:303,mockup:138,mockval:342,mod:[8,103,251],mod_import:344,mod_import_from_path:344,mod_prototype_list:251,mod_proxy_http:8,mod_proxy_wstunnel:8,mod_sslj:8,mode:[2,8,31,41,42,43,50,51,67,69,74,79,93,100,103,106,116,117,123,133,135,138,141,158,166,169,181,199,226,231,247,267,272,277,284,295,296,305,322,326,328,337,344],mode_clos:296,mode_init:296,mode_input:296,mode_keepal:296,mode_rec:296,model:[9,11,34,41,45,59,64,69,73,80,87,96,104,112,115,119,125,132,135,136,139,141,142,143,144,172,175,176,236,243,247,253,257,261,262,273,314,316,317,319,320,325,332,333,335,340,341,344,357,364],model_inst:340,modelattributebackend:316,modelbackend:349,modelbas:334,modelclass:[11,112],modelform:357,modelnam:[175,239,318],moder:[4,39,179],modern:[10,11,15,30,79,103,108,126,138,280],modif:[0,8,25,33,37,46,83,91,100,123,131,138,313,357],modifi:[0,2,4,11,20,22,25,26,31,33,34,38,39,40,43,44,46,51,53,55,56,57,58,60,68,73,78,85,89,93,96,100,104,105,109,110,111,114,118,119,122,123,125,128,131,135,137,138,139,140,144,153,166,175,180,185,187,189,195,203,206,213,217,218,219,220,221,232,234,239,247,252,261,318,322,328,334,340,343,347,357],modified_text:114,modul:[3,5,6,11,13,15,20,21,26,27,29,31,33,35,37,38,40,43,45,47,50,51,55,56,57,58,59,60,62,65,68,74,75,80,81,82,83,85,89,93,96,97,98,102,103,104,105,107,108,110,111,114,117,119,121,122,123,124,125,127,135,138,139,150,151,153,154,159,161,162,163,166,168,170,179,180,181,182,183,184,185,186,187,188,190,192,193,194,196,204,205,206,211,212,213,215,217,218,219,220,221,226,231,232,233,234,241,242,246,247,250,251,252,257,259,260,261,264,266,267,271,272,276,284,286,287,290,291,294,296,298,299,300,305,307,308,309,316,318,319,320,321,322,323,324,325,326,327,328,329,331,342,344],modular:55,modulepath:276,moifi:187,mollit:52,moment:[21,31,46,57,76,85,91,96,115,135,139,144,256],monei:[9,61,70,86,90],monetari:[37,179],monitor:[53,84,88,93,139,257,272,291,334],monitor_handl:[84,141,257],monitorhandl:[45,74,139,141,142,253,364],mono:25,monster:[29,43,57,61,64,89,109,159,252],month:[37,62,67,90,184,331,337,344],monthli:62,montorhandl:84,moo:[55,57,79,108,129],mood:[46,122],moon:[25,61,62,82],moor:122,moral:97,more:[0,1,2,3,4,5,9,10,11,12,13,14,15,17,19,20,21,22,23,25,26,27,28,31,33,34,35,36,37,39,40,41,42,43,44,46,49,50,51,52,55,56,58,59,60,61,62,63,64,66,67,68,69,70,71,72,73,74,75,76,77,79,83,85,86,87,88,89,90,91,93,95,96,97,100,102,103,104,105,108,109,110,111,112,113,114,115,116,118,119,121,122,123,124,125,126,127,131,132,133,134,136,137,138,141,143,144,148,151,152,153,158,159,164,165,166,169,170,171,175,178,179,180,181,182,184,186,187,190,195,198,204,205,206,213,214,215,217,218,219,220,221,226,231,232,233,234,235,247,251,252,277,279,282,298,299,308,313,316,317,321,322,324,325,326,327,328,329,330,334,341,344,345,357],more_command:329,morennanoth:170,morennthird:170,moreov:[90,102],morn:[187,188],most:[0,4,6,8,9,10,11,13,17,22,23,25,27,30,31,33,35,37,38,39,40,41,42,43,46,47,48,49,51,56,57,58,59,60,61,62,63,64,69,73,74,77,80,82,83,86,88,89,90,91,93,95,96,97,100,103,104,105,107,108,111,113,114,115,116,117,119,121,123,125,126,128,129,133,137,138,140,144,148,152,153,156,159,167,170,177,180,190,205,206,213,217,218,219,220,221,239,242,246,247,251,252,256,260,290,295,305,316,317,318,319,328,329,334,335,344],mostli:[40,51,57,69,73,90,91,95,114,123,125,137,138,152,185,205,219,235,287],motiv:[13,14,37,55,61,70,89,278,279,285,286,287,290,295,296,307,308],mount:100,mountain:[108,111],mous:[114,137,328],move:[0,4,9,14,15,21,22,23,29,33,34,41,43,44,46,49,50,51,52,54,58,61,63,69,77,79,82,85,89,91,95,96,111,116,117,122,126,133,134,138,153,159,165,179,180,188,194,213,217,218,219,220,221,231,232,233,235,238,241,247,299,318,322,329],move_callback:169,move_delai:169,move_hook:247,move_obj:235,move_to:[0,85,89,121,213,247],movecommand:44,moved_obj:[233,235,247],moved_object:247,movement:[58,109,121,169,213,217,218,219,220,221,247],mover:221,mptt:4,mratio:[151,168],msdp:[55,83,272,291],msdp_list:272,msdp_report:272,msdp_send:272,msdp_unreport:272,msdp_var:291,msg:[0,2,5,10,11,13,22,25,27,28,29,30,33,38,40,41,42,44,46,50,51,52,53,56,58,59,60,62,71,73,80,82,84,85,86,88,89,91,95,96,105,111,112,114,116,118,119,121,123,127,129,137,138,141,144,146,154,156,160,164,170,175,176,177,189,199,210,226,234,242,247,278,279,306,322,324,326,328,329,337,344],msg_all:116,msg_all_sess:[33,154],msg_arriv:0,msg_channel:164,msg_content:[0,21,27,33,46,62,73,89,102,118,121,123,132,247],msg_help:166,msg_leav:0,msg_locat:247,msg_other:179,msg_receiv:247,msg_self:247,msg_set:319,msglauncher2port:[267,276],msgmanag:[176,177],msgobj:[34,175],msgportal2serv:276,msgserver2port:276,msgstatu:[267,276],mssp:[55,104,141,142,262,275],mtt:294,much:[0,4,10,11,13,14,15,20,22,23,25,26,29,37,38,39,41,42,49,51,56,59,61,62,63,64,67,69,73,76,79,80,82,89,90,91,93,96,109,111,113,115,116,119,120,121,125,127,132,133,134,138,148,153,158,167,180,184,185,205,206,215,221,226,232,307,316,321,322,323,330,344,347],muck:57,mud:[8,15,21,22,23,24,30,40,43,49,55,56,60,61,63,64,72,73,74,80,87,88,90,91,92,95,97,98,100,101,104,105,108,110,111,114,115,116,117,122,124,126,128,132,135,137,138,140,148,153,156,221,230,264,280,281,282,287,290,291,294,322,331],mudbyt:79,mudconnector:79,mudderi:79,muddev:63,mudform:327,mudinfo:34,mudlab:79,mudlet:[24,96,101,272,282],mudmast:24,mudramm:24,muhammad:343,mukluk:24,mult:109,multi:[10,22,31,38,43,51,55,61,95,96,100,104,105,119,122,123,151,169,206,215,247,308,328,344],multiaccount_mod:97,multidesc:[141,142,178],multilin:343,multimatch:[31,151,206,247,344],multimatch_str:[144,206,247,344],multimedia:137,multipl:[6,12,14,22,23,27,30,31,33,40,43,51,55,58,61,62,64,73,79,84,88,89,90,95,96,104,105,107,108,109,114,115,122,123,125,131,138,144,150,152,157,158,159,164,166,168,169,170,183,185,186,187,189,190,196,202,206,215,217,218,219,220,233,242,247,251,252,261,265,269,272,276,291,299,316,317,322,328,330,341,344],multiplay:[55,57,79],multipleobjectsreturn:[144,146,148,175,177,179,182,184,187,189,195,203,204,205,206,212,213,214,217,218,219,220,221,223,226,231,232,233,235,239,246,247,251,256,259,274,300,316,319,331,335],multisess:[2,41,69,328],multisession_mod:[24,33,64,105,123,133,144,156,160,181,189,247,308],multisession_modd:51,multitud:[57,111,114],multumatch:247,mundan:21,murri:344,muse:79,mush:[9,36,55,60,73,79,108,116,124,139,183,202,364],mushclient:[24,74,96,272,282],musher:79,mushman:108,musoapbox:[57,79],must:[0,1,2,4,5,8,10,11,15,24,25,29,31,33,37,38,40,43,48,49,50,51,56,58,61,62,63,64,65,67,71,72,74,76,80,81,83,84,85,87,89,90,93,95,96,97,100,103,104,109,110,112,113,114,115,116,117,119,123,125,127,128,131,133,135,136,137,140,146,151,152,154,159,164,170,175,176,179,182,183,184,186,203,205,206,210,215,217,218,219,220,221,226,230,232,233,239,241,247,250,251,257,261,267,272,285,287,290,307,309,310,316,317,318,321,322,323,324,325,326,327,328,329,331,338,339,340,341,343,344,345],must_be_default:153,mutabl:325,mute:[17,41,144,164,175],mute_channel:164,mutelist:[41,175],mutltidesc:202,mutual:[226,317],mux2:129,mux:[20,21,33,34,41,45,55,58,103,108,139,149,167,183,364],mux_color_ansi_extra_map:183,mux_color_xterm256_extra_bg:183,mux_color_xterm256_extra_fg:183,mux_color_xterm256_extra_gbg:183,mux_color_xterm256_extra_gfg:183,muxaccountcommand:[167,199],muxaccountlookcommand:156,muxcommand:[5,25,28,29,30,33,44,53,58,119,123,141,142,149,155,156,157,158,159,164,165,166,168,169,171,182,185,186,187,193,199,202,203,212,214,219,220,233,247,326],mvattr:159,mxp:[24,55,74,114,141,142,166,262,272,275,287,290,321,328,343,344],mxp_pars:282,mxp_re:321,mxp_sub:321,mxp_url_r:321,mxp_url_sub:321,my_callback:309,my_datastor:86,my_funct:29,my_github_password:131,my_github_usernam:131,my_identsystem:87,my_number_handl:51,my_object:29,my_port:40,my_portal_plugin:40,my_script:102,my_server_plugin:40,my_servic:40,my_word_fil:205,myaccount:112,myapp:86,myarx:9,myattr:[11,144],myawesomegam:67,mybot:[43,164],mycallable1:51,mycar2:87,mychair:112,mychan:34,mychannel1:164,mychannel2:164,mychannel:[12,43,164],mycharact:81,mychargen:51,myclass:60,mycmd:[33,68],mycmdset:[5,31,33],mycommand1:31,mycommand2:31,mycommand3:31,mycommand:[30,31,33,83,170],mycommandtest:170,mycompon:137,myconf:36,mycontrib:127,mycss:137,mycssdiv:137,mycustom_protocol:40,mycustomcli:40,mycustomview:135,mydatastor:86,mydhaccount:100,mydhaccountt:100,mydhacct:100,myevennia:72,myevilcmdset:[31,152],myevmenu:51,myfix:131,myfunc:[10,115,127,344],myfunct:51,mygam:[2,3,5,6,9,13,14,21,23,25,26,27,30,31,35,40,42,44,47,49,51,53,54,56,57,58,60,62,63,65,67,69,71,73,74,75,76,80,81,82,85,86,89,90,93,95,96,100,102,104,106,109,110,111,114,116,118,119,120,121,123,125,127,128,131,133,134,135,136,137,180,181,183,187,199,202,212,213,292,342,344],mygamedir:38,mygamegam:81,myglobaleconomi:102,mygotocal:51,mygrapevin:164,myhandl:107,myhdaccount:100,myhousetypeclass:[43,159],myinstanc:86,myircchan:[43,164],mykwarg:51,mylayout:137,mylink:38,mylist2:11,mylist:[6,11,97,318],mylog:27,mymenu:51,mymethod:56,mymodul:115,mymud:[8,106],mymudgam:90,mynam:100,mynestedlist:325,mynod:51,mynoinputcommand:33,mynpc:123,myobj1:112,myobj2:112,myobj:[11,27,80,102,261],myobject:[5,11],myobjectcommand:25,myothercmdset:31,myownfactori:40,myownprototyp:109,mypassw:186,mypath:127,myplugin:137,myproc:40,myproc_en:40,myprotfunc:109,myroom:[43,56,102,112,159],myros:89,myscript:[102,112,125],myscriptpath:102,myserv:186,myservic:40,mysess:105,mysql:[36,55,64,128,344],mysqlclient:23,mysteri:[75,87],mytag1:137,mytag2:137,mythic:122,mytick:261,mytickerhandl:261,mytickerpool:261,mytop:20,mytup1:11,mytup:11,myvar:33,myview:135,naccount:308,naiv:[175,235,239,318],nake:33,name1:[43,159],name2:[43,159],name:[0,2,3,4,5,6,9,10,11,13,14,15,19,20,22,23,24,25,29,31,33,34,36,38,40,41,42,44,46,47,49,51,52,53,54,55,56,57,58,59,60,61,62,64,65,66,67,68,69,71,72,73,74,75,76,79,80,81,82,83,84,85,86,87,89,90,91,93,95,96,100,102,103,104,105,106,107,109,110,111,112,113,114,116,117,119,121,123,125,126,127,128,130,131,132,133,134,135,136,137,138,139,140,141,144,146,148,150,151,152,153,154,156,157,159,164,165,166,167,168,169,170,171,175,176,177,180,181,182,184,186,188,192,194,195,198,203,204,205,206,212,215,219,220,231,233,234,235,238,239,246,247,251,252,256,257,259,261,267,270,272,273,274,276,277,279,284,287,290,291,294,295,296,299,308,310,312,316,317,318,319,321,322,323,324,326,327,328,329,334,335,337,338,340,341,343,344,345,349,357],namecolor:215,namedtupl:192,nameerror:[42,95],namelist:199,namesak:97,namespac:[69,125,137,195,234,252,310,322],napoleon:38,narg:[114,234],narr:221,narrow:91,nativ:[34,38,42,51,88,102,209,310,312],nattempt:51,nattribut:[11,43,51,116,125,159,252,306,316,318,324,328],nattributehandl:316,natur:[11,15,27,55,79,88,112,146,330],natural_height:330,natural_kei:316,natural_width:330,navig:[9,48,49,51,106,111,128,133,134,221],naw:[24,52,141,142,262,275],nbsp:343,nchar:120,nclient:298,ncolumn:330,ncurs:141,ndb:[6,13,22,25,29,33,43,51,102,105,116,125,144,148,169,246,256,306,318,328],ndb_:[43,109,159,252],ndb_del:306,ndb_get:306,ndb_set:306,ndk:75,nearbi:[119,152,153,154,221],nearli:321,neat:[0,3,138,357],neatli:[108,344],necess:[40,95],necessari:[0,4,22,36,39,40,51,57,58,59,61,77,91,108,110,114,118,121,125,131,138,153,154,177,181,195,210,233,234,251,252,296,322,328,330,338,340,344],necessarili:[38,41,57,88,90,109,344],necessit:309,neck:[109,182],necklac:182,need:[1,2,3,4,5,6,8,9,10,11,13,14,15,19,20,21,22,23,25,26,27,28,29,30,31,33,34,35,36,37,38,39,40,41,42,43,44,45,46,48,49,50,51,54,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,79,80,81,82,83,84,85,86,87,88,89,90,91,93,95,96,97,98,100,102,103,104,105,106,109,110,111,112,113,114,115,116,117,118,119,121,122,123,124,125,126,127,128,130,131,133,134,135,136,137,138,140,144,146,148,152,154,156,159,164,165,167,169,170,175,179,180,186,187,189,193,194,195,196,203,204,205,206,215,217,218,219,220,221,226,231,232,233,234,235,242,246,247,251,252,267,269,271,272,276,284,291,296,298,306,307,308,312,316,318,321,322,324,328,329,330,331,338,339,341,344],need_gamedir:267,needl:203,neg:[62,126,152,326,344],negat:[114,119,242],negoti:[55,179,281,283,285,294,308],negotiate_s:283,neighbor:39,neither:[11,54,61,73,97,110,166,185,251,291,316,319,328,345],nenter:51,nest:[11,14,33,43,51,114,144,159,206,215,241,247,252,291,325],nested_mut:11,nested_r:159,nestl:111,net:[9,43,57,63,72,79,90,146,164,280,281,291,294,308],netrc:131,network:[40,43,53,55,64,65,70,71,72,79,90,103,113,139,146,164,278,279,284,305,308],neu:180,neutral:189,never:[12,14,26,27,31,33,51,54,56,60,61,62,64,80,86,88,91,95,96,104,114,115,118,119,121,125,127,131,133,144,169,194,205,206,220,221,231,242,247,306,316,325,344],nevertheless:[26,43,51,86,126,156,180],new_alias:154,new_arriv:233,new_attrobj:316,new_channel:[58,164],new_charact:231,new_coordin:235,new_datastor:86,new_goto:328,new_kei:[107,154,247],new_loc:[43,159],new_menu:180,new_nam:[43,107,159],new_name2:[43,159],new_obj:[80,247,252],new_obj_lockstr:159,new_object:[109,252],new_raw_str:151,new_room_lockstr:159,new_ros:89,new_script:102,new_typeclass:[144,318],new_typeclass_path:125,new_valu:[84,316],newbi:[25,48,55,124],newcom:[96,117],newer:9,newindex:215,newli:[43,46,58,60,66,131,133,159,175,180,199,204,234,247,252,259,324],newlin:[33,43,137,166,322,330],newnam:[33,43,159,318],newpassword:[43,157],newstr:137,nexist:22,nexit:[120,127],next:[0,4,5,6,9,10,11,12,13,14,20,21,22,23,25,28,29,30,31,33,36,38,39,41,42,46,49,50,51,52,56,58,60,61,62,64,65,68,72,73,75,76,77,79,80,81,83,85,86,89,90,95,96,98,100,102,103,106,110,111,114,116,119,121,122,123,127,131,133,134,137,138,180,184,202,215,217,218,219,220,221,232,242,267,322,328,329,331,344],next_nod:51,next_turn:[217,218,219,220,221],nextnod:328,nextnodenam:328,nextrpi:79,nexu:45,nfkc:144,ng2:330,nginx:8,nice:[0,12,22,27,49,54,58,61,62,68,70,81,90,96,100,111,119,127,138,140,159,179,182,206,251],nicer:[20,60,96],niceti:[43,159],nick:[2,11,45,57,74,79,89,129,139,144,146,159,164,165,175,206,246,247,279,316,317,364],nick_typ:87,nickhandl:[11,87,316],nicklist:[146,164,279],nicknam:[43,87,89,129,131,165,206,246,247,279,316,317],nickreplac:316,nicktemplateinvalid:316,nicktyp:[206,247],nifti:8,night:[58,61,132,138,187],nine:66,nineti:345,nit:[60,62],nline:337,no_act:328,no_channel:[31,33,152,328],no_default:[125,144,318],no_exit:[31,33,116,152,226,230,328],no_gmcp:291,no_log:153,no_match:180,no_mccp:280,no_more_weapons_msg:232,no_msdp:291,no_mssp:281,no_mxp:282,no_naw:283,no_obj:[31,152,226,230,328],no_prefix:[144,175],no_superuser_bypass:[144,175,242,247,318],no_tel:80,noansi:170,nobj:120,nocaptcha:133,nocaptcha_recaptcha:133,nocolor:[81,272,287,290,295,296],nodaemon:106,node1:[51,328],node2:[51,328],node3:[51,328],node:[13,85,109,188,215,230,249,265,328],node_abort:51,node_apply_diff:249,node_attack:51,node_background:51,node_betrayal_background:51,node_border_char:328,node_destin:249,node_examine_ent:249,node_exit:51,node_formatt:[51,188,328],node_four:51,node_game_index_field:265,node_game_index_start:265,node_hom:249,node_index:[249,328],node_kei:249,node_loc:249,node_login:51,node_matching_the_choic:51,node_mssp_start:265,node_mylist:51,node_on:51,node_parse_input:51,node_password:51,node_prototype_desc:249,node_prototype_kei:249,node_prototype_sav:249,node_prototype_spawn:249,node_readus:51,node_select:51,node_set_nam:51,node_start:265,node_test:51,node_text:51,node_usernam:51,node_validate_prototyp:249,node_view_and_apply_set:265,node_view_sheet:51,node_violent_background:51,node_with_other_nam:328,nodefunc1:51,nodefunc2:51,nodefunc:328,nodekei:328,nodenam:[51,328],nodename_to_goto:51,nodestartfunc:51,nodetext:[51,188,249,328],nodetext_formatt:[51,188,249,328],noecho:[43,169],noerror:247,nofound_str:[144,206,247,344],nogoahead:289,nohom:324,nois:21,noisi:[90,264,269,277,287,290,298,312],noloc:[43,159],nomarkup:[74,81],nomatch:[22,168,180,326,344],nomatch_exit:22,nomatch_single_exit:22,nomigr:127,non:[4,6,14,15,20,22,27,29,31,33,38,43,44,49,50,52,55,58,61,62,63,64,65,68,70,74,82,86,88,102,105,109,110,114,122,124,125,126,131,137,139,140,144,146,148,150,152,159,164,169,175,177,185,195,204,212,214,215,232,238,246,247,250,251,252,256,257,259,261,267,276,290,291,305,306,308,316,318,321,324,325,326,328,330,341,344],nonc:295,nondatabas:[11,306,318],none:[0,1,2,10,11,13,14,15,22,25,30,31,33,34,39,40,41,42,43,44,49,50,51,56,58,60,62,64,69,74,77,80,81,83,84,85,86,87,88,91,96,102,105,111,112,114,116,118,119,121,123,144,146,150,151,152,153,154,156,159,160,161,162,163,164,166,167,170,175,176,177,179,180,181,182,185,187,188,189,192,194,195,198,203,204,205,206,212,214,215,217,218,219,220,221,226,230,231,232,233,234,235,238,241,242,246,247,249,251,252,257,258,260,261,264,265,267,269,273,276,277,278,279,286,287,295,296,298,306,307,308,310,311,312,316,317,318,319,321,322,323,324,325,326,327,328,329,330,331,334,337,339,340,341,344,345,349,352,357],nonpc:123,nonsens:205,noon:[20,60,73,76,80,96],nop:290,nopkeepal:[24,290],nor:[11,13,29,31,42,54,106,108,116,126,185,186,234,247,251,291,316,319],norecapcha:133,norecaptcha_secret_kei:133,norecaptcha_site_kei:133,norecaptchafield:133,normal:[2,3,5,6,9,10,11,13,14,15,19,20,21,23,25,27,29,30,31,33,34,38,43,44,46,49,51,55,56,57,58,60,62,64,66,68,69,72,74,75,76,80,81,82,83,85,86,87,88,90,93,96,97,100,102,104,105,109,110,111,112,113,114,116,119,121,122,123,125,126,127,128,134,135,137,138,140,144,146,148,150,151,152,153,154,156,159,166,169,170,175,179,184,185,217,218,219,220,221,226,231,234,235,246,247,249,252,261,267,276,279,280,281,283,285,299,306,308,314,316,317,318,321,322,325,328,329,334,341,343,344,346],normal_turn_end:116,normalize_nam:247,normalize_usernam:144,north:[0,20,22,43,44,46,49,89,111,114,121,159,180,213,299],north_south:111,northeast:[20,43,159,235],northern:[22,111],northwest:159,nose:316,not_don:312,not_error:267,not_found:159,notabl:[6,9,10,40,43,63,97,131,154,159,170,179,318,325,344],notat:[43,119,159,321,344],notdatabas:125,note:[0,1,2,4,5,6,9,11,12,13,19,20,21,23,24,25,27,29,41,42,43,48,49,57,58,59,60,61,62,63,64,69,70,73,74,75,76,80,83,85,86,88,89,90,93,95,96,100,102,103,105,106,107,109,110,113,114,115,116,117,119,121,123,124,125,126,128,130,131,133,134,135,136,137,141,144,146,151,152,153,154,156,159,160,161,164,165,166,167,169,170,171,175,176,179,181,182,183,184,185,186,187,189,194,195,198,202,203,204,205,206,212,213,215,217,218,219,220,221,226,233,234,235,241,242,246,247,251,252,261,264,267,272,276,277,279,280,284,285,286,287,290,291,292,294,295,298,300,301,306,308,312,313,316,317,318,319,321,322,323,324,325,326,327,328,329,330,331,334,337,339,340,341,344,347,350,364],notepad:63,notfound:344,notgm:58,noth:[0,10,11,14,20,22,27,29,33,34,42,56,57,60,62,83,85,89,95,108,111,115,116,127,144,159,168,215,217,220,221,231,235,247,259,279,316,318,328],nother:120,notic:[0,10,12,13,20,22,23,29,33,36,37,39,41,42,46,62,69,70,91,96,117,121,126,127,131,180,223,280],notif:[4,75,131,137,138,199],notifi:[43,98,164,217,218,219,220,221,233,251],notificationsconfig:4,notimplementederror:290,notion:[62,115,116],noun:[205,206],noun_postfix:205,noun_prefix:205,noun_transl:205,now:[0,2,3,5,6,9,10,11,12,14,20,21,22,23,25,27,28,29,31,33,36,39,41,46,48,49,51,55,56,57,58,60,61,62,63,64,65,67,69,71,72,73,75,76,77,79,80,81,82,83,85,86,89,90,91,95,96,97,98,100,102,103,105,106,108,109,110,111,114,115,117,118,119,121,123,125,126,127,128,131,133,134,135,136,137,138,140,153,164,166,179,184,188,195,215,226,235,242,247,279,287,308,340,342,344],nowher:[95,111],noxterm256:290,npc:[9,33,46,51,61,64,73,111,119,124,139,179,214,241,364],npcname:118,npcshop:85,nprot:120,nr_start:258,nroom:[22,120],nroom_desc:127,nrow:330,ntf:63,nthe:226,nuanc:114,nudg:[78,226,312],nuisanc:103,nulla:52,num:[49,80,206,247],num_lines_to_append:337,num_object:119,num_objects__gt:119,num_tag:119,number:[0,6,10,11,12,13,20,21,23,25,26,27,31,33,34,36,38,41,43,49,50,51,57,58,60,61,62,64,71,73,77,81,85,87,90,93,95,96,97,98,100,102,104,105,107,111,112,114,115,116,119,120,122,123,125,127,131,134,135,140,141,144,146,151,152,153,157,159,164,165,166,176,177,182,184,185,188,190,192,194,195,198,204,205,206,215,217,218,219,220,221,247,251,252,258,265,267,272,278,279,281,285,298,299,308,310,312,316,317,319,321,322,324,326,328,329,330,331,334,337,341,344,357],number_of_dummi:267,number_tweet_output:120,numbertweetoutput:120,numer:[61,73,97,190,321],numpi:300,o_o:138,obelisk:232,obfusc:[205,206],obfuscate_languag:[205,206],obfuscate_whisp:[205,206],obj1:[11,43,80,97,109,159,203,221],obj2:[11,43,80,97,109,127,159,203,221,322],obj3:[11,43,109,159],obj4:11,obj5:11,obj:[2,6,10,11,22,25,27,31,33,41,42,43,48,56,58,59,60,80,82,84,86,87,89,91,96,102,109,112,115,117,119,121,125,127,139,144,152,153,154,157,159,165,167,169,170,176,180,182,187,188,189,192,194,195,198,199,203,206,215,217,218,219,220,221,226,232,233,235,241,242,246,247,252,256,257,258,296,298,299,306,316,317,318,319,322,324,325,329,339,340,341,344],obj_desc:220,obj_detail:233,obj_kei:220,obj_prototyp:252,obj_to_chang:125,obj_typeclass:220,objattr:[232,241],objclass:[334,344],object1:33,object2:[33,179,247],object:[0,2,9,10,12,13,14,15,18,19,21,22,23,26,29,30,31,33,34,36,38,39,40,41,42,44,45,46,47,49,50,51,52,53,55,56,57,58,62,69,73,74,77,79,81,83,84,85,86,87,88,91,93,95,102,103,104,107,108,109,110,114,115,116,117,118,120,122,123,125,127,129,132,133,134,135,137,138,139,140,141,142,143,144,146,147,148,150,151,152,153,154,156,157,158,159,160,161,164,165,166,167,169,170,171,175,176,177,178,179,180,181,182,186,187,188,189,192,193,194,195,196,198,199,203,204,206,209,210,211,212,213,214,215,217,218,219,220,221,223,226,229,230,231,233,234,235,238,239,241,242,249,250,251,252,253,256,257,258,259,260,261,265,267,269,271,272,273,274,276,277,280,281,282,283,284,285,286,287,289,291,294,296,298,299,305,306,307,308,310,311,312,316,317,318,319,321,322,323,324,325,326,327,328,329,330,334,335,338,339,340,341,342,343,344,345,349,351,357,360,364],object_from_modul:344,object_id:134,object_search:134,object_subscription_set:246,object_tot:317,object_typeclass:[342,360],objectcr:357,objectdb:[11,53,59,96,112,119,120,125,133,141,246,247,252,314,316,324,329,341],objectdb_set:[148,316,319],objectdbmanag:[245,246],objectdoesnotexist:[148,177,239,246,256,274,316,319,335],objectform:357,objectmanag:[245,247,317],objectnam:[6,58],objects_objectdb:86,objectsessionhandl:[2,247],objectupd:357,objid:80,objlist:109,objlocattr:[232,241],objmanip:[43,159],objmanipcommand:159,objnam:[27,43,125,159],objparam:252,objs2:112,objsparam:252,objtag:241,objtyp:176,obnoxi:269,obs:318,obscur:[48,72,82,205,206],observ:[13,14,20,43,81,88,159,165,187,206,223,233,291,322,344],obtain:[0,33,39,63,77,90,91,93,100,180,232],obviou:[0,59,61,103,121,128,138,190],obvious:[0,4,14,49,55,105,108,121,319],occaecat:52,occas:128,occasion:[90,119],occation:330,occur:[9,10,25,33,42,57,60,102,137,168,204,219,234,242,247,260,299,328,337],occurr:[46,91,123,321],ocean:[90,122],ocw:124,odd:[22,49,61,103,126],odor:58,off:[0,11,14,20,23,24,29,31,33,36,40,41,43,49,50,51,55,61,64,66,74,80,81,86,88,90,100,103,107,108,110,114,115,123,126,135,138,139,144,154,164,169,170,175,182,188,206,226,231,233,242,247,272,280,287,290,306,318,321,322,324,326,328,329,330,337,345],off_bal:29,offend:12,offer:[1,4,11,14,22,26,28,31,33,34,37,39,40,43,44,50,51,55,56,57,59,62,64,72,73,74,76,83,86,87,89,90,91,96,102,106,108,109,111,114,115,116,123,124,127,128,129,131,132,137,138,144,152,153,158,159,166,169,179,180,187,205,233,249,257,308,328],offernam:179,offici:[38,72,100,103,127,131,337],officia:52,offlin:[9,15,79,90,109,158,164,322],offscreen:9,offset:[206,326,337],often:[2,5,10,11,15,22,26,28,31,33,40,41,42,43,46,48,49,51,57,59,61,62,64,76,86,88,90,91,93,95,96,97,102,103,104,105,112,114,115,116,119,128,131,146,152,157,167,169,175,180,215,217,218,219,220,221,242,246,256,258,267,272,286,306,316,318,322,324,330,337,344],ohloh:37,okai:[41,42,48,49,51,58,75,77,111,123,128,198],olc:[43,47,159,249,252],olcmenu:249,old:[0,1,5,9,21,25,27,31,38,39,43,50,51,55,56,58,60,63,80,81,85,88,90,105,106,111,114,122,123,125,126,128,138,144,152,153,156,159,179,206,242,247,252,276,317,318,321,324,363],old_default_set:127,old_kei:[107,247],old_nam:107,older:[2,9,24,55,63,64,79,105,159],oldnam:318,oliv:114,omiss:60,omit:[91,100,109],on_:180,on_bad_request:269,on_ent:[22,180],on_leav:[22,180],on_nomatch:[22,180],onbeforeunload:[83,137],onbuild:100,onc:[0,2,5,6,9,10,13,16,21,22,23,25,33,34,37,38,39,40,41,42,43,46,47,49,51,55,57,58,60,61,62,63,64,67,72,79,80,83,85,89,90,93,95,96,97,100,102,105,108,114,116,119,121,122,125,126,128,131,133,137,144,146,151,154,159,164,167,170,175,179,180,188,189,195,199,203,205,212,215,217,218,219,220,221,223,226,231,232,233,234,235,247,251,256,259,272,277,290,294,305,316,321,328,329,337,342,344],onclos:[40,278,295],onconnectionclos:[83,137],oncustomfunc:83,ond:319,ondefault:83,one:[0,1,2,3,4,5,9,10,11,12,13,14,15,16,19,20,21,22,23,25,26,27,28,29,31,33,34,35,36,37,38,41,42,43,44,46,47,48,49,50,51,52,54,55,56,57,58,59,60,61,62,63,64,65,67,68,69,70,72,73,74,76,77,79,80,81,82,83,85,86,87,88,89,90,91,92,93,95,96,97,98,100,102,103,104,105,106,108,109,111,112,113,114,115,116,118,119,121,122,123,125,126,127,128,131,132,133,134,135,136,137,138,140,143,144,148,151,152,153,154,156,157,159,164,165,168,169,170,175,176,177,179,180,182,185,187,189,195,198,199,204,205,206,214,215,217,218,219,220,221,226,230,232,233,234,235,238,239,241,242,246,247,249,250,251,252,256,261,267,269,271,272,277,278,279,287,290,291,299,306,307,308,312,314,316,317,318,321,322,324,325,327,328,329,330,331,334,335,337,339,340,341,342,344,345,357,360],ones:[4,9,14,20,22,27,31,33,57,58,65,72,74,80,81,83,90,95,100,103,109,114,116,126,127,135,152,153,154,177,180,195,217,218,219,220,221,251,252,271,276,308,321,330,338],onewai:[43,159],ongo:[28,91,116,179,213],ongotopt:[83,137],onkeydown:[83,137],onli:[0,2,4,5,6,9,10,11,12,13,14,15,19,20,21,22,24,25,26,27,28,29,31,33,34,37,39,40,41,42,43,44,46,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,67,68,69,71,72,73,74,77,79,80,81,82,83,85,86,87,88,89,90,91,93,95,96,100,102,103,104,105,106,107,109,111,112,114,116,117,118,119,121,122,123,124,125,126,127,130,131,132,133,134,135,136,137,138,140,141,144,146,150,151,152,153,154,156,157,158,159,164,165,166,167,168,169,170,175,176,177,179,180,181,182,185,187,188,190,195,199,205,206,214,215,217,218,219,220,221,223,232,233,234,235,239,241,242,247,251,252,256,259,260,261,267,271,272,279,282,284,285,287,290,299,305,306,308,310,311,312,316,317,318,319,321,322,323,324,326,328,329,330,334,337,339,340,341,342,344,357],onlin:[7,12,15,21,37,41,43,55,57,58,60,61,64,65,68,69,70,71,73,77,79,89,96,98,101,104,108,116,123,128,129,139,141,156,164,175,180,188,281,322,364],onloggedin:[83,137],onlook:247,only_tim:341,only_valid:252,onmessag:[40,278,295],onopen:[40,278,295],onoptionsui:137,onprompt:[83,137],onsend:[83,137],onset:[5,11],onsil:83,ontabcr:137,ontext:[83,137],onto:[25,31,33,44,55,60,61,72,90,95,121,137,153,164,233,246,279,325,328],onunknowncmd:137,onward:107,oob:[24,30,33,45,83,104,137,138,139,144,146,166,189,247,272,290,291,295,296,308,328,364],oobfunc:104,oobhandl:334,oobobject:102,ooc:[2,53,58,102,105,114,123,144,148,156,159,160,167,177,181,199,247],ooccmdsetchargen:181,ooclook:[105,181,329],opaqu:[15,103],open:[0,3,4,5,9,20,22,23,26,31,34,37,38,42,46,50,55,57,58,60,63,64,65,67,69,70,71,72,73,75,79,80,90,95,96,103,105,106,111,114,116,123,130,131,133,134,138,159,166,169,179,180,188,212,213,221,226,232,310,316,324,337,344,363],open_parent_menu:180,open_submenu:[22,180],open_wal:232,openhatch:79,opensoci:70,opensourc:321,oper:[9,11,12,14,22,27,33,41,42,43,46,51,57,59,60,61,63,64,67,72,74,80,82,88,89,90,95,96,97,102,109,110,112,115,119,124,126,131,137,139,144,150,152,154,156,159,164,169,170,175,180,185,206,232,242,247,252,261,264,267,276,277,281,283,287,289,290,296,298,299,306,307,316,317,318,321,324,328,329,330,334,344,364],opic:170,opinion:[1,48],opnli:316,oppon:[11,73,218,220,231],opportun:[0,4,22,91,133,221],oppos:[27,89,103,110,114,306,319],opposit:[41,43,58,111,121,159,226],opt:[58,137,234],optim:[23,27,33,34,39,56,64,86,93,115,119,154,175,251,252,302,305,316],option100:51,option10:51,option11:51,option12:51,option13:51,option14:51,option1:51,option2:51,option3:51,option4:51,option5:51,option6:51,option7:51,option8:51,option9:51,option:[2,4,7,8,10,11,17,20,23,24,25,27,29,31,33,34,36,38,41,42,47,50,54,55,57,62,63,64,74,76,79,80,81,83,85,86,88,96,100,102,104,106,108,109,111,112,113,114,116,117,123,127,129,133,134,135,137,138,139,141,144,146,150,151,152,153,154,156,157,159,164,166,167,170,175,176,177,179,180,181,182,184,185,187,188,189,190,192,194,195,199,203,204,205,206,214,215,219,221,226,230,233,234,235,238,241,242,246,247,249,251,252,256,257,258,259,260,261,264,265,267,269,272,273,276,277,280,281,282,283,284,285,286,287,289,290,291,294,295,296,298,299,306,308,310,316,317,318,319,321,322,323,324,326,327,328,329,330,331,334,337,338,339,340,341,343,344,345,349,350],option_class:[141,323],option_dict:328,option_gener:328,option_kei:345,option_str:234,option_typ:339,option_valu:339,optiona:[144,264,318],optionalposit:1,optionclass:[141,142,320,323],optioncontain:323,optionhandl:[141,142,320,338],optionlist:[51,230,249,328],options2:137,options_dict:339,options_formatt:[51,188,230,249,328],optionsl:251,optionslist:230,optionstext:[51,188,328],optlist:215,optlist_to_menuopt:215,optuon:205,oracl:[23,344],orang:[114,203,234,321],orc:[57,61,109,117],orc_shaman:109,orchestr:100,order:[0,2,5,6,9,10,11,13,14,22,27,31,33,36,37,39,43,44,49,50,51,58,60,61,62,63,64,68,69,70,71,80,84,87,89,93,100,102,104,109,111,113,114,116,119,121,122,123,126,127,128,131,133,134,136,137,138,144,150,153,154,160,165,166,169,170,179,180,181,182,183,185,188,203,204,206,217,218,219,220,221,231,232,233,234,241,242,247,252,278,290,295,299,306,316,318,321,322,328,329,330,337,341,344],order_bi:119,order_clothes_list:182,ordered_clothes_list:182,ordered_permutation_regex:206,ordered_plugin:83,ordereddict:[11,344],ordin:321,org:[37,38,90,204,234,283,289,295,321,344,357],organ:[5,6,9,22,69,73,80,89,102,108,111,112,119,124,129,131,132,154,166,170],organiz:102,orient:[55,57,64,96,124],origin:[0,4,9,21,25,29,41,43,49,51,55,57,60,75,76,79,81,89,91,96,102,103,105,106,119,131,136,138,144,146,152,159,180,199,205,206,234,247,251,252,276,310,318,321,328,340,343,344,363],ormal:321,oscar:[175,239,318],osnam:344,oss:106,ostr:[144,176,238,341],osx:[63,131],other:[0,1,2,4,5,6,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,25,27,28,29,31,34,36,37,38,39,40,41,43,44,46,47,48,49,50,51,53,55,57,58,59,60,61,62,63,64,65,68,69,70,71,73,74,76,80,81,82,83,85,86,87,88,89,91,95,96,97,100,102,103,105,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,123,124,125,126,127,128,131,133,134,135,136,137,138,139,140,144,150,151,152,153,154,159,164,165,166,167,170,171,175,176,179,182,184,186,188,194,199,205,206,210,212,215,217,218,219,220,221,226,233,234,235,239,242,246,247,251,252,257,259,261,265,271,272,276,278,279,285,287,290,299,306,307,309,316,318,320,321,322,324,326,327,328,329,330,338,339,341,344,345],otherroom:212,otherwis:[0,4,11,15,23,25,27,29,31,33,37,39,41,42,43,51,59,62,68,69,76,78,83,86,89,90,91,95,97,100,102,103,105,109,114,121,123,131,135,141,151,152,156,159,164,175,179,183,187,188,192,195,206,217,218,219,220,221,235,242,247,250,251,252,260,267,278,279,287,306,310,311,321,328,329,337,341,342,344],our:[2,3,4,8,9,11,14,16,20,21,23,25,26,30,31,33,36,37,38,39,40,41,42,43,44,46,49,55,57,58,59,60,61,62,63,64,67,70,72,73,75,77,78,79,80,81,82,83,85,88,90,91,98,100,101,103,111,115,116,117,119,123,124,127,128,129,131,132,134,135,136,137,138,140,148,153,167,187,215,231,232,235,242,257,312,337,363],ourself:123,ourselv:[0,20,58,80,87,118,132,138,144,181,280,281,283,294],out:[0,1,3,6,8,9,10,12,13,14,15,16,17,19,20,21,22,23,26,28,29,33,34,37,38,39,41,42,43,44,45,46,47,48,49,51,53,54,55,56,57,59,60,61,62,63,64,66,69,70,71,77,79,80,86,88,89,90,91,93,95,96,97,100,102,104,105,108,109,111,114,116,117,118,119,121,122,123,126,127,129,131,133,135,137,138,139,143,144,151,152,156,158,159,164,179,181,184,186,188,199,205,206,209,210,212,213,217,218,219,220,221,230,232,251,252,259,267,269,291,295,296,298,307,308,316,325,327,328,330,343,344,357],outcom:[38,73,86,152,185,242,247,251],outdat:8,outdata:[40,308],outdoor:[112,119,122,132,233],outer:330,outermost:[11,29,74],outerwear:182,outfunc_nam:40,outgo:[67,88,90,96,105,146,247,279,291,307,344],outgoing_port:90,outlet:90,outlin:[36,43,111,133,278],outmessag:247,output:[4,14,20,22,26,27,34,40,43,51,52,58,74,79,88,91,95,96,100,105,106,108,110,111,113,114,116,120,121,123,126,128,129,135,137,138,141,142,154,159,164,166,169,170,178,180,184,189,207,208,210,217,218,219,220,221,267,272,287,291,299,306,321,328,329,337,340,344],outputcmd:291,outputcommand:[74,83],outputfunc:[40,59,83,247,272,278],outputfunc_nam:[40,272],outputfunct:83,outrank:317,outright:[12,90,363],outro:[122,233],outroroom:233,outsid:[0,13,15,20,21,38,39,57,64,67,73,88,96,100,104,108,109,110,112,121,134,166,204,220,231,241,291,306,307,316,319,330],outtempl:316,outtxt:27,outward:[49,90],over:[1,6,8,11,13,14,15,16,17,27,28,31,33,34,36,37,38,39,40,43,45,48,49,51,54,57,58,59,60,61,73,77,81,83,85,88,90,93,96,97,100,103,105,108,111,112,113,114,115,116,118,119,125,126,127,128,129,133,136,137,138,144,153,176,188,212,215,217,218,219,220,221,233,261,271,285,287,290,292,296,298,300,313,318,322,334,340,363],overal:[10,56,57,68,71,86,90,152,167,218],overcom:111,overhead:[23,27,34,113,132,206,235,316],overhear:205,overlap:[31,62,205,321,330],overload:[5,22,30,31,33,40,44,47,51,55,57,60,74,76,89,96,97,104,114,115,117,123,136,144,152,154,168,175,180,181,187,189,203,206,212,213,217,218,219,220,221,230,231,232,233,234,247,252,261,271,290,298,307,326,328,329,330,338],overrid:[1,3,4,9,20,21,22,25,31,36,43,51,53,54,68,69,80,83,91,96,102,105,107,109,117,118,121,135,136,137,144,154,159,164,166,170,175,176,180,187,195,205,219,221,233,234,242,247,252,259,290,308,312,316,321,328,329,334,337,338,341],overridden:[4,40,96,136,138,144,159,180,234,329],override_set:107,overriden:[144,166,206],overrod:16,overrul:[2,80,144,153,206,247,330],overseen:73,overshadow:61,overshoot:344,oversight:57,overview:[15,16,18,23,45,46,57,68,77,96,103,139,364],overwhelm:[46,61],overwrit:[5,43,76,136,138,159,166,285,317],overwritten:[33,134,233,319],owasp:357,own:[1,3,4,5,6,8,9,10,11,13,17,19,20,21,22,25,26,27,29,30,31,34,37,38,41,43,45,47,51,55,57,61,62,63,64,67,68,71,72,75,76,77,78,80,81,83,85,86,87,88,91,93,95,96,98,101,102,103,104,105,107,108,109,111,112,114,119,121,122,123,124,125,127,128,129,131,132,133,134,135,136,138,139,148,150,151,152,153,159,164,167,182,184,187,188,199,205,206,210,217,218,219,220,221,232,234,235,241,242,247,252,272,299,307,318,321,322,323,329,330,334,337,338,342,344,364],owner:[4,19,80,85,144,242,338],owner_object:80,ownership:[90,100],p_id:133,pace:[122,231],pack:[83,276],packag:[8,9,23,41,47,63,64,72,75,78,88,90,93,96,97,100,108,127,128,135,141,143,149,155,172,178,229,236,240,243,253,262,267,276,291,295,314,320,346],package_nam:64,packagenam:64,packed_data:276,packeddict:[97,318],packedlist:[97,318],packet:[83,287],pad:[17,114,321,330,344],pad_bottom:330,pad_char:330,pad_left:330,pad_right:330,pad_top:330,pad_width:330,page:[7,8,9,12,13,14,16,17,20,21,23,25,26,28,31,33,36,37,38,40,45,48,51,52,55,57,58,59,60,61,64,67,70,72,73,75,76,77,79,80,81,88,89,90,94,96,99,100,101,103,104,106,108,110,124,125,126,127,129,130,131,133,134,137,138,139,164,165,175,239,251,296,318,328,329,344,346,347,355,361,363,364],page_back:329,page_ban:164,page_end:329,page_formatt:[251,329],page_next:329,page_quit:329,page_top:329,pageno:[251,329],pager:[52,139,329],pages:[51,328],pagin:[251,329],paginag:329,paginated_db_queri:251,paginator_django:329,paginator_index:329,paginator_slic:329,pai:[56,85,90,103,232],paid:90,pain:[90,138],painstakingli:13,pair:[31,83,116,137,138,144,152,182,241,247,308,357],pal:87,palett:126,pallet:111,palm:188,pane:[43,88,137,138,171,186,230],panel:[67,106],panic:109,paper:[61,79,116],paperback:73,par:23,paradigm:[9,61,118,218],paragraph:[14,27,38,202,322,330,344],parallel:[57,62,69,317],paralyz:219,param:[67,159,247,261,269,279,312,343],paramat:[144,154,247,306],paramet:[0,22,24,31,36,39,42,46,49,62,91,100,106,119,127,141,144,146,150,151,152,153,154,159,164,166,170,175,176,177,179,180,182,184,185,187,188,189,190,192,193,194,195,198,199,204,205,206,209,210,212,215,217,218,219,220,221,226,230,233,234,235,238,239,242,246,247,249,251,252,257,258,259,260,261,264,265,266,267,269,271,272,273,274,276,277,278,279,280,281,282,283,284,285,286,287,289,290,291,292,294,295,296,298,304,305,306,307,308,310,311,312,316,317,318,319,321,322,323,324,325,326,327,328,329,330,331,334,337,338,339,341,342,343,344,345,349],paramount:127,paramt:345,paremt:252,parent1:109,parent2:109,parent:[2,6,22,25,27,31,33,38,40,43,44,60,64,81,89,96,109,114,118,121,123,125,140,148,156,159,167,169,180,206,215,234,246,247,251,252,256,316,317,318,326,335,337,344],parent_categori:215,parent_kei:[22,180],parenthes:95,pari:[79,90],pariatur:52,paricular:33,park:180,parlanc:3,parri:[116,232],parrot:118,pars:[3,15,31,33,38,40,43,50,51,63,81,83,88,97,104,108,109,114,123,124,129,134,139,149,150,151,154,159,165,166,167,169,170,179,180,185,186,187,199,206,209,210,211,215,226,232,233,234,242,247,250,251,252,272,279,282,291,295,296,298,308,316,321,322,326,327,328,343,344,364],parse_ansi:321,parse_ansi_to_irc:279,parse_fil:322,parse_html:343,parse_input:328,parse_irc_to_ansi:279,parse_languag:206,parse_menu_templ:[51,328],parse_nick_templ:316,parse_opt:215,parse_sdescs_and_recog:206,parseabl:251,parsed_str:279,parseerror:234,parser:[33,41,47,79,104,108,109,134,150,151,156,159,166,167,169,186,187,203,205,206,232,233,234,251,286,321,343],parsingerror:344,part1:203,part2:203,part:[1,4,5,9,11,13,14,15,16,20,22,23,26,29,33,36,37,38,39,40,41,42,44,45,46,48,49,51,57,58,60,61,68,69,70,73,76,80,85,86,88,90,91,92,95,102,105,106,111,114,116,117,119,122,123,124,125,127,131,135,136,137,138,139,140,151,152,154,164,167,168,170,175,179,180,185,203,206,215,220,226,233,238,241,242,250,251,259,267,271,296,298,307,310,312,316,317,321,322,326,328,344,364],part_a:179,part_b:179,parth:292,parti:[8,9,13,23,27,37,42,64,72,75,90,101,114,128,134,177,179,185],partial:[25,68,164,166,205,251,269,282,308,339,341,344,345],particip:[41,103,217,218,219,220,221],particular:[5,8,12,13,14,20,22,28,31,38,40,41,43,44,48,58,59,64,68,70,72,74,75,79,80,83,85,88,89,93,96,97,104,105,107,112,113,114,118,119,121,124,125,131,132,135,139,144,151,152,159,176,187,210,219,220,238,241,242,256,308,310,318,334,341],particularli:[0,4,12,38,39,51,55,127,154,167,170,206,252,271],partit:321,partli:[11,31,47,86,129,152],party_oth:179,pass:[4,10,21,23,25,27,28,29,30,33,36,40,43,49,51,52,62,69,74,80,82,83,85,88,90,91,95,96,100,102,105,107,109,110,111,115,117,119,121,125,127,130,134,138,139,144,146,152,164,170,171,175,182,184,185,188,189,194,209,210,212,215,217,218,219,220,221,226,232,241,242,247,250,251,257,260,261,265,277,285,287,290,295,296,306,312,316,318,327,328,329,330,337,338,339,340,343,344],passag:[83,116,182,232,233,331],passant:126,passavataridterminalrealm:287,passiv:[29,116,133],passthrough:[1,31,259],password1:357,password2:357,password:[4,9,12,23,35,36,51,64,74,80,103,131,139,144,156,157,171,186,204,210,272,287,290,311,324,349,357],password_chang:360,passwordresettest:360,past:[0,13,20,26,37,46,50,58,62,69,96,104,108,111,116,123,133,137,219,313,322,331],pastebin:37,patch:[125,342],path:[0,2,4,8,14,20,21,22,27,29,38,39,40,43,45,48,51,59,60,63,64,66,67,69,74,80,85,86,88,89,90,95,96,100,102,105,106,109,114,117,118,119,121,123,124,125,134,135,136,138,139,144,146,148,151,152,153,158,159,160,161,162,163,164,169,175,177,179,180,181,182,184,185,187,189,195,198,203,204,205,206,212,213,214,217,218,219,220,221,223,226,230,231,232,233,235,239,246,247,251,252,256,258,259,261,267,274,276,285,292,298,300,304,308,312,316,317,318,322,324,326,327,328,329,331,334,335,341,344],path_or_typeclass:198,pathnam:342,patient:[20,70],patreon:70,patrol:231,patrolling_pac:231,patron:[37,70],pattern:[3,4,16,51,69,87,127,133,134,135,140,157,206,311,316,344],pattern_is_regex:316,paul:125,paus:[10,39,46,51,100,102,110,116,169,170,194,259,260,328,344],pausabl:344,pauseproduc:269,paxboard:79,payload:[278,295],paypal:[37,70],paypalobject:70,pdb:[139,141],pdbref:[80,241],pdf:79,peac:117,peek:[20,26,51,91],peer:[278,295],peform:272,peg:103,pem:67,pemit:[43,108,157],penalti:[86,219],pend:312,pennmush:[57,108,129],pentagon:103,peopl:[2,20,21,26,37,43,54,55,58,61,64,68,71,72,73,79,80,81,85,90,95,96,97,103,108,114,116,119,139,164,165,186,206,232,233,324],pep8:26,per:[2,4,11,19,33,38,41,47,51,58,60,62,64,69,83,86,89,93,100,105,109,112,116,119,123,138,144,164,187,205,217,218,219,220,221,231,251,280,281,283,291,294,310,328,329,330,334,337,338],perceiv:62,percent:[33,344],percentag:[116,317,344],percentil:344,perception_method_test:303,perfect:[50,55,61,75,100,131],perfectli:[4,69,96,112,129,138,321],perform:[11,13,14,22,23,25,39,41,42,43,51,52,55,59,71,74,75,80,89,91,93,97,102,103,114,116,117,123,133,134,144,150,152,156,159,164,166,180,182,188,194,195,206,209,215,217,218,219,220,221,247,251,256,257,276,290,298,299,316,317,318,325,328,329,338,341,344,345,357],perhap:[16,22,42,46,62,69,77,91,97,108,138],period:[90,95,96,100,103,127,128,130,344],perist:[34,125],perm:[4,11,12,19,22,25,33,58,68,71,80,85,109,112,123,133,148,157,158,159,164,165,166,169,187,193,203,212,233,239,241,242,246,247,256,316,318],perm_abov:[80,241],perm_us:157,perman:[4,5,12,21,24,25,31,43,51,85,90,96,122,123,138,144,152,153,156,159,164,165,169,205,247,260,318],permiss:[2,4,7,8,9,11,12,18,20,21,23,25,31,41,43,45,66,68,70,71,75,93,108,109,123,133,139,144,147,148,152,154,156,157,158,159,164,165,167,175,193,206,221,239,241,242,246,247,251,252,256,316,317,318,319,322,324,337,341,364],permission_account_default:[80,298],permission_func_modul:241,permission_guest_default:66,permission_hierarchi:[19,80,241,242],permissionerror:251,permissionhandl:[133,319],permit:[41,78,159,311],permstr:[80,144,318,324],permut:206,perpetu:93,persis:29,persist:[0,6,21,22,27,31,33,34,43,51,55,56,57,60,64,79,84,86,89,102,104,105,109,110,115,116,121,123,125,144,148,153,159,169,177,180,184,188,195,205,206,213,215,217,218,219,220,221,226,230,232,239,246,247,249,251,256,257,259,260,261,272,273,274,305,306,310,314,318,324,326,328,330,331,344],person:[12,21,43,61,63,70,73,90,102,105,118,129,139,144,159,164,165,175,179,185,206],persona:96,perspect:[73,76,77,105],pertain:[103,126,136,350],pertin:[68,133],perus:137,peski:85,pester:[57,61],phase:[49,61],philosophi:80,phone:[16,64,75,139,204],phone_gener:204,phonem:205,php:[108,357],phrase:[46,198],phrase_ev:198,physic:[2,49,220,231],pick:[6,9,13,15,20,21,31,33,35,37,39,43,51,55,62,68,72,73,80,85,90,95,96,100,102,104,106,111,119,132,151,156,159,165,167,182,190,206,221,232,233,247,251,299],pickl:[11,29,83,115,257,261,264,274,276,277,316,317,325,326,328,340,344],pickle_protocol:340,pickledfield:340,pickledformfield:340,pickledobject:340,pickledobjectfield:340,pickledwidget:340,picklefield:[141,142,320],pickpocket:[43,166],pickup:[221,247],pictur:[21,40,57,106,138],pid:[36,80,100,110,131,133,241,247,267,277,344],piddir:36,pidfil:267,piec:[10,13,59,61,64,93,122,203,294,322,329],pierc:232,piggyback:144,pile:[153,322],pillow:75,ping:[146,164,267,279],pink:[119,321],pip:[9,23,26,38,42,47,59,63,65,71,75,93,96,97,98,100,127,128,130,133,141],pipe:[105,279,325],pitfal:[14,26,114,126],pixel:24,pizza:[148,177,239,246,256,316,318,319],pkg:75,pki:8,place:[0,2,3,4,5,8,9,11,14,15,20,21,25,26,30,37,38,41,43,46,49,51,55,62,63,64,69,71,73,75,76,80,83,89,90,91,95,96,100,102,103,104,105,109,111,121,123,124,126,128,129,131,132,133,135,136,138,144,157,159,165,175,179,180,182,184,188,203,206,209,217,218,219,220,221,226,232,233,235,247,259,276,285,290,306,307,308,316,322,323,325,328,344],placehold:[134,242,247,330],plai:[0,2,11,14,19,22,29,39,46,55,58,61,64,68,73,75,81,83,90,91,95,105,111,114,116,121,122,123,124,132,133,138,144,217,221,291,308,324],plain:[13,14,38,58,86,88,123,164,175,179,180,202,252,272,298,325],plaintext:210,plan:[9,14,15,40,41,42,45,55,56,90,96,100,124,125,127,139,322,364],plane:121,planet:[62,79],plant:234,plate:[82,125,204],platform:[9,16,56,63,90,102,106,131],playabl:[133,360],player1:247,player2:247,player:[9,10,11,12,19,20,21,22,25,29,31,34,40,41,43,51,53,54,55,58,60,61,64,65,68,71,73,77,80,81,83,85,90,91,93,95,97,98,105,108,110,111,112,113,116,117,118,119,120,121,122,123,124,133,138,139,153,156,159,164,169,176,179,180,188,190,198,199,203,205,206,210,214,215,220,221,226,233,234,235,238,256,281,290,307,322,327,328,344,357],playernam:71,playerornpc:9,pleas:[4,5,8,16,17,26,31,37,43,51,63,70,71,72,75,78,90,93,109,111,114,117,118,120,124,125,127,131,133,169,269,298,334,340,357,363],pleasur:16,plenti:[14,55,60,129],plot:300,plu:[22,27,43,64,73,106,169],pluck:33,plug:[96,103,107,136,235],plugin:[4,40,45,47,53,55,72,79,83,104,108,138,206,265,364],plugin_handl:[83,137],plugin_manag:137,plural:[19,58,80,220,247],png:[70,136],po1x1jbkiv:37,pocoo:344,point:[0,2,4,5,8,13,14,15,20,21,22,25,27,29,31,33,34,36,37,38,39,42,43,49,51,55,56,60,61,62,63,67,69,73,75,81,83,85,86,88,89,90,91,93,95,97,100,102,104,105,106,112,113,115,116,121,123,125,127,130,131,133,134,135,136,138,139,144,150,154,159,164,167,169,179,189,206,212,217,233,234,235,247,249,251,261,267,271,285,287,295,306,308,316,318,322,328,344,347],pointer:[26,49,56,91],pointless:[6,10,89,115,166],poison:[219,252],poke:119,pole:203,polici:[43,45,90,103,139,210,239,311,316],polit:103,poll:[40,136,156,231,267,296],pong:279,pool:[23,31,115,261,312,325],poor:[48,58],poorli:103,pop:[10,23,25,38,48,58,85,106,138],popen:277,popul:[22,23,36,41,57,61,62,81,124,135,138,152,160,161,162,163,180,182,187,203,206,214,217,218,219,220,221,226,230,231,232,233,260,261,298,322,326,327,329],popular:[9,57,64,79,103,108],popup:[137,138],port:[0,8,9,23,36,43,54,55,63,67,72,100,101,110,146,164,276,279,287,299,308,312],portal:[40,43,45,47,53,79,88,89,90,93,103,104,106,110,121,128,137,139,141,142,146,169,183,262,264,267,305,306,307,308,331,337,344,364],portal_connect:308,portal_disconnect:308,portal_disconnect_al:308,portal_l:277,portal_pid:[277,344],portal_receive_adminserver2port:277,portal_receive_launcher2port:277,portal_receive_server2port:277,portal_receive_statu:277,portal_reset_serv:308,portal_restart_serv:308,portal_run:267,portal_service_plugin_modul:40,portal_services_plugin:[40,104],portal_services_plugin_modul:40,portal_sess:40,portal_session_sync:308,portal_sessions_sync:308,portal_shutdown:308,portal_st:267,portal_uptim:331,portallogobserv:337,portalsess:[40,105,285],portalsessiondata:308,portalsessionhandl:[40,141,142,262,275,286,308],portalsessionsdata:308,portion:[77,180,190],pose:[29,58,116,144,165,195,206,226],pose_transform:175,posgresql:23,posit:[13,20,22,39,49,51,91,111,116,126,127,137,138,139,153,171,180,186,202,221,232,233,234,235,247,260,321,322,325,326,330,344,345],positive_integ:345,positiveinteg:338,posix:[337,344],possess:[7,77,189],possibl:[0,5,9,10,11,22,23,25,26,31,33,34,37,38,39,43,46,50,55,57,58,63,64,66,73,74,75,76,80,91,93,100,102,104,105,109,111,112,114,116,123,126,127,128,131,134,136,138,141,144,148,150,152,159,166,167,179,187,194,203,205,206,214,231,233,235,242,247,250,251,252,257,261,272,292,296,306,308,316,317,319,321,324,326,327,328,330,340,341,344],post:[5,31,34,37,55,57,58,61,63,69,70,71,80,98,107,111,120,133,136,210,259,296],post_delet:107,post_init:107,post_join_channel:175,post_leave_channel:175,post_migr:107,post_sav:107,post_send_messag:175,post_text:190,postfix:205,postgr:[23,64],postgresql:[55,344],postgresql_psycopg2:23,postinit:[83,137],posttext:188,postupd:[71,120],pot:12,potato:[24,234],potenti:[10,11,13,26,41,82,83,90,98,111,114,116,123,154,176,210,211,241,242,247,251,338,341,344],potion:[77,318],power:[15,19,20,29,30,31,33,42,43,46,50,51,55,56,58,61,64,80,89,96,109,111,116,122,123,137,138,152,153,158,159,215,220,234,322,328,344],powerfulli:0,pperm:[12,41,43,71,80,133,156,164,203,241,247],pperm_abov:241,pprofil:267,pprogram:267,practial:15,practic:[0,13,14,22,26,29,33,34,36,37,57,58,63,64,70,80,89,90,96,105,109,119,124,126,131,139,322,364],pre:[33,43,47,49,54,61,63,71,89,90,111,114,138,144,159,166,205,242,247,251,252,295,296,299,326,340],pre_delet:107,pre_init:107,pre_join_channel:175,pre_leave_channel:175,pre_migr:107,pre_sav:[107,340],pre_send_messag:175,pre_text:190,preced:[19,31,41,96,109,114,119,152,154,215,247,252,317,330],precend:150,precis:[11,96,126,321],predefin:[121,311],predict:[125,133],prefac:119,prefer:[21,22,23,31,37,43,47,55,57,71,80,90,91,96,106,109,111,123,131,137,138,152,154,157,180,206,218,231,238,247],prefix:[20,22,23,42,76,86,97,103,125,144,151,168,175,190,205,272,279,310,321,337,341,344,357],prefix_str:25,prematur:[27,93,179],prepai:90,prepar:[3,49,57,87,109,127,136,144,164,206,217,218,219,220,221,231,256,325,340,363],prepars:38,prepend:[199,206,247,321,322,328,344],preprocess:159,prerequisit:[9,36],prescrib:[55,57],preselect:138,presenc:[9,17,23,55,56,90,122,124,126,136,144,247,312,346],present:[1,4,8,22,42,46,48,49,51,62,69,77,85,91,96,97,104,105,116,123,131,138,180,188,190,204,205,214,215,234,252,326,344],preserv:[126,167,318,321,322,337,344],press:[9,14,15,22,26,31,33,42,51,63,80,83,88,95,96,100,106,110,180,226,232,265,328],pressur:82,presto:20,presum:[62,73,153,337,338],pretend:75,pretext:188,pretti:[0,22,25,26,37,38,39,41,60,64,67,72,85,88,89,90,116,121,123,126,131,133,138,154,175,182,204,236,242,251,327,329,338,344],prettier:[0,357],prettifi:[57,344],prettili:62,pretty_corn:330,prettyt:[27,330],prev:[51,329],prev_entri:51,prevent:[11,20,33,38,46,62,95,194,221,234,310,329],preview:38,previou:[0,10,11,14,16,22,29,31,33,41,42,51,52,58,60,62,69,80,85,86,87,91,95,96,100,104,107,114,119,123,126,164,215,233,249,328,337],previous:[20,31,34,43,49,50,67,72,74,91,102,104,114,119,127,133,136,154,157,159,164,175,179,272,288,292,299,308,319,344],prgmr:90,price:[90,232],primari:[17,100,125,133,206,247,316,341],primarili:[2,12,34,36,37,55,61,108,144,179,206,238,285,325,344],primarli:38,primary_kei:133,prime:[150,179],primit:[43,61,159],princess:[111,122],principl:[2,9,19,26,30,33,37,38,40,43,51,55,57,60,80,85,89,90,96,98,119,123,132,138,153,156,179,233],print:[4,9,10,11,21,25,26,27,40,42,43,50,51,58,59,83,86,91,95,96,97,110,113,125,156,185,205,234,251,266,267,327,328,329,330,337,344],print_debug_info:328,print_help:234,print_usag:234,printabl:293,printout:290,prio:[25,31,33,150,233],prior:[117,194,247],priorit:205,prioriti:[4,25,31,33,44,51,97,116,152,156,160,161,162,163,167,180,230,232,233,247,326,328,329],privat:[4,8,38,43,57,61,69,90,131,164,165,279,292],private_set:9,privatestaticroot:312,privileg:[21,23,43,60,63,65,72,98,123,165,206,235,247,318],privkei:67,privkeyfil:287,privmsg:279,prize:122,proactiv:115,probabl:[4,5,11,16,21,22,23,25,29,33,37,46,48,51,55,57,61,64,67,69,85,86,89,90,96,108,116,119,121,128,133,134,136,138,166,180,198,204,233,269,279,287,334,344,345],problem:[11,13,15,21,22,23,24,25,26,27,36,38,43,56,61,64,69,70,75,77,80,90,95,97,100,103,110,111,113,127,138,140,144,153,195,247,276,322],problemat:[25,344],proce:[14,15,100,121,126,164,294],procedud:51,procedur:[138,215,287,290],proceed:[131,344],process:[0,4,8,9,11,13,14,15,22,23,25,29,33,36,38,39,41,42,43,49,51,55,59,61,64,67,73,75,76,83,88,89,90,91,92,93,100,106,122,131,133,138,139,144,150,152,159,169,175,179,206,215,234,240,242,247,251,257,260,267,272,276,277,284,287,290,295,296,299,305,306,308,316,321,322,325,328,338,343,344,345,364],process_languag:206,process_recog:206,process_sdesc:206,processed_result:344,processor:[18,43,93,110,111,124,139,141,142,158,169,320,364],procpool:344,produc:[33,43,51,96,114,123,131,156,159,203,205,232,235,247,251,252,266,298,316,318,327,328,344],produce_weapon:232,producion:27,product:[23,26,36,90,93,103,106,128,131,135,298,301,328],production_set:9,prof:93,profession:[3,57,64,108],profil:[45,65,139,141,142,148,188,262,364],profile_templ:188,profit:138,profunc:109,prog:234,progmat:56,program:[2,10,15,23,43,53,56,57,63,64,67,70,75,77,79,86,90,92,93,95,96,100,103,106,108,110,114,124,127,128,169,234,262,267,290,296,298],programm:[91,95],programmat:[114,138],progress:[70,73,79,85,131,217,218,219,220,221,326,364],proident:52,project:[4,15,25,37,49,64,70,72,77,79,91,99,108,111,124,127,131,135,136,338],projectil:220,promis:26,promisqu:126,prompt:[9,12,23,24,26,42,54,63,64,75,83,88,96,100,111,124,125,137,139,154,170,215,265,279,290,295,296,322,328,364],promptli:14,prone:[1,128,153,318],pronoun:189,prop:61,propag:[8,152,271,340],proper:[15,21,23,27,36,39,43,44,56,57,61,64,85,91,96,100,103,116,123,127,131,133,135,137,138,159,170,179,180,196,205,327],properli:[9,29,58,62,69,84,106,108,117,125,126,127,128,131,133,140,154,179,211,233,241,260,261,287,344],properti:[5,6,13,22,25,39,43,53,55,56,57,59,61,68,73,80,81,84,86,87,96,97,104,109,110,111,115,116,119,121,123,126,127,144,146,148,154,156,159,167,169,170,175,177,180,188,194,203,206,215,217,219,220,221,226,231,232,233,234,235,239,241,242,246,247,251,252,256,258,259,260,272,274,279,285,298,299,306,307,308,316,318,319,323,325,328,338,339,340,341,344,357],propnam:123,propos:[50,138],proprietari:23,propval:123,propvalu:123,prosimii:[133,134],prospect:61,prot:252,prot_func_modul:[109,250],protect:[6,31,43,90,159,226],protfunc:[141,142,248,251,252],protfunc_callable_protkei:250,protfunc_modul:251,protfunc_pars:251,protfunct:251,protkei:[109,250,251],proto:[276,287],proto_def:203,protocol:[24,27,33,43,47,53,64,72,74,79,83,90,92,101,103,104,105,110,137,139,144,146,154,157,189,210,247,262,264,267,269,272,276,277,278,279,280,281,282,283,285,286,287,289,290,291,292,294,295,296,298,305,306,307,308,326,340,344,364],protocol_flag:[289,290,294,306],protocol_kei:307,protocol_path:[285,308],protodef:203,prototocol:[43,169],protototyp:[249,251,252],protototype_tag:109,prototoyp:250,prototyp:[43,45,46,47,53,55,120,139,141,142,159,169,203,218,219,232,364],prototype1:252,prototype2:252,prototype_:109,prototype_desc:[109,252],prototype_dict:[43,159],prototype_diff:252,prototype_diff_from_object:252,prototype_from_object:252,prototype_kei:[43,109,159,251,252],prototype_keykei:[43,159],prototype_lock:[109,252],prototype_modul:[43,109,159,251,252],prototype_pagin:251,prototype_par:[43,109,159,252],prototype_tag:252,prototype_to_str:251,prototypeevmor:251,prototypefunc:252,protpar:[251,252],protpart:251,provid:[0,3,4,11,12,16,17,22,25,29,33,36,38,41,43,47,55,69,75,77,90,91,96,97,100,102,103,108,109,119,124,125,126,127,131,133,134,136,137,138,144,154,159,164,175,180,182,188,190,193,203,204,215,217,218,219,220,221,234,235,241,247,250,259,287,310,317,328,338,339,340,344,345,357],provok:[42,79],proxi:[47,60,67,70,103,125,312],proxypass:8,proxypassrevers:8,prudent:36,prune:31,pseudo:[40,49,91,108,204,205],psionic:220,psql:23,psycopg2:23,pty:9,pub:[41,164,175],pubkeyfil:287,publicli:[54,61,79],publish:[21,36,79,100],pudb:141,puff:56,pull:[25,31,33,36,37,38,64,100,128,131,136,198,232,269],pullrequest:37,punch:31,punish:221,puppet:[2,9,19,21,22,31,33,39,40,41,43,55,57,58,62,74,80,96,97,105,107,114,118,123,133,143,144,150,156,159,167,181,199,247,306,308,318,360],puppet_object:[2,144],purchas:[67,85],pure:[46,56,88,114,125,126,256,267,316,321],pure_ascii:344,purg:[11,43,110,125,169],purpos:[4,11,67,83,90,92,95,112,119,123,126,133,146,150,154,185,194,287,316,325,328,344],pursu:[122,231],push:[22,38,76,100,103,126,198,226,232],pushd:63,put:[0,2,3,5,6,10,12,13,14,19,20,21,23,25,33,37,38,42,43,46,49,50,51,57,58,60,61,64,70,73,77,79,80,83,85,86,87,89,90,95,96,102,103,104,105,106,109,111,114,116,121,122,123,125,127,129,133,135,136,138,153,156,157,159,161,165,181,182,188,190,206,215,217,218,219,220,221,223,242,276,290,329,330,344],putti:90,puzzl:[79,122,141,142,178,232,233],puzzle_desc:232,puzzle_kei:233,puzzle_nam:203,puzzle_valu:233,puzzleedit:203,puzzlerecip:203,puzzlesystemcmdset:203,pwd:100,py3:276,pyc:[47,95],pycharm:[38,45,139,364],pyflak:26,pylint:26,pyopenssl:65,pypath:344,pypath_prefix:344,pypath_to_realpath:344,pypi:[64,79,90,93,321],pypiwin32:[9,63],pyprof2calltre:93,pyramid:235,pyramidmapprovid:235,python2:[9,63,97],python37:63,python3:[63,75],python:[0,2,3,4,9,10,11,12,14,15,19,20,21,22,23,27,29,31,33,37,38,39,42,43,45,46,47,49,50,51,53,56,58,60,62,63,64,65,66,69,72,73,75,76,80,82,83,85,86,89,90,91,93,97,98,100,102,103,104,106,108,109,110,111,113,114,116,118,119,123,124,125,127,128,130,133,134,135,139,151,153,158,159,163,169,170,180,185,192,193,194,195,196,198,204,234,235,242,246,250,252,258,261,267,269,276,280,285,295,306,308,312,314,317,318,321,322,324,325,326,327,328,330,331,334,337,340,344,347,363,364],python_execut:64,python_path:[153,344],pythonista:79,pythonpath:[153,267,277,322],pytz:345,qualiti:[61,151],quell:[2,6,20,121,156,212],quell_color:159,queri:[11,16,34,39,56,64,83,86,109,112,131,148,164,166,177,206,238,239,246,247,251,252,256,274,287,302,316,317,318,319,329,335,341,344,345],quersyet:119,query_al:316,query_categori:316,query_info:267,query_kei:316,query_statu:267,queryset:[64,102,112,119,176,199,238,251,273,317,329,341],queryset_maxs:329,quest:[55,57,61,63,117,122,139,233],question:[8,10,22,26,33,34,43,50,51,57,61,63,67,70,73,90,96,124,131,135,159,170,246,264,265,316,326,328,344],queu:267,queue:[36,116,312],qui:52,quick:[5,18,22,31,33,38,39,43,48,55,61,70,79,90,91,95,97,108,112,116,119,124,138,140,146,159,180,205,252,272,316,319,330],quicker:[0,37,86,87],quickli:[10,11,15,25,33,34,39,43,48,51,86,89,96,112,114,120,128,136,139,159,180,205,319,322],quickstart:[95,139,364],quiescentcallback:269,quiet:[25,43,85,144,157,159,164,180,182,206,247,329,344],quiethttp11clientfactori:269,quietli:[29,83,88,316],quirk:[24,45,139,153,364],quit:[0,2,4,10,17,21,22,23,30,33,38,39,40,42,46,50,51,54,55,57,60,67,75,85,93,96,105,119,127,128,133,156,171,180,186,188,194,220,287,326,328,329],quitfunc:[50,326],quitfunc_arg:326,quitsave_yesno:326,quo:115,quot:[23,27,35,43,50,51,80,95,96,109,114,118,159,171,186,206,326,328,340,344],qux:215,ra4d24e8a3cab:35,race:[8,55,56,61,73,79,117,133,344],rack:232,radiu:[39,49,111],rage:122,rail:[64,121],railroad:121,rain:[102,119,122,132],raini:233,rais:[10,15,27,33,69,73,77,83,91,109,119,134,144,146,170,176,180,185,187,192,194,195,204,205,206,242,250,251,261,266,267,285,290,296,311,316,317,319,321,322,324,327,328,330,337,338,339,340,344,345],raise_error:[339,344],raise_except:[1,316],ram:[11,90],ramalho:79,ran:[13,36,42,90,127,259],rand:102,randint:[73,91,109,116,120,123,217,218,219,220,221,252],random:[9,20,35,46,60,73,90,91,102,104,109,114,116,120,123,132,204,205,217,218,219,220,221,223,226,228,232,233,235,252,298,299,344],random_string_from_modul:344,random_string_gener:[141,142,178],randomli:[86,93,102,120,132,217,218,219,220,221,226,231,232,267,299],randomstringgener:204,randomstringgeneratorscript:204,rang:[24,31,39,42,43,49,50,56,59,63,88,91,93,103,109,111,116,118,120,122,127,159,184,188,218,221,317,326,357],rank:[19,241],raph:79,rapidli:153,raptur:291,rare:[10,22,33,34,38,63,86,104,106,115,128,164,242,324],rascal:112,rate:[33,37,43,64,90,164,261,267,286,344],rather:[2,3,11,13,20,22,25,26,29,33,37,38,39,41,43,47,55,57,60,61,64,71,86,89,91,93,95,97,102,104,110,111,112,115,116,127,128,129,131,134,135,138,144,148,152,156,159,160,164,166,167,169,175,179,190,194,202,206,217,218,219,220,221,236,247,249,251,252,316,318,321,330,339,340,343],ration:179,raw:[3,12,20,33,38,41,51,56,64,74,83,86,95,109,114,119,144,151,154,159,167,168,170,206,210,234,247,272,287,290,295,296,306,316,321,326,328,338,344],raw_cmdnam:[151,168],raw_desc:187,raw_input:[85,328],raw_nick:87,raw_str:[33,51,85,144,146,150,151,154,170,188,215,230,247,249,306,316,328],raw_templ:87,rawstr:[154,170],rcannot:22,rdelet:169,re_bg:343,re_bgfg:343,re_blink:343,re_bold:343,re_color:343,re_dblspac:343,re_double_spac:343,re_fg:343,re_format:321,re_hilit:343,re_invers:343,re_mxplink:343,re_mxpurl:343,re_norm:343,re_str:343,re_ulin:343,re_underlin:343,re_unhilit:343,re_url:343,reach:[20,22,39,51,73,87,88,90,95,101,121,122,141,154,188,192,221,287,291,310,328,329,341],reachabl:[64,115],react:[51,115,117,118,231,247],reactiv:[43,169],reactor:[278,305,312,342],read:[0,1,4,5,8,9,11,13,15,16,17,20,22,23,25,27,29,31,33,34,37,38,39,41,43,46,51,55,56,58,59,60,64,69,70,71,72,76,77,79,80,85,86,88,90,91,93,95,96,102,103,104,105,109,114,119,122,123,124,126,127,128,131,133,134,138,139,144,148,158,165,166,177,180,187,190,198,199,204,206,232,233,239,246,247,251,252,256,274,276,299,316,318,319,322,323,327,329,335,337,363],read_batchfil:322,read_default_fil:36,readabl:[1,27,38,49,51,93,96,108,114,115,125,166,232,321,328],readable_text:232,reader:[38,43,48,58,74,79,81,98,133,164,190,221,272,286],readi:[2,10,12,15,20,25,29,36,37,40,42,54,63,75,77,80,83,89,93,106,121,131,136,138,144,154,206,217,218,219,220,221,247,296,329,338,344],readili:[23,111],readin:327,readlin:337,readm:[14,37,47,53,130,131,178,210],readthedoc:[79,83],real:[2,10,21,22,27,31,38,39,42,46,55,58,59,62,63,66,67,72,73,89,90,93,95,100,108,109,110,111,116,119,123,125,126,131,148,153,177,179,184,205,206,219,241,298,322,331],real_address:2,real_nam:2,real_seconds_until:[184,331],real_word:205,realis:77,realist:[127,132],realiti:[21,55,56,61,77,79,126],realiz:[48,96,126,131],realli:[4,10,11,12,13,14,19,20,22,25,26,31,33,38,39,42,51,58,62,64,67,72,77,80,85,89,91,96,98,104,108,110,111,112,115,118,119,121,127,128,138,139,154,170,179,180,181,215,234,242,276,321,322,328,340],realm:287,realnam:89,realtim:[58,184],realtime_to_gametim:184,reason:[8,9,11,12,13,22,25,29,34,37,38,39,40,41,43,44,49,51,56,57,58,60,61,63,64,69,73,80,82,83,86,87,89,93,97,102,103,104,106,109,114,115,116,119,122,126,129,131,138,144,157,159,164,169,186,204,205,247,251,257,264,269,276,277,278,279,285,286,287,290,295,296,298,306,307,308,318,326,337,344],reasourc:109,reassign:49,reattach:[106,278,279],rebas:131,reboot:[11,27,28,43,50,55,67,84,86,90,100,102,105,115,116,128,144,153,164,169,183,188,231,232,247,256,257,259,261,267,307,308,326,328],reboot_evennia:267,rebuild:[58,63,100,128,279],rebuilt:33,rec:206,recach:233,recal:[95,138,232],recaptcha:133,receipt:[103,269],receiv:[31,33,34,37,41,42,51,52,58,77,83,87,91,105,113,114,117,127,133,137,138,144,152,153,170,171,175,176,177,186,199,206,210,247,269,272,276,278,279,285,295,296,298,305,306,324,329,341,344],receive_functioncal:276,receive_status_from_port:267,receiver1:170,receiver2:170,receiver_account_set:148,receiver_extern:177,receiver_object_set:246,receiver_script_set:256,recent:[4,17,25,60,67,123,310],recev:296,recip:[0,28,115,203],recipi:[34,58,144,175,176,199,247,276],reckon:9,reclaim:102,recog:[87,206],recog_regex:206,recogerror:206,recoghandl:206,recogn:[16,20,63,74,83,89,90,96,110,127,134,206,312],recognit:[206,316],recommend:[9,12,23,24,25,26,36,37,38,43,51,55,58,59,60,61,63,69,73,79,86,88,89,90,93,95,108,109,122,124,125,127,131,135,169,190,194,209,234,242,247,269,322,328,341],recommonmark:38,reconfigur:90,reconnect:[144,146,164,175,264,267,276,278,279,305,308],reconnectingclientfactori:[264,278,279,298],record:[15,23,90,123,210,221,310,357],record_ip:310,recours:12,recov:[27,28,29,56,217,218,219,220,221,242,344],recoveri:116,recreat:[23,63,102,111,128,146,153,322,323],rectangl:327,rectangular:[58,327],recur:64,recurs:[11,241,251],red:[13,14,20,31,43,59,80,87,95,109,114,126,159,169,226,232,321,345],red_bal:59,red_button:[13,14,20,43,87,141,142,159,178,222],red_button_script:[141,142,178,222],red_kei:80,redbutton:[13,14,20,43,87,159,226],redd:103,reddit:103,redefin:[22,33,55,89,247,357],redhat:[63,67],redirect:[8,22,40,69,96,105,133,135,180,328,361],redistribut:34,redit:180,redo:[50,61,326],redon:271,redraw:287,reduc:[116,217,218,219,220,221,280],redund:321,reel:153,reen:[114,321],ref:[23,38,125,206,247,344,357],refactor:[45,57,139,247,363,364],refer:[0,8,9,13,19,20,22,31,33,34,37,40,43,46,48,49,51,56,57,62,64,69,73,79,80,86,87,88,89,90,95,96,100,104,105,106,109,110,111,116,118,119,124,125,126,127,129,130,131,133,134,144,153,159,164,168,175,179,188,204,206,217,218,219,220,221,241,247,258,260,261,269,279,299,307,317,328,334,340,341,344],referenc:[43,56,89,104,109,159,164,175,206,239,318,344],referenti:344,referr:90,refin:[49,119],reflect:96,reflow:16,reformat:[252,330,337],reformat_cel:330,reformat_column:[111,330],refresh:[26,134,287,310],refus:12,regain:29,regard:[48,126,127,138,204],regardless:[12,19,31,33,58,73,80,81,83,102,105,114,119,121,125,127,138,144,152,175,179,189,206,247,261,284,287,290,305,307,316,319,322,334,337,344],regener:219,regex:[5,33,50,51,87,127,137,154,157,169,170,183,204,206,311,316,328,344,347],regex_nick:87,regex_tupl:206,regex_tuple_from_key_alia:206,region:[43,58,90,140,157],regist:[65,71,83,103,104,116,120,131,133,135,137,138,144,164,198,231,232,257,267,278,279,285,308,310,312,321,360],register_error:321,register_ev:198,registercompon:137,registertest:360,registr:65,registrar:67,registri:[204,310,312],regress:251,regul:242,regular:[3,17,33,38,51,69,79,90,96,105,115,127,132,134,135,146,152,182,203,204,233,242,261,316,319,334,344,347,363],regulararticl:335,regulararticle_set:335,regularcategori:335,regularli:[67,85,98,102,120,128,132,184,231,233,259,261,270,300,331],reilli:79,reinforc:79,reiniti:110,reinstal:63,reinvent:57,reject:[188,204],rejectedregex:204,rel:[10,13,14,19,22,31,49,51,82,104,123,131,133,184,221,322,328],relai:[27,33,43,72,105,144,164,179,189,247,285,308,328,329,344],relat:[28,31,33,34,43,47,51,56,57,72,79,96,102,103,104,110,125,132,137,138,139,148,149,152,167,172,176,177,184,198,210,217,218,219,220,221,230,233,239,246,247,256,261,272,308,316,318,319,321,328,335,337,346,350,357],related_nam:[148,177,239,246,256,316,318,319,335],relationship:[34,49,119,125],relay:146,releas:[9,28,37,43,55,63,78,79,90,96,169],releg:1,relev:[3,9,11,14,22,30,33,37,38,47,58,62,79,80,89,96,107,112,114,116,119,123,124,125,133,135,140,144,150,152,179,180,242,258,281,299,306,307,308,321,326,328,338],relevant_choic:180,reli:[9,34,41,51,62,70,81,85,86,88,91,114,115,119,126,127,135,189,206,233,267,318,328],reliabl:[13,23,25,29,125,334],reload:[0,2,3,5,6,7,12,13,14,19,21,22,26,27,28,29,31,33,35,36,39,40,41,42,44,48,50,51,55,57,58,60,62,63,65,66,68,69,71,73,74,81,92,95,96,98,102,104,105,106,115,116,117,118,121,123,125,128,133,134,135,136,139,144,146,153,158,159,169,175,180,181,185,186,187,195,202,206,212,213,232,233,235,242,247,257,259,261,267,276,277,279,281,305,308,312,316,322,324,326,327,328,331,344,364],reload_evennia:267,remain:[13,19,30,31,33,43,50,51,58,77,90,91,96,97,107,109,110,113,151,153,159,161,165,181,184,187,205,217,218,219,220,221,231,247,267,295,296,328,329,344],remaind:[21,33,184],remaining_repeat:102,remap:[38,316],remedi:60,rememb:[0,1,4,5,11,12,13,21,22,28,29,31,33,39,41,43,48,49,51,54,56,58,61,62,63,69,77,80,86,88,90,91,93,95,96,97,111,112,114,115,119,123,126,128,131,137,139,157,159,181,194,247,257,322,341],remind:[0,4,38,50],remit:[43,157],remnisc:57,remot:[25,100,103,164,276,278,290],remov:[0,1,4,9,11,12,21,22,27,31,36,39,41,43,48,50,51,55,58,69,80,81,84,85,87,89,91,93,98,102,115,116,122,127,128,131,133,136,138,141,152,153,157,159,164,165,166,169,170,175,177,180,182,187,188,192,196,203,204,205,206,215,217,218,219,220,221,226,242,246,247,252,257,260,261,267,285,296,308,310,316,319,321,325,328,334,340,342,343,344],remove_alia:164,remove_backspac:343,remove_bel:343,remove_charact:116,remove_default:[31,153],remove_receiv:177,remove_send:177,remove_user_channel_alia:175,removeth:316,renam:[9,20,43,58,81,136,159,165,247,318],render:[3,22,38,69,81,102,107,133,134,136,166,190,312,338,340,347,355,357],render_post:296,renew:[29,58,67,310],reorgan:[45,47],repair:[21,61],repeat:[0,42,61,62,75,88,93,102,110,111,116,118,121,136,139,144,146,179,184,204,215,256,259,267,272,291,316,324,328,331,344],repeatedli:[14,42,62,74,102,139,231,256,259,261,267,272,298,350],repeatlist:74,repetit:[62,116,204],replac:[5,6,9,22,23,25,29,30,31,33,36,38,41,43,50,51,57,69,74,80,87,89,95,96,100,104,105,109,111,114,116,119,134,135,136,137,138,144,151,152,153,154,157,165,166,169,170,175,179,181,183,186,187,188,192,195,202,203,205,206,226,230,233,234,242,247,249,251,252,279,282,295,296,306,316,321,326,327,328,330,343,344,347],replace_data:330,replace_timeslot:187,replace_whitespac:330,replacement_str:[43,165],replacement_templ:[43,165],replenish:[217,218,219,220,221],repli:[33,51,65,70,139,146,179,199,265,289,290,296,308,328],replic:[22,114,136],repo:[38,47,57,79,106,131,139,344],report:[22,24,26,33,37,43,61,63,70,73,75,84,91,93,97,102,103,104,115,116,127,131,136,138,159,164,192,195,206,234,247,267,272,279,282,283,290,291,295,298,306,308,321,324,328,344],report_to:324,repositori:[8,9,23,25,36,76,78,96,100,130,252],repositri:76,repr:[91,344],reprehenderit:52,repres:[0,2,9,20,21,22,25,31,33,40,46,49,53,56,61,62,64,69,77,86,89,95,96,105,107,113,116,119,125,126,127,133,136,144,150,176,182,188,190,192,198,204,205,206,210,212,215,219,232,233,234,247,252,260,261,264,278,279,295,296,306,307,308,312,316,317,321,323,324,328,329,330,340,344],represent:[2,11,28,40,58,64,73,77,86,87,88,105,113,119,126,176,192,195,206,251,256,276,295,296,319,325,331],reprocess:103,reproduc:[10,96,247],reput:209,reqhash:[317,344],reqiur:188,request:[3,8,26,37,40,43,51,63,69,80,90,103,107,119,123,131,133,134,135,139,144,146,157,179,195,247,251,267,269,276,279,281,286,287,289,296,312,319,328,349,350,351,355],request_finish:107,request_start:107,requestavatarid:287,requestfactori:312,requestor:[144,310],requir:[1,4,8,9,10,11,14,15,22,23,33,36,37,38,43,46,47,49,50,51,54,58,60,61,67,68,69,70,71,75,77,78,79,80,84,85,86,89,90,93,102,109,110,111,114,115,116,118,119,125,126,127,129,132,133,134,136,137,158,159,164,169,176,177,185,186,187,188,202,204,206,215,219,220,233,234,238,241,247,251,260,267,278,279,292,300,311,317,322,327,328,329,330,334,339,340,341,344,357],require_singl:251,requr:109,rerout:[138,156,160,279],rerun:[13,14,51,122],research:[79,194],resembl:[25,55,129],resend:33,reserv:[1,10,33,95,96,111,251,311,317,344],reset:[0,7,12,15,17,23,27,29,31,33,44,50,60,66,73,81,102,104,105,111,114,116,121,123,125,126,139,144,146,153,159,169,184,195,206,232,242,267,271,277,287,305,316,319,322,330,331,342,344],reset_cach:[316,319],reset_callcount:102,reset_gametim:[27,331],reset_serv:271,reset_tim:187,resid:[47,96,108,242],residu:[43,169,219],resist:[252,344],resiz:[58,138,327,330],resolut:[114,116],resolv:[26,29,42,60,70,90,95,104,116,131,203,217,218,219,220,221],resolve_attack:[217,218,219,220,221],resolve_combat:116,resort:[33,54,58,164,206,344],resourc:[9,23,26,28,38,41,47,48,53,56,90,95,96,103,108,115,124,127,135,136,139,220,257,265,296,312,323,342],respect:[0,6,23,33,43,48,58,80,104,105,123,125,157,159,166,179,199,203,206,213,242,247,306,307,318,319,322,324,330,341,344,357],respond:[0,46,51,61,83,84,107,110,117,118,126,294,298],respons:[7,10,16,17,37,49,51,60,63,64,70,85,88,90,91,118,120,121,144,146,153,164,175,233,235,239,247,265,267,269,276,298,299,308,318,338,340,344],resport:344,rest:[17,29,33,51,56,63,73,82,85,86,87,104,106,111,122,123,151,167,168,217,218,219,220,221,316,321,330],restart:[12,42,43,58,60,76,90,92,93,102,103,104,106,110,116,128,131,135,138,141,144,169,175,180,183,195,247,257,259,260,261,271,284,305,306,307,344],restartingwebsocketserverfactori:[146,278],restock:85,restor:[0,31,102,126,180,220,257,261],restrain:[43,159,241,327,344],restrict:[4,8,11,19,20,43,47,59,68,73,80,90,109,111,115,125,134,137,159,164,182,204,220,221,242,252,324,326,328,330,341],restructur:[38,56],result1:203,result2:[51,203],result:[10,11,23,27,30,31,33,38,43,44,48,51,58,59,73,80,88,90,91,95,96,97,104,105,109,114,115,116,118,119,123,124,126,127,131,134,135,136,144,151,152,154,159,166,170,175,177,179,185,188,203,204,205,206,209,217,218,219,220,221,233,238,242,247,251,252,267,276,298,316,318,321,326,327,328,330,334,337,338,341,344,345],result_nam:203,resum:[29,33,102,260],resurrect:231,resync:[146,276,306],ret:[33,170],ret_index:344,retain:[10,27,31,51,97,111,138,189,239,252,313,318,322,324,337,344],retext:38,retract:179,retreat:221,retri:267,retriev:[0,33,43,69,74,86,96,97,108,112,119,123,139,140,144,148,150,153,159,164,169,170,176,187,194,238,241,246,251,265,272,273,279,285,294,316,319,325,334,339,341,344],retriv:[146,323],retroact:[58,125],retur:52,return_appear:[49,60,122,123,182,187,206,232,247],return_cmdset:166,return_detail:[187,233],return_iter:251,return_key_and_categori:319,return_list:[1,316,319],return_map:111,return_minimap:111,return_obj:[1,11,87,316,319,339],return_par:252,return_prototyp:120,return_puppet:144,return_tagobj:319,return_tupl:[87,185,316],returnv:33,returnvalu:10,reus:[25,334],reusabl:122,rev342453534:344,reveal:182,revers:[29,31,33,39,111,114,121,126,134,148,164,177,235,239,246,256,312,316,318,319,321,335],reverseerror:[267,276],reversemanytoonedescriptor:[148,246,335],reverseproxyresourc:312,revert:[43,90,126,131,156,238],review:[0,31,37,41,64,70,128,135],revis:61,revisit:[36,328],reviu:51,revok:58,revolutionari:131,rework:[29,61],rewritemim:70,rfc1073:283,rfc858:289,rfc:[283,289],rfind:321,rgb:[114,321],rgbmatch:321,rhel:8,rhostmush:[57,108,129],rhs:[25,58,167,170],rhs_split:[159,165,167],rhslist:167,ricardo:344,riccardomurri:344,rich:[22,57,78,79,325],richard:79,rick:109,rid:[56,119,139],riddanc:12,ridden:[1,96],riddick:188,ride:121,right:[0,5,8,10,14,20,21,23,25,28,29,33,38,39,41,42,43,46,51,55,56,57,58,60,61,63,68,74,75,76,80,85,87,90,91,96,101,102,109,111,114,117,119,121,123,126,127,128,133,134,137,138,153,156,159,167,169,175,181,187,188,190,195,196,203,221,226,231,232,233,235,242,252,256,307,321,322,326,330,344,345],right_justifi:109,rigid:57,rindex:321,ring:205,ripe:96,rise:[31,62],risen:62,risk:[38,43,57,63,90,123,138,158,169,344],rival:111,rjust:321,rm_attr:159,rnormal:114,rnote:[43,169],road:[31,46,111,121,152],roadmap:[45,139,364],roam:[122,153,231],roar:111,robot:[77,133],robust:[85,91,103],rock:[6,60,86,116,124,153],rocki:122,rod:153,role:[17,23,55,57,61,73,91,217],roleplai:[9,11,57,61,68,73,79,116,123,139,185,206,364],roll1:73,roll2:73,roll:[11,58,61,63,73,91,114,116,123,185,217,218,219,220,221,310],roll_challeng:73,roll_dic:185,roll_dmg:73,roll_hit:73,roll_init:[217,218,219,220,221],roll_result:185,roll_skil:73,roller:[73,116,185],rom:79,roof:[43,159],room1:127,room56:13,room:[9,12,13,14,15,20,21,22,27,31,33,42,43,44,45,46,53,55,56,57,59,62,63,64,73,77,80,85,91,96,102,104,108,109,111,112,116,117,118,119,120,121,122,123,124,125,127,129,132,133,140,141,142,150,151,152,153,157,159,165,170,178,180,182,185,187,194,206,212,213,214,217,218,219,220,221,226,229,230,231,232,234,235,241,247,256,271,299,322,342,360,364],room_count:119,room_flag:56,room_lava:56,room_typeclass:[235,342,360],roombuildingmenu:[22,180],roomnam:[43,58,159],roomobj:119,roomref:121,root:[9,13,22,23,36,47,53,63,64,69,75,78,80,81,86,89,90,93,96,97,100,106,128,130,134,135,136,232,247,252,267,312,325,364],rose:[11,87,89,125],roster:[9,217,218,219,220,221],rosterentri:9,rot:127,rotat:337,rotate_log_fil:337,rotatelength:337,roughli:[58,61,96,344],round:[17,205,221,298,330],rounder:205,rout:[5,20,49,56,121,137,144],router:90,routin:[206,302,341,344],row:[0,3,16,25,38,49,58,64,69,86,111,114,116,126,137,330,344],rpcharact:206,rpcommand:206,rpg:[58,60,73,124,185,221],rpi:79,rplanguag:[141,142,178,206],rpm:63,rpobject:206,rpsystem:[38,141,142,178,202,205],rpsystemcmdset:206,rred:321,rsa:[287,288],rspli8t:91,rsplit:[123,321],rsrc:70,rss2chan:[98,164],rss:[7,43,55,79,128,139,141,142,146,164,172,262,272,275,285,364],rss_enabl:[98,164],rss_rate:146,rss_update_interv:[43,164],rss_url:[43,98,146,164],rssbot:146,rssbotfactori:286,rsschan:[43,164],rssfactori:286,rssreader:286,rst:38,rstop:169,rstrip:[91,321],rsyslog:209,rtest2:114,rtext:85,rthe:22,rthi:114,rtype:312,rubbish:[43,156],rubi:64,rudimentari:231,ruin:[122,187,233],rule:[12,13,14,21,33,47,55,58,61,68,77,79,80,96,114,124,126,127,131,139,180,204,205,217,218,221,239,322,364],rulebook:116,rumour:122,run:[0,2,3,5,6,8,9,10,11,13,14,15,20,21,23,24,26,27,28,29,31,35,36,38,40,43,45,46,47,51,53,54,56,57,59,60,61,62,63,64,67,68,69,72,73,76,79,80,81,83,85,86,90,91,92,93,95,96,97,101,102,103,104,109,110,111,115,119,121,122,123,124,125,126,128,130,131,132,133,134,136,137,138,139,141,144,146,150,151,153,154,158,159,164,165,166,169,170,175,195,196,206,209,213,215,217,218,219,220,221,230,235,241,242,247,251,252,256,259,260,261,267,271,273,277,284,285,292,296,298,301,305,306,310,312,318,321,322,326,328,329,331,337,341,342,344,363,364],run_async:[10,344],run_connect_wizard:267,run_dummyrunn:267,run_exec:328,run_exec_then_goto:328,run_init_hook:305,run_initial_setup:305,run_menu:267,run_start_hook:[60,125,318],runexec:328,runexec_kwarg:328,runnabl:109,runner:[36,106,232,298],runsnak:93,runtest:[170,196,211,228,293,303,335,342,352,360],runtim:[12,27,33,62,154,180,234,331,344],runtimeerror:[73,144,146,192,195,198,204,205,251,285,316,328,344],runtimewarn:251,rusernam:51,rush:29,rusti:85,ruv:36,ryou:22,sad:[133,290,328],safe:[11,26,30,31,43,46,56,60,64,82,89,97,104,131,133,144,156,179,242,261,276,308,312,318,322,325,334,344],safe_convert_input:344,safe_convert_to_typ:344,safe_ev:344,safer:[12,13],safest:[0,90,105,318],safeti:[2,43,56,89,90,123,125,139,159,179,246,322],sai:[0,5,6,10,12,14,17,20,22,25,26,27,29,31,33,39,40,41,44,46,51,56,57,58,60,61,62,63,64,69,73,77,78,80,89,90,91,93,96,109,114,116,117,118,119,123,125,126,127,128,129,131,137,138,139,140,153,165,175,179,181,185,188,198,205,206,215,226,233,247,328],said:[0,4,10,22,26,43,44,46,49,51,57,83,91,96,111,112,118,127,134,151,164,168,206,235,247,279,318,328],sake:[13,43,57,126,135,171,186],sale:85,same:[0,2,5,6,9,10,11,12,13,14,15,16,19,20,21,22,23,26,27,28,29,31,33,34,37,38,40,41,42,43,44,50,55,57,58,59,60,61,62,63,64,66,69,73,74,78,80,81,83,84,85,86,88,89,90,91,95,96,97,98,100,102,104,105,106,108,109,110,111,112,113,114,115,116,119,121,123,125,126,127,128,131,133,134,136,138,144,150,151,152,153,154,157,159,164,167,168,169,170,180,182,184,187,190,194,195,199,204,205,206,212,214,215,217,218,219,220,221,231,233,234,235,241,247,251,252,256,257,261,271,276,288,291,292,306,307,308,310,312,316,317,318,319,321,322,324,328,329,330,331,337,338,344,357],sampl:[8,36,56,100,215],san:190,sand:62,sandi:111,sane:[61,79,96],sanit:357,saniti:[9,49,111,127,139,338],sarah:[43,129,165],sat:[21,140],satisfi:[108,167,316],satur:103,save:[0,1,9,15,21,22,24,27,29,33,34,36,41,42,43,46,48,50,51,54,56,64,67,84,86,87,89,95,97,100,102,103,105,107,109,110,112,115,116,123,125,127,131,133,138,144,156,159,169,175,177,180,195,205,242,246,247,249,251,252,257,259,260,261,265,272,285,300,305,312,316,318,325,326,334,338,339,340,344],save_buff:326,save_data:338,save_for_next:[33,154],save_handl:338,save_kwarg:339,save_nam:261,save_prototyp:251,save_recip:203,savefunc:[50,326,339],savehandl:339,saver:325,saverdict:325,saverlist:325,saverset:325,saveyesnocmdset:326,saw:[10,46,69],say_text:118,saytext:206,scale:[23,57,61,73,106,114,205],scalewai:90,scan:[8,150,231,233],scarf:182,scatter:[219,322],scedul:331,scenario:58,scene:[11,21,38,55,59,61,73,74,97,109,112,114,116,122,126,204,233,256,261,334],schedul:[27,62,184,195,260,331],schema:[4,64,86,125,131,344],scheme:[28,33,43,63,86,114,159,169,321],scienc:[49,124],scientif:79,scissor:116,scm:9,scope:[29,55,64,74,124,134,138,204,324],score:[58,60,344],scratch:[40,46,57,58,61,63,123,124,128,136,139],scream:122,screen:[7,16,18,33,43,51,52,61,66,74,81,85,97,100,101,104,105,109,114,127,133,138,139,171,186,190,221,272,287,329,344,364],screenheight:[74,272],screenread:[74,272,295,296],screenshot:[55,133,139,364],screenwidth:[74,154,272],script:[6,11,13,14,20,27,36,45,47,53,55,56,57,59,61,62,63,71,80,84,85,86,89,90,93,103,104,105,106,107,108,109,110,112,115,116,117,119,120,122,125,130,132,133,137,138,139,141,142,144,146,158,159,169,176,177,178,179,184,187,191,192,198,203,204,205,213,217,218,219,220,221,223,226,233,235,246,247,251,252,267,300,305,322,323,324,331,339,341,342,344,360,364],script_path:[43,159],script_search:59,script_typeclass:[228,342,360],scriptbas:259,scriptclass:258,scriptdb:[53,119,125,141,256,314],scriptdb_set:[148,246,316,319],scriptdbmanag:[255,256],scripthandl:[141,142,253],scriptkei:[43,159],scriptmanag:255,scriptnam:323,scroll:[20,45,52,63,77,95,96,97,123,138,329],scrub:308,scrypt:102,sdesc:[56,202,206],sdesc_regex:206,sdescerror:206,sdeschandl:206,sdk:63,sea:[111,122],seamless:206,seamlessli:[92,102],search:[0,2,9,13,21,22,30,33,41,42,43,48,50,55,58,59,60,64,68,70,73,76,87,89,96,102,104,109,116,123,124,125,127,131,134,136,139,140,141,142,144,150,152,154,159,164,166,169,175,176,179,194,199,203,206,217,218,219,220,221,233,235,238,239,241,247,251,258,273,316,317,318,319,320,321,324,326,344,347,363,364],search_:[27,59],search_account:[58,107,119,141,247,341],search_account_attribut:119,search_account_tag:[119,341],search_at_multimatch_input:247,search_at_result:[206,247],search_attribute_object:119,search_channel:[41,119,141,164,176,341],search_channel_tag:[119,341],search_field:166,search_for_obj:159,search_help:[119,141,238],search_help_entri:341,search_helpentri:238,search_index_entri:[154,156,157,158,159,164,165,166,167,168,169,170,171,179,180,181,182,185,186,187,188,189,193,199,202,203,206,212,213,214,215,217,218,219,220,221,226,231,232,233,234,239,247,298,326,328,329],search_messag:[119,141,176,341],search_mod:206,search_multimatch_regex:247,search_object:[11,13,27,111,119,121,125,141,144,341],search_object_attribut:119,search_objects_with_prototyp:251,search_prototyp:251,search_script:[59,102,119,141,341],search_script_tag:[119,341],search_tag:[48,112,119,140,141,341],search_tag_account:112,search_tag_script:112,search_target:199,searchabl:194,searchdata:[144,206,247,341],searchstr:68,season:[61,187],sec:[10,29,62,74,184,279,331],secmsg:337,second:[0,10,11,14,16,21,22,25,27,29,31,33,38,39,41,43,51,62,63,69,80,85,86,88,90,91,95,100,102,103,104,109,110,114,115,116,119,120,121,123,126,127,132,134,144,146,151,159,164,166,170,184,194,195,198,206,213,217,218,219,220,221,223,231,241,247,252,260,261,267,272,281,286,299,310,321,324,328,331,337,344,345],secondari:[81,307],secondli:89,secreci:131,secret:[9,23,65,71,185,267],secret_kei:9,secret_set:[4,9,23,65,267],sect_insid:49,section:[1,4,9,11,15,18,21,22,23,25,26,29,31,33,35,36,38,39,40,48,51,58,60,62,63,68,69,75,77,80,86,89,90,93,95,96,100,111,113,119,124,125,127,133,137,138,139,166,187,205,252,321,322,328,345],sector:49,sector_typ:49,secur:[7,11,13,22,26,37,41,43,57,63,80,85,90,96,108,109,114,123,133,134,139,141,142,158,169,175,178,239,247,287,318,337,344,357,364],secure_attr:80,sed:36,see:[0,1,2,3,4,5,8,9,10,11,12,13,14,19,20,21,22,23,25,26,27,28,29,30,31,32,33,34,35,37,38,39,40,41,42,43,44,46,48,49,50,51,52,53,55,56,57,58,59,60,61,62,63,64,65,68,70,71,72,74,75,76,80,81,82,83,86,87,88,89,90,91,93,95,96,98,100,101,102,103,104,105,106,108,109,110,111,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,130,131,132,133,134,135,136,137,138,139,144,154,156,158,159,164,165,166,167,169,170,175,178,179,180,186,190,192,199,203,204,205,206,210,213,214,215,217,218,219,220,221,223,226,231,233,234,235,239,246,247,260,265,267,269,270,278,279,280,281,283,287,288,290,292,294,295,296,298,299,307,308,312,316,321,324,325,326,327,330,339,340,344,351,357],seek:[122,242,337],seem:[4,22,24,31,39,41,56,61,63,75,109,110,119,121,122,123,137,138,316,322],seen:[0,22,29,31,34,40,46,49,51,57,58,69,81,91,95,96,102,105,111,119,120,121,126,127,131,180,279,330],sefsefiwwj3:9,segment:[121,312],seldomli:[154,170],select:[2,20,22,27,31,38,43,51,54,63,69,77,80,85,86,104,105,106,111,119,120,123,131,133,137,138,140,151,152,157,215,218,318,326,328],selet:328,self:[0,1,2,5,6,9,10,11,13,20,21,22,25,27,28,29,30,31,33,38,39,40,41,42,43,44,49,50,51,56,57,58,59,60,62,63,71,72,73,76,77,80,81,82,85,86,87,89,95,96,102,109,115,116,117,118,119,120,121,123,125,127,129,132,134,144,146,148,150,152,153,154,156,159,160,164,167,169,170,175,177,179,180,181,182,185,187,188,192,199,202,203,206,215,217,218,219,220,221,223,226,230,231,232,233,234,235,241,247,260,265,267,269,270,274,278,279,285,287,288,290,292,294,295,296,298,306,307,308,316,318,319,321,326,328,329,334,338,339,340,344,351],self_pid:344,selfaccount:58,sell:[78,85,179],semi:[93,132,138,205],semicolon:[80,242,324],send:[2,12,22,25,27,29,33,34,41,43,51,52,58,59,61,64,67,70,71,73,74,76,80,81,83,89,91,93,95,96,102,103,105,107,110,113,114,115,116,118,120,123,126,133,137,138,139,140,144,146,153,154,157,164,170,175,176,177,179,188,189,199,206,210,221,223,230,231,247,260,261,264,267,269,270,272,276,277,278,279,280,282,285,286,287,289,290,291,293,295,296,298,299,306,307,308,309,321,324,325,328,330,344],send_:[40,83,285],send_adminportal2serv:277,send_adminserver2port:264,send_authent:278,send_channel:[278,279],send_default:[40,83,278,279,285,287,290,295,296],send_defeated_to:231,send_emot:206,send_functioncal:276,send_game_detail:269,send_heartbeat:278,send_instruct:267,send_mail:199,send_msgportal2serv:277,send_msgserver2port:264,send_p:279,send_privmsg:279,send_prompt:[287,290,295,296],send_random_messag:223,send_reconnect:279,send_request_nicklist:279,send_status2launch:277,send_subscrib:278,send_testing_tag:230,send_text:[40,83,287,290,295,296],send_to_online_onli:175,send_unsubscrib:278,sender:[34,41,43,107,144,146,175,176,177,179,206,247,278,309,324,334,341],sender_account_set:148,sender_extern:177,sender_object:309,sender_object_set:246,sender_script_set:256,sender_str:175,sendernam:43,senderobj:324,sendlin:[287,290,295],sendmessag:[40,188],sens:[1,10,22,31,37,56,58,80,86,89,96,102,121,138,152,226,324,325,328],sensibl:[90,271],sensit:[11,51,58,80,176,180,184,187,195,210,211,238,317,331,341],sensivit:204,sent:[25,34,51,58,69,74,83,88,91,105,107,113,114,119,137,138,144,146,150,164,170,175,176,177,180,186,188,195,199,210,228,234,247,264,267,269,272,276,277,278,279,287,291,295,306,308,316,328,341],sentenc:[46,91,198,205,206],sep:[321,344],sep_kei:[22,180],separ:[8,11,13,14,20,23,29,31,33,37,40,43,46,48,51,57,58,61,62,64,71,72,75,77,80,84,85,86,87,89,91,92,93,95,96,98,101,102,103,105,106,112,114,115,119,121,123,126,129,131,133,136,137,138,140,151,153,154,159,165,166,167,169,170,180,195,198,199,205,206,215,217,218,219,220,221,233,235,238,242,246,247,251,257,261,286,291,296,308,321,322,324,327,341,344],separatli:29,seq:87,sequenc:[10,13,14,15,33,64,80,81,87,89,113,126,154,158,170,175,184,206,242,265,271,321,322,328,330,343,344],seri:[51,61,79,114,131,136,138,330],serial:[11,83,138,250,260,261,285,325,338,340,344],serializ:296,seriou:[39,110],serious:63,serv:[45,49,55,64,83,101,103,104,111,135,152,219,296,312,322,324,355],server:[0,2,4,9,10,11,12,13,15,19,21,25,26,27,28,29,31,33,34,35,36,37,38,40,41,45,47,51,53,54,55,56,57,58,59,60,62,63,64,65,66,67,69,70,71,72,73,74,75,78,79,80,81,83,84,86,88,89,91,93,95,96,97,100,101,102,103,106,107,109,110,111,113,114,115,116,118,121,122,124,125,127,128,130,131,133,134,135,136,137,138,139,141,142,144,146,153,157,159,164,169,171,175,178,180,183,186,187,195,202,206,207,208,209,212,213,231,232,233,235,247,256,257,259,261,313,318,322,324,325,328,331,334,337,344,363,364],server_connect:285,server_disconnect:285,server_disconnect_al:285,server_epoch:[27,331],server_l:277,server_logged_in:285,server_nam:104,server_pid:[277,344],server_receive_adminportal2serv:264,server_receive_msgportal2serv:264,server_receive_statu:264,server_reload:[257,261],server_run:267,server_runn:305,server_servic:344,server_services_plugin:[40,104],server_services_plugin_modul:40,server_session_class:105,server_session_sync:285,server_st:267,server_twistd_cmd:277,server_twisted_cmd:277,serverconf:[157,261],serverconfig:[260,261,273,274],serverconfigmanag:[273,274],serverfactori:[277,287,290],serverload:[43,169],serverlogobserv:337,servermsg:337,servernam:[4,8,9,54,74,90,104],serverprocess:[43,169],serversess:[40,105,114,141,142,210,242,262,285,308,316],serversessionhandl:[40,105,308],serverset:[43,80,164,241],servic:[12,23,40,45,67,71,90,100,103,104,110,131,133,141,142,169,262,264,267,268,276,277,284,305,312,344],sessdata:[307,308],sessid:[2,33,105,123,246,247,264,276,277,285,308],session:[2,12,15,24,31,33,40,45,47,51,53,57,74,81,84,88,89,91,96,100,107,114,123,127,138,139,141,142,144,146,148,150,151,152,154,156,157,160,162,167,171,186,188,189,209,210,211,230,246,247,249,250,251,257,262,264,272,276,277,278,279,285,286,287,290,295,296,305,306,308,310,326,328,329,344,345,364],session_data:308,session_from_account:308,session_from_sessid:308,session_handl:[105,141],session_portal_partial_sync:308,session_portal_sync:308,sessioncmdset:[31,43,162],sessionhandl:[40,83,141,142,144,247,262,272,278,279,285,286,306,307],sessionid:285,sessions_from_account:308,sessions_from_charact:308,sessions_from_csessid:[285,308],sessions_from_puppet:308,sesslen:247,set:[0,2,3,6,7,8,10,11,12,13,14,15,16,17,19,20,21,22,23,24,25,26,27,29,30,32,33,34,35,36,37,38,39,40,41,42,44,45,46,47,50,52,53,55,56,57,58,59,60,61,63,64,66,67,68,69,71,74,75,76,82,83,85,86,87,89,91,93,95,96,97,100,102,105,107,108,109,110,111,112,113,114,116,117,119,120,121,124,125,126,128,129,130,133,134,135,136,137,138,139,141,143,144,146,148,150,151,152,153,154,156,157,159,160,161,162,163,164,166,167,170,172,175,180,181,182,183,184,185,186,187,188,189,193,195,198,202,203,205,206,209,212,213,215,217,218,219,220,221,226,228,230,231,232,233,234,235,241,242,246,247,250,251,252,258,259,260,261,264,266,267,271,272,273,274,277,278,280,281,283,284,287,289,290,292,293,298,299,301,303,305,306,307,308,310,312,313,316,317,318,319,321,322,323,324,325,326,327,328,329,330,331,334,335,337,338,339,340,341,342,343,344,345,347,350,357,360,364],set_active_coordin:235,set_al:231,set_alias:154,set_attr:159,set_cach:316,set_class_from_typeclass:318,set_dead:231,set_desc:164,set_descript:51,set_detail:[187,233],set_game_name_and_slogan:350,set_gamedir:267,set_kei:154,set_lock:164,set_log_filenam:175,set_nam:51,set_password:144,set_task:195,set_trac:[42,141],set_webclient_set:350,setcolor:81,setdesc:[57,165,212],setgend:189,sethelp:[20,68,166],sethom:159,setlock:212,setnam:40,setobjalia:[43,159],setperm:[43,157],setspe:213,sett:98,settabl:[74,86,290],setter:39,settestattr:50,settingnam:80,settings_chang:107,settings_default:[4,5,34,47,104,127,141,142,337,344],settings_ful:104,settings_mixin:[141,142,262,297],settl:[111,116],setup:[5,15,18,26,40,47,61,63,67,71,85,93,96,100,116,120,127,129,131,138,139,144,156,164,170,184,196,226,228,230,233,247,259,271,284,293,298,302,303,305,312,316,318,334,335,342,360,364],setup_str:302,setuptool:[63,75],sever:[0,11,14,19,22,29,31,33,36,41,42,43,48,50,52,55,56,57,59,62,69,79,80,102,104,109,113,116,119,125,137,158,159,167,169,187,194,195,231,233,247,293,294,319,324,344],sex:189,shall:[126,134],shaman:[57,109],shape:[20,22,39,58,61,111,235,330],sharabl:109,share:[9,25,31,36,37,42,46,57,59,63,64,65,80,86,90,102,103,105,112,116,119,125,133,135,194,195,252,261,298,316,317,319,330,344,351],sharedloginmiddlewar:351,sharedmemorymanag:[317,333],sharedmemorymodel:[177,239,316,318,334,335],sharedmemorymodelbas:[148,177,239,246,256,316,318,334,335],sharedmemorystest:335,shaw:[77,79],she:[0,22,33,56,91,126,180,189,205],sheer:[43,159],sheet:[23,38,51,133,134,137,327],sheet_lock:58,shell:[7,23,25,26,36,57,58,59,60,63,75,86,87,90,100,103,108,110,125,128,287,316],shield:[29,77,86],shift:[14,15,27,108,195,232,238,344],shiftroot:232,shine:[21,233],shini:344,ship:[55,64,75,111],shire:62,shirt:182,shoe:182,shoot:[21,220,221,327],shop:[51,57,108,124,139,364],shop_exit:85,shopcmdset:85,shopnam:85,shopper:85,short_descript:54,shortcom:85,shortcut:[0,3,22,23,27,29,31,33,38,43,47,59,69,91,96,100,107,116,119,125,129,133,134,141,146,153,154,159,164,180,192,235,242,247,338,344],shorten:[42,46,125,252],shorter:[40,61,104,108,117,118,125,132,175,205,316,317,324,337],shortest:[39,206],shorthand:[43,89,126,159],shortli:[0,22,77],shot:220,should:[0,1,2,3,4,5,6,8,9,10,11,12,13,14,15,16,19,20,22,23,24,25,26,27,29,31,33,34,37,38,39,40,41,42,43,46,47,48,51,55,57,58,59,60,61,62,63,64,65,66,67,68,69,72,73,74,75,76,77,80,81,82,83,85,86,88,89,90,91,93,95,96,97,98,100,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,119,121,122,123,124,125,126,127,128,129,130,131,133,134,135,136,137,138,139,140,144,146,148,150,152,153,154,156,158,159,160,163,164,166,167,169,170,175,177,180,182,184,187,192,195,198,199,202,203,204,205,206,209,217,218,219,220,221,230,231,233,234,241,242,246,247,249,251,252,256,259,260,261,265,266,267,271,274,278,284,287,290,291,293,295,296,298,299,305,306,307,308,310,311,313,316,318,319,321,322,324,325,326,328,329,330,331,337,338,339,340,342,344,345,357,360],should_join:175,should_leav:175,should_list_top:166,should_show_help:166,shoulddrop:[221,247],shoulder:[58,182],shouldget:[221,247],shouldgiv:[221,247],shouldmov:[217,218,219,220,221,247],shouldn:[0,13,21,22,29,41,48,58,93,126,180,195,198,220,298],shouldrot:337,shout:29,shove:21,show:[0,12,13,14,20,22,24,26,27,30,33,35,37,38,39,40,42,43,46,48,49,52,54,55,57,58,60,61,62,63,64,68,69,70,71,73,81,82,85,86,90,91,95,96,97,98,101,102,103,104,105,106,110,111,114,116,117,118,119,120,122,124,126,127,128,129,131,133,134,136,137,138,139,144,156,157,159,164,165,166,167,169,171,179,181,182,185,186,187,188,190,202,215,220,221,226,233,234,235,247,249,251,252,265,267,276,326,328,337,338,339,344,357],show_foot:329,show_map:49,show_non_edit:251,show_non_us:251,show_valu:190,show_version_info:267,show_warn:267,showcas:[31,111],shown:[0,4,9,22,25,29,35,41,43,49,51,54,57,62,68,109,114,121,133,138,154,157,164,168,170,180,182,204,206,226,232,247,267,328,329,347],showtim:62,shrink:330,shrug:46,shrunk:101,shuffl:27,shun:[26,90,108],shut:[0,4,29,43,93,100,102,104,137,144,169,247,259,261,267,269,276,277,284,285,305,308],shutdown:[12,19,31,58,93,102,105,110,144,146,169,261,267,276,277,284,305,306,318,324,328],shy:[26,61,129],sibl:[10,57,96,102],sid:[43,157],side:[0,1,11,24,36,38,43,48,49,58,73,74,83,91,105,112,119,126,127,133,137,138,144,146,148,165,167,177,179,185,212,239,246,256,264,276,277,285,288,291,292,295,306,307,308,316,318,319,321,330,335],sidestep:19,sidewai:330,sigint:267,sign:[0,14,20,46,83,90,91,106,115,123,132,164,187,247,261,316,321,345],signal:[45,93,110,139,141,142,217,218,219,220,221,262,267,290,296,298,334,364],signal_acccount_post_first_login:107,signal_account_:107,signal_account_post_connect:107,signal_account_post_cr:107,signal_account_post_last_logout:107,signal_account_post_login:107,signal_account_post_login_fail:107,signal_account_post_logout:107,signal_account_post_renam:107,signal_channel_post_cr:107,signal_helpentry_post_cr:107,signal_object_:107,signal_object_post_cr:107,signal_object_post_puppet:107,signal_object_post_unpuppet:107,signal_script_post_cr:107,signal_typed_object_post_renam:107,signatur:[33,73,154,192,260,265,267,269,270,278,287,288,290,292,295,296,316,321,328,339,340,351],signed_integ:345,signedinteg:338,signedon:279,signifi:[14,241,316],signific:[97,170],significantli:50,signup:4,silenc:[164,269],silenced_system_check:127,silent:[10,43,62,118,157,164,226,271,279],silli:[60,89,96,109],silvren:[55,90],similar:[0,11,13,20,21,22,25,33,41,48,51,55,58,64,67,68,73,77,86,89,90,96,102,106,121,125,129,136,137,140,144,154,156,170,175,180,188,205,217,218,219,220,221,235,239,247,308,319,324,328,344],similarli:[58,62,90,112,218,234],simpl:[0,2,4,5,6,9,10,13,14,15,17,25,26,28,30,31,33,35,38,39,40,41,43,46,49,50,55,56,57,58,59,60,61,64,67,69,70,73,74,76,77,81,85,86,88,89,90,91,95,96,98,100,103,105,108,109,111,112,116,117,118,119,120,122,123,124,126,132,133,135,139,159,175,179,180,181,186,187,188,189,194,199,203,204,205,206,212,213,214,215,217,218,219,220,221,223,226,231,232,233,235,236,246,247,252,259,277,286,288,322,323,328,344,354,355,357,364],simpledoor:[141,142,178],simplemu:24,simpler:[10,15,38,43,51,56,158,159,325],simpleresponsereceiv:269,simplest:[6,29,58,73,90,116,153,322,345],simpli:[5,8,11,12,13,17,20,21,22,23,25,29,31,37,38,39,40,41,47,49,51,55,58,59,61,63,71,72,73,80,81,83,85,96,102,103,104,109,112,114,118,121,123,125,127,128,131,132,138,140,144,152,153,154,170,171,175,180,186,187,196,206,213,215,217,218,219,220,221,226,232,239,247,285,316,318,322,323,327,329,344],simplic:[22,39,43,55,126,171,186,232],simplif:[45,116],simplifi:[10,69,100,111,116,118,192],simplist:[116,123,132,137,205,214],simul:[33,73,93,213],simultan:[58,88,116,344],sinc:[0,1,3,4,5,6,9,10,11,13,14,19,21,22,23,25,26,27,28,29,31,33,34,35,38,39,40,41,42,43,44,47,48,49,50,51,54,55,56,57,58,59,60,61,62,64,69,74,76,80,83,84,85,86,88,89,90,91,94,96,97,100,102,104,110,111,114,115,116,118,119,121,122,123,125,126,127,131,133,134,135,138,144,146,148,152,153,154,159,167,168,169,170,176,179,180,181,184,187,199,206,215,217,218,219,220,221,226,232,233,241,247,251,252,257,260,261,267,269,272,284,289,291,305,306,308,310,316,317,318,322,323,324,326,328,331,334,337,340,341,342,344,357],singl:[0,5,10,14,16,22,23,31,33,37,38,43,44,48,51,55,57,58,59,61,64,67,73,77,83,87,88,90,95,96,105,108,111,112,114,119,122,125,127,128,129,139,144,157,159,164,165,169,177,180,204,209,215,217,218,219,220,221,233,234,235,247,251,252,260,261,299,306,308,316,317,319,321,322,327,328,330,344,357],single_type_count:182,singleton:[84,105,115,257,260,323],singular:[58,61,247],sink:26,sint:52,sir:46,sit:[11,14,29,33,47,55,63,80,83,90,95,96,119,121,123,125,167,170,175,198,199,206,232,233,242,258,261,280,324,339,342],sitabl:125,sitat:233,site:[8,16,17,23,37,69,71,79,80,90,97,98,100,101,103,111,133,134,312],site_nam:59,situ:[11,318,325],situat:[0,6,11,22,33,37,42,43,46,62,76,83,86,102,105,119,125,131,153,154,159,194,334],six:[73,91,185,215],sixti:62,size:[16,24,42,49,58,97,101,108,111,137,138,141,235,269,283,321,327,329,330,334,337,344],size_limit:344,skeleton:123,sketch:[116,138],skill:[28,29,30,55,60,61,70,73,79,110,116,121,127,133,134,205,206,327],skill_combat:73,skillnam:73,skin:109,skip:[31,33,41,43,49,51,61,62,75,88,100,106,109,115,131,144,158,159,247,316,325,344],skipkei:296,skippabl:129,skull:109,sky:[102,132],slack:79,slam:188,slash:[20,38,41,55,73,116,122,232],slate:111,sleep:[10,29,33,73],slew:[61,73,75,322],slice:[119,156,321,329],slice_bright_bg:156,slice_bright_fg:156,slice_dark_bg:156,slice_dark_fg:156,slide:226,slight:[8,91,184,195],slightli:[42,62,63,79,116,123,177,187,218,234],slightly_smiling_fac:138,slip:343,slogan:9,slot:[58,134,187,188,218,220,252,344],slow:[27,116,169,176,213,231,235,251,280,286,321,341,344],slow_exit:[141,142,169,178],slower:[62,77,90,93],slowexit:213,slowli:79,slug:[175,239,318],small:[4,14,15,16,25,30,33,37,55,57,58,61,63,69,70,79,81,85,90,91,93,96,97,98,108,111,122,123,124,127,128,139,185,220,226,235,290,326,327,330,344],smaller:[13,14,16,38,101,330],smallest:[58,62,80,90,184,205,327,344],smallshield:86,smart:[41,77,91,235],smarter:109,smash:[61,226],smell:61,smelli:109,smile:[33,43,165],smith:327,smithi:29,smoothi:203,smoothli:134,smush:48,snake:136,snap:82,snapshot:131,snazzi:78,sneak:242,snippet:[10,13,21,31,43,55,64,80,109,114,139,169,276,343,344],snoop:103,snuff:26,social:[55,71],socializechat:299,soft:[4,64,139,205,364],softcod:[129,139],softli:78,softwar:[36,63,90,131],solar:62,soldier:85,sole:[57,69,146],solid:[49,55,114],solo:[20,63,124],solut:[0,9,14,25,27,29,39,56,69,73,85,90,91,103,111,115,118,121,122,125,127,138,168,242],solv:[21,27,44,49,61,63,77,97,111,203,232],some:[0,3,4,5,6,8,9,11,12,13,14,15,16,20,21,22,23,24,25,26,27,28,29,31,33,36,37,38,40,42,43,45,46,48,49,50,51,55,57,58,60,61,62,63,64,67,69,70,72,73,74,75,77,78,79,80,82,83,85,86,87,89,90,91,95,96,97,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,121,122,123,124,125,126,127,128,131,133,134,136,137,138,139,144,153,154,159,161,164,165,168,169,175,176,179,180,181,186,195,198,204,205,212,215,218,219,220,221,226,230,232,233,234,235,242,247,251,252,256,269,271,276,279,305,316,318,321,322,327,328,331,334,337,338,344,357],some_long_text_output:329,somebodi:[0,138],somehow:[33,40,73,80,87,90,113,140,182,326],someon:[0,1,29,33,43,46,48,49,58,60,80,85,90,96,103,107,115,117,118,119,138,144,165,182,226,231,232,247],somepassword:23,someplac:231,someth:[0,3,4,6,8,9,10,11,12,14,20,22,23,25,27,29,30,33,38,39,40,41,43,44,46,49,51,52,56,57,58,59,60,61,62,64,65,67,68,69,70,71,72,73,75,80,82,83,85,86,89,90,91,93,95,96,102,104,107,108,109,111,114,115,119,123,125,127,128,129,133,134,135,137,138,139,144,152,154,159,165,167,170,179,180,182,189,198,204,206,213,217,218,219,220,221,232,233,234,235,242,247,252,306,318,322,328,329,338,344],sometim:[6,22,27,33,40,42,50,51,60,62,64,80,86,91,93,95,96,102,109,110,119,136,138,166],somewhat:[4,22,41,57,127,138,180],somewher:[0,12,37,43,73,80,90,109,121,125,131,159,175,239,318,344],soon:[42,61,69,72,96,100,105,127,296,344],sophist:[10,27,55,108,116],sorl:4,sorri:[80,242],sort:[3,6,11,31,39,49,59,61,64,69,73,83,84,90,105,110,112,116,117,135,140,179,190,217,218,219,220,221,233,247,252,256,316,317,318,328,344,357],sort_kei:296,sought:[144,151,175,239,247,316,318],soul:111,sound:[22,29,37,58,61,80,82,83,102,104,111,115,131,138,205,291],sourc:[0,4,9,10,12,15,16,17,20,21,22,23,27,31,36,37,46,47,55,57,60,63,64,67,68,72,75,76,79,88,89,96,97,108,122,127,128,130,131,134,139,141,144,146,147,148,150,151,152,153,154,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,175,176,177,179,180,181,182,184,185,186,187,188,189,190,192,193,194,195,196,198,199,202,203,204,205,206,209,210,211,212,213,214,215,217,218,219,220,221,223,226,228,230,231,232,233,234,235,238,239,241,242,245,246,247,249,250,251,252,255,256,257,258,259,260,261,264,265,266,267,269,270,271,272,273,274,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,298,299,300,302,303,304,305,306,307,308,310,311,312,316,317,318,319,321,322,323,324,325,326,327,328,329,330,331,333,334,335,337,338,339,340,341,342,343,344,345,349,350,351,352,355,357,360,363],source_loc:[25,77,96,117,232,233,235,247],source_object:[171,186],sourceforg:[280,281,291,294],sourceurl:279,south:[0,22,43,44,49,111,121,159,299],south_north:111,southeast:159,southern:111,southwest:[20,43,159],space:[9,20,21,22,25,33,35,38,41,43,46,48,49,51,57,68,80,87,91,95,102,109,111,114,116,118,126,129,137,138,151,154,159,164,165,166,167,170,171,202,205,206,221,232,247,311,318,321,322,327,328,330,343,344,347],spaceship:121,spacestart:343,spaghetti:[13,328],spam:[12,28,103,116,138,164,310],spammi:[12,116],span:[16,17,108],spanish:76,spare:[217,218,219,220,221],spatial:111,spawen:203,spawn:[47,53,55,93,120,122,137,138,141,157,159,203,218,219,249,250,251,252],spawner:[18,45,89,120,139,141,142,159,219,220,248,250,364],spd:134,speak:[0,15,19,41,43,46,60,96,113,117,118,126,133,165,206,247],speaker:[46,205,206],spear:109,special:[2,10,11,13,14,15,19,20,25,26,27,30,31,33,35,37,41,42,51,58,60,61,64,69,76,77,80,81,83,85,86,88,89,95,102,103,104,107,111,112,113,114,116,119,122,123,125,127,131,134,137,146,148,150,153,165,168,187,189,206,215,219,220,232,233,235,242,247,271,272,295,299,316,318,322,328,343],specif:[0,2,4,9,11,12,22,23,24,25,26,27,31,33,36,37,38,39,40,41,42,43,46,47,50,51,53,55,56,59,61,62,64,67,69,77,78,79,80,82,87,88,89,90,91,95,96,100,105,107,110,111,112,115,116,119,121,122,123,124,125,126,127,131,132,133,134,135,137,138,144,150,157,159,166,169,177,178,179,180,192,193,194,195,199,204,206,238,241,247,257,267,272,279,295,296,306,316,318,321,322,326,328,329,330,344],specifi:[3,11,12,16,19,21,22,27,29,31,38,39,43,46,49,51,54,58,62,63,68,83,84,86,88,90,91,98,100,102,103,105,109,111,112,114,115,119,123,127,134,136,150,151,159,166,170,175,180,182,183,185,187,188,192,194,195,199,203,204,206,215,218,219,220,235,241,242,247,250,251,252,257,278,304,316,319,321,322,324,327,328,331,338,339,340,344,357],spectacular:42,speech:247,speed:[11,47,62,82,86,87,93,116,134,213,252,285,319,341],spell:[15,19,28,57,60,109,112,215,220,252],spell_attack:220,spell_conjur:220,spell_heal:220,spell_nam:220,spellnam:220,spend:[39,89,91,119,217,218,219,220,221],spend_act:[217,218,219,220,221],spend_item_us:219,spent:220,sphinx:38,spin:[62,90,170],spit:[3,60,116],splashscreen:186,split:[9,25,31,33,41,58,91,104,105,111,118,121,123,131,136,138,151,167,184,232,235,249,293,308,321,322,331],split_2:138,split_nested_attr:159,splithandl:138,spoken:[0,46,72,205,206,247],spool:63,sport:87,spot:[57,64,144],spread:[70,73,109],spring:[82,124,187],sprint:213,sprofil:267,spunki:77,spyrit:24,sql:[7,36,56,57,64,86,125,139,302,364],sqlite3:[25,55,64,86,123,127,128,131,344],sqlite3_prep:305,sqlite:[23,86,128,305],sqllite:36,sqrt:39,squar:[38,39,129],squeez:86,src:[10,17,20,59,75,80,89,100,102,133,137,139,210],srcobj:[154,167],srun:271,srv:36,ssessionhandl:83,ssh:[9,25,40,55,64,83,90,105,110,141,142,262,275,306,307],ssh_interfac:90,ssh_port:90,sshd:103,sshfactori:287,sshprotocol:287,sshserverfactori:287,sshuserauthserv:287,ssl:[7,8,43,55,64,67,83,88,141,142,146,164,262,275,279,292,307],ssl_context:[288,292],ssl_interfac:90,ssl_port:90,sslcertificatefil:8,sslcertificatekeyfil:8,sslciphersuit:8,sslengin:8,ssllab:8,sslprotocol:[8,288,292],ssltest:8,sslv3:67,sta:327,stab:[29,122,232],stabil:[61,170,205],stabl:[37,40,56,60,100],stabli:[97,261],stack:[13,31,61,121,137,152,153,247,251,308,328],stackexchang:127,stacktrac:251,staf:108,staff:[9,19,25,57,61,68,73,80,108,109,111,123,133,152,252,322],staffer:9,staffernam:9,stage:[2,36,56,61,77,111,123,131,133],stagger:279,stai:[1,31,49,51,63,90,91,121,125,126,138,235],stale:[100,125,260],stale_timeout:260,stamina:[30,190,220],stamp:[27,43,96,105,125,137,144,148,157,169,246,256,299,304,318],stanc:[116,206,247],stand:[13,17,20,21,22,25,29,38,43,49,56,61,63,72,73,80,86,90,95,96,111,116,121,122,123,127,131,133,138,165,179,206,231,247,256,261,298,319,322,324,330],standalon:[67,103],standard:[0,1,6,8,9,15,21,27,30,41,43,50,57,58,59,63,64,79,83,88,91,95,103,113,114,116,120,126,131,136,139,141,144,156,185,186,206,234,247,287,289,294,311,316,321,330,331,345,364],stanza:277,star:[43,159],stare:131,start:[0,1,2,3,4,5,7,12,13,14,15,16,18,20,21,23,25,26,27,29,31,33,34,38,39,40,41,42,43,44,45,47,48,49,50,51,54,55,57,59,60,61,62,64,65,66,67,69,70,72,73,74,75,76,77,79,80,83,84,86,87,90,91,93,95,96,97,98,101,102,103,104,105,106,107,108,109,111,114,116,119,120,121,123,124,125,127,128,130,131,132,133,136,137,138,139,144,146,151,152,158,159,164,165,166,167,168,169,170,175,179,180,185,187,188,189,190,195,205,206,215,217,218,219,220,221,226,230,231,233,235,247,249,251,256,258,259,260,261,264,267,269,271,272,277,278,279,280,284,285,286,291,292,298,299,304,305,308,312,317,321,322,323,324,326,328,329,330,331,337,344,347,363,364],start_all_dummy_cli:298,start_attack:231,start_bot_sess:308,start_delai:[102,116,120,121,256,261,324],start_driv:121,start_evennia:267,start_hunt:231,start_idl:231,start_index:164,start_lines1:267,start_lines2:267,start_loc_on_grid:49,start_olc:249,start_only_serv:267,start_ov:51,start_patrol:231,start_plugin_servic:40,start_portal_interact:267,start_serv:277,start_server_interact:267,start_sunrise_ev:62,start_text:215,start_turn:[217,218,219,220,221],startapp:[69,86,133,134],startclr:114,startedconnect:[264,278,279],starter:[9,136],starthour:25,startnod:[51,85,188,230,249,328],startnode_input:[51,188,230,249,328],startproduc:269,startservic:[270,312],startset:233,startswith:[41,43,84,159,170,321],starttupl:287,startup:[11,35,40,60,62,90,102,104,136,247,256,259,296,305,337,344],stat:[17,43,60,61,71,85,116,123,133,134,136,139,169,179,217,218,219,220,221,364],state:[11,13,14,31,33,42,43,50,51,55,56,64,80,95,100,102,105,110,114,116,121,122,126,127,131,137,138,144,150,152,153,156,163,171,175,212,217,218,219,220,221,226,231,233,252,256,258,259,261,267,287,316,326,328],state_unlog:163,statefultelnetprotocol:[290,298],statement:[10,13,14,27,31,42,49,51,55,58,59,83,86,95,96,118,119,124,226,322,343],static_overrid:[135,136,137],static_root:136,statict:[43,169],station:121,stationari:231,statist:[3,12,43,104,105,120,124,135,169,190,300,317,334],statu:[20,29,51,58,61,88,90,104,105,115,131,179,219,220,221,231,261,265,267,276,277,278,281,295],status:61,status_cod:269,stderr:234,stdin_open:100,stdout:[59,100,234,267,337],steadi:64,steal:[43,85,166],steer:121,step1:29,step2:29,step3:29,step:[0,4,7,8,13,14,21,23,29,31,33,36,38,39,41,43,45,46,50,51,58,63,69,73,77,82,85,86,91,97,100,102,106,108,121,122,123,126,127,128,134,138,139,158,164,180,233,261,271,283,294,298,299,308,318,322,325,326,328,329,363,364],stick:[15,33,38,43,51,63,113,157],still:[0,1,4,6,9,11,13,14,15,19,20,22,25,26,29,31,33,37,38,39,40,41,43,49,55,57,58,60,62,63,64,77,78,79,83,91,95,96,102,103,105,106,107,108,110,114,121,122,123,125,126,128,131,134,138,152,159,164,166,175,186,215,217,218,219,220,221,230,233,235,247,251,258,299,328,330,331,340,344],sting:111,stock:[34,55,85,101,210,357],stolen:[103,321],stone:[20,33,60],stoni:60,stop:[7,9,10,12,14,20,25,27,29,34,41,42,43,49,51,57,58,62,63,67,74,77,80,82,89,90,93,95,96,100,102,104,105,106,108,115,116,120,121,123,128,137,139,156,159,164,169,175,179,184,194,196,206,212,213,218,221,226,247,258,259,260,261,266,267,269,272,284,285,305,306,312,321,322,324,344,364],stop_driv:121,stop_evennia:267,stop_serv:277,stop_server_onli:267,stopproduc:269,stopservic:[270,312],storag:[11,13,23,28,29,33,43,47,56,64,73,85,86,96,102,125,133,138,148,169,177,198,205,235,242,246,247,251,252,256,259,261,274,310,314,316,318,323,338,339],storage_modul:323,storagecontain:102,storagescript:102,store:[0,2,9,13,15,21,23,27,28,29,31,33,34,37,39,40,41,43,44,46,47,49,50,55,56,57,58,60,61,64,69,73,75,80,82,85,86,87,89,91,95,97,100,102,104,105,112,113,115,116,119,121,123,125,127,128,131,133,134,135,136,137,138,139,144,146,148,153,156,157,159,160,162,166,167,177,179,187,188,195,202,204,205,206,210,213,214,219,223,232,233,235,241,242,246,250,251,252,253,257,258,259,260,261,267,271,272,273,274,277,279,280,281,283,291,294,299,305,306,307,308,310,312,316,317,318,319,321,323,324,325,326,327,328,329,334,338,339,340,344,357],store_kei:[261,344],store_result:48,store_tru:234,stored_obj:25,storekei:[85,261],storenam:85,storeroom:85,storeroom_exit:85,storeroom_kei:85,storeroom_key_nam:85,stori:[3,9,97,133],storm:[28,119],storypag:3,storytel:123,stove:247,str:[0,10,11,22,25,27,39,40,50,51,58,59,60,73,74,84,91,96,113,114,119,125,127,133,134,141,144,146,150,151,152,153,154,159,164,166,170,175,176,177,179,180,182,184,187,188,189,190,192,193,194,195,198,199,204,205,206,210,212,215,217,218,219,220,221,226,230,233,234,235,238,239,242,246,247,250,251,252,257,258,259,261,264,265,267,272,273,274,276,277,278,279,280,282,285,286,287,290,291,292,295,296,298,304,305,306,307,308,310,311,312,316,317,318,319,321,322,323,324,326,327,328,329,330,337,338,339,340,341,342,343,344,345,349],straight:[49,68,126],straightforward:[25,41,85,91,121,123],strang:[6,8,14,29,41,56,131,153],strangl:90,strategi:[42,221],strattr:[1,11,316],strawberri:234,stream:[106,276,280,306],streamlin:[36,179],strength:[11,57,58,60,61,73,80,116,134],stress:[93,298],stretch:111,stribg:344,strict:[10,251,321],stricter:251,strictli:[19,51,59,77,133,186,220,330],strike:[43,51,82,116,165,214,220,221],string1:344,string2:344,string:[5,9,11,12,13,15,19,20,22,23,25,27,29,31,33,34,35,38,41,42,43,49,50,54,55,57,58,59,60,62,68,71,76,82,83,84,86,87,88,89,90,93,95,96,97,104,109,111,112,113,114,115,116,119,124,125,127,129,133,134,137,138,139,141,142,144,146,148,150,151,154,157,159,164,165,166,167,168,169,170,175,176,177,179,180,182,186,188,198,199,203,204,205,206,210,211,215,217,218,219,220,221,226,230,231,235,238,239,240,241,242,246,247,250,251,252,256,259,261,267,269,272,276,279,287,290,291,293,299,304,306,308,311,316,317,318,319,320,321,322,324,325,326,327,329,330,337,338,340,341,342,343,344,345],string_from_modul:344,string_partial_match:344,string_similar:344,string_suggest:344,stringproduc:269,strip:[21,22,33,38,41,43,51,58,74,81,85,108,109,114,118,123,151,159,167,168,170,206,252,272,287,290,291,321,322,326,328,344],strip_ansi:[81,321,343],strip_control_sequ:344,strip_mxp:321,strip_raw_ansi:321,strip_raw_cod:321,strippabl:328,stroll:213,strong:[80,114,123,343],strongest:80,strongli:[64,73,95,124,205],strr:204,struct:56,structur:[9,11,33,37,41,43,45,47,48,49,51,55,56,59,63,64,68,69,80,83,88,95,96,109,119,133,134,136,138,159,164,175,206,247,251,252,291,296,319,325,328,354],strvalu:[11,316,317],stuck:[51,63],studi:59,stuff:[3,9,11,21,29,31,37,38,47,49,51,57,61,67,73,80,85,96,102,105,107,109,119,138,153,159,170,189,234,261,305,350],stumbl:97,stupidli:34,sturdi:327,stutter:108,style:[3,16,20,21,27,33,37,38,40,41,45,51,55,57,58,61,79,87,95,106,111,114,116,122,124,129,138,148,154,156,167,182,183,188,199,217,234,251,326,330,344],styled_foot:154,styled_head:[33,154],styled_separ:154,styled_t:[33,154],sub:[9,11,36,37,38,57,65,69,88,90,108,109,116,119,137,138,143,149,164,166,172,178,180,206,234,236,238,240,243,252,253,262,314,320,321,343,346,361],sub_ansi:321,sub_app:133,sub_brightbg:321,sub_dblspac:343,sub_mxp_link:343,sub_mxp_url:343,sub_text:343,sub_to_channel:164,sub_xterm256:321,subbed_chan:164,subcategori:166,subclass:[27,64,105,109,118,119,125,159,180,235,246,251,256,277,290,296,318,335,340,344],subdir:127,subdirectori:[37,127],subdomain:[8,90,103],subfold:[47,86,95,96,134,135],subhead:38,subject:[36,39,81,86,90,124,189,199],submarin:121,submenu:[106,180,249],submenu_class:180,submenu_obj:180,submiss:[188,357],submit:[17,37,103,133,188,357],submitcmd:188,submodul:291,subnegoti:291,subnet:[12,43,157],subpackag:[88,127],subprocess:[25,344],subreddit:79,subscrib:[12,33,34,41,43,53,58,64,80,115,128,132,146,164,175,176,219,261,278,309],subscribernam:164,subscript:[33,43,58,79,115,132,164,176,177,261],subsequ:[10,11,33,43,95,116,164,205,322,344],subsequent_ind:330,subset:[56,112,127],subsid:125,substitut:[51,71,87,106,247,321,343],substr:321,subsub:[166,170],subsubhead:38,subsubsubhead:38,subsubtop:[166,170],subsubtopicn:170,subsystem:[9,63,86,242],subtitl:17,subtop:[164,166,170],subtopic_separator_char:166,subtract:85,subturn:116,subword:344,succe:[61,116,185],succeed:[164,185,234],success:[73,116,123,134,144,164,175,179,185,217,218,219,220,221,226,232,233,242,251,260,267,271,318,326,338,344],success_teleport_msg:233,success_teleport_to:233,successfuli:203,successfulli:[10,28,33,36,60,77,110,111,130,144,203,232,235,247,260,267,279,311,318],suddenli:[26,97,318],sudo:[63,67,100,103],suffic:[17,57,61],suffici:[86,90,119],suffix:[27,97,114,321,337,344],suggest:[1,23,25,37,38,48,51,52,55,61,68,70,90,95,97,125,138,140,151,166,179,206,233,247,344],suggestion_cutoff:166,suggestion_maxnum:166,suit:[29,34,55,64,117,139,170,344],suitabl:[21,25,33,37,55,63,64,80,83,87,88,90,112,131,152,164,242,301,308,324,328],sum:[37,82,91,139,153],summar:[0,79,139],summari:[0,7,46,79,96,110,123,180],summer:187,sun:62,sunris:62,sunt:52,super_long_text:329,superfici:205,superflu:343,supersus:242,superus:[2,4,5,6,9,12,13,14,19,20,21,23,25,41,43,58,60,63,81,95,96,111,122,134,144,148,158,169,175,182,212,231,241,242,247,252,267,318,322,324],supplement:51,suppli:[10,11,27,34,37,43,51,58,59,63,68,72,74,84,88,93,102,105,109,112,114,115,116,123,127,148,153,154,157,159,164,169,170,176,180,184,186,187,190,246,247,251,256,261,278,308,318,326,331,341,344],supporst:294,support:[2,4,7,8,9,11,23,26,33,37,38,40,42,43,44,47,49,50,51,56,57,58,61,63,64,65,66,70,74,75,76,81,83,86,87,90,91,94,98,100,103,109,110,113,114,123,126,139,144,156,165,166,169,183,184,185,187,198,234,241,247,251,252,261,272,280,281,282,283,287,289,290,291,292,294,296,307,316,321,325,328,329,330,341,344,349,364],supports_set:[74,272],suppos:[0,33,51,61,76,83,109,119,138,144,180],supposedli:[67,205,291],suppress:[24,289],suppress_ga:[141,142,262,275],suppressga:289,supress:289,sur:79,sure:[0,2,4,5,8,9,11,12,13,14,15,19,20,21,23,25,28,29,30,31,33,36,37,38,41,42,43,44,49,51,57,58,60,61,62,63,67,71,72,73,75,78,80,81,86,87,89,90,91,93,95,96,97,100,102,105,106,109,110,111,112,113,115,116,118,123,125,126,127,128,131,133,134,136,137,138,140,144,146,152,153,154,156,159,167,176,180,182,196,204,205,206,211,215,220,223,231,232,233,238,241,242,247,251,252,258,267,271,277,279,284,305,311,312,313,317,318,321,323,325,328,334,340,341,343,344,360],surfac:[58,82,103],surpris:[22,39,69,80,91],surround:[31,33,43,111,116,119,129,157,231,340,344],surviv:[5,11,27,28,31,43,50,51,84,102,105,115,116,126,146,153,169,180,256,257,261,324,326,328,344],suscept:[27,56,242],suspect:133,suspend:[100,103,106],suspens:102,suspici:51,suspicion:133,svn:[36,108],swallow:[96,118,276,343],swap:[43,114,127,137,138,159,187,202,318,326],swap_autoind:326,swap_object:318,swap_typeclass:[60,125,144,318],swapcas:321,swapcont:138,swapper:318,swedish:76,sweep:102,swiftli:10,swing:[28,29,33,82],switch1:129,switch2:129,switch_map:169,switch_opt:[156,157,158,159,164,165,166,167,169,187],sword:[20,28,33,61,73,77,85,86,119,179,206,252,341,344],symbol:[14,15,33,49,75,106,108,119,215,235,329],symlink:[38,63],symmetr:330,sync:[64,83,105,131,285,290,305,306,307,308,316,325],sync_port:308,syncdata:[307,308],syncdb:127,synchron:337,syntact:[242,344],syntax:[5,6,13,14,15,21,22,23,29,33,41,43,46,48,51,55,58,60,62,76,80,91,97,114,119,123,129,134,141,142,154,158,159,166,167,170,180,185,187,188,234,242,247,267,279,306,316,318,320,321,364],syntaxerror:60,sys_cmd:152,sys_game_tim:59,syscmdkei:[33,53,141],syscommand:[141,142,149,155,247],syslog:209,sysroot:75,system:[0,2,4,5,9,10,11,19,21,22,23,26,27,28,29,31,34,36,37,38,39,40,41,44,46,47,49,53,55,56,59,60,62,63,64,67,74,75,76,77,79,81,83,84,85,86,87,90,93,95,97,102,103,104,105,107,108,109,110,111,112,114,115,119,121,122,125,126,127,128,129,131,132,134,136,138,139,140,141,142,146,148,149,150,152,154,155,156,158,166,168,170,172,175,176,177,179,180,182,186,193,194,195,196,198,199,202,203,205,206,209,210,211,215,217,218,219,220,221,230,233,235,236,239,241,242,246,247,249,252,253,267,290,296,304,314,318,322,324,327,328,337,363,364],system_command:33,systemat:39,systemctl:8,systemd:67,systemmultimatch:168,systemnoinput:168,systemnomatch:168,tab:[9,14,26,30,36,59,69,95,96,106,114,137,138,321,330,343],tabl:[0,4,13,15,43,45,46,48,53,58,59,64,69,82,88,97,111,113,114,119,125,128,134,154,156,164,166,169,188,291,310,321,327,329,330,341,344],table_char:327,table_format:156,table_lin:330,table_str:58,tablea:327,tableb:327,tablechar:[58,327],tableclos:[88,291],tablecol:330,tableopen:[88,291],tablet:16,tabletop:[58,73,79,124,217,221],tabsiz:[321,330],tabstop:343,tack:[20,119,153],tackl:37,tactic:[73,116],taction:116,tag:[9,12,13,18,20,24,27,33,45,48,51,53,55,57,58,64,73,74,86,87,88,95,96,100,109,114,119,124,125,134,136,137,138,139,140,141,142,154,156,157,158,159,164,165,166,167,168,169,170,171,175,177,179,180,181,182,183,185,186,187,188,189,193,199,202,203,204,206,209,212,213,214,215,217,218,219,220,221,226,230,231,232,233,234,239,241,247,251,252,282,296,298,304,314,317,318,321,324,326,327,328,329,330,341,344,364],taghandl:[112,125,319],tagkei:[241,319,324],taglin:17,tagnam:252,tagstr:[252,319],tagtyp:[112,317,319,341],tail:[76,90,100,267,337],tail_log_fil:[267,337],tail_log_funct:337,tailor:[4,69,357],take:[0,3,4,9,10,11,13,14,15,16,17,19,20,21,22,25,26,27,28,29,31,33,37,40,42,46,49,51,52,55,56,57,58,62,64,69,70,74,75,76,77,79,80,83,85,90,91,95,96,103,104,105,106,108,109,111,114,116,119,121,122,123,124,125,126,127,133,134,136,138,139,144,146,151,152,156,168,170,175,177,179,182,184,187,188,203,204,206,209,213,215,217,218,219,220,221,226,230,231,233,242,252,271,287,295,298,307,308,317,318,321,326,327,328,329,338,344,345],taken:[31,43,56,64,103,116,120,121,123,165,186,209,217,218,219,220,221,247,287,311,321,324],takeov:309,taladan:48,tale:3,talk:[23,27,33,34,37,40,41,43,46,58,60,90,91,131,138,164,165,179,205,206,214,233,264],talker:[55,61],talki:64,talking_npc:[141,142,178],talkingcmdset:214,talkingnpc:214,tall:[43,129,165,206],tallman:[43,165],tandem:61,tantal:14,target1:220,target2:220,target:[21,25,28,29,30,33,34,40,43,58,73,88,103,114,116,119,123,127,136,138,144,154,159,164,165,169,175,177,182,185,187,199,215,217,218,219,220,221,231,235,247,317,321,324,328,344],target_loc:[213,233,235,247],target_obj:242,targetlist:199,task:[0,27,36,40,41,91,93,102,110,112,138,169,170,193,195,215,260,261,344],task_handl:[141,260,344],task_id:[169,195,260],taskhandl:[141,142,253,344],taskhandlertask:[260,344],tast:[22,34,133],tavern:206,tax:[75,93],taylor:79,tb_basic:[141,142,178,216],tb_equip:[141,142,178,216],tb_filenam:322,tb_item:[141,142,178,216],tb_iter:322,tb_magic:[141,142,178,216],tb_rang:[141,142,178,216],tbbasiccharact:217,tbbasicturnhandl:217,tbearmor:218,tbequipcharact:218,tbequipturnhandl:218,tbeweapon:218,tbitemscharact:219,tbitemscharactertest:219,tbitemsturnhandl:219,tbmagiccharact:220,tbmagicturnhandl:220,tbodi:134,tbrangecharact:221,tbrangeobject:221,tbrangeturnhandl:221,tchar:116,tcp:[55,103],tcpserver:[40,312],teach:124,team:[33,36,61,64,70,108,131],teardown:[127,170,196,228,293,342],teaser:90,tech:79,technic:[4,6,9,10,11,19,20,23,39,40,51,64,70,83,90,108,112,114,119,125,139,141,142,178,179,222,316],techniqu:[29,139,321],tediou:[1,106,111],teenag:[21,103],tehom:[9,119],tehomcd:9,tel:[0,12,58,63,91,121,159],teleport:[12,14,20,43,58,85,122,140,159,165,233,322],teleportroom:233,televis:31,tell:[0,3,5,8,10,12,13,19,21,22,23,26,29,31,33,41,42,43,46,49,51,58,59,60,61,69,73,74,75,76,77,80,83,86,87,90,91,93,95,96,100,102,103,109,110,116,117,121,127,128,130,131,132,134,135,139,146,156,164,165,177,185,206,233,247,267,285,296,308,326],telnet:[9,15,25,30,40,43,55,63,64,75,79,83,100,101,103,105,110,114,137,138,141,142,166,169,262,275,280,281,282,283,287,288,289,291,292,294,298,306,307,343],telnet_:90,telnet_hostnam:54,telnet_interfac:90,telnet_oob:[88,141,142,262,275],telnet_port:[9,36,54,90,299],telnet_ssl:[141,142,262,275],telnetoob:291,telnetprotocol:[288,290,292],telnetserverfactori:290,temp:177,tempat:188,templat:[2,3,4,5,27,31,43,47,64,81,87,104,107,109,123,125,131,134,135,136,137,138,141,142,164,165,167,175,188,230,267,296,306,307,316,320,327,347,350,355],template2menu:[51,328],template_overrid:[4,135,136,137],template_regex:316,template_rend:107,template_str:[51,87],templates_overrid:135,templatestr:327,templatetag:[141,142,346,356],tempmsg:177,temporari:[6,11,110,122,127,131,153,177,198,217,218,219,220,221,261,328],temporarili:[20,26,31,43,51,60,90,97,102,127,164,169,195,203,226],tempt:[43,61,95,104,157],ten:[29,90,111],tend:[41,43,57,61,64,73,76,86,90,97,103,119,121,124,129,138,159,205,209],tent:[45,111,139],terabyt:25,term:[0,10,31,62,63,64,69,90,91,96,126,139,154,204,310],term_siz:[42,141],termin:[4,23,26,27,38,42,47,59,60,63,64,75,90,93,95,96,97,100,103,106,110,114,123,126,131,138,139,141,169,194,215,217,218,219,220,221,266,267,287,294,310],terminalrealm:287,terminals:287,terminalsessiontransport:287,terminalsessiontransport_getp:287,terrain:49,terribl:280,ters:102,test1:[11,74,330],test2:[11,33,74,114],test3:[11,330],test4:[11,330],test5:11,test6:11,test7:11,test8:11,test:[0,5,10,11,13,14,15,17,19,20,21,22,23,24,25,29,31,33,36,37,38,41,42,43,45,46,50,51,56,58,60,61,62,63,65,67,68,69,72,73,74,79,80,81,85,89,90,91,95,96,98,106,107,109,111,115,116,120,124,130,131,132,133,137,138,139,141,142,149,151,155,156,158,166,169,178,182,185,187,188,191,207,208,215,217,218,219,220,221,222,223,230,251,262,269,272,275,296,297,298,302,318,320,321,322,324,328,332,342,344,346,348,350,356,364],test_:127,test_about:170,test_accept:196,test_access:170,test_active_task:170,test_add:196,test_add_valid:196,test_all_com:170,test_alternative_cal:127,test_amp_in:293,test_amp_out:293,test_at_repeat:228,test_attribute_command:170,test_audit:211,test_ban:170,test_batch_command:170,test_bold:293,test_c_creates_button:303,test_c_creates_obj:303,test_c_dig:303,test_c_examin:303,test_c_help:303,test_c_login:303,test_c_login_no_dig:303,test_c_logout:303,test_c_look:303,test_c_mov:303,test_c_move_:303,test_c_move_n:303,test_c_soci:303,test_cal:[170,196],test_cancel:170,test_cas:127,test_cboot:170,test_cdesc:170,test_cdestroi:170,test_channel__al:170,test_channel__alias__unalia:170,test_channel__ban__unban:170,test_channel__boot:170,test_channel__cr:170,test_channel__desc:170,test_channel__destroi:170,test_channel__histori:170,test_channel__list:170,test_channel__lock:170,test_channel__msg:170,test_channel__mut:170,test_channel__noarg:170,test_channel__sub:170,test_channel__unlock:170,test_channel__unmut:170,test_channel__unsub:170,test_channel__who:170,test_char_cr:170,test_char_delet:170,test_clock:170,test_color:293,test_color_test:170,test_copi:170,test_creat:170,test_cwho:170,test_data_in:293,test_data_out:293,test_del:196,test_desc:170,test_desc_default_to_room:170,test_destroi:170,test_destroy_sequ:170,test_dig:170,test_do_nested_lookup:170,test_do_task:170,test_echo:170,test_edit:196,test_edit_valid:196,test_emit:170,test_empty_desc:170,test_examin:170,test_exit:196,test_exit_command:170,test_find:170,test_forc:170,test_func_name_manipul:170,test_general_context:352,test_get:360,test_get_and_drop:170,test_get_authent:360,test_get_dis:360,test_giv:170,test_handl:196,test_help:170,test_hom:170,test_ic:170,test_ic__nonaccess:170,test_ic__other_object:170,test_ident:293,test_idl:303,test_info_command:170,test_interrupt_command:170,test_invalid_access:360,test_inventori:170,test_ital:293,test_large_msg:293,test_list:196,test_list_cmdset:170,test_lock:[170,196],test_look:170,test_mask:211,test_memplot:303,test_menu:215,test_messag:304,test_misformed_command:170,test_mudlet_ttyp:293,test_multimatch:170,test_mux_command:170,test_mycmd_char:127,test_mycmd_room:127,test_nam:170,test_nested_attribute_command:170,test_new_task_waiting_input:170,test_nick:170,test_no_input:170,test_no_task:170,test_object:170,test_object_search:127,test_ooc:170,test_ooc_look:170,test_opt:170,test_pag:170,test_password:170,test_pause_unpaus:170,test_perm:170,test_persistent_task:170,test_pi:170,test_plain_ansi:293,test_pos:170,test_quel:170,test_queri:[141,142,262,297],test_quit:170,test_remov:170,test_resourc:[127,141,142,170,196,211,228,293,320,360],test_responce_of_y:170,test_return_valu:127,test_sai:170,test_script:170,test_send_random_messag:228,test_server_load:170,test_sess:170,test_set_game_name_and_slogan:352,test_set_help:170,test_set_hom:170,test_set_obj_alia:170,test_set_webclient_set:352,test_simpl:127,test_simple_default:170,test_spawn:170,test_split_nested_attr:170,test_start:196,test_subtopic_fetch:170,test_subtopic_fetch_00_test:170,test_subtopic_fetch_01_test_creating_extra_stuff:170,test_subtopic_fetch_02_test_cr:170,test_subtopic_fetch_03_test_extra:170,test_subtopic_fetch_04_test_extra_subsubtop:170,test_subtopic_fetch_05_test_creating_extra_subsub:170,test_subtopic_fetch_06_test_something_els:170,test_subtopic_fetch_07_test_mor:170,test_subtopic_fetch_08_test_more_second_mor:170,test_subtopic_fetch_09_test_more_mor:170,test_subtopic_fetch_10_test_more_second_more_again:170,test_subtopic_fetch_11_test_more_second_third:170,test_tag:170,test_task_complete_waiting_input:170,test_teleport:170,test_toggle_com:170,test_tunnel:170,test_tunnel_exit_typeclass:170,test_typeclass:170,test_upp:127,test_valid_access:360,test_valid_access_multisession_0:360,test_valid_access_multisession_2:360,test_valid_char:360,test_wal:170,test_whisp:170,test_who:170,test_without_migr:127,test_wrong_func_nam:170,testabl:127,testaccount:170,testadmin:170,testampserv:293,testapp:133,testbatchprocess:170,testbodyfunct:228,testbuild:170,testcas:[127,293,303,335,342,352],testcmdcallback:196,testcmdtask:170,testcomm:170,testcommand:51,testcommschannel:170,testdefaultcallback:196,testdummyrunnerset:303,testdynamic:127,tester:[90,119,285],testeventhandl:196,testform:327,testgener:170,testgeneralcontext:352,testhelp:170,testid:33,testinterruptcommand:170,testirc:293,testmemplot:303,testmenu:[188,328],testmixedrefer:335,testmod:308,testmymodel:127,testnnmain:170,testnod:51,testobj:127,testobject:127,testobjectdelet:335,testok:91,testregularrefer:335,testset:127,testsharedmemoryrefer:335,teststr:127,testsystem:170,testsystemcommand:170,testtelnet:293,testunconnectedcommand:170,testvalu:11,testwebsocket:293,text2html:[141,142,320],text:[0,1,2,5,7,9,10,13,14,15,17,18,21,22,24,26,30,33,34,35,37,40,43,45,46,48,50,52,53,55,56,57,58,59,60,63,68,72,73,76,77,78,79,80,81,83,85,86,87,88,90,91,95,96,97,98,100,108,109,110,111,112,118,121,123,124,126,127,131,133,137,138,139,144,146,151,154,156,157,158,159,164,165,166,167,168,169,170,171,176,177,179,180,181,182,185,186,187,188,189,190,193,195,199,202,203,205,206,210,212,213,214,215,217,218,219,220,221,226,231,232,233,234,239,242,247,249,252,256,264,265,272,278,279,282,285,286,287,290,291,295,296,298,306,307,308,311,312,316,317,319,321,322,324,326,327,328,329,330,338,341,343,344,345,357,364],text_:38,text_color:190,text_exit:[22,180],text_single_exit:22,textarea:[340,357],textbook:40,textbox:357,textfield:[86,133],textn:170,textstr:74,texttag:[81,126,139,364],texttohtmlpars:343,textual:39,textwrap:330,textwrapp:330,than:[0,2,4,6,8,11,13,14,16,19,23,25,26,29,31,33,35,37,38,39,42,43,46,47,49,51,52,54,55,57,58,60,61,62,64,68,69,71,73,76,80,82,86,89,90,91,93,95,97,103,104,105,106,109,110,112,113,114,115,116,119,122,123,125,126,127,128,129,131,134,135,137,138,139,144,148,151,152,153,156,157,158,159,160,164,166,167,169,170,179,180,181,184,190,195,204,205,206,213,215,217,218,219,220,221,232,234,241,247,249,251,267,293,308,313,316,317,318,321,322,328,329,330,334,337,339,340,341,343,344,347],thank:[4,102,134,138,199,312],thankfulli:133,thead:134,thei:[0,1,2,4,5,6,8,9,10,11,12,13,14,15,16,17,19,20,21,22,23,25,27,29,30,31,33,34,37,38,39,40,41,42,43,44,46,48,51,55,56,57,58,61,63,64,66,68,69,73,75,77,78,80,81,83,85,86,88,89,90,91,92,93,95,96,97,102,103,105,106,107,108,109,110,111,112,113,114,116,118,119,121,122,123,124,125,126,127,131,132,134,136,137,138,139,140,144,152,153,156,158,159,164,165,167,168,169,175,179,180,182,185,187,189,194,205,206,217,218,219,220,221,232,233,234,235,241,242,246,247,251,252,253,256,258,259,261,267,287,288,290,291,292,296,299,305,306,307,308,310,316,321,322,323,325,328,330,344,345,357],theirs:[116,181,189],them:[0,2,4,5,6,9,10,11,12,13,14,15,16,21,22,23,25,26,27,28,29,30,31,33,34,35,37,38,39,40,41,43,46,48,50,51,54,55,57,58,59,60,61,62,64,66,68,69,71,73,74,75,76,77,80,82,83,85,86,87,88,89,90,91,95,96,97,98,102,103,104,105,106,109,110,111,112,113,114,115,116,118,119,121,122,123,124,125,126,127,128,131,133,134,135,136,137,138,139,140,144,150,151,152,154,156,158,159,164,166,167,170,175,181,182,183,187,188,189,190,192,194,203,204,206,215,217,218,219,220,221,226,231,233,234,238,242,247,252,258,261,267,285,287,290,298,302,305,306,308,316,318,319,321,322,324,328,340,343],themat:61,theme:[61,134],themself:219,themselv:[0,11,19,21,28,31,33,43,49,51,55,58,69,72,73,80,81,85,89,97,102,107,113,119,121,123,125,127,132,138,140,159,206,247,256,259,267,317,319,340],theoret:[31,108],theori:[31,42,57,79,123,139,144,152,364],thereaft:87,therefor:[0,49,62,68,91,102,122,127,158,180,192],therein:[15,33,156,167,169,187,203,233],thereof:[206,247],thi:[0,1,2,3,4,5,6,8,9,10,11,12,13,14,15,16,18,19,20,21,22,23,24,25,26,27,28,29,30,31,33,34,35,36,37,38,39,40,42,43,44,45,46,47,48,49,50,51,52,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,70,71,72,73,74,75,76,77,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,143,144,146,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,192,193,194,195,198,199,202,203,204,205,206,209,210,212,213,214,215,217,218,219,220,221,223,226,229,230,231,232,233,234,235,236,238,239,240,241,242,243,246,247,250,251,252,253,256,257,258,259,260,261,262,264,265,266,267,269,271,272,273,274,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,294,295,296,298,299,300,301,302,304,305,306,307,308,309,310,311,312,313,314,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,334,335,337,338,339,340,341,342,343,344,345,346,347,349,350,354,355,357,361,363],thie:51,thief:61,thieveri:[43,166],thin:[10,22,29,111,182,337],thing:[0,1,3,4,5,6,8,9,10,11,12,13,15,19,20,21,22,25,26,27,28,29,30,31,33,34,37,39,40,41,43,46,47,48,49,50,51,55,58,59,60,61,63,64,67,69,70,71,73,74,75,76,79,80,82,83,85,86,89,90,91,93,95,96,97,100,102,103,104,105,107,108,109,110,111,114,115,116,118,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,144,152,153,159,179,180,187,195,205,206,215,221,226,230,233,234,242,246,247,271,276,280,312,316,318,321,322,330,340],think:[1,20,29,31,34,37,46,48,51,55,59,61,62,67,70,73,79,81,91,95,96,97,109,111,112,114,115,135,138,139,308],third:[0,8,9,23,27,37,38,39,42,43,51,64,69,72,75,90,96,101,114,121,127,128,134,159,170,321,328],thirdnod:51,this_sign:309,thoma:[12,43,87,157],thorn:[11,89],thorough:26,those:[2,3,4,6,9,11,13,14,15,19,20,21,23,28,30,31,33,35,36,43,44,47,48,51,55,56,57,58,60,61,62,64,68,71,73,77,78,79,80,81,85,86,88,89,90,95,96,103,105,109,110,111,112,114,118,119,121,123,124,125,127,128,130,131,135,136,138,153,154,156,159,164,165,166,170,176,180,206,210,215,217,226,232,233,242,251,252,260,290,295,298,317,318,328,329,330,338,339,342,344,357],though:[2,10,11,12,13,14,15,22,23,26,27,30,31,37,39,41,51,57,59,60,62,63,64,69,72,75,79,81,89,90,91,96,97,100,102,103,104,110,116,119,121,122,123,126,127,128,129,130,131,138,144,154,180,181,190,217,218,220,221,233,234,247,252,316,321,328,344],thought:[23,39,61,79,80,84,138],thousand:[39,90,111,133],thread:[23,27,55,79,110,286,312,337,344],threadpool:312,threat:103,three:[0,4,12,13,16,22,25,31,33,38,46,51,69,80,83,85,87,89,90,114,133,134,135,151,164,166,215,220,242,321,328],threshold:[228,310,322],thrill:85,throttl:[141,142,144,262,272,285],through:[0,1,2,5,9,13,14,17,23,25,27,30,31,33,34,38,39,40,41,44,46,48,51,52,55,56,57,58,59,60,61,62,64,68,69,70,71,76,77,80,83,85,87,88,89,90,91,93,96,97,98,99,103,104,105,106,107,108,109,110,114,116,117,119,121,122,124,136,138,139,140,141,144,153,159,164,166,170,179,187,192,210,212,217,218,219,220,221,235,240,242,246,247,257,258,261,267,269,274,283,287,290,296,299,304,306,307,317,318,322,324,327,328,329,343,344,357],throughout:[11,20,49,51,55,104,219],throughput:[175,324],thrown:116,thrust:232,thu:[14,19,31,33,39,43,44,51,54,57,58,73,80,83,86,96,108,111,114,121,122,123,125,134,135,136,156,160,181,205,242,247,261,299,313,316,317,324],thub:43,thud:189,thumb:[114,131],thumbnail:4,thunder:23,thunderstorm:122,thusli:75,tick:[23,33,38,51,64,115,131,132,139,219,231,233,261,299],ticker1:[115,261],ticker2:[115,261],ticker:[53,55,74,102,132,139,146,231,233,257,261,272,344],ticker_class:261,ticker_handl:[115,132,141,261,344],ticker_pool_class:261,ticker_storag:261,tickerhandl:[27,45,102,116,132,139,141,142,213,219,233,253,344,364],tickerpool:261,tickerpool_layout:261,tidbit:55,tidi:100,tie:[83,116,138],tied:[64,119,153,166,182,226,239],tier:90,ties:[49,135,161],tight:182,tightli:[103,175],tim:[182,188,190,215,217,218,219,220,221],time:[0,1,2,4,5,6,8,9,10,11,12,13,14,17,20,21,22,23,25,26,28,29,30,31,34,36,37,39,40,41,42,45,49,51,52,53,54,55,56,58,59,60,61,63,64,65,66,67,69,70,72,73,75,80,83,86,88,89,90,91,93,95,96,100,104,105,106,109,110,113,114,115,116,117,119,121,122,123,124,125,127,128,129,131,132,133,135,138,139,144,146,148,150,151,153,154,157,164,169,175,177,179,184,185,187,194,195,198,203,204,205,212,213,215,217,218,219,220,221,223,226,231,232,233,239,246,247,250,252,253,256,259,260,261,267,269,271,273,274,279,285,290,292,298,299,300,304,305,306,308,310,316,318,319,321,322,323,324,329,331,334,335,337,340,344,363],time_ev:198,time_factor:[27,62,184,331],time_format:[59,344],time_game_epoch:[27,62,331],time_to_tupl:184,time_unit:[62,184],time_until_next_repeat:102,timedelai:[29,260,342,344],timedelta:[338,345],timeeventscript:195,timefactor:62,timeformat:[337,344],timeit:93,timeout:[63,67,116,120,290,310,334],timer:[20,27,33,47,56,64,83,102,115,116,169,187,219,223,226,232,253,259,260,261,298,306,341],timerobject:102,timescript:331,timeslot:187,timestamp:[25,27,298,299,310,331],timestep:299,timestr:337,timetrac:[141,142,262,297],timetupl:62,timezon:[23,337,338,345],tini:[23,39,81],tinker:97,tintin:[24,280,281,291,294],tinyfugu:24,tinymud:[57,108],tinymush:[57,108,129],tinymux:[57,108],tip:[12,37,70,79,103,112],tire:[20,153],titeuf87:235,titl:[17,22,34,43,48,69,98,137,164,166,180,238,321,324],title_lone_categori:166,titlebar:137,titleblock:69,tlen:71,tls:8,tlsv10:67,tlsv1:8,tmp:[36,63],to_byt:344,to_closed_st:226,to_cur:219,to_displai:180,to_dupl:152,to_execut:344,to_exit:0,to_fil:209,to_init:221,to_non:247,to_obj:[144,154,247],to_object:176,to_open_st:226,to_pickl:325,to_str:344,to_syslog:209,tobox:276,toc:363,todai:[138,190],todo:58,toe:108,togeth:[0,3,8,9,14,22,29,31,33,38,43,48,49,57,58,61,64,68,71,73,83,89,90,92,116,119,122,123,124,125,126,127,131,138,150,159,161,166,187,202,203,205,206,232,233,246,252,276,295,308,321,322,341],toggl:[81,290],toggle_nop_keepal:290,togglecolor:81,toint:109,token:[71,287,290,322],told:[44,59,90,91,95,113,114,123,128,340],tolkien:62,tom:[43,58,87,123,129,159,165,189,206,327],tommi:[19,80,87],ton:[57,82],tone:114,tonon:[43,159],too:[0,4,6,9,11,12,13,14,17,20,21,22,25,27,29,33,38,39,41,42,43,46,47,48,49,51,57,58,59,60,61,63,69,73,80,83,84,85,91,93,96,106,114,116,121,122,123,125,128,131,133,138,157,159,178,215,220,226,241,272,276,310,312,322,327,328,329,330,341,344],took:[127,344],tool:[4,6,7,8,23,29,53,57,62,63,64,86,90,96,100,108,109,111,112,114,119,136,139],toolbox:79,tooltip:137,top:[5,9,13,22,26,29,31,33,38,39,47,48,50,52,57,58,59,60,63,68,69,75,79,85,93,95,96,101,102,104,110,111,112,117,123,125,130,131,133,134,138,139,148,153,177,180,182,184,202,206,215,234,235,239,246,256,267,309,316,318,319,322,329,330,337],topcistr:238,topic:[4,10,20,31,33,40,42,43,55,68,69,86,93,105,119,126,166,217,218,219,220,221,238,341,357],topicstr:238,tostr:276,total:[27,43,62,80,82,91,93,102,104,105,114,118,139,169,185,304,329,330,331],total_num:334,touch:[8,38,54,60,96,97,103,104,114,310],tour:91,toward:[22,33,40,42,91,102,111,190,221,231],tower:[111,187,233],trace:[83,96,195,304,328],traceback:[6,13,27,57,60,95,97,102,110,114,123,127,133,135,195,202,250,276,318,322,337,344],tracemessag:304,track:[11,27,30,49,57,61,64,73,77,82,86,95,98,99,100,102,105,116,121,128,132,133,138,144,153,175,221,257,278,279,284,287,290,305,310,325,326,338],tracker:[43,61,70,131],trade:[46,179],tradehandl:179,trader:46,tradetimeout:179,tradit:[10,15,36,73,74,83,90,103,114,116,138,235,290,306,329],tradition:[57,83],traffic:[8,103,280],train:79,traindriv:121,traindrivingscript:121,training_dummi:73,trainobject:121,trainscript:121,trainstop:121,trainstoppedscript:121,trait:[27,38,73,252],transact:179,transfer:[85,133,153,278,288,292,330],transform:36,transit:[89,124],translat:[14,40,45,79,87,88,113,114,126,205,206,252,269,321],transmiss:209,transmit:113,transpar:[67,105,126,137,138,246,261],transport:[276,287,296],transportfactori:287,transpos:126,trap:[14,82,122],traumat:51,travel:[49,82,83,88,96,213,235],travers:[11,44,49,80,85,89,121,212,213,231,232,235,241,247],traverse_:33,traversing_object:[212,213,235,247],travi:[45,139,364],treasur:[9,235],treat:[10,14,33,64,95,96,105,111,112,119,125,138,144,150,153,189,247,252,299,308,328,330,341],tree:[3,11,33,38,43,47,51,61,63,64,77,80,96,131,140,180,206,215,234,247,252,267,296,312,328,344],tree_select:[141,142,178],treestr:215,treshold:334,tri:[11,12,14,24,29,33,43,51,58,61,80,83,87,90,91,105,107,113,116,119,133,138,151,169,179,181,188,232,233,271,310,344,345],trial:[106,293],tribal:111,trick:[8,22,51,79,138,318,357],tricki:[109,126,127,138],trickier:[9,69],trigger:[21,24,31,33,36,42,46,49,51,56,57,69,74,83,84,89,100,105,107,114,115,116,117,118,121,134,135,138,144,146,150,151,154,156,170,180,198,226,231,233,246,247,252,261,269,272,276,298,305,309,324,328],trim:321,trip:96,tripl:[27,38,96,114,344],trivial:[27,33,40,42,91,93,138],troll:12,troubl:[5,8,9,23,41,46,58,63,70,75,91,105,131,139,316,363],troubleshoot:9,troublesom:[12,13,14],trove:9,truestr:188,truli:[0,12,39,41,105,187],trust:[19,43,51,57,169,322],truth:42,truthfulli:33,truthi:260,try_num_differenti:151,ttarget:116,tto:290,tty:[9,100],ttype:[55,141,142,262,275,287,290],ttype_step:294,tuck:111,tun:[43,159],tune:[67,126],tunnel:[0,20,22,44,49,58,121,159,292],tup:[39,206],tupl:[11,39,41,42,43,51,59,60,80,86,87,88,90,109,116,119,134,141,144,151,157,159,164,166,167,176,179,180,184,185,189,192,206,219,220,230,235,241,242,247,251,252,261,264,276,277,287,288,292,299,306,308,316,319,321,323,324,326,328,331,337,339,344],tupled:337,turbo:75,turkish:144,turn:[0,10,12,27,31,33,38,41,43,50,51,57,58,64,66,77,79,80,81,83,88,90,96,102,105,107,110,111,114,117,118,121,122,126,127,131,133,135,138,139,144,154,164,169,170,175,198,206,215,217,218,219,220,221,231,233,247,252,267,272,280,287,290,298,308,314,318,322,324,328,329,330,344,347,364],turn_act:116,turn_end_check:[217,218,219,220,221],turnbattl:[141,142,178],turnchar:219,tut:[122,233],tutor:230,tutori:[3,4,10,16,17,20,22,25,26,28,29,31,32,33,35,37,39,41,42,45,48,49,51,55,57,58,60,61,63,64,70,71,77,79,81,82,91,95,102,111,112,114,115,126,133,135,139,180,213,218,232,233,363,364],tutorial_bridge_posist:233,tutorial_cmdset:233,tutorial_exampl:[13,14,20,102,141,142,178],tutorial_info:233,tutorial_world:[20,22,63,122,141,142,178],tutorialclimb:232,tutorialevmenu:230,tutorialobject:[231,232],tutorialread:232,tutorialroom:[231,233],tutorialroomcmdset:233,tutorialroomlook:233,tutorialweapon:[231,232],tutorialweaponrack:232,tutorialworld:[232,233],tweak:[8,9,25,57,58,67,97,102,109,117,119,125,138,144,170,226,312,321],tweet:[124,139,364],tweet_output:120,tweet_stat:120,tweetstat:120,twenti:58,twice:[25,51,62,116,195,221,328],twist:[10,27,29,33,40,63,72,75,79,97,103,247,260,264,267,269,270,276,277,278,279,284,287,290,293,295,296,298,305,308,312,337],twistd:[63,106,110,284,305],twistedcli:40,twistedweb:103,twitch:[41,116],twitter:[7,55,120,139,364],twitter_api:71,two:[0,4,11,13,14,15,16,19,22,23,25,26,27,28,29,31,33,34,38,39,40,41,43,44,46,47,49,50,51,57,58,64,65,67,68,69,73,74,76,80,83,84,85,86,88,89,90,91,92,95,97,100,102,103,104,105,108,109,110,111,112,113,116,119,121,122,123,125,126,127,129,131,133,134,135,137,138,139,140,152,159,164,175,177,179,180,185,199,204,212,213,215,219,221,226,233,234,247,249,267,296,307,308,317,319,322,328,330,337,344,345,364],twowai:[43,159],txt:[9,38,40,50,75,78,90,96,146,205,283,291,326,328],tying:[90,347],typclass:206,type:[0,8,12,14,16,17,19,20,21,22,24,25,26,27,28,29,31,33,34,35,37,38,41,42,43,44,46,47,49,50,51,55,56,57,58,59,61,62,64,73,75,77,79,80,81,82,83,86,87,88,90,91,95,96,97,102,103,105,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,125,126,128,133,137,138,139,144,146,154,159,164,166,169,170,171,175,176,177,180,182,186,188,192,195,198,199,206,213,217,218,219,220,221,226,232,233,234,239,241,242,246,247,251,252,260,261,265,267,269,270,278,279,285,287,288,290,291,292,294,295,296,298,306,308,312,316,317,318,319,321,322,324,325,328,329,330,339,340,341,343,344,351,357],type_count:182,typecalass:316,typecalss:195,typeclass:[0,2,5,9,11,12,13,20,21,22,25,26,27,33,34,39,44,47,48,49,56,58,60,61,62,66,69,73,76,77,80,82,83,84,85,89,91,96,102,105,107,109,111,112,116,117,118,120,121,122,123,127,132,133,134,139,141,142,144,146,147,148,153,159,164,169,175,176,177,178,182,187,191,194,195,198,203,206,212,213,214,217,218,219,220,221,226,233,235,238,242,245,246,247,251,252,255,256,257,259,261,305,323,324,341,342,344,360,364],typeclass_path:[43,102,119,125,148,159,256,317,318],typeclass_search:317,typeclassbas:96,typeclassmanag:[147,176,245,255],typedobject:[41,125,148,154,177,206,235,246,247,256,316,317,318,319,339,344],typedobjectmanag:[176,238,317],typeerror:[42,185,296],typenam:[22,144,146,148,175,177,179,182,184,187,189,195,203,204,205,206,212,213,214,217,218,219,220,221,223,226,231,232,233,235,239,246,247,251,256,259,274,300,316,318,331,334,335],typeobject:319,types_count:182,typic:[27,55,91,127,220,221],typo:[37,38,70,103,363],ubbfwiuvdezxc0m:37,ubuntu:[8,63,67,97,103,131],ufw:103,ugli:[56,109,137,338],uid:[100,148,279,286,307,308],uit:[22,180],ulrik:58,ultima:79,umlaut:15,unabl:[71,190],unaccept:33,unaffect:[51,116,219,260],unalia:164,unarm:218,unarmor:218,unassign:138,unauthenticated_respons:360,unavoid:115,unban:[12,157,164,170,175],unban_us:164,unbias:185,unbroken:327,uncal:260,uncas:321,uncategor:341,unchang:[87,97,127,205,252,344],unclear:[30,363],uncolor:[81,114],uncom:[67,90],uncommit:131,uncompress:280,unconnect:[43,171,186],uncov:182,undefin:[36,86,112],under:[6,9,20,24,33,36,38,41,42,43,46,48,51,57,60,61,63,64,73,75,77,78,79,86,93,100,106,108,110,119,122,123,125,128,133,134,135,136,137,154,156,159,188,215,234,242,259,267,294,316,321,328,329,330,344],undergar:182,undergon:195,underli:[57,61,64,80,119,124,131],underlin:[330,343],underneath:[9,318],underscor:[0,38,51,74,88,95,97,114,119,152,344],underscror:152,understand:[4,10,15,24,25,26,29,30,31,33,37,38,39,41,42,44,48,49,55,60,61,63,79,81,83,91,95,96,103,104,105,109,111,113,114,123,124,127,131,133,134,136,139,151,152,164,204,205,206,312,321,344,364],understood:[83,91,111,127,295,296],undestand:25,undo:[50,103,326],undon:[43,156],undoubtedli:57,unexpect:[91,126,127,328],unexpectedli:334,unfamiliar:[63,74,80,88,90,118,124],unformat:[51,328,331],unfortun:[4,41,61],unhandl:60,unhappi:9,unhilit:343,unicod:[15,83,113,144,321,344],unicodeencodeerror:321,unicorn:119,unifi:[133,307],uniform:105,uninform:8,uninstal:63,uninstati:344,unintent:234,union:[31,51,152,226,328],uniqu:[2,12,13,20,31,33,35,36,38,40,43,46,51,55,57,60,61,64,71,80,83,84,90,95,96,102,105,109,112,119,123,125,127,137,138,144,150,152,154,159,164,169,171,175,176,181,184,186,194,204,205,206,212,215,218,219,231,233,238,247,251,252,261,264,276,277,285,298,299,307,308,316,317,318,319,324,326,338,341,344],unit:[27,31,34,36,37,45,47,55,62,64,79,82,107,124,130,139,176,184,198,219,269,324,331,344,350,364],unittest:[25,127,170,308,324,342],univers:[14,15,43,62,164],unix:[24,38,43,52,63,87,165,234,329,337,344],unixcommand:[141,142,178],unixcommandpars:234,unixtim:337,unjoin:179,unknown:[41,43,56,69,137,251,344],unleash:28,unless:[4,5,11,12,21,22,23,27,29,33,38,43,51,72,78,80,84,88,89,90,96,102,110,115,123,138,140,144,152,153,157,159,164,166,167,170,175,194,204,205,206,221,232,241,242,247,252,265,280,296,308,316,318,341,344,345],unlik:[37,51,64,73,90,107,127,144,180,219,318],unlimit:235,unlink:159,unload:342,unload_modul:342,unlock:[58,77,80,164,316],unlocks_red_chest:80,unlog:[43,157,162,163,171,186,308],unloggedin:[105,141,142,149,155,308],unloggedincmdset:[35,43,105,163,186],unlucki:12,unmask:206,unmodifi:[151,168,187,328],unmonitor:272,unmut:[164,175],unmute_channel:164,unnam:[112,152],unneccesari:113,unnecessari:[36,61],unneed:235,unpaced_data:276,unpack:[91,241],unpars:[74,87,151,295,296],unpaus:[100,102,169,260],unpickl:[83,276,316,325,340],unplay:[25,105],unpredict:344,unprivileg:252,unprogram:73,unpuppet:[43,96,107,123,156],unpuppet_al:144,unpuppet_object:[2,144],unquel:[20,43,80,122,156],unreal:79,unrecord_ip:310,unregist:135,unrel:[51,131],unrepat:344,unrepeat:[272,344],unreport:272,unsaf:[110,152,233],unsatisfactori:111,unsav:326,unsel:85,unset:[33,49,58,89,116,157,170,206,231,242,247,251,252,261,324,328,329,330,337],unset_lock:164,unsign:345,unsigned_integ:[338,345],unsignedinteg:338,unstabl:100,unstrip:151,unsub:164,unsub_from_channel:164,unsubscrib:[43,58,115,164,261,278],unsuit:[19,251,319],unsur:[15,37,63,71,76,90,116,138,213],untag:137,untest:[24,61,63,127],until:[5,8,10,11,12,13,20,26,29,30,31,33,36,48,51,61,63,64,86,87,93,95,97,102,114,115,119,123,126,131,136,137,138,139,179,182,184,198,217,218,219,220,221,226,231,232,233,247,260,267,296,298,321,322,331,344],untouch:321,untrust:[13,344],unus:[33,81,144,150,154,164,175,187,215,221,233,247,259,290,306,311,317],unusu:[103,119],unwant:139,unwield:218,unwieldli:153,upcom:54,updat:[2,4,5,8,9,11,13,14,20,23,24,28,29,30,33,36,38,39,43,45,49,51,55,57,58,61,62,63,64,68,71,73,75,76,79,81,83,84,86,88,89,90,91,95,97,98,100,102,115,116,123,127,133,134,135,136,137,138,139,146,153,154,159,164,167,169,170,175,183,187,195,206,220,233,239,242,246,247,249,250,252,257,283,285,286,291,305,306,308,310,316,318,325,326,327,328,329,330,334,344,357,360,364],update_attribut:316,update_buff:326,update_cached_inst:334,update_charsheet:58,update_current_descript:187,update_default:305,update_flag:306,update_po:49,update_session_count:306,update_undo:326,update_weath:233,updated_bi:192,updated_on:192,updatemethod:[137,138],upfir:106,upgrad:[63,64,75],upload:[4,63,64,90,100],upon:[14,29,61,80,86,90,96,100,103,113,117,123,188,210,217,218,219,220,221,258,269,278,310,329],upp:233,upper:[29,39,43,86,101,114,127,138,156,321],uppercas:[114,321],upping:114,ups:7,upsel:90,upsid:[41,235],upstart:40,upstream:[26,64,104,128],upt:153,uptim:[12,27,43,62,169,281,331],urfgar:109,uri:[175,239,318],url:[8,38,43,64,70,90,98,131,134,135,136,138,141,142,146,164,175,239,286,296,312,318,343,346,353,356],url_nam:360,url_or_ref:38,url_to_online_repo:131,urlencod:69,urlpattern:[3,4,69,133,134,135],usabl:[4,43,66,114,123,159,180,190,219,241,310,328],usag:[0,5,12,21,22,23,28,29,30,33,38,41,42,43,51,58,60,64,68,71,73,81,82,85,90,91,93,109,115,116,119,121,123,124,129,154,156,157,158,159,164,165,166,169,170,171,179,180,181,182,184,185,186,187,188,189,199,202,203,205,206,210,212,213,214,217,218,219,220,221,226,230,231,232,233,234,235,241,250,260,267,298,328,330,334],use:[0,2,3,4,5,6,8,9,10,11,12,13,14,15,16,17,19,20,21,22,23,24,25,26,27,28,29,31,33,34,35,36,37,38,39,40,41,42,43,46,47,48,49,50,51,52,54,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,76,79,80,81,82,83,84,85,86,87,88,89,90,91,93,95,96,98,100,102,103,104,105,106,107,108,109,111,112,113,114,116,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,144,146,148,150,151,152,153,154,156,159,160,164,165,166,167,169,170,175,177,179,180,181,182,185,187,189,190,194,198,199,202,203,204,205,206,212,214,215,217,218,219,220,221,223,226,230,231,232,233,234,235,241,242,246,247,251,252,260,261,265,272,276,289,291,292,295,298,299,306,307,308,316,317,318,319,321,322,323,324,326,327,328,329,330,334,337,338,340,344,345],use_dbref:[206,247,341],use_destin:247,use_i18n:76,use_item:219,use_nick:[144,206,247],use_required_attribut:357,use_success_location_messag:203,use_success_messag:203,use_xterm256:321,useabl:235,used:[0,2,3,7,9,10,11,13,15,16,17,19,20,22,23,24,27,29,30,31,34,35,38,40,41,43,46,47,48,50,51,52,54,55,56,57,58,59,60,62,63,64,67,68,69,72,73,74,79,80,82,83,84,85,86,87,88,89,90,91,93,95,96,100,102,103,104,105,107,108,109,110,111,112,113,114,115,116,118,119,120,121,122,123,124,125,126,127,128,129,131,133,134,135,136,137,139,141,144,146,150,152,153,154,156,159,164,166,167,168,169,170,175,179,180,182,184,186,187,188,189,190,192,194,195,198,199,204,205,206,213,215,217,218,219,220,221,226,231,232,233,234,235,238,239,240,241,242,247,251,252,259,260,261,262,264,265,269,272,273,276,277,278,279,280,281,282,283,284,285,287,289,290,291,294,295,296,299,306,308,309,316,317,318,319,320,321,322,324,325,326,328,329,330,337,338,339,340,341,344,345,350,357,363],used_kei:80,useful:[0,1,4,5,10,11,12,13,14,15,16,17,18,19,20,22,23,25,26,27,28,29,30,31,34,36,37,38,39,41,42,43,46,47,48,50,51,53,57,58,59,60,63,64,66,69,70,80,81,87,89,90,91,93,95,96,102,104,107,109,110,111,112,114,115,116,119,120,123,124,125,127,131,132,133,138,139,150,152,153,154,156,158,159,166,167,170,175,178,179,180,194,195,199,205,206,210,226,233,234,235,241,247,251,252,267,287,316,318,322,328,331,340,344],useless:231,user:[2,4,7,8,10,11,12,13,14,20,22,23,25,28,29,30,31,35,36,37,38,40,41,42,43,49,50,51,52,55,60,63,64,65,66,67,68,70,71,72,74,75,76,77,79,80,81,85,87,88,90,91,93,95,97,98,100,101,104,105,107,109,113,114,119,121,122,123,125,126,127,133,134,135,136,137,138,139,144,146,148,151,154,157,159,164,166,169,170,175,176,177,180,182,187,189,193,195,206,209,210,215,219,221,233,235,239,242,247,252,259,262,265,271,279,286,287,290,295,296,306,308,311,316,318,321,326,328,329,330,338,344,345,347,349,357,364],user_input:51,user_permiss:148,userauth:287,usercreationform:357,usernam:[2,4,12,35,51,74,100,107,119,131,134,144,148,186,287,311,349,357],username__contain:119,usernamefield:357,userpassword:[12,157],uses:[0,5,9,13,15,16,17,22,23,29,30,31,33,34,38,39,40,44,57,64,68,69,80,81,86,88,90,98,107,109,112,113,114,115,119,124,125,127,130,131,136,137,152,166,170,179,185,187,199,205,206,219,233,234,235,242,256,261,276,296,310,316,319,337,338,344,347],uses_databas:344,using:[2,4,5,6,8,9,10,11,12,13,14,15,19,20,21,22,23,24,25,26,27,28,29,30,31,33,34,36,37,38,39,41,43,45,46,47,49,50,51,53,55,56,57,58,59,60,61,62,63,64,67,68,70,71,72,73,74,77,78,79,80,81,83,85,86,87,88,89,90,91,93,95,96,97,100,101,102,103,105,107,108,109,110,111,112,114,115,116,117,118,120,121,122,123,124,125,126,128,129,131,132,133,134,137,138,139,140,144,148,150,153,154,156,158,159,164,166,167,168,169,170,175,179,180,181,184,185,187,188,190,194,203,205,206,212,213,214,215,217,218,219,220,221,230,231,233,234,235,242,247,250,251,252,256,260,261,278,279,280,285,286,290,296,299,308,309,310,312,316,318,319,321,322,326,328,329,331,337,338,339,340,341,342,344,346,357,363,364],usr:[63,64,75,100],usual:[0,2,4,5,6,8,9,11,19,20,21,22,23,25,26,27,29,30,31,33,34,37,38,40,41,43,46,47,50,51,52,57,59,60,62,63,64,67,72,74,80,81,87,89,90,91,93,95,96,97,100,102,105,106,109,110,112,114,115,119,124,125,126,127,131,133,136,144,146,151,152,153,154,156,159,164,165,169,170,177,184,194,195,198,204,205,206,233,234,242,246,247,252,267,269,274,299,306,316,318,321,323,324,328,329,337,339,341,344],utc:[23,345],utf8:[23,36],utf:[15,24,58,74,111,113,272,278,295,330,344],util:[8,10,11,13,14,16,34,41,45,47,48,49,50,51,52,57,58,59,62,63,81,82,85,86,89,96,97,102,103,111,114,117,124,127,133,134,137,139,141,142,158,169,170,175,177,178,184,187,188,191,195,196,211,213,220,226,228,230,239,247,249,251,259,260,274,293,298,316,317,318,346,357,360,364],utilis:328,uyi:205,v19:63,vagu:21,val:[11,88,144,156,291,344],valid:[1,11,13,26,30,31,33,42,43,44,51,58,60,67,69,88,89,90,91,95,96,97,102,103,109,110,114,119,123,133,134,141,142,144,151,153,159,167,170,175,176,179,180,188,192,195,196,204,206,215,220,232,233,234,235,242,247,249,251,252,257,259,260,261,262,265,267,291,295,306,316,317,319,322,324,328,338,339,340,341,343,344,345,357],valid_handl:338,validate_email_address:344,validate_nam:247,validate_onli:242,validate_password:[51,144],validate_prototyp:251,validate_sess:308,validate_usernam:144,validationerror:[144,251,311,338,340],validator_config:144,validator_kei:338,validatorfunc:[141,142,320],valign:330,valu:[0,2,4,6,10,11,12,17,20,22,25,27,28,31,33,39,41,42,43,49,50,58,59,60,61,62,64,67,69,73,74,77,80,81,82,84,85,86,87,88,90,97,102,111,114,115,116,123,125,126,127,128,133,134,137,138,139,144,148,150,152,154,156,157,159,170,175,177,180,182,185,188,189,190,192,195,196,203,204,205,206,211,217,218,219,220,221,228,233,235,239,241,242,246,247,250,251,252,256,260,261,265,272,273,274,276,285,290,291,306,307,308,313,316,317,318,319,321,323,324,325,326,327,328,334,335,338,339,340,341,344,345,350,357],valuabl:122,value1:109,value2:109,value_from_datadict:340,value_to_obj:251,value_to_obj_or_ani:251,value_to_str:340,valueerror:[41,91,109,123,180,202,204,316,319,321,324,344,345],valuei:111,values_list:119,valuex:111,vanilla:[9,26,49,56,58,86,101,125],vaniti:51,vari:[30,40,60,64,82,108,114,125,131,193,205,221,306,316,318],variabl:[0,3,5,11,13,28,31,33,38,41,43,46,49,51,55,56,58,64,66,69,80,83,88,91,95,96,97,100,103,104,106,109,113,121,124,133,134,135,137,138,144,148,150,154,156,159,164,167,169,170,175,183,187,188,192,194,195,198,203,233,241,246,247,251,252,264,267,277,280,281,283,287,289,299,306,313,321,322,328,344,350],variable_from_modul:344,variable_nam:[192,195],variablenam:344,varianc:205,variant:[11,55,112,153,180,186,213,278,321],variat:[62,73,116,152,187,205,344],varieti:[55,82,116,120,219,220],variou:[5,6,11,15,33,37,40,41,46,47,48,53,57,62,67,69,73,77,81,88,89,90,93,97,102,103,105,109,110,112,114,115,116,123,124,125,127,137,139,152,168,184,205,206,215,219,220,226,231,232,242,246,247,252,253,261,299,324,330,341,342,347],varnam:291,vast:[23,60,86,108,111,119],vastli:64,vcc:205,vccv:205,vccvccvc:205,vcpython27:9,vcv:205,vcvccv:205,vcvcvcc:205,vcvcvvccvcvv:205,vcvvccvvc:205,vector:344,vehicl:[21,124,139,364],velit:52,venu:[131,176],venv:[63,75],verb:[25,247,303],verbal:247,verbatim_el:344,verbos:[26,38,116,127,206],verbose_nam:[133,318],veri:[0,2,4,5,6,8,9,10,11,13,14,17,20,21,22,23,26,27,28,29,31,33,35,37,38,39,40,41,42,46,49,50,51,52,55,56,57,58,60,61,64,67,68,70,72,73,74,77,78,79,80,85,86,88,90,91,93,95,96,97,104,107,108,109,110,111,112,114,115,116,119,121,122,123,125,127,128,129,131,132,134,137,138,139,140,144,146,152,154,170,175,177,180,182,194,195,204,205,206,212,213,214,215,220,231,234,235,238,246,251,271,317,319,324,326,328,344],verif:90,verifi:[36,51,63,90,131,159,170,188,220,292],verify_online_play:188,verify_or_create_ssl_key_and_cert:292,verify_ssl_key_and_cert:288,verifyfunc:188,versa:[40,43,61,88,105,116,164,276],version:[2,4,7,11,13,14,20,21,23,24,29,30,31,33,35,36,37,41,43,47,51,54,57,60,61,63,64,74,75,76,79,81,86,87,90,91,95,96,100,108,111,114,123,124,125,126,128,136,137,139,159,167,169,171,181,182,186,187,206,218,219,220,221,226,232,247,252,267,272,286,310,316,321,329,344,357,363,364],version_info:267,versionad:38,versionchang:38,versu:55,vertic:[138,232,330,344],very_strong:242,very_weak:80,vest:103,vet:109,veteran:79,vfill_char:330,via:[10,11,27,37,40,51,52,55,56,57,63,70,73,74,83,85,86,90,92,93,101,103,108,109,114,119,123,125,126,131,137,172,176,177,209,226,246,256,316,319,321,335],viabl:231,vice:[40,43,61,88,105,116,164,276],vicin:[33,43,165,187,233],video:[79,95,114,137],vienv:9,view:[1,4,17,27,34,38,41,42,43,50,51,52,55,58,60,63,64,72,80,82,86,90,96,101,102,110,111,115,116,123,124,131,136,139,141,142,144,156,157,159,164,165,166,169,175,182,206,217,218,219,220,221,235,239,247,249,302,318,329,346,347,350,353,356,357,364],view_attr:159,viewabl:[53,55,166],viewer:[25,38,69,206,235,247,318],viewport:42,vim:[14,50,79,326],vincent:[180,187,204,234],violent:51,virtual:[4,41,43,55,57,59,63,79,90,124,169,187,331],virtual_env:75,virtualenv:[9,23,26,36,38,63,75,76,90,93,95,96,97,100,106,110,128],virtualhost:8,viru:63,visibl:[13,25,31,36,38,43,48,54,61,63,67,69,81,90,96,105,114,123,125,131,139,165,166,206,247,279,312,328,344],vision:[11,58,61],visit:[22,49,90,111,133,134,234,328],visitor:[103,134,135],vista:63,visual:[25,57,63,93,114,137,144,166,190,363],vital:91,vlgeoff:184,vniftg:63,vnum:56,vocabulari:[46,344],voic:[33,46,124,139,364],volatil:251,volum:[21,61,100],volund:119,voluntari:37,volupt:52,vowel:[119,205],vpad_char:330,vulner:[29,103],vvc:205,vvcc:205,vvccv:205,vvccvvcc:205,w001:127,wai:[0,2,5,6,9,10,11,12,13,14,15,19,20,21,22,23,27,28,30,31,33,37,38,39,40,41,42,43,44,46,48,49,54,55,56,57,58,61,62,63,64,68,69,70,72,73,74,75,79,80,82,83,84,85,86,87,88,89,90,91,92,93,95,96,97,98,102,103,104,105,106,107,109,110,111,112,113,114,115,116,117,118,119,121,122,123,124,125,126,127,128,129,131,132,133,136,138,139,140,144,151,152,159,166,175,179,184,185,187,188,190,194,198,205,212,213,215,217,218,219,220,221,226,230,231,232,234,242,247,251,261,267,272,276,287,308,310,312,313,314,317,319,322,327,328,330,334,337,340,364],wail:49,waist:182,wait:[0,10,20,25,27,28,29,33,42,51,102,121,138,146,170,194,198,217,218,219,220,221,226,267,277,296,298,310,324,328,344],wait_for_disconnect:277,wait_for_server_connect:277,wait_for_statu:267,wait_for_status_repli:267,waiter:267,waitinf:170,wake:188,walias:[43,159],walk:[0,14,21,31,39,46,49,60,62,85,139,213,214,215,226,235,322],walki:64,wall:[111,157,165,187,232,233],wanna:[37,179,226],want:[0,2,3,4,5,6,8,9,10,11,12,13,14,15,19,20,21,22,23,24,25,26,27,28,29,30,31,33,34,35,37,38,39,40,41,42,43,44,46,48,49,50,51,54,57,58,60,61,62,63,64,66,67,68,69,70,71,72,73,74,75,76,77,78,80,81,82,83,84,85,86,87,88,89,90,91,93,95,96,97,98,102,103,104,105,106,107,108,109,110,111,113,114,115,118,119,121,122,123,125,126,127,128,131,132,133,134,135,136,137,138,140,144,152,153,154,156,165,166,170,179,180,186,187,188,190,204,206,209,215,217,218,219,220,221,226,233,235,241,242,247,252,259,261,283,285,291,298,308,313,316,318,326,328,329,334,340,344,357,363],wanted_id:80,warchannel:164,ware:85,warehous:[209,322],wari:[114,235,247,318],warm:[102,110,271],warn:[8,23,27,31,59,60,63,64,90,91,93,104,105,111,128,134,138,140,152,175,210,266,267,292,337],warnmsg:337,warrior:[28,57,58,61,122,123,164],wasclean:[278,295],wasn:[0,42,134],wast:[6,14,115],watch:[14,84,106,139],water:[153,203],waterballon:203,wave:111,wcach:[43,169],wcactu:220,wcommandnam:234,wcure:220,wdestin:[43,159],weak:252,weakref:334,weaksharedmemorymodel:[274,334],weaksharedmemorymodelbas:[274,334],weakvalu:334,wealth:85,weapon:[29,51,61,64,73,77,82,85,86,109,116,122,218,231,232,252],weapon_ineffective_msg:231,weapon_prototyp:232,weaponrack_cmdset:232,wear:[82,182,206,218,226],wearabl:182,wearer:182,wearstyl:182,weather:[30,61,73,102,111,112,115,122,124,139,140,233,364],weather_script:102,weatherroom:[132,233],web:[4,8,9,16,17,23,25,30,38,47,53,55,61,63,64,67,69,72,75,76,79,80,83,95,101,109,110,119,139,141,142,269,271,281,285,291,295,296,306,310,312,319,325,364],web_client_url:54,web_get_admin_url:[175,239,318],web_get_create_url:[175,239,318],web_get_delete_url:[175,239,318],web_get_detail_url:[175,239,318],web_get_puppet_url:318,web_get_update_url:[175,239,318],webclient:[24,30,40,43,45,53,54,64,67,69,83,88,95,103,105,110,114,135,139,141,142,166,169,230,262,272,275,291,296,307,328,346,350,351,360,364],webclient_ajax:[137,141,142,262,275],webclient_en:103,webclient_opt:272,webclientdata:296,webclienttest:360,webpag:[8,17,77,90,354],webport:36,webserv:[3,7,8,9,23,36,40,47,55,67,90,100,101,104,135,139,141,142,262],webserver_en:103,webserver_interfac:[67,90],webserver_port:90,webservic:103,websit:[3,9,17,53,55,57,64,67,69,79,90,98,101,103,124,133,136,137,138,139,141,142,296,312,346,351,364],websocket:[40,55,64,90,100,137,278,284,295,307],websocket_client_interfac:[67,90],websocket_client_port:[67,90],websocket_client_url:[8,67,90],websocket_clos:295,websocketcli:295,websocketclientfactori:278,websocketclientprotocol:278,websocketserverfactori:284,websocketserverprotocol:295,weed:[26,119,152],week:[62,184,337,345],weeklylogfil:337,weigh:[82,298],weight:[23,38,61,108,124,139,190,205,317,364],weird:344,weirdli:96,welcom:[3,4,22,35,37,63,72,76,85],well:[2,4,6,9,11,12,16,17,19,21,22,23,25,26,33,37,38,39,40,41,43,44,45,46,49,50,51,52,55,57,58,61,62,64,66,68,69,71,74,75,81,85,88,89,91,96,98,103,104,105,106,108,109,113,116,118,119,120,123,124,125,127,128,131,133,134,135,136,138,148,152,153,154,159,164,169,172,175,179,182,187,194,202,205,206,215,219,220,221,226,231,247,256,260,262,267,276,278,279,285,302,310,316,317,321,325,328,331,340,344],went:[57,110,127,131,257,261],were:[1,10,11,13,24,31,33,37,38,42,44,51,58,59,64,69,77,82,85,86,91,100,102,104,108,109,119,123,125,126,127,137,144,151,152,153,164,175,204,215,247,251,314,318,322,341,344],weren:62,werewolf:25,werewolv:119,werkzeug:344,west:[20,25,44,49,111,159,233],west_east:111,west_exit:233,western:111,westward:233,wether:[179,324],wevennia:22,wflame:220,wflushmem:[43,169],wfull:220,wguild:164,what:[0,1,2,4,8,9,10,12,13,14,19,20,21,22,23,25,26,27,29,31,33,38,39,40,42,43,44,45,46,48,49,51,56,57,58,60,61,62,63,64,67,68,69,70,72,73,74,77,78,79,80,81,83,85,86,88,89,90,93,95,96,97,98,102,103,104,105,108,109,110,111,113,114,115,116,117,118,119,121,122,123,124,125,126,127,128,129,131,132,133,134,136,138,139,140,144,150,152,153,154,156,159,170,175,195,203,204,206,209,214,219,220,231,233,239,242,247,250,251,252,267,269,272,279,291,296,311,313,316,318,319,321,322,328,338,339,344,345,347,349,357,364],whatev:[2,11,14,21,22,23,27,33,40,43,46,48,51,56,58,61,64,67,78,82,89,91,100,102,111,123,127,131,133,134,138,144,146,153,159,188,220,231,232,247,252,256,257,278,287,290,295,308,316,329,338],whatnot:138,wheel:[57,63,75,115],whelp:[166,234],when:[0,2,3,4,5,6,8,9,10,11,12,13,14,15,17,19,20,21,22,23,24,26,27,29,30,31,33,34,35,36,37,38,39,40,41,42,43,44,46,47,49,50,51,52,56,57,58,59,60,61,62,63,64,65,66,67,68,69,73,74,75,76,77,78,79,80,82,83,84,85,86,87,88,89,90,91,93,95,96,97,98,100,102,103,104,105,106,107,108,109,110,111,112,113,114,116,117,118,119,120,121,122,123,124,125,126,127,128,129,131,132,133,136,137,138,139,141,144,146,148,150,152,153,154,156,158,159,164,165,166,167,168,169,171,175,176,177,179,180,181,182,184,185,186,187,188,189,190,195,196,198,199,202,203,204,205,206,212,214,215,217,218,219,220,221,223,226,228,230,231,232,233,234,235,238,239,242,246,247,249,251,252,256,257,259,260,261,264,267,269,273,274,276,277,278,279,280,281,282,283,285,287,288,289,290,291,292,295,296,298,299,305,306,307,308,309,310,316,318,319,321,322,324,325,326,327,328,329,330,334,335,337,339,344,347,357],when_stop:267,whenev:[6,10,11,22,25,33,46,64,66,74,76,80,84,87,90,95,98,100,102,106,107,109,111,113,117,119,128,144,153,175,231,232,233,247,257,259,269,286,306,307,308],where:[0,1,3,6,9,10,11,12,13,14,20,21,22,25,26,29,31,33,36,38,39,40,41,42,43,46,48,49,50,51,52,56,57,58,59,61,62,64,69,73,75,76,80,83,85,86,88,90,91,95,100,102,103,104,105,108,109,111,113,114,117,118,119,121,122,123,124,125,127,131,133,134,135,136,137,138,139,151,152,157,159,165,166,168,170,175,176,181,185,199,205,206,210,219,232,233,235,241,242,247,251,252,257,267,269,272,276,299,304,308,316,318,321,322,326,328,329,330,338,339,344],wherea:[11,12,13,19,21,26,31,33,34,40,42,55,56,61,80,81,85,86,93,97,103,105,109,113,114,116,125,128,205,261,296,316,334],whereabout:122,wherebi:220,wherev:[11,63,64,67,100,111,127,180,209,219],whether:[0,12,39,43,46,51,55,62,69,77,121,144,146,153,159,164,166,175,188,215,217,218,219,220,221,247,261,278,295,310,316,317,321,338,340,344],whewiu:9,which:[0,1,3,4,5,6,9,10,11,12,13,14,15,19,20,22,24,25,26,27,28,29,30,31,33,34,36,37,38,39,40,41,42,43,44,46,49,51,52,56,57,58,59,60,61,62,63,64,65,66,67,69,71,72,73,74,76,77,80,81,82,83,85,86,87,88,89,90,91,93,95,96,97,100,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,125,126,127,131,132,133,134,135,136,137,138,139,140,144,146,150,152,153,154,156,157,159,165,166,167,169,170,175,176,177,179,180,181,182,183,184,187,188,190,198,199,202,206,209,210,212,214,215,217,218,219,220,221,226,231,232,233,234,235,239,242,246,247,251,252,256,257,259,261,264,266,267,271,272,279,285,287,295,296,298,299,306,307,308,310,313,316,317,318,319,321,322,324,325,328,329,330,331,334,337,338,340,341,342,344,347,349,350,357],whichev:[27,90,103,233],whilst:[77,111],whim:139,whisp:205,whisper:[46,165,198,205,206,247],white:[48,74,114,126,321,344],whitelist:74,whitepag:[1,48,138],whitespac:[14,27,33,58,81,119,123,167,202,206,321,322,330,344],who:[4,10,11,12,21,34,41,46,49,51,55,56,58,61,73,80,87,95,103,109,114,116,119,121,123,124,125,127,132,133,138,146,154,156,159,164,175,179,188,195,205,206,217,218,219,220,221,232,239,242,247,252,318,326,328],whoever:133,whole:[4,16,43,49,51,55,57,60,61,67,87,96,111,112,122,123,129,138,152,159,169,221,330],wholist:175,whome:[43,159],whomev:[73,114,121,226],whose:[88,114,119,125,144,154,170,195,206,215,217,218,219,220,221,272,323,328,344],whould:328,why:[0,11,12,20,22,25,38,39,41,43,44,46,51,55,60,63,64,82,91,95,96,103,111,123,125,126,139,157,204,217,220,221,264,265,328],wick:316,wide:[16,25,27,39,43,58,61,73,86,91,138,157,219,220,235,327,330,344],widen:12,wider:[12,25,39,43,157,330],widest:344,widget:[340,357],width:[16,17,25,27,33,49,74,109,111,114,141,154,272,287,306,321,326,327,329,330,344],wield:[61,82,109,218],wifi:[90,103],wiki:[1,9,33,37,45,48,55,58,70,79,108,111,124,125,138,180,295,363,364],wiki_account_handl:4,wiki_account_signup_allow:4,wiki_can:4,wiki_can_admin:4,wiki_can_assign:4,wiki_can_assign_own:4,wiki_can_change_permiss:4,wiki_can_delet:4,wiki_can_moder:4,wiki_can_read:4,wiki_can_writ:4,wikiconfig:4,wikimedia:37,wikipedia:[15,37,55,113,127,131,295],wild:[108,126,131],wildcard:[12,43,57,87,157,159,344],wildcard_to_regexp:344,wilder:[141,142,178],wildernessexit:235,wildernessmap:235,wildernessmapprovid:235,wildernessroom:235,wildernessscript:235,wildli:205,will_suppress_ga:289,will_ttyp:294,willing:[58,61,79],win10:63,win7:63,win8:63,win:[9,24,91,116,122],wind:[122,132],window:[4,23,25,31,38,44,45,49,52,64,72,76,83,88,89,93,95,96,97,101,105,106,110,128,131,137,138,154,166,267,283,306,310,329,344],windowid:306,windows10:63,wingd:111,winpti:9,winter:187,wintext:73,wip:38,wipe:[9,13,23,111,138,152,159,169,219],wire:[27,40,64,83,88,90,113,138,168,264,276,277,308,321],wis:58,wisdom:[60,93],wise:[6,11,13,14,15,26,58,60,80,96,118,131,135],wise_text:60,wiseobject:60,wiser:20,wiseword:60,wish:[33,36,39,75,120,131,136,180,221,321,343,357],with_metaclass:96,with_tag:203,withdraw:[116,221],withdrawl:221,within:[1,8,9,10,11,22,24,26,31,33,37,38,39,43,47,49,51,56,58,64,90,95,97,100,114,115,116,117,118,119,120,124,126,131,134,136,137,138,144,148,150,159,179,187,190,192,210,238,247,252,260,310,316,317,321,337,344,357],without:[0,8,11,12,13,14,16,20,21,22,23,25,27,29,30,31,33,35,37,38,40,42,43,44,46,49,50,51,55,57,58,59,60,61,63,64,66,67,76,80,86,88,90,91,92,93,96,97,100,101,104,107,108,109,114,115,118,119,121,123,125,126,127,128,129,131,133,136,138,139,144,146,151,154,156,157,159,164,165,167,168,169,170,175,177,179,181,182,187,192,195,205,206,212,215,217,220,221,226,231,233,242,247,250,251,252,259,260,276,287,290,291,298,308,309,316,318,321,322,324,325,326,328,329,337,340,341,344,350],withstand:80,wiz:58,wizard:[109,233,252,265,267],wkei:[43,159],wlocat:[43,159],wlock:[43,159],wmagic:220,wmass:220,wndb_:[43,159],won:[0,2,4,10,11,12,13,15,21,22,23,29,31,38,41,42,46,57,61,63,69,73,78,81,83,85,86,91,95,96,100,111,114,119,123,125,127,134,137,138,153,188,204,223,226,312,321,340],wonder:[9,16,56,82,119,138],wont_suppress_ga:289,wont_ttyp:294,wooden:109,woosh:21,word:[14,27,33,43,46,49,50,62,69,70,72,76,88,89,91,93,95,96,97,111,119,122,126,131,136,151,166,167,171,186,198,205,206,279,326,341,344],word_fil:205,word_length_vari:205,wordi:205,work:[0,2,4,5,8,9,10,11,13,14,15,16,20,21,22,23,24,25,26,27,28,29,31,34,36,37,38,41,42,43,44,48,49,51,56,57,58,59,60,61,62,63,64,66,67,70,71,72,75,80,81,83,84,85,86,89,90,93,95,96,97,102,103,105,106,108,109,111,112,114,115,116,117,119,122,123,124,126,127,128,129,132,133,134,136,138,139,150,153,154,156,159,164,165,167,169,175,179,180,181,187,202,203,206,212,215,219,220,221,233,234,235,239,241,242,247,251,252,267,271,272,284,299,312,314,316,318,322,327,328,329,330,338,344,350,363,364],workaround:[63,100,131],workflow:61,world:[9,10,11,13,14,15,21,27,31,33,34,39,41,47,49,51,55,57,58,60,62,63,64,68,72,73,78,79,80,82,86,90,96,104,108,109,111,113,116,117,121,123,124,127,131,139,144,158,159,164,166,170,179,184,202,206,217,218,219,220,221,232,233,235,239,256,306,308,321,322,331,363,364],world_map:111,worm:49,worm_has_map:49,worn:[182,218],worri:[0,11,15,36,39,41,51,55,104,113,114,123,127,138,179],worst:61,worth:[0,8,21,29,51,61,70,79,91,93,124,125,133,179],worthi:61,worthless:90,would:[0,1,4,6,8,9,10,11,13,14,15,16,19,20,21,22,25,27,29,31,33,36,38,39,41,42,43,44,46,48,49,51,55,56,57,58,60,61,62,63,64,68,69,73,77,80,81,82,85,86,88,89,90,91,93,95,96,100,102,105,106,109,111,112,114,115,116,117,118,119,121,123,125,126,127,128,133,134,135,136,138,140,144,151,152,153,159,168,175,179,184,195,205,215,226,234,235,239,242,251,252,279,318,321,322,325,328,339,340,342,344],wouldn:[39,126,138],wound:220,wow:[69,138],wpermiss:[43,159],wprototype_desc:[43,159],wprototype_kei:[43,159],wprototype_lock:[43,159],wprototype_par:[43,159],wprototype_tag:[43,159],wrap:[10,30,49,51,59,96,102,109,119,136,182,188,206,274,314,330,344],wrap_conflictual_object:340,wrapper:[10,27,29,51,74,86,93,105,119,125,144,148,176,177,212,239,246,247,256,260,272,274,306,316,318,319,321,330,334,335,337,344],wresid:[43,169],write:[0,4,10,11,14,15,16,20,22,23,25,27,31,33,34,37,38,41,43,44,46,48,51,56,58,62,63,65,68,69,71,72,87,88,91,93,96,108,123,124,125,129,131,138,159,164,166,175,180,209,210,234,247,280,337,342,363,364],writeabl:75,written:[15,27,38,54,56,57,58,79,103,109,127,133,134,166,209,322],wrong:[26,41,42,43,60,63,81,85,95,110,127,152,159,169,206],wrote:170,wserver:[43,169],wservic:[43,164],wsgi:[8,312],wsgi_resourc:312,wsgiwebserv:312,wsl:[38,63],wss:[8,67,90],wtypeclass:[43,159],wwhere:247,www:[8,9,22,38,55,70,108,128,133,141,169,282,283,289,291,343,357],wyou:82,x0c:159,x1b:[321,343],x2x:58,x4x:327,x5x:327,x6x:327,x7x:327,x8x:327,x9x:327,x_r:39,xcode:63,xenial:130,xforward:312,xgettext:76,xit:[22,180],xmlcharrefreplac:321,xp_gain:73,xpo:330,xterm256:[43,55,74,81,83,137,156,183,190,272,287,290,321,364],xterm256_bg:321,xterm256_bg_sub:321,xterm256_fg:321,xterm256_fg_sub:321,xterm256_gbg:321,xterm256_gbg_sub:321,xterm256_gfg:321,xterm256_gfg_sub:321,xterm:[114,126],xterms256:114,xval:33,xxx:[25,42,204],xxxx:204,xxxxx1xxxxx:327,xxxxx3xxxxx:327,xxxxxxx2xxxxxxx:327,xxxxxxxxxx3xxxxxxxxxxx:58,xxxxxxxxxx4xxxxxxxxxxx:58,xxxxxxxxxxx:327,xxxxxxxxxxxxxx1xxxxxxxxxxxxxxx:58,xxxxxxxxxxxxxxxxxxxxxx:58,xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx:58,xyz:87,y_r:39,yan:[114,321],yank:50,yeah:138,year:[25,55,61,62,88,90,108,184,331,337,344,357],yearli:[62,90],yellow:[114,126,131,232],yep:138,yes:[10,33,39,46,51,126,138,159,169,198,265,326,328,344],yes_act:328,yes_no_question_cmdset:328,yesno:[51,326],yesnoquestioncmdset:328,yet:[0,2,4,12,14,22,25,28,35,36,41,42,46,49,51,54,60,63,64,67,76,79,86,90,96,105,109,111,119,121,128,130,131,133,134,138,144,164,171,179,186,195,226,242,246,260,285,308,312,321],yield:[10,23,33,80,108,159,170,210,330,344],yml:[100,130],yogurt:203,you:[0,1,2,3,4,5,6,8,9,10,11,12,13,14,15,16,17,19,20,21,22,23,24,25,27,28,29,30,31,33,34,35,36,37,38,39,40,41,42,43,44,46,47,48,49,50,51,54,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,95,96,97,98,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,144,153,154,156,159,164,165,166,167,168,169,170,171,175,179,180,181,182,183,184,187,188,190,193,194,195,198,199,202,203,204,205,206,209,210,212,213,214,215,217,218,219,220,221,223,226,232,233,234,235,241,242,247,252,258,259,260,261,269,278,279,280,296,298,308,310,312,313,316,318,321,322,324,327,328,330,331,340,341,344,357,363],young:77,your:[0,1,3,5,6,7,8,9,10,11,12,13,14,15,16,17,21,22,23,25,27,29,30,31,34,35,36,37,38,41,42,43,44,45,46,47,48,49,50,51,54,55,56,57,58,59,61,62,63,64,65,66,67,68,69,70,71,72,73,75,76,77,78,79,80,81,82,83,85,87,88,91,93,95,96,98,101,102,104,105,106,107,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,129,130,132,134,135,136,138,139,140,144,148,151,153,154,156,157,159,164,165,166,169,170,171,179,180,182,183,184,185,186,187,188,190,194,204,205,206,209,210,213,215,217,218,219,220,221,223,226,232,233,234,235,241,242,246,298,318,321,326,328,330,340,341,342,344,345,357,364],your_email:131,yourgam:209,yourhostnam:67,yournam:8,yourpassword:23,yourrepo:106,yourself:[0,2,5,6,14,16,19,22,23,26,31,37,42,43,51,55,58,63,69,70,73,78,80,86,89,90,91,96,102,108,111,119,123,125,130,131,135,159,165,179,189,206,212,220,223,328],yoursit:133,yourusernam:131,yourwebsit:133,yousuck:12,yousuckmor:12,youth:188,youtub:131,ypo:330,yrs:184,ythi:114,yum:[8,67,131],yvonn:58,z_r:39,zed:[77,79],zero:[20,27,109,164,206,247,316,321],zip:103,zlib:[75,276,280],zmud:[24,282],zone:[18,46,55,56,70,79,112,119,122,124,139,319,337,364],zope:97,zopeinterfac:63,zuggsoft:282,zy1rozgc6mq:45},titles:["A voice operated elevator using events","API refactoring","Accounts","Add a simple new web page","Add a wiki on your website","Adding Command Tutorial","Adding Object Typeclass Tutorial","Administrative Docs","Apache Config","Arxcode installing help","Async Process","Attributes","Banning","Batch Code Processor","Batch Command Processor","Batch Processors","Bootstrap & Evennia","Bootstrap Components and Utilities","Builder Docs","Building Permissions","Building Quickstart","Building a mech tutorial","Building menus","Choosing An SQL Server","Client Support Grid","Coding FAQ","Coding Introduction","Coding Utils","Command Cooldown","Command Duration","Command Prompt","Command Sets","Command System","Commands","Communications","Connection Screen","Continuous Integration","Contributing","Contributing to Evennia Docs","Coordinates","Custom Protocols","Customize channels","Debugging","Default Command Help","Default Exit Errors","Developer Central","Dialogues in events","Directory Overview","Docs refactoring","Dynamic In Game Map","EvEditor","EvMenu","EvMore","API Summary","Evennia Game Index","Evennia Introduction","Evennia for Diku Users","Evennia for MUSH Users","Evennia for roleplaying sessions","Execute Python Code","First Steps Coding","Game Planning","Gametime Tutorial","Getting Started","Glossary","Grapevine","Guest Logins","HAProxy Config (Optional)","Help System","Help System Tutorial","How To Get And Give Help","How to connect Evennia to Twitter","IRC","Implementing a game rule system","Inputfuncs","Installing on Android","Internationalization","Learn Python for Evennia The Hard Way","Licensing","Links","Locks","Manually Configuring Color","Mass and weight for objects","Messagepath","MonitorHandler","NPC shop Tutorial","New Models","Nicks","OOB","Objects","Online Setup","Parsing command arguments, theory and best practices","Portal And Server","Profiling","Python 3","Python basic introduction","Python basic tutorial part two","Quirks","RSS","Roadmap","Running Evennia in Docker","Screenshot","Scripts","Security","Server Conf","Sessions","Setting up PyCharm","Signals","Soft Code","Spawner and Prototypes","Start Stop Reload","Static In Game Map","Tags","Text Encodings","TextTags","TickerHandler","Turn based Combat System","Tutorial Aggressive NPCs","Tutorial NPCs listening","Tutorial Searching For Objects","Tutorial Tweeting Game Stats","Tutorial Vehicles","Tutorial World Introduction","Tutorial for basic MUSH like game","Tutorials","Typeclasses","Understanding Color Tags","Unit Testing","Updating Your Game","Using MUX as a Standard","Using Travis","Version Control","Weather Tutorial","Web Character Generation","Web Character View Tutorial","Web Features","Web Tutorial","Webclient","Webclient brainstorm","Wiki Index","Zones","evennia","evennia","evennia.accounts","evennia.accounts.accounts","evennia.accounts.admin","evennia.accounts.bots","evennia.accounts.manager","evennia.accounts.models","evennia.commands","evennia.commands.cmdhandler","evennia.commands.cmdparser","evennia.commands.cmdset","evennia.commands.cmdsethandler","evennia.commands.command","evennia.commands.default","evennia.commands.default.account","evennia.commands.default.admin","evennia.commands.default.batchprocess","evennia.commands.default.building","evennia.commands.default.cmdset_account","evennia.commands.default.cmdset_character","evennia.commands.default.cmdset_session","evennia.commands.default.cmdset_unloggedin","evennia.commands.default.comms","evennia.commands.default.general","evennia.commands.default.help","evennia.commands.default.muxcommand","evennia.commands.default.syscommands","evennia.commands.default.system","evennia.commands.default.tests","evennia.commands.default.unloggedin","evennia.comms","evennia.comms.admin","evennia.comms.channelhandler","evennia.comms.comms","evennia.comms.managers","evennia.comms.models","evennia.contrib","evennia.contrib.barter","evennia.contrib.building_menu","evennia.contrib.chargen","evennia.contrib.clothing","evennia.contrib.color_markups","evennia.contrib.custom_gametime","evennia.contrib.dice","evennia.contrib.email_login","evennia.contrib.extended_room","evennia.contrib.fieldfill","evennia.contrib.gendersub","evennia.contrib.health_bar","evennia.contrib.ingame_python","evennia.contrib.ingame_python.callbackhandler","evennia.contrib.ingame_python.commands","evennia.contrib.ingame_python.eventfuncs","evennia.contrib.ingame_python.scripts","evennia.contrib.ingame_python.tests","evennia.contrib.ingame_python.typeclasses","evennia.contrib.ingame_python.utils","evennia.contrib.mail","evennia.contrib.mapbuilder","evennia.contrib.menu_login","evennia.contrib.multidescer","evennia.contrib.puzzles","evennia.contrib.random_string_generator","evennia.contrib.rplanguage","evennia.contrib.rpsystem","evennia.contrib.security","evennia.contrib.security.auditing","evennia.contrib.security.auditing.outputs","evennia.contrib.security.auditing.server","evennia.contrib.security.auditing.tests","evennia.contrib.simpledoor","evennia.contrib.slow_exit","evennia.contrib.talking_npc","evennia.contrib.tree_select","evennia.contrib.turnbattle","evennia.contrib.turnbattle.tb_basic","evennia.contrib.turnbattle.tb_equip","evennia.contrib.turnbattle.tb_items","evennia.contrib.turnbattle.tb_magic","evennia.contrib.turnbattle.tb_range","evennia.contrib.tutorial_examples","evennia.contrib.tutorial_examples.bodyfunctions","evennia.contrib.tutorial_examples.cmdset_red_button","evennia.contrib.tutorial_examples.example_batch_code","evennia.contrib.tutorial_examples.red_button","evennia.contrib.tutorial_examples.red_button_scripts","evennia.contrib.tutorial_examples.tests","evennia.contrib.tutorial_world","evennia.contrib.tutorial_world.intro_menu","evennia.contrib.tutorial_world.mob","evennia.contrib.tutorial_world.objects","evennia.contrib.tutorial_world.rooms","evennia.contrib.unixcommand","evennia.contrib.wilderness","evennia.help","evennia.help.admin","evennia.help.manager","evennia.help.models","evennia.locks","evennia.locks.lockfuncs","evennia.locks.lockhandler","evennia.objects","evennia.objects.admin","evennia.objects.manager","evennia.objects.models","evennia.objects.objects","evennia.prototypes","evennia.prototypes.menus","evennia.prototypes.protfuncs","evennia.prototypes.prototypes","evennia.prototypes.spawner","evennia.scripts","evennia.scripts.admin","evennia.scripts.manager","evennia.scripts.models","evennia.scripts.monitorhandler","evennia.scripts.scripthandler","evennia.scripts.scripts","evennia.scripts.taskhandler","evennia.scripts.tickerhandler","evennia.server","evennia.server.admin","evennia.server.amp_client","evennia.server.connection_wizard","evennia.server.deprecations","evennia.server.evennia_launcher","evennia.server.game_index_client","evennia.server.game_index_client.client","evennia.server.game_index_client.service","evennia.server.initial_setup","evennia.server.inputfuncs","evennia.server.manager","evennia.server.models","evennia.server.portal","evennia.server.portal.amp","evennia.server.portal.amp_server","evennia.server.portal.grapevine","evennia.server.portal.irc","evennia.server.portal.mccp","evennia.server.portal.mssp","evennia.server.portal.mxp","evennia.server.portal.naws","evennia.server.portal.portal","evennia.server.portal.portalsessionhandler","evennia.server.portal.rss","evennia.server.portal.ssh","evennia.server.portal.ssl","evennia.server.portal.suppress_ga","evennia.server.portal.telnet","evennia.server.portal.telnet_oob","evennia.server.portal.telnet_ssl","evennia.server.portal.tests","evennia.server.portal.ttype","evennia.server.portal.webclient","evennia.server.portal.webclient_ajax","evennia.server.profiling","evennia.server.profiling.dummyrunner","evennia.server.profiling.dummyrunner_settings","evennia.server.profiling.memplot","evennia.server.profiling.settings_mixin","evennia.server.profiling.test_queries","evennia.server.profiling.tests","evennia.server.profiling.timetrace","evennia.server.server","evennia.server.serversession","evennia.server.session","evennia.server.sessionhandler","evennia.server.signals","evennia.server.throttle","evennia.server.validators","evennia.server.webserver","evennia.settings_default","evennia.typeclasses","evennia.typeclasses.admin","evennia.typeclasses.attributes","evennia.typeclasses.managers","evennia.typeclasses.models","evennia.typeclasses.tags","evennia.utils","evennia.utils.ansi","evennia.utils.batchprocessors","evennia.utils.containers","evennia.utils.create","evennia.utils.dbserialize","evennia.utils.eveditor","evennia.utils.evform","evennia.utils.evmenu","evennia.utils.evmore","evennia.utils.evtable","evennia.utils.gametime","evennia.utils.idmapper","evennia.utils.idmapper.manager","evennia.utils.idmapper.models","evennia.utils.idmapper.tests","evennia.utils.inlinefuncs","evennia.utils.logger","evennia.utils.optionclasses","evennia.utils.optionhandler","evennia.utils.picklefield","evennia.utils.search","evennia.utils.test_resources","evennia.utils.text2html","evennia.utils.utils","evennia.utils.validatorfuncs","evennia.web","evennia.web.urls","evennia.web.utils","evennia.web.utils.backends","evennia.web.utils.general_context","evennia.web.utils.middleware","evennia.web.utils.tests","evennia.web.webclient","evennia.web.webclient.urls","evennia.web.webclient.views","evennia.web.website","evennia.web.website.forms","evennia.web.website.templatetags","evennia.web.website.templatetags.addclass","evennia.web.website.tests","evennia.web.website.urls","evennia.web.website.views","Evennia Documentation","Toc"],titleterms:{"2017":138,"2019":[1,48,138],"3rd":138,"9th":138,"case":0,"class":[22,27,33,41,51,96,125,127],"default":[5,6,25,30,43,44,55,60,74,80,137,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171],"final":[49,75],"function":[22,42,51,53,80,89,95,102,114],"goto":51,"import":[26,38,41,95],"new":[3,4,6,58,60,69,86,97,102,114,125,127,133],"public":54,"return":[51,59,105],"static":111,"super":19,"switch":41,"try":41,Adding:[0,4,5,6,9,20,25,31,39,40,41,44,74,86,112,121,133],And:[70,92],For:119,NOT:77,PMs:58,TLS:8,The:[3,10,11,13,14,16,18,19,22,26,29,41,46,47,49,50,51,58,69,77,83,85,93,96,109,116,123,135],USE:77,Use:[26,103],Using:[49,52,84,86,90,93,109,112,127,129,130,140],Will:25,Yes:51,__unloggedin_look_command:43,abort:29,about:[29,43,115,125,128],abus:12,access:43,access_typ:80,account:[2,43,58,64,97,143,144,145,146,147,148,156],activ:[57,133],actual:[33,125],add:[3,4,23,25,60],add_choic:22,addclass:359,addcom:43,adding:127,addit:[9,39,41,44,100],address:25,admin:[43,64,97,135,145,157,173,237,244,254,263,315],administr:7,advanc:[18,29,53,87,110],aggress:117,alia:[43,97],alias:112,all:[25,51,67,69],allcom:43,alpha:61,altern:[9,106],amp:276,amp_client:264,amp_serv:277,analyz:93,android:75,ani:[13,55],annot:119,anoth:[38,41,119],ansi:[27,114,126,321],apach:8,api:[1,38,45,53,137],app:[69,133],arbitrari:51,area:[111,123],arg:91,arg_regex:33,argument:[1,51,91],arm:21,arx:9,arxcod:9,ascii:27,ask:[33,51],assign:[19,33],assort:[10,14,31,33,40,51,112,118],async:10,asynchron:10,attach:[106,107],attack:[73,123],attribut:[11,64,97,316],attributehandl:11,audit:[208,209,210,211],aug:[1,48],auto:68,automat:25,avail:[35,59,107],backend:349,ban:[12,43],barter:179,base:[25,109,116],basic:[4,13,14,18,55,71,95,96,123,127,136],batch:[13,14,15,322],batchcod:[13,43],batchcommand:43,batchprocess:[43,158],batchprocessor:322,befor:26,best:91,beta:61,between:[13,51,125],block:[13,29,38],blockquot:38,bodyfunct:223,bold:38,boot:[12,43],bootstrap:[16,17],border:17,bot:146,brainstorm:[45,138],branch:[51,131],bridg:77,brief:[55,69],briefli:88,bug:[38,97],build:[18,19,20,21,22,38,43,49,58,61,85,111,124,159],builder:18,building_menu:[22,180],busi:85,button:[17,20],calendar:62,call:33,callabl:51,callback:[0,46,137],callbackhandl:192,caller:51,can:[11,22,55],capcha:133,card:17,care:103,caveat:[13,14,75,114,125],cboot:43,ccreat:43,cdesc:43,cdestroi:43,cemit:43,central:45,certif:67,chainsol:138,chang:[0,5,6,25,38,58,60,76,97,103,108,128,131,136],channel:[25,34,41,43,58,64],channelhandl:174,charact:[6,24,25,46,58,60,61,64,73,82,89,96,123,133,134],charcreat:43,chardelet:43,chargen:[123,181],chat:138,cheat:42,check:[11,80],checker:26,checkpoint:133,choic:22,choos:23,clean:9,clickabl:114,client:[24,83,88,90,135,137,269],client_opt:74,clock:43,clone:[9,131],cloth:182,cloud9:90,cmdabout:43,cmdaccess:43,cmdaddcom:43,cmdallcom:43,cmdban:43,cmdbatchcod:43,cmdbatchcommand:43,cmdboot:43,cmdcboot:43,cmdcdesc:43,cmdcdestroi:43,cmdcemit:43,cmdchannel:43,cmdchannelcr:43,cmdcharcreat:43,cmdchardelet:43,cmdclock:43,cmdcolortest:43,cmdcopi:43,cmdcpattr:43,cmdcreat:43,cmdcwho:43,cmddelcom:43,cmddesc:43,cmddestroi:43,cmddig:43,cmddrop:43,cmdemit:43,cmdexamin:43,cmdfind:43,cmdforc:43,cmdget:43,cmdgive:43,cmdhandler:150,cmdhelp:43,cmdhome:43,cmdic:43,cmdinventori:43,cmdirc2chan:43,cmdlink:43,cmdlistcmdset:43,cmdlock:43,cmdlook:43,cmdmvattr:43,cmdname:43,cmdnewpassword:43,cmdnick:43,cmdobject:43,cmdooc:43,cmdooclook:43,cmdopen:43,cmdoption:43,cmdpage:43,cmdparser:151,cmdpassword:43,cmdperm:43,cmdpose:43,cmdpy:43,cmdquell:43,cmdquit:43,cmdreload:43,cmdreset:43,cmdrss2chan:43,cmdsai:43,cmdscript:43,cmdserverload:43,cmdservic:43,cmdsession:43,cmdset:[5,43,152],cmdset_account:160,cmdset_charact:161,cmdset_red_button:224,cmdset_sess:162,cmdset_unloggedin:163,cmdsetattribut:43,cmdsetdesc:43,cmdsethandl:153,cmdsethelp:43,cmdsethom:43,cmdsetobjalia:43,cmdshutdown:43,cmdspawn:43,cmdstyle:43,cmdtag:43,cmdteleport:43,cmdtime:43,cmdtunnel:43,cmdtypeclass:43,cmdunban:43,cmdunconnectedconnect:43,cmdunconnectedcr:43,cmdunconnectedhelp:43,cmdunconnectedlook:43,cmdunconnectedquit:43,cmdunlink:43,cmdwall:43,cmdwhisper:43,cmdwho:43,cmdwipe:43,code:[8,13,22,25,26,27,38,41,42,50,59,60,61,73,85,87,108,124,128,131,322],collabor:57,color:[17,25,27,43,81,126],color_markup:183,colour:114,combat:[116,123],comfort:100,comm:[43,164,172,173,174,175,176,177],command:[5,14,22,25,28,29,30,31,32,33,35,41,42,43,44,45,53,58,60,62,68,71,73,81,85,88,91,97,100,116,121,123,127,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,193,322],comment:[44,49],commit:131,commun:[13,34],complet:80,complex:[22,119],compon:[17,45],comput:90,concept:[45,49,116],conclud:[39,123],conclus:[22,41,91,111],condit:[25,119],conf:104,config:[8,53,67,81],configur:[8,23,65,67,71,72,81,98,106,131,133],congratul:61,connect:[35,43,54,71,90,97],connection_wizard:265,contain:[100,323],content:[25,55],continu:36,contrib:[22,37,124,127,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235],contribut:[37,38,53],control:131,convert:91,cooldown:28,coordin:39,copi:[8,43],core:[45,53,56,64],cpattr:43,cprofil:93,creat:[0,2,3,5,6,12,20,21,27,33,36,43,51,53,69,86,89,97,100,111,121,123,125,133,324],createnpc:123,creatur:100,credit:79,crop:27,current:[42,62],custom:[4,5,7,10,22,40,41,51,57,62,80,81,105,113,124,127,135,137],custom_gametim:184,cwho:43,data:[6,11,40,51,105,106],databas:[9,53,68,86,97,109,128],dbref:25,dbserial:325,deal:102,debug:[13,42,103],debugg:106,decor:[10,51],dedent:27,dedic:133,defaultobject:97,defin:[31,33,34,51,80,86,102,131],definit:80,delai:[10,27,29],delcom:43,delimit:25,demo:61,depend:[9,128],deploi:100,deprec:[38,266],desc:[43,51],descer:57,descript:100,design:85,destroi:43,detail:[43,69,133],develop:[45,57,79,100,103,110,124,127],dialogu:46,dice:[58,185],dictionari:51,differ:[56,125],dig:43,diku:56,direct:106,directori:[47,90,104],disabl:103,discuss:79,displai:[24,27,49,62],django:[64,80,110,119,133,135],doc:[7,18,26,38,48],docker:100,document:[37,38,129,363],don:[13,55,100],donat:37,down:[20,110,121],drop:43,dummi:73,dummyrunn:[93,298],dummyrunner_set:299,durat:29,dure:110,dynam:[33,49,51,127],earli:7,echo:74,edit:[22,38,50,123],editnpc:123,editor:50,elev:0,email_login:186,emit:43,emul:56,encod:[15,113],encrypt:90,end:41,engin:124,enjoi:8,enter:121,entir:0,entri:[20,68],error:[44,95,102,110],eveditor:[50,326],evennia:[4,5,7,8,9,16,23,25,26,38,41,42,45,47,54,55,56,57,58,67,71,75,76,77,79,90,91,95,96,100,106,109,110,124,126,127,128,131,137,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363],evennia_launch:267,evenniatest:127,event:[0,46,62],eventfunc:194,everi:30,everyth:22,evform:[58,327],evmenu:[25,51,328],evmor:[52,329],evtabl:[25,58,330],examin:[42,43],exampl:[39,42,46,50,51,73,80,83,90,102,108,116,127,137,322],example_batch_cod:225,execut:[42,59],exercis:77,exist:[6,125],exit:[0,6,25,33,44,89],expand:[116,121],explan:22,explor:[26,96],extended_room:187,extern:103,familiar:[56,57],faq:25,faster:127,featur:[38,55,69,135],feel:56,field:64,fieldfil:188,file:[13,14,15,38,43,104,127,131,322],fill:27,find:[39,43,59],firewal:103,first:[0,22,46,57,60,95,124],fix:131,flexibl:38,folder:[9,26,131],forc:43,foreground:110,forget:97,fork:[37,131],form:[17,133,357],format:51,forum:79,framework:79,from:[4,20,25,51,55,60,90,96,100,133,137,138,328],front:136,full:[22,41,69,83],func:41,further:[8,10,136],futur:[21,138],game:[7,26,27,39,45,47,49,54,55,57,58,59,61,62,73,90,100,111,120,123,124,127,128,131],game_index_cli:[268,269,270],gamedir:38,gameplai:122,gametim:[62,331],gap:77,gendersub:189,gener:[17,22,41,43,45,79,123,124,133,165,328],general_context:350,get:[20,43,51,63,67,70,119],get_client_opt:74,get_input:51,get_inputfunc:74,get_valu:74,git:[64,131],github:[38,64],give:[43,70],given:112,global:[53,91,102],glossari:64,gmcp:88,godhood:20,goldenlayout:137,googl:133,grant:58,grapevin:[65,278],griatch:[1,48,138],grid:[24,49],group:119,guest:66,gui:138,guid:9,handl:[12,69,103,110],handler:[53,107,116],haproxi:67,hard:77,have:123,head:38,health_bar:190,hello:95,help:[9,20,26,37,43,68,69,70,166,236,237,238,239],here:[26,55,60,96],hierarchi:58,hint:8,home:43,hook:125,host:90,hous:20,how:[2,33,58,70,71,89,100,113,121,125],html:[3,133],http:[8,67],idea:138,idmapp:[332,333,334,335],imag:[100,103],implement:73,improv:69,index:[54,69,133,139],info:[79,110],inform:[45,90],infrastructur:73,ingame_python:[191,192,193,194,195,196,197,198],ingo:83,inherit:140,inherits_from:27,initi:[6,23,25,116],initial_setup:271,inlin:114,inlinefunc:[114,336],input:[33,51,88],inputfunc:[74,83,88,272],insid:119,instal:[4,7,8,9,23,63,67,71,75,90,100,122,131,133],instanc:[33,86,125],instruct:88,integr:36,interact:[10,13,14,26],interfac:103,internation:76,interpret:106,intro_menu:230,introduct:[9,26,49,51,55,93,95,111,122,133],inventori:[43,82],irc2chan:43,irc:[72,279],issu:24,ital:38,jan:138,johnni:1,join:41,jumbotron:17,just:55,kei:[22,51,109],keyword:46,kill:110,know:[55,103],known:97,kovitiku:48,languag:[51,76],last:25,latest:[100,128],latin:25,launch:[50,51],layout:[16,41,47],learn:[26,55,77],leav:[41,121],legend:24,let:[13,42,69,90],librari:[47,96],licens:78,life:7,lift:12,like:[13,56,123],limit:[13,14,119],line:[21,42,50],link:[38,43,79,114],linux:[36,63,110],list:[38,42],list_nod:51,listen:118,literatur:79,live:110,local:[38,90,91],lock:[11,43,80,121,240,241,242],lockdown:90,lockfunc:241,lockhandl:242,log:[9,27,69,95,103],logfil:106,logger:337,login:[66,74],logo:136,longer:46,look:[5,43,56,95,123],lookup:53,mac:[63,110],machin:90,magic:97,mail:[131,199],main:[38,53],make:[20,21,27,57,58,60,67,121,123,127,131],manag:[4,137,147,176,238,245,255,273,317,333],manual:[54,81],map:[49,111],mapbuild:200,mapper:49,mariadb:23,markup:321,mass:82,master:[58,131],match:97,mccp:280,mech:21,mechan:124,memplot:300,menu:[22,27,51,85,249,328],menu_login:201,merg:31,messag:[0,25,83,88],messagepath:83,method:[33,41,81,97],middlewar:351,migrat:[4,64,128],mind:131,mini:127,minimap:111,miscellan:124,mob:231,mod_proxi:8,mod_ssl:8,mod_wsgi:8,mode:[13,14,64,90,105,110],model:[53,86,127,133,148,177,239,246,256,274,318,334],modif:58,modifi:[8,30],modul:[71,73,95,109,116],monitor:74,monitorhandl:[84,257],more:[16,29,38,53,57,80,81,128,135],most:26,move:[25,121],msdp:88,msg:[34,81,83],mssp:281,mud:79,multi:57,multidesc:[57,202],multipl:[11,119],multisess:[64,105],mush:[57,123],mutabl:[11,97],mux:129,muxcommand:167,mvattr:43,mxp:282,mysql:23,name:[12,43,88,97],naw:283,ndb:11,need:[0,55],nest:22,next:[57,63,71],nice:67,nick:[43,87],node:51,non:[11,25,28,54],nop:24,note:[8,10,14,15,31,33,38,40,51,87,112,118,122,127],npc:[85,117,118,123],number:91,object:[5,6,11,20,25,27,43,59,60,61,64,80,82,89,96,97,105,111,112,119,121,124,232,243,244,245,246,247],objmanipcommand:43,obtain:133,oct:138,octob:138,off:25,offici:79,olc:109,one:39,onli:[38,110],onlin:[38,90,131],oob:88,ooc:43,open:[43,85],oper:[0,10],option:[1,22,43,51,58,67,90,91,103,110],optionclass:338,optionhandl:339,other:[23,33,45,79,90,104],our:[0,22,69,95,96,108,121,133],out:[25,40,58],outgo:83,output:[59,127,209],outputcommand:88,outputfunc:88,outsid:[59,90],overal:73,overload:[81,125,135],overrid:97,overview:[36,47,86,116,136],own:[2,33,40,74,89,90,100,137],page:[3,4,43,69,135,136],parent:[57,86],pars:[25,41,91,95],part:96,parti:79,password:43,patch:37,path:[13,83],paus:[0,29,33],pax:9,pdb:42,perm:43,permiss:[19,58,80,112,122],perpetu:61,persist:[11,28,29,50],person:20,picklefield:340,pictur:133,pip:[4,64],plai:67,plan:[26,61,111],player:57,plugin:137,point:26,polici:129,port:[90,103],portal:[83,92,105,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296],portalsess:83,portalsessionhandl:[83,285],pose:43,posit:1,possibl:51,post:138,postgresql:23,practic:91,prepar:36,prerequisit:75,prevent:25,privileg:4,problem:108,process:[10,110],processor:[13,14,15,322],product:[21,100],profil:[93,297,298,299,300,301,302,303,304],program:[42,55],progress:77,project:[36,106],prompt:[30,51],properti:[2,11,31,33,34,51,64,89,102,105,112,125],protfunc:[109,250],protocol:[40,45,55,88],prototyp:[109,248,249,250,251,252],proxi:[8,90],publicli:131,pudb:42,puppet:64,push:[20,131],put:[67,69,131],puzzl:203,pycharm:106,python:[13,26,55,57,59,71,77,79,94,95,96],quell:[19,43,80,122],queri:[119,125],quick:[36,63],quickstart:20,quiet:91,quirk:97,quit:43,random_string_gener:204,read:[10,26,135,136],real:13,reboot:110,recapcha:133,receiv:[40,88],red_button:226,red_button_script:227,reduc:1,refactor:[1,48],refer:[25,38],regist:90,relat:[45,62],releas:[38,61],relev:90,reli:13,reload:[8,25,43,97,110],remark:123,rememb:38,remind:69,remot:[90,131],remov:[25,112],repeat:[51,74],repo:9,report:38,repositori:[26,37,38,64,131],request:38,requir:63,reset:[43,110,128],reshuffl:20,resourc:79,rest:38,restart:8,retriev:11,roadmap:99,role:58,roleplai:58,roller:58,rom:56,room:[0,6,25,39,49,58,61,82,89,233],rplanguag:205,rpsystem:206,rss2chan:43,rss:[98,286],rule:[31,73,116],run:[4,7,25,33,42,55,75,100,106,127],runner:127,safeti:13,sage:48,sai:43,same:[46,51],save:11,schema:128,score:123,screen:35,screenshot:101,script:[43,64,102,121,195,253,254,255,256,257,258,259,260,261],scripthandl:258,search:[27,31,39,53,86,91,112,119,341],secret:133,secur:[8,67,103,207,208,209,210,211],see:[69,97],select:25,self:91,send:[30,40,88],sent:30,separ:22,sept:[1,48],server:[7,8,23,43,76,90,92,104,105,123,210,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312],serverconf:104,serversess:[83,306],serversessionhandl:83,servic:[43,270],session:[25,43,58,64,83,105,307],sessionhandl:[105,308],set:[4,5,9,31,43,49,51,54,62,65,72,80,81,90,98,103,104,106,123,127,131],setdesc:43,sethelp:43,sethom:43,setpow:123,settings_default:313,settings_mixin:301,setup:[8,9,23,36,90],sever:[39,46,91],share:131,sharedmemorymodel:86,sheet:[42,58],shell:96,shop:85,shortcut:[11,53],show:[51,123],shut:110,shutdown:43,sidebar:38,signal:[107,309],simpl:[3,22,29,42,51,80,93,127],simpledoor:212,singl:11,singleton:53,site:[64,135],sitekei:133,slow_exit:213,soft:108,softcod:[57,108],solut:108,some:[39,41,56],somewher:55,sourc:[38,43,106],space:17,spawn:[43,57,109],spawner:[109,252],special:38,specif:5,spread:37,spuriou:24,sql:23,sqlite3:23,ssh:[88,103,287],ssl:[90,288],standard:[55,62,129],start:[9,58,63,85,100,110],stat:120,statu:110,step:[5,9,20,42,57,60,61,65,71,72,75,98,124,131,133],stop:110,storag:51,store:[6,11,25,51,109],string:[51,80,91,328],strip:91,structur:38,studi:0,stuff:[55,123],style:[17,43],sub:22,subclass:89,subject:96,suit:127,summari:[12,53,55],superus:80,support:[24,55,88],suppress_ga:289,surround:42,swap:125,synchron:10,syntax:[26,38,57,110,322],syscommand:168,system:[16,32,33,43,45,61,68,69,73,80,116,123,124,169],tabl:[25,27,38,86],tag:[39,43,112,126,319],talking_npc:214,taskhandl:260,tb_basic:217,tb_equip:218,tb_item:219,tb_magic:220,tb_rang:221,teamciti:36,tech:61,technic:[38,55,226],tel:43,telnet:[24,88,90,290],telnet_oob:291,telnet_ssl:292,templat:[36,51,69,133,328],templatetag:[358,359],tempmsg:34,temporari:51,termux:75,test:[55,59,93,123,127,170,196,211,228,293,303,335,352,360],test_queri:302,test_resourc:342,text2html:343,text:[27,38,51,74,113,114,136],texttag:114,theori:91,thi:[41,69],thing:[38,56,57,119],third:79,throttl:310,through:[37,42,100],ticker:[64,115],tickerhandl:[115,261],tie:58,time:[27,33,43,62,102,108],time_format:27,timer:93,timetrac:304,tip:131,titeuf87:138,to_byt:27,to_str:27,toc:364,togeth:[67,69],tool:[12,27,79],traceback:26,track:131,train:[73,121],translat:76,travi:130,treat:13,tree_select:215,trick:131,troubleshoot:[60,63,75],ttype:294,tunnel:43,turn:[25,97,116],turnbattl:[216,217,218,219,220,221],tutori:[0,5,6,18,21,46,62,69,85,96,116,117,118,119,120,121,122,123,124,127,132,134,136],tutorial_exampl:[222,223,224,225,226,227,228],tutorial_world:[229,230,231,232,233],tweak:[60,96],tweet:[71,120],twist:64,twitter:71,two:96,type:[2,5,6,11,60,89],typeclass:[6,43,45,53,57,64,81,97,119,124,125,140,197,314,315,316,317,318,319],unban:43,under:131,understand:126,ungm:58,uninstal:122,unit:127,unixcommand:234,unlink:43,unloggedin:[43,171],unmonitor:74,unrepeat:74,updat:[6,25,60,125,128,131],upgrad:128,upload:103,upstream:[97,131],url:[3,4,69,133,347,354,361],usag:[1,13,14,50],use:[55,97,115],used:[25,33],useful:[33,79],user:[19,33,56,57,69,103,124,131],userpassword:43,using:[0,42,119,127],util:[17,27,29,33,53,79,106,119,198,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,348,349,350,351,352],valid:[80,311],validatorfunc:345,valu:[51,109,119],variabl:[42,59],vehicl:121,verbatim:38,version:[38,131],versu:10,vhost:8,view:[3,68,69,133,134,135,355,362],virtualenv:64,voic:0,wai:[29,51,77],wall:43,want:[55,100],warn:38,weather:132,web:[3,45,88,90,97,103,124,133,134,135,136,137,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362],webclient:[137,138,295,353,354,355],webclient_ajax:296,webclient_gui:137,webserv:[103,312],websit:[4,135,356,357,358,359,360,361,362],websocket:[8,67],weight:82,what:[11,16,36,41,55,91,100],when:[25,115],where:[5,55,60,63,96],whisper:43,whitepag:45,who:[33,43],wiki:[4,139],wilder:235,willing:55,window:[9,63],wipe:43,wizard:54,word:37,work:[7,33,55,69,77,91,100,121,125,131],workaround:24,world:[18,20,61,95,122],write:[40,127,137],xterm256:[114,126],yield:[29,51],you:[26,55],your:[2,4,19,20,26,33,39,40,60,74,86,89,90,97,100,103,108,128,131,133,137],yourself:[20,60,61],zone:140}}) \ No newline at end of file diff --git a/docs/0.9.5/toc.html b/docs/0.9.5/toc.html index 77400af999..5c861ea362 100644 --- a/docs/0.9.5/toc.html +++ b/docs/0.9.5/toc.html @@ -254,7 +254,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        diff --git a/docs/1.0-dev/.buildinfo b/docs/1.0-dev/.buildinfo index 60a1cc1de2..da61a6e8c9 100644 --- a/docs/1.0-dev/.buildinfo +++ b/docs/1.0-dev/.buildinfo @@ -1,4 +1,4 @@ # Sphinx build info version 1 # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. -config: 80d96b3c9a53f30ed4966f16350793b4 +config: 0e6af2ce1c5d44eeec8b730fd2f289e5 tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/docs/1.0-dev/Coding/Coding-Introduction.html b/docs/1.0-dev/Coding/Coding-Introduction.html index 9aaddfb591..2fb6effedc 100644 --- a/docs/1.0-dev/Coding/Coding-Introduction.html +++ b/docs/1.0-dev/Coding/Coding-Introduction.html @@ -30,6 +30,7 @@ +
        develop branch
        @@ -236,7 +237,6 @@ chat are also there for you.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -253,6 +253,7 @@ chat are also there for you.

        +
        develop branch
        @@ -147,7 +148,6 @@ to you, but some things may still be useful.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -170,6 +170,7 @@ to you, but some things may still be useful.

        +
        develop branch
        @@ -414,7 +415,6 @@ build steps could be added or removed at this point, adding some features like U
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -431,6 +431,7 @@ build steps could be added or removed at this point, adding some features like U +
        develop branch
        @@ -370,7 +371,6 @@ topic here.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -387,6 +387,7 @@ topic here.

        +
        develop branch
        @@ -123,7 +124,6 @@ package imports from.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -140,6 +140,7 @@ package imports from.

        +
        develop branch
        @@ -385,7 +386,6 @@ For this, actual real-game testing is required.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -402,6 +402,7 @@ For this, actual real-game testing is required.

        +
        develop branch
        @@ -208,7 +209,6 @@ instructions, use the following command to fix it:

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -225,6 +225,7 @@ instructions, use the following command to fix it:

        +
        develop branch
        @@ -212,7 +213,6 @@ still running in interactive mode.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -229,6 +229,7 @@ still running in interactive mode.

        +
        develop branch
        @@ -586,7 +587,6 @@ will get much more information to help you fix the bug.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -603,6 +603,7 @@ will get much more information to help you fix the bug.

        +
        develop branch
        @@ -222,7 +223,6 @@ you then just run e
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -239,6 +239,7 @@ you then just run e +
        develop branch
        @@ -126,7 +127,6 @@ fitting your game.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -143,6 +143,7 @@ fitting your game.

        +
        develop branch
        @@ -543,7 +544,6 @@ understand the underlying ideas behind GIT
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -560,6 +560,7 @@ understand the underlying ideas behind GIT +
        develop branch
        @@ -198,7 +199,6 @@ any.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -215,6 +215,7 @@ any.

        +
        develop branch
        @@ -527,7 +528,6 @@ those will check for the 0.9.5 (v0.9.5 branch) -
        @@ -544,6 +544,7 @@ those will check for the Evennia 1.0-dev » +
        develop branch
        @@ -384,7 +385,6 @@ executed. When the code runs it has no knowledge of what file those strings wher
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -401,6 +401,7 @@ executed. When the code runs it has no knowledge of what file those strings wher +
        develop branch
        @@ -308,7 +309,6 @@ mode instead, see its readme for install instructions.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -325,6 +325,7 @@ mode instead, see its readme for install instructions.

        +
        develop branch
        @@ -162,7 +163,6 @@ allowed.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -179,6 +179,7 @@ allowed.

        +
        develop branch
        @@ -196,7 +197,6 @@ over 0.9.5 (v0.9.5 branch) -
        @@ -213,6 +213,7 @@ over Evennia 1.0-dev » +
        develop branch
        @@ -491,7 +492,6 @@ subscribers (and thus wipe all their aliases).

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -508,6 +508,7 @@ subscribers (and thus wipe all their aliases).

        +
        develop branch
        @@ -453,7 +454,6 @@ instructions.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -470,6 +470,7 @@ instructions.

        +
        develop branch
        @@ -498,7 +499,6 @@ commands having any combination of the keys and/or aliases “kick”, “punch
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -515,6 +515,7 @@ commands having any combination of the keys and/or aliases “kick”, “punch +
        develop branch
        @@ -94,7 +95,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -111,6 +111,7 @@ +
        develop branch
        @@ -871,7 +872,6 @@ on.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -888,6 +888,7 @@ on.

        +
        develop branch
        @@ -91,7 +92,6 @@ and is a building block for implementing other game systems. It’s used by the
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -108,6 +108,7 @@ and is a building block for implementing other game systems. It’s used by the +
        develop branch
        @@ -190,7 +191,6 @@ than, the doc-strings of each component in the 0.9.5 (v0.9.5 branch) -
        @@ -213,6 +213,7 @@ than, the doc-strings of each component in the Evennia 1.0-dev » +
        develop branch
        @@ -124,7 +125,6 @@ tutorial section on how to add new commands to a default command set.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -141,6 +141,7 @@ tutorial section on how to add new commands to a default command set.

        +
        develop branch
        @@ -332,7 +333,6 @@ editor can be useful if you want to test the code you have typed but add new lin
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -349,6 +349,7 @@ editor can be useful if you want to test the code you have typed but add new lin +
        develop branch
        @@ -1362,7 +1363,6 @@ until the exit node.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1379,6 +1379,7 @@ until the exit node.

        +
        develop branch
        @@ -125,7 +126,6 @@ paging.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -142,6 +142,7 @@ paging.

        +
        develop branch
        @@ -525,7 +526,6 @@ all the defaults (like 0.9.5 (v0.9.5 branch) -
        @@ -542,6 +542,7 @@ all the defaults (like Evennia 1.0-dev » +
        develop branch
        @@ -548,7 +549,6 @@ at that point).

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -565,6 +565,7 @@ at that point).

        +
        develop branch
        @@ -285,7 +286,6 @@ add more. By default the following fields/attributes can be monitored:

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -302,6 +302,7 @@ add more. By default the following fields/attributes can be monitored:

        +
        develop branch
        @@ -510,7 +511,6 @@ interface. It’s stand-alone from the permissions described above.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -527,6 +527,7 @@ interface. It’s stand-alone from the permissions described above.

        +
        develop branch
        @@ -182,7 +183,6 @@ the monitor to remove:

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -199,6 +199,7 @@ the monitor to remove:

        +
        develop branch
        @@ -188,7 +189,6 @@ it.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -205,6 +205,7 @@ it.

        +
        develop branch
        @@ -221,7 +222,6 @@ basically the unchanged strings you enter to the 0.9.5 (v0.9.5 branch) -
        @@ -238,6 +238,7 @@ basically the unchanged strings you enter to the Evennia 1.0-dev » +
        develop branch
        @@ -290,7 +291,6 @@ and display this as an error message. If this is not found, the Exit will instea
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -307,6 +307,7 @@ and display this as an error message. If this is not found, the Exit will instea +
        develop branch
        @@ -85,7 +86,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -102,6 +102,7 @@ +
        develop branch
        @@ -213,7 +214,6 @@ superuser can quell their powers this way, making them affectable by locks.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -230,6 +230,7 @@ superuser can quell their powers this way, making them affectable by locks.

        +
        develop branch
        @@ -93,7 +94,6 @@ This allows the two programs to communicate seamlessly.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -110,6 +110,7 @@ This allows the two programs to communicate seamlessly.

        +
        develop branch
        @@ -422,7 +423,6 @@ the api docs.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -439,6 +439,7 @@ the api docs.

        +
        develop branch
        @@ -606,7 +607,6 @@ traceback occurred in your script.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -623,6 +623,7 @@ traceback occurred in your script.

        +
        develop branch
        @@ -195,7 +196,6 @@ know about if you are an Evennia developer.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -212,6 +212,7 @@ know about if you are an Evennia developer.

        +
        develop branch
        @@ -85,7 +86,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -102,6 +102,7 @@ +
        develop branch
        @@ -275,7 +276,6 @@ module for details on the capabilities of the 0.9.5 (v0.9.5 branch) -
        @@ -292,6 +292,7 @@ module for details on the capabilities of the Evennia 1.0-dev » +
        develop branch
        @@ -208,7 +209,6 @@ decorator (only relevant for unit testing)

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -225,6 +225,7 @@ decorator (only relevant for unit testing)

        +
        develop branch
        @@ -288,7 +289,6 @@ is found in the 0.9.5 (v0.9.5 branch) -
        @@ -305,6 +305,7 @@ is found in the Evennia 1.0-dev » +
        develop branch
        @@ -215,7 +216,6 @@ same time without input from something else.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -232,6 +232,7 @@ same time without input from something else.

        +
        develop branch
        @@ -440,7 +441,6 @@ comments for examples and solutions.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -457,6 +457,7 @@ comments for examples and solutions.

        +
        develop branch
        @@ -204,7 +205,6 @@ copy over evennia/w
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -221,6 +221,7 @@ copy over evennia/w +
        develop branch
        @@ -257,7 +258,6 @@ following to your m
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -274,6 +274,7 @@ following to your m +
        develop branch
        @@ -350,7 +351,6 @@ window.plugin_handler.add("myplugin", myplugin);
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -367,6 +367,7 @@ window.plugin_handler.add("myplugin", myplugin); +
        develop branch
        @@ -164,7 +165,6 @@ come back or you reload it manually in your browser.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -181,6 +181,7 @@ come back or you reload it manually in your browser.

        +
        develop branch
        @@ -515,7 +516,6 @@ on the Django website - it covers all you need.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -532,6 +532,7 @@ on the Django website - it covers all you need.

        +
        develop branch
        @@ -354,7 +355,6 @@ your own liking.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -371,6 +371,7 @@ your own liking.

        +
        develop branch
        @@ -240,7 +241,6 @@ objects on the fly. For advanced users.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -257,6 +257,7 @@ objects on the fly. For advanced users.

        +
        develop branch
        @@ -192,7 +193,6 @@ started/introduction/) or read one of our other web tutorials.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -209,6 +209,7 @@ started/introduction/) or read one of our other web tutorials.

        +
        develop branch
        @@ -162,7 +163,6 @@ levels. Note that you cannot escalate your permissions this way; If the Characte
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -179,6 +179,7 @@ levels. Note that you cannot escalate your permissions this way; If the Characte +
        develop branch
        @@ -40,11 +41,12 @@
        @@ -117,6 +118,7 @@ will be shown.

        +
        develop branch
        @@ -269,7 +270,6 @@ use of ANSI color tags and the pitfalls of mixing ANSI and Xterms256 color tags
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -286,6 +286,7 @@ use of ANSI color tags and the pitfalls of mixing ANSI and Xterms256 color tags +
        develop branch
        @@ -149,7 +150,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -172,6 +172,7 @@ +
        develop branch
        @@ -431,7 +432,6 @@ ways.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -448,6 +448,7 @@ ways.

        +
        develop branch
        @@ -109,7 +110,6 @@ of nine names from
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -126,6 +126,7 @@ of nine names from +
        develop branch
        @@ -271,7 +272,6 @@ instead.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -288,6 +288,7 @@ instead.

        +
        develop branch
        @@ -305,7 +306,6 @@ may trigger changes in the GUI or play a sound etc.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -322,6 +322,7 @@ may trigger changes in the GUI or play a sound etc.

        +
        develop branch
        @@ -85,7 +86,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -102,6 +102,7 @@ +
        develop branch
        @@ -372,7 +373,6 @@ lot more information about querying the database.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -389,6 +389,7 @@ lot more information about querying the database.

        +
        develop branch
        @@ -270,7 +271,6 @@ same example ("
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -287,6 +287,7 @@ same example (" +
        develop branch
        @@ -177,7 +178,6 @@ pseudo-softcode plugin aimed at developers wanting to script their game from ins
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -194,6 +194,7 @@ pseudo-softcode plugin aimed at developers wanting to script their game from ins +
        develop branch
        @@ -149,7 +150,6 @@ the Wikipedia article 0.9.5 (v0.9.5 branch) -
        @@ -166,6 +166,7 @@ the Wikipedia article Evennia 1.0-dev » +
        develop branch
        @@ -125,7 +126,6 @@ circumstances. The parser is run on all outgoing messages if 0.9.5 (v0.9.5 branch) -
        @@ -142,6 +142,7 @@ circumstances. The parser is run on all outgoing messages if Evennia 1.0-dev » +
        develop branch
        @@ -204,7 +205,6 @@ something to the effect of

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -221,6 +221,7 @@ something to the effect of

        +
        develop branch
        @@ -230,7 +231,6 @@ implementation, the relevant django “applications” in default Evennia are 0.9.5 (v0.9.5 branch) -
        @@ -247,6 +247,7 @@ implementation, the relevant django “applications” in default Evennia are Evennia 1.0-dev » +
        develop branch
        @@ -139,7 +140,6 @@ properly search the inheritance tree.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -156,6 +156,7 @@ properly search the inheritance tree.

        +
        develop branch
        @@ -578,7 +579,6 @@ shown in the next tutorial.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -602,6 +602,7 @@ shown in the next tutorial.

        +
        develop branch
        @@ -336,7 +337,6 @@ on localhost at port 4000, and the webserver at http://localhost:4001/

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -353,6 +353,7 @@ on localhost at port 4000, and the webserver at http://localhost:4001/

        +
        develop branch
        @@ -1688,7 +1689,6 @@ exhaustive but user-friendly.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1712,6 +1712,7 @@ exhaustive but user-friendly.

        +
        develop branch
        @@ -432,7 +433,6 @@ want to solve the puzzles and mystery yourself).

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -455,6 +455,7 @@ want to solve the puzzles and mystery yourself).

        +
        develop branch
        @@ -344,7 +345,6 @@ from this rather than the more opinionated 0.9.5 (v0.9.5 branch) -
        @@ -368,6 +368,7 @@ from this rather than the more opinionated Contrib modules » +
        develop branch
        @@ -349,7 +350,6 @@ events).

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -373,6 +373,7 @@ events).

        +
        develop branch
        @@ -823,7 +824,6 @@ also look into up/down directions and figure out how to display that in a good w
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -847,6 +847,7 @@ also look into up/down directions and figure out how to display that in a good w +
        develop branch
        @@ -706,7 +707,6 @@ Tutorial), 0.9.5 (v0.9.5 branch) -
        @@ -730,6 +730,7 @@ Tutorial), Contrib modules » +
        develop branch
        @@ -849,7 +850,6 @@ to understand our friendly Google-style docstrings used in classes and functions
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -866,6 +866,7 @@ to understand our friendly Google-style docstrings used in classes and functions +
        develop branch
        @@ -208,7 +209,6 @@ UBBFWIuVDEZxC0M_2pM6ywO&dispatch=5885d80a13c0db1f8e263663d3faee8d66f31424b43
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -225,6 +225,7 @@ UBBFWIuVDEZxC0M_2pM6ywO&dispatch=5885d80a13c0db1f8e263663d3faee8d66f31424b43 +
        develop branch
        @@ -233,7 +234,6 @@ game-specific contributions and plugins (0.9.5 (v0.9.5 branch) -
        @@ -256,6 +256,7 @@ game-specific contributions and plugins (Evennia 1.0-dev » +
        develop branch
        @@ -237,7 +238,6 @@ your own game, you will end up with a small (very small) game that you can build
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -260,6 +260,7 @@ your own game, you will end up with a small (very small) game that you can build +
        develop branch
        @@ -473,7 +474,6 @@ activated whenever you want to use the 0.9.5 (v0.9.5 branch) -
        @@ -490,6 +490,7 @@ activated whenever you want to use the Evennia 1.0-dev » +
        develop branch
        @@ -93,8 +94,8 @@ needs doing, along with what your interests and skills are.

        github.

        … And finally, if you want to help motivate and support development you can also drop some coins -in the developer’s cup. You can make a donation via PayPal or, even better, become an -Evennia patron on Patreon! This is a great way to tip your hat and show that you +in the developer’s cup. You can make a donation via PayPal or, even better, +become an Evennia patron on Patreon! This is a great way to tip your hat and show that you appreciate the work done with the server! You can also encourage the community to take on particular issues by putting up a monetary bounty on it.

        @@ -158,7 +159,6 @@ issues by putting up a monetary 0.9.5 (v0.9.5 branch) -
        @@ -181,6 +181,7 @@ issues by putting up a monetary Evennia 1.0-dev » +
        develop branch
        @@ -412,7 +413,6 @@ necessary. If you’re interested in supporting this little project, you are mo
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -429,6 +429,7 @@ necessary. If you’re interested in supporting this little project, you are mo +
        develop branch
        @@ -387,7 +388,6 @@ shooting goodness would be made available to you only when you enter it.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -404,6 +404,7 @@ shooting goodness would be made available to you only when you enter it.

        +
        develop branch
        @@ -594,7 +595,6 @@ discussion where some suitable fonts are suggested.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -611,6 +611,7 @@ discussion where some suitable fonts are suggested.

        +
        develop branch
        @@ -228,7 +229,6 @@ other types of attacks for a while before the warrior can recover.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -245,6 +245,7 @@ other types of attacks for a while before the warrior can recover.

        +
        develop branch
        @@ -715,7 +716,6 @@ callback when the server comes back up (it will resume the countdown and ignore
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -732,6 +732,7 @@ callback when the server comes back up (it will resume the countdown and ignore +
        develop branch
        @@ -273,7 +274,6 @@ directly the easiest way is to just wrap those with a multiple inheritance to yo
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -290,6 +290,7 @@ directly the easiest way is to just wrap those with a multiple inheritance to yo +
        develop branch
        @@ -576,7 +577,6 @@ square (E, G, M and O) are not in this circle. So we remove them.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -593,6 +593,7 @@ square (E, G, M and O) are not in this circle. So we remove them.

        +
        develop branch
        @@ -250,7 +251,6 @@ matching “north” exit-command.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -267,6 +267,7 @@ matching “north” exit-command.

        +
        develop branch
        @@ -355,7 +356,6 @@ your mob.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -372,6 +372,7 @@ your mob.

        +
        develop branch
        @@ -320,7 +321,6 @@ or post a question in our 0.9.5 (v0.9.5 branch) -
        @@ -337,6 +337,7 @@ or post a question in our Evennia 1.0-dev » +
        develop branch
        @@ -1143,7 +1144,6 @@ when the message was sent.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1160,6 +1160,7 @@ when the message was sent.

        +
        develop branch
        @@ -468,7 +469,6 @@ same way as described for the default one above.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -485,6 +485,7 @@ same way as described for the default one above.

        +
        develop branch
        @@ -669,7 +670,6 @@ themselves links to display their details.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -686,6 +686,7 @@ themselves links to display their details.

        +
        develop branch
        @@ -246,7 +247,6 @@ in mind for your own game, this will give you a good start.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -269,6 +269,7 @@ in mind for your own game, this will give you a good start.

        +
        develop branch
        @@ -306,7 +307,6 @@ regardless of if Evennia thinks their client supports it or not.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -323,6 +323,7 @@ regardless of if Evennia thinks their client supports it or not.

        +
        develop branch
        @@ -217,7 +218,6 @@ the following message in the elevator’s appearance: 0.9.5 (v0.9.5 branch) -
        @@ -234,6 +234,7 @@ the following message in the elevator’s appearance: Evennia 1.0-dev » +
        develop branch
        @@ -566,7 +567,6 @@ it well stocked.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -583,6 +583,7 @@ it well stocked.

        +
        develop branch
        @@ -1078,7 +1079,6 @@ code.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1095,6 +1095,7 @@ code.

        +
        develop branch
        @@ -563,7 +564,6 @@ get into how we replace and extend Evennia’s default Commands.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -587,6 +587,7 @@ get into how we replace and extend Evennia’s default Commands.

        +
        develop branch
        @@ -405,7 +406,6 @@ example. Evennia comes with a tutorial world for you to explore. We will try tha
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -429,6 +429,7 @@ example. Evennia comes with a tutorial world for you to explore. We will try tha +
        develop branch
        @@ -155,7 +156,6 @@ You can find the parent class for Accounts in 0.9.5 (v0.9.5 branch) -
        @@ -179,6 +179,7 @@ You can find the parent class for Accounts in Starting Tutorial (Part 1) » +
        develop branch
        @@ -541,7 +542,6 @@ to understand how to plan what our tutorial game will be about.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -565,6 +565,7 @@ to understand how to plan what our tutorial game will be about.

        +
        develop branch
        @@ -232,7 +233,6 @@ to look it up in the docs:

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -256,6 +256,7 @@ to look it up in the docs:

        +
        develop branch
        @@ -330,7 +331,6 @@ equipment, stats and looks.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -354,6 +354,7 @@ equipment, stats and looks.

        +
        develop branch
        @@ -827,7 +828,6 @@ this tutorial. But that’s enough of them for now. It’s time to take some act
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -851,6 +851,7 @@ this tutorial. But that’s enough of them for now. It’s time to take some act +
        develop branch
        @@ -749,7 +750,6 @@ command on ourselves.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -773,6 +773,7 @@ command on ourselves.

        +
        develop branch
        @@ -730,7 +731,6 @@ Now let’s look at the rest of the stuff you’ve got going on inside that 0.9.5 (v0.9.5 branch) -
        @@ -754,6 +754,7 @@ Now let’s look at the rest of the stuff you’ve got going on inside that Starting Tutorial (Part 1) » +
        develop branch
        @@ -548,7 +549,6 @@ provides. But first we need to learn just where to find everything.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -572,6 +572,7 @@ provides. But first we need to learn just where to find everything.

        +
        develop branch
        @@ -383,7 +384,6 @@ Django queries and querysets in earnest.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -407,6 +407,7 @@ Django queries and querysets in earnest.

        +
        develop branch
        @@ -236,7 +237,6 @@ the log again just run

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -259,6 +259,7 @@ the log again just run

        +
        develop branch
        @@ -218,7 +219,6 @@ move on with how to access this power through code.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -242,6 +242,7 @@ move on with how to access this power through code.

        +
        develop branch
        @@ -322,7 +323,6 @@ have made their dream game a reality!

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -347,6 +347,7 @@ have made their dream game a reality!

        +
        develop branch
        @@ -341,7 +342,6 @@ back to your planning and adjust it as you learn what works and what does not.0.9.5 (v0.9.5 branch) -
        @@ -366,6 +366,7 @@ back to your planning and adjust it as you learn what works and what does not.Evennia Starting Tutorial (Part 2) » +
        develop branch
        @@ -558,7 +559,6 @@ to code themselves. So in the next lesson we will check out what help we have fr
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -575,6 +575,7 @@ to code themselves. So in the next lesson we will check out what help we have fr +
        develop branch
        @@ -248,7 +249,6 @@ then try to answer those questions for the sake of creating our little tutorial
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -273,6 +273,7 @@ then try to answer those questions for the sake of creating our little tutorial +
        develop branch
        @@ -138,7 +139,6 @@ and “what to think about” when creating a multiplayer online text game.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -162,6 +162,7 @@ and “what to think about” when creating a multiplayer online text game.

        +
        develop branch
        @@ -1181,7 +1182,6 @@ mixing them, or even try a third solution that better fits what you have in mind
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1198,6 +1198,7 @@ mixing them, or even try a third solution that better fits what you have in mind +
        develop branch
        @@ -462,7 +463,6 @@ your rules0.9.5 (v0.9.5 branch) -
        @@ -479,6 +479,7 @@ your rulesEvennia 1.0-dev » +
        develop branch
        @@ -138,7 +139,6 @@ with using Evennia. This be of much use when doing your own thing later.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -163,6 +163,7 @@ with using Evennia. This be of much use when doing your own thing later.

        +
        develop branch
        @@ -921,7 +922,6 @@ show others what’s going on.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -938,6 +938,7 @@ show others what’s going on.

        +
        develop branch
        @@ -980,7 +981,6 @@ as the 0.9.5 (v0.9.5 branch) -
        @@ -997,6 +997,7 @@ as the Evennia 1.0-dev » +
        develop branch
        @@ -105,7 +106,6 @@ and batchcode processors.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -122,6 +122,7 @@ and batchcode processors.

        +
        develop branch
        @@ -205,7 +206,6 @@ to.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -222,6 +222,7 @@ to.

        +
        develop branch
        @@ -103,7 +104,6 @@ to bring your game online so you can invite your first players.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -120,6 +120,7 @@ to bring your game online so you can invite your first players.

        +
        develop branch
        @@ -200,7 +201,6 @@ works and what possibilities exist.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -217,6 +217,7 @@ works and what possibilities exist.

        +
        develop branch
        @@ -227,7 +228,6 @@ AI code).

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -244,6 +244,7 @@ AI code).

        +
        develop branch
        @@ -235,7 +236,6 @@ Which way to go depends on the design requirements of your particular game.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -252,6 +252,7 @@ Which way to go depends on the design requirements of your particular game.

        +
        develop branch
        @@ -240,7 +241,6 @@ as mygame/typeclass
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -257,6 +257,7 @@ as mygame/typeclass +
        develop branch
        @@ -637,7 +638,6 @@ direction to which room it goes.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -654,6 +654,7 @@ direction to which room it goes.

        +
        develop branch
        @@ -251,7 +252,6 @@ push it over the limit, so to speak.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -268,6 +268,7 @@ push it over the limit, so to speak.

        +
        develop branch
        @@ -148,7 +149,6 @@ weather came before it. Expanding it to be more realistic is a useful exercise.<
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -165,6 +165,7 @@ weather came before it. Expanding it to be more realistic is a useful exercise.< +
        develop branch
        @@ -978,7 +979,6 @@ to see what happens. And do the same while checking the checkbox!

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -995,6 +995,7 @@ to see what happens. And do the same while checking the checkbox!

        +
        develop branch
        @@ -365,7 +366,6 @@ here.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -382,6 +382,7 @@ here.

        +
        develop branch
        @@ -104,7 +105,6 @@ as Evennia itself, unless the individual contributor has specifically defined ot
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -121,6 +121,7 @@ as Evennia itself, unless the individual contributor has specifically defined ot +
        develop branch
        @@ -298,7 +299,6 @@ programming curriculum for different skill levels

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -318,6 +318,7 @@ programming curriculum for different skill levels

        +
        develop branch
        @@ -281,7 +282,6 @@ port but this should be applicable also to other types of proxies (like nginx).<
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -298,6 +298,7 @@ port but this should be applicable also to other types of proxies (like nginx).< +
        develop branch
        @@ -453,7 +454,6 @@ others. If you try other databases out, consider expanding this page with instru
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -470,6 +470,7 @@ others. If you try other databases out, consider expanding this page with instru +
        develop branch
        @@ -235,7 +236,6 @@ parameter to disable it for that Evennia account permanently.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -252,6 +252,7 @@ parameter to disable it for that Evennia account permanently.

        +
        develop branch
        @@ -178,7 +179,6 @@ if you are not ready for players yet.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -195,6 +195,7 @@ if you are not ready for players yet.

        +
        develop branch
        @@ -595,7 +596,6 @@ you should update the line to the real location.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -612,6 +612,7 @@ you should update the line to the real location.

        +
        develop branch
        @@ -153,7 +154,6 @@ it to your channel in-game.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -170,6 +170,7 @@ it to your channel in-game.

        +
        develop branch
        @@ -340,7 +341,6 @@ uncommented in the config file, it will now start as a background process.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -357,6 +357,7 @@ uncommented in the config file, it will now start as a background process.

        +
        develop branch
        @@ -235,7 +236,6 @@ help.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -252,6 +252,7 @@ help.

        +
        develop branch
        @@ -171,7 +172,6 @@ name of the IRC channel you used (#evennia here).

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -188,6 +188,7 @@ name of the IRC channel you used (#evennia here).

        +
        develop branch
        @@ -222,7 +223,6 @@ killed if your phone is heavily taxed. Termux seems to keep a notification up to
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -239,6 +239,7 @@ killed if your phone is heavily taxed. Termux seems to keep a notification up to +
        develop branch
        @@ -595,7 +596,6 @@ https://aws.amazon.com/cloud9/

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -612,6 +612,7 @@ https://aws.amazon.com/cloud9/

        +
        develop branch
        @@ -138,7 +139,6 @@ same channels as 0.9.5 (v0.9.5 branch) -
        @@ -155,6 +155,7 @@ same channels as Evennia 1.0-dev » +
        develop branch
        @@ -379,7 +380,6 @@ line.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -396,6 +396,7 @@ line.

        +
        develop branch
        @@ -250,7 +251,6 @@ ISP snooping.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -267,6 +267,7 @@ ISP snooping.

        +
        develop branch
        @@ -85,7 +86,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -102,6 +102,7 @@ +
        develop branch
        @@ -151,7 +152,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -174,6 +174,7 @@ +
        develop branch
        @@ -198,7 +199,6 @@ a web browser at http
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -221,6 +221,7 @@ a web browser at http +
        develop branch
        @@ -289,7 +290,6 @@ In-game you should now get the message that the Server has successfully restarte
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -306,6 +306,7 @@ In-game you should now get the message that the Server has successfully restarte +
        develop branch
        @@ -103,7 +104,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -129,6 +129,7 @@ +
        develop branch
        @@ -348,7 +349,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -366,6 +366,7 @@ +
        develop branch
        @@ -1280,7 +1281,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1298,6 +1298,7 @@ +
        develop branch
        @@ -278,7 +279,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -296,6 +296,7 @@ +
        develop branch
        @@ -421,7 +422,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -439,6 +439,7 @@ +
        develop branch
        @@ -498,7 +499,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -516,6 +516,7 @@ +
        develop branch
        @@ -135,7 +136,6 @@ TASK_HANDLER = None TICKER_HANDLER = None MONITOR_HANDLER = None -CHANNEL_HANDLER = None # Containers GLOBAL_SCRIPTS = None @@ -189,7 +189,7 @@ global signals global settings, lockfuncs, logger, utils, gametime, ansi, spawn, managers global contrib, TICKER_HANDLER, MONITOR_HANDLER, SESSION_HANDLER - global CHANNEL_HANDLER, TASK_HANDLER + global TASK_HANDLER global GLOBAL_SCRIPTS, OPTION_CLASSES global EvMenu, EvTable, EvForm, EvMore, EvEditor global ANSIString @@ -252,7 +252,6 @@ from .scripts.tickerhandler import TICKER_HANDLER from .scripts.taskhandler import TASK_HANDLER from .server.sessionhandler import SESSION_HANDLER - from .comms.channelhandler import CHANNEL_HANDLER from .scripts.monitorhandler import MONITOR_HANDLER # containers @@ -381,7 +380,6 @@ CMD_NOINPUT - no input was given on command line CMD_NOMATCH - no valid command key was found CMD_MULTIMATCH - multiple command matches were found - CMD_CHANNEL - the command name is a channel name CMD_LOGINSTART - this command will be called as the very first command when an account connects to the server. @@ -396,7 +394,6 @@ CMD_NOINPUT = cmdhandler.CMD_NOINPUT CMD_NOMATCH = cmdhandler.CMD_NOMATCH CMD_MULTIMATCH = cmdhandler.CMD_MULTIMATCH - CMD_CHANNEL = cmdhandler.CMD_CHANNEL CMD_LOGINSTART = cmdhandler.CMD_LOGINSTART del cmdhandler @@ -514,7 +511,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -532,6 +528,7 @@ +
        develop branch
        @@ -40,7 +41,7 @@

        Source code for evennia.accounts.accounts

         """
        -Typeclass for Account objects
        +Typeclass for Account objects.
         
         Note that this object is primarily intended to
         store OOC information, not game info! This
        @@ -72,7 +73,7 @@
             SIGNAL_OBJECT_POST_PUPPET,
             SIGNAL_OBJECT_POST_UNPUPPET,
         )
        -from evennia.typeclasses.attributes import NickHandler
        +from evennia.typeclasses.attributes import NickHandler, ModelAttributeBackend
         from evennia.scripts.scripthandler import ScriptHandler
         from evennia.commands.cmdsethandler import CmdSetHandler
         from evennia.utils.optionhandler import OptionHandler
        @@ -80,7 +81,7 @@
         from django.utils.translation import gettext as _
         from random import getrandbits
         
        -__all__ = ("DefaultAccount",)
        +__all__ = ("DefaultAccount", "DefaultGuest")
         
         _SESSIONS = None
         
        @@ -89,14 +90,17 @@
         _MAX_NR_CHARACTERS = settings.MAX_NR_CHARACTERS
         _CMDSET_ACCOUNT = settings.CMDSET_ACCOUNT
         _MUDINFO_CHANNEL = None
        +_CONNECT_CHANNEL = None
         _CMDHANDLER = None
         
        +
         # Create throttles for too many account-creations and login attempts
         CREATION_THROTTLE = Throttle(
        -    limit=settings.CREATION_THROTTLE_LIMIT, timeout=settings.CREATION_THROTTLE_TIMEOUT
        +    name='creation', limit=settings.CREATION_THROTTLE_LIMIT,
        +    timeout=settings.CREATION_THROTTLE_TIMEOUT
         )
         LOGIN_THROTTLE = Throttle(
        -    limit=settings.LOGIN_THROTTLE_LIMIT, timeout=settings.LOGIN_THROTTLE_TIMEOUT
        +    name='login', limit=settings.LOGIN_THROTTLE_LIMIT, timeout=settings.LOGIN_THROTTLE_TIMEOUT
         )
         
         
        @@ -240,7 +244,7 @@
         
         
        [docs] @lazy_property def nicks(self): - return NickHandler(self)
        + return NickHandler(self, ModelAttributeBackend)
        [docs] @lazy_property def sessions(self): @@ -274,6 +278,21 @@ return objs +
        [docs] def get_display_name(self, looker, **kwargs): + """ + This is used by channels and other OOC communications methods to give a + custom display of this account's input. + + Args: + looker (Account): The one that will see this name. + **kwargs: Unused by default, can be used to pass game-specific data. + + Returns: + str: The name, possibly modified. + + """ + return f"|c{self.key}|n"
        + # session-related methods
        [docs] def disconnect_session_from_account(self, session, reason=None): @@ -316,11 +335,11 @@ raise RuntimeError("Session not found") if self.get_puppet(session) == obj: # already puppeting this object - self.msg(_("You are already puppeting this object.")) + self.msg("You are already puppeting this object.") return if not obj.access(self, "puppet"): # no access - self.msg(_("You don't have permission to puppet '{key}'.").format(key=obj.key)) + self.msg("You don't have permission to puppet '{obj.key}'.") return if obj.account: # object already puppeted @@ -336,8 +355,8 @@ else: txt1 = f"Taking over |c{obj.name}|n from another of your sessions." txt2 = f"|c{obj.name}|n|R is now acted from another of your sessions.|n" - self.msg(_(txt1), session=session) - self.msg(_(txt2), session=obj.sessions.all()) + self.msg(txt1, session=session) + self.msg(txt2, session=obj.sessions.all()) self.unpuppet_object(obj.sessions.get()) elif obj.account.is_connected: # controlled by another account @@ -359,8 +378,6 @@ obj.account = self session.puid = obj.id session.puppet = obj - # validate/start persistent scripts on object - obj.scripts.validate() # re-cache locks to make sure superuser bypass is updated obj.locks.cache_lock_bypass(obj) @@ -569,7 +586,7 @@ # Update throttle if ip: - LOGIN_THROTTLE.update(ip, "Too many authentication failures.") + LOGIN_THROTTLE.update(ip, _("Too many authentication failures.")) # Try to call post-failure hook session = kwargs.get("session", None) @@ -684,8 +701,9 @@ password (str): Password to set. Notes: - This is called by Django also when logging in; it should not be mixed up with validation, since that - would mean old passwords in the database (pre validation checks) could get invalidated. + This is called by Django also when logging in; it should not be mixed up with + validation, since that would mean old passwords in the database (pre validation checks) + could get invalidated. """ super(DefaultAccount, self).set_password(password) @@ -824,12 +842,10 @@ ) logger.log_sec(f"Account Created: {account} (IP: {ip}).") - except Exception as e: + except Exception: errors.append( - _( - "There was an error creating the Account. If this problem persists, contact an admin." - ) - ) + _("There was an error creating the Account. " + "If this problem persists, contact an admin.")) logger.log_trace() return None, errors @@ -845,7 +861,7 @@ # join the new account to the public channel pchannel = ChannelDB.objects.get_channel(settings.DEFAULT_CHANNELS[0]["key"]) if not pchannel or not pchannel.connect(account): - string = f"New account '{account.key}' could not connect to public channel!" + string = "New account '{account.key}' could not connect to public channel!" errors.append(string) logger.log_err(string) @@ -988,6 +1004,89 @@ self, raw_string, callertype="account", session=session, **kwargs )
        + # channel receive hooks + +
        [docs] def at_pre_channel_msg(self, message, channel, senders=None, **kwargs): + """ + Called by the Channel just before passing a message into `channel_msg`. + This allows for tweak messages per-user and also to abort the + receive on the receiver-level. + + Args: + message (str): The message sent to the channel. + channel (Channel): The sending channel. + senders (list, optional): Accounts or Objects acting as senders. + For most normal messages, there is only a single sender. If + there are no senders, this may be a broadcasting message. + **kwargs: These are additional keywords passed into `channel_msg`. + If `no_prefix=True` or `emit=True` are passed, the channel + prefix will not be added (`[channelname]: ` by default) + + Returns: + str or None: Allows for customizing the message for this recipient. + If returning `None` (or `False`) message-receiving is aborted. + The returning string will be passed into `self.channel_msg`. + + Notes: + This support posing/emotes by starting channel-send with : or ;. + + """ + if senders: + sender_string = ', '.join(sender.get_display_name(self) for sender in senders) + message_lstrip = message.lstrip() + if message_lstrip.startswith((':', ';')): + # this is a pose, should show as e.g. "User1 smiles to channel" + spacing = "" if message_lstrip[1:].startswith((':', '\'', ',')) else " " + message = f"{sender_string}{spacing}{message_lstrip[1:]}" + else: + # normal message + message = f"{sender_string}: {message}" + + if not kwargs.get("no_prefix") or not kwargs.get("emit"): + message = channel.channel_prefix() + message + + return message
        + +
        [docs] def channel_msg(self, message, channel, senders=None, **kwargs): + """ + This performs the actions of receiving a message to an un-muted + channel. + + Args: + message (str): The message sent to the channel. + channel (Channel): The sending channel. + senders (list, optional): Accounts or Objects acting as senders. + For most normal messages, there is only a single sender. If + there are no senders, this may be a broadcasting message or + similar. + **kwargs: These are additional keywords originally passed into + `Channel.msg`. + + Notes: + Before this, `Channel.at_pre_channel_msg` will fire, which offers a way + to customize the message for the receiver on the channel-level. + + """ + self.msg(text=(message, {"from_channel": channel.id}), + from_obj=senders, options={"from_channel": channel.id})
        + +
        [docs] def at_post_channel_msg(self, message, channel, senders=None, **kwargs): + """ + Called by `self.channel_msg` after message was received. + + Args: + message (str): The message sent to the channel. + channel (Channel): The sending channel. + senders (list, optional): Accounts or Objects acting as senders. + For most normal messages, there is only a single sender. If + there are no senders, this may be a broadcasting message. + **kwargs: These are additional keywords passed into `channel_msg`. + + """ + pass
        + + # search method +
        [docs] def search( self, searchdata, @@ -1295,30 +1394,42 @@ def _send_to_connect_channel(self, message): """ - Helper method for loading and sending to the comm channel - dedicated to connection messages. + Helper method for loading and sending to the comm channel dedicated to + connection messages. This will also be sent to the mudinfo channel. Args: message (str): A message to send to the connect channel. """ - global _MUDINFO_CHANNEL - if not _MUDINFO_CHANNEL: - try: - _MUDINFO_CHANNEL = ChannelDB.objects.filter(db_key=settings.CHANNEL_MUDINFO["key"])[ - 0 - ] - except Exception: - logger.log_trace() + global _MUDINFO_CHANNEL, _CONNECT_CHANNEL + if _MUDINFO_CHANNEL is None: + if settings.CHANNEL_MUDINFO: + try: + _MUDINFO_CHANNEL = ChannelDB.objects.get( + db_key=settings.CHANNEL_MUDINFO["key"]) + except ChannelDB.DoesNotExist: + logger.log_trace() + else: + _MUDINFO = False + if _CONNECT_CHANNEL is None: + if settings.CHANNEL_CONNECTINFO: + try: + _CONNECT_CHANNEL = ChannelDB.objects.get( + db_key=settings.CHANNEL_CONNECTINFO["key"]) + except ChannelDB.DoesNotExist: + logger.log_trace() + else: + _CONNECT_CHANNEL = False + if settings.USE_TZ: now = timezone.localtime() else: now = timezone.now() now = "%02i-%02i-%02i(%02i:%02i)" % (now.year, now.month, now.day, now.hour, now.minute) if _MUDINFO_CHANNEL: - _MUDINFO_CHANNEL.tempmsg(f"[{_MUDINFO_CHANNEL.key}, {now}]: {message}") - else: - logger.log_info(f"[{now}]: {message}") + _MUDINFO_CHANNEL.msg(f"[{now}]: {message}") + if _CONNECT_CHANNEL: + _CONNECT_CHANNEL.msg(f"[{now}]: {message}")
        [docs] def at_post_login(self, session=None, **kwargs): """ @@ -1505,7 +1616,7 @@ if hasattr(target, "return_appearance"): return target.return_appearance(self) else: - return _("{target} has no in-game appearance.").format(target=target) + return f"{target} has no in-game appearance." else: # list of targets - make list to disconnect from db characters = list(tar for tar in target if tar) if target else [] @@ -1548,19 +1659,18 @@ if is_su or len(characters) < charmax: if not characters: result.append( - _( - "\n\n You don't have any characters yet. See |whelp @charcreate|n for creating one." - ) + "\n\n You don't have any characters yet. See |whelp charcreate|n for " + "creating one." ) else: - result.append("\n |w@charcreate <name> [=description]|n - create new character") + result.append("\n |wcharcreate <name> [=description]|n - create new character") result.append( - "\n |w@chardelete <name>|n - delete a character (cannot be undone!)" + "\n |wchardelete <name>|n - delete a character (cannot be undone!)" ) if characters: string_s_ending = len(characters) > 1 and "s" or "" - result.append("\n |w@ic <character>|n - enter the game (|w@ooc|n to get back here)") + result.append("\n |wic <character>|n - enter the game (|wooc|n to get back here)") if is_su: result.append( f"\n\nAvailable character{string_s_ending} ({len(characters)}/unlimited):" @@ -1582,11 +1692,12 @@ sid = sess in sessions and sessions.index(sess) + 1 if sess and sid: result.append( - f"\n - |G{char.key}|n [{', '.join(char.permissions.all())}] (played by you in session {sid})" - ) + f"\n - |G{char.key}|n [{', '.join(char.permissions.all())}] " + f"(played by you in session {sid})") else: result.append( - f"\n - |R{char.key}|n [{', '.join(char.permissions.all())}] (played by someone else)" + f"\n - |R{char.key}|n [{', '.join(char.permissions.all())}] " + "(played by someone else)" ) else: # character is "free to puppet" @@ -1595,21 +1706,23 @@ return look_string
        -class DefaultGuest(DefaultAccount): +
        [docs]class DefaultGuest(DefaultAccount): """ This class is used for guest logins. Unlike Accounts, Guests and their characters are deleted after disconnection. + """ - @classmethod +
        [docs] @classmethod def create(cls, **kwargs): """ Forwards request to cls.authenticate(); returns a DefaultGuest object if one is available for use. - """ - return cls.authenticate(**kwargs) - @classmethod + """ + return cls.authenticate(**kwargs)
        + +
        [docs] @classmethod def authenticate(cls, **kwargs): """ Gets or creates a Guest account object. @@ -1673,7 +1786,7 @@ return account, errors - except Exception as e: + except Exception: # We are in the middle between logged in and -not, so we have # to handle tracebacks ourselves at this point. If we don't, # we won't see any errors at all. @@ -1681,9 +1794,9 @@ logger.log_trace() return None, errors - return account, errors + return account, errors
        - def at_post_login(self, session=None, **kwargs): +
        [docs] def at_post_login(self, session=None, **kwargs): """ In theory, guests only have one character regardless of which MULTISESSION_MODE we're in. They don't get a choice. @@ -1695,9 +1808,9 @@ """ self._send_to_connect_channel(_("|G{key} connected|n").format(key=self.key)) - self.puppet_object(session, self.db._last_puppet) + self.puppet_object(session, self.db._last_puppet)
        - def at_server_shutdown(self): +
        [docs] def at_server_shutdown(self): """ We repeat the functionality of `at_disconnect()` here just to be on the safe side. @@ -1706,9 +1819,9 @@ characters = self.db._playable_characters for character in characters: if character: - character.delete() + character.delete()
        - def at_post_disconnect(self, **kwargs): +
        [docs] def at_post_disconnect(self, **kwargs): """ Once having disconnected, destroy the guest's characters and @@ -1722,7 +1835,7 @@ for character in characters: if character: character.delete() - self.delete() + self.delete()
        @@ -1760,7 +1873,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1779,6 +1891,7 @@ +
        develop branch
        @@ -371,7 +372,7 @@ nicklist = ", ".join(sorted(kwargs["nicklist"], key=lambda n: n.lower())) for obj in self._nicklist_callers: obj.msg( - _("Nicks at {chstr}:\n {nicklist}").format(chstr=chstr, nicklist=nicklist) + "Nicks at {chstr}:\n {nicklist}".format(chstr=chstr, nicklist=nicklist) ) self._nicklist_callers = [] return @@ -382,7 +383,7 @@ chstr = f"{self.db.irc_channel} ({self.db.irc_network}:{self.db.irc_port})" for obj in self._ping_callers: obj.msg( - _("IRC ping return from {chstr} took {time}s.").format( + "IRC ping return from {chstr} took {time}s.".format( chstr=chstr, time=kwargs["timing"] ) ) @@ -438,6 +439,7 @@ # # RSS +#
        [docs]class RSSBot(Bot): @@ -655,7 +657,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -674,6 +675,7 @@ +
        develop branch
        @@ -265,7 +266,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -284,6 +284,7 @@ +
        develop branch
        @@ -135,7 +136,8 @@ "cmdset", max_length=255, null=True, - help_text="optional python path to a cmdset class. If creating a Character, this will default to settings.CMDSET_CHARACTER.", + help_text="optional python path to a cmdset class. If creating a Character, this will " + "default to settings.CMDSET_CHARACTER.", ) # marks if this is a "virtual" bot account object db_is_bot = models.BooleanField( @@ -150,8 +152,8 @@ __applabel__ = "accounts" __settingsclasspath__ = settings.BASE_SCRIPT_TYPECLASS - # class Meta: - # verbose_name = "Account" + class Meta: + verbose_name = "Account" # cmdset_storage property # This seems very sensitive to caching, so leaving it be for now /Griatch @@ -257,7 +259,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -276,6 +277,7 @@ +
        develop branch
        @@ -47,10 +48,6 @@ 1. The calling object (caller) is analyzed based on its callertype. 2. Cmdsets are gathered from different sources: - - channels: all available channel names are auto-created into a cmdset, to allow - for giving the channel name and have the following immediately - sent to the channel. The sending is performed by the CMD_CHANNEL - system command. - object cmdsets: all objects at caller's location are scanned for non-empty cmdsets. This includes cmdsets on exits. - caller: the caller is searched for its own currently active cmdset. @@ -64,14 +61,12 @@ cmdset, or fallback to error message. Exit. 7. If no match was found -> check for CMD_NOMATCH in current cmdset or fallback to error message. Exit. -8. A single match was found. If this is a channel-command (i.e. the - ommand name is that of a channel), --> check for CMD_CHANNEL in - current cmdset or use channelhandler default. Exit. -9. At this point we have found a normal command. We assign useful variables to it that +8. At this point we have found a normal command. We assign useful variables to it that will be available to the command coder at run-time. -12. We have a unique cmdobject, primed for use. Call all hooks: +9. We have a unique cmdobject, primed for use. Call all hooks: `at_pre_cmd()`, `cmdobj.parse()`, `cmdobj.func()` and finally `at_post_cmd()`. -13. Return deferred that will fire with the return from `cmdobj.func()` (unused by default). +10. Return deferred that will fire with the return from `cmdobj.func()` (unused by default). + """ from collections import defaultdict @@ -85,7 +80,6 @@ from twisted.internet.defer import inlineCallbacks, returnValue from django.conf import settings from evennia.commands.command import InterruptCommand -from evennia.comms.channelhandler import CHANNELHANDLER from evennia.utils import logger, utils from evennia.utils.utils import string_suggestions @@ -116,12 +110,11 @@ CMD_NOMATCH = "__nomatch_command" # command to call if multiple command matches were found CMD_MULTIMATCH = "__multimatch_command" -# command to call if found command is the name of a channel -CMD_CHANNEL = "__send_to_channel_command" # command to call as the very first one when the user connects. # (is expected to display the login screen) CMD_LOGINSTART = "__unloggedin_look_command" + # Function for handling multiple command matches. _SEARCH_AT_RESULT = utils.variable_from_module(*settings.SEARCH_AT_RESULT.rsplit(".", 1)) @@ -129,50 +122,50 @@ # is the normal "production message to echo to the account. _ERROR_UNTRAPPED = ( - """ -An untrapped error occurred. -""", - """ -An untrapped error occurred. Please file a bug report detailing the steps to reproduce. -""", + _(""" +An untrapped error occurred. +"""), + _(""" +An untrapped error occurred. Please file a bug report detailing the steps to reproduce. +"""), ) _ERROR_CMDSETS = ( - """ -A cmdset merger-error occurred. This is often due to a syntax -error in one of the cmdsets to merge. -""", - """ -A cmdset merger-error occurred. Please file a bug report detailing the -steps to reproduce. -""", + _(""" +A cmdset merger-error occurred. This is often due to a syntax +error in one of the cmdsets to merge. +"""), + _(""" +A cmdset merger-error occurred. Please file a bug report detailing the +steps to reproduce. +"""), ) _ERROR_NOCMDSETS = ( - """ -No command sets found! This is a critical bug that can have -multiple causes. -""", - """ -No command sets found! This is a sign of a critical bug. If -disconnecting/reconnecting doesn't" solve the problem, try to contact -the server admin through" some other means for assistance. -""", + _(""" +No command sets found! This is a critical bug that can have +multiple causes. +"""), + _(""" +No command sets found! This is a sign of a critical bug. If +disconnecting/reconnecting doesn't" solve the problem, try to contact +the server admin through" some other means for assistance. +"""), ) _ERROR_CMDHANDLER = ( - """ -A command handler bug occurred. If this is not due to a local change, -please file a bug report with the Evennia project, including the -traceback and steps to reproduce. -""", - """ -A command handler bug occurred. Please notify staff - they should -likely file a bug report with the Evennia project. -""", + _(""" +A command handler bug occurred. If this is not due to a local change, +please file a bug report with the Evennia project, including the +traceback and steps to reproduce. +"""), + _(""" +A command handler bug occurred. Please notify staff - they should +likely file a bug report with the Evennia project. +"""), ) -_ERROR_RECURSION_LIMIT = ( +_ERROR_RECURSION_LIMIT = _( "Command recursion limit ({recursion_limit}) " "reached for '{raw_cmdname}' ({cmdclass})." ) @@ -195,7 +188,7 @@ production string (with a timestamp) to be shown to the user. """ - string = "{traceback}\n{errmsg}\n(Traceback was logged {timestamp})." + string = _("{traceback}\n{errmsg}\n(Traceback was logged {timestamp}).") timestamp = logger.timeformat() tracestring = format_exc() logger.log_trace() @@ -344,23 +337,11 @@ """ try: - @inlineCallbacks - def _get_channel_cmdset(account_or_obj): - """ - Helper-method; Get channel-cmdsets - """ - # Create cmdset for all account's available channels - try: - channel_cmdset = yield CHANNELHANDLER.get_cmdset(account_or_obj) - returnValue([channel_cmdset]) - except Exception: - _msg_err(caller, _ERROR_CMDSETS) - raise ErrorReported(raw_string) - @inlineCallbacks def _get_local_obj_cmdsets(obj): """ Helper-method; Get Object-level cmdsets + """ # Gather cmdsets from location, objects in location or carried try: @@ -414,6 +395,7 @@ """ Helper method; Get cmdset while making sure to trigger all hooks safely. Returns the stack and the valid options. + """ try: yield obj.at_cmdset_get() @@ -446,13 +428,6 @@ cmdset for cmdset in local_obj_cmdsets if cmdset.key != "ExitCmdSet" ] cmdsets += local_obj_cmdsets - if not current.no_channels: - # also objs may have channels - channel_cmdsets = yield _get_channel_cmdset(obj) - cmdsets += channel_cmdsets - if not current.no_channels: - channel_cmdsets = yield _get_channel_cmdset(account) - cmdsets += channel_cmdsets elif callertype == "account": # we are calling the command from the account level @@ -470,11 +445,6 @@ cmdset for cmdset in local_obj_cmdsets if cmdset.key != "ExitCmdSet" ] cmdsets += local_obj_cmdsets - if not current.no_channels: - # also objs may have channels - cmdsets += yield _get_channel_cmdset(obj) - if not current.no_channels: - cmdsets += yield _get_channel_cmdset(account) elif callertype == "object": # we are calling the command from the object level @@ -488,9 +458,6 @@ cmdset for cmdset in local_obj_cmdsets if cmdset.key != "ExitCmdSet" ] cmdsets += yield local_obj_cmdsets - if not current.no_channels: - # also objs may have channels - cmdsets += yield _get_channel_cmdset(obj) else: raise Exception("get_and_merge_cmdsets: callertype %s is not valid." % callertype) @@ -649,11 +616,6 @@ # since this may be different for every command when # merging multiple cmdsets - if hasattr(cmd, "obj") and hasattr(cmd.obj, "scripts"): - # cmd.obj is automatically made available by the cmdhandler. - # we make sure to validate its scripts. - yield cmd.obj.scripts.validate() - if _testing: # only return the command instance returnValue(cmd) @@ -818,18 +780,6 @@ sysarg += _(' Type "help" for help.') raise ExecSystemCommand(syscmd, sysarg) - # Check if this is a Channel-cmd match. - if hasattr(cmd, "is_channel") and cmd.is_channel: - # even if a user-defined syscmd is not defined, the - # found cmd is already a system command in its own right. - syscmd = yield cmdset.get(CMD_CHANNEL) - if syscmd: - # replace system command with custom version - cmd = syscmd - cmd.session = session - sysarg = "%s:%s" % (cmdname, args) - raise ExecSystemCommand(cmd, sysarg) - # A normal command. ret = yield _run_command(cmd, cmdname, args, raw_cmdname, cmdset, session, account) returnValue(ret) @@ -903,7 +853,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -922,6 +871,7 @@ +
        develop branch
        @@ -112,7 +113,7 @@ for cmdname in [cmd.key] + cmd.aliases if cmdname and l_raw_string.startswith(cmdname.lower()) - and (not cmd.arg_regex or cmd.arg_regex.match(l_raw_string[len(cmdname) :])) + and (not cmd.arg_regex or cmd.arg_regex.match(l_raw_string[len(cmdname):])) ] ) else: @@ -131,7 +132,7 @@ if ( cmdname and l_raw_string.startswith(cmdname.lower()) - and (not cmd.arg_regex or cmd.arg_regex.match(l_raw_string[len(cmdname) :])) + and (not cmd.arg_regex or cmd.arg_regex.match(l_raw_string[len(cmdname):])) ): matches.append(create_match(cmdname, raw_string, cmd, raw_cmdname)) except Exception: @@ -139,7 +140,7 @@ return matches
        -
        [docs]def try_num_prefixes(raw_string): +
        [docs]def try_num_differentiators(raw_string): """ Test if user tried to separate multi-matches with a number separator (default 1-name, 2-name etc). This is usually called last, if no other @@ -167,7 +168,7 @@ # with a #num-command style syntax. We expect the regex to # contain the groups "number" and "name". mindex, new_raw_string = (num_ref_match.group("number"), num_ref_match.group("name")) - return mindex, new_raw_string + return int(mindex), new_raw_string else: return None, None
        @@ -211,19 +212,22 @@ if not raw_string: return [] - # find mathces, first using the full name + # find matches, first using the full name matches = build_matches(raw_string, cmdset, include_prefixes=True) - if not matches: - # try to match a number 1-cmdname, 2-cmdname etc - mindex, new_raw_string = try_num_prefixes(raw_string) - if mindex is not None: - return cmdparser(new_raw_string, cmdset, caller, match_index=int(mindex)) - if _CMD_IGNORE_PREFIXES: - # still no match. Try to strip prefixes - raw_string = ( - raw_string.lstrip(_CMD_IGNORE_PREFIXES) if len(raw_string) > 1 else raw_string - ) - matches = build_matches(raw_string, cmdset, include_prefixes=False) + + if not matches or len(matches) > 1: + # no single match, try parsing for optional numerical tags like 1-cmd + # or cmd-2, cmd.2 etc + match_index, new_raw_string = try_num_differentiators(raw_string) + if match_index is not None: + matches.extend(build_matches(new_raw_string, cmdset, include_prefixes=True)) + + if not matches and _CMD_IGNORE_PREFIXES: + # still no match. Try to strip prefixes + raw_string = ( + raw_string.lstrip(_CMD_IGNORE_PREFIXES) if len(raw_string) > 1 else raw_string + ) + matches = build_matches(raw_string, cmdset, include_prefixes=False) # only select command matches we are actually allowed to call. matches = [match for match in matches if match[2].access(caller, "cmd")] @@ -299,7 +303,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -318,6 +321,7 @@ +
        develop branch
        @@ -399,18 +400,14 @@ """ perm = "perm" if self.permanent else "non-perm" - options = ", ".join( - [ - "{}:{}".format(opt, "T" if getattr(self, opt) else "F") - for opt in ("no_exits", "no_objs", "no_channels", "duplicates") - if getattr(self, opt) is not None - ] - ) + options = ", ".join([ + "{}:{}".format(opt, "T" if getattr(self, opt) else "F") + for opt in ("no_exits", "no_objs", "no_channels", "duplicates") + if getattr(self, opt) is not None + ]) options = (", " + options) if options else "" - return ( - f"<CmdSet {self.key}, {self.mergetype}, {perm}, prio {self.priority}{options}>: " - + ", ".join([str(cmd) for cmd in sorted(self.commands, key=lambda o: o.key)]) - ) + return (f"<CmdSet {self.key}, {self.mergetype}, {perm}, prio {self.priority}{options}>: " + + ", ".join([str(cmd) for cmd in sorted(self.commands, key=lambda o: o.key)])) def __iter__(self): """ @@ -522,7 +519,8 @@ # This is used for diagnosis. cmdset_c.actual_mergetype = mergetype - # print "__add__ for %s (prio %i) called with %s (prio %i)." % (self.key, self.priority, cmdset_a.key, cmdset_a.priority) + # print "__add__ for %s (prio %i) called with %s (prio %i)." % (self.key, self.priority, + # cmdset_a.key, cmdset_a.priority) # return the system commands to the cmdset cmdset_c.add(sys_commands, allow_duplicates=True) @@ -715,6 +713,7 @@ Hook method - this should be overloaded in the inheriting class, and should take care of populating the cmdset by use of self.add(). + """ pass
        @@ -754,7 +753,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -773,6 +771,7 @@ +
        develop branch
        @@ -103,6 +104,7 @@ can then implement separate sets for different situations. For example, you can have a 'On a boat' set, onto which you then tack on the 'Fishing' set. Fishing from a boat? No problem! + """ import sys from traceback import format_exc @@ -144,7 +146,7 @@ _ERROR_CMDSET_EXCEPTION = _( """{traceback} -Compile/Run error when loading cmdset '{path}'.", +Compile/Run error when loading cmdset '{path}'. (Traceback was logged {timestamp})""" ) @@ -209,7 +211,7 @@ if "." in path: modpath, classname = python_path.rsplit(".", 1) else: - raise ImportError("The path '%s' is not on the form modulepath.ClassName" % path) + raise ImportError(f"The path '{path}' is not on the form modulepath.ClassName") try: # first try to get from cache @@ -353,6 +355,7 @@ def __str__(self): """ Display current commands + """ strings = ["<CmdSetHandler> stack:"] @@ -462,7 +465,8 @@ self.mergetype_stack.append(new_current.actual_mergetype) self.current = new_current
        -
        [docs] def add(self, cmdset, emit_to_obj=None, permanent=False, default_cmdset=False): +
        [docs] def add(self, cmdset, emit_to_obj=None, persistent=True, default_cmdset=False, + **kwargs): """ Add a cmdset to the handler, on top of the old ones, unless it is set as the default one (it will then end up at the bottom of the stack) @@ -471,7 +475,7 @@ cmdset (CmdSet or str): Can be a cmdset object or the python path to such an object. emit_to_obj (Object, optional): An object to receive error messages. - permanent (bool, optional): This cmdset will remain across a server reboot. + persistent (bool, optional): Let cmdset remain across server reload. default_cmdset (Cmdset, optional): Insert this to replace the default cmdset position (there is only one such position, always at the bottom of the stack). @@ -488,6 +492,11 @@ it's a 'quirk' that has to be documented. """ + if "permanent" in kwargs: + logger.log_dep("obj.cmdset.add() kwarg 'permanent' has changed name to " + "'persistent' and now defaults to True.") + persistent = kwargs['permanent'] if persistent is None else persistent + if not (isinstance(cmdset, str) or utils.inherits_from(cmdset, CmdSet)): string = _("Only CmdSets can be added to the cmdsethandler!") raise Exception(string) @@ -498,8 +507,8 @@ # this is (maybe) a python path. Try to import from cache. cmdset = self._import_cmdset(cmdset) if cmdset and cmdset.key != "_CMDSET_ERROR": - cmdset.permanent = permanent - if permanent and cmdset.key != "_CMDSET_ERROR": + cmdset.permanent = persistent # TODO change on cmdset too + if persistent and cmdset.key != "_CMDSET_ERROR": # store the path permanently storage = self.obj.cmdset_storage or [""] if default_cmdset: @@ -513,17 +522,21 @@ self.cmdset_stack.append(cmdset) self.update()
        -
        [docs] def add_default(self, cmdset, emit_to_obj=None, permanent=True): +
        [docs] def add_default(self, cmdset, emit_to_obj=None, persistent=True, **kwargs): """ Shortcut for adding a default cmdset. Args: cmdset (Cmdset): The Cmdset to add. emit_to_obj (Object, optional): Gets error messages - permanent (bool, optional): The new Cmdset should survive a server reboot. + persistent (bool, optional): The new Cmdset should survive a server reboot. """ - self.add(cmdset, emit_to_obj=emit_to_obj, permanent=permanent, default_cmdset=True)
        + if "permanent" in kwargs: + logger.log_dep("obj.cmdset.add_default() kwarg 'permanent' has changed name to " + "'persistent'.") + persistent = kwargs['permanent'] if persistent is None else persistent + self.add(cmdset, emit_to_obj=emit_to_obj, persistent=persistent, default_cmdset=True)
        [docs] def remove(self, cmdset=None, default_cmdset=False): """ @@ -730,7 +743,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -749,6 +761,7 @@ +
        develop branch
        @@ -57,6 +58,13 @@ from evennia.utils.ansi import ANSIString +
        [docs]class InterruptCommand(Exception): + + """Cleanly interrupt a command.""" + + pass
        + + def _init_command(cls, **kwargs): """ Helper command. @@ -125,6 +133,15 @@ break cls.help_category = cls.help_category.lower() + # pre-prepare a help index entry for quicker lookup + cls.search_index_entry = { + "key": cls.key, + "aliases": " ".join(cls.aliases), + "category": cls.help_category, + "text": cls.__doc__, + "tags": "", + } +
        [docs]class CommandMeta(type): """ @@ -144,9 +161,11 @@ # parsing errors. -
        [docs]class Command(object, metaclass=CommandMeta): +
        [docs]class Command(metaclass=CommandMeta): """ - Base command + ## Base command + + (you may see this if a child command had no help text defined) Usage: command [args] @@ -551,20 +570,6 @@ )[0] return settings.CLIENT_DEFAULT_WIDTH
        -
        [docs] def client_height(self): - """ - Get the client screenheight for the session using this command. - - Returns: - client height (int): The height (in characters) of the client window. - - """ - if self.session: - return self.session.protocol_flags.get( - "SCREENHEIGHT", {0: settings.CLIENT_DEFAULT_HEIGHT} - )[0] - return settings.CLIENT_DEFAULT_HEIGHT
        -
        [docs] def styled_table(self, *args, **kwargs): """ Create an EvTable styled by on user preferences. @@ -609,6 +614,7 @@ border_left_char=border_left_char, border_right_char=border_right_char, border_top_char=border_top_char, + border_bottom_char=border_bottom_char, **kwargs, ) return table
        @@ -712,13 +718,6 @@ if "mode" not in kwargs: kwargs["mode"] = "footer" return self._render_decoration(*args, **kwargs)
        - - -
        [docs]class InterruptCommand(Exception): - - """Cleanly interrupt a command.""" - - pass
        @@ -756,7 +755,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -775,6 +773,7 @@ +
        develop branch
        @@ -861,7 +862,7 @@ testing which colors your client support Usage: - color ansi||xterm256 + color ansi | xterm256 Prints a color map along with in-mud color codes to use to produce them. It also tests what is supported in your client. Choices are @@ -1130,7 +1131,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1149,6 +1149,7 @@ +
        develop branch
        @@ -671,7 +672,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -690,6 +690,7 @@ +
        develop branch
        @@ -224,7 +225,7 @@ # something went wrong. Purge cmdset except default caller.cmdset.clear() - caller.scripts.validate() # this will purge interactive mode + # caller.scripts.validate() # this will purge interactive mode # ------------------------------------------------------------- @@ -897,7 +898,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -916,6 +916,7 @@ +
        develop branch
        @@ -48,7 +49,7 @@ from evennia.objects.models import ObjectDB from evennia.locks.lockhandler import LockException from evennia.commands.cmdhandler import get_and_merge_cmdsets -from evennia.utils import create, utils, search, logger +from evennia.utils import create, utils, search, logger, funcparser from evennia.utils.utils import ( inherits_from, class_from_module, @@ -63,10 +64,11 @@ from evennia.utils.evmore import EvMore from evennia.prototypes import spawner, prototypes as protlib, menus as olc_menus from evennia.utils.ansi import raw as ansi_raw -from evennia.utils.inlinefuncs import raw as inlinefunc_raw COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS) +_FUNCPARSER = None + # limit symbol import for API __all__ = ( "ObjManipCommand", @@ -2163,7 +2165,8 @@ ) if "prototype" in self.switches: - modified = spawner.batch_update_objects_with_prototype(prototype, objects=[obj]) + modified = spawner.batch_update_objects_with_prototype( + prototype, objects=[obj], caller=self.caller) prototype_success = modified > 0 if not prototype_success: caller.msg("Prototype %s failed to apply." % prototype["key"]) @@ -2421,12 +2424,16 @@ value (any): Attribute value. Returns: """ + global _FUNCPARSER + if not _FUNCPARSER: + _FUNCPARSER = funcparser.FuncParser(settings.FUNCPARSER_OUTGOING_MESSAGES_MODULES) + if attr is None: return "No such attribute was found." value = utils.to_str(value) if crop: value = utils.crop(value) - value = inlinefunc_raw(ansi_raw(value)) + value = _FUNCPARSER.parse(ansi_raw(value), escape=True) if category: return f"{attr}[{category}] = {value}" else: @@ -2558,14 +2565,12 @@ def _format_options(cmdset): """helper for cmdset-option display""" - def _truefalse(string, value): if value is None: return "" if value: return f"{string}: T" return f"{string}: F" - options = ", ".join( _truefalse(opt, getattr(cmdset, opt)) for opt in ("no_exits", "no_objs", "no_channels", "duplicates") @@ -2582,8 +2587,7 @@ continue options = _format_options(cmdset) stored.append( - f"{cmdset.path} [{cmdset.key}] ({cmdset.mergetype}, prio {cmdset.priority}{options})" - ) + f"{cmdset.path} [{cmdset.key}] ({cmdset.mergetype}, prio {cmdset.priority}{options})") output["Stored Cmdset(s)"] = "\n " + "\n ".join(stored) # this gets all components of the currently merged set @@ -2621,15 +2625,13 @@ # the resulting merged cmdset options = _format_options(current_cmdset) merged = [ - f"<Current merged cmdset> ({current_cmdset.mergetype} prio {current_cmdset.priority}{options})" - ] + f"<Current merged cmdset> ({current_cmdset.mergetype} prio {current_cmdset.priority}{options})"] # the merge stack for cmdset in all_cmdsets: options = _format_options(cmdset) merged.append( - f"{cmdset.path} [{cmdset.key}] ({cmdset.mergetype} prio {cmdset.priority}{options})" - ) + f"{cmdset.path} [{cmdset.key}] ({cmdset.mergetype} prio {cmdset.priority}{options})") output["Merged Cmdset(s)"] = "\n " + "\n ".join(merged) # list the commands available to this object @@ -3109,7 +3111,7 @@ attach a script to an object Usage: - script[/switch] <obj> [= script_path or <scriptkey>] + addscript[/switch] <obj> [= script_path or <scriptkey>] Switches: start - start all non-running scripts on object, or a given script only @@ -3124,8 +3126,8 @@ the object. """ - key = "script" - aliases = "addscript" + key = "addscript" + aliases = ["attachscript"] switch_options = ("start", "stop") locks = "cmd:perm(script) or perm(Builder)" help_category = "Building" @@ -3170,7 +3172,6 @@ % (script.get_display_name(caller), obj.get_display_name(caller)) ) script.stop() - obj.scripts.validate() else: # rhs exists if not self.switches: # adding a new script, and starting it @@ -3509,7 +3510,7 @@ "Python structures are allowed. \nMake sure to use correct " "Python syntax. Remember especially to put quotes around all " "strings inside lists and dicts.|n For more advanced uses, embed " - "inlinefuncs in the strings." + "funcparser callables ($funcs) in the strings." ) else: string = "Expected {}, got {}.".format(expect, type(prototype)) @@ -3605,7 +3606,7 @@ return try: n_updated = spawner.batch_update_objects_with_prototype( - prototype, objects=existing_objects + prototype, objects=existing_objects, caller=caller, ) except Exception: logger.log_trace() @@ -3857,7 +3858,7 @@ # proceed to spawning try: - for obj in spawner.spawn(prototype): + for obj in spawner.spawn(prototype, caller=self.caller): self.caller.msg("Spawned %s." % obj.get_display_name(self.caller)) if not prototype.get("location") and not noloc: # we don't hardcode the location in the prototype (unless the user @@ -3903,7 +3904,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -3922,6 +3922,7 @@ +
        develop branch
        @@ -100,15 +101,15 @@ self.add(admin.CmdNewPassword()) # Comm commands + self.add(comms.CmdChannel()) + # self.add(comms.CmdChannels()) self.add(comms.CmdAddCom()) self.add(comms.CmdDelCom()) self.add(comms.CmdAllCom()) - self.add(comms.CmdChannels()) self.add(comms.CmdCdestroy()) self.add(comms.CmdChannelCreate()) self.add(comms.CmdClock()) self.add(comms.CmdCBoot()) - self.add(comms.CmdCemit()) self.add(comms.CmdCWho()) self.add(comms.CmdCdesc()) self.add(comms.CmdPage()) @@ -153,7 +154,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -172,6 +172,7 @@ +
        develop branch
        @@ -91,6 +92,7 @@ self.add(system.CmdServerLoad()) # self.add(system.CmdPs()) self.add(system.CmdTickers()) + self.add(system.CmdTasks()) # Admin commands self.add(admin.CmdBoot()) @@ -168,7 +170,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -187,6 +188,7 @@ +
        develop branch
        @@ -94,7 +95,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -113,6 +113,7 @@ +
        develop branch
        @@ -103,7 +104,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -122,6 +122,7 @@ +
        develop branch
        @@ -40,24 +41,24 @@

        Source code for evennia.commands.default.comms

         """
        -Comsystem command module.
        +Communication commands:
         
        -Comm commands are OOC commands and intended to be made available to
        -the Account at all times (they go into the AccountCmdSet). So we
        -make sure to homogenize self.caller to always be the account object
        -for easy handling.
        +- channel
        +- page
        +- irc/rss/grapevine linking
         
         """
        -import hashlib
        -import time
        +
         from django.conf import settings
        -from evennia.comms.models import ChannelDB, Msg
        +from evennia.comms.models import Msg
         from evennia.accounts.models import AccountDB
         from evennia.accounts import bots
        -from evennia.comms.channelhandler import CHANNELHANDLER
         from evennia.locks.lockhandler import LockException
        -from evennia.utils import create, logger, utils, evtable
        -from evennia.utils.utils import make_iter, class_from_module
        +from evennia.comms.comms import DefaultChannel
        +from evennia.utils import create, logger, utils
        +from evennia.utils.logger import tail_log_file
        +from evennia.utils.utils import class_from_module
        +from evennia.utils.evmenu import ask_yes_no
         
         COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
         CHANNEL_DEFAULT_TYPECLASS = class_from_module(
        @@ -66,18 +67,20 @@
         
         # limit symbol import for API
         __all__ = (
        +    "CmdChannel",
        +
             "CmdAddCom",
             "CmdDelCom",
             "CmdAllCom",
        -    "CmdChannels",
             "CmdCdestroy",
             "CmdCBoot",
        -    "CmdCemit",
             "CmdCWho",
             "CmdChannelCreate",
             "CmdClock",
             "CmdCdesc",
        +
             "CmdPage",
        +
             "CmdIRC2Chan",
             "CmdIRCStatus",
             "CmdRSS2Chan",
        @@ -85,36 +88,1212 @@
         )
         _DEFAULT_WIDTH = settings.CLIENT_DEFAULT_WIDTH
         
        +# helper functions to make it easier to override the main CmdChannel
        +# command and to keep the legacy addcom etc commands around.
         
        -def find_channel(caller, channelname, silent=False, noaliases=False):
        +
        +
        [docs]class CmdChannel(COMMAND_DEFAULT_CLASS): """ - Helper function for searching for a single channel with - some error handling. + Use and manage in-game channels. + + Usage: + channel channelname <msg> + channel channel name = <msg> + channel (show all subscription) + channel/all (show available channels) + channel/alias channelname = alias[;alias...] + channel/unalias alias + channel/who channelname + channel/history channelname [= index] + channel/sub channelname [= alias[;alias...]] + channel/unsub channelname[,channelname, ...] + channel/mute channelname[,channelname,...] + channel/unmute channelname[,channelname,...] + + channel/create channelname[;alias;alias[:typeclass]] [= description] + channel/destroy channelname [= reason] + channel/desc channelname = description + channel/lock channelname = lockstring + channel/unlock channelname = lockstring + channel/ban channelname (list bans) + channel/ban[/quiet] channelname[, channelname, ...] = subscribername [: reason] + channel/unban[/quiet] channelname[, channelname, ...] = subscribername + channel/boot[/quiet] channelname[,channelname,...] = subscribername [: reason] + + # subtopics + + ## sending + + Usage: channel channelname msg + channel channel name = msg (with space in channel name) + + This sends a message to the channel. Note that you will rarely use this + command like this; instead you can use the alias + + channelname <msg> + channelalias <msg> + + For example + + public Hello World + pub Hello World + + (this shortcut doesn't work for aliases containing spaces) + + See channel/alias for help on setting channel aliases. + + ## alias and unalias + + Usage: channel/alias channel = alias[;alias[;alias...]] + channel/unalias alias + channel - this will list your subs and aliases to each channel + + Set one or more personal aliases for referencing a channel. For example: + + channel/alias warrior's guild = warrior;wguild;warchannel;warrior guild + + You can now send to the channel using all of these: + + warrior's guild Hello + warrior Hello + wguild Hello + warchannel Hello + + Note that this will not work if the alias has a space in it. So the + 'warrior guild' alias must be used with the `channel` command: + + channel warrior guild = Hello + + Channel-aliases can be removed one at a time, using the '/unalias' switch. + + ## who + + Usage: channel/who channelname + + List the channel's subscribers. Shows who are currently offline or are + muting the channel. Subscribers who are 'muting' will not see messages sent + to the channel (use channel/mute to mute a channel). + + ## history + + Usage: channel/history channel [= index] + + This will display the last |c20|n lines of channel history. By supplying an + index number, you will step that many lines back before viewing those 20 lines. + + For example: + + channel/history public = 35 + + will go back 35 lines and show the previous 20 lines from that point (so + lines -35 to -55). + + ## sub and unsub + + Usage: channel/sub channel [=alias[;alias;...]] + channel/unsub channel + + This subscribes you to a channel and optionally assigns personal shortcuts + for you to use to send to that channel (see aliases). When you unsub, all + your personal aliases will also be removed. + + ## mute and unmute + + Usage: channel/mute channelname + channel/unmute channelname + + Muting silences all output from the channel without actually + un-subscribing. Other channel members will see that you are muted in the /who + list. Sending a message to the channel will automatically unmute you. + + ## create and destroy + + Usage: channel/create channelname[;alias;alias[:typeclass]] [= description] + channel/destroy channelname [= reason] + + Creates a new channel (or destroys one you control). You will automatically + join the channel you create and everyone will be kicked and loose all aliases + to a destroyed channel. + + ## lock and unlock + + Usage: channel/lock channelname = lockstring + channel/unlock channelname = lockstring + + Note: this is an admin command. + + A lockstring is on the form locktype:lockfunc(). Channels understand three + locktypes: + listen - who may listen or join the channel. + send - who may send messages to the channel + control - who controls the channel. This is usually the one creating + the channel. + + Common lockfuncs are all() and perm(). To make a channel everyone can + listen to but only builders can talk on, use this: + + listen:all() + send: perm(Builders) + + ## boot and ban + + Usage: + channel/boot[/quiet] channelname[,channelname,...] = subscribername [: reason] + channel/ban channelname[, channelname, ...] = subscribername [: reason] + channel/unban channelname[, channelname, ...] = subscribername + channel/unban channelname + channel/ban channelname (list bans) + + Booting will kick a named subscriber from channel(s) temporarily. The + 'reason' will be passed to the booted user. Unless the /quiet switch is + used, the channel will also be informed of the action. A booted user is + still able to re-connect, but they'll have to set up their aliases again. + + Banning will blacklist a user from (re)joining the provided channels. It + will then proceed to boot them from those channels if they were connected. + The 'reason' and `/quiet` works the same as for booting. + + Example: + boot mychannel1 = EvilUser : Kicking you to cool down a bit. + ban mychannel1,mychannel2= EvilUser : Was banned for spamming. + """ - channels = CHANNEL_DEFAULT_TYPECLASS.objects.channel_search(channelname) - if not channels: - if not noaliases: - channels = [ - chan - for chan in CHANNEL_DEFAULT_TYPECLASS.objects.get_all_channels() - if channelname in chan.aliases.all() - ] - if channels: + key = "channel" + aliases = ["chan", "channels"] + help_category = "Comms" + # these cmd: lock controls access to the channel command itself + # the admin: lock controls access to /boot/ban/unban switches + # the manage: lock controls access to /create/destroy/desc/lock/unlock switches + locks = "cmd:not pperm(channel_banned);admin:all();manage:all();changelocks:perm(Admin)" + switch_options = ( + "list", "all", "history", "sub", "unsub", "mute", "unmute", "alias", "unalias", + "create", "destroy", "desc", "lock", "unlock", "boot", "ban", "unban", "who",) + # disable this in child command classes if wanting on-character channels + account_caller = True + +
        [docs] def search_channel(self, channelname, exact=False, handle_errors=True): + """ + Helper function for searching for a single channel with some error + handling. + + Args: + channelname (str): Name, alias #dbref or partial name/alias to search + for. + exact (bool, optional): If an exact or fuzzy-match of the name should be done. + Note that even for a fuzzy match, an exactly given, unique channel name + will always be returned. + handle_errors (bool): If true, use `self.msg` to report errors if + there are non/multiple matches. If so, the return will always be + a single match or None. + Returns: + object, list or None: If `handle_errors` is `True`, this is either a found Channel + or `None`. Otherwise it's a list of zero, one or more channels found. + Notes: + The 'listen' and 'control' accesses are checked before returning. + + """ + caller = self.caller + # first see if this is a personal alias + channelname = caller.nicks.get(key=channelname, category="channel") or channelname + + # always try the exact match first. + channels = CHANNEL_DEFAULT_TYPECLASS.objects.channel_search(channelname, exact=True) + + if not channels and not exact: + # try fuzzy matching as well + channels = CHANNEL_DEFAULT_TYPECLASS.objects.channel_search(channelname, exact=exact) + + # check permissions + channels = [channel for channel in channels + if channel.access(caller, 'listen') or channel.access(caller, 'control')] + + if handle_errors: + if not channels: + self.msg(f"No channel found matching '{channelname}' " + "(could also be due to missing access).") + return None + elif len(channels) > 1: + self.msg("Multiple possible channel matches/alias for " + "'{channelname}':\n" + ", ".join(chan.key for chan in channels)) + return None return channels[0] - if not silent: - caller.msg("Channel '%s' not found." % channelname) - return None - elif len(channels) > 1: - matches = ", ".join(["%s(%s)" % (chan.key, chan.id) for chan in channels]) - if not silent: - caller.msg("Multiple channels match (be more specific): \n%s" % matches) - return None - return channels[0] + else: + if not channels: + return [] + elif len(channels) > 1: + return list(channels) + return [channels[0]]
        + +
        [docs] def msg_channel(self, channel, message, **kwargs): + """ + Send a message to a given channel. This will check the 'send' + permission on the channel. + + Args: + channel (Channel): The channel to send to. + message (str): The message to send. + **kwargs: Unused by default. These kwargs will be passed into + all channel messaging hooks for custom overriding. + + """ + if not channel.access(self.caller, "send"): + caller.msg(f"You are not allowed to send messages to channel {channel}") + return + + channel.msg(message, senders=self.caller, **kwargs)
        + +
        [docs] def get_channel_history(self, channel, start_index=0): + """ + View a channel's history. + + Args: + channel (Channel): The channel to access. + message (str): The message to send. + **kwargs: Unused by default. These kwargs will be passed into + all channel messaging hooks for custom overriding. + + """ + caller = self.caller + log_file = channel.get_log_filename() + + def send_msg(lines): + return self.msg( + "".join(line.split("[-]", 1)[1] if "[-]" in line else line for line in lines) + ) + # asynchronously tail the log file + tail_log_file(log_file, start_index, 20, callback=send_msg)
        + +
        [docs] def sub_to_channel(self, channel): + """ + Subscribe to a channel. Note that all permissions should + be checked before this step. + + Args: + channel (Channel): The channel to access. + + Returns: + bool, str: True, None if connection failed. If False, + the second part is an error string. + + """ + caller = self.caller + + if channel.has_connection(caller): + return False, f"Already listening to channel {channel.key}." + + # this sets up aliases in post_join_channel by default + result = channel.connect(caller) + + return result, "" if result else f"Were not allowed to subscribe to channel {channel.key}"
        + +
        [docs] def unsub_from_channel(self, channel, **kwargs): + """ + Un-Subscribe to a channel. Note that all permissions should + be checked before this step. + + Args: + channel (Channel): The channel to unsub from. + **kwargs: Passed on to nick removal. + + Returns: + bool, str: True, None if un-connection succeeded. If False, + the second part is an error string. + + """ + caller = self.caller + + if not channel.has_connection(caller): + return False, f"Not listening to channel {channel.key}." + + # this will also clean aliases + result = channel.disconnect(caller) + + return result, "" if result else f"Could not unsubscribe from channel {channel.key}"
        + +
        [docs] def add_alias(self, channel, alias, **kwargs): + """ + Add a new alias (nick) for the user to use with this channel. + + Args: + channel (Channel): The channel to alias. + alias (str): The personal alias to use for this channel. + **kwargs: If given, passed into nicks.add. + + Note: + We add two nicks - one is a plain `alias -> channel.key` that + we need to be able to reference this channel easily. The other + is a templated nick to easily be able to send messages to the + channel without needing to give the full `channel` command. The + structure of this nick is given by `self.channel_msg_pattern` + and `self.channel_msg_nick_replacement`. By default it maps + `alias <msg> -> channel <channelname> = <msg>`, so that you can + for example just write `pub Hello` to send a message. + + The alias created is `alias $1 -> channel channel = $1`, to allow + for sending to channel using the main channel command. + + """ + channel.add_user_channel_alias(self.caller, alias, **kwargs)
        + +
        [docs] def remove_alias(self, alias, **kwargs): + """ + Remove an alias from a channel. + + Args: + alias (str, optional): The alias to remove. + The channel will be reverse-determined from the + alias, if it exists. + + Returns: + bool, str: True, None if removal succeeded. If False, + the second part is an error string. + **kwargs: If given, passed into nicks.get/add. + + Note: + This will remove two nicks - the plain channel alias and the templated + nick used for easily sending messages to the channel. + + """ + if self.caller.nicks.has(alias, category="channel", **kwargs): + DefaultChannel.remove_user_channel_alias(self.caller, alias) + return True, "" + return False, "No such alias was defined."
        + +
        [docs] def get_channel_aliases(self, channel): + """ + Get a user's aliases for a given channel. The user is retrieved + through self.caller. + + Args: + channel (Channel): The channel to act on. + + Returns: + list: A list of zero, one or more alias-strings. + + """ + chan_key = channel.key.lower() + nicktuples = self.caller.nicks.get(category="channel", return_tuple=True, return_list=True) + if nicktuples: + return [tup[2] for tup in nicktuples if tup[3].lower() == chan_key] + return []
        + +
        [docs] def mute_channel(self, channel): + """ + Temporarily mute a channel. + + Args: + channel (Channel): The channel to alias. + + Returns: + bool, str: True, None if muting successful. If False, + the second part is an error string. + """ + if channel.mute(self.caller): + return True, "" + return False, f"Channel {channel.key} was already muted."
        + +
        [docs] def unmute_channel(self, channel): + """ + Unmute a channel. + + Args: + channel (Channel): The channel to alias. + + Returns: + bool, str: True, None if unmuting successful. If False, + the second part is an error string. + + """ + if channel.unmute(self.caller): + return True, "" + return False, f"Channel {channel.key} was already unmuted."
        + +
        [docs] def create_channel(self, name, description, typeclass=None, aliases=None): + """ + Create a new channel. Its name must not previously exist + (users can alias as needed). Will also connect to the + new channel. + + Args: + name (str): The new channel name/key. + description (str): This is used in listings. + aliases (list): A list of strings - alternative aliases for the channel + (not to be confused with per-user aliases; these are available for + everyone). + + Returns: + channel, str: new_channel, "" if creation successful. If False, + the second part is an error string. + + """ + caller = self.caller + if typeclass: + typeclass = class_from_module(typeclass) + else: + typeclass = CHANNEL_DEFAULT_TYPECLASS + + if typeclass.objects.channel_search(name, exact=True): + return False, f"Channel {name} already exists." + + # set up the new channel + lockstring = "send:all();listen:all();control:id(%s)" % caller.id + + new_chan = create.create_channel( + name, aliases=aliases, desc=description, locks=lockstring, typeclass=typeclass) + self.sub_to_channel(new_chan) + return new_chan, ""
        + +
        [docs] def destroy_channel(self, channel, message=None): + """ + Destroy an existing channel. Access should be checked before + calling this function. + + Args: + channel (Channel): The channel to alias. + message (str, optional): Final message to send onto the channel + before destroying it. If not given, a default message is + used. Set to the empty string for no message. + + if typeclass: + pass + + """ + caller = self.caller + + channel_key = channel.key + if message is None: + message = (f"|rChannel {channel_key} is being destroyed. " + "Make sure to clean any channel aliases.|n") + if message: + channel.msg(message, senders=caller, bypass_mute=True) + channel.delete() + logger.log_sec( + "Channel {} was deleted by {}".format(channel_key, caller) + )
        + +
        [docs] def set_lock(self, channel, lockstring): + """ + Set a lockstring on a channel. Permissions must have been + checked before this call. + + Args: + channel (Channel): The channel to operate on. + lockstring (str): A lockstring on the form 'type:lockfunc();...' + + Returns: + bool, str: True, None if setting lock was successful. If False, + the second part is an error string. + + """ + try: + channel.locks.add(lockstring) + except LockException as err: + return False, err + return True, ""
        + +
        [docs] def unset_lock(self, channel, lockstring): + """ + Remove locks in a lockstring on a channel. Permissions must have been + checked before this call. + + Args: + channel (Channel): The channel to operate on. + lockstring (str): A lockstring on the form 'type:lockfunc();...' + + Returns: + bool, str: True, None if setting lock was successful. If False, + the second part is an error string. + + """ + try: + channel.locks.remove(lockstring) + except LockException as err: + return False, err + return True, ""
        + +
        [docs] def set_desc(self, channel, description): + """ + Set a channel description. This is shown in listings etc. + + Args: + caller (Object or Account): The entity performing the action. + channel (Channel): The channel to operate on. + description (str): A short description of the channel. + + Returns: + bool, str: True, None if setting lock was successful. If False, + the second part is an error string. + + """ + channel.db.desc = description
        + +
        [docs] def boot_user(self, channel, target, quiet=False, reason=""): + """ + Boot a user from a channel, with optional reason. This will + also remove all their aliases for this channel. + + Args: + channel (Channel): The channel to operate on. + target (Object or Account): The entity to boot. + quiet (bool, optional): Whether or not to announce to channel. + reason (str, optional): A reason for the boot. + + Returns: + bool, str: True, None if setting lock was successful. If False, + the second part is an error string. + + """ + if not channel.subscriptions.has(target): + return False, f"{target} is not connected to channel {channel.key}." + # find all of target's nicks linked to this channel and delete them + for nick in [ + nick + for nick in target.nicks.get(category="channel") or [] + if nick.value[3].lower() == channel.key + ]: + nick.delete() + channel.disconnect(target) + reason = f" Reason: {reason}" if reason else "" + target.msg(f"You were booted from channel {channel.key} by {self.caller.key}.{reason}") + if not quiet: + channel.msg(f"{target.key} was booted from channel by {self.caller.key}.{reason}") + + logger.log_sec(f"Channel Boot: {target} (Channel: {channel}, " + f"Reason: {reason.strip()}, Caller: {self.caller}") + return True, ""
        + +
        [docs] def ban_user(self, channel, target, quiet=False, reason=""): + """ + Ban a user from a channel, by locking them out. This will also + boot them, if they are currently connected. + + Args: + channel (Channel): The channel to operate on. + target (Object or Account): The entity to ban + quiet (bool, optional): Whether or not to announce to channel. + reason (str, optional): A reason for the ban + + Returns: + bool, str: True, None if banning was successful. If False, + the second part is an error string. + + """ + self.boot_user(channel, target, quiet=quiet, reason=reason) + if channel.ban(target): + return True, "" + return False, f"{target} is already banned from this channel."
        + +
        [docs] def unban_user(self, channel, target): + """ + Un-Ban a user from a channel. This will not reconnect them + to the channel, just allow them to connect again (assuming + they have the suitable 'listen' lock like everyone else). + + Args: + channel (Channel): The channel to operate on. + target (Object or Account): The entity to unban + + Returns: + bool, str: True, None if unbanning was successful. If False, + the second part is an error string. + + """ + if channel.unban(target): + return True, "" + return False, f"{target} was not previously banned from this channel."
        + +
        [docs] def channel_list_bans(self, channel): + """ + Show a channel's bans. + + Args: + channel (Channel): The channel to operate on. + + Returns: + list: A list of strings, each the name of a banned user. + + """ + return [banned.key for banned in channel.banlist]
        + +
        [docs] def channel_list_who(self, channel): + """ + Show a list of online people is subscribing to a channel. This will check + the 'control' permission of `caller` to determine if only online users + should be returned or everyone. + + Args: + channel (Channel): The channel to operate on. + + Returns: + list: A list of prepared strings, with name + markers for if they are + muted or offline. + + """ + caller = self.caller + mute_list = list(channel.mutelist) + online_list = channel.subscriptions.online() + if channel.access(caller, 'control'): + # for those with channel control, show also offline users + all_subs = list(channel.subscriptions.all()) + else: + # for others, only show online users + all_subs = online_list + + who_list = [] + for subscriber in all_subs: + name = subscriber.get_display_name(caller) + conditions = ("muting" if subscriber in mute_list else "", + "offline" if subscriber not in online_list else "") + conditions = [cond for cond in conditions if cond] + cond_text = "(" + ", ".join(conditions) + ")" if conditions else "" + who_list.append(f"{name}{cond_text}") + + return who_list
        + +
        [docs] def list_channels(self, channelcls=CHANNEL_DEFAULT_TYPECLASS): + """ + Return a available channels. + + Args: + channelcls (Channel, optional): The channel-class to query on. Defaults + to the default channel class from settings. + + Returns: + tuple: A tuple `(subbed_chans, available_chans)` with the channels + currently subscribed to, and those we have 'listen' access to but + don't actually sub to yet. + + """ + caller = self.caller + subscribed_channels = list(channelcls.objects.get_subscriptions(caller)) + unsubscribed_available_channels = [ + chan + for chan in channelcls.objects.get_all_channels() + if chan not in subscribed_channels and chan.access(caller, "listen") + ] + return subscribed_channels, unsubscribed_available_channels
        + +
        [docs] def display_subbed_channels(self, subscribed): + """ + Display channels subscribed to. + + Args: + subscribed (list): List of subscribed channels + + Returns: + EvTable: Table to display. + + """ + comtable = self.styled_table( + "channel", + "my aliases", + "locks", + "description", + align="l", + maxwidth=_DEFAULT_WIDTH + ) + for chan in subscribed: + + locks = "-" + if chan.access(self.caller, "control"): + locks = chan.locks + + my_aliases = ", ".join(self.get_channel_aliases(chan)) + comtable.add_row( + *("{}{}".format( + chan.key, + "({})".format(",".join(chan.aliases.all())) if chan.aliases.all() else ""), + my_aliases, + locks, + chan.db.desc)) + return comtable
        + +
        [docs] def display_all_channels(self, subscribed, available): + """ + Display all available channels + + Args: + subscribed (list): List of subscribed channels + Returns: + EvTable: Table to display. + + """ + caller = self.caller + + comtable = self.styled_table( + "sub", + "channel", + "aliases", + "my aliases", + "description", + maxwidth=_DEFAULT_WIDTH, + ) + channels = subscribed + available + + for chan in channels: + if chan not in subscribed: + substatus = "|rNo|n" + elif caller in chan.mutelist: + substatus = "|rMuting|n" + else: + substatus = "|gYes|n" + my_aliases = ", ".join(self.get_channel_aliases(chan)) + comtable.add_row( + *(substatus, + chan.key, + ",".join(chan.aliases.all()) if chan.aliases.all() else "", + my_aliases, + chan.db.desc)) + comtable.reformat_column(0, width=8) + + return comtable
        + +
        [docs] def func(self): + """ + Main functionality of command. + """ + # from evennia import set_trace;set_trace() + + caller = self.caller + switches = self.switches + channel_names = [name for name in self.lhslist if name] + + #from evennia import set_trace;set_trace() + + if 'all' in switches: + # show all available channels + subscribed, available = self.list_channels() + table = self.display_all_channels(subscribed, available) + + self.msg( + "\n|wAvailable channels|n (use no argument to " + f"only show your subscriptions)\n{table}") + return + + if not channel_names: + # empty arg show only subscribed channels + subscribed, _ = self.list_channels() + table = self.display_subbed_channels(subscribed) + + self.msg("\n|wChannel subscriptions|n " + f"(use |w/all|n to see all available):\n{table}") + return + + if not self.switches and not self.args: + self.msg("Usage[/switches]: channel [= message]") + return + + if 'create' in switches: + # create a new channel + + if not self.access(caller, "manage"): + self.msg("You don't have access to use channel/create.") + return + + config = self.lhs + if not config: + self.msg("To create: channel/create name[;aliases][:typeclass] [= description]") + return + name, *typeclass = config.rsplit(":", 1) + typeclass = typeclass[0] if typeclass else None + name, *aliases = name.rsplit(";") + description = self.rhs or "" + chan, err = self.create_channel(name, description, typeclass=typeclass, aliases=aliases) + if chan: + self.msg(f"Created (and joined) new channel '{chan.key}'.") + else: + self.msg(err) + return + + if 'unalias' in switches: + # remove a personal alias (no channel needed) + alias = self.args.strip() + if not alias: + self.msg("Specify the alias to remove as channel/unalias <alias>") + return + success, err = self.remove_alias(alias) + if success: + self.msg(f"Removed your channel alias '{alias}'.") + else: + self.msg(err) + return + + possible_lhs_message = "" + if not self.rhs and self.args and " " in self.args: + # since we want to support messaging with `channel name text` (for + # channels without a space in their name), we need to check if the + # first 'channel name' is in fact 'channelname text' + no_rhs_channel_name = self.args.split(" ", 1)[0] + possible_lhs_message = self.args[len(no_rhs_channel_name):] + if possible_lhs_message.strip() == '=': + possible_lhs_message = "" + channel_names.append(no_rhs_channel_name) -
        [docs]class CmdAddCom(COMMAND_DEFAULT_CLASS): + channels = [] + errors = [] + for channel_name in channel_names: + # find a channel by fuzzy-matching. This also checks + # 'listen/control' perms. + found_channels = self.search_channel(channel_name, exact=False, handle_errors=False) + if not found_channels: + errors.append(f"No channel found matching '{channel_name}' " + "(could also be due to missing access).") + elif len(found_channels) > 1: + errors.append("Multiple possible channel matches/alias for " + "'{channel_name}':\n" + ", ".join(chan.key for chan in found_channels)) + else: + channels.append(found_channels[0]) + + if not channels: + self.msg('\n'.join(errors)) + return + + # we have at least one channel at this point + channel = channels[0] + + if not switches: + if self.rhs: + # send message to channel + self.msg_channel(channel, self.rhs.strip()) + elif channel and possible_lhs_message: + # called on the form channelname message without = + self.msg_channel(channel, possible_lhs_message.strip()) + else: + # inspect a given channel + subscribed, available = self.list_channels() + if channel in subscribed: + table = self.display_subbed_channels([channel]) + header = f"Channel |w{channel.key}|n" + self.msg(f"{header}\n(use |w{channel.key} <msg>|n (or a channel-alias) " + f"to chat and the 'channel' command " + f"to customize)\n{table}") + elif channel in available: + table = self.display_all_channels([], [channel]) + self.msg( + "\n|wNot subscribed to this channel|n (use /list to " + f"show all subscriptions)\n{table}") + return + + if 'history' in switches or 'hist' in switches: + # view channel history + + index = self.rhs or 0 + try: + index = max(0, int(index)) + except ValueError: + self.msg("The history index (describing how many lines to go back) " + "must be an integer >= 0.") + return + self.get_channel_history(channel, start_index=index) + return + + if 'sub' in switches: + # subscribe to a channel + aliases = [] + if self.rhs: + aliases = set(alias.strip().lower() for alias in self.rhs.split(";")) + success, err = self.sub_to_channel(channel) + if success: + for alias in aliases: + self.add_alias(channel, alias) + alias_txt = ', '.join(aliases) + alias_txt = f" using alias(es) {alias_txt}" if aliases else '' + self.msg("You are now subscribed " + f"to the channel {channel.key}{alias_txt}. Use /alias to " + "add additional aliases for referring to the channel.") + else: + self.msg(err) + return + + if 'unsub' in switches: + # un-subscribe from a channel + success, err = self.unsub_from_channel(channel) + if success: + self.msg(f"You un-subscribed from channel {channel.key}. " + "All aliases were cleared.") + else: + self.msg(err) + return + + if 'alias' in switches: + # create a new personal alias for a channel + alias = self.rhs + if not alias: + self.msg("Specify the alias as channel/alias channelname = alias") + return + self.add_alias(channel, alias) + self.msg(f"Added/updated your alias '{alias}' for channel {channel.key}.") + return + + if 'mute' in switches: + # mute a given channel + success, err = self.mute_channel(channel) + if success: + self.msg(f"Muted channel {channel.key}.") + else: + self.msg(err) + return + + if 'unmute' in switches: + # unmute a given channel + success, err = self.unmute_channel(channel) + if success: + self.msg(f"Un-muted channel {channel.key}.") + else: + self.msg(err) + return + + if 'destroy' in switches or 'delete' in switches: + # destroy a channel we control + + if not self.access(caller, "manage"): + self.msg("You don't have access to use channel/destroy.") + return + + if not channel.access(caller, "control"): + self.msg("You can only delete channels you control.") + return + + reason = self.rhs or None + + def _perform_delete(caller, *args, **kwargs): + self.destroy_channel(channel, message=reason) + self.msg(f"Channel {channel.key} was successfully deleted.") + + ask_yes_no( + caller, + prompt=f"Are you sure you want to delete channel '{channel.key}' " + "(make sure name is correct!)?\nThis will disconnect and " + "remove all users' aliases. {options}?", + yes_action=_perform_delete, + no_action="Aborted.", + default="N" + ) + + if 'desc' in switches: + # set channel description + + if not self.access(caller, "manage"): + self.msg("You don't have access to use channel/desc.") + return + + if not channel.access(caller, "control"): + self.msg("You can only change description of channels you control.") + return + + desc = self.rhs.strip() + + if not desc: + self.msg("Usage: /desc channel = description") + return + + self.set_desc(channel, desc) + self.msg("Updated channel description.") + + if 'lock' in switches: + # add a lockstring to channel + + if not self.access(caller, "changelocks"): + self.msg("You don't have access to use channel/lock.") + return + + if not channel.access(caller, "control"): + self.msg("You need 'control'-access to change locks on this channel.") + return + + lockstring = self.rhs.strip() + + if not lockstring: + self.msg("Usage: channel/lock channelname = lockstring") + return + + success, err = self.set_lock(channel, self.rhs) + if success: + self.msg("Added/updated lock on channel.") + else: + self.msg(f"Could not add/update lock: {err}") + return + + if 'unlock' in switches: + # remove/update lockstring from channel + + if not self.access(caller, "changelocks"): + self.msg("You don't have access to use channel/unlock.") + return + + if not channel.access(caller, "control"): + self.msg("You need 'control'-access to change locks on this channel.") + return + + lockstring = self.rhs.strip() + + if not lockstring: + self.msg("Usage: channel/unlock channelname = lockstring") + return + + success, err = self.unset_lock(channel, self.rhs) + if success: + self.msg("Removed lock from channel.") + else: + self.msg(f"Could not remove lock: {err}") + return + + if 'boot' in switches: + # boot a user from channel(s) + + if not self.access(caller, "admin"): + self.msg("You don't have access to use channel/boot.") + return + + if not self.rhs: + self.msg("Usage: channel/boot channel[,channel,...] = username [:reason]") + return + + target_str, *reason = self.rhs.rsplit(":", 1) + reason = reason[0].strip() if reason else "" + + for chan in channels: + + if not chan.access(caller, "control"): + self.msg(f"You need 'control'-access to boot a user from {chan.key}.") + return + + # the target must be a member of all given channels + target = caller.search(target_str, candidates=chan.subscriptions.all()) + if not target: + self.msg(f"Cannot boot '{target_str}' - not in channel {chan.key}.") + return + + def _boot_user(caller, *args, **kwargs): + for chan in channels: + success, err = self.boot_user(chan, target, quiet=False, reason=reason) + if success: + self.msg(f"Booted {target.key} from channel {chan.key}.") + else: + self.msg(f"Cannot boot {target.key} from channel {chan.key}: {err}") + + channames = ", ".join(chan.key for chan in channels) + reasonwarn = (". Also note that your reason will be echoed to the channel" + if reason else '') + ask_yes_no( + caller, + prompt=f"Are you sure you want to boot user {target.key} from " + f"channel(s) {channames} (make sure name/channels are correct{reasonwarn}). " + "{options}?", + yes_action=_boot_user, + no_action="Aborted.", + default="Y" + ) + return + + if 'ban' in switches: + # ban a user from channel(s) + + if not self.access(caller, "admin"): + self.msg("You don't have access to use channel/ban.") + return + + if not self.rhs: + # view bans for channels + + if not channel.access(caller, "control"): + self.msg(f"You need 'control'-access to view bans on channel {channel.key}") + return + + bans = ["Channel bans " + "(to ban, use channel/ban channel[,channel,...] = username [:reason]"] + bans.extend(self.channel_list_bans(channel)) + self.msg("\n".join(bans)) + return + + target_str, *reason = self.rhs.rsplit(":", 1) + reason = reason[0].strip() if reason else "" + + for chan in channels: + # the target must be a member of all given channels + if not chan.access(caller, "control"): + self.msg(f"You don't have access to ban users on channel {chan.key}") + return + + target = caller.search(target_str, candidates=chan.subscriptions.all()) + + if not target: + self.msg(f"Cannot ban '{target_str}' - not in channel {chan.key}.") + return + + def _ban_user(caller, *args, **kwargs): + for chan in channels: + success, err = self.ban_user(chan, target, quiet=False, reason=reason) + if success: + self.msg(f"Banned {target.key} from channel {chan.key}.") + else: + self.msg(f"Cannot boot {target.key} from channel {chan.key}: {err}") + + channames = ", ".join(chan.key for chan in channels) + reasonwarn = (". Also note that your reason will be echoed to the channel" + if reason else '') + ask_yes_no( + caller, + f"Are you sure you want to ban user {target.key} from " + f"channel(s) {channames} (make sure name/channels are correct{reasonwarn}) " + "{options}?", + _ban_user, + "Aborted.", + ) + return + + if 'unban' in switches: + # unban a previously banned user from channel + + if not self.access(caller, "admin"): + self.msg("You don't have access to use channel/unban.") + return + + target_str = self.rhs.strip() + + if not target_str: + self.msg("Usage: channel[,channel,...] = user") + return + + banlists = [] + for chan in channels: + # the target must be a member of all given channels + if not chan.access(caller, "control"): + self.msg(f"You don't have access to unban users on channel {chan.key}") + return + banlists.extend(chan.banlist) + + target = caller.search(target_str, candidates=banlists) + if not target: + self.msg("Could not find a banned user '{target_str}' in given channel(s).") + return + + for chan in channels: + success, err = self.unban_user(channel, target) + if success: + self.msg(f"Un-banned {target_str} from channel {chan.key}") + else: + self.msg(err) + return + + if "who" in switches: + # view who's a member of a channel + + who_list = [f"Subscribed to {channel.key}:"] + who_list.extend(self.channel_list_who(channel)) + self.msg("\n".join(who_list)) + return
        + + +# a channel-command parent for use with Characters/Objects. +class CmdObjectChannel(CmdChannel): + account_caller = False + + +
        [docs]class CmdAddCom(CmdChannel): """ - add a channel alias and/or subscribe to a channel + Add a channel alias and/or subscribe to a channel Usage: addcom [alias=] <channel> @@ -138,7 +1317,6 @@ caller = self.caller args = self.args - account = caller if not args: self.msg("Usage: addcom [alias =] channelname.") @@ -152,42 +1330,36 @@ channelname = self.args alias = None - channel = find_channel(caller, channelname) + channel = self.search_channel(channelname) if not channel: - # we use the custom search method to handle errors. - return - - # check permissions - if not channel.access(account, "listen"): - self.msg("%s: You are not allowed to listen to this channel." % channel.key) return string = "" - if not channel.has_connection(account): + if not channel.has_connection(caller): # we want to connect as well. - if not channel.connect(account): + success, err = self.sub_to_channel(channel) + if success: # if this would have returned True, the account is connected - self.msg("%s: You are not allowed to join this channel." % channel.key) + self.msg(f"You now listen to the channel {channel.key}") + else: + self.msg(f"{channel.key}: You are not allowed to join this channel.") return - else: - string += "You now listen to the channel %s. " % channel.key + + if channel.unmute(caller): + self.msg(f"You unmute channel {channel.key}.") else: - if channel.unmute(account): - string += "You unmute channel %s." % channel.key - else: - string += "You are already connected to channel %s." % channel.key + self.msg(f"You are already connected to channel {channel.key}.") if alias: # create a nick and add it to the caller. - caller.nicks.add(alias, channel.key, category="channel") - string += " You can now refer to the channel %s with the alias '%s'." - self.msg(string % (channel.key, alias)) + self.add_alias(channel, alias) + self.msg(f" You can now refer to the channel {channel} with the alias '{alias}'.") else: string += " No alias added." self.msg(string)
        -
        [docs]class CmdDelCom(COMMAND_DEFAULT_CLASS): +
        [docs]class CmdDelCom(CmdChannel): """ remove a channel alias and/or unsubscribe from channel @@ -213,49 +1385,42 @@ """Implementing the command. """ caller = self.caller - account = caller if not self.args: self.msg("Usage: delcom <alias or channel>") return - ostring = self.args.lower() + ostring = self.args.lower().strip() - channel = find_channel(caller, ostring, silent=True, noaliases=True) - if channel: - # we have given a channel name - unsubscribe - if not channel.has_connection(account): - self.msg("You are not listening to that channel.") - return - chkey = channel.key.lower() + channel = self.search_channel(ostring) + if not channel: + return + + if not channel.has_connection(caller): + self.msg("You are not listening to that channel.") + return + + if ostring == channel.key.lower(): + # an exact channel name - unsubscribe delnicks = "all" in self.switches # find all nicks linked to this channel and delete them if delnicks: - for nick in [ - nick - for nick in make_iter(caller.nicks.get(category="channel", return_obj=True)) - if nick and nick.pk and nick.value[3].lower() == chkey - ]: - nick.delete() - disconnect = channel.disconnect(account) - if disconnect: + aliases = self.get_channel_aliases(channel) + for alias in aliases: + self.remove_alias(alias) + success, err = self.unsub_from_channel(channel) + if success: wipednicks = " Eventual aliases were removed." if delnicks else "" - self.msg("You stop listening to channel '%s'.%s" % (channel.key, wipednicks)) + self.msg(f"You stop listening to channel '{channel.key}'.{wipednicks}") + else: + self.msg(err) return else: # we are removing a channel nick - channame = caller.nicks.get(key=ostring, category="channel") - channel = find_channel(caller, channame, silent=True) - if not channel: - self.msg("No channel with alias '%s' was found." % ostring) - else: - if caller.nicks.get(ostring, category="channel"): - caller.nicks.remove(ostring, category="channel") - self.msg("Your alias '%s' for channel %s was cleared." % (ostring, channel.key)) - else: - self.msg("You had no such alias defined for this channel.")
        + self.remove_alias(ostring) + self.msg(f"Any alias '{ostring}' for channel {channel.key} was cleared.")
        -
        [docs]class CmdAllCom(COMMAND_DEFAULT_CLASS): +
        [docs]class CmdAllCom(CmdChannel): """ perform admin operations on all channels @@ -270,6 +1435,7 @@ """ key = "allcom" + aliases = [] # important to not inherit parent's aliases locks = "cmd: not pperm(channel_banned)" help_category = "Comms" @@ -282,8 +1448,11 @@ caller = self.caller args = self.args if not args: - self.execute_cmd("channels") - self.msg("(Usage: allcom on | off | who | destroy)") + subscribed, available = self.list_channels() + table = self.display_all_channels(subscribed, available) + self.msg( + "\n|wAvailable channels:\n{table}") + return return if args == "on": @@ -327,125 +1496,7 @@ # wrong input self.msg("Usage: allcom on | off | who | clear")
        - -
        [docs]class CmdChannels(COMMAND_DEFAULT_CLASS): - """ - list all channels available to you - - Usage: - channels - clist - comlist - - Lists all channels available to you, whether you listen to them or not. - Use 'comlist' to only view your current channel subscriptions. - Use addcom/delcom to join and leave channels - """ - - key = "channels" - aliases = ["clist", "comlist", "chanlist", "channellist", "all channels"] - help_category = "Comms" - locks = "cmd: not pperm(channel_banned)" - - # this is used by the COMMAND_DEFAULT_CLASS parent - account_caller = True - -
        [docs] def func(self): - """Implement function""" - - caller = self.caller - - # all channels we have available to listen to - channels = [ - chan - for chan in CHANNEL_DEFAULT_TYPECLASS.objects.get_all_channels() - if chan.access(caller, "listen") - ] - if not channels: - self.msg("No channels available.") - return - # all channel we are already subscribed to - subs = CHANNEL_DEFAULT_TYPECLASS.objects.get_subscriptions(caller) - - if self.cmdstring == "comlist": - # just display the subscribed channels with no extra info - comtable = self.styled_table( - "|wchannel|n", - "|wmy aliases|n", - "|wdescription|n", - align="l", - maxwidth=_DEFAULT_WIDTH, - ) - for chan in subs: - clower = chan.key.lower() - nicks = caller.nicks.get(category="channel", return_obj=True) - comtable.add_row( - *[ - "%s%s" - % ( - chan.key, - chan.aliases.all() and "(%s)" % ",".join(chan.aliases.all()) or "", - ), - "%s" - % ",".join( - nick.db_key - for nick in make_iter(nicks) - if nick and nick.value[3].lower() == clower - ), - chan.db.desc, - ] - ) - self.msg( - "\n|wChannel subscriptions|n (use |wchannels|n to list all," - " |waddcom|n/|wdelcom|n to sub/unsub):|n\n%s" % comtable - ) - else: - # full listing (of channels caller is able to listen to) - comtable = self.styled_table( - "|wsub|n", - "|wchannel|n", - "|wmy aliases|n", - "|wlocks|n", - "|wdescription|n", - maxwidth=_DEFAULT_WIDTH, - ) - for chan in channels: - clower = chan.key.lower() - nicks = caller.nicks.get(category="channel", return_obj=True) - nicks = nicks or [] - if chan not in subs: - substatus = "|rNo|n" - elif caller in chan.mutelist: - substatus = "|rMuted|n" - else: - substatus = "|gYes|n" - comtable.add_row( - *[ - substatus, - "%s%s" - % ( - chan.key, - chan.aliases.all() and "(%s)" % ",".join(chan.aliases.all()) or "", - ), - "%s" - % ",".join( - nick.db_key - for nick in make_iter(nicks) - if nick.value[3].lower() == clower - ), - str(chan.locks), - chan.db.desc, - ] - ) - comtable.reformat_column(0, width=9) - comtable.reformat_column(3, width=14) - self.msg( - "\n|wAvailable channels|n (use |wcomlist|n,|waddcom|n and |wdelcom|n" - " to manage subscriptions):\n%s" % comtable - )
        - - -
        [docs]class CmdCdestroy(COMMAND_DEFAULT_CLASS): +
        [docs]class CmdCdestroy(CmdChannel): """ destroy a channel you created @@ -456,6 +1507,7 @@ """ key = "cdestroy" + aliases = [] help_category = "Comms" locks = "cmd: not pperm(channel_banned)" @@ -464,12 +1516,15 @@
        [docs] def func(self): """Destroy objects cleanly.""" + caller = self.caller if not self.args: self.msg("Usage: cdestroy <channelname>") return - channel = find_channel(caller, self.args) + + channel = self.search_channel(self.args) + if not channel: self.msg("Could not find channel %s." % self.args) return @@ -477,11 +1532,8 @@ self.msg("You are not allowed to do that.") return channel_key = channel.key - message = "%s is being destroyed. Make sure to change your aliases." % channel_key - msgobj = create.create_message(caller, message, channel) - channel.msg(msgobj) - channel.delete() - CHANNELHANDLER.update() + message = f"{channel.key} is being destroyed. Make sure to change your aliases." + self.destroy_channel(channel, message) self.msg("Channel '%s' was destroyed." % channel_key) logger.log_sec( "Channel Deleted: %s (Caller: %s, IP: %s)." @@ -489,7 +1541,7 @@ )
        -
        [docs]class CmdCBoot(COMMAND_DEFAULT_CLASS): +
        [docs]class CmdCBoot(CmdChannel): """ kick an account from a channel you control @@ -504,6 +1556,7 @@ """ key = "cboot" + aliases = [] switch_options = ("quiet",) locks = "cmd: not pperm(channel_banned)" help_category = "Comms" @@ -519,17 +1572,21 @@ self.msg(string) return - channel = find_channel(self.caller, self.lhs) + channel = self.search_channel(self.lhs) if not channel: return + reason = "" if ":" in self.rhs: - accountname, reason = self.rhs.rsplit(":", 1) - searchstring = accountname.lstrip("*") + target, reason = self.rhs.rsplit(":", 1) + is_account = target.strip().startswith("*") + searchstring = target.lstrip("*") else: + is_account = target.strip().startswith("*") searchstring = self.rhs.lstrip("*") - account = self.caller.search(searchstring, account=True) - if not account: + + target = self.caller.search(searchstring, account=is_account) + if not target: return if reason: reason = " (reason: %s)" % reason @@ -537,79 +1594,19 @@ string = "You don't control this channel." self.msg(string) return - if not channel.subscriptions.has(account): - string = "Account %s is not connected to channel %s." % (account.key, channel.key) - self.msg(string) - return - if "quiet" not in self.switches: - string = "%s boots %s from channel.%s" % (self.caller, account.key, reason) - channel.msg(string) - # find all account's nicks linked to this channel and delete them - for nick in [ - nick - for nick in account.character.nicks.get(category="channel") or [] - if nick.value[3].lower() == channel.key - ]: - nick.delete() - # disconnect account - channel.disconnect(account) - CHANNELHANDLER.update() - logger.log_sec( - "Channel Boot: %s (Channel: %s, Reason: %s, Caller: %s, IP: %s)." - % (account, channel, reason, self.caller, self.session.address) - )
        + + success, err = self.boot_user(target, quiet='quiet' in self.switches) + if success: + self.msg(f"Booted {target.key} from {channel.key}") + logger.log_sec( + "Channel Boot: %s (Channel: %s, Reason: %s, Caller: %s, IP: %s)." + % (self.caller, channel, reason, self.caller, self.session.address) + ) + else: + self.msg(err)
        -
        [docs]class CmdCemit(COMMAND_DEFAULT_CLASS): - """ - send an admin message to a channel you control - - Usage: - cemit[/switches] <channel> = <message> - - Switches: - sendername - attach the sender's name before the message - quiet - don't echo the message back to sender - - Allows the user to broadcast a message over a channel as long as - they control it. It does not show the user's name unless they - provide the /sendername switch. - - """ - - key = "cemit" - aliases = ["cmsg"] - switch_options = ("sendername", "quiet") - locks = "cmd: not pperm(channel_banned) and pperm(Player)" - help_category = "Comms" - - # this is used by the COMMAND_DEFAULT_CLASS parent - account_caller = True - -
        [docs] def func(self): - """Implement function""" - - if not self.args or not self.rhs: - string = "Usage: cemit[/switches] <channel> = <message>" - self.msg(string) - return - channel = find_channel(self.caller, self.lhs) - if not channel: - return - if not channel.access(self.caller, "control"): - string = "You don't control this channel." - self.msg(string) - return - message = self.rhs - if "sendername" in self.switches: - message = "%s: %s" % (self.caller.key, message) - channel.msg(message) - if "quiet" not in self.switches: - string = "Sent to channel %s: %s" % (channel.key, message) - self.msg(string)
        - - -
        [docs]class CmdCWho(COMMAND_DEFAULT_CLASS): +
        [docs]class CmdCWho(CmdChannel): """ show who is listening to a channel @@ -620,6 +1617,7 @@ """ key = "cwho" + aliases = [] locks = "cmd: not pperm(channel_banned)" help_category = "Comms" @@ -634,7 +1632,7 @@ self.msg(string) return - channel = find_channel(self.caller, self.lhs) + channel = self.search_channel(self.lhs) if not channel: return if not channel.access(self.caller, "listen"): @@ -646,7 +1644,7 @@ self.msg(string.strip())
        -
        [docs]class CmdChannelCreate(COMMAND_DEFAULT_CLASS): +
        [docs]class CmdChannelCreate(CmdChannel): """ create a new channel @@ -667,8 +1665,6 @@
        [docs] def func(self): """Implement the command""" - caller = self.caller - if not self.args: self.msg("Usage ccreate <channelname>[;alias;alias..] = description") return @@ -683,19 +1679,15 @@ if ";" in lhs: channame, aliases = lhs.split(";", 1) aliases = [alias.strip().lower() for alias in aliases.split(";")] - channel = CHANNEL_DEFAULT_TYPECLASS.objects.channel_search(channame) - if channel: - self.msg("A channel with that name already exists.") - return - # Create and set the channel up - lockstring = "send:all();listen:all();control:id(%s)" % caller.id - new_chan = create.create_channel(channame.strip(), aliases, description, locks=lockstring) - new_chan.connect(caller) - CHANNELHANDLER.update() - self.msg("Created channel %s and connected to it." % new_chan.key)
        + + new_chan, err = self.create_channel(channame, description, aliases=aliases) + if new_chan: + self.msg(f"Created channel {new_chan.key} and connected to it.") + else: + self.msg(err)
        -
        [docs]class CmdClock(COMMAND_DEFAULT_CLASS): +
        [docs]class CmdClock(CmdChannel): """ change channel locks of a channel you control @@ -707,8 +1699,8 @@ """ key = "clock" - locks = "cmd:not pperm(channel_banned)" aliases = ["clock"] + locks = "cmd:not pperm(channel_banned) and perm(Admin)" help_category = "Comms" # this is used by the COMMAND_DEFAULT_CLASS parent @@ -722,14 +1714,13 @@ self.msg(string) return - channel = find_channel(self.caller, self.lhs) + channel = self.search_channel(self.lhs) if not channel: return + if not self.rhs: # no =, so just view the current locks - string = "Current locks on %s:" % channel.key - string = "%s\n %s" % (string, channel.locks) - self.msg(string) + self.msg(f"Current locks on {channel.key}\n{channel.locks}") return # we want to add/change a lock. if not channel.access(self.caller, "control"): @@ -737,18 +1728,13 @@ self.msg(string) return # Try to add the lock - try: - channel.locks.add(self.rhs) - except LockException as err: - self.msg(err) - return - string = "Lock(s) applied. " - string += "Current locks on %s:" % channel.key - string = "%s\n %s" % (string, channel.locks) - self.msg(string)
        + success, err = self.set_lock(channel, self.rhs) + if success: + self.msg(f"Lock(s) applied. Current locks on {channel.key}:\n{channel.locks}") + else: + self.msg(err) - -
        [docs]class CmdCdesc(COMMAND_DEFAULT_CLASS): +
        [docs]class CmdCdesc(CmdChannel): """ describe a channel you control @@ -757,9 +1743,11 @@ Changes the description of the channel as shown in channel lists. + """ key = "cdesc" + aliases = [] locks = "cmd:not pperm(channel_banned)" help_category = "Comms" @@ -774,18 +1762,15 @@ if not self.rhs: self.msg("Usage: cdesc <channel> = <description>") return - channel = find_channel(caller, self.lhs) + channel = self.search_channel(self.lhs) if not channel: - self.msg("Channel '%s' not found." % self.lhs) return # check permissions if not channel.access(caller, "control"): self.msg("You cannot admin this channel.") return - # set the description - channel.db.desc = self.rhs - channel.save() - self.msg("Description of channel '%s' set to '%s'." % (channel.key, self.rhs))
        + self.set_desc(channel, self.rhs) + self.msg(f"Description of channel '{channel.key}' set to '{self.rhs}'.")
        [docs]class CmdPage(COMMAND_DEFAULT_CLASS): @@ -793,16 +1778,19 @@ send a private message to another account Usage: + page <account> <message> page[/switches] [<account>,<account>,... = <message>] tell '' page <number> - Switch: + Switches: last - shows who you last messaged list - show your last <number> of tells/pages (default) - Send a message to target user (if online). If no - argument is given, you will get a list of your latest messages. + Send a message to target user (if online). If no argument is given, you + will get a list of your latest messages. The equal sign is needed for + multiple targets or if sending to target with space in the name. + """ key = "page" @@ -821,9 +1809,10 @@ caller = self.caller # get the messages we've sent (not to channels) - pages_we_sent = Msg.objects.get_messages_by_sender(caller, exclude_channel_messages=True) + pages_we_sent = Msg.objects.get_messages_by_sender(caller) # get last messages we've got pages_we_got = Msg.objects.get_messages_by_receiver(caller) + targets, message, number = [], None, None if "last" in self.switches: if pages_we_sent: @@ -834,19 +1823,76 @@ self.msg("You haven't paged anyone yet.") return - if not self.args or not self.rhs: - pages = pages_we_sent + pages_we_got - pages = sorted(pages, key=lambda page: page.date_created) + if self.args: + if self.rhs: + for target in self.lhslist: + target_obj = self.caller.search(target) + if not target_obj: + return + targets.append(target_obj) + message = self.rhs.strip() + else: + target, *message = self.args.split(" ", 4) + if target and target.isnumeric(): + # a number to specify a historic page + number = int(target) + elif target: + target_obj = self.caller.search(target, quiet=True) + if target_obj: + # a proper target + targets = [target_obj[0]] + message = message[0].strip() + else: + # a message with a space in it - put it back together + message = target + " " + (message[0] if message else "") + else: + # a single-word message + message = message[0].strip() - number = 5 - if self.args: - try: - number = int(self.args) - except ValueError: - self.msg("Usage: tell [<account> = msg]") + pages = list(pages_we_sent) + list(pages_we_got) + pages = sorted(pages, key=lambda page: page.date_created) + + if message: + # send a message + if not targets: + # no target given - send to last person we paged + if pages_we_sent: + targets = pages_we_sent[-1].receivers + else: + self.msg("Who do you want page?") return - if len(pages) > number: + header = "|wAccount|n |c%s|n |wpages:|n" % caller.key + if message.startswith(":"): + message = "%s %s" % (caller.key, message.strip(":").strip()) + + # create the persistent message object + create.create_message(caller, message, receivers=targets) + + # tell the accounts they got a message. + received = [] + rstrings = [] + for target in targets: + if not target.access(caller, "msg"): + rstrings.append(f"You are not allowed to page {target}.") + continue + target.msg(f"{header} {message}") + if hasattr(target, "sessions") and not target.sessions.count(): + received.append(f"|C{target.name}|n") + rstrings.append( + f"{received[-1]} is offline. They will see your message " + "if they list their pages later." + ) + else: + received.append(f"|c{target.name}|n") + if rstrings: + self.msg("\n".join(rstrings)) + self.msg("You paged %s with: '%s'." % (", ".join(received), message)) + return + + else: + # no message to send + if number is not None and len(pages) > number: lastpages = pages[-number:] else: lastpages = pages @@ -890,6 +1936,7 @@ receiver=receiver, message=page.message, ) + ) lastpages = "\n ".join(listing) @@ -898,65 +1945,7 @@ else: string = "You haven't paged anyone yet." self.msg(string) - return - - # We are sending. Build a list of targets - - if not self.lhs: - # If there are no targets, then set the targets - # to the last person we paged. - if pages_we_sent: - receivers = pages_we_sent[-1].receivers - else: - self.msg("Who do you want to page?") - return - else: - receivers = self.lhslist - - recobjs = [] - for receiver in set(receivers): - if isinstance(receiver, str): - pobj = caller.search(receiver) - elif hasattr(receiver, "character"): - pobj = receiver - else: - self.msg("Who do you want to page?") - return - if pobj: - recobjs.append(pobj) - if not recobjs: - self.msg("Noone found to page.") - return - - header = "|wAccount|n |c%s|n |wpages:|n" % caller.key - message = self.rhs - - # if message begins with a :, we assume it is a 'page-pose' - if message.startswith(":"): - message = "%s %s" % (caller.key, message.strip(":").strip()) - - # create the persistent message object - create.create_message(caller, message, receivers=recobjs) - - # tell the accounts they got a message. - received = [] - rstrings = [] - for pobj in recobjs: - if not pobj.access(caller, "msg"): - rstrings.append("You are not allowed to page %s." % pobj) - continue - pobj.msg("%s %s" % (header, message)) - if hasattr(pobj, "sessions") and not pobj.sessions.count(): - received.append("|C%s|n" % pobj.name) - rstrings.append( - "%s is offline. They will see your message if they list their pages later." - % received[-1] - ) - else: - received.append("|c%s|n" % pobj.name) - if rstrings: - self.msg("\n".join(rstrings)) - self.msg("You paged %s with: '%s'." % (", ".join(received), message))
        + return def _list_bots(cmd): @@ -998,7 +1987,6 @@ else: return "No irc bots found." -
        [docs]class CmdIRC2Chan(COMMAND_DEFAULT_CLASS): """ Link an evennia channel to an external IRC channel @@ -1120,7 +2108,7 @@ Check and reboot IRC bot. Usage: - ircstatus [#dbref ping||nicklist||reconnect] + ircstatus [#dbref ping | nicklist | reconnect] If not given arguments, will return a list of all bots (like irc2chan/list). The 'ping' argument will ping the IRC network to @@ -1433,7 +2421,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1452,6 +2439,7 @@ +
        develop branch
        @@ -44,7 +45,7 @@ """ import re from django.conf import settings -from evennia.utils import utils, evtable +from evennia.utils import utils from evennia.typeclasses.attributes import NickTemplateInvalid COMMAND_DEFAULT_CLASS = utils.class_from_module(settings.COMMAND_DEFAULT_CLASS) @@ -420,13 +421,10 @@ string = "You are not carrying anything." else: from evennia.utils.ansi import raw as raw_ansi - table = self.styled_table(border="header") for item in items: - table.add_row( - f"|C{item.name}|n", - "{}|n".format(utils.crop(raw_ansi(item.db.desc), width=50) or ""), - ) + table.add_row(f"|C{item.name}|n", + "{}|n".format(utils.crop(raw_ansi(item.db.desc or ""), width=50) or "")) string = f"|wYou are carrying:\n{table}" self.caller.msg(string)
        @@ -444,7 +442,7 @@ key = "get" aliases = "grab" - locks = "cmd:all()" + locks = "cmd:all();view:perm(Developer);read:perm(Developer)" arg_regex = r"\s|$"
        [docs] def func(self): @@ -807,7 +805,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -826,6 +823,7 @@ +
        develop branch
        @@ -40,43 +41,74 @@

        Source code for evennia.commands.default.help

         """
        -The help command. The basic idea is that help texts for commands
        -are best written by those that write the commands - the admins. So
        -command-help is all auto-loaded and searched from the current command
        -set. The normal, database-tied help system is used for collaborative
        -creation of other help topics such as RP help or game-world aides.
        +The help command. The basic idea is that help texts for commands are best
        +written by those that write the commands - the developers. So command-help is
        +all auto-loaded and searched from the current command set. The normal,
        +database-tied help system is used for collaborative creation of other help
        +topics such as RP help or game-world aides. Help entries can also be created
        +outside the game in modules given by ``settings.FILE_HELP_ENTRY_MODULES``.
        +
         """
         
        +from dataclasses import dataclass
         from django.conf import settings
         from collections import defaultdict
        -from evennia.utils.utils import fill, dedent
        -from evennia.commands.command import Command
        +from evennia.utils.utils import dedent
         from evennia.help.models import HelpEntry
         from evennia.utils import create, evmore
        +from evennia.utils.ansi import ANSIString
        +from evennia.help.filehelp import FILE_HELP_ENTRIES
         from evennia.utils.eveditor import EvEditor
        -from evennia.utils.utils import string_suggestions, class_from_module
        +from evennia.utils.utils import (
        +    class_from_module,
        +    inherits_from,
        +    format_grid, pad
        +)
        +from evennia.help.utils import help_search_with_index, parse_entry_for_subcategories
         
         COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
        -HELP_MORE = settings.HELP_MORE
        -CMD_IGNORE_PREFIXES = settings.CMD_IGNORE_PREFIXES
        +HELP_MORE_ENABLED = settings.HELP_MORE_ENABLED
        +DEFAULT_HELP_CATEGORY = settings.DEFAULT_HELP_CATEGORY
        +HELP_CLICKABLE_TOPICS = settings.HELP_CLICKABLE_TOPICS
         
         # limit symbol import for API
         __all__ = ("CmdHelp", "CmdSetHelp")
        -_DEFAULT_WIDTH = settings.CLIENT_DEFAULT_WIDTH
        -_SEP = "|C" + "-" * _DEFAULT_WIDTH + "|n"
        +
        +@dataclass
        +class HelpCategory:
        +    """
        +    Mock 'help entry' to search categories with the same code.
        +
        +    """
        +    key: str
        +
        +    @property
        +    def search_index_entry(self):
        +        return {
        +            "key": self.key,
        +            "aliases": "",
        +            "category": self.key,
        +            "tags": "",
        +            "text": "",
        +        }
        +
        +    def __hash__(self):
        +        return hash(id(self))
         
         
         
        [docs]class CmdHelp(COMMAND_DEFAULT_CLASS): """ - View help or a list of topics + Get help. Usage: - help <topic or command> - help list - help all + help + help <topic, command or category> + help <topic>/<subtopic> + help <topic>/<subtopic>/<subsubtopic> ... + + Use the 'help' command alone to see an index of all help topics, organized + by category.eSome big topics may offer additional sub-topics. - This will search for help on commands and other - topics related to the game. """ key = "help" @@ -90,8 +122,13 @@ # Help messages are wrapped in an EvMore call (unless using the webclient # with separate help popups) If you want to avoid this, simply add - # 'HELP_MORE = False' in your settings/conf/settings.py - help_more = HELP_MORE + # 'HELP_MORE_ENABLED = False' in your settings/conf/settings.py + help_more = HELP_MORE_ENABLED + + # colors for the help index + index_type_separator_clr = "|w" + index_category_clr = "|W" + index_topic_clr = "|G" # suggestion cutoff, between 0 and 1 (1 => perfect match) suggestion_cutoff = 0.6 @@ -99,6 +136,12 @@ # number of suggestions (set to 0 to remove suggestions from help) suggestion_maxnum = 5 + # separator between subtopics: + subtopic_separator_char = r"/" + + # should topics disply their help entry when clicked + clickable_topics = HELP_CLICKABLE_TOPICS +
        [docs] def msg_help(self, text): """ messages text to the caller, adding an extra oob argument to indicate @@ -108,7 +151,7 @@ if type(self).help_more: usemore = True - if self.session and self.session.protocol_key in ("websocket", "ajax/comet"): + if self.session and self.session.protocol_key in ("websocket", "ajax/comet",): try: options = self.account.db._saved_webclient_options if options and options["helppopup"]: @@ -122,241 +165,541 @@ self.msg(text=(text, {"type": "help"}))
        -
        [docs] @staticmethod - def format_help_entry(title, help_text, aliases=None, suggested=None): - """ - This visually formats the help entry. +
        [docs] def format_help_entry(self, topic="", help_text="", aliases=None, suggested=None, + subtopics=None, click_topics=True): + """This visually formats the help entry. This method can be overriden to customize the way a help entry is displayed. Args: - title (str): the title of the help entry. - help_text (str): the text of the help entry. - aliases (list of str or None): the list of aliases. - suggested (list of str or None): suggested reading. + title (str, optional): The title of the help entry. + help_text (str, optional): Text of the help entry. + aliases (list, optional): List of help-aliases (displayed in header). + suggested (list, optional): Strings suggested reading (based on title). + subtopics (list, optional): A list of strings - the subcategories available + for this entry. + click_topics (bool, optional): Should help topics be clickable. Default is True. - Returns the formatted string, ready to be sent. + Returns: + help_message (str): Help entry formated for console. """ - string = _SEP + "\n" - if title: - string += "|CHelp for |w%s|n" % title + separator = "|C" + "-" * self.client_width() + "|n" + start = f"{separator}\n" + + title = f"|CHelp for |w{topic}|n" if topic else "|rNo help found|n" + if aliases: - string += " |C(aliases: %s|C)|n" % ("|C,|n ".join("|w%s|n" % ali for ali in aliases)) - if help_text: - string += "\n%s" % dedent(help_text.rstrip()) + aliases = ( + " |C(aliases: {}|C)|n".format("|C,|n ".join(f"|w{ali}|n" for ali in aliases)) + ) + else: + aliases = '' + + help_text = "\n" + dedent(help_text.strip('\n')) if help_text else "" + + if subtopics: + if click_topics: + subtopics = [ + f"|lchelp {topic}/{subtop}|lt|w{topic}/{subtop}|n|le" + for subtop in subtopics + ] + else: + subtopics = [f"|w{topic}/{subtop}|n" for subtop in subtopics] + subtopics = ( + "\n|CSubtopics:|n\n {}".format( + "\n ".join(format_grid(subtopics, width=self.client_width()))) + ) + else: + subtopics = '' + if suggested: - string += "\n\n|CSuggested:|n " - string += "%s" % fill("|C,|n ".join("|w%s|n" % sug for sug in suggested)) - string.strip() - string += "\n" + _SEP - return string
        + if click_topics: + suggested = [f"|lchelp {sug}|lt|w{sug}|n|le" for sug in suggested] + else: + suggested = [f"|w{sug}|n" for sug in suggested] + suggested = ( + "\n|COther topic suggestions:|n\n{}".format( + "\n ".join(format_grid(suggested, width=self.client_width()))) + ) + else: + suggested = '' -
        [docs] @staticmethod - def format_help_list(hdict_cmds, hdict_db): - """ - Output a category-ordered list. The input are the - pre-loaded help files for commands and database-helpfiles - respectively. You can override this method to return a - custom display of the list of commands and topics. - """ - string = "" - if hdict_cmds and any(hdict_cmds.values()): - string += "\n" + _SEP + "\n |CCommand help entries|n\n" + _SEP - for category in sorted(hdict_cmds.keys()): - string += "\n |w%s|n:\n" % (str(category).title()) - string += "|G" + fill("|C, |G".join(sorted(hdict_cmds[category]))) + "|n" - if hdict_db and any(hdict_db.values()): - string += "\n\n" + _SEP + "\n\r |COther help entries|n\n" + _SEP - for category in sorted(hdict_db.keys()): - string += "\n\r |w%s|n:\n" % (str(category).title()) - string += ( - "|G" - + fill(", ".join(sorted([str(topic) for topic in hdict_db[category]]))) - + "|n" - ) - return string
        + end = start -
        [docs] def check_show_help(self, cmd, caller): - """ - Helper method. If this return True, the given cmd - auto-help will be viewable in the help listing. - Override this to easily select what is shown to - the account. Note that only commands available - in the caller's merged cmdset are available. + partorder = (start, title + aliases, help_text, subtopics, suggested, end) + + return "\n".join(part.rstrip() for part in partorder if part)
        + +
        [docs] def format_help_index(self, cmd_help_dict=None, db_help_dict=None, title_lone_category=False, + click_topics=True): + """Output a category-ordered g for displaying the main help, grouped by + category. Args: - cmd (Command): Command class from the merged cmdset - caller (Character, Account or Session): The current caller - executing the help command. + cmd_help_dict (dict): A dict `{"category": [topic, topic, ...]}` for + command-based help. + db_help_dict (dict): A dict `{"category": [topic, topic], ...]}` for + database-based help. + title_lone_category (bool, optional): If a lone category should + be titled with the category name or not. While pointless in a + general index, the title should probably show when explicitly + listing the category itself. + click_topics (bool, optional): If help-topics are clickable or not + (for webclient or telnet clients with MXP support). + Returns: + str: The help index organized into a grid. + + Notes: + The input are the pre-loaded help files for commands and database-helpfiles + respectively. You can override this method to return a custom display of the list of + commands and topics. """ - # return only those with auto_help set and passing the cmd: lock - return cmd.auto_help and cmd.access(caller)
        + def _group_by_category(help_dict): + grid = [] + verbatim_elements = [] -
        [docs] def should_list_cmd(self, cmd, caller): + if len(help_dict) == 1 and not title_lone_category: + # don't list categories if there is only one + for category in help_dict: + # gather and sort the entries from the help dictionary + entries = sorted(set(help_dict.get(category, []))) + + # make the help topics clickable + if click_topics: + entries = [ + f'|lchelp {entry}|lt{entry}|le' for entry in entries + ] + + # add the entries to the grid + grid.extend(entries) + else: + # list the categories + for category in sorted(set(list(help_dict.keys()))): + category_str = f"-- {category.title()} " + grid.append( + ANSIString( + self.index_category_clr + category_str + + "-" * (width - len(category_str)) + + self.index_topic_clr + ) + ) + verbatim_elements.append(len(grid) - 1) + + # gather and sort the entries from the help dictionary + entries = sorted(set(help_dict.get(category, []))) + + # make the help topics clickable + if click_topics: + entries = [ + f'|lchelp {entry}|lt{entry}|le' for entry in entries + ] + + # add the entries to the grid + grid.extend(entries) + + return grid, verbatim_elements + + help_index = "" + width = self.client_width() + grid = [] + verbatim_elements = [] + cmd_grid, db_grid = "", "" + + if any(cmd_help_dict.values()): + # get the command-help entries by-category + sep1 = (self.index_type_separator_clr + + pad("Commands", width=width, fillchar='-') + + self.index_topic_clr) + grid, verbatim_elements = _group_by_category(cmd_help_dict) + gridrows = format_grid(grid, width, sep=" ", verbatim_elements=verbatim_elements) + cmd_grid = ANSIString("\n").join(gridrows) if gridrows else "" + + if any(db_help_dict.values()): + # get db-based help entries by-category + sep2 = (self.index_type_separator_clr + + pad("Game & World", width=width, fillchar='-') + + self.index_topic_clr) + grid, verbatim_elements = _group_by_category(db_help_dict) + gridrows = format_grid(grid, width, sep=" ", verbatim_elements=verbatim_elements) + db_grid = ANSIString("\n").join(gridrows) if gridrows else "" + + # only show the main separators if there are actually both cmd and db-based help + if cmd_grid and db_grid: + help_index = f"{sep1}\n{cmd_grid}\n{sep2}\n{db_grid}" + else: + help_index = f"{cmd_grid}{db_grid}" + + return help_index
        + +
        [docs] def can_read_topic(self, cmd_or_topic, caller): + """ + Helper method. If this return True, the given help topic + be viewable in the help listing. Note that even if this returns False, + the entry will still be visible in the help index unless `should_list_topic` + is also returning False. + + Args: + cmd_or_topic (Command, HelpEntry or FileHelpEntry): The topic/command to test. + caller: the caller checking for access. + + Returns: + bool: If command can be viewed or not. + + Notes: + This uses the 'read' lock. If no 'read' lock is defined, the topic is assumed readable + by all. + + """ + if inherits_from(cmd_or_topic, "evennia.commands.command.Command"): + return cmd_or_topic.auto_help and cmd_or_topic.access(caller, 'read', default=True) + else: + return cmd_or_topic.access(caller, 'read', default=True)
        + +
        [docs] def can_list_topic(self, cmd_or_topic, caller): """ Should the specified command appear in the help table? - This method only checks whether a specified command should - appear in the table of topics/commands. The command can be - used by the caller (see the 'check_show_help' method) and - the command will still be available, for instance, if a - character type 'help name of the command'. However, if - you return False, the specified command will not appear in - the table. This is sometimes useful to "hide" commands in - the table, but still access them through the help system. + This method only checks whether a specified command should appear in the table of + topics/commands. The command can be used by the caller (see the 'should_show_help' method) + and the command will still be available, for instance, if a character type 'help name of the + command'. However, if you return False, the specified command will not appear in the table. + This is sometimes useful to "hide" commands in the table, but still access them through the + help system. Args: - cmd: the command to be tested. - caller: the caller of the help system. + cmd_or_topic (Command, HelpEntry or FileHelpEntry): The topic/command to test. + caller: the caller checking for access. - Return: - True: the command should appear in the table. - False: the command shouldn't appear in the table. + Returns: + bool: If command should be listed or not. + + Notes: + By default, the 'view' lock will be checked, and if no such lock is defined, the 'read' + lock will be used. If neither lock is defined, the help entry is assumed to be + accessible to all. """ - return cmd.access(caller, "view", default=True)
        + has_view = ( + "view:" in cmd_or_topic.locks + if inherits_from(cmd_or_topic, "evennia.commands.command.Command") + else cmd_or_topic.locks.get("view") + ) + + if has_view: + return cmd_or_topic.access(caller, 'view', default=True) + else: + # no explicit 'view' lock - use the 'read' lock + return cmd_or_topic.access(caller, 'read', default=True)
        + +
        [docs] def collect_topics(self, caller, mode='list'): + """ + Collect help topics from all sources (cmd/db/file). + + Args: + caller (Object or Account): The user of the Command. + mode (str): One of 'list' or 'query', where the first means we are collecting to view + the help index and the second because of wanting to search for a specific help + entry/cmd to read. This determines which access should be checked. + + Returns: + tuple: A tuple of three dicts containing the different types of help entries + in the order cmd-help, db-help, file-help: + `({key: cmd,...}, {key: dbentry,...}, {key: fileentry,...}` + + """ + # start with cmd-help + cmdset = self.cmdset + # removing doublets in cmdset, caused by cmdhandler + # having to allow doublet commands to manage exits etc. + cmdset.make_unique(caller) + # retrieve all available commands and database / file-help topics. + # also check the 'cmd:' lock here + cmd_help_topics = [cmd for cmd in cmdset if cmd and cmd.access(caller, 'cmd')] + # get all file-based help entries, checking perms + file_help_topics = { + topic.key.lower().strip(): topic + for topic in FILE_HELP_ENTRIES.all() + } + # get db-based help entries, checking perms + db_help_topics = { + topic.key.lower().strip(): topic + for topic in HelpEntry.objects.all() + } + if mode == 'list': + # check the view lock for all help entries/commands and determine key + cmd_help_topics = { + cmd.auto_help_display_key + if hasattr(cmd, "auto_help_display_key") else cmd.key: cmd + for cmd in cmd_help_topics if self.can_list_topic(cmd, caller)} + db_help_topics = { + key: entry for key, entry in db_help_topics.items() + if self.can_list_topic(entry, caller) + } + file_help_topics = { + key: entry for key, entry in file_help_topics.items() + if self.can_list_topic(entry, caller)} + else: + # query + cmd_help_topics = { + cmd.auto_help_display_key + if hasattr(cmd, "auto_help_display_key") else cmd.key: cmd + for cmd in cmd_help_topics if self.can_read_topic(cmd, caller)} + db_help_topics = { + key: entry for key, entry in db_help_topics.items() + if self.can_read_topic(entry, caller) + } + file_help_topics = { + key: entry for key, entry in file_help_topics.items() + if self.can_read_topic(entry, caller)} + + return cmd_help_topics, db_help_topics, file_help_topics
        + +
        [docs] def parse(self): """ input is a string containing the command or topic to match. + + The allowed syntax is + :: + + help <topic>[/<subtopic>[/<subtopic>[/...]]] + + The database/command query is always for `<topic>`, and any subtopics + is then parsed from there. If a `<topic>` has spaces in it, it is + always matched before assuming the space begins a subtopic. + """ - self.original_args = self.args.strip() - self.args = self.args.strip().lower()
        + # parse the query + + if self.args: + self.subtopics = [part.strip().lower() + for part in self.args.split(self.subtopic_separator_char)] + self.topic = self.subtopics.pop(0) + else: + self.topic = "" + self.subtopics = []
        [docs] def func(self): """ Run the dynamic help entry creator. """ - query, cmdset = self.args, self.cmdset caller = self.caller - - suggestion_cutoff = self.suggestion_cutoff - suggestion_maxnum = self.suggestion_maxnum + query, subtopics, cmdset = self.topic, self.subtopics, self.cmdset + clickable_topics = self.clickable_topics if not query: - query = "all" + # list all available help entries, grouped by category. We want to + # build dictionaries {category: [topic, topic, ...], ...} - # removing doublets in cmdset, caused by cmdhandler - # having to allow doublet commands to manage exits etc. - cmdset.make_unique(caller) + cmd_help_topics, db_help_topics, file_help_topics = \ + self.collect_topics(caller, mode='list') - # retrieve all available commands and database topics - all_cmds = [cmd for cmd in cmdset if self.check_show_help(cmd, caller)] - all_topics = [ - topic for topic in HelpEntry.objects.all() if topic.access(caller, "view", default=True) - ] - all_categories = list( - set( - [cmd.help_category.lower() for cmd in all_cmds] - + [topic.help_category.lower() for topic in all_topics] - ) - ) + # db-topics override file-based ones + file_db_help_topics = {**file_help_topics, **db_help_topics} + + # group by category (cmds are listed separately) + cmd_help_by_category = defaultdict(list) + file_db_help_by_category = defaultdict(list) + for key, cmd in cmd_help_topics.items(): + cmd_help_by_category[cmd.help_category].append(key) + for key, entry in file_db_help_topics.items(): + file_db_help_by_category[entry.help_category].append(key) + + # generate the index and display + output = self.format_help_index(cmd_help_by_category, + file_db_help_by_category, + click_topics=clickable_topics) + self.msg_help(output) - if query in ("list", "all"): - # we want to list all available help entries, grouped by category - hdict_cmd = defaultdict(list) - hdict_topic = defaultdict(list) - # create the dictionaries {category:[topic, topic ...]} required by format_help_list - # Filter commands that should be reached by the help - # system, but not be displayed in the table, or be displayed differently. - for cmd in all_cmds: - if self.should_list_cmd(cmd, caller): - key = ( - cmd.auto_help_display_key - if hasattr(cmd, "auto_help_display_key") - else cmd.key - ) - hdict_cmd[cmd.help_category].append(key) - [hdict_topic[topic.help_category].append(topic.key) for topic in all_topics] - # report back - self.msg_help(self.format_help_list(hdict_cmd, hdict_topic)) return - # Try to access a particular command + # search for a specific entry. We need to check for 'read' access here before # building the + # set of possibilities. + cmd_help_topics, db_help_topics, file_help_topics = \ + self.collect_topics(caller, mode='query') - # build vocabulary of suggestions and rate them by string similarity. - suggestions = None - if suggestion_maxnum > 0: - vocabulary = ( - [cmd.key for cmd in all_cmds if cmd] - + [topic.key for topic in all_topics] - + all_categories - ) - [vocabulary.extend(cmd.aliases) for cmd in all_cmds] - suggestions = [ - sugg - for sugg in string_suggestions( - query, set(vocabulary), cutoff=suggestion_cutoff, maxnum=suggestion_maxnum - ) - if sugg != query - ] - if not suggestions: - suggestions = [ - sugg for sugg in vocabulary if sugg != query and sugg.startswith(query) - ] + # db-help topics takes priority over file-help + file_db_help_topics = {**file_help_topics, **db_help_topics} - # try an exact command auto-help match - match = [cmd for cmd in all_cmds if cmd == query] + # commands take priority over the other types + all_topics = {**file_db_help_topics, **cmd_help_topics} + + # get all categories + all_categories = list(set( + HelpCategory(topic.help_category) for topic in all_topics.values())) + + # all available help options - will be searched in order. We also check # the + # read-permission here. + entries = list(all_topics.values()) + all_categories + + # lunr search fields/boosts + match, suggestions = self.do_search(query, entries) if not match: - # try an inexact match with prefixes stripped from query and cmds - _query = query[1:] if query[0] in CMD_IGNORE_PREFIXES else query + # no topic matches found. Only give suggestions. + help_text = f"There is no help topic matching '{query}'." - match = [ - cmd - for cmd in all_cmds - for m in cmd._matchset - if m == _query or m[0] in CMD_IGNORE_PREFIXES and m[1:] == _query - ] + if not suggestions: + # we don't even have a good suggestion. Run a second search, + # doing a full-text search in the actual texts of the help + # entries - if len(match) == 1: - cmd = match[0] - key = cmd.auto_help_display_key if hasattr(cmd, "auto_help_display_key") else cmd.key - formatted = self.format_help_entry( - key, cmd.get_help(caller, cmdset), aliases=cmd.aliases, suggested=suggestions, - ) - self.msg_help(formatted) - return + search_fields = [ + {"field_name": "text", "boost": 1}, + ] - # try an exact database help entry match - match = list(HelpEntry.objects.find_topicmatch(query, exact=True)) - if len(match) == 1: - formatted = self.format_help_entry( - match[0].key, - match[0].entrytext, - aliases=match[0].aliases.all(), + for match_query in [query, f"{query}*"]: + _, suggestions = help_search_with_index( + match_query, entries, + suggestion_maxnum=self.suggestion_maxnum, + fields=search_fields + ) + + if suggestions: + help_text += ( + "\n... But matches where found within the help " + "texts of the suggestions below.") + break + + output = self.format_help_entry( + topic=None, # this will give a no-match style title + help_text=help_text, suggested=suggestions, + click_topics=clickable_topics ) - self.msg_help(formatted) + + self.msg_help(output) return - # try to see if a category name was entered - if query in all_categories: - self.msg_help( - self.format_help_list( - { - query: [ - cmd.auto_help_display_key - if hasattr(cmd, "auto_help_display_key") - else cmd.key - for cmd in all_cmds - if cmd.help_category == query - ] - }, - {query: [topic.key for topic in all_topics if topic.help_category == query]}, - ) - ) + if isinstance(match, HelpCategory): + # no subtopics for categories - these are just lists of topics + category = match.key + category_lower = category.lower() + cmds_in_category = [key for key, cmd in cmd_help_topics.items() + if category_lower == cmd.help_category] + topics_in_category = [key for key, topic in file_db_help_topics.items() + if category_lower == topic.help_category] + output = self.format_help_index({category: cmds_in_category}, + {category: topics_in_category}, + title_lone_category=True, + click_topics=clickable_topics) + self.msg_help(output) return - # no exact matches found. Just give suggestions. - self.msg( - self.format_help_entry( - "", f"No help entry found for '{query}'", None, suggested=suggestions - ), - options={"type": "help"}, - )
        + if inherits_from(match, "evennia.commands.command.Command"): + # a command match + topic = match.key + help_text = match.get_help(caller, cmdset) + aliases = match.aliases + suggested = suggestions[1:] + else: + # a database (or file-help) match + topic = match.key + help_text = match.entrytext + aliases = match.aliases if isinstance(match.aliases, list) else match.aliases.all() + suggested = suggestions[1:] + + # parse for subtopics. The subtopic_map is a dict with the current topic/subtopic + # text is stored under a `None` key and all other keys are subtopic titles pointing + # to nested dicts. + + subtopic_map = parse_entry_for_subcategories(help_text) + help_text = subtopic_map[None] + subtopic_index = [subtopic for subtopic in subtopic_map if subtopic is not None] + + if subtopics: + # if we asked for subtopics, parse the found topic_text to see if any match. + # the subtopics is a list describing the path through the subtopic_map. + + for subtopic_query in subtopics: + + if subtopic_query not in subtopic_map: + # exact match failed. Try startswith-match + fuzzy_match = False + for key in subtopic_map: + if key and key.startswith(subtopic_query): + subtopic_query = key + fuzzy_match = True + break + + if not fuzzy_match: + # startswith failed - try an 'in' match + for key in subtopic_map: + if key and subtopic_query in key: + subtopic_query = key + fuzzy_match = True + break + + if not fuzzy_match: + # no match found - give up + checked_topic = topic + f"/{subtopic_query}" + output = self.format_help_entry( + topic=topic, + help_text=f"No help entry found for '{checked_topic}'", + subtopics=subtopic_index, + click_topics=clickable_topics + ) + self.msg_help(output) + return + + # if we get here we have an exact or fuzzy match + + subtopic_map = subtopic_map.pop(subtopic_query) + subtopic_index = [subtopic for subtopic in subtopic_map if subtopic is not None] + # keep stepping down into the tree, append path to show position + topic = topic + f"/{subtopic_query}" + + # we reached the bottom of the topic tree + help_text = subtopic_map[None] + + output = self.format_help_entry( + topic=topic, + help_text=help_text, + aliases=aliases if not subtopics else None, + subtopics=subtopic_index, + suggested=suggested, + click_topics=clickable_topics + ) + + self.msg_help(output)
        def _loadhelp(caller): @@ -379,7 +722,7 @@ del caller.db._editing_help -
        [docs]class CmdSetHelp(COMMAND_DEFAULT_CLASS): +
        [docs]class CmdSetHelp(CmdHelp): """ Edit the help database. @@ -394,22 +737,64 @@ delete - remove help topic. Examples: - sethelp throw = This throws something at ... + sethelp lore = In the beginning was ... sethelp/append pickpocketing,Thievery = This steals ... sethelp/replace pickpocketing, ,attr(is_thief) = This steals ... sethelp/edit thievery - This command manipulates the help database. A help entry can be created, - appended/merged to and deleted. If you don't assign a category, the - "General" category will be used. If no lockstring is specified, default - is to let everyone read the help file. + If not assigning a category, the `settings.DEFAULT_HELP_CATEGORY` category + will be used. If no lockstring is specified, everyone will be able to read + the help entry. Sub-topics are embedded in the help text. + + Note that this cannot modify command-help entries - these are modified + in-code, outside the game. + + # SUBTOPICS + + ## Adding subtopics + + Subtopics helps to break up a long help entry into sub-sections. Users can + access subtopics with |whelp topic/subtopic/...|n Subtopics are created and + stored together with the main topic. + + To start adding subtopics, add the text '# SUBTOPICS' on a new line at the + end of your help text. After this you can now add any number of subtopics, + each starting with '## <subtopic-name>' on a line, followed by the + help-text of that subtopic. + Use '### <subsub-name>' to add a sub-subtopic and so on. Max depth is 5. A + subtopic's title is case-insensitive and can consist of multiple words - + the user will be able to enter a partial match to access it. + + For example: + + | Main help text for <topic> + | + | # SUBTOPICS + | + | ## about + | + | Text for the '<topic>/about' subtopic' + | + | ### more about-info + | + | Text for the '<topic>/about/more about-info sub-subtopic + | + | ## extra + | + | Text for the '<topic>/extra' subtopic """ key = "sethelp" + aliases = [] switch_options = ("edit", "replace", "append", "extend", "delete") locks = "cmd:perm(Helper)" help_category = "Building" + arg_regex = None + +
        [docs] def parse(self): + """We want to use the default parser rather than the CmdHelp.parse""" + return COMMAND_DEFAULT_CLASS.parse(self)
        [docs] def func(self): """Implement the function""" @@ -429,23 +814,71 @@ self.msg("You have to define a topic!") return topicstrlist = topicstr.split(";") - topicstr, aliases = (topicstrlist[0], topicstrlist[1:] if len(topicstr) > 1 else []) + topicstr, aliases = ( + topicstrlist[0], + topicstrlist[1:] if len(topicstr) > 1 else [], + ) aliastxt = ("(aliases: %s)" % ", ".join(aliases)) if aliases else "" old_entry = None # check if we have an old entry with the same name - try: - for querystr in topicstrlist: - old_entry = HelpEntry.objects.find_topicmatch(querystr) # also search by alias - if old_entry: - old_entry = list(old_entry)[0] + + cmd_help_topics, db_help_topics, file_help_topics = \ + self.collect_topics(self.caller, mode='query') + # db-help topics takes priority over file-help + file_db_help_topics = {**file_help_topics, **db_help_topics} + # commands take priority over the other types + all_topics = {**file_db_help_topics, **cmd_help_topics} + # get all categories + all_categories = list(set( + HelpCategory(topic.help_category) for topic in all_topics.values())) + # all available help options - will be searched in order. We also check # the + # read-permission here. + entries = list(all_topics.values()) + all_categories + + # default setup + category = lhslist[1] if nlist > 1 else DEFAULT_HELP_CATEGORY + lockstring = ",".join(lhslist[2:]) if nlist > 2 else "read:all()" + + # search for existing entries of this or other types + old_entry = None + for querystr in topicstrlist: + match, _ = self.do_search(querystr, entries) + if match: + warning = None + if isinstance(match, HelpCategory): + warning = (f"'{querystr}' matches (or partially matches) the name of " + "help-category '{match.key}'. If you continue, your help entry will " + "take precedence and the category (or part of its name) *may* not " + "be usable for grouping help entries anymore.") + elif inherits_from(match, "evennia.commands.command.Command"): + warning = (f"'{querystr}' matches (or partially matches) the key/alias of " + "Command '{match.key}'. Command-help take precedence over other " + "help entries so your help *may* be impossible to reach for those " + "with access to that command.") + elif inherits_from(match, "evennia.help.filehelp.FileHelpEntry"): + warning = (f"'{querystr}' matches (or partially matches) the name/alias of the " + "file-based help file '{match.key}'. File-help entries cannot be " + "modified from in-game (they are files on-disk). If you continue, " + "your help entry *may* shadow the file-based one's name partly or " + "completely.") + if warning: + # show a warning for a clashing help-entry type. Even if user accepts this + # we don't break here since we may need to show warnings for other inputs. + # We don't count this as an old-entry hit because we can't edit these + # types of entries. + self.msg(f"|rWarning:\n|r{warning}|n") + repl = yield("|wDo you still want to continue? Y/[N]?|n") + if repl.lower() not in ('y', 'yes'): + self.msg("Aborted.") + return + else: + # a db-based help entry - this is OK + old_entry = match + category = lhslist[1] if nlist > 1 else old_entry.help_category + lockstring = ",".join(lhslist[2:]) if nlist > 2 else old_entry.locks.get() break - category = lhslist[1] if nlist > 1 else old_entry.help_category - lockstring = ",".join(lhslist[2:]) if nlist > 2 else old_entry.locks.get() - except Exception: - old_entry = None - category = lhslist[1] if nlist > 1 else "General" - lockstring = ",".join(lhslist[2:]) if nlist > 2 else "view:all()" + category = category.lower() if "edit" in switches: @@ -458,7 +891,7 @@ helpentry = old_entry else: helpentry = create.create_help_entry( - topicstr, self.rhs, category=category, locks=lockstring, aliases=aliases + topicstr, self.rhs, category=category, locks=lockstring, aliases=aliases, ) self.caller.db._editing_help = helpentry @@ -487,6 +920,7 @@ old_entry.aliases.add(aliases) self.msg("Entry updated:\n%s%s" % (old_entry.entrytext, aliastxt)) return + if "delete" in switches or "del" in switches: # delete the help entry if not old_entry: @@ -513,8 +947,8 @@ self.msg("Overwrote the old topic '%s'%s." % (topicstr, aliastxt)) else: self.msg( - "Topic '%s'%s already exists. Use /replace to overwrite " - "or /append or /merge to add text to it." % (topicstr, aliastxt) + f"Topic '{topicstr}'{aliastxt} already exists. Use /edit to open in editor, or " + "/replace, /append and /merge to modify it directly." ) else: # no old entry. Create a new one. @@ -522,7 +956,7 @@ topicstr, self.rhs, category=category, locks=lockstring, aliases=aliases ) if new_entry: - self.msg("Topic '%s'%s was successfully created." % (topicstr, aliastxt)) + self.msg(f"Topic '{topicstr}'{aliastxt} was successfully created.") if "edit" in switches: # open the line editor to edit the helptext self.caller.db._editing_help = new_entry @@ -537,7 +971,7 @@ return else: self.msg( - "Error when creating topic '%s'%s! Contact an admin." % (topicstr, aliastxt) + f"Error when creating topic '{topicstr}'{aliastxt}! Contact an admin." )
        @@ -576,7 +1010,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -595,6 +1028,7 @@ +
        develop branch
        @@ -216,8 +217,8 @@ rhs = rhs.strip() if rhs is not None else None lhs = lhs.strip() # Further split left/right sides by comma delimiter - lhslist = [arg.strip() for arg in lhs.split(",")] if lhs is not None else "" - rhslist = [arg.strip() for arg in rhs.split(",")] if rhs is not None else "" + lhslist = [arg.strip() for arg in lhs.split(",")] if lhs is not None else [] + rhslist = [arg.strip() for arg in rhs.split(",")] if rhs is not None else [] # save to object properties: self.raw = raw self.switches = switches @@ -346,7 +347,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -365,6 +365,7 @@ +
        develop branch
        @@ -68,7 +69,6 @@ from evennia.commands.cmdhandler import CMD_NOINPUT from evennia.commands.cmdhandler import CMD_NOMATCH from evennia.commands.cmdhandler import CMD_MULTIMATCH -from evennia.commands.cmdhandler import CMD_CHANNEL from evennia.utils import utils from django.conf import settings @@ -145,53 +145,6 @@ matches = self.matches # at_search_result will itself msg the multimatch options to the caller. at_search_result([match[2] for match in matches], self.caller, query=matches[0][0])
        - - -# Command called when the command given at the command line -# was identified as a channel name, like there existing a -# channel named 'ooc' and the user wrote -# > ooc Hello! - - -
        [docs]class SystemSendToChannel(COMMAND_DEFAULT_CLASS): - """ - This is a special command that the cmdhandler calls - when it detects that the command given matches - an existing Channel object key (or alias). - """ - - key = CMD_CHANNEL - locks = "cmd:all()" - -
        [docs] def parse(self): - channelname, msg = self.args.split(":", 1) - self.args = channelname.strip(), msg.strip()
        - -
        [docs] def func(self): - """ - Create a new message and send it to channel, using - the already formatted input. - """ - caller = self.caller - channelkey, msg = self.args - if not msg: - caller.msg("Say what?") - return - channel = ChannelDB.objects.get_channel(channelkey) - if not channel: - caller.msg("Channel '%s' not found." % channelkey) - return - if not channel.has_connection(caller): - string = "You are not connected to channel '%s'." - caller.msg(string % channelkey) - return - if not channel.access(caller, "send"): - string = "You are not permitted to send to channel '%s'." - caller.msg(string % channelkey) - return - msg = "[%s] %s: %s" % (channel.key, caller.name, msg) - msgobj = create.create_message(caller, msg, channels=[channel]) - channel.msg(msgobj)
        @@ -229,7 +182,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -248,6 +200,7 @@ +
        develop branch
        @@ -49,7 +50,6 @@ import code import traceback import os -import io import datetime import sys import django @@ -66,9 +66,12 @@ from evennia.utils.eveditor import EvEditor from evennia.utils.evtable import EvTable from evennia.utils.evmore import EvMore -from evennia.utils.utils import crop, class_from_module +from evennia.utils.evmenu import ask_yes_no +from evennia.utils.utils import crop, class_from_module, iter_to_str +from evennia.scripts.taskhandler import TaskHandlerTask COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS) +_TASK_HANDLER = None # delayed imports _RESOURCE = None @@ -86,6 +89,7 @@ "CmdAbout", "CmdTime", "CmdServerLoad", + "CmdTasks", ) @@ -434,7 +438,9 @@ if noecho: prompt = "..." if console.push(line) else main_prompt else: - prompt = line if console.push(line) else f"{line}\n{main_prompt}" + if line: + self.caller.msg(f">>> {line}") + prompt = line if console.push(line) else main_prompt except SystemExit: break self.msg("|gClosing the Python console.|n") @@ -475,7 +481,6 @@ "|wintval|n", "|wnext|n", "|wrept|n", - "|wdb", "|wtypeclass|n", "|wdesc|n", align="r", @@ -487,9 +492,10 @@ nextrep = script.time_until_next_repeat() if nextrep is None: - nextrep = "PAUSED" if script.db._paused_time else "--" + nextrep = script.db._paused_time + nextrep = f"PAUSED {int(nextrep)}s" if nextrep else "--" else: - nextrep = "%ss" % nextrep + nextrep = f"{nextrep}s" maxrepeat = script.repeats remaining = script.remaining_repeats() or 0 @@ -499,7 +505,7 @@ rept = "-/-" table.add_row( - script.id, + f"#{script.id}", f"{script.obj.key}({script.obj.dbref})" if (hasattr(script, "obj") and script.obj) else "<Global>", @@ -507,7 +513,6 @@ script.interval if script.interval > 0 else "--", nextrep, rept, - "*" if script.persistent else "-", script.typeclass_path.rsplit(".", 1)[-1], crop(script.desc, width=20), ) @@ -517,16 +522,19 @@
        [docs]class CmdScripts(COMMAND_DEFAULT_CLASS): """ - list and manage all running scripts + List and manage all running scripts. Allows for creating new global + scripts. Usage: - scripts[/switches] [#dbref, key, script.path or <obj>] + script[/switches] [#dbref, key, script.path or <obj>] Switches: - start - start a script (must supply a script path) - stop - stops an existing script - kill - kills a script - without running its cleanup hooks - validate - run a validation on the script(s) + create - create a new global script of given typeclass path. This will + auto-start the script's timer if it has one. + start - start/unpause an existing script's timer. + stop - stops an existing script's timer + pause - pause a script's timer + delete - deletes script. This will also stop the timer as needed If no switches are given, this command just views all active scripts. The argument can be either an object, at which point it @@ -534,83 +542,100 @@ or #dbref. For using the /stop switch, a unique script #dbref is required since whole classes of scripts often have the same name. - Use script for managing commands on objects. + Use the `script` build-level command for managing scripts attached to + objects. + """ key = "scripts" - aliases = ["globalscript", "listscripts"] - switch_options = ("start", "stop", "kill", "validate") + aliases = ["scripts"] + switch_options = ("create", "start", "stop", "pause", "delete") locks = "cmd:perm(listscripts) or perm(Admin)" help_category = "System" excluded_typeclass_paths = ["evennia.prototypes.prototypes.DbPrototype"] + switch_mapping = { + "create": "|gCreated|n", + "start": "|gStarted|n", + "stop": "|RStopped|n", + "pause": "|Paused|n", + "delete": "|rDeleted|n" + } + + def _search_script(self, args): + # test first if this is a script match + scripts = ScriptDB.objects.get_all_scripts(key=args) + if scripts: + return scripts + # try typeclass path + scripts = ScriptDB.objects.filter(db_typeclass_path__iendswith=args) + if scripts: + return scripts + # try to find an object instead. + objects = ObjectDB.objects.object_search(args) + if objects: + scripts = ScriptDB.objects.filter(db_obj__in=objects) + return scripts +
        [docs] def func(self): """implement method""" caller = self.caller args = self.args - if args: - if "start" in self.switches: - # global script-start mode - new_script = create.create_script(args) - if new_script: - caller.msg("Global script %s was started successfully." % args) - else: - caller.msg("Global script %s could not start correctly. See logs." % args) + if "create" in self.switches: + # global script-start mode + verb = self.switch_mapping['create'] + if not args: + caller.msg("Usage script/create <key or typeclass>") return - - # test first if this is a script match - scripts = ScriptDB.objects.get_all_scripts(key=args) - if not scripts: - # try to find an object instead. - objects = ObjectDB.objects.object_search(args) - if objects: - scripts = [] - for obj in objects: - # get all scripts on the object(s) - scripts.extend(ScriptDB.objects.get_all_scripts_on_obj(obj)) - else: - # we want all scripts. - scripts = ScriptDB.objects.get_all_scripts() - if not scripts: - caller.msg("No scripts are running.") - return - # filter any found scripts by tag category. - scripts = scripts.exclude(db_typeclass_path__in=self.excluded_typeclass_paths) - - if not scripts: - string = "No scripts found with a key '%s', or on an object named '%s'." % (args, args) - caller.msg(string) + new_script = create.create_script(args) + if new_script: + caller.msg(f"Global Script {verb} - {new_script.key} ({new_script.typeclass_path})") + ScriptEvMore(caller, [new_script], session=self.session) + else: + caller.msg(f"Global Script |rNOT|n {verb} |r(see log)|n - arguments: {args}") return - if self.switches and self.switches[0] in ("stop", "del", "delete", "kill"): - # we want to delete something - if len(scripts) == 1: - # we have a unique match! - if "kill" in self.switches: - string = "Killing script '%s'" % scripts[0].key - scripts[0].stop(kill=True) - else: - string = "Stopping script '%s'." % scripts[0].key - scripts[0].stop() - # import pdb # DEBUG - # pdb.set_trace() # DEBUG - ScriptDB.objects.validate() # just to be sure all is synced - caller.msg(string) - else: - # multiple matches. - ScriptEvMore(caller, scripts, session=self.session) - caller.msg("Multiple script matches. Please refine your search") - elif self.switches and self.switches[0] in ("validate", "valid", "val"): - # run validation on all found scripts - nr_started, nr_stopped = ScriptDB.objects.validate(scripts=scripts) - string = "Validated %s scripts. " % ScriptDB.objects.all().count() - string += "Started %s and stopped %s scripts." % (nr_started, nr_stopped) - caller.msg(string) + # all other switches require existing scripts + if args: + scripts = self._search_script(args) + if not scripts: + caller.msg(f"No scripts found matching '{args}'.") + return else: - # No stopping or validation. We just want to view things. + scripts = ScriptDB.objects.all() + if not scripts: + caller.msg("No scripts found.") + return + + if args and self.switches: + # global script-modifying mode + if scripts.count() > 1: + caller.msg("Multiple script matches. Please refine your search.") + return + script = scripts[0] + script_key = script.key + script_typeclass_path = script.typeclass_path + for switch in self.switches: + verb = self.switch_mapping[switch] + msgs = [] + try: + getattr(script, switch)() + except Exception: + logger.log_trace() + msgs.append(f"Global Script |rNOT|n {verb} |r(see log)|n - " + f"{script_key} ({script_typeclass_path})|n") + else: + msgs.append(f"Global Script {verb} - " + f"{script_key} ({script_typeclass_path})") + caller.msg("\n".join(msgs)) + if "delete" not in self.switches: + ScriptEvMore(caller, [script], session=self.session) + return + else: + # simply show the found scripts ScriptEvMore(caller, scripts.order_by("id"), session=self.session)
        @@ -949,10 +974,14 @@ |wTwisted|n: {twisted} |wDjango|n: {django} - |wLicence|n https://opensource.org/licenses/BSD-3-Clause - |wWeb|n http://www.evennia.com + |wHomepage|n https://evennia.com + |wCode|n https://github.com/evennia/evennia + |wDemo|n https://demo.evennia.com + |wGame listing|n https://games.evennia.com |wIrc|n #evennia on irc.freenode.net:6667 - |wForum|n http://www.evennia.com/discussions + |wDiscord|n https://discord.gg/SVCkd4cY3q + |wForum|n https://github.com/evennia/evennia/discussions + |wLicence|n https://opensource.org/licenses/BSD-3-Clause |wMaintainer|n (2010-) Griatch (griatch AT gmail DOT com) |wMaintainer|n (2006-10) Greg Taylor @@ -995,7 +1024,7 @@ "|wIn-Game time", "|wReal time x %g" % gametime.TIMEFACTOR, align="l", - width=77, + width=78, border_top=0, ) epochtxt = "Epoch (%s)" % ("from settings" if settings.TIME_GAME_EPOCH else "server start") @@ -1219,6 +1248,227 @@ "*" if sub[5] else "-", ) self.caller.msg("|wActive tickers|n:\n" + str(table)) + + +
        [docs]class CmdTasks(COMMAND_DEFAULT_CLASS): + """ + Display or terminate active tasks (delays). + + Usage: + tasks[/switch] [task_id or function_name] + + Switches: + pause - Pause the callback of a task. + unpause - Process all callbacks made since pause() was called. + do_task - Execute the task (call its callback). + call - Call the callback of this task. + remove - Remove a task without executing it. + cancel - Stop a task from automatically executing. + + Notes: + A task is a single use method of delaying the call of a function. Calls are created + in code, using `evennia.utils.delay`. + See |luhttps://www.evennia.com/docs/latest/Command-Duration.html|ltthe docs|le for help. + + By default, tasks that are canceled and never called are cleaned up after one minute. + + Examples: + - `tasks/cancel move_callback` - Cancels all movement delays from the slow_exit contrib. + In this example slow exits creates it's tasks with + `utils.delay(move_delay, move_callback)` + - `tasks/cancel 2` - Cancel task id 2. + + """ + + key = "tasks" + aliases = ["delays", "task"] + switch_options = ("pause", "unpause", "do_task", "call", "remove", "cancel") + locks = "perm(Developer)" + help_category = "System" + +
        [docs] @staticmethod + def coll_date_func(task): + """Replace regex characters in date string and collect deferred function name.""" + t_comp_date = str(task[0]).replace('-', '/') + t_func_name = str(task[1]).split(' ') + t_func_mem_ref = t_func_name[3] if len(t_func_name) >= 4 else None + return t_comp_date, t_func_mem_ref
        + +
        [docs] def do_task_action(self, *args, **kwargs): + """ + Process the action of a tasks command. + + This exists to gain support with yes or no function from EvMenu. + """ + task_id = self.task_id + + # get a reference of the global task handler + global _TASK_HANDLER + if _TASK_HANDLER is None: + from evennia.scripts.taskhandler import TASK_HANDLER as _TASK_HANDLER + + # verify manipulating the correct task + task_args = _TASK_HANDLER.tasks.get(task_id, False) + if not task_args: # check if the task is still active + self.msg('Task completed while waiting for input.') + return + else: + # make certain a task with matching IDs has not been created + t_comp_date, t_func_mem_ref = self.coll_date_func(task_args) + if self.t_comp_date != t_comp_date or self.t_func_mem_ref != t_func_mem_ref: + self.msg('Task completed while waiting for input.') + return + + # Do the action requested by command caller + action_return = self.task_action() + self.msg(f'{self.action_request} request completed.') + self.msg(f'The task function {self.action_request} returned: {action_return}')
        + +
        [docs] def func(self): + # get a reference of the global task handler + global _TASK_HANDLER + if _TASK_HANDLER is None: + from evennia.scripts.taskhandler import TASK_HANDLER as _TASK_HANDLER + # handle no tasks active. + if not _TASK_HANDLER.tasks: + self.msg('There are no active tasks.') + if self.switches or self.args: + self.msg('Likely the task has completed and been removed.') + return + + # handle caller's request to manipulate a task(s) + if self.switches and self.lhs: + + # find if the argument is a task id or function name + action_request = self.switches[0] + try: + arg_is_id = int(self.lhslist[0]) + except ValueError: + arg_is_id = False + + # if the argument is a task id, proccess the action on a single task + if arg_is_id: + + err_arg_msg = 'Switch and task ID are required when manipulating a task.' + task_comp_msg = 'Task completed while processing request.' + + # handle missing arguments or switches + if not self.switches and self.lhs: + self.msg(err_arg_msg) + return + + # create a handle for the task + task_id = arg_is_id + task = TaskHandlerTask(task_id) + + # handle task no longer existing + if not task.exists(): + self.msg(f'Task {task_id} does not exist.') + return + + # get a reference of the function caller requested + switch_action = getattr(task, action_request, False) + if not switch_action: + self.msg(f'{self.switches[0]}, is not an acceptable task action or ' \ + f'{task_comp_msg.lower()}') + + # verify manipulating the correct task + if task_id in _TASK_HANDLER.tasks: + task_args = _TASK_HANDLER.tasks.get(task_id, False) + if not task_args: # check if the task is still active + self.msg(task_comp_msg) + return + else: + t_comp_date, t_func_mem_ref = self.coll_date_func(task_args) + t_func_name = str(task_args[1]).split(' ') + t_func_name = t_func_name[1] if len(t_func_name) >= 2 else None + + if task.exists(): # make certain the task has not been called yet. + prompt = (f'{action_request.capitalize()} task {task_id} with completion date ' + f'{t_comp_date} ({t_func_name}) {{options}}?') + no_msg = f'No {action_request} processed.' + # record variables for use in do_task_action method + self.task_id = task_id + self.t_comp_date = t_comp_date + self.t_func_mem_ref = t_func_mem_ref + self.task_action = switch_action + self.action_request = action_request + ask_yes_no(self.caller, + prompt=prompt, + yes_action=self.do_task_action, + no_action=no_msg, + default="Y", + allow_abort=True) + return True + else: + self.msg(task_comp_msg) + return + + # the argument is not a task id, process the action on all task deferring the function + # specified as an argument + else: + + name_match_found = False + arg_func_name = self.lhslist[0].lower() + + # repack tasks into a new dictionary + current_tasks = {} + for task_id, task_args in _TASK_HANDLER.tasks.items(): + current_tasks.update({task_id: task_args}) + + # call requested action on all tasks with the function name + for task_id, task_args in current_tasks.items(): + t_func_name = str(task_args[1]).split(' ') + t_func_name = t_func_name[1] if len(t_func_name) >= 2 else None + # skip this task if it is not for the function desired + if arg_func_name != t_func_name: + continue + name_match_found = True + task = TaskHandlerTask(task_id) + switch_action = getattr(task, action_request, False) + if switch_action: + action_return = switch_action() + self.msg(f'Task action {action_request} completed on task ID {task_id}.') + self.msg(f'The task function {action_request} returned: {action_return}') + + # provide a message if not tasks of the function name was found + if not name_match_found: + self.msg(f'No tasks deferring function name {arg_func_name} found.') + return + return True + + # check if an maleformed request was created + elif self.switches or self.lhs: + self.msg('Task command misformed.') + self.msg('Proper format tasks[/switch] [function name or task id]') + return + + # No task manupilation requested, build a table of tasks and display it + # get the width of screen in characters + width = self.client_width() + # create table header and list to hold tasks data and actions + tasks_header = ('Task ID', 'Completion Date', 'Function', 'Arguments', 'KWARGS', + 'persistent') + # empty list of lists, the size of the header + tasks_list = [list() for i in range(len(tasks_header))] + for task_id, task in _TASK_HANDLER.tasks.items(): + # collect data from the task + t_comp_date, t_func_mem_ref = self.coll_date_func(task) + t_func_name = str(task[1]).split(' ') + t_func_name = t_func_name[1] if len(t_func_name) >= 2 else None + t_args = str(task[2]) + t_kwargs = str(task[3]) + t_pers = str(task[4]) + # add task data to the tasks list + task_data = (task_id, t_comp_date, t_func_name, t_args, t_kwargs, t_pers) + for i in range(len(tasks_header)): + tasks_list[i].append(task_data[i]) + # create and display the table + tasks_table = EvTable(*tasks_header, table=tasks_list, maxwidth=width, border='cells', + align='center') + actions = (f'/{switch}' for switch in self.switch_options) + helptxt = f"\nActions: {iter_to_str(actions)}" + self.msg(str(tasks_table) + helptxt)
        @@ -1256,7 +1506,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1275,6 +1524,7 @@ +
        develop branch
        @@ -57,14 +58,16 @@ import datetime from anything import Anything +from parameterized import parameterized from django.conf import settings +from twisted.internet import task from unittest.mock import patch, Mock, MagicMock from evennia import DefaultRoom, DefaultExit, ObjectDB from evennia.commands.default.cmdset_character import CharacterCmdSet from evennia.utils.test_resources import EvenniaTest from evennia.commands.default import ( - help, + help as help_module, general, system, admin, @@ -75,7 +78,6 @@ unloggedin, syscommands, ) -from evennia.commands.cmdparser import build_matches from evennia.commands.default.muxcommand import MuxCommand from evennia.commands.command import Command, InterruptCommand from evennia.commands import cmdparser @@ -89,24 +91,50 @@ # set up signal here since we are not starting the server -_RE = re.compile(r"^\+|-+\+|\+-+|--+|\|(?:\s|$)", re.MULTILINE) +_RE_STRIP_EVMENU = re.compile(r"^\+|-+\+|\+-+|--+|\|(?:\s|$)", re.MULTILINE) # ------------------------------------------------------------ # Command testing # ------------------------------------------------------------ -
        [docs]@patch("evennia.server.portal.portal.LoopingCall", new=MagicMock()) class CommandTest(EvenniaTest): """ - Tests a command + Tests a Command by running it and comparing what messages it sends with + expected values. This tests without actually spinning up the cmdhandler + for every test, which is more controlled. + + Example: + :: + + from commands.echo import CmdEcho + + class MyCommandTest(CommandTest): + + def test_echo(self): + ''' + Test that the echo command really returns + what you pass into it. + ''' + self.call(MyCommand(), "hello world!", + "You hear your echo: 'Hello world!'") + """ + # formatting for .call's error message + _ERROR_FORMAT = """ +=========================== Wanted message =================================== +{expected_msg} +=========================== Returned message ================================= +{returned_msg} +============================================================================== +""".rstrip() +
        [docs] def call( self, cmdobj, - args, + input_args, msg=None, cmdset=None, noansi=True, @@ -118,54 +146,140 @@ raw_string=None, ): """ - Test a command by assigning all the needed - properties to cmdobj and running - cmdobj.at_pre_cmd() - cmdobj.parse() - cmdobj.func() - cmdobj.at_post_cmd() - The msgreturn value is compared to eventual - output sent to caller.msg in the game + Test a command by assigning all the needed properties to a cmdobj and + running the sequence. The resulting `.msg` calls will be mocked and + the text= calls to them compared to a expected output. + + Args: + cmdobj (Command): The command object to use. + input_args (str): This should be the full input the Command should + see, such as 'look here'. This will become `.args` for the Command + instance to parse. + msg (str or dict, optional): This is the expected return value(s) + returned through `caller.msg(text=...)` calls in the command. If a string, the + receiver is controlled with the `receiver` kwarg (defaults to `caller`). + If this is a `dict`, it is a mapping + `{receiver1: "expected1", receiver2: "expected2",...}` and `receiver` is + ignored. The message(s) are compared with the actual messages returned + to the receiver(s) as the Command runs. Each check uses `.startswith`, + so you can choose to only include the first part of the + returned message if that's enough to verify a correct result. EvMenu + decorations (like borders) are stripped and should not be included. This + should also not include color tags unless `noansi=False`. + If the command returns texts in multiple separate `.msg`- + calls to a receiver, separate these with `|` if `noansi=True` + (default) and `||` if `noansi=False`. If no `msg` is given (`None`), + then no automatic comparison will be done. + cmdset (str, optional): If given, make `.cmdset` available on the Command + instance as it runs. While `.cmdset` is normally available on the + Command instance by default, this is usually only used by + commands that explicitly operates/displays cmdsets, like + `examine`. + noansi (str, optional): By default the color tags of the `msg` is + ignored, this makes them significant. If unset, `msg` must contain + the same color tags as the actual return message. + caller (Object or Account, optional): By default `self.char1` is used as the + command-caller (the `.caller` property on the Command). This allows to + execute with another caller, most commonly an Account. + receiver (Object or Account, optional): This is the object to receive the + return messages we want to test. By default this is the same as `caller` + (which in turn defaults to is `self.char1`). Note that if `msg` is + a `dict`, this is ignored since the receiver is already specified there. + cmdstring (str, optional): Normally this is the Command's `key`. + This allows for tweaking the `.cmdname` property of the + Command`. This isb used for commands with multiple aliases, + where the command explicitly checs which alias was used to + determine its functionality. + obj (str, optional): This sets the `.obj` property of the Command - the + object on which the Command 'sits'. By default this is the same as `caller`. + This can be used for testing on-object Command interactions. + inputs (list, optional): A list of strings to pass to functions that pause to + take input from the user (normally using `@interactive` and + `ret = yield(question)` or `evmenu.get_input`). Each element of the + list will be passed into the command as if the user wrote that at the prompt. + raw_string (str, optional): Normally the `.raw_string` property is set as + a combination of your `key/cmdname` and `input_args`. This allows + direct control of what this is, for example for testing edge cases + or malformed inputs. Returns: - msg (str): The received message that was sent to the caller. + str or dict: The message sent to `receiver`, or a dict of + `{receiver: "msg", ...}` if multiple are given. This is usually + only used with `msg=None` to do the validation externally. + + Raises: + AssertionError: If the returns of `.msg` calls (tested with `.startswith`) does not + match `expected_input`. + + Notes: + As part of the tests, all methods of the Command will be called in + the proper order: + + - cmdobj.at_pre_cmd() + - cmdobj.parse() + - cmdobj.func() + - cmdobj.at_post_cmd() """ + # The `self.char1` is created in the `EvenniaTest` base along with + # other helper objects like self.room and self.obj caller = caller if caller else self.char1 - receiver = receiver if receiver else caller cmdobj.caller = caller cmdobj.cmdname = cmdstring if cmdstring else cmdobj.key cmdobj.raw_cmdname = cmdobj.cmdname cmdobj.cmdstring = cmdobj.cmdname # deprecated - cmdobj.args = args + cmdobj.args = input_args cmdobj.cmdset = cmdset cmdobj.session = SESSIONS.session_from_sessid(1) cmdobj.account = self.account - cmdobj.raw_string = raw_string if raw_string is not None else cmdobj.key + " " + args + cmdobj.raw_string = raw_string if raw_string is not None else cmdobj.key + " " + input_args cmdobj.obj = obj or (caller if caller else self.char1) - # test - old_msg = receiver.msg inputs = inputs or [] - try: + # set up receivers + receiver_mapping = {} + if isinstance(msg, dict): + # a mapping {receiver: msg, ...} + receiver_mapping = {recv: str(msg).strip() if msg else None + for recv, msg in msg.items()} + else: + # a single expected string and thus a single receiver (defaults to caller) + receiver = receiver if receiver else caller + receiver_mapping[receiver] = str(msg).strip() if msg is not None else None + + unmocked_msg_methods = {} + for receiver in receiver_mapping: + # save the old .msg method so we can get it back + # cleanly after the test + unmocked_msg_methods[receiver] = receiver.msg + # replace normal `.msg` with a mock receiver.msg = Mock() + + # Run the methods of the Command. This mimics what happens in the + # cmdhandler. This will have the mocked .msg be called as part of the + # execution. Mocks remembers what was sent to them so we will be able + # to retrieve what was sent later. + try: if cmdobj.at_pre_cmd(): return cmdobj.parse() ret = cmdobj.func() - # handle func's with yield in them (generators) + # handle func's with yield in them (making them generators) if isinstance(ret, types.GeneratorType): while True: try: inp = inputs.pop() if inputs else None if inp: try: + # this mimics a user's reply to a prompt ret.send(inp) except TypeError: next(ret) ret = ret.send(inp) else: + # non-input yield, like yield(10). We don't pause + # but fire it immediately. next(ret) except StopIteration: break @@ -176,40 +290,62 @@ except InterruptCommand: pass - # clean out evtable sugar. We only operate on text-type - stored_msg = [ - args[0] if args and args[0] else kwargs.get("text", utils.to_str(kwargs)) - for name, args, kwargs in receiver.msg.mock_calls - ] - # Get the first element of a tuple if msg received a tuple instead of a string - stored_msg = [str(smsg[0]) if isinstance(smsg, tuple) else str(smsg) for smsg in stored_msg] - if msg is not None: - msg = str(msg) # to be safe, e.g. `py` command may return ints - # set our separator for returned messages based on parsing ansi or not - msg_sep = "|" if noansi else "||" - # Have to strip ansi for each returned message for the regex to handle it correctly - returned_msg = msg_sep.join( - _RE.sub("", ansi.parse_ansi(mess, strip_ansi=noansi)) for mess in stored_msg - ).strip() - msg = msg.strip() - if msg == "" and returned_msg or not returned_msg.startswith(msg): - prt = "" - for ic, char in enumerate(msg): - import re + for inp in inputs: + # if there are any inputs left, we may have a non-generator + # input to handle (get_input/ask_yes_no that uses a separate + # cmdset rather than a yield + caller.execute_cmd(inp) - prt += char + # At this point the mocked .msg methods on each receiver will have + # stored all calls made to them (that's a basic function of the Mock + # class). We will not extract them and compare to what we expected to + # go to each receiver. - sep1 = "\n" + "=" * 30 + "Wanted message" + "=" * 34 + "\n" - sep2 = "\n" + "=" * 30 + "Returned message" + "=" * 32 + "\n" - sep3 = "\n" + "=" * 78 - retval = sep1 + msg + sep2 + returned_msg + sep3 - raise AssertionError(retval) - else: - returned_msg = "\n".join(str(msg) for msg in stored_msg) - returned_msg = ansi.parse_ansi(returned_msg, strip_ansi=noansi).strip() - receiver.msg = old_msg + returned_msgs = {} + for receiver, expected_msg in receiver_mapping.items(): + # get the stored messages from the Mock with Mock.mock_calls. + stored_msg = [ + args[0] if args and args[0] else kwargs.get("text", utils.to_str(kwargs)) + for name, args, kwargs in receiver.msg.mock_calls + ] + # we can return this now, we are done using the mock + receiver.msg = unmocked_msg_methods[receiver] - return returned_msg
        + # Get the first element of a tuple if msg received a tuple instead of a string + stored_msg = [str(smsg[0]) + if isinstance(smsg, tuple) else str(smsg) for smsg in stored_msg] + if expected_msg is None: + # no expected_msg; just build the returned_msgs dict + + returned_msg = "\n".join(str(msg) for msg in stored_msg) + returned_msgs[receiver] = ansi.parse_ansi(returned_msg, strip_ansi=noansi).strip() + else: + # compare messages to expected + + # set our separator for returned messages based on parsing ansi or not + msg_sep = "|" if noansi else "||" + + # We remove Evmenu decorations since that just makes it harder + # to write the comparison string. We also strip ansi before this + # comparison since otherwise it would mess with the regex. + returned_msg = msg_sep.join( + _RE_STRIP_EVMENU.sub( + "", ansi.parse_ansi(mess, strip_ansi=noansi)) + for mess in stored_msg).strip() + + # this is the actual test + if expected_msg == "" and returned_msg or not returned_msg.startswith(expected_msg): + # failed the test + raise AssertionError( + self._ERROR_FORMAT.format( + expected_msg=expected_msg, returned_msg=returned_msg) + ) + # passed! + returned_msgs[receiver] = returned_msg + + if len(returned_msgs) == 1: + return list(returned_msgs.values())[0] + return returned_msgs
        # ------------------------------------------------------------ @@ -314,16 +450,153 @@
        [docs]class TestHelp(CommandTest): + + maxDiff = None + +
        [docs] def setUp(self): + super().setUp() + # we need to set up a logger here since lunr takes over the logger otherwise + import logging + + logging.basicConfig(level=logging.ERROR)
        + +
        [docs] def tearDown(self): + super().tearDown() + import logging + + logging.disable(level=logging.ERROR)
        +
        [docs] def test_help(self): - self.call(help.CmdHelp(), "", "Command help entries", cmdset=CharacterCmdSet())
        + self.call(help_module.CmdHelp(), "", "Commands", cmdset=CharacterCmdSet())
        [docs] def test_set_help(self): self.call( - help.CmdSetHelp(), + help_module.CmdSetHelp(), "testhelp, General = This is a test", "Topic 'testhelp' was successfully created.", + cmdset=CharacterCmdSet() ) - self.call(help.CmdHelp(), "testhelp", "Help for testhelp", cmdset=CharacterCmdSet())
        + self.call(help_module.CmdHelp(), "testhelp", "Help for testhelp", cmdset=CharacterCmdSet()) + + @parameterized.expand([ + ("test", # main help entry + "Help for test\n\n" + "Main help text\n\n" + "Subtopics:\n" + " test/creating extra stuff" + " test/something else" + " test/more" + ), + ("test/creating extra stuff", # subtopic, full match + "Help for test/creating extra stuff\n\n" + "Help on creating extra stuff.\n\n" + "Subtopics:\n" + " test/creating extra stuff/subsubtopic\n" + ), + ("test/creating", # startswith-match + "Help for test/creating extra stuff\n\n" + "Help on creating extra stuff.\n\n" + "Subtopics:\n" + " test/creating extra stuff/subsubtopic\n" + ), + ("test/extra", # partial match + "Help for test/creating extra stuff\n\n" + "Help on creating extra stuff.\n\n" + "Subtopics:\n" + " test/creating extra stuff/subsubtopic\n" + ), + ("test/extra/subsubtopic", # partial subsub-match + "Help for test/creating extra stuff/subsubtopic\n\n" + "A subsubtopic text" + ), + ("test/creating extra/subsub", # partial subsub-match + "Help for test/creating extra stuff/subsubtopic\n\n" + "A subsubtopic text" + ), + ("test/Something else", # case + "Help for test/something else\n\n" + "Something else" + ), + ("test/More", # case + "Help for test/more\n\n" + "Another text\n\n" + "Subtopics:\n" + " test/more/second-more" + ), + ("test/More/Second-more", + "Help for test/more/second-more\n\n" + "The Second More text.\n\n" + "Subtopics:\n" + " test/more/second-more/more again" + " test/more/second-more/third more" + ), + ("test/More/-more", # partial match + "Help for test/more/second-more\n\n" + "The Second More text.\n\n" + "Subtopics:\n" + " test/more/second-more/more again" + " test/more/second-more/third more" + ), + ("test/more/second/more again", + "Help for test/more/second-more/more again\n\n" + "Even more text.\n" + ), + ("test/more/second/third", + "Help for test/more/second-more/third more\n\n" + "Third more text\n" + ), + ]) + def test_subtopic_fetch(self, helparg, expected): + """ + Check retrieval of subtopics. + + """ + class TestCmd(Command): + """ + Main help text + + # SUBTOPICS + + ## creating extra stuff + + Help on creating extra stuff. + + ### subsubtopic + + A subsubtopic text + + ## Something else + + Something else + + ## More + + Another text + + ### Second-More + + The Second More text. + + #### More again + + Even more text. + + #### Third more + + Third more text + + """ + key = "test" + + class TestCmdSet(CmdSet): + def at_cmdset_creation(self): + self.add(TestCmd()) + self.add(help_module.CmdHelp()) + + self.call(help_module.CmdHelp(), + helparg, + expected, + cmdset=TestCmdSet())
        [docs]class TestSystem(CommandTest): @@ -345,6 +618,170 @@
        [docs] def test_server_load(self): self.call(system.CmdServerLoad(), "", "Server CPU and Memory load:")
        +_TASK_HANDLER = None + +
        [docs]def func_test_cmd_tasks(): + return 'success'
        + +
        [docs]class TestCmdTasks(CommandTest): + +
        [docs] def setUp(self): + super().setUp() + # get a reference of TASK_HANDLER + self.timedelay = 5 + global _TASK_HANDLER + if _TASK_HANDLER is None: + from evennia.scripts.taskhandler import TASK_HANDLER as _TASK_HANDLER + _TASK_HANDLER.clock = task.Clock() + self.task_handler = _TASK_HANDLER + self.task_handler.clear() + self.task = self.task_handler.add(self.timedelay, func_test_cmd_tasks) + task_args = self.task_handler.tasks.get(self.task.get_id(), False)
        + + +
        [docs] def tearDown(self): + super().tearDown() + self.task_handler.clear()
        + +
        [docs] def test_no_tasks(self): + self.task_handler.clear() + self.call(system.CmdTasks(), '', 'There are no active tasks.')
        + +
        [docs] def test_active_task(self): + cmd_result = self.call(system.CmdTasks(), '') + for ptrn in ('Task ID', 'Completion Date', 'Function', 'KWARGS', 'persisten', + '1', r'\d+/\d+/\d+', r'\d+\:\d+\:\d+', r'ms\:\d+', 'func_test', '{}', + 'False'): + self.assertRegex(cmd_result, ptrn)
        + +
        [docs] def test_persistent_task(self): + self.task_handler.clear() + self.task_handler.add(self.timedelay, func_test_cmd_tasks, persistent=True) + cmd_result = self.call(system.CmdTasks(), '') + self.assertRegex(cmd_result, 'True')
        + +
        [docs] def test_pause_unpause(self): + # test pause + args = f'/pause {self.task.get_id()}' + wanted_msg = 'Yes or No, pause task 1? With completion date' + cmd_result = self.call(system.CmdTasks(), args, wanted_msg) + self.assertRegex(cmd_result, '\. Deferring function func_test_cmd_tasks\.') + self.char1.execute_cmd('y') + self.assertTrue(self.task.paused) + self.task_handler.clock.advance(self.timedelay + 1) + # test unpause + args = f'/unpause {self.task.get_id()}' + self.assertTrue(self.task.exists()) + wanted_msg = 'Yes or No, unpause task 1? With completion date' + cmd_result = self.call(system.CmdTasks(), args, wanted_msg) + self.assertRegex(cmd_result, '\. Deferring function func_test_cmd_tasks\.') + self.char1.execute_cmd('y') + # verify task continues after unpause + self.task_handler.clock.advance(1) + self.assertFalse(self.task.exists())
        + +
        [docs] def test_do_task(self): + args = f'/do_task {self.task.get_id()}' + wanted_msg = 'Yes or No, do_task task 1? With completion date' + cmd_result = self.call(system.CmdTasks(), args, wanted_msg) + self.assertRegex(cmd_result, '\. Deferring function func_test_cmd_tasks\.') + self.char1.execute_cmd('y') + self.assertFalse(self.task.exists())
        + +
        [docs] def test_remove(self): + args = f'/remove {self.task.get_id()}' + wanted_msg = 'Yes or No, remove task 1? With completion date' + cmd_result = self.call(system.CmdTasks(), args, wanted_msg) + self.assertRegex(cmd_result, '\. Deferring function func_test_cmd_tasks\.') + self.char1.execute_cmd('y') + self.assertFalse(self.task.exists())
        + +
        [docs] def test_call(self): + args = f'/call {self.task.get_id()}' + wanted_msg = 'Yes or No, call task 1? With completion date' + cmd_result = self.call(system.CmdTasks(), args, wanted_msg) + self.assertRegex(cmd_result, '\. Deferring function func_test_cmd_tasks\.') + self.char1.execute_cmd('y') + # make certain the task is still active + self.assertTrue(self.task.active()) + # go past delay time, the task should call do_task and remove itself after calling. + self.task_handler.clock.advance(self.timedelay + 1) + self.assertFalse(self.task.exists())
        + +
        [docs] def test_cancel(self): + args = f'/cancel {self.task.get_id()}' + wanted_msg = 'Yes or No, cancel task 1? With completion date' + cmd_result = self.call(system.CmdTasks(), args, wanted_msg) + self.assertRegex(cmd_result, '\. Deferring function func_test_cmd_tasks\.') + self.char1.execute_cmd('y') + self.assertTrue(self.task.exists()) + self.assertFalse(self.task.active())
        + +
        [docs] def test_func_name_manipulation(self): + self.task_handler.add(self.timedelay, func_test_cmd_tasks) # add an extra task + args = f'/remove func_test_cmd_tasks' + wanted_msg = 'Task action remove completed on task ID 1.|The task function remove returned: True|' \ + 'Task action remove completed on task ID 2.|The task function remove returned: True' + self.call(system.CmdTasks(), args, wanted_msg) + self.assertFalse(self.task_handler.tasks) # no tasks should exist.
        + +
        [docs] def test_wrong_func_name(self): + args = f'/remove intentional_fail' + wanted_msg = 'No tasks deferring function name intentional_fail found.' + self.call(system.CmdTasks(), args, wanted_msg) + self.assertTrue(self.task.active())
        + +
        [docs] def test_no_input(self): + args = f'/cancel {self.task.get_id()}' + self.call(system.CmdTasks(), args) + # task should complete since no input was received + self.task_handler.clock.advance(self.timedelay + 1) + self.assertFalse(self.task.exists())
        + +
        [docs] def test_responce_of_yes(self): + self.call(system.CmdTasks(), f'/cancel {self.task.get_id()}') + self.char1.msg = Mock() + self.char1.execute_cmd('y') + text = '' + for _, _, kwargs in self.char1.msg.mock_calls: + text += kwargs.get('text', '') + self.assertEqual(text, 'cancel request completed.The task function cancel returned: True') + self.assertTrue(self.task.exists())
        + +
        [docs] def test_task_complete_waiting_input(self): + """Test for task completing while waiting for input.""" + self.call(system.CmdTasks(), f'/cancel {self.task.get_id()}') + self.task_handler.clock.advance(self.timedelay + 1) + self.char1.msg = Mock() + self.char1.execute_cmd('y') + text = '' + for _, _, kwargs in self.char1.msg.mock_calls: + text += kwargs.get('text', '') + self.assertEqual(text, 'Task completed while waiting for input.') + self.assertFalse(self.task.exists())
        + +
        [docs] def test_new_task_waiting_input(self): + """ + Test task completing than a new task with the same ID being made while waitinf for input. + """ + self.assertTrue(self.task.get_id(), 1) + self.call(system.CmdTasks(), f'/cancel {self.task.get_id()}') + self.task_handler.clock.advance(self.timedelay + 1) + self.assertFalse(self.task.exists()) + self.task = self.task_handler.add(self.timedelay, func_test_cmd_tasks) + self.assertTrue(self.task.get_id(), 1) + self.char1.msg = Mock() + self.char1.execute_cmd('y') + text = '' + for _, _, kwargs in self.char1.msg.mock_calls: + text += kwargs.get('text', '') + self.assertEqual(text, 'Task completed while waiting for input.')
        + +
        [docs] def test_misformed_command(self): + wanted_msg = 'Task command misformed.|Proper format tasks[/switch] ' \ + '[function name or task id]' + self.call(system.CmdTasks(), f'/cancel', wanted_msg)
        +
        [docs]class TestAdmin(CommandTest):
        [docs] def test_emit(self): @@ -1012,11 +1449,8 @@ self.call(building.CmdSetHome(), "Obj = Room2", "Home location of Obj was set to Room")
        [docs] def test_list_cmdsets(self): - self.call( - building.CmdListCmdSets(), - "", - "<CmdSetHandler> stack:\n <CmdSet DefaultCharacter, Union, perm, prio 0>:", - ) + self.call(building.CmdListCmdSets(), "", + "<CmdSetHandler> stack:\n <CmdSet DefaultCharacter, Union, perm, prio 0>:") self.call(building.CmdListCmdSets(), "NotFound", "Could not find 'NotFound'")
        [docs] def test_typeclass(self): @@ -1194,8 +1628,8 @@ self.call(building.CmdScript(), "Obj ", "dbref ") self.call( - building.CmdScript(), "/start Obj", "0 scripts started on Obj" - ) # because it's already started + building.CmdScript(), "/start Obj", "1 scripts started on Obj" + ) # we allow running start again; this should still happen self.call(building.CmdScript(), "/stop Obj", "Stopping script") self.call( @@ -1464,21 +1898,13 @@ self.call( comms.CmdAddCom(), "tc = testchan", - "You are already connected to channel testchan. You can now", + "You are already connected to channel testchan.| You can now", receiver=self.account, ) self.call( comms.CmdDelCom(), "tc", - "Your alias 'tc' for channel testchan was cleared.", - receiver=self.account, - )
        - -
        [docs] def test_channels(self): - self.call( - comms.CmdChannels(), - "", - "Available channels (use comlist,addcom and delcom to manage", + "Any alias 'tc' for channel testchan was cleared.", receiver=self.account, )
        @@ -1486,7 +1912,7 @@ self.call( comms.CmdAllCom(), "", - "Available channels (use comlist,addcom and delcom to manage", + "Available channels:", receiver=self.account, )
        @@ -1506,14 +1932,6 @@ receiver=self.account, ) -
        [docs] def test_cemit(self): - self.call( - comms.CmdCemit(), - "testchan = Test Message", - "[testchan] Test Message|Sent to channel testchan: Test Message", - receiver=self.account, - )
        -
        [docs] def test_cwho(self): self.call( comms.CmdCWho(), @@ -1550,8 +1968,232 @@ )
        +from evennia.utils.create import create_channel # noqa + +
        [docs]class TestCommsChannel(CommandTest): + """ + Test the central `channel` command. + + """ +
        [docs] def setUp(self): + super(CommandTest, self).setUp() + self.channel = create_channel( + key="testchannel", + desc="A test channel") + self.channel.connect(self.char1) + self.cmdchannel = comms.CmdChannel + self.cmdchannel.account_caller = False
        + +
        [docs] def tearDown(self): + if self.channel.pk: + self.channel.delete()
        + + # test channel command +
        [docs] def test_channel__noarg(self): + self.call( + self.cmdchannel(), + "", + "Channel subscriptions" + )
        + +
        [docs] def test_channel__msg(self): + self.channel.msg = Mock() + self.call( + self.cmdchannel(), + "testchannel = Test message", + "" + ) + self.channel.msg.assert_called_with("Test message", senders=self.char1)
        + +
        [docs] def test_channel__list(self): + self.call( + self.cmdchannel(), + "/list", + "Channel subscriptions" + )
        + +
        [docs] def test_channel__all(self): + self.call( + self.cmdchannel(), + "/all", + "Available channels" + )
        + +
        [docs] def test_channel__history(self): + with patch("evennia.commands.default.comms.tail_log_file") as mock_tail: + self.call( + self.cmdchannel(), + "/history testchannel", + "" + ) + mock_tail.assert_called()
        + +
        [docs] def test_channel__sub(self): + self.channel.disconnect(self.char1) + + self.call( + self.cmdchannel(), + "/sub testchannel", + "You are now subscribed" + ) + self.assertTrue(self.char1 in self.channel.subscriptions.all()) + self.assertEqual(self.char1.nicks.nickreplace("testchannel Hello"), "channel testchannel = Hello")
        + +
        [docs] def test_channel__unsub(self): + self.call( + self.cmdchannel(), + "/unsub testchannel", + "You un-subscribed" + ) + self.assertFalse(self.char1 in self.channel.subscriptions.all())
        + +
        [docs] def test_channel__alias__unalias(self): + """Add and then remove a channel alias""" + # add alias + self.call( + self.cmdchannel(), + "/alias testchannel = foo", + "Added/updated your alias 'foo' for channel testchannel." + ) + self.assertEqual( + self.char1.nicks.nickreplace('foo Hello'), "channel testchannel = Hello") + + # use alias + self.channel.msg = Mock() + self.call( + self.cmdchannel(), + "foo = test message", + "") + self.channel.msg.assert_called_with("test message", senders=self.char1) + + # remove alias + self.call( + self.cmdchannel(), + "/unalias foo", + "Removed your channel alias 'foo'" + ) + self.assertEqual(self.char1.nicks.get('foo $1', category="channel"), None)
        + +
        [docs] def test_channel__mute(self): + self.call( + self.cmdchannel(), + "/mute testchannel", + "Muted channel testchannel" + ) + self.assertTrue(self.char1 in self.channel.mutelist)
        + +
        [docs] def test_channel__unmute(self): + self.channel.mute(self.char1) + + self.call( + self.cmdchannel(), + "/unmute testchannel = Char1", + "Un-muted channel testchannel" + ) + self.assertFalse(self.char1 in self.channel.mutelist)
        + +
        [docs] def test_channel__create(self): + self.call( + self.cmdchannel(), + "/create testchannel2", + "Created (and joined) new channel" + )
        + +
        [docs] def test_channel__destroy(self): + self.channel.msg = Mock() + self.call( + self.cmdchannel(), + "/destroy testchannel = delete reason", + "Are you sure you want to delete channel ", + inputs=['Yes'] + ) + self.channel.msg.assert_called_with( + "delete reason", bypass_mute=True, senders=self.char1)
        + +
        [docs] def test_channel__desc(self): + self.call( + self.cmdchannel(), + "/desc testchannel = Another description", + "Updated channel description." + )
        + +
        [docs] def test_channel__lock(self): + self.call( + self.cmdchannel(), + "/lock testchannel = foo:false()", + "Added/updated lock on channel" + ) + self.assertEqual(self.channel.locks.get('foo'), 'foo:false()')
        + +
        [docs] def test_channel__unlock(self): + self.channel.locks.add("foo:true()") + self.call( + self.cmdchannel(), + "/unlock testchannel = foo", + "Removed lock from channel" + ) + self.assertEqual(self.channel.locks.get('foo'), '')
        + +
        [docs] def test_channel__boot(self): + self.channel.connect(self.char2) + self.assertTrue(self.char2 in self.channel.subscriptions.all()) + self.channel.msg = Mock() + self.char2.msg = Mock() + + self.call( + self.cmdchannel(), + "/boot testchannel = Char2 : Booting from channel!", + "Are you sure ", + inputs=["Yes"] + ) + self.channel.msg.assert_called_with( + "Char2 was booted from channel by Char. Reason: Booting from channel!") + self.char2.msg.assert_called_with( + "You were booted from channel testchannel by Char. Reason: Booting from channel!")
        + +
        [docs] def test_channel__ban__unban(self): + """Test first ban and then unban""" + + # ban + self.channel.connect(self.char2) + self.assertTrue(self.char2 in self.channel.subscriptions.all()) + self.channel.msg = Mock() + self.char2.msg = Mock() + + self.call( + self.cmdchannel(), + "/ban testchannel = Char2 : Banning from channel!", + "Are you sure ", + inputs=["Yes"] + ) + self.channel.msg.assert_called_with( + "Char2 was booted from channel by Char. Reason: Banning from channel!") + self.char2.msg.assert_called_with( + "You were booted from channel testchannel by Char. Reason: Banning from channel!") + self.assertTrue(self.char2 in self.channel.banlist) + + # unban + + self.call( + self.cmdchannel(), + "/unban testchannel = Char2", + "Un-banned Char2 from channel testchannel" + ) + self.assertFalse(self.char2 in self.channel.banlist)
        + +
        [docs] def test_channel__who(self): + self.call( + self.cmdchannel(), + "/who testchannel", + "Subscribed to testchannel:\nChar" + )
        + +
        [docs]class TestBatchProcess(CommandTest): -
        [docs] def test_batch_commands(self): + +
        [docs] @patch("evennia.contrib.tutorial_examples.red_button.repeat") + @patch("evennia.contrib.tutorial_examples.red_button.delay") + def test_batch_commands(self, mock_delay, mock_repeat): # cannot test batchcode here, it must run inside the server process self.call( batchprocess.CmdBatchCommands(), @@ -1562,7 +2204,8 @@ confirm = building.CmdDestroy.confirm building.CmdDestroy.confirm = False self.call(building.CmdDestroy(), "button", "button was destroyed.") - building.CmdDestroy.confirm = confirm
        + building.CmdDestroy.confirm = confirm + mock_repeat.assert_called()
        [docs]class CmdInterrupt(Command): @@ -1617,16 +2260,7 @@ multimatch = syscommands.SystemMultimatch() multimatch.matches = matches - self.call(multimatch, "look", "")
        - -
        [docs] @patch("evennia.commands.default.syscommands.ChannelDB") - def test_channelcommand(self, mock_channeldb): - channel = MagicMock() - channel.msg = MagicMock() - mock_channeldb.objects.get_channel = MagicMock(return_value=channel) - - self.call(syscommands.SystemSendToChannel(), "public:Hello") - channel.msg.assert_called()
        + self.call(multimatch, "look", "")
        @@ -1664,7 +2298,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1683,6 +2316,7 @@ +
        develop branch
        @@ -335,6 +336,7 @@ |wquit|n - abort the connection First create an account e.g. with |wcreate Anna c67jHL8p|n +(If you have spaces in your name, use double quotes: |wcreate "Anna the Barbarian" c67jHL8p|n Next you can connect to the game: |wconnect Anna c67jHL8p|n You can use the |wlook|n command if you want to see the connect screen again. @@ -572,7 +574,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -591,6 +592,7 @@ +
        develop branch
        @@ -48,23 +49,48 @@ from django.utils.text import slugify from evennia.typeclasses.models import TypeclassBase -from evennia.comms.models import TempMsg, ChannelDB +from evennia.comms.models import ChannelDB from evennia.comms.managers import ChannelManager from evennia.utils import create, logger from evennia.utils.utils import make_iter -_CHANNEL_HANDLER = None -
        [docs]class DefaultChannel(ChannelDB, metaclass=TypeclassBase): """ This is the base class for all Channel Comms. Inherit from this to create different types of communication channels. + Class-level variables: + - `send_to_online_only` (bool, default True) - if set, will only try to + send to subscribers that are actually active. This is a useful optimization. + - `log_file` (str, default `"channel_{channelname}.log"`). This is the + log file to which the channel history will be saved. The `{channelname}` tag + will be replaced by the key of the Channel. If an Attribute 'log_file' + is set, this will be used instead. If this is None and no Attribute is found, + no history will be saved. + - `channel_prefix_string` (str, default `"[{channelname} ]"`) - this is used + as a simple template to get the channel prefix with `.channel_prefix()`. + """ objects = ChannelManager() + # channel configuration + + # only send to characters/accounts who has an active session (this is a + # good optimization since people can still recover history separately). + send_to_online_only = True + # store log in log file. `channel_key tag will be replace with key of channel. + # Will use log_file Attribute first, if given + log_file = "channel_{channelname}.log" + # which prefix to use when showing were a message is coming from. Set to + # None to disable and set this later. + channel_prefix_string = "[{channelname}] " + + # default nick-alias replacements (default using the 'channel' command) + channel_msg_nick_pattern = r"{alias}\s*?|{alias}\s+?(?P<arg1>.+?)" + channel_msg_nick_replacement = "channel {channelname} = $1" +
        [docs] def at_first_save(self): """ Called by the typeclass system the very first time the channel @@ -74,7 +100,6 @@ """ self.basetype_setup() self.at_channel_creation() - self.attributes.add("log_file", "channel_%s.log" % self.key) if hasattr(self, "_createdict"): # this is only set if the channel was created # with the utils.create.create_channel function. @@ -96,14 +121,11 @@ self.tags.batch_add(*cdict["tags"])
        [docs] def basetype_setup(self): - # delayed import of the channelhandler - global _CHANNEL_HANDLER - if not _CHANNEL_HANDLER: - from evennia.comms.channelhandler import CHANNEL_HANDLER as _CHANNEL_HANDLER - # register ourselves with the channelhandler. - _CHANNEL_HANDLER.add(self) + self.locks.add("send:all();listen:all();control:perm(Admin)") - self.locks.add("send:all();listen:all();control:perm(Admin)")
        + # make sure we don't have access to a same-named old channel's history. + log_file = self.get_log_filename() + logger.rotate_log_file(log_file, num_lines_to_append=0)
        [docs] def at_channel_creation(self): """ @@ -114,6 +136,33 @@ # helper methods, for easy overloading + _log_file = None + +
        [docs] def get_log_filename(self): + """ + File name to use for channel log. + + Returns: + str: The filename to use (this is always assumed to be inside + settings.LOG_DIR) + + """ + if not self._log_file: + self._log_file = self.attributes.get( + "log_file", self.log_file.format(channelname=self.key.lower())) + return self._log_file
        + +
        [docs] def set_log_filename(self, filename): + """ + Set a custom log filename. + + Args: + filename (str): The filename to set. This is a path starting from + inside the settings.LOG_DIR location. + + """ + self.attributes.add("log_file", filename)
        +
        [docs] def has_connection(self, subscriber): """ Checks so this account is actually listening @@ -142,6 +191,10 @@ def mutelist(self): return self.db.mute_list or [] + @property + def banlist(self): + return self.db.ban_list or [] + @property def wholist(self): subs = self.subscriptions.all() @@ -170,6 +223,10 @@ **kwargs (dict): Arbitrary, optional arguments for users overriding the call (unused by default). + Returns: + bool: True if muting was successful, False if we were already + muted. + """ mutelist = self.mutelist if subscriber not in mutelist: @@ -180,19 +237,67 @@
        [docs] def unmute(self, subscriber, **kwargs): """ - Removes an entity to the list of muted subscribers. A muted subscriber will no longer see channel messages, - but may use channel commands. + Removes an entity from the list of muted subscribers. A muted subscriber + will no longer see channel messages, but may use channel commands. Args: subscriber (Object or Account): The subscriber to unmute. **kwargs (dict): Arbitrary, optional arguments for users overriding the call (unused by default). + Returns: + bool: True if unmuting was successful, False if we were already + unmuted. + """ mutelist = self.mutelist if subscriber in mutelist: mutelist.remove(subscriber) - self.db.mute_list = mutelist + return True + return False
        + +
        [docs] def ban(self, target, **kwargs): + """ + Ban a given user from connecting to the channel. This will not stop + users already connected, so the user must be booted for this to take + effect. + + Args: + target (Object or Account): The entity to unmute. This need not + be a subscriber. + **kwargs (dict): Arbitrary, optional arguments for users + overriding the call (unused by default). + + Returns: + bool: True if banning was successful, False if target was already + banned. + """ + banlist = self.banlist + if target not in banlist: + banlist.append(target) + self.db.ban_list = banlist + return True + return False
        + +
        [docs] def unban(self, target, **kwargs): + """ + Un-Ban a given user. This will not reconnect them - they will still + have to reconnect and set up aliases anew. + + Args: + target (Object or Account): The entity to unmute. This need not + be a subscriber. + **kwargs (dict): Arbitrary, optional arguments for users + overriding the call (unused by default). + + Returns: + bool: True if unbanning was successful, False if target was not + previously banned. + """ + banlist = list(self.banlist) + if target in banlist: + banlist = [banned for banned in banlist if banned != target] + self.db.ban_list = banlist return True return False
        @@ -212,7 +317,7 @@ """ # check access - if not self.access(subscriber, "listen"): + if subscriber in self.banlist or not self.access(subscriber, "listen"): return False # pre-join hook connect = self.pre_join_channel(subscriber) @@ -285,7 +390,7 @@ )
        [docs] @classmethod - def create(cls, key, account=None, *args, **kwargs): + def create(cls, key, creator=None, *args, **kwargs): """ Creates a basic Channel with default parameters, unless otherwise specified or extended. @@ -294,7 +399,8 @@ Args: key (str): This must be unique. - account (Account): Account to attribute this object to. + creator (Account or Object): Entity to associate with this channel + (used for tracking) Keyword Args: aliases (list of str): List of alternative (likely shorter) keynames. @@ -322,8 +428,8 @@ # Record creator id and creation IP if ip: obj.db.creator_ip = ip - if account: - obj.db.creator_id = account.id + if creator: + obj.db.creator_id = creator.id except Exception as exc: errors.append("An error occurred while creating this '%s' object." % key) @@ -333,284 +439,189 @@
        [docs] def delete(self): """ - Deletes channel while also cleaning up channelhandler. + Deletes channel. """ self.attributes.clear() self.aliases.clear() - super().delete() - from evennia.comms.channelhandler import CHANNELHANDLER + for subscriber in self.subscriptions.all(): + self.disconnect(subscriber) + super().delete()
        - CHANNELHANDLER.update()
        - -
        [docs] def message_transform( - self, msgobj, emit=False, prefix=True, sender_strings=None, external=False, **kwargs - ): - """ - Generates the formatted string sent to listeners on a channel. - - Args: - msgobj (Msg): Message object to send. - emit (bool, optional): In emit mode the message is not associated - with a specific sender name. - prefix (bool, optional): Prefix `msg` with a text given by `self.channel_prefix`. - sender_strings (list, optional): Used by bots etc, one string per external sender. - external (bool, optional): If this is an external sender or not. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - """ - if sender_strings or external: - body = self.format_external(msgobj, sender_strings, emit=emit) - else: - body = self.format_message(msgobj, emit=emit) - if prefix: - body = "%s%s" % (self.channel_prefix(msgobj, emit=emit), body) - msgobj.message = body - return msgobj
        - -
        [docs] def distribute_message(self, msgobj, online=False, **kwargs): - """ - Method for grabbing all listeners that a message should be - sent to on this channel, and sending them a message. - - Args: - msgobj (Msg or TempMsg): Message to distribute. - online (bool): Only send to receivers who are actually online - (not currently used): - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Notes: - This is also where logging happens, if enabled. - - """ - # get all accounts or objects connected to this channel and send to them - if online: - subs = self.subscriptions.online() - else: - subs = self.subscriptions.all() - for entity in subs: - # if the entity is muted, we don't send them a message - if entity in self.mutelist: - continue - try: - # note our addition of the from_channel keyword here. This could be checked - # by a custom account.msg() to treat channel-receives differently. - entity.msg( - msgobj.message, from_obj=msgobj.senders, options={"from_channel": self.id} - ) - except AttributeError as e: - logger.log_trace("%s\nCannot send msg to '%s'." % (e, entity)) - - if msgobj.keep_log: - # log to file - logger.log_file( - msgobj.message, self.attributes.get("log_file") or "channel_%s.log" % self.key - )
        - -
        [docs] def msg( - self, - msgobj, - header=None, - senders=None, - sender_strings=None, - keep_log=None, - online=False, - emit=False, - external=False, - ): - """ - Send the given message to all accounts connected to channel. Note that - no permission-checking is done here; it is assumed to have been - done before calling this method. The optional keywords are not used if - persistent is False. - - Args: - msgobj (Msg, TempMsg or str): If a Msg/TempMsg, the remaining - keywords will be ignored (since the Msg/TempMsg object already - has all the data). If a string, this will either be sent as-is - (if persistent=False) or it will be used together with `header` - and `senders` keywords to create a Msg instance on the fly. - header (str, optional): A header for building the message. - senders (Object, Account or list, optional): Optional if persistent=False, used - to build senders for the message. - sender_strings (list, optional): Name strings of senders. Used for external - connections where the sender is not an account or object. - When this is defined, external will be assumed. The list will be - filtered so each sender-string only occurs once. - keep_log (bool or None, optional): This allows to temporarily change the logging status of - this channel message. If `None`, the Channel's `keep_log` Attribute will - be used. If `True` or `False`, that logging status will be used for this - message only (note that for unlogged channels, a `True` value here will - create a new log file only for this message). - online (bool, optional) - If this is set true, only messages people who are - online. Otherwise, messages all accounts connected. This can - make things faster, but may not trigger listeners on accounts - that are offline. - emit (bool, optional) - Signals to the message formatter that this message is - not to be directly associated with a name. - external (bool, optional): Treat this message as being - agnostic of its sender. - - Returns: - success (bool): Returns `True` if message sending was - successful, `False` otherwise. - - """ - senders = make_iter(senders) if senders else [] - if isinstance(msgobj, str): - # given msgobj is a string - convert to msgobject (always TempMsg) - msgobj = TempMsg(senders=senders, header=header, message=msgobj, channels=[self]) - # we store the logging setting for use in distribute_message() - msgobj.keep_log = keep_log if keep_log is not None else self.db.keep_log - - # start the sending - msgobj = self.pre_send_message(msgobj) - if not msgobj: - return False - if sender_strings: - sender_strings = list(set(make_iter(sender_strings))) - msgobj = self.message_transform( - msgobj, emit=emit, sender_strings=sender_strings, external=external - ) - self.distribute_message(msgobj, online=online) - self.post_send_message(msgobj) - return True
        - -
        [docs] def tempmsg(self, message, header=None, senders=None): - """ - A wrapper for sending non-persistent messages. - - Args: - message (str): Message to send. - header (str, optional): Header of message to send. - senders (Object or list, optional): Senders of message to send. - - """ - self.msg(message, senders=senders, header=header, keep_log=False)
        - - # hooks - -
        [docs] def channel_prefix(self, msg=None, emit=False, **kwargs): +
        [docs] def channel_prefix(self): """ Hook method. How the channel should prefix itself for users. - Args: - msg (str, optional): Prefix text - emit (bool, optional): Switches to emit mode, which usually - means to not prefix the channel's info. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - Returns: - prefix (str): The created channel prefix. + str: The channel prefix. """ - return "" if emit else "[%s] " % self.key
        + return self.channel_prefix_string.format(channelname=self.key)
        -
        [docs] def format_senders(self, senders=None, **kwargs): +
        [docs] def add_user_channel_alias(self, user, alias, **kwargs): """ - Hook method. Function used to format a list of sender names. + Add a personal user-alias for this channel to a given subscriber. Args: - senders (list): Sender object names. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). + user (Object or Account): The one to alias this channel. + alias (str): The desired alias. - Returns: - formatted_list (str): The list of names formatted appropriately. + Note: + This is tightly coupled to the default `channel` command. If you + change that, you need to change this as well. + + We add two nicks - one is a plain `alias -> channel.key` that + users need to be able to reference this channel easily. The other + is a templated nick to easily be able to send messages to the + channel without needing to give the full `channel` command. The + structure of this nick is given by `self.channel_msg_nick_pattern` + and `self.channel_msg_nick_replacement`. By default it maps + `alias <msg> -> channel <channelname> = <msg>`, so that you can + for example just write `pub Hello` to send a message. + + The alias created is `alias $1 -> channel channel = $1`, to allow + for sending to channel using the main channel command. + + """ + chan_key = self.key.lower() + + # the message-pattern allows us to type the channel on its own without + # needing to use the `channel` command explicitly. + msg_nick_pattern = self.channel_msg_nick_pattern.format(alias=alias) + msg_nick_replacement = self.channel_msg_nick_replacement.format(channelname=chan_key) + user.nicks.add(msg_nick_pattern, msg_nick_replacement, category="inputline", + pattern_is_regex=True, **kwargs) + + if chan_key != alias: + # this allows for using the alias for general channel lookups + user.nicks.add(alias, chan_key, category="channel", **kwargs)
        + +
        [docs] @classmethod + def remove_user_channel_alias(cls, user, alias, **kwargs): + """ + Remove a personal channel alias from a user. + + Args: + user (Object or Account): The user to remove an alias from. + alias (str): The alias to remove. + **kwargs: Unused by default. Can be used to pass extra variables + into a custom implementation. Notes: - This function exists separately so that external sources - can use it to format source names in the same manner as - normal object/account names. + The channel-alias actually consists of two aliases - one + channel-based one for searching channels with the alias and one + inputline one for doing the 'channelalias msg' - call. + + This is a classmethod because it doesn't actually operate on the + channel instance. + + It sits on the channel because the nick structure for this is + pretty complex and needs to be located in a central place (rather + on, say, the channel command). """ - if not senders: - return "" - return ", ".join(senders)
        + user.nicks.remove(alias, category="channel", **kwargs) + msg_nick_pattern = cls.channel_msg_nick_pattern.format(alias=alias) + user.nicks.remove(msg_nick_pattern, category="inputline", **kwargs)
        -
        [docs] def pose_transform(self, msgobj, sender_string, **kwargs): +
        [docs] def at_pre_msg(self, message, **kwargs): """ - Hook method. Detects if the sender is posing, and modifies the - message accordingly. + Called before the starting of sending the message to a receiver. This + is called before any hooks on the receiver itself. If this returns + None/False, the sending will be aborted. Args: - msgobj (Msg or TempMsg): The message to analyze for a pose. - sender_string (str): The name of the sender/poser. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). + message (str): The message to send. + **kwargs (any): Keywords passed on from `.msg`. This includes + `senders`. Returns: - string (str): A message that combines the `sender_string` - component with `msg` in different ways depending on if a - pose was performed or not (this must be analyzed by the - hook). + str, False or None: Any custom changes made to the message. If + falsy, no message will be sent. """ - pose = False - message = msgobj.message - message_start = message.lstrip() - if message_start.startswith((":", ";")): - pose = True - message = message[1:] - if not message.startswith((":", "'", ",")): - if not message.startswith(" "): - message = " " + message - if pose: - return "%s%s" % (sender_string, message) + return message
        + +
        [docs] def msg(self, message, senders=None, bypass_mute=False, **kwargs): + """ + Send message to channel, causing it to be distributed to all non-muted + subscribed users of that channel. + + Args: + message (str): The message to send. + senders (Object, Account or list, optional): If not given, there is + no way to associate one or more senders with the message (like + a broadcast message or similar). + bypass_mute (bool, optional): If set, always send, regardless of + individual mute-state of subscriber. This can be used for + global announcements or warnings/alerts. + **kwargs (any): This will be passed on to all hooks. Use `no_prefix` + to exclude the channel prefix. + + Notes: + The call hook calling sequence is: + + - `msg = channel.at_pre_msg(message, **kwargs)` (aborts for all if return None) + - `msg = receiver.at_pre_channel_msg(msg, channel, **kwargs)` (aborts for receiver if return None) + - `receiver.at_channel_msg(msg, channel, **kwargs)` + - `receiver.at_post_channel_msg(msg, channel, **kwargs)`` + Called after all receivers are processed: + - `channel.at_post_all_msg(message, **kwargs)` + + (where the senders/bypass_mute are embedded into **kwargs for + later access in hooks) + + """ + senders = make_iter(senders) if senders else [] + if self.send_to_online_only: + receivers = self.subscriptions.online() else: - return "%s: %s" % (sender_string, message)
        + receivers = self.subscriptions.all() + if not bypass_mute: + receivers = [receiver for receiver in receivers if receiver not in self.mutelist] -
        [docs] def format_external(self, msgobj, senders, emit=False, **kwargs): + send_kwargs = {'senders': senders, 'bypass_mute': bypass_mute, **kwargs} + + # pre-send hook + message = self.at_pre_msg(message, **send_kwargs) + if message in (None, False): + return + + for receiver in receivers: + # send to each individual subscriber + + try: + recv_message = receiver.at_pre_channel_msg(message, self, **send_kwargs) + if recv_message in (None, False): + return + + receiver.channel_msg(recv_message, self, **send_kwargs) + + receiver.at_post_channel_msg(recv_message, self, **send_kwargs) + + except Exception: + logger.log_trace(f"Error sending channel message to {receiver}.") + + # post-send hook + self.at_post_msg(message, **send_kwargs)
        + +
        [docs] def at_post_msg(self, message, **kwargs): """ - Hook method. Used for formatting external messages. This is - needed as a separate operation because the senders of external - messages may not be in-game objects/accounts, and so cannot - have things like custom user preferences. + This is called after sending to *all* valid recipients. It is normally + used for logging/channel history. Args: - msgobj (Msg or TempMsg): The message to send. - senders (list): Strings, one per sender. - emit (bool, optional): A sender-agnostic message or not. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Returns: - transformed (str): A formatted string. + message (str): The message sent. + **kwargs (any): Keywords passed on from `msg`, including `senders`. """ - if emit or not senders: - return msgobj.message - senders = ", ".join(senders) - return self.pose_transform(msgobj, senders)
        - -
        [docs] def format_message(self, msgobj, emit=False, **kwargs): - """ - Hook method. Formats a message body for display. - - Args: - msgobj (Msg or TempMsg): The message object to send. - emit (bool, optional): The message is agnostic of senders. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Returns: - transformed (str): The formatted message. - - """ - # We don't want to count things like external sources as senders for - # the purpose of constructing the message string. - senders = [sender for sender in msgobj.senders if hasattr(sender, "key")] - if not senders: - emit = True - if emit: - return msgobj.message - else: - senders = [sender.key for sender in msgobj.senders] - senders = ", ".join(senders) - return self.pose_transform(msgobj, senders)
        + # save channel history to log file + log_file = self.get_log_filename() + if log_file: + senders = ",".join(sender.key for sender in kwargs.get("senders", [])) + senders = f"{senders}: " if senders else "" + message = f"{senders}{message}" + logger.log_file(message, log_file)
        [docs] def pre_join_channel(self, joiner, **kwargs): """ @@ -637,8 +648,13 @@ **kwargs (dict): Arbitrary, optional arguments for users overriding the call (unused by default). + Notes: + By default this adds the needed channel nicks to the joiner. + """ - pass
        + key_and_aliases = [self.key.lower()] + [alias.lower() for alias in self.aliases.all()] + for key_or_alias in key_and_aliases: + self.add_user_channel_alias(joiner, key_or_alias, **kwargs)
        [docs] def pre_leave_channel(self, leaver, **kwargs): """ @@ -666,36 +682,12 @@ overriding the call (unused by default). """ - pass
        - -
        [docs] def pre_send_message(self, msg, **kwargs): - """ - Hook method. Runs before a message is sent to the channel and - should return the message object, after any transformations. - If the message is to be discarded, return a false value. - - Args: - msg (Msg or TempMsg): Message to send. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Returns: - result (Msg, TempMsg or bool): If False, abort send. - - """ - return msg
        - -
        [docs] def post_send_message(self, msg, **kwargs): - """ - Hook method. Run after a message is sent to the channel. - - Args: - msg (Msg or TempMsg): Message sent. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - """ - pass
        + chan_key = self.key.lower() + key_or_aliases = [self.key.lower()] + [alias.lower() for alias in self.aliases.all()] + nicktuples = leaver.nicks.get(category="channel", return_tuple=True, return_list=True) + key_or_aliases += [tup[2] for tup in nicktuples if tup[3].lower() == chan_key] + for key_or_alias in key_or_aliases: + self.remove_user_channel_alias(leaver, key_or_alias, **kwargs)
        [docs] def at_init(self): """ @@ -755,7 +747,7 @@ """ try: return reverse("%s-create" % slugify(cls._meta.verbose_name)) - except: + except Exception: return "#"
        [docs] def web_get_detail_url(self): @@ -770,8 +762,10 @@ a named view of 'channel-detail' would be referenced by this method. ex. - url(r'channels/(?P<slug>[\w\d\-]+)/$', - ChannelDetailView.as_view(), name='channel-detail') + :: + + url(r'channels/(?P<slug>[\w\d\-]+)/$', + ChannelDetailView.as_view(), name='channel-detail') If no View has been created and defined in urls.py, returns an HTML anchor. @@ -789,7 +783,7 @@ "%s-detail" % slugify(self._meta.verbose_name), kwargs={"slug": slugify(self.db_key)}, ) - except: + except Exception: return "#"
        [docs] def web_get_update_url(self): @@ -804,8 +798,10 @@ a named view of 'channel-update' would be referenced by this method. ex. - url(r'channels/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/change/$', - ChannelUpdateView.as_view(), name='channel-update') + :: + + url(r'channels/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/change/$', + ChannelUpdateView.as_view(), name='channel-update') If no View has been created and defined in urls.py, returns an HTML anchor. @@ -823,7 +819,7 @@ "%s-update" % slugify(self._meta.verbose_name), kwargs={"slug": slugify(self.db_key)}, ) - except: + except Exception: return "#"
        [docs] def web_get_delete_url(self): @@ -856,11 +852,41 @@ "%s-delete" % slugify(self._meta.verbose_name), kwargs={"slug": slugify(self.db_key)}, ) - except: + except Exception: return "#"
        # Used by Django Sites/Admin - get_absolute_url = web_get_detail_url + get_absolute_url = web_get_detail_url + + # TODO Evennia 1.0+ removed hooks. Remove in 1.1. +
        [docs] def message_transform(self, *args, **kwargs): + raise RuntimeError("Channel.message_transform is no longer used in 1.0+. " + "Use Account/Object.at_pre_channel_msg instead.")
        + +
        [docs] def distribute_message(self, msgobj, online=False, **kwargs): + raise RuntimeError("Channel.distribute_message is no longer used in 1.0+.")
        + +
        [docs] def format_senders(self, senders=None, **kwargs): + raise RuntimeError("Channel.format_senders is no longer used in 1.0+. " + "Use Account/Object.at_pre_channel_msg instead.")
        + +
        [docs] def pose_transform(self, msgobj, sender_string, **kwargs): + raise RuntimeError("Channel.pose_transform is no longer used in 1.0+. " + "Use Account/Object.at_pre_channel_msg instead.")
        + +
        [docs] def format_external(self, msgobj, senders, emit=False, **kwargs): + raise RuntimeError("Channel.format_external is no longer used in 1.0+. " + "Use Account/Object.at_pre_channel_msg instead.")
        + +
        [docs] def format_message(self, msgobj, emit=False, **kwargs): + raise RuntimeError("Channel.format_message is no longer used in 1.0+. " + "Use Account/Object.at_pre_channel_msg instead.")
        + +
        [docs] def pre_send_message(self, msg, **kwargs): + raise RuntimeError("Channel.pre_send_message was renamed to Channel.at_pre_msg.")
        + +
        [docs] def post_send_message(self, msg, **kwargs): + raise RuntimeError("Channel.post_send_message was renamed to Channel.at_post_msg.")
        @@ -898,7 +924,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -917,6 +942,7 @@ +
        develop branch
        @@ -55,6 +56,7 @@ _AccountDB = None _ObjectDB = None _ChannelDB = None +_ScriptDB = None _SESSIONS = None # error class @@ -95,6 +97,8 @@ return inp, "object" elif clsname == "ChannelDB": return inp, "channel" + elif clsname == "ScriptDB": + return inp, "script" if isinstance(inp, str): return inp, "string" elif dbref(inp): @@ -144,6 +148,14 @@ return _ChannelDB.objects.get(id=obj) logger.log_err("%s %s %s %s %s" % (objtype, inp, obj, typ, type(inp))) raise CommError() + elif objtype == "script": + if typ == "string": + return _ScriptDB.objects.get(db_key__iexact=obj) + if typ == "dbref": + return _ScriptDB.objects.get(id=obj) + logger.log_err("%s %s %s %s %s" % (objtype, inp, obj, typ, type(inp))) + raise CommError() + # an unknown return None
        @@ -199,48 +211,30 @@ except Exception: return None -
        [docs] def get_messages_by_sender(self, sender, exclude_channel_messages=False): +
        [docs] def get_messages_by_sender(self, sender): """ Get all messages sent by one entity - this could be either a account or an object Args: sender (Account or Object): The sender of the message. - exclude_channel_messages (bool, optional): Only return messages - not aimed at a channel (that is, private tells for example) Returns: - messages (list): List of matching messages + QuerySet: Matching messages. Raises: CommError: For incorrect sender types. """ obj, typ = identify_object(sender) - if exclude_channel_messages: - # explicitly exclude channel recipients - if typ == "account": - return list( - self.filter(db_sender_accounts=obj, db_receivers_channels__isnull=True).exclude( - db_hide_from_accounts=obj - ) - ) - elif typ == "object": - return list( - self.filter(db_sender_objects=obj, db_receivers_channels__isnull=True).exclude( - db_hide_from_objects=obj - ) - ) - else: - raise CommError + if typ == "account": + return self.filter(db_sender_accounts=obj).exclude(db_hide_from_accounts=obj) + elif typ == "object": + return self.filter(db_sender_objects=obj).exclude(db_hide_from_objects=obj) + elif typ == "script": + return self.filter(db_sender_scripts=obj) else: - # get everything, channel or not - if typ == "account": - return list(self.filter(db_sender_accounts=obj).exclude(db_hide_from_accounts=obj)) - elif typ == "object": - return list(self.filter(db_sender_objects=obj).exclude(db_hide_from_objects=obj)) - else: - raise CommError
        + raise CommError
        [docs] def get_messages_by_receiver(self, recipient): """ @@ -250,7 +244,7 @@ recipient (Object, Account or Channel): The recipient of the messages to search for. Returns: - messages (list): Matching messages. + Queryset: Matching messages. Raises: CommError: If the `recipient` is not of a valid type. @@ -258,34 +252,21 @@ """ obj, typ = identify_object(recipient) if typ == "account": - return list(self.filter(db_receivers_accounts=obj).exclude(db_hide_from_accounts=obj)) + return self.filter(db_receivers_accounts=obj).exclude(db_hide_from_accounts=obj) elif typ == "object": - return list(self.filter(db_receivers_objects=obj).exclude(db_hide_from_objects=obj)) - elif typ == "channel": - return list(self.filter(db_receivers_channels=obj).exclude(db_hide_from_channels=obj)) + return self.filter(db_receivers_objects=obj).exclude(db_hide_from_objects=obj) + elif typ == 'script': + return self.filter(db_receivers_scripts=obj) else: raise CommError
        -
        [docs] def get_messages_by_channel(self, channel): - """ - Get all persistent messages sent to one channel. - - Args: - channel (Channel): The channel to find messages for. - - Returns: - messages (list): Persistent Msg objects saved for this channel. - - """ - return self.filter(db_receivers_channels=channel).exclude(db_hide_from_channels=channel)
        -
        [docs] def search_message(self, sender=None, receiver=None, freetext=None, dbref=None): """ Search the message database for particular messages. At least one of the arguments must be given to do a search. Args: - sender (Object or Account, optional): Get messages sent by a particular account or object + sender (Object, Account or Script, optional): Get messages sent by a particular sender. receiver (Object, Account or Channel, optional): Get messages received by a certain account,object or channel freetext (str): Search for a text string in a message. NOTE: @@ -296,40 +277,45 @@ always gives only one match. Returns: - messages (list or Msg): A list of message matches or a single match if `dbref` was given. + Queryset: Message matches. """ # unique msg id if dbref: - msg = self.objects.filter(id=dbref) - if msg: - return msg[0] + return self.objects.filter(id=dbref) # We use Q objects to gradually build up the query - this way we only # need to do one database lookup at the end rather than gradually # refining with multiple filter:s. Django Note: Q objects can be # combined with & and | (=AND,OR). ~ negates the queryset - # filter by sender + # filter by sender (we need __pk to avoid an error with empty Q() objects) sender, styp = identify_object(sender) + if sender: + spk = sender.pk if styp == "account": - sender_restrict = Q(db_sender_accounts=sender) & ~Q(db_hide_from_accounts=sender) + sender_restrict = Q(db_sender_accounts__pk=spk) & ~Q(db_hide_from_accounts__pk=spk) elif styp == "object": - sender_restrict = Q(db_sender_objects=sender) & ~Q(db_hide_from_objects=sender) + sender_restrict = Q(db_sender_objects__pk=spk) & ~Q(db_hide_from_objects__pk=spk) + elif styp == 'script': + sender_restrict = Q(db_sender_scripts__pk=spk) else: sender_restrict = Q() # filter by receiver receiver, rtyp = identify_object(receiver) + if receiver: + rpk = receiver.pk if rtyp == "account": - receiver_restrict = Q(db_receivers_accounts=receiver) & ~Q( - db_hide_from_accounts=receiver - ) + receiver_restrict = ( + Q(db_receivers_accounts__pk=rpk) & ~Q(db_hide_from_accounts__pk=rpk)) elif rtyp == "object": - receiver_restrict = Q(db_receivers_objects=receiver) & ~Q(db_hide_from_objects=receiver) + receiver_restrict = Q(db_receivers_objects__pk=rpk) & ~Q(db_hide_from_objects__pk=rpk) + elif rtyp == 'script': + receiver_restrict = Q(db_receivers_scripts__pk=rpk) elif rtyp == "channel": - receiver_restrict = Q(db_receivers_channels=receiver) & ~Q( - db_hide_from_channels=receiver - ) + raise DeprecationWarning( + "Msg.objects.search don't accept channel recipients since " + "Channels no longer accepts Msg objects.") else: receiver_restrict = Q() # filter by full text @@ -338,7 +324,7 @@ else: fulltext_restrict = Q() # execute the query - return list(self.filter(sender_restrict & receiver_restrict & fulltext_restrict))
        + return self.filter(sender_restrict & receiver_restrict & fulltext_restrict) # back-compatibility alias message_search = search_message @@ -491,7 +477,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -510,6 +495,7 @@ +
        develop branch
        @@ -57,6 +58,7 @@ Channels are central objects that act as targets for Msgs. Accounts can connect to channels by use of a ChannelConnect object (this object is necessary to easily be able to delete connections on the fly). + """ from django.conf import settings from django.utils import timezone @@ -75,8 +77,6 @@ _SA = object.__setattr__ _DA = object.__delattr__ -_CHANNELHANDLER = None - # ------------------------------------------------------------ # @@ -96,17 +96,16 @@ - db_sender_accounts: Account senders - db_sender_objects: Object senders - db_sender_scripts: Script senders - - db_sender_external: External senders (defined as string names) + - db_sender_external: External sender (defined as string name) - db_receivers_accounts: Receiving accounts - db_receivers_objects: Receiving objects - db_receivers_scripts: Receiveing scripts - - db_receivers_channels: Receiving channels + - db_receiver_external: External sender (defined as string name) - db_header: Header text - db_message: The actual message text - db_date_created: time message was created / sent - db_hide_from_sender: bool if message should be hidden from sender - db_hide_from_receivers: list of receiver objects to hide message from - - db_hide_from_channels: list of channels objects to hide message from - db_lock_storage: Internal storage of lock strings. """ @@ -118,14 +117,11 @@ # These databse fields are all set using their corresponding properties, # named same as the field, but withtout the db_* prefix. - # Sender is either an account, an object or an external sender, like - # an IRC channel; normally there is only one, but if co-modification of - # a message is allowed, there may be more than one "author" db_sender_accounts = models.ManyToManyField( "accounts.AccountDB", related_name="sender_account_set", blank=True, - verbose_name="sender(account)", + verbose_name="Senders (Accounts)", db_index=True, ) @@ -133,14 +129,14 @@ "objects.ObjectDB", related_name="sender_object_set", blank=True, - verbose_name="sender(object)", + verbose_name="Senders (Objects)", db_index=True, ) db_sender_scripts = models.ManyToManyField( "scripts.ScriptDB", related_name="sender_script_set", blank=True, - verbose_name="sender(script)", + verbose_name="Senders (Scripts)", db_index=True, ) db_sender_external = models.CharField( @@ -149,16 +145,15 @@ null=True, blank=True, db_index=True, - help_text="identifier for external sender, for example a sender over an " - "IRC connection (i.e. someone who doesn't have an exixtence in-game).", + help_text="Identifier for single external sender, for use with senders " + "not represented by a regular database model." ) - # The destination objects of this message. Stored as a - # comma-separated string of object dbrefs. Can be defined along - # with channels below. + db_receivers_accounts = models.ManyToManyField( "accounts.AccountDB", related_name="receiver_account_set", blank=True, + verbose_name="Receivers (Accounts)", help_text="account receivers", ) @@ -166,16 +161,25 @@ "objects.ObjectDB", related_name="receiver_object_set", blank=True, + verbose_name="Receivers (Objects)", help_text="object receivers", ) db_receivers_scripts = models.ManyToManyField( "scripts.ScriptDB", related_name="receiver_script_set", blank=True, + verbose_name="Receivers (Scripts)", help_text="script_receivers", ) - db_receivers_channels = models.ManyToManyField( - "ChannelDB", related_name="channel_set", blank=True, help_text="channel recievers" + + db_receiver_external = models.CharField( + "external receiver", + max_length=1024, + null=True, + blank=True, + db_index=True, + help_text="Identifier for single external receiver, for use with recievers " + "not represented by a regular database model." ) # header could be used for meta-info about the message if your system needs @@ -192,7 +196,7 @@ "locks", blank=True, help_text="access locks on this message." ) - # these can be used to filter/hide a given message from supplied objects/accounts/channels + # these can be used to filter/hide a given message from supplied objects/accounts db_hide_from_accounts = models.ManyToManyField( "accounts.AccountDB", related_name="hide_from_accounts_set", blank=True ) @@ -200,24 +204,18 @@ db_hide_from_objects = models.ManyToManyField( "objects.ObjectDB", related_name="hide_from_objects_set", blank=True ) - db_hide_from_channels = models.ManyToManyField( - "ChannelDB", related_name="hide_from_channels_set", blank=True - ) db_tags = models.ManyToManyField( Tag, blank=True, - help_text="tags on this message. Tags are simple string markers to identify, group and alias messages.", + help_text="tags on this message. Tags are simple string markers to " + "identify, group and alias messages.", ) # Database manager objects = managers.MsgManager() _is_deleted = False -
        [docs] def __init__(self, *args, **kwargs): - SharedMemoryModel.__init__(self, *args, **kwargs) - self.extra_senders = []
        - class Meta(object): "Define Django meta options" verbose_name = "Msg" @@ -238,28 +236,28 @@ # value = self.attr and del self.attr respectively (where self # is the object in question). - # sender property (wraps db_sender_*) - # @property - def __senders_get(self): - "Getter. Allows for value = self.sender" + @property + def senders(self): + "Getter. Allows for value = self.senders" return ( list(self.db_sender_accounts.all()) + list(self.db_sender_objects.all()) + list(self.db_sender_scripts.all()) - + self.extra_senders + + ([self.db_sender_external] if self.db_sender_external else []) ) - # @sender.setter - def __senders_set(self, senders): + @senders.setter + def senders(self, senders): "Setter. Allows for self.sender = value" + + if isinstance(senders, str): + self.db_sender_external = senders + self.save(update_fields=["db_sender_external"]) + return + for sender in make_iter(senders): if not sender: continue - if isinstance(sender, str): - self.db_sender_external = sender - self.extra_senders.append(sender) - self.save(update_fields=["db_sender_external"]) - continue if not hasattr(sender, "__dbclass__"): raise ValueError("This is a not a typeclassed object!") clsname = sender.__dbclass__.__name__ @@ -270,32 +268,32 @@ elif clsname == "ScriptDB": self.db_sender_scripts.add(sender) - # @sender.deleter - def __senders_del(self): + @senders.deleter + def senders(self): "Deleter. Clears all senders" self.db_sender_accounts.clear() self.db_sender_objects.clear() self.db_sender_scripts.clear() self.db_sender_external = "" - self.extra_senders = [] self.save() - senders = property(__senders_get, __senders_set, __senders_del) -
        [docs] def remove_sender(self, senders): """ Remove a single sender or a list of senders. Args: senders (Account, Object, str or list): Senders to remove. + If a string, removes the external sender. """ + if isinstance(senders, str): + self.db_sender_external = "" + self.save(update_fields=["db_sender_external"]) + return + for sender in make_iter(senders): if not sender: continue - if isinstance(sender, str): - self.db_sender_external = "" - self.save(update_fields=["db_sender_external"]) if not hasattr(sender, "__dbclass__"): raise ValueError("This is a not a typeclassed object!") clsname = sender.__dbclass__.__name__ @@ -306,26 +304,33 @@ elif clsname == "ScriptDB": self.db_sender_accounts.remove(sender)
        - # receivers property - # @property - def __receivers_get(self): + @property + def receivers(self): """ Getter. Allows for value = self.receivers. - Returns four lists of receivers: accounts, objects, scripts and channels. + Returns four lists of receivers: accounts, objects, scripts and + external_receivers. + """ return ( list(self.db_receivers_accounts.all()) + list(self.db_receivers_objects.all()) + list(self.db_receivers_scripts.all()) - + list(self.db_receivers_channels.all()) + + ([self.db_receiver_external] if self.db_receiver_external else []) ) - # @receivers.setter - def __receivers_set(self, receivers): + @receivers.setter + def receivers(self, receivers): """ - Setter. Allows for self.receivers = value. - This appends a new receiver to the message. + Setter. Allows for self.receivers = value. This appends a new receiver + to the message. If a string, replaces an external receiver. + """ + if isinstance(receivers, str): + self.db_receiver_external = receivers + self.save(update_fields=['db_receiver_external']) + return + for receiver in make_iter(receivers): if not receiver: continue @@ -338,32 +343,34 @@ self.db_receivers_accounts.add(receiver) elif clsname == "ScriptDB": self.db_receivers_scripts.add(receiver) - elif clsname == "ChannelDB": - self.db_receivers_channels.add(receiver) - # @receivers.deleter - def __receivers_del(self): + @receivers.deleter + def receivers(self): "Deleter. Clears all receivers" self.db_receivers_accounts.clear() self.db_receivers_objects.clear() self.db_receivers_scripts.clear() - self.db_receivers_channels.clear() + self.db_receiver_external = "" self.save() - receivers = property(__receivers_get, __receivers_set, __receivers_del) -
        [docs] def remove_receiver(self, receivers): """ - Remove a single receiver or a list of receivers. + Remove a single receiver, a list of receivers, or a single extral receiver. Args: - receivers (Account, Object, Script, Channel or list): Receiver to remove. + receivers (Account, Object, Script, list or str): Receiver + to remove. A string removes the external receiver. """ + if isinstance(receivers, str): + self.db_receiver_external = "" + self.save(update_fields="db_receiver_external") + return + for receiver in make_iter(receivers): if not receiver: continue - if not hasattr(receiver, "__dbclass__"): + elif not hasattr(receiver, "__dbclass__"): raise ValueError("This is a not a typeclassed object!") clsname = receiver.__dbclass__.__name__ if clsname == "ObjectDB": @@ -371,47 +378,26 @@ elif clsname == "AccountDB": self.db_receivers_accounts.remove(receiver) elif clsname == "ScriptDB": - self.db_receivers_scripts.remove(receiver) - elif clsname == "ChannelDB": - self.db_receivers_channels.remove(receiver)
        + self.db_receivers_scripts.remove(receiver)
        - # channels property - # @property - def __channels_get(self): - "Getter. Allows for value = self.channels. Returns a list of channels." - return self.db_receivers_channels.all() - - # @channels.setter - def __channels_set(self, value): - """ - Setter. Allows for self.channels = value. - Requires a channel to be added. - """ - for val in (v for v in make_iter(value) if v): - self.db_receivers_channels.add(val) - - # @channels.deleter - def __channels_del(self): - "Deleter. Allows for del self.channels" - self.db_receivers_channels.clear() - self.save() - - channels = property(__channels_get, __channels_set, __channels_del) - - def __hide_from_get(self): + @property + def hide_from(self): """ Getter. Allows for value = self.hide_from. - Returns 3 lists of accounts, objects and channels + Returns two lists of accounts and objects. + """ return ( self.db_hide_from_accounts.all(), self.db_hide_from_objects.all(), - self.db_hide_from_channels.all(), ) - # @hide_from_sender.setter - def __hide_from_set(self, hiders): - "Setter. Allows for self.hide_from = value. Will append to hiders" + @hide_from.setter + def hide_from(self, hiders): + """ + Setter. Allows for self.hide_from = value. Will append to hiders. + + """ for hider in make_iter(hiders): if not hider: continue @@ -422,31 +408,28 @@ self.db_hide_from_accounts.add(hider.__dbclass__) elif clsname == "ObjectDB": self.db_hide_from_objects.add(hider.__dbclass__) - elif clsname == "ChannelDB": - self.db_hide_from_channels.add(hider.__dbclass__) - # @hide_from_sender.deleter - def __hide_from_del(self): - "Deleter. Allows for del self.hide_from_senders" + @hide_from.deleter + def hide_from(self): + """ + Deleter. Allows for del self.hide_from_senders + + """ self.db_hide_from_accounts.clear() self.db_hide_from_objects.clear() - self.db_hide_from_channels.clear() self.save() - hide_from = property(__hide_from_get, __hide_from_set, __hide_from_del) - # # Msg class methods # def __str__(self): - "This handles what is shown when e.g. printing the message" - senders = ",".join(getattr(obj, "key", str(obj)) for obj in self.senders) + """ + This handles what is shown when e.g. printing the message. - receivers = ",".join( - ["[%s]" % getattr(obj, "key", str(obj)) for obj in self.channels] - + [getattr(obj, "key", str(obj)) for obj in self.receivers] - ) + """ + senders = ",".join(getattr(obj, "key", str(obj)) for obj in self.senders) + receivers = ",".join(getattr(obj, "key", str(obj)) for obj in self.receivers) return "%s->%s: %s" % (senders, receivers, crop(self.message, width=40))
        [docs] def access(self, accessing_obj, access_type="read", default=False): @@ -474,9 +457,8 @@
        [docs]class TempMsg(object): """ - This is a non-persistent object for sending temporary messages - that will not be stored. It mimics the "real" Msg object, but - doesn't require sender to be given. + This is a non-persistent object for sending temporary messages that will not be stored. It + mimics the "real" Msg object, but doesn't require sender to be given. """ @@ -484,7 +466,6 @@ self, senders=None, receivers=None, - channels=None, message="", header="", type="", @@ -496,18 +477,16 @@ Args: senders (any or list, optional): Senders of the message. - receivers (Account, Object, Channel or list, optional): Receivers of this message. - channels (Channel or list, optional): Channels to send to. + receivers (Account, Object, Script or list, optional): Receivers of this message. message (str, optional): Message to send. header (str, optional): Header of message. type (str, optional): Message class, if any. lockstring (str, optional): Lock for the message. - hide_from (Account, Object, Channel or list, optional): Entities to hide this message from. + hide_from (Account, Object, or list, optional): Entities to hide this message from. """ self.senders = senders and make_iter(senders) or [] self.receivers = receivers and make_iter(receivers) or [] - self.channels = channels and make_iter(channels) or [] self.type = type self.header = header self.message = message @@ -522,11 +501,10 @@ def __str__(self): """ This handles what is shown when e.g. printing the message. + """ senders = ",".join(obj.key for obj in self.senders) - receivers = ",".join( - ["[%s]" % obj.key for obj in self.channels] + [obj.key for obj in self.receivers] - ) + receivers = ",".join(obj.key for obj in self.receivers) return "%s->%s: %s" % (senders, receivers, crop(self.message, width=40))
        [docs] def remove_sender(self, sender): @@ -548,7 +526,8 @@ Remove a receiver or a list of receivers Args: - receiver (Object, Account, Channel, str or list): Receivers to remove. + receiver (Object, Account, Script, str or list): Receivers to remove. + """ for o in make_iter(receiver): @@ -585,6 +564,7 @@ This handler manages subscriptions to the channel and hides away which type of entity is subscribing (Account or Object) + """ def __init__(self, obj): @@ -644,9 +624,6 @@ no hooks will be called. """ - global _CHANNELHANDLER - if not _CHANNELHANDLER: - from evennia.comms.channelhandler import CHANNEL_HANDLER as _CHANNELHANDLER for subscriber in make_iter(entity): if subscriber: clsname = subscriber.__dbclass__.__name__ @@ -655,7 +632,6 @@ self.obj.db_object_subscriptions.add(subscriber) elif clsname == "AccountDB": self.obj.db_account_subscriptions.add(subscriber) - _CHANNELHANDLER._cached_cmdsets.pop(subscriber, None) self._recache() def remove(self, entity): @@ -667,9 +643,6 @@ entities to un-subscribe from the channel. """ - global _CHANNELHANDLER - if not _CHANNELHANDLER: - from evennia.comms.channelhandler import CHANNEL_HANDLER as _CHANNELHANDLER for subscriber in make_iter(entity): if subscriber: clsname = subscriber.__dbclass__.__name__ @@ -678,7 +651,6 @@ self.obj.db_account_subscriptions.remove(entity) elif clsname == "ObjectDB": self.obj.db_object_subscriptions.remove(entity) - _CHANNELHANDLER._cached_cmdsets.pop(subscriber, None) self._recache() def all(self): @@ -714,7 +686,8 @@ if not obj.is_connected: continue except ObjectDoesNotExist: - # a subscribed object has already been deleted. Mark that we need a recache and ignore it + # a subscribed object has already been deleted. Mark that we need a recache and + # ignore it recache_needed = True continue subs.append(obj) @@ -768,7 +741,7 @@ __defaultclasspath__ = "evennia.comms.comms.DefaultChannel" __applabel__ = "comms" - class Meta(object): + class Meta: "Define Django meta options" verbose_name = "Channel" verbose_name_plural = "Channels" @@ -817,7 +790,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -836,6 +808,7 @@ +
        develop branch
        @@ -973,7 +974,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -992,6 +992,7 @@ +
        develop branch
        @@ -1343,7 +1344,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1362,6 +1362,7 @@ +
        develop branch
        @@ -270,7 +271,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -289,6 +289,7 @@ +
        develop branch
        @@ -820,7 +821,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -839,6 +839,7 @@ +
        develop branch
        @@ -385,7 +386,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -404,6 +404,7 @@ +
        develop branch
        @@ -338,7 +339,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -357,6 +357,7 @@ +
        develop branch
        @@ -439,7 +440,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -458,6 +458,7 @@ +
        develop branch
        @@ -857,7 +858,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -876,6 +876,7 @@ +
        develop branch
        @@ -430,7 +431,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -449,6 +449,7 @@ +
        develop branch
        @@ -1157,7 +1158,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1176,6 +1176,7 @@ +
        develop branch
        @@ -316,7 +317,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -335,6 +335,7 @@ +
        develop branch
        @@ -384,7 +385,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -403,6 +403,7 @@ +
        develop branch
        @@ -215,12 +216,11 @@ self.call(commands.CmdSpeak(), "", "What do you want to say?", cmdstring="") self.call(commands.CmdSpeak(), "Hello!", "You say: Hello!", cmdstring="") self.call(commands.CmdSpeak(), "", "What do you want to whisper?", cmdstring="whisper") - self.call(commands.CmdSpeak(), "Hi.", "You whisper: Hi.", cmdstring="whisper") - self.call(commands.CmdSpeak(), "Hi.", "You whisper: Hi.", cmdstring="whisper") + self.call(commands.CmdSpeak(), "Hi.", "You whisper: (Hi.)", cmdstring="whisper") self.call(commands.CmdSpeak(), "HELLO!", "You shout: HELLO!", cmdstring="shout") - self.call(commands.CmdSpeak(), "Hello to obj", "You say: Hello", cmdstring="say") - self.call(commands.CmdSpeak(), "Hello to obj", "You shout: Hello", cmdstring="shout")
        + self.call(commands.CmdSpeak(), "Hello", "You say: Hello", cmdstring="say") + self.call(commands.CmdSpeak(), "Hello", "You shout: HELLO", cmdstring="shout")
        [docs] def test_emote(self): self.call( @@ -313,7 +313,7 @@ dirname = path.join(path.dirname(__file__), "states") states = [] for imp, module, ispackage in pkgutil.walk_packages( - path=[dirname], prefix="evscaperoom.states." + path=[dirname], prefix="evennia.contrib.evscaperoom.states." ): mod = mod_import(module) states.append(mod) @@ -382,7 +382,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -401,6 +400,7 @@ +
        develop branch
        @@ -271,7 +272,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -290,6 +290,7 @@ +
        develop branch
        @@ -669,7 +670,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -688,6 +688,7 @@ +
        develop branch
        @@ -792,7 +793,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -811,6 +811,7 @@ +
        develop branch
        @@ -233,7 +234,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -252,6 +252,7 @@ +
        develop branch
        @@ -196,7 +197,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -215,6 +215,7 @@ +
        develop branch
        @@ -301,7 +302,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -320,6 +320,7 @@ +
        develop branch
        @@ -659,7 +660,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -678,6 +678,7 @@ +
        develop branch
        @@ -167,7 +168,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -186,6 +186,7 @@ +
        develop branch
        @@ -87,9 +88,10 @@ self.db.locked = [] # Tasks - self.db.tasks = {}
        + self.db.tasks = {} + self.at_server_start() -
        [docs] def at_start(self): +
        [docs] def at_server_start(self): """Set up the event system when starting. Note that this hook is called every time the server restarts @@ -744,7 +746,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -763,6 +764,7 @@ +
        develop branch
        @@ -89,7 +90,7 @@ """Stop the event handler.""" OLD_EVENTS.clear() OLD_EVENTS.update(self.handler.ndb.events) - self.handler.stop() + self.handler.delete() CallbackHandler.script = None super().tearDown()
        @@ -311,11 +312,11 @@ """Stop the callback handler.""" OLD_EVENTS.clear() OLD_EVENTS.update(self.handler.ndb.events) - self.handler.stop() + self.handler.delete() for script in ScriptDB.objects.filter( db_typeclass_path="evennia.contrib.ingame_python.scripts.TimeEventScript" ): - script.stop() + script.delete() CallbackHandler.script = None super().tearDown() @@ -490,7 +491,7 @@ """Stop the callback handler.""" OLD_EVENTS.clear() OLD_EVENTS.update(self.handler.ndb.events) - self.handler.stop() + self.handler.delete() CallbackHandler.script = None super().tearDown() @@ -619,7 +620,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -638,6 +638,7 @@ +
        develop branch
        @@ -99,7 +100,6 @@ typeclass_name = typeclass.__module__ + "." + typeclass.__name__ try: storage = ScriptDB.objects.get(db_key="event_handler") - assert storage.is_active assert storage.ndb.events is not None except (ScriptDB.DoesNotExist, AssertionError): storage = EVENTS @@ -339,7 +339,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -358,6 +357,7 @@ +
        develop branch
        @@ -435,7 +436,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -454,6 +454,7 @@ +
        develop branch
        @@ -346,7 +347,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -365,6 +365,7 @@ +
        develop branch
        @@ -890,7 +891,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -909,6 +909,7 @@ +
        develop branch
        @@ -430,7 +431,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -449,6 +449,7 @@ +
        develop branch
        @@ -101,21 +102,46 @@ Below is an example of "elvish", using "rounder" vowels and sounds: ```python - phonemes = "oi oh ee ae aa eh ah ao aw ay er ey ow ia ih iy " \ - "oy ua uh uw y p b t d f v t dh s z sh zh ch jh k " \ - "ng g m n l r w", + # vowel/consonant grammar possibilities + grammar = ("v vv vvc vcc vvcc cvvc vccv vvccv vcvccv vcvcvcc vvccvvcc " + "vcvvccvvc cvcvvcvvcc vcvcvvccvcvv") + + # all not in this group is considered a consonant vowels = "eaoiuy" - grammar = "v vv vvc vcc vvcc cvvc vccv vvccv vcvccv vcvcvcc vvccvvcc " \ - "vcvvccvvc cvcvvcvvcc vcvcvvccvcvv", + + # you need a representative of all of the minimal grammars here, so if a + # grammar v exists, there must be atleast one phoneme available with only + # one vowel in it + phonemes = ("oi oh ee ae aa eh ah ao aw ay er ey ow ia ih iy " + "oy ua uh uw y p b t d f v t dh s z sh zh ch jh k " + "ng g m n l r w") + + # how much the translation varies in length compared to the original. 0 is + # smallest, higher values give ever bigger randomness (including removing + # short words entirely) word_length_variance = 1 + + # if a proper noun (word starting with capitalized letter) should be + # translated or not. If not (default) it means e.g. names will remain + # unchanged across languages. + noun_translate = False + + # all proper nouns (words starting with a capital letter not at the beginning + # of a sentence) can have either a postfix or -prefix added at all times noun_postfix = "'la" + + # words in dict will always be translated this way. The 'auto_translations' + # is instead a list or filename to file with words to use to help build a + # bigger dictionary by creating random translations of each word in the + # list *once* and saving the result for subsequent use. manual_translations = {"the":"y'e", "we":"uyi", "she":"semi", "he":"emi", "you": "do", 'me':'mi','i':'me', 'be':"hy'e", 'and':'y'} rplanguage.add_language(key="elvish", phonemes=phonemes, grammar=grammar, word_length_variance=word_length_variance, + noun_translate=noun_translate, noun_postfix=noun_postfix, vowels=vowels, - manual_translations=manual_translations + manual_translations=manual_translations, auto_translations="my_word_file.txt") ``` @@ -158,7 +184,8 @@ _RE_FLAGS = re.MULTILINE + re.IGNORECASE + re.DOTALL + re.UNICODE _RE_GRAMMAR = re.compile(r"vv|cc|v|c", _RE_FLAGS) _RE_WORD = re.compile(r"\w+", _RE_FLAGS) -_RE_EXTRA_CHARS = re.compile(r"\s+(?=\W)|[,.?;](?=[,.?;]|\s+[,.?;])", _RE_FLAGS) +# superfluous chars, except ` ... ` +_RE_EXTRA_CHARS = re.compile(r"\s+(?!... )(?=\W)|[,.?;](?!.. )(?=[,?;]|\s+[,.?;])", _RE_FLAGS)
        [docs]class LanguageError(RuntimeError): @@ -239,9 +266,13 @@ 0 means a minimal variance, higher variance may mean words have wildly varying length; this strongly affects how the language "looks". - noun_translate (bool, optional): If a proper noun, identified as a - capitalized word, should be translated or not. By default they - will not, allowing for e.g. the names of characters to be understandable. + noun_translate (bool, optional): If a proper noun should be translated or + not. By default they will not, allowing for e.g. the names of characters + to be understandable. A 'noun' is identified as a capitalized word + *not at the start of a sentence*. This simple metric means that names + starting a sentence always will be translated (- but hey, maybe + the fantasy language just never uses a noun at the beginning of + sentences, who knows?) noun_prefix (str, optional): A prefix to go before every noun in this language (if any). noun_postfix (str, optuonal): A postfix to go after every noun @@ -286,7 +317,7 @@ # {"vv": ["ea", "oh", ...], ...} grammar2phonemes = defaultdict(list) for phoneme in phonemes.split(): - if re.search("\W", phoneme): + if re.search(r"\W", phoneme): raise LanguageError("The phoneme '%s' contains an invalid character" % phoneme) gram = "".join(["v" if char in vowels else "c" for char in phoneme]) grammar2phonemes[gram].append(phoneme) @@ -294,7 +325,7 @@ # allowed grammar are grouped by length gramdict = defaultdict(list) for gram in grammar.split(): - if re.search("\W|(!=[cv])", gram): + if re.search(r"\W|(!=[cv])", gram): raise LanguageError( "The grammar '%s' is invalid (only 'c' and 'v' are allowed)" % gram ) @@ -321,7 +352,13 @@ # use the corresponding length structure = choice(grammar[wlen]) for match in _RE_GRAMMAR.finditer(structure): - new_word += choice(grammar2phonemes[match.group()]) + try: + new_word += choice(grammar2phonemes[match.group()]) + except IndexError: + raise IndexError( + "Could not find a matching phoneme for the grammar " + f"'{match.group()}'. Make there is at least one phoneme matching this " + "combination of consonants and vowels.") translation[word.lower()] = new_word.lower() if manual_translations: @@ -360,6 +397,11 @@ word = match.group() lword = len(word) + # find out what preceeded this word + wpos = match.start() + preceeding = match.string[:wpos].strip() + start_sentence = preceeding.endswith((".", "!", "?")) or not preceeding + if len(word) <= self.level: # below level. Don't translate new_word = word @@ -369,11 +411,6 @@ if not new_word: # no dictionary translation. Generate one - # find out what preceeded this word - wpos = match.start() - preceeding = match.string[:wpos].strip() - start_sentence = preceeding.endswith((".", "!", "?")) or not preceeding - # make up translation on the fly. Length can # vary from un-translated word. wlen = max( @@ -408,24 +445,30 @@ break if word.istitle(): - title_word = "" - if not start_sentence and not self.language.get("noun_translate", False): - # don't translate what we identify as proper nouns (names) - title_word = word - elif new_word: - title_word = new_word + if not start_sentence: + # this is a noun. We miss nouns at the start of + # sentences this way, but it's as good as we can get + # with this simple analysis. Maybe the fantasy language + # just don't consider nouns at the beginning of + # sentences, who knows? + if not self.language.get("noun_translate", False): + # don't translate what we identify as proper nouns (names) + new_word = word - if title_word: - # Regardless of if we translate or not, we will add the custom prefix/postfixes - new_word = "%s%s%s" % ( - self.language["noun_prefix"], - title_word.capitalize(), - self.language["noun_postfix"], + # add noun prefix and/or postfix + new_word = "{prefix}{word}{postfix}".format( + prefix=self.language["noun_prefix"], + word=new_word.capitalize(), + postfix=self.language["noun_postfix"], ) if len(word) > 1 and word.isupper(): # keep LOUD words loud also when translated new_word = new_word.upper() + + if start_sentence: + new_word = new_word.capitalize() + return new_word
        [docs] def translate(self, text, level=0.0, language="default"): @@ -532,19 +575,18 @@ return list(_LANGUAGE_HANDLER.attributes.get("language_storage", {}))
        -# ------------------------------------------------------------ +# ----------------------------------------------------------------------------- # # Whisper obscuration # -# This obsucration table is designed by obscuring certain -# vowels first, following by consonants that tend to be -# more audible over long distances, like s. Finally it -# does non-auditory replacements, like exclamation marks -# and capitalized letters (assumed to be spoken louder) that may still -# give a user some idea of the sentence structure. Then the word -# lengths are also obfuscated and finally the whisper # length itself. +# This obsucration table is designed by obscuring certain vowels first, +# following by consonants that tend to be more audible over long distances, +# like s. Finally it does non-auditory replacements, like exclamation marks and +# capitalized letters (assumed to be spoken louder) that may still give a user +# some idea of the sentence structure. Then the word lengths are also +# obfuscated and finally the whisper length itself. # -# ------------------------------------------------------------ +# ------------------------------------------------------------------------------ _RE_WHISPER_OBSCURE = [ @@ -621,7 +663,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -640,6 +681,7 @@ +
        develop branch
        @@ -324,7 +325,8 @@ the markers and a tuple (langname, saytext), where langname can be None. Raises: - rplanguage.LanguageError: If an invalid language was specified. + evennia.contrib.rpsystem.LanguageError: If an invalid language was + specified. Notes: Note that no errors are raised if the wrong language identifier @@ -1702,7 +1704,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1721,6 +1722,7 @@ +
        develop branch
        @@ -136,7 +137,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -155,6 +155,7 @@ +
        develop branch
        @@ -325,7 +326,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -344,6 +344,7 @@ +
        develop branch
        @@ -190,7 +191,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -209,6 +209,7 @@ +
        develop branch
        @@ -248,7 +249,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -267,6 +267,7 @@ +
        develop branch
        @@ -220,7 +221,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -239,6 +239,7 @@ +
        develop branch
        @@ -209,7 +210,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -228,6 +228,7 @@ +
        develop branch
        @@ -653,7 +654,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -672,6 +672,7 @@ +
        develop branch
        @@ -221,10 +222,10 @@
        [docs]def at_defeat(defeated): """ Announces the defeat of a fighter in combat. - + Args: defeated (obj): Fighter that's been defeated. - + Notes: All this does is announce a defeat message by default, but if you want anything else to happen to defeated fighters (like putting them @@ -523,6 +524,7 @@ if disengage_check: # All characters have disengaged self.obj.msg_contents("All fighters have disengaged! Combat is over!") self.stop() # Stop this script and end combat. + self.delete() return # Check to see if only one character is left standing. If so, end combat. @@ -538,6 +540,7 @@ LastStanding = fighter # Pick the one fighter left with HP remaining self.obj.msg_contents("Only %s remains! Combat is over!" % LastStanding) self.stop() # Stop this script and end combat. + self.delete() return # Cycle to the next turn. @@ -856,7 +859,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -875,6 +877,7 @@ +
        develop branch
        @@ -1214,7 +1215,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1233,6 +1233,7 @@ +
        develop branch
        @@ -1533,7 +1534,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1552,6 +1552,7 @@ +
        develop branch
        @@ -1455,7 +1456,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1474,6 +1474,7 @@ +
        develop branch
        @@ -683,7 +684,6 @@ Args: to_init (object): Object to initialize range field for. - Keyword Args: anchor_obj (object): Object to copy range values from, or None for a random object. add_distance (int): Distance to put between to_init object and anchor object. @@ -1512,7 +1512,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1531,6 +1530,7 @@ +
        develop branch
        @@ -142,7 +143,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -161,6 +161,7 @@ +
        develop branch
        @@ -47,14 +48,381 @@ Create this button with - @create/drop examples.red_button.RedButton + create/drop red_button.RedButton Note that you must drop the button before you can see its messages! + +## Technical + +The button's functionality is controlled by CmdSets that gets added and removed +depending on the 'state' the button is in. + +- Lid-closed state: In this state the button is covered by a glass cover and trying + to 'push' it will fail. You can 'nudge', 'smash' or 'open' the lid. +- Lid-open state: In this state the lid is open but will close again after a certain + time. Using 'push' now will press the button and trigger the Blind-state. +- Blind-state: In this mode you are blinded by a bright flash. This will affect your + normal commands like 'look' and help until the blindness wears off after a certain + time. + +Timers are handled by persistent delays on the button. These are examples of +`evennia.utils.utils.delay` calls that wait a certain time before calling a method - +such as when closing the lid and un-blinding a character. + """ import random from evennia import DefaultObject -from evennia.contrib.tutorial_examples import red_button_scripts as scriptexamples -from evennia.contrib.tutorial_examples import cmdset_red_button as cmdsetexamples +from evennia import Command, CmdSet +from evennia.utils.utils import delay, repeat, interactive + + +# Commands on the button (not all awailable at the same time) + + +# Commands for the state when the lid covering the button is closed. + +
        [docs]class CmdPushLidClosed(Command): + """ + Push the red button (lid closed) + + Usage: + push button + + """ + + key = "push button" + aliases = ["push", "press button", "press"] + locks = "cmd:all()" + +
        [docs] def func(self): + """ + This is the version of push used when the lid is closed. + + An alternative would be to make a 'push' command in a default cmdset + that is always available on the button and then use if-statements to + check if the lid is open or closed. + + """ + self.caller.msg("You cannot push the button = there is a glass lid covering it.")
        + + +
        [docs]class CmdNudge(Command): + """ + Try to nudge the button's lid. + + Usage: + nudge lid + + This command will have you try to push the lid of the button away. + + """ + + key = "nudge lid" # two-word command name! + aliases = ["nudge"] + locks = "cmd:all()" + +
        [docs] def func(self): + """ + Nudge the lid. Random chance of success to open it. + + """ + rand = random.random() + if rand < 0.5: + self.caller.msg("You nudge at the lid. It seems stuck.") + elif rand < 0.7: + self.caller.msg("You move the lid back and forth. It won't budge.") + else: + self.caller.msg("You manage to get a nail under the lid.") + # self.obj is the button object + self.obj.to_open_state()
        + + +
        [docs]class CmdSmashGlass(Command): + """ + Smash the protective glass. + + Usage: + smash glass + + Try to smash the glass of the button. + + """ + + key = "smash glass" + aliases = ["smash lid", "break lid", "smash"] + locks = "cmd:all()" + +
        [docs] def func(self): + """ + The lid won't open, but there is a small chance of causing the lamp to + break. + + """ + rand = random.random() + self.caller.location.msg_contents( + f"{self.caller.name} tries to smash the glass of the button.", + exclude=self.caller) + + if rand < 0.2: + string = ("You smash your hand against the glass" + " with all your might. The lid won't budge" + " but you cause quite the tremor through the button's mount." + "\nIt looks like the button's lamp stopped working for the time being, " + "but the lid is still as closed as ever.") + # self.obj is the button itself + self.obj.break_lamp() + elif rand < 0.6: + string = "You hit the lid hard. It doesn't move an inch." + else: + string = ("You place a well-aimed fist against the glass of the lid." + " Unfortunately all you get is a pain in your hand. Maybe" + " you should just try to just ... open the lid instead?") + self.caller.msg(string)
        + + +
        [docs]class CmdOpenLid(Command): + """ + open lid + + Usage: + open lid + + """ + + key = "open lid" + aliases = ["open button"] + locks = "cmd:all()" + +
        [docs] def func(self): + "simply call the right function." + + if self.obj.db.lid_locked: + self.caller.msg("This lid seems locked in place for the moment.") + return + + string = "\nA ticking sound is heard, like a winding mechanism. Seems " + string += "the lid will soon close again." + self.caller.msg(string) + self.caller.location.msg_contents( + f"{self.caller.name} opens the lid of the button.", + exclude=self.caller) + self.obj.to_open_state()
        + + +
        [docs]class LidClosedCmdSet(CmdSet): + """ + A simple cmdset tied to the redbutton object. + + It contains the commands that launches the other + command sets, making the red button a self-contained + item (i.e. you don't have to manually add any + scripts etc to it when creating it). + + Note that this is given with a `key_mergetype` set. This + is set up so that the cmdset with merge with Union merge type + *except* if the other cmdset to merge with is LidOpenCmdSet, + in which case it will Replace that. So these two cmdsets will + be mutually exclusive. + + """ + + key = "LidClosedCmdSet" + +
        [docs] def at_cmdset_creation(self): + "Populates the cmdset when it is instantiated." + self.add(CmdPushLidClosed()) + self.add(CmdNudge()) + self.add(CmdSmashGlass()) + self.add(CmdOpenLid())
        + + +# Commands for the state when the button's protective cover is open - now the +# push command will work. You can also close the lid again. + +
        [docs]class CmdPushLidOpen(Command): + """ + Push the red button + + Usage: + push button + + """ + + key = "push button" + aliases = ["push", "press button", "press"] + locks = "cmd:all()" + + @interactive + def func(self): + """ + This version of push will immediately trigger the next button state. + + The use of the @interactive decorator allows for using `yield` to add + simple pauses in how quickly a message is returned to the user. This + kind of pause will not survive a server reload. + + """ + # pause a little between each message. + self.caller.msg("You reach out to press the big red button ...") + yield(2) # pause 2s before next message + self.caller.msg("\n\n|wBOOOOM! A bright light blinds you!|n") + yield(1) # pause 1s before next message + self.caller.msg("\n\n|xThe world goes dark ...|n") + + name = self.caller.name + self.caller.location.msg_contents( + f"{name} presses the button. BOOM! {name} is blinded by a flash!", + exclude=self.caller) + self.obj.blind_target(self.caller)
        + + +
        [docs]class CmdCloseLid(Command): + """ + Close the lid + + Usage: + close lid + + Closes the lid of the red button. + """ + + key = "close lid" + aliases = ["close"] + locks = "cmd:all()" + +
        [docs] def func(self): + "Close the lid" + + self.obj.to_closed_state() + + # this will clean out scripts dependent on lid being open. + self.caller.msg("You close the button's lid. It clicks back into place.") + self.caller.location.msg_contents( + f"{self.caller.name} closes the button's lid.", + exclude=self.caller)
        + + +
        [docs]class LidOpenCmdSet(CmdSet): + """ + This is the opposite of the Closed cmdset. + + Note that this is given with a `key_mergetype` set. This + is set up so that the cmdset with merge with Union merge type + *except* if the other cmdset to merge with is LidClosedCmdSet, + in which case it will Replace that. So these two cmdsets will + be mutually exclusive. + + """ + + key = "LidOpenCmdSet" + +
        [docs] def at_cmdset_creation(self): + """Setup the cmdset""" + self.add(CmdPushLidOpen()) + self.add(CmdCloseLid())
        + + +# Commands for when the button has been pushed and the player is blinded. This +# replaces commands on the player making them 'blind' for a while. + +
        [docs]class CmdBlindLook(Command): + """ + Looking around in darkness + + Usage: + look <obj> + + ... not that there's much to see in the dark. + + """ + + key = "look" + aliases = ["l", "get", "examine", "ex", "feel", "listen"] + locks = "cmd:all()" + +
        [docs] def func(self): + "This replaces all the senses when blinded." + + # we decide what to reply based on which command was + # actually tried + + if self.cmdstring == "get": + string = "You fumble around blindly without finding anything." + elif self.cmdstring == "examine": + string = "You try to examine your surroundings, but can't see a thing." + elif self.cmdstring == "listen": + string = "You are deafened by the boom." + elif self.cmdstring == "feel": + string = "You fumble around, hands outstretched. You bump your knee." + else: + # trying to look + string = ("You are temporarily blinded by the flash. " + "Until it wears off, all you can do is feel around blindly.") + self.caller.msg(string) + self.caller.location.msg_contents( + f"{self.caller.name} stumbles around, blinded.", + exclude=self.caller)
        + + +
        [docs]class CmdBlindHelp(Command): + """ + Help function while in the blinded state + + Usage: + help + + """ + + key = "help" + aliases = "h" + locks = "cmd:all()" + +
        [docs] def func(self): + """ + Just give a message while blinded. We could have added this to the + CmdBlindLook command too if we wanted to keep things more compact. + + """ + self.caller.msg("You are beyond help ... until you can see again.")
        + + +
        [docs]class BlindCmdSet(CmdSet): + """ + This is the cmdset added to the *account* when + the button is pushed. + + Since this has mergetype Replace it will completely remove the commands of + all other cmdsets while active. To allow some limited interaction + (pose/say) we import those default commands and add them too. + + We also disable all exit-commands generated by exits and + object-interactions while blinded by setting `no_exits` and `no_objs` flags + on the cmdset. This is to avoid the player walking off or interfering with + other objects while blinded. Account-level commands however (channel messaging + etc) will not be affected by the blinding. + + """ + + key = "BlindCmdSet" + # we want it to completely replace all normal commands + # until the timed script removes it again. + mergetype = "Replace" + # we want to stop the player from walking around + # in this blinded state, so we hide all exits too. + # (channel commands will still work). + no_exits = True # keep player in the same room + no_objs = True # don't allow object commands + +
        [docs] def at_cmdset_creation(self): + "Setup the blind cmdset" + from evennia.commands.default.general import CmdSay + from evennia.commands.default.general import CmdPose + + self.add(CmdSay()) + self.add(CmdPose()) + self.add(CmdBlindLook()) + self.add(CmdBlindHelp())
        + # # Definition of the object itself @@ -63,149 +431,192 @@
        [docs]class RedButton(DefaultObject): """ - This class describes an evil red button. It will use the script - definition in contrib/examples/red_button_scripts to blink at regular - intervals. It also uses a series of script and commands to handle - pushing the button and causing effects when doing so. + This class describes an evil red button. It will blink invitingly and + temporarily blind whomever presses it. - The following attributes can be set on the button: - desc_lid_open - description when lid is open - desc_lid_closed - description when lid is closed - desc_lamp_broken - description when lamp is broken + The button can take a few optional attributes controlling how things will + be displayed in its various states. This is a useful way to give builders + the option to customize a complex object from in-game. Actual return messages + to event-actions are (in this example) left with each command, but one could + also imagine having those handled via Attributes as well, if one wanted a + completely in-game customizable button without needing to tweak command + classes. + + Attributes: + - `desc_closed_lid`: This is the description to show of the button + when the lid is closed. + - `desc_open_lid`": Shown when the lid is open + - `auto_close_msg`: Message to show when lid auto-closes + - `desc_add_lamp_broken`: Extra desc-line added after normal desc when lamp + is broken. + - blink_msg: A list of strings to randomly choose from when the lamp + blinks. + + Notes: + The button starts with lid closed. To set the initial description, + you can either set desc after creating it or pass a `desc` attribute + when creating it, such as + `button = create_object(RedButton, ..., attributes=[('desc', 'my desc')])`. """ + # these are the pre-set descriptions. Setting attributes will override + # these on the fly. + + desc_closed_lid = ("This is a large red button, inviting yet evil-looking. " + "A closed glass lid protects it.") + desc_open_lid = ("This is a large red button, inviting yet evil-looking. " + "Its glass cover is open and the button exposed.") + auto_close_msg = "The button's glass lid silently slides back in place." + lamp_breaks_msg = "The lamp flickers, the button going dark." + desc_add_lamp_broken = "\nThe big red button has stopped blinking for the time being." + # note that this is a list. A random message will display each time + blink_msgs = ["The red button flashes briefly.", + "The red button blinks invitingly.", + "The red button flashes. You know you wanna push it!"]
        [docs] def at_object_creation(self): """ - This function is called when object is created. Use this - instead of e.g. __init__. - """ - # store desc (default, you can change this at creation time) - desc = "This is a large red button, inviting yet evil-looking. " - desc += "A closed glass lid protects it." - self.db.desc = desc + This function is called (once) when object is created. - # We have to define all the variables the scripts - # are checking/using *before* adding the scripts or - # they might be deactivated before even starting! - self.db.lid_open = False + """ self.db.lamp_works = True - self.db.lid_locked = False - self.cmdset.add_default(cmdsetexamples.DefaultCmdSet, permanent=True) + # start closed + self.to_closed_state() - # since the cmdsets relevant to the button are added 'on the fly', - # we need to setup custom scripts to do this for us (also, these scripts - # check so they are valid (i.e. the lid is actually still closed)). - # The AddClosedCmdSet script makes sure to add the Closed-cmdset. - self.scripts.add(scriptexamples.ClosedLidState) - # the script EventBlinkButton makes the button blink regularly. - self.scripts.add(scriptexamples.BlinkButtonEvent)
        + # start blinking every 35s. + repeat(35, self._do_blink, persistent=True)
        - # state-changing methods - -
        [docs] def open_lid(self): + def _do_blink(self): """ - Opens the glass lid and start the timer so it will soon close - again. + Have the button blink invitingly unless it's broken. """ + if self.location and self.db.lamp_works: + possible_messages = self.db.blink_msgs or self.blink_msgs + self.location.msg_contents(random.choice(possible_messages)) - if self.db.lid_open: - return - desc = self.db.desc_lid_open - if not desc: - desc = "This is a large red button, inviting yet evil-looking. " - desc += "Its glass cover is open and the button exposed." - self.db.desc = desc - self.db.lid_open = True - - # with the lid open, we validate scripts; this will clean out - # scripts that depend on the lid to be closed. - self.scripts.validate() - # now add new scripts that define the open-lid state - self.scripts.add(scriptexamples.OpenLidState) - # we also add a scripted event that will close the lid after a while. - # (this one cleans itself after being called once) - self.scripts.add(scriptexamples.CloseLidEvent)
        - -
        [docs] def close_lid(self): + def _set_desc(self, attrname=None): """ - Close the glass lid. This validates all scripts on the button, - which means that scripts only being valid when the lid is open - will go away automatically. - - """ - - if not self.db.lid_open: - return - desc = self.db.desc_lid_closed - if not desc: - desc = "This is a large red button, inviting yet evil-looking. " - desc += "Its glass cover is closed, protecting it." - self.db.desc = desc - self.db.lid_open = False - - # clean out scripts depending on lid to be open - self.scripts.validate() - # add scripts related to the closed state - self.scripts.add(scriptexamples.ClosedLidState)
        - -
        [docs] def break_lamp(self, feedback=True): - """ - Breaks the lamp in the button, stopping it from blinking. + Set a description, based on the attrname given, taking the lamp-status + into account. Args: - feedback (bool): Show a message about breaking the lamp. + attrname (str, optional): This will first check for an Attribute with this name, + secondly for a property on the class. So if `attrname="auto_close_msg"`, + we will first look for an attribute `.db.auto_close_msg` and if that's + not found we'll use `.auto_close_msg` instead. If unset (`None`), the + currently set desc will not be changed (only lamp will be checked). + + Notes: + If `self.db.lamp_works` is `False`, we'll append + `desc_add_lamp_broken` text. + + """ + if attrname: + # change desc + desc = self.attributes.get(attrname) or getattr(self, attrname) + else: + # use existing desc + desc = self.db.desc + + if not self.db.lamp_works: + # lamp not working. Add extra to button's desc + desc += self.db.desc_add_lamp_broken or self.desc_add_lamp_broken + + self.db.desc = desc + + # state-changing methods and actions + +
        [docs] def to_closed_state(self, msg=None): + """ + Switches the button to having its lid closed. + + Args: + msg (str, optional): If given, display a message to the room + when lid closes. + + This will first try to get the Attribute (self.db.desc_closed_lid) in + case it was set by a builder and if that was None, it will fall back to + self.desc_closed_lid, the default description (note that lack of .db). + """ + self._set_desc("desc_closed_lid") + # remove lidopen-state, if it exists + self.cmdset.remove(LidOpenCmdSet) + # add lid-closed cmdset + self.cmdset.add(LidClosedCmdSet) + + if msg and self.location: + self.location.msg_contents(msg)
        + +
        [docs] def to_open_state(self): + """ + Switches the button to having its lid open. This also starts a timer + that will eventually close it again. + + """ + self._set_desc("desc_open_lid") + # remove lidopen-state, if it exists + self.cmdset.remove(LidClosedCmdSet) + # add lid-open cmdset + self.cmdset.add(LidOpenCmdSet) + + # wait 20s then call self.to_closed_state with a message as argument + delay(35, self.to_closed_state, + self.db.auto_close_msg or self.auto_close_msg, + persistent=True)
        + + def _unblind_target(self, caller): + """ + This is called to un-blind after a certain time. + + """ + caller.cmdset.remove(BlindCmdSet) + caller.msg("You blink feverishly as your eyesight slowly returns.") + self.location.msg_contents( + f"{caller.name} seems to be recovering their eyesight, blinking feverishly.", + exclude=caller) + +
        [docs] def blind_target(self, caller): + """ + Someone was foolish enough to press the button! Blind them + temporarily. + + Args: + caller (Object): The one to be blinded. + + """ + + # we don't need to remove other cmdsets, this will replace all, + # then restore whatever was there when it goes away. + caller.cmdset.add(BlindCmdSet) + + # wait 20s then call self._unblind to remove blindness effect. The + # persistent=True means the delay should survive a server reload. + delay(20, self._unblind_target, caller, + persistent=True)
        + + def _unbreak_lamp(self): + """ + This is called to un-break the lamp after a certain time. + + """ + # we do this quietly, the user will just notice it starting blinking again + self.db.lamp_works = True + self._set_desc() + +
        [docs] def break_lamp(self): + """ + Breaks the lamp in the button, stopping it from blinking for a while """ self.db.lamp_works = False - desc = self.db.desc_lamp_broken - if not desc: - self.db.desc += "\nThe big red button has stopped blinking for the time being." - else: - self.db.desc = desc + # this will update the desc with the info about the broken lamp + self._set_desc() + self.location.msg_contents(self.db.lamp_breaks_msg or self.lamp_breaks_msg) - if feedback and self.location: - self.location.msg_contents("The lamp flickers, the button going dark.") - self.scripts.validate()
        - -
        [docs] def press_button(self, pobject): - """ - Someone was foolish enough to press the button! - - Args: - pobject (Object): The person pressing the button - - """ - # deactivate the button so it won't flash/close lid etc. - self.scripts.add(scriptexamples.DeactivateButtonEvent) - # blind the person pressing the button. Note that this - # script is set on the *character* pressing the button! - pobject.scripts.add(scriptexamples.BlindedState)
        - - # script-related methods - -
        + # wait 21s before unbreaking the lamp again + delay(21, self._unbreak_lamp)
        @@ -243,7 +654,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -262,6 +672,7 @@ +
        develop branch
        @@ -147,7 +148,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -166,6 +166,7 @@ +
        develop branch
        @@ -473,8 +474,9 @@ and the main window. - Use |y<Return>|n (or click the arrow on the right) to send your input. -- Use |yShift + <up/down-arrow>|n to step back and forth in your command-history. -- Use |yShift + <Return>|n to add a new line to your input without sending. +- Use |yCtrl + <up/down-arrow>|n to step back and forth in your command-history. +- Use |yCtrl + <Return>|n to add a new line to your input without sending. +(Cmd instead of Ctrl-key on Macs) There is also some |wextra|n info to learn about customizing the webclient. @@ -735,7 +737,7 @@ After playing through the tutorial-world quest, if you aim to make a game with Evennia you are wise to take a look at the |wEvennia documentation|n at - |yhttps://www.evennia.com/docs/latest + |yhttps://www.evennia.com/docs/latest|n - You can start by trying to build some stuff by following the |wBuilder quick-start|n: @@ -857,7 +859,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -876,6 +877,7 @@ +
        develop branch
        @@ -110,7 +111,7 @@ stationary (idling) until attacked. aggressive: if set, will attack Characters in the same room using whatever Weapon it - carries (see tutorial_world.objects.Weapon). + carries (see tutorial_world.objects.TutorialWeapon). if unset, the mob will never engage in combat no matter what. hunting: if set, the mob will pursue enemies trying @@ -209,9 +210,9 @@ be "ticked". Args: - interval (int): The number of seconds + interval (int or None): The number of seconds between ticks - hook_key (str): The name of the method + hook_key (str or None): The name of the method (on this mob) to call every interval seconds. stop (bool, optional): Just stop the @@ -413,16 +414,11 @@ return # we use the same attack commands as defined in - # tutorial_world.objects.Weapon, assuming that + # tutorial_world.objects.TutorialWeapon, assuming that # the mob is given a Weapon to attack with. attack_cmd = random.choice(("thrust", "pierce", "stab", "slash", "chop")) self.execute_cmd("%s %s" % (attack_cmd, target)) - if target.db.health is None: - # This is not an attackable target - logger.log_err(f"{self.key} found {target} had an `health` attribute of `None`.") - return - # analyze the current state if target.db.health <= 0: # we reduced the target to <= 0 health. Move them to the @@ -517,7 +513,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -536,6 +531,7 @@ +
        develop branch
        @@ -55,8 +56,8 @@ Obelisk LightSource CrumblingWall -Weapon -WeaponRack +TutorialWeapon +TutorialWeaponRack """ @@ -832,7 +833,7 @@ # ------------------------------------------------------------- # -# Weapon - object type +# TutorialWeapon - object type # # A weapon is necessary in order to fight in the tutorial # world. A weapon (which here is assumed to be a bladed @@ -972,7 +973,7 @@ self.add(CmdAttack())
        -
        [docs]class Weapon(TutorialObject): +
        [docs]class TutorialWeapon(TutorialObject): """ This defines a bladed weapon. @@ -984,7 +985,7 @@ """ -
        [docs] def at_object_creation(self): +
        [docs] def at_object_creation(self): """Called at first creation of the object""" super().at_object_creation() self.db.hit = 0.4 # hit chance @@ -993,7 +994,7 @@ self.db.magic = False self.cmdset.add_default(CmdSetWeapon, permanent=True)
        -
        [docs] def reset(self): +
        [docs] def reset(self): """ When reset, the weapon is simply deleted, unless it has a place to return to. @@ -1023,7 +1024,7 @@ WEAPON_PROTOTYPES = { "weapon": { - "typeclass": "evennia.contrib.tutorial_world.objects.Weapon", + "typeclass": "evennia.contrib.tutorial_world.objects.TutorialWeapon", "key": "Weapon", "hit": 0.2, "parry": 0.2, @@ -1168,7 +1169,7 @@ self.add(CmdGetWeapon())
        -
        [docs]class WeaponRack(TutorialObject): +
        [docs]class TutorialWeaponRack(TutorialObject): """ This object represents a weapon store. When people use the "get weapon" command on this rack, it will produce one @@ -1185,7 +1186,7 @@ """ -
        [docs] def at_object_creation(self): +
        [docs] def at_object_creation(self): """ called at creation """ @@ -1199,13 +1200,12 @@ |wstab/thrust/pierce <target>|n - poke at the enemy. More damage but harder to hit. |wslash/chop/bash <target>|n - swipe at the enemy. Less damage but easier to hit. |wdefend/parry|n - protect yourself and make yourself harder to hit.) - """ - ).strip() + """).strip() self.db.no_more_weapons_msg = "you find nothing else of use." self.db.available_weapons = ["knife", "dagger", "sword", "club"]
        -
        [docs] def produce_weapon(self, caller): +
        [docs] def produce_weapon(self, caller): """ This will produce a new weapon from the rack, assuming the caller hasn't already gotten one. When @@ -1261,7 +1261,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1280,6 +1279,7 @@ +
        develop branch
        @@ -119,7 +120,6 @@ helptext += "\n\n (Write 'give up' if you want to abandon your quest.)" caller.msg(helptext)
        - # for the @detail command we inherit from MuxCommand, since # we want to make use of MuxCommand's pre-parsing of '=' in the # argument. @@ -244,26 +244,22 @@ looking_at_obj.at_desc(looker=caller) return
        -
        [docs]class CmdTutorialGiveUp(default_cmds.MuxCommand): """ Give up the tutorial-world quest and return to Limbo, the start room of the server. """ - key = "give up" - aliases = ["abort"] + aliases = ['abort']
        [docs] def func(self): outro_room = OutroRoom.objects.all() if outro_room: outro_room = outro_room[0] else: - self.caller.msg( - "That didn't work (seems like a bug). " - "Try to use the |wteleport|n command instead." - ) + self.caller.msg("That didn't work (seems like a bug). " + "Try to use the |wteleport|n command instead.") return self.caller.move_to(outro_room)
        @@ -431,7 +427,6 @@ # # ------------------------------------------------------------- -
        [docs]class CmdEvenniaIntro(Command): """ Start the Evennia intro wizard. @@ -440,12 +435,10 @@ intro """ - key = "intro"
        [docs] def func(self): from .intro_menu import init_menu - # quell also superusers if self.caller.account: self.caller.account.execute_cmd("quell") @@ -501,7 +494,6 @@ character.account.execute_cmd("quell") character.msg("(Auto-quelling while in tutorial-world)")
        - # ------------------------------------------------------------- # # Bridge - unique room @@ -1215,6 +1207,7 @@
        [docs] def at_object_leave(self, character, destination): if character.account: character.account.execute_cmd("unquell")
        +
        @@ -1252,7 +1245,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1271,6 +1263,7 @@ +
        develop branch
        @@ -164,7 +165,7 @@ # Replace the -h/--help self.add_argument( - "-h", "--hel", nargs=0, action=HelpAction, help="display the command help" + "-h", "--help", nargs=0, action=HelpAction, help="display the command help" )
        [docs] def format_usage(self): @@ -371,7 +372,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -390,6 +390,7 @@ +
        develop branch
        @@ -853,7 +854,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -872,6 +872,7 @@ +
        develop branch
        @@ -42,7 +43,6 @@ """ Custom manager for HelpEntry objects. """ -from django.db import models from evennia.utils import logger, utils from evennia.typeclasses.managers import TypedObjectManager @@ -172,7 +172,7 @@ for topic in topics: topic.help_category = default_category topic.save() - string = _("Help database moved to category {default_category}").format( + string = "Help database moved to category {default_category}".format( default_category=default_category ) logger.log_info(string)
        @@ -228,7 +228,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -247,6 +246,7 @@ +
        develop branch
        @@ -114,11 +115,11 @@ db_tags = models.ManyToManyField( Tag, blank=True, - help_text="tags on this object. Tags are simple string markers to identify, group and alias objects.", + help_text="tags on this object. Tags are simple string markers to " + "identify, group and alias objects.", ) - # (deprecated, only here to allow MUX helpfile load (don't use otherwise)). - # TODO: remove this when not needed anymore. - db_staff_only = models.BooleanField(default=False) + # Creation date. This is not changed once the object is created. + db_date_created = models.DateTimeField("creation date", editable=False, auto_now=True) # Database manager objects = HelpEntryManager() @@ -138,7 +139,7 @@ def aliases(self): return AliasHandler(self)
        - class Meta(object): + class Meta: "Define Django meta options" verbose_name = "Help Entry" verbose_name_plural = "Help Entries" @@ -148,22 +149,41 @@ # HelpEntry main class methods # # - def __str__(self): - return self.key + return str(self.key) def __repr__(self): - return "%s" % self.key + return f"<HelpEntry {self.key}>" -
        [docs] def access(self, accessing_obj, access_type="read", default=False): +
        [docs] def access(self, accessing_obj, access_type="read", default=True): """ - Determines if another object has permission to access. - accessing_obj - object trying to access this one - access_type - type of access sought - default - what to return if no lock of access_type was found + Determines if another object has permission to access this help entry. + + Accesses used by default: + 'read' - read the help entry itself. + 'view' - see help entry in help index. + + Args: + accessing_obj (Object or Account): Entity trying to access this one. + access_type (str): type of access sought. + default (bool): What to return if no lock of `access_type` was found. + """ return self.locks.check(accessing_obj, access_type=access_type, default=default)
        + @property + def search_index_entry(self): + """ + Property for easily retaining a search index entry for this object. + """ + return { + "key": self.db_key, + "aliases": " ".join(self.aliases.all()), + "category": self.db_help_category, + "text": self.db_entrytext, + "tags": " ".join(str(tag) for tag in self.tags.all()), + } + # # Web/Django methods # @@ -196,7 +216,9 @@ a named view of 'character-create' would be referenced by this method. ex. - url(r'characters/create/', ChargenView.as_view(), name='character-create') + :: + + url(r'characters/create/', ChargenView.as_view(), name='character-create') If no View has been created and defined in urls.py, returns an HTML anchor. @@ -211,7 +233,7 @@ """ try: return reverse("%s-create" % slugify(cls._meta.verbose_name)) - except: + except Exception: return "#"
        [docs] def web_get_detail_url(self): @@ -226,8 +248,9 @@ a named view of 'character-detail' would be referenced by this method. ex. - url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/$', - CharDetailView.as_view(), name='character-detail') + :: + url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/$', + CharDetailView.as_view(), name='character-detail') If no View has been created and defined in urls.py, returns an HTML anchor. @@ -245,8 +268,7 @@ "%s-detail" % slugify(self._meta.verbose_name), kwargs={"category": slugify(self.db_help_category), "topic": slugify(self.db_key)}, ) - except Exception as e: - print(e) + except Exception: return "#"
        [docs] def web_get_update_url(self): @@ -261,8 +283,10 @@ a named view of 'character-update' would be referenced by this method. ex. - url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/change/$', - CharUpdateView.as_view(), name='character-update') + :: + + url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/change/$', + CharUpdateView.as_view(), name='character-update') If no View has been created and defined in urls.py, returns an HTML anchor. @@ -280,7 +304,7 @@ "%s-update" % slugify(self._meta.verbose_name), kwargs={"category": slugify(self.db_help_category), "topic": slugify(self.db_key)}, ) - except: + except Exception: return "#"
        [docs] def web_get_delete_url(self): @@ -294,8 +318,10 @@ a named view of 'character-detail' would be referenced by this method. ex. - url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/delete/$', - CharDeleteView.as_view(), name='character-delete') + :: + + url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/delete/$', + CharDeleteView.as_view(), name='character-delete') If no View has been created and defined in urls.py, returns an HTML anchor. @@ -313,7 +339,7 @@ "%s-delete" % slugify(self._meta.verbose_name), kwargs={"category": slugify(self.db_help_category), "topic": slugify(self.db_key)}, ) - except: + except Exception: return "#"
        # Used by Django Sites/Admin @@ -355,7 +381,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -374,6 +399,7 @@ +
        develop branch
        @@ -52,81 +53,6 @@ with a lock variable/field, so be careful to not expect a certain object type. - -**Appendix: MUX locks** - -Below is a list nicked from the MUX help file on the locks available -in standard MUX. Most of these are not relevant to core Evennia since -locks in Evennia are considerably more flexible and can be implemented -on an individual command/typeclass basis rather than as globally -available like the MUX ones. So many of these are not available in -basic Evennia, but could all be implemented easily if needed for the -individual game. - -``` -MUX Name: Affects: Effect: ----------------------------------------------------------------------- -DefaultLock: Exits: controls who may traverse the exit to - its destination. - Evennia: "traverse:<lockfunc()>" - Rooms: controls whether the account sees the - SUCC or FAIL message for the room - following the room description when - looking at the room. - Evennia: Custom typeclass - Accounts/Things: controls who may GET the object. - Evennia: "get:<lockfunc()" - EnterLock: Accounts/Things: controls who may ENTER the object - Evennia: - GetFromLock: All but Exits: controls who may gets things from a - given location. - Evennia: - GiveLock: Accounts/Things: controls who may give the object. - Evennia: - LeaveLock: Accounts/Things: controls who may LEAVE the object. - Evennia: - LinkLock: All but Exits: controls who may link to the location - if the location is LINK_OK (for linking - exits or setting drop-tos) or ABODE (for - setting homes) - Evennia: - MailLock: Accounts: controls who may @mail the account. - Evennia: - OpenLock: All but Exits: controls who may open an exit. - Evennia: - PageLock: Accounts: controls who may page the account. - Evennia: "send:<lockfunc()>" - ParentLock: All: controls who may make @parent links to - the object. - Evennia: Typeclasses and - "puppet:<lockstring()>" - ReceiveLock: Accounts/Things: controls who may give things to the - object. - Evennia: - SpeechLock: All but Exits: controls who may speak in that location - Evennia: - TeloutLock: All but Exits: controls who may teleport out of the - location. - Evennia: - TportLock: Rooms/Things: controls who may teleport there - Evennia: - UseLock: All but Exits: controls who may USE the object, GIVE - the object money and have the PAY - attributes run, have their messages - heard and possibly acted on by LISTEN - and AxHEAR, and invoke $-commands - stored on the object. - Evennia: Commands and Cmdsets. - DropLock: All but rooms: controls who may drop that object. - Evennia: - VisibleLock: All: Controls object visibility when the - object is not dark and the looker - passes the lock. In DARK locations, the - object must also be set LIGHT and the - viewer must pass the VisibleLock. - Evennia: Room typeclass with - Dark/light script -``` """ @@ -153,16 +79,21 @@
        [docs]def true(*args, **kwargs): - "Always returns True." - return True
        + """ + Always returns True. + """ + return True
        [docs]def all(*args, **kwargs): return True
        [docs]def false(*args, **kwargs): - "Always returns False" + """ + Always returns False + + """ return False
        @@ -170,6 +101,10 @@ return False +
        [docs]def superuser(*args, **kwargs): + return False
        + +
        [docs]def self(accessing_obj, accessed_obj, *args, **kwargs): """ Check if accessing_obj is the same as accessed_obj @@ -580,8 +515,6 @@ Only true if accessed_obj has the specified tag and optional category. """ - if hasattr(accessed_obj, "obj"): - accessed_obj = accessed_obj.obj tagkey = args[0] if args else None category = args[1] if len(args) > 1 else None return bool(accessed_obj.tags.get(tagkey, category=category))
        @@ -613,9 +546,6 @@ in your inventory will also pass the lock). """ - if hasattr(accessed_obj, "obj"): - accessed_obj = accessed_obj.obj - def _recursive_inside(obj, accessed_obj, lvl=1): if obj.location: if obj.location == accessed_obj: @@ -690,17 +620,6 @@ return False -
        [docs]def superuser(*args, **kwargs): - """ - Only accepts an accesing_obj that is superuser (e.g. user #1) - - Since a superuser would not ever reach this check (superusers - bypass the lock entirely), any user who gets this far cannot be a - superuser, hence we just return False. :) - """ - return False
        - -
        [docs]def has_account(accessing_obj, accessed_obj, *args, **kwargs): """ Only returns true if accessing_obj has_account is true, that is, @@ -779,7 +698,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -798,6 +716,7 @@ +
        develop branch
        @@ -165,6 +166,7 @@
        [docs]class LockException(Exception): """ Raised during an error in a lock. + """ pass
        @@ -180,6 +182,7 @@ def _cache_lockfuncs(): """ Updates the cache. + """ global _LOCKFUNCS _LOCKFUNCS = {} @@ -204,7 +207,7 @@ # -
        [docs]class LockHandler(object): +
        [docs]class LockHandler: """ This handler should be attached to all objects implementing permission checks, under the property 'lockhandler'. @@ -274,7 +277,8 @@ funcname, rest = (part.strip().strip(")") for part in funcstring.split("(", 1)) func = _LOCKFUNCS.get(funcname, None) if not callable(func): - elist.append(_("Lock: lock-function '%s' is not available.") % funcstring) + elist.append(_("Lock: lock-function '{lockfunc}' is not available.").format( + lockfunc=funcstring)) continue args = list(arg.strip() for arg in rest.split(",") if arg and "=" not in arg) kwargs = dict( @@ -301,16 +305,13 @@ continue if access_type in locks: duplicates += 1 - wlist.append( - _( - "LockHandler on %(obj)s: access type '%(access_type)s' changed from '%(source)s' to '%(goal)s' " - % { - "obj": self.obj, - "access_type": access_type, - "source": locks[access_type][2], - "goal": raw_lockstring, - } - ) + wlist.append(_( + "LockHandler on {obj}: access type '{access_type}' " + "changed from '{source}' to '{goal}' ".format( + obj=self.obj, + access_type=access_type, + source=locks[access_type][2], + goal=raw_lockstring)) ) locks[access_type] = (evalstring, tuple(lock_funcs), raw_lockstring) if wlist and WARNING_LOG: @@ -325,12 +326,14 @@ def _cache_locks(self, storage_lockstring): """ Store data + """ self.locks = self._parse_lockstring(storage_lockstring) def _save_locks(self): """ Store locks to obj + """ self.obj.lock_storage = ";".join([tup[2] for tup in self.locks.values()]) @@ -734,6 +737,28 @@ access_type=access_type, ) +def check_perm(obj, permission, no_superuser_bypass=False): + """ + Shortcut for checking if an object has the given `permission`. If the + permission is in `settings.PERMISSION_HIERARCHY`, the check passes + if the object has this permission or higher. + + This is equivalent to calling the perm() lockfunc, but without needing + an accessed object. + + Args: + obj (Object, Account): The object to check access. If this has a linked + Account, the account is checked instead (same rules as per perm()). + permission (str): The permission string to check. + no_superuser_bypass (bool, optional): If unset, the superuser + will always pass this check. + + """ + from evennia.locks.lockfuncs import perm + if not no_superuser_bypass and obj.is_superuser: + return True + return perm(obj, None, permission) + def validate_lockstring(lockstring): """ @@ -833,7 +858,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -852,6 +876,7 @@ +
        develop branch
        @@ -43,7 +44,6 @@ Custom manager for Objects. """ import re -from itertools import chain from django.db.models import Q from django.conf import settings from django.db.models.fields import exceptions @@ -195,7 +195,8 @@ Args: attribute_name (str): Attribute key to search for. - attribute_value (any): Attribute value to search for. This can also be database objects. + attribute_value (any): Attribute value to search for. This can also be database + objects. candidates (list, optional): Candidate objects to limit search to. typeclasses (list, optional): Python pats to restrict matches with. @@ -632,6 +633,7 @@ """ Clear the db_sessid field of all objects having also the db_account field set. + """ self.filter(db_sessid__isnull=False).update(db_sessid=None) @@ -675,7 +677,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -694,6 +695,7 @@ +
        develop branch
        @@ -54,6 +55,7 @@ the database object. Like everything else, they can be accessed transparently through the decorating TypeClass. """ +from collections import defaultdict from django.conf import settings from django.db import models from django.core.exceptions import ObjectDoesNotExist @@ -83,34 +85,49 @@ """ self.obj = obj - self._pkcache = {} + self._pkcache = set() self._idcache = obj.__class__.__instance_cache__ + self._typecache = defaultdict(set) self.init()
        +
        [docs] def load(self): + """ + Retrieves all objects from database. Used for initializing. + + Returns: + Objects (list of ObjectDB) + """ + return list(self.obj.locations_set.all())
        +
        [docs] def init(self): """ Re-initialize the content cache """ - self._pkcache.update( - dict((obj.pk, None) for obj in ObjectDB.objects.filter(db_location=self.obj) if obj.pk) - )
        + objects = self.load() + self._pkcache = {obj.pk for obj in objects} + for obj in objects: + for ctype in obj._content_types: + self._typecache[ctype].add(obj.pk) -
        [docs] def get(self, exclude=None): +
        [docs] def get(self, exclude=None, content_type=None): """ Return the contents of the cache. Args: exclude (Object or list of Object): object(s) to ignore + content_type (str or None): Filter list by a content-type. If None, don't filter. Returns: objects (list): the Objects inside this location """ - if exclude: - pks = [pk for pk in self._pkcache if pk not in [excl.pk for excl in make_iter(exclude)]] + if content_type is not None: + pks = self._typecache[content_type] else: pks = self._pkcache + if exclude: + pks = pks - {excl.pk for excl in make_iter(exclude)} try: return [self._idcache[pk] for pk in pks] except KeyError: @@ -120,10 +137,9 @@ try: return [self._idcache[pk] for pk in pks] except KeyError: - # this means the central instance_cache was totally flushed. - # Re-fetching from database will rebuild the necessary parts of the cache - # for next fetch. - return list(ObjectDB.objects.filter(db_location=self.obj))
        + # this means an actual failure of caching. Return real database match. + logger.log_err("contents cache failed for %s." % self.obj.key) + return self.load()
        [docs] def add(self, obj): """ @@ -133,7 +149,9 @@ obj (Object): object to add """ - self._pkcache[obj.pk] = None
        + self._pkcache.add(obj.pk) + for ctype in obj._content_types: + self._typecache[ctype].add(obj.pk)
        [docs] def remove(self, obj): """ @@ -143,7 +161,10 @@ obj (Object): object to remove """ - self._pkcache.pop(obj.pk, None)
        + self._pkcache.remove(obj.pk) + for ctype in obj._content_types: + if obj.pk in self._typecache[ctype]: + self._typecache[ctype].remove(obj.pk)
        [docs] def clear(self): """ @@ -151,6 +172,7 @@ """ self._pkcache = {} + self._typecache = defaultdict(set) self.init()
        @@ -398,7 +420,7 @@ ) [o.contents_cache.init() for o in self.__dbclass__.get_all_cached_instances()] - class Meta(object): + class Meta: """Define Django meta options""" verbose_name = "Object" @@ -440,7 +462,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -459,6 +480,7 @@ +
        develop branch
        @@ -45,34 +46,27 @@ These are the (default) starting points for all in-game visible entities. +This is the v1.0 develop version (for ref in doc building). + """ import time -import inflect from collections import defaultdict +import inflect from django.conf import settings +from django.utils.translation import gettext as _ -from evennia.typeclasses.models import TypeclassBase -from evennia.typeclasses.attributes import NickHandler +from evennia.commands import cmdset +from evennia.commands.cmdsethandler import CmdSetHandler from evennia.objects.manager import ObjectManager from evennia.objects.models import ObjectDB from evennia.scripts.scripthandler import ScriptHandler -from evennia.commands import cmdset, command -from evennia.commands.cmdsethandler import CmdSetHandler -from evennia.utils import create -from evennia.utils import search -from evennia.utils import logger -from evennia.utils import ansi -from evennia.utils.utils import ( - class_from_module, - variable_from_module, - lazy_property, - make_iter, - is_iter, - list_to_string, - to_str, -) -from django.utils.translation import gettext as _ +from evennia.typeclasses.attributes import ModelAttributeBackend, NickHandler +from evennia.typeclasses.models import TypeclassBase +from evennia.utils import ansi, create, funcparser, logger, search +from evennia.utils.utils import (class_from_module, is_iter, lazy_property, + list_to_string, make_iter, to_str, + variable_from_module) _INFLECT = inflect.engine() _MULTISESSION_MODE = settings.MULTISESSION_MODE @@ -86,11 +80,19 @@ # the sessid_max is based on the length of the db_sessid csv field (excluding commas) _SESSID_MAX = 16 if _MULTISESSION_MODE in (1, 3) else 1 +_MSG_CONTENTS_PARSER = funcparser.FuncParser( + { + "you": funcparser.funcparser_callable_you, + "You": funcparser.funcparser_callable_You, + "conj": funcparser.funcparser_callable_conjugate + } +) -
        [docs]class ObjectSessionHandler(object): + +
        [docs]class ObjectSessionHandler: """ - Handles the get/setting of the sessid - comma-separated integer field + Handles the get/setting of the sessid comma-separated integer field + """
        [docs] def __init__(self, obj): @@ -148,7 +150,7 @@ ] if None in sessions: # this happens only if our cache has gone out of sync with the SessionHandler. - self._recache() + return self.get(sessid=sessid) return sessions
        @@ -247,6 +249,9 @@ """ + # Used for sorting / filtering in inventories / room contents. + _content_types = ("object",) + # lockstring of newly created objects, for easy overloading. # Will be formatted with the appropriate attributes. lockstring = "control:id({account_id}) or perm(Admin);delete:id({account_id}) or perm(Admin)" @@ -265,7 +270,7 @@
        [docs] @lazy_property def nicks(self): - return NickHandler(self)
        + return NickHandler(self, ModelAttributeBackend)
        [docs] @lazy_property def sessions(self): @@ -300,7 +305,7 @@ and not self.db_account.attributes.get("_quell") ) -
        [docs] def contents_get(self, exclude=None): +
        [docs] def contents_get(self, exclude=None, content_type=None): """ Returns the contents of this object, i.e. all objects that has this object set as its location. @@ -309,17 +314,18 @@ Args: exclude (Object): Object to exclude from returned contents list + content_type (str): A content_type to filter by. None for no + filtering. Returns: contents (list): List of contents of this Object. Notes: - Also available as the `contents` property. + Also available as the `contents` property, minus exclusion + and filtering. """ - con = self.contents_cache.get(exclude=exclude) - # print "contents_get:", self, con, id(self), calledby() # DEBUG - return con
        + return self.contents_cache.get(exclude=exclude, content_type=content_type)
        [docs] def contents_set(self, *args): "You cannot replace this property" @@ -335,6 +341,7 @@ """ Returns all exits from this object, i.e. all objects at this location having the property destination != `None`. + """ return [exi for exi in self.contents if exi.destination] @@ -381,6 +388,7 @@ Returns: singular (str): The singular form to display. plural (str): The determined plural form of the key, including the count. + """ plural_category = "plural_key" key = kwargs.get("key", self.key) @@ -415,6 +423,7 @@ nofound_string=None, multimatch_string=None, use_dbref=None, + stacked=0, ): """ Returns an Object matching a search string/condition @@ -443,7 +452,9 @@ to search. Note that this is used to query the *contents* of a location and will not match for the location itself - if you want that, don't set this or use `candidates` to specify - exactly which objects should be searched. + exactly which objects should be searched. If this nor candidates are + given, candidates will include caller's inventory, current location and + all objects in the current location. attribute_name (str): Define which property to search. If set, no key+alias search will be performed. This can be used to search database fields (db_ will be automatically @@ -471,10 +482,19 @@ will be treated like a normal string. If `None` (default), the ability to query by #dbref is turned on if `self` has the permission 'Builder' and is turned off otherwise. + stacked (int, optional): If > 0, multimatches will be analyzed to determine if they + only contains identical objects; these are then assumed 'stacked' and no multi-match + error will be generated, instead `stacked` number of matches will be returned. If + `stacked` is larger than number of matches, returns that number of matches. If + the found stack is a mix of objects, return None and handle the multi-match + error depending on the value of `quiet`. Returns: - match (Object, None or list): will return an Object/None if `quiet=False`, - otherwise it will return a list of 0, 1 or more matches. + Object: If finding a match an `quiet=False` + None: If not finding a unique match and `quiet=False`. + list: With 0, 1 or more matching objects if `quiet=True` + list: With 2 or more matching objects if `stacked` is a positive integer and + the matched stack has only object-copies. Notes: To find Accounts, use eg. `evennia.account_search`. If @@ -542,8 +562,29 @@ use_dbref=use_dbref, ) + nresults = len(results) + if stacked > 0 and nresults > 1: + # handle stacks, disable multimatch errors + nstack = nresults + if not exact: + # we re-run exact match agains one of the matches to + # make sure we were not catching partial matches not belonging + # to the stack + nstack = len(ObjectDB.objects.get_objs_with_key_or_alias( + results[0].key, + exact=True, + candidates=list(results), + typeclasses=[typeclass] if typeclass else None + )) + if nstack == nresults: + # a valid stack, return multiple results + return list(results)[:stacked] + if quiet: + # don't auto-handle error messaging return list(results) + + # handle error messages return _AT_SEARCH_RESULT( results, self, @@ -703,6 +744,7 @@ Keyword Args: Keyword arguments will be passed to the function for all objects. + """ contents = self.contents if exclude: @@ -719,64 +761,94 @@ text (str or tuple): Message to send. If a tuple, this should be on the valid OOB outmessage form `(message, {kwargs})`, where kwargs are optional data passed to the `text` - outputfunc. + outputfunc. The message will be parsed for `{key}` formatting and + `$You/$you()/$You(key)` and `$conj(verb)` inline function callables. + The `key` is taken from the `mapping` kwarg {"key": object, ...}`. + The `mapping[key].get_display_name(looker=recipient)` will be called + for that key for every recipient of the string. exclude (list, optional): A list of objects not to send to. from_obj (Object, optional): An object designated as the "sender" of the message. See `DefaultObject.msg()` for more info. mapping (dict, optional): A mapping of formatting keys - `{"key":<object>, "key2":<object2>,...}. The keys - must match `{key}` markers in the `text` if this is a string or - in the internal `message` if `text` is a tuple. These - formatting statements will be - replaced by the return of `<object>.get_display_name(looker)` - for every looker in contents that receives the - message. This allows for every object to potentially - get its own customized string. - Keyword Args: - Keyword arguments will be passed on to `obj.msg()` for all - messaged objects. + `{"key":<object>, "key2":<object2>,...}. + The keys must either match `{key}` or `$You(key)/$you(key)` markers + in the `text` string. If `<object>` doesn't have a `get_display_name` + method, it will be returned as a string. If not set, a key `you` will + be auto-added to point to `from_obj` if given, otherwise to `self`. + **kwargs: Keyword arguments will be passed on to `obj.msg()` for all + messaged objects. Notes: - The `mapping` argument is required if `message` contains - {}-style format syntax. The keys of `mapping` should match - named format tokens, and its values will have their - `get_display_name()` function called for each object in - the room before substitution. If an item in the mapping does - not have `get_display_name()`, its string value will be used. + For 'actor-stance' reporting (You say/Name says), use the + `$You()/$you()/$You(key)` and `$conj(verb)` (verb-conjugation) + inline callables. This will use the respective `get_display_name()` + for all onlookers except for `from_obj or self`, which will become + 'You/you'. If you use `$You/you(key)`, the key must be in `mapping`. - Example: - Say Char is a Character object and Npc is an NPC object: + For 'director-stance' reporting (Name says/Name says), use {key} + syntax directly. For both `{key}` and `You/you(key)`, + `mapping[key].get_display_name(looker=recipient)` may be called + depending on who the recipient is. - char.location.msg_contents( - "{attacker} kicks {defender}", - mapping=dict(attacker=char, defender=npc), exclude=(char, npc)) + Examples: - This will result in everyone in the room seeing 'Char kicks NPC' - where everyone may potentially see different results for Char and Npc - depending on the results of `char.get_display_name(looker)` and - `npc.get_display_name(looker)` for each particular onlooker + Let's assume + - `player1.key -> "Player1"`, + `player1.get_display_name(looker=player2) -> "The First girl"` + - `player2.key -> "Player2"`, + `player2.get_display_name(looker=player1) -> "The Second girl"` + + Actor-stance: + :: + + char.location.msg_contents( + "$You() $conj(attack) $you(defender).", + mapping={"defender": player2}) + + - player1 will see `You attack The Second girl.` + - player2 will see 'The First girl attacks you.' + + Director-stance: + :: + + char.location.msg_contents( + "{attacker} attacks {defender}.", + mapping={"attacker:player1, "defender":player2}) + + - player1 will see: 'Player1 attacks The Second girl.' + - player2 will see: 'The First girl attacks Player2' """ # we also accept an outcommand on the form (message, {kwargs}) is_outcmd = text and is_iter(text) inmessage = text[0] if is_outcmd else text outkwargs = text[1] if is_outcmd and len(text) > 1 else {} + mapping = mapping or {} + you = from_obj or self + + if 'you' not in mapping: + mapping[you] = you contents = self.contents if exclude: exclude = make_iter(exclude) contents = [obj for obj in contents if obj not in exclude] - for obj in contents: - if mapping: - substitutions = { - t: sub.get_display_name(obj) if hasattr(sub, "get_display_name") else str(sub) - for t, sub in mapping.items() - } - outmessage = inmessage.format(**substitutions) - else: - outmessage = inmessage - obj.msg(text=(outmessage, outkwargs), from_obj=from_obj, **kwargs)
        + + for receiver in contents: + + # actor-stance replacements + inmessage = _MSG_CONTENTS_PARSER.parse( + inmessage, raise_errors=True, return_string=True, + caller=you, receiver=receiver, mapping=mapping) + + # director-stance replacements + outmessage = inmessage.format( + **{key: obj.get_display_name(looker=receiver) + if hasattr(obj, "get_display_name") else str(obj) + for key, obj in mapping.items()}) + + receiver.msg(text=(outmessage, outkwargs), from_obj=from_obj, **kwargs)
        [docs] def move_to( self, @@ -838,7 +910,7 @@ self.msg("%s%s" % (string, "" if err is None else " (%s)" % err)) return - errtxt = _("Couldn't perform move ('%s'). Contact an admin.") + errtxt = _("Couldn't perform move ({err}). Contact an admin.") if not emit_to_obj: emit_to_obj = self @@ -857,10 +929,10 @@ # Before the move, call eventual pre-commands. if move_hooks: try: - if not self.at_before_move(destination): + if not self.at_before_move(destination, **kwargs): return False except Exception as err: - logerr(errtxt % "at_before_move()", err) + logerr(errtxt.format(err="at_before_move()"), err) return False # Save the old location @@ -869,9 +941,9 @@ # Call hook on source location if move_hooks and source_location: try: - source_location.at_object_leave(self, destination) + source_location.at_object_leave(self, destination, **kwargs) except Exception as err: - logerr(errtxt % "at_object_leave()", err) + logerr(errtxt.format(err="at_object_leave()"), err) return False if not quiet: @@ -879,14 +951,14 @@ try: self.announce_move_from(destination, **kwargs) except Exception as err: - logerr(errtxt % "at_announce_move()", err) + logerr(errtxt.format(err="at_announce_move()"), err) return False # Perform move try: self.location = destination except Exception as err: - logerr(errtxt % "location change", err) + logerr(errtxt.format(err="location change"), err) return False if not quiet: @@ -894,25 +966,25 @@ try: self.announce_move_to(source_location, **kwargs) except Exception as err: - logerr(errtxt % "announce_move_to()", err) + logerr(errtxt.format(err="announce_move_to()"), err) return False if move_hooks: # Perform eventual extra commands on the receiving location # (the object has already arrived at this point) try: - destination.at_object_receive(self, source_location) + destination.at_object_receive(self, source_location, **kwargs) except Exception as err: - logerr(errtxt % "at_object_receive()", err) + logerr(errtxt.format(err="at_object_receive()"), err) return False # Execute eventual extra commands on this object after moving it # (usually calling 'look') if move_hooks: try: - self.at_after_move(source_location) + self.at_after_move(source_location, **kwargs) except Exception as err: - logerr(errtxt % "at_after_move", err) + logerr(errtxt.format(err="at_after_move"), err) return False return True
        @@ -920,6 +992,7 @@ """ Destroys all of the exits and any exits pointing to this object as a destination. + """ for out_exit in [exi for exi in ObjectDB.objects.get_contents(self) if exi.db_destination]: out_exit.delete() @@ -930,6 +1003,7 @@ """ Moves all objects (accounts/things) to their home location or to default home. + """ # Gather up everything that thinks this is its location. default_home_id = int(settings.DEFAULT_HOME.lstrip("#")) @@ -939,8 +1013,8 @@ # we are deleting default home! default_home = None except Exception: - string = _("Could not find default home '(#%d)'.") - logger.log_err(string % default_home_id) + string = _("Could not find default home '(#{dbid})'.") + logger.log_err(string.format(dbid=default_home_id)) default_home = None for obj in self.contents: @@ -952,18 +1026,17 @@ # If for some reason it's still None... if not home: - string = "Missing default home, '%s(#%d)' " - string += "now has a null location." obj.location = None obj.msg(_("Something went wrong! You are dumped into nowhere. Contact an admin.")) - logger.log_err(string % (obj.name, obj.dbid)) + logger.log_err("Missing default home - '{name}(#{dbid})' now " + "has a null location.".format(name=obj.name, dbid=obj.dbid)) return if obj.has_account: if home: string = "Your current location has ceased to exist," - string += " moving you to %s(#%d)." - obj.msg(_(string) % (home.name, home.dbid)) + string += " moving you to (#{dbid})." + obj.msg(_(string).format(dbid=home.dbid)) else: # Famous last words: The account should never see this. string = "This place should not exist ... contact an admin." @@ -1070,8 +1143,8 @@
        [docs] def at_object_post_copy(self, new_obj, **kwargs): """ - Called by DefaultObject.copy(). Meant to be overloaded. In case there's extra data not covered by - .copy(), this can be used to deal with it. + Called by DefaultObject.copy(). Meant to be overloaded. In case there's extra data not + covered by .copy(), this can be used to deal with it. Args: new_obj (Object): The new Copy of this object. @@ -1119,7 +1192,7 @@ self.account = None for script in _ScriptDB.objects.get_all_scripts_on_obj(self): - script.stop() + script.delete() # Destroy any exits to and from this room, if any self.clear_exits() @@ -1512,7 +1585,8 @@ if not source_location and self.location.has_account: # This was created from nowhere and added to an account's # inventory; it's probably the result of a create command. - string = "You now have %s in your possession." % self.get_display_name(self.location) + string = _("You now have {name} in your possession.").format( + name=self.get_display_name(self.location)) self.location.msg(string) return @@ -1520,9 +1594,9 @@ if msg: string = msg else: - string = "{object} arrives to {destination} from {origin}." + string = _("{object} arrives to {destination} from {origin}.") else: - string = "{object} arrives to {destination}." + string = _("{object} arrives to {destination}.") origin = source_location destination = self.location @@ -1705,20 +1779,26 @@ **kwargs (dict): Arbitrary, optional arguments for users overriding the call (unused by default). """ + + def filter_visible(obj_list): + # Helper method to determine if objects are visible to the looker. + return [obj for obj in obj_list if obj != looker and obj.access(looker, "view")] + if not looker: return "" + # get and identify all objects - visible = (con for con in self.contents if con != looker and con.access(looker, "view")) - exits, users, things = [], [], defaultdict(list) - for con in visible: - key = con.get_display_name(looker) - if con.destination: - exits.append(key) - elif con.has_account: - users.append("|c%s|n" % key) - else: - # things can be pluralized - things[key].append(con) + exits_list = filter_visible(self.contents_get(content_type="exit")) + users_list = filter_visible(self.contents_get(content_type="character")) + things_list = filter_visible(self.contents_get(content_type="object")) + + things = defaultdict(list) + + for thing in things_list: + things[thing.key].append(thing) + users = [f"|c{user.key}|n" for user in users_list] + exits = [ex.key for ex in exits_list] + # get description, build string string = "|c%s|n\n" % self.get_display_name(looker) desc = self.db.desc @@ -1923,7 +2003,8 @@ a say. This is sent by the whisper command by default. Other verbal commands could use this hook in similar ways. - receivers (Object or iterable): If set, this is the target or targets for the say/whisper. + receivers (Object or iterable): If set, this is the target or targets for the + say/whisper. Returns: message (str): The (possibly modified) text to be spoken. @@ -1954,8 +2035,8 @@ msg_self (bool or str, optional): If boolean True, echo `message` to self. If a string, return that message. If False or unset, don't echo to self. msg_location (str, optional): The message to echo to self's location. - receivers (Object or iterable, optional): An eventual receiver or receivers of the message - (by default only used by whispers). + receivers (Object or iterable, optional): An eventual receiver or receivers of the + message (by default only used by whispers). msg_receivers(str): Specific message to pass to the receiver(s). This will parsed with the {receiver} placeholder replaced with the given receiver. Keyword Args: @@ -1990,8 +2071,7 @@ msg_type = "whisper" msg_self = ( '{self} whisper to {all_receivers}, "|n{speech}|n"' - if msg_self is True - else msg_self + if msg_self is True else msg_self ) msg_receivers = msg_receivers or '{object} whispers: "|n{speech}|n"' msg_location = None @@ -2078,6 +2158,9 @@ """ + # Tuple of types used for indexing inventory contents. Characters generally wouldn't be in + # anyone's inventory, but this also governs displays in room contents. + _content_types = ("character",) # lockstring of newly created rooms, for easy overloading. # Will be formatted with the appropriate attributes. lockstring = ( @@ -2117,6 +2200,13 @@ # If no typeclass supplied, use this class kwargs["typeclass"] = kwargs.pop("typeclass", cls) + # Normalize to latin characters and validate, if necessary, the supplied key + key = cls.normalize_name(key) + + if not cls.validate_name(key): + errors.append(_("Invalid character name.")) + return obj, errors + # Set the supplied key as the name of the intended object kwargs["key"] = key @@ -2133,7 +2223,7 @@ # Check to make sure account does not have too many chars if account: if len(account.characters) >= settings.MAX_NR_CHARACTERS: - errors.append("There are too many characters associated with this account.") + errors.append(_("There are too many characters associated with this account.")) return obj, errors # Create the Character @@ -2149,7 +2239,8 @@ # Add locks if not locks and account: - # Allow only the character itself and the creator account to puppet this character (and Developers). + # Allow only the character itself and the creator account to puppet this character + # (and Developers). locks = cls.lockstring.format(**{"character_id": obj.id, "account_id": account.id}) elif not locks and not account: locks = cls.lockstring.format(**{"character_id": obj.id, "account_id": -1}) @@ -2158,14 +2249,47 @@ # If no description is set, set a default description if description or not obj.db.desc: - obj.db.desc = description if description else "This is a character." + obj.db.desc = description if description else _("This is a character.") except Exception as e: - errors.append("An error occurred while creating this '%s' object." % key) + errors.append(f"An error occurred while creating object '{key} object.") logger.log_err(e) return obj, errors
        +
        [docs] @classmethod + def normalize_name(cls, name): + """ + Normalize the character name prior to creating. Note that this should be refactored to + support i18n for non-latin scripts, but as we (currently) have no bug reports requesting + better support of non-latin character sets, requiring character names to be latinified is an + acceptable option. + + Args: + name (str) : The name of the character + + Returns: + latin_name (str) : A valid name. + """ + + from evennia.utils.utils import latinify + + latin_name = latinify(name, default="X") + return latin_name
        + +
        [docs] @classmethod + def validate_name(cls, name): + """ Validate the character name prior to creating. Overload this function to add custom validators + + Args: + name (str) : The name of the character + Returns: + valid (bool) : True if character creation should continue; False if it should fail + + """ + + return True # Default validator does not perform any operations
        +
        [docs] def basetype_setup(self): """ Setup character-specific security. @@ -2197,6 +2321,7 @@ Args: account (Account): This is the connecting account. session (Session): Session controlling the connection. + """ if ( self.location is None @@ -2210,7 +2335,8 @@ self.db.prelogout_location = self.location # save location again to be sure. else: account.msg( - "|r%s has no location and no home is set.|n" % self, session=session + _("|r{obj} has no location and no home is set.|n").format(obj=self), + session=session ) # Note to set home.
        [docs] def at_post_puppet(self, **kwargs): @@ -2228,11 +2354,12 @@ puppeting this Object. """ - self.msg("\nYou become |c%s|n.\n" % self.name) + self.msg(_("\nYou become |c{name}|n.\n").format(name=self.key)) self.msg((self.at_look(self.location), {"type": "look"}), options=None) def message(obj, from_obj): - obj.msg("%s has entered the game." % self.get_display_name(obj), from_obj=from_obj) + obj.msg(_("{name} has entered the game.").format(name=self.get_display_name(obj)), + from_obj=from_obj) self.location.for_contents(message, exclude=[self], from_obj=self)
        @@ -2255,7 +2382,8 @@ if self.location: def message(obj, from_obj): - obj.msg("%s has left the game." % self.get_display_name(obj), from_obj=from_obj) + obj.msg(_("{name} has left the game.").format(name=self.get_display_name(obj)), + from_obj=from_obj) self.location.for_contents(message, exclude=[self], from_obj=self) self.db.prelogout_location = self.location @@ -2266,6 +2394,7 @@ """ Returns the idle time of the least idle session in seconds. If no sessions are connected it returns nothing. + """ idle = [session.cmd_last_visible for session in self.sessions.all()] if idle: @@ -2277,6 +2406,7 @@ """ Returns the maximum connection time of all connected sessions in seconds. Returns nothing if there are no sessions. + """ conn = [session.conn_time for session in self.sessions.all()] if conn: @@ -2294,6 +2424,10 @@ location is always `None`. """ + # A tuple of strings used for indexing this object inside an inventory. + # Generally, a room isn't expected to HAVE a location, but maybe in some games? + _content_types = ("room",) + # lockstring of newly created rooms, for easy overloading. # Will be formatted with the {id} of the creating object. lockstring = ( @@ -2366,7 +2500,7 @@ # If no description is set, set a default description if description or not obj.db.desc: - obj.db.desc = description if description else "This is a room." + obj.db.desc = description if description else _("This is a room.") except Exception as e: errors.append("An error occurred while creating this '%s' object." % key) @@ -2428,7 +2562,9 @@ overriding the call (unused by default). Returns: - A string with identifying information to disambiguate the command, conventionally with a preceding space. + A string with identifying information to disambiguate the command, conventionally with a + preceding space. + """ if self.obj.destination: return " (exit to %s)" % self.obj.destination.get_display_name(caller) @@ -2452,6 +2588,7 @@ """ + _content_types = ("exit",) exit_command = ExitCommand priority = 101 @@ -2569,7 +2706,7 @@ # If no description is set, set a default description if description or not obj.db.desc: - obj.db.desc = description if description else "This is an exit." + obj.db.desc = description if description else _("This is an exit.") except Exception as e: errors.append("An error occurred while creating this '%s' object." % key) @@ -2666,7 +2803,7 @@ read for an error string instead. """ - traversing_object.msg("You cannot go there.")
        + traversing_object.msg(_("You cannot go there."))
        @@ -2704,7 +2841,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -2723,6 +2859,7 @@ +
        develop branch
        @@ -218,9 +219,7 @@ if kwargs.get("test_parse", True): out.append(" Simulating prototype-func parsing ...") - err, parsed_value = protlib.protfunc_parser(value, testing=True) - if err: - out.append(" |yPython `literal_eval` warning: {}|n".format(err)) + parsed_value = protlib.protfunc_parser(value, testing=True, prototype=prototype) if parsed_value != value: out.append( " |g(Example-)value when parsed ({}):|n {}".format(type(parsed_value), parsed_value) @@ -305,7 +304,7 @@ def _format_protfuncs(): out = [] sorted_funcs = [ - (key, func) for key, func in sorted(protlib.PROT_FUNCS.items(), key=lambda tup: tup[0]) + (key, func) for key, func in sorted(protlib.FUNC_PARSER.callables.items(), key=lambda tup: tup[0]) ] for protfunc_name, protfunc in sorted_funcs: out.append( @@ -2156,7 +2155,8 @@ objects = kwargs["objects"] back_node = kwargs["back_node"] diff = kwargs.get("diff", None) - num_changed = spawner.batch_update_objects_with_prototype(prototype, diff=diff, objects=objects) + num_changed = spawner.batch_update_objects_with_prototype(prototype, diff=diff, objects=objects, + caller=caller) caller.msg("|g{num} objects were updated successfully.|n".format(num=num_changed)) return back_node @@ -2524,7 +2524,7 @@ if not prototype.get("location"): prototype["location"] = caller - obj = spawner.spawn(prototype) + obj = spawner.spawn(prototype, caller=caller) if obj: obj = obj[0] text = "|gNew instance|n {key} ({dbref}) |gspawned at location |n{loc}|n|g.|n".format( @@ -2835,7 +2835,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -2854,6 +2853,7 @@ +
        develop branch
        @@ -40,35 +41,30 @@

        Source code for evennia.prototypes.protfuncs

         """
        -Protfuncs are function-strings embedded in a prototype and allows for a builder to create a
        -prototype with custom logics without having access to Python. The Protfunc is parsed using the
        -inlinefunc parser but is fired at the moment the spawning happens, using the creating object's
        -session as input.
        +Protfuncs are FuncParser-callables that can be embedded in a prototype to
        +provide custom logic without having access to Python. The protfunc is parsed at
        +the time of spawning, using the creating object's session as input. If the
        +protfunc returns a non-string, this is what will be added to the prototype.
         
         In the prototype dict, the protfunc is specified as a string inside the prototype, e.g.:
         
             { ...
         
        -    "key": "$funcname(arg1, arg2, ...)"
        +    "key": "$funcname(args, kwargs)"
         
             ...  }
         
        -and multiple functions can be nested (no keyword args are supported). The result will be used as the
        -value for that prototype key for that individual spawn.
        -
        -Available protfuncs are callables in one of the modules of `settings.PROT_FUNC_MODULES`. They
        -are specified as functions
        +Available protfuncs are either all callables in one of the modules of `settings.PROT_FUNC_MODULES`
        +or all callables added to a dict FUNCPARSER_CALLABLES in such a module.
         
             def funcname (*args, **kwargs)
         
        -where *args are the arguments given in the prototype, and **kwargs are inserted by Evennia:
        +At spawn-time the spawner passes the following extra kwargs into each callable (in addition to
        +what is added in the call itself):
         
             - session (Session): The Session of the entity spawning using this prototype.
             - prototype (dict): The dict this protfunc is a part of.
             - current_key (str): The active key this value belongs to in the prototype.
        -    - testing (bool): This is set if this function is called as part of the prototype validation; if
        -        set, the protfunc should take care not to perform any persistent actions, such as operate on
        -        objects or add things to the database.
         
         Any traceback raised by this function will be handled at the time of spawning and abort the spawn
         before any object is created/updated. It must otherwise return the value to store for the specified
        @@ -76,315 +72,33 @@
         
         """
         
        -from ast import literal_eval
        -from random import randint as base_randint, random as base_random, choice as base_choice
        -import re
        -
        -from evennia.utils import search
        -from evennia.utils.utils import justify as base_justify, is_iter, to_str
        -
        -_PROTLIB = None
        -
        -_RE_DBREF = re.compile(r"\#[0-9]+")
        +from evennia.utils import funcparser
         
         
        -# default protfuncs
        -
        -
        -
        [docs]def random(*args, **kwargs): +
        [docs]def protfunc_callable_protkey(*args, **kwargs): """ - Usage: $random() - Returns a random value in the interval [0, 1) - - """ - return base_random()
        - - -
        [docs]def randint(*args, **kwargs): - """ - Usage: $randint(start, end) - Returns random integer in interval [start, end] - - """ - if len(args) != 2: - raise TypeError("$randint needs two arguments - start and end.") - start, end = int(args[0]), int(args[1]) - return base_randint(start, end)
        - - -
        [docs]def left_justify(*args, **kwargs): - """ - Usage: $left_justify(<text>) - Returns <text> left-justified. - - """ - if args: - return base_justify(args[0], align="l") - return ""
        - - -
        [docs]def right_justify(*args, **kwargs): - """ - Usage: $right_justify(<text>) - Returns <text> right-justified across screen width. - - """ - if args: - return base_justify(args[0], align="r") - return ""
        - - -
        [docs]def center_justify(*args, **kwargs): - - """ - Usage: $center_justify(<text>) - Returns <text> centered in screen width. - - """ - if args: - return base_justify(args[0], align="c") - return ""
        - - -
        [docs]def choice(*args, **kwargs): - """ - Usage: $choice(val, val, val, ...) - Returns one of the values randomly - """ - if args: - return base_choice(args) - return ""
        - - -
        [docs]def full_justify(*args, **kwargs): - - """ - Usage: $full_justify(<text>) - Returns <text> filling up screen width by adding extra space. - - """ - if args: - return base_justify(args[0], align="f") - return ""
        - - -
        [docs]def protkey(*args, **kwargs): - """ - Usage: $protkey(<key>) + Usage: $protkey(keyname) Returns the value of another key in this prototoype. Will raise an error if the key is not found in this prototype. """ - if args: - prototype = kwargs["prototype"] - return prototype[args[0].strip()]
        + if not args: + return "" + + prototype = kwargs.get("prototype", {}) + prot_value = prototype[args[0]] + try: + return funcparser.funcparser_callable_eval(prot_value, **kwargs) + except funcparser.ParsingError: + return prot_value
        -
        [docs]def add(*args, **kwargs): - """ - Usage: $add(val1, val2) - Returns the result of val1 + val2. Values must be - valid simple Python structures possible to add, - such as numbers, lists etc. - - """ - if len(args) > 1: - val1, val2 = args[0], args[1] - # try to convert to python structures, otherwise, keep as strings - try: - val1 = literal_eval(val1.strip()) - except Exception: - pass - try: - val2 = literal_eval(val2.strip()) - except Exception: - pass - return val1 + val2 - raise ValueError("$add requires two arguments.")
        - - -
        [docs]def sub(*args, **kwargs): - """ - Usage: $del(val1, val2) - Returns the value of val1 - val2. Values must be - valid simple Python structures possible to - subtract. - - """ - if len(args) > 1: - val1, val2 = args[0], args[1] - # try to convert to python structures, otherwise, keep as strings - try: - val1 = literal_eval(val1.strip()) - except Exception: - pass - try: - val2 = literal_eval(val2.strip()) - except Exception: - pass - return val1 - val2 - raise ValueError("$sub requires two arguments.")
        - - -
        [docs]def mult(*args, **kwargs): - """ - Usage: $mul(val1, val2) - Returns the value of val1 * val2. The values must be - valid simple Python structures possible to - multiply, like strings and/or numbers. - - """ - if len(args) > 1: - val1, val2 = args[0], args[1] - # try to convert to python structures, otherwise, keep as strings - try: - val1 = literal_eval(val1.strip()) - except Exception: - pass - try: - val2 = literal_eval(val2.strip()) - except Exception: - pass - return val1 * val2 - raise ValueError("$mul requires two arguments.")
        - - -
        [docs]def div(*args, **kwargs): - """ - Usage: $div(val1, val2) - Returns the value of val1 / val2. Values must be numbers and - the result is always a float. - - """ - if len(args) > 1: - val1, val2 = args[0], args[1] - # try to convert to python structures, otherwise, keep as strings - try: - val1 = literal_eval(val1.strip()) - except Exception: - pass - try: - val2 = literal_eval(val2.strip()) - except Exception: - pass - return val1 / float(val2) - raise ValueError("$mult requires two arguments.")
        - - -
        [docs]def toint(*args, **kwargs): - """ - Usage: $toint(<number>) - Returns <number> as an integer. - """ - if args: - val = args[0] - try: - return int(literal_eval(val.strip())) - except ValueError: - return val - raise ValueError("$toint requires one argument.")
        - - -
        [docs]def eval(*args, **kwargs): - """ - Usage $eval(<expression>) - Returns evaluation of a simple Python expression. The string may *only* consist of the following - Python literal structures: strings, numbers, tuples, lists, dicts, booleans, - and None. The strings can also contain #dbrefs. Escape embedded protfuncs as $$protfunc(..) - - those will then be evaluated *after* $eval. - - """ - global _PROTLIB - if not _PROTLIB: - from evennia.prototypes import prototypes as _PROTLIB - - string = ",".join(args) - struct = literal_eval(string) - - if isinstance(struct, str): - # we must shield the string, otherwise it will be merged as a string and future - # literal_evas will pick up e.g. '2' as something that should be converted to a number - struct = '"{}"'.format(struct) - - # convert any #dbrefs to objects (also in nested structures) - struct = _PROTLIB.value_to_obj_or_any(struct) - - return struct
        - - -def _obj_search(*args, **kwargs): - "Helper function to search for an object" - - query = "".join(args) - session = kwargs.get("session", None) - return_list = kwargs.pop("return_list", False) - account = None - - if session: - account = session.account - - targets = search.search_object(query) - - if return_list: - retlist = [] - if account: - for target in targets: - if target.access(account, target, "control"): - retlist.append(target) - else: - retlist = targets - return retlist - else: - # single-match - if not targets: - raise ValueError("$obj: Query '{}' gave no matches.".format(query)) - if len(targets) > 1: - raise ValueError( - "$obj: Query '{query}' gave {nmatches} matches. Limit your " - "query or use $objlist instead.".format(query=query, nmatches=len(targets)) - ) - target = targets[0] - if account: - if not target.access(account, target, "control"): - raise ValueError( - "$obj: Obj {target}(#{dbref} cannot be added - " - "Account {account} does not have 'control' access.".format( - target=target.key, dbref=target.id, account=account - ) - ) - return target - - -
        [docs]def obj(*args, **kwargs): - """ - Usage $obj(<query>) - Returns one Object searched globally by key, alias or #dbref. Error if more than one. - - """ - obj = _obj_search(return_list=False, *args, **kwargs) - if obj: - return "#{}".format(obj.id) - return "".join(args)
        - - -
        [docs]def objlist(*args, **kwargs): - """ - Usage $objlist(<query>) - Returns list with one or more Objects searched globally by key, alias or #dbref. - - """ - return ["#{}".format(obj.id) for obj in _obj_search(return_list=True, *args, **kwargs)]
        - - -
        [docs]def dbref(*args, **kwargs): - """ - Usage $dbref(<#dbref>) - Validate that a #dbref input is valid. - """ - if not args or len(args) < 1 or _RE_DBREF.match(args[0]) is None: - raise ValueError("$dbref requires a valid #dbref argument.") - - return obj(args[0])
        +# this is picked up by FuncParser +FUNCPARSER_CALLABLES = { + "protkey": protfunc_callable_protkey, + **funcparser.FUNCPARSER_CALLABLES, + **funcparser.SEARCHING_CALLABLES, +}
        @@ -422,7 +136,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -441,6 +154,7 @@ +
        develop branch
        @@ -48,10 +49,10 @@ import hashlib import time -from ast import literal_eval from django.conf import settings -from django.db.models import Q, Subquery +from django.db.models import Q from django.core.paginator import Paginator +from django.utils.translation import gettext as _ from evennia.scripts.scripts import DefaultScript from evennia.objects.models import ObjectDB from evennia.typeclasses.attributes import Attribute @@ -59,19 +60,17 @@ from evennia.utils.evmore import EvMore from evennia.utils.utils import ( all_from_module, + variable_from_module, make_iter, is_iter, dbid_to_obj, - callables_from_module, - get_all_typeclasses, - to_str, - dbref, justify, class_from_module, ) from evennia.locks.lockhandler import validate_lockstring, check_lockstring from evennia.utils import logger -from evennia.utils import inlinefuncs, dbserialize +from evennia.utils.funcparser import FuncParser +from evennia.utils import dbserialize from evennia.utils.evtable import EvTable @@ -97,13 +96,18 @@ "tags", "attrs", ) +_ERRSTR = _("Error") +_WARNSTR = _("Warning") PROTOTYPE_TAG_CATEGORY = "from_prototype" _PROTOTYPE_TAG_META_CATEGORY = "db_prototype" -PROT_FUNCS = {} _PROTOTYPE_FALLBACK_LOCK = "spawn:all();edit:all()" +# the protfunc parser +FUNC_PARSER = FuncParser(settings.PROT_FUNC_MODULES) + +
        [docs]class PermissionError(RuntimeError): pass
        @@ -120,7 +124,6 @@ """ Homogenize the more free-form prototype supported pre Evennia 0.7 into the stricter form. - Args: prototype (dict): Prototype. custom_keys (list, optional): Custom keys which should not be interpreted as attrs, beyond @@ -195,11 +198,30 @@ # to remove a default prototype, override it with an empty dict. # internally we store as (key, desc, locks, tags, prototype_dict) prots = [] - for variable_name, prot in all_from_module(mod).items(): - if isinstance(prot, dict): - if "prototype_key" not in prot: - prot["prototype_key"] = variable_name.lower() + + prototype_list = variable_from_module(mod, "PROTOTYPE_LIST") + if prototype_list: + # found mod.PROTOTYPE_LIST - this should be a list of valid + # prototype dicts that must have 'prototype_key' set. + for prot in prototype_list: + if not isinstance(prot, dict): + logger.log_err(f"Prototype read from {mod}.PROTOTYPE_LIST " + f"is not a dict (skipping): {prot}") + continue + elif "prototype_key" not in prot: + logger.log_err(f"Prototype read from {mod}.PROTOTYPE_LIST " + f"is missing the 'prototype_key' (skipping): {prot}") + continue prots.append((prot["prototype_key"], homogenize_prototype(prot))) + else: + # load all global dicts in module as prototypes. If the prototype_key + # is not given, the variable name will be used. + for variable_name, prot in all_from_module(mod).items(): + if isinstance(prot, dict): + if "prototype_key" not in prot: + prot["prototype_key"] = variable_name.lower() + prots.append((prot["prototype_key"], homogenize_prototype(prot))) + # assign module path to each prototype_key for easy reference _MODULE_PROTOTYPE_MODULES.update({prototype_key.lower(): mod for prototype_key, _ in prots}) # make sure the prototype contains all meta info @@ -228,6 +250,7 @@
        [docs]class DbPrototype(DefaultScript): """ This stores a single prototype, in an Attribute `prototype`. + """
        [docs] def at_script_creation(self): @@ -279,7 +302,7 @@ prototype_key = in_prototype.get("prototype_key") if not prototype_key: - raise ValidationError("Prototype requires a prototype_key") + raise ValidationError(_("Prototype requires a prototype_key")) prototype_key = str(prototype_key).lower() @@ -287,7 +310,8 @@ if prototype_key in _MODULE_PROTOTYPES: mod = _MODULE_PROTOTYPE_MODULES.get(prototype_key, "N/A") raise PermissionError( - "{} is a read-only prototype " "(defined as code in {}).".format(prototype_key, mod) + _("{protkey} is a read-only prototype " "(defined as code in {module}).").format( + protkey=prototype_key, module=mod) ) # make sure meta properties are included with defaults @@ -354,20 +378,23 @@ if prototype_key in _MODULE_PROTOTYPES: mod = _MODULE_PROTOTYPE_MODULES.get(prototype_key.lower(), "N/A") raise PermissionError( - "{} is a read-only prototype " "(defined as code in {}).".format(prototype_key, mod) + _("{protkey} is a read-only prototype " "(defined as code in {module}).").format( + protkey=prototype_key, module=mod) ) stored_prototype = DbPrototype.objects.filter(db_key__iexact=prototype_key) if not stored_prototype: - raise PermissionError("Prototype {} was not found.".format(prototype_key)) + raise PermissionError(_("Prototype {prototype_key} was not found.").format( + prototype_key=prototype_key)) stored_prototype = stored_prototype[0] if caller: if not stored_prototype.access(caller, "edit"): raise PermissionError( - "{} needs explicit 'edit' permissions to " - "delete prototype {}.".format(caller, prototype_key) + _("{caller} needs explicit 'edit' permissions to " + "delete prototype {prototype_key}.").format( + caller=caller, prototype_key=prototype_key) ) stored_prototype.delete() return True
        @@ -466,7 +493,11 @@ nmodules = len(module_prototypes) ndbprots = db_matches.count() if nmodules + ndbprots != 1: - raise KeyError(f"Found {nmodules + ndbprots} matching prototypes {module_prototypes}.") + raise KeyError(_( + "Found {num} matching prototypes {module_prototypes}.").format( + num=nmodules + ndbprots, + module_prototypes=module_prototypes) + ) if return_iterators: # trying to get the entire set of prototypes - we must paginate @@ -496,10 +527,14 @@ Listing 1000+ prototypes can be very slow. So we customize EvMore to display an EvTable per paginated page rather than to try creating an EvTable for the entire dataset and then paginate it. + """
        [docs] def __init__(self, caller, *args, session=None, **kwargs): - """Store some extra properties on the EvMore class""" + """ + Store some extra properties on the EvMore class + + """ self.show_non_use = kwargs.pop("show_non_use", False) self.show_non_edit = kwargs.pop("show_non_edit", False) super().__init__(caller, *args, session=session, **kwargs)
        @@ -510,6 +545,7 @@ and we must handle these separately since they cannot be paginated in the same way. We will build the prototypes so that the db-prototypes come first (they are likely the most volatile), followed by the mod-prototypes. + """ dbprot_query, modprot_list = inp # set the number of entries per page to half the reported height of the screen @@ -531,6 +567,7 @@ """ The listing is separated in db/mod prototypes, so we need to figure out which one to pick based on the page number. Also, pageno starts from 0. + """ dbprot_pages, modprot_list = self._data @@ -539,15 +576,16 @@ else: # get the correct slice, adjusted for the db-prototypes pageno = max(0, pageno - self._npages_db) - return modprot_list[pageno * self.height : pageno * self.height + self.height]
        + return modprot_list[pageno * self.height: pageno * self.height + self.height]
        [docs] def page_formatter(self, page): - """Input is a queryset page from django.Paginator""" + """ + Input is a queryset page from django.Paginator + + """ caller = self._caller # get use-permissions of readonly attributes (edit is always False) - display_tuples = [] - table = EvTable( "|wKey|n", "|wSpawn/Edit|n", @@ -616,7 +654,7 @@ dbprot_query, modprot_list = search_prototype(key, tags, return_iterators=True) if not dbprot_query and not modprot_list: - caller.msg("No prototypes found.", session=session) + caller.msg(_("No prototypes found."), session=session) return None # get specific prototype (one value or exception) @@ -667,7 +705,7 @@ protkey = protkey and protkey.lower() or prototype.get("prototype_key", None) if strict and not bool(protkey): - _flags["errors"].append("Prototype lacks a `prototype_key`.") + _flags["errors"].append(_("Prototype lacks a 'prototype_key'.")) protkey = "[UNSET]" typeclass = prototype.get("typeclass") @@ -676,12 +714,13 @@ if strict and not (typeclass or prototype_parent): if is_prototype_base: _flags["errors"].append( - "Prototype {} requires `typeclass` " "or 'prototype_parent'.".format(protkey) + _("Prototype {protkey} requires `typeclass` " "or 'prototype_parent'.").format( + protkey=protkey) ) else: _flags["warnings"].append( - "Prototype {} can only be used as a mixin since it lacks " - "a typeclass or a prototype_parent.".format(protkey) + _("Prototype {protkey} can only be used as a mixin since it lacks " + "'typeclass' or 'prototype_parent' keys.").format(protkey=protkey) ) if strict and typeclass: @@ -689,9 +728,9 @@ class_from_module(typeclass) except ImportError as err: _flags["errors"].append( - "{}: Prototype {} is based on typeclass {}, which could not be imported!".format( - err, protkey, typeclass - ) + _("{err}: Prototype {protkey} is based on typeclass {typeclass}, " + "which could not be imported!").format( + err=err, protkey=protkey, typeclass=typeclass) ) # recursively traverse prototype_parent chain @@ -699,19 +738,22 @@ for protstring in make_iter(prototype_parent): protstring = protstring.lower() if protkey is not None and protstring == protkey: - _flags["errors"].append("Prototype {} tries to parent itself.".format(protkey)) + _flags["errors"].append(_("Prototype {protkey} tries to parent itself.").format( + protkey=protkey)) protparent = protparents.get(protstring) if not protparent: _flags["errors"].append( - "Prototype {}'s prototype_parent '{}' was not found.".format(protkey, protstring) + _("Prototype {protkey}'s prototype_parent '{parent}' was not found.").format( + protkey=protkey, parent=protstring) ) if id(prototype) in _flags["visited"]: _flags["errors"].append( - "{} has infinite nesting of prototypes.".format(protkey or prototype) + _("{protkey} has infinite nesting of prototypes.").format( + protkey=protkey or prototype) ) if _flags["errors"]: - raise RuntimeError("Error: " + "\nError: ".join(_flags["errors"])) + raise RuntimeError(f"{_ERRSTR}: " + f"\n{_ERRSTR}: ".join(_flags["errors"])) _flags["visited"].append(id(prototype)) _flags["depth"] += 1 validate_prototype( @@ -726,16 +768,16 @@ # if we get back to the current level without a typeclass it's an error. if strict and is_prototype_base and _flags["depth"] <= 0 and not _flags["typeclass"]: _flags["errors"].append( - "Prototype {} has no `typeclass` defined anywhere in its parent\n " - "chain. Add `typeclass`, or a `prototype_parent` pointing to a " - "prototype with a typeclass.".format(protkey) + _("Prototype {protkey} has no `typeclass` defined anywhere in its parent\n " + "chain. Add `typeclass`, or a `prototype_parent` pointing to a " + "prototype with a typeclass.").format(protkey=protkey) ) if _flags["depth"] <= 0: if _flags["errors"]: - raise RuntimeError("Error: " + "\nError: ".join(_flags["errors"])) + raise RuntimeError(f"{_ERRSTR}:_" + f"\n{_ERRSTR}: ".join(_flags["errors"])) if _flags["warnings"]: - raise RuntimeWarning("Warning: " + "\nWarning: ".join(_flags["warnings"])) + raise RuntimeWarning(f"{_WARNSTR}: " + f"\n{_WARNSTR}: ".join(_flags["warnings"])) # make sure prototype_locks are set to defaults prototype_locks = [ @@ -752,18 +794,7 @@ prototype["prototype_locks"] = prototype_locks
        -# Protfunc parsing (in-prototype functions) - -for mod in settings.PROT_FUNC_MODULES: - try: - callables = callables_from_module(mod) - PROT_FUNCS.update(callables) - except ImportError: - logger.log_trace() - raise - - -
        [docs]def protfunc_parser(value, available_functions=None, testing=False, stacktrace=False, **kwargs): +
        [docs]def protfunc_parser(value, available_functions=None, testing=False, stacktrace=False, caller=None, **kwargs): """ Parse a prototype value string for a protfunc and process it. @@ -775,45 +806,27 @@ protfuncs, all other types are returned as-is. available_functions (dict, optional): Mapping of name:protfunction to use for this parsing. If not set, use default sources. - testing (bool, optional): Passed to protfunc. If in a testing mode, some protfuncs may - behave differently. stacktrace (bool, optional): If set, print the stack parsing process of the protfunc-parser. Keyword Args: session (Session): Passed to protfunc. Session of the entity spawning the prototype. protototype (dict): Passed to protfunc. The dict this protfunc is a part of. current_key(str): Passed to protfunc. The key in the prototype that will hold this value. + caller (Object or Account): This is necessary for certain protfuncs that perform object + searches and have to check permissions. any (any): Passed on to the protfunc. Returns: - testresult (tuple): If `testing` is set, returns a tuple (error, result) where error is - either None or a string detailing the error from protfunc_parser or seen when trying to - run `literal_eval` on the parsed string. - any (any): A structure to replace the string on the prototype level. If this is a - callable or a (callable, (args,)) structure, it will be executed as if one had supplied - it to the prototype directly. This structure is also passed through literal_eval so one - can get actual Python primitives out of it (not just strings). It will also identify - eventual object #dbrefs in the output from the protfunc. + any: A structure to replace the string on the prototype leve. Note + that FunctionParser functions $funcname(*args, **kwargs) can return any + data type to insert into the prototype. """ if not isinstance(value, str): return value - available_functions = PROT_FUNCS if available_functions is None else available_functions + result = FUNC_PARSER.parse(value, raise_errors=True, return_str=False, caller=caller, **kwargs) - result = inlinefuncs.parse_inlinefunc( - value, available_funcs=available_functions, stacktrace=stacktrace, testing=testing, **kwargs - ) - - err = None - try: - result = literal_eval(result) - except ValueError: - pass - except Exception as exc: - err = str(exc) - if testing: - return err, result return result
        @@ -828,7 +841,7 @@ clr (str, optional): What coloration tag to use. """ out = [] - for protfunc_name, protfunc in PROT_FUNCS.items(): + for protfunc_name, protfunc in FUNC_PARSER.callables.items(): out.append( "- |c${name}|n - |W{docs}".format( name=protfunc_name, docs=protfunc.__doc__.strip().replace("\n", "") @@ -877,10 +890,10 @@ category=category if category else "|wNone|n" ) out.append( - "{attrkey}{cat_locks} |c=|n {value}".format( + "{attrkey}{cat_locks}{locks} |c=|n {value}".format( attrkey=attrkey, cat_locks=cat_locks, - locks=locks if locks else "|wNone|n", + locks=" |w(locks:|n {locks})".format(locks=locks) if locks else "", value=value, ) ) @@ -953,7 +966,7 @@ return default
        -
        [docs]def init_spawn_value(value, validator=None): +
        [docs]def init_spawn_value(value, validator=None, caller=None): """ Analyze the prototype value and produce a value useful at the point of spawning. @@ -964,6 +977,8 @@ other - will be assigned depending on the variable type validator (callable, optional): If given, this will be called with the value to check and guarantee the outcome is of a given type. + caller (Object or Account): This is necessary for certain protfuncs that perform object + searches and have to check permissions. Returns: any (any): The (potentially pre-processed value to use for this prototype key) @@ -978,7 +993,7 @@ value = validator(value[0](*make_iter(args))) else: value = validator(value) - result = protfunc_parser(value) + result = protfunc_parser(value, caller=caller) if result != value: return validator(result) return result
        @@ -1044,7 +1059,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1063,6 +1077,7 @@ +
        develop branch
        @@ -81,8 +82,8 @@ supported are 'edit' and 'use'. prototype_tags(list, optional): List of tags or tuples (tag, category) used to group prototype in listings - prototype_parent (str, tuple or callable, optional): name (prototype_key) of eventual parent prototype, or - a list of parents, for multiple left-to-right inheritance. + prototype_parent (str, tuple or callable, optional): name (prototype_key) of eventual parent + prototype, or a list of parents, for multiple left-to-right inheritance. prototype: Deprecated. Same meaning as 'parent'. typeclass (str or callable, optional): if not set, will use typeclass of parent prototype or use @@ -179,6 +180,7 @@ import time from django.conf import settings +from django.utils.translation import gettext as _ import evennia from evennia.objects.models import ObjectDB @@ -396,8 +398,8 @@ This is most useful for displaying. implicit_keep (bool, optional): If set, the resulting diff will assume KEEP unless the new prototype explicitly change them. That is, if a key exists in `prototype1` and - not in `prototype2`, it will not be REMOVEd but set to KEEP instead. This is particularly - useful for auto-generated prototypes when updating objects. + not in `prototype2`, it will not be REMOVEd but set to KEEP instead. This is + particularly useful for auto-generated prototypes when updating objects. Returns: diff (dict): A structure detailing how to convert prototype1 to prototype2. All @@ -510,8 +512,8 @@ out.extend(_get_all_nested_diff_instructions(val)) else: raise RuntimeError( - "Diff contains non-dicts that are not on the " - "form (old, new, inst): {}".format(diffpart) + _("Diff contains non-dicts that are not on the " + "form (old, new, action_to_take): {diffpart}").format(diffpart) ) return out @@ -648,7 +650,8 @@ return "\n ".join(line for line in texts if line)
        -
        [docs]def batch_update_objects_with_prototype(prototype, diff=None, objects=None, exact=False): +
        [docs]def batch_update_objects_with_prototype(prototype, diff=None, objects=None, + exact=False, caller=None): """ Update existing objects with the latest version of the prototype. @@ -665,6 +668,7 @@ if it's not set in the prototype. With `exact=True`, all un-specified properties of the objects will be removed if they exist. This will lead to a more accurate 1:1 correlation between the object and the prototype but is usually impractical. + caller (Object or Account, optional): This may be used by protfuncs to do permission checks. Returns: changed (int): The number of objects that had changes applied to them. @@ -716,33 +720,35 @@ do_save = True if key == "key": - obj.db_key = init_spawn_value(val, str) + obj.db_key = init_spawn_value(val, str, caller=caller) elif key == "typeclass": - obj.db_typeclass_path = init_spawn_value(val, str) + obj.db_typeclass_path = init_spawn_value(val, str, caller=caller) elif key == "location": - obj.db_location = init_spawn_value(val, value_to_obj) + obj.db_location = init_spawn_value(val, value_to_obj, caller=caller) elif key == "home": - obj.db_home = init_spawn_value(val, value_to_obj) + obj.db_home = init_spawn_value(val, value_to_obj, caller=caller) elif key == "destination": - obj.db_destination = init_spawn_value(val, value_to_obj) + obj.db_destination = init_spawn_value(val, value_to_obj, caller=caller) elif key == "locks": if directive == "REPLACE": obj.locks.clear() - obj.locks.add(init_spawn_value(val, str)) + obj.locks.add(init_spawn_value(val, str, caller=caller)) elif key == "permissions": if directive == "REPLACE": obj.permissions.clear() - obj.permissions.batch_add(*(init_spawn_value(perm, str) for perm in val)) + obj.permissions.batch_add(*(init_spawn_value(perm, str, caller=caller) + for perm in val)) elif key == "aliases": if directive == "REPLACE": obj.aliases.clear() - obj.aliases.batch_add(*(init_spawn_value(alias, str) for alias in val)) + obj.aliases.batch_add(*(init_spawn_value(alias, str, caller=caller) + for alias in val)) elif key == "tags": if directive == "REPLACE": obj.tags.clear() obj.tags.batch_add( *( - (init_spawn_value(ttag, str), tcategory, tdata) + (init_spawn_value(ttag, str, caller=caller), tcategory, tdata) for ttag, tcategory, tdata in val ) ) @@ -752,8 +758,8 @@ obj.attributes.batch_add( *( ( - init_spawn_value(akey, str), - init_spawn_value(aval, value_to_obj), + init_spawn_value(akey, str, caller=caller), + init_spawn_value(aval, value_to_obj, caller=caller), acategory, alocks, ) @@ -764,7 +770,7 @@ # we don't auto-rerun exec statements, it would be huge security risk! pass else: - obj.attributes.add(key, init_spawn_value(val, value_to_obj)) + obj.attributes.add(key, init_spawn_value(val, value_to_obj, caller=caller)) elif directive == "REMOVE": do_save = True if key == "key": @@ -877,7 +883,7 @@ # Spawner mechanism -
        [docs]def spawn(*prototypes, **kwargs): +
        [docs]def spawn(*prototypes, caller=None, **kwargs): """ Spawn a number of prototyped objects. @@ -886,6 +892,7 @@ prototype_key (will be used to find the prototype) or a full prototype dictionary. These will be batched-spawned as one object each. Keyword Args: + caller (Object or Account, optional): This may be used by protfuncs to do access checks. prototype_modules (str or list): A python-path to a prototype module, or a list of such paths. These will be used to build the global protparents dictionary accessible by the input @@ -951,32 +958,41 @@ "key", "Spawned-{}".format(hashlib.md5(bytes(str(time.time()), "utf-8")).hexdigest()[:6]), ) - create_kwargs["db_key"] = init_spawn_value(val, str) + create_kwargs["db_key"] = init_spawn_value(val, str, caller=caller) val = prot.pop("location", None) - create_kwargs["db_location"] = init_spawn_value(val, value_to_obj) + create_kwargs["db_location"] = init_spawn_value(val, value_to_obj, caller=caller) - val = prot.pop("home", settings.DEFAULT_HOME) - create_kwargs["db_home"] = init_spawn_value(val, value_to_obj) + val = prot.pop("home", None) + if val: + create_kwargs["db_home"] = init_spawn_value(val, value_to_obj, caller=caller) + else: + try: + create_kwargs["db_home"] = init_spawn_value( + settings.DEFAULT_HOME, value_to_obj, caller=caller) + except ObjectDB.DoesNotExist: + # settings.DEFAULT_HOME not existing is common for unittests + pass val = prot.pop("destination", None) - create_kwargs["db_destination"] = init_spawn_value(val, value_to_obj) + create_kwargs["db_destination"] = init_spawn_value(val, value_to_obj, caller=caller) val = prot.pop("typeclass", settings.BASE_OBJECT_TYPECLASS) - create_kwargs["db_typeclass_path"] = init_spawn_value(val, str) + create_kwargs["db_typeclass_path"] = init_spawn_value(val, str, caller=caller) # extract calls to handlers val = prot.pop("permissions", []) - permission_string = init_spawn_value(val, make_iter) + permission_string = init_spawn_value(val, make_iter, caller=caller) val = prot.pop("locks", "") - lock_string = init_spawn_value(val, str) + lock_string = init_spawn_value(val, str, caller=caller) val = prot.pop("aliases", []) - alias_string = init_spawn_value(val, make_iter) + alias_string = init_spawn_value(val, make_iter, caller=caller) val = prot.pop("tags", []) tags = [] - for (tag, category, data) in val: - tags.append((init_spawn_value(tag, str), category, data)) + for (tag, category, *data) in val: + tags.append((init_spawn_value(tag, str, caller=caller), category, data[0] + if data else None)) prototype_key = prototype.get("prototype_key", None) if prototype_key: @@ -984,11 +1000,11 @@ tags.append((prototype_key, PROTOTYPE_TAG_CATEGORY)) val = prot.pop("exec", "") - execs = init_spawn_value(val, make_iter) + execs = init_spawn_value(val, make_iter, caller=caller) # extract ndb assignments nattributes = dict( - (key.split("_", 1)[1], init_spawn_value(val, value_to_obj)) + (key.split("_", 1)[1], init_spawn_value(val, value_to_obj, caller=caller)) for key, val in prot.items() if key.startswith("ndb_") ) @@ -996,8 +1012,9 @@ # the rest are attribute tuples (attrname, value, category, locks) val = make_iter(prot.pop("attrs", [])) attributes = [] - for (attrname, value, category, locks) in val: - attributes.append((attrname, init_spawn_value(value), category, locks)) + for (attrname, value, *rest) in val: + attributes.append((attrname, init_spawn_value(value, caller=caller), + rest[0] if rest else None, rest[1] if len(rest) > 1 else None)) simple_attributes = [] for key, value in ( @@ -1008,7 +1025,7 @@ continue else: simple_attributes.append( - (key, init_spawn_value(value, value_to_obj_or_any), None, None) + (key, init_spawn_value(value, value_to_obj_or_any, caller=caller), None, None) ) attributes = attributes + simple_attributes @@ -1068,7 +1085,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1087,6 +1103,7 @@ +
        develop branch
        @@ -145,112 +146,22 @@ scripts = self.get_id(dbref) for script in make_iter(scripts): script.stop() - - def remove_non_persistent(self, obj=None): - """ - This cleans up the script database of all non-persistent - scripts. It is called every time the server restarts. - - Args: - obj (Object, optional): Only remove non-persistent scripts - assigned to this object. - - """ - if obj: - to_stop = self.filter(db_obj=obj, db_persistent=False, db_is_active=True) - to_delete = self.filter(db_obj=obj, db_persistent=False, db_is_active=False) - else: - to_stop = self.filter(db_persistent=False, db_is_active=True) - to_delete = self.filter(db_persistent=False, db_is_active=False) - nr_deleted = to_stop.count() + to_delete.count() - for script in to_stop: - script.stop() - for script in to_delete: script.delete() - return nr_deleted - def validate(self, scripts=None, obj=None, key=None, dbref=None, init_mode=None): + def update_scripts_after_server_start(self): """ - This will step through the script database and make sure - all objects run scripts that are still valid in the context - they are in. This is called by the game engine at regular - intervals but can also be initiated by player scripts. - - Only one of the arguments are supposed to be supplied - at a time, since they are exclusive to each other. - - Args: - scripts (list, optional): A list of script objects to - validate. - obj (Object, optional): Validate only scripts defined on - this object. - key (str): Validate only scripts with this key. - dbref (int): Validate only the single script with this - particular id. - init_mode (str, optional): This is used during server - upstart and can have three values: - - `None` (no init mode). Called during run. - - `"reset"` - server reboot. Kill non-persistent scripts - - `"reload"` - server reload. Keep non-persistent scripts. - Returns: - nr_started, nr_stopped (tuple): Statistics on how many objects - where started and stopped. - - Notes: - This method also makes sure start any scripts it validates - which should be harmless, since already-active scripts have - the property 'is_running' set and will be skipped. + Update/sync/restart/delete scripts after server shutdown/restart. """ + for script in self.filter(db_is_active=True, db_persistent=False): + script._stop_task() - # we store a variable that tracks if we are calling a - # validation from within another validation (avoids - # loops). + for script in self.filter(db_is_active=True): + script._unpause_task(auto_unpause=True) + script.at_server_start() - global VALIDATE_ITERATION - if VALIDATE_ITERATION > 0: - # we are in a nested validation. Exit. - VALIDATE_ITERATION -= 1 - return None, None - VALIDATE_ITERATION += 1 - - # not in a validation - loop. Validate as normal. - - nr_started = 0 - nr_stopped = 0 - - if init_mode: - if init_mode == "reset": - # special mode when server starts or object logs in. - # This deletes all non-persistent scripts from database - nr_stopped += self.remove_non_persistent(obj=obj) - # turn off the activity flag for all remaining scripts - scripts = self.get_all_scripts() - for script in scripts: - script.is_active = False - - elif not scripts: - # normal operation - if dbref and self.dbref(dbref, reqhash=False): - scripts = self.get_id(dbref) - elif obj: - scripts = self.get_all_scripts_on_obj(obj, key=key) - else: - scripts = self.get_all_scripts(key=key) - - if not scripts: - # no scripts available to validate - VALIDATE_ITERATION -= 1 - return None, None - - for script in scripts: - if script.is_valid(): - nr_started += script.start(force_restart=init_mode) - else: - script.stop() - nr_stopped += 1 - VALIDATE_ITERATION -= 1 - return nr_started, nr_stopped + for script in self.filter(db_is_active=False): + script.at_server_start() def search_script(self, ostring, obj=None, only_timed=False, typeclass=None): """ @@ -362,7 +273,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -381,6 +291,7 @@ +
        develop branch
        @@ -142,7 +143,7 @@ # how often to run Script (secs). -1 means there is no timer db_interval = models.IntegerField( - "interval", default=-1, help_text="how often to repeat script, in seconds. -1 means off." + "interval", default=-1, help_text="how often to repeat script, in seconds. <= 0 means off." ) # start script right away or wait interval seconds first db_start_delay = models.BooleanField( @@ -151,7 +152,7 @@ # how many times this script is to be repeated, if interval!=0. db_repeats = models.IntegerField("number of repeats", default=0, help_text="0 means off.") # defines if this script should survive a reboot or not - db_persistent = models.BooleanField("survive server reboot", default=False) + db_persistent = models.BooleanField("survive server reboot", default=True) # defines if this script has already been started in this session db_is_active = models.BooleanField("script active", default=False) @@ -257,7 +258,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -276,6 +276,7 @@ +
        develop branch
        @@ -68,11 +69,13 @@ """ This is a resource singleton that allows for registering callbacks for when a field or Attribute is updated (saved). + """
        [docs] def __init__(self): """ Initialize the handler. + """ self.savekey = "_monitorhandler_save" self.monitors = defaultdict(lambda: defaultdict(dict))
        @@ -281,7 +284,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -300,6 +302,7 @@ +
        develop branch
        @@ -89,15 +90,11 @@ next_repeat = script.time_until_next_repeat() except Exception: next_repeat = "?" - string += _( - "\n '%(key)s' (%(next_repeat)s/%(interval)s, %(repeats)s repeats): %(desc)s" - ) % { - "key": script.key, - "next_repeat": next_repeat, - "interval": interval, - "repeats": repeats, - "desc": script.desc, - } + string += _("\n '{key}' ({next_repeat}/{interval}, {repeats} repeats): {desc}").format( + key=script.key, next_repeat=next_repeat, + interval=interval, + repeats=repeats, + desc=script.desc) return string.strip()
        [docs] def add(self, scriptclass, key=None, autostart=True): @@ -149,7 +146,8 @@ scripts = ScriptDB.objects.get_all_scripts_on_obj(self.obj, key=key) num = 0 for script in scripts: - num += script.start() + script.start() + num += 1 return num
        [docs] def get(self, key): @@ -184,7 +182,8 @@ ] num = 0 for script in delscripts: - num += script.stop() + script.delete() + num += 1 return num
        # alias to delete @@ -195,22 +194,7 @@ Get all scripts stored in this handler. """ - return ScriptDB.objects.get_all_scripts_on_obj(self.obj)
        - -
        [docs] def validate(self, init_mode=False): - """ - Runs a validation on this object's scripts only. This should - be called regularly to crank the wheels. - - Args: - init_mode (str, optional): - This is used during server - upstart and can have three values: - - `False` (no init mode). Called during run. - - `"reset"` - server reboot. Kill non-persistent scripts - - `"reload"` - server reload. Keep non-persistent scripts. - - """ - ScriptDB.objects.validate(obj=self.obj, init_mode=init_mode)
        + return ScriptDB.objects.get_all_scripts_on_obj(self.obj)
        @@ -248,7 +232,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -267,6 +250,7 @@ +
        develop branch
        @@ -48,7 +49,6 @@ from twisted.internet.defer import Deferred, maybeDeferred from twisted.internet.task import LoopingCall -from django.core.exceptions import ObjectDoesNotExist from django.utils.translation import gettext as _ from evennia.typeclasses.models import TypeclassBase from evennia.scripts.models import ScriptDB @@ -58,21 +58,11 @@ __all__ = ["DefaultScript", "DoNothing", "Store"] -FLUSHING_INSTANCES = False # whether we're in the process of flushing scripts from the cache -SCRIPT_FLUSH_TIMERS = {} # stores timers for scripts that are currently being flushed - - -def restart_scripts_after_flush(): - """After instances are flushed, validate scripts so they're not dead for a long period of time""" - global FLUSHING_INSTANCES - ScriptDB.objects.validate() - FLUSHING_INSTANCES = False - - class ExtendedLoopingCall(LoopingCall): """ - LoopingCall that can start at a delay different - than `self.interval`. + Custom child of LoopingCall that can start at a delay different than + `self.interval` and self.count=0. This allows it to support pausing + by resuming at a later period. """ @@ -90,10 +80,10 @@ interval (int): Repeat interval in seconds. now (bool, optional): Whether to start immediately or after `start_delay` seconds. - start_delay (int): The number of seconds before starting. - If None, wait interval seconds. Only valid if `now` is `False`. - It is used as a way to start with a variable start time - after a pause. + start_delay (int, optional): This only applies is `now=False`. It gives + number of seconds to wait before starting. If `None`, use + `interval` as this value instead. Internally, this is used as a + way to start with a variable start time after a pause. count_start (int): Number of repeats to start at. The count goes up every time the system repeats. This is used to implement something repeating `N` number of times etc. @@ -172,7 +162,7 @@ of start_delay into account. Returns: - next (int or None): The time in seconds until the next call. This + int or None: The time in seconds until the next call. This takes `start_delay` into account. Returns `None` if the task is not running. @@ -180,7 +170,7 @@ if self.running and self.interval > 0: total_runtime = self.clock.seconds() - self.starttime interval = self.start_delay or self.interval - return interval - (total_runtime % self.interval) + return max(0, interval - (total_runtime % self.interval)) class ScriptBase(ScriptDB, metaclass=TypeclassBase): @@ -188,6 +178,8 @@ Base class for scripts. Don't inherit from this, inherit from the class `DefaultScript` below instead. + This handles the timer-component of the Script. + """ objects = ScriptManager() @@ -198,36 +190,176 @@ def __repr__(self): return str(self) - def _start_task(self): + def at_idmapper_flush(self): """ - Start task runner. + If we're flushing this object, make sure the LoopingCall is gone too. + """ + ret = super().at_idmapper_flush() + if ret and self.ndb._task: + self.ndb._pause_task(auto_pause=True) + # TODO - restart anew ? + return ret + + def _start_task(self, interval=None, start_delay=None, repeats=None, force_restart=False, + auto_unpause=False, **kwargs): + """ + Start/Unpause task runner, optionally with new values. If given, this will + update the Script's fields. + + Keyword Args: + interval (int): How often to tick the task, in seconds. If this is <= 0, + no task will start and properties will not be updated on the Script. + start_delay (int): If the start should be delayed. + repeats (int): How many repeats. 0 for infinite repeats. + force_restart (bool): If set, always create a new task running even if an + old one already was running. Otherwise this will only happen if + new script properties were passed. + auto_unpause (bool): This is an automatic unpaused (used e.g by Evennia after + a reload) and should not un-pause manually paused Script timers. + Note: + If setting the `start-delay` of a *paused* Script, the Script will + restart exactly after that new start-delay, ignoring the time it + was paused at. If only changing the `interval`, the Script will + come out of pause comparing the time it spent in the *old* interval + with the *new* interval in order to determine when next to fire. + + Examples: + - Script previously had an interval of 10s and was paused 5s into that interval. + Script is now restarted with a 20s interval. It will next fire after 15s. + - Same Script is restarted with a 3s interval. It will fire immediately. """ + if self.pk is None: + # script object already deleted from db - don't start a new timer + raise ScriptDB.DoesNotExist + + # handle setting/updating fields + update_fields = [] + old_interval = self.db_interval + if interval is not None: + self.db_interval = interval + update_fields.append("db_interval") + if start_delay is not None: + self.db_start_delay = start_delay + update_fields.append("db_start_delay") + if repeats is not None: + self.db_repeats = repeats + update_fields.append("db_repeats") + + # validate interval + if self.db_interval and self.db_interval > 0: + if not self.is_active: + self.db_is_active = True + update_fields.append("db_is_active") + else: + # no point in starting a task with no interval. + return + + restart = bool(update_fields) or force_restart + self.save(update_fields=update_fields) + + if self.ndb._task and self.ndb._task.running: + if restart: + # a change needed/forced; stop/remove old task + self._stop_task() + else: + # task alreaady running and no changes needed + return + if not self.ndb._task: + # we should have a fresh task after this point self.ndb._task = ExtendedLoopingCall(self._step_task) - if self.db._paused_time: - # the script was paused; restarting - callcount = self.db._paused_callcount or 0 - self.ndb._task.start( - self.db_interval, now=False, start_delay=self.db._paused_time, count_start=callcount - ) - del self.db._paused_time - del self.db._paused_repeats + self._unpause_task(interval=interval, start_delay=start_delay, + auto_unpause=auto_unpause, + old_interval=old_interval) - elif not self.ndb._task.running: - # starting script anew + if not self.ndb._task.running: + # if not unpausing started it, start script anew with the new values self.ndb._task.start(self.db_interval, now=not self.db_start_delay) - def _stop_task(self): + self.at_start(**kwargs) + + def _pause_task(self, auto_pause=False, **kwargs): """ - Stop task runner + Pause task where it is, saving the current status. + + Args: + auto_pause (str): + + """ + if not self.db._paused_time: + # only allow pause if not already paused + task = self.ndb._task + if task: + self.db._paused_time = task.next_call_time() + self.db._paused_callcount = task.callcount + self.db._manually_paused = not auto_pause + if task.running: + task.stop() + self.ndb._task = None + + self.at_pause(auto_pause=auto_pause, **kwargs) + + def _unpause_task(self, interval=None, start_delay=None, auto_unpause=False, + old_interval=0, **kwargs): + """ + Unpause task from paused status. This is used for auto-paused tasks, such + as tasks paused on a server reload. + + Args: + interval (int): How often to tick the task, in seconds. + start_delay (int): If the start should be delayed. + auto_unpause (bool): If set, this will only unpause scripts that were unpaused + automatically (useful during a system reload/shutdown). + old_interval (int): The old Script interval (or current one if nothing changed). Used + to recalculate the unpause startup interval. + + """ + paused_time = self.db._paused_time + if paused_time: + if auto_unpause and self.db._manually_paused: + # this was manually paused. + return + + # task was paused. This will use the new values as needed. + callcount = self.db._paused_callcount or 0 + if start_delay is None and interval is not None: + # adjust start-delay based on how far we were into previous interval + start_delay = max(0, interval - (old_interval - paused_time)) + else: + start_delay = paused_time + + if not self.ndb._task: + self.ndb._task = ExtendedLoopingCall(self._step_task) + + self.ndb._task.start( + self.db_interval, now=False, start_delay=start_delay, count_start=callcount + ) + del self.db._paused_time + del self.db._paused_callcount + del self.db._manually_paused + + self.at_start(**kwargs) + + def _stop_task(self, **kwargs): + """ + Stop task runner and delete the task. """ task = self.ndb._task if task and task.running: task.stop() self.ndb._task = None + self.db_is_active = False + + # make sure this is not confused as a paused script + del self.db._paused_time + del self.db._paused_callcount + del self.db._manually_paused + + self.save(update_fields=["db_is_active"]) + self.at_stop(**kwargs) def _step_errback(self, e): """ @@ -236,8 +368,8 @@ """ cname = self.__class__.__name__ estring = _( - "Script %(key)s(#%(dbid)s) of type '%(cname)s': at_repeat() error '%(err)s'." - ) % {"key": self.key, "dbid": self.dbid, "cname": cname, "err": e.getErrorMessage()} + "Script {key}(#{dbid}) of type '{name}': at_repeat() error '{err}'.".format( + key=self.key, dbid=self.dbid, name=cname, err=e.getErrorMessage())) try: self.db_obj.msg(estring) except Exception: @@ -280,12 +412,7 @@ logger.log_trace() return None - def at_script_creation(self): - """ - Should be overridden in child. - - """ - pass + # Access methods / hooks def at_first_save(self, **kwargs): """ @@ -347,12 +474,185 @@ for key, value in cdict["nattributes"]: self.nattributes.add(key, value) - if not cdict.get("autostart"): - # don't auto-start the script - return + if cdict.get("autostart"): + # autostart the script + self._start_task(force_restart=True) - # auto-start script (default) - self.start() + def delete(self): + """ + Delete the Script. Makes sure to stop any timer tasks first. + + """ + self._stop_task() + self.at_script_delete() + super().delete() + + def at_script_creation(self): + """ + Should be overridden in child. + + """ + pass + + def at_script_delete(self): + """ + Called when script is deleted, after at_stop. + + """ + pass + + def is_valid(self): + """ + If returning False, `at_repeat` will not be called and timer will stop + updating. + """ + return True + + def at_repeat(self, **kwargs): + """ + Called repeatedly every `interval` seconds, once `.start()` has + been called on the Script at least once. + + Args: + **kwargs (dict): Arbitrary, optional arguments for users + overriding the call (unused by default). + + """ + pass + + def at_start(self, **kwargs): + pass + + def at_pause(self, **kwargs): + pass + + def at_stop(self, **kwargs): + pass + + + def start(self, interval=None, start_delay=None, repeats=None, **kwargs): + """ + Start/Unpause timer component, optionally with new values. If given, + this will update the Script's fields. This will start `at_repeat` being + called every `interval` seconds. + + Keyword Args: + interval (int): How often to fire `at_repeat` in seconds. + start_delay (int): If the start of ticking should be delayed. + repeats (int): How many repeats. 0 for infinite repeats. + **kwargs: Optional (default unused) kwargs passed on into the `at_start` hook. + + Notes: + If setting the `start-delay` of a *paused* Script, the Script will + restart exactly after that new start-delay, ignoring the time it + was paused at. If only changing the `interval`, the Script will + come out of pause comparing the time it spent in the *old* interval + with the *new* interval in order to determine when next to fire. + + Examples: + - Script previously had an interval of 10s and was paused 5s into that interval. + Script is now restarted with a 20s interval. It will next fire after 15s. + - Same Script is restarted with a 3s interval. It will fire immediately. + + """ + self._start_task(interval=interval, start_delay=start_delay, repeats=repeats, **kwargs) + + # legacy alias + update = start + + def stop(self, **kwargs): + """ + Stop the Script's timer component. This will not delete the Sctipt, + just stop the regular firing of `at_repeat`. Running `.start()` will + start the timer anew, optionally with new settings.. + + Args: + **kwargs: Optional (default unused) kwargs passed on into the `at_stop` hook. + + """ + self._stop_task(**kwargs) + + def pause(self, **kwargs): + """ + Manually the Script's timer component manually. + + Args: + **kwargs: Optional (default unused) kwargs passed on into the `at_pause` hook. + + """ + self._pause_task(manual_pause=True, **kwargs) + + def unpause(self, **kwargs): + """ + Manually unpause a Paused Script. + + Args: + **kwargs: Optional (default unused) kwargs passed on into the `at_start` hook. + + """ + self._unpause_task(**kwargs) + + def time_until_next_repeat(self): + """ + Get time until the script fires it `at_repeat` hook again. + + Returns: + int or None: Time in seconds until the script runs again. + If not a timed script, return `None`. + + Notes: + This hook is not used in any way by the script's stepping + system; it's only here for the user to be able to check in + on their scripts and when they will next be run. + + """ + task = self.ndb._task + if task: + try: + return int(round(task.next_call_time())) + except TypeError: + pass + return None + + def remaining_repeats(self): + """ + Get the number of returning repeats for limited Scripts. + + Returns: + int or None: The number of repeats remaining until the Script + stops. Returns `None` if it has unlimited repeats. + + """ + task = self.ndb._task + if task: + return max(0, self.db_repeats - task.callcount) + return None + + def reset_callcount(self, value=0): + """ + Reset the count of the number of calls done. + + Args: + value (int, optional): The repeat value to reset to. Default + is to set it all the way back to 0. + + Notes: + This is only useful if repeats != 0. + + """ + task = self.ndb._task + if task: + task.callcount = max(0, int(value)) + + def force_repeat(self): + """ + Fire a premature triggering of the script callback. This + will reset the timer and count down repeats as if the script + had fired normally. + """ + task = self.ndb._task + if task: + task.force_repeat()
        [docs]class DefaultScript(ScriptBase): @@ -399,287 +699,20 @@ """ pass
        -
        [docs] def time_until_next_repeat(self): - """ - Get time until the script fires it `at_repeat` hook again. - - Returns: - next (int): Time in seconds until the script runs again. - If not a timed script, return `None`. - - Notes: - This hook is not used in any way by the script's stepping - system; it's only here for the user to be able to check in - on their scripts and when they will next be run. - - """ - task = self.ndb._task - if task: - try: - return int(round(task.next_call_time())) - except TypeError: - pass - return None
        - -
        [docs] def remaining_repeats(self): - """ - Get the number of returning repeats for limited Scripts. - - Returns: - remaining (int or `None`): The number of repeats - remaining until the Script stops. Returns `None` - if it has unlimited repeats. - - """ - task = self.ndb._task - if task: - return max(0, self.db_repeats - task.callcount) - return None
        - -
        [docs] def at_idmapper_flush(self): - """If we're flushing this object, make sure the LoopingCall is gone too""" - ret = super(DefaultScript, self).at_idmapper_flush() - if ret and self.ndb._task: - try: - from twisted.internet import reactor - - global FLUSHING_INSTANCES - # store the current timers for the _task and stop it to avoid duplicates after cache flush - paused_time = self.ndb._task.next_call_time() - callcount = self.ndb._task.callcount - self._stop_task() - SCRIPT_FLUSH_TIMERS[self.id] = (paused_time, callcount) - # here we ensure that the restart call only happens once, not once per script - if not FLUSHING_INSTANCES: - FLUSHING_INSTANCES = True - reactor.callLater(2, restart_scripts_after_flush) - except Exception: - import traceback - - traceback.print_exc() - return ret
        - -
        [docs] def start(self, force_restart=False): - """ - Called every time the script is started (for persistent - scripts, this is usually once every server start) - - Args: - force_restart (bool, optional): Normally an already - started script will not be started again. if - `force_restart=True`, the script will always restart - the script, regardless of if it has started before. - - Returns: - result (int): 0 or 1 depending on if the script successfully - started or not. Used in counting. - - """ - if self.is_active and not force_restart: - # The script is already running, but make sure we have a _task if - # this is after a cache flush - if not self.ndb._task and self.db_interval > 0: - self.ndb._task = ExtendedLoopingCall(self._step_task) - try: - start_delay, callcount = SCRIPT_FLUSH_TIMERS[self.id] - del SCRIPT_FLUSH_TIMERS[self.id] - now = False - except (KeyError, ValueError, TypeError): - now = not self.db_start_delay - start_delay = None - callcount = 0 - self.ndb._task.start( - self.db_interval, now=now, start_delay=start_delay, count_start=callcount - ) - return 0 - - obj = self.obj - if obj: - # check so the scripted object is valid and initalized - try: - obj.cmdset - except AttributeError: - # this means the object is not initialized. - logger.log_trace() - self.is_active = False - return 0 - - # try to restart a paused script - try: - if self.unpause(manual_unpause=False): - return 1 - except RuntimeError: - # manually paused. - return 0 - - # start the script from scratch - self.is_active = True - try: - self.at_start() - except Exception: - logger.log_trace() - - if self.db_interval > 0: - self._start_task() - return 1
        - -
        [docs] def stop(self, kill=False): - """ - Called to stop the script from running. This also deletes the - script. - - Args: - kill (bool, optional): - Stop the script without - calling any relevant script hooks. - - Returns: - result (int): 0 if the script failed to stop, 1 otherwise. - Used in counting. - - """ - if not kill: - try: - self.at_stop() - except Exception: - logger.log_trace() - self._stop_task() - try: - self.delete() - except AssertionError: - logger.log_trace() - return 0 - except ObjectDoesNotExist: - return 0 - return 1
        - -
        [docs] def pause(self, manual_pause=True): - """ - This stops a running script and stores its active state. - It WILL NOT call the `at_stop()` hook. - - """ - self.db._manual_pause = manual_pause - if not self.db._paused_time: - # only allow pause if not already paused - task = self.ndb._task - if task: - self.db._paused_time = task.next_call_time() - self.db._paused_callcount = task.callcount - self._stop_task() - self.is_active = False
        - -
        [docs] def unpause(self, manual_unpause=True): - """ - Restart a paused script. This WILL call the `at_start()` hook. - - Args: - manual_unpause (bool, optional): This is False if unpause is - called by the server reload/reset mechanism. - Returns: - result (bool): True if unpause was triggered, False otherwise. - - Raises: - RuntimeError: If trying to automatically resart this script - (usually after a reset/reload), but it was manually paused, - and so should not the auto-unpaused. - - """ - if not manual_unpause and self.db._manual_pause: - # if this script was paused manually (by a direct call of pause), - # it cannot be automatically unpaused (e.g. by a @reload) - raise RuntimeError - - # Ensure that the script is fully unpaused, so that future calls - # to unpause do not raise a RuntimeError - self.db._manual_pause = False - - if self.db._paused_time: - # only unpause if previously paused - self.is_active = True - - try: - self.at_start() - except Exception: - logger.log_trace() - - self._start_task() - return True
        - -
        [docs] def restart(self, interval=None, repeats=None, start_delay=None): - """ - Restarts an already existing/running Script from the - beginning, optionally using different settings. This will - first call the stop hooks, and then the start hooks again. - Args: - interval (int, optional): Allows for changing the interval - of the Script. Given in seconds. if `None`, will use the already stored interval. - repeats (int, optional): The number of repeats. If unset, will - use the previous setting. - start_delay (bool, optional): If we should wait `interval` seconds - before starting or not. If `None`, re-use the previous setting. - - """ - try: - self.at_stop() - except Exception: - logger.log_trace() - self._stop_task() - self.is_active = False - # remove all pause flags - del self.db._paused_time - del self.db._manual_pause - del self.db._paused_callcount - # set new flags and start over - if interval is not None: - interval = max(0, interval) - self.interval = interval - if repeats is not None: - self.repeats = repeats - if start_delay is not None: - self.start_delay = start_delay - self.start()
        - -
        [docs] def reset_callcount(self, value=0): - """ - Reset the count of the number of calls done. - - Args: - value (int, optional): The repeat value to reset to. Default - is to set it all the way back to 0. - - Notes: - This is only useful if repeats != 0. - - """ - task = self.ndb._task - if task: - task.callcount = max(0, int(value))
        - -
        [docs] def force_repeat(self): - """ - Fire a premature triggering of the script callback. This - will reset the timer and count down repeats as if the script - had fired normally. - """ - task = self.ndb._task - if task: - task.force_repeat()
        -
        [docs] def is_valid(self): """ - Is called to check if the script is valid to run at this time. - Should return a boolean. The method is assumed to collect all - needed information from its related self.obj. + Is called to check if the script's timer is valid to run at this time. + Should return a boolean. If False, the timer will be stopped. """ - return not self._is_deleted
        + return True
        [docs] def at_start(self, **kwargs): """ - Called whenever the script is started, which for persistent - scripts is at least once every server start. It will also be - called when starting again after a pause (such as after a - server reload) + Called whenever the script timer is started, which for persistent + timed scripts is at least once every server start. It will also be + called when starting again after a pause (including after a + server reload). Args: **kwargs (dict): Arbitrary, optional arguments for users @@ -696,18 +729,38 @@ **kwargs (dict): Arbitrary, optional arguments for users overriding the call (unused by default). + """ + pass
        + +
        [docs] def at_pause(self, manual_pause=True, **kwargs): + """ + Called when this script's timer pauses. + + Args: + manual_pause (bool): If set, pausing was done by a direct call. The + non-manual pause indicates the script was paused as part of + the server reload. + """ pass
        [docs] def at_stop(self, **kwargs): """ - Called whenever when it's time for this script to stop (either - because is_valid returned False or it runs out of iterations) + Called whenever when it's time for this script's timer to stop (either + because is_valid returned False, it ran out of iterations or it was manuallys + stopped. - Args + Args: **kwargs (dict): Arbitrary, optional arguments for users overriding the call (unused by default). + """ + pass
        + +
        [docs] def at_script_delete(self): + """ + Called when the Script is deleted, after at_stop(). + """ pass
        @@ -724,6 +777,15 @@ """ This hook is called whenever the server is shutting down fully (i.e. not for a restart). + """ + pass + +
        [docs] def at_server_start(self): + """ + This hook is called after the server has started. It can be used to add + post-startup setup for Scripts without a timer component (for which at_start + could be used). + """ pass
        @@ -792,7 +854,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -811,6 +872,7 @@ +
        develop branch
        @@ -103,22 +104,28 @@ return TASK_HANDLER.get_deferred(self.task_id)
        [docs] def pause(self): - """Pause the callback of a task. - To resume use TaskHandlerTask.unpause + """ + Pause the callback of a task. + To resume use `TaskHandlerTask.unpause`. + """ d = self.deferred if d: d.pause()
        [docs] def unpause(self): - """Unpause a task, run the task if it has passed delay time.""" + """ + Unpause a task, run the task if it has passed delay time. + + """ d = self.deferred if d: d.unpause()
        @property def paused(self): - """A task attribute to check if the deferred instance of a task has been paused. + """ + A task attribute to check if the deferred instance of a task has been paused. This exists to mock usage of a twisted deferred object. @@ -134,7 +141,8 @@ return None
        [docs] def do_task(self): - """Execute the task (call its callback). + """ + Execute the task (call its callback). If calling before timedelay, cancel the deferred instance affliated to this task. Remove the task from the dictionary of current tasks on a successful callback. @@ -147,7 +155,8 @@ return TASK_HANDLER.do_task(self.task_id)
        [docs] def call(self): - """Call the callback of a task. + """ + Call the callback of a task. Leave the task unaffected otherwise. This does not use the task's deferred instance. The only requirement is that the task exist in task handler. @@ -214,7 +223,8 @@ return None
        [docs] def exists(self): - """Check if a task exists. + """ + Check if a task exists. Most task handler methods check for existence for you. Returns: @@ -224,7 +234,8 @@ return TASK_HANDLER.exists(self.task_id)
        [docs] def get_id(self): - """ Returns the global id for this task. For use with + """ + Returns the global id for this task. For use with `evennia.scripts.taskhandler.TASK_HANDLER`. Returns: @@ -256,7 +267,7 @@ self.clock = reactor # number of seconds before an uncalled canceled task is removed from TaskHandler self.stale_timeout = 60 - self._now = False # used in unit testing to manually set now time
        + self._now = False # used in unit testing to manually set now time
        [docs] def load(self): """Load from the ServerConfig. @@ -312,7 +323,10 @@ return True
        [docs] def save(self): - """Save the tasks in ServerConfig.""" + """ + Save the tasks in ServerConfig. + + """ for task_id, (date, callback, args, kwargs, persistent, _) in self.tasks.items(): if task_id in self.to_save: @@ -320,21 +334,30 @@ if not persistent: continue + safe_callback = callback if getattr(callback, "__self__", None): # `callback` is an instance method obj = callback.__self__ name = callback.__name__ - callback = (obj, name) + safe_callback = (obj, name) # Check if callback can be pickled. args and kwargs have been checked - safe_callback = None + try: + dbserialize(safe_callback) + except (TypeError, AttributeError, PickleError) as err: + raise ValueError( + "the specified callback {callback} cannot be pickled. " + "It must be a top-level function in a module or an " + "instance method ({err}).".format(callback=callback, err=err) + ) + self.to_save[task_id] = dbserialize((date, safe_callback, args, kwargs)) - self.to_save[task_id] = dbserialize((date, callback, args, kwargs)) ServerConfig.objects.conf("delayed_tasks", self.to_save)
        [docs] def add(self, timedelay, callback, *args, **kwargs): - """Add a new task. + """ + Add a new task. If the persistent kwarg is truthy: The callback, args and values for kwarg will be serialized. Type @@ -378,17 +401,6 @@ safe_args = [] safe_kwargs = {} - # an unsaveable callback should immediately abort - try: - dbserialize(callback) - except (TypeError, AttributeError, PickleError): - raise ValueError( - "the specified callback {} cannot be pickled. " - "It must be a top-level function in a module or an " - "instance method.".format(callback) - ) - return - # Check that args and kwargs contain picklable information for arg in args: try: @@ -440,7 +452,8 @@ return TaskHandlerTask(task_id)
        [docs] def exists(self, task_id): - """Check if a task exists. + """ + Check if a task exists. Most task handler methods check for existence for you. Args: @@ -456,7 +469,8 @@ return False
        [docs] def active(self, task_id): - """Check if a task is active (has not been called yet). + """ + Check if a task is active (has not been called yet). Args: task_id (int): an existing task ID. @@ -474,7 +488,8 @@ return False
        [docs] def cancel(self, task_id): - """Stop a task from automatically executing. + """ + Stop a task from automatically executing. This will not remove the task. Args: @@ -500,7 +515,8 @@ return False
        [docs] def remove(self, task_id): - """Remove a task without executing it. + """ + Remove a task without executing it. Deletes the instance of the task's deferred. Args: @@ -526,8 +542,8 @@ return True
        [docs] def clear(self, save=True, cancel=True): - """clear all tasks. - By default tasks are canceled and removed from the database also. + """ + Clear all tasks. By default tasks are canceled and removed from the database as well. Args: save=True (bool): Should changes to persistent tasks be saved to database. @@ -549,7 +565,8 @@ return True
        [docs] def call_task(self, task_id): - """Call the callback of a task. + """ + Call the callback of a task. Leave the task unaffected otherwise. This does not use the task's deferred instance. The only requirement is that the task exist in task handler. @@ -569,7 +586,8 @@ return callback(*args, **kwargs)
        [docs] def do_task(self, task_id): - """Execute the task (call its callback). + """ + Execute the task (call its callback). If calling before timedelay cancel the deferred instance affliated to this task. Remove the task from the dictionary of current tasks on a successful callback. @@ -614,7 +632,8 @@ return None
        [docs] def create_delays(self): - """Create the delayed tasks for the persistent tasks. + """ + Create the delayed tasks for the persistent tasks. This method should be automatically called when Evennia starts. """ @@ -668,7 +687,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -687,6 +705,7 @@ +
        develop branch
        @@ -719,7 +720,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -738,6 +738,7 @@ +
        develop branch
        @@ -46,9 +47,11 @@ """ import os +from django.conf import settings from evennia.server.portal import amp from twisted.internet import protocol from evennia.utils import logger +from evennia.utils.utils import class_from_module
        [docs]class AMPClientFactory(protocol.ReconnectingClientFactory): @@ -74,7 +77,7 @@ """ self.server = server - self.protocol = AMPServerClientProtocol + self.protocol = class_from_module(settings.AMP_CLIENT_PROTOCOL_CLASS) self.maxDelay = 10 # not really used unless connecting to multiple servers, but # avoids having to check for its existence on the protocol @@ -326,7 +329,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -345,6 +347,7 @@ +
        develop branch
        @@ -597,7 +598,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -616,6 +616,7 @@ +
        develop branch
        @@ -45,7 +46,7 @@ These all print to the terminal. """ - +import os
        [docs]def check_errors(settings): """ @@ -100,6 +101,21 @@ "Update your settings file (see evennia/settings_default.py " "for more info)." ) + depstring = ( + "settings.{} was renamed to {}. Update your settings file (the FuncParser " + "replaces and generalizes that which inlinefuncs used to do).") + if hasattr(settings, "INLINEFUNC_ENABLED"): + raise DeprecationWarning(depstring.format( + "settings.INLINEFUNC_ENABLED", "FUNCPARSER_PARSE_OUTGOING_MESSAGES_ENABLED")) + if hasattr(settings, "INLINEFUNC_STACK_MAXSIZE"): + raise DeprecationWarning(depstring.format( + "settings.INLINEFUNC_STACK_MAXSIZE", "FUNCPARSER_MAX_NESTING")) + if hasattr(settings, "INLINEFUNC_MODULES"): + raise DeprecationWarning(depstring.format( + "settings.INLINEFUNC_MODULES", "FUNCPARSER_OUTGOING_MESSAGES_MODULES")) + if hasattr(settings, "PROTFUNC_MODULES"): + raise DeprecationWarning(depstring.format( + "settings.PROTFUNC_MODULES", "FUNCPARSER_PROTOTYPE_VALUE_MODULES")) gametime_deprecation = ( "The settings TIME_SEC_PER_MIN, TIME_MIN_PER_HOUR," @@ -142,6 +158,26 @@ "settings.CYCLE_LOGFILES is unused and should be removed. " "Use PORTAL/SERVER_LOG_DAY_ROTATION and PORTAL/SERVER_LOG_MAX_SIZE " "to control log cycling." + ) + if hasattr(settings, "CHANNEL_COMMAND_CLASS") or hasattr(settings, "CHANNEL_HANDLER_CLASS"): + raise DeprecationWarning( + "settings.CHANNEL_HANDLER_CLASS and CHANNEL COMMAND_CLASS are " + "unused and should be removed. The ChannelHandler is no more; " + "channels are now handled by aliasing the default 'channel' command.") + + template_overrides_dir = os.path.join(settings.GAME_DIR, "web", "template_overrides") + static_overrides_dir = os.path.join(settings.GAME_DIR, "web", "static_overrides") + if os.path.exists(template_overrides_dir): + raise DeprecationWarning( + f"The template_overrides directory ({template_overrides_dir}) has changed name.\n" + " - Rename your existing `template_overrides` folder to `templates` instead." + ) + if os.path.exists(static_overrides_dir): + raise DeprecationWarning( + f"The static_overrides directory ({static_overrides_dir}) has changed name.\n" + " 1. Delete any existing `web/static` folder and all its contents (this " + "was auto-generated)\n" + " 2. Rename your existing `static_overrides` folder to `static` instead." )
        @@ -200,7 +236,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -219,6 +254,7 @@ +
        develop branch
        @@ -133,9 +134,9 @@ # requirements PYTHON_MIN = "3.7" -TWISTED_MIN = "18.0.0" -DJANGO_MIN = "2.2.5" -DJANGO_LT = "3.0" +TWISTED_MIN = "20.3.0" +DJANGO_MIN = "3.2.0" +DJANGO_LT = "4.0" try: sys.path[1] = EVENNIA_ROOT @@ -1464,7 +1465,18 @@ "\nCreate a superuser below. The superuser is Account #1, the 'owner' " "account of the server. Email is optional and can be empty.\n" ) - django.core.management.call_command("createsuperuser", interactive=True)
        + from os import environ + + username = environ.get("EVENNIA_SUPERUSER_USERNAME") + email = environ.get("EVENNIA_SUPERUSER_EMAIL") + password = environ.get("EVENNIA_SUPERUSER_PASSWORD") + + if (username is not None) and (password is not None) and len(password) > 0: + from evennia.accounts.models import AccountDB + superuser = AccountDB.objects.create_superuser(username, email, password) + superuser.save() + else: + django.core.management.call_command("createsuperuser", interactive=True)
        [docs]def check_database(always_return=False): @@ -2300,7 +2312,7 @@ if option in ("makemessages", "compilemessages"): # some commands don't require the presence of a game directory to work need_gamedir = False - if option in ("shell", "check", "makemigrations", "createsuperuser"): + if option in ("shell", "check", "makemigrations", "createsuperuser", "shell_plus"): # some django commands requires the database to exist, # or evennia._init to have run before they work right. check_db = True @@ -2370,7 +2382,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -2389,6 +2400,7 @@ +
        develop branch
        @@ -255,7 +256,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -274,6 +274,7 @@ +
        develop branch
        @@ -134,7 +135,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -153,6 +153,7 @@ +
        develop branch
        @@ -66,13 +67,11 @@ """ -LIMBO_DESC = _( - """ -Welcome to your new |wEvennia|n-based game! Visit http://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 '|wbatchcommand tutorial_world.build|n'. - """ -) +LIMBO_DESC = _(""" +Welcome to your new |wEvennia|n-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 '|wbatchcommand tutorial_world.build|n'. +""") WARNING_POSTGRESQL_FIX = """ @@ -81,7 +80,7 @@ but the superuser was not yet connected to them. Please use in game commands to connect Account #1 to those channels when first logging in. - """ +"""
        [docs]def get_god_account(): @@ -172,10 +171,9 @@ goduser = get_god_account() channel_mudinfo = settings.CHANNEL_MUDINFO - if not channel_mudinfo: - raise RuntimeError("settings.CHANNEL_MUDINFO must be defined.") - channel = create.create_channel(**channel_mudinfo) - channel.connect(goduser) + if channel_mudinfo: + channel = create.create_channel(**channel_mudinfo) + channel.connect(goduser) channel_connectinfo = settings.CHANNEL_CONNECTINFO if channel_connectinfo: @@ -315,7 +313,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -334,6 +331,7 @@ +
        develop branch
        @@ -119,11 +120,11 @@ puppet = session.puppet if puppet: txt = puppet.nicks.nickreplace( - txt, categories=("inputline", "channel"), include_account=True + txt, categories=("inputline"), include_account=True ) else: txt = session.account.nicks.nickreplace( - txt, categories=("inputline", "channel"), include_account=False + txt, categories=("inputline"), include_account=False ) kwargs.pop("options", None) cmdhandler(session, txt, callertype="session", session=session, **kwargs) @@ -528,7 +529,6 @@ Keyword Args: <option name>: an option to save - """ account = session.account @@ -694,7 +694,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -713,6 +712,7 @@ +
        develop branch
        @@ -129,7 +130,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -148,6 +148,7 @@ +
        develop branch
        @@ -49,9 +50,8 @@ manager's conf() method. """ -import pickle - from django.db import models + from evennia.utils.idmapper.models import WeakSharedMemoryModel from evennia.utils import logger, utils from evennia.utils.dbserialize import to_pickle, from_pickle @@ -151,7 +151,7 @@ value = property(__value_get, __value_set, __value_del) - class Meta(object): + class Meta: "Define Django meta options" verbose_name = "Server Config value" verbose_name_plural = "Server Config values" @@ -159,9 +159,8 @@ # # ServerConfig other methods # - def __repr__(self): - return "<{} {}>".format(self.__class__.__name__, self.key, self.value) + return "<{} {}>".format(self.__class__.__name__, self.key)
        [docs] def store(self, key, value): """ @@ -211,7 +210,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -230,6 +228,7 @@ +
        develop branch
        @@ -56,7 +57,7 @@ import pickle from twisted.internet.defer import DeferredList, Deferred -from evennia.utils.utils import to_str, variable_from_module +from evennia.utils.utils import variable_from_module # delayed import _LOGGER = None @@ -134,7 +135,10 @@ def _get_logger(): - "Delay import of logger until absolutely necessary" + """ + Delay import of logger until absolutely necessary + + """ global _LOGGER if not _LOGGER: from evennia.utils import logger as _LOGGER @@ -143,7 +147,10 @@ @wraps def catch_traceback(func): - "Helper decorator" + """ + Helper decorator + + """ def decorator(*args, **kwargs): try: @@ -394,6 +401,7 @@
        [docs] def dataReceived(self, data): """ Handle non-AMP messages, such as HTTP communication. + """ # print("dataReceived: {}".format(data)) if data[:1] == NUL: @@ -454,6 +462,7 @@ that is irrelevant. If a true connection error happens, the portal will continuously try to reconnect, showing the problem that way. + """ # print("ConnectionLost: {}: {}".format(self, reason)) try: @@ -463,20 +472,20 @@ # Error handling -
        [docs] def errback(self, e, info): +
        [docs] def errback(self, err, info): """ Error callback. Handles errors to avoid dropping connections on server tracebacks. Args: - e (Failure): Deferred error instance. + err (Failure): Deferred error instance. info (str): Error string. """ - e.trap(Exception) + err.trap(Exception) _get_logger().log_err( "AMP Error from {info}: {trcbck} {err}".format( - info=info, trcbck=e.getTraceback(), err=e.getErrorMessage() + info=info, trcbck=err.getTraceback(), err=err.getErrorMessage() ) )
        @@ -616,7 +625,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -635,6 +643,7 @@ +
        develop branch
        @@ -52,6 +53,7 @@ from django.conf import settings from subprocess import Popen, STDOUT from evennia.utils import logger +from evennia.utils.utils import class_from_module def _is_windows(): @@ -83,7 +85,10 @@ noisy = False
        [docs] def logPrefix(self): - "How this is named in logs" + """ + How this is named in logs + + """ return "AMP"
        [docs] def __init__(self, portal): @@ -97,7 +102,7 @@ """ self.portal = portal - self.protocol = AMPServerProtocol + self.protocol = class_from_module(settings.AMP_SERVER_PROTOCOL_CLASS) self.broadcasts = [] self.server_connection = None self.launcher_connection = None @@ -115,7 +120,7 @@ protocol (Protocol): The created protocol. """ - self.portal.amp_protocol = AMPServerProtocol() + self.portal.amp_protocol = self.protocol() self.portal.amp_protocol.factory = self return self.portal.amp_protocol
        @@ -557,7 +562,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -576,6 +580,7 @@ +
        develop branch
        @@ -376,7 +377,7 @@ # incoming broadcast from network payload = data["payload"] - print("channels/broadcast:", payload["channel"], self.channel) + # print("channels/broadcast:", payload["channel"], self.channel) if str(payload["channel"]) != self.channel: # only echo from channels this particular bot actually listens to return @@ -435,7 +436,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -454,6 +454,7 @@ +
        develop branch
        @@ -554,7 +555,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -573,6 +573,7 @@ +
        develop branch
        @@ -40,7 +41,8 @@

        Source code for evennia.server.portal.portalsessionhandler

         """
        -Sessionhandler for portal sessions
        +Sessionhandler for portal sessions.
        +
         """
         
         
        @@ -48,8 +50,11 @@
         from collections import deque, namedtuple
         from twisted.internet import reactor
         from django.conf import settings
        -from evennia.server.sessionhandler import SessionHandler, PCONN, PDISCONN, PCONNSYNC, PDISCONNALL
        +from evennia.server.sessionhandler import SessionHandler
        +from evennia.server.portal.amp import PCONN, PDISCONN, PCONNSYNC, PDISCONNALL
         from evennia.utils.logger import log_trace
        +from evennia.utils.utils import class_from_module
        +from django.utils.translation import gettext as _
         
         # module import
         _MOD_IMPORT = None
        @@ -74,6 +79,9 @@
         # Portal-SessionHandler class
         # -------------------------------------------------------------
         
        +DOS_PROTECTION_MSG = _("{servername} DoS protection is active."
        +                       "You are queued to connect in {num} seconds ...")
        +
         
         
        [docs]class PortalSessionHandler(SessionHandler): """ @@ -109,6 +117,19 @@ """ self.connection_time = time.time()
        +
        [docs] def generate_sessid(self): + """ + Simply generates a sessid that's guaranteed to be unique for this Portal run. + + Returns: + sessid + + """ + self.latest_sessid += 1 + if self.latest_sessid in self: + return self.generate_sessid() + return self.latest_sessid
        +
        [docs] def connect(self, session): """ Called by protocol at first connect. This adds a not-yet @@ -132,22 +153,17 @@ if not session.sessid: # if the session already has a sessid (e.g. being inherited in the # case of a webclient auto-reconnect), keep it - self.latest_sessid += 1 - session.sessid = self.latest_sessid + session.sessid = self.generate_sessid() session.server_connected = False _CONNECTION_QUEUE.appendleft(session) if len(_CONNECTION_QUEUE) > 1: session.data_out( - text=[ - [ - "%s DoS protection is active. You are queued to connect in %g seconds ..." - % ( - settings.SERVERNAME, - len(_CONNECTION_QUEUE) * _MIN_TIME_BETWEEN_CONNECTS, - ) - ], + text=( + (DOS_PROTECTION_MSG.format( + servername=settings.SERVERNAME, + num=len(_CONNECTION_QUEUE) * _MIN_TIME_BETWEEN_CONNECTS),), {}, - ] + ) ) now = time.time() if ( @@ -247,6 +263,7 @@
        [docs] def disconnect_all(self): """ Disconnect all sessions, informing the Server. + """ def _callback(result, sessionhandler): @@ -504,7 +521,8 @@ log_trace()
        -PORTAL_SESSIONS = PortalSessionHandler() +_PORTAL_SESSION_HANDLER_CLASS = class_from_module(settings.PORTAL_SESSION_HANDLER_CLASS) +PORTAL_SESSIONS = _PORTAL_SESSION_HANDLER_CLASS()
        @@ -542,7 +560,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -561,6 +578,7 @@ +
        develop branch
        @@ -186,6 +187,7 @@
        [docs] def start(self): """ Called by portalsessionhandler. Starts the bot. + """ def errback(fail): @@ -239,7 +241,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -258,6 +259,7 @@ +
        develop branch
        @@ -84,10 +85,9 @@ from twisted.python import components from django.conf import settings -from evennia.server import session from evennia.accounts.models import AccountDB from evennia.utils import ansi -from evennia.utils.utils import to_str +from evennia.utils.utils import to_str, class_from_module _RE_N = re.compile(r"\|n$") _RE_SCREENREADER_REGEX = re.compile( @@ -103,29 +103,32 @@ CTRL_BACKSLASH = "\x1c" CTRL_L = "\x0c" -_NO_AUTOGEN = """ -Evennia could not generate SSH private- and public keys ({{err}}) +_NO_AUTOGEN = f""" +Evennia could not generate SSH private- and public keys ({{err}}) Using conch default keys instead. If this error persists, create the keys manually (using the tools for your OS) and put them here: - {} - {} -""".format( - _PRIVATE_KEY_FILE, _PUBLIC_KEY_FILE -) + {_PRIVATE_KEY_FILE} + {_PUBLIC_KEY_FILE} +""" + +_BASE_SESSION_CLASS = class_from_module(settings.BASE_SESSION_CLASS) # not used atm
        [docs]class SSHServerFactory(protocol.ServerFactory): - "This is only to name this better in logs" + """ + This is only to name this better in logs + + """ noisy = False
        [docs] def logPrefix(self): return "SSH"
        -
        [docs]class SshProtocol(Manhole, session.Session): +
        [docs]class SshProtocol(Manhole, _BASE_SESSION_CLASS): """ Each account connecting over ssh gets this protocol assigned to them. All communication between game and account goes through @@ -318,18 +321,18 @@ text (str): The first argument is always the text string to send. No other arguments are considered. Keyword Args: - options (dict): Send-option flags: + options (dict): Send-option flags (booleans) - - mxp: Enforce MXP link support. - - ansi: Enforce no ANSI colors. - - xterm256: Enforce xterm256 colors, regardless of TTYPE setting. - - nocolor: Strip all colors. - - raw: Pass string through without any ansi processing - (i.e. include Evennia ansi markers but do not + - mxp: enforce mxp link support. + - ansi: enforce no ansi colors. + - xterm256: enforce xterm256 colors, regardless of ttype setting. + - nocolor: strip all colors. + - raw: pass string through without any ansi processing + (i.e. include evennia ansi markers but do not convert them into ansi tokens) - - echo: Turn on/off line echo on the client. Turn + - echo: turn on/off line echo on the client. turn off line echo for client, for example for password. - Note that it must be actively turned back on again! + note that it must be actively turned back on again! """ # print "telnet.send_text", args,kwargs # DEBUG @@ -602,7 +605,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -621,6 +623,7 @@ +
        develop branch
        @@ -58,10 +59,8 @@ import re import json import html -from twisted.internet.protocol import Protocol from django.conf import settings -from evennia.server.session import Session -from evennia.utils.utils import to_str, mod_import +from evennia.utils.utils import mod_import, class_from_module from evennia.utils.ansi import parse_ansi from evennia.utils.text2html import parse_html from autobahn.twisted.websocket import WebSocketServerProtocol @@ -81,12 +80,13 @@ # called when the browser is navigating away from the page GOING_AWAY = WebSocketServerProtocol.CLOSE_STATUS_CODE_GOING_AWAY -STATE_CLOSING = WebSocketServerProtocol.STATE_CLOSING +_BASE_SESSION_CLASS = class_from_module(settings.BASE_SESSION_CLASS) -
        [docs]class WebSocketClient(WebSocketServerProtocol, Session): +
        [docs]class WebSocketClient(WebSocketServerProtocol, _BASE_SESSION_CLASS): """ Implements the server-side of the Websocket connection. + """ # nonce value, used to prevent the webclient from erasing the @@ -198,7 +198,7 @@ # in case anyone wants to expose this functionality later. # # sendClose() under autobahn/websocket/interfaces.py - ret = self.sendClose(CLOSE_NORMAL, reason)
        + self.sendClose(CLOSE_NORMAL, reason)
        [docs] def onClose(self, wasClean, code=None, reason=None): """ @@ -302,8 +302,6 @@ return else: return - # just to be sure - text = to_str(text) flags = self.protocol_flags @@ -387,7 +385,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -406,6 +403,7 @@ +
        develop branch
        @@ -56,6 +57,7 @@ The WebClient resource in this module will handle these requests and act as a gateway to sessions connected over the webclient. + """ import json import re @@ -68,7 +70,7 @@ from django.conf import settings from evennia.utils.ansi import parse_ansi from evennia.utils import utils -from evennia.utils.utils import to_bytes, to_str +from evennia.utils.utils import to_bytes from evennia.utils.text2html import parse_html from evennia.server import session @@ -264,10 +266,13 @@ return jsonify({"msg": host_string, "csessid": csessid})
        [docs] def mode_keepalive(self, request): - """ This is called by render_POST when the client is replying to the keepalive. + + Args: + request (Request): Incoming request. + """ csessid = self.get_client_sessid(request) self.last_alive[csessid] = (time.time(), False) @@ -543,7 +548,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -562,6 +566,7 @@ +
        develop branch
        @@ -81,8 +82,16 @@ from twisted.internet import reactor, protocol from twisted.internet.task import LoopingCall -from django.conf import settings -from evennia.utils import mod_import, time_format +import django +django.setup() +import evennia # noqa +evennia._init() + +from django.conf import settings # noqa +from evennia.utils import mod_import, time_format # noqa +from evennia.commands.command import Command # noqa +from evennia.commands.cmdset import CmdSet # noqa +from evennia.utils.ansi import strip_ansi # noqa # Load the dummyrunner settings module @@ -92,8 +101,10 @@ "Error: Dummyrunner could not find settings file at %s" % settings.DUMMYRUNNER_SETTINGS_MODULE ) +IDMAPPER_CACHE_MAXSIZE = settings.IDMAPPER_CACHE_MAXSIZE DATESTRING = "%Y%m%d%H%M%S" +CLIENTS = [] # Settings @@ -112,18 +123,37 @@ # Port to use, if not specified on command line TELNET_PORT = DUMMYRUNNER_SETTINGS.TELNET_PORT or settings.TELNET_PORTS[0] # -NLOGGED_IN = 0 +NCONNECTED = 0 # client has received a connection +NLOGIN_SCREEN = 0 # client has seen the login screen (server responded) +NLOGGING_IN = 0 # client starting login procedure +NLOGGED_IN = 0 # client has authenticated and logged in - -# Messages +# time when all clients have logged_in +TIME_ALL_LOGIN = 0 +# actions since all logged in +TOTAL_ACTIONS = 0 +TOTAL_LAG_MEASURES = 0 +# lag per 30s for all logged in +TOTAL_LAG = 0 +TOTAL_LAG_IN = 0 +TOTAL_LAG_OUT = 0 INFO_STARTING = """ - Dummyrunner starting using {N} dummy account(s). If you don't see + Dummyrunner starting using {nclients} dummy account(s). If you don't see any connection messages, make sure that the Evennia server is running. - Use Ctrl-C to stop/disconnect clients. + TELNET_PORT = {port} + IDMAPPER_CACHE_MAXSIZE = {idmapper_cache_size} MB + TIMESTEP = {timestep} (rate {rate}/s) + CHANCE_OF_LOGIN = {chance_of_login}% per time step + CHANCE_OF_ACTION = {chance_of_action}% per time step + -> avg rate (per client, after login): {avg_rate} cmds/s + -> total avg rate (after login): {avg_rate_total} cmds/s + + Use Ctrl-C (or Cmd-C) to stop/disconnect all clients. + """ ERROR_NO_MIXIN = """ @@ -138,6 +168,7 @@ to test all commands - change PASSWORD_HASHERS to use a faster (but less safe) algorithm when creating large numbers of accounts at the same time + - set LOGIN_THROTTLE/CREATION_THROTTLE=None to disable it If you don't want to use the custom settings of the mixin for some reason, you can change their values manually after the import, or @@ -209,6 +240,39 @@ """ + +
        [docs]class CmdDummyRunnerEchoResponse(Command): + """ + Dummyrunner command measuring the round-about response time + from sending to receiving a result. + + Usage: + dummyrunner_echo_response <timestamp> + + Responds with + dummyrunner_echo_response:<timestamp>,<current_time> + + The dummyrunner will send this and then compare the send time + with the receive time on both ends. + + """ + key = "dummyrunner_echo_response" + +
        [docs] def func(self): + # returns (dummy_client_timestamp,current_time) + self.msg(f"dummyrunner_echo_response:{self.args},{time.time()}") + if self.caller.account.is_superuser: + print(f"cmddummyrunner lag in: {time.time() - float(self.args)}s")
        + + +
        [docs]class DummyRunnerCmdSet(CmdSet): + """ + Dummyrunner injected cmdset. + + """ +
        [docs] def at_cmdset_creation(self): + self.add(CmdDummyRunnerEchoResponse())
        + # ------------------------------------------------------------ # Helper functions # ------------------------------------------------------------ @@ -222,12 +286,12 @@ Makes unique ids. Returns: - count (int): A globally unique counter. + str: A globally unique id. """ global ICOUNT ICOUNT += 1 - return str(ICOUNT)
        + return str("{:03d}".format(ICOUNT)) GCOUNT = 0 @@ -243,7 +307,7 @@ """ global GCOUNT GCOUNT += 1 - return "%s-%s" % (time.strftime(DATESTRING), GCOUNT) + return "%s_%s" % (time.strftime(DATESTRING), GCOUNT)
        [docs]def makeiter(obj): @@ -263,7 +327,6 @@ # Client classes # ------------------------------------------------------------ -
        [docs]class DummyClient(telnet.StatefulTelnetProtocol): """ Handles connection to a running Evennia server, @@ -272,29 +335,80 @@ """ +
        [docs] def report(self, text, clientkey): + pad = " " * (25 - len(text)) + tim = round(time.time() - self.connection_timestamp) + print(f"{text} {clientkey}{pad}\t" + f"conn: {NCONNECTED} -> " + f"welcome screen: {NLOGIN_SCREEN} -> " + f"authing: {NLOGGING_IN} -> " + f"loggedin/tot: {NLOGGED_IN}/{NCLIENTS} (after {tim}s)")
        +
        [docs] def connectionMade(self): """ Called when connection is first established. """ + global NCONNECTED # public properties self.cid = idcounter() - self.key = "Dummy-%s" % self.cid - self.gid = "%s-%s" % (time.strftime(DATESTRING), self.cid) + self.key = f"Dummy-{self.cid}" + self.gid = f"{time.strftime(DATESTRING)}_{self.cid}" self.istep = 0 self.exits = [] # exit names created self.objs = [] # obj names created + self.connection_timestamp = time.time() + self.connection_attempt = 0 + self.action_started = 0 self._connected = False self._loggedin = False self._logging_out = False + self._ready = False self._report = "" self._cmdlist = [] # already stepping in a cmd definition self._login = self.factory.actions[0] self._logout = self.factory.actions[1] self._actions = self.factory.actions[2:] - reactor.addSystemEventTrigger("before", "shutdown", self.logout)
        + reactor.addSystemEventTrigger("before", "shutdown", self.logout) + + NCONNECTED += 1 + self.report("-> connected", self.key) + + reactor.callLater(30, self._retry_welcome_screen)
        + + def _retry_welcome_screen(self): + if not self._connected and not self._ready: + # we have connected but not received anything for 30s. + # (unclear why this would be - overload?) + # try sending a look to get something to start with + self.report("?? retrying welcome screen", self.key) + self.sendLine(bytes("look", 'utf-8')) + # make sure to check again later + reactor.callLater(30, self._retry_welcome_screen) + + def _print_statistics(self): + global TIME_ALL_LOGIN, TOTAL_ACTIONS + global TOTAL_LAG, TOTAL_LAG_MEASURES, TOTAL_LAG_IN, TOTAL_LAG_OUT + + tim = time.time() - TIME_ALL_LOGIN + avgrate = round(TOTAL_ACTIONS / tim) + lag = TOTAL_LAG / (TOTAL_LAG_MEASURES or 1) + lag_in = TOTAL_LAG_IN / (TOTAL_LAG_MEASURES or 1) + lag_out = TOTAL_LAG_OUT / (TOTAL_LAG_MEASURES or 1) + + TOTAL_ACTIONS = 0 + TOTAL_LAG = 0 + TOTAL_LAG_IN = 0 + TOTAL_LAG_OUT = 0 + TOTAL_LAG_MEASURES = 0 + TIME_ALL_LOGIN = time.time() + + print(f".. running 30s average: ~{avgrate} actions/s " + f"lag: {lag:.2}s (in: {lag_in:.2}s, out: {lag_out:.2}s)") + + reactor.callLater(30, self._print_statistics)
        [docs] def dataReceived(self, data): """ @@ -305,15 +419,67 @@ data (str): Incoming data. """ - if not self._connected and not data.startswith(chr(255)): - # wait until we actually get text back (not just telnet - # negotiation) - self._connected = True - # start client tick - d = LoopingCall(self.step) - # dissipate exact step by up to +/- 0.5 second - timestep = TIMESTEP + (-0.5 + (random.random() * 1.0)) - d.start(timestep, now=True).addErrback(self.error)
        + global NLOGIN_SCREEN, NLOGGED_IN, NLOGGING_IN, NCONNECTED + global TOTAL_ACTIONS, TIME_ALL_LOGIN + global TOTAL_LAG, TOTAL_LAG_MEASURES, TOTAL_LAG_IN, TOTAL_LAG_OUT + + if not data.startswith(b"\xff"): + # regular text, not a telnet command + + if NCLIENTS == 1: + print("dummy-client sees:", str(data, "utf-8")) + + if not self._connected: + # waiting for connection + # wait until we actually get text back (not just telnet + # negotiation) + # start client tick + d = LoopingCall(self.step) + df = max(abs(TIMESTEP * 0.001), min(TIMESTEP/10, 0.5)) + # dither next attempt with random time + timestep = TIMESTEP + (-df + (random.random() * df)) + d.start(timestep, now=True).addErrback(self.error) + self.connection_attempt += 1 + + self._connected = True + NLOGIN_SCREEN += 1 + NCONNECTED -= 1 + self.report("<- server sent login screen", self.key) + + elif self._loggedin: + if not self._ready: + # logged in, ready to run + NLOGGED_IN += 1 + NLOGGING_IN -= 1 + self._ready = True + self.report("== logged in", self.key) + if NLOGGED_IN == NCLIENTS and not TIME_ALL_LOGIN: + # all are logged in! We can start collecting statistics + print(".. All clients connected and logged in!") + TIME_ALL_LOGIN = time.time() + reactor.callLater(30, self._print_statistics) + + elif TIME_ALL_LOGIN: + TOTAL_ACTIONS += 1 + + try: + data = strip_ansi(str(data, "utf-8").strip()) + if data.startswith("dummyrunner_echo_response:"): + # handle special lag-measuring command. This returns + # dummyrunner_echo_response:<starttime>,<midpointtime> + now = time.time() + _, data = data.split(":", 1) + start_time, mid_time = (float(part) for part in data.split(",", 1)) + lag_in = mid_time - start_time + lag_out = now - mid_time + total_lag = now - start_time # full round-about time + + TOTAL_LAG += total_lag + TOTAL_LAG_IN += lag_in + TOTAL_LAG_OUT += lag_out + TOTAL_LAG_MEASURES += 1 + except Exception: + pass
        [docs] def connectionLost(self, reason): """ @@ -324,7 +490,7 @@ """ if not self._logging_out: - print("client %s(%s) lost connection (%s)" % (self.key, self.cid, reason))
        + self.report("XX lost connection", self.key)
        [docs] def error(self, err): """ @@ -351,9 +517,9 @@ """ self._logging_out = True - cmd = self._logout(self) - print("client %s(%s) logout (%s actions)" % (self.key, self.cid, self.istep)) - self.sendLine(cmd)
        + cmd = self._logout(self)[0] + self.report(f"-> logout/disconnect ({self.istep} actions)", self.key) + self.sendLine(bytes(cmd, 'utf-8'))
        [docs] def step(self): """ @@ -362,7 +528,7 @@ all "intelligence" of the dummy client. """ - global NLOGGED_IN + global NLOGGING_IN, NLOGIN_SCREEN rand = random.random() @@ -370,11 +536,13 @@ # no commands ready. Load some. if not self._loggedin: - if rand < CHANCE_OF_LOGIN: + if rand < CHANCE_OF_LOGIN or NLOGGING_IN < 10: + # lower rate of logins, but not below 1 / s # get the login commands self._cmdlist = list(makeiter(self._login(self))) - NLOGGED_IN += 1 # this is for book-keeping - print("connecting client %s (%i/%i)..." % (self.key, NLOGGED_IN, NCLIENTS)) + NLOGGING_IN += 1 # this is for book-keeping + NLOGIN_SCREEN -= 1 + self.report("-> create/login", self.key) self._loggedin = True else: # no login yet, so cmdlist not yet set @@ -388,12 +556,26 @@ # at this point we always have a list of commands if rand < CHANCE_OF_ACTION: # send to the game - self.sendLine(str(self._cmdlist.pop(0))) - self.istep += 1
        + cmd = str(self._cmdlist.pop(0)) + + if cmd.startswith("dummyrunner_echo_response"): + # we need to set the timer element as close to + # the send as possible + cmd = cmd.format(timestamp=time.time()) + + self.sendLine(bytes(cmd, 'utf-8')) + self.action_started = time.time() + self.istep += 1 + + if NCLIENTS == 1: + print(f"dummy-client sent: {cmd}") -
        [docs]class DummyFactory(protocol.ClientFactory): +
        [docs]class DummyFactory(protocol.ReconnectingClientFactory): protocol = DummyClient + initialDelay = 1 + maxDelay = 1 + noisy = False
        [docs] def __init__(self, actions): "Setup the factory base (shared by all clients)" @@ -438,7 +620,7 @@ # setting up all clients (they are automatically started) factory = DummyFactory(actions) for i in range(NCLIENTS): - reactor.connectTCP("localhost", TELNET_PORT, factory) + reactor.connectTCP("127.0.0.1", TELNET_PORT, factory) # start reactor reactor.run()
        @@ -463,12 +645,23 @@ ) args = parser.parse_args() + nclients = int(args.nclients[0]) - print(INFO_STARTING.format(N=args.nclients[0])) + print(INFO_STARTING.format( + nclients=nclients, + port=TELNET_PORT, + idmapper_cache_size=IDMAPPER_CACHE_MAXSIZE, + timestep=TIMESTEP, + rate=1/TIMESTEP, + chance_of_login=CHANCE_OF_LOGIN * 100, + chance_of_action=CHANCE_OF_ACTION * 100, + avg_rate=(1 / TIMESTEP) * CHANCE_OF_ACTION, + avg_rate_total=(1 / TIMESTEP) * CHANCE_OF_ACTION * nclients + )) # run the dummyrunner - t0 = time.time() - start_all_dummy_clients(nclients=args.nclients[0]) + TIME_START = t0 = time.time() + start_all_dummy_clients(nclients=nclients) ttot = time.time() - t0 # output runtime @@ -510,7 +703,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -529,6 +721,7 @@ +
        develop branch
        @@ -47,45 +48,47 @@ The settings are global variables: -TIMESTEP - time in seconds between each 'tick' -CHANCE_OF_ACTION - chance 0-1 of action happening -CHANCE_OF_LOGIN - chance 0-1 of login happening -TELNET_PORT - port to use, defaults to settings.TELNET_PORT -ACTIONS - see below +- TIMESTEP - time in seconds between each 'tick'. 1 is a good start. +- CHANCE_OF_ACTION - chance 0-1 of action happening. Default is 0.5. +- CHANCE_OF_LOGIN - chance 0-1 of login happening. 0.01 is a good number. +- TELNET_PORT - port to use, defaults to settings.TELNET_PORT +- ACTIONS - see below ACTIONS is a tuple -``` +```python (login_func, logout_func, (0.3, func1), (0.1, func2) ... ) + ``` where the first entry is the function to call on first connect, with a chance of occurring given by CHANCE_OF_LOGIN. This function is usually responsible for logging in the account. The second entry is always called when the dummyrunner disconnects from the server and should -thus issue a logout command. The other entries are tuples (chance, +thus issue a logout command. The other entries are tuples (chance, func). They are picked randomly, their commonality based on the cumulative chance given (the chance is normalized between all options so if will still work also if the given chances don't add up to 1). -Since each function can return a list of game-command strings, each -function may result in multiple operations. + +The PROFILE variable define pre-made ACTION tuples for convenience. + +Each function should return an iterable of one or more command-call +strings (like "look here"), so each can group multiple command operations. An action-function is called with a "client" argument which is a -reference to the dummy client currently performing the action. It -returns a string or a list of command strings to execute. Use the -client object for optionally saving data between actions. +reference to the dummy client currently performing the action. The client object has the following relevant properties and methods: - key - an optional client key. This is only used for dummyrunner output. - Default is "Dummy-<cid>" + Default is "Dummy-<cid>" - cid - client id - gid - globally unique id, hashed with time stamp - istep - the current step - exits - an empty list. Can be used to store exit names - objs - an empty list. Can be used to store object names - counter() - returns a unique increasing id, hashed with time stamp - to make it unique also between dummyrunner instances. + to make it unique also between dummyrunner instances. The return should either be a single command string or a tuple of command strings. This list of commands will always be executed every @@ -93,14 +96,18 @@ (no randomness) and allows for setting up a more complex chain of commands (such as creating an account and logging in). ---- +---- """ +import random +import string + # Dummy runner settings # Time between each dummyrunner "tick", in seconds. Each dummy # will be called with this frequency. -TIMESTEP = 2 +TIMESTEP = 1 +# TIMESTEP = 0.025 # 40/s # Chance of a dummy actually performing an action on a given tick. # This spreads out usage randomly, like it would be in reality. @@ -109,7 +116,7 @@ # Chance of a currently unlogged-in dummy performing its login # action every tick. This emulates not all accounts logging in # at exactly the same time. -CHANCE_OF_LOGIN = 1.0 +CHANCE_OF_LOGIN = 0.01 # Which telnet port to connect to. If set to None, uses the first # default telnet port of the running server. @@ -120,9 +127,10 @@ # some convenient templates -DUMMY_NAME = "Dummy-%s" -DUMMY_PWD = "password-%s" -START_ROOM = "testing_room_start_%s" +DUMMY_NAME = "Dummy_{gid}" +DUMMY_PWD = (''.join(random.choice(string.ascii_letters + string.digits) + for _ in range(20)) + "-{gid}") +START_ROOM = "testing_room_start_{gid}" ROOM_TEMPLATE = "testing_room_%s" EXIT_TEMPLATE = "exit_%s" OBJ_TEMPLATE = "testing_obj_%s" @@ -135,42 +143,45 @@ # login/logout -
        [docs]def c_login(client): "logins to the game" # we always use a new client name - cname = DUMMY_NAME % client.gid - cpwd = DUMMY_PWD % client.gid + cname = DUMMY_NAME.format(gid=client.gid) + cpwd = DUMMY_PWD.format(gid=client.gid) + room_name = START_ROOM.format(gid=client.gid) - # set up for digging a first room (to move to and keep the - # login room clean) - roomname = ROOM_TEMPLATE % client.counter() - exitname1 = EXIT_TEMPLATE % client.counter() - exitname2 = EXIT_TEMPLATE % client.counter() - client.exits.extend([exitname1, exitname2]) + # we assign the dummyrunner cmdsert to ourselves so # we can use special commands + add_cmdset = ( + "py from evennia.server.profiling.dummyrunner import DummyRunnerCmdSet;" + "self.cmdset.add(DummyRunnerCmdSet, persistent=False)" + ) + # create character, log in, then immediately dig a new location and + # teleport it (to keep the login room clean) cmds = ( - "create %s %s" % (cname, cpwd), - "connect %s %s" % (cname, cpwd), - "@dig %s" % START_ROOM % client.gid, - "@teleport %s" % START_ROOM % client.gid, - "@dig %s = %s, %s" % (roomname, exitname1, exitname2), + f"create {cname} {cpwd}", + f"connect {cname} {cpwd}", + f"dig {room_name}", + f"teleport {room_name}", + add_cmdset, ) return cmds
        [docs]def c_login_nodig(client): "logins, don't dig its own room" - cname = DUMMY_NAME % client.gid - cpwd = DUMMY_PWD % client.gid - - cmds = ("create %s %s" % (cname, cpwd), "connect %s %s" % (cname, cpwd)) + cname = DUMMY_NAME.format(gid=client.gid) + cpwd = DUMMY_PWD.format(gid=client.gid) + cmds = ( + f"create {cname} {cpwd}", + f"connect {cname} {cpwd}" + ) return cmds
        [docs]def c_logout(client): "logouts of the game" - return "@quit"
        + return ("quit",)
        # random commands @@ -182,7 +193,7 @@ if not cmds: cmds = ["look %s" % exi for exi in client.exits] if not cmds: - cmds = "look" + cmds = ("look",) return cmds @@ -192,7 +203,7 @@ if not cmds: cmds = ["examine %s" % exi for exi in client.exits] if not cmds: - cmds = "examine me" + cmds = ("examine me",) return cmds @@ -204,7 +215,7 @@
        [docs]def c_help(client): "reads help files" - cmds = ("help", "help @teleport", "help look", "help @tunnel", "help @dig") + cmds = ("help", "dummyrunner_echo_response",) return cmds
        @@ -214,7 +225,7 @@ exitname1 = EXIT_TEMPLATE % client.counter() exitname2 = EXIT_TEMPLATE % client.counter() client.exits.extend([exitname1, exitname2]) - return "@dig/tel %s = %s, %s" % (roomname, exitname1, exitname2) + return ("dig/tel %s = %s, %s" % (roomname, exitname1, exitname2),)
        [docs]def c_creates_obj(client): @@ -222,10 +233,10 @@ objname = OBJ_TEMPLATE % client.counter() client.objs.append(objname) cmds = ( - "@create %s" % objname, - '@desc %s = "this is a test object' % objname, - "@set %s/testattr = this is a test attribute value." % objname, - "@set %s/testattr2 = this is a second test attribute." % objname, + "create %s" % objname, + 'desc %s = "this is a test object' % objname, + "set %s/testattr = this is a test attribute value." % objname, + "set %s/testattr2 = this is a second test attribute." % objname, ) return cmds
        @@ -234,16 +245,14 @@ "creates example button, storing name on client" objname = TOBJ_TEMPLATE % client.counter() client.objs.append(objname) - cmds = ("@create %s:%s" % (objname, TOBJ_TYPECLASS), "@desc %s = test red button!" % objname) + cmds = ("create %s:%s" % (objname, TOBJ_TYPECLASS), "desc %s = test red button!" % objname) return cmds
        [docs]def c_socialize(client): "socializechats on channel" cmds = ( - "ooc Hello!", - "ooc Testing ...", - "ooc Testing ... times 2", + "pub Hello!", "say Yo!", "emote stands looking around.", ) @@ -253,84 +262,120 @@
        [docs]def c_moves(client): "moves to a previously created room, using the stored exits" cmds = client.exits # try all exits - finally one will work - return "look" if not cmds else cmds
        + return ("look",) if not cmds else cmds
        [docs]def c_moves_n(client): "move through north exit if available" - return "north"
        + return ("north",)
        [docs]def c_moves_s(client): "move through south exit if available" - return "south"
        + return ("south",) -# Action tuple (required) -# -# This is a tuple of client action functions. The first element is the -# function the client should use to log into the game and move to -# STARTROOM . The second element is the logout command, for cleanly -# exiting the mud. The following elements are 2-tuples of (probability, -# action_function). The probablities should normally sum up to 1, -# otherwise the system will normalize them. +
        [docs]def c_measure_lag(client): + """ + Special dummyrunner command, injected in c_login. It measures + response time. Including this in the ACTION tuple will give more + dummyrunner output about just how fast commands are being processed. + + The dummyrunner will treat this special and inject the + {timestamp} just before sending. + + """ + return ("dummyrunner_echo_response {timestamp}",)
        + + +# Action profile (required) + +# Some pre-made profiles to test. To make your own, just assign a tuple to ACTIONS. # +# idler - does nothing after logging in +# looker - just looks around +# normal_player - moves around, reads help, looks around (digs rarely) (spammy) +# normal_builder - digs now and then, examines, creates objects, moves +# heavy_builder - digs and creates a lot, moves and examines +# socializing_builder - builds a lot, creates help entries, moves, chat (spammy) +# only_digger - extreme builder that only digs room after room + +PROFILE = "looker" -# "normal builder" definitionj -# ACTIONS = ( c_login, -# c_logout, -# (0.5, c_looks), -# (0.08, c_examines), -# (0.1, c_help), -# (0.01, c_digs), -# (0.01, c_creates_obj), -# (0.3, c_moves)) -# "heavy" builder definition -# ACTIONS = ( c_login, -# c_logout, -# (0.2, c_looks), -# (0.1, c_examines), -# (0.2, c_help), -# (0.1, c_digs), -# (0.1, c_creates_obj), -# #(0.01, c_creates_button), -# (0.2, c_moves)) -# "passive account" definition -# ACTIONS = ( c_login, -# c_logout, -# (0.7, c_looks), -# #(0.1, c_examines), -# (0.3, c_help)) -# #(0.1, c_digs), -# #(0.1, c_creates_obj), -# #(0.1, c_creates_button), -# #(0.4, c_moves)) -# "inactive account" definition -# ACTIONS = (c_login_nodig, -# c_logout, -# (1.0, c_idles)) -# "normal account" definition -ACTIONS = (c_login, c_logout, (0.01, c_digs), (0.39, c_looks), (0.2, c_help), (0.4, c_moves)) -# walking tester. This requires a pre-made -# "loop" of multiple rooms that ties back -# to limbo (using @tunnel and @open) -# ACTIONS = (c_login_nodig, -# c_logout, -# (1.0, c_moves_n)) -# "socializing heavy builder" definition -# ACTIONS = (c_login, -# c_logout, -# (0.1, c_socialize), -# (0.1, c_looks), -# (0.2, c_help), -# (0.1, c_creates_obj), -# (0.2, c_digs), -# (0.3, c_moves)) -# "heavy digger memory tester" definition -# ACTIONS = (c_login, -# c_logout, -# (1.0, c_digs)) +if PROFILE == 'idler': + ACTIONS = ( + c_login, + c_logout, + (0.9, c_idles), + (0.1, c_measure_lag), + ) +elif PROFILE == 'looker': + ACTIONS = ( + c_login, + c_logout, + (0.8, c_looks), + (0.2, c_measure_lag) + ) +elif PROFILE == 'normal_player': + ACTIONS = ( + c_login, + c_logout, + (0.01, c_digs), + (0.29, c_looks), + (0.2, c_help), + (0.3, c_moves), + (0.05, c_socialize), + (0.1, c_measure_lag) + ) +elif PROFILE == 'normal_builder': + ACTIONS = ( + c_login, + c_logout, + (0.5, c_looks), + (0.08, c_examines), + (0.1, c_help), + (0.01, c_digs), + (0.01, c_creates_obj), + (0.2, c_moves), + (0.1, c_measure_lag) + ) +elif PROFILE == 'heavy_builder': + ACTIONS = ( + c_login, + c_logout, + (0.1, c_looks), + (0.1, c_examines), + (0.2, c_help), + (0.1, c_digs), + (0.1, c_creates_obj), + (0.2, c_moves), + (0.1, c_measure_lag) + ) +elif PROFILE == 'socializing_builder': + ACTIONS = ( + c_login, + c_logout, + (0.1, c_socialize), + (0.1, c_looks), + (0.1, c_help), + (0.1, c_creates_obj), + (0.2, c_digs), + (0.3, c_moves), + (0.1, c_measure_lag) + ) +elif PROFILE == 'only_digger': + ACTIONS = ( + c_login, + c_logout, + (0.9, c_digs), + (0.1, c_measure_lag) + ) + +else: + print("No dummyrunner ACTION profile defined.") + import sys + sys.exit()
        @@ -368,7 +413,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -387,6 +431,7 @@ +
        develop branch
        @@ -192,7 +193,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -211,6 +211,7 @@ +
        develop branch
        @@ -119,7 +120,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -138,6 +138,7 @@ +
        develop branch
        @@ -41,6 +42,7 @@

        Source code for evennia.server.profiling.tests

         from django.test import TestCase
         from mock import Mock, patch, mock_open
        +from anything import Something
         from .dummyrunner_settings import (
             c_creates_button,
             c_creates_obj,
        @@ -70,8 +72,8 @@
                 self.client.cid = 1
                 self.client.counter = Mock(return_value=1)
                 self.client.gid = "20171025161153-1"
        -        self.client.name = "Dummy-%s" % self.client.gid
        -        self.client.password = "password-%s" % self.client.gid
        +        self.client.name = "Dummy_%s" % self.client.gid
        +        self.client.password = Something,
                 self.client.start_room = "testing_room_start_%s" % self.client.gid
                 self.client.objs = []
                 self.client.exits = []
        @@ -84,28 +86,25 @@ self.assertEqual( c_login(self.client), ( - "create %s %s" % (self.client.name, self.client.password), - "connect %s %s" % (self.client.name, self.client.password), - "@dig %s" % self.client.start_room, - "@teleport %s" % self.client.start_room, - "@dig testing_room_1 = exit_1, exit_1", + Something, # create + Something, # connect + "dig %s" % self.client.start_room, + "teleport %s" % self.client.start_room, + "py from evennia.server.profiling.dummyrunner import DummyRunnerCmdSet;" + "self.cmdset.add(DummyRunnerCmdSet, persistent=False)" ), )
        [docs] def test_c_login_no_dig(self): - self.assertEqual( - c_login_nodig(self.client), - ( - "create %s %s" % (self.client.name, self.client.password), - "connect %s %s" % (self.client.name, self.client.password), - ), - )
        + cmd1, cmd2 = c_login_nodig(self.client) + self.assertTrue(cmd1.startswith("create " + self.client.name + " ")) + self.assertTrue(cmd2.startswith("connect " + self.client.name + " "))
        [docs] def test_c_logout(self): - self.assertEqual(c_logout(self.client), "@quit")
        + self.assertEqual(c_logout(self.client), ("quit",))
        [docs] def perception_method_tests(self, func, verb, alone_suffix=""): - self.assertEqual(func(self.client), "%s%s" % (verb, alone_suffix)) + self.assertEqual(func(self.client), ("%s%s" % (verb, alone_suffix),)) self.client.exits = ["exit1", "exit2"] self.assertEqual(func(self.client), ["%s exit1" % verb, "%s exit2" % verb]) self.client.objs = ["foo", "bar"] @@ -124,11 +123,11 @@
        [docs] def test_c_help(self): self.assertEqual( c_help(self.client), - ("help", "help @teleport", "help look", "help @tunnel", "help @dig"), + ("help", "dummyrunner_echo_response"), )
        [docs] def test_c_digs(self): - self.assertEqual(c_digs(self.client), ("@dig/tel testing_room_1 = exit_1, exit_1")) + self.assertEqual(c_digs(self.client), ("dig/tel testing_room_1 = exit_1, exit_1", )) self.assertEqual(self.client.exits, ["exit_1", "exit_1"]) self.clear_client_lists()
        @@ -137,10 +136,10 @@ self.assertEqual( c_creates_obj(self.client), ( - "@create %s" % objname, - '@desc %s = "this is a test object' % objname, - "@set %s/testattr = this is a test attribute value." % objname, - "@set %s/testattr2 = this is a second test attribute." % objname, + "create %s" % objname, + 'desc %s = "this is a test object' % objname, + "set %s/testattr = this is a test attribute value." % objname, + "set %s/testattr2 = this is a second test attribute." % objname, ), ) self.assertEqual(self.client.objs, [objname]) @@ -151,7 +150,7 @@ typeclass_name = "contrib.tutorial_examples.red_button.RedButton" self.assertEqual( c_creates_button(self.client), - ("@create %s:%s" % (objname, typeclass_name), "@desc %s = test red button!" % objname), + ("create %s:%s" % (objname, typeclass_name), "desc %s = test red button!" % objname), ) self.assertEqual(self.client.objs, [objname]) self.clear_client_lists()
        @@ -160,25 +159,23 @@ self.assertEqual( c_socialize(self.client), ( - "ooc Hello!", - "ooc Testing ...", - "ooc Testing ... times 2", + "pub Hello!", "say Yo!", "emote stands looking around.", ), )
        [docs] def test_c_moves(self): - self.assertEqual(c_moves(self.client), "look") + self.assertEqual(c_moves(self.client), ("look",)) self.client.exits = ["south", "north"] self.assertEqual(c_moves(self.client), ["south", "north"]) self.clear_client_lists()
        [docs] def test_c_move_n(self): - self.assertEqual(c_moves_n(self.client), "north")
        + self.assertEqual(c_moves_n(self.client), ("north",))
        [docs] def test_c_move_s(self): - self.assertEqual(c_moves_s(self.client), "south")
        + self.assertEqual(c_moves_s(self.client), ("south",))
        [docs]class TestMemPlot(TestCase): @@ -238,7 +235,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -257,6 +253,7 @@ +
        develop branch
        @@ -116,7 +117,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -135,6 +135,7 @@ +
        develop branch
        @@ -40,12 +41,12 @@

        Source code for evennia.server.server

         """
        -This module implements the main Evennia server process, the core of
        -the game engine.
        +This module implements the main Evennia server process, the core of the game
        +engine.
         
        -This module should be started with the 'twistd' executable since it
        -sets up all the networking features.  (this is done automatically
        -by evennia/server/server_runner.py).
        +This module should be started with the 'twistd' executable since it sets up all
        +the networking features.  (this is done automatically by
        +evennia/server/server_runner.py).
         
         """
         import time
        @@ -63,6 +64,7 @@
         django.setup()
         
         import evennia
        +import importlib
         
         evennia._init()
         
        @@ -73,11 +75,9 @@
         from evennia.accounts.models import AccountDB
         from evennia.scripts.models import ScriptDB
         from evennia.server.models import ServerConfig
        -from evennia.server import initial_setup
         
         from evennia.utils.utils import get_evennia_version, mod_import, make_iter
         from evennia.utils import logger
        -from evennia.comms import channelhandler
         from evennia.server.sessionhandler import SESSIONS
         
         from django.utils.translation import gettext as _
        @@ -184,12 +184,6 @@
             if _MAINTENANCE_COUNT % 5 == 0:
                 # check cache size every 5 minutes
                 _FLUSH_CACHE(_IDMAPPER_CACHE_MAXSIZE)
        -    if _MAINTENANCE_COUNT % 60 == 0:
        -        # validate scripts every hour
        -        evennia.ScriptDB.objects.validate()
        -    if _MAINTENANCE_COUNT % 61 == 0:
        -        # validate channels off-sync with scripts
        -        evennia.CHANNEL_HANDLER.update()
             if _MAINTENANCE_COUNT % (60 * 7) == 0:
                 # drop database connection every 7 hrs to avoid default timeouts on MySQL
                 # (see https://github.com/evennia/evennia/issues/1376)
        @@ -216,12 +210,13 @@
         # ------------------------------------------------------------
         
         
        -
        [docs]class Evennia(object): +
        [docs]class Evennia: """ The main Evennia server handler. This object sets up the database and tracks and interlinks all the twisted network services that make up evennia. + """
        [docs] def __init__(self, application): @@ -246,12 +241,6 @@ self.start_time = time.time() - # initialize channelhandler - try: - channelhandler.CHANNELHANDLER.update() - except OperationalError: - print("channelhandler couldn't update - db not set up") - # wrap the SIGINT handler to make sure we empty the threadpool # even when we reload and we have long-running requests in queue. # this is necessary over using Twisted's signal handler. @@ -297,6 +286,7 @@ This allows for changing default cmdset locations and default typeclasses in the settings file and have them auto-update all already existing objects. + """ global INFO_DICT @@ -386,6 +376,7 @@ Once finished the last_initial_setup_step is set to -1. """ global INFO_DICT + initial_setup = importlib.import_module(settings.INITIAL_SETUP_MODULE) last_initial_setup_step = ServerConfig.objects.conf("last_initial_setup_step") if not last_initial_setup_step: # None is only returned if the config does not exist, @@ -444,18 +435,17 @@ """ Shuts down the server from inside it. - Keyword Args: - mode (str): Sets the server restart mode: - - 'reload': server restarts, no "persistent" scripts - are stopped, at_reload hooks called. - - 'reset' - server restarts, non-persistent scripts stopped, - at_shutdown hooks called but sessions will not - be disconnected. - -'shutdown' - like reset, but server will not auto-restart. - _reactor_stopping: This is set if server is stopped by a kill - command OR this method was already called - once - in both cases the reactor is dead/stopping already. - + mode - sets the server restart mode. + - 'reload' - server restarts, no "persistent" scripts + are stopped, at_reload hooks called. + - 'reset' - server restarts, non-persistent scripts stopped, + at_shutdown hooks called but sessions will not + be disconnected. + - 'shutdown' - like reset, but server will not auto-restart. + _reactor_stopping - this is set if server is stopped by a kill + command OR this method was already called + once - in both cases the reactor is + dead/stopping already. """ if _reactor_stopping and hasattr(self, "shutdown_complete"): # this means we have already passed through this method @@ -472,9 +462,9 @@ yield [o.at_server_reload() for o in ObjectDB.get_all_cached_instances()] yield [p.at_server_reload() for p in AccountDB.get_all_cached_instances()] yield [ - (s.pause(manual_pause=False), s.at_server_reload()) + (s._pause_task(auto_pause=True), s.at_server_reload()) for s in ScriptDB.get_all_cached_instances() - if s.id and (s.is_active or s.attributes.has("_manual_pause")) + if s.id and s.is_active ] yield self.sessions.all_sessions_portal_sync() self.at_server_reload_stop() @@ -498,11 +488,9 @@ ] yield ObjectDB.objects.clear_all_sessids() yield [ - ( - s.pause(manual_pause=s.attributes.get("_manual_pause", False)), - s.at_server_shutdown(), - ) + (s._pause_task(auto_pause=True), s.at_server_shutdown()) for s in ScriptDB.get_all_cached_instances() + if s.id and s.is_active ] ServerConfig.objects.conf("server_restart_mode", "reset") self.at_server_cold_stop() @@ -527,7 +515,10 @@ ServerConfig.objects.conf("runtime", _GAMETIME_MODULE.runtime())
        [docs] def get_info_dict(self): - "Return the server info, for display." + """ + Return the server info, for display. + + """ return INFO_DICT
        # server start/stop hooks @@ -536,6 +527,7 @@ """ This is called every time the server starts up, regardless of how it was shut down. + """ if SERVER_STARTSTOP_MODULE: SERVER_STARTSTOP_MODULE.at_server_start()
        @@ -544,6 +536,7 @@ """ This is called just before a server is shut down, regardless of it is fore a reload, reset or shutdown. + """ if SERVER_STARTSTOP_MODULE: SERVER_STARTSTOP_MODULE.at_server_stop()
        @@ -551,6 +544,7 @@
        [docs] def at_server_reload_start(self): """ This is called only when server starts back up after a reload. + """ if SERVER_STARTSTOP_MODULE: SERVER_STARTSTOP_MODULE.at_server_reload_start()
        @@ -561,7 +555,7 @@ after reconnecting. Args: - mode (str): One of reload, reset or shutdown. + mode (str): One of 'reload', 'reset' or 'shutdown'. """ @@ -573,9 +567,8 @@ TICKER_HANDLER.restore(mode == "reload") - # after sync is complete we force-validate all scripts - # (this also starts any that didn't yet start) - ScriptDB.objects.validate(init_mode=mode) + # Un-pause all scripts, stop non-persistent timers + ScriptDB.objects.update_scripts_after_server_start() # start the task handler from evennia.scripts.taskhandler import TASK_HANDLER @@ -591,11 +584,10 @@ god_account = AccountDB.objects.get(id=1) # mudinfo mudinfo_chan = settings.CHANNEL_MUDINFO - if not mudinfo_chan: - raise RuntimeError("settings.CHANNEL_MUDINFO must be defined.") - if not ChannelDB.objects.filter(db_key=mudinfo_chan["key"]): - channel = create_channel(**mudinfo_chan) - channel.connect(god_account) + if mudinfo_chan: + if not ChannelDB.objects.filter(db_key=mudinfo_chan["key"]): + channel = create_channel(**mudinfo_chan) + channel.connect(god_account) # connectinfo connectinfo_chan = settings.CHANNEL_MUDINFO if connectinfo_chan: @@ -613,6 +605,7 @@
        [docs] def at_server_reload_stop(self): """ This is called only time the server stops before a reload. + """ if SERVER_STARTSTOP_MODULE: SERVER_STARTSTOP_MODULE.at_server_reload_stop()
        @@ -621,6 +614,7 @@ """ This is called only when the server starts "cold", i.e. after a shutdown or a reset. + """ # We need to do this just in case the server was killed in a way where # the normal cleanup operations did not have time to run. @@ -632,7 +626,7 @@ from evennia.scripts.models import ScriptDB for script in ScriptDB.objects.filter(db_persistent=False): - script.stop() + script._stop_task() if GUEST_ENABLED: for guest in AccountDB.objects.all().filter( @@ -648,6 +642,7 @@
        [docs] def at_server_cold_stop(self): """ This is called only when the server goes down due to a shutdown or reset. + """ if SERVER_STARTSTOP_MODULE: SERVER_STARTSTOP_MODULE.at_server_cold_stop()
        @@ -818,7 +813,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -837,6 +831,7 @@ +
        develop branch
        @@ -47,142 +48,22 @@ It is stored on the Server side (as opposed to protocol-specific sessions which are stored on the Portal side) """ -import weakref import time from django.utils import timezone from django.conf import settings from evennia.comms.models import ChannelDB from evennia.utils import logger -from evennia.utils.utils import make_iter, lazy_property +from evennia.utils.utils import make_iter, lazy_property, class_from_module from evennia.commands.cmdsethandler import CmdSetHandler -from evennia.server.session import Session from evennia.scripts.monitorhandler import MONITOR_HANDLER +from evennia.typeclasses.attributes import AttributeHandler, InMemoryAttributeBackend, DbHolder _GA = object.__getattribute__ _SA = object.__setattr__ _ObjectDB = None _ANSI = None -# i18n -from django.utils.translation import gettext as _ - -# Handlers for Session.db/ndb operation - - -
        [docs]class NDbHolder(object): - """Holder for allowing property access of attributes""" - -
        [docs] def __init__(self, obj, name, manager_name="attributes"): - _SA(self, name, _GA(obj, manager_name)) - _SA(self, "name", name)
        - - def __getattribute__(self, attrname): - if attrname == "all": - # we allow to overload our default .all - attr = _GA(self, _GA(self, "name")).get("all") - return attr if attr else _GA(self, "all") - return _GA(self, _GA(self, "name")).get(attrname) - - def __setattr__(self, attrname, value): - _GA(self, _GA(self, "name")).add(attrname, value) - - def __delattr__(self, attrname): - _GA(self, _GA(self, "name")).remove(attrname) - -
        [docs] def get_all(self): - return _GA(self, _GA(self, "name")).all()
        - - all = property(get_all)
        - - -
        [docs]class NAttributeHandler(object): - """ - NAttributeHandler version without recache protection. - This stand-alone handler manages non-database saving. - It is similar to `AttributeHandler` and is used - by the `.ndb` handler in the same way as `.db` does - for the `AttributeHandler`. - """ - -
        [docs] def __init__(self, obj): - """ - Initialized on the object - """ - self._store = {} - self.obj = weakref.proxy(obj)
        - -
        [docs] def has(self, key): - """ - Check if object has this attribute or not. - - Args: - key (str): The Nattribute key to check. - - Returns: - has_nattribute (bool): If Nattribute is set or not. - - """ - return key in self._store
        - -
        [docs] def get(self, key, default=None): - """ - Get the named key value. - - Args: - key (str): The Nattribute key to get. - - Returns: - the value of the Nattribute. - - """ - return self._store.get(key, default)
        - -
        [docs] def add(self, key, value): - """ - Add new key and value. - - Args: - key (str): The name of Nattribute to add. - value (any): The value to store. - - """ - self._store[key] = value
        - -
        [docs] def remove(self, key): - """ - Remove Nattribute from storage. - - Args: - key (str): The name of the Nattribute to remove. - - """ - if key in self._store: - del self._store[key]
        - -
        [docs] def clear(self): - """ - Remove all NAttributes from handler. - - """ - self._store = {}
        - -
        [docs] def all(self, return_tuples=False): - """ - List the contents of the handler. - - Args: - return_tuples (bool, optional): Defines if the Nattributes - are returns as a list of keys or as a list of `(key, value)`. - - Returns: - nattributes (list): A list of keys `[key, key, ...]` or a - list of tuples `[(key, value), ...]` depending on the - setting of `return_tuples`. - - """ - if return_tuples: - return [(key, value) for (key, value) in self._store.items() if not key.startswith("_")] - return [key for key in self._store if not key.startswith("_")]
        +_BASE_SESSION_CLASS = class_from_module(settings.BASE_SESSION_CLASS) # ------------------------------------------------------------- @@ -190,7 +71,7 @@ # ------------------------------------------------------------- -
        [docs]class ServerSession(Session): +
        [docs]class ServerSession(_BASE_SESSION_CLASS): """ This class represents an account's session and is a template for individual protocols to communicate with Evennia. @@ -202,7 +83,10 @@ """
        [docs] def __init__(self): - """Initiate to avoid AttributeErrors down the line""" + """ + Initiate to avoid AttributeErrors down the line + + """ self.puppet = None self.account = None self.cmdset_storage_string = "" @@ -216,6 +100,10 @@ cmdset_storage = property(__cmdset_storage_get, __cmdset_storage_set) + @property + def id(self): + return self.sessid +
        [docs] def at_sync(self): """ This is called whenever a session has been resynced with the @@ -385,7 +273,7 @@ Update the protocol_flags and sync them with Portal. Keyword Args: - any: A key:value pair to set in the + protocol_flag (any): A key and value to set in the protocol_flags dictionary. Notes: @@ -417,14 +305,13 @@ the respective inputfuncs. Keyword Args: - any: Incoming data from protocol on + kwargs (any): Incoming data from protocol on the form `{"commandname": ((args), {kwargs}),...}` Notes: This method is here in order to give the user a single place to catch and possibly process all incoming data from the client. It should usually always end by sending this data off to `self.sessionhandler.call_inputfuncs(self, **kwargs)`. - """ self.sessionhandler.call_inputfuncs(self, **kwargs)
        @@ -434,7 +321,9 @@ Args: text (str): String input. - kwargs (str or tuple): Send-commands identified + + Keyword Args: + any (str or tuple): Send-commands identified by their keys. Or "options", carrying options for the protocol(s). @@ -473,7 +362,10 @@ self.sessionhandler.data_in(session or self, **kwargs)
        def __eq__(self, other): - """Handle session comparisons""" + """ + Handle session comparisons + + """ try: return self.address == other.address except AttributeError: @@ -520,6 +412,7 @@
        [docs] def at_cmdset_get(self, **kwargs): """ A dummy hook all objects with cmdsets need to have + """ pass
        @@ -530,7 +423,7 @@
        [docs] @lazy_property def nattributes(self): - return NAttributeHandler(self)
        + return AttributeHandler(self, InMemoryAttributeBackend)
        [docs] @lazy_property def attributes(self): @@ -548,7 +441,7 @@ try: return self._ndb_holder except AttributeError: - self._ndb_holder = NDbHolder(self, "nattrhandler", manager_name="nattributes") + self._ndb_holder = DbHolder(self, "nattrhandler", manager_name="nattributes") return self._ndb_holder
        # @ndb.setter @@ -566,7 +459,10 @@ # @ndb.deleter
        [docs] def ndb_del(self): - """Stop accidental deletion.""" + """ + Stop accidental deletion. + + """ raise Exception("Cannot delete the ndb object!")
        ndb = property(ndb_get, ndb_set, ndb_del) @@ -575,7 +471,10 @@ # Mock access method for the session (there is no lock info # at this stage, so we just present a uniform API)
        [docs] def access(self, *args, **kwargs): - """Dummy method to mimic the logged-in API.""" + """ + Dummy method to mimic the logged-in API. + + """ return True
        @@ -614,7 +513,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -633,6 +531,7 @@ +
        develop branch
        @@ -53,7 +54,7 @@ # ------------------------------------------------------------ -
        [docs]class Session(object): +
        [docs]class Session: """ This class represents a player's session and is a template for both portal- and server-side sessions. @@ -76,26 +77,6 @@ """ - # names of attributes that should be affected by syncing. - _attrs_to_sync = ( - "protocol_key", - "address", - "suid", - "sessid", - "uid", - "csessid", - "uname", - "logged_in", - "puid", - "conn_time", - "cmd_last", - "cmd_last_visible", - "cmd_total", - "protocol_flags", - "server_data", - "cmdset_storage_string", - ) -
        [docs] def init_session(self, protocol_key, address, sessionhandler): """ Initialize the Session. This should be called by the protocol when @@ -162,9 +143,9 @@ the keys given by self._attrs_to_sync. """ - return dict( - (key, value) for key, value in self.__dict__.items() if key in self._attrs_to_sync - )
        + return { + attr: getattr(self, attr) for attr in settings.SESSION_SYNC_ATTRS if hasattr(self, attr) + }
        [docs] def load_sync_data(self, sessdata): """ @@ -270,7 +251,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -289,6 +269,7 @@ +
        develop branch
        @@ -45,12 +46,12 @@ There are two similar but separate stores of sessions: - - ServerSessionHandler - this stores generic game sessions - for the game. These sessions has no knowledge about - how they are connected to the world. - - PortalSessionHandler - this stores sessions created by - twisted protocols. These are dumb connectors that - handle network communication but holds no game info. +- ServerSessionHandler - this stores generic game sessions + for the game. These sessions has no knowledge about + how they are connected to the world. +- PortalSessionHandler - this stores sessions created by + twisted protocols. These are dumb connectors that + handle network communication but holds no game info. """ import time @@ -59,18 +60,19 @@ from evennia.commands.cmdhandler import CMD_LOGINSTART from evennia.utils.logger import log_trace from evennia.utils.utils import ( - variable_from_module, is_iter, make_iter, delay, callables_from_module, + class_from_module, ) +from evennia.server.portal import amp from evennia.server.signals import SIGNAL_ACCOUNT_POST_LOGIN, SIGNAL_ACCOUNT_POST_LOGOUT from evennia.server.signals import SIGNAL_ACCOUNT_POST_FIRST_LOGIN, SIGNAL_ACCOUNT_POST_LAST_LOGOUT -from evennia.utils.inlinefuncs import parse_inlinefunc from codecs import decode as codecs_decode +from django.utils.translation import gettext as _ -_INLINEFUNC_ENABLED = settings.INLINEFUNC_ENABLED +_FUNCPARSER_PARSE_OUTGOING_MESSAGES_ENABLED = settings.FUNCPARSER_PARSE_OUTGOING_MESSAGES_ENABLED # delayed imports _AccountDB = None @@ -79,7 +81,7 @@ _ScriptDB = None _OOB_HANDLER = None -_ERR_BAD_UTF8 = "Your client sent an incorrect UTF-8 sequence." +_ERR_BAD_UTF8 = _("Your client sent an incorrect UTF-8 sequence.")
        [docs]class DummySession(object): @@ -88,28 +90,6 @@ DUMMYSESSION = DummySession() -# AMP signals -PCONN = chr(1) # portal session connect -PDISCONN = chr(2) # portal session disconnect -PSYNC = chr(3) # portal session sync -SLOGIN = chr(4) # server session login -SDISCONN = chr(5) # server session disconnect -SDISCONNALL = chr(6) # server session disconnect all -SSHUTD = chr(7) # server shutdown -SSYNC = chr(8) # server session sync -SCONN = chr(11) # server portal connection (for bots) -PCONNSYNC = chr(12) # portal post-syncing session -PDISCONNALL = chr(13) # portal session discnnect all -SRELOAD = chr(14) # server reloading (have portal start a new server) -SSTART = chr(15) # server start (portal must already be running anyway) -PSHUTD = chr(16) # portal (+server) shutdown -SSHUTD = chr(17) # server shutdown -PSTATUS = chr(18) # ping server or portal status -SRESET = chr(19) # server shutdown in reset mode - -# i18n -from django.utils.translation import gettext as _ - _SERVERNAME = settings.SERVERNAME _MULTISESSION_MODE = settings.MULTISESSION_MODE _IDLE_TIMEOUT = settings.IDLE_TIMEOUT @@ -117,6 +97,8 @@ _MAX_SERVER_COMMANDS_PER_SECOND = 100.0 _MAX_SESSION_COMMANDS_PER_SECOND = 5.0 _MODEL_MAP = None +_FUNCPARSER = None + # input handlers @@ -133,8 +115,7 @@ global _ServerSession, _AccountDB, _ServerConfig, _ScriptDB if not _ServerSession: # we allow optional arbitrary serversession class for overloading - modulename, classname = settings.SERVER_SESSION_CLASS.rsplit(".", 1) - _ServerSession = variable_from_module(modulename, classname) + _ServerSession = class_from_module(settings.SERVER_SESSION_CLASS) if not _AccountDB: from evennia.accounts.models import AccountDB as _AccountDB if not _ServerConfig: @@ -142,10 +123,10 @@ if not _ScriptDB: from evennia.scripts.models import ScriptDB as _ScriptDB # including once to avoid warnings in Python syntax checkers - assert _ServerSession - assert _AccountDB - assert _ServerConfig - assert _ScriptDB
        + assert _ServerSession, "ServerSession class could not load" + assert _AccountDB, "AccountDB class could not load" + assert _ServerConfig, "ServerConfig class could not load" + assert _ScriptDB, "ScriptDB class c ould not load"
        # ----------------------------------------------------------- @@ -160,24 +141,36 @@ """ def __getitem__(self, key): - "Clean out None-sessions automatically." + """ + Clean out None-sessions automatically. + + """ if None in self: del self[None] return super().__getitem__(key)
        [docs] def get(self, key, default=None): - "Clean out None-sessions automatically." + """ + Clean out None-sessions automatically. + + """ if None in self: del self[None] return super().get(key, default)
        def __setitem__(self, key, value): - "Don't assign None sessions" + """ + Don't assign None sessions" + + """ if key is not None: super().__setitem__(key, value) def __contains__(self, key): - "None-keys are not accepted." + """ + None-keys are not accepted. + + """ return False if key is None else super().__contains__(key)
        [docs] def get_sessions(self, include_unloggedin=False): @@ -210,29 +203,32 @@
        [docs] def clean_senddata(self, session, kwargs): """ - Clean up data for sending across the AMP wire. Also apply INLINEFUNCS. + Clean up data for sending across the AMP wire. Also apply the + FuncParser using callables from `settings.FUNCPARSER_OUTGOING_MESSAGES_MODULES`. Args: session (Session): The relevant session instance. - kwargs (dict) Each keyword represents a - send-instruction, with the keyword itself being the name - of the instruction (like "text"). Suitable values for each - keyword are: - :: - - arg -> [[arg], {}] - [args] -> [[args], {}] - {kwargs} -> [[], {kwargs}] - [args, {kwargs}] -> [[arg], {kwargs}] - [[args], {kwargs}] -> [[args], {kwargs}] + kwargs (dict) Each keyword represents a send-instruction, with the keyword itself being + the name of the instruction (like "text"). Suitable values for each keyword are: + - arg -> [[arg], {}] + - [args] -> [[args], {}] + - {kwargs} -> [[], {kwargs}] + - [args, {kwargs}] -> [[arg], {kwargs}] + - [[args], {kwargs}] -> [[args], {kwargs}] Returns: kwargs (dict): A cleaned dictionary of cmdname:[[args],{kwargs}] pairs, - where the keys, args and kwargs have all been converted to - send-safe entities (strings or numbers), and inlinefuncs have been - applied. + where the keys, args and kwargs have all been converted to + send-safe entities (strings or numbers), and funcparser parsing has been + applied. """ + global _FUNCPARSER + if not _FUNCPARSER: + from evennia.utils.funcparser import FuncParser + _FUNCPARSER = FuncParser(settings.FUNCPARSER_OUTGOING_MESSAGES_MODULES, + raise_errors=True) + options = kwargs.pop("options", None) or {} raw = options.get("raw", False) strip_inlinefunc = options.get("strip_inlinefunc", False) @@ -253,7 +249,10 @@ return data def _validate(data): - "Helper function to convert data to AMP-safe (picketable) values" + """ + Helper function to convert data to AMP-safe (picketable) values" + + """ if isinstance(data, dict): newdict = {} for key, part in data.items(): @@ -264,9 +263,11 @@ elif isinstance(data, (str, bytes)): data = _utf8(data) - if _INLINEFUNC_ENABLED and not raw and isinstance(self, ServerSessionHandler): - # only parse inlinefuncs on the outgoing path (sessionhandler->) - data = parse_inlinefunc(data, strip=strip_inlinefunc, session=session) + if (_FUNCPARSER_PARSE_OUTGOING_MESSAGES_ENABLED + and not raw and isinstance(self, ServerSessionHandler)): + # only apply funcparser on the outgoing path (sessionhandler->) + # data = parse_inlinefunc(data, strip=strip_inlinefunc, session=session) + data = _FUNCPARSER.parse(data, strip=strip_inlinefunc, session=session) return str(data) elif ( @@ -314,14 +315,11 @@
        [docs]class ServerSessionHandler(SessionHandler): """ - This object holds the stack of sessions active in the game at - any time. + This object holds the stack of sessions active in the game at any time. - A session register with the handler in two steps, first by - registering itself with the connect() method. This indicates an - non-authenticated session. Whenever the session is authenticated - the session together with the related account is sent to the login() - method. + A session register with the handler in two steps, first by registering itself with the connect() + method. This indicates an non-authenticated session. Whenever the session is authenticated the + session together with the related account is sent to the login() method. """ @@ -366,7 +364,7 @@ sess.load_sync_data(portalsessiondata) sess.at_sync() # validate all scripts - _ScriptDB.objects.validate() + # _ScriptDB.objects.validate() self[sess.sessid] = sess if sess.logged_in and sess.uid: @@ -494,7 +492,7 @@ """ self.server.amp_protocol.send_AdminServer2Portal( - DUMMYSESSION, operation=SCONN, protocol_path=protocol_path, config=configdict + DUMMYSESSION, operation=amp.SCONN, protocol_path=protocol_path, config=configdict )
        [docs] def portal_restart_server(self): @@ -502,14 +500,14 @@ Called by server when reloading. We tell the portal to start a new server instance. """ - self.server.amp_protocol.send_AdminServer2Portal(DUMMYSESSION, operation=SRELOAD)
        + self.server.amp_protocol.send_AdminServer2Portal(DUMMYSESSION, operation=amp.SRELOAD)
        [docs] def portal_reset_server(self): """ Called by server when reloading. We tell the portal to start a new server instance. """ - self.server.amp_protocol.send_AdminServer2Portal(DUMMYSESSION, operation=SRESET)
        + self.server.amp_protocol.send_AdminServer2Portal(DUMMYSESSION, operation=amp.SRESET)
        [docs] def portal_shutdown(self): """ @@ -517,13 +515,12 @@ itself down) """ - self.server.amp_protocol.send_AdminServer2Portal(DUMMYSESSION, operation=PSHUTD)
        + self.server.amp_protocol.send_AdminServer2Portal(DUMMYSESSION, operation=amp.PSHUTD)
        [docs] def login(self, session, account, force=False, testmode=False): """ - Log in the previously unloggedin session and the account we by - now should know is connected to it. After this point we assume - the session to be logged in one way or another. + Log in the previously unloggedin session and the account we by now should know is connected + to it. After this point we assume the session to be logged in one way or another. Args: session (Session): The Session to authenticate. @@ -565,7 +562,7 @@ # sync the portal to the session if not testmode: self.server.amp_protocol.send_AdminServer2Portal( - session, operation=SLOGIN, sessiondata={"logged_in": True, "uid": session.uid} + session, operation=amp.SLOGIN, sessiondata={"logged_in": True, "uid": session.uid} ) account.at_post_login(session=session) if nsess < 2: @@ -610,7 +607,7 @@ if sync_portal: # inform portal that session should be closed. self.server.amp_protocol.send_AdminServer2Portal( - session, operation=SDISCONN, reason=reason + session, operation=amp.SDISCONN, reason=reason )
        [docs] def all_sessions_portal_sync(self): @@ -621,7 +618,7 @@ """ sessdata = self.get_all_sync_data() return self.server.amp_protocol.send_AdminServer2Portal( - DUMMYSESSION, operation=SSYNC, sessiondata=sessdata + DUMMYSESSION, operation=amp.SSYNC, sessiondata=sessdata )
        [docs] def session_portal_sync(self, session): @@ -632,7 +629,7 @@ """ sessdata = {session.sessid: session.get_sync_data()} return self.server.amp_protocol.send_AdminServer2Portal( - DUMMYSESSION, operation=SSYNC, sessiondata=sessdata, clean=False + DUMMYSESSION, operation=amp.SSYNC, sessiondata=sessdata, clean=False )
        [docs] def session_portal_partial_sync(self, session_data): @@ -645,7 +642,7 @@ """ return self.server.amp_protocol.send_AdminServer2Portal( - DUMMYSESSION, operation=SSYNC, sessiondata=session_data, clean=False + DUMMYSESSION, operation=amp.SSYNC, sessiondata=session_data, clean=False )
        [docs] def disconnect_all_sessions(self, reason="You have been disconnected."): @@ -661,7 +658,7 @@ del session # tell portal to disconnect all sessions self.server.amp_protocol.send_AdminServer2Portal( - DUMMYSESSION, operation=SDISCONNALL, reason=reason + DUMMYSESSION, operation=amp.SDISCONNALL, reason=reason )
        [docs] def disconnect_duplicate_sessions( @@ -680,7 +677,8 @@ # mean connecting from the same host would not catch duplicates sid = id(curr_session) doublet_sessions = [ - sess for sess in self.values() if sess.logged_in and sess.uid == uid and id(sess) != sid + sess for sess in self.values() + if sess.logged_in and sess.uid == uid and id(sess) != sid ] for session in doublet_sessions: @@ -790,8 +788,8 @@ puppet (Object): Object puppeted Returns. - sessions (Session or list): Can be more than one of Object is controlled by - more than one Session (MULTISESSION_MODE > 1). + sessions (Session or list): Can be more than one of Object is controlled by more than + one Session (MULTISESSION_MODE > 1). """ sessions = puppet.sessid.get() @@ -804,8 +802,9 @@ Given a client identification hash (for session types that offer them) return all sessions with a matching hash. - Args: + Args csessid (str): The session hash. + Returns: sessions (list): The sessions with matching .csessid, if any. @@ -868,9 +867,9 @@
        [docs] def call_inputfuncs(self, session, **kwargs): """ - Split incoming data into its inputfunc counterparts. - This should be called by the serversession.data_in - as `sessionhandler.call_inputfunc(self, **kwargs)`. + Split incoming data into its inputfunc counterparts. This should be + called by the `serversession.data_in` as + `sessionhandler.call_inputfunc(self, **kwargs)`. We also intercept OOB communication here. @@ -878,8 +877,8 @@ sessions (Session): Session. Keyword Args: - kwargs (any): Incoming data from protocol on - the form `{"commandname": ((args), {kwargs}),...}` + any (tuple): Incoming data from protocol, each + on the form `commandname=((args), {kwargs})`. """ @@ -900,7 +899,11 @@ log_trace()
        -SESSION_HANDLER = ServerSessionHandler() +# import class from settings +_SESSION_HANDLER_CLASS = class_from_module(settings.SERVER_SESSION_HANDLER_CLASS) + +# Instantiate class. These globals are used to provide singleton-like behavior. +SESSION_HANDLER = _SESSION_HANDLER_CLASS() SESSIONS = SESSION_HANDLER # legacy @@ -939,7 +942,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -958,6 +960,7 @@ +
        develop branch
        @@ -39,12 +40,14 @@

        Source code for evennia.server.throttle

        -from collections import defaultdict, deque
        +from django.core.cache import caches
        +from collections import deque
         from evennia.utils import logger
         import time
        +from django.utils.translation import gettext as _
         
         
        -
        [docs]class Throttle(object): +
        [docs]class Throttle: """ Keeps a running count of failed actions per IP address. @@ -53,28 +56,58 @@ This version of the throttle is usable by both the terminal server as well as the web server, imposes limits on memory consumption by using deques - with length limits instead of open-ended lists, and removes sparse keys when - no recent failures have been recorded. + with length limits instead of open-ended lists, and uses native Django + caches for automatic key eviction and persistence configurability. """ - error_msg = "Too many failed attempts; you must wait a few minutes before trying again." + error_msg = _("Too many failed attempts; you must wait a few minutes before trying again.")
        [docs] def __init__(self, **kwargs): """ Allows setting of throttle parameters. Keyword Args: - limit (int): Max number of failures before imposing limiter + name (str): Name of this throttle. + limit (int): Max number of failures before imposing limiter. If `None`, + the throttle is disabled. timeout (int): number of timeout seconds after max number of tries has been reached. cache_size (int): Max number of attempts to record per IP within a rolling window; this is NOT the same as the limit after which the throttle is imposed! """ - self.storage = defaultdict(deque) - self.cache_size = self.limit = kwargs.get("limit", 5) + try: + self.storage = caches['throttle'] + except Exception: + logger.log_trace("Throttle: Errors encountered; using default cache.") + self.storage = caches['default'] + + self.name = kwargs.get('name', 'undefined-throttle') + self.limit = kwargs.get("limit", 5) + self.cache_size = kwargs.get('cache_size', self.limit) self.timeout = kwargs.get("timeout", 5 * 60)
        +
        [docs] def get_cache_key(self, *args, **kwargs): + """ + Creates a 'prefixed' key containing arbitrary terms to prevent key + collisions in the same namespace. + + """ + return '-'.join((self.name, *args))
        + +
        [docs] def touch(self, key, *args, **kwargs): + """ + Refreshes the timeout on a given key and ensures it is recorded in the + key register. + + Args: + key(str): Key of entry to renew. + + """ + cache_key = self.get_cache_key(key) + if self.storage.touch(cache_key, self.timeout): + self.record_key(key)
        +
        [docs] def get(self, ip=None): """ Convenience function that returns the storage table, or part of. @@ -91,9 +124,18 @@ """ if ip: - return self.storage.get(ip, deque(maxlen=self.cache_size)) + cache_key = self.get_cache_key(str(ip)) + return self.storage.get(cache_key, deque(maxlen=self.cache_size)) else: - return self.storage
        + keys_key = self.get_cache_key('keys') + keys = self.storage.get_or_set(keys_key, set(), self.timeout) + data = self.storage.get_many((self.get_cache_key(x) for x in keys)) + + found_keys = set(data.keys()) + if len(keys) != len(found_keys): + self.storage.set(keys_key, found_keys, self.timeout) + + return data
        [docs] def update(self, ip, failmsg="Exceeded threshold."): """ @@ -108,14 +150,17 @@ None """ + cache_key = self.get_cache_key(ip) + # Get current status previously_throttled = self.check(ip) - # Enforce length limits - if not self.storage[ip].maxlen: - self.storage[ip] = deque(maxlen=self.cache_size) + # Get previous failures, if any + entries = self.storage.get(cache_key, []) + entries.append(time.time()) - self.storage[ip].append(time.time()) + # Store updated record + self.storage.set(cache_key, deque(entries, maxlen=self.cache_size), self.timeout) # See if this update caused a change in status currently_throttled = self.check(ip) @@ -123,9 +168,63 @@ # If this makes it engage, log a single activation event if not previously_throttled and currently_throttled: logger.log_sec( - "Throttle Activated: %s (IP: %s, %i hits in %i seconds.)" - % (failmsg, ip, self.limit, self.timeout) - )
        + f"Throttle Activated: {failmsg} (IP: {ip}, " + f"{self.limit} hits in {self.timeout} seconds.)" + ) + + self.record_ip(ip)
        + +
        [docs] def remove(self, ip, *args, **kwargs): + """ + Clears data stored for an IP from the throttle. + + Args: + ip(str): IP to clear. + + """ + exists = self.get(ip) + if not exists: + return False + + cache_key = self.get_cache_key(ip) + self.storage.delete(cache_key) + self.unrecord_ip(ip) + + # Return True if NOT exists + return not bool(self.get(ip))
        + +
        [docs] def record_ip(self, ip, *args, **kwargs): + """ + Tracks keys as they are added to the cache (since there is no way to + get a list of keys after-the-fact). + + Args: + ip(str): IP being added to cache. This should be the original + IP, not the cache-prefixed key. + + """ + keys_key = self.get_cache_key('keys') + keys = self.storage.get(keys_key, set()) + keys.add(ip) + self.storage.set(keys_key, keys, self.timeout) + return True
        + +
        [docs] def unrecord_ip(self, ip, *args, **kwargs): + """ + Forces removal of a key from the key registry. + + Args: + ip(str): IP to remove from list of keys. + + """ + keys_key = self.get_cache_key('keys') + keys = self.storage.get(keys_key, set()) + try: + keys.remove(ip) + self.storage.set(keys_key, keys, self.timeout) + return True + except KeyError: + return False
        [docs] def check(self, ip): """ @@ -141,19 +240,26 @@ False otherwise. """ + if self.limit is None: + # throttle is disabled + return False + now = time.time() ip = str(ip) + cache_key = self.get_cache_key(ip) + # checking mode - latest_fails = self.storage[ip] + latest_fails = self.storage.get(cache_key) if latest_fails and len(latest_fails) >= self.limit: # too many fails recently if now - latest_fails[-1] < self.timeout: # too soon - timeout in play + self.touch(cache_key) return True else: # timeout has passed. clear faillist - del self.storage[ip] + self.remove(ip) return False else: return False
        @@ -194,7 +300,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -213,6 +318,7 @@ +
        develop branch
        @@ -126,8 +127,8 @@ """ return _( - "%s From a terminal client, you can also use a phrase of multiple words if " - "you enclose the password in double quotes." % self.policy + "{policy} From a terminal client, you can also use a phrase of multiple words if " + "you enclose the password in double quotes.".format(policy=self.policy) )
        @@ -166,7 +167,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -185,6 +185,7 @@ +
        develop branch
        @@ -376,7 +377,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -395,6 +395,7 @@ +
        develop branch
        @@ -51,7 +52,8 @@ """ import re import fnmatch -import weakref + +from collections import defaultdict from django.db import models from django.conf import settings @@ -72,7 +74,7 @@ # ------------------------------------------------------------- -
        [docs]class Attribute(SharedMemoryModel): +
        [docs]class IAttribute: """ Attributes are things that are specific to different types of objects. For example, a drink container needs to store its fill level, whereas an exit @@ -94,6 +96,115 @@ - category (str): Optional character string for grouping the Attribute. + This class is an API/Interface/Abstract base class; do not instantiate it directly. + """ + +
        [docs] @lazy_property + def locks(self): + return LockHandler(self)
        + + key = property(lambda self: self.db_key) + strvalue = property(lambda self: self.db_strvalue) + category = property(lambda self: self.db_category) + model = property(lambda self: self.db_model) + attrtype = property(lambda self: self.db_attrtype) + date_created = property(lambda self: self.db_date_created) + + def __lock_storage_get(self): + return self.db_lock_storage + + def __lock_storage_set(self, value): + self.db_lock_storage = value + + def __lock_storage_del(self): + self.db_lock_storage = "" + + lock_storage = property(__lock_storage_get, __lock_storage_set, __lock_storage_del) + +
        [docs] def access(self, accessing_obj, access_type="read", default=False, **kwargs): + """ + Determines if another object has permission to access. + + Args: + accessing_obj (object): Entity trying to access this one. + access_type (str, optional): Type of access sought, see + the lock documentation. + default (bool, optional): What result to return if no lock + of access_type was found. The default, `False`, means a lockdown + policy, only allowing explicit access. + kwargs (any, optional): Not used; here to make the API consistent with + other access calls. + + Returns: + result (bool): If the lock was passed or not. + + """ + result = self.locks.check(accessing_obj, access_type=access_type, default=default) + return result
        + + # + # + # Attribute methods + # + # + + def __str__(self): + return smart_str("%s(%s)" % (self.db_key, self.id)) + + def __repr__(self): + return "%s(%s)" % (self.db_key, self.id)
        + + +
        [docs]class InMemoryAttribute(IAttribute): + """ + This Attribute is used purely for NAttributes/NAttributeHandler. It has no database backend. + + """ + + # Primary Key has no meaning for an InMemoryAttribute. This merely serves to satisfy other code. + +
        [docs] def __init__(self, pk, **kwargs): + """ + Create an Attribute that exists only in Memory. + + Args: + pk (int): This is a fake 'primary key' / id-field. It doesn't actually have to be + unique, but is fed an incrementing number from the InMemoryBackend by default. This + is needed only so Attributes can be sorted. Some parts of the API also see the lack + of a .pk field as a sign that the Attribute was deleted. + **kwargs: Other keyword arguments are used to construct the actual Attribute. + + """ + self.id = pk + self.pk = pk + + # Copy all kwargs to local properties. We use db_ for compatability here. + for key, value in kwargs.items(): + # Value and locks are special. We must call the wrappers. + if key == "value": + self.value = value + elif key == "lock_storage": + self.lock_storage = value + else: + setattr(self, f"db_{key}", value)
        + + # value property (wraps db_value) + def __value_get(self): + return self.db_value + + def __value_set(self, new_value): + self.db_value = new_value + + def __value_del(self): + pass + + value = property(__value_get, __value_set, __value_del)
        + + +
        [docs]class Attribute(IAttribute, SharedMemoryModel): + """ + This attribute is stored via Django. Most Attributes will be using this class. + """ # @@ -150,34 +261,9 @@ # Database manager # objects = managers.AttributeManager() -
        [docs] @lazy_property - def locks(self): - return LockHandler(self)
        - class Meta(object): "Define Django meta options" - verbose_name = "Evennia Attribute" - - # read-only wrappers - key = property(lambda self: self.db_key) - strvalue = property(lambda self: self.db_strvalue) - category = property(lambda self: self.db_category) - model = property(lambda self: self.db_model) - attrtype = property(lambda self: self.db_attrtype) - date_created = property(lambda self: self.db_date_created) - - def __lock_storage_get(self): - return self.db_lock_storage - - def __lock_storage_set(self, value): - self.db_lock_storage = value - self.save(update_fields=["db_lock_storage"]) - - def __lock_storage_del(self): - self.db_lock_storage = "" - self.save(update_fields=["db_lock_storage"]) - - lock_storage = property(__lock_storage_get, __lock_storage_set, __lock_storage_del) + verbose_name = "Attribute" # Wrapper properties to easily set database fields. These are # @property decorators that allows to access these fields using @@ -187,9 +273,23 @@ # value = self.attr and del self.attr respectively (where self # is the object in question). + # lock_storage wrapper. Overloaded for saving to database. + def __lock_storage_get(self): + return self.db_lock_storage + + def __lock_storage_set(self, value): + super().__lock_storage_set(value) + self.save(update_fields=["db_lock_storage"]) + + def __lock_storage_del(self): + super().__lock_storage_del() + self.save(update_fields=["db_lock_storage"]) + + lock_storage = property(__lock_storage_get, __lock_storage_set, __lock_storage_del) + # value property (wraps db_value) - # @property - def __value_get(self): + @property + def value(self): """ Getter. Allows for `value = self.value`. We cannot cache here since it makes certain cases (such @@ -198,115 +298,164 @@ """ return from_pickle(self.db_value, db_obj=self) - # @value.setter - def __value_set(self, new_value): + @value.setter + def value(self, new_value): """ Setter. Allows for self.value = value. We cannot cache here, see self.__value_get. """ self.db_value = to_pickle(new_value) - # print("value_set, self.db_value:", repr(self.db_value)) # DEBUG self.save(update_fields=["db_value"]) - # @value.deleter - def __value_del(self): + @value.deleter + def value(self): """Deleter. Allows for del attr.value. This removes the entire attribute.""" - self.delete() - - value = property(__value_get, __value_set, __value_del) - - # - # - # Attribute methods - # - # - - def __str__(self): - return smart_str("%s[category=%s](#%s)" % (self.db_key, self.db_category, self.id)) - - def __repr__(self): - return "%s[category=%s](#%s)" % (self.db_key, self.db_category, self.id) - -
        [docs] def access(self, accessing_obj, access_type="attrread", default=False, **kwargs): - """ - Determines if another object has permission to access. - - Args: - accessing_obj (object): Entity trying to access this one. - access_type (str, optional): Type of access sought, see - the lock documentation. - default (bool, optional): What result to return if no lock - of access_type was found. The default, `False`, means a lockdown - policy, only allowing explicit access. - kwargs (any, optional): Not used; here to make the API consistent with - other access calls. - - Returns: - result (bool): If the lock was passed or not. - - """ - result = self.locks.check(accessing_obj, access_type=access_type, default=default) - return result
        - + self.delete()
        # # Handlers making use of the Attribute model # -
        [docs]class AttributeHandler(object): +
        [docs]class IAttributeBackend: """ - Handler for adding Attributes to the object. + Abstract interface for the backends used by the Attribute Handler. + + All Backends must implement this base class. """ - _m2m_fieldname = "db_attributes" _attrcreate = "attrcreate" _attredit = "attredit" _attrread = "attrread" - _attrtype = None + _attrclass = None -
        [docs] def __init__(self, obj): - """Initialize handler.""" - self.obj = obj - self._objid = obj.id - self._model = to_str(obj.__dbclass__.__name__.lower()) +
        [docs] def __init__(self, handler, attrtype): + self.handler = handler + self.obj = handler.obj + self._attrtype = attrtype + self._objid = handler.obj.id self._cache = {} # store category names fully cached self._catcache = {} # full cache was run on all attributes self._cache_complete = False
        - def _query_all(self): - "Fetch all Attributes on this object" - query = { - "%s__id" % self._model: self._objid, - "attribute__db_model__iexact": self._model, - "attribute__db_attrtype": self._attrtype, - } - return [ - conn.attribute - for conn in getattr(self.obj, self._m2m_fieldname).through.objects.filter(**query) - ] +
        [docs] def query_all(self): + """ + Fetch all Attributes from this object. - def _fullcache(self): + Returns: + attrlist (list): A list of Attribute objects. + """ + raise NotImplementedError()
        + +
        [docs] def query_key(self, key, category): + """ + + Args: + key (str): The key of the Attribute being searched for. + category (str or None): The category of the desired Attribute. + + Returns: + attribute (IAttribute): A single Attribute. + """ + raise NotImplementedError()
        + +
        [docs] def query_category(self, category): + """ + Returns every matching Attribute as a list, given a category. + + This method calls up whatever storage the backend uses. + + Args: + category (str or None): The category to query. + + Returns: + attrs (list): The discovered Attributes. + """ + raise NotImplementedError()
        + + def _full_cache(self): """Cache all attributes of this object""" if not _TYPECLASS_AGGRESSIVE_CACHE: return - attrs = self._query_all() - self._cache = dict( - ( - "%s-%s" - % ( - to_str(attr.db_key).lower(), - attr.db_category.lower() if attr.db_category is not None else None, - ), - attr, - ) + attrs = self.query_all() + self._cache = { + f"{to_str(attr.key).lower()}-{attr.category.lower() if attr.category else None}": attr for attr in attrs - ) + } self._cache_complete = True - def _getcache(self, key=None, category=None): + def _get_cache_key(self, key, category): + """ + Fetch cache key. + + Args: + key (str): The key of the Attribute being searched for. + category (str or None): The category of the desired Attribute. + + Returns: + attribute (IAttribute): A single Attribute. + """ + cachekey = "%s-%s" % (key, category) + cachefound = False + try: + attr = _TYPECLASS_AGGRESSIVE_CACHE and self._cache[cachekey] + cachefound = True + except KeyError: + attr = None + + if attr and (not hasattr(attr, "pk") and attr.pk is None): + # clear out Attributes deleted from elsewhere. We must search this anew. + attr = None + cachefound = False + del self._cache[cachekey] + if cachefound and _TYPECLASS_AGGRESSIVE_CACHE: + if attr: + return [attr] # return cached entity + else: + return [] # no such attribute: return an empty list + else: + conn = self.query_key(key, category) + if conn: + attr = conn[0].attribute + if _TYPECLASS_AGGRESSIVE_CACHE: + self._cache[cachekey] = attr + return [attr] if attr.pk else [] + else: + # There is no such attribute. We will explicitly save that + # in our cache to avoid firing another query if we try to + # retrieve that (non-existent) attribute again. + if _TYPECLASS_AGGRESSIVE_CACHE: + self._cache[cachekey] = None + return [] + + def _get_cache_category(self, category): + """ + Retrieves Attribute list (by category) from cache. + + Args: + category (str or None): The category to query. + + Returns: + attrs (list): The discovered Attributes. + """ + catkey = "-%s" % category + if _TYPECLASS_AGGRESSIVE_CACHE and catkey in self._catcache: + return [attr for key, attr in self._cache.items() if key.endswith(catkey) and attr] + else: + # we have to query to make this category up-date in the cache + attrs = self.query_category(category) + if _TYPECLASS_AGGRESSIVE_CACHE: + for attr in attrs: + if attr.pk: + cachekey = "%s-%s" % (attr.key, category) + self._cache[cachekey] = attr + # mark category cache as up-to-date + self._catcache[catkey] = True + return attrs + + def _get_cache(self, key=None, category=None): """ Retrieve from cache or database (always caches) @@ -332,85 +481,31 @@ key = key.strip().lower() if key else None category = category.strip().lower() if category is not None else None if key: - cachekey = "%s-%s" % (key, category) - cachefound = False - try: - attr = _TYPECLASS_AGGRESSIVE_CACHE and self._cache[cachekey] - cachefound = True - except KeyError: - attr = None + return self._get_cache_key(key, category) + return self._get_cache_category(category) - if attr and (not hasattr(attr, "pk") and attr.pk is None): - # clear out Attributes deleted from elsewhere. We must search this anew. - attr = None - cachefound = False - del self._cache[cachekey] - if cachefound and _TYPECLASS_AGGRESSIVE_CACHE: - if attr: - return [attr] # return cached entity - else: - return [] # no such attribute: return an empty list - else: - query = { - "%s__id" % self._model: self._objid, - "attribute__db_model__iexact": self._model, - "attribute__db_attrtype": self._attrtype, - "attribute__db_key__iexact": key.lower(), - "attribute__db_category__iexact": category.lower() if category else None, - } - if not self.obj.pk: - return [] - conn = getattr(self.obj, self._m2m_fieldname).through.objects.filter(**query) - if conn: - attr = conn[0].attribute - if _TYPECLASS_AGGRESSIVE_CACHE: - self._cache[cachekey] = attr - return [attr] if attr.pk else [] - else: - # There is no such attribute. We will explicitly save that - # in our cache to avoid firing another query if we try to - # retrieve that (non-existent) attribute again. - if _TYPECLASS_AGGRESSIVE_CACHE: - self._cache[cachekey] = None - return [] - else: - # only category given (even if it's None) - we can't - # assume the cache to be complete unless we have queried - # for this category before - catkey = "-%s" % category - if _TYPECLASS_AGGRESSIVE_CACHE and catkey in self._catcache: - return [attr for key, attr in self._cache.items() if key.endswith(catkey) and attr] - else: - # we have to query to make this category up-date in the cache - query = { - "%s__id" % self._model: self._objid, - "attribute__db_model__iexact": self._model, - "attribute__db_attrtype": self._attrtype, - "attribute__db_category__iexact": category.lower() if category else None, - } - attrs = [ - conn.attribute - for conn in getattr(self.obj, self._m2m_fieldname).through.objects.filter( - **query - ) - ] - if _TYPECLASS_AGGRESSIVE_CACHE: - for attr in attrs: - if attr.pk: - cachekey = "%s-%s" % (attr.db_key, category) - self._cache[cachekey] = attr - # mark category cache as up-to-date - self._catcache[catkey] = True - return attrs +
        [docs] def get(self, key=None, category=None): + """ + Frontend for .get_cache. Retrieves Attribute(s). - def _setcache(self, key, category, attr_obj): + Args: + key (str, optional): Attribute key to query for + category (str, optional): Attribiute category + + Returns: + args (list): Returns a list of zero or more matches + found from cache or database. + """ + return self._get_cache(key, category)
        + + def _set_cache(self, key, category, attr_obj): """ Update cache. Args: key (str): A cleaned key string category (str or None): A cleaned category name - attr_obj (Attribute): The newly saved attribute + attr_obj (IAttribute): The newly saved attribute """ if not _TYPECLASS_AGGRESSIVE_CACHE: @@ -424,7 +519,7 @@ self._catcache.pop(catkey, None) self._cache_complete = False - def _delcache(self, key, category): + def _delete_cache(self, key, category): """ Remove attribute from cache @@ -447,7 +542,7 @@ self._catcache.pop(catkey, None) self._cache_complete = False -
        [docs] def reset_cache(self): +
        [docs] def reset_cache(self): """ Reset cache from the outside. """ @@ -455,6 +550,435 @@ self._cache = {} self._catcache = {}
        +
        [docs] def do_create_attribute(self, key, category, lockstring, value, strvalue): + """ + Does the hard work of actually creating Attributes, whatever is needed. + + Args: + key (str): The Attribute's key. + category (str or None): The Attribute's category, or None + lockstring (str): Any locks for the Attribute. + value (obj): The Value of the Attribute. + strvalue (bool): Signifies if this is a strvalue Attribute. Value MUST be a string or + this will lead to Trouble. Ignored for InMemory attributes. + + Returns: + attr (IAttribute): The new Attribute. + """ + raise NotImplementedError()
        + +
        [docs] def create_attribute(self, key, category, lockstring, value, strvalue=False, cache=True): + """ + Creates Attribute (using the class specified for the backend), (optionally) caches it, and + returns it. + + This MUST actively save the Attribute to whatever database backend is used, AND + call self.set_cache(key, category, new_attrobj) + + Args: + key (str): The Attribute's key. + category (str or None): The Attribute's category, or None + lockstring (str): Any locks for the Attribute. + value (obj): The Value of the Attribute. + strvalue (bool): Signifies if this is a strvalue Attribute. Value MUST be a string or + this will lead to Trouble. Ignored for InMemory attributes. + cache (bool): Whether to cache the new Attribute + + Returns: + attr (IAttribute): The new Attribute. + """ + attr = self.do_create_attribute(key, category, lockstring, value, strvalue) + if cache: + self._set_cache(key, category, attr) + return attr
        + +
        [docs] def do_update_attribute(self, attr, value): + """ + Simply sets a new Value to an Attribute. + + Args: + attr (IAttribute): The Attribute being changed. + value (obj): The Value for the Attribute. + + """ + raise NotImplementedError()
        + +
        [docs] def do_batch_update_attribute(self, attr_obj, category, lock_storage, new_value, strvalue): + """ + Called opnly by batch add. For the database backend, this is a method + of updating that can alter category and lock-storage. + + Args: + attr_obj (IAttribute): The Attribute being altered. + category (str or None): The attribute's (new) category. + lock_storage (str): The attribute's new locks. + new_value (obj): The Attribute's new value. + strvalue (bool): Signifies if this is a strvalue Attribute. Value MUST be a string or + this will lead to Trouble. Ignored for InMemory attributes. + """ + raise NotImplementedError()
        + +
        [docs] def do_batch_finish(self, attr_objs): + """ + Called after batch_add completed. Used for handling database operations + and/or caching complications. + + Args: + attr_objs (list of IAttribute): The Attributes created/updated thus far. + + """ + raise NotImplementedError()
        + +
        [docs] def batch_add(self, *args, **kwargs): + """ + Batch-version of `.add()`. This is more efficient than repeat-calling + `.add` when having many Attributes to add. + + Args: + *args (tuple): Tuples of varying length representing the + Attribute to add to this object. Supported tuples are + + - (key, value) + - (key, value, category) + - (key, value, category, lockstring) + - (key, value, category, lockstring, default_access) + + Raises: + RuntimeError: If trying to pass a non-iterable as argument. + + Notes: + The indata tuple order matters, so if you want a lockstring but no + category, set the category to `None`. This method does not have the + ability to check editing permissions and is mainly used internally. + It does not use the normal `self.add` but applies the Attributes + directly to the database. + + """ + new_attrobjs = [] + strattr = kwargs.get("strattr", False) + for tup in args: + if not is_iter(tup) or len(tup) < 2: + raise RuntimeError("batch_add requires iterables as arguments (got %r)." % tup) + ntup = len(tup) + keystr = str(tup[0]).strip().lower() + new_value = tup[1] + category = str(tup[2]).strip().lower() if ntup > 2 and tup[2] is not None else None + lockstring = tup[3] if ntup > 3 else "" + + attr_objs = self._get_cache(keystr, category) + + if attr_objs: + attr_obj = attr_objs[0] + # update an existing attribute object + self.do_batch_update_attribute(attr_obj, category, lockstring, new_value, strattr) + else: + new_attr = self.do_create_attribute( + keystr, category, lockstring, new_value, strvalue=strattr + ) + new_attrobjs.append(new_attr) + if new_attrobjs: + self.do_batch_finish(new_attrobjs)
        + +
        [docs] def do_delete_attribute(self, attr): + """ + Does the hard work of actually deleting things. + + Args: + attr (IAttribute): The attribute to delete. + """ + raise NotImplementedError()
        + +
        [docs] def delete_attribute(self, attr): + """ + Given an Attribute, deletes it. Also remove it from cache. + + Args: + attr (IAttribute): The attribute to delete. + """ + if not attr: + return + self._delete_cache(attr.key, attr.category) + self.do_delete_attribute(attr)
        + +
        [docs] def update_attribute(self, attr, value): + """ + Simply updates an Attribute. + + Args: + attr (IAttribute): The attribute to delete. + value (obj): The new value. + """ + self.do_update_attribute(attr, value)
        + +
        [docs] def do_batch_delete(self, attribute_list): + """ + Given a list of attributes, deletes them all. + The default implementation is fine, but this is overridable since some databases may allow + for a better method. + + Args: + attribute_list (list of IAttribute): + """ + for attribute in attribute_list: + self.delete_attribute(attribute)
        + +
        [docs] def clear_attributes(self, category, accessing_obj, default_access): + """ + Remove all Attributes on this object. + + Args: + category (str, optional): If given, clear only Attributes + of this category. + accessing_obj (object, optional): If given, check the + `attredit` lock on each Attribute before continuing. + default_access (bool, optional): Use this permission as + fallback if `access_obj` is given but there is no lock of + type `attredit` on the Attribute in question. + + """ + category = category.strip().lower() if category is not None else None + + if not self._cache_complete: + self._full_cache() + + if category is not None: + attrs = [attr for attr in self._cache.values() if attr.category == category] + else: + attrs = self._cache.values() + + if accessing_obj: + self.do_batch_delete( + [ + attr + for attr in attrs + if attr.access(accessing_obj, self._attredit, default=default_access) + ] + ) + else: + # have to cast the results to a list or we'll get a RuntimeError for removing from the + # dict we're iterating + self.do_batch_delete(list(attrs)) + self.reset_cache()
        + +
        [docs] def get_all_attributes(self): + """ + Simply returns all Attributes of this object, sorted by their IDs. + + Returns: + attributes (list of IAttribute) + """ + if _TYPECLASS_AGGRESSIVE_CACHE: + if not self._cache_complete: + self._full_cache() + return sorted([attr for attr in self._cache.values() if attr], key=lambda o: o.id) + else: + return sorted([attr for attr in self.query_all() if attr], key=lambda o: o.id)
        + + +
        [docs]class InMemoryAttributeBackend(IAttributeBackend): + """ + This Backend for Attributes stores NOTHING in the database. Everything is kept in memory, and + normally lost on a crash, reload, shared memory flush, etc. It generates IDs for the Attributes + it manages, but these are of little importance beyond sorting and satisfying the caching logic + to know an Attribute hasn't been deleted out from under the cache's nose. + + """ + + _attrclass = InMemoryAttribute + +
        [docs] def __init__(self, handler, attrtype): + super().__init__(handler, attrtype) + self._storage = dict() + self._category_storage = defaultdict(list) + self._id_counter = 0
        + + def _next_id(self): + """ + Increments the internal ID counter and returns the new value. + + Returns: + next_id (int): A simple integer. + """ + self._id_counter += 1 + return self._id_counter + +
        [docs] def query_all(self): + return self._storage.values()
        + +
        [docs] def query_key(self, key, category): + found = self._storage.get((key, category), None) + if found: + return [found] + return []
        + +
        [docs] def query_category(self, category): + if category is None: + return self._storage.values() + return self._category_storage.get(category, [])
        + +
        [docs] def do_create_attribute(self, key, category, lockstring, value, strvalue): + """ + See parent class. + + strvalue has no meaning for InMemory attributes. + + """ + new_attr = self._attrclass( + pk=self._next_id(), key=key, category=category, lock_storage=lockstring, value=value + ) + self._storage[(key, category)] = new_attr + self._category_storage[category].append(new_attr) + return new_attr
        + +
        [docs] def do_update_attribute(self, attr, value): + attr.value = value
        + +
        [docs] def do_batch_update_attribute(self, attr_obj, category, lock_storage, new_value, strvalue): + """ + No need to bother saving anything. Just set some values. + """ + attr_obj.db_category = category + attr_obj.db_lock_storage = lock_storage if lock_storage else "" + attr_obj.value = new_value
        + +
        [docs] def do_batch_finish(self, attr_objs): + """ + Nothing to do here for In-Memory. + + Args: + attr_objs (list of IAttribute): The Attributes created/updated thus far. + """ + pass
        + +
        [docs] def do_delete_attribute(self, attr): + """ + Removes the Attribute from local storage. Once it's out of the cache, garbage collection + will handle the rest. + + Args: + attr (IAttribute): The attribute to delete. + """ + del self._storage[(attr.key, attr.category)] + self._category_storage[attr.category].remove(attr)
        + + +
        [docs]class ModelAttributeBackend(IAttributeBackend): + """ + Uses Django models for storing Attributes. + """ + + _attrclass = Attribute + _m2m_fieldname = "db_attributes" + +
        [docs] def __init__(self, handler, attrtype): + super().__init__(handler, attrtype) + self._model = to_str(handler.obj.__dbclass__.__name__.lower())
        + +
        [docs] def query_all(self): + query = { + "%s__id" % self._model: self._objid, + "attribute__db_model__iexact": self._model, + "attribute__db_attrtype": self._attrtype, + } + return [ + conn.attribute + for conn in getattr(self.obj, self._m2m_fieldname).through.objects.filter(**query) + ]
        + +
        [docs] def query_key(self, key, category): + query = { + "%s__id" % self._model: self._objid, + "attribute__db_model__iexact": self._model, + "attribute__db_attrtype": self._attrtype, + "attribute__db_key__iexact": key.lower(), + "attribute__db_category__iexact": category.lower() if category else None, + } + if not self.obj.pk: + return [] + return getattr(self.obj, self._m2m_fieldname).through.objects.filter(**query)
        + +
        [docs] def query_category(self, category): + query = { + "%s__id" % self._model: self._objid, + "attribute__db_model__iexact": self._model, + "attribute__db_attrtype": self._attrtype, + "attribute__db_category__iexact": category.lower() if category else None, + } + return [ + conn.attribute + for conn in getattr(self.obj, self._m2m_fieldname).through.objects.filter(**query) + ]
        + +
        [docs] def do_create_attribute(self, key, category, lockstring, value, strvalue): + kwargs = { + "db_key": key, + "db_category": category, + "db_model": self._model, + "db_lock_storage": lockstring if lockstring else "", + "db_attrtype": self._attrtype, + } + if strvalue: + kwargs["db_value"] = None + kwargs["db_strvalue"] = value + else: + kwargs["db_value"] = to_pickle(value) + kwargs["db_strvalue"] = None + new_attr = self._attrclass(**kwargs) + new_attr.save() + getattr(self.obj, self._m2m_fieldname).add(new_attr) + self._set_cache(key, category, new_attr) + return new_attr
        + +
        [docs] def do_update_attribute(self, attr, value): + attr.value = value
        + +
        [docs] def do_batch_update_attribute(self, attr_obj, category, lock_storage, new_value, strvalue): + attr_obj.db_category = category + attr_obj.db_lock_storage = lock_storage if lock_storage else "" + if strvalue: + # store as a simple string (will not notify OOB handlers) + attr_obj.db_strvalue = new_value + attr_obj.value = None + else: + # store normally (this will also notify OOB handlers) + attr_obj.value = new_value + attr_obj.db_strvalue = None + attr_obj.save(update_fields=["db_strvalue", "db_value", "db_category", "db_lock_storage"])
        + +
        [docs] def do_batch_finish(self, attr_objs): + # Add new objects to m2m field all at once + getattr(self.obj, self._m2m_fieldname).add(*attr_objs)
        + +
        [docs] def do_delete_attribute(self, attr): + try: + attr.delete() + except AssertionError: + # This could happen if the Attribute has already been deleted. + pass
        + + +
        [docs]class AttributeHandler: + """ + Handler for adding Attributes to the object. + """ + + _attrcreate = "attrcreate" + _attredit = "attredit" + _attrread = "attrread" + _attrtype = None + +
        [docs] def __init__(self, obj, backend_class): + """ + Setup the AttributeHandler. + + Args: + obj (TypedObject): An Account, Object, Channel, ServerSession (not technically a typed + object), etc. backend_class (IAttributeBackend class): The class of the backend to + use. + """ + self.obj = obj + self.backend = backend_class(self, self._attrtype)
        +
        [docs] def has(self, key=None, category=None): """ Checks if the given Attribute (or list of Attributes) exists on @@ -476,7 +1000,7 @@ category = category.strip().lower() if category is not None else None for keystr in make_iter(key): keystr = key.strip().lower() - ret.extend(bool(attr) for attr in self._getcache(keystr, category)) + ret.extend(bool(attr) for attr in self.backend.get(keystr, category)) return ret[0] if len(ret) == 1 else ret
        [docs] def get( @@ -516,7 +1040,8 @@ looked-after Attribute. default_access (bool, optional): If no `attrread` lock is set on object, this determines if the lock should then be passed or not. - return_list (bool, optional): + return_list (bool, optional): Always return a list, also if there is only + one or zero matches found. Returns: result (any or list): One or more matches for keys and/or @@ -534,7 +1059,7 @@ ret = [] for keystr in make_iter(key): # it's okay to send a None key - attr_objs = self._getcache(keystr, category) + attr_objs = self.backend.get(keystr, category) if attr_objs: ret.extend(attr_objs) elif raise_exception: @@ -599,35 +1124,16 @@ return category = category.strip().lower() if category is not None else None - keystr = key.strip().lower() - attr_obj = self._getcache(key, category) + attr_obj = self.backend.get(key, category) if attr_obj: # update an existing attribute object attr_obj = attr_obj[0] - if strattr: - # store as a simple string (will not notify OOB handlers) - attr_obj.db_strvalue = value - attr_obj.save(update_fields=["db_strvalue"]) - else: - # store normally (this will also notify OOB handlers) - attr_obj.value = value + self.backend.update_attribute(attr_obj, value) else: # create a new Attribute (no OOB handlers can be notified) - kwargs = { - "db_key": keystr, - "db_category": category, - "db_model": self._model, - "db_attrtype": self._attrtype, - "db_value": None if strattr else to_pickle(value), - "db_strvalue": value if strattr else None, - } - new_attr = Attribute(**kwargs) - new_attr.save() - getattr(self.obj, self._m2m_fieldname).add(new_attr) - # update cache - self._setcache(keystr, category, new_attr)
        + self.backend.create_attribute(keystr, category, lockstring, value, strattr)
        [docs] def batch_add(self, *args, **kwargs): """ @@ -639,10 +1145,10 @@ length) representing the Attribute to add to this object. Supported tuples are - - `(key, value)` - - `(key, value, category)` - - `(key, value, category, lockstring)` - - `(key, value, category, lockstring, default_access)` + - (key, value) + - (key, value, category) + - (key, value, category, lockstring) + - (key, value, category, lockstring, default_access) Keyword Args: strattr (bool): If `True`, value must be a string. This @@ -662,50 +1168,7 @@ to the database. """ - new_attrobjs = [] - strattr = kwargs.get("strattr", False) - for tup in args: - if not is_iter(tup) or len(tup) < 2: - raise RuntimeError("batch_add requires iterables as arguments (got %r)." % tup) - ntup = len(tup) - keystr = str(tup[0]).strip().lower() - new_value = tup[1] - category = str(tup[2]).strip().lower() if ntup > 2 and tup[2] is not None else None - lockstring = tup[3] if ntup > 3 else "" - - attr_objs = self._getcache(keystr, category) - - if attr_objs: - attr_obj = attr_objs[0] - # update an existing attribute object - attr_obj.db_category = category - attr_obj.db_lock_storage = lockstring or "" - attr_obj.save(update_fields=["db_category", "db_lock_storage"]) - if strattr: - # store as a simple string (will not notify OOB handlers) - attr_obj.db_strvalue = new_value - attr_obj.save(update_fields=["db_strvalue"]) - else: - # store normally (this will also notify OOB handlers) - attr_obj.value = new_value - else: - # create a new Attribute (no OOB handlers can be notified) - kwargs = { - "db_key": keystr, - "db_category": category, - "db_model": self._model, - "db_attrtype": self._attrtype, - "db_value": None if strattr else to_pickle(new_value), - "db_strvalue": new_value if strattr else None, - "db_lock_storage": lockstring or "", - } - new_attr = Attribute(**kwargs) - new_attr.save() - new_attrobjs.append(new_attr) - self._setcache(keystr, category, new_attr) - if new_attrobjs: - # Add new objects to m2m field all at once - getattr(self.obj, self._m2m_fieldname).add(*new_attrobjs)
        + self.backend.batch_add(*args, **kwargs)
        [docs] def remove( self, @@ -754,20 +1217,13 @@ for keystr in make_iter(key): keystr = keystr.lower() - attr_objs = self._getcache(keystr, category) + attr_objs = self.backend.get(keystr, category) for attr_obj in attr_objs: if not ( accessing_obj and not attr_obj.access(accessing_obj, self._attredit, default=default_access) ): - try: - attr_obj.delete() - except AssertionError: - print("Assertionerror for attr.delete()") - # this happens if the attr was already deleted - pass - finally: - self._delcache(keystr, category) + self.backend.delete_attribute(attr_obj) if not attr_objs and raise_exception: raise AttributeError
        @@ -785,27 +1241,7 @@ type `attredit` on the Attribute in question. """ - category = category.strip().lower() if category is not None else None - - if not self._cache_complete: - self._fullcache() - - if category is not None: - attrs = [attr for attr in self._cache.values() if attr.category == category] - else: - attrs = self._cache.values() - - if accessing_obj: - [ - attr.delete() - for attr in attrs - if attr and attr.access(accessing_obj, self._attredit, default=default_access) - ] - else: - [attr.delete() for attr in attrs if attr and attr.pk] - self._cache = {} - self._catcache = {} - self._cache_complete = False
        + self.backend.clear_attributes(category, accessing_obj, default_access)
        [docs] def all(self, accessing_obj=None, default_access=True): """ @@ -824,12 +1260,7 @@ their values!) in the handler. """ - if _TYPECLASS_AGGRESSIVE_CACHE: - if not self._cache_complete: - self._fullcache() - attrs = sorted([attr for attr in self._cache.values() if attr], key=lambda o: o.id) - else: - attrs = sorted([attr for attr in self._query_all() if attr], key=lambda o: o.id) + attrs = self.backend.get_all_attributes() if accessing_obj: return [ @@ -838,9 +1269,45 @@ if attr.access(accessing_obj, self._attredit, default=default_access) ] else: - return attrs
        + return attrs + +
        [docs] def reset_cache(self): + self.backend.reset_cache()
        +# DbHolders for .db and .ndb properties on Typeclasses. + +_GA = object.__getattribute__ +_SA = object.__setattr__ + + +
        [docs]class DbHolder: + "Holder for allowing property access of attributes" + +
        [docs] def __init__(self, obj, name, manager_name="attributes"): + _SA(self, name, _GA(obj, manager_name)) + _SA(self, "name", name)
        + + def __getattribute__(self, attrname): + if attrname == "all": + # we allow to overload our default .all + attr = _GA(self, _GA(self, "name")).get("all") + return attr if attr else _GA(self, "all") + return _GA(self, _GA(self, "name")).get(attrname) + + def __setattr__(self, attrname, value): + _GA(self, _GA(self, "name")).add(attrname, value) + + def __delattr__(self, attrname): + _GA(self, _GA(self, "name")).remove(attrname) + +
        [docs] def get_all(self): + return _GA(self, _GA(self, "name")).get_all_attributes()
        + + all = property(get_all)
        + + +# # Nick templating # @@ -860,7 +1327,7 @@ This will be converted to the following regex: -\@desc (?P<1>\w+) (?P<2>\w+) $(?P<3>\w+) + \@desc (?P<1>\w+) (?P<2>\w+) $(?P<3>\w+) Supported template markers (through fnmatch) * matches anything (non-greedy) -> .*? @@ -871,8 +1338,10 @@ $N argument position (1-99) """ +_RE_OR = re.compile(r"(?<!\\)\|") +_RE_NICK_RE_ARG = re.compile(r"arg([1-9][0-9]?)") _RE_NICK_ARG = re.compile(r"\\(\$)([1-9][0-9]?)") -_RE_NICK_TEMPLATE_ARG = re.compile(r"(\$)([1-9][0-9]?)") +_RE_NICK_RAW_ARG = re.compile(r"(\$)([1-9][0-9]?)") _RE_NICK_SPACE = re.compile(r"\\ ") @@ -880,45 +1349,72 @@ pass -
        [docs]def initialize_nick_templates(in_template, out_template): +
        [docs]def initialize_nick_templates(pattern, replacement, pattern_is_regex=False): """ Initialize the nick templates for matching and remapping a string. Args: - in_template (str): The template to be used for nick recognition. - out_template (str): The template to be used to replace the string - matched by the in_template. + pattern (str): The pattern to be used for nick recognition. This will + be parsed for shell patterns into a regex, unless `pattern_is_regex` + is `True`, in which case it must be an already valid regex string. In + this case, instead of `$N`, numbered arguments must instead be given + as matching groups named as `argN`, such as `(?P<arg1>.+?)`. + replacement (str): The template to be used to replace the string + matched by the pattern. This can contain `$N` markers and is never + parsed into a regex. + pattern_is_regex (bool): If set, `pattern` is a full regex string + instead of containing shell patterns. Returns: - (regex, str): Regex to match against strings and a template - Template with markers `{arg1}`, `{arg2}`, etc for - replacement using the standard `.format` method. + regex, template (str): Regex to match against strings and template + with markers ``{arg1}, {arg2}``, etc for replacement using the standard + `.format` method. Raises: - attributes.NickTemplateInvalid: If the in/out template does not have a matching - number of $args. + evennia.typecalasses.attributes.NickTemplateInvalid: If the in/out + template does not have a matching number of `$args`. + + Examples: + - `pattern` (shell syntax): `"grin $1"` + - `pattern` (regex): `"grin (?P<arg1.+?>)"` + - `replacement`: `"emote gives a wicked grin to $1"` """ - # create the regex for in_template - regex_string = fnmatch.translate(in_template) - # we must account for a possible line break coming over the wire + # create the regex from the pattern + if pattern_is_regex: + # Note that for a regex we can't validate in the way we do for the shell + # pattern, since you may have complex OR statements or optional arguments. - # NOTE-PYTHON3: fnmatch.translate format changed since Python2 - regex_string = regex_string[:-2] + r"(?:[\n\r]*?)\Z" + # Explicit regex given from the onset - this already contains argN + # groups. we need to split out any | - separated parts so we can + # attach the line-break/ending extras all regexes require. + pattern_regex_string = r"|".join( + or_part + r"(?:[\n\r]*?)\Z" + for or_part in _RE_OR.split(pattern)) - # validate the templates - regex_args = [match.group(2) for match in _RE_NICK_ARG.finditer(regex_string)] - temp_args = [match.group(2) for match in _RE_NICK_TEMPLATE_ARG.finditer(out_template)] - if set(regex_args) != set(temp_args): - # We don't have the same $-tags in input/output. - raise NickTemplateInvalid + else: + # Shell pattern syntax - convert $N to argN groups + # for the shell pattern we make sure we have matching $N on both sides + pattern_args = [match.group(1) for match in _RE_NICK_RAW_ARG.finditer(pattern)] + replacement_args = [ + match.group(1) for match in _RE_NICK_RAW_ARG.finditer(replacement)] + if set(pattern_args) != set(replacement_args): + # We don't have the same amount of argN/$N tags in input/output. + raise NickTemplateInvalid("Nicks: Both in/out-templates must contain the same $N tags.") - regex_string = _RE_NICK_SPACE.sub(r"\\s+", regex_string) - regex_string = _RE_NICK_ARG.sub(lambda m: "(?P<arg%s>.+?)" % m.group(2), regex_string) - template_string = _RE_NICK_TEMPLATE_ARG.sub(lambda m: "{arg%s}" % m.group(2), out_template) + # generate regex from shell pattern + pattern_regex_string = fnmatch.translate(pattern) + pattern_regex_string = _RE_NICK_SPACE.sub(r"\\s+", pattern_regex_string) + pattern_regex_string = _RE_NICK_ARG.sub( + lambda m: "(?P<arg%s>.+?)" % m.group(2), pattern_regex_string) + # we must account for a possible line break coming over the wire + pattern_regex_string = pattern_regex_string[:-2] + r"(?:[\n\r]*?)\Z" - return regex_string, template_string
        + # map the replacement to match the arg1 group-names, to make replacement easy + replacement_string = _RE_NICK_RAW_ARG.sub(lambda m: "{arg%s}" % m.group(2), replacement) + + return pattern_regex_string, replacement_string
        [docs]def parse_nick_template(string, template_regex, outtemplate): @@ -926,17 +1422,21 @@ Parse a text using a template and map it to another template Args: - string (str): The input string to processj + string (str): The input string to process template_regex (regex): A template regex created with initialize_nick_template. outtemplate (str): The template to which to map the matches produced by the template_regex. This should have $1, $2, - etc to match the regex. + etc to match the template-regex. Un-found $N-markers (possible if + the regex has optional matching groups) are replaced with empty + strings. """ match = template_regex.match(string) if match: - return True, outtemplate.format(**match.groupdict()) + matchdict = {key: value if value is not None else "" + for key, value in match.groupdict().items()} + return True, outtemplate.format(**matchdict) return False, string
        @@ -985,6 +1485,9 @@ a string. kwargs (any, optional): These are passed on to `AttributeHandler.get`. + Returns: + str or tuple: The nick replacement string or nick tuple. + """ if return_tuple or "return_obj" in kwargs: return super().get(key=key, category=category, **kwargs) @@ -998,24 +1501,46 @@ ) return None -
        [docs] def add(self, key, replacement, category="inputline", **kwargs): +
        [docs] def add(self, pattern, replacement, category="inputline", pattern_is_regex=False, **kwargs): """ - Add a new nick. + Add a new nick, a mapping pattern -> replacement. Args: - key (str): A key (or template) for the nick to match for. - replacement (str): The string (or template) to replace `key` with (the "nickname"). + pattern (str): A pattern to match for. This will be parsed for + shell patterns using the `fnmatch` library and can contain + `$N`-markers to indicate the locations of arguments to catch. If + `pattern_is_regex=True`, this must instead be a valid regular + expression and the `$N`-markers must be named `argN` that matches + numbered regex groups (see examples). + replacement (str): The string (or template) to replace `key` with + (the "nickname"). This may contain `$N` markers to indicate where to + place the argument-matches category (str, optional): the category within which to retrieve the nick. The "inputline" means replacing data sent by the user. - kwargs (any, optional): These are passed on to `AttributeHandler.get`. + pattern_is_regex (bool): If `True`, the `pattern` will be parsed as a + raw regex string. Instead of using `$N` markers in this string, one + then must mark numbered arguments as a named regex-groupd named `argN`. + For example, `(?P<arg1>.+?)` will match the behavior of using `$1` + in the shell pattern. + **kwargs (any, optional): These are passed on to `AttributeHandler.get`. + + Notes: + For most cases, the shell-pattern is much shorter and easier. The + regex pattern form can be useful for more complex matchings though, + for example in order to add optional arguments, such as with + `(?P<argN>.*?)`. + + Example: + - pattern (default shell syntax): `"gr $1 at $2"` + - pattern (with pattern_is_regex=True): `r"gr (?P<arg1>.+?) at (?P<arg2>.+?)"` + - replacement: `"emote With a flourish, $1 grins at $2."` """ - if category == "channel": - nick_regex, nick_template = initialize_nick_templates(key + " $1", replacement + " $1") - else: - nick_regex, nick_template = initialize_nick_templates(key, replacement) - super().add(key, (nick_regex, nick_template, key, replacement), category=category, **kwargs)
        + nick_regex, nick_template = initialize_nick_templates( + pattern, replacement, pattern_is_regex=pattern_is_regex) + super().add(pattern, (nick_regex, nick_template, pattern, replacement), + category=category, **kwargs)
        [docs] def remove(self, key, category="inputline", **kwargs): """ @@ -1081,95 +1606,6 @@ if is_match: break return raw_string
        - - -
        [docs]class NAttributeHandler(object): - """ - This stand-alone handler manages non-database saving. - It is similar to `AttributeHandler` and is used - by the `.ndb` handler in the same way as `.db` does - for the `AttributeHandler`. - """ - -
        [docs] def __init__(self, obj): - """ - Initialized on the object - """ - self._store = {} - self.obj = weakref.proxy(obj)
        - -
        [docs] def has(self, key): - """ - Check if object has this attribute or not. - - Args: - key (str): The Nattribute key to check. - - Returns: - has_nattribute (bool): If Nattribute is set or not. - - """ - return key in self._store
        - -
        [docs] def get(self, key): - """ - Get the named key value. - - Args: - key (str): The Nattribute key to get. - - Returns: - the value of the Nattribute. - - """ - return self._store.get(key, None)
        - -
        [docs] def add(self, key, value): - """ - Add new key and value. - - Args: - key (str): The name of Nattribute to add. - value (any): The value to store. - - """ - self._store[key] = value
        - -
        [docs] def remove(self, key): - """ - Remove Nattribute from storage. - - Args: - key (str): The name of the Nattribute to remove. - - """ - if key in self._store: - del self._store[key]
        - -
        [docs] def clear(self): - """ - Remove all NAttributes from handler. - - """ - self._store = {}
        - -
        [docs] def all(self, return_tuples=False): - """ - List the contents of the handler. - - Args: - return_tuples (bool, optional): Defines if the Nattributes - are returns as a list of keys or as a list of `(key, value)`. - - Returns: - nattributes (list): A list of keys `[key, key, ...]` or a - list of tuples `[(key, value), ...]` depending on the - setting of `return_tuples`. - - """ - if return_tuples: - return [(key, value) for (key, value) in self._store.items() if not key.startswith("_")] - return [key for key in self._store if not key.startswith("_")]
        @@ -1207,7 +1643,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1226,6 +1661,7 @@ +
        develop branch
        @@ -75,14 +76,12 @@ self, key=None, category=None, value=None, strvalue=None, obj=None, attrtype=None, **kwargs ): """ - Return Attribute objects by key, by category, by value, by - `strvalue`, by object (it is stored on) or with a combination of - those criteria. + Return Attribute objects by key, by category, by value, by strvalue, by + object (it is stored on) or with a combination of those criteria. Args: - key (str, optional): The attribute's key to search for. - category (str, optional): The category of the attribute(s) - to search for. + key (str, optional): The attribute's key to search for + category (str, optional): The category of the attribute(s) to search for. value (str, optional): The attribute value to search for. Note that this is not a very efficient operation since it will query for a pickled entity. Mutually exclusive to @@ -93,13 +92,13 @@ precedence if given. obj (Object, optional): On which object the Attribute to search for is. - attrtype (str, optional): An attribute-type to search for. + attrype (str, optional): An attribute-type to search for. By default this is either `None` (normal Attributes) or `"nick"`. - kwargs (any): Currently unused. Reserved for future use. + **kwargs (any): Currently unused. Reserved for future use. Returns: - attributes (list): The matching Attributes. + list: The matching Attributes. """ dbmodel = self.model.__dbclass__.__name__.lower() @@ -217,7 +216,7 @@ to search for. obj (Object, optional): On which object the Tag to search for is. - tagtype (str, optional): One of None (normal tags), + tagtype (str, optional): One of `None` (normal tags), "alias" or "permission" global_search (bool, optional): Include all possible tags, not just tags on this object @@ -620,7 +619,7 @@ for parent in (parent for parent in parents if hasattr(parent, "path")): query = query | Q(db_typeclass_path__exact=parent.path) # actually query the database - return self.filter(query)
        + return super().filter(query) class TypeclassManager(TypedObjectManager): @@ -638,13 +637,21 @@ Search by supplying a string with optional extra search criteria to aid the query. Args: - query (str): A search criteria that accepts extra search criteria on the + query (str): A search criteria that accepts extra search criteria on the following + forms: + + [key|alias|#dbref...] + [tag==<tagstr>[:category]...] + [attr==<key>:<value>:category...] + + All three can be combined in the same query, separated by spaces. - following forms: [key|alias|#dbref...] [tag==<tagstr>[:category]...] [attr==<key>:<value>:category...] - " != " != " Returns: - matches (queryset): A queryset result matching all queries exactly. If wanting to use spaces or - ==, != in tags or attributes, enclose them in quotes. + matches (queryset): A queryset result matching all queries exactly. If wanting to use + spaces or ==, != in tags or attributes, enclose them in quotes. + + Example: + house = smart_search("key=foo alias=bar tag=house:building tag=magic attr=color:red") Note: The flexibility of this method is limited by the input line format. Tag/attribute @@ -926,7 +933,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -945,6 +951,7 @@ +
        develop branch
        @@ -65,8 +66,6 @@ This module also contains the Managers for the respective models; inherit from these to create custom managers. ----- - """ from django.db.models import signals @@ -79,7 +78,13 @@ from django.utils.encoding import smart_str from django.utils.text import slugify -from evennia.typeclasses.attributes import Attribute, AttributeHandler, NAttributeHandler +from evennia.typeclasses.attributes import ( + Attribute, + AttributeHandler, + ModelAttributeBackend, + InMemoryAttributeBackend, +) +from evennia.typeclasses.attributes import DbHolder from evennia.typeclasses.tags import Tag, TagHandler, AliasHandler, PermissionHandler from evennia.utils.idmapper.models import SharedMemoryModel, SharedMemoryModelBase @@ -106,6 +111,7 @@ def call_at_first_save(sender, instance, created, **kwargs): """ Receives a signal just after the object is saved. + """ if created: instance.at_first_save() @@ -114,6 +120,7 @@ def remove_attributes_on_delete(sender, instance, **kwargs): """ Wipe object's Attributes when it's deleted + """ instance.db_attributes.all().delete() @@ -135,6 +142,7 @@ Metaclass which should be set for the root of model proxies that don't define any new fields, like Object, Script etc. This is the basis for the typeclassing system. + """ def __new__(cls, name, bases, attrs): @@ -203,35 +211,6 @@ return new_class -class DbHolder(object): - """ - Holder for allowing property access of attributes. - - """ - - def __init__(self, obj, name, manager_name="attributes"): - _SA(self, name, _GA(obj, manager_name)) - _SA(self, "name", name) - - def __getattribute__(self, attrname): - if attrname == "all": - # we allow to overload our default .all - attr = _GA(self, _GA(self, "name")).get("all") - return attr if attr else _GA(self, "all") - return _GA(self, _GA(self, "name")).get(attrname) - - def __setattr__(self, attrname, value): - _GA(self, _GA(self, "name")).add(attrname, value) - - def __delattr__(self, attrname): - _GA(self, _GA(self, "name")).remove(attrname) - - def get_all(self): - return _GA(self, _GA(self, "name")).all() - - all = property(get_all) - - # # Main TypedObject abstraction # @@ -245,15 +224,16 @@ mechanics for managing connected attributes. The TypedObject has the following properties: - key - main name - name - alias for key - typeclass_path - the path to the decorating typeclass - typeclass - auto-linked typeclass - date_created - time stamp of object creation - permissions - perm strings - dbref - #id of object - db - persistent attribute storage - ndb - non-persistent attribute storage + + - key - main name + - name - alias for key + - typeclass_path - the path to the decorating typeclass + - typeclass - auto-linked typeclass + - date_created - time stamp of object creation + - permissions - perm strings + - dbref - #id of object + - db - persistent attribute storage + - ndb - non-persistent attribute storage """ @@ -274,7 +254,8 @@ "typeclass", max_length=255, null=True, - help_text="this defines what 'type' of entity this is. This variable holds a Python path to a module with a valid Evennia Typeclass.", + help_text="this defines what 'type' of entity this is. This variable holds " + "a Python path to a module with a valid Evennia Typeclass.", db_index=True, ) # Creation date. This is not changed once the object is created. @@ -283,16 +264,20 @@ db_lock_storage = models.TextField( "locks", blank=True, - help_text="locks limit access to an entity. A lock is defined as a 'lock string' on the form 'type:lockfunctions', defining what functionality is locked and how to determine access. Not defining a lock means no access is granted.", + help_text="locks limit access to an entity. A lock is defined as a 'lock string' " + "on the form 'type:lockfunctions', defining what functionality is locked and " + "how to determine access. Not defining a lock means no access is granted.", ) # many2many relationships db_attributes = models.ManyToManyField( Attribute, - help_text="attributes on this object. An attribute can hold any pickle-able python object (see docs for special cases).", + help_text="attributes on this object. An attribute can hold any pickle-able " + "python object (see docs for special cases).", ) db_tags = models.ManyToManyField( Tag, - help_text="tags on this object. Tags are simple string markers to identify, group and alias objects.", + help_text="tags on this object. Tags are simple string markers to identify, " + "group and alias objects.", ) # Database manager @@ -355,8 +340,10 @@ than use the one in the model. Args: - *args: Passed through to parent. - **kwargs: Passed through to parent. + Passed through to parent. + + Keyword Args: + Passed through to parent. Notes: The loading mechanism will attempt the following steps: @@ -383,7 +370,7 @@ # initialize all handlers in a lazy fashion
        [docs] @lazy_property def attributes(self): - return AttributeHandler(self)
        + return AttributeHandler(self, ModelAttributeBackend)
        [docs] @lazy_property def locks(self): @@ -403,9 +390,9 @@
        [docs] @lazy_property def nattributes(self): - return NAttributeHandler(self)
        + return AttributeHandler(self, InMemoryAttributeBackend)
        -
        [docs] class Meta(object): +
        [docs] class Meta: """ Django setup info. """ @@ -680,7 +667,7 @@ superuser lock bypass (be careful with this one). Keyword Args: - kwargs (any): Ignored, but is there to make the api + kwar (any): Ignored, but is there to make the api consistent with the object-typeclass method access, which use it to feed to its hook methods. @@ -765,22 +752,22 @@ # Attribute storage # - # @property db - def __db_get(self): + @property + def db(self): """ Attribute handler wrapper. Allows for the syntax - :: + ```python obj.db.attrname = value - and + # and value = obj.db.attrname - and + # and del obj.db.attrname - and + # and all_attr = obj.db.all() - - (unless there is an attribute named 'all', in which case that will be - returned instead). + # (unless there is an attribute + # named 'all', in which case that will be returned instead). + ``` """ try: @@ -789,44 +776,29 @@ self._db_holder = DbHolder(self, "attributes") return self._db_holder - # @db.setter - def __db_set(self, value): - """Stop accidentally replacing the db object""" + @db.setter + def db(self, value): + "Stop accidentally replacing the db object" string = "Cannot assign directly to db object! " string += "Use db.attr=value instead." raise Exception(string) - # @db.deleter - def __db_del(self): - """Stop accidental deletion.""" + @db.deleter + def db(self): + "Stop accidental deletion." raise Exception("Cannot delete the db object!") - db = property(__db_get, __db_set, __db_del) - # # Non-persistent (ndb) storage # - # @property ndb - def __ndb_get(self): + @property + def ndb(self): """ - A non-attr_obj store (NonDataBase). Everything stored to this is - guaranteed to be cleared when a server is shutdown. Syntax is same as - for the `.db` property, e.g. - :: - - obj.ndb.attrname = value - and - value = obj.ndb.attrname - and - del obj.ndb.attrname - and - all_attr = obj.ndb.all() - - What makes this preferable over just assigning properties directly on - the object is that Evennia can track caching for these properties and - for example avoid wiping objects with set `.ndb` data on cache flushes. - + A non-attr_obj store (ndb: NonDataBase). Everything stored + to this is guaranteed to be cleared when a server is shutdown. + Syntax is same as for the _get_db_holder() method and + property, e.g. obj.ndb.attr = value etc. """ try: return self._ndb_holder @@ -834,20 +806,18 @@ self._ndb_holder = DbHolder(self, "nattrhandler", manager_name="nattributes") return self._ndb_holder - # @db.setter - def __ndb_set(self, value): + @ndb.setter + def ndb(self, value): "Stop accidentally replacing the ndb object" string = "Cannot assign directly to ndb object! " string += "Use ndb.attr=value instead." raise Exception(string) - # @db.deleter - def __ndb_del(self): + @ndb.deleter + def ndb(self): "Stop accidental deletion." raise Exception("Cannot delete the ndb object!") - ndb = property(__ndb_get, __ndb_set, __ndb_del) -
        [docs] def get_display_name(self, looker, **kwargs): """ Displays the name of the object in a viewer-aware manner. @@ -931,37 +901,32 @@
        [docs] @classmethod def web_get_create_url(cls): """ - Returns the URI path for a View that allows users to create new instances of this object. + ex. Chargen = '/characters/create/' + + For this to work, the developer must have defined a named view somewhere + in urls.py that follows the format 'modelname-action', so in this case + a named view of 'character-create' would be referenced by this method. + + ex. + url(r'characters/create/', ChargenView.as_view(), name='character-create') + + If no View has been created and defined in urls.py, returns an + HTML anchor. + + This method is naive and simply returns a path. Securing access to + the actual view and limiting who can create new objects is the + developer's responsibility. + Returns: path (str): URI path to object creation page, if defined. - Examples: - :: - - Chargen = '/characters/create/' - - For this to work, the developer must have defined a named view somewhere - in urls.py that follows the format 'modelname-action', so in this case - a named view of 'character-create' would be referenced by this method. - :: - - url(r'characters/create/', ChargenView.as_view(), name='character-create') - - If no View has been created and defined in urls.py, returns an - HTML anchor. - - Notes: - This method is naive and simply returns a path. Securing access to - the actual view and limiting who can create new objects is the - developer's responsibility. - """ try: return reverse("%s-create" % slugify(cls._meta.verbose_name)) - except: + except Exception: return "#"
        [docs] def web_get_detail_url(self): @@ -973,21 +938,24 @@ path (str): URI path to object detail page, if defined. Examples: - :: - Oscar (Character) = '/characters/oscar/1/' + ```python + Oscar (Character) = '/characters/oscar/1/' + ``` For this to work, the developer must have defined a named view somewhere in urls.py that follows the format 'modelname-action', so in this case a named view of 'character-detail' would be referenced by this method. - :: + + ```python + url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/$', CharDetailView.as_view(), name='character-detail') + ``` If no View has been created and defined in urls.py, returns an HTML anchor. - Notes: This method is naive and simply returns a path. Securing access to the actual view and limiting who can view this object is the developer's responsibility. @@ -998,7 +966,7 @@ "%s-detail" % slugify(self._meta.verbose_name), kwargs={"pk": self.pk, "slug": slugify(self.name)}, ) - except: + except Exception: return "#"
        [docs] def web_get_puppet_url(self): @@ -1007,7 +975,7 @@ object. Returns: - path (str): URI path to object puppet page, if defined. + str: URI path to object puppet page, if defined. Examples: :: @@ -1025,7 +993,6 @@ If no View has been created and defined in urls.py, returns an HTML anchor. - Notes: This method is naive and simply returns a path. Securing access to the actual view and limiting who can view this object is the developer's responsibility. @@ -1037,7 +1004,7 @@ "%s-puppet" % slugify(self._meta.verbose_name), kwargs={"pk": self.pk, "slug": slugify(self.name)}, ) - except: + except Exception: return "#"
        [docs] def web_get_update_url(self): @@ -1046,12 +1013,13 @@ object. Returns: - path (str): URI path to object update page, if defined. + str: URI path to object update page, if defined. Examples: - :: - Oscar (Character) = '/characters/oscar/1/change/' + ```python + Oscar (Character) = '/characters/oscar/1/change/' + ``` For this to work, the developer must have defined a named view somewhere in urls.py that follows the format 'modelname-action', so in this case @@ -1059,23 +1027,23 @@ :: url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/change/$', - CharUpdateView.as_view(), name='character-update') + CharUpdateView.as_view(), name='character-update') If no View has been created and defined in urls.py, returns an HTML anchor. - Notes: This method is naive and simply returns a path. Securing access to the actual view and limiting who can modify objects is the developer's responsibility. + """ try: return reverse( "%s-update" % slugify(self._meta.verbose_name), kwargs={"pk": self.pk, "slug": slugify(self.name)}, ) - except: + except Exception: return "#"
        [docs] def web_get_delete_url(self): @@ -1086,25 +1054,26 @@ path (str): URI path to object deletion page, if defined. Examples: - :: - Oscar (Character) = '/characters/oscar/1/delete/' + ```python + Oscar (Character) = '/characters/oscar/1/delete/' + ``` - For this to work, the developer must have defined a named view somewhere - in urls.py that follows the format 'modelname-action', so in this case - a named view of 'character-detail' would be referenced by this method. + For this to work, the developer must have defined a named view + somewhere in urls.py that follows the format 'modelname-action', so + in this case a named view of 'character-detail' would be referenced + by this method. :: url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/delete/$', - CharDeleteView.as_view(), name='character-delete') + CharDeleteView.as_view(), name='character-delete') - If no View has been created and defined in urls.py, returns an - HTML anchor. + If no View has been created and defined in urls.py, returns an HTML + anchor. - Notes: This method is naive and simply returns a path. Securing access to - the actual view and limiting who can delete this object is the developer's - responsibility. + the actual view and limiting who can delete this object is the + developer's responsibility. """ @@ -1113,7 +1082,7 @@ "%s-delete" % slugify(self._meta.verbose_name), kwargs={"pk": self.pk, "slug": slugify(self.name)}, ) - except: + except Exception: return "#"
        # Used by Django Sites/Admin @@ -1155,7 +1124,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1174,6 +1142,7 @@ +
        develop branch
        @@ -94,7 +95,7 @@ "key", max_length=255, null=True, help_text="tag identifier", db_index=True ) db_category = models.CharField( - "category", max_length=64, null=True, help_text="tag category", db_index=True + "category", max_length=64, null=True, blank=True, help_text="tag category", db_index=True ) db_data = models.TextField( "data", @@ -116,7 +117,7 @@ db_index=True, ) - class Meta(object): + class Meta: "Define Django meta options" verbose_name = "Tag" unique_together = (("db_key", "db_category", "db_tagtype", "db_model"),) @@ -166,7 +167,10 @@ self._cache_complete = False
        def _query_all(self): - "Get all tags for this objects" + """ + Get all tags for this object. + + """ query = { "%s__id" % self._model: self._objid, "tag__db_model": self._model, @@ -178,7 +182,10 @@ ] def _fullcache(self): - "Cache all tags of this object" + """ + Cache all tags of this object. + + """ if not _TYPECLASS_AGGRESSIVE_CACHE: return tags = self._query_all() @@ -318,6 +325,7 @@
        [docs] def reset_cache(self): """ Reset the cache from the outside. + """ self._cache_complete = False self._cache = {} @@ -360,6 +368,40 @@ getattr(self.obj, self._m2m_fieldname).add(tagobj) self._setcache(tagstr, category, tagobj)
        +
        [docs] def has(self, tag=None, category=None, return_list=False): + """ + Checks if the given Tag (or list of Tags) exists on the object. + + Args: + tag (str or iterable): The Tag key or tags to check for. + If `None`, search by category. + category (str, optional): Limit the check to Tags with this + category (note, that `None` is the default category). + + Returns: + has_tag (bool or list): If the Tag exists on this object or not. + If `tag` was given as an iterable then the return is a list of booleans. + + Raises: + ValueError: If neither `tag` nor `category` is given. + + """ + ret = [] + category = category.strip().lower() if category is not None else None + if tag: + for tag_str in make_iter(tag): + tag_str = tag_str.strip().lower() + ret.extend(bool(tag) for tag in self._getcache(tag_str, category)) + elif category: + ret.extend(bool(tag) for tag in self._getcache(category=category)) + else: + raise ValueError("Either tag or category must be provided.") + + if return_list: + return ret + + return ret[0] if len(ret) == 1 else ret
        +
        [docs] def get(self, key=None, default=None, category=None, return_tagobj=False, return_list=False): """ Get the tag for the given key, category or combination of the two. @@ -490,8 +532,9 @@ Batch-add tags from a list of tuples. Args: - *args (tuple or str): Each argument should be a `tagstr` keys or tuple `(keystr, category)` or - `(keystr, category, data)`. It's possible to mix input types. + *args (tuple or str): Each argument should be a `tagstr` keys or tuple + `(keystr, category)` or `(keystr, category, data)`. It's possible to mix input + types. Notes: This will generate a mimimal number of self.add calls, @@ -572,7 +615,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -591,6 +633,7 @@ +
        develop branch
        @@ -42,18 +43,64 @@ """ ANSI - Gives colour to text. -Use the codes defined in ANSIPARSER in your text to apply colour to text -according to the ANSI standard. +Use the codes defined in the *ANSIParser* class to apply colour to text. The +`parse_ansi` function in this module parses text for markup and `strip_ansi` +removes it. -Examples: +You should usually not need to call `parse_ansi` explicitly; it is run by +Evennia just before returning data to/from the user. Alternative markup is +possible by overriding the parser class (see also contrib/ for deprecated +markup schemes). + + +Supported standards: + +- ANSI 8 bright and 8 dark fg (foreground) colors +- ANSI 8 dark bg (background) colors +- 'ANSI' 8 bright bg colors 'faked' with xterm256 (bright bg not included in ANSI standard) +- Xterm256 - 255 fg/bg colors + 26 greyscale fg/bg colors + +## Markup + +ANSI colors: `r` ed, `g` reen, `y` ellow, `b` lue, `m` agenta, `c` yan, `n` ormal (no color). +Capital letters indicate the 'dark' variant. + +- `|r` fg bright red +- `|R` fg dark red +- `|[r` bg bright red +- `|[R` bg dark red +- `|[R|g` bg dark red, fg bright green ```python "This is |rRed text|n and this is normal again." + ``` -Mostly you should not need to call `parse_ansi()` explicitly; it is run by -Evennia just before returning data to/from the user. Depreciated example forms -are available by extending the ansi mapping. +Xterm256 colors are given as RGB (Red-Green-Blue), with values 0-5: + +- `|500` fg bright red +- `|050` fg bright green +- `|005` fg bright blue +- `|110` fg dark brown +- `|425` fg pink +- `|[431` bg orange + +Xterm256 greyscale: + +- `|=a` fg black +- `|=g` fg dark grey +- `|=o` fg middle grey +- `|=v` fg bright grey +- `|=z` fg white +- `|[=r` bg middle grey + +```python +"This is |500Red text|n and this is normal again." +"This is |[=jText on dark grey background" + +``` + +---- """ import functools @@ -121,9 +168,11 @@
        [docs]class ANSIParser(object): """ - A class that parses ANSI markup to ANSI command sequences. + A class that parses ANSI markup + to ANSI command sequences - We also allow to escape colour codes by prepending with an extra `|`. + We also allow to escape colour codes + by prepending with an extra `|`. """ @@ -216,6 +265,7 @@ ansi_xterm256_bright_bg_map += settings.COLOR_ANSI_XTERM256_BRIGHT_BG_EXTRA_MAP mxp_re = r"\|lc(.*?)\|lt(.*?)\|le" + mxp_url_re = r"\|lu(.*?)\|lt(.*?)\|le" # prepare regex matching brightbg_sub = re.compile( @@ -230,6 +280,7 @@ # xterm256_sub = re.compile(r"|".join([tup[0] for tup in xterm256_map]), re.DOTALL) ansi_sub = re.compile(r"|".join([re.escape(tup[0]) for tup in ansi_map]), re.DOTALL) mxp_sub = re.compile(mxp_re, re.DOTALL) + mxp_url_sub = re.compile(mxp_url_re, re.DOTALL) # used by regex replacer to correctly map ansi sequences ansi_map_dict = dict(ansi_map) @@ -330,8 +381,9 @@ colval = 16 + (red * 36) + (green * 6) + blue return "\033[%s8;5;%sm" % (3 + int(background), colval) - # replaced since some clients (like Potato) does not accept codes with leading zeroes, see issue #1024. - # return "\033[%s8;5;%s%s%sm" % (3 + int(background), colval // 100, (colval % 100) // 10, colval%10) + # replaced since some clients (like Potato) does not accept codes with leading zeroes, + # see issue #1024. + # return "\033[%s8;5;%s%s%sm" % (3 + int(background), colval // 100, (colval % 100) // 10, colval%10) # noqa else: # xterm256 not supported, convert the rgb value to ansi instead @@ -416,7 +468,9 @@ string (str): The processed string. """ - return self.mxp_sub.sub(r"\2", string)
        + string = self.mxp_sub.sub(r"\2", string) + string = self.mxp_url_sub.sub(r"\1", string) # replace with url verbatim + return string
        [docs] def parse_ansi(self, string, strip_ansi=False, xterm256=False, mxp=False): """ @@ -722,7 +776,8 @@ """ - # A compiled Regex for the format mini-language: https://docs.python.org/3/library/string.html#formatspec + # A compiled Regex for the format mini-language: + # https://docs.python.org/3/library/string.html#formatspec re_format = re.compile( r"(?i)(?P<just>(?P<fill>.)?(?P<align>\<|\>|\=|\^))?(?P<sign>\+|\-| )?(?P<alt>\#)?" r"(?P<zero>0)?(?P<width>\d+)?(?P<grouping>\_|\,)?(?:\.(?P<precision>\d+))?" @@ -795,12 +850,14 @@ Current features supported: fill, align, width. Args: - format_spec (str): The format specification passed by f-string or str.format(). This is a string such as - "0<30" which would mean "left justify to 30, filling with zeros". The full specification can be found - at https://docs.python.org/3/library/string.html#formatspec + format_spec (str): The format specification passed by f-string or str.format(). This is + a string such as "0<30" which would mean "left justify to 30, filling with zeros". + The full specification can be found at + https://docs.python.org/3/library/string.html#formatspec Returns: ansi_str (str): The formatted ANSIString's .raw() form, for display. + """ # This calls the compiled regex stored on ANSIString's class to analyze the format spec. # It returns a dictionary. @@ -1060,7 +1117,7 @@ current_index = 0 result = tuple() for section in parent_result: - result += (self[current_index : current_index + len(section)],) + result += (self[current_index: current_index + len(section)],) current_index += len(section) return result
        @@ -1180,7 +1237,7 @@ start = next + bylen maxsplit -= 1 # NB. if it's already < 0, it stays < 0 - res.append(self[start : len(self)]) + res.append(self[start: len(self)]) if drop_spaces: return [part for part in res if part != ""] return res @@ -1223,7 +1280,7 @@ if next < 0: break # Get character codes after the index as well. - res.append(self[next + bylen : end]) + res.append(self[next + bylen: end]) end = next maxsplit -= 1 # NB. if it's already < 0, it stays < 0 @@ -1277,7 +1334,7 @@ ic -= 1 ir2 -= 1 rstripped = rstripped[::-1] - return ANSIString(lstripped + raw[ir1 : ir2 + 1] + rstripped) + return ANSIString(lstripped + raw[ir1: ir2 + 1] + rstripped)
        [docs] def lstrip(self, chars=None): """ @@ -1396,7 +1453,7 @@ start = None end = char._char_indexes[0] prefix = char._raw_string[start:end] - postfix = char._raw_string[end + 1 :] + postfix = char._raw_string[end + 1:] line = char._clean_string * amount code_indexes = [i for i in range(0, len(prefix))] length = len(prefix) + len(line) @@ -1494,7 +1551,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1513,6 +1569,7 @@ +
        develop branch
        @@ -41,24 +42,22 @@

        Source code for evennia.utils.batchprocessors

         """
         This module contains the core methods for the Batch-command- and
        -Batch-code-processors respectively. In short, these are two different
        -ways to build a game world using a normal text-editor without having
        -to do so 'on the fly' in-game. They also serve as an automatic backup
        -so you can quickly recreate a world also after a server reset. The
        -functions in this module is meant to form the backbone of a system
        -called and accessed through game commands.
        +Batch-code-processors respectively. In short, these are two different ways to
        +build a game world using a normal text-editor without having to do so 'on the
        +fly' in-game. They also serve as an automatic backup so you can quickly
        +recreate a world also after a server reset. The functions in this module is
        +meant to form the backbone of a system called and accessed through game
        +commands.
         
        -The Batch-command processor is the simplest. It simply runs a list of
        -in-game commands in sequence by reading them from a text file. The
        -advantage of this is that the builder only need to remember the normal
        -in-game commands. They are also executing with full permission checks
        -etc, making it relatively safe for builders to use. The drawback is
        -that in-game there is really a builder-character walking around
        -building things, and it can be important to create rooms and objects
        -in the right order, so the character can move between them. Also
        -objects that affects players (such as mobs, dark rooms etc) will
        -affect the building character too, requiring extra care to turn
        -off/on.
        +The Batch-command processor is the simplest. It simply runs a list of in-game
        +commands in sequence by reading them from a text file. The advantage of this is
        +that the builder only need to remember the normal in-game commands. They are
        +also executing with full permission checks etc, making it relatively safe for
        +builders to use. The drawback is that in-game there is really a
        +builder-character walking around building things, and it can be important to
        +create rooms and objects in the right order, so the character can move between
        +them. Also objects that affects players (such as mobs, dark rooms etc) will
        +affect the building character too, requiring extra care to turn off/on.
         
         The Batch-code processor is a more advanced system that accepts full
         Python code, executing in chunks. The advantage of this is much more
        @@ -72,8 +71,7 @@
         recommended that the batch-code processor is limited only to
         superusers or highly trusted staff.
         
        -Batch-Command processor file syntax
        ------------------------------------
        +# Batch-command processor file syntax
         
         The batch-command processor accepts 'batchcommand files' e.g
         `batch.ev`, containing a sequence of valid Evennia commands in a
        @@ -81,31 +79,39 @@
         had been run at the game prompt.
         
         Each Evennia command must be delimited by a line comment to mark its
        -end. This way entire game worlds can be created and planned offline; it is
        +end.
        +
        +::
        +
        +    look
        +    # delimiting comment
        +    create/drop box
        +    # another required comment
        +
        +One can also inject another batchcmdfile:
        +
        +::
        +
        +    #INSERT path.batchcmdfile
        +
        +This way entire game worlds can be created and planned offline; it is
         especially useful in order to create long room descriptions where a
         real offline text editor is often much better than any online text
         editor or prompt.
         
        -There is only one batchcommand-specific entry to use in a batch-command
        -files (all others are just like in-game commands):
        +## Example of batch.ev file:
         
        -- `#INSERT path.batchcmdfile` - this as the first entry on a line will
        -  import and run a batch.ev file in this position, as if it was
        -  written in this file.
        -
        -
        -Example of batch.ev file:
         ::
         
             # batch file
             # all lines starting with # are comments; they also indicate
             # that a command definition is over.
         
        -    @create box
        +    create box
         
             # this comment ends the @create command.
         
        -    @set box/desc = A large box.
        +    set box/desc = A large box.
         
             Inside are some scattered piles of clothing.
         
        @@ -117,25 +123,22 @@
             # is ignored.  An empty line in the command definition is parsed as a \n
             # (so two empty lines becomes a new paragraph).
         
        -    @teleport #221
        +    teleport #221
         
             # (Assuming #221 is a warehouse or something.)
             # (remember, this comment ends the @teleport command! Don'f forget it)
         
             # Example of importing another file at this point.
        -    #INSERT examples.batch
        +    #IMPORT examples.batch
         
        -    @drop box
        +    drop box
         
             # Done, the box is in the warehouse! (this last comment is not necessary to
        -    # close the @drop command since it's the end of the file)
        -
        +    # close the drop command since it's the end of the file)
         
         An example batch file is `contrib/examples/batch_example.ev`.
         
        -
        -Batch-Code processor file syntax
        ---------------------------------
        +# Batch-code processor file syntax
         
         The Batch-code processor accepts full python modules (e.g. `batch.py`)
         that looks identical to normal Python files. The difference from
        @@ -169,13 +172,14 @@
         Importing works as normal. The following variables are automatically
         made available in the script namespace.
         
        -- `caller` -  The object executing the batchscript
        +- `caller` - The object executing the batchscript
         - `DEBUG` - This is a boolean marking if the batchprocessor is running
        -  in debug mode. It can be checked to e.g. delete created objects
        -  when running a CODE block multiple times during testing.
        -  (avoids creating a slew of same-named db objects)
        +            in debug mode. It can be checked to e.g. delete created objects
        +            when running a CODE block multiple times during testing.
        +            (avoids creating a slew of same-named db objects)
        +
        +## Example batch.py file
         
        -Example batch.py file:
         ::
         
             #HEADER
        @@ -204,8 +208,6 @@
         
             script = create.create_script()
         
        -----
        -
         """
         import re
         import codecs
        @@ -243,7 +245,7 @@
                 file_ending (str): The file ending of this file (.ev or .py)
         
             Returns:
        -        str: The text content of the batch file.
        +        text (str): The text content of the batch file.
         
             Raises:
                 IOError: If problems reading file.
        @@ -290,22 +292,30 @@
         
         
        [docs] def parse_file(self, pythonpath): """ - This parses the lines of a batchfile according to the following - rules: + This parses the lines of a batch-command-file. - 1. `#` at the beginning of a line marks the end of the command before - it. It is also a comment and any number of # can exist on - subsequent lines (but not inside comments). - 2. `#INSERT` at the beginning of a line imports another - batch-cmd file file and pastes it into the batch file as if - it was written there. - 3. Commands are placed alone at the beginning of a line and their - arguments are considered to be everything following (on any - number of lines) until the next comment line beginning with #. - 4. Newlines are ignored in command definitions - 5. A completely empty line in a command line definition is condered - a newline (so two empty lines is a paragraph). - 6. Excess spaces and indents inside arguments are stripped. + Args: + pythonpath (str): The dot-python path to the file. + + Returns: + list: A list of all parsed commands with arguments, as strings. + + Notes: + Parsing follows the following rules: + + 1. A `#` at the beginning of a line marks the end of the command before + it. It is also a comment and any number of # can exist on + subsequent lines (but not inside comments). + 2. #INSERT at the beginning of a line imports another + batch-cmd file file and pastes it into the batch file as if + it was written there. + 3. Commands are placed alone at the beginning of a line and their + arguments are considered to be everything following (on any + number of lines) until the next comment line beginning with #. + 4. Newlines are ignored in command definitions + 5. A completely empty line in a command line definition is condered + a newline (so two empty lines is a paragraph). + 6. Excess spaces and indents inside arguments are stripped. """ @@ -316,7 +326,7 @@ try: path = match.group(1) return "\n#\n".join(self.parse_file(path)) - except IOError as err: + except IOError: raise IOError("#INSERT {} failed.".format(path)) text = _RE_INSERT.sub(replace_insert, text) @@ -354,21 +364,23 @@
        [docs] def parse_file(self, pythonpath): """ - This parses the lines of a batchfile according to the following - rules: + This parses the lines of a batch-code file Args: pythonpath (str): The dot-python path to the file. Returns: - codeblocks (list): A list of all #CODE blocks, each with - prepended #HEADER data. If no #CODE blocks were found, - this will be a list of one element. + list: A list of all `#CODE` blocks, each with + prepended `#HEADER` block data. If no `#CODE` + blocks were found, this will be a list of one element + containing all code in the file (so a normal Python file). Notes: + Parsing is done according to the following rules: + 1. Code before a #CODE/HEADER block are considered part of - the first code/header block or is the ONLY block if no - #CODE/HEADER blocks are defined. + the first code/header block or is the ONLY block if no + `#CODE/HEADER` blocks are defined. 2. Lines starting with #HEADER starts a header block (ends other blocks) 3. Lines starting with #CODE begins a code block (ends other blocks) 4. Lines starting with #INSERT are on form #INSERT filename. Code from @@ -377,6 +389,7 @@ 5. Code after the last block is considered part of the last header/code block + """ text = "".join(read_batchfile(pythonpath, file_ending=".py")) @@ -503,7 +516,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -522,6 +534,7 @@ +
        develop branch
        @@ -60,7 +61,7 @@ SCRIPTDB = None -
        [docs]class Container(object): +
        [docs]class Container: """ Base container class. A container is simply a storage object whose properties can be acquired as a property on it. This is generally @@ -196,12 +197,11 @@ new_script.start() return new_script - if ( - (found.interval != interval) - or (found.start_delay != start_delay) - or (found.repeats != repeats) - ): - found.restart(interval=interval, start_delay=start_delay, repeats=repeats) + if ((found.interval != interval) + or (found.start_delay != start_delay) + or (found.repeats != repeats)): + # the setup changed + found.start(interval=interval, start_delay=start_delay, repeats=repeats) if found.desc != desc: found.desc = desc return found @@ -318,7 +318,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -337,6 +336,7 @@ +
        develop branch
        @@ -40,27 +41,19 @@

        Source code for evennia.utils.create

         """
        -This module gathers all the essential database-creation
        -functions for the game engine's various object types.
        +This module gathers all the essential database-creation functions for the game
        +engine's various object types.
         
        -Only objects created 'stand-alone' are in here, e.g. object Attributes
        -are always created directly through their respective objects.
        +Only objects created 'stand-alone' are in here. E.g. object Attributes are
        +always created through their respective objects handlers.
         
        -Each creation_* function also has an alias named for the entity being
        -created, such as create_object() and object().  This is for
        -consistency with the utils.search module and allows you to do the
        -shorter "create.object()".
        +Each `creation_*` function also has an alias named for the entity being created,
        +such as create_object() and object(). This is for consistency with the
        +utils.search module and allows you to do the shorter `create.object()`.
         
        -The respective object managers hold more methods for manipulating and
        -searching objects already existing in the database.
        +The respective object managers hold more methods for manipulating and searching
        +objects already existing in the database.
         
        -Models covered:
        - Objects
        - Scripts
        - Help
        - Message
        - Channel
        - Accounts
         """
         from django.conf import settings
         from django.db import IntegrityError
        @@ -81,7 +74,6 @@
         _AccountDB = None
         _to_object = None
         _ChannelDB = None
        -_channelhandler = None
         
         
         # limit symbol import from API
        @@ -122,31 +114,30 @@
             Keyword Args:
                 typeclass (class or str): Class or python path to a typeclass.
                 key (str): Name of the new object. If not set, a name of
        -            #dbref will be set.
        +            `#dbref` will be set.
                 home (Object or str): Obj or #dbref to use as the object's
                     home location.
                 permissions (list): A list of permission strings or tuples (permstring, category).
                 locks (str): one or more lockstrings, separated by semicolons.
                 aliases (list): A list of alternative keys or tuples (aliasstring, category).
                 tags (list): List of tag keys or tuples (tagkey, category) or (tagkey, category, data).
        -        destination (Object or str): Obj or #dbref to use as an Exit's
        -            target.
        +        destination (Object or str): Obj or #dbref to use as an Exit's target.
                 report_to (Object): The object to return error messages to.
                 nohome (bool): This allows the creation of objects without a
                     default home location; only used when creating the default
                     location itself or during unittests.
                 attributes (list): Tuples on the form (key, value) or (key, value, category),
        -           (key, value, lockstring) or (key, value, lockstring, default_access).
        -           to set as Attributes on the new object.
        +            (key, value, lockstring) or (key, value, lockstring, default_access).
        +            to set as Attributes on the new object.
                 nattributes (list): Non-persistent tuples on the form (key, value). Note that
        -           adding this rarely makes sense since this data will not survive a reload.
        +            adding this rarely makes sense since this data will not survive a reload.
         
             Returns:
                 object (Object): A newly created object of the given typeclass.
         
             Raises:
                 ObjectDB.DoesNotExist: If trying to create an Object with
        -        `location` or `home` that can't be found.
        +            `location` or `home` that can't be found.
         
             """
             global _ObjectDB
        @@ -270,9 +261,8 @@
                 report_to (Object): The object to return error messages to.
                 desc (str): Optional description of script
                 tags (list): List of tags or tuples (tag, category).
        -        attributes (list): List of tuples `(key, value)`, `(key, value, category)`,
        -           `(key, value, category, lockstring)` or
        -           `(key, value, category, lockstring, default_access)`.
        +        attributes (list): List if tuples (key, value) or (key, value, category)
        +           (key, value, lockstring) or (key, value, lockstring, default_access).
         
             Returns:
                 script (obj): An instance of the script created
        @@ -412,33 +402,38 @@
         
         
         
        [docs]def create_message( - senderobj, message, channels=None, receivers=None, locks=None, tags=None, header=None -): + senderobj, message, receivers=None, locks=None, tags=None, + header=None, **kwargs): """ Create a new communication Msg. Msgs represent a unit of database-persistent communication between entites. Args: - senderobj (Object or Account): The entity sending the Msg. + senderobj (Object, Account, Script, str or list): The entity (or + entities) sending the Msg. If a `str`, this is the id-string + for an external sender type. message (str): Text with the message. Eventual headers, titles etc should all be included in this text string. Formatting will be retained. - channels (Channel, key or list): A channel or a list of channels to - send to. The channels may be actual channel objects or their - unique key strings. - receivers (Object, Account, str or list): An Account/Object to send - to, or a list of them. May be Account objects or accountnames. + receivers (Object, Account, Script, str or list): An Account/Object to send + to, or a list of them. If a string, it's an identifier for an external + receiver. locks (str): Lock definition string. tags (list): A list of tags or tuples `(tag, category)`. header (str): Mime-type or other optional information for the message Notes: - The Comm system is created very open-ended, so it's fully possible - to let a message both go to several channels and to several - receivers at the same time, it's up to the command definitions to - limit this as desired. + The Comm system is created to be very open-ended, so it's fully + possible to let a message both go several receivers at the same time, + it's up to the command definitions to limit this as desired. """ + if 'channels' in kwargs: + raise DeprecationWarning( + "create_message() does not accept 'channel' kwarg anymore " + "- channels no longer accept Msg objects." + ) + global _Msg if not _Msg: from evennia.comms.models import Msg as _Msg @@ -450,8 +445,6 @@ for sender in make_iter(senderobj): new_message.senders = sender new_message.header = header - for channel in make_iter(channels): - new_message.channels = channel for receiver in make_iter(receivers): new_message.receivers = receiver if locks: @@ -670,7 +663,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -689,6 +681,7 @@ +
        develop branch
        @@ -70,7 +71,7 @@ from django.core.exceptions import ObjectDoesNotExist from django.contrib.contenttypes.models import ContentType from django.utils.safestring import SafeString -from evennia.utils.utils import uses_database, is_iter, to_str, to_bytes +from evennia.utils.utils import uses_database, is_iter, to_bytes from evennia.utils import logger __all__ = ("to_pickle", "from_pickle", "do_pickle", "do_unpickle", "dbserialize", "dbunserialize") @@ -657,7 +658,7 @@ that saves assigned data to the database. Skip if not serializing onto a given object. If db_obj is given, this function will convert lists, dicts and sets to their - `_SaverList`, `_SaverDict` and `_SaverSet` counterparts. + _SaverList, _SaverDict and _SaverSet counterparts. Returns: data (any): Unpickled data. @@ -832,7 +833,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -851,6 +851,7 @@ +
        develop branch
        @@ -42,56 +43,52 @@ """ EvEditor (Evennia Line Editor) -This implements an advanced line editor for editing longer texts -in-game. The editor mimics the command mechanisms of the "VI" editor -(a famous line-by-line editor) as far as reasonable. +This implements an advanced line editor for editing longer texts in-game. The +editor mimics the command mechanisms of the "VI" editor (a famous line-by-line +editor) as far as reasonable. Features of the editor: - - undo/redo. - - edit/replace on any line of the buffer. - - search&replace text anywhere in buffer. - - formatting of buffer, or selection, to certain width + indentations. - - allow to echo the input or not, depending on your client. +- undo/redo. +- edit/replace on any line of the buffer. +- search&replace text anywhere in buffer. +- formatting of buffer, or selection, to certain width + indentations. +- allow to echo the input or not, depending on your client. +- in-built help -To use the editor, just import EvEditor from this module -and initialize it: -:: +To use the editor, just import EvEditor from this module and initialize it: - from evennia.utils.eveditor import EvEditor - EvEditor(caller, loadfunc=None, savefunc=None, quitfunc=None, key="", persistent=True) +```python +from evennia.utils.eveditor import EvEditor -- `caller` is the user of the editor, the one to see all feedback. -- `loadfunc(caller)` is called when the editor is first launched; the - return from this function is loaded as the starting buffer in the - editor. -- `safefunc(caller, buffer)` is called with the current buffer when - saving in the editor. The function should return True/False depending - on if the saving was successful or not. -- `quitfunc(caller)` is called when the editor exits. If this is given, - no automatic quit messages will be given. -- `key` is an optional identifier for the editing session, to be - displayed in the editor. -- `persistent` means the editor state will be saved to the database making it - survive a server reload. Note that using this mode, the load- save- - and quit-funcs must all be possible to pickle - notable unusable - callables are class methods and functions defined inside other - functions. With persistent=False, no such restriction exists. -- `code` set to True activates features on the EvEditor to enter Python code. +# set up an editor to edit the caller's 'desc' Attribute +def _loadfunc(caller): + return caller.db.desc -In addition, the EvEditor can be used to enter Python source code, -and offers basic handling of indentation. +def _savefunc(caller, buffer): + caller.db.desc = buffer.strip() + return True ----- +def _quitfunc(caller): + caller.msg("Custom quit message") + +# start the editor +EvEditor(caller, loadfunc=None, savefunc=None, quitfunc=None, key="", + persistent=True, code=False) +``` + +The editor can also be used to format Python code and be made to +survive a reload. See the `EvEditor` class for more details. """ import re from django.conf import settings -from evennia import Command, CmdSet +from evennia import CmdSet from evennia.utils import is_iter, fill, dedent, logger, justify, to_str, utils from evennia.utils.ansi import raw from evennia.commands import cmdhandler +from django.utils.translation import gettext as _ # we use cmdhandler instead of evennia.syscmdkeys to # avoid some cases of loading before evennia init'd @@ -109,7 +106,7 @@ # # ------------------------------------------------------------- -_HELP_TEXT = """ +_HELP_TEXT = _(""" <txt> - any non-command is appended to the end of the buffer. : <l> - view buffer or only line(s) <l> :: <l> - raw-view buffer or only line(s) <l> @@ -145,66 +142,66 @@ :fd <l> - de-indent entire buffer or line <l> :echo - turn echoing of the input on/off (helpful for some clients) -""" +""") -_HELP_LEGEND = """ +_HELP_LEGEND = _(""" Legend: <l> - line number, like '5' or range, like '3:7'. <w> - a single word, or multiple words with quotes around them. <txt> - longer string, usually not needing quotes. -""" +""") -_HELP_CODE = """ +_HELP_CODE = _(""" :! - Execute code buffer without saving :< - Decrease the level of automatic indentation for the next lines :> - Increase the level of automatic indentation for the next lines := - Switch automatic indentation on/off """.lstrip( "\n" -) +)) -_ERROR_LOADFUNC = """ +_ERROR_LOADFUNC = _(""" {error} |rBuffer load function error. Could not load initial data.|n -""" +""") -_ERROR_SAVEFUNC = """ +_ERROR_SAVEFUNC = _(""" {error} |rSave function returned an error. Buffer not saved.|n -""" +""") -_ERROR_NO_SAVEFUNC = "|rNo save function defined. Buffer cannot be saved.|n" +_ERROR_NO_SAVEFUNC = _("|rNo save function defined. Buffer cannot be saved.|n") -_MSG_SAVE_NO_CHANGE = "No changes need saving" -_DEFAULT_NO_QUITFUNC = "Exited editor." +_MSG_SAVE_NO_CHANGE = _("No changes need saving") +_DEFAULT_NO_QUITFUNC = _("Exited editor.") -_ERROR_QUITFUNC = """ +_ERROR_QUITFUNC = _(""" {error} |rQuit function gave an error. Skipping.|n -""" +""") -_ERROR_PERSISTENT_SAVING = """ +_ERROR_PERSISTENT_SAVING = _(""" {error} |rThe editor state could not be saved for persistent mode. Switching to non-persistent mode (which means the editor session won't survive an eventual server reload - so save often!)|n -""" +""") -_TRACE_PERSISTENT_SAVING = ( +_TRACE_PERSISTENT_SAVING = _( "EvEditor persistent-mode error. Commonly, this is because one or " "more of the EvEditor callbacks could not be pickled, for example " "because it's a class method or is defined inside another function." ) -_MSG_NO_UNDO = "Nothing to undo." -_MSG_NO_REDO = "Nothing to redo." -_MSG_UNDO = "Undid one step." -_MSG_REDO = "Redid one step." +_MSG_NO_UNDO = _("Nothing to undo.") +_MSG_NO_REDO = _("Nothing to redo.") +_MSG_UNDO = _("Undid one step.") +_MSG_REDO = _("Redid one step.") # ------------------------------------------------------------- # @@ -226,7 +223,10 @@ help_cateogory = "LineEditor"
        [docs] def func(self): - """Implement the yes/no choice.""" + """ + Implement the yes/no choice. + + """ # this is only called from inside the lineeditor # so caller.ndb._lineditor must be set. @@ -241,7 +241,10 @@
        [docs]class SaveYesNoCmdSet(CmdSet): - """Stores the yesno question""" + """ + Stores the yesno question + + """ key = "quitsave_yesno" priority = 150 # override other cmdsets. @@ -271,17 +274,18 @@
        [docs] def parse(self): """ - Handles pre-parsing + Handles pre-parsing. Editor commands are on the form + + :: - Usage: :cmd [li] [w] [txt] Where all arguments are optional. - - li - line number (int), starting from 1. This could also - be a range given as <l>:<l>. - - w - word(s) (string), could be encased in quotes. - - txt - extra text (string), could be encased in quotes. + - `li` - line number (int), starting from 1. This could also + be a range given as <l>:<l>. + - `w` - word(s) (string), could be encased in quotes. + - `txt` - extra text (string), could be encased in quotes. """ @@ -376,6 +380,7 @@ def _load_editor(caller): """ Load persistent editor from storage. + """ saved_options = caller.attributes.get("_eveditor_saved") saved_buffer, saved_undo = caller.attributes.get("_eveditor_buffer_temp", (None, None)) @@ -401,6 +406,7 @@
        [docs]class CmdLineInput(CmdEditorBase): """ No command match - Inputs line of text into buffer. + """ key = _CMD_NOMATCH @@ -485,6 +491,7 @@ This command handles all the in-editor :-style commands. Since each command is small and very limited, this makes for a more efficient presentation. + """ caller = self.caller editor = caller.ndb._eveditor @@ -512,7 +519,7 @@ # Insert single colon alone on a line editor.update_buffer([":"] if lstart == 0 else linebuffer + [":"]) if echo_mode: - caller.msg("Single ':' added to buffer.") + caller.msg(_("Single ':' added to buffer.")) elif cmd == ":h": # help entry editor.display_help() @@ -527,7 +534,7 @@ # quit. If not saved, will ask if self.editor._unsaved: caller.cmdset.add(SaveYesNoCmdSet) - caller.msg("Save before quitting? |lcyes|lt[Y]|le/|lcno|ltN|le") + caller.msg(_("Save before quitting?") + " |lcyes|lt[Y]|le/|lcno|ltN|le") else: editor.quit() elif cmd == ":q!": @@ -542,24 +549,26 @@ elif cmd == ":UU": # reset buffer editor.update_buffer(editor._pristine_buffer) - caller.msg("Reverted all changes to the buffer back to original state.") + caller.msg(_("Reverted all changes to the buffer back to original state.")) elif cmd == ":dd": # :dd <l> - delete line <l> buf = linebuffer[:lstart] + linebuffer[lend:] editor.update_buffer(buf) - caller.msg("Deleted %s." % self.lstr) + caller.msg(_("Deleted {string}.").format(string=self.lstr)) elif cmd == ":dw": # :dw <w> - delete word in entire buffer # :dw <l> <w> delete word only on line(s) <l> if not self.arg1: - caller.msg("You must give a search word to delete.") + caller.msg(_("You must give a search word to delete.")) else: if not self.linerange: lstart = 0 lend = self.cline + 1 - caller.msg("Removed %s for lines %i-%i." % (self.arg1, lstart + 1, lend + 1)) + caller.msg(_("Removed {arg1} for lines {l1}-{l2}.").format( + arg1=self.arg1, l1=lstart + 1, l2=lend + 1)) else: - caller.msg("Removed %s for %s." % (self.arg1, self.lstr)) + caller.msg(_("Removed {arg1} for {line}.").format( + arg1=self.arg1, line=self.lstr)) sarea = "\n".join(linebuffer[lstart:lend]) sarea = re.sub(r"%s" % self.arg1.strip("'").strip('"'), "", sarea, re.MULTILINE) buf = linebuffer[:lstart] + sarea.split("\n") + linebuffer[lend:] @@ -574,49 +583,52 @@ editor._indent = 0 if editor._persistent: caller.attributes.add("_eveditor_indent", 0) - caller.msg("Cleared %i lines from buffer." % self.nlines) + caller.msg(_("Cleared {nlines} lines from buffer.").format(nlines=self.nlines)) elif cmd == ":y": # :y <l> - yank line(s) to copy buffer cbuf = linebuffer[lstart:lend] editor._copy_buffer = cbuf - caller.msg("%s, %s yanked." % (self.lstr.capitalize(), cbuf)) + caller.msg(_("{line}, {cbuf} yanked.").format(line=self.lstr.capitalize(), cbuf=cbuf)) elif cmd == ":x": # :x <l> - cut line to copy buffer cbuf = linebuffer[lstart:lend] editor._copy_buffer = cbuf buf = linebuffer[:lstart] + linebuffer[lend:] editor.update_buffer(buf) - caller.msg("%s, %s cut." % (self.lstr.capitalize(), cbuf)) + caller.msg(_("{line}, {cbuf} cut.").format(line=self.lstr.capitalize(), cbuf=cbuf)) elif cmd == ":p": # :p <l> paste line(s) from copy buffer if not editor._copy_buffer: - caller.msg("Copy buffer is empty.") + caller.msg(_("Copy buffer is empty.")) else: buf = linebuffer[:lstart] + editor._copy_buffer + linebuffer[lstart:] editor.update_buffer(buf) - caller.msg("Pasted buffer %s to %s." % (editor._copy_buffer, self.lstr)) + caller.msg(_("Pasted buffer {cbuf} to {line}.").format( + cbuf=editor._copy_buffer, line=self.lstr)) elif cmd == ":i": # :i <l> <txt> - insert new line new_lines = self.args.split("\n") if not new_lines: - caller.msg("You need to enter a new line and where to insert it.") + caller.msg(_("You need to enter a new line and where to insert it.")) else: buf = linebuffer[:lstart] + new_lines + linebuffer[lstart:] editor.update_buffer(buf) - caller.msg("Inserted %i new line(s) at %s." % (len(new_lines), self.lstr)) + caller.msg(_("Inserted {num} new line(s) at {line}.").format( + num=len(new_lines), line=self.lstr)) elif cmd == ":r": # :r <l> <txt> - replace lines new_lines = self.args.split("\n") if not new_lines: - caller.msg("You need to enter a replacement string.") + caller.msg(_("You need to enter a replacement string.")) else: buf = linebuffer[:lstart] + new_lines + linebuffer[lend:] editor.update_buffer(buf) - caller.msg("Replaced %i line(s) at %s." % (len(new_lines), self.lstr)) + caller.msg(_("Replaced {num} line(s) at {line}.").format( + num=len(new_lines), line=self.lstr)) elif cmd == ":I": # :I <l> <txt> - insert text at beginning of line(s) <l> if not self.raw_string and not editor._codefunc: - caller.msg("You need to enter text to insert.") + caller.msg(_("You need to enter text to insert.")) else: buf = ( linebuffer[:lstart] @@ -624,11 +636,11 @@ + linebuffer[lend:] ) editor.update_buffer(buf) - caller.msg("Inserted text at beginning of %s." % self.lstr) + caller.msg(_("Inserted text at beginning of {line}.").format(line=self.lstr)) elif cmd == ":A": # :A <l> <txt> - append text after end of line(s) if not self.args: - caller.msg("You need to enter text to append.") + caller.msg(_("You need to enter text to append.")) else: buf = ( linebuffer[:lstart] @@ -636,23 +648,24 @@ + linebuffer[lend:] ) editor.update_buffer(buf) - caller.msg("Appended text to end of %s." % self.lstr) + caller.msg(_("Appended text to end of {line}.").format(line=self.lstr)) elif cmd == ":s": # :s <li> <w> <txt> - search and replace words # in entire buffer or on certain lines if not self.arg1 or not self.arg2: - caller.msg("You must give a search word and something to replace it with.") + caller.msg(_("You must give a search word and something to replace it with.")) else: if not self.linerange: lstart = 0 lend = self.cline + 1 caller.msg( - "Search-replaced %s -> %s for lines %i-%i." - % (self.arg1, self.arg2, lstart + 1, lend) + _("Search-replaced {arg1} -> {arg2} for lines {l1}-{l2}.").format( + arg1=self.arg1, arg2=self.arg2, l1=lstart + 1, l2=lend) ) else: caller.msg( - "Search-replaced %s -> %s for %s." % (self.arg1, self.arg2, self.lstr) + _("Search-replaced {arg1} -> {arg2} for {line}.").format( + arg1=self.arg1, arg2=self.arg2, line=self.lstr) ) sarea = "\n".join(linebuffer[lstart:lend]) @@ -674,9 +687,10 @@ if not self.linerange: lstart = 0 lend = self.cline + 1 - caller.msg("Flood filled lines %i-%i." % (lstart + 1, lend)) + caller.msg(_("Flood filled lines {l1}-{l2}.").format( + l1=lstart + 1, l2=lend)) else: - caller.msg("Flood filled %s." % self.lstr) + caller.msg(_("Flood filled {line}.").format(line=self.lstr)) fbuf = "\n".join(linebuffer[lstart:lend]) fbuf = fill(fbuf, width=width) buf = linebuffer[:lstart] + fbuf.split("\n") + linebuffer[lend:] @@ -698,16 +712,19 @@ width = _DEFAULT_WIDTH if self.arg1 and self.arg1.lower() not in align_map: self.caller.msg( - "Valid justifications are [f]ull (default), [c]enter, [r]right or [l]eft" + _("Valid justifications are") + + " [f]ull (default), [c]enter, [r]right or [l]eft" ) return align = align_map[self.arg1.lower()] if self.arg1 else "f" if not self.linerange: lstart = 0 lend = self.cline + 1 - self.caller.msg("%s-justified lines %i-%i." % (align_name[align], lstart + 1, lend)) + self.caller.msg(_("{align}-justified lines {l1}-{l2}.").format( + align=align_name[align], l1=lstart + 1, l2=lend)) else: - self.caller.msg("%s-justified %s." % (align_name[align], self.lstr)) + self.caller.msg(_("{align}-justified {line}.").format( + align=align_name[align], line=self.lstr)) jbuf = "\n".join(linebuffer[lstart:lend]) jbuf = justify(jbuf, width=width, align=align) buf = linebuffer[:lstart] + jbuf.split("\n") + linebuffer[lend:] @@ -718,9 +735,9 @@ if not self.linerange: lstart = 0 lend = self.cline + 1 - caller.msg("Indented lines %i-%i." % (lstart + 1, lend)) + caller.msg(_("Indented lines {l1}-{l2}.").format(l1=lstart + 1, l2=lend)) else: - caller.msg("Indented %s." % self.lstr) + caller.msg(_("Indented {line}.").format(line=self.lstr)) fbuf = [indent + line for line in linebuffer[lstart:lend]] buf = linebuffer[:lstart] + fbuf + linebuffer[lend:] editor.update_buffer(buf) @@ -729,9 +746,10 @@ if not self.linerange: lstart = 0 lend = self.cline + 1 - caller.msg("Removed left margin (dedented) lines %i-%i." % (lstart + 1, lend)) + caller.msg(_("Removed left margin (dedented) lines {l1}-{l2}.").format( + l1=lstart + 1, l2=lend)) else: - caller.msg("Removed left margin (dedented) %s." % self.lstr) + caller.msg(_("Removed left margin (dedented) {line}.").format(line=self.lstr)) fbuf = "\n".join(linebuffer[lstart:lend]) fbuf = dedent(fbuf) buf = linebuffer[:lstart] + fbuf.split("\n") + linebuffer[lend:] @@ -739,45 +757,49 @@ elif cmd == ":echo": # set echoing on/off editor._echo_mode = not editor._echo_mode - caller.msg("Echo mode set to %s" % editor._echo_mode) + caller.msg(_("Echo mode set to {mode}").format(mode=editor._echo_mode)) elif cmd == ":!": if editor._codefunc: editor._codefunc(caller, editor._buffer) else: - caller.msg("This command is only available in code editor mode.") + caller.msg(_("This command is only available in code editor mode.")) elif cmd == ":<": # :< if editor._codefunc: editor.decrease_indent() indent = editor._indent if indent >= 0: - caller.msg("Decreased indentation: new indentation is {}.".format(indent)) + caller.msg(_( + "Decreased indentation: new indentation is {indent}.").format( + indent=indent)) else: - caller.msg("|rManual indentation is OFF.|n Use := to turn it on.") + caller.msg(_("|rManual indentation is OFF.|n Use := to turn it on.")) else: - caller.msg("This command is only available in code editor mode.") + caller.msg(_("This command is only available in code editor mode.")) elif cmd == ":>": # :> if editor._codefunc: editor.increase_indent() indent = editor._indent if indent >= 0: - caller.msg("Increased indentation: new indentation is {}.".format(indent)) + caller.msg(_( + "Increased indentation: new indentation is {indent}.").format( + indent=indent)) else: - caller.msg("|rManual indentation is OFF.|n Use := to turn it on.") + caller.msg(_("|rManual indentation is OFF.|n Use := to turn it on.")) else: - caller.msg("This command is only available in code editor mode.") + caller.msg(_("This command is only available in code editor mode.")) elif cmd == ":=": # := if editor._codefunc: editor.swap_autoindent() indent = editor._indent if indent >= 0: - caller.msg("Auto-indentation turned on.") + caller.msg(_("Auto-indentation turned on.")) else: - caller.msg("Auto-indentation turned off.") + caller.msg(_("Auto-indentation turned off.")) else: - caller.msg("This command is only available in code editor mode.")
        + caller.msg(_("This command is only available in code editor mode."))
        [docs]class EvEditorCmdSet(CmdSet): @@ -798,7 +820,7 @@ # ------------------------------------------------------------- -
        [docs]class EvEditor(object): +
        [docs]class EvEditor: """ This defines a line editor object. It creates all relevant commands and tracks the current state of the buffer. It also cleans up after @@ -924,12 +946,13 @@
        [docs] def load_buffer(self): """ Load the buffer using the load function hook. + """ try: self._buffer = self._loadfunc(self._caller) if not isinstance(self._buffer, str): self._buffer = to_str(self._buffer) - self._caller.msg("|rNote: input buffer was converted to a string.|n") + self._caller.msg(_("|rNote: input buffer was converted to a string.|n")) except Exception as e: from evennia.utils import logger @@ -1066,7 +1089,7 @@ header = ( "|n" + sep * 10 - + "Line Editor [%s]" % self._key + + _("Line Editor [{name}]").format(name=self._key) + sep * (_DEFAULT_WIDTH - 24 - len(self._key)) ) footer = ( @@ -1074,7 +1097,7 @@ + sep * 10 + "[l:%02i w:%03i c:%04i]" % (nlines, nwords, nchars) + sep * 12 - + "(:h for help)" + + _("(:h for help)") + sep * (_DEFAULT_WIDTH - 54) ) if linenums: @@ -1195,7 +1218,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1214,6 +1236,7 @@ +
        develop branch
        @@ -54,32 +55,34 @@ object when displaying the form. Example of input file `testform.py`: -:: - FORMCHAR = "x" - TABLECHAR = "c" +```python +FORMCHAR = "x" +TABLECHAR = "c" - FORM = ''' - .------------------------------------------------. - | | - | Name: xxxxx1xxxxx Player: xxxxxxx2xxxxxxx | - | xxxxxxxxxxx | - | | - >----------------------------------------------< - | | - | Desc: xxxxxxxxxxx STR: x4x DEX: x5x | - | xxxxx3xxxxx INT: x6x STA: x7x | - | xxxxxxxxxxx LUC: x8x MAG: x9x | - | | - >----------------------------------------------< - | | | - | cccccccc | ccccccccccccccccccccccccccccccccccc | - | cccccccc | ccccccccccccccccccccccccccccccccccc | - | cccAcccc | ccccccccccccccccccccccccccccccccccc | - | cccccccc | ccccccccccccccccccccccccccccccccccc | - | cccccccc | cccccccccccccccccBccccccccccccccccc | - | | | - ------------------------------------------------- +FORM = ''' +.------------------------------------------------. +| | +| Name: xxxxx1xxxxx Player: xxxxxxx2xxxxxxx | +| xxxxxxxxxxx | +| | + >----------------------------------------------< +| | +| Desc: xxxxxxxxxxx STR: x4x DEX: x5x | +| xxxxx3xxxxx INT: x6x STA: x7x | +| xxxxxxxxxxx LUC: x8x MAG: x9x | +| | + >----------------------------------------------< +| | | +| cccccccc | ccccccccccccccccccccccccccccccccccc | +| cccccccc | ccccccccccccccccccccccccccccccccccc | +| cccAcccc | ccccccccccccccccccccccccccccccccccc | +| cccccccc | ccccccccccccccccccccccccccccccccccc | +| cccccccc | cccccccccccccccccBccccccccccccccccc | +| | | +------------------------------------------------- +''' +``` The first line of the `FORM` string is ignored. The forms and table markers must mark out complete, unbroken rectangles, each containing @@ -93,8 +96,8 @@ Use as follows: -:: +```python from evennia import EvForm, EvTable # create a new form from the template @@ -126,9 +129,10 @@ "B": tableB}) print(form) - +``` This produces the following result: + :: .------------------------------------------------. @@ -152,7 +156,6 @@ | | | ------------------------------------------------ - The marked forms have been replaced with EvCells of text and with EvTables. The form can be updated by simply re-applying `form.map()` with the updated data. @@ -230,15 +233,16 @@
        [docs] def __init__(self, filename=None, cells=None, tables=None, form=None, **kwargs): """ - Initiate the form. + Initiate the form Keyword Args: filename (str): Path to template file. - cells (dict): A dictionary mapping of `{id:text}`. - tables (dict): A dictionary mapping of `{id:EvTable}`. - form (dict): A dictionary of - `{"FORMCHAR":char, "TABLECHAR":char, "FORM":templatestring}`. - if this is given, filename is not read. + cells (dict): A dictionary mapping `{id: text}` + tables (dict): A dictionary mapping `{id: EvTable}`. + form (dict): A dictionary + `{"FORMCHAR":char, "TABLECHAR":char, "FORM":templatestring}`. + If this is given, filename is not read. + Notes: Other kwargs are fed as options to the EvCells and EvTables (see `evtable.EvCell` and `evtable.EvTable` for more info). @@ -541,7 +545,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -560,6 +563,7 @@ +
        develop branch
        @@ -40,12 +41,14 @@

        Source code for evennia.utils.evmenu

         """
        -The EvMenu is a full in-game menu system for Evennia.
        +EvMenu
        +
        +This implements a full menu system for Evennia.
         
         To start the menu, just import the EvMenu class from this module.
        -
         Example usage:
        -::
        +
        +```python
         
             from evennia.utils.evmenu import EvMenu
         
        @@ -53,10 +56,11 @@
                  startnode="node1",
                  cmdset_mergetype="Replace", cmdset_priority=1,
                  auto_quit=True, cmd_on_exit="look", persistent=True)
        +```
         
         Where `caller` is the Object to use the menu on - it will get a new
        -cmdset while using the Menu. The `menu_module_path` is the python path
        -to a python module containing function definitions. By adjusting the
        +cmdset while using the Menu. The menu_module_path is the python path
        +to a python module containing function definitions.  By adjusting the
         keyword options of the Menu() initialization call you can start the
         menu at different places in the menu definition file, adjust if the
         menu command should overload the normal commands or not, etc.
        @@ -70,7 +74,8 @@
         
         The menu is defined in a module (this can be the same module as the
         command definition too) with function definitions:
        -::
        +
        +```python
         
             def node1(caller):
                 # (this is the start node if called like above)
        @@ -84,8 +89,9 @@
             def another_node(caller, input_string, **kwargs):
                 # code
                 return text, options
        +```
         
        -Where `caller` is the object using the menu and input_string is the
        +Where caller is the object using the menu and input_string is the
         command entered by the user on the *previous* node (the command
         entered to get to this node). The node function code will only be
         executed once per node-visit and the system will accept nodes with
        @@ -102,42 +108,42 @@
         menu is immediately exited and the default "look" command is called.
         
         - `text` (str, tuple or None): Text shown at this node. If a tuple, the
        -  second element in the tuple is a help text to display at this
        -  node when the user enters the menu help command there.
        +   second element in the tuple is a help text to display at this
        +   node when the user enters the menu help command there.
         - `options` (tuple, dict or None): If `None`, this exits the menu.
           If a single dict, this is a single-option node. If a tuple,
        -  it should be a tuple of option dictionaries. Option dicts have
        -  the following keys:
        +  it should be a tuple of option dictionaries. Option dicts have the following keys:
         
           - `key` (str or tuple, optional): What to enter to choose this option.
        -      If a tuple, it must be a tuple of strings, where the first string is the
        -      key which will be shown to the user and the others are aliases.
        -      If unset, the options' number will be used. The special key `_default`
        -      marks this option as the default fallback when no other option matches
        -      the user input. There can only be one `_default` option per node. It
        -      will not be displayed in the list.
        +    If a tuple, it must be a tuple of strings, where the first string is the
        +    key which will be shown to the user and the others are aliases.
        +    If unset, the options' number will be used. The special key `_default`
        +    marks this option as the default fallback when no other option matches
        +    the user input. There can only be one `_default` option per node. It
        +    will not be displayed in the list.
           - `desc` (str, optional): This describes what choosing the option will do.
           - `goto` (str, tuple or callable): If string, should be the name of node to go to
        -      when this option is selected. If a callable, it has the signature
        -      `callable(caller[,raw_input][,**kwargs])`. If a tuple, the first element
        -      is the callable and the second is a dict with the kwargs to pass to
        -      the callable. Those kwargs will also be passed into the next node if possible.
        -      Such a callable should return either a str or a (str, dict), where the
        -      string is the name of the next node to go to and the dict is the new,
        -      (possibly modified) kwarg to pass into the next node. If the callable returns
        -      None or the empty string, the current node will be revisited.
        +    when this option is selected. If a callable, it has the signature
        +    `callable(caller[,raw_input][,**kwargs])`. If a tuple, the first element
        +    is the callable and the second is a dict with the `**kwargs` to pass to
        +    the callable. Those kwargs will also be passed into the next node if possible.
        +    Such a callable should return either a str or a (str, dict), where the
        +    string is the name of the next node to go to and the dict is the new,
        +    (possibly modified) kwarg to pass into the next node. If the callable returns
        +    None or the empty string, the current node will be revisited.
           - `exec` (str, callable or tuple, optional): This takes the same input as `goto` above
        -      and runs before it. If given a node name, the node will be executed but will not
        -      be considered the next node. If node/callback returns str or (str, dict), these will
        -      replace the `goto` step (`goto` callbacks will not fire), with the string being the
        -      next node name and the optional dict acting as the kwargs-input for the next node.
        -      If an exec callable returns `None`, the current node is re-run.
        +    and runs before it. If given a node name, the node will be executed but will not
        +    be considered the next node. If node/callback returns str or (str, dict), these will
        +    replace the `goto` step (`goto` callbacks will not fire), with the string being the
        +    next node name and the optional dict acting as the kwargs-input for the next node.
        +    If an exec callable returns the empty string (only), the current node is re-run.
         
        -If key is not given, the option will automatically be identified by
        +If `key` is not given, the option will automatically be identified by
         its number 1..N.
         
         Example:
        -::
        +
        +```python
         
             # in menu_module.py
         
        @@ -173,8 +179,11 @@
                 text = "This ends the menu since there are no options."
                 return text, None
         
        +```
        +
         When starting this menu with  `Menu(caller, "path.to.menu_module")`,
         the first node will look something like this:
        +
         ::
         
             This is a node text
        @@ -193,9 +202,8 @@
         reaching a node without any options.
         
         
        -For a menu demo, import CmdTestMenu from this module and add it to
        -your default cmdset. Run it with this module, like `testmenu
        -evennia.utils.evmenu`.
        +For a menu demo, import `CmdTestMenu` from this module and add it to
        +your default cmdset. Run it with this module, like `testmenu evennia.utils.evmenu`.
         
         
         ## Menu generation from template string
        @@ -211,10 +219,13 @@
         For maximum flexibility you can inject normally-created nodes in the menu tree
         before passing it to EvMenu. If that's not needed, you can also create a menu
         in one step with:
        -::
        +
        +```python
         
             evmenu.template2menu(caller, menu_template, goto_callables)
         
        +```
        +
         The `goto_callables` is a mapping `{"funcname": callable, ...}`, where each
         callable must be a module-global function on the form
         `funcname(caller, raw_string, **kwargs)` (like any goto-callable). The
        @@ -292,9 +303,9 @@
         key:values will be converted to strings/numbers with literal_eval before passed
         into the callable.
         
        -The "> " option takes a glob or regex to perform different actions depending on user
        -input. Make sure to sort these in increasing order of generality since they
        -will be tested in sequence.
        +The \\> option takes a glob or regex to perform different actions depending
        +on user input. Make sure to sort these in increasing order of generality since
        +they will be tested in sequence.
         
         ----
         
        @@ -446,7 +457,8 @@
                             )  # don't give the session as a kwarg here, direct to original
                             raise EvMenuError(err)
                 # we must do this after the caller with the menu has been correctly identified since it
        -        # can be either Account, Object or Session (in the latter case this info will be superfluous).
        +        # can be either Account, Object or Session (in the latter case this info will be
        +        # superfluous).
                 caller.ndb._evmenu._session = self.session
                 # we have a menu, use it.
                 menu.parse_input(self.raw_string)
        @@ -573,9 +585,7 @@ by default in all nodes of the menu. This will print out the current state of the menu. Deactivate for production use! When the debug flag is active, the `persistent` flag is deactivated. - - Keyword Args: - any (any): All kwargs will become initialization variables on `caller.ndb._evmenu`, + **kwargs: All kwargs will become initialization variables on `caller.ndb._menutree`, to be available at run. Raises: @@ -652,7 +662,8 @@ ).intersection(set(kwargs.keys())) if reserved_clash: raise RuntimeError( - f"One or more of the EvMenu `**kwargs` ({list(reserved_clash)}) is reserved by EvMenu for internal use." + f"One or more of the EvMenu `**kwargs` ({list(reserved_clash)}) " + "is reserved by EvMenu for internal use." ) for key, val in kwargs.items(): setattr(self, key, val) @@ -775,30 +786,6 @@ Call a node-like callable, with a variable number of raw_string, *args, **kwargs, all of which should work also if not present (only `caller` is always required). Return its result. - Viable node-like callable forms: - :: - - _callname(caller) - _callname(caller, raw_string) - _callname(caller, **kwargs) - _callname(caller, raw_string, **kwargs) - - If this is a node: - - - `caller` is the one using the menu. - - `raw_string` is the users exact input on the *previous* node. - - `**kwargs` is either passed through the previous node or returned - along with the node name from the goto-callable leading to this node. - - If this is a goto-callable: - - - `caller` is the one using the menu. - - `raw_string` is the user's exact input when chosing the option that triggered - this goto-callable. - - `**kwargs` is any extra dict passed to the callable in the option - definition, or (if no explit kwarg was given to the callable) the - previous node's kwarg, if any. - """ try: try: @@ -1003,8 +990,7 @@ raw_string (str): The raw default string entered on the previous node (only used if the node accepts it as an argument) - Keyword Args: - any: Extra arguments to goto callables. + **kwargs: Extra arguments to goto callables. """ @@ -1320,7 +1306,7 @@ table.extend([" " for i in range(nrows - nlastcol)]) # build the actual table grid - table = [table[icol * nrows : (icol * nrows) + nrows] for icol in range(0, ncols)] + table = [table[icol * nrows: (icol * nrows) + nrows] for icol in range(0, ncols)] # adjust the width of each column for icol in range(len(table)): @@ -1377,33 +1363,50 @@ option_generator (callable or list): A list of strings indicating the options, or a callable that is called as option_generator(caller) to produce such a list. select (callable or str, optional): Node to redirect a selection to. Its `**kwargs` will - contain the `available_choices` list and `selection` will hold one - of the elements in that list. If a callable, it will be called as - `select(caller, menuchoice, **kwargs)` where menuchoice is the - chosen option as a string and `available_choices` is the list of available - options offered by the option_generator. The callable whould return - the name of the target node to goto after this selection (or None to repeat the - list-node). Note that if this is not given, the decorated node - must itself provide a way to continue from the node! + contain the `available_choices` list and `selection` will hold one of the elements in + that list. If a callable, it will be called as + `select(caller, menuchoice, **kwargs)` where menuchoice is the chosen option as a + string and `available_choices` is a kwarg mapping the option keys to the choices + offered by the option_generator. The callable whould return the name of the target node + to goto after this selection (or None to repeat the list-node). Note that if this is not + given, the decorated node must itself provide a way to continue from the node! pagesize (int): How many options to show per page. Example: - :: - def _selectfunc(caller, menuchoice, **kwargs): - # menuchoice would be either 'foo' or 'bar' here - # kwargs['available_choices'] would be the list ['foo', 'bar'] - return "the_next_node_to_go_to" + ```python + def select(caller, selection, available_choices=None, **kwargs): + ''' + Args: + caller (Object or Account): User of the menu. + selection (str): What caller chose in the menu + available_choices (list): The keys of elements available on the *current listing + page*. + **kwargs: Kwargs passed on from the node. + Returns: + tuple, str or None: A tuple (nextnodename, **kwargs) or just nextnodename. Return + `None` to go back to the listnode. - @list_node(['foo', 'bar'], _selectfunc) - def node_index(caller): - text = "describing the list" - return text, [] + # (do something with `selection` here) + + return "nextnode", **kwargs + + @list_node(['foo', 'bar'], select) + def node_index(caller): + text = "describing the list" + + # optional extra options in addition to the list-options + extra_options = [] + + return text, extra_options + + ``` Notes: - All normal `goto` or `exec` callables returned from the decorated nodes will, if they accept - `**kwargs`, get a new kwarg `available_choices` injected. This is the ordered list of named - options (descs) visible on the current node page. + All normal `goto` or `exec` callables returned from the decorated nodes + will, if they accept `**kwargs`, get a new kwarg 'available_choices' + injected. These are the ordered list of named options (descs) visible + on the current node page. """ @@ -1411,6 +1414,7 @@ def _select_parser(caller, raw_string, **kwargs): """ Parse the select action + """ available_choices = kwargs.get("available_choices", []) @@ -1418,14 +1422,15 @@ index = int(raw_string.strip()) - 1 selection = available_choices[index] except Exception: - caller.msg("|rInvalid choice.|n") + caller.msg(_("|rInvalid choice.|n")) else: if callable(select): try: if bool(getargspec(select).keywords): - return select(caller, selection, available_choices=available_choices) + return select( + caller, selection, available_choices=available_choices, **kwargs) else: - return select(caller, selection) + return select(caller, selection, **kwargs) except Exception: logger.log_trace() elif select: @@ -1450,7 +1455,7 @@ if option_list: nall_options = len(option_list) pages = [ - option_list[ind : ind + pagesize] for ind in range(0, nall_options, pagesize) + option_list[ind: ind + pagesize] for ind in range(0, nall_options, pagesize) ] npages = len(pages) @@ -1464,7 +1469,7 @@ # callback being called with a result from the available choices options.extend( [ - {"desc": opt, "goto": (_select_parser, {"available_choices": page})} + {"desc": opt, "goto": (_select_parser, {"available_choices": page, **kwargs})} for opt in page ] ) @@ -1475,7 +1480,7 @@ # allows us to call ourselves over and over, using different kwargs. options.append( { - "key": ("|Wcurrent|n", "c"), + "key": (_("|Wcurrent|n"), "c"), "desc": "|W({}/{})|n".format(page_index + 1, npages), "goto": (lambda caller: None, {"optionpage_index": page_index}), } @@ -1483,14 +1488,14 @@ if page_index > 0: options.append( { - "key": ("|wp|Wrevious page|n", "p"), + "key": (_("|wp|Wrevious page|n"), "p"), "goto": (lambda caller: None, {"optionpage_index": page_index - 1}), } ) if page_index < npages - 1: options.append( { - "key": ("|wn|Wext page|n", "n"), + "key": (_("|wn|Wext page|n"), "n"), "goto": (lambda caller: None, {"optionpage_index": page_index + 1}), } ) @@ -1616,7 +1621,7 @@ self.add(CmdGetInput())
        -class _Prompt(object): +class _Prompt: """Dummy holder""" pass @@ -1624,60 +1629,51 @@
        [docs]def get_input(caller, prompt, callback, session=None, *args, **kwargs): """ - This is a helper function for easily request input from - the caller. + This is a helper function for easily request input from the caller. Args: - caller (Account or Object): The entity being asked - the question. This should usually be an object - controlled by a user. - prompt (str): This text will be shown to the user, - in order to let them know their input is needed. + caller (Account or Object): The entity being asked the question. This + should usually be an object controlled by a user. + prompt (str): This text will be shown to the user, in order to let them + know their input is needed. callback (callable): A function that will be called - when the user enters a reply. It must take three - arguments: the `caller`, the `prompt` text and the - `result` of the input given by the user. If the - callback doesn't return anything or return False, - the input prompt will be cleaned up and exited. If - returning True, the prompt will remain and continue to - accept input. + when the user enters a reply. It must take three arguments: the + `caller`, the `prompt` text and the `result` of the input given by + the user. If the callback doesn't return anything or return False, + the input prompt will be cleaned up and exited. If returning True, + the prompt will remain and continue to accept input. session (Session, optional): This allows to specify the - session to send the prompt to. It's usually only - needed if `caller` is an Account in multisession modes - greater than 2. The session is then updated by the - command and is available (for example in callbacks) - through `caller.ndb.getinput._session`. - args, kwargs (optional): Extra arguments will be - passed to the fall back function as a list 'args' - and all keyword arguments as a dictionary 'kwargs'. - To utilise `*args` and `**kwargs`, a value for the - session argument must be provided (None by default) - and the callback function must take `*args` and - `**kwargs` as arguments. + session to send the prompt to. It's usually only needed if `caller` + is an Account in multisession modes greater than 2. The session is + then updated by the command and is available (for example in + callbacks) through `caller.ndb.getinput._session`. + *args (any): Extra arguments to pass to `callback`. To utilise `*args` + (and `**kwargs`), a value for the `session` argument must also be + provided. + **kwargs (any): Extra kwargs to pass to `callback`. Raises: RuntimeError: If the given callback is not callable. Notes: - The result value sent to the callback is raw and not - processed in any way. This means that you will get - the ending line return character from most types of - client inputs. So make sure to strip that before - doing a comparison. + The result value sent to the callback is raw and not processed in any + way. This means that you will get the ending line return character from + most types of client inputs. So make sure to strip that before doing a + comparison. - When the prompt is running, a temporary object - `caller.ndb._getinput` is stored; this will be removed - when the prompt finishes. - If you need the specific Session of the caller (which - may not be easy to get if caller is an account in higher - multisession modes), then it is available in the - callback through `caller.ndb._getinput._session`. + When the prompt is running, a temporary object `caller.ndb._getinput` + is stored; this will be removed when the prompt finishes. - Chaining get_input functions will result in the caller - stacking ever more instances of InputCmdSets. Whilst - they will all be cleared on concluding the get_input - chain, EvMenu should be considered for anything beyond - a single question. + If you need the specific Session of the caller (which may not be easy + to get if caller is an account in higher multisession modes), then it + is available in the callback through `caller.ndb._getinput._session`. + This is why the `session` is required as input. + + It's not recommended to 'chain' `get_input` into a sequence of + questions. This will result in the caller stacking ever more instances + of InputCmdSets. While they will all be cleared on concluding the + get_input chain, EvMenu should be considered for anything beyond a + single question. """ if not callable(callback): @@ -1692,6 +1688,186 @@ caller.msg(prompt, session=session)
        +
        [docs]class CmdYesNoQuestion(Command): + """ + Handle a prompt for yes or no. Press [return] for the default choice. + + """ + + key = _CMD_NOINPUT + aliases = [_CMD_NOMATCH, "yes", "no", 'y', 'n', 'a', 'abort'] + arg_regex = r"^$" + + def _clean(self, caller): + del caller.ndb._yes_no_question + if not caller.cmdset.has(YesNoQuestionCmdSet) and hasattr(caller, "account"): + caller.account.cmdset.remove(YesNoQuestionCmdSet) + else: + caller.cmdset.remove(YesNoQuestionCmdSet) + +
        [docs] def func(self): + """This is called when user enters anything.""" + caller = self.caller + try: + yes_no_question = caller.ndb._yes_no_question + if not yes_no_question and hasattr(caller, "account"): + yes_no_question = caller.account.ndb._yes_no_question + caller = caller.account + + if not yes_no_question: + self._clean(caller) + return + + inp = self.cmdname + + if inp == _CMD_NOINPUT: + raw = self.raw_cmdname.strip() + if not raw: + # use default + inp = yes_no_question.default + else: + inp = raw + + if inp in ('a', 'abort') and yes_no_question.allow_abort: + caller.msg(_("Aborted.")) + self._clean(caller) + return + + caller.ndb._yes_no_question.session = self.session + + args = yes_no_question.args + kwargs = yes_no_question.kwargs + kwargs['caller_session'] = self.session + + if inp in ('yes', 'y'): + yes_no_question.yes_callable(caller, *args, **kwargs) + elif inp in ('no', 'n'): + yes_no_question.no_callable(caller, *args, **kwargs) + else: + # invalid input. Resend prompt without cleaning + caller.msg(yes_no_question.prompt, session=self.session) + return + + # cleanup + self._clean(caller) + except Exception: + # make sure to clean up cmdset if something goes wrong + caller.msg(_("|rError in ask_yes_no. Choice not confirmed (report to admin)|n")) + logger.log_trace("Error in ask_yes_no") + self._clean(caller) + raise
        + + +
        [docs]class YesNoQuestionCmdSet(CmdSet): + """ + This stores the input command + """ + + key = "yes_no_question_cmdset" + priority = 1 + mergetype = "Replace" + no_objs = True + no_exits = True + no_channels = False + +
        [docs] def at_cmdset_creation(self): + """called once at creation""" + self.add(CmdYesNoQuestion())
        + + +
        [docs]def ask_yes_no(caller, prompt="Yes or No {options}?", yes_action="Yes", no_action="No", + default=None, allow_abort=False, session=None, *args, **kwargs): + """ + A helper question for asking a simple yes/no question. This will cause + the system to pause and wait for input from the player. + + Args: + prompt (str): The yes/no question to ask. This takes an optional formatting + marker `{options}` which will be filled with 'Y/N', '[Y]/N' or + 'Y/[N]' depending on the setting of `default`. If `allow_abort` is set, + then the 'A(bort)' option will also be available. + yes_action (callable or str): If a callable, this will be called + with `(caller, *args, **kwargs)` when the Yes-choice is made. + If a string, this string will be echoed back to the caller. + no_action (callable or str): If a callable, this will be called + with `(caller, *args, **kwargs)` when the No-choice is made. + If a string, this string will be echoed back to the caller. + default (str optional): This is what the user will get if they just press the + return key without giving any input. One of 'N', 'Y', 'A' or `None` + for no default (an explicit choice must be given). If 'A' (abort) + is given, `allow_abort` kwarg is ignored and assumed set. + allow_abort (bool, optional): If set, the 'A(bort)' option is available + (a third option meaning neither yes or no but just exits the prompt). + session (Session, optional): This allows to specify the + session to send the prompt to. It's usually only needed if `caller` + is an Account in multisession modes greater than 2. The session is + then updated by the command and is available (for example in + callbacks) through `caller.ndb._yes_no_question.session`. + *args: Additional arguments passed on into callables. + **kwargs: Additional keyword args passed on into callables. + + Raises: + RuntimeError, FooError: If default and `allow_abort` clashes. + + Example: + :: + + # just returning strings + ask_yes_no(caller, "Are you happy {options}?", + "you answered yes", "you answered no") + # trigger callables + ask_yes_no(caller, "Are you sad {options}?", + _callable_yes, _callable_no, allow_abort=True) + + """ + def _callable_yes_txt(caller, *args, **kwargs): + yes_txt = kwargs['yes_txt'] + session = kwargs['caller_session'] + caller.msg(yes_txt, session=session) + + def _callable_no_txt(caller, *args, **kwargs): + no_txt = kwargs['no_txt'] + session = kwargs['caller_session'] + caller.msg(no_txt, session=session) + + if not callable(yes_action): + kwargs['yes_txt'] = str(yes_action) + yes_action = _callable_yes_txt + + if not callable(no_action): + kwargs['no_txt'] = str(no_action) + no_action = _callable_no_txt + + # prepare the prompt with options + options = "Y/N" + abort_txt = "/Abort" if allow_abort else "" + if default: + default = default.lower() + if default == "y": + options = "[Y]/N" + elif default == "n": + options = "Y/[N]" + elif default == "a": + allow_abort = True + abort_txt = "/[A]bort" + options += abort_txt + prompt = prompt.format(options=options) + + caller.ndb._yes_no_question = _Prompt() + caller.ndb._yes_no_question.prompt = prompt + caller.ndb._yes_no_question.session = session + caller.ndb._yes_no_question.prompt = prompt + caller.ndb._yes_no_question.default = default + caller.ndb._yes_no_question.allow_abort = allow_abort + caller.ndb._yes_no_question.yes_callable = yes_action + caller.ndb._yes_no_question.no_callable = no_action + caller.ndb._yes_no_question.args = args + caller.ndb._yes_no_question.kwargs = kwargs + + caller.cmdset.add(YesNoQuestionCmdSet) + caller.msg(prompt, session=session)
        + + # ------------------------------------------------------------- # # Menu generation from menu template string @@ -1701,7 +1877,9 @@ _RE_NODE = re.compile(r"##\s*?NODE\s+?(?P<nodename>\S[\S\s]*?)$", re.I + re.M) _RE_OPTIONS_SEP = re.compile(r"##\s*?OPTIONS\s*?$", re.I + re.M) _RE_CALLABLE = re.compile(r"\S+?\(\)", re.I + re.M) -_RE_CALLABLE = re.compile(r"(?P<funcname>\S+?)(?:\((?P<kwargs>[\S\s]+?)\)|\(\))", re.I + re.M) +_RE_CALLABLE = re.compile( + r"(?P<funcname>\S+?)(?:\((?P<kwargs>[\S\s]+?)\)|\(\))", re.I + re.M +) _HELP_NO_OPTION_MATCH = _("Choose an option or try 'help'.") @@ -1715,8 +1893,8 @@ # Input/option/goto handler functions that allows for dynamically generated # nodes read from the menu template. - -def _process_callable(caller, goto, goto_callables, raw_string, current_nodename, kwargs): +def _process_callable(caller, goto, goto_callables, raw_string, + current_nodename, kwargs): """ Central helper for parsing a goto-callable (`funcname(**kwargs)`) out of the right-hand-side of the template options and map this to an actual @@ -1732,18 +1910,12 @@ for kwarg in gotokwargs.split(","): if kwarg and "=" in kwarg: key, value = [part.strip() for part in kwarg.split("=", 1)] - if key in ( - "evmenu_goto", - "evmenu_gotomap", - "_current_nodename", - "evmenu_current_nodename", - "evmenu_goto_callables", - ): + if key in ("evmenu_goto", "evmenu_gotomap", "_current_nodename", + "evmenu_current_nodename", "evmenu_goto_callables"): raise RuntimeError( f"EvMenu template error: goto-callable '{goto}' uses a " f"kwarg ({kwarg}) that is reserved for the EvMenu templating " - "system. Rename the kwarg." - ) + "system. Rename the kwarg.") try: key = literal_eval(key) except ValueError: @@ -1770,7 +1942,8 @@ goto = kwargs["evmenu_goto"] goto_callables = kwargs["evmenu_goto_callables"] current_nodename = kwargs["evmenu_current_nodename"] - return _process_callable(caller, goto, goto_callables, raw_string, current_nodename, kwargs) + return _process_callable(caller, goto, goto_callables, raw_string, + current_nodename, kwargs) def _generated_input_goto_func(caller, raw_string, **kwargs): @@ -1790,15 +1963,13 @@ # start with glob patterns for pattern, goto in gotomap.items(): if fnmatch(raw_string.lower(), pattern): - return _process_callable( - caller, goto, goto_callables, raw_string, current_nodename, kwargs - ) + return _process_callable(caller, goto, goto_callables, raw_string, + current_nodename, kwargs) # no glob pattern match; try regex for pattern, goto in gotomap.items(): if pattern and re.match(pattern, raw_string.lower(), flags=re.I + re.M): - return _process_callable( - caller, goto, goto_callables, raw_string, current_nodename, kwargs - ) + return _process_callable(caller, goto, goto_callables, raw_string, + current_nodename, kwargs) # no match, show error raise EvMenuGotoAbortMessage(_HELP_NO_OPTION_MATCH) @@ -1829,35 +2000,28 @@ dict: A `{"node": nodefunc}` menutree suitable to pass into EvMenu. """ - def _validate_kwarg(goto, kwarg): """ Validate goto-callable kwarg is on correct form. """ - if not "=" in kwarg: + if "=" not in kwarg: raise RuntimeError( f"EvMenu template error: goto-callable '{goto}' has a " f"non-kwarg argument ({kwarg}). All callables in the " "template must have only keyword-arguments, or no " - "args at all." - ) + "args at all.") key, _ = [part.strip() for part in kwarg.split("=", 1)] - if key in ( - "evmenu_goto", - "evmenu_gotomap", - "_current_nodename", - "evmenu_current_nodename", - "evmenu_goto_callables", - ): + if key in ("evmenu_goto", "evmenu_gotomap", "_current_nodename", + "evmenu_current_nodename", "evmenu_goto_callables"): raise RuntimeError( f"EvMenu template error: goto-callable '{goto}' uses a " f"kwarg ({kwarg}) that is reserved for the EvMenu templating " - "system. Rename the kwarg." - ) + "system. Rename the kwarg.") def _parse_options(nodename, optiontxt, goto_callables): """ Parse option section into option dict. + """ options = [] optiontxt = optiontxt[0].strip() if optiontxt else "" @@ -1883,7 +2047,7 @@ if match: kwargs = match.group("kwargs") if kwargs: - for kwarg in kwargs.split(","): + for kwarg in kwargs.split(','): _validate_kwarg(goto, kwarg) # parse key [;aliases|pattern] @@ -1895,7 +2059,7 @@ if main_key.startswith(_OPTION_INPUT_MARKER): # if we have a pattern, build the arguments for _default later - pattern = main_key[len(_OPTION_INPUT_MARKER) :].strip() + pattern = main_key[len(_OPTION_INPUT_MARKER):].strip() inputparsemap[pattern] = goto else: # a regular goto string/callable target @@ -1935,6 +2099,7 @@ def _parse(caller, menu_template, goto_callables): """ Parse the menu string format into a node tree. + """ nodetree = {} splits = _RE_NODE.split(menu_template) @@ -1956,7 +2121,12 @@
        [docs]def template2menu( - caller, menu_template, goto_callables=None, startnode="start", persistent=False, **kwargs, + caller, + menu_template, + goto_callables=None, + startnode="start", + persistent=False, + **kwargs, ): """ Helper function to generate and start an EvMenu based on a menu template @@ -1981,7 +2151,12 @@ """ goto_callables = goto_callables or {} menu_tree = parse_menu_template(caller, menu_template, goto_callables) - return EvMenu(caller, menu_tree, persistent=persistent, **kwargs,)
        + return EvMenu( + caller, + menu_tree, + persistent=persistent, + **kwargs, + )
        @@ -2019,7 +2194,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -2038,6 +2212,7 @@ +
        develop branch
        @@ -43,29 +44,34 @@ """ EvMore - pager mechanism -This is a pager for displaying long texts and allows stepping up and -down in the text (the name comes from the traditional 'more' unix -command). +This is a pager for displaying long texts and allows stepping up and down in +the text (the name comes from the traditional 'more' unix command). To use, simply pass the text through the EvMore object: -:: + + +```python from evennia.utils.evmore import EvMore text = some_long_text_output() EvMore(caller, text, always_page=False, session=None, justify_kwargs=None, **kwargs) +``` -One can also use the convenience function msg from this module: -:: +One can also use the convenience function `msg` from this module to avoid +having to set up the `EvMenu` object manually: + +```python from evennia.utils import evmore text = some_long_text_output() evmore.msg(caller, text, always_page=False, session=None, justify_kwargs=None, **kwargs) +``` -Where always_page decides if the pager is used also if the text is not long -enough to need to scroll, session is used to determine which session to relay -to and `justify_kwargs` are kwargs to pass to `utils.utils.justify` in order to +The `always_page` argument decides if the pager is used also if the text is not long +enough to need to scroll, `session` is used to determine which session to relay +to and `justify_kwargs` are kwargs to pass to utils.utils.justify in order to change the formatting of the text. The remaining `**kwargs` will be passed on to the `caller.msg()` construct every time the page is updated. @@ -77,7 +83,9 @@ from django.core.paginator import Paginator from evennia import Command, CmdSet from evennia.commands import cmdhandler -from evennia.utils.utils import make_iter, inherits_from, justify +from evennia.utils.ansi import ANSIString +from evennia.utils.utils import make_iter, inherits_from, justify, dedent +from django.utils.translation import gettext as _ _CMD_NOMATCH = cmdhandler.CMD_NOMATCH _CMD_NOINPUT = cmdhandler.CMD_NOINPUT @@ -88,6 +96,8 @@ _EVTABLE = None +_LBR = ANSIString("\n") + # text _DISPLAY = """{text} @@ -169,10 +179,9 @@ return qs.count()
        -
        [docs]class EvMore: +
        [docs]class EvMore(object): """ - The main pager object. - + The main pager object """
        [docs] def __init__( @@ -190,16 +199,15 @@ ): """ - Initialization of the Evmore input handler. + Initialization of the EvMore pager. Args: caller (Object or Account): Entity reading the text. inp (str, EvTable, Paginator or iterator): The text or data to put under paging. - If a string, paginage normally. If this text contains - one or more \\\\f (backslash + f) format symbols, automatic - pagination and justification are force-disabled and - page-breaks will only happen after each \\\\f. + one or more `\\\\f` format symbol, automatic pagination and justification + are force-disabled and page-breaks will only happen after each `\\\\f`. - If `EvTable`, the EvTable will be paginated with the same setting on each page if it is too long. The table decorations will be considered in the size of the page. @@ -207,8 +215,9 @@ expected to be a line in the final display. Each line will be run through `iter_callable`. - always_page (bool, optional): If `False`, the pager will only kick - in if `inp` is too big to fit the screen. + always_page (bool, optional): If `False`, the + pager will only kick in if `inp` is too big + to fit the screen. session (Session, optional): If given, this session will be used to determine the screen width and will receive all output. justify (bool, optional): If set, auto-justify long lines. This must be turned @@ -224,51 +233,29 @@ the caller when the more page exits. Note that this will be using whatever cmdset the user had *before* the evmore pager was activated (so none of the evmore commands will be available when this is run). - kwargs (any, any): These will be passed on to the `caller.msg` method. + kwargs (any, optional): These will be passed on to the `caller.msg` method. Examples: - Basic use: - :: - super_long_text = " ... " - EvMore(caller, super_long_text) - - Paginated query data - this is an optimization to avoid fetching - database data until it's actually paged to. - :: - - from django.core.paginator import Paginator - - query = ObjectDB.objects.all() - pages = Paginator(query, 10) # 10 objs per page - EvMore(caller, pages) - - Automatic split EvTable over multiple EvMore pages - :: - - table = EvMore(*header, table=tabledata) - EvMore(caller, table) - - Every page a separate EvTable (optimization for very large data sets) - :: - - from evennia import EvTable, EvMore - - class TableEvMore(EvMore): - def init_pages(self, data): - pages = # depends on data type - super().init_pages(pages) - - def page_formatter(self, page): - table = EvTable() - - for line in page: - cols = # split raw line into columns - table.add_row(*cols) - - return str(table) - - TableEvMore(caller, pages) + ```python + super_long_text = " ... " + EvMore(caller, super_long_text) + ``` + Paginator + ```python + from django.core.paginator import Paginator + query = ObjectDB.objects.all() + pages = Paginator(query, 10) # 10 objs per page + EvMore(caller, pages) + ``` + Every page an EvTable + ```python + from evennia import EvTable + def _to_evtable(page): + table = ... # convert page to a table + return EvTable(*headers, table=table, ...) + EvMore(caller, pages, page_formatter=_to_evtable) + ``` """ self._caller = caller @@ -287,7 +274,7 @@ self._justify_kwargs = justify_kwargs self.exit_on_lastpage = exit_on_lastpage self.exit_cmd = exit_cmd - self._exit_msg = "Exited |wmore|n pager." + self._exit_msg = _("Exited |wmore|n pager.") self._kwargs = kwargs self._data = None @@ -410,8 +397,9 @@ """ Paginate by slice. This is done with an eye on memory efficiency (usually for querysets); to avoid fetching all objects at the same time. + """ - return self._data[pageno * self.height : pageno * self.height + self.height]
        + return self._data[pageno * self.height: pageno * self.height + self.height]
        [docs] def paginator_django(self, pageno): """ @@ -455,9 +443,12 @@
        [docs] def init_f_str(self, text): """ - The input contains \\\\f (backslash + f) markers. We use \\\\f to indicate - the user wants to enforce their line breaks on their own. If so, we do - no automatic line-breaking/justification at all. + The input contains `\\f` markers. We use `\\f` to indicate the user wants to + enforce their line breaks on their own. If so, we do no automatic + line-breaking/justification at all. + + Args: + text (str): The string to format with f-markers. """ self._data = text.split("\f") @@ -486,7 +477,7 @@ lines = text.split("\n") self._data = [ - "\n".join(lines[i : i + self.height]) for i in range(0, len(lines), self.height) + _LBR.join(lines[i: i + self.height]) for i in range(0, len(lines), self.height) ] self._npages = len(self._data)
        @@ -504,16 +495,15 @@ Notes: If overridden, this method must perform the following actions: - - read and re-store `self._data` (the incoming data set) if needed - for pagination to work. + - read and re-store `self._data` (the incoming data set) if needed for pagination to + work. - set `self._npages` to the total number of pages. Default is 1. - set `self._paginator` to a callable that will take a page number 1...N and return the data to display on that page (not any decorations or next/prev buttons). If only wanting to change the paginator, override `self.paginator` instead. - - set `self._page_formatter` to a callable that will receive the - page from `self._paginator` and format it with one element per - line. Default is `str`. Or override `self.page_formatter` - directly instead. + - set `self._page_formatter` to a callable that will receive the page from + `self._paginator` and format it with one element per line. Default is `str`. Or + override `self.page_formatter` directly instead. By default, helper methods are called that perform these actions depending on supported inputs. @@ -590,40 +580,6 @@ """ EvMore-supported version of msg, mimicking the normal msg method. - Args: - caller (Object or Account): Entity reading the text. - text (str, EvTable or iterator): The text or data to put under paging. - - - If a string, paginage normally. If this text contains - one or more \\\\f (backslash + f) format symbol, automatic pagination is disabled - and page-breaks will only happen after each \\\\f. - - If `EvTable`, the EvTable will be paginated with the same - setting on each page if it is too long. The table - decorations will be considered in the size of the page. - - Otherwise `text` is converted to an iterator, where each step is - is expected to be a line in the final display, and each line - will be run through repr(). - - always_page (bool, optional): If `False`, the - pager will only kick in if `text` is too big - to fit the screen. - session (Session, optional): If given, this session will be used - to determine the screen width and will receive all output. - justify (bool, optional): If set, justify long lines in output. Disable for - fixed-format output, like tables. - justify_kwargs (dict, bool or None, optional): If given, this should - be valid keyword arguments to the utils.justify() function. If False, - no justification will be done. - exit_on_lastpage (bool, optional): Immediately exit pager when reaching the last page. - use_evtable (bool, optional): If True, each page will be rendered as an - EvTable. For this to work, `text` must be an iterable, where each element - is the table (list of list) to render on that page. - evtable_args (tuple, optional): The args to use for EvTable on each page. - evtable_kwargs (dict, optional): The kwargs to use for EvTable on each - page (except `table`, which is supplied by EvMore per-page). - kwargs (any, optional): These will be passed on - to the `caller.msg` method. - """ EvMore( caller, @@ -635,6 +591,9 @@ exit_on_lastpage=exit_on_lastpage, **kwargs, )
        + + +msg.__doc__ += dedent(EvMore.__init__.__doc__)
        @@ -672,7 +631,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -691,6 +649,7 @@ +
        develop branch
        @@ -40,21 +41,25 @@

        Source code for evennia.utils.evtable

         """
        -This is an advanced ASCII table creator. It was inspired by
        -[prettytable](https://code.google.com/p/prettytable/) but shares no code.
        +This is an advanced ASCII table creator. It was inspired by Prettytable
        +(https://code.google.com/p/prettytable/) but shares no code and is considerably
        +more advanced, supporting auto-balancing of incomplete tables and ANSI colors among
        +other things.
         
         Example usage:
        -::
         
        -    from evennia.utils import evtable
        +```python
        +  from evennia.utils import evtable
         
        -    table = evtable.EvTable("Heading1", "Heading2",
        +  table = evtable.EvTable("Heading1", "Heading2",
                           table=[[1,2,3],[4,5,6],[7,8,9]], border="cells")
        -    table.add_column("This is long data", "This is even longer data")
        -    table.add_row("This is a single row")
        -    print table
        +  table.add_column("This is long data", "This is even longer data")
        +  table.add_row("This is a single row")
        +  print table
        +```
         
         Result:
        +
         ::
         
             +----------------------+----------+---+--------------------------+
        @@ -71,13 +76,15 @@
         
         As seen, the table will automatically expand with empty cells to make
         the table symmetric. Tables can be restricted to a given width:
        -::
         
        -    table.reformat(width=50, align="l")
        +```python
        +  table.reformat(width=50, align="l")
        +```
         
         (We could just have added these keywords to the table creation call)
         
         This yields the following result:
        +
         ::
         
             +-----------+------------+-----------+-----------+
        @@ -98,16 +105,21 @@
             | row       |            |           |           |
             +-----------+------------+-----------+-----------+
         
        +
         Table-columns can be individually formatted. Note that if an
         individual column is set with a specific width, table auto-balancing
         will not affect this column (this may lead to the full table being too
         wide, so be careful mixing fixed-width columns with auto- balancing).
         Here we change the width and alignment of the column at index 3
         (Python starts from 0):
        -::
         
        -    table.reformat_column(3, width=30, align="r")
        -    print table
        +```python
        +
        +table.reformat_column(3, width=30, align="r")
        +print table
        +```
        +
        +::
         
             +-----------+-------+-----+-----------------------------+---------+
             | Heading1  | Headi |     |                             |         |
        @@ -131,15 +143,14 @@
         vertically. This will lead to text contents being cropped. Each cell
         can only shrink to a minimum width and height of 1.
         
        -`EvTable` is intended to be used with [ANSIString](evennia.utils.ansi#ansistring)
        -for supporting ANSI-coloured string types.
        +`EvTable` is intended to be used with `ANSIString` for supporting ANSI-coloured
        +string types.
         
        -When a cell is auto-wrapped across multiple lines, ANSI-reset
        -sequences will be put at the end of each wrapped line. This means that
        -the colour of a wrapped cell will not "bleed", but it also means that
        -eventual colour outside the table will not transfer "across" a table,
        -you need to re-set the color to have it appear on both sides of the
        -table string.
        +When a cell is auto-wrapped across multiple lines, ANSI-reset sequences will be
        +put at the end of each wrapped line. This means that the colour of a wrapped
        +cell will not "bleed", but it also means that eventual colour outside the table
        +will not transfer "across" a table, you need to re-set the color to have it
        +appear on both sides of the table string.
         
         ----
         
        @@ -270,12 +281,12 @@
                         del chunks[-1]
         
                     while chunks:
        -                l = d_len(chunks[-1])
        +                ln = d_len(chunks[-1])
         
                         # Can at least squeeze this chunk onto the current line.
        -                if cur_len + l <= width:
        +                if cur_len + ln <= width:
                             cur_line.append(chunks.pop())
        -                    cur_len += l
        +                    cur_len += ln
         
                         # Nope, this line is full.
                         else:
        @@ -293,10 +304,10 @@
                     # Convert current line back to a string and store it in list
                     # of all lines (return value).
                     if cur_line:
        -                l = ""
        +                ln = ""
                         for w in cur_line:  # ANSI fix
        -                    l += w  #
        -                lines.append(indent + l)
        +                    ln += w  #
        +                lines.append(indent + ln)
                 return lines
        @@ -1130,8 +1141,9 @@ height (int, optional): Fixed height of table. Defaults to being unset. Width is still given precedence. If given, table cells will crop text rather than expand vertically. - evenwidth (bool, optional): Used with the `width` keyword. Adjusts columns to have as even width as - possible. This often looks best also for mixed-length tables. Default is `False`. + evenwidth (bool, optional): Used with the `width` keyword. Adjusts columns to have as + even width as possible. This often looks best also for mixed-length tables. Default + is `False`. maxwidth (int, optional): This will set a maximum width of the table while allowing it to be smaller. Only if it grows wider than this size will it be resized by expanding horizontally (or crop `height` is given). @@ -1378,7 +1390,8 @@ self.ncols = ncols self.nrows = nrowmax - # add borders - these add to the width/height, so we must do this before calculating width/height + # add borders - these add to the width/height, so we must do this before calculating + # width/height self._borders() # equalize widths within each column @@ -1465,7 +1478,8 @@ except Exception: raise - # equalize heights for each row (we must do this here, since it may have changed to fit new widths) + # equalize heights for each row (we must do this here, since it may have changed to fit new + # widths) cheights = [ max(cell.get_height() for cell in (col[iy] for col in self.worktable)) for iy in range(nrowmax) @@ -1826,7 +1840,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1845,6 +1858,7 @@ +
        develop branch
        @@ -48,7 +49,6 @@ """ import time -from calendar import monthrange from datetime import datetime, timedelta from django.db.utils import OperationalError @@ -68,6 +68,7 @@ try: GAME_TIME_OFFSET = ServerConfig.objects.conf("gametime_offset", default=0) except OperationalError: + # the db is not initialized print("Gametime offset could not load - db not set up.") GAME_TIME_OFFSET = 0 @@ -349,7 +350,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -368,6 +368,7 @@ +
        develop branch
        @@ -109,7 +110,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -128,6 +128,7 @@ +
        develop branch
        @@ -104,7 +105,8 @@ return super(SharedMemoryModelBase, cls).__call__(*args, **kwargs) instance_key = cls._get_cache_key(args, kwargs) - # depending on the arguments, we might not be able to infer the PK, so in that case we create a new instance + # depending on the arguments, we might not be able to infer the PK, so in that case we + # create a new instance if instance_key is None: return new_instance() cached_instance = cls.get_cached_instance(instance_key) @@ -195,9 +197,9 @@ if isinstance(value, (str, int)): value = to_str(value) if value.isdigit() or value.startswith("#"): - # we also allow setting using dbrefs, if so we try to load the matching object. - # (we assume the object is of the same type as the class holding the field, if - # not a custom handler must be used for that field) + # we also allow setting using dbrefs, if so we try to load the matching + # object. (we assume the object is of the same type as the class holding + # the field, if not a custom handler must be used for that field) dbid = dbref(value, reqhash=False) if dbid: model = _GA(cls, "_meta").get_field(fname).model @@ -307,21 +309,24 @@ pk = cls._meta.pks[0] else: pk = cls._meta.pk - # get the index of the pk in the class fields. this should be calculated *once*, but isn't atm + # get the index of the pk in the class fields. this should be calculated *once*, but isn't + # atm pk_position = cls._meta.fields.index(pk) if len(args) > pk_position: # if it's in the args, we can get it easily by index result = args[pk_position] elif pk.attname in kwargs: - # retrieve the pk value. Note that we use attname instead of name, to handle the case where the pk is a - # a ForeignKey. + # retrieve the pk value. Note that we use attname instead of name, to handle the case + # where the pk is a a ForeignKey. result = kwargs[pk.attname] elif pk.name != pk.attname and pk.name in kwargs: - # ok we couldn't find the value, but maybe it's a FK and we can find the corresponding object instead + # ok we couldn't find the value, but maybe it's a FK and we can find the corresponding + # object instead result = kwargs[pk.name] if result is not None and isinstance(result, Model): - # if the pk value happens to be a model instance (which can happen wich a FK), we'd rather use its own pk as the key + # if the pk value happens to be a model instance (which can happen wich a FK), we'd + # rather use its own pk as the key result = result._get_pk_val() return result @@ -749,7 +754,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -768,6 +772,7 @@ +
        develop branch
        @@ -154,7 +155,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -173,6 +173,7 @@ +
        develop branch
        @@ -57,7 +58,6 @@ import os import time -import glob from datetime import datetime from traceback import format_exc from twisted.python import log, logfile @@ -88,6 +88,7 @@ Returns: timestring (str): A formatted string of the given time. + """ when = when if when else time.time() @@ -167,6 +168,7 @@ server.log.2020_01_29 server.log.2020_01_29__1 server.log.2020_01_29__2 + """ suffix = "" copy_suffix = 0 @@ -187,7 +189,10 @@ return suffix
        [docs] def write(self, data): - "Write data to log file" + """ + Write data to log file + + """ logfile.BaseLogFile.write(self, data) self.lastDate = max(self.lastDate, self.toDate()) self.size += len(data)
        @@ -196,6 +201,7 @@
        [docs]class PortalLogObserver(log.FileLogObserver): """ Reformat logging + """ timeFormat = None @@ -330,6 +336,7 @@ Prints any generic debugging/informative info that should appear in the log. infomsg: (string) The message to be logged. + """ try: infomsg = str(infomsg) @@ -348,6 +355,7 @@ Args: depmsg (str): The deprecation message to log. + """ try: depmsg = str(depmsg) @@ -366,6 +374,7 @@ Args: secmsg (str): The security message to log. + """ try: secmsg = str(secmsg) @@ -387,6 +396,7 @@ the LogFile's rotate method in order to append some of the last lines of the previous log to the start of the new log, in order to preserve a continuous chat history for channel log files. + """ # we delay import of settings to keep logger module as free @@ -398,12 +408,15 @@ _CHANNEL_LOG_NUM_TAIL_LINES = settings.CHANNEL_LOG_NUM_TAIL_LINES num_lines_to_append = _CHANNEL_LOG_NUM_TAIL_LINES -
        [docs] def rotate(self): +
        [docs] def rotate(self, num_lines_to_append=None): """ Rotates our log file and appends some number of lines from the previous log to the start of the new one. + """ - append_tail = self.num_lines_to_append > 0 + append_tail = (num_lines_to_append + if num_lines_to_append is not None + else self.num_lines_to_append) if not append_tail: logfile.LogFile.rotate(self) return @@ -416,9 +429,11 @@ """ Convenience method for accessing our _file attribute's seek method, which is used in tail_log_function. + Args: *args: Same args as file.seek **kwargs: Same kwargs as file.seek + """ return self._file.seek(*args, **kwargs)
        @@ -426,12 +441,14 @@ """ Convenience method for accessing our _file attribute's readlines method, which is used in tail_log_function. + Args: *args: same args as file.readlines **kwargs: same kwargs as file.readlines Returns: lines (list): lines from our _file attribute. + """ return [line.decode("utf-8") for line in self._file.readlines(*args, **kwargs)]
        @@ -513,6 +530,43 @@ deferToThread(callback, filehandle, msg).addErrback(errback) +
        [docs]def log_file_exists(filename="game.log"): + """ + Determine if a log-file already exists. + + Args: + filename (str): The filename (within the log-dir). + + Returns: + bool: If the log file exists or not. + + """ + global _LOGDIR + if not _LOGDIR: + from django.conf import settings + _LOGDIR = settings.LOG_DIR + + filename = os.path.join(_LOGDIR, filename) + return os.path.exists(filename)
        + + +
        [docs]def rotate_log_file(filename="game.log", num_lines_to_append=None): + """ + Force-rotate a log-file, without + + Args: + filename (str): The log file, located in settings.LOG_DIR. + num_lines_to_append (int, optional): Include N number of + lines from previous file in new one. If `None`, use default. + Set to 0 to include no lines. + + """ + if log_file_exists(filename): + file_handle = _open_log_file(filename) + if file_handle: + file_handle.rotate(num_lines_to_append=num_lines_to_append)
        + +
        [docs]def tail_log_file(filename, offset, nlines, callback=None): """ Return the tail of the log file. @@ -552,7 +606,7 @@ lines_found = filehandle.readlines() block_count -= 1 # return the right number of lines - lines_found = lines_found[-nlines - offset : -offset if offset else None] + lines_found = lines_found[-nlines - offset: -offset if offset else None] if callback: callback(lines_found) return None @@ -610,7 +664,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -629,6 +682,7 @@ +
        develop branch
        @@ -39,13 +40,7 @@

        Source code for evennia.utils.optionclasses

        -"""
        -Option classes store user- or server Options in a generic way
        -while also providing validation.
        -
        -"""
        -
        -import datetime
        +import datetime
         from evennia import logger
         from evennia.utils.ansi import strip_ansi
         from evennia.utils.validatorfuncs import _TZ_DICT
        @@ -157,8 +152,8 @@
         
        [docs] def save(self, **kwargs): """ Stores the current value using `.handler.save_handler(self.key, value, **kwargs)` - where kwargs are a combination of those passed into this function and the - ones specified by the OptionHandler. + where `kwargs` are a combination of those passed into this function and + the ones specified by the `OptionHandler`. Keyword Args: any (any): Not used by default. These are passed in from self.set @@ -405,7 +400,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -424,6 +418,7 @@ +
        develop branch
        @@ -41,12 +42,13 @@

        Source code for evennia.utils.optionhandler

         from evennia.utils.utils import string_partial_matching
         from evennia.utils.containers import OPTION_CLASSES
        +from django.utils.translation import gettext as _
         
         _GA = object.__getattribute__
         _SA = object.__setattr__
         
         
        -
        [docs]class InMemorySaveHandler(object): +
        [docs]class InMemorySaveHandler: """ Fallback SaveHandler, implementing a minimum of the required save mechanism and storing data in memory. @@ -63,7 +65,7 @@ return self.storage.get(key, default)
        -
        [docs]class OptionHandler(object): +
        [docs]class OptionHandler: """ This is a generic Option handler. Retrieve options either as properties on this handler or by using the .get method. @@ -98,6 +100,7 @@ A common one to pass would be AttributeHandler.get. save_kwargs (any): Optional extra kwargs to pass into `savefunc` above. load_kwargs (any): Optional extra kwargs to pass into `loadfunc` above. + Notes: Both loadfunc and savefunc must be specified. If only one is given, the other will be ignored and in-memory storage will be used. @@ -174,7 +177,7 @@ """ if key not in self.options_dict: if raise_error: - raise KeyError("Option not found!") + raise KeyError(_("Option not found!")) return default # get the options or load/recache it op_found = self.options.get(key) or self._load_option(key) @@ -195,12 +198,14 @@ """ if not key: - raise ValueError("Option field blank!") + raise ValueError(_("Option field blank!")) match = string_partial_matching(list(self.options_dict.keys()), key, ret_index=False) if not match: - raise ValueError("Option not found!") + raise ValueError(_("Option not found!")) if len(match) > 1: - raise ValueError(f"Multiple matches: {', '.join(match)}. Please be more specific.") + raise ValueError(_("Multiple matches:") + + f"{', '.join(match)}. " + + _("Please be more specific.")) match = match[0] op = self.get(match, return_obj=True) op.set(value, **kwargs) @@ -256,7 +261,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -275,6 +279,7 @@ +
        develop branch
        @@ -327,7 +328,7 @@ return value
        [docs] def value_to_string(self, obj): - value = self._get_val_from_obj(obj) + value = self.value_from_object(obj) return self.get_db_prep_value(value)
        [docs] def get_internal_type(self): @@ -378,7 +379,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -397,6 +397,7 @@ +
        develop branch
        @@ -78,6 +79,7 @@ "search_message", "search_channel", "search_help_entry", + "search_tag", "search_script_tag", "search_account_tag", "search_channel_tag", @@ -95,13 +97,13 @@ Tag = ContentType.objects.get(app_label="typeclasses", model="tag").model_class() except OperationalError: # this is a fallback used during tests/doc building - print("Couldn't initialize search managers - db not set up.") - from evennia.objects.models import ObjectDB - from evennia.accounts.models import AccountDB - from evennia.scripts.models import ScriptDB - from evennia.comms.models import Msg, ChannelDB - from evennia.help.models import HelpEntry - from evennia.typeclasses.tags import Tag + print("Couldn't initialize search managers - db not set up.") + from evennia.objects.models import ObjectDB + from evennia.accounts.models import AccountDB + from evennia.scripts.models import ScriptDB + from evennia.comms.models import Msg, ChannelDB + from evennia.help.models import HelpEntry + from evennia.typeclasses.tags import Tag # noqa # ------------------------------------------------------------------- # Search manager-wrappers @@ -439,7 +441,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -458,6 +459,7 @@ +
        develop branch
        @@ -80,18 +81,18 @@ should directly give the module pathname to unload. Example: - :: - # (in a test method) - unload_module(foo) - with mock.patch("foo.GLOBALTHING", "mockval"): - import foo - ... # test code using foo.GLOBALTHING, now set to 'mockval' + ```python + # (in a test method) + unload_module(foo) + with mock.patch("foo.GLOBALTHING", "mockval"): + import foo + ... # test code using foo.GLOBALTHING, now set to 'mockval' + ``` - Notes: - This allows for mocking constants global to the module, since - otherwise those would not be mocked (since a module is only - loaded once). + This allows for mocking constants global to the module, since + otherwise those would not be mocked (since a module is only + loaded once). """ if isinstance(module, str): @@ -251,7 +252,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -270,6 +270,7 @@ +
        develop branch
        @@ -144,9 +145,10 @@ ) re_dblspace = re.compile(r" {2,}", re.M) re_url = re.compile( - r'((?:ftp|www|https?)\W+(?:(?!\.(?:\s|$)|&\w+;)[^"\',;$*^\\(){}<>\[\]\s])+)(\.(?:\s|$)|&\w+;|)' + r'(?<!=")((?:ftp|www|https?)\W+(?:(?!\.(?:\s|$)|&\w+;)[^"\',;$*^\\(){}<>\[\]\s])+)(\.(?:\s|$)|&\w+;|)' ) re_mxplink = re.compile(r"\|lc(.*?)\|lt(.*?)\|le", re.DOTALL) + re_mxpurl = re.compile(r"\|lu(.*?)\|lt(.*?)\|le", re.DOTALL) def _sub_bgfg(self, colormatch): # print("colormatch.groups()", colormatch.groups()) @@ -331,6 +333,21 @@ ) return val
        +
        [docs] def sub_mxp_urls(self, match): + """ + Helper method to be passed to re.sub, + replaces MXP links with HTML code. + Args: + match (re.Matchobject): Match for substitution. + Returns: + text (str): Processed text. + """ + url, text = [grp.replace('"', "\\&quot;") for grp in match.groups()] + val = ( + r"""<a id="mxplink" href="{url}" target="_blank">{text}</a>""".format(url=url, text=text) + ) + return val
        +
        [docs] def sub_text(self, match): """ Helper method to be passed to re.sub, @@ -378,6 +395,7 @@ # convert all ansi to html result = re.sub(self.re_string, self.sub_text, text) result = re.sub(self.re_mxplink, self.sub_mxp_links, result) + result = re.sub(self.re_mxpurl, self.sub_mxp_urls, result) result = self.re_color(result) result = self.re_bold(result) result = self.re_underline(result) @@ -444,7 +462,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -463,6 +480,7 @@ +
        develop branch
        @@ -50,7 +51,6 @@ import os import gc import sys -import copy import types import math import re @@ -61,6 +61,8 @@ import importlib import importlib.util import importlib.machinery +from ast import literal_eval +from simpleeval import simple_eval from unicodedata import east_asian_width from twisted.internet.task import deferLater from twisted.internet.defer import returnValue # noqa - used as import target @@ -74,18 +76,23 @@ from django.apps import apps from django.core.validators import validate_email as django_validate_email from django.core.exceptions import ValidationError as DjangoValidationError + from evennia.utils import logger _MULTIMATCH_TEMPLATE = settings.SEARCH_MULTIMATCH_TEMPLATE _EVENNIA_DIR = settings.EVENNIA_DIR _GAME_DIR = settings.GAME_DIR ENCODINGS = settings.ENCODINGS + +_TASK_HANDLER = None +_TICKER_HANDLER = None + _GA = object.__getattribute__ _SA = object.__setattr__ _DA = object.__delattr__ -
        [docs]def is_iter(obj): +
        [docs]def is_iter(obj): """ Checks if an object behaves iterably. @@ -110,7 +117,7 @@ return False
        -
        [docs]def make_iter(obj): +
        [docs]def make_iter(obj): """ Makes sure that the object is always iterable. @@ -125,7 +132,7 @@ return not is_iter(obj) and [obj] or obj
        -
        [docs]def wrap(text, width=None, indent=0): +
        [docs]def wrap(text, width=None, indent=0): """ Safely wrap text to a certain number of characters. @@ -149,7 +156,7 @@ fill = wrap -
        [docs]def pad(text, width=None, align="c", fillchar=" "): +
        [docs]def pad(text, width=None, align="c", fillchar=" "): """ Pads to a given width. @@ -175,7 +182,7 @@ return text.center(width, fillchar)
        -
        [docs]def crop(text, width=None, suffix="[...]"): +
        [docs]def crop(text, width=None, suffix="[...]"): """ Crop text to a certain width, throwing away text from too-long lines. @@ -203,16 +210,18 @@ return to_str(text)
        -
        [docs]def dedent(text, baseline_index=None): +
        [docs]def dedent(text, baseline_index=None, indent=None): """ Safely clean all whitespace at the left of a paragraph. Args: text (str): The text to dedent. - baseline_index (int or None, optional): Which row to use as a 'base' + baseline_index (int, optional): Which row to use as a 'base' for the indentation. Lines will be dedented to this level but no further. If None, indent so as to completely deindent the least indented text. + indent (int, optional): If given, force all lines to this indent. + This bypasses `baseline_index`. Returns: text (str): Dedented string. @@ -225,18 +234,23 @@ """ if not text: return "" - if baseline_index is None: + if indent is not None: + lines = text.split("\n") + ind = " " * indent + indline = "\n" + ind + return ind + indline.join(line.strip() for line in lines) + elif baseline_index is None: return textwrap.dedent(text) else: lines = text.split("\n") baseline = lines[baseline_index] spaceremove = len(baseline) - len(baseline.lstrip(" ")) return "\n".join( - line[min(spaceremove, len(line) - len(line.lstrip(" "))) :] for line in lines + line[min(spaceremove, len(line) - len(line.lstrip(" "))):] for line in lines )
        -
        [docs]def justify(text, width=None, align="f", indent=0): +
        [docs]def justify(text, width=None, align="f", indent=0): """ Fully justify a text so that it fits inside `width`. When using full justification (default) this will be done by padding between @@ -329,7 +343,7 @@ return "\n".join([indentstring + line for line in lines])
        -
        [docs]def columnize(string, columns=2, spacing=4, align="l", width=None): +
        [docs]def columnize(string, columns=2, spacing=4, align="l", width=None): """ Break a string into a number of columns, using as little vertical space as possible. @@ -371,7 +385,7 @@ cols = [] istart = 0 for irows in nrows: - cols.append(onecol[istart : istart + irows]) + cols.append(onecol[istart: istart + irows]) istart = istart + irows for col in cols: if len(col) < height: @@ -385,7 +399,7 @@ return "\n".join(rows)
        -
        [docs]def iter_to_string(initer, endsep="and", addquote=False): +
        [docs]def iter_to_str(initer, endsep="and", addquote=False): """ This pretty-formats an iterable list as string output, adding an optional alternative separator to the second to last entry. If `addquote` @@ -401,23 +415,21 @@ values with double quotes. Returns: - liststr (str): The list represented as a string. + str: The list represented as a string. Examples: ```python - # no endsep: - [1,2,3] -> '1, 2, 3' - # with endsep=='and': - [1,2,3] -> '1, 2 and 3' - # with addquote and endsep - [1,2,3] -> '"1", "2" and "3"' + >>> list_to_string([1,2,3], endsep='') + '1, 2, 3' + >>> list_to_string([1,2,3], ensdep='and') + '1, 2, and 3' + >>> list_to_string([1,2,3], endsep='and', addquote=True) + '"1", "2", and "3"' ``` """ - if not endsep: - endsep = "," - else: + if endsep: endsep = " " + endsep if not initer: return "" @@ -425,18 +437,23 @@ if addquote: if len(initer) == 1: return '"%s"' % initer[0] - return ", ".join('"%s"' % v for v in initer[:-1]) + "%s %s" % (endsep, '"%s"' % initer[-1]) + elif len(initer) == 2: + return '"%s"' % ('"%s "' % endsep).join(str(v) for v in initer) + return ", ".join('"%s"' % v for v in initer[:-1]) + ",%s %s" % (endsep, '"%s"' % initer[-1]) else: if len(initer) == 1: return str(initer[0]) - return ", ".join(str(v) for v in initer[:-1]) + "%s %s" % (endsep, initer[-1])
        + elif len(initer) == 2: + return ("%s " % endsep).join(str(v) for v in initer) + return ", ".join(str(v) for v in initer[:-1]) + ",%s %s" % (endsep, initer[-1])
        -# legacy alias -list_to_string = iter_to_string +# legacy aliases +list_to_string = iter_to_str +iter_to_string = iter_to_str -
        [docs]def wildcard_to_regexp(instring): +
        [docs]def wildcard_to_regexp(instring): """ Converts a player-supplied string that may have wildcards in it to regular expressions. This is useful for name matching. @@ -468,7 +485,7 @@ return regexp_string
        -
        [docs]def time_format(seconds, style=0): +
        [docs]def time_format(seconds, style=0): """ Function to return a 'prettified' version of a value in seconds. @@ -604,7 +621,7 @@ return retval.strip()
        -
        [docs]def datetime_format(dtobj): +
        [docs]def datetime_format(dtobj): """ Pretty-prints the time since a given time. @@ -635,7 +652,7 @@ return timestring
        -
        [docs]def host_os_is(osname): +
        [docs]def host_os_is(osname): """ Check to see if the host OS matches the query. @@ -650,7 +667,7 @@ return os.name == osname
        -
        [docs]def get_evennia_version(mode="long"): +
        [docs]def get_evennia_version(mode="long"): """ Helper method for getting the current evennia version. @@ -676,7 +693,7 @@ return vers
        -
        [docs]def pypath_to_realpath(python_path, file_ending=".py", pypath_prefixes=None): +
        [docs]def pypath_to_realpath(python_path, file_ending=".py", pypath_prefixes=None): """ Converts a dotted Python path to an absolute path under the Evennia library directory or under the current game directory. @@ -736,7 +753,7 @@ return list(set(p for p in paths if os.path.isfile(p)))
        -
        [docs]def dbref(inp, reqhash=True): +
        [docs]def dbref(inp, reqhash=True): """ Converts/checks if input is a valid dbref. @@ -764,7 +781,7 @@ return inp if isinstance(inp, int) else None
        -
        [docs]def dbref_to_obj(inp, objclass, raise_errors=True): +
        [docs]def dbref_to_obj(inp, objclass, raise_errors=True): """ Convert a #dbref to a valid object. @@ -820,7 +837,7 @@ } -
        [docs]def latinify(string, default="?", pure_ascii=False): +
        [docs]def latinify(string, default="?", pure_ascii=False): """ Convert a unicode string to "safe" ascii/latin-1 characters. This is used as a last resort when normal encoding does not work. @@ -874,7 +891,7 @@ return "".join(converted)
        -
        [docs]def to_bytes(text, session=None): +
        [docs]def to_bytes(text, session=None): """ Try to encode the given text to bytes, using encodings from settings or from Session. Will always return a bytes, even if given something that is not str or bytes. @@ -891,7 +908,7 @@ the text with "?" in place of problematic characters. If the specified encoding cannot be found, the protocol flag is reset to utf-8. In any case, returns bytes. - Note: + Notes: If `text` is already bytes, return it as is. """ @@ -917,7 +934,7 @@ return text.encode(default_encoding, errors="replace")
        -
        [docs]def to_str(text, session=None): +
        [docs]def to_str(text, session=None): """ Try to decode a bytestream to a python str, using encoding schemas from settings or from Session. Will always return a str(), also if not given a str/bytes. @@ -931,7 +948,7 @@ Returns: decoded_text (str): The decoded text. - Note: + Notes: If `text` is already str, return it as is. """ if isinstance(text, str): @@ -956,7 +973,7 @@ return text.decode(default_encoding, errors="replace")
        -
        [docs]def validate_email_address(emailaddress): +
        [docs]def validate_email_address(emailaddress): """ Checks if an email address is syntactically correct. Makes use of the django email-validator for consistency. @@ -979,24 +996,23 @@ return True
        -
        [docs]def inherits_from(obj, parent): +
        [docs]def inherits_from(obj, parent): """ Takes an object and tries to determine if it inherits at *any* distance from parent. Args: - obj (any): Object to analyze. This may be either an instance - or a class. - parent (any): Can be either instance, class or python path to class. + obj (any): Object to analyze. This may be either an instance or + a class. + parent (any): Can be either an instance, a class or the python + path to the class. Returns: inherits_from (bool): If `parent` is a parent to `obj` or not. Notes: - What differs this function from e.g. `isinstance()` is that `obj` - may be both an instance and a class, and parent may be an - instance, a class, or the python path to a class (counting from - the evennia root directory). + What differentiates this function from Python's `isinstance()` is the + flexibility in the types allowed for the object and parent being compared. """ @@ -1017,7 +1033,7 @@ return any(1 for obj_path in obj_paths if obj_path == parent_path)
        -
        [docs]def server_services(): +
        [docs]def server_services(): """ Lists all services active on the Server. Observe that since services are launched in memory, this function will only return @@ -1038,14 +1054,13 @@ return server
        -
        [docs]def uses_database(name="sqlite3"): +
        [docs]def uses_database(name="sqlite3"): """ Checks if the game is currently using a given database. This is a shortcut to having to use the full backend name. Args: - name (str): One of 'sqlite3', 'mysql', 'postgresql' - or 'oracle'. + name (str): One of 'sqlite3', 'mysql', 'postgresql' or 'oracle'. Returns: uses (bool): If the given database is used or not. @@ -1058,10 +1073,7 @@ return engine == "django.db.backends.%s" % name
        -_TASK_HANDLER = None - - -
        [docs]def delay(timedelay, callback, *args, **kwargs): +
        [docs]def delay(timedelay, callback, *args, **kwargs): """ Delay the calling of a callback (function). @@ -1069,8 +1081,7 @@ timedelay (int or float): The delay in seconds. callback (callable): Will be called as `callback(*args, **kwargs)` after `timedelay` seconds. - args (any): Will be used as arguments to callback. - + *args: Will be used as arguments to callback Keyword Args: persistent (bool, optional): If True the delay remains after a server restart. persistent is False by default. @@ -1080,7 +1091,7 @@ task (TaskHandlerTask): An instance of a task. Refer to, evennia.scripts.taskhandler.TaskHandlerTask - Note: + Notes: The task handler (`evennia.scripts.taskhandler.TASK_HANDLER`) will be called for persistent or non-persistent tasks. If persistent is set to True, the callback, its arguments @@ -1097,18 +1108,88 @@ """ global _TASK_HANDLER - # Do some imports here to avoid circular import and speed things up if _TASK_HANDLER is None: from evennia.scripts.taskhandler import TASK_HANDLER as _TASK_HANDLER + return _TASK_HANDLER.add(timedelay, callback, *args, **kwargs)
        +
        [docs]def repeat(interval, callback, persistent=True, idstring="", stop=False, + store_key=None, *args, **kwargs): + """ + Start a repeating task using the TickerHandler. + + Args: + interval (int): How often to call callback. + callback (callable): This will be called with `*args, **kwargs` every + `interval` seconds. This must be possible to pickle regardless + of if `persistent` is set or not! + persistent (bool, optional): If ticker survives a server reload. + idstring (str, optional): Separates multiple tickers. This is useful + mainly if wanting to set up multiple repeats for the same + interval/callback but with different args/kwargs. + stop (bool, optional): If set, use the given parameters to _stop_ a running + ticker instead of creating a new one. + store_key (tuple, optional): This is only used in combination with `stop` and + should be the return given from the original `repeat` call. If this + is given, all other args except `stop` are ignored. + *args: Used as arguments to `callback`. + **kwargs: Keyword-arguments to pass to `callback`. + + Returns: + tuple or None: The tuple is the `store_key` - the identifier for the + created ticker. Store this and pass into unrepat() in order to to stop + this ticker later. Returns `None` if `stop=True`. + + Raises: + KeyError: If trying to stop a ticker that was not found. + + """ + global _TICKER_HANDLER + if _TICKER_HANDLER is None: + from evennia.scripts.tickerhandler import TICKER_HANDLER as _TICKER_HANDLER + + if stop: + # we pass all args, but only store_key matters if given + _TICKER_HANDLER.remove(interval=interval, + callback=callback, + idstring=idstring, + persistent=persistent, + store_key=store_key) + else: + return _TICKER_HANDLER.add(interval=interval, + callback=callback, + idstring=idstring, + persistent=persistent)
        + +
        [docs]def unrepeat(store_key): + """ + This is used to stop a ticker previously started with `repeat`. + + Args: + store_key (tuple): This is the return from `repeat`, used to uniquely + identify the ticker to stop. Without the store_key, the ticker + must be stopped by passing its parameters to `TICKER_HANDLER.remove` + directly. + + Returns: + bool: True if a ticker was stopped, False if not (for example because no + matching ticker was found or it was already stopped). + + """ + try: + repeat(None, None, stop=True, store_key=store_key) + return True + except KeyError: + return False
        + + _PPOOL = None _PCMD = None _PROC_ERR = "A process has ended with a probable error condition: process ended by signal 9." -
        [docs]def run_async(to_execute, *args, **kwargs): +
        [docs]def run_async(to_execute, *args, **kwargs): """ Runs a function or executes a code snippet asynchronously. @@ -1117,17 +1198,16 @@ executed with `*args` and non-reserved `**kwargs` as arguments. The callable will be executed using ProcPool, or in a thread if ProcPool is not available. - Keyword Args: at_return (callable): Should point to a callable with one - argument. It will be called with the return value from - to_execute. + argument. It will be called with the return value from + to_execute. at_return_kwargs (dict): This dictionary will be used as - keyword arguments to the at_return callback. + keyword arguments to the at_return callback. at_err (callable): This will be called with a Failure instance - if there is an error in to_execute. + if there is an error in to_execute. at_err_kwargs (dict): This dictionary will be used as keyword - arguments to the at_err errback. + arguments to the at_err errback. Notes: All other `*args` and `**kwargs` will be passed on to @@ -1167,7 +1247,7 @@ deferred.addErrback(errback, **errback_kwargs)
        -
        [docs]def check_evennia_dependencies(): +
        [docs]def check_evennia_dependencies(): """ Checks the versions of Evennia's dependencies including making some checks for runtime libraries. @@ -1200,8 +1280,8 @@ except ImportError: errstring += ( "\n ERROR: IRC is enabled, but twisted.words is not installed. Please install it." - "\n Linux Debian/Ubuntu users should install package 'python-twisted-words', others" - "\n can get it from http://twistedmatrix.com/trac/wiki/TwistedWords." + "\n Linux Debian/Ubuntu users should install package 'python-twisted-words', " + "\n others can get it from http://twistedmatrix.com/trac/wiki/TwistedWords." ) not_error = False errstring = errstring.strip() @@ -1211,9 +1291,9 @@ return not_error
        -
        [docs]def has_parent(basepath, obj): +
        [docs]def has_parent(basepath, obj): """ - Checks if `basepath` is somewhere in `obj`'s parent tree. + Checks if `basepath` is somewhere in obj's parent tree. Args: basepath (str): Python dotpath to compare against obj path. @@ -1235,7 +1315,7 @@ return False
        -
        [docs]def mod_import_from_path(path): +
        [docs]def mod_import_from_path(path): """ Load a Python module at the specified path. @@ -1259,7 +1339,7 @@ return None
        -
        [docs]def mod_import(module): +
        [docs]def mod_import(module): """ A generic Python module loader. @@ -1290,7 +1370,7 @@ return None
        -
        [docs]def all_from_module(module): +
        [docs]def all_from_module(module): """ Return all global-level variables defined in a module. @@ -1301,23 +1381,24 @@ already imported module object (e.g. `models`) Returns: - variables (dict): A dict of {variablename: variable} for all + dict: A dict of {variablename: variable} for all variables in the given module. Notes: - Ignores modules and variable names starting with an underscore. + Ignores modules and variable names starting with an underscore, as well + as variables imported into the module from other modules. """ mod = mod_import(module) if not mod: return {} # make sure to only return variables actually defined in this - # module if available (try to avoid not imports) + # module if available (try to avoid imports) members = getmembers(mod, predicate=lambda obj: getmodule(obj) in (mod, None)) return dict((key, val) for key, val in members if not key.startswith("_"))
        -
        [docs]def callables_from_module(module): +
        [docs]def callables_from_module(module): """ Return all global-level callables defined in a module. @@ -1340,7 +1421,7 @@ return dict((key, val) for key, val in members if not key.startswith("_"))
        -
        [docs]def variable_from_module(module, variable=None, default=None): +
        [docs]def variable_from_module(module, variable=None, default=None): """ Retrieve a variable or list of variables from a module. The variable(s) must be defined globally in the module. If no variable @@ -1387,7 +1468,7 @@ return result
        -
        [docs]def string_from_module(module, variable=None, default=None): +
        [docs]def string_from_module(module, variable=None, default=None): """ This is a wrapper for `variable_from_module` that requires return value to be a string to pass. It's primarily used by login screen. @@ -1416,7 +1497,7 @@ return default
        -
        [docs]def random_string_from_module(module): +
        [docs]def random_string_from_module(module): """ Returns a random global string from a module. @@ -1429,7 +1510,7 @@ return random.choice(string_from_module(module))
        -
        [docs]def fuzzy_import_from_module(path, variable, default=None, defaultpaths=None): +
        [docs]def fuzzy_import_from_module(path, variable, default=None, defaultpaths=None): """ Import a variable based on a fuzzy path. First the literal `path` will be tried, then all given `defaultpaths` will be @@ -1461,9 +1542,9 @@ return default
        -
        [docs]def class_from_module(path, defaultpaths=None, fallback=None): +
        [docs]def class_from_module(path, defaultpaths=None, fallback=None): """ - Return a class from a module, given the module's path. This is + Return a class from a module, given the class' full python path. This is primarily used to convert db_typeclass_path:s to classes. Args: @@ -1541,7 +1622,7 @@ object_from_module = class_from_module -
        [docs]def init_new_account(account): +
        [docs]def init_new_account(account): """ Deprecated. """ @@ -1550,7 +1631,7 @@ logger.log_dep("evennia.utils.utils.init_new_account is DEPRECATED and should not be used.")
        -
        [docs]def string_similarity(string1, string2): +
        [docs]def string_similarity(string1, string2): """ This implements a "cosine-similarity" algorithm as described for example in *Proceedings of the 22nd International Conference on Computation @@ -1580,7 +1661,7 @@ return 0
        -
        [docs]def string_suggestions(string, vocabulary, cutoff=0.6, maxnum=3): +
        [docs]def string_suggestions(string, vocabulary, cutoff=0.6, maxnum=3): """ Given a `string` and a `vocabulary`, return a match or a list of suggestions based on string similarity. @@ -1594,8 +1675,8 @@ Returns: suggestions (list): Suggestions from `vocabulary` with a - similarity-rating that higher than or equal to `cutoff`. - Could be empty if there are no matches. + similarity-rating that higher than or equal to `cutoff`. + Could be empty if there are no matches. """ return [ @@ -1609,7 +1690,7 @@ ][:maxnum]
        -
        [docs]def string_partial_matching(alternatives, inp, ret_index=True): +
        [docs]def string_partial_matching(alternatives, inp, ret_index=True): """ Partially matches a string based on a list of `alternatives`. Matching is made from the start of each subword in each @@ -1661,13 +1742,11 @@ return []
        -
        [docs]def format_table(table, extra_space=1): +
        [docs]def format_table(table, extra_space=1): """ - Note: `evennia.utils.evtable` is more powerful than this, but this function - can be useful when the number of columns and rows are unknown and must be - calculated on the fly. + Format a 2D array of strings into a multi-column table. - Args. + Args: table (list): A list of lists to represent columns in the table: `[[val,val,val,...], [val,val,val,...], ...]`, where each val will be placed on a separate row in the @@ -1677,26 +1756,30 @@ padding (in characters) should be left between columns. Returns: - table (list): A list of lists representing the rows to print - out one by one. + list: A list of lists representing the rows to print out one by one. Notes: The function formats the columns to be as wide as the widest member of each column. - Example: - :: + `evennia.utils.evtable` is more powerful than this, but this + function can be useful when the number of columns and rows are + unknown and must be calculated on the fly. - ftable = format_table([[...], [...], ...]) - for ir, row in enumarate(ftable): - if ir == 0: - # make first row white - string += "\\\\n|w" + ""join(row) + "|n" - else: - string += "\\\\n" + "".join(row) - print(string) + Examples: :: + + ftable = format_table([[1,2,3], [4,5,6]]) + string = "" + for ir, row in enumarate(ftable): + if ir == 0: + # make first row white + string += "\\n|w" + "".join(row) + "|n" + else: + string += "\\n" + "".join(row) + print(string) """ + if not table: return [[]] @@ -1712,7 +1795,226 @@ return ftable
        -
        [docs]def get_evennia_pids(): +
        [docs]def percent(value, minval, maxval, formatting="{:3.1f}%"): + """ + Get a value in an interval as a percentage of its position + in that interval. This also understands negative numbers. + + Args: + value (number): This should be a value minval<=value<=maxval. + minval (number or None): Smallest value in interval. This could be None + for an open interval (then return will always be 100%) + maxval (number or None): Biggest value in interval. This could be None + for an open interval (then return will always be 100%) + formatted (str, optional): This is a string that should + accept one formatting tag. This will receive the + current value as a percentage. If None, the + raw float will be returned instead. + Returns: + str or float: The formatted value or the raw percentage as a float. + Notes: + We try to handle a weird interval gracefully. + + - If either maxval or minval is None (open interval), we (aribtrarily) assume 100%. + - If minval > maxval, we return 0%. + - If minval == maxval == value we are looking at a single value match and return 100%. + - If minval == maxval != value we return 0%. + - If value not in [minval..maxval], we set value to the closest + boundary, so the result will be 0% or 100%, respectively. + + """ + result = None + if None in (minval, maxval): + # we have no boundaries, percent calculation makes no sense, + # we set this to 100% since it + result = 100.0 + elif minval > maxval: + # interval has no width so we cannot + # occupy any position within it. + result = 0.0 + elif minval == maxval == value: + # this is a single value that we match + result = 100.0 + elif minval == maxval != value: + # interval has no width so we cannot be in it. + result = 0.0 + + if result is None: + # constrain value to interval + value = min(max(minval, value), maxval) + + # these should both be >0 + dpart = value - minval + dfull = maxval - minval + result = (dpart / dfull) * 100.0 + + if isinstance(formatting, str): + return formatting.format(result) + return result
        + + +import functools # noqa + + +
        [docs]def percentile(iterable, percent, key=lambda x: x): + """ + Find the percentile of a list of values. + + Args: + iterable (iterable): A list of values. Note N MUST BE already sorted. + percent (float): A value from 0.0 to 1.0. + key (callable, optional). Function to compute value from each element of N. + + Returns: + float: The percentile of the values + + """ + if not iterable: + return None + k = (len(iterable) - 1) * percent + f = math.floor(k) + c = math.ceil(k) + if f == c: + return key(iterable[int(k)]) + d0 = key(iterable[int(f)]) * (c - k) + d1 = key(iterable[int(c)]) * (k - f) + return d0 + d1
        + + +
        [docs]def format_grid(elements, width=78, sep=" ", verbatim_elements=None): + """ + This helper function makes a 'grid' output, where it distributes the given + string-elements as evenly as possible to fill out the given width. + will not work well if the variation of length is very big! + + Args: + elements (iterable): A 1D list of string elements to put in the grid. + width (int, optional): The width of the grid area to fill. + sep (str, optional): The extra separator to put between words. If + set to the empty string, words may run into each other. + verbatim_elements (list, optional): This is a list of indices pointing to + specific items in the `elements` list. An element at this index will + not be included in the calculation of the slot sizes. It will still + be inserted into the grid at the correct position and may be surrounded + by padding unless filling the entire line. This is useful for embedding + decorations in the grid, such as horizontal bars. + ignore_ansi (bool, optional): Ignore ansi markups when calculating white spacing. + + Returns: + list: The grid as a list of ready-formatted rows. We return it + like this to make it easier to insert decorations between rows, such + as horizontal bars. + """ + + def _minimal_rows(elements): + """ + Minimalistic distribution with minimal spacing, good for single-line + grids but will look messy over many lines. + """ + rows = [""] + for element in elements: + rowlen = display_len((rows[-1])) + elen = display_len((element)) + if rowlen + elen <= width: + rows[-1] += element + else: + rows.append(element) + return rows + + def _weighted_rows(elements): + """ + Dynamic-space, good for making even columns in a multi-line grid but + will look strange for a single line. + """ + wls = [display_len((elem)) for elem in elements] + wls_percentile = [wl for iw, wl in enumerate(wls) if iw not in verbatim_elements] + + if wls_percentile: + # get the nth percentile as a good representation of average width + averlen = int(percentile(sorted(wls_percentile), 0.9)) + 2 # include extra space + aver_per_row = width // averlen + 1 + else: + # no adjustable rows, just keep all as-is + aver_per_row = 1 + + if aver_per_row == 1: + # one line per row, output directly since this is trivial + # we use rstrip here to remove extra spaces added by sep + return [ + crop(element.rstrip(), width) + " " \ + * max(0, width - display_len((element.rstrip()))) + for iel, element in enumerate(elements) + ] + + indices = [averlen * ind for ind in range(aver_per_row - 1)] + + rows = [] + ic = 0 + row = "" + for ie, element in enumerate(elements): + + wl = wls[ie] + lrow = display_len((row)) + # debug = row.replace(" ", ".") + + if lrow + wl > width: + # this slot extends outside grid, move to next line + row += " " * (width - lrow) + rows.append(row) + if wl >= width: + # remove sep if this fills the entire line + element = element.rstrip() + row = crop(element, width) + ic = 0 + elif ic >= aver_per_row - 1: + # no more slots available on this line + row += " " * max(0, (width - lrow)) + rows.append(row) + row = crop(element, width) + ic = 0 + else: + try: + while lrow > max(0, indices[ic]): + # slot too wide, extend into adjacent slot + ic += 1 + row += " " * max(0, indices[ic] - lrow) + except IndexError: + # we extended past edge of grid, crop or move to next line + if ic == 0: + row = crop(element, width) + else: + row += " " * max(0, width - lrow) + rows.append(row) + ic = 0 + else: + # add a new slot + row += element + " " * max(0, averlen - wl) + ic += 1 + + if ie >= nelements - 1: + # last element, make sure to store + row += " " * max(0, width - display_len((row))) + rows.append(row) + return rows + + if not elements: + return [] + if not verbatim_elements: + verbatim_elements = [] + + nelements = len(elements) + # add sep to all but the very last element + elements = [elements[ie] + sep for ie in range(nelements - 1)] + [elements[-1]] + + if sum(display_len((element)) for element in elements) <= width: + # grid fits in one line + return _minimal_rows(elements) + else: + # full multi-line grid + return _weighted_rows(elements)
        + + +
        [docs]def get_evennia_pids(): """ Get the currently valid PIDs (Process IDs) of the Portal and Server by trying to access a PID file. @@ -1723,13 +2025,13 @@ Examples: This can be used to determine if we are in a subprocess by - something like: ```python self_pid = os.getpid() server_pid, portal_pid = get_evennia_pids() is_subprocess = self_pid not in (server_pid, portal_pid) ``` + """ server_pidfile = os.path.join(settings.GAME_DIR, "server.pid") portal_pidfile = os.path.join(settings.GAME_DIR, "portal.pid") @@ -1745,7 +2047,7 @@ return None, None
        -
        [docs]def deepsize(obj, max_depth=4): +
        [docs]def deepsize(obj, max_depth=4): """ Get not only size of the given object, but also the size of objects referenced by the object, down to `max_depth` distance @@ -1787,7 +2089,7 @@ _missing = object() -
        [docs]class lazy_property(object): +
        [docs]class lazy_property(object): """ Delays loading of property until first access. Credit goes to the Implementation in the werkzeug suite: @@ -1807,7 +2109,7 @@ """ -
        [docs] def __init__(self, func, name=None, doc=None): +
        [docs] def __init__(self, func, name=None, doc=None): """Store all properties for now""" self.__name__ = name or func.__name__ self.__module__ = func.__module__ @@ -1831,7 +2133,7 @@ ) # + range(127,160)]))) -
        [docs]def strip_control_sequences(string): +
        [docs]def strip_control_sequences(string): """ Remove non-print text sequences. @@ -1848,7 +2150,7 @@ return _RE_CONTROL_CHAR.sub("", _STRIP_ANSI(string))
        -
        [docs]def calledby(callerdepth=1): +
        [docs]def calledby(callerdepth=1): """ Only to be used for debug purposes. Insert this debug function in another function; it will print which function called it. @@ -1873,7 +2175,7 @@ return "[called by '%s': %s:%s %s]" % (frame[3], path, frame[2], frame[4])
        -
        [docs]def m_len(target): +
        [docs]def m_len(target): """ Provides length checking for strings with MXP patterns, and falls back to normal len for other objects. @@ -1894,7 +2196,7 @@ return len(target)
        -
        [docs]def display_len(target): +
        [docs]def display_len(target): """ Calculate the 'visible width' of text. This is not necessarily the same as the number of characters in the case of certain asian characters. This will also @@ -1928,7 +2230,7 @@ # Replace this hook function by changing settings.SEARCH_AT_RESULT. -
        [docs]def at_search_result(matches, caller, query="", quiet=False, **kwargs): +
        [docs]def at_search_result(matches, caller, query="", quiet=False, **kwargs): """ This is a generic hook for handling all processing of a search result, including error reporting. This is also called by the cmdhandler @@ -1945,23 +2247,22 @@ query (str, optional): The search query used to produce `matches`. quiet (bool, optional): If `True`, no messages will be echoed to caller on errors. - Keyword Args: nofound_string (str): Replacement string to echo on a notfound error. multimatch_string (str): Replacement string to echo on a multimatch error. Returns: processed_result (Object or None): This is always a single result - or `None`. If `None`, any error reporting/handling should - already have happened. The returned object is of the type we are - checking multimatches for (e.g. Objects or Commands) + or `None`. If `None`, any error reporting/handling should + already have happened. The returned object is of the type we are + checking multimatches for (e.g. Objects or Commands) """ error = "" if not matches: # no results. - error = kwargs.get("nofound_string") or _("Could not find '%s'." % query) + error = kwargs.get("nofound_string") or _("Could not find '{query}'.").format(query=query) matches = None elif len(matches) > 1: multimatch_string = kwargs.get("multimatch_string") @@ -1986,7 +2287,7 @@ name=result.get_display_name(caller) if hasattr(result, "get_display_name") else query, - aliases=" [%s]" % ";".join(aliases) if aliases else "", + aliases=" [{alias}]".format(alias=";".join(aliases) if aliases else ""), info=result.get_extra_info(caller), ) matches = None @@ -1999,7 +2300,7 @@ return matches
        -
        [docs]class LimitedSizeOrderedDict(OrderedDict): +
        [docs]class LimitedSizeOrderedDict(OrderedDict): """ This dictionary subclass is both ordered and limited to a maximum number of elements. Its main use is to hold a cache that can never @@ -2007,16 +2308,16 @@ """ -
        [docs] def __init__(self, *args, **kwargs): +
        [docs] def __init__(self, *args, **kwargs): """ Limited-size ordered dict. Keyword Args: size_limit (int): Use this to limit the number of elements - alloweds to be in this list. By default the overshooting elements - will be removed in FIFO order. + alloweds to be in this list. By default the overshooting elements + will be removed in FIFO order. fifo (bool, optional): Defaults to `True`. Remove overshooting elements - in FIFO order. If `False`, remove in FILO order. + in FIFO order. If `False`, remove in FILO order. """ super().__init__() @@ -2049,12 +2350,12 @@ super().__setitem__(key, value) self._check_size() -
        [docs] def update(self, *args, **kwargs): +
        [docs] def update(self, *args, **kwargs): super().update(*args, **kwargs) self._check_size()
        -
        [docs]def get_game_dir_path(): +
        [docs]def get_game_dir_path(): """ This is called by settings_default in order to determine the path of the game directory. @@ -2064,7 +2365,7 @@ """ # current working directory, assumed to be somewhere inside gamedir. - for _ in range(10): + for inum in range(10): gpath = os.getcwd() if "server" in os.listdir(gpath): if os.path.isfile(os.path.join("server", "conf", "settings.py")): @@ -2074,21 +2375,21 @@ raise RuntimeError("server/conf/settings.py not found: Must start from inside game dir.")
        -
        [docs]def get_all_typeclasses(parent=None): +
        [docs]def get_all_typeclasses(parent=None): """ List available typeclasses from all available modules. Args: - parent (str, optional): If given, only return typeclasses inheriting (at any distance) - from this parent. + parent (str, optional): If given, only return typeclasses inheriting + (at any distance) from this parent. Returns: - typeclasses (dict): On the form {"typeclass.path": typeclass, ...} + dict: On the form `{"typeclass.path": typeclass, ...}` Notes: - This will dynamicall retrieve all abstract django models inheriting at any distance - from the TypedObject base (aka a Typeclass) so it will work fine with any custom - classes being added. + This will dynamically retrieve all abstract django models inheriting at + any distance from the TypedObject base (aka a Typeclass) so it will + work fine with any custom classes being added. """ from evennia.typeclasses.models import TypedObject @@ -2107,16 +2408,49 @@ return typeclasses
        -
        [docs]def interactive(func): +
        [docs]def get_all_cmdsets(parent=None): """ - Decorator to make a method pausable with yield(seconds) and able to ask for - user-input with `response=yield(question)`. For the question-asking to - work, 'caller' must the name of an argument or kwarg to the decorated - function. + List available cmdsets from all available modules. - Example: - :: + Args: + parent (str, optional): If given, only return cmdsets inheriting (at + any distance) from this parent. + Returns: + dict: On the form {"cmdset.path": cmdset, ...} + + Notes: + This will dynamically retrieve all abstract django models inheriting at + any distance from the CmdSet base so it will work fine with any custom + classes being added. + + """ + from evennia.commands.cmdset import CmdSet + + base_cmdset = class_from_module(parent) if parent else CmdSet + + cmdsets = { + "{}.{}".format(subclass.__module__, subclass.__name__): subclass + for subclass in base_cmdset.__subclasses__() + } + return cmdsets
        + + +
        [docs]def interactive(func): + """ + Decorator to make a method pausable with `yield(seconds)` + and able to ask for user-input with `response=yield(question)`. + For the question-asking to work, one of the args or kwargs to the + decorated function must be named 'caller'. + + Raises: + ValueError: If asking an interactive question but the decorated + function has no arg or kwarg named 'caller'. + ValueError: If passing non int/float to yield using for pausing. + + Examples: + + ```python @interactive def myfunc(caller): caller.msg("This is a test") @@ -2128,9 +2462,10 @@ yield(5) else: # ... + ``` Notes: - This turns the method into a generator! + This turns the decorated function or method into a generator. """ from evennia.utils.evmenu import get_input @@ -2174,6 +2509,107 @@ return ret return decorator
        + + +
        [docs]def safe_convert_to_types(converters, *args, raise_errors=True, **kwargs): + """ + Helper function to safely convert inputs to expected data types. + + Args: + converters (tuple): A tuple `((converter, converter,...), {kwarg: converter, ...})` to + match a converter to each element in `*args` and `**kwargs`. + Each converter will will be called with the arg/kwarg-value as the only argument. + If there are too few converters given, the others will simply not be converter. If the + converter is given as the string 'py', it attempts to run + `safe_eval`/`literal_eval` on the input arg or kwarg value. It's possible to + skip the arg/kwarg part of the tuple, an empty tuple/dict will then be assumed. + *args: The arguments to convert with `argtypes`. + raise_errors (bool, optional): If set, raise any errors. This will + abort the conversion at that arg/kwarg. Otherwise, just skip the + conversion of the failing arg/kwarg. This will be set by the FuncParser if + this is used as a part of a FuncParser callable. + **kwargs: The kwargs to convert with `kwargtypes` + + Returns: + tuple: `(args, kwargs)` in converted form. + + Raises: + utils.funcparser.ParsingError: If parsing failed in the `'py'` + converter. This also makes this compatible with the FuncParser + interface. + any: Any other exception raised from other converters, if raise_errors is True. + + Notes: + This function is often used to validate/convert input from untrusted sources. For + security, the "py"-converter is deliberately limited and uses `safe_eval`/`literal_eval` + which only supports simple expressions or simple containers with literals. NEVER + use the python `eval` or `exec` methods as a converter for any untrusted input! Allowing + untrusted sources to execute arbitrary python on your server is a severe security risk, + + Example: + :: + + $funcname(1, 2, 3.0, c=[1,2,3]) + + def _funcname(*args, **kwargs): + args, kwargs = safe_convert_input(((int, int, float), {'c': 'py'}), *args, **kwargs) + # ... + + """ + def _safe_eval(inp): + if not inp: + return '' + if not isinstance(inp, str): + # already converted + return inp + + try: + return literal_eval(inp) + except Exception as err: + literal_err = f"{err.__class__.__name__}: {err}" + try: + return simple_eval(inp) + except Exception as err: + simple_err = f"{str(err.__class__.__name__)}: {err}" + pass + + if raise_errors: + from evennia.utils.funcparser import ParsingError + err = (f"Errors converting '{inp}' to python:\n" + f"literal_eval raised {literal_err}\n" + f"simple_eval raised {simple_err}") + raise ParsingError(err) + + # handle an incomplete/mixed set of input converters + if not converters: + return args, kwargs + arg_converters, *kwarg_converters = converters + arg_converters = make_iter(arg_converters) + kwarg_converters = kwarg_converters[0] if kwarg_converters else {} + + # apply the converters + if args and arg_converters: + args = list(args) + arg_converters = make_iter(arg_converters) + for iarg, arg in enumerate(args[:len(arg_converters)]): + converter = arg_converters[iarg] + converter = _safe_eval if converter in ('py', 'python') else converter + try: + args[iarg] = converter(arg) + except Exception: + if raise_errors: + raise + args = tuple(args) + if kwarg_converters and isinstance(kwarg_converters, dict): + for key, converter in kwarg_converters.items(): + converter = _safe_eval if converter in ('py', 'python') else converter + if key in {**kwargs}: + try: + kwargs[key] = converter(kwargs[key]) + except Exception: + if raise_errors: + raise + return args, kwargs
        @@ -2211,7 +2647,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -2230,6 +2665,7 @@ +
        develop branch
        @@ -63,18 +64,20 @@ try: return str(entry) except Exception as err: - raise ValueError(f"Input could not be converted to text ({err})")
        + raise ValueError(_("Input could not be converted to text ({err})").format(err=err))
        [docs]def color(entry, option_key="Color", **kwargs): """ The color should be just a color character, so 'r' if red color is desired. + """ if not entry: - raise ValueError(f"Nothing entered for a {option_key}!") + raise ValueError(_("Nothing entered for a {option_key}!").format(option_key=option_key)) test_str = strip_ansi(f"|{entry}|n") if test_str: - raise ValueError(f"'{entry}' is not a valid {option_key}.") + raise ValueError(_("'{entry}' is not a valid {option_key}.").format( + entry=entry, option_key=option_key)) return entry
        @@ -89,12 +92,10 @@ account (AccountDB): The Account performing this lookup. Unless `from_tz` is provided, the account's timezone option will be used. from_tz (pytz.timezone): An instance of a pytz timezone object from the - user. If not provided, tries to use the timezone option of the `account`. + user. If not provided, tries to use the timezone option of `account`. If neither one is provided, defaults to UTC. - Returns: datetime in UTC. - Raises: ValueError: If encountering a malformed timezone, date string or other format error. @@ -126,13 +127,17 @@ entry = f"{split_time[0]} {split_time[1]} {split_time[2]} {split_time[3]}" else: raise ValueError( - f"{option_key} must be entered in a 24-hour format such as: {now.strftime('%b %d %H:%M')}" + _("{option_key} must be entered in a 24-hour format such as: {timeformat}").format( + option_key=option_key, + timeformat=now.strftime('%b %d %H:%M')) ) try: local = _dt.datetime.strptime(entry, "%b %d %H:%M %Y") except ValueError: raise ValueError( - f"{option_key} must be entered in a 24-hour format such as: {now.strftime('%b %d %H:%M')}" + _("{option_key} must be entered in a 24-hour format such as: {timeformat}").format( + option_key=option_key, + timeformat=now.strftime('%b %d %H:%M')) ) local_tz = from_tz.localize(local) return local_tz.astimezone(utc)
        @@ -143,8 +148,9 @@ Take a string and derive a datetime timedelta from it. Args: - entry (string): This is a string from user-input. The intended format is, for example: "5d 2w 90s" for - 'five days, two weeks, and ninety seconds.' Invalid sections are ignored. + entry (string): This is a string from user-input. The intended format is, for example: + "5d 2w 90s" for 'five days, two weeks, and ninety seconds.' Invalid sections are + ignored. option_key (str): Name to display this query as. Returns: @@ -172,7 +178,10 @@ elif _re.match(r"^[\d]+y$", interval): days += int(interval.rstrip("y")) * 365 else: - raise ValueError(f"Could not convert section '{interval}' to a {option_key}.") + raise ValueError( + _("Could not convert section '{interval}' to a {option_key}.").format( + interval=interval, option_key=option_key) + ) return _dt.timedelta(days, seconds, 0, 0, minutes, hours, weeks)
        @@ -180,45 +189,56 @@
        [docs]def future(entry, option_key="Future Datetime", from_tz=None, **kwargs): time = datetime(entry, option_key, from_tz=from_tz) if time < _dt.datetime.utcnow().replace(tzinfo=_dt.timezone.utc): - raise ValueError(f"That {option_key} is in the past! Must give a Future datetime!") + raise ValueError(_("That {option_key} is in the past! Must give a Future datetime!").format( + option_key=option_key)) return time
        [docs]def signed_integer(entry, option_key="Signed Integer", **kwargs): if not entry: - raise ValueError(f"Must enter a whole number for {option_key}!") + raise ValueError(_("Must enter a whole number for {option_key}!").format( + option_key=option_key)) try: num = int(entry) except ValueError: - raise ValueError(f"Could not convert '{entry}' to a whole number for {option_key}!") + raise ValueError(_("Could not convert '{entry}' to a whole " + "number for {option_key}!").format( + entry=entry, option_key=option_key)) return num
        [docs]def positive_integer(entry, option_key="Positive Integer", **kwargs): num = signed_integer(entry, option_key) if not num >= 1: - raise ValueError(f"Must enter a whole number greater than 0 for {option_key}!") + raise ValueError(_("Must enter a whole number greater than 0 for {option_key}!").format( + option_key=option_key)) return num
        [docs]def unsigned_integer(entry, option_key="Unsigned Integer", **kwargs): num = signed_integer(entry, option_key) if not num >= 0: - raise ValueError(f"{option_key} must be a whole number greater than or equal to 0!") + raise ValueError(_("{option_key} must be a whole number greater than " + "or equal to 0!").format( + option_key=option_key)) return num
        [docs]def boolean(entry, option_key="True/False", **kwargs): """ Simplest check in computer logic, right? This will take user input to flick the switch on or off + Args: entry (str): A value such as True, On, Enabled, Disabled, False, 0, or 1. option_key (str): What kind of Boolean we are setting. What Option is this for? Returns: Boolean + """ - error = f"Must enter 0 (false) or 1 (true) for {option_key}. Also accepts True, False, On, Off, Yes, No, Enabled, and Disabled" + error = (_("Must enter a true/false input for {option_key}. Accepts {alternatives}.").format( + option_key=option_key, + alternatives="0/1, True/False, On/Off, Yes/No, Enabled/Disabled")) if not isinstance(entry, str): raise ValueError(error) entry = entry.upper() @@ -239,41 +259,44 @@ Returns: A PYTZ timezone. + """ if not entry: - raise ValueError(f"No {option_key} entered!") + raise ValueError(_("No {option_key} entered!").format(option_key=option_key)) found = _partial(list(_TZ_DICT.keys()), entry, ret_index=False) if len(found) > 1: raise ValueError( - f"That matched: {', '.join(str(t) for t in found)}. Please be more specific!" - ) + _("That matched: {matches}. Please be more specific!").format( + matches=', '.join(str(t) for t in found))) if found: return _TZ_DICT[found[0]] - raise ValueError(f"Could not find timezone '{entry}' for {option_key}!")
        + raise ValueError(_("Could not find timezone '{entry}' for {option_key}!").format( + entry=entry, option_key=option_key))
        [docs]def email(entry, option_key="Email Address", **kwargs): if not entry: - raise ValueError("Email address field empty!") + raise ValueError(_("Email address field empty!")) valid = validate_email_address(entry) if not valid: - raise ValueError(f"That isn't a valid {option_key}!") + raise ValueError(_("That isn't a valid {option_key}!").format(option_key=option_key)) return entry
        [docs]def lock(entry, option_key="locks", access_options=None, **kwargs): entry = entry.strip() if not entry: - raise ValueError(f"No {option_key} entered to set!") + raise ValueError(_("No {option_key} entered to set!").format(option_key=option_key)) for locksetting in entry.split(";"): access_type, lockfunc = locksetting.split(":", 1) if not access_type: - raise ValueError("Must enter an access type!") + raise ValueError(_("Must enter an access type!")) if access_options: if access_type not in access_options: - raise ValueError(f"Access type must be one of: {', '.join(access_options)}") + raise ValueError(_("Access type must be one of: {alternatives}").format( + alternatives=', '.join(access_options))) if not lockfunc: - raise ValueError("Lock func not entered.") + raise ValueError(_("Lock func not entered.")) return entry
        @@ -312,7 +335,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -331,6 +353,7 @@ +
        develop branch
        @@ -95,7 +96,6 @@ more Objects depending on settings. An Account has no in-game existence.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -112,6 +112,7 @@ more Objects depending on settings. An Account has no in-game existence.

        +
        develop branch
        @@ -91,7 +92,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -108,6 +108,7 @@ +
        develop branch
        @@ -412,7 +413,6 @@ class built by **create_forward_many_to_many_manager()** define
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -429,6 +429,7 @@ class built by **create_forward_many_to_many_manager()** define +
        develop branch
        @@ -45,15 +46,11 @@ command line. The processing of a command works as follows:

        1. The calling object (caller) is analyzed based on its callertype.

        2. Cmdsets are gathered from different sources: -- channels: all available channel names are auto-created into a cmdset, to allow

          +- object cmdsets: all objects at caller’s location are scanned for non-empty

          -

          for giving the channel name and have the following immediately -sent to the channel. The sending is performed by the CMD_CHANNEL -system command.

          +

          cmdsets. This includes cmdsets on exits.

            -
          • object cmdsets: all objects at caller’s location are scanned for non-empty -cmdsets. This includes cmdsets on exits.

          • caller: the caller is searched for its own currently active cmdset.

          • account: lastly the cmdsets defined on caller.account are added.

          @@ -67,19 +64,10 @@ input string for possible command matches.

        3. cmdset, or fallback to error message. Exit.

        4. If no match was found -> check for CMD_NOMATCH in current cmdset or fallback to error message. Exit.

        5. -
        6. A single match was found. If this is a channel-command (i.e. the -ommand name is that of a channel), –> check for CMD_CHANNEL in -current cmdset or use channelhandler default. Exit.

        7. At this point we have found a normal command. We assign useful variables to it that will be available to the command coder at run-time.

        8. -
        -
          -
        1. We have a unique cmdobject, primed for use. Call all hooks:

        2. -
        -
        -

        at_pre_cmd(), cmdobj.parse(), cmdobj.func() and finally at_post_cmd().

        -
        -
          +
        1. We have a unique cmdobject, primed for use. Call all hooks: +at_pre_cmd(), cmdobj.parse(), cmdobj.func() and finally at_post_cmd().

        2. Return deferred that will fire with the return from cmdobj.func() (unused by default).

        @@ -183,7 +171,6 @@ default Evennia.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -200,6 +187,7 @@ default Evennia.

        +
        develop branch
        @@ -96,8 +97,8 @@ in the match, otherwise strip them before matching.

        -
        -evennia.commands.cmdparser.try_num_prefixes(raw_string)[source]
        +
        +evennia.commands.cmdparser.try_num_differentiators(raw_string)[source]

        Test if user tried to separate multi-matches with a number separator (default 1-name, 2-name etc). This is usually called last, if no other match was found.

        @@ -206,7 +207,6 @@ the remaining arguments, and the matched cmdobject from the cmdset.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -223,6 +223,7 @@ the remaining arguments, and the matched cmdobject from the cmdset.

        +
        develop branch
        @@ -423,7 +424,6 @@ self.add().

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -440,6 +440,7 @@ self.add().

        +
        develop branch
        @@ -176,7 +177,7 @@ to the central cmdhandler.get_and_merge_cmdsets()!

        -add(cmdset, emit_to_obj=None, permanent=False, default_cmdset=False)[source]
        +add(cmdset, emit_to_obj=None, persistent=True, default_cmdset=False, **kwargs)[source]

        Add a cmdset to the handler, on top of the old ones, unless it is set as the default one (it will then end up at the bottom of the stack)

        @@ -185,7 +186,7 @@ is set as the default one (it will then end up at the bottom of the stack)

      • cmdset (CmdSet or str) – Can be a cmdset object or the python path to such an object.

      • emit_to_obj (Object, optional) – An object to receive error messages.

      • -
      • permanent (bool, optional) – This cmdset will remain across a server reboot.

      • +
      • persistent (bool, optional) – Let cmdset remain across server reload.

      • default_cmdset (Cmdset, optional) – Insert this to replace the default cmdset position (there is only one such position, always at the bottom of the stack).

      • @@ -206,14 +207,14 @@ it’s a ‘quirk’ that has to be documented.

        -add_default(cmdset, emit_to_obj=None, permanent=True)[source]
        +add_default(cmdset, emit_to_obj=None, persistent=True, **kwargs)[source]

        Shortcut for adding a default cmdset.

        Parameters
        • cmdset (Cmdset) – The Cmdset to add.

        • emit_to_obj (Object, optional) – Gets error messages

        • -
        • permanent (bool, optional) – The new Cmdset should survive a server reboot.

        • +
        • persistent (bool, optional) – The new Cmdset should survive a server reboot.

        @@ -391,7 +392,6 @@ handled automatically by @reload).

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -408,6 +408,7 @@ handled automatically by @reload).

        +
        develop branch
        @@ -41,6 +42,13 @@

        evennia.commands.command

        The base Command class.

        All commands in Evennia inherit from the ‘Command’ class in this module.

        +
        +
        +exception evennia.commands.command.InterruptCommand[source]
        +

        Bases: Exception

        +

        Cleanly interrupt a command.

        +
        +
        class evennia.commands.command.CommandMeta(*args, **kwargs)[source]
        @@ -58,7 +66,7 @@
        class evennia.commands.command.Command(**kwargs)[source]

        Bases: object

        -

        Base command

        +

        (you may see this if a child command had no help text defined)

        Usage:

        command [args]

        @@ -375,17 +383,6 @@ commands the caller can use.

        -
        -
        -client_height()[source]
        -

        Get the client screenheight for the session using this command.

        -
        -
        Returns
        -

        client height (int) – The height (in characters) of the client window.

        -
        -
        -
        -
        styled_table(*args, **kwargs)[source]
        @@ -438,13 +435,11 @@ detailing the contents of the table.

        save_for_next = False
        - +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'command', 'tags': '', 'text': '\n ## Base command\n\n (you may see this if a child command had no help text defined)\n\n Usage:\n command [args]\n\n This is the base command class. Inherit from this\n to create new commands.\n\n The cmdhandler makes the following variables available to the\n command methods (so you can always assume them to be there):\n self.caller - the game object calling the command\n self.cmdstring - the command name used to trigger this command (allows\n you to know which alias was used, for example)\n cmd.args - everything supplied to the command following the cmdstring\n (this is usually what is parsed in self.parse())\n cmd.cmdset - the cmdset from which this command was matched (useful only\n seldomly, notably for help-type commands, to create dynamic\n help entries and lists)\n cmd.obj - the object on which this command is defined. If a default command,\n this is usually the same as caller.\n cmd.rawstring - the full raw string input, including any args and no parsing.\n\n The following class properties can/should be defined on your child class:\n\n key - identifier for command (e.g. "look")\n aliases - (optional) list of aliases (e.g. ["l", "loo"])\n locks - lock string (default is "cmd:all()")\n help_category - how to organize this help entry in help system\n (default is "General")\n auto_help - defaults to True. Allows for turning off auto-help generation\n arg_regex - (optional) raw string regex defining how the argument part of\n the command should look in order to match for this command\n (e.g. must it be a space between cmdname and arg?)\n auto_help_display_key - (optional) if given, this replaces the string shown\n in the auto-help listing. This is particularly useful for system-commands\n whose actual key is not really meaningful.\n\n (Note that if auto_help is on, this initial string is also used by the\n system to create the help entry for the command, so it\'s a good idea to\n format it similar to this one). This behavior can be changed by\n overriding the method \'get_help\' of a command: by default, this\n method returns cmd.__doc__ (that is, this very docstring, or\n the docstring of your command). You can, however, extend or\n replace this without disabling auto_help.\n '}
        +
        -
        -
        -exception evennia.commands.command.InterruptCommand[source]
        -

        Bases: Exception

        -

        Cleanly interrupt a command.

        @@ -492,7 +487,6 @@ detailing the contents of the table.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -509,6 +503,7 @@ detailing the contents of the table.

        +
        develop branch
        @@ -70,7 +71,7 @@ method. Otherwise all text will be returned to all connected sessions.

        -aliases = ['ls', 'l']
        +aliases = ['l', 'ls']
        @@ -99,6 +100,11 @@ method. Otherwise all text will be returned to all connected sessions.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'l ls', 'category': 'general', 'key': 'look', 'tags': '', 'text': '\n look while out-of-character\n\n Usage:\n look\n\n Look in the ooc state.\n '}
        +
        +
        @@ -153,6 +159,11 @@ as you the account have access right to puppet it.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'puppet', 'category': 'general', 'key': 'ic', 'tags': '', 'text': '\n control an object you have permission to puppet\n\n Usage:\n ic <character>\n\n Go in-character (IC) as a given Character.\n\n This will attempt to "become" a different object assuming you have\n the right to do so. Note that it\'s the ACCOUNT character that puppets\n characters/objects and which needs to have the correct permission!\n\n You cannot become an object that is already controlled by another\n account. In principle <character> can be any in-game object as long\n as you the account have access right to puppet it.\n '}
        +
        +
        @@ -202,6 +213,11 @@ as you the account have access right to puppet it.

        lock_storage = 'cmd:pperm(Player)'
        +
        +
        +search_index_entry = {'aliases': 'unpuppet', 'category': 'general', 'key': 'ooc', 'tags': '', 'text': '\n stop puppeting and go ooc\n\n Usage:\n ooc\n\n Go out-of-character (OOC).\n\n This will leave your current character and put you in a incorporeal OOC state.\n '}
        +
        +
        @@ -250,6 +266,11 @@ as you the account have access right to puppet it.

        lock_storage = 'cmd:pperm(Player)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'password', 'tags': '', 'text': '\n change your password\n\n Usage:\n password <old password> = <new password>\n\n Changes your password. Make sure to pick a safe one.\n '}
        +
        +
        @@ -306,6 +327,11 @@ game. Use the /all switch to disconnect from all sessions.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'quit', 'tags': '', 'text': '\n quit the game\n\n Usage:\n quit\n\n Switch:\n all - disconnect all connected sessions\n\n Gracefully disconnect your current session from the\n game. Use the /all switch to disconnect from all sessions.\n '}
        +
        +
        @@ -357,6 +383,11 @@ if you want.

        lock_storage = 'cmd:pperm(Player)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'charcreate', 'tags': '', 'text': '\n create a new character\n\n Usage:\n charcreate <charname> [= desc]\n\n Create a new character, optionally giving it a description. You\n may use upper-case letters in the name - you will nevertheless\n always be able to access your character using lower-case letters\n if you want.\n '}
        +
        +
        @@ -415,6 +446,11 @@ later connecting with a client with different capabilities.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'options', 'category': 'general', 'key': 'option', 'tags': '', 'text': '\n Set an account option\n\n Usage:\n option[/save] [name = value]\n\n Switches:\n save - Save the current option settings for future logins.\n clear - Clear the saved options.\n\n This command allows for viewing and setting client interface\n settings. Note that saved options may not be able to be used if\n later connecting with a client with different capabilities.\n\n\n '}
        +
        +
        @@ -463,6 +499,11 @@ later connecting with a client with different capabilities.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'sessions', 'tags': '', 'text': '\n check your connected session(s)\n\n Usage:\n sessions\n\n Lists the sessions currently connected to your account.\n\n '}
        +
        +
        @@ -513,6 +554,11 @@ also for those with all permissions.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'doing', 'category': 'general', 'key': 'who', 'tags': '', 'text': '\n list who is currently online\n\n Usage:\n who\n doing\n\n Shows who is currently online. Doing is an alias that limits info\n also for those with all permissions.\n '}
        +
        +
        @@ -521,7 +567,7 @@ also for those with all permissions.

        Bases: evennia.commands.default.muxcommand.MuxCommand

        testing which colors your client support

        -
        Usage:

        color ansi||xterm256

        +
        Usage:

        color ansi | xterm256

        Prints a color map along with in-mud color codes to use to produce @@ -592,6 +638,11 @@ Takes a table of columns [[val,val,…],[val,val,…],…]

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'color', 'tags': '', 'text': '\n testing which colors your client support\n\n Usage:\n color ansi | xterm256\n\n Prints a color map along with in-mud color codes to use to produce\n them. It also tests what is supported in your client. Choices are\n 16-color ansi (supported in most muds) or the 256-color xterm256\n standard. No checking is done to determine your client supports\n color - if not you will see rubbish appear.\n '}
        +
        +
        @@ -647,6 +698,11 @@ Use the unquell command to revert back to normal operation.

        lock_storage = 'cmd:pperm(Player)'
        +
        +
        +search_index_entry = {'aliases': 'unquell', 'category': 'general', 'key': 'quell', 'tags': '', 'text': "\n use character's permissions instead of account's\n\n Usage:\n quell\n unquell\n\n Normally the permission level of the Account is used when puppeting a\n Character/Object to determine access. This command will switch the lock\n system to make use of the puppeted Object's permissions instead. This is\n useful mainly for testing.\n Hierarchical permission quelling only work downwards, thus an Account cannot\n use a higher-permission Character to escalate their permission level.\n Use the unquell command to revert back to normal operation.\n "}
        +
        +
        @@ -690,6 +746,11 @@ Use the unquell command to revert back to normal operation.

        lock_storage = 'cmd:pperm(Player)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'chardelete', 'tags': '', 'text': '\n delete a character - this cannot be undone!\n\n Usage:\n chardelete <charname>\n\n Permanently deletes one of your characters.\n '}
        +
        +
        @@ -747,6 +808,11 @@ to all the variables defined therein.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'style', 'tags': '', 'text': '\n In-game style options\n\n Usage:\n style\n style <option> = <value>\n\n Configure stylings for in-game display elements like table borders, help\n entriest etc. Use without arguments to see all available options.\n\n '}
        +
        + @@ -794,7 +860,6 @@ to all the variables defined therein.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -811,6 +876,7 @@ to all the variables defined therein.

        +
        develop branch
        @@ -90,6 +91,11 @@ supplied it will be echoed to the user unless /quiet is set.

        lock_storage = 'cmd:perm(boot) or perm(Admin)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'admin', 'key': 'boot', 'tags': '', 'text': '\n kick an account from the server.\n\n Usage\n boot[/switches] <account obj> [: reason]\n\n Switches:\n quiet - Silently boot without informing account\n sid - boot by session id instead of name or dbref\n\n Boot an account object from the server. If a reason is\n supplied it will be echoed to the user unless /quiet is set.\n '}
        +
        +
        @@ -164,6 +170,11 @@ values in each tuple is set to the empty string.

        lock_storage = 'cmd:perm(ban) or perm(Developer)'
        +
        +
        +search_index_entry = {'aliases': 'bans', 'category': 'admin', 'key': 'ban', 'tags': '', 'text': "\n ban an account from the server\n\n Usage:\n ban [<name or ip> [: reason]]\n\n Without any arguments, shows numbered list of active bans.\n\n This command bans a user from accessing the game. Supply an optional\n reason to be able to later remember why the ban was put in place.\n\n It is often preferable to ban an account from the server than to\n delete an account with accounts/delete. If banned by name, that account\n account can no longer be logged into.\n\n IP (Internet Protocol) address banning allows blocking all access\n from a specific address or subnet. Use an asterisk (*) as a\n wildcard.\n\n Examples:\n ban thomas - ban account 'thomas'\n ban/ip 134.233.2.111 - ban specific ip address\n ban/ip 134.233.2.* - ban all in a subnet\n ban/ip 134.233.*.* - even wider ban\n\n A single IP filter can be easy to circumvent by changing computers\n or requesting a new IP address. Setting a wide IP block filter with\n wildcards might be tempting, but remember that it may also\n accidentally block innocent users connecting from the same country\n or region.\n\n "}
        +
        +
        @@ -210,6 +221,11 @@ unban.

        lock_storage = 'cmd:perm(unban) or perm(Developer)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'admin', 'key': 'unban', 'tags': '', 'text': '\n remove a ban from an account\n\n Usage:\n unban <banid>\n\n This will clear an account name/ip ban previously set with the ban\n command. Use this command without an argument to view a numbered\n list of bans. Use the numbers in this list to select which one to\n unban.\n\n '}
        +
        +
        @@ -268,6 +284,11 @@ to accounts respectively.

        lock_storage = 'cmd:perm(emit) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': 'remit pemit', 'category': 'admin', 'key': 'emit', 'tags': '', 'text': '\n admin command for emitting message to multiple objects\n\n Usage:\n emit[/switches] [<obj>, <obj>, ... =] <message>\n remit [<obj>, <obj>, ... =] <message>\n pemit [<obj>, <obj>, ... =] <message>\n\n Switches:\n room - limit emits to rooms only (default)\n accounts - limit emits to accounts only\n contents - send to the contents of matched objects too\n\n Emits a message to the selected objects or to\n your immediate surroundings. If the object is a room,\n send to its contents. remit and pemit are just\n limited forms of emit, for sending to rooms and\n to accounts respectively.\n '}
        +
        +
        @@ -311,6 +332,11 @@ to accounts respectively.

        lock_storage = 'cmd:perm(newpassword) or perm(Admin)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'admin', 'key': 'userpassword', 'tags': '', 'text': "\n change the password of an account\n\n Usage:\n userpassword <user obj> = <new password>\n\n Set an account's password.\n "}
        +
        +
        @@ -364,6 +390,11 @@ or account. If no permission is given, list all permissions on <object>.lock_storage = 'cmd:perm(perm) or perm(Developer)'
        +
        +
        +search_index_entry = {'aliases': 'setperm', 'category': 'admin', 'key': 'perm', 'tags': '', 'text': '\n set the permissions of an account/object\n\n Usage:\n perm[/switch] <object> [= <permission>[,<permission>,...]]\n perm[/switch] *<account> [= <permission>[,<permission>,...]]\n\n Switches:\n del - delete the given permission from <object> or <account>.\n account - set permission on an account (same as adding * to name)\n\n This command sets/clears individual permission strings on an object\n or account. If no permission is given, list all permissions on <object>.\n '}
        +
        +
        @@ -408,6 +439,11 @@ including all currently unlogged in.

        lock_storage = 'cmd:perm(wall) or perm(Admin)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'admin', 'key': 'wall', 'tags': '', 'text': '\n make an announcement to all\n\n Usage:\n wall <message>\n\n Announces a message to all connected sessions\n including all currently unlogged in.\n '}
        +
        +
        @@ -457,6 +493,11 @@ including all currently unlogged in.

        lock_storage = 'cmd:perm(spawn) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'building', 'key': 'force', 'tags': '', 'text': '\n forces an object to execute a command\n\n Usage:\n force <object>=<command string>\n\n Example:\n force bob=get stick\n '}
        +
        + @@ -504,7 +545,6 @@ including all currently unlogged in.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -521,6 +561,7 @@ including all currently unlogged in.

        +
        develop branch
        @@ -104,6 +105,11 @@ skipping, reloading etc.

        lock_storage = 'cmd:perm(batchcommands) or perm(Developer)'
        +
        +
        +search_index_entry = {'aliases': 'batchcommand batchcmd', 'category': 'building', 'key': 'batchcommands', 'tags': '', 'text': '\n build from batch-command file\n\n Usage:\n batchcommands[/interactive] <python.path.to.file>\n\n Switch:\n interactive - this mode will offer more control when\n executing the batch file, like stepping,\n skipping, reloading etc.\n\n Runs batches of commands from a batch-cmd text file (*.ev).\n\n '}
        +
        +
        @@ -162,6 +168,11 @@ object copies behind when testing out the script.

        lock_storage = 'cmd:superuser()'
        +
        +
        +search_index_entry = {'aliases': 'batchcodes', 'category': 'building', 'key': 'batchcode', 'tags': '', 'text': '\n build from batch-code file\n\n Usage:\n batchcode[/interactive] <python path to file>\n\n Switch:\n interactive - this mode will offer more control when\n executing the batch file, like stepping,\n skipping, reloading etc.\n debug - auto-delete all objects that has been marked as\n deletable in the script file (see example files for\n syntax). This is useful so as to to not leave multiple\n object copies behind when testing out the script.\n\n Runs batches of commands from a batch-code text file (*.py).\n\n '}
        +
        + @@ -209,7 +220,6 @@ object copies behind when testing out the script.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -226,6 +236,7 @@ object copies behind when testing out the script.

        +
        develop branch
        @@ -86,6 +87,11 @@ the cases, see the module doc.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'command', 'tags': '', 'text': "\n This is a parent class for some of the defining objmanip commands\n since they tend to have some more variables to define new objects.\n\n Each object definition can have several components. First is\n always a name, followed by an optional alias list and finally an\n some optional data, such as a typeclass or a location. A comma ','\n separates different objects. Like this:\n\n name1;alias;alias;alias:option, name2;alias;alias ...\n\n Spaces between all components are stripped.\n\n A second situation is attribute manipulation. Such commands\n are simpler and offer combinations\n\n objname/attr/attr/attr, objname/attr, ...\n\n "}
        +
        +
        @@ -147,6 +153,11 @@ by everyone.

        lock_storage = 'cmd:perm(setobjalias) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': 'setobjalias', 'category': 'building', 'key': 'alias', 'tags': '', 'text': "\n adding permanent aliases for object\n\n Usage:\n alias <obj> [= [alias[,alias,alias,...]]]\n alias <obj> =\n alias/category <obj> = [alias[,alias,...]:<category>\n\n Switches:\n category - requires ending input with :category, to store the\n given aliases with the given category.\n\n Assigns aliases to an object so it can be referenced by more\n than one name. Assign empty to remove all aliases from object. If\n assigning a category, all aliases given will be using this category.\n\n Observe that this is not the same thing as personal aliases\n created with the 'nick' command! Aliases set with alias are\n changing the object in question, making those aliases usable\n by everyone.\n "}
        +
        +
        @@ -192,6 +203,11 @@ one exact copy of the original object will be created with the name lock_storage = 'cmd:perm(copy) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'building', 'key': 'copy', 'tags': '', 'text': "\n copy an object and its properties\n\n Usage:\n copy <original obj> [= <new_name>][;alias;alias..]\n [:<new_location>] [,<new_name2> ...]\n\n Create one or more copies of an object. If you don't supply any targets,\n one exact copy of the original object will be created with the name *_copy.\n "}
        +
        +
        @@ -284,6 +300,11 @@ required and get the attribute from the object.

        lock_storage = 'cmd:perm(cpattr) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'building', 'key': 'cpattr', 'tags': '', 'text': "\n copy attributes between objects\n\n Usage:\n cpattr[/switch] <obj>/<attr> = <obj1>/<attr1> [,<obj2>/<attr2>,<obj3>/<attr3>,...]\n cpattr[/switch] <obj>/<attr> = <obj1> [,<obj2>,<obj3>,...]\n cpattr[/switch] <attr> = <obj1>/<attr1> [,<obj2>/<attr2>,<obj3>/<attr3>,...]\n cpattr[/switch] <attr> = <obj1>[,<obj2>,<obj3>,...]\n\n Switches:\n move - delete the attribute from the source object after copying.\n\n Example:\n cpattr coolness = Anna/chillout, Anna/nicety, Tom/nicety\n ->\n copies the coolness attribute (defined on yourself), to attributes\n on Anna and Tom.\n\n Copy the attribute one object to one or more attributes on another object.\n If you don't supply a source object, yourself is used.\n "}
        +
        +
        @@ -338,6 +359,11 @@ object. If you don’t supply a source object, yourself is used.

        lock_storage = 'cmd:perm(mvattr) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'building', 'key': 'mvattr', 'tags': '', 'text': "\n move attributes between objects\n\n Usage:\n mvattr[/switch] <obj>/<attr> = <obj1>/<attr1> [,<obj2>/<attr2>,<obj3>/<attr3>,...]\n mvattr[/switch] <obj>/<attr> = <obj1> [,<obj2>,<obj3>,...]\n mvattr[/switch] <attr> = <obj1>/<attr1> [,<obj2>/<attr2>,<obj3>/<attr3>,...]\n mvattr[/switch] <attr> = <obj1>[,<obj2>,<obj3>,...]\n\n Switches:\n copy - Don't delete the original after moving.\n\n Move an attribute from one object to one or more attributes on another\n object. If you don't supply a source object, yourself is used.\n "}
        +
        +
        @@ -406,6 +432,11 @@ object of this type like this:

        lock_storage = 'cmd:perm(create) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'building', 'key': 'create', 'tags': '', 'text': "\n create new objects\n\n Usage:\n create[/drop] <objname>[;alias;alias...][:typeclass], <objname>...\n\n switch:\n drop - automatically drop the new object into your current\n location (this is not echoed). This also sets the new\n object's home to the current location rather than to you.\n\n Creates one or more new objects. If typeclass is given, the object\n is created as a child of this typeclass. The typeclass script is\n assumed to be located under types/ and any further\n directory structure is given in Python notation. So if you have a\n correct typeclass 'RedButton' defined in\n types/examples/red_button.py, you could create a new\n object of this type like this:\n\n create/drop button;red : examples.red_button.RedButton\n\n "}
        +
        +
        @@ -462,6 +493,11 @@ describe the current room.

        lock_storage = 'cmd:perm(desc) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': 'describe', 'category': 'building', 'key': 'desc', 'tags': '', 'text': '\n describe an object or the current room.\n\n Usage:\n desc [<obj> =] <description>\n\n Switches:\n edit - Open up a line editor for more advanced editing.\n\n Sets the "desc" attribute on an object. If an object is not given,\n describe the current room.\n '}
        +
        +
        @@ -494,7 +530,7 @@ You can specify the /force switch to bypass this confirmation.

        -aliases = ['delete', 'del']
        +aliases = ['del', 'delete']
        @@ -533,6 +569,11 @@ You can specify the /force switch to bypass this confirmation.

        lock_storage = 'cmd:perm(destroy) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': 'del delete', 'category': 'building', 'key': 'destroy', 'tags': '', 'text': '\n permanently delete objects\n\n Usage:\n destroy[/switches] [obj, obj2, obj3, [dbref-dbref], ...]\n\n Switches:\n override - The destroy command will usually avoid accidentally\n destroying account objects. This switch overrides this safety.\n force - destroy without confirmation.\n Examples:\n destroy house, roof, door, 44-78\n destroy 5-10, flower, 45\n destroy/force north\n\n Destroys one or many objects. If dbrefs are used, a range to delete can be\n given, e.g. 4-10. Also the end points will be deleted. This command\n displays a confirmation before destroying, to make sure of your choice.\n You can specify the /force switch to bypass this confirmation.\n '}
        +
        +
        @@ -602,6 +643,11 @@ would be ‘north;no;n’.

        lock_storage = 'cmd:perm(dig) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'building', 'key': 'dig', 'tags': '', 'text': "\n build new rooms and connect them to the current location\n\n Usage:\n dig[/switches] <roomname>[;alias;alias...][:typeclass]\n [= <exit_to_there>[;alias][:typeclass]]\n [, <exit_to_here>[;alias][:typeclass]]\n\n Switches:\n tel or teleport - move yourself to the new room\n\n Examples:\n dig kitchen = north;n, south;s\n dig house:myrooms.MyHouseTypeclass\n dig sheer cliff;cliff;sheer = climb up, climb down\n\n This command is a convenient way to build rooms quickly; it creates the\n new room and you can optionally set up exits back and forth between your\n current room and the new one. You can add as many aliases as you\n like to the name of the room and the exits in question; an example\n would be 'north;no;n'.\n "}
        +
        +
        @@ -672,6 +718,11 @@ For more flexibility and power in creating rooms, use dig.

        lock_storage = 'cmd: perm(tunnel) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': 'tun', 'category': 'building', 'key': 'tunnel', 'tags': '', 'text': '\n create new rooms in cardinal directions only\n\n Usage:\n tunnel[/switch] <direction>[:typeclass] [= <roomname>[;alias;alias;...][:typeclass]]\n\n Switches:\n oneway - do not create an exit back to the current location\n tel - teleport to the newly created room\n\n Example:\n tunnel n\n tunnel n = house;mike\'s place;green building\n\n This is a simple way to build using pre-defined directions:\n |wn,ne,e,se,s,sw,w,nw|n (north, northeast etc)\n |wu,d|n (up and down)\n |wi,o|n (in and out)\n The full names (north, in, southwest, etc) will always be put as\n main name for the exit, using the abbreviation as an alias (so an\n exit will always be able to be used with both "north" as well as\n "n" for example). Opposite directions will automatically be\n created back from the new room unless the /oneway switch is given.\n For more flexibility and power in creating rooms, use dig.\n '}
        +
        +
        @@ -727,6 +778,11 @@ currently set destination.

        lock_storage = 'cmd:perm(link) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'building', 'key': 'link', 'tags': '', 'text': '\n link existing rooms together with exits\n\n Usage:\n link[/switches] <object> = <target>\n link[/switches] <object> =\n link[/switches] <object>\n\n Switch:\n twoway - connect two exits. For this to work, BOTH <object>\n and <target> must be exit objects.\n\n If <object> is an exit, set its destination to <target>. Two-way operation\n instead sets the destination to the *locations* of the respective given\n arguments.\n The second form (a lone =) sets the destination to None (same as\n the unlink command) and the third form (without =) just shows the\n currently set destination.\n '}
        +
        +
        @@ -777,6 +833,11 @@ and call func in CmdLink

        lock_storage = 'cmd:perm(unlink) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'building', 'key': 'unlink', 'tags': '', 'text': '\n remove exit-connections between rooms\n\n Usage:\n unlink <Object>\n\n Unlinks an object, for example an exit, disconnecting\n it from whatever it was connected to.\n '}
        +
        +
        @@ -825,6 +886,11 @@ It is also a convenient target of the “home” command.

        lock_storage = 'cmd:perm(sethome) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'building', 'key': 'sethome', 'tags': '', 'text': '\n set an object\'s home location\n\n Usage:\n sethome <obj> [= <home_location>]\n sethom <obj>\n\n The "home" location is a "safety" location for objects; they\n will be moved there if their current location ceases to exist. All\n objects should always have a home location for this reason.\n It is also a convenient target of the "home" command.\n\n If no location is given, just view the object\'s home location.\n '}
        +
        +
        @@ -869,6 +935,11 @@ to a user. Defaults to yourself.

        lock_storage = 'cmd:perm(listcmdsets) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': 'listcmsets', 'category': 'building', 'key': 'cmdsets', 'tags': '', 'text': '\n list command sets defined on an object\n\n Usage:\n cmdsets <obj>\n\n This displays all cmdsets assigned\n to a user. Defaults to yourself.\n '}
        +
        +
        @@ -913,6 +984,11 @@ rename an account.

        lock_storage = 'cmd:perm(rename) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': 'rename', 'category': 'building', 'key': 'name', 'tags': '', 'text': '\n change the name and/or aliases of an object\n\n Usage:\n name <obj> = <newname>;alias1;alias2\n\n Rename an object to something new. Use *obj to\n rename an account.\n\n '}
        +
        +
        @@ -974,6 +1050,11 @@ as well as the self.create_exit() method.

        lock_storage = 'cmd:perm(open) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'building', 'key': 'open', 'tags': '', 'text': '\n open a new exit from the current room\n\n Usage:\n open <new exit>[;alias;alias..][:typeclass] [,<return exit>[;alias;..][:typeclass]]] = <destination>\n\n Handles the creation of exits. If a destination is given, the exit\n will point there. The <return exit> argument sets up an exit at the\n destination leading back to the current room. Destination name\n can be given both as a #dbref and a name, if that name is globally\n unique.\n\n '}
        +
        +
        @@ -1129,6 +1210,11 @@ with older attrs that might have been named with []’s.

        lock_storage = 'cmd:perm(set) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'building', 'key': 'set', 'tags': '', 'text': '\n set attribute on an object or account\n\n Usage:\n set <obj>/<attr> = <value>\n set <obj>/<attr> =\n set <obj>/<attr>\n set *<account>/<attr> = <value>\n\n Switch:\n edit: Open the line editor (string values only)\n script: If we\'re trying to set an attribute on a script\n channel: If we\'re trying to set an attribute on a channel\n account: If we\'re trying to set an attribute on an account\n room: Setting an attribute on a room (global search)\n exit: Setting an attribute on an exit (global search)\n char: Setting an attribute on a character (global search)\n character: Alias for char, as above.\n\n Sets attributes on objects. The second example form above clears a\n previously set attribute while the third form inspects the current value of\n the attribute (if any). The last one (with the star) is a shortcut for\n operating on a player Account rather than an Object.\n\n The most common data to save with this command are strings and\n numbers. You can however also set Python primitives such as lists,\n dictionaries and tuples on objects (this might be important for\n the functionality of certain custom objects). This is indicated\n by you starting your value with one of |c\'|n, |c"|n, |c(|n, |c[|n\n or |c{ |n.\n\n Once you have stored a Python primitive as noted above, you can include\n |c[<key>]|n in <attr> to reference nested values in e.g. a list or dict.\n\n Remember that if you use Python primitives like this, you must\n write proper Python syntax too - notably you must include quotes\n around your strings or you will get an error.\n\n '}
        +
        +
        @@ -1183,7 +1269,7 @@ server settings.

        -aliases = ['type', 'update', 'parent', 'swap']
        +aliases = ['update', 'parent', 'type', 'swap']
        @@ -1212,6 +1298,11 @@ server settings.

        lock_storage = 'cmd:perm(typeclass) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': 'update parent type swap', 'category': 'building', 'key': 'typeclass', 'tags': '', 'text': "\n set or change an object's typeclass\n\n Usage:\n typeclass[/switch] <object> [= typeclass.path]\n typeclass/prototype <object> = prototype_key\n\n typeclass/list/show [typeclass.path]\n swap - this is a shorthand for using /force/reset flags.\n update - this is a shorthand for using the /force/reload flag.\n\n Switch:\n show, examine - display the current typeclass of object (default) or, if\n given a typeclass path, show the docstring of that typeclass.\n update - *only* re-run at_object_creation on this object\n meaning locks or other properties set later may remain.\n reset - clean out *all* the attributes and properties on the\n object - basically making this a new clean object.\n force - change to the typeclass also if the object\n already has a typeclass of the same name.\n list - show available typeclasses. Only typeclasses in modules actually\n imported or used from somewhere in the code will show up here\n (those typeclasses are still available if you know the path)\n prototype - clean and overwrite the object with the specified\n prototype key - effectively making a whole new object.\n\n Example:\n type button = examples.red_button.RedButton\n type/prototype button=a red button\n\n If the typeclass_path is not given, the current object's typeclass is\n assumed.\n\n View or set an object's typeclass. If setting, the creation hooks of the\n new typeclass will be run on the object. If you have clashing properties on\n the old class, use /reset. By default you are protected from changing to a\n typeclass of the same name as the one you already have - use /force to\n override this protection.\n\n The given typeclass must be identified by its location using python\n dot-notation pointing to the correct module and class. If no typeclass is\n given (or a wrong typeclass is given). Errors in the path or new typeclass\n will lead to the old typeclass being kept. The location of the typeclass\n module is searched from the default typeclass directory, as defined in the\n server settings.\n\n "}
        +
        +
        @@ -1259,6 +1350,11 @@ matching the given attribute-wildcard search string.

        lock_storage = 'cmd:perm(wipe) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'building', 'key': 'wipe', 'tags': '', 'text': "\n clear all attributes from an object\n\n Usage:\n wipe <object>[/<attr>[/<attr>...]]\n\n Example:\n wipe box\n wipe box/colour\n\n Wipes all of an object's attributes, or optionally only those\n matching the given attribute-wildcard search string.\n "}
        +
        +
        @@ -1326,6 +1422,11 @@ them by ‘;’, i.e:

        lock_storage = 'cmd: perm(locks) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': 'locks', 'category': 'building', 'key': 'lock', 'tags': '', 'text': "\n assign a lock definition to an object\n\n Usage:\n lock <object or *account>[ = <lockstring>]\n or\n lock[/switch] <object or *account>/<access_type>\n\n Switch:\n del - delete given access type\n view - view lock associated with given access type (default)\n\n If no lockstring is given, shows all locks on\n object.\n\n Lockstring is of the form\n access_type:[NOT] func1(args)[ AND|OR][ NOT] func2(args) ...]\n Where func1, func2 ... valid lockfuncs with or without arguments.\n Separator expressions need not be capitalized.\n\n For example:\n 'get: id(25) or perm(Admin)'\n The 'get' lock access_type is checked e.g. by the 'get' command.\n An object locked with this example lock will only be possible to pick up\n by Admins or by an object with id=25.\n\n You can add several access_types after one another by separating\n them by ';', i.e:\n 'get:id(25); delete:perm(Builder)'\n "}
        +
        +
        @@ -1447,6 +1548,11 @@ non-persistent data stored on object

        lock_storage = 'cmd:perm(examine) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': 'ex exam', 'category': 'building', 'key': 'examine', 'tags': '', 'text': '\n get detailed information about an object\n\n Usage:\n examine [<object>[/attrname]]\n examine [*<account>[/attrname]]\n\n Switch:\n account - examine an Account (same as adding *)\n object - examine an Object (useful when OOC)\n\n The examine command shows detailed game info about an\n object and optionally a specific attribute on it.\n If object is not specified, the current location is examined.\n\n Append a * before the search string to examine an account.\n\n '}
        +
        +
        @@ -1478,7 +1584,7 @@ one is given.

        -aliases = ['locate', 'search']
        +aliases = ['search', 'locate']
        @@ -1507,6 +1613,11 @@ one is given.

        lock_storage = 'cmd:perm(find) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': 'search locate', 'category': 'building', 'key': 'find', 'tags': '', 'text': '\n search the database for objects\n\n Usage:\n find[/switches] <name or dbref or *account> [= dbrefmin[-dbrefmax]]\n locate - this is a shorthand for using the /loc switch.\n\n Switches:\n room - only look for rooms (location=None)\n exit - only look for exits (destination!=None)\n char - only look for characters (BASE_CHARACTER_TYPECLASS)\n exact - only exact matches are returned.\n loc - display object location if exists and match has one result\n startswith - search for names starting with the string, rather than containing\n\n Searches the database for an object of a particular name or exact #dbref.\n Use *accountname to search for an account. The switches allows for\n limiting object matches to certain game entities. Dbrefmin and dbrefmax\n limits matches to within the given dbrefs range, or above/below if only\n one is given.\n '}
        +
        +
        @@ -1580,6 +1691,11 @@ teleported to the target location.

        lock_storage = 'cmd:perm(teleport) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': 'teleport', 'category': 'building', 'key': 'tel', 'tags': '', 'text': "\n teleport object to another location\n\n Usage:\n tel/switch [<object> to||=] <target location>\n\n Examples:\n tel Limbo\n tel/quiet box = Limbo\n tel/tonone box\n\n Switches:\n quiet - don't echo leave/arrive messages to the source/target\n locations for the move.\n intoexit - if target is an exit, teleport INTO\n the exit object instead of to its destination\n tonone - if set, teleport the object to a None-location. If this\n switch is set, <target location> is ignored.\n Note that the only way to retrieve\n an object from a None location is by direct #dbref\n reference. A puppeted object cannot be moved to None.\n loc - teleport object to the target's location instead of its contents\n\n Teleports an object somewhere. If no object is given, you yourself are\n teleported to the target location.\n "}
        +
        +
        @@ -1588,7 +1704,7 @@ teleported to the target location.

        Bases: evennia.commands.default.muxcommand.MuxCommand

        attach a script to an object

        -
        Usage:

        script[/switch] <obj> [= script_path or <scriptkey>]

        +
        Usage:

        addscript[/switch] <obj> [= script_path or <scriptkey>]

        Switches:

        start - start all non-running scripts on object, or a given script only stop - stop all scripts on objects, or a given script only

        @@ -1603,12 +1719,12 @@ object without specifying a script key/path will start/stop ALL scripts on the object.

        -key = 'script'
        +key = 'addscript'
        -aliases = ['addscript']
        +aliases = ['attachscript']
        @@ -1637,6 +1753,11 @@ the object.

        lock_storage = 'cmd:perm(script) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': 'attachscript', 'category': 'building', 'key': 'addscript', 'tags': '', 'text': '\n attach a script to an object\n\n Usage:\n addscript[/switch] <obj> [= script_path or <scriptkey>]\n\n Switches:\n start - start all non-running scripts on object, or a given script only\n stop - stop all scripts on objects, or a given script only\n\n If no script path/key is given, lists all scripts active on the given\n object.\n Script path can be given from the base location for scripts as given in\n settings. If adding a new script, it will be started automatically\n (no /start switch is needed). Using the /start or /stop switches on an\n object without specifying a script key/path will start/stop ALL scripts on\n the object.\n '}
        +
        +
        @@ -1703,6 +1824,11 @@ enough to for most grouping schemes.

        lock_storage = 'cmd:perm(tag) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': 'tags', 'category': 'building', 'key': 'tag', 'tags': '', 'text': '\n handles the tags of an object\n\n Usage:\n tag[/del] <obj> [= <tag>[:<category>]]\n tag/search <tag>[:<category]\n\n Switches:\n search - return all objects with a given Tag\n del - remove the given tag. If no tag is specified,\n clear all tags on object.\n\n Manipulates and lists tags on objects. Tags allow for quick\n grouping of and searching for objects. If only <obj> is given,\n list all tags on the object. If /search is used, list objects\n with the given tag.\n The category can be used for grouping tags themselves, but it\n should be used with restrain - tags on their own are usually\n enough to for most grouping schemes.\n '}
        +
        +
        @@ -1809,6 +1935,11 @@ displays a list of available prototypes.

        lock_storage = 'cmd:perm(spawn) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': 'olc', 'category': 'building', 'key': 'spawn', 'tags': '', 'text': '\n spawn objects from prototype\n\n Usage:\n spawn[/noloc] <prototype_key>\n spawn[/noloc] <prototype_dict>\n\n spawn/search [prototype_keykey][;tag[,tag]]\n spawn/list [tag, tag, ...]\n spawn/list modules - list only module-based prototypes\n spawn/show [<prototype_key>]\n spawn/update <prototype_key>\n\n spawn/save <prototype_dict>\n spawn/edit [<prototype_key>]\n olc - equivalent to spawn/edit\n\n Switches:\n noloc - allow location to be None if not specified explicitly. Otherwise,\n location will default to caller\'s current location.\n search - search prototype by name or tags.\n list - list available prototypes, optionally limit by tags.\n show, examine - inspect prototype by key. If not given, acts like list.\n raw - show the raw dict of the prototype as a one-line string for manual editing.\n save - save a prototype to the database. It will be listable by /list.\n delete - remove a prototype from database, if allowed to.\n update - find existing objects with the same prototype_key and update\n them with latest version of given prototype. If given with /save,\n will auto-update all objects with the old version of the prototype\n without asking first.\n edit, menu, olc - create/manipulate prototype in a menu interface.\n\n Example:\n spawn GOBLIN\n spawn {"key":"goblin", "typeclass":"monster.Monster", "location":"#2"}\n spawn/save {"key": "grunt", prototype: "goblin"};;mobs;edit:all()\n \x0c\n Dictionary keys:\n |wprototype_parent |n - name of parent prototype to use. Required if typeclass is\n not set. Can be a path or a list for multiple inheritance (inherits\n left to right). If set one of the parents must have a typeclass.\n |wtypeclass |n - string. Required if prototype_parent is not set.\n |wkey |n - string, the main object identifier\n |wlocation |n - this should be a valid object or #dbref\n |whome |n - valid object or #dbref\n |wdestination|n - only valid for exits (object or dbref)\n |wpermissions|n - string or list of permission strings\n |wlocks |n - a lock-string\n |waliases |n - string or list of strings.\n |wndb_|n<name> - value of a nattribute (ndb_ is stripped)\n\n |wprototype_key|n - name of this prototype. Unique. Used to store/retrieve from db\n and update existing prototyped objects if desired.\n |wprototype_desc|n - desc of this prototype. Used in listings\n |wprototype_locks|n - locks of this prototype. Limits who may use prototype\n |wprototype_tags|n - tags of this prototype. Used to find prototype\n\n any other keywords are interpreted as Attributes and their values.\n\n The available prototypes are defined globally in modules set in\n settings.PROTOTYPE_MODULES. If spawn is used without arguments it\n displays a list of available prototypes.\n\n '}
        +
        + @@ -1856,7 +1987,6 @@ displays a list of available prototypes.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1873,6 +2003,7 @@ displays a list of available prototypes.

        +
        develop branch
        @@ -118,7 +119,6 @@ command method rather than caller.msg().

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -135,6 +135,7 @@ command method rather than caller.msg().

        +
        develop branch
        @@ -116,7 +117,6 @@ Account cmdset. Account commands remain available also to Characters.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -133,6 +133,7 @@ Account cmdset. Account commands remain available also to Characters.

        +
        develop branch
        @@ -113,7 +114,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -130,6 +130,7 @@ +
        develop branch
        @@ -115,7 +116,6 @@ of the state instance in this module.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -132,6 +132,7 @@ of the state instance in this module.

        +
        develop branch
        @@ -39,16 +40,696 @@

        evennia.commands.default.comms

        -

        Comsystem command module.

        -

        Comm commands are OOC commands and intended to be made available to -the Account at all times (they go into the AccountCmdSet). So we -make sure to homogenize self.caller to always be the account object -for easy handling.

        +

        Communication commands:

        +
          +
        • channel

        • +
        • page

        • +
        • irc/rss/grapevine linking

        • +
        +
        +
        +class evennia.commands.default.comms.CmdChannel(**kwargs)[source]
        +

        Bases: evennia.commands.default.muxcommand.MuxCommand

        +

        Use and manage in-game channels.

        +
        +
        Usage:

        channel channelname <msg> +channel channel name = <msg> +channel (show all subscription) +channel/all (show available channels) +channel/alias channelname = alias[;alias…] +channel/unalias alias +channel/who channelname +channel/history channelname [= index] +channel/sub channelname [= alias[;alias…]] +channel/unsub channelname[,channelname, …] +channel/mute channelname[,channelname,…] +channel/unmute channelname[,channelname,…]

        +

        channel/create channelname[;alias;alias[:typeclass]] [= description] +channel/destroy channelname [= reason] +channel/desc channelname = description +channel/lock channelname = lockstring +channel/unlock channelname = lockstring +channel/ban channelname (list bans) +channel/ban[/quiet] channelname[, channelname, …] = subscribername [: reason] +channel/unban[/quiet] channelname[, channelname, …] = subscribername +channel/boot[/quiet] channelname[,channelname,…] = subscribername [: reason]

        +
        +
        +
        +
        Usage: channel channelname msg

        channel channel name = msg (with space in channel name)

        +
        +
        +

        This sends a message to the channel. Note that you will rarely use this +command like this; instead you can use the alias

        +
        +

        channelname <msg> +channelalias <msg>

        +
        +

        For example

        +
        +

        public Hello World +pub Hello World

        +
        +

        (this shortcut doesn’t work for aliases containing spaces)

        +

        See channel/alias for help on setting channel aliases.

        +
        +
        Usage: channel/alias channel = alias[;alias[;alias…]]

        channel/unalias alias +channel - this will list your subs and aliases to each channel

        +
        +
        +

        Set one or more personal aliases for referencing a channel. For example:

        +
        +

        channel/alias warrior’s guild = warrior;wguild;warchannel;warrior guild

        +
        +

        You can now send to the channel using all of these:

        +
        +

        warrior’s guild Hello +warrior Hello +wguild Hello +warchannel Hello

        +
        +

        Note that this will not work if the alias has a space in it. So the +‘warrior guild’ alias must be used with the channel command:

        +
        +

        channel warrior guild = Hello

        +
        +

        Channel-aliases can be removed one at a time, using the ‘/unalias’ switch.

        +

        Usage: channel/who channelname

        +

        List the channel’s subscribers. Shows who are currently offline or are +muting the channel. Subscribers who are ‘muting’ will not see messages sent +to the channel (use channel/mute to mute a channel).

        +

        Usage: channel/history channel [= index]

        +

        This will display the last |c20|n lines of channel history. By supplying an +index number, you will step that many lines back before viewing those 20 lines.

        +

        For example:

        +
        +

        channel/history public = 35

        +
        +

        will go back 35 lines and show the previous 20 lines from that point (so +lines -35 to -55).

        +
        +
        Usage: channel/sub channel [=alias[;alias;…]]

        channel/unsub channel

        +
        +
        +

        This subscribes you to a channel and optionally assigns personal shortcuts +for you to use to send to that channel (see aliases). When you unsub, all +your personal aliases will also be removed.

        +
        +
        Usage: channel/mute channelname

        channel/unmute channelname

        +
        +
        +

        Muting silences all output from the channel without actually +un-subscribing. Other channel members will see that you are muted in the /who +list. Sending a message to the channel will automatically unmute you.

        +
        +
        Usage: channel/create channelname[;alias;alias[:typeclass]] [= description]

        channel/destroy channelname [= reason]

        +
        +
        +

        Creates a new channel (or destroys one you control). You will automatically +join the channel you create and everyone will be kicked and loose all aliases +to a destroyed channel.

        +
        +
        Usage: channel/lock channelname = lockstring

        channel/unlock channelname = lockstring

        +
        +
        +

        Note: this is an admin command.

        +

        A lockstring is on the form locktype:lockfunc(). Channels understand three +locktypes:

        +
        +

        listen - who may listen or join the channel. +send - who may send messages to the channel +control - who controls the channel. This is usually the one creating

        +
        +

        the channel.

        +
        +
        +

        Common lockfuncs are all() and perm(). To make a channel everyone can +listen to but only builders can talk on, use this:

        +
        +

        listen:all() +send: perm(Builders)

        +
        +
        +
        Usage:

        channel/boot[/quiet] channelname[,channelname,…] = subscribername [: reason] +channel/ban channelname[, channelname, …] = subscribername [: reason] +channel/unban channelname[, channelname, …] = subscribername +channel/unban channelname +channel/ban channelname (list bans)

        +
        +
        +

        Booting will kick a named subscriber from channel(s) temporarily. The +‘reason’ will be passed to the booted user. Unless the /quiet switch is +used, the channel will also be informed of the action. A booted user is +still able to re-connect, but they’ll have to set up their aliases again.

        +

        Banning will blacklist a user from (re)joining the provided channels. It +will then proceed to boot them from those channels if they were connected. +The ‘reason’ and /quiet works the same as for booting.

        +

        Example

        +

        boot mychannel1 = EvilUser : Kicking you to cool down a bit. +ban mychannel1,mychannel2= EvilUser : Was banned for spamming.

        +
        +
        +key = 'channel'
        +
        + +
        +
        +aliases = ['channels', 'chan']
        +
        + +
        +
        +help_category = 'comms'
        +
        + +
        +
        +locks = 'cmd:not pperm(channel_banned);admin:all();manage:all();changelocks:perm(Admin)'
        +
        + +
        +
        +switch_options = ('list', 'all', 'history', 'sub', 'unsub', 'mute', 'unmute', 'alias', 'unalias', 'create', 'destroy', 'desc', 'lock', 'unlock', 'boot', 'ban', 'unban', 'who')
        +
        + +
        +
        +account_caller = True
        +
        + +
        +
        +search_channel(channelname, exact=False, handle_errors=True)[source]
        +

        Helper function for searching for a single channel with some error +handling.

        +
        +
        Parameters
        +
          +
        • channelname (str) – Name, alias #dbref or partial name/alias to search +for.

        • +
        • exact (bool, optional) – If an exact or fuzzy-match of the name should be done. +Note that even for a fuzzy match, an exactly given, unique channel name +will always be returned.

        • +
        • handle_errors (bool) – If true, use self.msg to report errors if +there are non/multiple matches. If so, the return will always be +a single match or None.

        • +
        +
        +
        Returns
        +

        object, list or None

        +
        +
        If handle_errors is True, this is either a found Channel

        or None. Otherwise it’s a list of zero, one or more channels found.

        +
        +
        +

        +
        +
        +

        Notes

        +

        The ‘listen’ and ‘control’ accesses are checked before returning.

        +
        + +
        +
        +msg_channel(channel, message, **kwargs)[source]
        +

        Send a message to a given channel. This will check the ‘send’ +permission on the channel.

        +
        +
        Parameters
        +
          +
        • channel (Channel) – The channel to send to.

        • +
        • message (str) – The message to send.

        • +
        • **kwargs – Unused by default. These kwargs will be passed into +all channel messaging hooks for custom overriding.

        • +
        +
        +
        +
        + +
        +
        +get_channel_history(channel, start_index=0)[source]
        +

        View a channel’s history.

        +
        +
        Parameters
        +
          +
        • channel (Channel) – The channel to access.

        • +
        • message (str) – The message to send.

        • +
        • **kwargs – Unused by default. These kwargs will be passed into +all channel messaging hooks for custom overriding.

        • +
        +
        +
        +
        + +
        +
        +sub_to_channel(channel)[source]
        +

        Subscribe to a channel. Note that all permissions should +be checked before this step.

        +
        +
        Parameters
        +

        channel (Channel) – The channel to access.

        +
        +
        Returns
        +

        bool, str

        +
        +
        True, None if connection failed. If False,

        the second part is an error string.

        +
        +
        +

        +
        +
        +
        + +
        +
        +unsub_from_channel(channel, **kwargs)[source]
        +

        Un-Subscribe to a channel. Note that all permissions should +be checked before this step.

        +
        +
        Parameters
        +
          +
        • channel (Channel) – The channel to unsub from.

        • +
        • **kwargs – Passed on to nick removal.

        • +
        +
        +
        Returns
        +

        bool, str

        +
        +
        True, None if un-connection succeeded. If False,

        the second part is an error string.

        +
        +
        +

        +
        +
        +
        + +
        +
        +add_alias(channel, alias, **kwargs)[source]
        +

        Add a new alias (nick) for the user to use with this channel.

        +
        +
        Parameters
        +
          +
        • channel (Channel) – The channel to alias.

        • +
        • alias (str) – The personal alias to use for this channel.

        • +
        • **kwargs – If given, passed into nicks.add.

        • +
        +
        +
        +
        +

        Note

        +

        We add two nicks - one is a plain alias -> channel.key that +we need to be able to reference this channel easily. The other +is a templated nick to easily be able to send messages to the +channel without needing to give the full channel command. The +structure of this nick is given by self.channel_msg_pattern +and self.channel_msg_nick_replacement. By default it maps +alias <msg> -> channel <channelname> = <msg>, so that you can +for example just write pub Hello to send a message.

        +

        The alias created is alias $1 -> channel channel = $1, to allow +for sending to channel using the main channel command.

        +
        +
        + +
        +
        +remove_alias(alias, **kwargs)[source]
        +

        Remove an alias from a channel.

        +
        +
        Parameters
        +

        alias (str, optional) – The alias to remove. +The channel will be reverse-determined from the +alias, if it exists.

        +
        +
        Returns
        +

        bool, str

        +
        +
        True, None if removal succeeded. If False,

        the second part is an error string.

        +
        +
        +

        **kwargs: If given, passed into nicks.get/add.

        +

        +
        +
        +
        +

        Note

        +

        This will remove two nicks - the plain channel alias and the templated +nick used for easily sending messages to the channel.

        +
        +
        + +
        +
        +get_channel_aliases(channel)[source]
        +

        Get a user’s aliases for a given channel. The user is retrieved +through self.caller.

        +
        +
        Parameters
        +

        channel (Channel) – The channel to act on.

        +
        +
        Returns
        +

        list – A list of zero, one or more alias-strings.

        +
        +
        +
        + +
        +
        +mute_channel(channel)[source]
        +

        Temporarily mute a channel.

        +
        +
        Parameters
        +

        channel (Channel) – The channel to alias.

        +
        +
        Returns
        +

        bool, str

        +
        +
        True, None if muting successful. If False,

        the second part is an error string.

        +
        +
        +

        +
        +
        +
        + +
        +
        +unmute_channel(channel)[source]
        +

        Unmute a channel.

        +
        +
        Parameters
        +

        channel (Channel) – The channel to alias.

        +
        +
        Returns
        +

        bool, str

        +
        +
        True, None if unmuting successful. If False,

        the second part is an error string.

        +
        +
        +

        +
        +
        +
        + +
        +
        +create_channel(name, description, typeclass=None, aliases=None)[source]
        +

        Create a new channel. Its name must not previously exist +(users can alias as needed). Will also connect to the +new channel.

        +
        +
        Parameters
        +
          +
        • name (str) – The new channel name/key.

        • +
        • description (str) – This is used in listings.

        • +
        • aliases (list) – A list of strings - alternative aliases for the channel +(not to be confused with per-user aliases; these are available for +everyone).

        • +
        +
        +
        Returns
        +

        channel, str

        +
        +
        new_channel, “” if creation successful. If False,

        the second part is an error string.

        +
        +
        +

        +
        +
        +
        + +
        +
        +destroy_channel(channel, message=None)[source]
        +

        Destroy an existing channel. Access should be checked before +calling this function.

        +
        +
        Parameters
        +
          +
        • channel (Channel) – The channel to alias.

        • +
        • message (str, optional) – Final message to send onto the channel +before destroying it. If not given, a default message is +used. Set to the empty string for no message.

        • +
        +
        +
        +
        +
        if typeclass:

        pass

        +
        +
        +
        + +
        +
        +set_lock(channel, lockstring)[source]
        +

        Set a lockstring on a channel. Permissions must have been +checked before this call.

        +
        +
        Parameters
        +
          +
        • channel (Channel) – The channel to operate on.

        • +
        • lockstring (str) – A lockstring on the form ‘type:lockfunc();…’

        • +
        +
        +
        Returns
        +

        bool, str

        +
        +
        True, None if setting lock was successful. If False,

        the second part is an error string.

        +
        +
        +

        +
        +
        +
        + +
        +
        +unset_lock(channel, lockstring)[source]
        +

        Remove locks in a lockstring on a channel. Permissions must have been +checked before this call.

        +
        +
        Parameters
        +
          +
        • channel (Channel) – The channel to operate on.

        • +
        • lockstring (str) – A lockstring on the form ‘type:lockfunc();…’

        • +
        +
        +
        Returns
        +

        bool, str

        +
        +
        True, None if setting lock was successful. If False,

        the second part is an error string.

        +
        +
        +

        +
        +
        +
        + +
        +
        +set_desc(channel, description)[source]
        +

        Set a channel description. This is shown in listings etc.

        +
        +
        Parameters
        +
          +
        • caller (Object or Account) – The entity performing the action.

        • +
        • channel (Channel) – The channel to operate on.

        • +
        • description (str) – A short description of the channel.

        • +
        +
        +
        Returns
        +

        bool, str

        +
        +
        True, None if setting lock was successful. If False,

        the second part is an error string.

        +
        +
        +

        +
        +
        +
        + +
        +
        +boot_user(channel, target, quiet=False, reason='')[source]
        +

        Boot a user from a channel, with optional reason. This will +also remove all their aliases for this channel.

        +
        +
        Parameters
        +
          +
        • channel (Channel) – The channel to operate on.

        • +
        • target (Object or Account) – The entity to boot.

        • +
        • quiet (bool, optional) – Whether or not to announce to channel.

        • +
        • reason (str, optional) – A reason for the boot.

        • +
        +
        +
        Returns
        +

        bool, str

        +
        +
        True, None if setting lock was successful. If False,

        the second part is an error string.

        +
        +
        +

        +
        +
        +
        + +
        +
        +ban_user(channel, target, quiet=False, reason='')[source]
        +

        Ban a user from a channel, by locking them out. This will also +boot them, if they are currently connected.

        +
        +
        Parameters
        +
          +
        • channel (Channel) – The channel to operate on.

        • +
        • target (Object or Account) – The entity to ban

        • +
        • quiet (bool, optional) – Whether or not to announce to channel.

        • +
        • reason (str, optional) – A reason for the ban

        • +
        +
        +
        Returns
        +

        bool, str

        +
        +
        True, None if banning was successful. If False,

        the second part is an error string.

        +
        +
        +

        +
        +
        +
        + +
        +
        +unban_user(channel, target)[source]
        +

        Un-Ban a user from a channel. This will not reconnect them +to the channel, just allow them to connect again (assuming +they have the suitable ‘listen’ lock like everyone else).

        +
        +
        Parameters
        +
          +
        • channel (Channel) – The channel to operate on.

        • +
        • target (Object or Account) – The entity to unban

        • +
        +
        +
        Returns
        +

        bool, str

        +
        +
        True, None if unbanning was successful. If False,

        the second part is an error string.

        +
        +
        +

        +
        +
        +
        + +
        +
        +channel_list_bans(channel)[source]
        +

        Show a channel’s bans.

        +
        +
        Parameters
        +

        channel (Channel) – The channel to operate on.

        +
        +
        Returns
        +

        list – A list of strings, each the name of a banned user.

        +
        +
        +
        + +
        +
        +channel_list_who(channel)[source]
        +

        Show a list of online people is subscribing to a channel. This will check +the ‘control’ permission of caller to determine if only online users +should be returned or everyone.

        +
        +
        Parameters
        +

        channel (Channel) – The channel to operate on.

        +
        +
        Returns
        +

        list

        +
        +
        A list of prepared strings, with name + markers for if they are

        muted or offline.

        +
        +
        +

        +
        +
        +
        + +
        +
        +list_channels(channelcls=<class 'evennia.comms.comms.DefaultChannel'>)[source]
        +

        Return a available channels.

        +
        +
        Parameters
        +

        channelcls (Channel, optional) – The channel-class to query on. Defaults +to the default channel class from settings.

        +
        +
        Returns
        +

        tuple

        +
        +
        A tuple (subbed_chans, available_chans) with the channels

        currently subscribed to, and those we have ‘listen’ access to but +don’t actually sub to yet.

        +
        +
        +

        +
        +
        +
        + +
        +
        +display_subbed_channels(subscribed)[source]
        +

        Display channels subscribed to.

        +
        +
        Parameters
        +

        subscribed (list) – List of subscribed channels

        +
        +
        Returns
        +

        EvTable – Table to display.

        +
        +
        +
        + +
        +
        +display_all_channels(subscribed, available)[source]
        +

        Display all available channels

        +
        +
        Parameters
        +

        subscribed (list) – List of subscribed channels

        +
        +
        Returns
        +

        EvTable – Table to display.

        +
        +
        +
        + +
        +
        +func()[source]
        +

        Main functionality of command.

        +
        + +
        +
        +lock_storage = 'cmd:not pperm(channel_banned);admin:all();manage:all();changelocks:perm(Admin)'
        +
        + +
        +
        +search_index_entry = {'aliases': 'channels chan', 'category': 'comms', 'key': 'channel', 'tags': '', 'text': "\n Use and manage in-game channels.\n\n Usage:\n channel channelname <msg>\n channel channel name = <msg>\n channel (show all subscription)\n channel/all (show available channels)\n channel/alias channelname = alias[;alias...]\n channel/unalias alias\n channel/who channelname\n channel/history channelname [= index]\n channel/sub channelname [= alias[;alias...]]\n channel/unsub channelname[,channelname, ...]\n channel/mute channelname[,channelname,...]\n channel/unmute channelname[,channelname,...]\n\n channel/create channelname[;alias;alias[:typeclass]] [= description]\n channel/destroy channelname [= reason]\n channel/desc channelname = description\n channel/lock channelname = lockstring\n channel/unlock channelname = lockstring\n channel/ban channelname (list bans)\n channel/ban[/quiet] channelname[, channelname, ...] = subscribername [: reason]\n channel/unban[/quiet] channelname[, channelname, ...] = subscribername\n channel/boot[/quiet] channelname[,channelname,...] = subscribername [: reason]\n\n # subtopics\n\n ## sending\n\n Usage: channel channelname msg\n channel channel name = msg (with space in channel name)\n\n This sends a message to the channel. Note that you will rarely use this\n command like this; instead you can use the alias\n\n channelname <msg>\n channelalias <msg>\n\n For example\n\n public Hello World\n pub Hello World\n\n (this shortcut doesn't work for aliases containing spaces)\n\n See channel/alias for help on setting channel aliases.\n\n ## alias and unalias\n\n Usage: channel/alias channel = alias[;alias[;alias...]]\n channel/unalias alias\n channel - this will list your subs and aliases to each channel\n\n Set one or more personal aliases for referencing a channel. For example:\n\n channel/alias warrior's guild = warrior;wguild;warchannel;warrior guild\n\n You can now send to the channel using all of these:\n\n warrior's guild Hello\n warrior Hello\n wguild Hello\n warchannel Hello\n\n Note that this will not work if the alias has a space in it. So the\n 'warrior guild' alias must be used with the `channel` command:\n\n channel warrior guild = Hello\n\n Channel-aliases can be removed one at a time, using the '/unalias' switch.\n\n ## who\n\n Usage: channel/who channelname\n\n List the channel's subscribers. Shows who are currently offline or are\n muting the channel. Subscribers who are 'muting' will not see messages sent\n to the channel (use channel/mute to mute a channel).\n\n ## history\n\n Usage: channel/history channel [= index]\n\n This will display the last |c20|n lines of channel history. By supplying an\n index number, you will step that many lines back before viewing those 20 lines.\n\n For example:\n\n channel/history public = 35\n\n will go back 35 lines and show the previous 20 lines from that point (so\n lines -35 to -55).\n\n ## sub and unsub\n\n Usage: channel/sub channel [=alias[;alias;...]]\n channel/unsub channel\n\n This subscribes you to a channel and optionally assigns personal shortcuts\n for you to use to send to that channel (see aliases). When you unsub, all\n your personal aliases will also be removed.\n\n ## mute and unmute\n\n Usage: channel/mute channelname\n channel/unmute channelname\n\n Muting silences all output from the channel without actually\n un-subscribing. Other channel members will see that you are muted in the /who\n list. Sending a message to the channel will automatically unmute you.\n\n ## create and destroy\n\n Usage: channel/create channelname[;alias;alias[:typeclass]] [= description]\n channel/destroy channelname [= reason]\n\n Creates a new channel (or destroys one you control). You will automatically\n join the channel you create and everyone will be kicked and loose all aliases\n to a destroyed channel.\n\n ## lock and unlock\n\n Usage: channel/lock channelname = lockstring\n channel/unlock channelname = lockstring\n\n Note: this is an admin command.\n\n A lockstring is on the form locktype:lockfunc(). Channels understand three\n locktypes:\n listen - who may listen or join the channel.\n send - who may send messages to the channel\n control - who controls the channel. This is usually the one creating\n the channel.\n\n Common lockfuncs are all() and perm(). To make a channel everyone can\n listen to but only builders can talk on, use this:\n\n listen:all()\n send: perm(Builders)\n\n ## boot and ban\n\n Usage:\n channel/boot[/quiet] channelname[,channelname,...] = subscribername [: reason]\n channel/ban channelname[, channelname, ...] = subscribername [: reason]\n channel/unban channelname[, channelname, ...] = subscribername\n channel/unban channelname\n channel/ban channelname (list bans)\n\n Booting will kick a named subscriber from channel(s) temporarily. The\n 'reason' will be passed to the booted user. Unless the /quiet switch is\n used, the channel will also be informed of the action. A booted user is\n still able to re-connect, but they'll have to set up their aliases again.\n\n Banning will blacklist a user from (re)joining the provided channels. It\n will then proceed to boot them from those channels if they were connected.\n The 'reason' and `/quiet` works the same as for booting.\n\n Example:\n boot mychannel1 = EvilUser : Kicking you to cool down a bit.\n ban mychannel1,mychannel2= EvilUser : Was banned for spamming.\n\n "}
        +
        + +
        +
        class evennia.commands.default.comms.CmdAddCom(**kwargs)[source]
        -

        Bases: evennia.commands.default.muxcommand.MuxCommand

        -

        add a channel alias and/or subscribe to a channel

        +

        Bases: evennia.commands.default.comms.CmdChannel

        +

        Add a channel alias and/or subscribe to a channel

        Usage:

        addcom [alias=] <channel>

        @@ -93,12 +774,17 @@ aliases to an already joined channel.

        lock_storage = 'cmd:not pperm(channel_banned)'
        +
        +
        +search_index_entry = {'aliases': 'aliaschan chanalias', 'category': 'comms', 'key': 'addcom', 'tags': '', 'text': '\n Add a channel alias and/or subscribe to a channel\n\n Usage:\n addcom [alias=] <channel>\n\n Joins a given channel. If alias is given, this will allow you to\n refer to the channel by this alias rather than the full channel\n name. Subsequent calls of this command can be used to add multiple\n aliases to an already joined channel.\n '}
        +
        +
        class evennia.commands.default.comms.CmdDelCom(**kwargs)[source]
        -

        Bases: evennia.commands.default.muxcommand.MuxCommand

        +

        Bases: evennia.commands.default.comms.CmdChannel

        remove a channel alias and/or unsubscribe from channel

        Usage:

        delcom <alias or channel> @@ -145,12 +831,17 @@ for that channel.

        lock_storage = 'cmd:not perm(channel_banned)'
        +
        +
        +search_index_entry = {'aliases': 'delaliaschan delchanalias', 'category': 'comms', 'key': 'delcom', 'tags': '', 'text': "\n remove a channel alias and/or unsubscribe from channel\n\n Usage:\n delcom <alias or channel>\n delcom/all <channel>\n\n If the full channel name is given, unsubscribe from the\n channel. If an alias is given, remove the alias but don't\n unsubscribe. If the 'all' switch is used, remove all aliases\n for that channel.\n "}
        +
        +
        class evennia.commands.default.comms.CmdAllCom(**kwargs)[source]
        -

        Bases: evennia.commands.default.muxcommand.MuxCommand

        +

        Bases: evennia.commands.default.comms.CmdChannel

        perform admin operations on all channels

        Usage:

        allcom [on | off | who | destroy]

        @@ -165,6 +856,11 @@ channels that you control.

        key = 'allcom'
        +
        +
        +aliases = []
        +
        +
        locks = 'cmd: not pperm(channel_banned)'
        @@ -186,66 +882,14 @@ channels that you control.

        Runs the function

        -
        -
        -aliases = []
        -
        -
        lock_storage = 'cmd: not pperm(channel_banned)'
        -
        - -
        -
        -class evennia.commands.default.comms.CmdChannels(**kwargs)[source]
        -

        Bases: evennia.commands.default.muxcommand.MuxCommand

        -

        list all channels available to you

        -
        -
        Usage:

        channels -clist -comlist

        -
        -
        -

        Lists all channels available to you, whether you listen to them or not. -Use ‘comlist’ to only view your current channel subscriptions. -Use addcom/delcom to join and leave channels

        -
        -key = 'channels'
        -
        - -
        -
        -aliases = ['chanlist', 'clist', 'channellist', 'all channels', 'comlist']
        -
        - -
        -
        -help_category = 'comms'
        -
        - -
        -
        -locks = 'cmd: not pperm(channel_banned)'
        -
        - -
        -
        -account_caller = True
        -
        - -
        -
        -func()[source]
        -

        Implement function

        -
        - -
        -
        -lock_storage = 'cmd: not pperm(channel_banned)'
        +
        +search_index_entry = {'aliases': '', 'category': 'comms', 'key': 'allcom', 'tags': '', 'text': "\n perform admin operations on all channels\n\n Usage:\n allcom [on | off | who | destroy]\n\n Allows the user to universally turn off or on all channels they are on, as\n well as perform a 'who' for all channels they are on. Destroy deletes all\n channels that you control.\n\n Without argument, works like comlist.\n "}
        @@ -253,7 +897,7 @@ Use addcom/delcom to join and leave channels

        class evennia.commands.default.comms.CmdCdestroy(**kwargs)[source]
        -

        Bases: evennia.commands.default.muxcommand.MuxCommand

        +

        Bases: evennia.commands.default.comms.CmdChannel

        destroy a channel you created

        Usage:

        cdestroy <channel>

        @@ -265,6 +909,11 @@ Use addcom/delcom to join and leave channels

        key = 'cdestroy'
        +
        +
        +aliases = []
        +
        +
        help_category = 'comms'
        @@ -287,13 +936,13 @@ Use addcom/delcom to join and leave channels

        -
        -aliases = []
        +
        +lock_storage = 'cmd: not pperm(channel_banned)'
        -
        -lock_storage = 'cmd: not pperm(channel_banned)'
        +
        +search_index_entry = {'aliases': '', 'category': 'comms', 'key': 'cdestroy', 'tags': '', 'text': '\n destroy a channel you created\n\n Usage:\n cdestroy <channel>\n\n Destroys a channel that you control.\n '}
        @@ -301,7 +950,7 @@ Use addcom/delcom to join and leave channels

        class evennia.commands.default.comms.CmdCBoot(**kwargs)[source]
        -

        Bases: evennia.commands.default.muxcommand.MuxCommand

        +

        Bases: evennia.commands.default.comms.CmdChannel

        kick an account from a channel you control

        Usage:

        cboot[/quiet] <channel> = <account> [:reason]

        @@ -315,6 +964,11 @@ Use addcom/delcom to join and leave channels

        key = 'cboot'
        +
        +
        +aliases = []
        +
        +
        switch_options = ('quiet',)
        @@ -341,72 +995,14 @@ Use addcom/delcom to join and leave channels

        implement the function

        -
        -
        -aliases = []
        -
        -
        lock_storage = 'cmd: not pperm(channel_banned)'
        -
        - -
        -
        -class evennia.commands.default.comms.CmdCemit(**kwargs)[source]
        -

        Bases: evennia.commands.default.muxcommand.MuxCommand

        -

        send an admin message to a channel you control

        -
        -
        Usage:

        cemit[/switches] <channel> = <message>

        -
        -
        Switches:

        sendername - attach the sender’s name before the message -quiet - don’t echo the message back to sender

        -
        -
        -

        Allows the user to broadcast a message over a channel as long as -they control it. It does not show the user’s name unless they -provide the /sendername switch.

        -
        -key = 'cemit'
        -
        - -
        -
        -aliases = ['cmsg']
        -
        - -
        -
        -switch_options = ('sendername', 'quiet')
        -
        - -
        -
        -locks = 'cmd: not pperm(channel_banned) and pperm(Player)'
        -
        - -
        -
        -help_category = 'comms'
        -
        - -
        -
        -account_caller = True
        -
        - -
        -
        -func()[source]
        -

        Implement function

        -
        - -
        -
        -lock_storage = 'cmd: not pperm(channel_banned) and pperm(Player)'
        +
        +search_index_entry = {'aliases': '', 'category': 'comms', 'key': 'cboot', 'tags': '', 'text': "\n kick an account from a channel you control\n\n Usage:\n cboot[/quiet] <channel> = <account> [:reason]\n\n Switch:\n quiet - don't notify the channel\n\n Kicks an account or object from a channel you control.\n\n "}
        @@ -414,7 +1010,7 @@ provide the /sendername switch.

        class evennia.commands.default.comms.CmdCWho(**kwargs)[source]
        -

        Bases: evennia.commands.default.muxcommand.MuxCommand

        +

        Bases: evennia.commands.default.comms.CmdChannel

        show who is listening to a channel

        Usage:

        cwho <channel>

        @@ -426,6 +1022,11 @@ provide the /sendername switch.

        key = 'cwho'
        +
        +
        +aliases = []
        +
        +
        locks = 'cmd: not pperm(channel_banned)'
        @@ -448,13 +1049,13 @@ provide the /sendername switch.

        -
        -aliases = []
        +
        +lock_storage = 'cmd: not pperm(channel_banned)'
        -
        -lock_storage = 'cmd: not pperm(channel_banned)'
        +
        +search_index_entry = {'aliases': '', 'category': 'comms', 'key': 'cwho', 'tags': '', 'text': '\n show who is listening to a channel\n\n Usage:\n cwho <channel>\n\n List who is connected to a given channel you have access to.\n '}
        @@ -462,7 +1063,7 @@ provide the /sendername switch.

        class evennia.commands.default.comms.CmdChannelCreate(**kwargs)[source]
        -

        Bases: evennia.commands.default.muxcommand.MuxCommand

        +

        Bases: evennia.commands.default.comms.CmdChannel

        create a new channel

        Usage:

        ccreate <new channel>[;alias;alias…] = description

        @@ -505,12 +1106,17 @@ provide the /sendername switch.

        lock_storage = 'cmd:not pperm(channel_banned) and pperm(Player)'
        +
        +
        +search_index_entry = {'aliases': 'channelcreate', 'category': 'comms', 'key': 'ccreate', 'tags': '', 'text': '\n create a new channel\n\n Usage:\n ccreate <new channel>[;alias;alias...] = description\n\n Creates a new channel owned by you.\n '}
        +
        +
        class evennia.commands.default.comms.CmdClock(**kwargs)[source]
        -

        Bases: evennia.commands.default.muxcommand.MuxCommand

        +

        Bases: evennia.commands.default.comms.CmdChannel

        change channel locks of a channel you control

        Usage:

        clock <channel> [= <lockstring>]

        @@ -524,13 +1130,13 @@ lockstring was given, view the current lock definitions.

        -
        -locks = 'cmd:not pperm(channel_banned)'
        +
        +aliases = []
        -
        -aliases = []
        +
        +locks = 'cmd:not pperm(channel_banned) and perm(Admin)'
        @@ -551,7 +1157,12 @@ lockstring was given, view the current lock definitions.

        -lock_storage = 'cmd:not pperm(channel_banned)'
        +lock_storage = 'cmd:not pperm(channel_banned) and perm(Admin)' +
        + +
        +
        +search_index_entry = {'aliases': '', 'category': 'comms', 'key': 'clock', 'tags': '', 'text': '\n change channel locks of a channel you control\n\n Usage:\n clock <channel> [= <lockstring>]\n\n Changes the lock access restrictions of a channel. If no\n lockstring was given, view the current lock definitions.\n '}
        @@ -559,7 +1170,7 @@ lockstring was given, view the current lock definitions.

        class evennia.commands.default.comms.CmdCdesc(**kwargs)[source]
        -

        Bases: evennia.commands.default.muxcommand.MuxCommand

        +

        Bases: evennia.commands.default.comms.CmdChannel

        describe a channel you control

        Usage:

        cdesc <channel> = <description>

        @@ -572,6 +1183,11 @@ channel lists.

        key = 'cdesc'
        +
        +
        +aliases = []
        +
        +
        locks = 'cmd:not pperm(channel_banned)'
        @@ -594,13 +1210,13 @@ channel lists.

        -
        -aliases = []
        +
        +lock_storage = 'cmd:not pperm(channel_banned)'
        -
        -lock_storage = 'cmd:not pperm(channel_banned)'
        +
        +search_index_entry = {'aliases': '', 'category': 'comms', 'key': 'cdesc', 'tags': '', 'text': '\n describe a channel you control\n\n Usage:\n cdesc <channel> = <description>\n\n Changes the description of the channel as shown in\n channel lists.\n\n '}
        @@ -611,16 +1227,18 @@ channel lists.

        Bases: evennia.commands.default.muxcommand.MuxCommand

        send a private message to another account

        -
        Usage:

        page[/switches] [<account>,<account>,… = <message>] +

        Usage:

        page <account> <message> +page[/switches] [<account>,<account>,… = <message>] tell ‘’ page <number>

        -
        Switch:

        last - shows who you last messaged +

        Switches:

        last - shows who you last messaged list - show your last <number> of tells/pages (default)

        -

        Send a message to target user (if online). If no -argument is given, you will get a list of your latest messages.

        +

        Send a message to target user (if online). If no argument is given, you +will get a list of your latest messages. The equal sign is needed for +multiple targets or if sending to target with space in the name.

        key = 'page'
        @@ -662,6 +1280,11 @@ argument is given, you will get a list of your latest messages.

        lock_storage = 'cmd:not pperm(page_banned)'
        +
        +
        +search_index_entry = {'aliases': 'tell', 'category': 'comms', 'key': 'page', 'tags': '', 'text': "\n send a private message to another account\n\n Usage:\n page <account> <message>\n page[/switches] [<account>,<account>,... = <message>]\n tell ''\n page <number>\n\n Switches:\n last - shows who you last messaged\n list - show your last <number> of tells/pages (default)\n\n Send a message to target user (if online). If no argument is given, you\n will get a list of your latest messages. The equal sign is needed for\n multiple targets or if sending to target with space in the name.\n\n "}
        +
        +
        @@ -701,7 +1324,7 @@ The bot will relay everything said in the evennia channel to the IRC channel and vice versa. The bot will automatically connect at server start, so this command need only be given once. The /disconnect switch will permanently delete the bot. To only -temporarily deactivate it, use the |wservices|n command instead. +temporarily deactivate it, use the |wservices|n command instead. Provide an optional bot class path to use a custom bot.

        @@ -739,6 +1362,11 @@ Provide an optional bot class path to use a custom bot.

        lock_storage = 'cmd:serversetting(IRC_ENABLED) and pperm(Developer)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'comms', 'key': 'irc2chan', 'tags': '', 'text': '\n Link an evennia channel to an external IRC channel\n\n Usage:\n irc2chan[/switches] <evennia_channel> = <ircnetwork> <port> <#irchannel> <botname>[:typeclass]\n irc2chan/delete botname|#dbid\n\n Switches:\n /delete - this will delete the bot and remove the irc connection\n to the channel. Requires the botname or #dbid as input.\n /remove - alias to /delete\n /disconnect - alias to /delete\n /list - show all irc<->evennia mappings\n /ssl - use an SSL-encrypted connection\n\n Example:\n irc2chan myircchan = irc.dalnet.net 6667 #mychannel evennia-bot\n irc2chan public = irc.freenode.net 6667 #evgaming #evbot:accounts.mybot.MyBot\n\n This creates an IRC bot that connects to a given IRC network and\n channel. If a custom typeclass path is given, this will be used\n instead of the default bot class.\n The bot will relay everything said in the evennia channel to the\n IRC channel and vice versa. The bot will automatically connect at\n server start, so this command need only be given once. The\n /disconnect switch will permanently delete the bot. To only\n temporarily deactivate it, use the |wservices|n command instead.\n Provide an optional bot class path to use a custom bot.\n '}
        +
        +
        @@ -747,7 +1375,7 @@ Provide an optional bot class path to use a custom bot.

        Bases: evennia.commands.default.muxcommand.MuxCommand

        Check and reboot IRC bot.

        -
        Usage:

        ircstatus [#dbref ping||nicklist||reconnect]

        +
        Usage:

        ircstatus [#dbref ping | nicklist | reconnect]

        If not given arguments, will return a list of all bots (like @@ -790,6 +1418,11 @@ messages sent to either channel will be lost.

        lock_storage = 'cmd:serversetting(IRC_ENABLED) and perm(ircstatus) or perm(Builder))'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'comms', 'key': 'ircstatus', 'tags': '', 'text': "\n Check and reboot IRC bot.\n\n Usage:\n ircstatus [#dbref ping | nicklist | reconnect]\n\n If not given arguments, will return a list of all bots (like\n irc2chan/list). The 'ping' argument will ping the IRC network to\n see if the connection is still responsive. The 'nicklist' argument\n (aliases are 'who' and 'users') will return a list of users on the\n remote IRC channel. Finally, 'reconnect' will force the client to\n disconnect and reconnect again. This may be a last resort if the\n client has silently lost connection (this may happen if the remote\n network experience network issues). During the reconnection\n messages sent to either channel will be lost.\n\n "}
        +
        +
        @@ -862,6 +1495,11 @@ to identify the connection uniquely.

        lock_storage = 'cmd:serversetting(RSS_ENABLED) and pperm(Developer)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'comms', 'key': 'rss2chan', 'tags': '', 'text': '\n link an evennia channel to an external RSS feed\n\n Usage:\n rss2chan[/switches] <evennia_channel> = <rss_url>\n\n Switches:\n /disconnect - this will stop the feed and remove the connection to the\n channel.\n /remove - "\n /list - show all rss->evennia mappings\n\n Example:\n rss2chan rsschan = http://code.google.com/feeds/p/evennia/updates/basic\n\n This creates an RSS reader that connects to a given RSS feed url. Updates\n will be echoed as a title and news link to the given channel. The rate of\n updating is set with the RSS_UPDATE_INTERVAL variable in settings (default\n is every 10 minutes).\n\n When disconnecting you need to supply both the channel and url again so as\n to identify the connection uniquely.\n '}
        +
        +
        @@ -935,6 +1573,11 @@ must be added to game settings.

        lock_storage = 'cmd:serversetting(GRAPEVINE_ENABLED) and pperm(Developer)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'comms', 'key': 'grapevine2chan', 'tags': '', 'text': '\n Link an Evennia channel to an exteral Grapevine channel\n\n Usage:\n grapevine2chan[/switches] <evennia_channel> = <grapevine_channel>\n grapevine2chan/disconnect <connection #id>\n\n Switches:\n /list - (or no switch): show existing grapevine <-> Evennia\n mappings and available grapevine chans\n /remove - alias to disconnect\n /delete - alias to disconnect\n\n Example:\n grapevine2chan mygrapevine = gossip\n\n This creates a link between an in-game Evennia channel and an external\n Grapevine channel. The game must be registered with the Grapevine network\n (register at https://grapevine.haus) and the GRAPEVINE_* auth information\n must be added to game settings.\n '}
        +
        +
        @@ -982,7 +1625,6 @@ must be added to game settings.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -999,6 +1641,7 @@ must be added to game settings.

        +
        develop branch
        @@ -86,6 +87,11 @@ lock_storage = 'cmd:perm(home) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'home', 'tags': '', 'text': "\n move to your character's home location\n\n Usage:\n home\n\n Teleports you to your home location.\n "}
        +
        +
        @@ -107,7 +113,7 @@ look *<account&g
        -aliases = ['ls', 'l']
        +aliases = ['l', 'ls']
        @@ -136,6 +142,11 @@ look *<account&g lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'l ls', 'category': 'general', 'key': 'look', 'tags': '', 'text': '\n look at location or object\n\n Usage:\n look\n look <obj>\n look *<account>\n\n Observes your location or objects in your vicinity.\n '}
        +
        +
        @@ -195,7 +206,7 @@ for everyone to use, you need build privileges and the alias command.

        -aliases = ['nickname', 'nicks']
        +aliases = ['nicks', 'nickname']
        @@ -225,6 +236,11 @@ for everyone to use, you need build privileges and the alias command.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'nicks nickname', 'category': 'general', 'key': 'nick', 'tags': '', 'text': '\n define a personal alias/nick by defining a string to\n match and replace it with another on the fly\n\n Usage:\n nick[/switches] <string> [= [replacement_string]]\n nick[/switches] <template> = <replacement_template>\n nick/delete <string> or number\n nicks\n\n Switches:\n inputline - replace on the inputline (default)\n object - replace on object-lookup\n account - replace on account-lookup\n list - show all defined aliases (also "nicks" works)\n delete - remove nick by index in /list\n clearall - clear all nicks\n\n Examples:\n nick hi = say Hello, I\'m Sarah!\n nick/object tom = the tall man\n nick build $1 $2 = create/drop $1;$2\n nick tell $1 $2=page $1=$2\n nick tm?$1=page tallman=$1\n nick tm\\=$1=page tallman=$1\n\n A \'nick\' is a personal string replacement. Use $1, $2, ... to catch arguments.\n Put the last $-marker without an ending space to catch all remaining text. You\n can also use unix-glob matching for the left-hand side <string>:\n\n * - matches everything\n ? - matches 0 or 1 single characters\n [abcd] - matches these chars in any order\n [!abcd] - matches everything not among these chars\n \\= - escape literal \'=\' you want in your <string>\n\n Note that no objects are actually renamed or changed by this command - your nicks\n are only available to you. If you want to permanently add keywords to an object\n for everyone to use, you need build privileges and the alias command.\n\n '}
        +
        +
        @@ -274,6 +290,11 @@ inv

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'inv i', 'category': 'general', 'key': 'inventory', 'tags': '', 'text': '\n view inventory\n\n Usage:\n inventory\n inv\n\n Shows your inventory.\n '}
        +
        +
        @@ -324,6 +345,11 @@ look at you.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'setdesc', 'tags': '', 'text': '\n describe yourself\n\n Usage:\n setdesc <description>\n\n Add a description to yourself. This\n will be visible to people when they\n look at you.\n '}
        +
        +
        @@ -349,7 +375,7 @@ your inventory.

        -locks = 'cmd:all()'
        +locks = 'cmd:all();view:perm(Developer);read:perm(Developer)'
        @@ -370,7 +396,12 @@ your inventory.

        -lock_storage = 'cmd:all()'
        +lock_storage = 'cmd:all();view:perm(Developer);read:perm(Developer)' +
        + +
        +
        +search_index_entry = {'aliases': 'grab', 'category': 'general', 'key': 'get', 'tags': '', 'text': '\n pick up something\n\n Usage:\n get <obj>\n\n Picks up an object from your location and puts it in\n your inventory.\n '}
        @@ -422,6 +453,11 @@ location you are currently in.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'drop', 'tags': '', 'text': '\n drop something\n\n Usage:\n drop <obj>\n\n Lets you drop an object from your inventory into the\n location you are currently in.\n '}
        +
        +
        @@ -476,6 +512,11 @@ placing it in their inventory.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'give', 'tags': '', 'text': '\n give away something to someone\n\n Usage:\n give <inventory obj> <to||=> <target>\n\n Gives an items from your inventory to another character,\n placing it in their inventory.\n '}
        +
        +
        @@ -519,6 +560,11 @@ placing it in their inventory.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '\' "', 'category': 'general', 'key': 'say', 'tags': '', 'text': '\n speak as your character\n\n Usage:\n say <message>\n\n Talk to those in your current location.\n '}
        +
        +
        @@ -564,6 +610,11 @@ others in the room being informed.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'whisper', 'tags': '', 'text': '\n Speak privately as your character to another\n\n Usage:\n whisper <character> = <message>\n whisper <char1>, <char2> = <message>\n\n Talk privately to one or more characters in your current location, without\n others in the room being informed.\n '}
        +
        +
        @@ -591,7 +642,7 @@ automatically begin with your name.

        -aliases = [':', 'emote']
        +aliases = ['emote', ':']
        @@ -625,6 +676,11 @@ space.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'emote :', 'category': 'general', 'key': 'pose', 'tags': '', 'text': "\n strike a pose\n\n Usage:\n pose <pose text>\n pose's <pose text>\n\n Example:\n pose is standing by the wall, smiling.\n -> others will see:\n Tom is standing by the wall, smiling.\n\n Describe an action being taken. The pose text will\n automatically begin with your name.\n "}
        +
        +
        @@ -645,7 +701,7 @@ which permission groups you are a member of.

        -aliases = ['hierarchy', 'groups']
        +aliases = ['groups', 'hierarchy']
        @@ -674,6 +730,11 @@ which permission groups you are a member of.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'groups hierarchy', 'category': 'general', 'key': 'access', 'tags': '', 'text': '\n show your current game access\n\n Usage:\n access\n\n This command shows you the permission hierarchy and\n which permission groups you are a member of.\n '}
        +
        +
        @@ -721,7 +782,6 @@ which permission groups you are a member of.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -738,6 +798,7 @@ which permission groups you are a member of.

        +
        develop branch
        @@ -39,24 +40,26 @@

        evennia.commands.default.help

        -

        The help command. The basic idea is that help texts for commands -are best written by those that write the commands - the admins. So -command-help is all auto-loaded and searched from the current command -set. The normal, database-tied help system is used for collaborative -creation of other help topics such as RP help or game-world aides.

        +

        The help command. The basic idea is that help texts for commands are best +written by those that write the commands - the developers. So command-help is +all auto-loaded and searched from the current command set. The normal, +database-tied help system is used for collaborative creation of other help +topics such as RP help or game-world aides. Help entries can also be created +outside the game in modules given by **settings.FILE_HELP_ENTRY_MODULES**.

        class evennia.commands.default.help.CmdHelp(**kwargs)[source]

        Bases: evennia.commands.default.muxcommand.MuxCommand

        -

        View help or a list of topics

        +

        Get help.

        -
        Usage:

        help <topic or command> -help list -help all

        +
        Usage:

        help +help <topic, command or category> +help <topic>/<subtopic> +help <topic>/<subtopic>/<subsubtopic> …

        -

        This will search for help on commands and other -topics related to the game.

        +

        Use the ‘help’ command alone to see an index of all help topics, organized +by category.eSome big topics may offer additional sub-topics.

        key = 'help'
        @@ -87,6 +90,21 @@ topics related to the game.

        help_more = True
        +
        +
        +index_type_separator_clr = '|w'
        +
        + +
        +
        +index_category_clr = '|W'
        +
        + +
        +
        +index_topic_clr = '|G'
        +
        +
        suggestion_cutoff = 0.6
        @@ -97,6 +115,16 @@ topics related to the game.

        suggestion_maxnum = 5
        +
        +
        +subtopic_separator_char = '/'
        +
        + +
        +
        +clickable_topics = True
        +
        +
        msg_help(text)[source]
        @@ -107,73 +135,147 @@ help window

        -static format_help_entry(title, help_text, aliases=None, suggested=None)[source]
        +format_help_entry(topic='', help_text='', aliases=None, suggested=None, subtopics=None, click_topics=True)[source]

        This visually formats the help entry. This method can be overriden to customize the way a help entry is displayed.

        Parameters
          -
        • title (str) – the title of the help entry.

        • -
        • help_text (str) – the text of the help entry.

        • -
        • aliases (list of str or None) – the list of aliases.

        • -
        • suggested (list of str or None) – suggested reading.

        • -
        -
        -
        -

        Returns the formatted string, ready to be sent.

        -
        - -
        -
        -static format_help_list(hdict_cmds, hdict_db)[source]
        -

        Output a category-ordered list. The input are the -pre-loaded help files for commands and database-helpfiles -respectively. You can override this method to return a -custom display of the list of commands and topics.

        -
        - -
        -
        -check_show_help(cmd, caller)[source]
        -

        Helper method. If this return True, the given cmd -auto-help will be viewable in the help listing. -Override this to easily select what is shown to -the account. Note that only commands available -in the caller’s merged cmdset are available.

        -
        -
        Parameters
        -
          -
        • cmd (Command) – Command class from the merged cmdset

        • -
        • caller (Character, Account or Session) – The current caller -executing the help command.

        • -
        -
        -
        -
        - -
        -
        -should_list_cmd(cmd, caller)[source]
        -

        Should the specified command appear in the help table?

        -

        This method only checks whether a specified command should -appear in the table of topics/commands. The command can be -used by the caller (see the ‘check_show_help’ method) and -the command will still be available, for instance, if a -character type ‘help name of the command’. However, if -you return False, the specified command will not appear in -the table. This is sometimes useful to “hide” commands in -the table, but still access them through the help system.

        -
        -
        Parameters
        -
          -
        • cmd – the command to be tested.

        • -
        • caller – the caller of the help system.

        • +
        • title (str, optional) – The title of the help entry.

        • +
        • help_text (str, optional) – Text of the help entry.

        • +
        • aliases (list, optional) – List of help-aliases (displayed in header).

        • +
        • suggested (list, optional) – Strings suggested reading (based on title).

        • +
        • subtopics (list, optional) – A list of strings - the subcategories available +for this entry.

        • +
        • click_topics (bool, optional) – Should help topics be clickable. Default is True.

        Returns
        -

        True – the command should appear in the table. -False: the command shouldn’t appear in the table.

        +

        help_message (str) – Help entry formated for console.

        +
        +
        +
        + +
        +
        +format_help_index(cmd_help_dict=None, db_help_dict=None, title_lone_category=False, click_topics=True)[source]
        +

        Output a category-ordered g for displaying the main help, grouped by +category.

        +
        +
        Parameters
        +
          +
        • cmd_help_dict (dict) – A dict {“category”: [topic, topic, …]} for +command-based help.

        • +
        • db_help_dict (dict) – A dict {“category”: [topic, topic], …]} for +database-based help.

        • +
        • title_lone_category (bool, optional) – If a lone category should +be titled with the category name or not. While pointless in a +general index, the title should probably show when explicitly +listing the category itself.

        • +
        • click_topics (bool, optional) – If help-topics are clickable or not +(for webclient or telnet clients with MXP support).

        • +
        +
        +
        Returns
        +

        str – The help index organized into a grid.

        +
        +
        +

        Notes

        +

        The input are the pre-loaded help files for commands and database-helpfiles +respectively. You can override this method to return a custom display of the list of +commands and topics.

        +
        + +
        +
        +can_read_topic(cmd_or_topic, caller)[source]
        +

        Helper method. If this return True, the given help topic +be viewable in the help listing. Note that even if this returns False, +the entry will still be visible in the help index unless should_list_topic +is also returning False.

        +
        +
        Parameters
        +
        +
        +
        Returns
        +

        bool – If command can be viewed or not.

        +
        +
        +

        Notes

        +

        This uses the ‘read’ lock. If no ‘read’ lock is defined, the topic is assumed readable +by all.

        +
        + +
        +
        +can_list_topic(cmd_or_topic, caller)[source]
        +

        Should the specified command appear in the help table?

        +

        This method only checks whether a specified command should appear in the table of +topics/commands. The command can be used by the caller (see the ‘should_show_help’ method) +and the command will still be available, for instance, if a character type ‘help name of the +command’. However, if you return False, the specified command will not appear in the table. +This is sometimes useful to “hide” commands in the table, but still access them through the +help system.

        +
        +
        Parameters
        +
        +
        +
        Returns
        +

        bool – If command should be listed or not.

        +
        +
        +

        Notes

        +

        By default, the ‘view’ lock will be checked, and if no such lock is defined, the ‘read’ +lock will be used. If neither lock is defined, the help entry is assumed to be +accessible to all.

        +
        + +
        +
        +collect_topics(caller, mode='list')[source]
        +

        Collect help topics from all sources (cmd/db/file).

        +
        +
        Parameters
        +
          +
        • caller (Object or Account) – The user of the Command.

        • +
        • mode (str) – One of ‘list’ or ‘query’, where the first means we are collecting to view +the help index and the second because of wanting to search for a specific help +entry/cmd to read. This determines which access should be checked.

        • +
        +
        +
        Returns
        +

        tuple – A tuple of three dicts containing the different types of help entries +in the order cmd-help, db-help, file-help:

        +
        +

        ({key: cmd,…}, {key: dbentry,…}, {key: fileentry,…}

        +
        +

        +
        +
        +
        + +
        + +

        Perform a help-query search, default using Lunr search engine.

        +
        +
        Parameters
        +
          +
        • query (str) – The help entry to search for.

        • +
        • entries (list) – All possibilities. A mix of commands, HelpEntries and FileHelpEntries.

        • +
        • search_fields (list) – A list of dicts defining how Lunr will find the +search data on the elements. If not given, will use a default.

        • +
        +
        +
        Returns
        +

        tuple – A tuple (match, suggestions).

        @@ -182,6 +284,13 @@ False: the command shouldn’t appear in the table.

        parse()[source]

        input is a string containing the command or topic to match.

        +

        The allowed syntax is

        +
        help <topic>[/<subtopic>[/<subtopic>[/...]]]
        +
        +
        +

        The database/command query is always for <topic>, and any subtopics +is then parsed from there. If a <topic> has spaces in it, it is +always matched before assuming the space begins a subtopic.

        @@ -200,12 +309,17 @@ False: the command shouldn’t appear in the table.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '?', 'category': 'general', 'key': 'help', 'tags': '', 'text': "\n Get help.\n\n Usage:\n help\n help <topic, command or category>\n help <topic>/<subtopic>\n help <topic>/<subtopic>/<subsubtopic> ...\n\n Use the 'help' command alone to see an index of all help topics, organized\n by category.eSome big topics may offer additional sub-topics.\n\n "}
        +
        +
        class evennia.commands.default.help.CmdSetHelp(**kwargs)[source]
        -

        Bases: evennia.commands.default.muxcommand.MuxCommand

        +

        Bases: evennia.commands.default.help.CmdHelp

        Edit the help database.

        Usage:

        help[/switches] <topic>[[;alias;alias][,category[,locks]] [= <text>]

        @@ -218,19 +332,53 @@ delete - remove help topic.

        Examples

        -

        sethelp throw = This throws something at … +

        sethelp lore = In the beginning was … sethelp/append pickpocketing,Thievery = This steals … sethelp/replace pickpocketing, ,attr(is_thief) = This steals … sethelp/edit thievery

        -

        This command manipulates the help database. A help entry can be created, -appended/merged to and deleted. If you don’t assign a category, the -“General” category will be used. If no lockstring is specified, default -is to let everyone read the help file.

        +

        If not assigning a category, the settings.DEFAULT_HELP_CATEGORY category +will be used. If no lockstring is specified, everyone will be able to read +the help entry. Sub-topics are embedded in the help text.

        +

        Note that this cannot modify command-help entries - these are modified +in-code, outside the game.

        +

        Subtopics helps to break up a long help entry into sub-sections. Users can +access subtopics with |whelp topic/subtopic/…|n Subtopics are created and +stored together with the main topic.

        +

        To start adding subtopics, add the text ‘# SUBTOPICS’ on a new line at the +end of your help text. After this you can now add any number of subtopics, +each starting with ‘## <subtopic-name>’ on a line, followed by the +help-text of that subtopic. +Use ‘### <subsub-name>’ to add a sub-subtopic and so on. Max depth is 5. A +subtopic’s title is case-insensitive and can consist of multiple words - +the user will be able to enter a partial match to access it.

        +

        For example:

        +
        +
        Main help text for <topic>
        +

        +
        # SUBTOPICS
        +

        +
        ## about
        +

        +
        Text for the ‘<topic>/about’ subtopic’
        +

        +
        ### more about-info
        +

        +
        Text for the ‘<topic>/about/more about-info sub-subtopic
        +

        +
        ## extra
        +

        +
        Text for the ‘<topic>/extra’ subtopic
        +
        key = 'sethelp'
        +
        +
        +aliases = []
        +
        +
        switch_options = ('edit', 'replace', 'append', 'extend', 'delete')
        @@ -246,6 +394,17 @@ is to let everyone read the help file.

        help_category = 'building'
        +
        +
        +arg_regex = None
        +
        + +
        +
        +parse()[source]
        +

        We want to use the default parser rather than the CmdHelp.parse

        +
        +
        func()[source]
        @@ -253,13 +412,13 @@ is to let everyone read the help file.

        -
        -aliases = []
        +
        +lock_storage = 'cmd:perm(Helper)'
        -
        -lock_storage = 'cmd:perm(Helper)'
        +
        +search_index_entry = {'aliases': '', 'category': 'building', 'key': 'sethelp', 'tags': '', 'text': "\n Edit the help database.\n\n Usage:\n help[/switches] <topic>[[;alias;alias][,category[,locks]] [= <text>]\n\n Switches:\n edit - open a line editor to edit the topic's help text.\n replace - overwrite existing help topic.\n append - add text to the end of existing topic with a newline between.\n extend - as append, but don't add a newline.\n delete - remove help topic.\n\n Examples:\n sethelp lore = In the beginning was ...\n sethelp/append pickpocketing,Thievery = This steals ...\n sethelp/replace pickpocketing, ,attr(is_thief) = This steals ...\n sethelp/edit thievery\n\n If not assigning a category, the `settings.DEFAULT_HELP_CATEGORY` category\n will be used. If no lockstring is specified, everyone will be able to read\n the help entry. Sub-topics are embedded in the help text.\n\n Note that this cannot modify command-help entries - these are modified\n in-code, outside the game.\n\n # SUBTOPICS\n\n ## Adding subtopics\n\n Subtopics helps to break up a long help entry into sub-sections. Users can\n access subtopics with |whelp topic/subtopic/...|n Subtopics are created and\n stored together with the main topic.\n\n To start adding subtopics, add the text '# SUBTOPICS' on a new line at the\n end of your help text. After this you can now add any number of subtopics,\n each starting with '## <subtopic-name>' on a line, followed by the\n help-text of that subtopic.\n Use '### <subsub-name>' to add a sub-subtopic and so on. Max depth is 5. A\n subtopic's title is case-insensitive and can consist of multiple words -\n the user will be able to enter a partial match to access it.\n\n For example:\n\n | Main help text for <topic>\n |\n | # SUBTOPICS\n |\n | ## about\n |\n | Text for the '<topic>/about' subtopic'\n |\n | ### more about-info\n |\n | Text for the '<topic>/about/more about-info sub-subtopic\n |\n | ## extra\n |\n | Text for the '<topic>/extra' subtopic\n\n "}
        @@ -309,7 +468,6 @@ is to let everyone read the help file.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -326,6 +484,7 @@ is to let everyone read the help file.

        +
        develop branch
        @@ -105,7 +106,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -122,6 +122,7 @@ +
        develop branch
        @@ -184,6 +185,11 @@ to all the variables defined therein.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'command', 'tags': '', 'text': "\n This sets up the basis for a MUX command. The idea\n is that most other Mux-related commands should just\n inherit from this and don't have to implement much\n parsing of their own unless they do something particularly\n advanced.\n\n Note that the class's __doc__ string (this text) is\n used by Evennia to create the automatic help entry for\n the command, so make sure to document consistently here.\n "}
        +
        +
        @@ -224,6 +230,11 @@ character is actually attached to this Account and Session.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'command', 'tags': '', 'text': '\n This is an on-Account version of the MuxCommand. Since these commands sit\n on Accounts rather than on Characters/Objects, we need to check\n this in the parser.\n\n Account commands are available also when puppeting a Character, it\'s\n just that they are applied with a lower priority and are always\n available, also when disconnected from a character (i.e. "ooc").\n\n This class makes sure that caller is always an Account object, while\n creating a new property "character" that is set only if a\n character is actually attached to this Account and Session.\n '}
        +
        + @@ -271,7 +282,6 @@ character is actually attached to this Account and Session.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -288,6 +298,7 @@ character is actually attached to this Account and Session.

        +
        develop branch
        @@ -89,6 +90,11 @@ the line is just added to the editor buffer).

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': '__noinput_command', 'tags': '', 'text': '\n This is called when there is no input given\n '}
        +
        +
        @@ -127,6 +133,11 @@ the line is just added to the editor buffer).

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': '__nomatch_command', 'tags': '', 'text': '\n No command was found matching the given input.\n '}
        +
        +
        @@ -175,118 +186,9 @@ the raw_cmdname is the cmdname unmodified by eventual prefix-st lock_storage = 'cmd:all()'
        - - -
        -
        -class evennia.commands.default.syscommands.SystemSendToChannel(**kwargs)[source]
        -

        Bases: evennia.commands.default.muxcommand.MuxCommand

        -

        This is a special command that the cmdhandler calls -when it detects that the command given matches -an existing Channel object key (or alias).

        -
        -key = '__send_to_channel_command'
        -
        - -
        -
        -locks = 'cmd:all()'
        -
        - -
        -
        -parse()[source]
        -

        This method is called by the cmdhandler once the command name -has been identified. It creates a new set of member variables -that can be later accessed from self.func() (see below)

        -

        The following variables are available for our use when entering this -method (from the command definition, and assigned on the fly by the -cmdhandler):

        -
        -

        self.key - the name of this command (‘look’) -self.aliases - the aliases of this cmd (‘l’) -self.permissions - permission string for this command -self.help_category - overall category of command

        -

        self.caller - the object calling this command -self.cmdstring - the actual command name used to call this

        -
        -
        -
        (this allows you to know which alias was used,

        for example)

        -
        -
        -
        -

        self.args - the raw input; everything following self.cmdstring. -self.cmdset - the cmdset from which this command was picked. Not

        -
        -

        often used (useful for commands like ‘help’ or to -list all available commands etc)

        -
        -
        -
        self.obj - the object on which this command was defined. It is often

        the same as self.caller.

        -
        -
        -
        -

        A MUX command has the following possible syntax:

        -
        -

        name[ with several words][/switch[/switch..]] arg1[,arg2,…] [[=|,] arg[,..]]

        -
        -

        The ‘name[ with several words]’ part is already dealt with by the -cmdhandler at this point, and stored in self.cmdname (we don’t use -it here). The rest of the command is stored in self.args, which can -start with the switch indicator /.

        -
        -
        Optional variables to aid in parsing, if set:
        -
        self.switch_options - (tuple of valid /switches expected by this

        command (without the /))

        -
        -
        self.rhs_split - Alternate string delimiter or tuple of strings

        to separate left/right hand sides. tuple form -gives priority split to first string delimiter.

        -
        -
        -
        -
        -

        This parser breaks self.args into its constituents and stores them in the -following variables:

        -
        -

        self.switches = [list of /switches (without the /)] -self.raw = This is the raw argument input, including switches -self.args = This is re-defined to be everything except the switches -self.lhs = Everything to the left of = (lhs:’left-hand side’). If

        -
        -

        no = is found, this is identical to self.args.

        -
        -
        -
        self.rhs: Everything to the right of = (rhs:’right-hand side’).

        If no ‘=’ is found, this is None.

        -
        -
        -

        self.lhslist - [self.lhs split into a list by comma] -self.rhslist - [list of self.rhs split into a list by comma] -self.arglist = [list of space-separated args (stripped, including ‘=’ if it exists)]

        -

        All args and list members are stripped of excess whitespace around the -strings, but case is preserved.

        -
        -
        - -
        -
        -func()[source]
        -

        Create a new message and send it to channel, using -the already formatted input.

        -
        - -
        -
        -aliases = []
        -
        - -
        -
        -help_category = 'general'
        -
        - -
        -
        -lock_storage = 'cmd:all()'
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': '__multimatch_command', 'tags': '', 'text': "\n Multiple command matches.\n\n The cmdhandler adds a special attribute 'matches' to this\n system command.\n\n matches = [(cmdname, args, cmdobj, cmdlen, mratio, raw_cmdname) , (cmdname, ...), ...]\n\n Here, `cmdname` is the command's name and `args` the rest of the incoming string,\n without said command name. `cmdobj` is the Command instance, the cmdlen is\n the same as len(cmdname) and mratio is a measure of how big a part of the\n full input string the cmdname takes up - an exact match would be 1.0. Finally,\n the `raw_cmdname` is the cmdname unmodified by eventual prefix-stripping.\n\n "}
        @@ -336,7 +238,6 @@ the already formatted input.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -353,6 +254,7 @@ the already formatted input.

        +
        develop branch
        @@ -83,6 +84,11 @@ reset to purge) and at_reload() hooks will be called.

        lock_storage = 'cmd:perm(reload) or perm(Developer)'
        +
        +
        +search_index_entry = {'aliases': 'restart', 'category': 'system', 'key': 'reload', 'tags': '', 'text': '\n reload the server\n\n Usage:\n reload [reason]\n\n This restarts the server. The Portal is not\n affected. Non-persistent scripts will survive a reload (use\n reset to purge) and at_reload() hooks will be called.\n '}
        +
        +
        @@ -135,6 +141,11 @@ cmdsets etc will be wiped.

        lock_storage = 'cmd:perm(reload) or perm(Developer)'
        +
        +
        +search_index_entry = {'aliases': 'reboot', 'category': 'system', 'key': 'reset', 'tags': '', 'text': '\n reset and reboot the server\n\n Usage:\n reset\n\n Notes:\n For normal updating you are recommended to use reload rather\n than this command. Use shutdown for a complete stop of\n everything.\n\n This emulates a cold reboot of the Server component of Evennia.\n The difference to shutdown is that the Server will auto-reboot\n and that it does not affect the Portal, so no users will be\n disconnected. Contrary to reload however, all shutdown hooks will\n be called and any non-database saved scripts, ndb-attributes,\n cmdsets etc will be wiped.\n\n '}
        +
        +
        @@ -178,6 +189,11 @@ cmdsets etc will be wiped.

        lock_storage = 'cmd:perm(shutdown) or perm(Developer)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'system', 'key': 'shutdown', 'tags': '', 'text': '\n stop the server completely\n\n Usage:\n shutdown [announcement]\n\n Gracefully shut down both Server and Portal.\n '}
        +
        +
        @@ -265,20 +281,30 @@ should only be accessible by trusted server admins/superusers.|n

        lock_storage = 'cmd:perm(py) or perm(Developer)'
        +
        +
        +search_index_entry = {'aliases': '!', 'category': 'system', 'key': 'py', 'tags': '', 'text': "\n execute a snippet of python code\n\n Usage:\n py [cmd]\n py/edit\n py/time <cmd>\n py/clientraw <cmd>\n py/noecho\n\n Switches:\n time - output an approximate execution time for <cmd>\n edit - open a code editor for multi-line code experimentation\n clientraw - turn off all client-specific escaping. Note that this may\n lead to different output depending on prototocol (such as angular brackets\n being parsed as HTML in the webclient but not in telnet clients)\n noecho - in Python console mode, turn off the input echo (e.g. if your client\n does this for you already)\n\n Without argument, open a Python console in-game. This is a full console,\n accepting multi-line Python code for testing and debugging. Type `exit()` to\n return to the game. If Evennia is reloaded, the console will be closed.\n\n Enter a line of instruction after the 'py' command to execute it\n immediately. Separate multiple commands by ';' or open the code editor\n using the /edit switch (all lines added in editor will be executed\n immediately when closing or using the execute command in the editor).\n\n A few variables are made available for convenience in order to offer access\n to the system (you can import more at execution time).\n\n Available variables in py environment:\n self, me : caller\n here : caller.location\n evennia : the evennia API\n inherits_from(obj, parent) : check object inheritance\n\n You can explore The evennia API from inside the game by calling\n the `__doc__` property on entities:\n py evennia.__doc__\n py evennia.managers.__doc__\n\n |rNote: In the wrong hands this command is a severe security risk. It\n should only be accessible by trusted server admins/superusers.|n\n\n "}
        +
        +
        class evennia.commands.default.system.CmdScripts(**kwargs)[source]

        Bases: evennia.commands.default.muxcommand.MuxCommand

        -

        list and manage all running scripts

        -
        -
        Usage:

        scripts[/switches] [#dbref, key, script.path or <obj>]

        +

        List and manage all running scripts. Allows for creating new global +scripts.

        +
        +
        Usage:

        script[/switches] [#dbref, key, script.path or <obj>]

        -
        Switches:

        start - start a script (must supply a script path) -stop - stops an existing script -kill - kills a script - without running its cleanup hooks -validate - run a validation on the script(s)

        +
        Switches:
        +
        create - create a new global script of given typeclass path. This will

        auto-start the script’s timer if it has one.

        +
        +
        +

        start - start/unpause an existing script’s timer. +stop - stops an existing script’s timer +pause - pause a script’s timer +delete - deletes script. This will also stop the timer as needed

        If no switches are given, this command just views all active @@ -286,7 +312,8 @@ scripts. The argument can be either an object, at which point it will be searched for all scripts defined on it, or a script name or #dbref. For using the /stop switch, a unique script #dbref is required since whole classes of scripts often have the same name.

        -

        Use script for managing commands on objects.

        +

        Use the script build-level command for managing scripts attached to +objects.

        key = 'scripts'
        @@ -294,12 +321,12 @@ required since whole classes of scripts often have the same name.

        -aliases = ['listscripts', 'globalscript']
        +aliases = []
        -switch_options = ('start', 'stop', 'kill', 'validate')
        +switch_options = ('create', 'start', 'stop', 'pause', 'delete')
        @@ -317,6 +344,11 @@ required since whole classes of scripts often have the same name.

        excluded_typeclass_paths = ['evennia.prototypes.prototypes.DbPrototype']
        +
        +
        +switch_mapping = {'create': '|gCreated|n', 'delete': '|rDeleted|n', 'pause': '|Paused|n', 'start': '|gStarted|n', 'stop': '|RStopped|n'}
        +
        +
        func()[source]
        @@ -328,6 +360,11 @@ required since whole classes of scripts often have the same name.

        lock_storage = 'cmd:perm(listscripts) or perm(Admin)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'system', 'key': 'scripts', 'tags': '', 'text': "\n List and manage all running scripts. Allows for creating new global\n scripts.\n\n Usage:\n script[/switches] [#dbref, key, script.path or <obj>]\n\n Switches:\n create - create a new global script of given typeclass path. This will\n auto-start the script's timer if it has one.\n start - start/unpause an existing script's timer.\n stop - stops an existing script's timer\n pause - pause a script's timer\n delete - deletes script. This will also stop the timer as needed\n\n If no switches are given, this command just views all active\n scripts. The argument can be either an object, at which point it\n will be searched for all scripts defined on it, or a script name\n or #dbref. For using the /stop switch, a unique script #dbref is\n required since whole classes of scripts often have the same name.\n\n Use the `script` build-level command for managing scripts attached to\n objects.\n\n "}
        +
        +
        @@ -349,7 +386,7 @@ given, <nr> defaults to 10.

        -aliases = ['listobjects', 'listobjs', 'db', 'stats']
        +aliases = ['listobjects', 'db', 'stats', 'listobjs']
        @@ -373,6 +410,11 @@ given, <nr> defaults to 10.

        lock_storage = 'cmd:perm(listobjects) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': 'listobjects db stats listobjs', 'category': 'system', 'key': 'objects', 'tags': '', 'text': '\n statistics on objects in the database\n\n Usage:\n objects [<nr>]\n\n Gives statictics on objects in database as well as\n a list of <nr> latest objects in database. If not\n given, <nr> defaults to 10.\n '}
        +
        +
        @@ -430,6 +472,11 @@ in the list.

        lock_storage = 'cmd:perm(service) or perm(Developer)'
        +
        +
        +search_index_entry = {'aliases': 'services', 'category': 'system', 'key': 'service', 'tags': '', 'text': '\n manage system services\n\n Usage:\n service[/switch] <service>\n\n Switches:\n list - shows all available services (default)\n start - activates or reactivate a service\n stop - stops/inactivate a service (can often be restarted)\n delete - tries to permanently remove a service\n\n Service management system. Allows for the listing,\n starting, and stopping of services. If no switches\n are given, services will be listed. Note that to operate on the\n service you have to supply the full (green or red) name as given\n in the list.\n '}
        +
        +
        @@ -473,6 +520,11 @@ in the list.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'version', 'category': 'system', 'key': 'about', 'tags': '', 'text': '\n show Evennia info\n\n Usage:\n about\n\n Display info about the game engine.\n '}
        +
        +
        @@ -517,6 +569,11 @@ and the current time stamp.

        lock_storage = 'cmd:perm(time) or perm(Player)'
        +
        +
        +search_index_entry = {'aliases': 'uptime', 'category': 'system', 'key': 'time', 'tags': '', 'text': '\n show server time statistics\n\n Usage:\n time\n\n List Server time statistics such as uptime\n and the current time stamp.\n '}
        +
        +
        @@ -585,6 +642,100 @@ the released memory will instead be re-used by the program.

        lock_storage = 'cmd:perm(list) or perm(Developer)'
        +
        +
        +search_index_entry = {'aliases': 'serverprocess serverload', 'category': 'system', 'key': 'server', 'tags': '', 'text': "\n show server load and memory statistics\n\n Usage:\n server[/mem]\n\n Switches:\n mem - return only a string of the current memory usage\n flushmem - flush the idmapper cache\n\n This command shows server load statistics and dynamic memory\n usage. It also allows to flush the cache of accessed database\n objects.\n\n Some Important statistics in the table:\n\n |wServer load|n is an average of processor usage. It's usually\n between 0 (no usage) and 1 (100% usage), but may also be\n temporarily higher if your computer has multiple CPU cores.\n\n The |wResident/Virtual memory|n displays the total memory used by\n the server process.\n\n Evennia |wcaches|n all retrieved database entities when they are\n loaded by use of the idmapper functionality. This allows Evennia\n to maintain the same instances of an entity and allowing\n non-persistent storage schemes. The total amount of cached objects\n are displayed plus a breakdown of database object types.\n\n The |wflushmem|n switch allows to flush the object cache. Please\n note that due to how Python's memory management works, releasing\n caches may not show you a lower Residual/Virtual memory footprint,\n the released memory will instead be re-used by the program.\n\n "}
        +
        + + + +
        +
        +class evennia.commands.default.system.CmdTasks(**kwargs)[source]
        +

        Bases: evennia.commands.default.muxcommand.MuxCommand

        +

        Display or terminate active tasks (delays).

        +
        +
        Usage:

        tasks[/switch] [task_id or function_name]

        +
        +
        Switches:

        pause - Pause the callback of a task. +unpause - Process all callbacks made since pause() was called. +do_task - Execute the task (call its callback). +call - Call the callback of this task. +remove - Remove a task without executing it. +cancel - Stop a task from automatically executing.

        +
        +
        +

        Notes

        +

        A task is a single use method of delaying the call of a function. Calls are created +in code, using evennia.utils.delay. +See |luhttps://www.evennia.com/docs/latest/Command-Duration.html|ltthe docs|le for help.

        +

        By default, tasks that are canceled and never called are cleaned up after one minute.

        +

        Examples

        +
          +
        • +
          tasks/cancel move_callback - Cancels all movement delays from the slow_exit contrib.

          In this example slow exits creates it’s tasks with +utils.delay(move_delay, move_callback)

          +
          +
          +
        • +
        • tasks/cancel 2 - Cancel task id 2.

        • +
        +
        +
        +key = 'tasks'
        +
        + +
        +
        +aliases = ['task', 'delays']
        +
        + +
        +
        +switch_options = ('pause', 'unpause', 'do_task', 'call', 'remove', 'cancel')
        +
        + +
        +
        +locks = 'cmd:all();perm(Developer)'
        +
        + +
        +
        +help_category = 'system'
        +
        + +
        +
        +static coll_date_func(task)[source]
        +

        Replace regex characters in date string and collect deferred function name.

        +
        + +
        +
        +do_task_action(*args, **kwargs)[source]
        +

        Process the action of a tasks command.

        +

        This exists to gain support with yes or no function from EvMenu.

        +
        + +
        +
        +func()[source]
        +

        This is the hook function that actually does all the work. It is called +by the cmdhandler right after self.parser() finishes, and so has access +to all the variables defined therein.

        +
        + +
        +
        +lock_storage = 'cmd:all();cmd:perm(Developer)'
        +
        + +
        +
        +search_index_entry = {'aliases': 'task delays', 'category': 'system', 'key': 'tasks', 'tags': '', 'text': "\n Display or terminate active tasks (delays).\n\n Usage:\n tasks[/switch] [task_id or function_name]\n\n Switches:\n pause - Pause the callback of a task.\n unpause - Process all callbacks made since pause() was called.\n do_task - Execute the task (call its callback).\n call - Call the callback of this task.\n remove - Remove a task without executing it.\n cancel - Stop a task from automatically executing.\n\n Notes:\n A task is a single use method of delaying the call of a function. Calls are created\n in code, using `evennia.utils.delay`.\n See |luhttps://www.evennia.com/docs/latest/Command-Duration.html|ltthe docs|le for help.\n\n By default, tasks that are canceled and never called are cleaned up after one minute.\n\n Examples:\n - `tasks/cancel move_callback` - Cancels all movement delays from the slow_exit contrib.\n In this example slow exits creates it's tasks with\n `utils.delay(move_delay, move_callback)`\n - `tasks/cancel 2` - Cancel task id 2.\n\n "}
        +
        +
        @@ -632,7 +783,6 @@ the released memory will instead be re-used by the program.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -649,6 +799,7 @@ the released memory will instead be re-used by the program.

        +
        develop branch
        @@ -51,25 +52,107 @@ main test suite started with

        class evennia.commands.default.tests.CommandTest(methodName='runTest')[source]

        Bases: evennia.utils.test_resources.EvenniaTest

        -

        Tests a command

        +

        Tests a Command by running it and comparing what messages it sends with +expected values. This tests without actually spinning up the cmdhandler +for every test, which is more controlled.

        +

        Example:

        +
        from commands.echo import CmdEcho
        +
        +class MyCommandTest(CommandTest):
        +
        +    def test_echo(self):
        +        '''
        +        Test that the echo command really returns
        +        what you pass into it.
        +        '''
        +        self.call(MyCommand(), "hello world!",
        +                  "You hear your echo: 'Hello world!'")
        +
        +
        -call(cmdobj, args, msg=None, cmdset=None, noansi=True, caller=None, receiver=None, cmdstring=None, obj=None, inputs=None, raw_string=None)[source]
        -

        Test a command by assigning all the needed -properties to cmdobj and running

        -
        -

        cmdobj.at_pre_cmd() -cmdobj.parse() -cmdobj.func() -cmdobj.at_post_cmd()

        -
        -

        The msgreturn value is compared to eventual -output sent to caller.msg in the game

        +call(cmdobj, input_args, msg=None, cmdset=None, noansi=True, caller=None, receiver=None, cmdstring=None, obj=None, inputs=None, raw_string=None)[source] +

        Test a command by assigning all the needed properties to a cmdobj and +running the sequence. The resulting .msg calls will be mocked and +the text= calls to them compared to a expected output.

        -
        Returns
        -

        msg (str) – The received message that was sent to the caller.

        +
        Parameters
        +
          +
        • cmdobj (Command) – The command object to use.

        • +
        • input_args (str) – This should be the full input the Command should +see, such as ‘look here’. This will become .args for the Command +instance to parse.

        • +
        • msg (str or dict, optional) – This is the expected return value(s) +returned through caller.msg(text=…) calls in the command. If a string, the +receiver is controlled with the receiver kwarg (defaults to caller). +If this is a dict, it is a mapping +{receiver1: “expected1”, receiver2: “expected2”,…} and receiver is +ignored. The message(s) are compared with the actual messages returned +to the receiver(s) as the Command runs. Each check uses .startswith, +so you can choose to only include the first part of the +returned message if that’s enough to verify a correct result. EvMenu +decorations (like borders) are stripped and should not be included. This +should also not include color tags unless noansi=False. +If the command returns texts in multiple separate .msg- +calls to a receiver, separate these with | if noansi=True +(default) and || if noansi=False. If no msg is given (None), +then no automatic comparison will be done.

        • +
        • cmdset (str, optional) – If given, make .cmdset available on the Command +instance as it runs. While .cmdset is normally available on the +Command instance by default, this is usually only used by +commands that explicitly operates/displays cmdsets, like +examine.

        • +
        • noansi (str, optional) – By default the color tags of the msg is +ignored, this makes them significant. If unset, msg must contain +the same color tags as the actual return message.

        • +
        • caller (Object or Account, optional) – By default self.char1 is used as the +command-caller (the .caller property on the Command). This allows to +execute with another caller, most commonly an Account.

        • +
        • receiver (Object or Account, optional) – This is the object to receive the +return messages we want to test. By default this is the same as caller +(which in turn defaults to is self.char1). Note that if msg is +a dict, this is ignored since the receiver is already specified there.

        • +
        • cmdstring (str, optional) – Normally this is the Command’s key. +This allows for tweaking the .cmdname property of the +Command**. This isb used for commands with multiple aliases, +where the command explicitly checs which alias was used to +determine its functionality.

        • +
        • obj (str, optional) – This sets the .obj property of the Command - the +object on which the Command ‘sits’. By default this is the same as caller. +This can be used for testing on-object Command interactions.

        • +
        • inputs (list, optional) – A list of strings to pass to functions that pause to +take input from the user (normally using @interactive and +ret = yield(question) or evmenu.get_input). Each element of the +list will be passed into the command as if the user wrote that at the prompt.

        • +
        • raw_string (str, optional) – Normally the .raw_string property is set as +a combination of your key/cmdname and input_args. This allows +direct control of what this is, for example for testing edge cases +or malformed inputs.

        • +
        +
        +
        Returns
        +

        str or dict

        +
        +
        The message sent to receiver, or a dict of

        {receiver: “msg”, …} if multiple are given. This is usually +only used with msg=None to do the validation externally.

        +

        +
        +
        Raises
        +

        AssertionError – If the returns of .msg calls (tested with .startswith) does not +match expected_input.

        +
        +
        +

        Notes

        +

        As part of the tests, all methods of the Command will be called in +the proper order:

        +
          +
        • cmdobj.at_pre_cmd()

        • +
        • cmdobj.parse()

        • +
        • cmdobj.func()

        • +
        • cmdobj.at_post_cmd()

        • +
        @@ -139,6 +222,23 @@ output sent to caller.msg in the game

        class evennia.commands.default.tests.TestHelp(methodName='runTest')[source]

        Bases: evennia.commands.default.tests.CommandTest

        +
        +
        +maxDiff = None
        +
        + +
        +
        +setUp()[source]
        +

        Sets up testing environment

        +
        + +
        +
        +tearDown()[source]
        +

        Hook method for deconstructing the test fixture after testing it.

        +
        +
        test_help()[source]
        @@ -149,6 +249,83 @@ output sent to caller.msg in the game

        test_set_help()[source]
        +
        +
        +test_subtopic_fetch = None
        +
        + +
        +
        +test_subtopic_fetch_00_test()
        +

        Check retrieval of subtopics [with helparg=’test’, expected=’Help for testnnMain help text… test/something else test/more’].

        +
        + +
        +
        +test_subtopic_fetch_01_test_creating_extra_stuff()
        +

        Check retrieval of subtopics [with helparg=’test/creating extra stuff’, expected=’Help for test/creating extra st…ating extra stuff/subsubtopicn’].

        +
        + +
        +
        +test_subtopic_fetch_02_test_creating()
        +

        Check retrieval of subtopics [with helparg=’test/creating’, expected=’Help for test/creating extra st…ating extra stuff/subsubtopicn’].

        +
        + +
        +
        +test_subtopic_fetch_03_test_extra()
        +

        Check retrieval of subtopics [with helparg=’test/extra’, expected=’Help for test/creating extra st…ating extra stuff/subsubtopicn’].

        +
        + +
        +
        +test_subtopic_fetch_04_test_extra_subsubtopic()
        +

        Check retrieval of subtopics [with helparg=’test/extra/subsubtopic’, expected=’Help for test/creating extra st…bsubtopicnnA subsubtopic text’].

        +
        + +
        +
        +test_subtopic_fetch_05_test_creating_extra_subsub()
        +

        Check retrieval of subtopics [with helparg=’test/creating extra/subsub’, expected=’Help for test/creating extra st…bsubtopicnnA subsubtopic text’].

        +
        + +
        +
        +test_subtopic_fetch_06_test_Something_else()
        +

        Check retrieval of subtopics [with helparg=’test/Something else’, expected=’Help for test/something elsennSomething else’].

        +
        + +
        +
        +test_subtopic_fetch_07_test_More()
        +

        Check retrieval of subtopics [with helparg=’test/More’, expected=’Help for test/morennAnother t…opics:n test/more/second-more’].

        +
        + +
        +
        +test_subtopic_fetch_08_test_More_Second_more()
        +

        Check retrieval of subtopics [with helparg=’test/More/Second-more’, expected=’Help for test/more/second-more...est/more/second-more/third more’].

        +
        + +
        +
        +test_subtopic_fetch_09_test_More_more()
        +

        Check retrieval of subtopics [with helparg=’test/More/-more’, expected=’Help for test/more/second-more...est/more/second-more/third more’].

        +
        + +
        +
        +test_subtopic_fetch_10_test_more_second_more_again()
        +

        Check retrieval of subtopics [with helparg=’test/more/second/more again’, expected=’Help for test/more/second-more/more againnnEven more text.n’].

        +
        + +
        +
        +test_subtopic_fetch_11_test_more_second_third()
        +

        Check retrieval of subtopics [with helparg=’test/more/second/third’, expected=’Help for test/more/second-more/third morennThird more textn’].

        +
        +
        @@ -182,6 +359,106 @@ output sent to caller.msg in the game

        +
        +
        +evennia.commands.default.tests.func_test_cmd_tasks()[source]
        +
        + +
        +
        +class evennia.commands.default.tests.TestCmdTasks(methodName='runTest')[source]
        +

        Bases: evennia.commands.default.tests.CommandTest

        +
        +
        +setUp()[source]
        +

        Sets up testing environment

        +
        + +
        +
        +tearDown()[source]
        +

        Hook method for deconstructing the test fixture after testing it.

        +
        + +
        +
        +test_no_tasks()[source]
        +
        + +
        +
        +test_active_task()[source]
        +
        + +
        +
        +test_persistent_task()[source]
        +
        + +
        +
        +test_pause_unpause()[source]
        +
        + +
        +
        +test_do_task()[source]
        +
        + +
        +
        +test_remove()[source]
        +
        + +
        +
        +test_call()[source]
        +
        + +
        +
        +test_cancel()[source]
        +
        + +
        +
        +test_func_name_manipulation()[source]
        +
        + +
        +
        +test_wrong_func_name()[source]
        +
        + +
        +
        +test_no_input()[source]
        +
        + +
        +
        +test_responce_of_yes()[source]
        +
        + +
        +
        +test_task_complete_waiting_input()[source]
        +

        Test for task completing while waiting for input.

        +
        + +
        +
        +test_new_task_waiting_input()[source]
        +

        Test task completing than a new task with the same ID being made while waitinf for input.

        +
        + +
        +
        +test_misformed_command()[source]
        +
        + +
        +
        class evennia.commands.default.tests.TestAdmin(methodName='runTest')[source]
        @@ -447,11 +724,6 @@ output sent to caller.msg in the game

        test_toggle_com()[source]
        -
        -
        -test_channels()[source]
        -
        -
        test_all_com()[source]
        @@ -467,11 +739,6 @@ output sent to caller.msg in the game

        test_cdesc()[source]
        -
        -
        -test_cemit()[source]
        -
        -
        test_cwho()[source]
        @@ -494,13 +761,124 @@ output sent to caller.msg in the game

        +
        +
        +class evennia.commands.default.tests.TestCommsChannel(methodName='runTest')[source]
        +

        Bases: evennia.commands.default.tests.CommandTest

        +

        Test the central channel command.

        +
        +
        +setUp()[source]
        +

        Sets up testing environment

        +
        + +
        +
        +tearDown()[source]
        +

        Hook method for deconstructing the test fixture after testing it.

        +
        + +
        +
        +test_channel__noarg()[source]
        +
        + +
        +
        +test_channel__msg()[source]
        +
        + +
        +
        +test_channel__list()[source]
        +
        + +
        +
        +test_channel__all()[source]
        +
        + +
        +
        +test_channel__history()[source]
        +
        + +
        +
        +test_channel__sub()[source]
        +
        + +
        +
        +test_channel__unsub()[source]
        +
        + +
        +
        +test_channel__alias__unalias()[source]
        +

        Add and then remove a channel alias

        +
        + +
        +
        +test_channel__mute()[source]
        +
        + +
        +
        +test_channel__unmute()[source]
        +
        + +
        +
        +test_channel__create()[source]
        +
        + +
        +
        +test_channel__destroy()[source]
        +
        + +
        +
        +test_channel__desc()[source]
        +
        + +
        +
        +test_channel__lock()[source]
        +
        + +
        +
        +test_channel__unlock()[source]
        +
        + +
        +
        +test_channel__boot()[source]
        +
        + +
        +
        +test_channel__ban__unban()[source]
        +

        Test first ban and then unban

        +
        + +
        +
        +test_channel__who()[source]
        +
        + +
        +
        class evennia.commands.default.tests.TestBatchProcess(methodName='runTest')[source]

        Bases: evennia.commands.default.tests.CommandTest

        -test_batch_commands()[source]
        +test_batch_commands(mock_delay, mock_repeat)[source]
        @@ -509,7 +887,7 @@ output sent to caller.msg in the game

        class evennia.commands.default.tests.CmdInterrupt(**kwargs)[source]

        Bases: evennia.commands.command.Command

        -

        Base command

        +

        (you may see this if a child command had no help text defined)

        Usage:

        command [args]

        @@ -600,6 +978,11 @@ set in self.parse())

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'interrupt', 'tags': '', 'text': '\n ## Base command\n\n (you may see this if a child command had no help text defined)\n\n Usage:\n command [args]\n\n This is the base command class. Inherit from this\n to create new commands.\n\n The cmdhandler makes the following variables available to the\n command methods (so you can always assume them to be there):\n self.caller - the game object calling the command\n self.cmdstring - the command name used to trigger this command (allows\n you to know which alias was used, for example)\n cmd.args - everything supplied to the command following the cmdstring\n (this is usually what is parsed in self.parse())\n cmd.cmdset - the cmdset from which this command was matched (useful only\n seldomly, notably for help-type commands, to create dynamic\n help entries and lists)\n cmd.obj - the object on which this command is defined. If a default command,\n this is usually the same as caller.\n cmd.rawstring - the full raw string input, including any args and no parsing.\n\n The following class properties can/should be defined on your child class:\n\n key - identifier for command (e.g. "look")\n aliases - (optional) list of aliases (e.g. ["l", "loo"])\n locks - lock string (default is "cmd:all()")\n help_category - how to organize this help entry in help system\n (default is "General")\n auto_help - defaults to True. Allows for turning off auto-help generation\n arg_regex - (optional) raw string regex defining how the argument part of\n the command should look in order to match for this command\n (e.g. must it be a space between cmdname and arg?)\n auto_help_display_key - (optional) if given, this replaces the string shown\n in the auto-help listing. This is particularly useful for system-commands\n whose actual key is not really meaningful.\n\n (Note that if auto_help is on, this initial string is also used by the\n system to create the help entry for the command, so it\'s a good idea to\n format it similar to this one). This behavior can be changed by\n overriding the method \'get_help\' of a command: by default, this\n method returns cmd.__doc__ (that is, this very docstring, or\n the docstring of your command). You can, however, extend or\n replace this without disabling auto_help.\n '}
        +
        +
        @@ -638,11 +1021,6 @@ set in self.parse())

        test_multimatch()[source]
        -
        -
        -test_channelcommand(mock_channeldb)[source]
        -
        - @@ -690,7 +1068,6 @@ set in self.parse())

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -707,6 +1084,7 @@ set in self.parse())

        +
        develop branch
        @@ -59,7 +60,7 @@ connect “account name” “pass word”

        -aliases = ['conn', 'co', 'con']
        +aliases = ['con', 'co', 'conn']
        @@ -92,6 +93,11 @@ there is no object yet before the account has logged in)

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'con co conn', 'category': 'general', 'key': 'connect', 'tags': '', 'text': '\n connect to the game\n\n Usage (at login screen):\n connect accountname password\n connect "account name" "pass word"\n\n Use the create command to first create an account before logging in.\n\n If you have spaces in your name, enclose it in double quotes.\n '}
        +
        +
        @@ -113,7 +119,7 @@ create “account name” “pass word”

        -aliases = ['cr', 'cre']
        +aliases = ['cre', 'cr']
        @@ -142,6 +148,11 @@ create “account name” “pass word”

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'cre cr', 'category': 'general', 'key': 'create', 'tags': '', 'text': '\n create a new account account\n\n Usage (at login screen):\n create <accountname> <password>\n create "account name" "pass word"\n\n This creates a new account account.\n\n If you have spaces in your name, enclose it in double quotes.\n '}
        +
        +
        @@ -163,7 +174,7 @@ version is a bit more complicated.

        -aliases = ['qu', 'q']
        +aliases = ['q', 'qu']
        @@ -187,6 +198,11 @@ version is a bit more complicated.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'q qu', 'category': 'general', 'key': 'quit', 'tags': '', 'text': '\n quit when in unlogged-in state\n\n Usage:\n quit\n\n We maintain a different version of the quit command\n here for unconnected accounts for the sake of simplicity. The logged in\n version is a bit more complicated.\n '}
        +
        +
        @@ -232,6 +248,11 @@ All it does is display the connect screen.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'look l', 'category': 'general', 'key': '__unloggedin_look_command', 'tags': '', 'text': '\n look when in unlogged-in state\n\n Usage:\n look\n\n This is an unconnected version of the look command for simplicity.\n\n This is called by the server and kicks everything in gear.\n All it does is display the connect screen.\n '}
        +
        +
        @@ -252,7 +273,7 @@ for simplicity. It shows a pane of info.

        -aliases = ['h', '?']
        +aliases = ['?', 'h']
        @@ -276,6 +297,11 @@ for simplicity. It shows a pane of info.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '? h', 'category': 'general', 'key': 'help', 'tags': '', 'text': '\n get help when in unconnected-in state\n\n Usage:\n help\n\n This is an unconnected version of the help command,\n for simplicity. It shows a pane of info.\n '}
        +
        +
        @@ -323,7 +349,6 @@ for simplicity. It shows a pane of info.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -340,6 +365,7 @@ for simplicity. It shows a pane of info.

        +
        develop branch
        @@ -121,7 +122,6 @@ Evennia.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -138,6 +138,7 @@ Evennia.

        +
        develop branch
        @@ -46,11 +47,50 @@

        Bases: evennia.comms.models.ChannelDB

        This is the base class for all Channel Comms. Inherit from this to create different types of communication channels.

        +
        +
        Class-level variables:
          +
        • send_to_online_only (bool, default True) - if set, will only try to +send to subscribers that are actually active. This is a useful optimization.

        • +
        • log_file (str, default “channel_{channelname}.log”). This is the +log file to which the channel history will be saved. The {channelname} tag +will be replaced by the key of the Channel. If an Attribute ‘log_file’ +is set, this will be used instead. If this is None and no Attribute is found, +no history will be saved.

        • +
        • channel_prefix_string (str, default “[{channelname} ]”) - this is used +as a simple template to get the channel prefix with .channel_prefix().

        • +
        +
        +
        objects = <evennia.comms.managers.ChannelManager object>
        +
        +
        +send_to_online_only = True
        +
        + +
        +
        +log_file = 'channel_{channelname}.log'
        +
        + +
        +
        +channel_prefix_string = '[{channelname}] '
        +
        + +
        +
        +channel_msg_nick_pattern = '{alias}\\s*?|{alias}\\s+?(?P<arg1>.+?)'
        +
        + +
        +
        +channel_msg_nick_replacement = 'channel {channelname} = $1'
        +
        +
        at_first_save()[source]
        @@ -70,6 +110,34 @@ the hooks called by this method.

        Called once, when the channel is first created.

        +
        +
        +get_log_filename()[source]
        +

        File name to use for channel log.

        +
        +
        Returns
        +

        str

        +
        +
        The filename to use (this is always assumed to be inside

        settings.LOG_DIR)

        +
        +
        +

        +
        +
        +
        + +
        +
        +set_log_filename(filename)[source]
        +

        Set a custom log filename.

        +
        +
        Parameters
        +

        filename (str) – The filename to set. This is a path starting from +inside the settings.LOG_DIR location.

        +
        +
        +
        +
        has_connection(subscriber)[source]
        @@ -100,6 +168,11 @@ to this channel.

        property mutelist
        +
        +
        +property banlist
        +
        +
        property wholist
        @@ -119,14 +192,22 @@ but may use channel commands.

        overriding the call (unused by default).

        +
        Returns
        +

        bool

        +
        +
        True if muting was successful, False if we were already

        muted.

        +
        +
        +

        +
        unmute(subscriber, **kwargs)[source]
        -

        Removes an entity to the list of muted subscribers. A muted subscriber will no longer see channel messages, -but may use channel commands.

        +

        Removes an entity from the list of muted subscribers. A muted subscriber +will no longer see channel messages, but may use channel commands.

        Parameters
          @@ -135,6 +216,65 @@ but may use channel commands.

          overriding the call (unused by default).

        +
        Returns
        +

        bool

        +
        +
        True if unmuting was successful, False if we were already

        unmuted.

        +
        +
        +

        +
        +
        +
        + +
        +
        +ban(target, **kwargs)[source]
        +

        Ban a given user from connecting to the channel. This will not stop +users already connected, so the user must be booted for this to take +effect.

        +
        +
        Parameters
        +
          +
        • target (Object or Account) – The entity to unmute. This need not +be a subscriber.

        • +
        • **kwargs (dict) – Arbitrary, optional arguments for users +overriding the call (unused by default).

        • +
        +
        +
        Returns
        +

        bool

        +
        +
        True if banning was successful, False if target was already

        banned.

        +
        +
        +

        +
        +
        +
        + +
        +
        +unban(target, **kwargs)[source]
        +

        Un-Ban a given user. This will not reconnect them - they will still +have to reconnect and set up aliases anew.

        +
        +
        Parameters
        +
          +
        • target (Object or Account) – The entity to unmute. This need not +be a subscriber.

        • +
        • **kwargs (dict) – Arbitrary, optional arguments for users +overriding the call (unused by default).

        • +
        +
        +
        Returns
        +

        bool

        +
        +
        True if unbanning was successful, False if target was not

        previously banned.

        +
        +
        +

        +
        @@ -210,7 +350,7 @@ overriding the call (unused by default).

        -classmethod create(key, account=None, *args, **kwargs)[source]
        +classmethod create(key, creator=None, *args, **kwargs)[source]

        Creates a basic Channel with default parameters, unless otherwise specified or extended.

        Provides a friendlier interface to the utils.create_channel() function.

        @@ -218,7 +358,8 @@ specified or extended.

        Parameters
        • key (str) – This must be unique.

        • -
        • account (Account) – Account to attribute this object to.

        • +
        • creator (Account or Object) – Entity to associate with this channel +(used for tracking)

        Keyword Arguments
        @@ -242,172 +383,92 @@ errors (list): A list of errors in string form, if any.

        delete()[source]
        -

        Deletes channel while also cleaning up channelhandler.

        -
        - -
        -
        -message_transform(msgobj, emit=False, prefix=True, sender_strings=None, external=False, **kwargs)[source]
        -

        Generates the formatted string sent to listeners on a channel.

        -
        -
        Parameters
        -
          -
        • msgobj (Msg) – Message object to send.

        • -
        • emit (bool, optional) – In emit mode the message is not associated -with a specific sender name.

        • -
        • prefix (bool, optional) – Prefix msg with a text given by self.channel_prefix.

        • -
        • sender_strings (list, optional) – Used by bots etc, one string per external sender.

        • -
        • external (bool, optional) – If this is an external sender or not.

        • -
        • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

        • -
        -
        -
        -
        - -
        -
        -distribute_message(msgobj, online=False, **kwargs)[source]
        -

        Method for grabbing all listeners that a message should be -sent to on this channel, and sending them a message.

        -
        -
        Parameters
        -
          -
        • msgobj (Msg or TempMsg) – Message to distribute.

        • -
        • online (bool) – Only send to receivers who are actually online -(not currently used):

        • -
        • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

        • -
        -
        -
        -

        Notes

        -

        This is also where logging happens, if enabled.

        -
        - -
        -
        -msg(msgobj, header=None, senders=None, sender_strings=None, keep_log=None, online=False, emit=False, external=False)[source]
        -

        Send the given message to all accounts connected to channel. Note that -no permission-checking is done here; it is assumed to have been -done before calling this method. The optional keywords are not used if -persistent is False.

        -
        -
        Parameters
        -
          -
        • msgobj (Msg, TempMsg or str) – If a Msg/TempMsg, the remaining -keywords will be ignored (since the Msg/TempMsg object already -has all the data). If a string, this will either be sent as-is -(if persistent=False) or it will be used together with header -and senders keywords to create a Msg instance on the fly.

        • -
        • header (str, optional) – A header for building the message.

        • -
        • senders (Object, Account or list, optional) – Optional if persistent=False, used -to build senders for the message.

        • -
        • sender_strings (list, optional) – Name strings of senders. Used for external -connections where the sender is not an account or object. -When this is defined, external will be assumed. The list will be -filtered so each sender-string only occurs once.

        • -
        • keep_log (bool or None, optional) – This allows to temporarily change the logging status of -this channel message. If None, the Channel’s keep_log Attribute will -be used. If True or False, that logging status will be used for this -message only (note that for unlogged channels, a True value here will -create a new log file only for this message).

        • -
        • online (bool, optional) – online. Otherwise, messages all accounts connected. This can -make things faster, but may not trigger listeners on accounts -that are offline.

        • -
        • emit (bool, optional) – not to be directly associated with a name.

        • -
        • external (bool, optional) – Treat this message as being -agnostic of its sender.

        • -
        -
        -
        Returns
        -

        success (bool)

        -
        -
        Returns True if message sending was

        successful, False otherwise.

        -
        -
        -

        -
        -
        -
        - -
        -
        -tempmsg(message, header=None, senders=None)[source]
        -

        A wrapper for sending non-persistent messages.

        -
        -
        Parameters
        -
          -
        • message (str) – Message to send.

        • -
        • header (str, optional) – Header of message to send.

        • -
        • senders (Object or list, optional) – Senders of message to send.

        • -
        -
        -
        +

        Deletes channel.

        -channel_prefix(msg=None, emit=False, **kwargs)[source]
        +channel_prefix()[source]

        Hook method. How the channel should prefix itself for users.

        -
        Parameters
        -
          -
        • msg (str, optional) – Prefix text

        • -
        • emit (bool, optional) – Switches to emit mode, which usually -means to not prefix the channel’s info.

        • -
        • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

        • -
        -
        -
        Returns
        -

        prefix (str) – The created channel prefix.

        +
        Returns
        +

        str – The channel prefix.

        -
        -format_senders(senders=None, **kwargs)[source]
        -

        Hook method. Function used to format a list of sender names.

        +
        +add_user_channel_alias(user, alias, **kwargs)[source]
        +

        Add a personal user-alias for this channel to a given subscriber.

        Parameters
          -
        • senders (list) – Sender object names.

        • -
        • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

        • +
        • user (Object or Account) – The one to alias this channel.

        • +
        • alias (str) – The desired alias.

        -
        Returns
        -

        formatted_list (str) – The list of names formatted appropriately.

        +
        +
        +

        Note

        +

        This is tightly coupled to the default channel command. If you +change that, you need to change this as well.

        +

        We add two nicks - one is a plain alias -> channel.key that +users need to be able to reference this channel easily. The other +is a templated nick to easily be able to send messages to the +channel without needing to give the full channel command. The +structure of this nick is given by self.channel_msg_nick_pattern +and self.channel_msg_nick_replacement. By default it maps +alias <msg> -> channel <channelname> = <msg>, so that you can +for example just write pub Hello to send a message.

        +

        The alias created is alias $1 -> channel channel = $1, to allow +for sending to channel using the main channel command.

        +
        +
        + +
        +
        +classmethod remove_user_channel_alias(user, alias, **kwargs)[source]
        +

        Remove a personal channel alias from a user.

        +
        +
        Parameters
        +
          +
        • user (Object or Account) – The user to remove an alias from.

        • +
        • alias (str) – The alias to remove.

        • +
        • **kwargs – Unused by default. Can be used to pass extra variables +into a custom implementation.

        • +

        Notes

        -

        This function exists separately so that external sources -can use it to format source names in the same manner as -normal object/account names.

        +

        The channel-alias actually consists of two aliases - one +channel-based one for searching channels with the alias and one +inputline one for doing the ‘channelalias msg’ - call.

        +

        This is a classmethod because it doesn’t actually operate on the +channel instance.

        +

        It sits on the channel because the nick structure for this is +pretty complex and needs to be located in a central place (rather +on, say, the channel command).

        -
        -pose_transform(msgobj, sender_string, **kwargs)[source]
        -

        Hook method. Detects if the sender is posing, and modifies the -message accordingly.

        +
        +at_pre_msg(message, **kwargs)[source]
        +

        Called before the starting of sending the message to a receiver. This +is called before any hooks on the receiver itself. If this returns +None/False, the sending will be aborted.

        Parameters
          -
        • msgobj (Msg or TempMsg) – The message to analyze for a pose.

        • -
        • sender_string (str) – The name of the sender/poser.

        • -
        • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

        • +
        • message (str) – The message to send.

        • +
        • **kwargs (any) – Keywords passed on from .msg. This includes +senders.

        Returns
        -

        string (str)

        +

        str, False or None

        -
        A message that combines the sender_string

        component with msg in different ways depending on if a -pose was performed or not (this must be analyzed by the -hook).

        +
        Any custom changes made to the message. If

        falsy, no message will be sent.

        @@ -416,44 +477,51 @@ hook).

        -
        -format_external(msgobj, senders, emit=False, **kwargs)[source]
        -

        Hook method. Used for formatting external messages. This is -needed as a separate operation because the senders of external -messages may not be in-game objects/accounts, and so cannot -have things like custom user preferences.

        +
        +msg(message, senders=None, bypass_mute=False, **kwargs)[source]
        +

        Send message to channel, causing it to be distributed to all non-muted +subscribed users of that channel.

        Parameters
          -
        • msgobj (Msg or TempMsg) – The message to send.

        • -
        • senders (list) – Strings, one per sender.

        • -
        • emit (bool, optional) – A sender-agnostic message or not.

        • -
        • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

        • +
        • message (str) – The message to send.

        • +
        • senders (Object, Account or list, optional) – If not given, there is +no way to associate one or more senders with the message (like +a broadcast message or similar).

        • +
        • bypass_mute (bool, optional) – If set, always send, regardless of +individual mute-state of subscriber. This can be used for +global announcements or warnings/alerts.

        • +
        • **kwargs (any) – This will be passed on to all hooks. Use no_prefix +to exclude the channel prefix.

        -
        Returns
        -

        transformed (str) – A formatted string.

        -
        +

        Notes

        +

        The call hook calling sequence is:

        +
          +
        • msg = channel.at_pre_msg(message, **kwargs) (aborts for all if return None)

        • +
        • msg = receiver.at_pre_channel_msg(msg, channel, **kwargs) (aborts for receiver if return None)

        • +
        • receiver.at_channel_msg(msg, channel, **kwargs)

        • +
        • receiver.at_post_channel_msg(msg, channel, **kwargs)**

        • +
        +

        Called after all receivers are processed: +- channel.at_post_all_msg(message, **kwargs)

        +

        (where the senders/bypass_mute are embedded into **kwargs for +later access in hooks)

        -
        -format_message(msgobj, emit=False, **kwargs)[source]
        -

        Hook method. Formats a message body for display.

        +
        +at_post_msg(message, **kwargs)[source]
        +

        This is called after sending to all valid recipients. It is normally +used for logging/channel history.

        Parameters
          -
        • msgobj (Msg or TempMsg) – The message object to send.

        • -
        • emit (bool, optional) – The message is agnostic of senders.

        • -
        • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

        • +
        • message (str) – The message sent.

        • +
        • **kwargs (any) – Keywords passed on from msg, including senders.

        -
        Returns
        -

        transformed (str) – The formatted message.

        -
        @@ -489,6 +557,8 @@ overriding the call (unused by default).

        +

        Notes

        +

        By default this adds the needed channel nicks to the joiner.

        @@ -525,41 +595,6 @@ overriding the call (unused by default).

        -
        -
        -pre_send_message(msg, **kwargs)[source]
        -

        Hook method. Runs before a message is sent to the channel and -should return the message object, after any transformations. -If the message is to be discarded, return a false value.

        -
        -
        Parameters
        -
          -
        • msg (Msg or TempMsg) – Message to send.

        • -
        • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

        • -
        -
        -
        Returns
        -

        result (Msg, TempMsg or bool) – If False, abort send.

        -
        -
        -
        - -
        -
        -post_send_message(msg, **kwargs)[source]
        -

        Hook method. Run after a message is sent to the channel.

        -
        -
        Parameters
        -
          -
        • msg (Msg or TempMsg) – Message sent.

        • -
        • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

        • -
        -
        -
        -
        -
        at_init()[source]
        @@ -614,11 +649,11 @@ this object.

        For this to work, the developer must have defined a named view somewhere in urls.py that follows the format ‘modelname-action’, so in this case a named view of ‘channel-detail’ would be referenced by this method.

        -

        ex. -url(r’channels/(?P<slug>[wd-]+)/$’,

        -
        -

        ChannelDetailView.as_view(), name=’channel-detail’)

        -
        +

        ex.

        +
        url(r'channels/(?P<slug>[\w\d\-]+)/$',
        +    ChannelDetailView.as_view(), name='channel-detail')
        +
        +

        If no View has been created and defined in urls.py, returns an HTML anchor.

        This method is naive and simply returns a path. Securing access to @@ -640,11 +675,11 @@ object.

        For this to work, the developer must have defined a named view somewhere in urls.py that follows the format ‘modelname-action’, so in this case a named view of ‘channel-update’ would be referenced by this method.

        -

        ex. -url(r’channels/(?P<slug>[wd-]+)/(?P<pk>[0-9]+)/change/$’,

        -
        -

        ChannelUpdateView.as_view(), name=’channel-update’)

        -
        +

        ex.

        +
        url(r'channels/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/change/$',
        +    ChannelUpdateView.as_view(), name='channel-update')
        +
        +

        If no View has been created and defined in urls.py, returns an HTML anchor.

        This method is naive and simply returns a path. Securing access to @@ -691,11 +726,11 @@ this object.

        For this to work, the developer must have defined a named view somewhere in urls.py that follows the format ‘modelname-action’, so in this case a named view of ‘channel-detail’ would be referenced by this method.

        -

        ex. -url(r’channels/(?P<slug>[wd-]+)/$’,

        -
        -

        ChannelDetailView.as_view(), name=’channel-detail’)

        -
        +

        ex.

        +
        url(r'channels/(?P<slug>[\w\d\-]+)/$',
        +    ChannelDetailView.as_view(), name='channel-detail')
        +
        +

        If no View has been created and defined in urls.py, returns an HTML anchor.

        This method is naive and simply returns a path. Securing access to @@ -708,6 +743,46 @@ responsibility.

        +
        +
        +message_transform(*args, **kwargs)[source]
        +
        + +
        +
        +distribute_message(msgobj, online=False, **kwargs)[source]
        +
        + +
        +
        +format_senders(senders=None, **kwargs)[source]
        +
        + +
        +
        +pose_transform(msgobj, sender_string, **kwargs)[source]
        +
        + +
        +
        +format_external(msgobj, senders, emit=False, **kwargs)[source]
        +
        + +
        +
        +format_message(msgobj, emit=False, **kwargs)[source]
        +
        + +
        +
        +pre_send_message(msg, **kwargs)[source]
        +
        + +
        +
        +post_send_message(msg, **kwargs)[source]
        +
        +
        exception DoesNotExist
        @@ -777,7 +852,6 @@ responsibility.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -794,6 +868,7 @@ responsibility.

        +
        develop branch
        @@ -94,7 +95,6 @@ as code related to external communication like IRC or RSS.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -111,6 +111,7 @@ as code related to external communication like IRC or RSS.

        +
        develop branch
        @@ -135,19 +136,15 @@ of which may be Channels).

        -get_messages_by_sender(sender, exclude_channel_messages=False)[source]
        +get_messages_by_sender(sender)[source]

        Get all messages sent by one entity - this could be either a account or an object

        Parameters
        -
          -
        • sender (Account or Object) – The sender of the message.

        • -
        • exclude_channel_messages (bool, optional) – Only return messages -not aimed at a channel (that is, private tells for example)

        • -
        +

        sender (Account or Object) – The sender of the message.

        Returns
        -

        messages (list) – List of matching messages

        +

        QuerySet – Matching messages.

        Raises

        CommError – For incorrect sender types.

        @@ -164,7 +161,7 @@ not aimed at a channel (that is, private tells for example)

        recipient (Object, Account or Channel) – The recipient of the messages to search for.

        Returns
        -

        messages (list) – Matching messages.

        +

        Queryset – Matching messages.

        Raises

        CommError – If the recipient is not of a valid type.

        @@ -172,20 +169,6 @@ not aimed at a channel (that is, private tells for example)

        -
        -
        -get_messages_by_channel(channel)[source]
        -

        Get all persistent messages sent to one channel.

        -
        -
        Parameters
        -

        channel (Channel) – The channel to find messages for.

        -
        -
        Returns
        -

        messages (list) – Persistent Msg objects saved for this channel.

        -
        -
        -
        -
        search_message(sender=None, receiver=None, freetext=None, dbref=None)[source]
        @@ -194,7 +177,7 @@ one of the arguments must be given to do a search.

        Parameters
          -
        • sender (Object or Account, optional) – Get messages sent by a particular account or object

        • +
        • sender (Object, Account or Script, optional) – Get messages sent by a particular sender.

        • receiver (Object, Account or Channel, optional) – Get messages received by a certain account,object or channel

        • freetext (str) – Search for a text string in a message. NOTE: @@ -206,7 +189,7 @@ always gives only one match.

        Returns
        -

        messages (list or Msg) – A list of message matches or a single match if dbref was given.

        +

        Queryset – Message matches.

        @@ -219,7 +202,7 @@ one of the arguments must be given to do a search.

        Parameters
          -
        • sender (Object or Account, optional) – Get messages sent by a particular account or object

        • +
        • sender (Object, Account or Script, optional) – Get messages sent by a particular sender.

        • receiver (Object, Account or Channel, optional) – Get messages received by a certain account,object or channel

        • freetext (str) – Search for a text string in a message. NOTE: @@ -231,7 +214,7 @@ always gives only one match.

        Returns
        -

        messages (list or Msg) – A list of message matches or a single match if dbref was given.

        +

        Queryset – Message matches.

        @@ -374,7 +357,6 @@ case sensitive) match.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -391,6 +373,7 @@ case sensitive) match.

        +
        develop branch
        @@ -64,17 +65,16 @@ accessed via specific handler methods):

      • db_sender_accounts: Account senders

      • db_sender_objects: Object senders

      • db_sender_scripts: Script senders

      • -
      • db_sender_external: External senders (defined as string names)

      • +
      • db_sender_external: External sender (defined as string name)

      • db_receivers_accounts: Receiving accounts

      • db_receivers_objects: Receiving objects

      • db_receivers_scripts: Receiveing scripts

      • -
      • db_receivers_channels: Receiving channels

      • +
      • db_receiver_external: External sender (defined as string name)

      • db_header: Header text

      • db_message: The actual message text

      • db_date_created: time message was created / sent

      • db_hide_from_sender: bool if message should be hidden from sender

      • db_hide_from_receivers: list of receiver objects to hide message from

      • -
      • db_hide_from_channels: list of channels objects to hide message from

      • db_lock_storage: Internal storage of lock strings.

      • @@ -181,19 +181,10 @@ class built by **create_forward_many_to_many_manager()** define
        -
        -db_receivers_channels
        -

        Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

        -

        In the example:

        -
        class Pizza(Model):
        -    toppings = ManyToManyField(Topping, related_name='pizzas')
        -
        -
        -

        **Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

        -

        Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

        +
        +db_receiver_external
        +

        A wrapper for a deferred-loading field. When the value is read from this +object the first time, the query is executed.

        @@ -256,22 +247,6 @@ instances.

        class built by **create_forward_many_to_many_manager()** defined below.

        -
        -
        -db_hide_from_channels
        -

        Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

        -

        In the example:

        -
        class Pizza(Model):
        -    toppings = ManyToManyField(Topping, related_name='pizzas')
        -
        -
        -

        **Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

        -

        Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

        -
        -
        db_tags
        @@ -293,12 +268,6 @@ class built by **create_forward_many_to_many_manager()** define objects = <evennia.comms.managers.MsgManager object>
        -
        -
        -__init__(*args, **kwargs)[source]
        -

        Initialize self. See help(type(self)) for accurate signature.

        -
        -
        locks[source]
        @@ -312,7 +281,7 @@ class built by **create_forward_many_to_many_manager()** define
        property senders
        -

        Getter. Allows for value = self.sender

        +

        Getter. Allows for value = self.senders

        @@ -321,7 +290,8 @@ class built by **create_forward_many_to_many_manager()** define

        Remove a single sender or a list of senders.

        Parameters
        -

        senders (Account, Object, str or list) – Senders to remove.

        +

        senders (Account, Object, str or list) – Senders to remove. +If a string, removes the external sender.

        @@ -330,31 +300,29 @@ class built by **create_forward_many_to_many_manager()** define
        property receivers

        Getter. Allows for value = self.receivers. -Returns four lists of receivers: accounts, objects, scripts and channels.

        +Returns four lists of receivers: accounts, objects, scripts and

        +
        +

        external_receivers.

        +
        remove_receiver(receivers)[source]
        -

        Remove a single receiver or a list of receivers.

        +

        Remove a single receiver, a list of receivers, or a single extral receiver.

        Parameters
        -

        receivers (Account, Object, Script, Channel or list) – Receiver to remove.

        +

        receivers (Account, Object, Script, list or str) – Receiver +to remove. A string removes the external receiver.

        -
        -
        -property channels
        -

        Getter. Allows for value = self.channels. Returns a list of channels.

        -
        -
        property hide_from

        Getter. Allows for value = self.hide_from. -Returns 3 lists of accounts, objects and channels

        +Returns two lists of accounts and objects.

        @@ -433,6 +401,12 @@ object the first time, the query is executed.

        path = 'evennia.comms.models.Msg'
        +
        +
        +property receiver_external
        +

        A wrapper for getting database field db_receiver_external.

        +
        +
        property sender_external
        @@ -448,26 +422,24 @@ object the first time, the query is executed.

        -class evennia.comms.models.TempMsg(senders=None, receivers=None, channels=None, message='', header='', type='', lockstring='', hide_from=None)[source]
        +class evennia.comms.models.TempMsg(senders=None, receivers=None, message='', header='', type='', lockstring='', hide_from=None)[source]

        Bases: object

        -

        This is a non-persistent object for sending temporary messages -that will not be stored. It mimics the “real” Msg object, but -doesn’t require sender to be given.

        +

        This is a non-persistent object for sending temporary messages that will not be stored. It +mimics the “real” Msg object, but doesn’t require sender to be given.

        -__init__(senders=None, receivers=None, channels=None, message='', header='', type='', lockstring='', hide_from=None)[source]
        +__init__(senders=None, receivers=None, message='', header='', type='', lockstring='', hide_from=None)[source]

        Creates the temp message.

        Parameters
        • senders (any or list, optional) – Senders of the message.

        • -
        • receivers (Account, Object, Channel or list, optional) – Receivers of this message.

        • -
        • channels (Channel or list, optional) – Channels to send to.

        • +
        • receivers (Account, Object, Script or list, optional) – Receivers of this message.

        • message (str, optional) – Message to send.

        • header (str, optional) – Header of message.

        • type (str, optional) – Message class, if any.

        • lockstring (str, optional) – Lock for the message.

        • -
        • hide_from (Account, Object, Channel or list, optional) – Entities to hide this message from.

        • +
        • hide_from (Account, Object, or list, optional) – Entities to hide this message from.

        @@ -495,7 +467,7 @@ doesn’t require sender to be given.

        Remove a receiver or a list of receivers

        Parameters
        -

        receiver (Object, Account, Channel, str or list) – Receivers to remove.

        +

        receiver (Object, Account, Script, str or list) – Receivers to remove.

        @@ -571,11 +543,6 @@ class built by **create_forward_many_to_many_manager()** define objects = <evennia.comms.managers.ChannelDBManager object>
        -
        -
        -subscriptions[source]
        -
        -
        exception DoesNotExist
        @@ -588,22 +555,6 @@ class built by **create_forward_many_to_many_manager()** define

        Bases: django.core.exceptions.MultipleObjectsReturned

        -
        -
        -channel_set
        -

        Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

        -

        In the example:

        -
        class Pizza(Model):
        -    toppings = ManyToManyField(Topping, related_name='pizzas')
        -
        -
        -

        **Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

        -

        Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

        -
        -
        db_attributes
        @@ -646,22 +597,6 @@ class built by **create_forward_many_to_many_manager()** define get_previous_by_db_date_created(*, field=<django.db.models.fields.DateTimeField: db_date_created>, is_next=False, **kwargs)
        -
        -
        -hide_from_channels_set
        -

        Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

        -

        In the example:

        -
        class Pizza(Model):
        -    toppings = ManyToManyField(Topping, related_name='pizzas')
        -
        -
        -

        **Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

        -

        Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

        -
        -
        id
        @@ -679,6 +614,11 @@ object the first time, the query is executed.

        typename = 'SharedMemoryModelBase'
        +
        +
        +subscriptions[source]
        +
        +
        @@ -726,7 +666,6 @@ object the first time, the query is executed.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -743,6 +682,7 @@ object the first time, the query is executed.

        +
        develop branch
        @@ -37,8 +38,471 @@
        -
        -

        evennia.contrib.awsstorage.aws_s3_cdn

        +
        +

        evennia.contrib.awsstorage.aws_s3_cdn

        +

        AWS Storage System +The Right Honourable Reverend (trhr) 2020

        +

        ABOUT THIS PLUGIN:

        +

        This plugin migrates the Web-based portion of Evennia, namely images, +javascript, and other items located inside staticfiles into Amazon AWS (S3) for hosting.

        +

        Files hosted on S3 are “in the cloud,” and while your personal +server may be sufficient for serving multimedia to a minimal number of users, +the perfect use case for this plugin would be:

        +
          +
        1. Servers supporting heavy web-based traffic (webclient, etc)

        2. +
        3. With a sizable number of users

        4. +
        5. Where the users are globally distributed

        6. +
        7. Where multimedia files are served to users as a part of gameplay

        8. +
        +

        Bottom line - if you’re sending an image to a player every time they traverse a +map, the bandwidth reduction will be substantial. If not, probably skip +this one.

        +

        Note that storing and serving files via S3 is not technically free outside of +Amazon’s “free tier” offering, which you may or may not be eligible for; +evennia’s base install currently requires 1.5MB of storage space on S3, +making the current total cost to install this plugin ~$0.0005 per year. If +you have substantial media assets and intend to serve them to many users, +caveat emptor on a total cost of ownership - check AWS’s pricing structure.

        +

        See the ./README.md file for details and install instructions.

        +
        +
        +evennia.contrib.awsstorage.aws_s3_cdn.setting(name, default=None)[source]
        +

        Helper function to get a Django setting by name. If setting doesn’t exist +it will return a default.

        +
        +
        Parameters
        +

        name (str) – A Django setting name

        +
        +
        Returns
        +

        The value of the setting variable by that name

        +
        +
        +
        + +
        +
        +evennia.contrib.awsstorage.aws_s3_cdn.safe_join(base, *paths)[source]
        +

        Helper function, a version of django.utils._os.safe_join for S3 paths. +Joins one or more path components to the base path component +intelligently. Returns a normalized version of the final path. +The final path must be located inside of the base path component +(otherwise a ValueError is raised). Paths outside the base path +indicate a possible security sensitive operation.

        +
        +
        Parameters
        +
          +
        • base (str) – A path string to the base of the staticfiles

        • +
        • *paths (list) – A list of paths as referenced from the base path

        • +
        +
        +
        Returns
        +

        final_path (str) – A joined path, base + filepath

        +
        +
        +
        + +
        +
        +evennia.contrib.awsstorage.aws_s3_cdn.check_location(storage)[source]
        +

        Helper function to make sure that the storage location is configured correctly.

        +
        +
        Parameters
        +

        storage (Storage) – A Storage object (Django)

        +
        +
        Raises
        +

        ImproperlyConfigured – If the storage location is not configured correctly, +this is raised.

        +
        +
        +
        + +
        +
        +evennia.contrib.awsstorage.aws_s3_cdn.lookup_env(names)[source]
        +

        Helper function for looking up names in env vars. Returns the first element found.

        +
        +
        Parameters
        +

        names (str) – A list of environment variables

        +
        +
        Returns
        +

        value (str) – The value of the found environment variable.

        +
        +
        +
        + +
        +
        +evennia.contrib.awsstorage.aws_s3_cdn.get_available_overwrite_name(name, max_length)[source]
        +

        Helper function indicating files that will be overwritten during trunc.

        +
        +
        Parameters
        +
          +
        • name (str) – The name of the file

        • +
        • max_length (int) – The maximum length of a filename

        • +
        +
        +
        Returns
        +

        joined (path) – A joined path including directory, file, and extension

        +
        +
        +
        + +
        +
        +class evennia.contrib.awsstorage.aws_s3_cdn.S3Boto3StorageFile(*args, **kwargs)[source]
        +

        Bases: django.core.files.base.File

        +

        The default file object used by the S3Boto3Storage backend. +This file implements file streaming using boto’s multipart +uploading functionality. The file can be opened in read or +write mode. +This class extends Django’s File class. However, the contained +data is only the data contained in the current buffer. So you +should not access the contained file object directly. You should +access the data via this class. +Warning: This file must be closed using the close() method in +order to properly write the file to S3. Be sure to close the file +in your application.

        +
        +
        +__init__(name, mode, storage, buffer_size=None)[source]
        +

        Initializes the File object.

        +
        +
        Parameters
        +
          +
        • name (str) – The name of the file

        • +
        • mode (str) – The access mode (‘r’ or ‘w’)

        • +
        • storage (Storage) – The Django Storage object

        • +
        • buffer_size (int) – The buffer size, for multipart uploads

        • +
        +
        +
        +
        + +
        +
        +buffer_size = 5242880
        +
        + +
        +
        +property size
        +

        Helper property to return filesize

        +
        + +
        +
        +property file
        +

        Helper function to manage zipping and temporary files

        +
        + +
        +
        +read(*args, **kwargs)[source]
        +

        Checks if file is in read mode; then continues to boto3 operation

        +
        + +
        +
        +readline(*args, **kwargs)[source]
        +

        Checks if file is in read mode; then continues to boto3 operation

        +
        + +
        +
        +write(content)[source]
        +

        Checks if file is in write mode or needs multipart handling, +then continues to boto3 operation.

        +
        + +
        +
        +close()[source]
        +

        Manages file closing after multipart uploads

        +
        + +
        +
        +deconstruct()
        +

        Return a 3-tuple of class import path, positional arguments, +and keyword arguments.

        +
        + +
        + +
        +
        +class evennia.contrib.awsstorage.aws_s3_cdn.S3Boto3Storage(*args, **kwargs)[source]
        +

        Bases: django.core.files.storage.Storage

        +

        Amazon Simple Storage Service using Boto3 +This storage backend supports opening files in read or write +mode and supports streaming(buffering) data in chunks to S3 +when writing.

        +
        +
        +default_content_type = 'application/octet-stream'
        +
        + +
        +
        +access_key_names = ['AWS_S3_ACCESS_KEY_ID', 'AWS_ACCESS_KEY_ID']
        +
        + +
        +
        +secret_key_names = ['AWS_S3_SECRET_ACCESS_KEY', 'AWS_SECRET_ACCESS_KEY']
        +
        + +
        +
        +security_token_names = ['AWS_SESSION_TOKEN', 'AWS_SECURITY_TOKEN']
        +
        + +
        +
        +file_overwrite = True
        +
        + +
        +
        +object_parameters = {}
        +
        + +
        +
        +bucket_name = None
        +
        + +
        +
        +auto_create_bucket = False
        +
        + +
        +
        +default_acl = 'public-read'
        +
        + +
        +
        +bucket_acl = 'public-read'
        +
        + +
        +
        +querystring_auth = True
        +
        + +
        +
        +querystring_expire = 3600
        +
        + +
        +
        +signature_version = None
        +
        + +
        +
        +reduced_redundancy = False
        +
        + +
        +
        +location = ''
        +
        + +
        +
        +encryption = False
        +
        + +
        +
        +custom_domain = None
        +
        + +
        +
        +addressing_style = None
        +
        + +
        +
        +secure_urls = True
        +
        + +
        +
        +file_name_charset = 'utf-8'
        +
        + +
        +
        +gzip = False
        +
        + +
        +
        +preload_metadata = False
        +
        + +
        +
        +gzip_content_types = ('text/css', 'text/javascript', 'application/javascript', 'application/x-javascript', 'image/svg+xml')
        +
        + +
        +
        +endpoint_url = None
        +
        + +
        +
        +proxies = None
        +
        + +
        +
        +region_name = None
        +
        + +
        +
        +use_ssl = True
        +
        + +
        +
        +verify = None
        +
        + +
        +
        +max_memory_size = 0
        +
        + +
        +
        +__init__(acl=None, bucket=None, **settings)[source]
        +

        Check if some of the settings we’ve provided as class attributes +need to be overwritten with values passed in here.

        +
        + +
        +
        +url_protocol = 'http:'
        +
        + +
        +
        +access_key = ''
        +
        + +
        +
        +secret_key = ''
        +
        + +
        +
        +security_token = None
        +
        + +
        +
        +config = None
        +
        + +
        +
        +property connection
        +

        Creates the actual connection to S3

        +
        + +
        +
        +property bucket
        +

        Get the current bucket. If there is no current bucket object +create it.

        +
        + +
        +
        +property entries
        +

        Get the locally cached files for the bucket.

        +
        + +
        +
        +delete(name)[source]
        +

        Deletes a file from S3.

        +
        + +
        +
        +exists(name)[source]
        +

        Checks if file exists.

        +
        + +
        +
        +listdir(name)[source]
        +

        Translational function to go from S3 file paths to the format +Django’s listdir expects.

        +
        + +
        +
        +size(name)[source]
        +

        Gets the filesize of a remote file.

        +
        + +
        +
        +deconstruct()
        +

        Return a 3-tuple of class import path, positional arguments, +and keyword arguments.

        +
        + +
        +
        +get_object_parameters(name)[source]
        +

        Returns a dictionary that is passed to file upload. Override this +method to adjust this on a per-object basis to set e.g ContentDisposition. +By default, returns the value of AWS_S3_OBJECT_PARAMETERS. +Setting ContentEncoding will prevent objects from being automatically gzipped.

        +
        + +
        +
        +get_modified_time(name)[source]
        +

        Returns an (aware) datetime object containing the last modified time if +USE_TZ is True, otherwise returns a naive datetime in the local timezone.

        +
        + +
        +
        +modified_time(name)[source]
        +

        Returns a naive datetime object containing the last modified time. +If USE_TZ=False then get_modified_time will return a naive datetime +so we just return that, else we have to localize and strip the tz

        +
        + +
        +
        +url(name, parameters=None, expire=None)[source]
        +

        Returns the URL of a remotely-hosted file

        +
        + +
        +
        +get_available_name(name, max_length=None)[source]
        +

        Overwrite existing file with the same name.

        +
        + +
        +
        @@ -84,7 +548,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +564,7 @@ +
        develop branch
        @@ -39,6 +40,7 @@

        evennia.contrib.awsstorage

        +

        Intended to be a collecting folder for Django-specific contribs that do not have observable effects to players.

        @@ -107,6 +108,7 @@ +
        develop branch
        @@ -37,8 +38,225 @@
        -
        -

        evennia.contrib.awsstorage.tests

        +
        +

        evennia.contrib.awsstorage.tests

        +
        +
        +class evennia.contrib.awsstorage.tests.S3Boto3TestCase(methodName='runTest')[source]
        +

        Bases: django.test.testcases.TestCase

        +
        +
        +setUp()[source]
        +

        Hook method for setting up the test fixture before exercising it.

        +
        + +
        + +
        +
        +class evennia.contrib.awsstorage.tests.S3Boto3StorageTests(methodName='runTest')[source]
        +

        Bases: evennia.contrib.awsstorage.tests.S3Boto3TestCase

        +
        +
        +test_clean_name()[source]
        +

        Test the base case of _clean_name

        +
        + +
        +
        +test_clean_name_normalize()[source]
        +

        Test the normalization of _clean_name

        +
        + +
        +
        +test_clean_name_trailing_slash()[source]
        +

        Test the _clean_name when the path has a trailing slash

        +
        + +
        +
        +test_clean_name_windows()[source]
        +

        Test the _clean_name when the path has a trailing slash

        +
        + +
        +
        +test_pickle_with_bucket()[source]
        +

        Test that the storage can be pickled with a bucket attached

        +
        + +
        +
        +test_pickle_without_bucket()[source]
        +

        Test that the storage can be pickled, without a bucket instance

        +
        + +
        +
        +test_storage_url_slashes()[source]
        +

        Test URL generation.

        +
        + +
        +
        +test_storage_save()[source]
        +

        Test saving a file

        +
        + +
        +
        +test_storage_save_with_acl()[source]
        +

        Test saving a file with user defined ACL.

        +
        + +
        +
        +test_content_type()[source]
        +

        Test saving a file with a None content type.

        +
        + +
        +
        +test_storage_save_gzipped()[source]
        +

        Test saving a gzipped file

        +
        + +
        +
        +test_storage_save_gzip()[source]
        +

        Test saving a file with gzip enabled.

        +
        + +
        +
        +test_storage_save_gzip_twice()[source]
        +

        Test saving the same file content twice with gzip enabled.

        +
        + +
        +
        +test_compress_content_len()[source]
        +

        Test that file returned by _compress_content() is readable.

        +
        + +
        +
        +test_storage_open_write()[source]
        +

        Test opening a file in write mode

        +
        + +
        +
        +test_storage_open_no_write()[source]
        +

        Test opening file in write mode and closing without writing.

        +

        A file should be created as by obj.put(…).

        +
        + +
        +
        +test_storage_open_no_overwrite_existing()[source]
        +

        Test opening an existing file in write mode and closing without writing.

        +
        + +
        +
        +test_storage_write_beyond_buffer_size()[source]
        +

        Test writing content that exceeds the buffer size

        +
        + +
        +
        +test_auto_creating_bucket()[source]
        +
        + +
        +
        +test_auto_creating_bucket_with_acl()[source]
        +
        + +
        +
        +test_storage_exists()[source]
        +
        + +
        +
        +test_storage_exists_false()[source]
        +
        + +
        +
        +test_storage_exists_doesnt_create_bucket()[source]
        +
        + +
        +
        +test_storage_delete()[source]
        +
        + +
        +
        +test_storage_listdir_base()[source]
        +
        + +
        +
        +test_storage_listdir_subdir()[source]
        +
        + +
        +
        +test_storage_size()[source]
        +
        + +
        +
        +test_storage_mtime()[source]
        +
        + +
        +
        +test_storage_url()[source]
        +
        + +
        +
        +test_generated_url_is_encoded()[source]
        +
        + +
        +
        +test_special_characters()[source]
        +
        + +
        +
        +test_strip_signing_parameters()[source]
        +
        + +
        +
        +test_connection_threading()[source]
        +
        + +
        +
        +test_location_leading_slash()[source]
        +
        + +
        +
        +test_override_class_variable()[source]
        +
        + +
        +
        +test_override_init_argument()[source]
        +
        + +
        +
        @@ -84,7 +302,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +318,7 @@ +
        develop branch
        @@ -403,6 +404,11 @@ available to the command

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'command', 'tags': '', 'text': '\n Base command for Trade commands to inherit from. Implements the\n custom parsing.\n '}
        +
        +
        @@ -446,6 +452,11 @@ available to the command

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'trade', 'key': 'trade help', 'tags': '', 'text': '\n help command for the trade system.\n\n Usage:\n trade help\n\n Displays help for the trade commands.\n '}
        +
        +
        @@ -490,6 +501,11 @@ standing offer.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'trading', 'key': 'offer', 'tags': '', 'text': '\n offer one or more items in trade.\n\n Usage:\n offer <object> [, object2, ...][:emote]\n\n Offer objects in trade. This will replace the currently\n standing offer.\n '}
        +
        +
        @@ -537,6 +553,11 @@ the current offer using the ‘offers’ command.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'agree', 'category': 'trading', 'key': 'accept', 'tags': '', 'text': "\n accept the standing offer\n\n Usage:\n accept [:emote]\n agreee [:emote]\n\n This will accept the current offer. The other party must also accept\n for the deal to go through. You can use the 'decline' command to change\n your mind as long as the other party has not yet accepted. You can inspect\n the current offer using the 'offers' command.\n "}
        +
        +
        @@ -583,6 +604,11 @@ decline the old offer.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'trading', 'key': 'decline', 'tags': '', 'text': "\n decline the standing offer\n\n Usage:\n decline [:emote]\n\n This will decline a previously 'accept'ed offer (so this allows you to\n change your mind). You can only use this as long as the other party\n has not yet accepted the deal. Also, changing the offer will automatically\n decline the old offer.\n "}
        +
        +
        @@ -627,6 +653,11 @@ determine if it’s worth your while.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'eval', 'category': 'trading', 'key': 'evaluate', 'tags': '', 'text': "\n evaluate objects on offer\n\n Usage:\n evaluate <offered object>\n\n This allows you to examine any object currently on offer, to\n determine if it's worth your while.\n "}
        +
        +
        @@ -651,7 +682,7 @@ try to influence the other part in the deal.

        -aliases = ['deal', 'offers']
        +aliases = ['offers', 'deal']
        @@ -675,6 +706,11 @@ try to influence the other part in the deal.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'offers deal', 'category': 'trading', 'key': 'status', 'tags': '', 'text': "\n show a list of the current deal\n\n Usage:\n status\n deal\n offers\n\n Shows the currently suggested offers on each sides of the deal. To\n accept the current deal, use the 'accept' command. Use 'offer' to\n change your deal. You might also want to use 'say', 'emote' etc to\n try to influence the other part in the deal.\n "}
        +
        +
        @@ -719,6 +755,11 @@ finish trade [:say]

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'finish trade', 'category': 'trading', 'key': 'end trade', 'tags': '', 'text': '\n end the trade prematurely\n\n Usage:\n end trade [:say]\n finish trade [:say]\n\n This ends the trade prematurely. No trade will take place.\n\n '}
        +
        +
        @@ -793,6 +834,11 @@ info to your choice.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'barter', 'category': 'general', 'key': 'trade', 'tags': '', 'text': '\n Initiate trade with another party\n\n Usage:\n trade <other party> [:say]\n trade <other party> accept [:say]\n trade <other party> decline [:say]\n\n Initiate trade with another party. The other party needs to repeat\n this command with trade accept/decline within a minute in order to\n properly initiate the trade action. You can use the decline option\n yourself if you want to retract an already suggested trade. The\n optional say part works like the say command and allows you to add\n info to your choice.\n '}
        +
        + @@ -840,7 +886,6 @@ info to your choice.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -857,6 +902,7 @@ info to your choice.

        +
        develop branch
        @@ -251,6 +252,11 @@ overloading evential same-named class properties.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': '__noinput_command', 'tags': '', 'text': 'No input has been found.'}
        +
        +
        @@ -297,6 +303,11 @@ overloading evential same-named class properties.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': '__nomatch_command', 'tags': '', 'text': 'No input has been found.'}
        +
        +
        @@ -861,6 +872,11 @@ set in self.parse())

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': '@edit', 'tags': '', 'text': "\n Generic building command.\n\n Syntax:\n @edit [object]\n\n Open a building menu to edit the specified object. This menu allows to\n change the object's key and description.\n\n Examples:\n @edit here\n @edit self\n @edit #142\n\n "}
        +
        + @@ -908,7 +924,6 @@ set in self.parse())

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -925,6 +940,7 @@ set in self.parse())

        +
        develop branch
        @@ -77,7 +78,7 @@ at them with this command.

        -aliases = ['ls', 'l']
        +aliases = ['l', 'ls']
        @@ -107,6 +108,11 @@ that is checked by the @ic command directly.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'l ls', 'category': 'general', 'key': 'look', 'tags': '', 'text': '\n ooc look\n\n Usage:\n look\n look <character>\n\n This is an OOC version of the look command. Since an Account doesn\'t\n have an in-game existence, there is no concept of location or\n "self".\n\n If any characters are available for you to control, you may look\n at them with this command.\n '}
        +
        +
        @@ -152,6 +158,11 @@ attribute on ourselves to remember it.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'create', 'tags': '', 'text': '\n creates a character\n\n Usage:\n create <character name>\n\n This will create a new character, assuming\n the given character name does not already exist.\n '}
        +
        +
        @@ -217,7 +228,6 @@ attribute on ourselves to remember it.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -234,6 +244,7 @@ attribute on ourselves to remember it.

        +
        develop branch
        @@ -359,6 +360,11 @@ provide will be displayed after the clothing’s name.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'clothing', 'key': 'wear', 'tags': '', 'text': "\n Puts on an item of clothing you are holding.\n\n Usage:\n wear <obj> [wear style]\n\n Examples:\n wear shirt\n wear scarf wrapped loosely about the shoulders\n\n All the clothes you are wearing are appended to your description.\n If you provide a 'wear style' after the command, the message you\n provide will be displayed after the clothing's name.\n "}
        +
        +
        @@ -399,6 +405,11 @@ off the covering item first.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'clothing', 'key': 'remove', 'tags': '', 'text': "\n Takes off an item of clothing.\n\n Usage:\n remove <obj>\n\n Removes an item of clothing you are wearing. You can't remove\n clothes that are covered up by something else - you must take\n off the covering item first.\n "}
        +
        +
        @@ -439,6 +450,11 @@ You can’t remove an item of clothing if it’s covered.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'clothing', 'key': 'cover', 'tags': '', 'text': "\n Covers a worn item of clothing with another you're holding or wearing.\n\n Usage:\n cover <obj> [with] <obj>\n\n When you cover a clothing item, it is hidden and no longer appears in\n your description until it's uncovered or the item covering it is removed.\n You can't remove an item of clothing if it's covered.\n "}
        +
        +
        @@ -480,6 +496,11 @@ it is also covered by something else.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'clothing', 'key': 'uncover', 'tags': '', 'text': "\n Reveals a worn item of clothing that's currently covered up.\n\n Usage:\n uncover <obj>\n\n When you uncover an item of clothing, you allow it to appear in your\n description without having to take off the garment that's currently\n covering it. You can't uncover an item of clothing if the item covering\n it is also covered by something else.\n "}
        +
        +
        @@ -529,6 +550,11 @@ location you are currently in.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'drop', 'tags': '', 'text': '\n drop something\n\n Usage:\n drop <obj>\n\n Lets you drop an object from your inventory into the\n location you are currently in.\n '}
        +
        +
        @@ -578,6 +604,11 @@ placing it in their inventory.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'give', 'tags': '', 'text': '\n give away something to someone\n\n Usage:\n give <inventory obj> = <target>\n\n Gives an items from your inventory to another character,\n placing it in their inventory.\n '}
        +
        +
        @@ -627,6 +658,11 @@ inv

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'inv i', 'category': 'general', 'key': 'inventory', 'tags': '', 'text': '\n view inventory\n\n Usage:\n inventory\n inv\n\n Shows your inventory.\n '}
        +
        +
        @@ -700,7 +736,6 @@ items.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -717,6 +752,7 @@ items.

        +
        develop branch
        @@ -126,7 +127,6 @@ COLOR_ANSI_BRIGHT_BGS_EXTRA_MAP = color_markups.CURLY_COLOR_ANSI_BRIGHT_BGS_EXTR
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -143,6 +143,7 @@ COLOR_ANSI_BRIGHT_BGS_EXTRA_MAP = color_markups.CURLY_COLOR_ANSI_BRIGHT_BGS_EXTR +
        develop branch
        @@ -46,8 +47,776 @@
        -
        -

        evennia.contrib.crafting.crafting

        +
        +

        evennia.contrib.crafting.crafting

        +

        Crafting - Griatch 2020

        +

        This is a general crafting engine. The basic functionality of crafting is to +combine any number of of items or tools in a ‘recipe’ to produce a new result.

        +
        +

        item + item + item + tool + tool -> recipe -> new result

        +
        +

        This is useful not only for traditional crafting but the engine is flexible +enough to also be useful for puzzles or similar.

        +
        +

        Installation

        +
          +
        • Add the CmdCraft Command from this module to your default cmdset. This +allows for crafting from in-game using a simple syntax.

        • +
        • Create a new module and add it to a new list in your settings file +(server/conf/settings.py) named CRAFT_RECIPES_MODULES, such as +CRAFT_RECIPE_MODULES = [“world.recipes_weapons”].

        • +
        • In the new module(s), create one or more classes, each a child of +CraftingRecipe from this module. Each such class must have a unique .name +property. It also defines what inputs are required and what is created using +this recipe.

        • +
        • Objects to use for crafting should (by default) be tagged with tags using the +tag-category crafting_material or crafting_tool. The name of the object +doesn’t matter, only its tag.

        • +
        +
        +
        +

        Crafting in game

        +

        The default craft command handles all crafting needs.

        +
        > craft spiked club from club, nails
        +
        +
        +

        Here, spiked club specifies the recipe while club and nails are objects +the crafter must have in their inventory. These will be consumed during +crafting (by default only if crafting was successful).

        +

        A recipe can also require tools (like the hammer above). These must be +either in inventory or be in the current location. Tools are not consumed +during the crafting process.

        +
        > craft wooden doll from wood with knife
        +
        +
        +
        +
        +

        Crafting in code

        +

        In code, you should use the helper function craft from this module. This +specifies the name of the recipe to use and expects all suitable +ingredients/tools as arguments (consumables and tools should be added together, +tools will be identified before consumables).

        +
        from evennia.contrib.crafting import crafting
        +
        +spiked_club = crafting.craft(crafter, "spiked club", club, nails)
        +
        +
        +

        The result is always a list with zero or more objects. A fail leads to an empty +list. The crafter should already have been notified of any error in this case +(this should be handle by the recipe itself).

        +
        +
        +

        Recipes

        +

        A recipe is a class that works like an input/output blackbox: you initialize +it with consumables (and/or tools) if they match the recipe, a new +result is spit out. Consumables are consumed in the process while tools are not.

        +

        This module contains a base class for making new ingredient types +(CraftingRecipeBase) and an implementation of the most common form of +crafting (CraftingRecipe) using objects and prototypes.

        +

        Recipes are put in one or more modules added as a list to the +CRAFT_RECIPE_MODULES setting, for example:

        +
        CRAFT_RECIPE_MODULES = ['world.recipes_weapons', 'world.recipes_potions']
        +
        +
        +

        Below is an example of a crafting recipe and how craft calls it under the +hood. See the CraftingRecipe class for details of which properties and +methods are available to override - the craft behavior can be modified +substantially this way.

        +
        from evennia.contrib.crafting.crafting import CraftingRecipe
        +
        +class PigIronRecipe(CraftingRecipe):
        +    # Pig iron is a high-carbon result of melting iron in a blast furnace.
        +
        +    name = "pig iron"  # this is what crafting.craft and CmdCraft uses
        +    tool_tags = ["blast furnace"]
        +    consumable_tags = ["iron ore", "coal", "coal"]
        +    output_prototypes = [
        +        {"key": "Pig Iron ingot",
        +         "desc": "An ingot of crude pig iron.",
        +         "tags": [("pig iron", "crafting_material")]}
        +    ]
        +
        +# for testing, conveniently spawn all we need based on the tags on the class
        +tools, consumables = PigIronRecipe.seed()
        +
        +recipe = PigIronRecipe(caller, *(tools + consumables))
        +result = recipe.craft()
        +
        +
        +

        If the above class was added to a module in CRAFT_RECIPE_MODULES, it could be +called using its .name property, as “pig iron”.

        +

        The [example_recipies](api:evennia.contrib.crafting.example_recipes) module has +a full example of the components for creating a sword from base components.

        +
        +
        +
        +exception evennia.contrib.crafting.crafting.CraftingError[source]
        +

        Bases: RuntimeError

        +

        Crafting error.

        +
        + +
        +
        +exception evennia.contrib.crafting.crafting.CraftingValidationError[source]
        +

        Bases: evennia.contrib.crafting.crafting.CraftingError

        +

        Error if crafting validation failed.

        +
        + +
        +
        +class evennia.contrib.crafting.crafting.CraftingRecipeBase(crafter, *inputs, **kwargs)[source]
        +

        Bases: object

        +

        The recipe handles all aspects of performing a ‘craft’ operation. This is +the base of the crafting system, intended to be replace if you want to +adapt it for very different functionality - see the CraftingRecipe child +class for an implementation of the most common type of crafting using +objects.

        +

        Example of usage:

        +
        recipe = CraftRecipe(crafter, obj1, obj2, obj3)
        +result = recipe.craft()
        +
        +
        +

        Note that the most common crafting operation is that the inputs are +consumed - so in that case the recipe cannot be used a second time (doing so +will raise a CraftingError)

        +

        Process:

        +
          +
        1. .craft(**kwargs) - this starts the process on the initialized recipe. The kwargs +are optional but will be passed into all of the following hooks.

        2. +
        3. .pre_craft(**kwargs) - this normally validates inputs and stores them in +.validated_inputs.. Raises CraftingValidationError otherwise.

        4. +
        +
          +
        1. .do_craft(**kwargs) - should return the crafted item(s) or the empty list. Any +crafting errors should be immediately reported to user.

        2. +
        3. .post_craft(crafted_result, **kwargs)- always called, even if pre_craft +raised a CraftingError or CraftingValidationError. +Should return crafted_result (modified or not).

        4. +
        +
        +
        +name = 'recipe base'
        +
        + +
        +
        +allow_reuse = False
        +
        + +
        +
        +__init__(crafter, *inputs, **kwargs)[source]
        +

        Initialize the recipe.

        +
        +
        Parameters
        +
          +
        • crafter (Object) – The one doing the crafting.

        • +
        • *inputs (any) – The ingredients of the recipe to use.

        • +
        • **kwargs (any) – Any other parameters that are relevant for +this recipe.

        • +
        +
        +
        +
        + +
        +
        +msg(message, **kwargs)[source]
        +

        Send message to crafter. This is a central point to override if wanting +to change crafting return style in some way.

        +
        +
        Parameters
        +
          +
        • message (str) – The message to send.

        • +
        • **kwargs – Any optional properties relevant to this send.

        • +
        +
        +
        +
        + +
        +
        +pre_craft(**kwargs)[source]
        +

        Hook to override.

        +

        This is called just before crafting operation and is normally +responsible for validating the inputs, storing data on +self.validated_inputs.

        +
        +
        Parameters
        +
          +
        • **kwargs – Optional extra flags passed during initialization or

        • +
        • **.craft

        • +
        +
        +
        Raises
        +

        CraftingValidationError – If validation fails.

        +
        +
        +
        + +
        +
        +do_craft(**kwargs)[source]
        +

        Hook to override.

        +

        This performs the actual crafting. At this point the inputs are +expected to have been verified already. If needed, the validated +inputs are available on this recipe instance.

        +
        +
        Parameters
        +

        **kwargs – Any extra flags passed at initialization.

        +
        +
        Returns
        +

        any – The result of crafting.

        +
        +
        +
        + +
        +
        +post_craft(crafting_result, **kwargs)[source]
        +

        Hook to override.

        +

        This is called just after crafting has finished. A common use of this +method is to delete the inputs.

        +
        +
        Parameters
        +
          +
        • crafting_result (any) – The outcome of crafting, as returned by do_craft.

        • +
        • **kwargs – Any extra flags passed at initialization.

        • +
        +
        +
        Returns
        +

        any – The final crafting result.

        +
        +
        +
        + +
        +
        +craft(raise_exception=False, **kwargs)[source]
        +

        Main crafting call method. Call this to produce a result and make +sure all hooks run correctly.

        +
        +
        Parameters
        +
          +
        • raise_exception (bool) – If crafting would return None, raise +exception instead.

        • +
        • **kwargs (any) – Any other parameters that is relevant +for this particular craft operation. This will temporarily +override same-named kwargs given at the creation of this recipe +and be passed into all of the crafting hooks.

        • +
        +
        +
        Returns
        +

        any – The result of the craft, or None if crafting failed.

        +
        +
        Raises
        +
          +
        • CraftingValidationError – If recipe validation failed and +raise_exception is True.

        • +
        • CraftingError – On If trying to rerun a no-rerun recipe, or if crafting +would return None and raise_exception** is set.

        • +
        +
        +
        +
        + +
        + +
        +
        +class evennia.contrib.crafting.crafting.CraftingRecipe(crafter, *inputs, **kwargs)[source]
        +

        Bases: evennia.contrib.crafting.crafting.CraftingRecipeBase

        +

        The CraftRecipe implements the most common form of crafting: Combining (and +consuming) inputs to produce a new result. This type of recipe only works +with typeclassed entities as inputs and outputs, since it’s based on Tags +and Prototypes.

        +

        There are two types of crafting ingredients: ‘tools’ and ‘consumables’. The +difference between them is that the former is not consumed in the crafting +process. So if you need a hammer and anvil to craft a sword, they are +‘tools’ whereas the materials of the sword are ‘consumables’.

        +

        Examples:

        +
        class FlourRecipe(CraftRecipe):
        +    name = "flour"
        +    tool_tags = ['windmill']
        +    consumable_tags = ["wheat"]
        +    output_prototypes = [
        +        {"key": "Bag of flour",
        +         "typeclass": "typeclasses.food.Flour",
        +         "desc": "A small bag of flour."
        +         "tags": [("flour", "crafting_material"),
        +        }
        +
        +class BreadRecipe(CraftRecipe):
        +    name = "bread"
        +    tool_tags = ["roller", "owen"]
        +    consumable_tags = ["flour", "egg", "egg", "salt", "water", "yeast"]
        +    output_prototypes = [
        +        {"key": "bread",
        +         "desc": "A tasty bread."
        +        }
        +
        +
        +
          +
        • name (str): The name of this recipe. This should be globally unique.

        • +
        +
          +
        • tool_tag_category (str): What tag-category tools must use. Default is +‘crafting_tool’.

        • +
        • tool_tags (list): Object-tags to use for tooling. If more than one instace +of a tool is needed, add multiple entries here.

        • +
        • tool_names (list): Human-readable names for tools. These are used for informative +messages/errors. If not given, the tags will be used. If given, this list should +match the length of tool_tags.:

        • +
        • exact_tools (bool, default True): Must have exactly the right tools, any extra +leads to failure.

        • +
        • exact_tool_order (bool, default False): Tools must be added in exactly the +right order for crafting to pass.

        • +
        +
          +
        • consumable_tag_category (str): What tag-category consumables must use. +Default is ‘crafting_material’.

        • +
        • consumable_tags (list): Tags for objects that will be consumed as part of +running the recipe.

        • +
        • consumable_names (list): Human-readable names for consumables. Same as for tools.

        • +
        • exact_consumables (bool, default True): Normally, adding more consumables +than needed leads to a a crafting error. If this is False, the craft will +still succeed (only the needed ingredients will be consumed).

        • +
        • exact_consumable_order (bool, default False): Normally, the order in which +ingredients are added does not matter. With this set, trying to add consumables in +another order than given will lead to failing crafting.

        • +
        • consume_on_fail (bool, default False): Normally, consumables remain if +crafting fails. With this flag, a failed crafting will still consume +consumables. Note that this will also consume any ‘extra’ consumables +added not part of the recipe!

        • +
        +
          +
        • output_prototypes (list): One or more prototypes (prototype_keys or +full dicts) describing how to create the result(s) of this recipe.

        • +
        • output_names (list): Human-readable names for (prospective) prototypes. +This is used in error messages. If not given, this is extracted from the +prototypes’ key if possible.

        • +
        +

        custom messages all have custom formatting markers. Many are empty strings +when not applicable.

        +
        {missing}: Comma-separated list of tool/consumable missing for missing/out of order errors.
        +{excess}: Comma-separated list of tool/consumable added in excess of recipe
        +{inputs}: Comma-separated list of any inputs (tools + consumables) involved in error.
        +{tools}: Comma-sepatated list of tools involved in error.
        +{consumables}: Comma-separated list of consumables involved in error.
        +{outputs}: Comma-separated list of (expected) outputs
        +{t0}..{tN-1}: Individual tools, same order as **.tool_names**.
        +{c0}..{cN-1}: Individual consumables, same order as **.consumable_names**.
        +{o0}..{oN-1}: Individual outputs, same order as **.output_names**.
        +
        +
        +
          +
        • error_tool_missing_message: “Could not craft {outputs} without {missing}.”

        • +
        • error_tool_order_message: +“Could not craft {outputs} since {missing} was added in the wrong order.”

        • +
        • error_tool_excess_message: “Could not craft {outputs} (extra {excess}).”

        • +
        • error_consumable_missing_message: “Could not craft {outputs} without {missing}.”

        • +
        • error_consumable_order_message: +“Could not craft {outputs} since {missing} was added in the wrong order.”

        • +
        • error_consumable_excess_message: “Could not craft {outputs} (excess {excess}).”

        • +
        • success_message: “You successfuly craft {outputs}!”

        • +
        • failure_message: “” (this is handled by the other error messages by default)

        • +
        +
          +
        1. Crafting starts by calling .craft(**kwargs) on the parent class. The +**kwargs are optional, extends any **kwargs passed to the class +constructor and will be passed into all the following hooks.

        2. +
        +
          +
        1. .pre_craft(**kwargs) should handle validation of inputs. Results should +be stored in validated_consumables/tools respectively. Raises CraftingValidationError +otherwise.

        2. +
        3. .do_craft(**kwargs) will not be called if validation failed. Should return +a list of the things crafted.

        4. +
        5. .post_craft(crafting_result, **kwargs) is always called, also if validation +failed (crafting_result will then be falsy). It does any cleanup. By default +this deletes consumables.

        6. +
        +

        Use .msg to conveniently send messages to the crafter. Raise +evennia.contrib.crafting.crafting.CraftingError exception to abort +crafting at any time in the sequence. If raising with a text, this will be +shown to the crafter automatically

        +
        +
        +name = 'crafting recipe'
        +
        + +
        +
        +consumable_tag_category = 'crafting_material'
        +
        + +
        +
        +tool_tag_category = 'crafting_tool'
        +
        + +
        +
        +tool_tags = []
        +
        + +
        +
        +exact_tools = True
        +
        + +
        +
        +exact_tool_order = False
        +
        + +
        +
        +error_tool_missing_message = 'Could not craft {outputs} without {missing}.'
        +
        + +
        +
        +error_tool_order_message = 'Could not craft {outputs} since {missing} was added in the wrong order.'
        +
        + +
        +
        +error_tool_excess_message = 'Could not craft {outputs} without the exact tools (extra {excess}).'
        +
        + +
        +
        +consumable_tags = []
        +
        + +
        +
        +consume_on_fail = False
        +
        + +
        +
        +exact_consumables = True
        +
        + +
        +
        +exact_consumable_order = False
        +
        + +
        +
        +error_consumable_missing_message = 'Could not craft {outputs} without {missing}.'
        +
        + +
        +
        +error_consumable_order_message = 'Could not craft {outputs} since {missing} was added in the wrong order.'
        +
        + +
        +
        +error_consumable_excess_message = 'Could not craft {outputs} without the exact ingredients (extra {excess}).'
        +
        + +
        +
        +output_prototypes = []
        +
        + +
        +
        +failure_message = ''
        +
        + +
        +
        +success_message = 'You successfully craft {outputs}!'
        +
        + +
        +
        +__init__(crafter, *inputs, **kwargs)[source]
        +
        +
        Parameters
        +
          +
        • crafter (Object) – The one doing the crafting.

        • +
        • *inputs (Object) – The ingredients (+tools) of the recipe to use. The +The recipe will itself figure out (from tags) which is a tool and +which is a consumable.

        • +
        • **kwargs (any) – Any other parameters that are relevant for +this recipe. These will be passed into the crafting hooks.

        • +
        +
        +
        +

        Notes

        +

        Internally, this class stores validated data in +.validated_consumables and .validated_tools respectively. The +.validated_inputs property (from parent) holds a list of everything +types in the order inserted to the class constructor.

        +
        + +
        +
        +consumable_names = []
        +
        + +
        +
        +tool_names = []
        +
        + +
        +
        +output_names = []
        +
        + +
        +
        +classmethod seed(tool_kwargs=None, consumable_kwargs=None)[source]
        +

        This is a helper class-method for easy testing and application of this +recipe. When called, it will create simple dummy ingredients with names +and tags needed by this recipe.

        +
        +
        Parameters
        +
          +
        • consumable_kwargs (dict, optional) – This will be passed as +**consumable_kwargs into the create_object call for each consumable. +If not given, matching consumable_name or consumable_tag +will be used for key.

        • +
        • tool_kwargs (dict, optional) – Will be passed as **tool_kwargs into the create_object +call for each tool. If not given, the matching +tool_name or tool_tag will be used for key.

        • +
        +
        +
        Returns
        +

        tuple – A tuple (tools, consumables) with newly created dummy +objects matching the recipe ingredient list.

        +
        +
        +

        Example:

        +
        tools, consumables = SwordRecipe.seed()
        +recipe = SwordRecipe(caller, *(tools + consumables))
        +result = recipe.craft()
        +
        +
        +

        Notes

        +

        If key is given in consumable/tool_kwargs then _every_ created item +of each type will have the same key.

        +
        + +
        +
        +pre_craft(**kwargs)[source]
        +

        Do pre-craft checks, including input validation.

        +

        Check so the given inputs are what is needed. This operates on +self.inputs which is set to the inputs added to the class +constructor. Validated data is stored as lists on .validated_tools +and .validated_consumables respectively.

        +
        +
        Parameters
        +

        **kwargs – Any optional extra kwargs passed during initialization of +the recipe class.

        +
        +
        Raises
        +

        CraftingValidationError – If validation fails. At this point the crafter +is expected to have been informed of the problem already.

        +
        +
        +
        + +
        +
        +do_craft(**kwargs)[source]
        +

        Hook to override. This will not be called if validation in pre_craft +fails.

        +

        This performs the actual crafting. At this point the inputs are +expected to have been verified already.

        +
        +
        Returns
        +

        list

        +
        +
        A list of spawned objects created from the inputs, or None

        on a failure.

        +
        +
        +

        +
        +
        +

        Notes

        +

        This method should use self.msg to inform the user about the +specific reason of failure immediately. +We may want to analyze the tools in some way here to affect the +crafting process.

        +
        + +
        +
        +post_craft(craft_result, **kwargs)[source]
        +

        Hook to override. +This is called just after crafting has finished. A common use of +this method is to delete the inputs.

        +
        +
        Parameters
        +
          +
        • craft_result (list) – The crafted result, provided by self.do_craft.

        • +
        • **kwargs (any) – Passed from self.craft.

        • +
        +
        +
        Returns
        +

        list – The return(s) of the craft, possibly modified in this method.

        +
        +
        +

        Notes

        +

        This is _always_ called, also if validation in pre_craft fails +(craft_result will then be None).

        +
        + +
        + +
        +
        +evennia.contrib.crafting.crafting.craft(crafter, recipe_name, *inputs, raise_exception=False, **kwargs)[source]
        +

        Access function. Craft a given recipe from a source recipe module. A +recipe module is a Python module containing recipe classes. Note that this +requires settings.CRAFT_RECIPE_MODULES to be added to a list of one or +more python-paths to modules holding Recipe-classes.

        +
        +
        Parameters
        +
          +
        • crafter (Object) – The one doing the crafting.

        • +
        • recipe_name (str) – The CraftRecipe.name to use. This uses fuzzy-matching +if the result is unique.

        • +
        • *inputs – Suitable ingredients and/or tools (Objects) to use in the crafting.

        • +
        • raise_exception (bool, optional) – If crafting failed for whatever +reason, raise CraftingError. The user will still be informed by the +recipe.

        • +
        • **kwargs – Optional kwargs to pass into the recipe (will passed into +recipe.craft).

        • +
        +
        +
        Returns
        +

        list – Crafted objects, if any.

        +
        +
        Raises
        +
          +
        • CraftingError – If raise_exception is True and crafting failed to

        • +
        • produce an output. KeyError – If recipe_name failed to find a

        • +
        • matching recipe class (or the hit was not precise enough.)

        • +
        +
        +
        +

        Notes

        +

        If no recipe_module is given, will look for a list settings.CRAFT_RECIPE_MODULES and +lastly fall back to the example module “evennia.contrib.”

        +
        + +
        +
        +class evennia.contrib.crafting.crafting.CraftingCmdSet(cmdsetobj=None, key=None)[source]
        +

        Bases: evennia.commands.cmdset.CmdSet

        +

        Store crafting command.

        +
        +
        +key = 'Crafting cmdset'
        +
        + +
        +
        +at_cmdset_creation()[source]
        +

        Hook method - this should be overloaded in the inheriting +class, and should take care of populating the cmdset by use of +self.add().

        +
        + +
        +
        +path = 'evennia.contrib.crafting.crafting.CraftingCmdSet'
        +
        + +
        + +
        +
        +class evennia.contrib.crafting.crafting.CmdCraft(**kwargs)[source]
        +

        Bases: evennia.commands.command.Command

        +

        Craft an item using ingredients and tools

        +
        +
        Usage:

        craft <recipe> [from <ingredient>,…] [using <tool>, …]

        +
        +
        +

        Examples

        +

        craft snowball from snow +craft puppet from piece of wood using knife +craft bread from flour, butter, water, yeast using owen, bowl, roller +craft fireball using wand, spellbook

        +

        Notes

        +

        Ingredients must be in the crafter’s inventory. Tools can also be +things in the current location, like a furnace, windmill or anvil.

        +
        +
        +key = 'craft'
        +
        + +
        +
        +locks = 'cmd:all()'
        +
        + +
        +
        +help_category = 'general'
        +
        + +
        +
        +aliases = []
        +
        + +
        +
        +arg_regex = re.compile('\\s|$', re.IGNORECASE)
        +
        + +
        +
        +lock_storage = 'cmd:all()'
        +
        + +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'craft', 'tags': '', 'text': "\n Craft an item using ingredients and tools\n\n Usage:\n craft <recipe> [from <ingredient>,...] [using <tool>, ...]\n\n Examples:\n craft snowball from snow\n craft puppet from piece of wood using knife\n craft bread from flour, butter, water, yeast using owen, bowl, roller\n craft fireball using wand, spellbook\n\n Notes:\n Ingredients must be in the crafter's inventory. Tools can also be\n things in the current location, like a furnace, windmill or anvil.\n\n "}
        +
        + +
        +
        +parse()[source]
        +

        Handle parsing of:

        +
        <recipe> [FROM <ingredients>] [USING <tools>]
        +
        +
        +

        Examples:

        +
        craft snowball from snow
        +craft puppet from piece of wood using knife
        +craft bread from flour, butter, water, yeast using owen, bowl, roller
        +craft fireball using wand, spellbook
        +
        +
        +
        + +
        +
        +func()[source]
        +

        Perform crafting.

        +

        Will check the craft locktype. If a consumable/ingredient does not pass +this check, we will check for the ‘crafting_consumable_err_msg’ +Attribute, otherwise will use a default. If failing on a tool, will use +the crafting_tool_err_msg if available.

        +
        + +
        + +
        @@ -70,6 +839,17 @@
        +

        Table of Contents

        + +

        Previous topic

        Crafting system contrib

        @@ -99,7 +879,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -123,6 +902,7 @@ +
        develop branch
        @@ -46,8 +47,344 @@
        -
        -

        evennia.contrib.crafting.example_recipes

        +
        +

        evennia.contrib.crafting.example_recipes

        +

        How to make a sword - example crafting tree for the crafting system.

        +

        See the SwordSmithingBaseRecipe in this module for an example of extendng the +recipe with a mocked ‘skill’ system (just random chance in our case). The skill +system used is game-specific but likely to be needed for most ‘real’ crafting +systems.

        +

        Note that ‘tools’ are references to the tools used - they don’t need to be in +the inventory of the crafter. So when ‘blast furnace’ is given below, it is a +reference to a blast furnace used, not suggesting the crafter is carrying it +around with them.

        +
        +

        Sword crafting tree

        +
        # base materials (consumables)
        +
        +iron ore, ash, sand, coal, oak wood, water, fur
        +
        +# base tools (marked with [T] for clarity and assumed to already exist)
        +
        +blast furnace[T], furnace[T], crucible[T], anvil[T],
        +hammer[T], knife[T], cauldron[T]
        +
        +# recipes for making a sword
        +
        +pig iron = iron ore + 2xcoal + blast furnace[T]
        +crucible_steel = pig iron + ash + sand + 2xcoal + crucible[T]
        +sword blade = crucible steel + hammer[T] + anvil[T] + furnace[T]
        +sword pommel = crucible steel + hammer[T] + anvil[T] + furnace[T]
        +sword guard = crucible steel + hammer[T] + anvil[T] + furnace[T]
        +
        +rawhide = fur + knife[T]
        +oak bark + cleaned oak wood = oak wood + knife[T]
        +leather = rawhide + oak bark + water + cauldron[T]
        +
        +sword handle = cleaned oak wood + knife[T]
        +
        +sword = sword blade + sword guard + sword pommel
        +        + sword handle + leather + knife[T] + hammer[T] + furnace[T]
        +
        +
        +
        +
        +
        +evennia.contrib.crafting.example_recipes.random() → x in the interval [0, 1).
        +
        + +
        +
        +class evennia.contrib.crafting.example_recipes.PigIronRecipe(crafter, *inputs, **kwargs)[source]
        +

        Bases: evennia.contrib.crafting.crafting.CraftingRecipe

        +

        Pig iron is a high-carbon result of melting iron in a blast furnace.

        +
        +
        +name = 'pig iron'
        +
        + +
        +
        +tool_tags = ['blast furnace']
        +
        + +
        +
        +consumable_tags = ['iron ore', 'coal', 'coal']
        +
        + +
        +
        +output_prototypes = [{'key': 'Pig Iron ingot', 'desc': 'An ingot of crude pig iron.', 'tags': [('pig iron', 'crafting_material')]}]
        +
        + +
        + +
        +
        +class evennia.contrib.crafting.example_recipes.CrucibleSteelRecipe(crafter, *inputs, **kwargs)[source]
        +

        Bases: evennia.contrib.crafting.crafting.CraftingRecipe

        +

        Mixing pig iron with impurities like ash and sand and melting it in a +crucible produces a medieval level of steel (like damascus steel).

        +
        +
        +name = 'crucible steel'
        +
        + +
        +
        +tool_tags = ['crucible']
        +
        + +
        +
        +consumable_tags = ['pig iron', 'ash', 'sand', 'coal', 'coal']
        +
        + +
        +
        +output_prototypes = [{'key': 'Crucible steel ingot', 'desc': 'An ingot of multi-colored crucible steel.', 'tags': [('crucible steel', 'crafting_material')]}]
        +
        + +
        + +
        +
        +class evennia.contrib.crafting.example_recipes.SwordBladeRecipe(crafter, *inputs, **kwargs)[source]
        +

        Bases: evennia.contrib.crafting.example_recipes._SwordSmithingBaseRecipe

        +

        A [sword]blade requires hammering the steel out into shape using heat and +force. This also includes the tang, which is the base for the hilt (the +part of the sword you hold on to).

        +
        +
        +name = 'sword blade'
        +
        + +
        +
        +tool_tags = ['hammer', 'anvil', 'furnace']
        +
        + +
        +
        +consumable_tags = ['crucible steel']
        +
        + +
        +
        +output_prototypes = [{'key': 'Sword blade', 'desc': 'A long blade that may one day become a sword.', 'tags': [('sword blade', 'crafting_material')]}]
        +
        + +
        + +
        +
        +class evennia.contrib.crafting.example_recipes.SwordPommelRecipe(crafter, *inputs, **kwargs)[source]
        +

        Bases: evennia.contrib.crafting.example_recipes._SwordSmithingBaseRecipe

        +

        The pommel is the ‘button’ or ‘ball’ etc the end of the sword hilt, holding +it together.

        +
        +
        +name = 'sword pommel'
        +
        + +
        +
        +tool_tags = ['hammer', 'anvil', 'furnace']
        +
        + +
        +
        +consumable_tags = ['crucible steel']
        +
        + +
        +
        +output_prototypes = [{'key': 'Sword pommel', 'desc': 'The pommel for a future sword.', 'tags': [('sword pommel', 'crafting_material')]}]
        +
        + +
        + +
        +
        +class evennia.contrib.crafting.example_recipes.SwordGuardRecipe(crafter, *inputs, **kwargs)[source]
        +

        Bases: evennia.contrib.crafting.example_recipes._SwordSmithingBaseRecipe

        +

        The guard stops the hand from accidentally sliding off the hilt onto the +sword’s blade and also protects the hand when parrying.

        +
        +
        +name = 'sword guard'
        +
        + +
        +
        +tool_tags = ['hammer', 'anvil', 'furnace']
        +
        + +
        +
        +consumable_tags = ['crucible steel']
        +
        + +
        +
        +output_prototypes = [{'key': 'Sword guard', 'desc': 'The cross-guard for a future sword.', 'tags': [('sword guard', 'crafting_material')]}]
        +
        + +
        + +
        +
        +class evennia.contrib.crafting.example_recipes.RawhideRecipe(crafter, *inputs, **kwargs)[source]
        +

        Bases: evennia.contrib.crafting.crafting.CraftingRecipe

        +

        Rawhide is animal skin cleaned and stripped of hair.

        +
        +
        +name = 'rawhide'
        +
        + +
        +
        +tool_tags = ['knife']
        +
        + +
        +
        +consumable_tags = ['fur']
        +
        + +
        +
        +output_prototypes = [{'key': 'Rawhide', 'desc': 'Animal skin, cleaned and with hair removed.', 'tags': [('rawhide', 'crafting_material')]}]
        +
        + +
        + +
        +
        +class evennia.contrib.crafting.example_recipes.OakBarkRecipe(crafter, *inputs, **kwargs)[source]
        +

        Bases: evennia.contrib.crafting.crafting.CraftingRecipe

        +

        The actual thing needed for tanning leather is Tannin, but we skip +the step of refining tannin from the bark and use the bark as-is.

        +

        This produces two outputs - the bark and the cleaned wood.

        +
        +
        +name = 'oak bark'
        +
        + +
        +
        +tool_tags = ['knife']
        +
        + +
        +
        +consumable_tags = ['oak wood']
        +
        + +
        +
        +output_prototypes = [{'key': 'Oak bark', 'desc': 'Bark of oak, stripped from the core wood.', 'tags': [('oak bark', 'crafting_material')]}, {'key': 'Oak Wood (cleaned)', 'desc': 'Oakwood core, stripped of bark.', 'tags': [('cleaned oak wood', 'crafting_material')]}]
        +
        + +
        + +
        +
        +class evennia.contrib.crafting.example_recipes.LeatherRecipe(crafter, *inputs, **kwargs)[source]
        +

        Bases: evennia.contrib.crafting.crafting.CraftingRecipe

        +

        Leather is produced by tanning rawhide in a process traditionally involving +the chemical Tannin. Here we abbreviate this process a bit. Maybe a +‘tanning rack’ tool should be required too …

        +
        +
        +name = 'leather'
        +
        + +
        +
        +tool_tags = ['cauldron']
        +
        + +
        +
        +consumable_tags = ['rawhide', 'oak bark', 'water']
        +
        + +
        +
        +output_prototypes = [{'key': 'Piece of Leather', 'desc': 'A piece of leather.', 'tags': [('leather', 'crafting_material')]}]
        +
        + +
        + +
        +
        +class evennia.contrib.crafting.example_recipes.SwordHandleRecipe(crafter, *inputs, **kwargs)[source]
        +

        Bases: evennia.contrib.crafting.crafting.CraftingRecipe

        +

        The handle is the part of the hilt between the guard and the pommel where +you hold the sword. It consists of wooden pieces around the steel tang. It +is wrapped in leather, but that will be added at the end.

        +
        +
        +name = 'sword handle'
        +
        + +
        +
        +tool_tags = ['knife']
        +
        + +
        +
        +consumable_tags = ['cleaned oak wood']
        +
        + +
        +
        +output_prototypes = [{'key': 'Sword handle', 'desc': "Two pieces of wood to be be fitted onto a sword's tang as its handle.", 'tags': [('sword handle', 'crafting_material')]}]
        +
        + +
        + +
        +
        +class evennia.contrib.crafting.example_recipes.SwordRecipe(crafter, *inputs, **kwargs)[source]
        +

        Bases: evennia.contrib.crafting.example_recipes._SwordSmithingBaseRecipe

        +

        A finished sword consists of a Blade ending in a non-sharp part called the +Tang. The cross Guard is put over the tang against the edge of the blade. +The Handle is put over the tang to give something easier to hold. The +Pommel locks everything in place. The handle is wrapped in leather +strips for better grip.

        +

        This covers only a single ‘sword’ type.

        +
        +
        +name = 'sword'
        +
        + +
        +
        +tool_tags = ['hammer', 'furnace', 'knife']
        +
        + +
        +
        +consumable_tags = ['sword blade', 'sword guard', 'sword pommel', 'sword handle', 'leather']
        +
        + +
        +
        +output_prototypes = [{'key': 'Sword', 'desc': 'A bladed weapon.', 'tags': [('sword', 'crafting_material')]}]
        +
        + +
        +
        +exact_consumable_order = True
        +
        + +
        + +
        @@ -70,6 +407,14 @@
        +

        Table of Contents

        + +

        Previous topic

        evennia.contrib.crafting.crafting

        @@ -99,7 +444,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -123,6 +467,7 @@ +
        develop branch
        @@ -108,6 +117,7 @@ +
        develop branch
        @@ -37,8 +38,221 @@
        -
        -

        evennia.contrib.crafting.tests

        +
        +

        evennia.contrib.crafting.tests

        +

        Unit tests for the crafting system contrib.

        +
        +
        +class evennia.contrib.crafting.tests.TestCraftUtils(methodName='runTest')[source]
        +

        Bases: django.test.testcases.TestCase

        +

        Test helper utils for crafting.

        +
        +
        +maxDiff = None
        +
        + +
        +
        +test_load_recipes()[source]
        +

        This should only load the example module now

        +
        + +
        + +
        +
        +class evennia.contrib.crafting.tests.TestCraftingRecipeBase(methodName='runTest')[source]
        +

        Bases: django.test.testcases.TestCase

        +

        Test the parent recipe class.

        +
        +
        +setUp()[source]
        +

        Hook method for setting up the test fixture before exercising it.

        +
        + +
        +
        +test_msg()[source]
        +

        Test messaging to crafter

        +
        + +
        +
        +test_pre_craft()[source]
        +

        Test validating hook

        +
        + +
        +
        +test_pre_craft_fail()[source]
        +

        Should rase error if validation fails

        +
        + +
        +
        +test_craft_hook__succeed()[source]
        +

        Test craft hook, the main access method.

        +
        + +
        +
        +test_craft_hook__fail()[source]
        +

        Test failing the call

        +
        + +
        + +
        +
        +class evennia.contrib.crafting.tests.TestCraftingRecipe(methodName='runTest')[source]
        +

        Bases: django.test.testcases.TestCase

        +

        Test the CraftingRecipe class with one recipe

        +
        +
        +maxDiff = None
        +
        + +
        +
        +setUp()[source]
        +

        Hook method for setting up the test fixture before exercising it.

        +
        + +
        +
        +tearDown()[source]
        +

        Hook method for deconstructing the test fixture after testing it.

        +
        + +
        +
        +test_error_format()[source]
        +

        Test the automatic error formatter

        +
        + +
        +
        +test_craft__success()[source]
        +

        Test to create a result from the recipe

        +
        + +
        +
        +test_seed__success()[source]
        +

        Test seed helper classmethod

        +
        + +
        +
        +test_craft_missing_tool__fail()[source]
        +

        Fail craft by missing tool2

        +
        + +
        +
        +test_craft_missing_cons__fail()[source]
        +

        Fail craft by missing cons3

        +
        + +
        +
        +test_craft_missing_cons__always_consume__fail()[source]
        +

        Fail craft by missing cons3, with always-consume flag

        +
        + +
        +
        +test_craft_wrong_tool__fail()[source]
        +

        Fail craft by including a wrong tool

        +
        + +
        +
        +test_craft_tool_excess__fail()[source]
        +

        Fail by too many consumables

        +
        + +
        +
        +test_craft_cons_excess__fail()[source]
        +

        Fail by too many consumables

        +
        + +
        +
        +test_craft_tool_excess__sucess()[source]
        +

        Allow too many consumables

        +
        + +
        +
        +test_craft_cons_excess__sucess()[source]
        +

        Allow too many consumables

        +
        + +
        +
        +test_craft_tool_order__fail()[source]
        +

        Strict tool-order recipe fail

        +
        + +
        +
        +test_craft_cons_order__fail()[source]
        +

        Strict tool-order recipe fail

        +
        + +
        + +
        +
        +class evennia.contrib.crafting.tests.TestCraftSword(methodName='runTest')[source]
        +

        Bases: django.test.testcases.TestCase

        +

        Test the craft function by crafting the example sword.

        +
        +
        +setUp()[source]
        +

        Hook method for setting up the test fixture before exercising it.

        +
        + +
        +
        +test_craft_sword(mockrandom)[source]
        +

        Craft example sword. For the test, every crafting works.

        +
        + +
        + +
        +
        +class evennia.contrib.crafting.tests.TestCraftCommand(methodName='runTest')[source]
        +

        Bases: evennia.commands.default.tests.CommandTest

        +

        Test the crafting command

        +
        +
        +setUp()[source]
        +

        Sets up testing environment

        +
        + +
        +
        +test_craft__success()[source]
        +

        Successfully craft using command

        +
        + +
        +
        +test_craft__notools__failure()[source]
        +

        Craft fail no tools

        +
        + +
        +
        +test_craft__nocons__failure()[source]
        +
        + +
        +
        @@ -84,7 +298,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +314,7 @@ +
        develop branch
        @@ -313,7 +314,6 @@ The time is given in units as keyword arguments.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -330,6 +330,7 @@ The time is given in units as keyword arguments.

        +
        develop branch
        @@ -149,7 +150,7 @@ everyone but the person rolling.

        -aliases = ['@dice', 'roll']
        +aliases = ['roll', '@dice']
        @@ -173,6 +174,11 @@ everyone but the person rolling.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'roll @dice', 'category': 'general', 'key': 'dice', 'tags': '', 'text': "\n roll dice\n\n Usage:\n dice[/switch] <nr>d<sides> [modifier] [success condition]\n\n Switch:\n hidden - tell the room the roll is being done, but don't show the result\n secret - don't inform the room about neither roll nor result\n\n Examples:\n dice 3d6 + 4\n dice 1d100 - 2 < 50\n\n This will roll the given number of dice with given sides and modifiers.\n So e.g. 2d6 + 3 means to 'roll a 6-sided die 2 times and add the result,\n then add 3 to the total'.\n Accepted modifiers are +, -, * and /.\n A success condition is given as normal Python conditionals\n (<,>,<=,>=,==,!=). So e.g. 2d6 + 3 > 10 means that the roll will succeed\n only if the final result is above 8. If a success condition is given, the\n outcome (pass/fail) will be echoed along with how much it succeeded/failed\n with. The hidden/secret switches will hide all or parts of the roll from\n everyone but the person rolling.\n "}
        +
        +
        @@ -239,7 +245,6 @@ Add with @py self.cmdset.add(“contrib.dice.DiceCmdSet”)

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -256,6 +261,7 @@ Add with @py self.cmdset.add(“contrib.dice.DiceCmdSet”)

        +
        develop branch
        @@ -74,7 +75,7 @@ the module given by settings.CONNECTION_SCREEN_MODULE.

        -aliases = ['conn', 'co', 'con']
        +aliases = ['con', 'co', 'conn']
        @@ -102,6 +103,11 @@ there is no object yet before the account has logged in)

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'con co conn', 'category': 'general', 'key': 'connect', 'tags': '', 'text': '\n Connect to the game.\n\n Usage (at login screen):\n connect <email> <password>\n\n Use the create command to first create an account before logging in.\n '}
        +
        +
        @@ -121,7 +127,7 @@ there is no object yet before the account has logged in)

        -aliases = ['cr', 'cre']
        +aliases = ['cre', 'cr']
        @@ -155,6 +161,11 @@ name enclosed in quotes:

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'cre cr', 'category': 'general', 'key': 'create', 'tags': '', 'text': '\n Create a new account.\n\n Usage (at login screen):\n create "accountname" <email> <password>\n\n This creates a new account account.\n\n '}
        +
        +
        @@ -171,7 +182,7 @@ version is a bit more complicated.

        -aliases = ['qu', 'q']
        +aliases = ['q', 'qu']
        @@ -195,6 +206,11 @@ version is a bit more complicated.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'q qu', 'category': 'general', 'key': 'quit', 'tags': '', 'text': '\n We maintain a different version of the `quit` command\n here for unconnected accounts for the sake of simplicity. The logged in\n version is a bit more complicated.\n '}
        +
        +
        @@ -235,6 +251,11 @@ All it does is display the connect screen.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'look l', 'category': 'general', 'key': '__unloggedin_look_command', 'tags': '', 'text': '\n This is an unconnected version of the `look` command for simplicity.\n\n This is called by the server and kicks everything in gear.\n All it does is display the connect screen.\n '}
        +
        +
        @@ -250,7 +271,7 @@ for simplicity. It shows a pane of info.

        -aliases = ['h', '?']
        +aliases = ['?', 'h']
        @@ -274,6 +295,11 @@ for simplicity. It shows a pane of info.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '? h', 'category': 'general', 'key': 'help', 'tags': '', 'text': '\n This is an unconnected version of the help command,\n for simplicity. It shows a pane of info.\n '}
        +
        +
        @@ -321,7 +347,6 @@ for simplicity. It shows a pane of info.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -338,6 +363,7 @@ for simplicity. It shows a pane of info.

        +
        develop branch
        @@ -123,6 +124,11 @@ the operation will be general or on the room.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'evscaperoom', 'key': 'command', 'tags': '', 'text': "\n Base command parent for all Evscaperoom commands.\n\n This operates on the premise of 'focus' - the 'focus'\n is set on the caller, then subsequent commands will\n operate on that focus. If no focus is set,\n the operation will be general or on the room.\n\n Syntax:\n\n command [<obj1>|<arg1>] [<prep> <obj2>|<arg2>]\n\n "}
        +
        +
        @@ -142,7 +148,7 @@ the operation will be general or on the room.

        -aliases = ['abort', 'chicken out', 'q', 'quit']
        +aliases = ['abort', 'q', 'quit', 'chicken out']
        @@ -164,6 +170,11 @@ set in self.parse())

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': 'abort q quit chicken out', 'category': 'evscaperoom', 'key': 'give up', 'tags': '', 'text': '\n Give up\n\n Usage:\n give up\n\n Abandons your attempts at escaping and of ever winning the pie-eating contest.\n\n '}
        +
        +
        @@ -182,7 +193,7 @@ set in self.parse())

        -aliases = ['ls', 'l']
        +aliases = ['l', 'ls']
        @@ -214,6 +225,11 @@ set in self.parse())

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': 'l ls', 'category': 'evscaperoom', 'key': 'look', 'tags': '', 'text': '\n Look at the room, an object or the currently focused object\n\n Usage:\n look [obj]\n\n '}
        +
        +
        @@ -267,6 +283,11 @@ set in self.parse())

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'evscaperoom', 'key': 'who', 'tags': '', 'text': '\n List other players in the game.\n\n Usage:\n who\n who all\n\n Show who is in the room with you, or (with who all), who is online on the\n server as a whole.\n\n '}
        +
        +
        @@ -287,7 +308,7 @@ shout

        -aliases = ['whisper', 'shout', ';']
        +aliases = ['shout', ';', 'whisper']
        @@ -314,6 +335,11 @@ set in self.parse())

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': 'shout ; whisper', 'category': 'general', 'key': 'say', 'tags': '', 'text': '\n Perform an communication action.\n\n Usage:\n say <text>\n whisper\n shout\n\n '}
        +
        +
        @@ -339,7 +365,7 @@ emote /me points to /box and /lever.

        -aliases = [':', 'pose']
        +aliases = ['pose', ':']
        @@ -376,6 +402,11 @@ set in self.parse())

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': 'pose :', 'category': 'general', 'key': 'emote', 'tags': '', 'text': '\n Perform a free-form emote. Use /me to\n include yourself in the emote and /name\n to include other objects or characters.\n Use "..." to enact speech.\n\n Usage:\n emote <emote>\n :<emote\n\n Example:\n emote /me smiles at /peter\n emote /me points to /box and /lever.\n\n '}
        +
        +
        @@ -396,7 +427,7 @@ looks and what actions is available.

        -aliases = ['ex', 'examine', 'unfocus', 'e']
        +aliases = ['unfocus', 'e', 'ex', 'examine']
        @@ -423,6 +454,11 @@ set in self.parse())

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': 'unfocus e ex examine', 'category': 'evscaperoom', 'key': 'focus', 'tags': '', 'text': '\n Focus your attention on a target.\n\n Usage:\n focus <obj>\n\n Once focusing on an object, use look to get more information about how it\n looks and what actions is available.\n\n '}
        +
        +
        @@ -463,6 +499,11 @@ set in self.parse())

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': 'option', 'category': 'evscaperoom', 'key': 'options', 'tags': '', 'text': '\n Start option menu\n\n Usage:\n options\n\n '}
        +
        +
        @@ -477,7 +518,7 @@ set in self.parse())

        -aliases = ['inv', 'i', 'give', 'inventory']
        +aliases = ['inv', 'inventory', 'i', 'give']
        @@ -499,6 +540,11 @@ set in self.parse())

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': 'inv inventory i give', 'category': 'evscaperoom', 'key': 'get', 'tags': '', 'text': '\n Use focus / examine instead.\n\n '}
        +
        +
        @@ -538,6 +584,11 @@ to all the variables defined therein.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '@open @dig', 'category': 'general', 'key': 'open', 'tags': '', 'text': '\n Interact with an object in focus.\n\n Usage:\n <action> [arg]\n\n '}
        +
        +
        @@ -602,6 +653,11 @@ set in self.parse())

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'evscaperoom', 'key': '__nomatch_command', 'tags': '', 'text': '\n Interact with an object in focus.\n\n Usage:\n <action> [arg]\n\n This is a special catch-all command which will operate on\n the current focus. It will look for a method\n `focused_object.at_focus_<action>(caller, **kwargs)` and call\n it. This allows objects to just add a new hook to make that\n action apply to it. The obj1, prep, obj2, arg1, arg2 are passed\n as keys into the method.\n\n '}
        +
        +
        @@ -638,6 +694,11 @@ set in self.parse())

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'evscaperoom', 'key': 'stand', 'tags': '', 'text': '\n Stand up from whatever position you had.\n\n '}
        +
        +
        @@ -678,6 +739,11 @@ set in self.parse())

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '?', 'category': 'evscaperoom', 'key': 'help', 'tags': '', 'text': '\n Get help.\n\n Usage:\n help <topic> or <command>\n\n '}
        +
        +
        @@ -734,6 +800,11 @@ set in self.parse())

        lock_storage = 'cmd:perm(Admin)'
        +
        +
        +search_index_entry = {'aliases': 'cobj', 'category': 'evscaperoom', 'key': 'createobj', 'tags': '', 'text': '\n Create command, only for Admins during debugging.\n\n Usage:\n createobj name[:typeclass]\n\n Here, :typeclass is a class in evscaperoom.commands\n\n '}
        +
        +
        @@ -789,6 +860,11 @@ set in self.parse())

        lock_storage = 'cmd:perm(Admin)'
        +
        +
        +search_index_entry = {'aliases': 'setflag', 'category': 'evscaperoom', 'key': 'flag', 'tags': '', 'text': '\n Assign a flag to an object. Admin use only\n\n Usage:\n flag <obj> with <flagname>\n\n '}
        +
        +
        @@ -845,6 +921,11 @@ set in self.parse())

        lock_storage = 'cmd:perm(Admin)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'evscaperoom', 'key': 'jumpstate', 'tags': '', 'text': '\n Jump to a given state.\n\n Args:\n jumpstate <statename>\n\n '}
        +
        +
        @@ -881,6 +962,11 @@ set in self.parse())

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'evscaperoom', 'key': 'evscaperoom', 'tags': '', 'text': '\n Go to the Evscaperoom start menu\n\n '}
        +
        +
        @@ -952,7 +1038,6 @@ self.add().

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -969,6 +1054,7 @@ self.add().

        +
        develop branch
        @@ -96,7 +97,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -113,6 +113,7 @@ +
        develop branch
        @@ -194,7 +195,6 @@ option related to this node.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -211,6 +211,7 @@ option related to this node.

        +
        develop branch
        @@ -1814,7 +1815,6 @@ inject the list of callsigns.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1831,6 +1831,7 @@ inject the list of callsigns.

        +
        develop branch
        @@ -273,7 +274,6 @@ contents of the object by default.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -290,6 +290,7 @@ contents of the object by default.

        +
        develop branch
        @@ -84,7 +85,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +101,7 @@ +
        develop branch
        @@ -270,7 +271,6 @@ happens just before room.character_cleanup()

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -287,6 +287,7 @@ happens just before room.character_cleanup()

        +
        develop branch
        @@ -210,7 +211,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -227,6 +227,7 @@ +
        develop branch
        @@ -202,7 +203,6 @@ surrounded by borders.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -219,6 +219,7 @@ surrounded by borders.

        +
        develop branch
        @@ -276,7 +277,7 @@ look *<account&g
        -aliases = ['ls', 'l']
        +aliases = ['l', 'ls']
        @@ -294,6 +295,11 @@ look *<account&g lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'l ls', 'category': 'general', 'key': 'look', 'tags': '', 'text': '\n look\n\n Usage:\n look\n look <obj>\n look <room detail>\n look *<account>\n\n Observes your location, details at your location or objects in your vicinity.\n '}
        +
        +
        @@ -357,6 +363,11 @@ version of the desc command.

        lock_storage = 'cmd:perm(desc) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': 'describe', 'category': 'building', 'key': 'desc', 'tags': '', 'text': '\n `desc` - describe an object or room.\n\n Usage:\n desc[/switch] [<obj> =] <description>\n\n Switches for `desc`:\n spring - set description for <season> in current room.\n summer\n autumn\n winter\n\n Sets the "desc" attribute on an object. If an object is not given,\n describe the current room.\n\n You can also embed special time markers in your room description, like this:\n\n ```\n <night>In the darkness, the forest looks foreboding.</night>.\n ```\n\n Text marked this way will only display when the server is truly at the given\n timeslot. The available times are night, morning, afternoon and evening.\n\n Note that seasons and time-of-day slots only work on rooms in this\n version of the `desc` command.\n\n '}
        +
        +
        @@ -415,6 +426,11 @@ to all the variables defined therein.

        lock_storage = 'cmd:perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'building', 'key': '@detail', 'tags': '', 'text': '\n sets a detail on a room\n\n Usage:\n @detail[/del] <key> [= <description>]\n @detail <key>;<alias>;... = description\n\n Example:\n @detail\n @detail walls = The walls are covered in ...\n @detail castle;ruin;tower = The distant ruin ...\n @detail/del wall\n @detail/del castle;ruin;tower\n\n This command allows to show the current room details if you enter it\n without any argument. Otherwise, sets or deletes a detail on the current\n room, if this room supports details like an extended room. To add new\n detail, just use the @detail command, specifying the key, an equal sign\n and the description. You can assign the same description to several\n details using the alias syntax (replace key by alias1;alias2;alias3;...).\n To remove one or several details, use the @detail/del switch.\n\n '}
        +
        +
        @@ -458,6 +474,11 @@ to all the variables defined therein.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'time', 'tags': '', 'text': '\n Check the game time\n\n Usage:\n time\n\n Shows the current in-game time and season.\n '}
        +
        +
        @@ -525,7 +546,6 @@ self.add().

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -542,6 +562,7 @@ self.add().

        +
        develop branch
        @@ -364,6 +365,11 @@ send

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'testmenu', 'tags': '', 'text': "\n This test command will initialize a menu that presents you with a form.\n You can fill out the fields of this form in any order, and then type in\n 'send' to send a message to another online player, which will reach them\n after a delay you specify.\n\n Usage:\n <field> = <new value>\n clear <field>\n help\n look\n quit\n send\n "}
        +
        +
        @@ -439,7 +445,6 @@ send

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -456,6 +461,7 @@ send

        +
        develop branch
        @@ -110,6 +111,11 @@ default cmdset before it becomes available.

        lock_storage = 'cmd:all();call:all()'
        +
        +
        +search_index_entry = {'aliases': '@sex', 'category': 'general', 'key': '@gender', 'tags': '', 'text': '\n Sets gender on yourself\n\n Usage:\n @gender male||female||neutral||ambiguous\n\n '}
        +
        +
        @@ -218,7 +224,6 @@ All extra kwargs will be passed on to the protocol.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -235,6 +240,7 @@ All extra kwargs will be passed on to the protocol.

        +
        develop branch
        @@ -141,7 +142,6 @@ readers will be unable to read the graphical aspect of the bar.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -158,6 +158,7 @@ readers will be unable to read the graphical aspect of the bar.

        +
        develop branch
        @@ -204,6 +233,7 @@ useful but are deemed too game-specific to go into the core library.

        +
        develop branch
        @@ -319,7 +320,6 @@ the expected fields for a callback (code, author, valid…).

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -336,6 +336,7 @@ the expected fields for a callback (code, author, valid…).

        +
        develop branch
        @@ -52,7 +53,7 @@
        -aliases = ['@calls', '@callback', '@callbacks']
        +aliases = ['@calls', '@callbacks', '@callback']
        @@ -131,6 +132,11 @@ on user permission.

        lock_storage = 'cmd:perm(developer)'
        +
        +
        +search_index_entry = {'aliases': '@calls @callbacks @callback', 'category': 'building', 'key': '@call', 'tags': '', 'text': '\n Command to edit callbacks.\n '}
        +
        + @@ -178,7 +184,6 @@ on user permission.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -195,6 +200,7 @@ on user permission.

        +
        develop branch
        @@ -151,7 +152,6 @@ to be called from inside another event.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -168,6 +168,7 @@ to be called from inside another event.

        +
        develop branch
        @@ -95,7 +96,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -112,6 +112,7 @@ +
        develop branch
        @@ -56,8 +57,8 @@ editing and deleting these events and callbacks.

        -
        -at_start()[source]
        +
        +at_server_start()[source]

        Set up the event system when starting.

        Note that this hook is called every time the server restarts (including when it’s reloaded). This hook performs the following @@ -440,7 +441,6 @@ restart only twice.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -457,6 +457,7 @@ restart only twice.

        +
        develop branch
        @@ -226,7 +227,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -243,6 +243,7 @@ +
        develop branch
        @@ -84,7 +85,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +101,7 @@ +
        develop branch
        @@ -204,7 +205,6 @@ either “yes” or “okay” (maybe ‘say I don’t like it, but okay’).

        0.9.5 (v0.9.5 branch) -
        @@ -221,6 +221,7 @@ either “yes” or “okay” (maybe ‘say I don’t like it, but okay’).

        Evennia 1.0-dev » +
        develop branch
        @@ -218,6 +219,11 @@ the newly created mails.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': 'mail', 'category': 'general', 'key': '@mail', 'tags': '', 'text': '\n Communicate with others by sending mail.\n\n Usage:\n @mail - Displays all the mail an account has in their mailbox\n @mail <#> - Displays a specific message\n @mail <accounts>=<subject>/<message>\n - Sends a message to the comma separated list of accounts.\n @mail/delete <#> - Deletes a specific message\n @mail/forward <account list>=<#>[/<Message>]\n - Forwards an existing message to the specified list of accounts,\n original message is delivered with optional Message prepended.\n @mail/reply <#>=<message>\n - Replies to a message #. Prepends message to the original\n message text.\n Switches:\n delete - deletes a message\n forward - forward a received message to another object with an optional message attached.\n reply - Replies to a received message, appending the original message to the bottom.\n Examples:\n @mail 2\n @mail Griatch=New mail/Hey man, I am sending you a message!\n @mail/delete 6\n @mail/forward feend78 Griatch=4/You guys should read this.\n @mail/reply 9=Thanks for the info!\n\n '}
        +
        +
        @@ -286,6 +292,11 @@ reply - Replies to a received message, appending the original message to the b lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': 'mail', 'category': 'general', 'key': '@mail', 'tags': '', 'text': '\n Communicate with others by sending mail.\n\n Usage:\n @mail - Displays all the mail an account has in their mailbox\n @mail <#> - Displays a specific message\n @mail <accounts>=<subject>/<message>\n - Sends a message to the comma separated list of accounts.\n @mail/delete <#> - Deletes a specific message\n @mail/forward <account list>=<#>[/<Message>]\n - Forwards an existing message to the specified list of accounts,\n original message is delivered with optional Message prepended.\n @mail/reply <#>=<message>\n - Replies to a message #. Prepends message to the original\n message text.\n Switches:\n delete - deletes a message\n forward - forward a received message to another object with an optional message attached.\n reply - Replies to a received message, appending the original message to the bottom.\n Examples:\n @mail 2\n @mail Griatch=New mail/Hey man, I am sending you a message!\n @mail/delete 6\n @mail/forward feend78 Griatch=4/You guys should read this.\n @mail/reply 9=Thanks for the info!\n\n '}
        +
        + @@ -333,7 +344,6 @@ reply - Replies to a received message, appending the original message to the b
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -350,6 +360,7 @@ reply - Replies to a received message, appending the original message to the b +
        develop branch
        @@ -84,7 +85,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +101,7 @@ +
        develop branch
        @@ -84,7 +85,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +101,7 @@ +
        develop branch
        @@ -116,6 +117,11 @@ description in use and db.multidesc to store all descriptions.< lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'desc', 'category': 'general', 'key': '+desc', 'tags': '', 'text': '\n Manage multiple descriptions\n\n Usage:\n +desc [key] - show current desc desc with <key>\n +desc <key> = <text> - add/replace desc with <key>\n +desc/list - list descriptions (abbreviated)\n +desc/list/full - list descriptions (full texts)\n +desc/edit <key> - add/edit desc <key> in line editor\n +desc/del <key> - delete desc <key>\n +desc/swap <key1>-<key2> - swap positions of <key1> and <key2> in list\n +desc/set <key> [+key+...] - set desc as default or combine multiple descs\n\n Notes:\n When combining multiple descs with +desc/set <key> + <key2> + ...,\n any keys not matching an actual description will be inserted\n as plain text. Use e.g. ansi line break ||/ to add a new\n paragraph and + + or ansi space ||_ to add extra whitespace.\n\n '}
        +
        + @@ -163,7 +169,6 @@ description in use and db.multidesc to store all descriptions.<
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -180,6 +185,7 @@ description in use and db.multidesc to store all descriptions.< +
        develop branch
        @@ -206,6 +207,11 @@ to all the variables defined therein.

        lock_storage = 'cmd:perm(puzzle) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': '@puzzlerecipe', 'category': 'puzzles', 'key': '@puzzle', 'tags': '', 'text': "\n Creates a puzzle recipe. A puzzle consists of puzzle-parts that\n the player can 'use' together to create a specified result.\n\n Usage:\n @puzzle name,<part1[,part2,...>] = <result1[,result2,...]>\n\n Example:\n create/drop balloon\n create/drop glass of water\n create/drop water balloon\n @puzzle waterballon,balloon,glass of water = water balloon\n @del ballon, glass of water, water balloon\n @armpuzzle #1\n\n Notes:\n Each part and result are objects that must (temporarily) exist and be placed in their\n corresponding location in order to create the puzzle. After the creation of the puzzle,\n these objects are not needed anymore and can be deleted. Components of the puzzle\n will be re-created by use of the `@armpuzzle` command later.\n\n "}
        +
        +
        @@ -269,6 +275,11 @@ to all the variables defined therein.

        lock_storage = 'cmd:perm(puzzleedit) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'puzzles', 'key': '@puzzleedit', 'tags': '', 'text': "\n Edits puzzle properties\n\n Usage:\n @puzzleedit[/delete] <#dbref>\n @puzzleedit <#dbref>/use_success_message = <Custom message>\n @puzzleedit <#dbref>/use_success_location_message = <Custom message from {caller} producing {result_names}>\n @puzzleedit <#dbref>/mask = attr1[,attr2,...]>\n @puzzleedit[/addpart] <#dbref> = <obj[,obj2,...]>\n @puzzleedit[/delpart] <#dbref> = <obj[,obj2,...]>\n @puzzleedit[/addresult] <#dbref> = <obj[,obj2,...]>\n @puzzleedit[/delresult] <#dbref> = <obj[,obj2,...]>\n\n Switches:\n addpart - adds parts to the puzzle\n delpart - removes parts from the puzzle\n addresult - adds results to the puzzle\n delresult - removes results from the puzzle\n delete - deletes the recipe. Existing parts and results aren't modified\n\n mask - attributes to exclude during matching (e.g. location, desc, etc.)\n use_success_location_message containing {result_names} and {caller} will\n automatically be replaced with correct values. Both are optional.\n\n When removing parts/results, it's possible to remove all.\n\n "}
        +
        +
        @@ -316,6 +327,11 @@ to all the variables defined therein.

        lock_storage = 'cmd:perm(armpuzzle) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'puzzles', 'key': '@armpuzzle', 'tags': '', 'text': '\n Arms a puzzle by spawning all its parts.\n\n Usage:\n @armpuzzle <puzzle #dbref>\n\n Notes:\n Create puzzles with `@puzzle`; get list of\n defined puzzles using `@lspuzzlerecipes`.\n\n '}
        +
        +
        @@ -364,6 +380,11 @@ to all the variables defined therein.

        lock_storage = 'cmd:pperm(use) or pperm(Player)'
        +
        +
        +search_index_entry = {'aliases': 'combine', 'category': 'puzzles', 'key': 'use', 'tags': '', 'text': '\n Use an object, or a group of objects at once.\n\n\n Example:\n You look around you and see a pole, a long string, and a needle.\n\n use pole, long string, needle\n\n Genius! You built a fishing pole.\n\n\n Usage:\n use <obj1> [,obj2,...]\n '}
        +
        +
        @@ -408,6 +429,11 @@ to all the variables defined therein.

        lock_storage = 'cmd:perm(lspuzzlerecipes) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'puzzles', 'key': '@lspuzzlerecipes', 'tags': '', 'text': '\n Searches for all puzzle recipes\n\n Usage:\n @lspuzzlerecipes\n '}
        +
        +
        @@ -452,6 +478,11 @@ to all the variables defined therein.

        lock_storage = 'cmd:perm(lsarmedpuzzles) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'puzzles', 'key': '@lsarmedpuzzles', 'tags': '', 'text': '\n Searches for all armed puzzles\n\n Usage:\n @lsarmedpuzzles\n '}
        +
        +
        @@ -519,7 +550,6 @@ self.add().

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -536,6 +566,7 @@ self.add().

        +
        develop branch
        @@ -299,7 +300,6 @@ calling the get method.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -316,6 +316,7 @@ calling the get method.

        +
        develop branch
        @@ -98,18 +99,46 @@ words compared to the original and can help change the “feel” for the language you are creating. You can also add your own dictionary and “fix” random words for a list of input words.

        Below is an example of “elvish”, using “rounder” vowels and sounds:

        -
        phonemes = "oi oh ee ae aa eh ah ao aw ay er ey ow ia ih iy "                "oy ua uh uw y p b t d f v t dh s z sh zh ch jh k "                "ng g m n l r w",
        +
        # vowel/consonant grammar possibilities
        +grammar = ("v vv vvc vcc vvcc cvvc vccv vvccv vcvccv vcvcvcc vvccvvcc "
        +           "vcvvccvvc cvcvvcvvcc vcvcvvccvcvv")
        +
        +# all not in this group is considered a consonant
         vowels = "eaoiuy"
        -grammar = "v vv vvc vcc vvcc cvvc vccv vvccv vcvccv vcvcvcc vvccvvcc "               "vcvvccvvc cvcvvcvvcc vcvcvvccvcvv",
        +
        +# you need a representative of all of the minimal grammars here, so if a
        +# grammar v exists, there must be atleast one phoneme available with only
        +# one vowel in it
        +phonemes = ("oi oh ee ae aa eh ah ao aw ay er ey ow ia ih iy "
        +            "oy ua uh uw y p b t d f v t dh s z sh zh ch jh k "
        +            "ng g m n l r w")
        +
        +# how much the translation varies in length compared to the original. 0 is
        +# smallest, higher values give ever bigger randomness (including removing
        +# short words entirely)
         word_length_variance = 1
        +
        +# if a proper noun (word starting with capitalized letter) should be
        +# translated or not. If not (default) it means e.g. names will remain
        +# unchanged across languages.
        +noun_translate = False
        +
        +# all proper nouns (words starting with a capital letter not at the beginning
        +# of a sentence) can have either a postfix or -prefix added at all times
         noun_postfix = "'la"
        +
        +# words in dict will always be translated this way. The 'auto_translations'
        +# is instead a list or filename to file with words to use to help build a
        +# bigger dictionary by creating random translations of each word in the
        +# list *once* and saving the result for subsequent use.
         manual_translations = {"the":"y'e", "we":"uyi", "she":"semi", "he":"emi",
                               "you": "do", 'me':'mi','i':'me', 'be':"hy'e", 'and':'y'}
         
         rplanguage.add_language(key="elvish", phonemes=phonemes, grammar=grammar,
                                  word_length_variance=word_length_variance,
        +                         noun_translate=noun_translate,
                                  noun_postfix=noun_postfix, vowels=vowels,
        -                         manual_translations=manual_translations
        +                         manual_translations=manual_translations,
                                  auto_translations="my_word_file.txt")
         
        @@ -190,9 +219,13 @@ cvcvccc would be c+v+c+v+cc+c (a word like ‘galosch’).

        0 means a minimal variance, higher variance may mean words have wildly varying length; this strongly affects how the language “looks”.

        -
      • noun_translate (bool, optional) – If a proper noun, identified as a -capitalized word, should be translated or not. By default they -will not, allowing for e.g. the names of characters to be understandable.

      • +
      • noun_translate (bool, optional) – If a proper noun should be translated or +not. By default they will not, allowing for e.g. the names of characters +to be understandable. A ‘noun’ is identified as a capitalized word +not at the start of a sentence. This simple metric means that names +starting a sentence always will be translated (- but hey, maybe +the fantasy language just never uses a noun at the beginning of +sentences, who knows?)

      • noun_prefix (str, optional) – A prefix to go before every noun in this language (if any).

      • noun_postfix (str, optuonal) – A postfix to go after every noun @@ -379,7 +412,6 @@ means fully obscured.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -396,6 +428,7 @@ means fully obscured.

        +
        develop branch
        @@ -266,7 +267,10 @@ langname can be None.

        Raises
        -

        rplanguage.LanguageError – If an invalid language was specified.

        +

        Notes

        @@ -551,6 +555,11 @@ mechanism. This is useful for adding masks/hoods etc.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'command', 'tags': '', 'text': 'simple parent'}
        +
        +
        @@ -604,6 +613,11 @@ a different language.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': ':', 'category': 'general', 'key': 'emote', 'tags': '', 'text': '\n Emote an action, allowing dynamic replacement of\n text in the emote.\n\n Usage:\n emote text\n\n Example:\n emote /me looks around.\n emote With a flurry /me attacks /tall man with his sword.\n emote "Hello", /me says.\n\n Describes an event in the world. This allows the use of /ref\n markers to replace with the short descriptions or recognized\n strings of objects in the same room. These will be translated to\n emotes to match each person seeing it. Use "..." for saying\n things and langcode"..." without spaces to say something in\n a different language.\n\n '}
        +
        +
        @@ -647,6 +661,11 @@ a different language.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '\' "', 'category': 'general', 'key': 'say', 'tags': '', 'text': '\n speak as your character\n\n Usage:\n say <message>\n\n Talk to those in your current location.\n '}
        +
        +
        @@ -690,6 +709,11 @@ a different language.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'sdesc', 'tags': '', 'text': '\n Assign yourself a short description (sdesc).\n\n Usage:\n sdesc <short description>\n\n Assigns a short description to yourself.\n\n '}
        +
        +
        @@ -748,6 +772,11 @@ sdesc in the emote, regardless of who is seeing it.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'pose', 'tags': '', 'text': "\n Set a static pose\n\n Usage:\n pose <pose>\n pose default <pose>\n pose reset\n pose obj = <pose>\n pose default obj = <pose>\n pose reset obj =\n\n Examples:\n pose leans against the tree\n pose is talking to the barkeep.\n pose box = is sitting on the floor.\n\n Set a static pose. This is the end of a full sentence that starts\n with your sdesc. If no full stop is given, it will be added\n automatically. The default pose is the pose you get when using\n pose reset. Note that you can use sdescs/recogs to reference\n people in your pose, but these always appear as that person's\n sdesc in the emote, regardless of who is seeing it.\n\n "}
        +
        +
        @@ -773,7 +802,7 @@ Using the command without arguments will list all current recogs.

        -aliases = ['recognize', 'forget']
        +aliases = ['forget', 'recognize']
        @@ -798,6 +827,11 @@ Using the command without arguments will list all current recogs.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': 'forget recognize', 'category': 'general', 'key': 'recog', 'tags': '', 'text': '\n Recognize another person in the same room.\n\n Usage:\n recog\n recog sdesc as alias\n forget alias\n\n Example:\n recog tall man as Griatch\n forget griatch\n\n This will assign a personal alias for a person, or forget said alias.\n Using the command without arguments will list all current recogs.\n\n '}
        +
        +
        @@ -842,6 +876,11 @@ set in self.parse())

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': 'unmask', 'category': 'general', 'key': 'mask', 'tags': '', 'text': "\n Wear a mask\n\n Usage:\n mask <new sdesc>\n unmask\n\n This will put on a mask to hide your identity. When wearing\n a mask, your sdesc will be replaced by the sdesc you pick and\n people's recognitions of you will be disabled.\n\n "}
        +
        +
        @@ -1250,7 +1289,6 @@ the evennia.contrib.rplanguage module.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1267,6 +1305,7 @@ the evennia.contrib.rplanguage module.

        +
        develop branch
        @@ -91,7 +92,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -108,6 +108,7 @@ +
        develop branch
        @@ -126,7 +127,6 @@ compromised or taken down, losing your logs along with it is no help!).

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -143,6 +143,7 @@ compromised or taken down, losing your logs along with it is no help!).

        +
        develop branch
        @@ -165,7 +166,6 @@ writing to log. Recording cleartext password attempts is bad policy.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -182,6 +182,7 @@ writing to log. Recording cleartext password attempts is bad policy.

        +
        develop branch
        @@ -105,7 +106,6 @@ parsed from the Session object.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -122,6 +122,7 @@ parsed from the Session object.

        +
        develop branch
        @@ -94,7 +95,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -111,6 +111,7 @@ +
        develop branch
        @@ -180,6 +181,11 @@ unique.

        lock_storage = 'cmd:perm(open) or perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'building', 'key': 'open', 'tags': '', 'text': '\n open a new exit from the current room\n\n Usage:\n open <new exit>[;alias;alias..][:typeclass] [,<return exit>[;alias;..][:typeclass]]] = <destination>\n\n Handles the creation of exits. If a destination is given, the exit\n will point there. The <return exit> argument sets up an exit at the\n destination leading back to the current room. Destination name\n can be given both as a #dbref and a name, if that name is globally\n unique.\n\n '}
        +
        +
        @@ -223,6 +229,11 @@ close <door>

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'close', 'category': 'general', 'key': 'open', 'tags': '', 'text': '\n Open and close a door\n\n Usage:\n open <door>\n close <door>\n\n '}
        +
        + @@ -270,7 +281,6 @@ close <door>

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -287,6 +297,7 @@ close <door>

        +
        develop branch
        @@ -134,6 +135,11 @@ is assumed.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'setspeed', 'tags': '', 'text': "\n set your movement speed\n\n Usage:\n setspeed stroll|walk|run|sprint\n\n This will set your movement speed, determining how long time\n it takes to traverse exits. If no speed is set, 'walk' speed\n is assumed.\n "}
        +
        +
        @@ -173,6 +179,11 @@ stored deferred from the exit traversal above.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'stop', 'tags': '', 'text': '\n stop moving\n\n Usage:\n stop\n\n Stops the current movement, if any.\n '}
        +
        + @@ -220,7 +231,6 @@ stored deferred from the exit traversal above.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -237,6 +247,7 @@ stored deferred from the exit traversal above.

        +
        develop branch
        @@ -121,6 +122,11 @@ that NPC and give you options on what to talk about.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'talk', 'tags': '', 'text': '\n Talks to an npc\n\n Usage:\n talk\n\n This command is only available if a talkative non-player-character\n (NPC) is actually present. It will strike up a conversation with\n that NPC and give you options on what to talk about.\n '}
        +
        +
        @@ -227,7 +233,6 @@ the conversation defined above.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -244,6 +249,7 @@ the conversation defined above.

        +
        develop branch
        @@ -37,8 +38,406 @@
        -
        -

        evennia.contrib.test_traits

        +
        +

        evennia.contrib.test_traits

        +

        Unit test module for Trait classes.

        +
        +
        +class evennia.contrib.test_traits.TraitHandlerTest(methodName='runTest')[source]
        +

        Bases: evennia.contrib.test_traits._TraitHandlerBase

        +

        Testing for TraitHandler

        +
        +
        +setUp()[source]
        +

        Hook method for setting up the test fixture before exercising it.

        +
        + +
        +
        +test_add_trait()[source]
        +
        + +
        +
        +test_cache()[source]
        +

        Cache should not be set until first get

        +
        + +
        +
        +test_setting()[source]
        +

        Don’t allow setting stuff on traithandler

        +
        + +
        +
        +test_getting()[source]
        +

        Test we are getting data from the dbstore

        +
        + +
        +
        +test_all()[source]
        +

        Test all method

        +
        + +
        +
        +test_remove()[source]
        +

        Test remove method

        +
        + +
        +
        +test_clear()[source]
        +

        Test clear method

        +
        + +
        +
        +test_trait_db_connection()[source]
        +

        Test that updating a trait property actually updates value in db

        +
        + +
        + +
        +
        +class evennia.contrib.test_traits.TestTrait(methodName='runTest')[source]
        +

        Bases: evennia.contrib.test_traits._TraitHandlerBase

        +

        Test the base Trait class

        +
        +
        +setUp()[source]
        +

        Hook method for setting up the test fixture before exercising it.

        +
        + +
        +
        +test_init()[source]
        +
        + +
        +
        +test_validate_input__valid()[source]
        +

        Test valid validation input

        +
        + +
        +
        +test_validate_input__fail()[source]
        +

        Test failing validation

        +
        + +
        +
        +test_trait_getset()[source]
        +

        Get-set-del operations on trait

        +
        + +
        +
        +test_repr()[source]
        +
        + +
        + +
        +
        +class evennia.contrib.test_traits.TestTraitStatic(methodName='runTest')[source]
        +

        Bases: evennia.contrib.test_traits._TraitHandlerBase

        +

        Test for static Traits

        +
        +
        +setUp()[source]
        +

        Hook method for setting up the test fixture before exercising it.

        +
        + +
        +
        +test_init()[source]
        +
        + +
        +
        +test_value()[source]
        +

        value is base + mod

        +
        + +
        +
        +test_delete()[source]
        +

        Deleting resets to default.

        +
        + +
        + +
        +
        +class evennia.contrib.test_traits.TestTraitCounter(methodName='runTest')[source]
        +

        Bases: evennia.contrib.test_traits._TraitHandlerBase

        +

        Test for counter- Traits

        +
        +
        +setUp()[source]
        +

        Hook method for setting up the test fixture before exercising it.

        +
        + +
        +
        +test_init()[source]
        +
        + +
        +
        +test_value()[source]
        +

        value is current + mod, where current defaults to base

        +
        + +
        +
        +test_boundaries__minmax()[source]
        +

        Test range

        +
        + +
        +
        +test_boundaries__bigmod()[source]
        +

        add a big mod

        +
        + +
        +
        +test_boundaries__change_boundaries()[source]
        +

        Change boundaries after base/mod change

        +
        + +
        +
        +test_boundaries__disable()[source]
        +

        Disable and re-enable boundaries

        +
        + +
        +
        +test_boundaries__inverse()[source]
        +

        Set inverse boundaries - limited by base

        +
        + +
        +
        +test_current()[source]
        +

        Modifying current value

        +
        + +
        +
        +test_delete()[source]
        +

        Deleting resets to default.

        +
        + +
        +
        +test_percentage()[source]
        +

        Test percentage calculation

        +
        + +
        +
        +test_descs()[source]
        +

        Test descriptions

        +
        + +
        + +
        +
        +class evennia.contrib.test_traits.TestTraitCounterTimed(methodName='runTest')[source]
        +

        Bases: evennia.contrib.test_traits._TraitHandlerBase

        +

        Test for trait with timer component

        +
        +
        +setUp()[source]
        +

        Hook method for setting up the test fixture before exercising it.

        +
        + +
        +
        +test_timer_rate(mock_time)[source]
        +

        Test time stepping

        +
        + +
        +
        +test_timer_ratetarget(mock_time)[source]
        +

        test ratetarget

        +
        + +
        + +
        +
        +class evennia.contrib.test_traits.TestTraitGauge(methodName='runTest')[source]
        +

        Bases: evennia.contrib.test_traits._TraitHandlerBase

        +
        +
        +setUp()[source]
        +

        Hook method for setting up the test fixture before exercising it.

        +
        + +
        +
        +test_init()[source]
        +
        + +
        +
        +test_value()[source]
        +

        value is current, where current defaults to base + mod

        +
        + +
        +
        +test_boundaries__minmax()[source]
        +

        Test range

        +
        + +
        +
        +test_boundaries__bigmod()[source]
        +

        add a big mod

        +
        + +
        +
        +test_boundaries__change_boundaries()[source]
        +

        Change boundaries after current change

        +
        + +
        +
        +test_boundaries__disable()[source]
        +

        Disable and re-enable boundary

        +
        + +
        +
        +test_boundaries__inverse()[source]
        +

        Try to set reversed boundaries

        +
        + +
        +
        +test_current()[source]
        +

        Modifying current value

        +
        + +
        +
        +test_delete()[source]
        +

        Deleting resets to default.

        +
        + +
        +
        +test_percentage()[source]
        +

        Test percentage calculation

        +
        + +
        +
        +test_descs()[source]
        +

        Test descriptions

        +
        + +
        + +
        +
        +class evennia.contrib.test_traits.TestTraitGaugeTimed(methodName='runTest')[source]
        +

        Bases: evennia.contrib.test_traits._TraitHandlerBase

        +

        Test for trait with timer component

        +
        +
        +setUp()[source]
        +

        Hook method for setting up the test fixture before exercising it.

        +
        + +
        +
        +test_timer_rate(mock_time)[source]
        +

        Test time stepping

        +
        + +
        +
        +test_timer_ratetarget(mock_time)[source]
        +

        test ratetarget

        +
        + +
        + +
        +
        +class evennia.contrib.test_traits.TestNumericTraitOperators(methodName='runTest')[source]
        +

        Bases: django.test.testcases.TestCase

        +

        Test case for numeric magic method implementations.

        +
        +
        +setUp()[source]
        +

        Hook method for setting up the test fixture before exercising it.

        +
        + +
        +
        +tearDown()[source]
        +

        Hook method for deconstructing the test fixture after testing it.

        +
        + +
        +
        +test_pos_shortcut()[source]
        +

        overridden unary + operator returns value property

        +
        + +
        +
        +test_add_traits()[source]
        +

        test addition of Trait objects

        +
        + +
        +
        +test_sub_traits()[source]
        +

        test subtraction of Trait objects

        +
        + +
        +
        +test_mul_traits()[source]
        +

        test multiplication of Trait objects

        +
        + +
        +
        +test_floordiv()[source]
        +

        test floor division of Trait objects

        +
        + +
        +
        +test_comparisons_traits()[source]
        +

        test equality comparison between Trait objects

        +
        + +
        +
        +test_comparisons_numeric()[source]
        +

        equality comparisons between Trait and numeric

        +
        + +
        +
        @@ -84,7 +483,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +499,7 @@ +
        develop branch
        @@ -37,8 +38,811 @@
        -
        -

        evennia.contrib.traits

        +
        +

        evennia.contrib.traits

        +

        Traits

        +

        Whitenoise 2014, Ainneve contributors, +Griatch 2020

        +

        A Trait represents a modifiable property on (usually) a Character. They can +be used to represent everything from attributes (str, agi etc) to skills +(hunting 10, swords 14 etc) and dynamically changing things like HP, XP etc.

        +

        Traits use Evennia Attributes under the hood, making them persistent (they survive +a server reload/reboot).

        +
        +

        Adding Traits to a typeclass

        +

        To access and manipulate traits on an entity, its Typeclass needs to have a +TraitHandler assigned it. Usually, the handler is made available as .traits +(in the same way as .tags or .attributes). It’s recommended to do this +using Evennia’s lazy_property (which basically just means it’s not +initialized until it’s actually accessed).

        +

        Here’s an example for adding the TraitHandler to the base Object class:

        +
        # mygame/typeclasses/objects.py
        +
        +from evennia import DefaultObject
        +from evennia.utils import lazy_property
        +from evennia.contrib.traits import TraitHandler
        +
        +# ...
        +
        +class Object(DefaultObject):
        +    ...
        +    @lazy_property
        +    def traits(self):
        +        # this adds the handler as .traits
        +        return TraitHandler(self)
        +
        +
        +
        +
        +

        Using traits

        +

        A trait is added to the traithandler, after which one can access it +as a property on the handler (similarly to how you can do .db.attrname for Attributes +in Evennia).

        +
        # this is an example using the "static" trait, described below
        +
        +>>> obj.traits.add("hunting", "Hunting Skill", trait_type="static", base=4)
        +>>> obj.traits.hunting.value
        +4
        +>>> obj.traits.hunting.value += 5
        +>>> obj.traits.hunting.value
        +9
        +>>> obj.traits.add("hp", "Health", trait_type="gauge", min=0, max=100)
        +>>> obj.traits.hp.value
        +100
        +>>> obj.traits.hp -= 200
        +>>> obj.traits.hp.value
        +0
        +>>> obj.traits.hp.reset()
        +>>> obj.traits.hp.value
        +100
        +# you can also access property with getitem
        +>>> obj.traits.hp["value"]
        +100
        +# you can store arbitrary data persistently as well
        +>>> obj.traits.hp.effect = "poisoned!"
        +>>> obj.traits.hp.effect
        +"poisoned!"
        +
        +
        +

        When adding the trait, you supply the name of the property (hunting) along +with a more human-friendly name (“Hunting Skill”). The latter will show if you +print the trait etc. The trait_type is important, this specifies which type +of trait this is.

        +
        +
        +

        Trait types

        +

        All default traits have a read-only .value property that shows the relevant or +‘current’ value of the trait. Exactly what this means depends on the type of trait.

        +

        Traits can also be combined to do arithmetic with their .value, if both have a +compatible type.

        +
        >>> trait1 + trait2
        +54
        +>>> trait1.value
        +3
        +>>> trait1 + 2
        +>>> trait1.value
        +5
        +
        +
        +

        Two numerical traits can also be compared (bigger-than etc), which is useful in +all sorts of rule-resolution.

        +
        if trait1 > trait2:
        +    # do stuff
        +
        +
        +
        +
        +

        Static trait

        +

        value = base + mod

        +

        The static trait has a base value and an optional mod-ifier. A typical use +of a static trait would be a Strength stat or Skill value. That is, something +that varies slowly or not at all, and which may be modified in-place.

        +
        >>> obj.traits.add("str", "Strength", trait_type="static", base=10, mod=2)
        +>>> obj.traits.mytrait.value
        +12   # base + mod
        +>>> obj.traits.mytrait.base += 2
        +>>> obj.traits.mytrait.mod += 1
        +>>> obj.traits.mytrait.value
        +15
        +>>> obj.traits.mytrait.mod = 0
        +>>> obj.traits.mytrait.value
        +12
        +
        +
        +
        +

        Counter

        +
        min/unset     base    base+mod                       max/unset
        +|--------------|--------|---------X--------X------------|
        +                            current   value
        +                                      = current
        +                                      + mod
        +
        +
        +

        A counter describes a value that can move from a base. The .current property +is the thing usually modified. It starts at the .base. One can also add a +modifier, which will both be added to the base and to current (forming +.value). The min/max of the range are optional, a boundary set to None will +remove it. A suggested use for a Counter Trait would be to track skill values.

        +
        >>> obj.traits.add("hunting", "Hunting Skill", trait_type="counter",
        +                   base=10, mod=1, min=0, max=100)
        +>>> obj.traits.hunting.value
        +11  # current starts at base + mod
        +>>> obj.traits.hunting.current += 10
        +>>> obj.traits.hunting.value
        +21
        +# reset back to base+mod by deleting current
        +>>> del obj.traits.hunting.current
        +>>> obj.traits.hunting.value
        +11
        +>>> obj.traits.hunting.max = None  # removing upper bound
        +
        +
        +

        Counters have some extra properties:

        +
        +

        .descs

        +

        The descs property is a dict {upper_bound:text_description}. This allows for easily +storing a more human-friendly description of the current value in the +interval. Here is an example for skill values between 0 and 10:

        +
        {0: "unskilled", 1: "neophyte", 5: "trained", 7: "expert", 9: "master"}
        +
        +
        +

        The keys must be supplied from smallest to largest. Any values below the lowest and above the +highest description will be considered to be included in the closest description slot. +By calling .desc() on the Counter, will you get the text matching the current value +value.

        +
        # (could also have passed descs= to traits.add())
        +>>> obj.traits.hunting.descs = {
        +    0: "unskilled", 10: "neophyte", 50: "trained", 70: "expert", 90: "master"}
        +>>> obj.traits.hunting.value
        +11
        +>>> obj.traits.hunting.desc()
        +"neophyte"
        +>>> obj.traits.hunting.current += 60
        +>>> obj.traits.hunting.value
        +71
        +>>> obj.traits.hunting.desc()
        +"expert"
        +
        +
        +
        +
        +

        .rate

        +

        The rate property defaults to 0. If set to a value different from 0, it +allows the trait to change value dynamically. This could be used for example +for an attribute that was temporarily lowered but will gradually (or abruptly) +recover after a certain time. The rate is given as change of the current +.value per-second, and this will still be restrained by min/max boundaries, +if those are set.

        +

        It is also possible to set a .ratetarget, for the auto-change to stop at +(rather than at the min/max boundaries). This allows the value to return to +a previous value.

        +
        >>> obj.traits.hunting.value
        +71
        +>>> obj.traits.hunting.ratetarget = 71
        +# debuff hunting for some reason
        +>>> obj.traits.hunting.current -= 30
        +>>> obj.traits.hunting.value
        +41
        +>>> obj.traits.hunting.rate = 1  # 1/s increase
        +# Waiting 5s
        +>>> obj.traits.hunting.value
        +46
        +# Waiting 8s
        +>>> obj.traits.hunting.value
        +54
        +# Waiting 100s
        +>>> obj.traits.hunting.value
        +71    # we have stopped at the ratetarget
        +>>> obj.traits.hunting.rate = 0  # disable auto-change
        +
        +
        +

        Note that if .rate is a non-integer, the resulting .value (at least until it +reaches a boundary or rate-target) will also come out a float (so you can get a +very exact value at the current time). If you expect an integer, you must run +int() (or something like round()) on the result yourself.

        +
        +
        +

        .percent()

        +

        If both min and max are defined, the .percent() method of the trait will +return the value as a percentage.

        +
        >>> obj.traits.hunting.percent()
        +"71.0%"
        +>>> obj.traits.hunting.percent(formatting=None)
        +71.0
        +
        +
        +
        +
        +
        +

        Gauge

        +

        This emulates a [fuel-] gauge that empties from a base+mod value.

        +
        min/0                                            max=base+mod
        + |-----------------------X---------------------------|
        +                       value
        +                      = current
        +
        +
        +

        The .current value will start from a full gauge. The .max property is +read-only and is set by .base + .mod. So contrary to a Counter, the +.mod modifier only applies to the max value of the gauge and not the current +value. The minimum bound defaults to 0 if not set explicitly.

        +

        This trait is useful for showing commonly depletable resources like health, +stamina and the like.

        +
        >>> obj.traits.add("hp", "Health", trait_type="gauge", base=100)
        +>>> obj.traits.hp.value  # (or .current)
        +100
        +>>> obj.traits.hp.mod = 10
        +>>> obj.traits.hp.value
        +110
        +>>> obj.traits.hp.current -= 30
        +>>> obj.traits.hp.value
        +80
        +
        +
        +

        The Gauge trait is subclass of the Counter, so you have access to the same +methods and properties where they make sense. So gauges can also have a +.descs dict to describe the intervals in text, and can use .percent() to +get how filled it is as a percentage etc.

        +

        The .rate is particularly relevant for gauges - useful for everything +from poison slowly draining your health, to resting gradually increasing it.

        +
        +
        +

        Trait

        +

        A single value of any type.

        +

        This is the ‘base’ Trait, meant to inherit from if you want to invent +trait-types from scratch (most of the time you’ll probably inherit from some of +the more advanced trait-type classes though). A Trait**s **.value can be +anything (that can be stored in an Attribute) and if it’s a integer/float you +can do arithmetic with it, but otherwise it acts just like a glorified +Attribute.

        +
        >>> obj.traits.add("mytrait", "My Trait", trait_type="trait", value=30)
        +>>> obj.traits.mytrait.value
        +30
        +>>> obj.traits.mytrait.value = "stringvalue"
        +>>> obj.traits.mytrait.value
        +"stringvalue"
        +
        +
        +
        +
        +
        +

        Expanding with your own Traits

        +

        A Trait is a class inhering from evennia.contrib.traits.Trait (or from one of +the existing Trait classes).

        +
        # in a file, say, 'mygame/world/traits.py'
        +
        +from evennia.contrib.traits import StaticTrait
        +
        +class RageTrait(StaticTrait):
        +
        +    trait_type = "rage"
        +    default_keys = {
        +        "rage": 0
        +    }
        +
        +    def berserk(self):
        +        self.mod = 100
        +
        +    def sedate(self):
        +        self.mod = 0
        +
        +
        +

        Above is an example custom-trait-class “rage” that stores a property “rage” on +itself, with a default value of 0. This has all the functionality of a Trait - +for example, if you do del on the rage property, it will be set back to its +default (0). Above we also added some helper methods.

        +

        To add your custom RageTrait to Evennia, add the following to your settings file +(assuming your class is in mygame/world/traits.py):

        +
        TRAIT_CLASS_PATHS = ["world.traits.RageTrait"]
        +
        +
        +

        Reload the server and you should now be able to use your trait:

        +
        >>> obj.traits.add("mood", "A dark mood", rage=30, trait_type='rage')
        +>>> obj.traits.mood.rage
        +30
        +
        +
        +
        +
        +
        +exception evennia.contrib.traits.TraitException(msg)[source]
        +

        Bases: RuntimeError

        +

        Base exception class raised by Trait objects.

        +
        +
        Parameters
        +

        msg (str) – informative error message

        +
        +
        +
        +
        +__init__(msg)[source]
        +

        Initialize self. See help(type(self)) for accurate signature.

        +
        + +
        + +
        +
        +class evennia.contrib.traits.MandatoryTraitKey[source]
        +

        Bases: object

        +

        This represents a required key that must be +supplied when a Trait is initialized. It’s used +by Trait classes when defining their required keys.

        +
        + +
        +
        +class evennia.contrib.traits.TraitHandler(obj, db_attribute_key='traits', db_attribute_category='traits')[source]
        +

        Bases: object

        +

        Factory class that instantiates Trait objects.

        +
        +
        +__init__(obj, db_attribute_key='traits', db_attribute_category='traits')[source]
        +

        Initialize the handler and set up its internal Attribute-based storage.

        +
        +
        Parameters
        +
          +
        • obj (Object) – Parent Object typeclass for this TraitHandler

        • +
        • db_attribute_key (str) – Name of the DB attribute for trait data storage

        • +
        +
        +
        +
        + +
        +
        +property all
        +

        Get all trait keys in this handler.

        +
        +
        Returns
        +

        list – All Trait keys.

        +
        +
        +
        + +
        +
        +get(trait_key)[source]
        +
        +
        Parameters
        +

        trait_key (str) – key from the traits dict containing config data.

        +
        +
        Returns
        +

        (Trait or None) – named Trait class or None if trait key +is not found in traits collection.

        +
        +
        +
        + +
        +
        +add(trait_key, name=None, trait_type='static', force=True, **trait_properties)[source]
        +

        Create a new Trait and add it to the handler.

        +
        +
        Parameters
        +
          +
        • trait_key (str) – This is the name of the property that will be made +available on this handler (example ‘hp’).

        • +
        • name (str, optional) – Name of the Trait, like “Health”. If +not given, will use trait_key starting with a capital letter.

        • +
        • trait_type (str, optional) – One of ‘static’, ‘counter’ or ‘gauge’.

        • +
        • force_add (bool) – If set, create a new Trait even if a Trait with +the same trait_key already exists.

        • +
        • trait_properties (dict) – These will all be use to initialize +the new trait. See the properties class variable on each +Trait class to see which are required.

        • +
        +
        +
        Raises
        +

        TraitException – If specifying invalid values for the given Trait, +the trait_type is not recognized, or an existing trait +already exists (and force is unset).

        +
        +
        +
        + +
        +
        +remove(trait_key)[source]
        +

        Remove a Trait from the handler’s parent object.

        +
        +
        Parameters
        +

        trait_key (str) – The name of the trait to remove.

        +
        +
        +
        + +
        +
        +clear()[source]
        +

        Remove all Traits from the handler’s parent object.

        +
        + +
        + +
        +
        +class evennia.contrib.traits.Trait(trait_data)[source]
        +

        Bases: object

        +

        Represents an object or Character trait. This simple base is just +storing anything in it’s ‘value’ property, so it’s pretty much just a +different wrapper to an Attribute. It does no type-checking of what is +stored.

        +
        +

        Note

        +

        See module docstring for configuration details.

        +
        +

        value

        +
        +
        +trait_type = 'trait'
        +
        + +
        +
        +default_keys = {'value': None}
        +
        + +
        +
        +allow_extra_properties = True
        +
        + +
        +
        +__init__(trait_data)[source]
        +

        This both initializes and validates the Trait on creation. It must +raise exception if validation fails. The TraitHandler will call this +when the trait is furst added, to make sure it validates before +storing.

        +
        +
        Parameters
        +

        trait_data (any) – Any pickle-able values to store with this trait. +This must contain any cls.default_keys that do not have a default +value in cls.data_default_values. Any extra kwargs will be made +available as extra properties on the Trait, assuming the class +variable allow_extra_properties is set.

        +
        +
        Raises
        +

        TraitException – If input-validation failed.

        +
        +
        +
        + +
        +
        +static validate_input(cls, trait_data)[source]
        +

        Validate input

        +
        +
        Parameters
        +

        trait_data (dict or _SaverDict) – Data to be used for +initialization of this trait.

        +
        +
        Returns
        +

        dict

        +
        +
        Validated data, possibly complemented with default

        values from default_keys.

        +
        +
        +

        +
        +
        Raises
        +

        TraitException – If finding unset keys without a default.

        +
        +
        +
        + +
        +
        +property name
        +

        Display name for the trait.

        +
        + +
        +
        +property key
        +

        Display name for the trait.

        +
        + +
        +
        +property value
        +

        Store a value

        +
        + +
        + +
        +
        +class evennia.contrib.traits.StaticTrait(trait_data)[source]
        +

        Bases: evennia.contrib.traits.Trait

        +

        Static Trait. This is a single value with a modifier, +with no concept of a ‘current’ value.

        +

        value = base + mod

        +
        +
        +trait_type = 'static'
        +
        + +
        +
        +default_keys = {'base': 0, 'mod': 0}
        +
        + +
        +
        +property mod
        +

        The trait’s modifier.

        +
        + +
        +
        +property value
        +

        The value of the Trait

        +
        + +
        + +
        +
        +class evennia.contrib.traits.CounterTrait(trait_data)[source]
        +

        Bases: evennia.contrib.traits.Trait

        +

        Counter Trait.

        +

        This includes modifications and min/max limits as well as the notion of a +current value. The value can also be reset to the base value.

        +
        +
        min/unset base base+mod max/unset
        +
        |--------------|——–|---------X--------X------------|
        +
        current value

        = current ++ mod

        +
        +
        +
        +
        +
        +
        +
          +
        • value = current + mod, starts at base + mod

        • +
        • if min or max is None, there is no upper/lower bound (default)

        • +
        • if max is set to “base”, max will be equal ot base+mod

        • +
        • descs are used to optionally describe each value interval. +The desc of the current value value can then be retrieved +with .desc(). The property is set as {lower_bound_inclusive:desc} +and should be given smallest-to-biggest. For example, for +a skill rating between 0 and 10:

          +
          +
          +
          {0: “unskilled”,

          1: “neophyte”, +5: “traited”, +7: “expert”, +9: “master”}

          +
          +
          +
          +
        • +
        • rate/ratetarget are optional settings to include a rate-of-change +of the current value. This is calculated on-demand and allows for +describing a value that is gradually growing smaller/bigger. The +increase will stop when either reaching a boundary (if set) or +ratetarget. Setting the rate to 0 (default) stops any change.

        • +
        +
        +
        +trait_type = 'counter'
        +
        + +
        +
        +default_keys = {'base': 0, 'descs': None, 'max': None, 'min': None, 'mod': 0, 'rate': 0, 'ratetarget': None}
        +
        + +
        +
        +static validate_input(cls, trait_data)[source]
        +

        Add extra validation for descs

        +
        + +
        +
        +property base
        +
        + +
        +
        +property mod
        +
        + +
        +
        +property min
        +
        + +
        +
        +property max
        +
        + +
        +
        +property current
        +

        The current value of the Trait. This does not have .mod added.

        +
        + +
        +
        +property value
        +

        The value of the Trait (current + mod)

        +
        + +
        +
        +property ratetarget
        +
        + +
        +
        +percent(formatting='{:3.1f}%')[source]
        +

        Return the current value as a percentage.

        +
        +
        Parameters
        +

        formatting (str, optional) – Should contain a +format-tag which will receive the value. If +this is set to None, the raw float will be +returned.

        +
        +
        Returns
        +

        float or str

        +
        +
        Depending of if a formatting string

        is supplied or not.

        +
        +
        +

        +
        +
        +
        + +
        +
        +reset()[source]
        +

        Resets current property equal to base value.

        +
        + +
        +
        +desc()[source]
        +

        Retrieve descriptions of the current value, if available.

        +

        This must be a mapping {upper_bound_inclusive: text}, +ordered from small to big. Any value above the highest +upper bound will be included as being in the highest bound. +rely on Python3.7+ dicts retaining ordering to let this +describe the interval.

        +
        +
        Returns
        +

        str

        +
        +
        The description describing the value value.

        If not found, returns the empty string.

        +
        +
        +

        +
        +
        +
        + +
        + +
        +
        +class evennia.contrib.traits.GaugeTrait(trait_data)[source]
        +

        Bases: evennia.contrib.traits.CounterTrait

        +

        Gauge Trait.

        +

        This emulates a gauge-meter that empties from a base+mod value.

        +
        +
        min/0 max=base+mod
        +
        |-----------------------X---------------------------|
        +

        value

        +
        +

        = current

        +
        +
        +
        +
        +
          +
        • min defaults to 0

        • +
        • max value is always base + mad

        • +
        • .max is an alias of .base

        • +
        • value = current and varies from min to max.

        • +
        • +
          descs is a mapping {upper_bound_inclusive: desc}. These

          are checked with .desc() and can be retrieve a text +description for a given current value.

          +

          For example, this could be used to describe health +values between 0 and 100:

          +
          +
          +
          {0: “Dead”

          10: “Badly hurt”, +30: “Bleeding”, +50: “Hurting”, +90: “Healthy”}

          +
          +
          +
          +
          +
          +
        • +
        +
        +
        +trait_type = 'gauge'
        +
        + +
        +
        +default_keys = {'base': 0, 'descs': None, 'min': 0, 'mod': 0, 'rate': 0, 'ratetarget': None}
        +
        + +
        +
        +property base
        +
        + +
        +
        +property mod
        +
        + +
        +
        +property min
        +
        + +
        +
        +property max
        +

        The max is always base + mod.

        +
        + +
        +
        +property current
        +

        The current value of the gauge.

        +
        + +
        +
        +property value
        +

        The value of the trait

        +
        + +
        +
        +percent(formatting='{:3.1f}%')[source]
        +

        Return the current value as a percentage.

        +
        +
        Parameters
        +

        formatting (str, optional) – Should contain a +format-tag which will receive the value. If +this is set to None, the raw float will be +returned.

        +
        +
        Returns
        +

        float or str

        +
        +
        Depending of if a formatting string

        is supplied or not.

        +
        +
        +

        +
        +
        +
        + +
        +
        +reset()[source]
        +

        Fills the gauge to its maximum allowed by base + mod

        +
        + +
        + +
        @@ -61,6 +865,28 @@
        +

        Table of Contents

        + +
        -
        @@ -101,6 +926,7 @@ +
        develop branch
        @@ -370,6 +371,11 @@ set in self.parse())

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'namecolor', 'tags': '', 'text': '\n Set or remove a special color on your name. Just an example for the\n easy menu selection tree contrib.\n '}
        +
        +
        @@ -434,7 +440,6 @@ to determine the color the player chose.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -451,6 +456,7 @@ to determine the color the player chose.

        +
        develop branch
        @@ -93,7 +94,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -110,6 +110,7 @@ +
        develop branch
        @@ -501,6 +502,11 @@ When it’s your turn, you can attack other characters.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'fight', 'tags': '', 'text': "\n Starts a fight with everyone in the same room as you.\n\n Usage:\n fight\n\n When you start a fight, everyone in the room who is able to\n fight is added to combat, and a turn order is randomly rolled.\n When it's your turn, you can attack other characters.\n "}
        +
        +
        @@ -540,6 +546,11 @@ a chance to hit, and if successful, will deal damage.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'attack', 'tags': '', 'text': '\n Attacks another character.\n\n Usage:\n attack <target>\n\n When in a fight, you may attack another character. The attack has\n a chance to hit, and if successful, will deal damage.\n '}
        +
        +
        @@ -560,7 +571,7 @@ if there are still any actions you can take.

        -aliases = ['hold', 'wait']
        +aliases = ['wait', 'hold']
        @@ -579,6 +590,11 @@ if there are still any actions you can take.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': 'wait hold', 'category': 'combat', 'key': 'pass', 'tags': '', 'text': '\n Passes on your turn.\n\n Usage:\n pass\n\n When in a fight, you can use this command to end your turn early, even\n if there are still any actions you can take.\n '}
        +
        +
        @@ -619,6 +635,11 @@ fight ends.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': 'spare', 'category': 'combat', 'key': 'disengage', 'tags': '', 'text': "\n Passes your turn and attempts to end combat.\n\n Usage:\n disengage\n\n Ends your turn early and signals that you're trying to end\n the fight. If all participants in a fight disengage, the\n fight ends.\n "}
        +
        +
        @@ -658,6 +679,11 @@ rest if you’re not in a fight.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'rest', 'tags': '', 'text': "\n Recovers damage.\n\n Usage:\n rest\n\n Resting recovers your HP to its maximum, but you can only\n rest if you're not in a fight.\n "}
        +
        +
        @@ -699,6 +725,11 @@ topics related to the game.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '?', 'category': 'general', 'key': 'help', 'tags': '', 'text': '\n View help or a list of topics\n\n Usage:\n help <topic or command>\n help list\n help all\n\n This will search for help on commands and other\n topics related to the game.\n '}
        +
        +
        @@ -769,7 +800,6 @@ topics related to the game.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -786,6 +816,7 @@ topics related to the game.

        +
        develop branch
        @@ -618,6 +619,11 @@ When it’s your turn, you can attack other characters.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'fight', 'tags': '', 'text': "\n Starts a fight with everyone in the same room as you.\n\n Usage:\n fight\n\n When you start a fight, everyone in the room who is able to\n fight is added to combat, and a turn order is randomly rolled.\n When it's your turn, you can attack other characters.\n "}
        +
        +
        @@ -657,6 +663,11 @@ a chance to hit, and if successful, will deal damage.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'attack', 'tags': '', 'text': '\n Attacks another character.\n\n Usage:\n attack <target>\n\n When in a fight, you may attack another character. The attack has\n a chance to hit, and if successful, will deal damage.\n '}
        +
        +
        @@ -677,7 +688,7 @@ if there are still any actions you can take.

        -aliases = ['hold', 'wait']
        +aliases = ['wait', 'hold']
        @@ -696,6 +707,11 @@ if there are still any actions you can take.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': 'wait hold', 'category': 'combat', 'key': 'pass', 'tags': '', 'text': '\n Passes on your turn.\n\n Usage:\n pass\n\n When in a fight, you can use this command to end your turn early, even\n if there are still any actions you can take.\n '}
        +
        +
        @@ -736,6 +752,11 @@ fight ends.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': 'spare', 'category': 'combat', 'key': 'disengage', 'tags': '', 'text': "\n Passes your turn and attempts to end combat.\n\n Usage:\n disengage\n\n Ends your turn early and signals that you're trying to end\n the fight. If all participants in a fight disengage, the\n fight ends.\n "}
        +
        +
        @@ -775,6 +796,11 @@ rest if you’re not in a fight.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'rest', 'tags': '', 'text': "\n Recovers damage.\n\n Usage:\n rest\n\n Resting recovers your HP to its maximum, but you can only\n rest if you're not in a fight.\n "}
        +
        +
        @@ -816,6 +842,11 @@ topics related to the game.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '?', 'category': 'general', 'key': 'help', 'tags': '', 'text': '\n View help or a list of topics\n\n Usage:\n help <topic or command>\n help list\n help all\n\n This will search for help on commands and other\n topics related to the game.\n '}
        +
        +
        @@ -859,6 +890,11 @@ currently wielding.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'wield', 'tags': '', 'text': '\n Wield a weapon you are carrying\n\n Usage:\n wield <weapon>\n\n Select a weapon you are carrying to wield in combat. If\n you are already wielding another weapon, you will switch\n to the weapon you specify instead. Using this command in\n combat will spend your action for your turn. Use the\n "unwield" command to stop wielding any weapon you are\n currently wielding.\n '}
        +
        +
        @@ -898,6 +934,11 @@ weapon you are currently wielding and become unarmed.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'unwield', 'tags': '', 'text': '\n Stop wielding a weapon.\n\n Usage:\n unwield\n\n After using this command, you will stop wielding any\n weapon you are currently wielding and become unarmed.\n '}
        +
        +
        @@ -938,6 +979,11 @@ command to remove any armor you are wearing.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'don', 'tags': '', 'text': '\n Don armor that you are carrying\n\n Usage:\n don <armor>\n\n Select armor to wear in combat. You can\'t use this\n command in the middle of a fight. Use the "doff"\n command to remove any armor you are wearing.\n '}
        +
        +
        @@ -978,6 +1024,11 @@ You can’t use this command in combat.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'doff', 'tags': '', 'text': "\n Stop wearing armor.\n\n Usage:\n doff\n\n After using this command, you will stop wearing any\n armor you are currently using and become unarmored.\n You can't use this command in combat.\n "}
        +
        +
        @@ -1048,7 +1099,6 @@ You can’t use this command in combat.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1065,6 +1115,7 @@ You can’t use this command in combat.

        +
        develop branch
        @@ -652,6 +653,11 @@ When it’s your turn, you can attack other characters.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'fight', 'tags': '', 'text': "\n Starts a fight with everyone in the same room as you.\n\n Usage:\n fight\n\n When you start a fight, everyone in the room who is able to\n fight is added to combat, and a turn order is randomly rolled.\n When it's your turn, you can attack other characters.\n "}
        +
        +
        @@ -691,6 +697,11 @@ a chance to hit, and if successful, will deal damage.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'attack', 'tags': '', 'text': '\n Attacks another character.\n\n Usage:\n attack <target>\n\n When in a fight, you may attack another character. The attack has\n a chance to hit, and if successful, will deal damage.\n '}
        +
        +
        @@ -711,7 +722,7 @@ if there are still any actions you can take.

        -aliases = ['hold', 'wait']
        +aliases = ['wait', 'hold']
        @@ -730,6 +741,11 @@ if there are still any actions you can take.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': 'wait hold', 'category': 'combat', 'key': 'pass', 'tags': '', 'text': '\n Passes on your turn.\n\n Usage:\n pass\n\n When in a fight, you can use this command to end your turn early, even\n if there are still any actions you can take.\n '}
        +
        +
        @@ -770,6 +786,11 @@ fight ends.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': 'spare', 'category': 'combat', 'key': 'disengage', 'tags': '', 'text': "\n Passes your turn and attempts to end combat.\n\n Usage:\n disengage\n\n Ends your turn early and signals that you're trying to end\n the fight. If all participants in a fight disengage, the\n fight ends.\n "}
        +
        +
        @@ -809,6 +830,11 @@ rest if you’re not in a fight.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'rest', 'tags': '', 'text': "\n Recovers damage.\n\n Usage:\n rest\n\n Resting recovers your HP to its maximum, but you can only\n rest if you're not in a fight.\n "}
        +
        +
        @@ -850,6 +876,11 @@ topics related to the game.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '?', 'category': 'general', 'key': 'help', 'tags': '', 'text': '\n View help or a list of topics\n\n Usage:\n help <topic or command>\n help list\n help all\n\n This will search for help on commands and other\n topics related to the game.\n '}
        +
        +
        @@ -890,6 +921,11 @@ to attack others, and as such can only be used in combat.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'use', 'tags': '', 'text': '\n Use an item.\n\n Usage:\n use <item> [= target]\n\n An item can have various function - looking at the item may\n provide information as to its effects. Some items can be used\n to attack others, and as such can only be used in combat.\n '}
        +
        +
        @@ -1043,7 +1079,6 @@ items using the same function work differently.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1060,6 +1095,7 @@ items using the same function work differently.

        +
        develop branch
        @@ -524,6 +525,11 @@ When it’s your turn, you can attack other characters.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'fight', 'tags': '', 'text': "\n Starts a fight with everyone in the same room as you.\n\n Usage:\n fight\n\n When you start a fight, everyone in the room who is able to\n fight is added to combat, and a turn order is randomly rolled.\n When it's your turn, you can attack other characters.\n "}
        +
        +
        @@ -563,6 +569,11 @@ a chance to hit, and if successful, will deal damage.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'attack', 'tags': '', 'text': '\n Attacks another character.\n\n Usage:\n attack <target>\n\n When in a fight, you may attack another character. The attack has\n a chance to hit, and if successful, will deal damage.\n '}
        +
        +
        @@ -583,7 +594,7 @@ if there are still any actions you can take.

        -aliases = ['hold', 'wait']
        +aliases = ['wait', 'hold']
        @@ -602,6 +613,11 @@ if there are still any actions you can take.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': 'wait hold', 'category': 'combat', 'key': 'pass', 'tags': '', 'text': '\n Passes on your turn.\n\n Usage:\n pass\n\n When in a fight, you can use this command to end your turn early, even\n if there are still any actions you can take.\n '}
        +
        +
        @@ -642,6 +658,11 @@ fight ends.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': 'spare', 'category': 'combat', 'key': 'disengage', 'tags': '', 'text': "\n Passes your turn and attempts to end combat.\n\n Usage:\n disengage\n\n Ends your turn early and signals that you're trying to end\n the fight. If all participants in a fight disengage, the\n fight ends.\n "}
        +
        +
        @@ -695,6 +716,11 @@ fight ends.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'magic', 'key': 'learnspell', 'tags': '', 'text': "\n Learn a magic spell.\n\n Usage:\n learnspell <spell name>\n\n Adds a spell by name to your list of spells known.\n\n The following spells are provided as examples:\n\n |wmagic missile|n (3 MP): Fires three missiles that never miss. Can target\n up to three different enemies.\n\n |wflame shot|n (3 MP): Shoots a high-damage jet of flame at one target.\n\n |wcure wounds|n (5 MP): Heals damage on one target.\n\n |wmass cure wounds|n (10 MP): Like 'cure wounds', but can heal up to 5\n targets at once.\n\n |wfull heal|n (12 MP): Heals one target back to full HP.\n\n |wcactus conjuration|n (2 MP): Creates a cactus.\n "}
        +
        +
        @@ -742,6 +768,11 @@ function.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'magic', 'key': 'cast', 'tags': '', 'text': "\n Cast a magic spell that you know, provided you have the MP\n to spend on its casting.\n\n Usage:\n cast <spellname> [= <target1>, <target2>, etc...]\n\n Some spells can be cast on multiple targets, some can be cast\n on only yourself, and some don't need a target specified at all.\n Typing 'cast' by itself will give you a list of spells you know.\n "}
        +
        +
        @@ -781,6 +812,11 @@ only rest if you’re not in a fight.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'rest', 'tags': '', 'text': "\n Recovers damage and restores MP.\n\n Usage:\n rest\n\n Resting recovers your HP and MP to their maximum, but you can\n only rest if you're not in a fight.\n "}
        +
        +
        @@ -820,6 +856,11 @@ other targets in combat.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'status', 'tags': '', 'text': '\n Gives combat information.\n\n Usage:\n status\n\n Shows your current and maximum HP and your distance from\n other targets in combat.\n '}
        +
        +
        @@ -861,6 +902,11 @@ topics related to the game.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '?', 'category': 'general', 'key': 'help', 'tags': '', 'text': '\n View help or a list of topics\n\n Usage:\n help <topic or command>\n help list\n help all\n\n This will search for help on commands and other\n topics related to the game.\n '}
        +
        +
        @@ -982,7 +1028,6 @@ instead of creating objects directly.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -999,6 +1044,7 @@ instead of creating objects directly.

        +
        develop branch
        @@ -815,6 +816,11 @@ When it’s your turn, you can attack other characters.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'fight', 'tags': '', 'text': "\n Starts a fight with everyone in the same room as you.\n\n Usage:\n fight\n\n When you start a fight, everyone in the room who is able to\n fight is added to combat, and a turn order is randomly rolled.\n When it's your turn, you can attack other characters.\n "}
        +
        +
        @@ -856,6 +862,11 @@ you. Use the ‘approach’ command to get closer to a target.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'attack', 'tags': '', 'text': "\n Attacks another character in melee.\n\n Usage:\n attack <target>\n\n When in a fight, you may attack another character. The attack has\n a chance to hit, and if successful, will deal damage. You can only\n attack engaged targets - that is, targets that are right next to\n you. Use the 'approach' command to get closer to a target.\n "}
        +
        +
        @@ -898,6 +909,11 @@ nearby enemies.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'shoot', 'tags': '', 'text': "\n Attacks another character from range.\n\n Usage:\n shoot <target>\n\n When in a fight, you may shoot another character. The attack has\n a chance to hit, and if successful, will deal damage. You can attack\n any target in combat by shooting, but can't shoot if there are any\n targets engaged with you. Use the 'withdraw' command to retreat from\n nearby enemies.\n "}
        +
        +
        @@ -937,6 +953,11 @@ characters you are 0 spaces away from.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'approach', 'tags': '', 'text': '\n Approaches an object.\n\n Usage:\n approach <target>\n\n Move one space toward a character or object. You can only attack\n characters you are 0 spaces away from.\n '}
        +
        +
        @@ -975,6 +996,11 @@ characters you are 0 spaces away from.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'withdraw', 'tags': '', 'text': '\n Moves away from an object.\n\n Usage:\n withdraw <target>\n\n Move one space away from a character or object.\n '}
        +
        +
        @@ -995,7 +1021,7 @@ if there are still any actions you can take.

        -aliases = ['hold', 'wait']
        +aliases = ['wait', 'hold']
        @@ -1014,6 +1040,11 @@ if there are still any actions you can take.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': 'wait hold', 'category': 'combat', 'key': 'pass', 'tags': '', 'text': '\n Passes on your turn.\n\n Usage:\n pass\n\n When in a fight, you can use this command to end your turn early, even\n if there are still any actions you can take.\n '}
        +
        +
        @@ -1054,6 +1085,11 @@ fight ends.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': 'spare', 'category': 'combat', 'key': 'disengage', 'tags': '', 'text': "\n Passes your turn and attempts to end combat.\n\n Usage:\n disengage\n\n Ends your turn early and signals that you're trying to end\n the fight. If all participants in a fight disengage, the\n fight ends.\n "}
        +
        +
        @@ -1093,6 +1129,11 @@ rest if you’re not in a fight.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'rest', 'tags': '', 'text': "\n Recovers damage.\n\n Usage:\n rest\n\n Resting recovers your HP to its maximum, but you can only\n rest if you're not in a fight.\n "}
        +
        +
        @@ -1132,6 +1173,11 @@ other targets in combat.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'combat', 'key': 'status', 'tags': '', 'text': '\n Gives combat information.\n\n Usage:\n status\n\n Shows your current and maximum HP and your distance from\n other targets in combat.\n '}
        +
        +
        @@ -1173,6 +1219,11 @@ topics related to the game.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '?', 'category': 'general', 'key': 'help', 'tags': '', 'text': '\n View help or a list of topics\n\n Usage:\n help <topic or command>\n help list\n help all\n\n This will search for help on commands and other\n topics related to the game.\n '}
        +
        +
        @@ -1243,7 +1294,6 @@ topics related to the game.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1260,6 +1310,7 @@ topics related to the game.

        +
        develop branch
        @@ -139,7 +140,6 @@ a random check here so as to only return 33% of the time.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -156,6 +156,7 @@ a random check here so as to only return 33% of the time.

        +
        develop branch
        @@ -84,7 +85,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +101,7 @@ +
        develop branch
        @@ -93,7 +97,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -110,6 +113,7 @@ +
        develop branch
        @@ -37,8 +38,79 @@
        -
        -

        evennia.contrib.tutorial_examples.mirror

        +
        +

        evennia.contrib.tutorial_examples.mirror

        +

        TutorialMirror

        +

        A simple mirror object to experiment with.

        +
        +
        +class evennia.contrib.tutorial_examples.mirror.TutorialMirror(*args, **kwargs)[source]
        +

        Bases: evennia.objects.objects.DefaultObject

        +

        A simple mirror object that +- echoes back the description of the object looking at it +- echoes back whatever is being sent to its .msg - to the

        +
        +

        sender, if given, otherwise to the location of the mirror.

        +
        +
        +
        +return_appearance(looker, **kwargs)[source]
        +

        This formats the description of this object. Called by the ‘look’ command.

        +
        +
        Parameters
        +
          +
        • looker (Object) – Object doing the looking.

        • +
        • **kwargs (dict) – Arbitrary, optional arguments for users +overriding the call (unused by default).

        • +
        +
        +
        +
        + +
        +
        +msg(text=None, from_obj=None, **kwargs)[source]
        +

        Simply override .msg to echo back to the messenger or to the current +location.

        +
        +
        Parameters
        +
          +
        • text (str or tuple, optional) – The message to send. This +is treated internally like any send-command, so its +value can be a tuple if sending multiple arguments to +the text oob command.

        • +
        • from_obj (obj or iterable) – given, at_msg_send will be called. This value will be +passed on to the protocol. If iterable, will execute hook +on all entities in it.

        • +
        +
        +
        +
        + +
        +
        +exception DoesNotExist
        +

        Bases: evennia.objects.objects.DefaultObject.DoesNotExist

        +
        + +
        +
        +exception MultipleObjectsReturned
        +

        Bases: evennia.objects.objects.DefaultObject.MultipleObjectsReturned

        +
        + +
        +
        +path = 'evennia.contrib.tutorial_examples.mirror.TutorialMirror'
        +
        + +
        +
        +typename = 'TutorialMirror'
        +
        + +
        +
        @@ -84,7 +156,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +172,7 @@ +
        develop branch
        @@ -44,74 +45,627 @@ script.examples as well as commands.examples to make an interactive button typeclass.

        Create this button with

        -

        @create/drop examples.red_button.RedButton

        +

        create/drop red_button.RedButton

        Note that you must drop the button before you can see its messages!

        +
        +

        Technical

        +

        The button’s functionality is controlled by CmdSets that gets added and removed +depending on the ‘state’ the button is in.

        +
          +
        • Lid-closed state: In this state the button is covered by a glass cover and trying +to ‘push’ it will fail. You can ‘nudge’, ‘smash’ or ‘open’ the lid.

        • +
        • Lid-open state: In this state the lid is open but will close again after a certain +time. Using ‘push’ now will press the button and trigger the Blind-state.

        • +
        • Blind-state: In this mode you are blinded by a bright flash. This will affect your +normal commands like ‘look’ and help until the blindness wears off after a certain +time.

        • +
        +

        Timers are handled by persistent delays on the button. These are examples of +evennia.utils.utils.delay calls that wait a certain time before calling a method - +such as when closing the lid and un-blinding a character.

        +
        +
        +class evennia.contrib.tutorial_examples.red_button.CmdPushLidClosed(**kwargs)[source]
        +

        Bases: evennia.commands.command.Command

        +

        Push the red button (lid closed)

        +
        +
        Usage:

        push button

        +
        +
        +
        +
        +key = 'push button'
        +
        + +
        +
        +aliases = ['press button', 'press', 'push']
        +
        + +
        +
        +locks = 'cmd:all()'
        +
        + +
        +
        +func()[source]
        +

        This is the version of push used when the lid is closed.

        +

        An alternative would be to make a ‘push’ command in a default cmdset +that is always available on the button and then use if-statements to +check if the lid is open or closed.

        +
        + +
        +
        +help_category = 'general'
        +
        + +
        +
        +lock_storage = 'cmd:all()'
        +
        + +
        +
        +search_index_entry = {'aliases': 'press button press push', 'category': 'general', 'key': 'push button', 'tags': '', 'text': '\n Push the red button (lid closed)\n\n Usage:\n push button\n\n '}
        +
        + +
        + +
        +
        +class evennia.contrib.tutorial_examples.red_button.CmdNudge(**kwargs)[source]
        +

        Bases: evennia.commands.command.Command

        +

        Try to nudge the button’s lid.

        +
        +
        Usage:

        nudge lid

        +
        +
        +

        This command will have you try to push the lid of the button away.

        +
        +
        +key = 'nudge lid'
        +
        + +
        +
        +aliases = ['nudge']
        +
        + +
        +
        +locks = 'cmd:all()'
        +
        + +
        +
        +func()[source]
        +

        Nudge the lid. Random chance of success to open it.

        +
        + +
        +
        +help_category = 'general'
        +
        + +
        +
        +lock_storage = 'cmd:all()'
        +
        + +
        +
        +search_index_entry = {'aliases': 'nudge', 'category': 'general', 'key': 'nudge lid', 'tags': '', 'text': "\n Try to nudge the button's lid.\n\n Usage:\n nudge lid\n\n This command will have you try to push the lid of the button away.\n\n "}
        +
        + +
        + +
        +
        +class evennia.contrib.tutorial_examples.red_button.CmdSmashGlass(**kwargs)[source]
        +

        Bases: evennia.commands.command.Command

        +

        Smash the protective glass.

        +
        +
        Usage:

        smash glass

        +
        +
        +

        Try to smash the glass of the button.

        +
        +
        +key = 'smash glass'
        +
        + +
        +
        +aliases = ['break lid', 'smash lid', 'smash']
        +
        + +
        +
        +locks = 'cmd:all()'
        +
        + +
        +
        +func()[source]
        +

        The lid won’t open, but there is a small chance of causing the lamp to +break.

        +
        + +
        +
        +help_category = 'general'
        +
        + +
        +
        +lock_storage = 'cmd:all()'
        +
        + +
        +
        +search_index_entry = {'aliases': 'break lid smash lid smash', 'category': 'general', 'key': 'smash glass', 'tags': '', 'text': '\n Smash the protective glass.\n\n Usage:\n smash glass\n\n Try to smash the glass of the button.\n\n '}
        +
        + +
        + +
        +
        +class evennia.contrib.tutorial_examples.red_button.CmdOpenLid(**kwargs)[source]
        +

        Bases: evennia.commands.command.Command

        +

        open lid

        +
        +
        Usage:

        open lid

        +
        +
        +
        +
        +key = 'open lid'
        +
        + +
        +
        +aliases = ['open button']
        +
        + +
        +
        +locks = 'cmd:all()'
        +
        + +
        +
        +func()[source]
        +

        simply call the right function.

        +
        + +
        +
        +help_category = 'general'
        +
        + +
        +
        +lock_storage = 'cmd:all()'
        +
        + +
        +
        +search_index_entry = {'aliases': 'open button', 'category': 'general', 'key': 'open lid', 'tags': '', 'text': '\n open lid\n\n Usage:\n open lid\n\n '}
        +
        + +
        + +
        +
        +class evennia.contrib.tutorial_examples.red_button.LidClosedCmdSet(cmdsetobj=None, key=None)[source]
        +

        Bases: evennia.commands.cmdset.CmdSet

        +

        A simple cmdset tied to the redbutton object.

        +

        It contains the commands that launches the other +command sets, making the red button a self-contained +item (i.e. you don’t have to manually add any +scripts etc to it when creating it).

        +

        Note that this is given with a key_mergetype set. This +is set up so that the cmdset with merge with Union merge type +except if the other cmdset to merge with is LidOpenCmdSet, +in which case it will Replace that. So these two cmdsets will +be mutually exclusive.

        +
        +
        +key = 'LidClosedCmdSet'
        +
        + +
        +
        +at_cmdset_creation()[source]
        +

        Populates the cmdset when it is instantiated.

        +
        + +
        +
        +path = 'evennia.contrib.tutorial_examples.red_button.LidClosedCmdSet'
        +
        + +
        + +
        +
        +class evennia.contrib.tutorial_examples.red_button.CmdPushLidOpen(**kwargs)[source]
        +

        Bases: evennia.commands.command.Command

        +

        Push the red button

        +
        +
        Usage:

        push button

        +
        +
        +
        +
        +key = 'push button'
        +
        + +
        +
        +aliases = ['press button', 'press', 'push']
        +
        + +
        +
        +locks = 'cmd:all()'
        +
        + +
        +
        +func(**kwargs)
        +

        This is the actual executing part of the command. It is +called directly after self.parse(). See the docstring of this +module for which object properties are available (beyond those +set in self.parse())

        +
        + +
        +
        +help_category = 'general'
        +
        + +
        +
        +lock_storage = 'cmd:all()'
        +
        + +
        +
        +search_index_entry = {'aliases': 'press button press push', 'category': 'general', 'key': 'push button', 'tags': '', 'text': '\n Push the red button\n\n Usage:\n push button\n\n '}
        +
        + +
        + +
        +
        +class evennia.contrib.tutorial_examples.red_button.CmdCloseLid(**kwargs)[source]
        +

        Bases: evennia.commands.command.Command

        +

        Close the lid

        +
        +
        Usage:

        close lid

        +
        +
        +

        Closes the lid of the red button.

        +
        +
        +key = 'close lid'
        +
        + +
        +
        +aliases = ['close']
        +
        + +
        +
        +locks = 'cmd:all()'
        +
        + +
        +
        +func()[source]
        +

        Close the lid

        +
        + +
        +
        +help_category = 'general'
        +
        + +
        +
        +lock_storage = 'cmd:all()'
        +
        + +
        +
        +search_index_entry = {'aliases': 'close', 'category': 'general', 'key': 'close lid', 'tags': '', 'text': '\n Close the lid\n\n Usage:\n close lid\n\n Closes the lid of the red button.\n '}
        +
        + +
        + +
        +
        +class evennia.contrib.tutorial_examples.red_button.LidOpenCmdSet(cmdsetobj=None, key=None)[source]
        +

        Bases: evennia.commands.cmdset.CmdSet

        +

        This is the opposite of the Closed cmdset.

        +

        Note that this is given with a key_mergetype set. This +is set up so that the cmdset with merge with Union merge type +except if the other cmdset to merge with is LidClosedCmdSet, +in which case it will Replace that. So these two cmdsets will +be mutually exclusive.

        +
        +
        +key = 'LidOpenCmdSet'
        +
        + +
        +
        +at_cmdset_creation()[source]
        +

        Setup the cmdset

        +
        + +
        +
        +path = 'evennia.contrib.tutorial_examples.red_button.LidOpenCmdSet'
        +
        + +
        + +
        +
        +class evennia.contrib.tutorial_examples.red_button.CmdBlindLook(**kwargs)[source]
        +

        Bases: evennia.commands.command.Command

        +

        Looking around in darkness

        +
        +
        Usage:

        look <obj>

        +
        +
        +

        … not that there’s much to see in the dark.

        +
        +
        +key = 'look'
        +
        + +
        +
        +aliases = ['listen', 'get', 'feel', 'l', 'ex', 'examine']
        +
        + +
        +
        +locks = 'cmd:all()'
        +
        + +
        +
        +func()[source]
        +

        This replaces all the senses when blinded.

        +
        + +
        +
        +help_category = 'general'
        +
        + +
        +
        +lock_storage = 'cmd:all()'
        +
        + +
        +
        +search_index_entry = {'aliases': 'listen get feel l ex examine', 'category': 'general', 'key': 'look', 'tags': '', 'text': "\n Looking around in darkness\n\n Usage:\n look <obj>\n\n ... not that there's much to see in the dark.\n\n "}
        +
        + +
        + +
        +
        +class evennia.contrib.tutorial_examples.red_button.CmdBlindHelp(**kwargs)[source]
        +

        Bases: evennia.commands.command.Command

        +

        Help function while in the blinded state

        +
        +
        Usage:

        help

        +
        +
        +
        +
        +key = 'help'
        +
        + +
        +
        +aliases = ['h']
        +
        + +
        +
        +locks = 'cmd:all()'
        +
        + +
        +
        +func()[source]
        +

        Just give a message while blinded. We could have added this to the +CmdBlindLook command too if we wanted to keep things more compact.

        +
        + +
        +
        +help_category = 'general'
        +
        + +
        +
        +lock_storage = 'cmd:all()'
        +
        + +
        +
        +search_index_entry = {'aliases': 'h', 'category': 'general', 'key': 'help', 'tags': '', 'text': '\n Help function while in the blinded state\n\n Usage:\n help\n\n '}
        +
        + +
        + +
        +
        +class evennia.contrib.tutorial_examples.red_button.BlindCmdSet(cmdsetobj=None, key=None)[source]
        +

        Bases: evennia.commands.cmdset.CmdSet

        +

        This is the cmdset added to the account when +the button is pushed.

        +

        Since this has mergetype Replace it will completely remove the commands of +all other cmdsets while active. To allow some limited interaction +(pose/say) we import those default commands and add them too.

        +

        We also disable all exit-commands generated by exits and +object-interactions while blinded by setting no_exits and no_objs flags +on the cmdset. This is to avoid the player walking off or interfering with +other objects while blinded. Account-level commands however (channel messaging +etc) will not be affected by the blinding.

        +
        +
        +key = 'BlindCmdSet'
        +
        + +
        +
        +mergetype = 'Replace'
        +
        + +
        +
        +no_exits = True
        +
        + +
        +
        +no_objs = True
        +
        + +
        +
        +at_cmdset_creation()[source]
        +

        Setup the blind cmdset

        +
        + +
        +
        +path = 'evennia.contrib.tutorial_examples.red_button.BlindCmdSet'
        +
        + +
        +
        class evennia.contrib.tutorial_examples.red_button.RedButton(*args, **kwargs)[source]

        Bases: evennia.objects.objects.DefaultObject

        -

        This class describes an evil red button. It will use the script -definition in contrib/examples/red_button_scripts to blink at regular -intervals. It also uses a series of script and commands to handle -pushing the button and causing effects when doing so.

        -
        -
        The following attributes can be set on the button:

        desc_lid_open - description when lid is open -desc_lid_closed - description when lid is closed -desc_lamp_broken - description when lamp is broken

        -
        -
        +

        This class describes an evil red button. It will blink invitingly and +temporarily blind whomever presses it.

        +

        The button can take a few optional attributes controlling how things will +be displayed in its various states. This is a useful way to give builders +the option to customize a complex object from in-game. Actual return messages +to event-actions are (in this example) left with each command, but one could +also imagine having those handled via Attributes as well, if one wanted a +completely in-game customizable button without needing to tweak command +classes.

        +

        Attributes: +- desc_closed_lid: This is the description to show of the button

        +
        +

        when the lid is closed.

        +
        +
          +
        • desc_open_lid”: Shown when the lid is open

        • +
        • auto_close_msg: Message to show when lid auto-closes

        • +
        • desc_add_lamp_broken: Extra desc-line added after normal desc when lamp +is broken.

        • +
        • blink_msg: A list of strings to randomly choose from when the lamp +blinks.

        • +
        +

        Notes: +The button starts with lid closed. To set the initial description, +you can either set desc after creating it or pass a desc attribute +when creating it, such as +button = create_object(RedButton, …, attributes=[(‘desc’, ‘my desc’)]).

        +
        +
        +desc_closed_lid = 'This is a large red button, inviting yet evil-looking. A closed glass lid protects it.'
        +
        + +
        +
        +desc_open_lid = 'This is a large red button, inviting yet evil-looking. Its glass cover is open and the button exposed.'
        +
        + +
        +
        +auto_close_msg = "The button's glass lid silently slides back in place."
        +
        + +
        +
        +lamp_breaks_msg = 'The lamp flickers, the button going dark.'
        +
        + +
        +
        +desc_add_lamp_broken = '\nThe big red button has stopped blinking for the time being.'
        +
        + +
        + +
        +
        at_object_creation()[source]
        -

        This function is called when object is created. Use this -instead of e.g. __init__.

        +

        This function is called (once) when object is created.

        -
        -open_lid()[source]
        -

        Opens the glass lid and start the timer so it will soon close -again.

        +
        +to_closed_state(msg=None)[source]
        +

        Switches the button to having its lid closed.

        +
        +
        Parameters
        +
          +
        • msg (str, optional) – If given, display a message to the room

        • +
        • lid closes. (when) –

        • +
        +
        +
        +

        This will first try to get the Attribute (self.db.desc_closed_lid) in +case it was set by a builder and if that was None, it will fall back to +self.desc_closed_lid, the default description (note that lack of .db).

        -
        -close_lid()[source]
        -

        Close the glass lid. This validates all scripts on the button, -which means that scripts only being valid when the lid is open -will go away automatically.

        +
        +to_open_state()[source]
        +

        Switches the button to having its lid open. This also starts a timer +that will eventually close it again.

        +
        + +
        +
        +blind_target(caller)[source]
        +

        Someone was foolish enough to press the button! Blind them +temporarily.

        +
        +
        Parameters
        +

        caller (Object) – The one to be blinded.

        +
        +
        -break_lamp(feedback=True)[source]
        -

        Breaks the lamp in the button, stopping it from blinking.

        -
        -
        Parameters
        -

        feedback (bool) – Show a message about breaking the lamp.

        -
        -
        -
        - -
        -
        -press_button(pobject)[source]
        -

        Someone was foolish enough to press the button!

        -
        -
        Parameters
        -

        pobject (Object) – The person pressing the button

        -
        -
        -
        - -
        - -

        The script system will regularly call this -function to make the button blink. Now and then -it won’t blink at all though, to add some randomness -to how often the message is echoed.

        +break_lamp()[source] +

        Breaks the lamp in the button, stopping it from blinking for a while

        @@ -138,6 +692,7 @@ to how often the message is echoed.

        +
        @@ -160,6 +715,14 @@ to how often the message is echoed.

        +

        Table of Contents

        + +
        -
        @@ -200,6 +762,7 @@ to how often the message is echoed.

        +
        develop branch
        @@ -120,7 +121,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -137,6 +137,7 @@ +
        develop branch
        @@ -93,7 +94,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -110,6 +110,7 @@ +
        develop branch
        @@ -275,7 +276,6 @@ option related to this node.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -292,6 +292,7 @@ option related to this node.

        +
        develop branch
        @@ -88,6 +89,11 @@ to turn on/off the mob.”

        lock_storage = 'cmd:superuser()'
        +
        +
        +search_index_entry = {'aliases': 'moboff', 'category': 'general', 'key': 'mobon', 'tags': '', 'text': "\n Activates/deactivates Mob\n\n Usage:\n mobon <mob>\n moboff <mob>\n\n This turns the mob from active (alive) mode\n to inactive (dead) mode. It is used during\n building to activate the mob once it's\n prepared.\n "}
        +
        +
        @@ -123,7 +129,7 @@ the way it came. If unset, the mob will remain stationary (idling) until attacked.

        aggressive: if set, will attack Characters in

        the same room using whatever Weapon it -carries (see tutorial_world.objects.Weapon). +carries (see tutorial_world.objects.TutorialWeapon). if unset, the mob will never engage in combat no matter what.

        @@ -319,7 +325,6 @@ right away, also when patrolling on a very slow ticker.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -336,6 +341,7 @@ right away, also when patrolling on a very slow ticker.

        +
        develop branch
        @@ -50,8 +51,8 @@ TutorialClimbable Obelisk LightSource CrumblingWall -Weapon -WeaponRack

        +TutorialWeapon +TutorialWeaponRack

        class evennia.contrib.tutorial_world.objects.TutorialObject(*args, **kwargs)[source]
        @@ -134,6 +135,11 @@ Attribute “readable_text” on the object and displays that.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'tutorialworld', 'key': 'read', 'tags': '', 'text': '\n Usage:\n read [obj]\n\n Read some text of a readable object.\n '}
        +
        +
        @@ -231,6 +237,11 @@ Attribute and add the readable cmdset.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'tutorialworld', 'key': 'climb', 'tags': '', 'text': '\n Climb an object\n\n Usage:\n climb <object>\n\n This allows you to climb.\n '}
        +
        +
        @@ -351,7 +362,7 @@ of the object. We overload it with our own version.

        -aliases = ['burn', 'light']
        +aliases = ['light', 'burn']
        @@ -376,6 +387,11 @@ to sit on a “lightable” object, we operate only on self.obj.

        lock_storage = 'cmd:holds()'
        +
        +
        +search_index_entry = {'aliases': 'light burn', 'category': 'tutorialworld', 'key': 'on', 'tags': '', 'text': '\n Creates light where there was none. Something to burn.\n '}
        +
        +
        @@ -477,7 +493,7 @@ shift green root up/down

        -aliases = ['pull', 'move', 'push', 'shiftroot']
        +aliases = ['pull', 'shiftroot', 'push', 'move']
        @@ -511,6 +527,11 @@ yellow/green - horizontal roots

        lock_storage = 'cmd:locattr(is_lit)'
        +
        +
        +search_index_entry = {'aliases': 'pull shiftroot push move', 'category': 'tutorialworld', 'key': 'shift', 'tags': '', 'text': '\n Shifts roots around.\n\n Usage:\n shift blue root left/right\n shift red root left/right\n shift yellow root up/down\n shift green root up/down\n\n '}
        +
        +
        @@ -525,7 +546,7 @@ yellow/green - horizontal roots

        -aliases = ['press button', 'push button', 'button']
        +aliases = ['push button', 'press button', 'button']
        @@ -549,6 +570,11 @@ yellow/green - horizontal roots

        lock_storage = 'cmd:objattr(button_exposed) and objlocattr(is_lit)'
        +
        +
        +search_index_entry = {'aliases': 'push button press button button', 'category': 'tutorialworld', 'key': 'press', 'tags': '', 'text': '\n Presses a button.\n '}
        +
        +
        @@ -690,7 +716,7 @@ parry - forgoes your attack but will make you harder to hit on next

        -aliases = ['kill', 'pierce', 'hit', 'chop', 'thrust', 'defend', 'bash', 'parry', 'stab', 'slash', 'fight']
        +aliases = ['thrust', 'kill', 'pierce', 'fight', 'bash', 'parry', 'stab', 'hit', 'defend', 'slash', 'chop']
        @@ -714,6 +740,11 @@ parry - forgoes your attack but will make you harder to hit on next

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'thrust kill pierce fight bash parry stab hit defend slash chop', 'category': 'tutorialworld', 'key': 'attack', 'tags': '', 'text': '\n Attack the enemy. Commands:\n\n stab <enemy>\n slash <enemy>\n parry\n\n stab - (thrust) makes a lot of damage but is harder to hit with.\n slash - is easier to land, but does not make as much damage.\n parry - forgoes your attack but will make you harder to hit on next\n enemy attack.\n\n '}
        +
        +
        @@ -735,8 +766,8 @@ parry - forgoes your attack but will make you harder to hit on next

        -
        -class evennia.contrib.tutorial_world.objects.Weapon(*args, **kwargs)[source]
        +
        +class evennia.contrib.tutorial_world.objects.TutorialWeapon(*args, **kwargs)[source]

        Bases: evennia.contrib.tutorial_world.objects.TutorialObject

        This defines a bladed weapon.

        @@ -749,38 +780,38 @@ damage - base damage given (modified by hit success and

        -
        -at_object_creation()[source]
        +
        +at_object_creation()[source]

        Called at first creation of the object

        -
        -reset()[source]
        +
        +reset()[source]

        When reset, the weapon is simply deleted, unless it has a place to return to.

        -
        -exception DoesNotExist
        +
        +exception DoesNotExist

        Bases: evennia.contrib.tutorial_world.objects.TutorialObject.DoesNotExist

        -
        -exception MultipleObjectsReturned
        +
        +exception MultipleObjectsReturned

        Bases: evennia.contrib.tutorial_world.objects.TutorialObject.MultipleObjectsReturned

        -
        -path = 'evennia.contrib.tutorial_world.objects.Weapon'
        +
        +path = 'evennia.contrib.tutorial_world.objects.TutorialWeapon'
        -
        -typename = 'Weapon'
        +
        +typename = 'TutorialWeapon'
        @@ -826,6 +857,11 @@ itself handle all messages.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'tutorialworld', 'key': 'get weapon', 'tags': '', 'text': '\n Usage:\n get weapon\n\n This will try to obtain a weapon from the container.\n '}
        +
        +
        @@ -852,8 +888,8 @@ itself handle all messages.

        -
        -class evennia.contrib.tutorial_world.objects.WeaponRack(*args, **kwargs)[source]
        +
        +class evennia.contrib.tutorial_world.objects.TutorialWeaponRack(*args, **kwargs)[source]

        Bases: evennia.contrib.tutorial_world.objects.TutorialObject

        This object represents a weapon store. When people use the “get weapon” command on this rack, it will produce one @@ -871,14 +907,14 @@ grab another one.

        -
        -at_object_creation()[source]
        +
        +at_object_creation()[source]

        called at creation

        -
        -produce_weapon(caller)[source]
        +
        +produce_weapon(caller)[source]

        This will produce a new weapon from the rack, assuming the caller hasn’t already gotten one. When doing so, the caller will get Tagged with the id @@ -887,25 +923,25 @@ pulling weapons from it indefinitely.

        -
        -exception DoesNotExist
        +
        +exception DoesNotExist

        Bases: evennia.contrib.tutorial_world.objects.TutorialObject.DoesNotExist

        -
        -exception MultipleObjectsReturned
        +
        +exception MultipleObjectsReturned

        Bases: evennia.contrib.tutorial_world.objects.TutorialObject.MultipleObjectsReturned

        -
        -path = 'evennia.contrib.tutorial_world.objects.WeaponRack'
        +
        +path = 'evennia.contrib.tutorial_world.objects.TutorialWeaponRack'
        -
        -typename = 'WeaponRack'
        +
        +typename = 'TutorialWeaponRack'
        @@ -955,7 +991,6 @@ pulling weapons from it indefinitely.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -972,6 +1007,7 @@ pulling weapons from it indefinitely.

        +
        develop branch
        @@ -87,6 +88,11 @@ called tutorial_info and display that.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'tut', 'category': 'tutorialworld', 'key': 'tutorial', 'tags': '', 'text': '\n Get help during the tutorial\n\n Usage:\n tutorial [obj]\n\n This command allows you to get behind-the-scenes info\n about an object or the current location.\n\n '}
        +
        +
        @@ -140,6 +146,11 @@ the set_detail method and uses it.

        lock_storage = 'cmd:perm(Builder)'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'tutorialworld', 'key': '@detail', 'tags': '', 'text': '\n sets a detail on a room\n\n Usage:\n @detail <key> = <description>\n @detail <key>;<alias>;... = description\n\n Example:\n @detail walls = The walls are covered in ...\n @detail castle;ruin;tower = The distant ruin ...\n\n This sets a "detail" on the object this command is defined on\n (TutorialRoom for this tutorial). This detail can be accessed with\n the TutorialRoomLook command sitting on TutorialRoom objects (details\n are set as a simple dictionary on the room). This is a Builder command.\n\n We custom parse the key for the ;-separator in order to create\n multiple aliases to the detail all at once.\n '}
        +
        +
        @@ -174,7 +185,7 @@ code except for adding in the details.

        -aliases = ['ls', 'l']
        +aliases = ['l', 'ls']
        @@ -187,6 +198,11 @@ code except for adding in the details.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'l ls', 'category': 'tutorialworld', 'key': 'look', 'tags': '', 'text': '\n looks at the room and on details\n\n Usage:\n look <obj>\n look <room detail>\n look *<account>\n\n Observes your location, details at your location or objects\n in your vicinity.\n\n Tutorial: This is a child of the default Look command, that also\n allows us to look at "details" in the room. These details are\n things to examine and offers some extra description without\n actually having to be actual database objects. It uses the\n return_detail() hook on TutorialRooms for this.\n '}
        +
        +
        @@ -223,6 +239,11 @@ to all the variables defined therein.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': 'abort', 'category': 'general', 'key': 'give up', 'tags': '', 'text': '\n Give up the tutorial-world quest and return to Limbo, the start room of the\n server.\n\n '}
        +
        +
        @@ -428,6 +449,11 @@ set in self.parse())

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'intro', 'tags': '', 'text': '\n Start the Evennia intro wizard.\n\n Usage:\n intro\n\n '}
        +
        +
        @@ -557,6 +583,11 @@ on the bridge, 0 - 4.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'e', 'category': 'tutorialworld', 'key': 'east', 'tags': '', 'text': '\n Go eastwards across the bridge.\n\n Tutorial info:\n This command relies on the caller having two Attributes\n (assigned by the room when entering):\n - east_exit: a unique name or dbref to the room to go to\n when exiting east.\n - west_exit: a unique name or dbref to the room to go to\n when exiting west.\n The room must also have the following Attributes\n - tutorial_bridge_posistion: the current position on\n on the bridge, 0 - 4.\n\n '}
        +
        +
        @@ -615,6 +646,11 @@ on the bridge, 0 - 4.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'w', 'category': 'tutorialworld', 'key': 'west', 'tags': '', 'text': '\n Go westwards across the bridge.\n\n Tutorial info:\n This command relies on the caller having two Attributes\n (assigned by the room when entering):\n - east_exit: a unique name or dbref to the room to go to\n when exiting east.\n - west_exit: a unique name or dbref to the room to go to\n when exiting west.\n The room must also have the following property:\n - tutorial_bridge_posistion: the current position on\n on the bridge, 0 - 4.\n\n '}
        +
        +
        @@ -659,6 +695,11 @@ if they fall off the bridge.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'l', 'category': 'tutorialworld', 'key': 'look', 'tags': '', 'text': '\n looks around at the bridge.\n\n Tutorial info:\n This command assumes that the room has an Attribute\n "fall_exit", a unique name or dbref to the place they end upp\n if they fall off the bridge.\n '}
        +
        +
        @@ -673,7 +714,7 @@ if they fall off the bridge.

        -aliases = ['h', '?']
        +aliases = ['?', 'h']
        @@ -697,6 +738,11 @@ if they fall off the bridge.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '? h', 'category': 'tutorial world', 'key': 'help', 'tags': '', 'text': '\n Overwritten help command while on the bridge.\n '}
        +
        +
        @@ -820,7 +866,7 @@ to find something.

        -aliases = ['feel', 'fiddle', 'search', 'l', 'feel around']
        +aliases = ['fiddle', 'feel around', 'feel', 'l', 'search']
        @@ -846,6 +892,11 @@ random chance of eventually finding a light source.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': 'fiddle feel around feel l search', 'category': 'tutorialworld', 'key': 'look', 'tags': '', 'text': '\n Look around in darkness\n\n Usage:\n look\n\n Look around in the darkness, trying\n to find something.\n '}
        +
        +
        @@ -884,6 +935,11 @@ random chance of eventually finding a light source.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'tutorialworld', 'key': 'help', 'tags': '', 'text': '\n Help command for the dark state.\n '}
        +
        +
        @@ -926,6 +982,11 @@ suggestions)

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': '__nomatch_command', 'tags': '', 'text': "\n This is a system command. Commands with special keys are used to\n override special sitations in the game. The CMD_NOMATCH is used\n when the given command is not found in the current command set (it\n replaces Evennia's default behavior or offering command\n suggestions)\n "}
        +
        +
        @@ -1197,7 +1258,6 @@ overriding the call (unused by default).

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1214,6 +1274,7 @@ overriding the call (unused by default).

        +
        develop branch
        @@ -318,6 +319,11 @@ use its add_argument method.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'command', 'tags': '', 'text': '\n Unix-type commands, supporting short and long options.\n\n This command syntax uses the Unix-style commands with short options\n (-X) and long options (--something). The `argparse` module is\n used to parse the command.\n\n In order to use it, you should override two methods:\n - `init_parser`: this method is called when the command is created.\n It can be used to set options in the parser. `self.parser`\n contains the `argparse.ArgumentParser`, so you can add arguments\n here.\n - `func`: this method is called to execute the command, but after\n the parser has checked the arguments given to it are valid.\n You can access the namespace of valid arguments in `self.opts`\n at this point.\n\n The help of UnixCommands is derived from the docstring, in a\n slightly different way than usual: the first line of the docstring\n is used to represent the program description (the very short\n line at the top of the help message). The other lines below are\n used as the program\'s "epilog", displayed below the options. It\n means in your docstring, you don\'t have to write the options.\n They will be automatically provided by the parser and displayed\n accordingly. The `argparse` module provides a default \'-h\' or\n \'--help\' option on the command. Typing |whelp commandname|n will\n display the same as |wcommandname -h|n, though this behavior can\n be changed.\n\n '}
        +
        + @@ -365,7 +371,6 @@ use its add_argument method.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -382,6 +387,7 @@ use its add_argument method.

        +
        develop branch
        @@ -711,7 +712,6 @@ coordinate.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -728,6 +728,7 @@ coordinate.

        +
        develop branch
        @@ -37,8 +38,168 @@
        -
        -

        evennia.help.filehelp

        +
        +

        evennia.help.filehelp

        +

        The filehelp-system allows for defining help files outside of the game. These +will be treated as non-command help entries and displayed in the same way as +help entries created using the sethelp default command. After changing an +entry on-disk you need to reload the server to have the change show in-game.

        +

        An filehelp file is a regular python module with dicts representing each help +entry. If a list HELP_ENTRY_DICTS is found in the module, this should be a list of +dicts. Otherwise all top-level dicts in the module will be assumed to be a +help-entry dict.

        +

        Each help-entry dict is on the form

        +
        {'key': <str>,
        + 'text': <str>,
        + 'category': <str>,   # optional, otherwise settings.DEFAULT_HELP_CATEGORY
        + 'aliases': <list>,   # optional
        + 'locks': <str>}      # optional, use access-type 'view'. Default is view:all()
        +
        +
        +

        The text** should be formatted on the same form as other help entry-texts and +can contain **# subtopics** as normal.

        +

        New help-entry modules are added to the system by providing the python-path to +the module to settings.FILE_HELP_ENTRY_MODULES. Note that if same-key entries are +added, entries in latter modules will override that of earlier ones. Use +settings.DEFAULT_HELP_CATEGORY** to customize what category is used if +not set explicitly.

        +

        An example of the contents of a module:

        +
        help_entry1 = {
        +    "key": "The Gods",   # case-insensitive, also partial-matching ('gods') works
        +    "aliases": ['pantheon', 'religion'],
        +    "category": "Lore",
        +    "locks": "view:all()",   # this is optional unless restricting access
        +    "text": '''
        +        The gods formed the world ...
        +
        +        # Subtopics
        +
        +        ## Pantheon
        +
        +        ...
        +
        +        ### God of love
        +
        +        ...
        +
        +        ### God of war
        +
        +        ...
        +
        +    '''
        +}
        +
        +
        +HELP_ENTRY_DICTS = [
        +    help_entry1,
        +    ...
        +]
        +
        +
        +
        +
        +
        +class evennia.help.filehelp.FileHelpEntry(key: str, aliases: list, help_category: str, entrytext: str, lock_storage: str)[source]
        +

        Bases: object

        +

        Represents a help entry read from file. This mimics the api of the +database-bound HelpEntry so that they can be used interchangeably in the +help command.

        +
        +
        +key: str
        +
        + +
        +
        +aliases: list
        +
        + +
        +
        +help_category: str
        +
        + +
        +
        +entrytext: str
        +
        + +
        +
        +lock_storage: str
        +
        + +
        +
        +property search_index_entry
        +

        Property for easily retaining a search index entry for this object.

        +
        + +
        +
        +locks[source]
        +
        + +
        +
        +access(accessing_obj, access_type='view', default=True)[source]
        +

        Determines if another object has permission to access this help entry.

        +
        +
        Parameters
        +
          +
        • accessing_obj (Object or Account) – Entity trying to access this one.

        • +
        • access_type (str) – type of access sought.

        • +
        • default (bool) – What to return if no lock of access_type was found.

        • +
        +
        +
        +
        + +
        +
        +__init__(key: str, aliases: list, help_category: str, entrytext: str, lock_storage: str) → None
        +

        Initialize self. See help(type(self)) for accurate signature.

        +
        + +
        + +
        +
        +class evennia.help.filehelp.FileHelpStorageHandler(help_file_modules=['world.help_entries'])[source]
        +

        Bases: object

        +

        This reads and stores help entries for quick access. By default +it reads modules from settings.FILE_HELP_ENTRY_MODULES.

        +

        Note that this is not meant to any searching/lookup - that is all handled +by the help command.

        +
        +
        +__init__(help_file_modules=['world.help_entries'])[source]
        +

        Initialize the storage.

        +
        + +
        +
        +load()[source]
        +

        Load/reload file-based help-entries from file.

        +
        + +
        +
        +all(return_dict=False)[source]
        +

        Get all help entries.

        +
        +
        Parameters
        +

        return_dict (bool) – Return a dict **{key: FileHelpEntry,…}**. Otherwise, +return a list of **FileHelpEntry.

        +
        +
        Returns
        +

        dict or list – Depending on the setting of **return_dict**.

        +
        +
        +
        + +
        +
        @@ -84,7 +245,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +261,7 @@ +
        develop branch
        @@ -96,7 +97,6 @@ itself.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -113,6 +113,7 @@ itself.

        +
        develop branch
        @@ -222,7 +223,6 @@ up in one easily separated category.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -239,6 +239,7 @@ up in one easily separated category.

        +
        develop branch
        @@ -105,8 +106,8 @@ class built by **create_forward_many_to_many_manager()** define
        -
        -db_staff_only
        +
        +db_date_created

        A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

        @@ -133,11 +134,28 @@ object the first time, the query is executed.

        -access(accessing_obj, access_type='read', default=False)[source]
        -

        Determines if another object has permission to access. -accessing_obj - object trying to access this one -access_type - type of access sought -default - what to return if no lock of access_type was found

        +access(accessing_obj, access_type='read', default=True)[source] +

        Determines if another object has permission to access this help entry.

        +
        +
        Accesses used by default:

        ‘read’ - read the help entry itself. +‘view’ - see help entry in help index.

        +
        +
        +
        +
        Parameters
        +
          +
        • accessing_obj (Object or Account) – Entity trying to access this one.

        • +
        • access_type (str) – type of access sought.

        • +
        • default (bool) – What to return if no lock of access_type was found.

        • +
        +
        +
        +
        + +
        +
        +property search_index_entry
        +

        Property for easily retaining a search index entry for this object.

        @@ -161,8 +179,10 @@ instances of this object.

        For this to work, the developer must have defined a named view somewhere in urls.py that follows the format ‘modelname-action’, so in this case a named view of ‘character-create’ would be referenced by this method.

        -

        ex. -url(r’characters/create/’, ChargenView.as_view(), name=’character-create’)

        +

        ex.

        +
        url(r'characters/create/', ChargenView.as_view(), name='character-create')
        +
        +

        If no View has been created and defined in urls.py, returns an HTML anchor.

        This method is naive and simply returns a path. Securing access to @@ -184,11 +204,11 @@ this object.

        For this to work, the developer must have defined a named view somewhere in urls.py that follows the format ‘modelname-action’, so in this case a named view of ‘character-detail’ would be referenced by this method.

        -

        ex. -url(r’characters/(?P<slug>[wd-]+)/(?P<pk>[0-9]+)/$’,

        -
        -

        CharDetailView.as_view(), name=’character-detail’)

        -
        +

        ex.

        +
        url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/$',
        +    CharDetailView.as_view(), name='character-detail')
        +
        +

        If no View has been created and defined in urls.py, returns an HTML anchor.

        This method is naive and simply returns a path. Securing access to @@ -210,11 +230,11 @@ object.

        For this to work, the developer must have defined a named view somewhere in urls.py that follows the format ‘modelname-action’, so in this case a named view of ‘character-update’ would be referenced by this method.

        -

        ex. -url(r’characters/(?P<slug>[wd-]+)/(?P<pk>[0-9]+)/change/$’,

        -
        -

        CharUpdateView.as_view(), name=’character-update’)

        -
        +

        ex.

        +
        url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/change/$',
        +    CharUpdateView.as_view(), name='character-update')
        +
        +

        If no View has been created and defined in urls.py, returns an HTML anchor.

        This method is naive and simply returns a path. Securing access to @@ -235,11 +255,11 @@ responsibility.

        For this to work, the developer must have defined a named view somewhere in urls.py that follows the format ‘modelname-action’, so in this case a named view of ‘character-detail’ would be referenced by this method.

        -

        ex. -url(r’characters/(?P<slug>[wd-]+)/(?P<pk>[0-9]+)/delete/$’,

        -
        -

        CharDeleteView.as_view(), name=’character-delete’)

        -
        +

        ex.

        +
        url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/delete/$',
        +    CharDeleteView.as_view(), name='character-delete')
        +
        +

        If no View has been created and defined in urls.py, returns an HTML anchor.

        This method is naive and simply returns a path. Securing access to @@ -261,11 +281,11 @@ this object.

        For this to work, the developer must have defined a named view somewhere in urls.py that follows the format ‘modelname-action’, so in this case a named view of ‘character-detail’ would be referenced by this method.

        -

        ex. -url(r’characters/(?P<slug>[wd-]+)/(?P<pk>[0-9]+)/$’,

        -
        -

        CharDetailView.as_view(), name=’character-detail’)

        -
        +

        ex.

        +
        url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/$',
        +    CharDetailView.as_view(), name='character-detail')
        +
        +

        If no View has been created and defined in urls.py, returns an HTML anchor.

        This method is naive and simply returns a path. Securing access to @@ -290,12 +310,28 @@ responsibility.

        Bases: django.core.exceptions.MultipleObjectsReturned

        +
        +
        +property date_created
        +

        A wrapper for getting database field db_date_created.

        +
        +
        property entrytext

        A wrapper for getting database field db_entrytext.

        +
        +
        +get_next_by_db_date_created(*, field=<django.db.models.fields.DateTimeField: db_date_created>, is_next=True, **kwargs)
        +
        + +
        +
        +get_previous_by_db_date_created(*, field=<django.db.models.fields.DateTimeField: db_date_created>, is_next=False, **kwargs)
        +
        +
        property help_category
        @@ -326,12 +362,6 @@ object the first time, the query is executed.

        path = 'evennia.help.models.HelpEntry'
        -
        -
        -property staff_only
        -

        A wrapper for getting database field db_staff_only.

        -
        -
        typename = 'SharedMemoryModelBase'
        @@ -384,7 +414,6 @@ object the first time, the query is executed.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -401,6 +430,7 @@ object the first time, the query is executed.

        +
        develop branch
        @@ -37,8 +38,110 @@
        -
        -

        evennia.help.utils

        +
        +

        evennia.help.utils

        +

        Resources for indexing help entries and for splitting help entries into +sub-categories.

        +

        This is used primarily by the default help command.

        +
        +
        +evennia.help.utils.help_search_with_index(query, candidate_entries, suggestion_maxnum=5, fields=None)[source]
        +

        Lunr-powered fast index search and suggestion wrapper. See https://lunrjs.com/.

        +
        +
        Parameters
        +
          +
        • query (str) – The query to search for.

        • +
        • candidate_entries (list) – This is the body of possible entities to search. Each +must have a property .search_index_entry that returns a dict with all +keys in the fields arg.

        • +
        • suggestion_maxnum (int) – How many matches to allow at most in a multi-match.

        • +
        • fields (list, optional) – A list of Lunr field mappings +**{“field_name”: str, “boost”: int}**. See the Lunr documentation +for more details. The field name must exist in the dicts returned +by .search_index_entry of the candidates. If not given, a default setup +is used, prefering keys > aliases > category > tags.

        • +
        +
        +
        Returns
        +

        tuple

        +
        +
        A tuple (matches, suggestions), each a list, where the suggestion_maxnum limits

        how many suggestions are included.

        +
        +
        +

        +
        +
        +
        + +
        +
        +evennia.help.utils.parse_entry_for_subcategories(entry)[source]
        +

        Parse a command docstring for special sub-category blocks:

        +
        +
        Parameters
        +

        entry (str) – A help entry to parse

        +
        +
        Returns
        +

        dict

        +
        +
        The dict is a mapping that splits the entry into subcategories. This

        will always hold a key None for the main help entry and +zero or more keys holding the subcategories. Each is itself +a dict with a key None for the main text of that subcategory +followed by any sub-sub-categories down to a max-depth of 5.

        +
        +
        +

        +
        +
        +

        Example:

        +
        '''
        +Main topic text
        +
        +# SUBTOPICS
        +
        +## foo
        +
        +A subcategory of the main entry, accessible as **help topic foo**
        +(or using /, like **help topic/foo**)
        +
        +## bar
        +
        +Another subcategory, accessed as **help topic bar**
        +(or **help topic/bar**)
        +
        +### moo
        +
        +A subcategory of bar, accessed as **help bar moo**
        +(or **help bar/moo**)
        +
        +#### dum
        +
        +A subcategory of moo, accessed **help bar moo dum**
        +(or **help bar/moo/dum**)
        +
        +'''
        +
        +
        +

        This will result in this returned entry structure:

        +
        {
        +   None: "Main topic text":
        +   "foo": {
        +        None: "main topic/foo text"
        +   },
        +   "bar": {
        +        None: "Main topic/bar text",
        +        "moo": {
        +            None: "topic/bar/moo text"
        +            "dum": {
        +                None: "topic/bar/moo/dum text"
        +            }
        +        }
        +   }
        +}
        +
        +
        +
        +
        @@ -84,7 +187,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +203,7 @@ +
        develop branch
        @@ -45,7 +46,6 @@
      • evennia.contrib.crafting
      • @@ -262,7 +288,10 @@ with ‘q’, remove the break line and restart server when finished.

      • evennia.contrib.tutorial_examples.bodyfunctions
      • evennia.contrib.tutorial_examples.example_batch_code
      • evennia.contrib.tutorial_examples.mirror
      • -
      • evennia.contrib.tutorial_examples.red_button
      • +
      • evennia.contrib.tutorial_examples.red_button +
      • evennia.contrib.tutorial_examples.tests
      • @@ -283,10 +312,7 @@ with ‘q’, remove the break line and restart server when finished.

      • evennia.locks
      • @@ -379,10 +405,19 @@ with ‘q’, remove the break line and restart server when finished.

      • evennia.utils -
      • @@ -546,6 +580,7 @@ with ‘q’, remove the break line and restart server when finished.

        +
        develop branch
        @@ -44,10 +45,7 @@ lock strings are processed through the lockhandler in this package. It also contains the default lock functions used in lock definitions.

        @@ -96,7 +94,6 @@ also contains the default lock functions used in lock definitions.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -113,6 +110,7 @@ also contains the default lock functions used in lock definitions.

        +
        develop branch
        @@ -48,106 +49,6 @@ Run the access() method of the handler to execute the lock chec

        Note that accessing_obj and accessed_obj can be any object type with a lock variable/field, so be careful to not expect a certain object type.

        -

        Appendix: MUX locks

        -

        Below is a list nicked from the MUX help file on the locks available -in standard MUX. Most of these are not relevant to core Evennia since -locks in Evennia are considerably more flexible and can be implemented -on an individual command/typeclass basis rather than as globally -available like the MUX ones. So many of these are not available in -basic Evennia, but could all be implemented easily if needed for the -individual game.

        -
        -

        MUX Name: Affects: Effect:

        -
        -
        DefaultLock: Exits: controls who may traverse the exit to
        -
        -
        -
        its destination.

        Evennia: “traverse:<lockfunc()>”

        -
        -
        -
        -
        -
        Rooms: controls whether the account sees the

        SUCC or FAIL message for the room -following the room description when -looking at the room.

        -
        -

        Evennia: Custom typeclass

        -
        -
        -
        Accounts/Things: controls who may GET the object.

        Evennia: “get:<lockfunc()”

        -
        -
        -
        -
        -
        EnterLock: Accounts/Things: controls who may ENTER the object

        Evennia:

        -
        -
        GetFromLock: All but Exits: controls who may gets things from a
        -
        given location.

        Evennia:

        -
        -
        -
        -
        GiveLock: Accounts/Things: controls who may give the object.

        Evennia:

        -
        -
        LeaveLock: Accounts/Things: controls who may LEAVE the object.

        Evennia:

        -
        -
        LinkLock: All but Exits: controls who may link to the location

        if the location is LINK_OK (for linking -exits or setting drop-tos) or ABODE (for -setting homes)

        -
        -

        Evennia:

        -
        -
        -
        MailLock: Accounts: controls who may @mail the account.

        Evennia:

        -
        -
        OpenLock: All but Exits: controls who may open an exit.

        Evennia:

        -
        -
        PageLock: Accounts: controls who may page the account.

        Evennia: “send:<lockfunc()>”

        -
        -
        ParentLock: All: controls who may make @parent links to
        -
        the object.

        Evennia: Typeclasses and

        -
        -
        -

        “puppet:<lockstring()>”

        -
        -
        ReceiveLock: Accounts/Things: controls who may give things to the
        -
        object.

        Evennia:

        -
        -
        -
        -
        SpeechLock: All but Exits: controls who may speak in that location

        Evennia:

        -
        -
        TeloutLock: All but Exits: controls who may teleport out of the
        -
        location.

        Evennia:

        -
        -
        -
        -
        TportLock: Rooms/Things: controls who may teleport there

        Evennia:

        -
        -
        UseLock: All but Exits: controls who may USE the object, GIVE

        the object money and have the PAY -attributes run, have their messages -heard and possibly acted on by LISTEN -and AxHEAR, and invoke $-commands -stored on the object.

        -
        -

        Evennia: Commands and Cmdsets.

        -
        -
        -
        DropLock: All but rooms: controls who may drop that object.

        Evennia:

        -
        -
        VisibleLock: All: Controls object visibility when the

        object is not dark and the looker -passes the lock. In DARK locations, the -object must also be set LIGHT and the -viewer must pass the VisibleLock.

        -
        -
        -
        Evennia: Room typeclass with

        Dark/light script

        -
        -
        -
        -
        -
        -
        -
        evennia.locks.lockfuncs.true(*args, **kwargs)[source]
        @@ -170,6 +71,11 @@ viewer must pass the VisibleLock.

        evennia.locks.lockfuncs.none(*args, **kwargs)[source]
        +
        +
        +evennia.locks.lockfuncs.superuser(*args, **kwargs)[source]
        +
        +
        evennia.locks.lockfuncs.self(accessing_obj, accessed_obj, *args, **kwargs)[source]
        @@ -461,15 +367,6 @@ accessed_obj.location == accessing_obj), or if accessing_obj itself holds an object matching the given key.

        -
        -
        -evennia.locks.lockfuncs.superuser(*args, **kwargs)[source]
        -

        Only accepts an accesing_obj that is superuser (e.g. user #1)

        -

        Since a superuser would not ever reach this check (superusers -bypass the lock entirely), any user who gets this far cannot be a -superuser, hence we just return False. :)

        -
        -
        evennia.locks.lockfuncs.has_account(accessing_obj, accessed_obj, *args, **kwargs)[source]
        @@ -494,7 +391,6 @@ everything will enter this function as strings, so they have to be unpacked to their real value. We only support basic properties.

        -
        @@ -517,14 +413,6 @@ unpacked to their real value. We only support basic properties.

        -

        Table of Contents

        - -
          @@ -548,7 +436,6 @@ unpacked to their real value. We only support basic properties.

        • 0.9.5 (v0.9.5 branch)
        -
        @@ -565,6 +452,7 @@ unpacked to their real value. We only support basic properties.

        +
        develop branch
        @@ -456,7 +457,6 @@ among the locks defined by lockstring.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -473,6 +473,7 @@ among the locks defined by lockstring.

        +
        develop branch
        @@ -93,7 +94,6 @@ objects inherit from classes in this package.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -110,6 +110,7 @@ objects inherit from classes in this package.

        +
        develop branch
        @@ -91,7 +92,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -108,6 +108,7 @@ +
        develop branch
        @@ -70,6 +71,17 @@ handler is defined

        +
        +
        +load()[source]
        +

        Retrieves all objects from database. Used for initializing.

        +
        +
        Returns
        +

        Objects (list of ObjectDB)

        +
        +
        +
        +
        init()[source]
        @@ -78,11 +90,14 @@ handler is defined

        -get(exclude=None)[source]
        +get(exclude=None, content_type=None)[source]

        Return the contents of the cache.

        Parameters
        -

        exclude (Object or list of Object) – object(s) to ignore

        +
          +
        • exclude (Object or list of Object) – object(s) to ignore

        • +
        • content_type (str or None) – Filter list by a content-type. If None, don’t filter.

        • +
        Returns

        objects (list) – the Objects inside this location

        @@ -550,7 +565,6 @@ class built by **create_forward_many_to_many_manager()** define
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -567,6 +581,7 @@ class built by **create_forward_many_to_many_manager()** define +
        develop branch
        @@ -43,12 +44,12 @@ DefaultCharacter, DefaultAccount, DefaultRoom and DefaultExit. These are the (default) starting points for all in-game visible entities.

        +

        This is the v1.0 develop version (for ref in doc building).

        class evennia.objects.objects.ObjectSessionHandler(obj)[source]

        Bases: object

        -

        Handles the get/setting of the sessid -comma-separated integer field

        +

        Handles the get/setting of the sessid comma-separated integer field

        __init__(obj)[source]
        @@ -198,21 +199,26 @@ currently connected to this object.

        -contents_get(exclude=None)[source]
        +contents_get(exclude=None, content_type=None)[source]

        Returns the contents of this object, i.e. all objects that has this object set as its location. This should be publically available.

        Parameters
        -

        exclude (Object) – Object to exclude from returned -contents list

        +
          +
        • exclude (Object) – Object to exclude from returned +contents list

        • +
        • content_type (str) – A content_type to filter by. None for no +filtering.

        • +
        Returns

        contents (list) – List of contents of this Object.

        Notes

        -

        Also available as the contents property.

        +

        Also available as the contents property, minus exclusion +and filtering.

        @@ -229,15 +235,20 @@ objects that has this object set as its location. This should be publically available.

        Parameters
        -

        exclude (Object) – Object to exclude from returned -contents list

        +
          +
        • exclude (Object) – Object to exclude from returned +contents list

        • +
        • content_type (str) – A content_type to filter by. None for no +filtering.

        • +
        Returns

        contents (list) – List of contents of this Object.

        Notes

        -

        Also available as the contents property.

        +

        Also available as the contents property, minus exclusion +and filtering.

        @@ -301,7 +312,7 @@ plural (str): The determined plural form of the key, including the count.

        -search(searchdata, global_search=False, use_nicks=True, typeclass=None, location=None, attribute_name=None, quiet=False, exact=False, candidates=None, nofound_string=None, multimatch_string=None, use_dbref=None)[source]
        +search(searchdata, global_search=False, use_nicks=True, typeclass=None, location=None, attribute_name=None, quiet=False, exact=False, candidates=None, nofound_string=None, multimatch_string=None, use_dbref=None, stacked=0)[source]

        Returns an Object matching a search string/condition

        Perform a standard object search in the database, handling multiple results and lack thereof gracefully. By default, only @@ -336,7 +347,9 @@ for a broader search.

        to search. Note that this is used to query the contents of a location and will not match for the location itself - if you want that, don’t set this or use candidates to specify -exactly which objects should be searched.

        +exactly which objects should be searched. If this nor candidates are +given, candidates will include caller’s inventory, current location and +all objects in the current location.

      • attribute_name (str) – Define which property to search. If set, no key+alias search will be performed. This can be used to search database fields (db_ will be automatically @@ -364,14 +377,22 @@ to find an object (globally) by its database-id 123. If False, will be treated like a normal string. If None (default), the ability to query by #dbref is turned on if self has the permission ‘Builder’ and is turned off otherwise.

      • +
      • stacked (int, optional) – If > 0, multimatches will be analyzed to determine if they +only contains identical objects; these are then assumed ‘stacked’ and no multi-match +error will be generated, instead stacked number of matches will be returned. If +stacked is larger than number of matches, returns that number of matches. If +the found stack is a mix of objects, return None and handle the multi-match +error depending on the value of quiet.

      • Returns
        -

        match (Object, None or list)

        -
        -
        will return an Object/None if quiet=False,

        otherwise it will return a list of 0, 1 or more matches.

        -
        -
        +

        Object – If finding a match an quiet=False +None: If not finding a unique match and quiet=False. +list: With 0, 1 or more matching objects if quiet=True +list: With 2 or more matching objects if stacked is a positive integer and

        +
        +

        the matched stack has only object-copies.

        +

        @@ -526,47 +547,66 @@ function on.

      • text (str or tuple) – Message to send. If a tuple, this should be on the valid OOB outmessage form (message, {kwargs}), where kwargs are optional data passed to the text -outputfunc.

      • +outputfunc. The message will be parsed for {key} formatting and +$You/$you()/$You(key) and $conj(verb) inline function callables. +The key is taken from the mapping kwarg {“key”: object, …}**. +The mapping[key].get_display_name(looker=recipient) will be called +for that key for every recipient of the string.

      • exclude (list, optional) – A list of objects not to send to.

      • from_obj (Object, optional) – An object designated as the “sender” of the message. See DefaultObject.msg() for more info.

      • mapping (dict, optional) – A mapping of formatting keys -{“key”:<object>, “key2”:<object2>,…}. The keys -must match **{key} markers in the text if this is a string or -in the internal message if text is a tuple. These -formatting statements will be -replaced by the return of <object>.get_display_name(looker) -for every looker in contents that receives the -message. This allows for every object to potentially -get its own customized string.

      • - - -
        Keyword Arguments
        -
          -
        • arguments will be passed on to obj.msg() for all (Keyword) –

        • -
        • objects. (messaged) –

        • +{“key”:<object>, “key2”:<object2>,…}. +The keys must either match **{key} or $You(key)/$you(key) markers +in the text string. If <object> doesn’t have a get_display_name +method, it will be returned as a string. If not set, a key you will +be auto-added to point to from_obj if given, otherwise to self.

          +
        • **kwargs – Keyword arguments will be passed on to obj.msg() for all +messaged objects.

        Notes

        -

        The mapping argument is required if message contains -{}-style format syntax. The keys of mapping should match -named format tokens, and its values will have their -get_display_name() function called for each object in -the room before substitution. If an item in the mapping does -not have get_display_name(), its string value will be used.

        -

        Example

        -

        Say Char is a Character object and Npc is an NPC object:

        -
        -
        char.location.msg_contents(

        “{attacker} kicks {defender}”, -mapping=dict(attacker=char, defender=npc), exclude=(char, npc))

        -
        -
        -

        This will result in everyone in the room seeing ‘Char kicks NPC’ -where everyone may potentially see different results for Char and Npc -depending on the results of char.get_display_name(looker) and -npc.get_display_name(looker) for each particular onlooker

        +

        For ‘actor-stance’ reporting (You say/Name says), use the +$You()/$you()/$You(key) and $conj(verb) (verb-conjugation) +inline callables. This will use the respective get_display_name() +for all onlookers except for from_obj or self, which will become +‘You/you’. If you use $You/you(key), the key must be in mapping.

        +

        For ‘director-stance’ reporting (Name says/Name says), use {key} +syntax directly. For both {key} and You/you(key), +mapping[key].get_display_name(looker=recipient) may be called +depending on who the recipient is.

        +

        Examples

        +

        Let’s assume +- player1.key -> “Player1”,

        +
        +

        player1.get_display_name(looker=player2) -> “The First girl”

        +
        +
          +
        • player2.key -> “Player2”, +player2.get_display_name(looker=player1) -> “The Second girl”

        • +
        +

        Actor-stance:

        +
        char.location.msg_contents(
        +    "$You() $conj(attack) $you(defender).",
        +    mapping={"defender": player2})
        +
        +
        +
          +
        • player1 will see You attack The Second girl.

        • +
        • player2 will see ‘The First girl attacks you.’

        • +
        +

        Director-stance:

        +
        char.location.msg_contents(
        +    "{attacker} attacks {defender}.",
        +    mapping={"attacker:player1, "defender":player2})
        +
        +
        +
          +
        • player1 will see: ‘Player1 attacks The Second girl.’

        • +
        • player2 will see: ‘The First girl attacks Player2’

        • +
        @@ -684,8 +724,8 @@ specified, the copy will be named <old_key>_copy by default.

        at_object_post_copy(new_obj, **kwargs)[source]
        -

        Called by DefaultObject.copy(). Meant to be overloaded. In case there’s extra data not covered by -.copy(), this can be used to deal with it.

        +

        Called by DefaultObject.copy(). Meant to be overloaded. In case there’s extra data not +covered by .copy(), this can be used to deal with it.

        Parameters

        new_obj (Object) – The new Copy of this object.

        @@ -1367,7 +1407,8 @@ text from the object. Returning None aborts the command.

        a say. This is sent by the whisper command by default. Other verbal commands could use this hook in similar ways.

        -
      • receivers (Object or iterable) – If set, this is the target or targets for the say/whisper.

      • +
      • receivers (Object or iterable) – If set, this is the target or targets for the +say/whisper.

      • Returns
        @@ -1392,8 +1433,8 @@ re-writing it completely.

      • msg_self (bool or str, optional) – If boolean True, echo message to self. If a string, return that message. If False or unset, don’t echo to self.

      • msg_location (str, optional) – The message to echo to self’s location.

      • -
      • receivers (Object or iterable, optional) – An eventual receiver or receivers of the message -(by default only used by whispers).

      • +
      • receivers (Object or iterable, optional) – An eventual receiver or receivers of the +message (by default only used by whispers).

      • msg_receivers (str) – Specific message to pass to the receiver(s). This will parsed with the {receiver} placeholder replaced with the given receiver.

      • @@ -1495,6 +1536,37 @@ errors (list): A list of errors in string form, if any.

        +
        +
        +classmethod normalize_name(name)[source]
        +

        Normalize the character name prior to creating. Note that this should be refactored to +support i18n for non-latin scripts, but as we (currently) have no bug reports requesting +better support of non-latin character sets, requiring character names to be latinified is an +acceptable option.

        +
        +
        Parameters
        +

        name (str) – The name of the character

        +
        +
        Returns
        +

        latin_name (str) – A valid name.

        +
        +
        +
        + +
        +
        +classmethod validate_name(name)[source]
        +

        Validate the character name prior to creating. Overload this function to add custom validators

        +
        +
        Parameters
        +

        name (str) – The name of the character

        +
        +
        Returns
        +

        valid (bool) – True if character creation should continue; False if it should fail

        +
        +
        +
        +
        basetype_setup()[source]
        @@ -1699,7 +1771,8 @@ overriding the call (unused by default).

        Returns
        -

        A string with identifying information to disambiguate the command, conventionally with a preceding space.

        +

        A string with identifying information to disambiguate the command, conventionally with a +preceding space.

        @@ -1724,6 +1797,11 @@ overriding the call (unused by default).

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'command', 'tags': '', 'text': '\n This is a command that simply cause the caller to traverse\n the object it is attached to.\n\n '}
        +
        +
        @@ -1933,7 +2011,6 @@ read for an error string instead.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1950,6 +2027,7 @@ read for an error string instead.

        +
        develop branch
        @@ -92,7 +93,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -109,6 +109,7 @@ +
        develop branch
        @@ -197,7 +198,6 @@ prototype rather than creating a new one.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -214,6 +214,7 @@ prototype rather than creating a new one.

        +
        develop branch
        @@ -39,188 +40,43 @@

        evennia.prototypes.protfuncs

        -

        Protfuncs are function-strings embedded in a prototype and allows for a builder to create a -prototype with custom logics without having access to Python. The Protfunc is parsed using the -inlinefunc parser but is fired at the moment the spawning happens, using the creating object’s -session as input.

        +

        Protfuncs are FuncParser-callables that can be embedded in a prototype to +provide custom logic without having access to Python. The protfunc is parsed at +the time of spawning, using the creating object’s session as input. If the +protfunc returns a non-string, this is what will be added to the prototype.

        In the prototype dict, the protfunc is specified as a string inside the prototype, e.g.:

        { …

        -

        “key”: “$funcname(arg1, arg2, …)”

        +

        “key”: “$funcname(args, kwargs)”

        … }

        -

        and multiple functions can be nested (no keyword args are supported). The result will be used as the -value for that prototype key for that individual spawn.

        -

        Available protfuncs are callables in one of the modules of settings.PROT_FUNC_MODULES. They -are specified as functions

        +

        Available protfuncs are either all callables in one of the modules of settings.PROT_FUNC_MODULES +or all callables added to a dict FUNCPARSER_CALLABLES in such a module.

        def funcname (*args, **kwargs)

        -

        where *args are the arguments given in the prototype, and **kwargs are inserted by Evennia:

        +

        At spawn-time the spawner passes the following extra kwargs into each callable (in addition to +what is added in the call itself):

        • session (Session): The Session of the entity spawning using this prototype.

        • prototype (dict): The dict this protfunc is a part of.

        • current_key (str): The active key this value belongs to in the prototype.

        • -
        • -
          testing (bool): This is set if this function is called as part of the prototype validation; if

          set, the protfunc should take care not to perform any persistent actions, such as operate on -objects or add things to the database.

          -
          -
          -

        Any traceback raised by this function will be handled at the time of spawning and abort the spawn before any object is created/updated. It must otherwise return the value to store for the specified prototype key (this value must be possible to serialize in an Attribute).

        -
        -evennia.prototypes.protfuncs.base_random()
        -

        random() -> x in the interval [0, 1).

        -
        - -
        -
        -evennia.prototypes.protfuncs.random(*args, **kwargs)[source]
        -

        Usage: $random() -Returns a random value in the interval [0, 1)

        -
        - -
        -
        -evennia.prototypes.protfuncs.randint(*args, **kwargs)[source]
        -

        Usage: $randint(start, end) -Returns random integer in interval [start, end]

        -
        - -
        -
        -evennia.prototypes.protfuncs.left_justify(*args, **kwargs)[source]
        -

        Usage: $left_justify(<text>) -Returns <text> left-justified.

        -
        - -
        -
        -evennia.prototypes.protfuncs.right_justify(*args, **kwargs)[source]
        -

        Usage: $right_justify(<text>) -Returns <text> right-justified across screen width.

        -
        - -
        -
        -evennia.prototypes.protfuncs.center_justify(*args, **kwargs)[source]
        -

        Usage: $center_justify(<text>) -Returns <text> centered in screen width.

        -
        - -
        -
        -evennia.prototypes.protfuncs.choice(*args, **kwargs)[source]
        -

        Usage: $choice(val, val, val, …) -Returns one of the values randomly

        -
        - -
        -
        -evennia.prototypes.protfuncs.full_justify(*args, **kwargs)[source]
        -

        Usage: $full_justify(<text>) -Returns <text> filling up screen width by adding extra space.

        -
        - -
        -
        -evennia.prototypes.protfuncs.protkey(*args, **kwargs)[source]
        -

        Usage: $protkey(<key>) +

        +evennia.prototypes.protfuncs.protfunc_callable_protkey(*args, **kwargs)[source]
        +

        Usage: $protkey(keyname) Returns the value of another key in this prototoype. Will raise an error if

        the key is not found in this prototype.

        -
        -
        -evennia.prototypes.protfuncs.add(*args, **kwargs)[source]
        -

        Usage: $add(val1, val2) -Returns the result of val1 + val2. Values must be

        -
        -

        valid simple Python structures possible to add, -such as numbers, lists etc.

        -
        -
        - -
        -
        -evennia.prototypes.protfuncs.sub(*args, **kwargs)[source]
        -

        Usage: $del(val1, val2) -Returns the value of val1 - val2. Values must be

        -
        -

        valid simple Python structures possible to -subtract.

        -
        -
        - -
        -
        -evennia.prototypes.protfuncs.mult(*args, **kwargs)[source]
        -

        Usage: $mul(val1, val2) -Returns the value of val1 * val2. The values must be

        -
        -

        valid simple Python structures possible to -multiply, like strings and/or numbers.

        -
        -
        - -
        -
        -evennia.prototypes.protfuncs.div(*args, **kwargs)[source]
        -

        Usage: $div(val1, val2) -Returns the value of val1 / val2. Values must be numbers and

        -
        -

        the result is always a float.

        -
        -
        - -
        -
        -evennia.prototypes.protfuncs.toint(*args, **kwargs)[source]
        -

        Usage: $toint(<number>) -Returns <number> as an integer.

        -
        - -
        -
        -evennia.prototypes.protfuncs.eval(*args, **kwargs)[source]
        -

        Usage $eval(<expression>) -Returns evaluation of a simple Python expression. The string may only consist of the following

        -
        -

        Python literal structures: strings, numbers, tuples, lists, dicts, booleans, -and None. The strings can also contain #dbrefs. Escape embedded protfuncs as $$protfunc(..) -- those will then be evaluated after $eval.

        -
        -
        - -
        -
        -evennia.prototypes.protfuncs.obj(*args, **kwargs)[source]
        -

        Usage $obj(<query>) -Returns one Object searched globally by key, alias or #dbref. Error if more than one.

        -
        - -
        -
        -evennia.prototypes.protfuncs.objlist(*args, **kwargs)[source]
        -

        Usage $objlist(<query>) -Returns list with one or more Objects searched globally by key, alias or #dbref.

        -
        - -
        -
        -evennia.prototypes.protfuncs.dbref(*args, **kwargs)[source]
        -

        Usage $dbref(<#dbref>) -Validate that a #dbref input is valid.

        -
        -
        @@ -266,7 +122,6 @@ Validate that a #dbref input is valid.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -283,6 +138,7 @@ Validate that a #dbref input is valid.

        +
        develop branch
        @@ -340,7 +341,7 @@ with (it may still be useful as a mix-in prototype).

        -evennia.prototypes.prototypes.protfunc_parser(value, available_functions=None, testing=False, stacktrace=False, **kwargs)[source]
        +evennia.prototypes.prototypes.protfunc_parser(value, available_functions=None, testing=False, stacktrace=False, caller=None, **kwargs)[source]

        Parse a prototype value string for a protfunc and process it.

        Available protfuncs are specified as callables in one of the modules of settings.PROTFUNC_MODULES, or specified on the command line.

        @@ -351,8 +352,6 @@ with (it may still be useful as a mix-in prototype).

        protfuncs, all other types are returned as-is.

      • available_functions (dict, optional) – Mapping of name:protfunction to use for this parsing. If not set, use default sources.

      • -
      • testing (bool, optional) – Passed to protfunc. If in a testing mode, some protfuncs may -behave differently.

      • stacktrace (bool, optional) – If set, print the stack parsing process of the protfunc-parser.

      • @@ -361,22 +360,15 @@ behave differently.

      • session (Session) – Passed to protfunc. Session of the entity spawning the prototype.

      • protototype (dict) – Passed to protfunc. The dict this protfunc is a part of.

      • current_key (str) – Passed to protfunc. The key in the prototype that will hold this value.

      • +
      • caller (Object or Account) – This is necessary for certain protfuncs that perform object +searches and have to check permissions.

      • any (any) – Passed on to the protfunc.

      • Returns
        -

        testresult (tuple)

        -
        -
        If testing is set, returns a tuple (error, result) where error is

        either None or a string detailing the error from protfunc_parser or seen when trying to -run literal_eval on the parsed string.

        -
        -
        any (any): A structure to replace the string on the prototype level. If this is a

        callable or a (callable, (args,)) structure, it will be executed as if one had supplied -it to the prototype directly. This structure is also passed through literal_eval so one -can get actual Python primitives out of it (not just strings). It will also identify -eventual object #dbrefs in the output from the protfunc.

        -
        -
        -

        +

        any – A structure to replace the string on the prototype leve. Note +that FunctionParser functions $funcname(*args, **kwargs) can return any +data type to insert into the prototype.

        @@ -423,18 +415,22 @@ eventual object #dbrefs in the output from the protfunc.

        -evennia.prototypes.prototypes.init_spawn_value(value, validator=None)[source]
        +evennia.prototypes.prototypes.init_spawn_value(value, validator=None, caller=None)[source]

        Analyze the prototype value and produce a value useful at the point of spawning.

        Parameters

        value (any) –

        This can be: callable - will be called as callable() -(callable, (args,)) - will be called as callable(*args) +(callable, (args,)) - will be called as callable(*args) other - will be assigned depending on the variable type validator (callable, optional): If given, this will be called with the value to

        check and guarantee the outcome is of a given type.

        +
        +
        caller (Object or Account): This is necessary for certain protfuncs that perform object

        searches and have to check permissions.

        +
        +

        Returns
        @@ -500,7 +496,6 @@ validator (callable, optional): If given, this will be called with the value to<
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -517,6 +512,7 @@ validator (callable, optional): If given, this will be called with the value to< +
        develop branch
        @@ -80,7 +81,7 @@ prototype_locks (str, optional): locks for restricting access to this prototype.
        prototype_tags(list, optional): List of tags or tuples (tag, category) used to group prototype

        in listings

        -
        prototype_parent (str, tuple or callable, optional): name (prototype_key) of eventual parent prototype, or

        a list of parents, for multiple left-to-right inheritance.

        +
        prototype_parent (str, tuple or callable, optional): name (prototype_key) of eventual parent

        prototype, or a list of parents, for multiple left-to-right inheritance.

        prototype: Deprecated. Same meaning as ‘parent’.

        @@ -224,8 +225,8 @@ attr/tag (for example) are represented by a tuple.

        This is most useful for displaying.

      • implicit_keep (bool, optional) – If set, the resulting diff will assume KEEP unless the new prototype explicitly change them. That is, if a key exists in prototype1 and -not in prototype2, it will not be REMOVEd but set to KEEP instead. This is particularly -useful for auto-generated prototypes when updating objects.

      • +not in prototype2, it will not be REMOVEd but set to KEEP instead. This is +particularly useful for auto-generated prototypes when updating objects.

        Returns
        @@ -349,7 +350,7 @@ of the olc _format_diff_text_and_options without the options.

        -evennia.prototypes.spawner.batch_update_objects_with_prototype(prototype, diff=None, objects=None, exact=False)[source]
        +evennia.prototypes.spawner.batch_update_objects_with_prototype(prototype, diff=None, objects=None, exact=False, caller=None)[source]

        Update existing objects with the latest version of the prototype.

        Parameters
        @@ -366,6 +367,7 @@ expected - for example, one usually do not want to remove the object’s locatio if it’s not set in the prototype. With exact=True, all un-specified properties of the objects will be removed if they exist. This will lead to a more accurate 1:1 correlation between the object and the prototype but is usually impractical.

        +
      • caller (Object or Account, optional) – This may be used by protfuncs to do permission checks.

      • Returns
        @@ -435,7 +437,7 @@ unprivileged users!

        -evennia.prototypes.spawner.spawn(*prototypes, **kwargs)[source]
        +evennia.prototypes.spawner.spawn(*prototypes, caller=None, **kwargs)[source]

        Spawn a number of prototyped objects.

        Parameters
        @@ -445,6 +447,7 @@ dictionary. These will be batched-spawned as one object each.

        Keyword Arguments
          +
        • caller (Object or Account, optional) – This may be used by protfuncs to do access checks.

        • prototype_modules (str or list) – A python-path to a prototype module, or a list of such paths. These will be used to build the global protparents dictionary accessible by the input @@ -518,7 +521,6 @@ custom prototype_parents are given to this function.

        • 0.9.5 (v0.9.5 branch)
        -
        @@ -535,6 +537,7 @@ custom prototype_parents are given to this function.

        +
        develop branch
        @@ -99,7 +100,6 @@ timed effects.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -116,6 +116,7 @@ timed effects.

        +
        develop branch
        @@ -91,7 +92,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -108,6 +108,7 @@ +
        develop branch
        @@ -378,7 +379,6 @@ class built by **create_forward_many_to_many_manager()** define
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -395,6 +395,7 @@ class built by **create_forward_many_to_many_manager()** define +
        develop branch
        @@ -200,7 +201,6 @@ all kwargs must be possible to pickle!

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -217,6 +217,7 @@ all kwargs must be possible to pickle!

        +
        develop branch
        @@ -138,25 +139,6 @@ If no key is given, delete all scripts on the object!

        Get all scripts stored in this handler.

        -
        -
        -validate(init_mode=False)[source]
        -

        Runs a validation on this object’s scripts only. This should -be called regularly to crank the wheels.

        -
        -
        Parameters
        -

        init_mode (str, optional) –

          -
        • This is used during server

        • -
        -

        upstart and can have three values: -- False (no init mode). Called during run. -- “reset” - server reboot. Kill non-persistent scripts -- “reload” - server reload. Keep non-persistent scripts.

        -

        -
        -
        -
        - @@ -204,7 +186,6 @@ be called regularly to crank the wheels.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -221,6 +202,7 @@ be called regularly to crank the wheels.

        +
        develop branch
        @@ -70,182 +71,20 @@ errors (list): A list of errors in string form, if any.

        Only called once, when script is first created.

        -
        -
        -time_until_next_repeat()[source]
        -

        Get time until the script fires it at_repeat hook again.

        -
        -
        Returns
        -

        next (int)

        -
        -
        Time in seconds until the script runs again.

        If not a timed script, return None.

        -
        -
        -

        -
        -
        -

        Notes

        -

        This hook is not used in any way by the script’s stepping -system; it’s only here for the user to be able to check in -on their scripts and when they will next be run.

        -
        - -
        -
        -remaining_repeats()[source]
        -

        Get the number of returning repeats for limited Scripts.

        -
        -
        Returns
        -

        remaining (int or None) –

        -
        -
        The number of repeats

        remaining until the Script stops. Returns None -if it has unlimited repeats.

        -
        -
        -

        -
        -
        -
        - -
        -
        -at_idmapper_flush()[source]
        -

        If we’re flushing this object, make sure the LoopingCall is gone too

        -
        - -
        -
        -start(force_restart=False)[source]
        -

        Called every time the script is started (for persistent -scripts, this is usually once every server start)

        -
        -
        Parameters
        -

        force_restart (bool, optional) – Normally an already -started script will not be started again. if -force_restart=True, the script will always restart -the script, regardless of if it has started before.

        -
        -
        Returns
        -

        result (int)

        -
        -
        0 or 1 depending on if the script successfully

        started or not. Used in counting.

        -
        -
        -

        -
        -
        -
        - -
        -
        -stop(kill=False)[source]
        -

        Called to stop the script from running. This also deletes the -script.

        -
        -
        Parameters
        -

        kill (bool, optional) –

          -
        • Stop the script without

        • -
        -

        calling any relevant script hooks.

        -

        -
        -
        Returns
        -

        result (int)

        -
        -
        0 if the script failed to stop, 1 otherwise.

        Used in counting.

        -
        -
        -

        -
        -
        -
        - -
        -
        -pause(manual_pause=True)[source]
        -

        This stops a running script and stores its active state. -It WILL NOT call the at_stop() hook.

        -
        - -
        -
        -unpause(manual_unpause=True)[source]
        -

        Restart a paused script. This WILL call the at_start() hook.

        -
        -
        Parameters
        -

        manual_unpause (bool, optional) – This is False if unpause is -called by the server reload/reset mechanism.

        -
        -
        Returns
        -

        result (bool) – True if unpause was triggered, False otherwise.

        -
        -
        Raises
        -

        RuntimeError – If trying to automatically resart this script -(usually after a reset/reload), but it was manually paused, -and so should not the auto-unpaused.

        -
        -
        -
        - -
        -
        -restart(interval=None, repeats=None, start_delay=None)[source]
        -

        Restarts an already existing/running Script from the -beginning, optionally using different settings. This will -first call the stop hooks, and then the start hooks again. -:param interval: Allows for changing the interval

        -
        -

        of the Script. Given in seconds. if None, will use the already stored interval.

        -
        -
        -
        Parameters
        -
          -
        • repeats (int, optional) – The number of repeats. If unset, will -use the previous setting.

        • -
        • start_delay (bool, optional) – If we should wait interval seconds -before starting or not. If None, re-use the previous setting.

        • -
        -
        -
        -
        - -
        -
        -reset_callcount(value=0)[source]
        -

        Reset the count of the number of calls done.

        -
        -
        Parameters
        -

        value (int, optional) – The repeat value to reset to. Default -is to set it all the way back to 0.

        -
        -
        -

        Notes

        -

        This is only useful if repeats != 0.

        -
        - -
        -
        -force_repeat()[source]
        -

        Fire a premature triggering of the script callback. This -will reset the timer and count down repeats as if the script -had fired normally.

        -
        -
        is_valid()[source]
        -

        Is called to check if the script is valid to run at this time. -Should return a boolean. The method is assumed to collect all -needed information from its related self.obj.

        +

        Is called to check if the script’s timer is valid to run at this time. +Should return a boolean. If False, the timer will be stopped.

        at_start(**kwargs)[source]
        -

        Called whenever the script is started, which for persistent -scripts is at least once every server start. It will also be -called when starting again after a pause (such as after a -server reload)

        +

        Called whenever the script timer is started, which for persistent +timed scripts is at least once every server start. It will also be +called when starting again after a pause (including after a +server reload).

        Parameters

        **kwargs (dict) – Arbitrary, optional arguments for users @@ -266,20 +105,39 @@ overriding the call (unused by default).

        +
        +
        +at_pause(manual_pause=True, **kwargs)[source]
        +

        Called when this script’s timer pauses.

        +
        +
        Parameters
        +

        manual_pause (bool) – If set, pausing was done by a direct call. The +non-manual pause indicates the script was paused as part of +the server reload.

        +
        +
        +
        +
        at_stop(**kwargs)[source]
        -

        Called whenever when it’s time for this script to stop (either -because is_valid returned False or it runs out of iterations)

        -
        -
        Args
        -
        **kwargs (dict): Arbitrary, optional arguments for users

        overriding the call (unused by default).

        -
        -
        +

        Called whenever when it’s time for this script’s timer to stop (either +because is_valid returned False, it ran out of iterations or it was manuallys +stopped.

        +
        +
        Parameters
        +

        **kwargs (dict) – Arbitrary, optional arguments for users +overriding the call (unused by default).

        +
        +
        +at_script_delete()[source]
        +

        Called when the Script is deleted, after at_stop().

        +
        +
        at_server_reload()[source]
        @@ -296,6 +154,14 @@ to do it.

        (i.e. not for a restart).

        +
        +
        +at_server_start()[source]
        +

        This hook is called after the server has started. It can be used to add +post-startup setup for Scripts without a timer component (for which at_start +could be used).

        +
        +
        exception DoesNotExist
        @@ -435,7 +301,6 @@ to do it.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -452,6 +317,7 @@ to do it.

        +
        develop branch
        @@ -139,7 +140,7 @@ called(self): A task attribute to check if the deferred instance of a task has b
        pause()[source]

        Pause the callback of a task. -To resume use TaskHandlerTask.unpause

        +To resume use TaskHandlerTask.unpause.

        @@ -440,8 +441,7 @@ Deletes the instance of the task’s deferred.

        clear(save=True, cancel=True)[source]
        -

        clear all tasks. -By default tasks are canceled and removed from the database also.

        +

        Clear all tasks. By default tasks are canceled and removed from the database as well.

        Parameters
          @@ -564,7 +564,6 @@ This method should be automatically called when Evennia starts.

        • 0.9.5 (v0.9.5 branch)
        -
        @@ -581,6 +580,7 @@ This method should be automatically called when Evennia starts.

        +
        develop branch
        @@ -428,7 +429,6 @@ non-db objects.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -445,6 +445,7 @@ non-db objects.

        +
        develop branch
        @@ -266,7 +267,6 @@ operation, as defined by the global variables in
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -283,6 +283,7 @@ operation, as defined by the global variables in +
        develop branch
        @@ -205,7 +206,6 @@ fails (and is expected to echo why if so).

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -222,6 +222,7 @@ fails (and is expected to echo why if so).

        +
        develop branch
        @@ -109,7 +110,6 @@ does not stop launch.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -126,6 +126,7 @@ does not stop launch.

        +
        develop branch
        @@ -583,7 +584,6 @@ settings here. The result will be printed to the terminal.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -600,6 +600,7 @@ settings here. The result will be printed to the terminal.

        +
        develop branch
        @@ -195,7 +196,6 @@ to this Protocol. The connection has been closed.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -212,6 +212,7 @@ to this Protocol. The connection has been closed.

        +
        develop branch
        @@ -90,7 +91,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -107,6 +107,7 @@ +
        develop branch
        @@ -114,7 +115,6 @@ to the Evennia Game Index.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -131,6 +131,7 @@ to the Evennia Game Index.

        +
        develop branch
        @@ -151,7 +152,6 @@ to connect to the game.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -168,6 +168,7 @@ to connect to the game.

        +
        develop branch
        @@ -144,7 +145,6 @@ steps need to be redone.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -161,6 +161,7 @@ steps need to be redone.

        +
        develop branch
        @@ -383,7 +384,6 @@ logging a missing inputfunc for it.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -400,6 +400,7 @@ logging a missing inputfunc for it.

        +
        develop branch
        @@ -122,7 +123,6 @@ value (str): If key was given, this is the stored value, or

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -139,6 +139,7 @@ value (str): If key was given, this is the stored value, or

        +
        develop branch
        @@ -176,7 +177,6 @@ object the first time, the query is executed.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -193,6 +193,7 @@ object the first time, the query is executed.

        +
        develop branch
        @@ -436,13 +437,13 @@ that way.

        -errback(e, info)[source]
        +errback(err, info)[source]

        Error callback. Handles errors to avoid dropping connections on server tracebacks.

        Parameters
          -
        • e (Failure) – Deferred error instance.

        • +
        • err (Failure) – Deferred error instance.

        • info (str) – Error string.

        @@ -559,7 +560,6 @@ function call

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -576,6 +576,7 @@ function call

        +
        develop branch
        @@ -77,7 +78,7 @@ these are the Evennia Server and the evennia launcher).

        Parameters
          -
        • portal (Portal) – The Evennia Portal service instance.

        • +
        • portal (Portal) – The Evennia Portal service instance.

        • protocol (Protocol) – The protocol the factory creates instances of.

        @@ -307,7 +308,6 @@ global variables in evennia/server/amp.py.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -324,6 +324,7 @@ global variables in evennia/server/amp.py.

        +
        develop branch
        @@ -304,7 +305,6 @@ disconnect this protocol.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -321,6 +321,7 @@ disconnect this protocol.

        +
        develop branch
        @@ -109,7 +110,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -126,6 +126,7 @@ +
        develop branch
        @@ -420,7 +421,6 @@ sessions.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -437,6 +437,7 @@ sessions.

        +
        develop branch
        @@ -37,8 +38,78 @@
        -
        -

        evennia.server.portal.mccp

        +
        +

        evennia.server.portal.mccp

        +

        MCCP - Mud Client Compression Protocol

        +

        This implements the MCCP v2 telnet protocol as per +http://tintin.sourceforge.net/mccp/. MCCP allows for the server to +compress data when sending to supporting clients, reducing bandwidth +by 70-90%.. The compression is done using Python’s builtin zlib +library. If the client doesn’t support MCCP, server sends uncompressed +as normal. Note: On modern hardware you are not likely to notice the +effect of MCCP unless you have extremely heavy traffic or sits on a +terribly slow connection.

        +

        This protocol is implemented by the telnet protocol importing +mccp_compress and calling it from its write methods.

        +
        +
        +evennia.server.portal.mccp.mccp_compress(protocol, data)[source]
        +

        Handles zlib compression, if applicable.

        +
        +
        Parameters
        +

        data (str) – Incoming data to compress.

        +
        +
        Returns
        +

        stream (binary) – Zlib-compressed data.

        +
        +
        +
        + +
        +
        +class evennia.server.portal.mccp.Mccp(protocol)[source]
        +

        Bases: object

        +

        Implements the MCCP protocol. Add this to a +variable on the telnet protocol to set it up.

        +
        +
        +__init__(protocol)[source]
        +

        initialize MCCP by storing protocol on +ourselves and calling the client to see if +it supports MCCP. Sets callbacks to +start zlib compression in that case.

        +
        +
        Parameters
        +

        protocol (Protocol) – The active protocol instance.

        +
        +
        +
        + +
        +
        +no_mccp(option)[source]
        +

        Called if client doesn’t support mccp or chooses to turn it off.

        +
        +
        Parameters
        +

        option (Option) – Option dict (not used).

        +
        +
        +
        + +
        +
        +do_mccp(option)[source]
        +

        The client supports MCCP. Set things up by +creating a zlib compression stream.

        +
        +
        Parameters
        +

        option (Option) – Option dict (not used).

        +
        +
        +
        + +
        +
        @@ -84,7 +155,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +171,7 @@ +
        develop branch
        @@ -37,8 +38,79 @@
        -
        -

        evennia.server.portal.mssp

        +
        +

        evennia.server.portal.mssp

        +

        MSSP - Mud Server Status Protocol

        +

        This implements the MSSP telnet protocol as per +http://tintin.sourceforge.net/mssp/. MSSP allows web portals and +listings to have their crawlers find the mud and automatically +extract relevant information about it, such as genre, how many +active players and so on.

        +
        +
        +class evennia.server.portal.mssp.Mssp(protocol)[source]
        +

        Bases: object

        +

        Implements the MSSP protocol. Add this to a variable on the telnet +protocol to set it up.

        +
        +
        +__init__(protocol)[source]
        +

        initialize MSSP by storing protocol on ourselves and calling +the client to see if it supports MSSP.

        +
        +
        Parameters
        +

        protocol (Protocol) – The active protocol instance.

        +
        +
        +
        + +
        +
        +get_player_count()[source]
        +

        Get number of logged-in players.

        +
        +
        Returns
        +

        count (int) – The number of players in the MUD.

        +
        +
        +
        + +
        +
        +get_uptime()[source]
        +

        Get how long the portal has been online (reloads are not counted).

        +
        +
        Returns
        +

        uptime (int) – Number of seconds of uptime.

        +
        +
        +
        + +
        +
        +no_mssp(option)[source]
        +

        Called when mssp is not requested. This is the normal +operation.

        +
        +
        Parameters
        +

        option (Option) – Not used.

        +
        +
        +
        + +
        +
        +do_mssp(option)[source]
        +

        Negotiate all the information.

        +
        +
        Parameters
        +

        option (Option) – Not used.

        +
        +
        +
        + +
        +
        @@ -84,7 +156,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +172,7 @@ +
        develop branch
        @@ -37,8 +38,71 @@
        -
        -

        evennia.server.portal.mxp

        +
        +

        evennia.server.portal.mxp

        +

        MXP - Mud eXtension Protocol.

        +

        Partial implementation of the MXP protocol. +The MXP protocol allows more advanced formatting options for telnet clients +that supports it (mudlet, zmud, mushclient are a few)

        +

        This only implements the SEND tag.

        +

        More information can be found on the following links: +http://www.zuggsoft.com/zmud/mxp.htm +http://www.mushclient.com/mushclient/mxp.htm +http://www.gammon.com.au/mushclient/addingservermxp.htm

        +
        +
        +evennia.server.portal.mxp.mxp_parse(text)[source]
        +

        Replaces links to the correct format for MXP.

        +
        +
        Parameters
        +

        text (str) – The text to parse.

        +
        +
        Returns
        +

        parsed (str) – The parsed text.

        +
        +
        +
        + +
        +
        +class evennia.server.portal.mxp.Mxp(protocol)[source]
        +

        Bases: object

        +

        Implements the MXP protocol.

        +
        +
        +__init__(protocol)[source]
        +

        Initializes the protocol by checking if the client supports it.

        +
        +
        Parameters
        +

        protocol (Protocol) – The active protocol instance.

        +
        +
        +
        + +
        +
        +no_mxp(option)[source]
        +

        Called when the Client reports to not support MXP.

        +
        +
        Parameters
        +

        option (Option) – Not used.

        +
        +
        +
        + +
        +
        +do_mxp(option)[source]
        +

        Called when the Client reports to support MXP.

        +
        +
        Parameters
        +

        option (Option) – Not used.

        +
        +
        +
        + +
        +
        @@ -84,7 +148,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +164,7 @@ +
        develop branch
        @@ -37,8 +38,67 @@
        -
        -

        evennia.server.portal.naws

        +
        +

        evennia.server.portal.naws

        +

        NAWS - Negotiate About Window Size

        +

        This implements the NAWS telnet option as per +https://www.ietf.org/rfc/rfc1073.txt

        +

        NAWS allows telnet clients to report their current window size to the +client and update it when the size changes

        +
        +
        +class evennia.server.portal.naws.Naws(protocol)[source]
        +

        Bases: object

        +

        Implements the NAWS protocol. Add this to a variable on the telnet +protocol to set it up.

        +
        +
        +__init__(protocol)[source]
        +

        initialize NAWS by storing protocol on ourselves and calling +the client to see if it supports NAWS.

        +
        +
        Parameters
        +

        protocol (Protocol) – The active protocol instance.

        +
        +
        +
        + +
        +
        +no_naws(option)[source]
        +

        Called when client is not reporting NAWS. This is the normal +operation.

        +
        +
        Parameters
        +

        option (Option) – Not used.

        +
        +
        +
        + +
        +
        +do_naws(option)[source]
        +

        Client wants to negotiate all the NAWS information.

        +
        +
        Parameters
        +

        option (Option) – Not used.

        +
        +
        +
        + +
        +
        +negotiate_sizes(options)[source]
        +

        Step through the NAWS handshake.

        +
        +
        Parameters
        +

        option (list) – The incoming NAWS options.

        +
        +
        +
        + +
        +
        @@ -84,7 +144,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +160,7 @@ +
        develop branch
        @@ -37,8 +38,66 @@
        -
        -

        evennia.server.portal.portal

        +
        +

        evennia.server.portal.portal

        +

        This module implements the main Evennia server process, the core of +the game engine.

        +

        This module should be started with the ‘twistd’ executable since it +sets up all the networking features. (this is done automatically +by game/evennia.py).

        +
        +
        +class evennia.server.portal.portal.Portal(application)[source]
        +

        Bases: object

        +

        The main Portal server handler. This object sets up the database +and tracks and interlinks all the twisted network services that +make up Portal.

        +
        +
        +__init__(application)[source]
        +

        Setup the server.

        +
        +
        Parameters
        +

        application (Application) – An instantiated Twisted application

        +
        +
        +
        + +
        +
        +get_info_dict()[source]
        +

        Return the Portal info, for display.

        +
        + +
        +
        +shutdown(_reactor_stopping=False, _stop_server=False)[source]
        +

        Shuts down the server from inside it.

        +
        +
        Parameters
        +
          +
        • _reactor_stopping (bool, optional) – This is set if server +is already in the process of shutting down; in this case +we don’t need to stop it again.

        • +
        • _stop_server (bool, optional) – Only used in portal-interactive mode; +makes sure to stop the Server cleanly.

        • +
        +
        +
        +

        Note that restarting (regardless of the setting) will not work +if the Portal is currently running in daemon mode. In that +case it always needs to be restarted manually.

        +
        + +
        + +
        +
        +class evennia.server.portal.portal.Websocket(*args, **kwargs)[source]
        +

        Bases: autobahn.twisted.websocket.WebSocketServerFactory

        +

        Only here for better naming in logs

        +
        +
        @@ -84,7 +143,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +159,7 @@ +
        develop branch
        @@ -39,7 +40,7 @@

        evennia.server.portal.portalsessionhandler

        -

        Sessionhandler for portal sessions

        +

        Sessionhandler for portal sessions.

        class evennia.server.portal.portalsessionhandler.PortalSessionHandler(*args, **kwargs)[source]
        @@ -63,6 +64,17 @@ to the server using the AMP connection.

        At this point, the AMP connection is already established.

        +
        +
        +generate_sessid()[source]
        +

        Simply generates a sessid that’s guaranteed to be unique for this Portal run.

        +
        +
        Returns
        +

        sessid

        +
        +
        +
        +
        connect(session)[source]
        @@ -332,7 +344,6 @@ method exixts, it sends the data to a method send_default.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -349,6 +360,7 @@ method exixts, it sends the data to a method send_default.

        +
        develop branch
        @@ -184,7 +185,6 @@ on slow connections.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -201,6 +201,7 @@ on slow connections.

        +
        develop branch
        @@ -225,18 +226,18 @@ reaching this point.

        are considered.

        Keyword Arguments
        -

        options (dict) –

        Send-option flags:

        +

        options (dict) –

        Send-option flags (booleans)

          -
        • mxp: Enforce MXP link support.

        • -
        • ansi: Enforce no ANSI colors.

        • -
        • xterm256: Enforce xterm256 colors, regardless of TTYPE setting.

        • -
        • nocolor: Strip all colors.

        • -
        • raw: Pass string through without any ansi processing -(i.e. include Evennia ansi markers but do not +

        • mxp: enforce mxp link support.

        • +
        • ansi: enforce no ansi colors.

        • +
        • xterm256: enforce xterm256 colors, regardless of ttype setting.

        • +
        • nocolor: strip all colors.

        • +
        • raw: pass string through without any ansi processing +(i.e. include evennia ansi markers but do not convert them into ansi tokens)

        • -
        • echo: Turn on/off line echo on the client. Turn +

        • echo: turn on/off line echo on the client. turn off line echo for client, for example for password. -Note that it must be actively turned back on again!

        • +note that it must be actively turned back on again!

        @@ -405,7 +406,6 @@ do not exist, the keypair is created.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -422,6 +422,7 @@ do not exist, the keypair is created.

        +
        develop branch
        @@ -37,8 +38,49 @@
        -
        -

        evennia.server.portal.ssl

        +
        +

        evennia.server.portal.ssl

        +

        This is a simple context factory for auto-creating +SSL keys and certificates.

        +
        +
        +class evennia.server.portal.ssl.SSLProtocol(*args, **kwargs)[source]
        +

        Bases: evennia.server.portal.telnet.TelnetProtocol

        +

        Communication is the same as telnet, except data transfer +is done with encryption.

        +
        +
        +__init__(*args, **kwargs)[source]
        +

        Initialize self. See help(type(self)) for accurate signature.

        +
        + +
        + +
        +
        +evennia.server.portal.ssl.verify_SSL_key_and_cert(keyfile, certfile)[source]
        +

        This function looks for RSA key and certificate in the current +directory. If files ssl.key and ssl.cert does not exist, they +are created.

        +
        + +
        +
        +evennia.server.portal.ssl.getSSLContext()[source]
        +

        This is called by the portal when creating the SSL context +server-side.

        +
        +
        Returns
        +

        ssl_context (tuple)

        +
        +
        A key and certificate that is either

        existing previously or or created on the fly.

        +
        +
        +

        +
        +
        +
        +
        @@ -84,7 +126,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +142,7 @@ +
        develop branch
        @@ -37,8 +38,57 @@
        -
        -

        evennia.server.portal.suppress_ga

        +
        +

        evennia.server.portal.suppress_ga

        +

        SUPPRESS-GO-AHEAD

        +

        This supports suppressing or activating Evennia +the GO-AHEAD telnet operation after every server reply. +If the client sends no explicit DONT SUPRESS GO-AHEAD, +Evennia will default to supressing it since many clients +will fail to use it and has no knowledge of this standard.

        +

        It is set as the NOGOAHEAD protocol_flag option.

        +

        http://www.faqs.org/rfcs/rfc858.html

        +
        +
        +class evennia.server.portal.suppress_ga.SuppressGA(protocol)[source]
        +

        Bases: object

        +

        Implements the SUPRESS-GO-AHEAD protocol. Add this to a variable on the telnet +protocol to set it up.

        +
        +
        +__init__(protocol)[source]
        +

        Initialize suppression of GO-AHEADs.

        +
        +
        Parameters
        +

        protocol (Protocol) – The active protocol instance.

        +
        +
        +
        + +
        +
        +wont_suppress_ga(option)[source]
        +

        Called when client requests to not suppress GA.

        +
        +
        Parameters
        +

        option (Option) – Not used.

        +
        +
        +
        + +
        +
        +will_suppress_ga(option)[source]
        +

        Client will suppress GA

        +
        +
        Parameters
        +

        option (Option) – Not used.

        +
        +
        +
        + +
        +
        @@ -84,7 +134,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +150,7 @@ +
        develop branch
        @@ -37,8 +38,250 @@
        -
        -

        evennia.server.portal.telnet

        +
        +

        evennia.server.portal.telnet

        +

        This module implements the telnet protocol.

        +

        This depends on a generic session module that implements +the actual login procedure of the game, tracks +sessions etc.

        +
        +
        +class evennia.server.portal.telnet.TelnetServerFactory[source]
        +

        Bases: twisted.internet.protocol.ServerFactory

        +

        This exists only to name this better in logs.

        +
        +
        +noisy = False
        +
        + +
        +
        +logPrefix()[source]
        +

        Describe this factory for log messages.

        +
        + +
        + +
        +
        +class evennia.server.portal.telnet.TelnetProtocol(*args, **kwargs)[source]
        +

        Bases: twisted.conch.telnet.Telnet, twisted.conch.telnet.StatefulTelnetProtocol, evennia.server.session.Session

        +

        Each player connecting over telnet (ie using most traditional mud +clients) gets a telnet protocol instance assigned to them. All +communication between game and player goes through here.

        +
        +
        +__init__(*args, **kwargs)[source]
        +

        Initialize self. See help(type(self)) for accurate signature.

        +
        + +
        +
        +dataReceived(data)[source]
        +

        Unused by default, but a good place to put debug printouts +of incoming data.

        +
        + +
        +
        +connectionMade()[source]
        +

        This is called when the connection is first established.

        +
        + +
        +
        +toggle_nop_keepalive()[source]
        +

        Allow to toggle the NOP keepalive for those sad clients that +can’t even handle a NOP instruction. This is turned off by the +protocol_flag NOPKEEPALIVE (settable e.g. by the default +option command).

        +
        + +
        +
        +handshake_done(timeout=False)[source]
        +

        This is called by all telnet extensions once they are finished. +When all have reported, a sync with the server is performed. +The system will force-call this sync after a small time to handle +clients that don’t reply to handshakes at all.

        +
        + +
        +
        +at_login()[source]
        +

        Called when this session gets authenticated by the server.

        +
        + +
        +
        +enableRemote(option)[source]
        +

        This sets up the remote-activated options we allow for this protocol.

        +
        +
        Parameters
        +

        option (char) – The telnet option to enable.

        +
        +
        Returns
        +

        enable (bool) – If this option should be enabled.

        +
        +
        +
        + +
        +
        +disableRemote(option)[source]
        +

        Signal a programming error by raising an exception.

        +

        L{enableRemote} must return true for the given value of C{option} in +order for this method to be called. If a subclass of L{Telnet} +overrides enableRemote to allow certain options to be enabled, it must +also override disableRemote tto disable those options.

        +

        @raise NotImplementedError: Always raised.

        +
        + +
        +
        +enableLocal(option)[source]
        +

        Call to allow the activation of options for this protocol

        +
        +
        Parameters
        +

        option (char) – The telnet option to enable locally.

        +
        +
        Returns
        +

        enable (bool) – If this option should be enabled.

        +
        +
        +
        + +
        +
        +disableLocal(option)[source]
        +

        Disable a given option locally.

        +
        +
        Parameters
        +

        option (char) – The telnet option to disable locally.

        +
        +
        +
        + +
        +
        +connectionLost(reason)[source]
        +

        this is executed when the connection is lost for whatever +reason. it can also be called directly, from the disconnect +method

        +
        +
        Parameters
        +

        reason (str) – Motivation for losing connection.

        +
        +
        +
        + +
        +
        +applicationDataReceived(data)[source]
        +

        Telnet method called when non-telnet-command data is coming in +over the telnet connection. We pass it on to the game engine +directly.

        +
        +
        Parameters
        +

        data (str) – Incoming data.

        +
        +
        +
        + +
        +
        +sendLine(line)[source]
        +

        Hook overloading the one used by linereceiver.

        +
        +
        Parameters
        +

        line (str) – Line to send.

        +
        +
        +
        + +
        +
        +disconnect(reason='')[source]
        +

        Generic hook for the engine to call in order to +disconnect this protocol.

        +
        +
        Parameters
        +

        reason (str, optional) – Reason for disconnecting.

        +
        +
        +
        + +
        +
        +data_in(**kwargs)[source]
        +

        Data User -> Evennia

        +
        +
        Keyword Arguments
        +

        kwargs (any) – Options from the protocol.

        +
        +
        +
        + +
        +
        +data_out(**kwargs)[source]
        +

        Data Evennia -> User

        +
        +
        Keyword Arguments
        +

        kwargs (any) – Options to the protocol

        +
        +
        +
        + +
        +
        +send_text(*args, **kwargs)[source]
        +

        Send text data. This is an in-band telnet operation.

        +
        +
        Parameters
        +

        text (str) – The first argument is always the text string to send. No other arguments +are considered.

        +
        +
        Keyword Arguments
        +

        options (dict) –

        Send-option flags

        +
          +
        • mxp: Enforce MXP link support.

        • +
        • ansi: Enforce no ANSI colors.

        • +
        • xterm256: Enforce xterm256 colors, regardless of TTYPE.

        • +
        • noxterm256: Enforce no xterm256 color support, regardless of TTYPE.

        • +
        • nocolor: Strip all Color, regardless of ansi/xterm256 setting.

        • +
        • +
          raw: Pass string through without any ansi processing

          (i.e. include Evennia ansi markers but do not +convert them into ansi tokens)

          +
          +
          +
        • +
        • +
          echo: Turn on/off line echo on the client. Turn

          off line echo for client, for example for password. +Note that it must be actively turned back on again!

          +
          +
          +
        • +
        +

        +
        +
        +
        + +
        +
        +send_prompt(*args, **kwargs)[source]
        +

        Send a prompt - a text without a line end. See send_text for argument options.

        +
        + +
        +
        +send_default(cmdname, *args, **kwargs)[source]
        +

        Send other oob data

        +
        + +
        +
        @@ -84,7 +327,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +343,7 @@ +
        develop branch
        @@ -37,8 +38,220 @@
        -
        -

        evennia.server.portal.telnet_oob

        +
        +

        evennia.server.portal.telnet_oob

        +

        Telnet OOB (Out of band communication)

        +

        OOB protocols allow for asynchronous communication between Evennia and +compliant telnet clients. The “text” type of send command will always +be sent “in-band”, appearing in the client’s main text output. OOB +commands, by contrast, can have many forms and it is up to the client +how and if they are handled. Examples of OOB instructions could be to +instruct the client to play sounds or to update a graphical health +bar.

        +

        Note that in Evennia’s Web client, all send commands are “OOB +commands”, (including the “text” one), there is no equivalence to +MSDP/GMCP for the webclient since it doesn’t need it.

        +

        This implements the following telnet OOB communication protocols:

        + +
        +
        +
        +class evennia.server.portal.telnet_oob.TelnetOOB(protocol)[source]
        +

        Bases: object

        +

        Implements the MSDP and GMCP protocols.

        +
        +
        +__init__(protocol)[source]
        +

        Initiates by storing the protocol on itself and trying to +determine if the client supports MSDP.

        +
        +
        Parameters
        +

        protocol (Protocol) – The active protocol.

        +
        +
        +
        + +
        +
        +no_msdp(option)[source]
        +

        Client reports No msdp supported or wanted.

        +
        +
        Parameters
        +

        option (Option) – Not used.

        +
        +
        +
        + +
        +
        +do_msdp(option)[source]
        +

        Client reports that it supports msdp.

        +
        +
        Parameters
        +

        option (Option) – Not used.

        +
        +
        +
        + +
        +
        +no_gmcp(option)[source]
        +

        If this is reached, it means neither MSDP nor GMCP is +supported.

        +
        +
        Parameters
        +

        option (Option) – Not used.

        +
        +
        +
        + +
        +
        +do_gmcp(option)[source]
        +

        Called when client confirms that it can do MSDP or GMCP.

        +
        +
        Parameters
        +

        option (Option) – Not used.

        +
        +
        +
        + +
        +
        +encode_msdp(cmdname, *args, **kwargs)[source]
        +

        Encode into a valid MSDP command.

        +
        +
        Parameters
        +
          +
        • cmdname (str) – Name of send instruction.

        • +
        • args (any) – Arguments to OOB command.

        • +
        • kwargs (any) – Arguments to OOB command.

        • +
        +
        +
        +

        Notes

        +

        The output of this encoding will be +MSDP structures on these forms:

        +
        [cmdname, [], {}]           -> VAR cmdname VAL ""
        +[cmdname, [arg], {}]        -> VAR cmdname VAL arg
        +[cmdname, [args],{}]        -> VAR cmdname VAL ARRAYOPEN VAL arg VAL arg ... ARRAYCLOSE
        +[cmdname, [], {kwargs}]     -> VAR cmdname VAL TABLEOPEN VAR key VAL val ... TABLECLOSE
        +[cmdname, [args], {kwargs}] -> VAR cmdname VAL ARRAYOPEN VAL arg VAL arg ... ARRAYCLOSE
        +                               VAR cmdname VAL TABLEOPEN VAR key VAL val ... TABLECLOSE
        +
        +
        +

        Further nesting is not supported, so if an array argument +consists of an array (for example), that array will be +json-converted to a string.

        +
        + +
        +
        +encode_gmcp(cmdname, *args, **kwargs)[source]
        +

        Encode into GMCP messages.

        +
        +
        Parameters
        +
          +
        • cmdname (str) – GMCP OOB command name.

        • +
        • args (any) – Arguments to OOB command.

        • +
        • kwargs (any) – Arguments to OOB command.

        • +
        +
        +
        +

        Notes

        +

        GMCP messages will be outgoing on the following +form (the non-JSON cmdname at the start is what +IRE games use, supposedly, and what clients appear +to have adopted). A cmdname without Package will end +up in the Core package, while Core package names will +be stripped on the Evennia side.

        +
        [cmd.name, [], {}]          -> Cmd.Name
        +[cmd.name, [arg], {}]       -> Cmd.Name arg
        +[cmd.name, [args],{}]       -> Cmd.Name [args]
        +[cmd.name, [], {kwargs}]    -> Cmd.Name {kwargs}
        +[cmdname, [args, {kwargs}]  -> Core.Cmdname [[args],{kwargs}]
        +
        +
        +

        Notes

        +

        There are also a few default mappings between evennia outputcmds and GMCP:

        +
        client_options -> Core.Supports.Get
        +get_inputfuncs -> Core.Commands.Get
        +get_value      -> Char.Value.Get
        +repeat         -> Char.Repeat.Update
        +monitor        -> Char.Monitor.Update
        +
        +
        +
        + +
        +
        +decode_msdp(data)[source]
        +

        Decodes incoming MSDP data.

        +
        +
        Parameters
        +

        data (str or list) – MSDP data.

        +
        +
        +

        Notes

        +

        Clients should always send MSDP data on +one of the following forms:

        +
        cmdname ''          -> [cmdname, [], {}]
        +cmdname val         -> [cmdname, [val], {}]
        +cmdname array       -> [cmdname, [array], {}]
        +cmdname table       -> [cmdname, [], {table}]
        +cmdname array cmdname table -> [cmdname, [array], {table}]
        +
        +
        +

        Observe that all MSDP_VARS are used to identify cmdnames, +so if there are multiple arrays with the same cmdname +given, they will be merged into one argument array, same +for tables. Different MSDP_VARS (outside tables) will be +identified as separate cmdnames.

        +
        + +
        +
        +decode_gmcp(data)[source]
        +

        Decodes incoming GMCP data on the form ‘varname <structure>’.

        +
        +
        Parameters
        +

        data (str or list) – GMCP data.

        +
        +
        +

        Notes

        +

        Clients send data on the form “Module.Submodule.Cmdname <structure>”. +We assume the structure is valid JSON.

        +

        The following is parsed into Evennia’s formal structure:

        +
        Core.Name                         -> [name, [], {}]
        +Core.Name string                  -> [name, [string], {}]
        +Core.Name [arg, arg,...]          -> [name, [args], {}]
        +Core.Name {key:arg, key:arg, ...} -> [name, [], {kwargs}]
        +Core.Name [[args], {kwargs}]      -> [name, [args], {kwargs}]
        +
        +
        +
        + +
        +
        +data_out(cmdname, *args, **kwargs)[source]
        +

        Return a MSDP- or GMCP-valid subnegotiation across the protocol.

        +
        +
        Parameters
        +
          +
        • cmdname (str) – OOB-command name.

        • +
        • args (any) – Arguments to OOB command.

        • +
        • kwargs (any) – Arguments to OOB command.

        • +
        +
        +
        +
        + +
        +
        @@ -84,7 +297,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +313,7 @@ +
        develop branch
        @@ -37,8 +38,60 @@
        -
        -

        evennia.server.portal.telnet_ssl

        +
        +

        evennia.server.portal.telnet_ssl

        +

        This allows for running the telnet communication over an encrypted SSL tunnel. To use it, requires a +client supporting Telnet SSL.

        +

        The protocol will try to automatically create the private key and certificate on the server side +when starting and will warn if this was not possible. These will appear as files ssl.key and +ssl.cert in mygame/server/.

        +
        +
        +class evennia.server.portal.telnet_ssl.SSLProtocol(*args, **kwargs)[source]
        +

        Bases: evennia.server.portal.telnet.TelnetProtocol

        +

        Communication is the same as telnet, except data transfer +is done with encryption set up by the portal at start time.

        +
        +
        +__init__(*args, **kwargs)[source]
        +

        Initialize self. See help(type(self)) for accurate signature.

        +
        + +
        + +
        +
        +evennia.server.portal.telnet_ssl.verify_or_create_SSL_key_and_cert(keyfile, certfile)[source]
        +

        Verify or create new key/certificate files.

        +
        +
        Parameters
        +
          +
        • keyfile (str) – Path to ssl.key file.

        • +
        • certfile (str) – Parth to ssl.cert file.

        • +
        +
        +
        +

        Notes

        +

        If files don’t already exist, they are created.

        +
        + +
        +
        +evennia.server.portal.telnet_ssl.getSSLContext()[source]
        +

        This is called by the portal when creating the SSL context +server-side.

        +
        +
        Returns
        +

        ssl_context (tuple)

        +
        +
        A key and certificate that is either

        existing previously or created on the fly.

        +
        +
        +

        +
        +
        +
        +
        @@ -84,7 +137,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +153,7 @@ +
        develop branch
        @@ -37,8 +38,116 @@
        -
        -

        evennia.server.portal.tests

        +
        +

        evennia.server.portal.tests

        +
        +
        +class evennia.server.portal.tests.TestAMPServer(methodName='runTest')[source]
        +

        Bases: twisted.trial._asynctest.TestCase

        +

        Test AMP communication

        +
        +
        +setUp()[source]
        +

        Hook method for setting up the test fixture before exercising it.

        +
        + +
        +
        +test_amp_out()[source]
        +
        + +
        +
        +test_amp_in()[source]
        +
        + +
        +
        +test_large_msg()[source]
        +

        Send message larger than AMP_MAXLEN - should be split into several

        +
        + +
        + +
        +
        +class evennia.server.portal.tests.TestIRC(methodName='runTest')[source]
        +

        Bases: django.test.testcases.TestCase

        +
        +
        +test_plain_ansi()[source]
        +

        Test that printable characters do not get mangled.

        +
        + +
        +
        +test_bold()[source]
        +
        + +
        +
        +test_italic()[source]
        +
        + +
        +
        +test_colors()[source]
        +
        + +
        +
        +test_identity()[source]
        +

        Test that the composition of the function and +its inverse gives the correct string.

        +
        + +
        + +
        +
        +class evennia.server.portal.tests.TestTelnet(methodName='runTest')[source]
        +

        Bases: twisted.trial._asynctest.TestCase

        +
        +
        +setUp()[source]
        +

        Hook method for setting up the test fixture before exercising it.

        +
        + +
        +
        +test_mudlet_ttype()[source]
        +
        + +
        + +
        +
        +class evennia.server.portal.tests.TestWebSocket(methodName='runTest')[source]
        +

        Bases: evennia.utils.test_resources.EvenniaTest

        +
        +
        +setUp()[source]
        +

        Sets up testing environment

        +
        + +
        +
        +tearDown()[source]
        +

        Hook method for deconstructing the test fixture after testing it.

        +
        + +
        +
        +test_data_in()[source]
        +
        + +
        +
        +test_data_out()[source]
        +
        + +
        +
        @@ -84,7 +193,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +209,7 @@ +
        develop branch
        @@ -37,8 +38,66 @@
        -
        -

        evennia.server.portal.ttype

        +
        +

        evennia.server.portal.ttype

        +

        TTYPE (MTTS) - Mud Terminal Type Standard

        +

        This module implements the TTYPE telnet protocol as per +http://tintin.sourceforge.net/mtts/. It allows the server to ask the +client about its capabilities. If the client also supports TTYPE, it +will return with information such as its name, if it supports colour +etc. If the client does not support TTYPE, this will be ignored.

        +

        All data will be stored on the protocol’s protocol_flags dictionary, +under the ‘TTYPE’ key.

        +
        +
        +class evennia.server.portal.ttype.Ttype(protocol)[source]
        +

        Bases: object

        +

        Handles ttype negotiations. Called and initiated by the +telnet protocol.

        +
        +
        +__init__(protocol)[source]
        +

        Initialize ttype by storing protocol on ourselves and calling +the client to see if it supporst ttype.

        +
        +
        Parameters
        +

        protocol (Protocol) – The protocol instance.

        +
        +
        +

        Notes

        +

        The self.ttype_step indicates how far in the data +retrieval we’ve gotten.

        +
        + +
        +
        +wont_ttype(option)[source]
        +

        Callback if ttype is not supported by client.

        +
        +
        Parameters
        +

        option (Option) – Not used.

        +
        +
        +
        + +
        +
        +will_ttype(option)[source]
        +

        Handles negotiation of the ttype protocol once the client has +confirmed that it will respond with the ttype protocol.

        +
        +
        Parameters
        +

        option (Option) – Not used.

        +
        +
        +

        Notes

        +

        The negotiation proceeds in several steps, each returning a +certain piece of information about the client. All data is +stored on protocol.protocol_flags under the TTYPE key.

        +
        + +
        +
        @@ -84,7 +143,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +159,7 @@ +
        develop branch
        @@ -259,7 +260,6 @@ client instead.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -276,6 +276,7 @@ client instead.

        +
        develop branch
        @@ -171,6 +172,11 @@ mode operation (at startup)

        mode_keepalive(request)[source]

        This is called by render_POST when the client is replying to the keepalive.

        +
        +
        Parameters
        +

        request (Request) – Incoming request.

        +
        +
        @@ -384,7 +390,6 @@ client instead.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -401,6 +406,7 @@ client instead.

        +
        develop branch
        @@ -67,13 +68,83 @@ change which actions by adding a path to

        in your settings. See utils.dummyrunner_actions.py for instructions on how to define this module.

        +
        +
        +class evennia.server.profiling.dummyrunner.CmdDummyRunnerEchoResponse(**kwargs)[source]
        +

        Bases: evennia.commands.command.Command

        +

        Dummyrunner command measuring the round-about response time +from sending to receiving a result.

        +
        +
        Usage:

        dummyrunner_echo_response <timestamp>

        +
        +
        Responds with

        dummyrunner_echo_response:<timestamp>,<current_time>

        +
        +
        +

        The dummyrunner will send this and then compare the send time +with the receive time on both ends.

        +
        +
        +key = 'dummyrunner_echo_response'
        +
        + +
        +
        +func()[source]
        +

        This is the actual executing part of the command. It is +called directly after self.parse(). See the docstring of this +module for which object properties are available (beyond those +set in self.parse())

        +
        + +
        +
        +aliases = []
        +
        + +
        +
        +help_category = 'general'
        +
        + +
        +
        +lock_storage = 'cmd:all();'
        +
        + +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'dummyrunner_echo_response', 'tags': '', 'text': '\n Dummyrunner command measuring the round-about response time\n from sending to receiving a result.\n\n Usage:\n dummyrunner_echo_response <timestamp>\n\n Responds with\n dummyrunner_echo_response:<timestamp>,<current_time>\n\n The dummyrunner will send this and then compare the send time\n with the receive time on both ends.\n\n '}
        +
        + +
        + +
        +
        +class evennia.server.profiling.dummyrunner.DummyRunnerCmdSet(cmdsetobj=None, key=None)[source]
        +

        Bases: evennia.commands.cmdset.CmdSet

        +

        Dummyrunner injected cmdset.

        +
        +
        +at_cmdset_creation()[source]
        +

        Hook method - this should be overloaded in the inheriting +class, and should take care of populating the cmdset by use of +self.add().

        +
        + +
        +
        +path = 'evennia.server.profiling.dummyrunner.DummyRunnerCmdSet'
        +
        + +
        +
        evennia.server.profiling.dummyrunner.idcounter()[source]

        Makes unique ids.

        Returns
        -

        count (int) – A globally unique counter.

        +

        str – A globally unique id.

        @@ -110,6 +181,11 @@ for instructions on how to define this module.

        Handles connection to a running Evennia server, mimicking a real account by sending commands on a timer.

        +
        +
        +report(text, clientkey)[source]
        +
        +
        connectionMade()[source]
        @@ -180,13 +256,28 @@ all “intelligence” of the dummy client.

        class evennia.server.profiling.dummyrunner.DummyFactory(actions)[source]
        -

        Bases: twisted.internet.protocol.ClientFactory

        +

        Bases: twisted.internet.protocol.ReconnectingClientFactory

        protocol

        alias of DummyClient

        +
        +
        +initialDelay = 1
        +
        + +
        +
        +maxDelay = 1
        +
        + +
        +
        +noisy = False
        +
        +
        __init__(actions)[source]
        @@ -251,7 +342,6 @@ all “intelligence” of the dummy client.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -268,6 +358,7 @@ all “intelligence” of the dummy client.

        +
        develop branch
        @@ -43,51 +44,48 @@

        This module defines dummyrunner settings and sets up the actions available to dummy accounts.

        The settings are global variables:

        -

        TIMESTEP - time in seconds between each ‘tick’ -CHANCE_OF_ACTION - chance 0-1 of action happening -CHANCE_OF_LOGIN - chance 0-1 of login happening -TELNET_PORT - port to use, defaults to settings.TELNET_PORT -ACTIONS - see below

        +
          +
        • TIMESTEP - time in seconds between each ‘tick’. 1 is a good start.

        • +
        • CHANCE_OF_ACTION - chance 0-1 of action happening. Default is 0.5.

        • +
        • CHANCE_OF_LOGIN - chance 0-1 of login happening. 0.01 is a good number.

        • +
        • TELNET_PORT - port to use, defaults to settings.TELNET_PORT

        • +
        • ACTIONS - see below

        • +

        ACTIONS is a tuple

        -

        (login_func, logout_func, (0.3, func1), (0.1, func2) … )

        +
        (login_func, logout_func, (0.3, func1), (0.1, func2) ... )
        +
        +

        where the first entry is the function to call on first connect, with a chance of occurring given by CHANCE_OF_LOGIN. This function is usually responsible for logging in the account. The second entry is always called when the dummyrunner disconnects from the server and should -thus issue a logout command. The other entries are tuples (chance, +thus issue a logout command. The other entries are tuples (chance, func). They are picked randomly, their commonality based on the cumulative chance given (the chance is normalized between all options -so if will still work also if the given chances don’t add up to 1). -Since each function can return a list of game-command strings, each -function may result in multiple operations.

        +so if will still work also if the given chances don’t add up to 1).

        +

        The PROFILE variable define pre-made ACTION tuples for convenience.

        +

        Each function should return an iterable of one or more command-call +strings (like “look here”), so each can group multiple command operations.

        An action-function is called with a “client” argument which is a -reference to the dummy client currently performing the action. It -returns a string or a list of command strings to execute. Use the -client object for optionally saving data between actions.

        +reference to the dummy client currently performing the action.

        The client object has the following relevant properties and methods:

          -
        • -
          key - an optional client key. This is only used for dummyrunner output.

          Default is “Dummy-<cid>”

          -
          -
          -
        • +
        • key - an optional client key. This is only used for dummyrunner output. +Default is “Dummy-<cid>”

        • cid - client id

        • gid - globally unique id, hashed with time stamp

        • istep - the current step

        • exits - an empty list. Can be used to store exit names

        • objs - an empty list. Can be used to store object names

        • -
        • -
          counter() - returns a unique increasing id, hashed with time stamp

          to make it unique also between dummyrunner instances.

          -
          -
          -
        • +
        • counter() - returns a unique increasing id, hashed with time stamp +to make it unique also between dummyrunner instances.

        The return should either be a single command string or a tuple of command strings. This list of commands will always be executed every TIMESTEP with a chance given by CHANCE_OF_ACTION by in the order given (no randomness) and allows for setting up a more complex chain of commands (such as creating an account and logging in).

        -

        +
        evennia.server.profiling.dummyrunner_settings.c_login(client)[source]
        @@ -172,6 +170,16 @@ commands (such as creating an account and logging in).

        move through south exit if available

        +
        +
        +evennia.server.profiling.dummyrunner_settings.c_measure_lag(client)[source]
        +

        Special dummyrunner command, injected in c_login. It measures +response time. Including this in the ACTION tuple will give more +dummyrunner output about just how fast commands are being processed.

        +

        The dummyrunner will treat this special and inject the +{timestamp} just before sending.

        +
        + @@ -217,7 +225,6 @@ commands (such as creating an account and logging in).

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -234,6 +241,7 @@ commands (such as creating an account and logging in).

        +
        develop branch
        @@ -95,7 +96,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -112,6 +112,7 @@ +
        develop branch
        @@ -129,7 +130,6 @@ the script will append to this file if it already exists.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -146,6 +146,7 @@ the script will append to this file if it already exists.

        +
        develop branch
        @@ -91,7 +92,6 @@ servers!

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -108,6 +108,7 @@ servers!

        +
        develop branch
        @@ -93,7 +94,6 @@ to setup the environment to test.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -110,6 +110,7 @@ to setup the environment to test.

        +
        develop branch
        @@ -187,7 +188,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -204,6 +204,7 @@ +
        develop branch
        @@ -102,7 +103,6 @@ This message will get attached time stamp.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -119,6 +119,7 @@ This message will get attached time stamp.

        +
        develop branch
        @@ -39,11 +40,11 @@

        evennia.server.server

        -

        This module implements the main Evennia server process, the core of -the game engine.

        -

        This module should be started with the ‘twistd’ executable since it -sets up all the networking features. (this is done automatically -by evennia/server/server_runner.py).

        +

        This module implements the main Evennia server process, the core of the game +engine.

        +

        This module should be started with the ‘twistd’ executable since it sets up all +the networking features. (this is done automatically by +evennia/server/server_runner.py).

        class evennia.server.server.Evennia(application)[source]
        @@ -100,20 +101,20 @@ Once finished the last_initial_setup_step is set to -1.

        shutdown(mode='reload', _reactor_stopping=False)[source]

        Shuts down the server from inside it.

        -
        -
        Keyword Arguments
        -
          -
        • mode (str) – Sets the server restart mode:

        • -
        • 'reload' (-) – server restarts, no “persistent” scripts +

          +
          mode - sets the server restart mode.
            +
          • ‘reload’ - server restarts, no “persistent” scripts are stopped, at_reload hooks called.

          • -
          • 'reset' - server restarts, non-persistent scripts stopped, (-) – at_shutdown hooks called but sessions will not +

          • ‘reset’ - server restarts, non-persistent scripts stopped, +at_shutdown hooks called but sessions will not be disconnected.

          • -
          • - like reset, but server will not auto-restart. (-'shutdown') –

          • -
          • _reactor_stopping – This is set if server is stopped by a kill -command OR this method was already called -once - in both cases the reactor is dead/stopping already.

          • +
          • ‘shutdown’ - like reset, but server will not auto-restart.

          +
          _reactor_stopping - this is set if server is stopped by a kill

          command OR this method was already called +once - in both cases the reactor is +dead/stopping already.

          +
        @@ -150,7 +151,7 @@ of it is fore a reload, reset or shutdown.

        after reconnecting.

        Parameters
        -

        mode (str) – One of reload, reset or shutdown.

        +

        mode (str) – One of ‘reload’, ‘reset’ or ‘shutdown’.

        @@ -221,7 +222,6 @@ shutdown or a reset.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -238,6 +238,7 @@ shutdown or a reset.

        +
        develop branch
        @@ -44,126 +45,6 @@ a connection to the outside world but don’t know any details about how the connection actually happens (so it’s the same for telnet, web, ssh etc).

        It is stored on the Server side (as opposed to protocol-specific sessions which are stored on the Portal side)

        -
        -
        -class evennia.server.serversession.NDbHolder(obj, name, manager_name='attributes')[source]
        -

        Bases: object

        -

        Holder for allowing property access of attributes

        -
        -
        -__init__(obj, name, manager_name='attributes')[source]
        -

        Initialize self. See help(type(self)) for accurate signature.

        -
        - -
        -
        -get_all()[source]
        -
        - -
        -
        -property all
        -
        - -
        - -
        -
        -class evennia.server.serversession.NAttributeHandler(obj)[source]
        -

        Bases: object

        -

        NAttributeHandler version without recache protection. -This stand-alone handler manages non-database saving. -It is similar to AttributeHandler and is used -by the .ndb handler in the same way as .db does -for the AttributeHandler.

        -
        -
        -__init__(obj)[source]
        -

        Initialized on the object

        -
        - -
        -
        -has(key)[source]
        -

        Check if object has this attribute or not.

        -
        -
        Parameters
        -

        key (str) – The Nattribute key to check.

        -
        -
        Returns
        -

        has_nattribute (bool) – If Nattribute is set or not.

        -
        -
        -
        - -
        -
        -get(key, default=None)[source]
        -

        Get the named key value.

        -
        -
        Parameters
        -

        key (str) – The Nattribute key to get.

        -
        -
        Returns
        -

        the value of the Nattribute.

        -
        -
        -
        - -
        -
        -add(key, value)[source]
        -

        Add new key and value.

        -
        -
        Parameters
        -
          -
        • key (str) – The name of Nattribute to add.

        • -
        • value (any) – The value to store.

        • -
        -
        -
        -
        - -
        -
        -remove(key)[source]
        -

        Remove Nattribute from storage.

        -
        -
        Parameters
        -

        key (str) – The name of the Nattribute to remove.

        -
        -
        -
        - -
        -
        -clear()[source]
        -

        Remove all NAttributes from handler.

        -
        - -
        -
        -all(return_tuples=False)[source]
        -

        List the contents of the handler.

        -
        -
        Parameters
        -

        return_tuples (bool, optional) – Defines if the Nattributes -are returns as a list of keys or as a list of (key, value).

        -
        -
        Returns
        -

        nattributes (list)

        -
        -
        A list of keys [key, key, …] or a

        list of tuples [(key, value), …] depending on the -setting of return_tuples.

        -
        -
        -

        -
        -
        -
        - -
        -
        class evennia.server.serversession.ServerSession[source]
        @@ -184,6 +65,11 @@ through their session.

        property cmdset_storage
        +
        +
        +property id
        +
        +
        at_sync()[source]
        @@ -296,7 +182,7 @@ idle timers and command counters.

        Update the protocol_flags and sync them with Portal.

        Keyword Arguments
        -

        any – A key:value pair to set in the +

        protocol_flag (any) – A key and value to set in the protocol_flags dictionary.

        @@ -329,7 +215,7 @@ for the protocol(s).

        the respective inputfuncs.

        Keyword Arguments
        -

        any – Incoming data from protocol on +

        kwargs (any) – Incoming data from protocol on the form {“commandname”: ((args), {kwargs}),…}

        @@ -346,12 +232,12 @@ this data off to self.sessionhandler.call_inputfuncs(self, **kwargs)

        Wrapper to mimic msg() functionality of Objects and Accounts.

        Parameters
        -
          -
        • text (str) – String input.

        • -
        • kwargs (str or tuple) – Send-commands identified +

          text (str) – String input.

          +
          +
          Keyword Arguments
          +

          any (str or tuple) – Send-commands identified by their keys. Or “options”, carrying options -for the protocol(s).

        • -
        +for the protocol(s).

        @@ -507,7 +393,6 @@ property, e.g. obj.ndb.attr = value etc.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -524,6 +409,7 @@ property, e.g. obj.ndb.attr = value etc.

        +
        develop branch
        @@ -197,7 +198,6 @@ should overload this to format/handle the outgoing data as needed.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -214,6 +214,7 @@ should overload this to format/handle the outgoing data as needed.

        +
        develop branch
        @@ -42,8 +43,7 @@

        This module defines handlers for storing sessions when handles sessions of users connecting to the server.

        There are two similar but separate stores of sessions:

        -
        -
          +
          • ServerSessionHandler - this stores generic game sessions

            for the game. These sessions has no knowledge about how they are connected to the world.

            @@ -57,7 +57,6 @@ handle network communication but holds no game info.

          -
        class evennia.server.sessionhandler.DummySession[source]
        @@ -116,35 +115,27 @@ sessions in store.

        clean_senddata(session, kwargs)[source]
        -

        Clean up data for sending across the AMP wire. Also apply INLINEFUNCS.

        +

        Clean up data for sending across the AMP wire. Also apply the +FuncParser using callables from settings.FUNCPARSER_OUTGOING_MESSAGES_MODULES.

        Parameters
        • session (Session) – The relevant session instance.

        • -
        • kwargs (dict) –

          send-instruction, with the keyword itself being the name -of the instruction (like “text”). Suitable values for each -keyword are:

          -
          arg                ->  [[arg], {}]
          -[args]             ->  [[args], {}]
          -{kwargs}           ->  [[], {kwargs}]
          -[args, {kwargs}]   ->  [[arg], {kwargs}]
          -[[args], {kwargs}] ->  [[args], {kwargs}]
          -
          -
          -

        • +
        • kwargs (dict) – the name of the instruction (like “text”). Suitable values for each keyword are: +- arg -> [[arg], {}] +- [args] -> [[args], {}] +- {kwargs} -> [[], {kwargs}] +- [args, {kwargs}] -> [[arg], {kwargs}] +- [[args], {kwargs}] -> [[args], {kwargs}]

        Returns
        -

        kwargs (dict)

        -
        -
        A cleaned dictionary of cmdname:[[args],{kwargs}] pairs,

        where the keys, args and kwargs have all been converted to -send-safe entities (strings or numbers), and inlinefuncs have been +

        kwargs (dict) – A cleaned dictionary of cmdname:[[args],{kwargs}] pairs, +where the keys, args and kwargs have all been converted to +send-safe entities (strings or numbers), and funcparser parsing has been applied.

        -

        -
        -
        @@ -153,13 +144,10 @@ applied.

        class evennia.server.sessionhandler.ServerSessionHandler(*args, **kwargs)[source]

        Bases: evennia.server.sessionhandler.SessionHandler

        -

        This object holds the stack of sessions active in the game at -any time.

        -

        A session register with the handler in two steps, first by -registering itself with the connect() method. This indicates an -non-authenticated session. Whenever the session is authenticated -the session together with the related account is sent to the login() -method.

        +

        This object holds the stack of sessions active in the game at any time.

        +

        A session register with the handler in two steps, first by registering itself with the connect() +method. This indicates an non-authenticated session. Whenever the session is authenticated the +session together with the related account is sent to the login() method.

        __init__(*args, **kwargs)[source]
        @@ -279,9 +267,8 @@ itself down)

        login(session, account, force=False, testmode=False)[source]
        -

        Log in the previously unloggedin session and the account we by -now should know is connected to it. After this point we assume -the session to be logged in one way or another.

        +

        Log in the previously unloggedin session and the account we by now should know is connected +to it. After this point we assume the session to be logged in one way or another.

        Parameters
          @@ -463,7 +450,7 @@ object.

        Returns.
        -
        sessions (Session or list): Can be more than one of Object is controlled by

        more than one Session (MULTISESSION_MODE > 1).

        +
        sessions (Session or list): Can be more than one of Object is controlled by more than

        one Session (MULTISESSION_MODE > 1).

        @@ -481,7 +468,7 @@ object.

        Returns.
        -
        sessions (Session or list): Can be more than one of Object is controlled by

        more than one Session (MULTISESSION_MODE > 1).

        +
        sessions (Session or list): Can be more than one of Object is controlled by more than

        one Session (MULTISESSION_MODE > 1).

        @@ -493,12 +480,13 @@ object.

        sessions_from_csessid(csessid)[source]

        Given a client identification hash (for session types that offer them) return all sessions with a matching hash.

        -
        -
        Parameters
        -

        csessid (str) – The session hash.

        +
        +
        Args

        csessid (str): The session hash.

        -
        Returns
        -

        sessions (list) – The sessions with matching .csessid, if any.

        +
        +
        +
        Returns
        +

        sessions (list) – The sessions with matching .csessid, if any.

        @@ -555,17 +543,17 @@ this class’ sessionhandler.call_inputfunc with the
        call_inputfuncs(session, **kwargs)[source]
        -

        Split incoming data into its inputfunc counterparts. -This should be called by the serversession.data_in -as sessionhandler.call_inputfunc(self, **kwargs).

        +

        Split incoming data into its inputfunc counterparts. This should be +called by the serversession.data_in as +sessionhandler.call_inputfunc(self, **kwargs).

        We also intercept OOB communication here.

        Parameters

        sessions (Session) – Session.

        Keyword Arguments
        -

        kwargs (any) – Incoming data from protocol on -the form {“commandname”: ((args), {kwargs}),…}

        +

        any (tuple) – Incoming data from protocol, each +on the form commandname=((args), {kwargs}).

        @@ -617,7 +605,6 @@ the form {“commandname”: ((args), {kwargs}),…}

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -634,6 +621,7 @@ the form {“commandname”: ((args), {kwargs}),…}

        +
        develop branch
        @@ -39,22 +40,20 @@

        evennia.server.signals

        -

        This module brings Django Signals into Evennia. These are events that -can be subscribed to by importing a given Signal and using the -following code.

        -
        THIS_SIGNAL.connect(callback, sender_object**)
        +

        This module brings Django Signals into Evennia. These are events that can be +subscribed to by importing a given Signal and using the following code.

        +
        THIS_SIGNAL.connect(callback, sender_object)
         
        -

        When other code calls THIS_SIGNAL.send(sender, **kwargs), the callback -will be triggered.

        -

        Callbacks must be in the following format:

        +

        When other code calls THIS_SIGNAL.send(sender, **kwargs), the callback will +be triggered.

        +

        Callbacks must be on the following format:

        def my_callback(sender, **kwargs):
        -    ...
        +    # ...
         
        -

        This is used on top of hooks to make certain features easier to -add to contribs without necessitating a full takeover of hooks -that may be in high demand.

        +

        This is used on top of hooks to make certain features easier to add to contribs +without necessitating a full takeover of hooks that may be in high demand.

        @@ -100,7 +99,6 @@ that may be in high demand.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -117,6 +115,7 @@ that may be in high demand.

        +
        develop branch
        @@ -48,8 +49,8 @@ particular threshold.

        This version of the throttle is usable by both the terminal server as well as the web server, imposes limits on memory consumption by using deques -with length limits instead of open-ended lists, and removes sparse keys when -no recent failures have been recorded.

        +with length limits instead of open-ended lists, and uses native Django +caches for automatic key eviction and persistence configurability.

        error_msg = 'Too many failed attempts; you must wait a few minutes before trying again.'
        @@ -62,7 +63,9 @@ no recent failures have been recorded.

        Keyword Arguments
          -
        • limit (int) – Max number of failures before imposing limiter

        • +
        • name (str) – Name of this throttle.

        • +
        • limit (int) – Max number of failures before imposing limiter. If None, +the throttle is disabled.

        • timeout (int) – number of timeout seconds after max number of tries has been reached.

        • cache_size (int) – Max number of attempts to record per IP within a @@ -73,6 +76,25 @@ the throttle is imposed!

        +
        +
        +get_cache_key(*args, **kwargs)[source]
        +

        Creates a ‘prefixed’ key containing arbitrary terms to prevent key +collisions in the same namespace.

        +
        + +
        +
        +touch(key, *args, **kwargs)[source]
        +

        Refreshes the timeout on a given key and ensures it is recorded in the +key register.

        +
        +
        Parameters
        +

        key (str) – Key of entry to renew.

        +
        +
        +
        +
        get(ip=None)[source]
        @@ -113,6 +135,41 @@ of throttle.

        +
        +
        +remove(ip, *args, **kwargs)[source]
        +

        Clears data stored for an IP from the throttle.

        +
        +
        Parameters
        +

        ip (str) – IP to clear.

        +
        +
        +
        + +
        +
        +record_ip(ip, *args, **kwargs)[source]
        +

        Tracks keys as they are added to the cache (since there is no way to +get a list of keys after-the-fact).

        +
        +
        Parameters
        +

        ip (str) – IP being added to cache. This should be the original +IP, not the cache-prefixed key.

        +
        +
        +
        + +
        +
        +unrecord_ip(ip, *args, **kwargs)[source]
        +

        Forces removal of a key from the key registry.

        +
        +
        Parameters
        +

        ip (str) – IP to remove from list of keys.

        +
        +
        +
        +
        check(ip)[source]
        @@ -181,7 +238,6 @@ fails recently.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -198,6 +254,7 @@ fails recently.

        +
        develop branch
        @@ -146,7 +147,6 @@ by this validator.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -163,6 +163,7 @@ by this validator.

        +
        develop branch
        @@ -304,7 +305,6 @@ directory this path represents.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -321,6 +321,7 @@ directory this path represents.

        +
        develop branch
        @@ -92,7 +93,6 @@ always be sure of what you have changed and what is default behaviour.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -109,6 +109,7 @@ always be sure of what you have changed and what is default behaviour.

        +
        develop branch
        @@ -45,9 +46,9 @@ both pure-string values and pickled arbitrary data.

        the Attribute- and NickHandlers as well as the NAttributeHandler, which is a non-db version of Attributes.

        -
        -class evennia.typeclasses.attributes.Attribute(*args, **kwargs)[source]
        -

        Bases: evennia.utils.idmapper.models.SharedMemoryModel

        +
        +class evennia.typeclasses.attributes.IAttribute[source]
        +

        Bases: object

        Attributes are things that are specific to different types of objects. For example, a drink container needs to store its fill level, whereas an exit needs to store its open/closed/locked/unlocked state. These are done via @@ -82,6 +83,106 @@ attributes on the fly as we like.

        +

        This class is an API/Interface/Abstract base class; do not instantiate it directly.

        +
        +
        +locks[source]
        +
        + +
        +
        +property key
        +
        + +
        +
        +property strvalue
        +
        + +
        +
        +property category
        +
        + +
        +
        +property model
        +
        + +
        +
        +property attrtype
        +
        + +
        +
        +property date_created
        +
        + +
        +
        +property lock_storage
        +
        + +
        +
        +access(accessing_obj, access_type='read', default=False, **kwargs)[source]
        +

        Determines if another object has permission to access.

        +
        +
        Parameters
        +
          +
        • accessing_obj (object) – Entity trying to access this one.

        • +
        • access_type (str, optional) – Type of access sought, see +the lock documentation.

        • +
        • default (bool, optional) – What result to return if no lock +of access_type was found. The default, False, means a lockdown +policy, only allowing explicit access.

        • +
        • kwargs (any, optional) – Not used; here to make the API consistent with +other access calls.

        • +
        +
        +
        Returns
        +

        result (bool) – If the lock was passed or not.

        +
        +
        +
        + +
        + +
        +
        +class evennia.typeclasses.attributes.InMemoryAttribute(pk, **kwargs)[source]
        +

        Bases: evennia.typeclasses.attributes.IAttribute

        +

        This Attribute is used purely for NAttributes/NAttributeHandler. It has no database backend.

        +
        +
        +__init__(pk, **kwargs)[source]
        +

        Create an Attribute that exists only in Memory.

        +
        +
        Parameters
        +
          +
        • pk (int) – This is a fake ‘primary key’ / id-field. It doesn’t actually have to be +unique, but is fed an incrementing number from the InMemoryBackend by default. This +is needed only so Attributes can be sorted. Some parts of the API also see the lack +of a .pk field as a sign that the Attribute was deleted.

        • +
        • **kwargs – Other keyword arguments are used to construct the actual Attribute.

        • +
        +
        +
        +
        + +
        +
        +property value
        +
        + +
        + +
        +
        +class evennia.typeclasses.attributes.Attribute(*args, **kwargs)[source]
        +

        Bases: evennia.typeclasses.attributes.IAttribute, evennia.utils.idmapper.models.SharedMemoryModel

        +

        This attribute is stored via Django. Most Attributes will be using this class.

        db_key
        @@ -138,41 +239,6 @@ object the first time, the query is executed.

        object the first time, the query is executed.

        -
        -
        -locks[source]
        -
        - -
        -
        -property key
        -
        - -
        -
        -property strvalue
        -
        - -
        -
        -property category
        -
        - -
        -
        -property model
        -
        - -
        -
        -property attrtype
        -
        - -
        -
        -property date_created
        -
        -
        property lock_storage
        @@ -187,29 +253,6 @@ as storing a dbobj which is then deleted elsewhere) out-of-sync. The overhead of unpickling seems hard to avoid.

        -
        -
        -access(accessing_obj, access_type='attrread', default=False, **kwargs)[source]
        -

        Determines if another object has permission to access.

        -
        -
        Parameters
        -
          -
        • accessing_obj (object) – Entity trying to access this one.

        • -
        • access_type (str, optional) – Type of access sought, see -the lock documentation.

        • -
        • default (bool, optional) – What result to return if no lock -of access_type was found. The default, False, means a lockdown -policy, only allowing explicit access.

        • -
        • kwargs (any, optional) – Not used; here to make the API consistent with -other access calls.

        • -
        -
        -
        Returns
        -

        result (bool) – If the lock was passed or not.

        -
        -
        -
        -
        exception DoesNotExist
        @@ -238,6 +281,18 @@ instances.

        class built by **create_forward_many_to_many_manager()** defined below.

        +
        +
        +property attrtype
        +

        A wrapper for getting database field db_attrtype.

        +
        + +
        +
        +property category
        +

        A wrapper for getting database field db_category.

        +
        +
        channeldb_set
        @@ -254,6 +309,12 @@ instances.

        class built by **create_forward_many_to_many_manager()** defined below.

        +
        +
        +property date_created
        +

        A wrapper for getting database field db_date_created.

        +
        +
        get_next_by_db_date_created(*, field=<django.db.models.fields.DateTimeField: db_date_created>, is_next=True, **kwargs)
        @@ -271,6 +332,18 @@ class built by **create_forward_many_to_many_manager()** define object the first time, the query is executed.

        +
        +
        +property key
        +

        A wrapper for getting database field db_key.

        +
        + +
        +
        +property model
        +

        A wrapper for getting database field db_model.

        +
        +
        objectdb_set
        @@ -308,6 +381,12 @@ instances.

        class built by **create_forward_many_to_many_manager()** defined below.

        +
        +
        +property strvalue
        +

        A wrapper for getting database field db_strvalue.

        +
        +
        typename = 'SharedMemoryModelBase'
        @@ -315,21 +394,545 @@ class built by **create_forward_many_to_many_manager()** define
        +
        +
        +class evennia.typeclasses.attributes.IAttributeBackend(handler, attrtype)[source]
        +

        Bases: object

        +

        Abstract interface for the backends used by the Attribute Handler.

        +

        All Backends must implement this base class.

        +
        +
        +__init__(handler, attrtype)[source]
        +

        Initialize self. See help(type(self)) for accurate signature.

        +
        + +
        +
        +query_all()[source]
        +

        Fetch all Attributes from this object.

        +
        +
        Returns
        +

        attrlist (list) – A list of Attribute objects.

        +
        +
        +
        + +
        +
        +query_key(key, category)[source]
        +
        +
        Parameters
        +
          +
        • key (str) – The key of the Attribute being searched for.

        • +
        • category (str or None) – The category of the desired Attribute.

        • +
        +
        +
        Returns
        +

        attribute (IAttribute) – A single Attribute.

        +
        +
        +
        + +
        +
        +query_category(category)[source]
        +

        Returns every matching Attribute as a list, given a category.

        +

        This method calls up whatever storage the backend uses.

        +
        +
        Parameters
        +

        category (str or None) – The category to query.

        +
        +
        Returns
        +

        attrs (list) – The discovered Attributes.

        +
        +
        +
        + +
        +
        +get(key=None, category=None)[source]
        +

        Frontend for .get_cache. Retrieves Attribute(s).

        +
        +
        Parameters
        +
          +
        • key (str, optional) – Attribute key to query for

        • +
        • category (str, optional) – Attribiute category

        • +
        +
        +
        Returns
        +

        args (list)

        +
        +
        Returns a list of zero or more matches

        found from cache or database.

        +
        +
        +

        +
        +
        +
        + +
        +
        +reset_cache()[source]
        +

        Reset cache from the outside.

        +
        + +
        +
        +do_create_attribute(key, category, lockstring, value, strvalue)[source]
        +

        Does the hard work of actually creating Attributes, whatever is needed.

        +
        +
        Parameters
        +
          +
        • key (str) – The Attribute’s key.

        • +
        • category (str or None) – The Attribute’s category, or None

        • +
        • lockstring (str) – Any locks for the Attribute.

        • +
        • value (obj) – The Value of the Attribute.

        • +
        • strvalue (bool) – Signifies if this is a strvalue Attribute. Value MUST be a string or +this will lead to Trouble. Ignored for InMemory attributes.

        • +
        +
        +
        Returns
        +

        attr (IAttribute) – The new Attribute.

        +
        +
        +
        + +
        +
        +create_attribute(key, category, lockstring, value, strvalue=False, cache=True)[source]
        +

        Creates Attribute (using the class specified for the backend), (optionally) caches it, and +returns it.

        +

        This MUST actively save the Attribute to whatever database backend is used, AND +call self.set_cache(key, category, new_attrobj)

        +
        +
        Parameters
        +
          +
        • key (str) – The Attribute’s key.

        • +
        • category (str or None) – The Attribute’s category, or None

        • +
        • lockstring (str) – Any locks for the Attribute.

        • +
        • value (obj) – The Value of the Attribute.

        • +
        • strvalue (bool) – Signifies if this is a strvalue Attribute. Value MUST be a string or +this will lead to Trouble. Ignored for InMemory attributes.

        • +
        • cache (bool) – Whether to cache the new Attribute

        • +
        +
        +
        Returns
        +

        attr (IAttribute) – The new Attribute.

        +
        +
        +
        + +
        +
        +do_update_attribute(attr, value)[source]
        +

        Simply sets a new Value to an Attribute.

        +
        +
        Parameters
        +
          +
        • attr (IAttribute) – The Attribute being changed.

        • +
        • value (obj) – The Value for the Attribute.

        • +
        +
        +
        +
        + +
        +
        +do_batch_update_attribute(attr_obj, category, lock_storage, new_value, strvalue)[source]
        +

        Called opnly by batch add. For the database backend, this is a method +of updating that can alter category and lock-storage.

        +
        +
        Parameters
        +
          +
        • attr_obj (IAttribute) – The Attribute being altered.

        • +
        • category (str or None) – The attribute’s (new) category.

        • +
        • lock_storage (str) – The attribute’s new locks.

        • +
        • new_value (obj) – The Attribute’s new value.

        • +
        • strvalue (bool) – Signifies if this is a strvalue Attribute. Value MUST be a string or +this will lead to Trouble. Ignored for InMemory attributes.

        • +
        +
        +
        +
        + +
        +
        +do_batch_finish(attr_objs)[source]
        +

        Called after batch_add completed. Used for handling database operations +and/or caching complications.

        +
        +
        Parameters
        +

        attr_objs (list of IAttribute) – The Attributes created/updated thus far.

        +
        +
        +
        + +
        +
        +batch_add(*args, **kwargs)[source]
        +

        Batch-version of .add(). This is more efficient than repeat-calling +.add when having many Attributes to add.

        +
        +
        Parameters
        +

        *args (tuple) –

        Tuples of varying length representing the +Attribute to add to this object. Supported tuples are

        +
          +
        • (key, value)

        • +
        • (key, value, category)

        • +
        • (key, value, category, lockstring)

        • +
        • (key, value, category, lockstring, default_access)

        • +
        +

        +
        +
        Raises
        +

        RuntimeError – If trying to pass a non-iterable as argument.

        +
        +
        +

        Notes

        +

        The indata tuple order matters, so if you want a lockstring but no +category, set the category to None. This method does not have the +ability to check editing permissions and is mainly used internally. +It does not use the normal self.add but applies the Attributes +directly to the database.

        +
        + +
        +
        +do_delete_attribute(attr)[source]
        +

        Does the hard work of actually deleting things.

        +
        +
        Parameters
        +

        attr (IAttribute) – The attribute to delete.

        +
        +
        +
        + +
        +
        +delete_attribute(attr)[source]
        +

        Given an Attribute, deletes it. Also remove it from cache.

        +
        +
        Parameters
        +

        attr (IAttribute) – The attribute to delete.

        +
        +
        +
        + +
        +
        +update_attribute(attr, value)[source]
        +

        Simply updates an Attribute.

        +
        +
        Parameters
        +
          +
        • attr (IAttribute) – The attribute to delete.

        • +
        • value (obj) – The new value.

        • +
        +
        +
        +
        + +
        +
        +do_batch_delete(attribute_list)[source]
        +

        Given a list of attributes, deletes them all. +The default implementation is fine, but this is overridable since some databases may allow +for a better method.

        +
        +
        Parameters
        +

        attribute_list (list of IAttribute) –

        +
        +
        +
        + +
        +
        +clear_attributes(category, accessing_obj, default_access)[source]
        +

        Remove all Attributes on this object.

        +
        +
        Parameters
        +
          +
        • category (str, optional) – If given, clear only Attributes +of this category.

        • +
        • accessing_obj (object, optional) – If given, check the +attredit lock on each Attribute before continuing.

        • +
        • default_access (bool, optional) – Use this permission as +fallback if access_obj is given but there is no lock of +type attredit on the Attribute in question.

        • +
        +
        +
        +
        + +
        +
        +get_all_attributes()[source]
        +

        Simply returns all Attributes of this object, sorted by their IDs.

        +
        +
        Returns
        +

        attributes (list of IAttribute)

        +
        +
        +
        + +
        + +
        +
        +class evennia.typeclasses.attributes.InMemoryAttributeBackend(handler, attrtype)[source]
        +

        Bases: evennia.typeclasses.attributes.IAttributeBackend

        +

        This Backend for Attributes stores NOTHING in the database. Everything is kept in memory, and +normally lost on a crash, reload, shared memory flush, etc. It generates IDs for the Attributes +it manages, but these are of little importance beyond sorting and satisfying the caching logic +to know an Attribute hasn’t been deleted out from under the cache’s nose.

        +
        +
        +__init__(handler, attrtype)[source]
        +

        Initialize self. See help(type(self)) for accurate signature.

        +
        + +
        +
        +query_all()[source]
        +

        Fetch all Attributes from this object.

        +
        +
        Returns
        +

        attrlist (list) – A list of Attribute objects.

        +
        +
        +
        + +
        +
        +query_key(key, category)[source]
        +
        +
        Parameters
        +
          +
        • key (str) – The key of the Attribute being searched for.

        • +
        • category (str or None) – The category of the desired Attribute.

        • +
        +
        +
        Returns
        +

        attribute (IAttribute) – A single Attribute.

        +
        +
        +
        + +
        +
        +query_category(category)[source]
        +

        Returns every matching Attribute as a list, given a category.

        +

        This method calls up whatever storage the backend uses.

        +
        +
        Parameters
        +

        category (str or None) – The category to query.

        +
        +
        Returns
        +

        attrs (list) – The discovered Attributes.

        +
        +
        +
        + +
        +
        +do_create_attribute(key, category, lockstring, value, strvalue)[source]
        +

        See parent class.

        +

        strvalue has no meaning for InMemory attributes.

        +
        + +
        +
        +do_update_attribute(attr, value)[source]
        +

        Simply sets a new Value to an Attribute.

        +
        +
        Parameters
        +
          +
        • attr (IAttribute) – The Attribute being changed.

        • +
        • value (obj) – The Value for the Attribute.

        • +
        +
        +
        +
        + +
        +
        +do_batch_update_attribute(attr_obj, category, lock_storage, new_value, strvalue)[source]
        +

        No need to bother saving anything. Just set some values.

        +
        + +
        +
        +do_batch_finish(attr_objs)[source]
        +

        Nothing to do here for In-Memory.

        +
        +
        Parameters
        +

        attr_objs (list of IAttribute) – The Attributes created/updated thus far.

        +
        +
        +
        + +
        +
        +do_delete_attribute(attr)[source]
        +

        Removes the Attribute from local storage. Once it’s out of the cache, garbage collection +will handle the rest.

        +
        +
        Parameters
        +

        attr (IAttribute) – The attribute to delete.

        +
        +
        +
        + +
        + +
        +
        +class evennia.typeclasses.attributes.ModelAttributeBackend(handler, attrtype)[source]
        +

        Bases: evennia.typeclasses.attributes.IAttributeBackend

        +

        Uses Django models for storing Attributes.

        +
        +
        +__init__(handler, attrtype)[source]
        +

        Initialize self. See help(type(self)) for accurate signature.

        +
        + +
        +
        +query_all()[source]
        +

        Fetch all Attributes from this object.

        +
        +
        Returns
        +

        attrlist (list) – A list of Attribute objects.

        +
        +
        +
        + +
        +
        +query_key(key, category)[source]
        +
        +
        Parameters
        +
          +
        • key (str) – The key of the Attribute being searched for.

        • +
        • category (str or None) – The category of the desired Attribute.

        • +
        +
        +
        Returns
        +

        attribute (IAttribute) – A single Attribute.

        +
        +
        +
        + +
        +
        +query_category(category)[source]
        +

        Returns every matching Attribute as a list, given a category.

        +

        This method calls up whatever storage the backend uses.

        +
        +
        Parameters
        +

        category (str or None) – The category to query.

        +
        +
        Returns
        +

        attrs (list) – The discovered Attributes.

        +
        +
        +
        + +
        +
        +do_create_attribute(key, category, lockstring, value, strvalue)[source]
        +

        Does the hard work of actually creating Attributes, whatever is needed.

        +
        +
        Parameters
        +
          +
        • key (str) – The Attribute’s key.

        • +
        • category (str or None) – The Attribute’s category, or None

        • +
        • lockstring (str) – Any locks for the Attribute.

        • +
        • value (obj) – The Value of the Attribute.

        • +
        • strvalue (bool) – Signifies if this is a strvalue Attribute. Value MUST be a string or +this will lead to Trouble. Ignored for InMemory attributes.

        • +
        +
        +
        Returns
        +

        attr (IAttribute) – The new Attribute.

        +
        +
        +
        + +
        +
        +do_update_attribute(attr, value)[source]
        +

        Simply sets a new Value to an Attribute.

        +
        +
        Parameters
        +
          +
        • attr (IAttribute) – The Attribute being changed.

        • +
        • value (obj) – The Value for the Attribute.

        • +
        +
        +
        +
        + +
        +
        +do_batch_update_attribute(attr_obj, category, lock_storage, new_value, strvalue)[source]
        +

        Called opnly by batch add. For the database backend, this is a method +of updating that can alter category and lock-storage.

        +
        +
        Parameters
        +
          +
        • attr_obj (IAttribute) – The Attribute being altered.

        • +
        • category (str or None) – The attribute’s (new) category.

        • +
        • lock_storage (str) – The attribute’s new locks.

        • +
        • new_value (obj) – The Attribute’s new value.

        • +
        • strvalue (bool) – Signifies if this is a strvalue Attribute. Value MUST be a string or +this will lead to Trouble. Ignored for InMemory attributes.

        • +
        +
        +
        +
        + +
        +
        +do_batch_finish(attr_objs)[source]
        +

        Called after batch_add completed. Used for handling database operations +and/or caching complications.

        +
        +
        Parameters
        +

        attr_objs (list of IAttribute) – The Attributes created/updated thus far.

        +
        +
        +
        + +
        +
        +do_delete_attribute(attr)[source]
        +

        Does the hard work of actually deleting things.

        +
        +
        Parameters
        +

        attr (IAttribute) – The attribute to delete.

        +
        +
        +
        + +
        +
        -class evennia.typeclasses.attributes.AttributeHandler(obj)[source]
        +class evennia.typeclasses.attributes.AttributeHandler(obj, backend_class)[source]

        Bases: object

        Handler for adding Attributes to the object.

        -__init__(obj)[source]
        -

        Initialize handler.

        -
        - -
        -
        -reset_cache()[source]
        -

        Reset cache from the outside.

        +__init__(obj, backend_class)[source] +

        Setup the AttributeHandler.

        +
        +
        Parameters
        +

        obj (TypedObject) – An Account, Object, Channel, ServerSession (not technically a typed +object), etc. backend_class (IAttributeBackend class): The class of the backend to +use.

        +
        +
        @@ -386,7 +989,8 @@ permission lock will be checked before returning each looked-after Attribute.

      • default_access (bool, optional) – If no attrread lock is set on object, this determines if the lock should then be passed or not.

      • -
      • return_list (bool, optional) –

      • +
      • return_list (bool, optional) – Always return a list, also if there is only +one or zero matches found.

      • Returns
        @@ -444,14 +1048,12 @@ repeat-calling add when having many Attributes to add.

        *args (tuple) –

        Each argument should be a tuples (can be of varying length) representing the Attribute to add to this object. Supported tuples are

        -
        -
          -
        • (key, value)

        • -
        • (key, value, category)

        • -
        • (key, value, category, lockstring)

        • -
        • (key, value, category, lockstring, default_access)

        • +
            +
          • (key, value)

          • +
          • (key, value, category)

          • +
          • (key, value, category, lockstring)

          • +
          • (key, value, category, lockstring, default_access)

          -

        Keyword Arguments
        @@ -550,6 +1152,34 @@ Attributes has no lock of type attrread defined on them.

        +
        +
        +reset_cache()[source]
        +
        + + + +
        +
        +class evennia.typeclasses.attributes.DbHolder(obj, name, manager_name='attributes')[source]
        +

        Bases: object

        +

        Holder for allowing property access of attributes

        +
        +
        +__init__(obj, name, manager_name='attributes')[source]
        +

        Initialize self. See help(type(self)) for accurate signature.

        +
        + +
        +
        +get_all()[source]
        +
        + +
        +
        +property all
        +
        +
        @@ -560,30 +1190,45 @@ Attributes has no lock of type attrread defined on them.

        -evennia.typeclasses.attributes.initialize_nick_templates(in_template, out_template)[source]
        +evennia.typeclasses.attributes.initialize_nick_templates(pattern, replacement, pattern_is_regex=False)[source]

        Initialize the nick templates for matching and remapping a string.

        Parameters
          -
        • in_template (str) – The template to be used for nick recognition.

        • -
        • out_template (str) – The template to be used to replace the string -matched by the in_template.

        • +
        • pattern (str) – The pattern to be used for nick recognition. This will +be parsed for shell patterns into a regex, unless pattern_is_regex +is True, in which case it must be an already valid regex string. In +this case, instead of $N, numbered arguments must instead be given +as matching groups named as argN, such as (?P<arg1>.+?).

        • +
        • replacement (str) – The template to be used to replace the string +matched by the pattern. This can contain $N markers and is never +parsed into a regex.

        • +
        • pattern_is_regex (bool) – If set, pattern is a full regex string +instead of containing shell patterns.

        Returns
        -

        (regex, str)

        +

        regex, template (str)

        -
        Regex to match against strings and a template

        Template with markers {arg1}, {arg2}, etc for -replacement using the standard .format method.

        +
        Regex to match against strings and template

        with markers **{arg1}, {arg2}**, etc for replacement using the standard +.format method.

        Raises
        -

        attributes.NickTemplateInvalid – If the in/out template does not have a matching -number of $args.

        +
          +
        • evennia.typecalasses.attributes.NickTemplateInvalid – If the in/out

        • +
        • template does not have a matching number of $args.

        • +
        +

        Examples

        +
          +
        • pattern (shell syntax): “grin $1”

        • +
        • pattern (regex): “grin (?P<arg1.+?>)”

        • +
        • replacement: “emote gives a wicked grin to $1”

        • +
        @@ -593,12 +1238,14 @@ number of $args.

        Parameters
          -
        • string (str) – The input string to processj

        • +
        • string (str) – The input string to process

        • template_regex (regex) – A template regex created with initialize_nick_template.

        • outtemplate (str) – The template to which to map the matches produced by the template_regex. This should have $1, $2, -etc to match the regex.

        • +etc to match the template-regex. Un-found $N-markers (possible if +the regex has optional matching groups) are replaced with empty +strings.

        @@ -614,7 +1261,14 @@ They also always use the strvalue fields for their data.

        __init__(*args, **kwargs)[source]
        -

        Initialize handler.

        +

        Setup the AttributeHandler.

        +
        +
        Parameters
        +

        obj (TypedObject) – An Account, Object, Channel, ServerSession (not technically a typed +object), etc. backend_class (IAttributeBackend class): The class of the backend to +use.

        +
        +
        @@ -659,25 +1313,51 @@ a string.

      • kwargs (any, optional) – These are passed on to AttributeHandler.get.

      • +
        Returns
        +

        str or tuple – The nick replacement string or nick tuple.

        +
        -add(key, replacement, category='inputline', **kwargs)[source]
        -

        Add a new nick.

        +add(pattern, replacement, category='inputline', pattern_is_regex=False, **kwargs)[source] +

        Add a new nick, a mapping pattern -> replacement.

        Parameters
          -
        • key (str) – A key (or template) for the nick to match for.

        • -
        • replacement (str) – The string (or template) to replace key with (the “nickname”).

        • +
        • pattern (str) – A pattern to match for. This will be parsed for +shell patterns using the fnmatch library and can contain +$N-markers to indicate the locations of arguments to catch. If +pattern_is_regex=True, this must instead be a valid regular +expression and the $N-markers must be named argN that matches +numbered regex groups (see examples).

        • +
        • replacement (str) – The string (or template) to replace key with +(the “nickname”). This may contain $N markers to indicate where to +place the argument-matches

        • category (str, optional) – the category within which to retrieve the nick. The “inputline” means replacing data sent by the user.

        • -
        • kwargs (any, optional) – These are passed on to AttributeHandler.get.

        • +
        • pattern_is_regex (bool) – If True, the pattern will be parsed as a +raw regex string. Instead of using $N markers in this string, one +then must mark numbered arguments as a named regex-groupd named argN. +For example, (?P<arg1>.+?) will match the behavior of using $1 +in the shell pattern.

        • +
        • **kwargs (any, optional) – These are passed on to AttributeHandler.get.

        +

        Notes

        +

        For most cases, the shell-pattern is much shorter and easier. The +regex pattern form can be useful for more complex matchings though, +for example in order to add optional arguments, such as with +(?P<argN>.*?).

        +

        Example

        +
          +
        • pattern (default shell syntax): “gr $1 at $2”

        • +
        • pattern (with pattern_is_regex=True): r”gr (?P<arg1>.+?) at (?P<arg2>.+?)”

        • +
        • replacement: “emote With a flourish, $1 grins at $2.”

        • +
        @@ -727,102 +1407,6 @@ with nicks stored on the Account level.

        -
        -
        -class evennia.typeclasses.attributes.NAttributeHandler(obj)[source]
        -

        Bases: object

        -

        This stand-alone handler manages non-database saving. -It is similar to AttributeHandler and is used -by the .ndb handler in the same way as .db does -for the AttributeHandler.

        -
        -
        -__init__(obj)[source]
        -

        Initialized on the object

        -
        - -
        -
        -has(key)[source]
        -

        Check if object has this attribute or not.

        -
        -
        Parameters
        -

        key (str) – The Nattribute key to check.

        -
        -
        Returns
        -

        has_nattribute (bool) – If Nattribute is set or not.

        -
        -
        -
        - -
        -
        -get(key)[source]
        -

        Get the named key value.

        -
        -
        Parameters
        -

        key (str) – The Nattribute key to get.

        -
        -
        Returns
        -

        the value of the Nattribute.

        -
        -
        -
        - -
        -
        -add(key, value)[source]
        -

        Add new key and value.

        -
        -
        Parameters
        -
          -
        • key (str) – The name of Nattribute to add.

        • -
        • value (any) – The value to store.

        • -
        -
        -
        -
        - -
        -
        -remove(key)[source]
        -

        Remove Nattribute from storage.

        -
        -
        Parameters
        -

        key (str) – The name of the Nattribute to remove.

        -
        -
        -
        - -
        -
        -clear()[source]
        -

        Remove all NAttributes from handler.

        -
        - -
        -
        -all(return_tuples=False)[source]
        -

        List the contents of the handler.

        -
        -
        Parameters
        -

        return_tuples (bool, optional) – Defines if the Nattributes -are returns as a list of keys or as a list of (key, value).

        -
        -
        Returns
        -

        nattributes (list)

        -
        -
        A list of keys [key, key, …] or a

        list of tuples [(key, value), …] depending on the -setting of return_tuples.

        -
        -
        -

        -
        -
        -
        - -
        - @@ -868,7 +1452,6 @@ setting of return_tuples.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -885,6 +1468,7 @@ setting of return_tuples.

        +
        develop branch
        @@ -98,7 +99,6 @@ Attribute and Tag models are defined along with their handlers.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -115,6 +115,7 @@ Attribute and Tag models are defined along with their handlers.

        +
        develop branch
        @@ -50,15 +51,13 @@ all Attributes and TypedObjects).

        get_attribute(key=None, category=None, value=None, strvalue=None, obj=None, attrtype=None, **kwargs)[source]
        -

        Return Attribute objects by key, by category, by value, by -strvalue, by object (it is stored on) or with a combination of -those criteria.

        +

        Return Attribute objects by key, by category, by value, by strvalue, by +object (it is stored on) or with a combination of those criteria.

        Parameters
          -
        • key (str, optional) – The attribute’s key to search for.

        • -
        • category (str, optional) – The category of the attribute(s) -to search for.

        • +
        • key (str, optional) – The attribute’s key to search for

        • +
        • category (str, optional) – The category of the attribute(s) to search for.

        • value (str, optional) – The attribute value to search for. Note that this is not a very efficient operation since it will query for a pickled entity. Mutually exclusive to @@ -69,14 +68,14 @@ mutually exclusive to the value keyword and will take precedence if given.

        • obj (Object, optional) – On which object the Attribute to search for is.

        • -
        • attrtype (str, optional) – An attribute-type to search for. +

        • attrype (str, optional) – An attribute-type to search for. By default this is either None (normal Attributes) or “nick”.

        • -
        • kwargs (any) – Currently unused. Reserved for future use.

        • +
        • **kwargs (any) – Currently unused. Reserved for future use.

        Returns
        -

        attributes (list) – The matching Attributes.

        +

        list – The matching Attributes.

        @@ -168,7 +167,7 @@ stored on) or with a combination of those criteria.

        to search for.

      • obj (Object, optional) – On which object the Tag to search for is.

      • -
      • tagtype (str, optional) – One of None (normal tags), +

      • tagtype (str, optional) – One of None (normal tags), “alias” or “permission”

      • global_search (bool, optional) – Include all possible tags, not just tags on this object

      • @@ -493,7 +492,6 @@ Mutually exclusive to include_children.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -510,6 +508,7 @@ Mutually exclusive to include_children.

        +
        develop branch
        @@ -60,7 +61,6 @@ The admin should usually not have to deal directly with the database object layer.

        This module also contains the Managers for the respective models; inherit from these to create custom managers.

        -
        class evennia.typeclasses.models.TypedObject(*args, **kwargs)[source]
        @@ -68,18 +68,18 @@ these to create custom managers.

        Abstract Django model.

        This is the basis for a typed object. It also contains all the mechanics for managing connected attributes.

        -
        -
        The TypedObject has the following properties:

        key - main name -name - alias for key -typeclass_path - the path to the decorating typeclass -typeclass - auto-linked typeclass -date_created - time stamp of object creation -permissions - perm strings -dbref - #id of object -db - persistent attribute storage -ndb - non-persistent attribute storage

        -
        -
        +

        The TypedObject has the following properties:

        +
          +
        • key - main name

        • +
        • name - alias for key

        • +
        • typeclass_path - the path to the decorating typeclass

        • +
        • typeclass - auto-linked typeclass

        • +
        • date_created - time stamp of object creation

        • +
        • permissions - perm strings

        • +
        • dbref - #id of object

        • +
        • db - persistent attribute storage

        • +
        • ndb - non-persistent attribute storage

        • +
        db_key
        @@ -159,10 +159,10 @@ a class based on the db_typeclass_path database field rather than use the one in the model.

        Parameters
        -
          -
        • *args – Passed through to parent.

        • -
        • **kwargs – Passed through to parent.

        • -
        +

        through to parent. (Passed) –

        +
        +
        Keyword Arguments
        +

        through to parent. (Passed) –

        Notes

        @@ -368,7 +368,7 @@ superuser lock bypass (be careful with this one).

        Keyword Arguments
        -

        kwargs (any) – Ignored, but is there to make the api +

        kwar (any) – Ignored, but is there to make the api consistent with the object-typeclass method access, which use it to feed to its hook methods.

        @@ -401,36 +401,30 @@ without involving any locks.

        property db

        Attribute handler wrapper. Allows for the syntax

        obj.db.attrname = value
        -  and
        +# and
         value = obj.db.attrname
        -  and
        +# and
         del obj.db.attrname
        -  and
        +# and
         all_attr = obj.db.all()
        +# (unless there is an attribute
        +#  named 'all', in which case that will be returned instead).
         
        -

        (unless there is an attribute named ‘all’, in which case that will be -returned instead).

        property ndb
        -

        A non-attr_obj store (NonDataBase). Everything stored to this is -guaranteed to be cleared when a server is shutdown. Syntax is same as -for the .db property, e.g.

        -
        obj.ndb.attrname = value
        -  and
        -value = obj.ndb.attrname
        -  and
        -del obj.ndb.attrname
        -  and
        -all_attr = obj.ndb.all()
        -
        -
        -

        What makes this preferable over just assigning properties directly on -the object is that Evennia can track caching for these properties and -for example avoid wiping objects with set .ndb data on cache flushes.

        +

        NonDataBase). Everything stored +to this is guaranteed to be cleared when a server is shutdown. +Syntax is same as for the _get_db_holder() method and +property, e.g. obj.ndb.attr = value etc.

        +
        +
        Type
        +

        A non-attr_obj store (ndb

        +
        +
        @@ -517,141 +511,22 @@ at/getting information for this object.

        classmethod web_get_create_url()[source]

        Returns the URI path for a View that allows users to create new instances of this object.

        +

        ex. Chargen = ‘/characters/create/’

        +

        For this to work, the developer must have defined a named view somewhere +in urls.py that follows the format ‘modelname-action’, so in this case +a named view of ‘character-create’ would be referenced by this method.

        +

        ex. +url(r’characters/create/’, ChargenView.as_view(), name=’character-create’)

        +

        If no View has been created and defined in urls.py, returns an +HTML anchor.

        +

        This method is naive and simply returns a path. Securing access to +the actual view and limiting who can create new objects is the +developer’s responsibility.

        Returns

        path (str) – URI path to object creation page, if defined.

        -

        Examples

        -
        Chargen = '/characters/create/'
        -
        -
        -

        For this to work, the developer must have defined a named view somewhere -in urls.py that follows the format ‘modelname-action’, so in this case -a named view of ‘character-create’ would be referenced by this method.

        -
        url(r'characters/create/', ChargenView.as_view(), name='character-create')
        -
        -
        -

        If no View has been created and defined in urls.py, returns an -HTML anchor.

        -

        Notes

        -

        This method is naive and simply returns a path. Securing access to -the actual view and limiting who can create new objects is the -developer’s responsibility.

        -
        - -
        -
        -web_get_detail_url()[source]
        -

        Returns the URI path for a View that allows users to view details for -this object.

        -
        -
        Returns
        -

        path (str) – URI path to object detail page, if defined.

        -
        -
        -

        Examples

        -
        Oscar (Character) = '/characters/oscar/1/'
        -
        -
        -

        For this to work, the developer must have defined a named view somewhere -in urls.py that follows the format ‘modelname-action’, so in this case -a named view of ‘character-detail’ would be referenced by this method.

        -
        CharDetailView.as_view(), name='character-detail')
        -
        -
        -

        If no View has been created and defined in urls.py, returns an -HTML anchor.

        -

        Notes

        -

        This method is naive and simply returns a path. Securing access to -the actual view and limiting who can view this object is the -developer’s responsibility.

        -
        - -
        -
        -web_get_puppet_url()[source]
        -

        Returns the URI path for a View that allows users to puppet a specific -object.

        -
        -
        Returns
        -

        path (str) – URI path to object puppet page, if defined.

        -
        -
        -

        Examples

        -
        Oscar (Character) = '/characters/oscar/1/puppet/'
        -
        -
        -

        For this to work, the developer must have defined a named view somewhere -in urls.py that follows the format ‘modelname-action’, so in this case -a named view of ‘character-puppet’ would be referenced by this method.

        -
        url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/puppet/$',
        -    CharPuppetView.as_view(), name='character-puppet')
        -
        -
        -

        If no View has been created and defined in urls.py, returns an -HTML anchor.

        -

        Notes

        -

        This method is naive and simply returns a path. Securing access to -the actual view and limiting who can view this object is the developer’s -responsibility.

        -
        - -
        -
        -web_get_update_url()[source]
        -

        Returns the URI path for a View that allows users to update this -object.

        -
        -
        Returns
        -

        path (str) – URI path to object update page, if defined.

        -
        -
        -

        Examples

        -
        Oscar (Character) = '/characters/oscar/1/change/'
        -
        -
        -

        For this to work, the developer must have defined a named view somewhere -in urls.py that follows the format ‘modelname-action’, so in this case -a named view of ‘character-update’ would be referenced by this method.

        -
        url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/change/$',
        -    CharUpdateView.as_view(), name='character-update')
        -
        -
        -

        If no View has been created and defined in urls.py, returns an -HTML anchor.

        -

        Notes

        -

        This method is naive and simply returns a path. Securing access to -the actual view and limiting who can modify objects is the developer’s -responsibility.

        -
        - -
        -
        -web_get_delete_url()[source]
        -

        Returns the URI path for a View that allows users to delete this object.

        -
        -
        Returns
        -

        path (str) – URI path to object deletion page, if defined.

        -
        -
        -

        Examples

        -
        Oscar (Character) = '/characters/oscar/1/delete/'
        -
        -
        -

        For this to work, the developer must have defined a named view somewhere -in urls.py that follows the format ‘modelname-action’, so in this case -a named view of ‘character-detail’ would be referenced by this method.

        -
        url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/delete/$',
        -    CharDeleteView.as_view(), name='character-delete')
        -
        -
        -

        If no View has been created and defined in urls.py, returns an -HTML anchor.

        -

        Notes

        -

        This method is naive and simply returns a path. Securing access to -the actual view and limiting who can delete this object is the developer’s -responsibility.

        @@ -660,34 +535,6 @@ responsibility.

        A wrapper for getting database field db_date_created.

        -
        -
        -get_absolute_url()
        -

        Returns the URI path for a View that allows users to view details for -this object.

        -
        -
        Returns
        -

        path (str) – URI path to object detail page, if defined.

        -
        -
        -

        Examples

        -
        Oscar (Character) = '/characters/oscar/1/'
        -
        -
        -

        For this to work, the developer must have defined a named view somewhere -in urls.py that follows the format ‘modelname-action’, so in this case -a named view of ‘character-detail’ would be referenced by this method.

        -
        CharDetailView.as_view(), name='character-detail')
        -
        -
        -

        If no View has been created and defined in urls.py, returns an -HTML anchor.

        -

        Notes

        -

        This method is naive and simply returns a path. Securing access to -the actual view and limiting who can view this object is the -developer’s responsibility.

        -
        -
        get_next_by_db_date_created(*, field=<django.db.models.fields.DateTimeField: db_date_created>, is_next=True, **kwargs)
        @@ -720,6 +567,146 @@ developer’s responsibility.

        typename = 'SharedMemoryModelBase'
        +
        +
        +web_get_detail_url()[source]
        +

        Returns the URI path for a View that allows users to view details for +this object.

        +
        +
        Returns
        +

        path (str) – URI path to object detail page, if defined.

        +
        +
        +

        Examples

        +
        Oscar (Character) = '/characters/oscar/1/'
        +
        +
        +

        For this to work, the developer must have defined a named view somewhere +in urls.py that follows the format ‘modelname-action’, so in this case +a named view of ‘character-detail’ would be referenced by this method.

        +
        url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/$',
        +    CharDetailView.as_view(), name='character-detail')
        +
        +
        +

        If no View has been created and defined in urls.py, returns an +HTML anchor.

        +

        This method is naive and simply returns a path. Securing access to +the actual view and limiting who can view this object is the +developer’s responsibility.

        +
        + +
        +
        +web_get_puppet_url()[source]
        +

        Returns the URI path for a View that allows users to puppet a specific +object.

        +
        +
        Returns
        +

        str – URI path to object puppet page, if defined.

        +
        +
        +

        Examples

        +
        Oscar (Character) = '/characters/oscar/1/puppet/'
        +
        +
        +

        For this to work, the developer must have defined a named view somewhere +in urls.py that follows the format ‘modelname-action’, so in this case +a named view of ‘character-puppet’ would be referenced by this method.

        +
        url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/puppet/$',
        +    CharPuppetView.as_view(), name='character-puppet')
        +
        +
        +

        If no View has been created and defined in urls.py, returns an +HTML anchor.

        +

        This method is naive and simply returns a path. Securing access to +the actual view and limiting who can view this object is the developer’s +responsibility.

        +
        + +
        +
        +web_get_update_url()[source]
        +

        Returns the URI path for a View that allows users to update this +object.

        +
        +
        Returns
        +

        str – URI path to object update page, if defined.

        +
        +
        +

        Examples

        +
        Oscar (Character) = '/characters/oscar/1/change/'
        +
        +
        +

        For this to work, the developer must have defined a named view somewhere +in urls.py that follows the format ‘modelname-action’, so in this case +a named view of ‘character-update’ would be referenced by this method.

        +
        url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/change/$',
        +CharUpdateView.as_view(), name='character-update')
        +
        +
        +

        If no View has been created and defined in urls.py, returns an +HTML anchor.

        +

        This method is naive and simply returns a path. Securing access to +the actual view and limiting who can modify objects is the developer’s +responsibility.

        +
        + +
        +
        +web_get_delete_url()[source]
        +

        Returns the URI path for a View that allows users to delete this object.

        +
        +
        Returns
        +

        path (str) – URI path to object deletion page, if defined.

        +
        +
        +

        Examples

        +
        Oscar (Character) = '/characters/oscar/1/delete/'
        +
        +
        +

        For this to work, the developer must have defined a named view +somewhere in urls.py that follows the format ‘modelname-action’, so +in this case a named view of ‘character-detail’ would be referenced +by this method.

        +
        url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/delete/$',
        +CharDeleteView.as_view(), name='character-delete')
        +
        +
        +

        If no View has been created and defined in urls.py, returns an HTML +anchor.

        +

        This method is naive and simply returns a path. Securing access to +the actual view and limiting who can delete this object is the +developer’s responsibility.

        +
        + +
        +
        +get_absolute_url()
        +

        Returns the URI path for a View that allows users to view details for +this object.

        +
        +
        Returns
        +

        path (str) – URI path to object detail page, if defined.

        +
        +
        +

        Examples

        +
        Oscar (Character) = '/characters/oscar/1/'
        +
        +
        +

        For this to work, the developer must have defined a named view somewhere +in urls.py that follows the format ‘modelname-action’, so in this case +a named view of ‘character-detail’ would be referenced by this method.

        +
        url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/$',
        +    CharDetailView.as_view(), name='character-detail')
        +
        +
        +

        If no View has been created and defined in urls.py, returns an +HTML anchor.

        +

        This method is naive and simply returns a path. Securing access to +the actual view and limiting who can view this object is the +developer’s responsibility.

        +
        +
        @@ -767,7 +754,6 @@ developer’s responsibility.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -784,6 +770,7 @@ developer’s responsibility.

        +
        develop branch
        @@ -270,6 +271,33 @@ existing Tag object, this will be re-used and no new Tag will be created.

        +
        +
        +has(tag=None, category=None, return_list=False)[source]
        +

        Checks if the given Tag (or list of Tags) exists on the object.

        +
        +
        Parameters
        +
          +
        • tag (str or iterable) – The Tag key or tags to check for. +If None, search by category.

        • +
        • category (str, optional) – Limit the check to Tags with this +category (note, that None is the default category).

        • +
        +
        +
        Returns
        +

        has_tag (bool or list)

        +
        +
        If the Tag exists on this object or not.

        If tag was given as an iterable then the return is a list of booleans.

        +
        +
        +

        +
        +
        Raises
        +

        ValueError – If neither tag nor category is given.

        +
        +
        +
        +
        get(key=None, default=None, category=None, return_tagobj=False, return_list=False)[source]
        @@ -364,8 +392,9 @@ tuples [(key, category), …].

        Batch-add tags from a list of tuples.

        Parameters
        -

        *args (tuple or str) – Each argument should be a tagstr keys or tuple (keystr, category) or -(keystr, category, data). It’s possible to mix input types.

        +

        *args (tuple or str) – Each argument should be a tagstr keys or tuple +(keystr, category) or (keystr, category, data). It’s possible to mix input +types.

        Notes

        @@ -436,7 +465,6 @@ of a latter tuple with the same category).

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -453,6 +481,7 @@ of a latter tuple with the same category).

        +
        develop branch
        @@ -40,21 +41,65 @@

        evennia.utils.ansi

        ANSI - Gives colour to text.

        -

        Use the codes defined in ANSIPARSER in your text to apply colour to text -according to the ANSI standard.

        -

        Examples:

        +

        Use the codes defined in the ANSIParser class to apply colour to text. The +parse_ansi function in this module parses text for markup and strip_ansi +removes it.

        +

        You should usually not need to call parse_ansi explicitly; it is run by +Evennia just before returning data to/from the user. Alternative markup is +possible by overriding the parser class (see also contrib/ for deprecated +markup schemes).

        +

        Supported standards:

        +
          +
        • ANSI 8 bright and 8 dark fg (foreground) colors

        • +
        • ANSI 8 dark bg (background) colors

        • +
        • ‘ANSI’ 8 bright bg colors ‘faked’ with xterm256 (bright bg not included in ANSI standard)

        • +
        • Xterm256 - 255 fg/bg colors + 26 greyscale fg/bg colors

        • +
        +
        +

        Markup

        +

        ANSI colors: r ed, g reen, y ellow, b lue, m agenta, c yan, n ormal (no color). +Capital letters indicate the ‘dark’ variant.

        +
          +
        • |r fg bright red

        • +
        • |R fg dark red

        • +
        • |[r bg bright red

        • +
        • |[R bg dark red

        • +
        • |[R|g bg dark red, fg bright green

        • +
        "This is |rRed text|n and this is normal again."
         
        -

        Mostly you should not need to call parse_ansi() explicitly; it is run by -Evennia just before returning data to/from the user. Depreciated example forms -are available by extending the ansi mapping.

        +

        Xterm256 colors are given as RGB (Red-Green-Blue), with values 0-5:

        +
          +
        • |500 fg bright red

        • +
        • |050 fg bright green

        • +
        • |005 fg bright blue

        • +
        • |110 fg dark brown

        • +
        • |425 fg pink

        • +
        • |[431 bg orange

        • +
        +

        Xterm256 greyscale:

        +
          +
        • |=a fg black

        • +
        • |=g fg dark grey

        • +
        • |=o fg middle grey

        • +
        • |=v fg bright grey

        • +
        • |=z fg white

        • +
        • |[=r bg middle grey

        • +
        +
        "This is |500Red text|n and this is normal again."
        +"This is |[=jText on dark grey background"
        +
        +
        +
        class evennia.utils.ansi.ANSIParser[source]

        Bases: object

        -

        A class that parses ANSI markup to ANSI command sequences.

        -

        We also allow to escape colour codes by prepending with an extra |.

        +

        A class that parses ANSI markup +to ANSI command sequences

        +

        We also allow to escape colour codes +by prepending with an extra |.

        ansi_map = [('|n', '\x1b[0m'), ('|/', '\r\n'), ('|-', '\t'), ('|>', ' '), ('|_', ' '), ('|*', '\x1b[7m'), ('|^', '\x1b[5m'), ('|u', '\x1b[4m'), ('|r', '\x1b[1m\x1b[31m'), ('|g', '\x1b[1m\x1b[32m'), ('|y', '\x1b[1m\x1b[33m'), ('|b', '\x1b[1m\x1b[34m'), ('|m', '\x1b[1m\x1b[35m'), ('|c', '\x1b[1m\x1b[36m'), ('|w', '\x1b[1m\x1b[37m'), ('|x', '\x1b[1m\x1b[30m'), ('|R', '\x1b[22m\x1b[31m'), ('|G', '\x1b[22m\x1b[32m'), ('|Y', '\x1b[22m\x1b[33m'), ('|B', '\x1b[22m\x1b[34m'), ('|M', '\x1b[22m\x1b[35m'), ('|C', '\x1b[22m\x1b[36m'), ('|W', '\x1b[22m\x1b[37m'), ('|X', '\x1b[22m\x1b[30m'), ('|h', '\x1b[1m'), ('|H', '\x1b[22m'), ('|!R', '\x1b[31m'), ('|!G', '\x1b[32m'), ('|!Y', '\x1b[33m'), ('|!B', '\x1b[34m'), ('|!M', '\x1b[35m'), ('|!C', '\x1b[36m'), ('|!W', '\x1b[37m'), ('|!X', '\x1b[30m'), ('|[R', '\x1b[41m'), ('|[G', '\x1b[42m'), ('|[Y', '\x1b[43m'), ('|[B', '\x1b[44m'), ('|[M', '\x1b[45m'), ('|[C', '\x1b[46m'), ('|[W', '\x1b[47m'), ('|[X', '\x1b[40m')]
        @@ -90,6 +135,11 @@ are available by extending the ansi mapping.

        mxp_re = '\\|lc(.*?)\\|lt(.*?)\\|le'
        +
        +
        +mxp_url_re = '\\|lu(.*?)\\|lt(.*?)\\|le'
        +
        +
        brightbg_sub = re.compile('(?<!\\|)\\|\\[r|(?<!\\|)\\|\\[g|(?<!\\|)\\|\\[y|(?<!\\|)\\|\\[b|(?<!\\|)\\|\\[m|(?<!\\|)\\|\\[c|(?<!\\|)\\|\\[w|(?<!\\|)\\|\\[x', re.DOTALL)
        @@ -125,6 +175,11 @@ are available by extending the ansi mapping.

        mxp_sub = re.compile('\\|lc(.*?)\\|lt(.*?)\\|le', re.DOTALL)
        +
        +
        +mxp_url_sub = re.compile('\\|lu(.*?)\\|lt(.*?)\\|le', re.DOTALL)
        +
        +
        ansi_map_dict = {'|!B': '\x1b[34m', '|!C': '\x1b[36m', '|!G': '\x1b[32m', '|!M': '\x1b[35m', '|!R': '\x1b[31m', '|!W': '\x1b[37m', '|!X': '\x1b[30m', '|!Y': '\x1b[33m', '|*': '\x1b[7m', '|-': '\t', '|/': '\r\n', '|>': ' ', '|B': '\x1b[22m\x1b[34m', '|C': '\x1b[22m\x1b[36m', '|G': '\x1b[22m\x1b[32m', '|H': '\x1b[22m', '|M': '\x1b[22m\x1b[35m', '|R': '\x1b[22m\x1b[31m', '|W': '\x1b[22m\x1b[37m', '|X': '\x1b[22m\x1b[30m', '|Y': '\x1b[22m\x1b[33m', '|[B': '\x1b[44m', '|[C': '\x1b[46m', '|[G': '\x1b[42m', '|[M': '\x1b[45m', '|[R': '\x1b[41m', '|[W': '\x1b[47m', '|[X': '\x1b[40m', '|[Y': '\x1b[43m', '|^': '\x1b[5m', '|_': ' ', '|b': '\x1b[1m\x1b[34m', '|c': '\x1b[1m\x1b[36m', '|g': '\x1b[1m\x1b[32m', '|h': '\x1b[1m', '|m': '\x1b[1m\x1b[35m', '|n': '\x1b[0m', '|r': '\x1b[1m\x1b[31m', '|u': '\x1b[4m', '|w': '\x1b[1m\x1b[37m', '|x': '\x1b[1m\x1b[30m', '|y': '\x1b[1m\x1b[33m'}
        @@ -842,6 +897,7 @@ with.

        +
        @@ -864,6 +920,14 @@ with.

        +

        Table of Contents

        + +
        -
        @@ -904,6 +967,7 @@ with.

        +
        develop branch
        @@ -40,23 +41,21 @@

        evennia.utils.batchprocessors

        This module contains the core methods for the Batch-command- and -Batch-code-processors respectively. In short, these are two different -ways to build a game world using a normal text-editor without having -to do so ‘on the fly’ in-game. They also serve as an automatic backup -so you can quickly recreate a world also after a server reset. The -functions in this module is meant to form the backbone of a system -called and accessed through game commands.

        -

        The Batch-command processor is the simplest. It simply runs a list of -in-game commands in sequence by reading them from a text file. The -advantage of this is that the builder only need to remember the normal -in-game commands. They are also executing with full permission checks -etc, making it relatively safe for builders to use. The drawback is -that in-game there is really a builder-character walking around -building things, and it can be important to create rooms and objects -in the right order, so the character can move between them. Also -objects that affects players (such as mobs, dark rooms etc) will -affect the building character too, requiring extra care to turn -off/on.

        +Batch-code-processors respectively. In short, these are two different ways to +build a game world using a normal text-editor without having to do so ‘on the +fly’ in-game. They also serve as an automatic backup so you can quickly +recreate a world also after a server reset. The functions in this module is +meant to form the backbone of a system called and accessed through game +commands.

        +

        The Batch-command processor is the simplest. It simply runs a list of in-game +commands in sequence by reading them from a text file. The advantage of this is +that the builder only need to remember the normal in-game commands. They are +also executing with full permission checks etc, making it relatively safe for +builders to use. The drawback is that in-game there is really a +builder-character walking around building things, and it can be important to +create rooms and objects in the right order, so the character can move between +them. Also objects that affects players (such as mobs, dark rooms etc) will +affect the building character too, requiring extra care to turn off/on.

        The Batch-code processor is a more advanced system that accepts full Python code, executing in chunks. The advantage of this is much more power; practically anything imaginable can be coded and handled using @@ -69,33 +68,38 @@ etc. You also need to know Python and Evennia’s API. Hence it’s recommended that the batch-code processor is limited only to superusers or highly trusted staff.

        -

        Batch-Command processor file syntax

        +

        Batch-command processor file syntax

        The batch-command processor accepts ‘batchcommand files’ e.g batch.ev, containing a sequence of valid Evennia commands in a simple format. The engine runs each command in sequence, as if they had been run at the game prompt.

        Each Evennia command must be delimited by a line comment to mark its -end. This way entire game worlds can be created and planned offline; it is +end.

        +
        look
        +# delimiting comment
        +create/drop box
        +# another required comment
        +
        +
        +

        One can also inject another batchcmdfile:

        +
        #INSERT path.batchcmdfile
        +
        +
        +

        This way entire game worlds can be created and planned offline; it is especially useful in order to create long room descriptions where a real offline text editor is often much better than any online text editor or prompt.

        -

        There is only one batchcommand-specific entry to use in a batch-command -files (all others are just like in-game commands):

        -
          -
        • #INSERT path.batchcmdfile - this as the first entry on a line will -import and run a batch.ev file in this position, as if it was -written in this file.

        • -
        -

        Example of batch.ev file:

        +
        +

        Example of batch.ev file:

        # batch file
         # all lines starting with # are comments; they also indicate
         # that a command definition is over.
         
        -@create box
        +create box
         
         # this comment ends the @create command.
         
        -@set box/desc = A large box.
        +set box/desc = A large box.
         
         Inside are some scattered piles of clothing.
         
        @@ -108,24 +112,25 @@ written in this file.

        # (so two empty lines becomes a new paragraph). -@teleport #221 +teleport #221 # (Assuming #221 is a warehouse or something.) # (remember, this comment ends the @teleport command! Don'f forget it) # Example of importing another file at this point. -#INSERT examples.batch +#IMPORT examples.batch -@drop box +drop box # Done, the box is in the warehouse! (this last comment is not necessary to -# close the @drop command since it's the end of the file) +# close the drop command since it's the end of the file)

        An example batch file is contrib/examples/batch_example.ev.

        +
        -

        Batch-Code processor file syntax

        +

        Batch-code processor file syntax

        The Batch-code processor accepts full python modules (e.g. batch.py) that looks identical to normal Python files. The difference from importing and running any Python module is that the batch-code module @@ -156,13 +161,17 @@ this file.

        Importing works as normal. The following variables are automatically made available in the script namespace.

          -
        • caller - The object executing the batchscript

        • -
        • DEBUG - This is a boolean marking if the batchprocessor is running -in debug mode. It can be checked to e.g. delete created objects +

        • caller - The object executing the batchscript

        • +
        • +
          DEBUG - This is a boolean marking if the batchprocessor is running

          in debug mode. It can be checked to e.g. delete created objects when running a CODE block multiple times during testing. -(avoids creating a slew of same-named db objects)

        • +(avoids creating a slew of same-named db objects)

          + + +
        -

        Example batch.py file:

        +
        +

        Example batch.py file

        #HEADER
         
         from django.conf import settings
        @@ -190,7 +199,6 @@ when running a CODE block multiple times during testing.
         script = create.create_script()
         
        -
        evennia.utils.batchprocessors.read_batchfile(pythonpath, file_ending='.py')[source]
        @@ -207,7 +215,7 @@ or .py). The ending should not be included in the python path.

        Returns
        -

        str – The text content of the batch file.

        +

        text (str) – The text content of the batch file.

        Raises

        IOError – If problems reading file.

        @@ -223,13 +231,22 @@ or .py). The ending should not be included in the python path.

        parse_file(pythonpath)[source]
        -

        This parses the lines of a batchfile according to the following -rules:

        +

        This parses the lines of a batch-command-file.

        +
        +
        Parameters
        +

        pythonpath (str) – The dot-python path to the file.

        +
        +
        Returns
        +

        list – A list of all parsed commands with arguments, as strings.

        +
        +
        +

        Notes

        +

        Parsing follows the following rules:

          -
        1. # at the beginning of a line marks the end of the command before +

        2. A # at the beginning of a line marks the end of the command before it. It is also a comment and any number of # can exist on subsequent lines (but not inside comments).

        3. -
        4. #INSERT at the beginning of a line imports another +

        5. #INSERT at the beginning of a line imports another batch-cmd file file and pastes it into the batch file as if it was written there.

        6. Commands are placed alone at the beginning of a line and their @@ -264,30 +281,28 @@ a newline (so two empty lines is a paragraph).

        7. parse_file(pythonpath)[source]
          -

          This parses the lines of a batchfile according to the following -rules:

          +

          This parses the lines of a batch-code file

          Parameters

          pythonpath (str) – The dot-python path to the file.

          Returns
          -

          codeblocks (list)

          +

          list

          -
          A list of all #CODE blocks, each with

          prepended #HEADER data. If no #CODE blocks were found, -this will be a list of one element.

          +
          A list of all #CODE blocks, each with

          prepended #HEADER block data. If no #CODE +blocks were found, this will be a list of one element +containing all code in the file (so a normal Python file).

          Notes

          +

          Parsing is done according to the following rules:

            -
          1. -
            Code before a #CODE/HEADER block are considered part of

            the first code/header block or is the ONLY block if no -#CODE/HEADER blocks are defined.

            -
            -
            -
          2. +
          3. Code before a #CODE/HEADER block are considered part of +the first code/header block or is the ONLY block if no +#CODE/HEADER blocks are defined.

          4. Lines starting with #HEADER starts a header block (ends other blocks)

          5. Lines starting with #CODE begins a code block (ends other blocks)

          6. Lines starting with #INSERT are on form #INSERT filename. Code from @@ -320,6 +335,7 @@ namespace.

          +
        @@ -346,8 +362,14 @@ namespace.

        Table of Contents

        @@ -375,7 +397,6 @@ namespace.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -392,6 +413,7 @@ namespace.

        +
        develop branch
        @@ -231,7 +232,6 @@ scripts defined in settings.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -248,6 +248,7 @@ scripts defined in settings.

        +
        develop branch
        @@ -39,25 +40,15 @@

        evennia.utils.create

        -

        This module gathers all the essential database-creation -functions for the game engine’s various object types.

        -

        Only objects created ‘stand-alone’ are in here, e.g. object Attributes -are always created directly through their respective objects.

        -

        Each creation_* function also has an alias named for the entity being -created, such as create_object() and object(). This is for -consistency with the utils.search module and allows you to do the -shorter “create.object()”.

        -

        The respective object managers hold more methods for manipulating and -searching objects already existing in the database.

        -
        -
        Models covered:

        Objects -Scripts -Help -Message -Channel -Accounts

        -
        -
        +

        This module gathers all the essential database-creation functions for the game +engine’s various object types.

        +

        Only objects created ‘stand-alone’ are in here. E.g. object Attributes are +always created through their respective objects handlers.

        +

        Each creation_* function also has an alias named for the entity being created, +such as create_object() and object(). This is for consistency with the +utils.search module and allows you to do the shorter create.object().

        +

        The respective object managers hold more methods for manipulating and searching +objects already existing in the database.

        evennia.utils.create.create_object(typeclass=None, key=None, location=None, home=None, permissions=None, locks=None, aliases=None, tags=None, destination=None, report_to=None, nohome=False, attributes=None, nattributes=None)[source]
        @@ -67,15 +58,14 @@ Accounts

        • typeclass (class or str) – Class or python path to a typeclass.

        • key (str) – Name of the new object. If not set, a name of -#dbref will be set.

        • +#dbref will be set.

        • home (Object or str) – Obj or #dbref to use as the object’s home location.

        • permissions (list) – A list of permission strings or tuples (permstring, category).

        • locks (str) – one or more lockstrings, separated by semicolons.

        • aliases (list) – A list of alternative keys or tuples (aliasstring, category).

        • tags (list) – List of tag keys or tuples (tagkey, category) or (tagkey, category, data).

        • -
        • destination (Object or str) – Obj or #dbref to use as an Exit’s -target.

        • +
        • destination (Object or str) – Obj or #dbref to use as an Exit’s target.

        • report_to (Object) – The object to return error messages to.

        • nohome (bool) – This allows the creation of objects without a default home location; only used when creating the default @@ -91,10 +81,8 @@ adding this rarely makes sense since this data will not survive a reload.

          object (Object) – A newly created object of the given typeclass.

        Raises
        -
        +

        ObjectDB.DoesNotExist – If trying to create an Object with +location or home that can’t be found.

        @@ -132,9 +120,8 @@ created or if the start method must be called explicitly.

        report_to (Object) – The object to return error messages to.

      • desc (str) – Optional description of script

      • tags (list) – List of tags or tuples (tag, category).

      • -
      • attributes (list) – List of tuples (key, value), (key, value, category), -(key, value, category, lockstring) or -(key, value, category, lockstring, default_access).

      • +
      • attributes (list) – List if tuples (key, value) or (key, value, category) +(key, value, lockstring) or (key, value, lockstring, default_access).

      • Returns
        @@ -172,21 +159,21 @@ in-game setting information and so on.

        -evennia.utils.create.create_message(senderobj, message, channels=None, receivers=None, locks=None, tags=None, header=None)[source]
        +evennia.utils.create.create_message(senderobj, message, receivers=None, locks=None, tags=None, header=None, **kwargs)[source]

        Create a new communication Msg. Msgs represent a unit of database-persistent communication between entites.

        Parameters
          -
        • senderobj (Object or Account) – The entity sending the Msg.

        • +
        • senderobj (Object, Account, Script, str or list) – The entity (or +entities) sending the Msg. If a str, this is the id-string +for an external sender type.

        • message (str) – Text with the message. Eventual headers, titles etc should all be included in this text string. Formatting will be retained.

        • -
        • channels (Channel, key or list) – A channel or a list of channels to -send to. The channels may be actual channel objects or their -unique key strings.

        • -
        • receivers (Object, Account, str or list) – An Account/Object to send -to, or a list of them. May be Account objects or accountnames.

        • +
        • receivers (Object, Account, Script, str or list) – An Account/Object to send +to, or a list of them. If a string, it’s an identifier for an external +receiver.

        • locks (str) – Lock definition string.

        • tags (list) – A list of tags or tuples (tag, category).

        • header (str) – Mime-type or other optional information for the message

        • @@ -194,10 +181,9 @@ to, or a list of them. May be Account objects or accountnames.

        Notes

        -

        The Comm system is created very open-ended, so it’s fully possible -to let a message both go to several channels and to several -receivers at the same time, it’s up to the command definitions to -limit this as desired.

        +

        The Comm system is created to be very open-ended, so it’s fully +possible to let a message both go several receivers at the same time, +it’s up to the command definitions to limit this as desired.

        @@ -315,7 +301,6 @@ operations and is thus not suitable for play-testing the game.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -332,6 +317,7 @@ operations and is thus not suitable for play-testing the game.

        +
        develop branch
        @@ -88,7 +89,7 @@ will save to when they update. It must have a ‘value’ property that saves assigned data to the database. Skip if not serializing onto a given object. If db_obj is given, this function will convert lists, dicts and sets to their -_SaverList, _SaverDict and _SaverSet counterparts.

        +_SaverList, _SaverDict and _SaverSet counterparts.

        Returns
        @@ -166,7 +167,6 @@ function will convert lists, dicts and sets to their
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -183,6 +183,7 @@ function will convert lists, dicts and sets to their +
        develop branch
        @@ -40,47 +41,39 @@

        evennia.utils.eveditor

        EvEditor (Evennia Line Editor)

        -

        This implements an advanced line editor for editing longer texts -in-game. The editor mimics the command mechanisms of the “VI” editor -(a famous line-by-line editor) as far as reasonable.

        +

        This implements an advanced line editor for editing longer texts in-game. The +editor mimics the command mechanisms of the “VI” editor (a famous line-by-line +editor) as far as reasonable.

        Features of the editor:

        -
        -
          +
          • undo/redo.

          • edit/replace on any line of the buffer.

          • search&replace text anywhere in buffer.

          • formatting of buffer, or selection, to certain width + indentations.

          • allow to echo the input or not, depending on your client.

          • +
          • in-built help

          -
        -

        To use the editor, just import EvEditor from this module -and initialize it:

        +

        To use the editor, just import EvEditor from this module and initialize it:

        from evennia.utils.eveditor import EvEditor
        -EvEditor(caller, loadfunc=None, savefunc=None, quitfunc=None, key="", persistent=True)
        +
        +# set up an editor to edit the caller's 'desc' Attribute
        +def _loadfunc(caller):
        +    return caller.db.desc
        +
        +def _savefunc(caller, buffer):
        +    caller.db.desc = buffer.strip()
        +    return True
        +
        +def _quitfunc(caller):
        +    caller.msg("Custom quit message")
        +
        +# start the editor
        +EvEditor(caller, loadfunc=None, savefunc=None, quitfunc=None, key="",
        +         persistent=True, code=False)
         
        -
          -
        • caller is the user of the editor, the one to see all feedback.

        • -
        • loadfunc(caller) is called when the editor is first launched; the -return from this function is loaded as the starting buffer in the -editor.

        • -
        • safefunc(caller, buffer) is called with the current buffer when -saving in the editor. The function should return True/False depending -on if the saving was successful or not.

        • -
        • quitfunc(caller) is called when the editor exits. If this is given, -no automatic quit messages will be given.

        • -
        • key is an optional identifier for the editing session, to be -displayed in the editor.

        • -
        • persistent means the editor state will be saved to the database making it -survive a server reload. Note that using this mode, the load- save- -and quit-funcs must all be possible to pickle - notable unusable -callables are class methods and functions defined inside other -functions. With persistent=False, no such restriction exists.

        • -
        • code set to True activates features on the EvEditor to enter Python code.

        • -
        -

        In addition, the EvEditor can be used to enter Python source code, -and offers basic handling of indentation.

        -
        +

        The editor can also be used to format Python code and be made to +survive a reload. See the EvEditor class for more details.

        class evennia.utils.eveditor.CmdSaveYesNo(**kwargs)[source]
        @@ -124,6 +117,11 @@ command was given specifically as “no” or “n”.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '__noinput_command', 'category': 'general', 'key': '__nomatch_command', 'tags': '', 'text': '\n Save the editor state on quit. This catches\n nomatches (defaults to Yes), and avoid saves only if\n command was given specifically as "no" or "n".\n '}
        +
        +
        @@ -182,17 +180,19 @@ command was given specifically as “no” or “n”.

        parse()[source]
        -

        Handles pre-parsing

        -
        -
        Usage:

        :cmd [li] [w] [txt]

        -
        -
        +

        Handles pre-parsing. Editor commands are on the form

        +
        :cmd [li] [w] [txt]
        +
        +

        Where all arguments are optional.

          -
        • li - line number (int), starting from 1. This could also -be a range given as <l>:<l>.

        • -
        • w - word(s) (string), could be encased in quotes.

        • -
        • txt - extra text (string), could be encased in quotes.

        • +
        • +
          li - line number (int), starting from 1. This could also

          be a range given as <l>:<l>.

          +
          +
          +
        • +
        • w - word(s) (string), could be encased in quotes.

        • +
        • txt - extra text (string), could be encased in quotes.

        @@ -216,6 +216,11 @@ be a range given as <l>:<l>.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '', 'category': 'general', 'key': 'command', 'tags': '', 'text': '\n Base parent for editor commands\n '}
        +
        +
        @@ -251,6 +256,11 @@ indentation.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': '__noinput_command', 'category': 'general', 'key': '__nomatch_command', 'tags': '', 'text': '\n No command match - Inputs line of text into buffer.\n\n '}
        +
        +
        @@ -265,7 +275,7 @@ indentation.

        -aliases = [':echo', ':::', ':dd', ':q', ':u', ':I', ':uu', ':A', ':wq', ':', ':y', ':=', ':!', ':h', ':j', ':>', ':s', ':dw', ':DD', ':S', ':q!', ':UU', ':fd', ':w', ':r', ':f', ':fi', ':p', ':i', ':x', '::', ':<']
        +aliases = [':A', ':h', '::', ':x', ':q', ':::', ':q!', ':S', ':w', ':i', ':!', ':fd', ':DD', ':>', ':dw', ':', ':p', ':dd', ':y', ':uu', ':I', ':r', ':fi', ':wq', ':<', ':echo', ':UU', ':u', ':s', ':=', ':f', ':j']
        @@ -291,6 +301,11 @@ efficient presentation.

        lock_storage = 'cmd:all()'
        +
        +
        +search_index_entry = {'aliases': ':A :h :: :x :q ::: :q! :S :w :i :! :fd :DD :> :dw : :p :dd :y :uu :I :r :fi :wq :< :echo :UU :u :s := :f :j', 'category': 'general', 'key': ':editor_command_group', 'tags': '', 'text': '\n Commands for the editor\n '}
        +
        +
        @@ -519,7 +534,6 @@ formatting information.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -536,6 +550,7 @@ formatting information.

        +
        develop branch
        @@ -73,6 +74,7 @@ object when displaying the form.

        | cccccccc | cccccccccccccccccBccccccccccccccccc | | | | ------------------------------------------------- +'''

        The first line of the FORM string is ignored. The forms and table @@ -163,16 +165,16 @@ EvCell or Tables.

        __init__(filename=None, cells=None, tables=None, form=None, **kwargs)[source]
        -

        Initiate the form.

        +

        Initiate the form

        Keyword Arguments
        • filename (str) – Path to template file.

        • -
        • cells (dict) – A dictionary mapping of {id:text}.

        • -
        • tables (dict) – A dictionary mapping of {id:EvTable}.

        • -
        • form (dict) – A dictionary of +

        • cells (dict) – A dictionary mapping {id: text}

        • +
        • tables (dict) – A dictionary mapping {id: EvTable}.

        • +
        • form (dict) – A dictionary {“FORMCHAR”:char, “TABLECHAR”:char, “FORM”:templatestring}. -if this is given, filename is not read.

        • +If this is given, filename is not read.

        @@ -261,7 +263,6 @@ if this is given, filename is not read.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -278,6 +279,7 @@ if this is given, filename is not read.

        +
        develop branch
        @@ -39,9 +40,10 @@

        evennia.utils.evmenu

        -

        The EvMenu is a full in-game menu system for Evennia.

        -

        To start the menu, just import the EvMenu class from this module.

        -

        Example usage:

        +

        EvMenu

        +

        This implements a full menu system for Evennia.

        +

        To start the menu, just import the EvMenu class from this module. +Example usage:

        from evennia.utils.evmenu import EvMenu
         
         EvMenu(caller, menu_module_path,
        @@ -51,8 +53,8 @@
         

        Where caller is the Object to use the menu on - it will get a new -cmdset while using the Menu. The menu_module_path is the python path -to a python module containing function definitions. By adjusting the +cmdset while using the Menu. The menu_module_path is the python path +to a python module containing function definitions. By adjusting the keyword options of the Menu() initialization call you can start the menu at different places in the menu definition file, adjust if the menu command should overload the normal commands or not, etc.

        @@ -78,7 +80,7 @@ command definition too) with function definitions:

        return text, options
        -

        Where caller is the object using the menu and input_string is the +

        Where caller is the object using the menu and input_string is the command entered by the user on the previous node (the command entered to get to this node). The node function code will only be executed once per node-visit and the system will accept nodes with @@ -92,50 +94,43 @@ deleted when the menu is exited.

        returned as None as well. If the options are returned as None, the menu is immediately exited and the default “look” command is called.

          -
        • text (str, tuple or None): Text shown at this node. If a tuple, the -second element in the tuple is a help text to display at this -node when the user enters the menu help command there.

        • +
        • +
          text (str, tuple or None): Text shown at this node. If a tuple, the

          second element in the tuple is a help text to display at this +node when the user enters the menu help command there.

          +
          +
          +
        • options (tuple, dict or None): If None, this exits the menu. If a single dict, this is a single-option node. If a tuple, -it should be a tuple of option dictionaries. Option dicts have -the following keys:

          +it should be a tuple of option dictionaries. Option dicts have the following keys:

            -
          • -
            key (str or tuple, optional): What to enter to choose this option.

            If a tuple, it must be a tuple of strings, where the first string is the +

          • key (str or tuple, optional): What to enter to choose this option. +If a tuple, it must be a tuple of strings, where the first string is the key which will be shown to the user and the others are aliases. If unset, the options’ number will be used. The special key _default marks this option as the default fallback when no other option matches the user input. There can only be one _default option per node. It -will not be displayed in the list.

            -
          • -
            -
          • +will not be displayed in the list.

          • desc (str, optional): This describes what choosing the option will do.

          • -
          • -
            goto (str, tuple or callable): If string, should be the name of node to go to

            when this option is selected. If a callable, it has the signature +

          • goto (str, tuple or callable): If string, should be the name of node to go to +when this option is selected. If a callable, it has the signature callable(caller[,raw_input][,**kwargs]). If a tuple, the first element -is the callable and the second is a dict with the kwargs to pass to +is the callable and the second is a dict with the **kwargs to pass to the callable. Those kwargs will also be passed into the next node if possible. Such a callable should return either a str or a (str, dict), where the string is the name of the next node to go to and the dict is the new, (possibly modified) kwarg to pass into the next node. If the callable returns -None or the empty string, the current node will be revisited.

            -
          • -
            -
          • -
          • -
            exec (str, callable or tuple, optional): This takes the same input as goto above

            and runs before it. If given a node name, the node will be executed but will not +None or the empty string, the current node will be revisited.

          • +
          • exec (str, callable or tuple, optional): This takes the same input as goto above +and runs before it. If given a node name, the node will be executed but will not be considered the next node. If node/callback returns str or (str, dict), these will replace the goto step (goto callbacks will not fire), with the string being the next node name and the optional dict acting as the kwargs-input for the next node. -If an exec callable returns None, the current node is re-run.

            -
        -
        - +If an exec callable returns the empty string (only), the current node is re-run.

        -

        If key is not given, the option will automatically be identified by +

        If key is not given, the option will automatically be identified by its number 1..N.

        Example:

        # in menu_module.py
        @@ -189,9 +184,8 @@ same Using help will show the help text, otherwise a list of
         available commands while in menu mode.

        The menu tree is exited either by using the in-menu quit command or by reaching a node without any options.

        -

        For a menu demo, import CmdTestMenu from this module and add it to -your default cmdset. Run it with this module, like testmenu -evennia.utils.evmenu.

        +

        For a menu demo, import CmdTestMenu from this module and add it to +your default cmdset. Run it with this module, like testmenu evennia.utils.evmenu.

        @@ -40,9 +41,8 @@

        evennia.utils.evmore

        EvMore - pager mechanism

        -

        This is a pager for displaying long texts and allows stepping up and -down in the text (the name comes from the traditional ‘more’ unix -command).

        +

        This is a pager for displaying long texts and allows stepping up and down in +the text (the name comes from the traditional ‘more’ unix command).

        To use, simply pass the text through the EvMore object:

        from evennia.utils.evmore import EvMore
         
        @@ -50,16 +50,17 @@ command).

        EvMore(caller, text, always_page=False, session=None, justify_kwargs=None, **kwargs)
        -

        One can also use the convenience function msg from this module:

        +

        One can also use the convenience function msg from this module to avoid +having to set up the EvMenu object manually:

        from evennia.utils import evmore
         
         text = some_long_text_output()
         evmore.msg(caller, text, always_page=False, session=None, justify_kwargs=None, **kwargs)
         
        -

        Where always_page decides if the pager is used also if the text is not long -enough to need to scroll, session is used to determine which session to relay -to and justify_kwargs are kwargs to pass to utils.utils.justify in order to +

        The always_page argument decides if the pager is used also if the text is not long +enough to need to scroll, session is used to determine which session to relay +to and justify_kwargs are kwargs to pass to utils.utils.justify in order to change the formatting of the text. The remaining **kwargs will be passed on to the caller.msg() construct every time the page is updated.


        @@ -75,7 +76,7 @@ the caller.msg() construct every time the page is updated.

        -aliases = ['end', 'b', 'e', 'top', 'a', 'quit', 't', 'back', 'next', 'n', 'abort', 'q']
        +aliases = ['quit', 'next', 'e', 'n', 'end', 'back', 't', 'q', 'a', 'abort', 'top', 'b']
        @@ -99,6 +100,11 @@ the caller.msg() construct every time the page is updated.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': 'quit next e n end back t q a abort top b', 'category': 'general', 'key': '__noinput_command', 'tags': '', 'text': '\n Manipulate the text paging\n '}
        +
        +
        @@ -137,6 +143,11 @@ the caller.msg() construct every time the page is updated.

        lock_storage = 'cmd:all();'
        +
        +
        +search_index_entry = {'aliases': 'l', 'category': 'general', 'key': 'look', 'tags': '', 'text': '\n Override look to display window and prevent OOCLook from firing\n '}
        +
        +
        @@ -178,11 +189,11 @@ self.add().

        class evennia.utils.evmore.EvMore(caller, inp, always_page=False, session=None, justify=False, justify_kwargs=None, exit_on_lastpage=False, exit_cmd=None, page_formatter=<class 'str'>, **kwargs)[source]

        Bases: object

        -

        The main pager object.

        +

        The main pager object

        __init__(caller, inp, always_page=False, session=None, justify=False, justify_kwargs=None, exit_on_lastpage=False, exit_cmd=None, page_formatter=<class 'str'>, **kwargs)[source]
        -

        Initialization of the Evmore input handler.

        +

        Initialization of the EvMore pager.

        Parameters
          @@ -190,9 +201,8 @@ self.add().

        • inp (str, EvTable, Paginator or iterator) –

          The text or data to put under paging.

          • If a string, paginage normally. If this text contains -one or more \f (backslash + f) format symbols, automatic -pagination and justification are force-disabled and -page-breaks will only happen after each \f.

          • +one or more \f format symbol, automatic pagination and justification +are force-disabled and page-breaks will only happen after each \f.

          • If EvTable, the EvTable will be paginated with the same setting on each page if it is too long. The table decorations will be considered in the size of the page.

          • @@ -201,8 +211,9 @@ expected to be a line in the final display. Each line will be run through iter_callable.

        • -
        • always_page (bool, optional) – If False, the pager will only kick -in if inp is too big to fit the screen.

        • +
        • always_page (bool, optional) – If False, the +pager will only kick in if inp is too big +to fit the screen.

        • session (Session, optional) – If given, this session will be used to determine the screen width and will receive all output.

        • justify (bool, optional) – If set, auto-justify long lines. This must be turned @@ -218,48 +229,28 @@ exit message will not be shown.

        • the caller when the more page exits. Note that this will be using whatever cmdset the user had before the evmore pager was activated (so none of the evmore commands will be available when this is run).

          -
        • kwargs (any, any) – These will be passed on to the caller.msg method.

        • +
        • kwargs (any, optional) – These will be passed on to the caller.msg method.

        Examples

        -

        Basic use:

        super_long_text = " ... "
         EvMore(caller, super_long_text)
         
        -

        Paginated query data - this is an optimization to avoid fetching -database data until it’s actually paged to.

        +

        Paginator

        from django.core.paginator import Paginator
        -
         query = ObjectDB.objects.all()
         pages = Paginator(query, 10)  # 10 objs per page
         EvMore(caller, pages)
         
        -

        Automatic split EvTable over multiple EvMore pages

        -
        table = EvMore(*header, table=tabledata)
        -EvMore(caller, table)
        -
        -
        -

        Every page a separate EvTable (optimization for very large data sets)

        -
        from evennia import EvTable, EvMore
        -
        -class TableEvMore(EvMore):
        -    def init_pages(self, data):
        -        pages = # depends on data type
        -        super().init_pages(pages)
        -
        -    def page_formatter(self, page):
        -        table = EvTable()
        -
        -        for line in page:
        -            cols = # split raw line into columns
        -            table.add_row(*cols)
        -
        -        return str(table)
        -
        -TableEvMore(caller, pages)
        +

        Every page an EvTable

        +
        from evennia import EvTable
        +def _to_evtable(page):
        +    table = ... # convert page to a table
        +    return EvTable(*headers, table=table, ...)
        +EvMore(caller, pages, page_formatter=_to_evtable)
         
        @@ -353,9 +344,14 @@ querysets); to avoid fetching all objects at the same time.

        init_f_str(text)[source]
        -

        The input contains \f (backslash + f) markers. We use \f to indicate -the user wants to enforce their line breaks on their own. If so, we do -no automatic line-breaking/justification at all.

        +

        The input contains f markers. We use f to indicate the user wants to +enforce their line breaks on their own. If so, we do no automatic +line-breaking/justification at all.

        +
        +
        Parameters
        +

        text (str) – The string to format with f-markers.

        +
        +
        @@ -378,16 +374,15 @@ strings, querysets, django.Paginator, EvTables and any iterables with strings.Notes

        If overridden, this method must perform the following actions:

          -
        • read and re-store self._data (the incoming data set) if needed -for pagination to work.

        • +
        • read and re-store self._data (the incoming data set) if needed for pagination to +work.

        • set self._npages to the total number of pages. Default is 1.

        • set self._paginator to a callable that will take a page number 1…N and return the data to display on that page (not any decorations or next/prev buttons). If only wanting to change the paginator, override self.paginator instead.

        • -
        • set self._page_formatter to a callable that will receive the -page from self._paginator and format it with one element per -line. Default is str. Or override self.page_formatter -directly instead.

        • +
        • set self._page_formatter to a callable that will receive the page from +self._paginator and format it with one element per line. Default is str. Or +override self.page_formatter directly instead.

        By default, helper methods are called that perform these actions depending on supported inputs.

        @@ -439,46 +434,69 @@ EvTable across many pages and feed it into EvMore all at once).

        evennia.utils.evmore.msg(caller, text='', always_page=False, session=None, justify=False, justify_kwargs=None, exit_on_lastpage=True, **kwargs)[source]
        -

        EvMore-supported version of msg, mimicking the normal msg method.

        +
        +

        EvMore-supported version of msg, mimicking the normal msg method.

        +
        +

        Initialization of the EvMore pager.

        Parameters
        • caller (Object or Account) – Entity reading the text.

        • -
        • text (str, EvTable or iterator) –

          The text or data to put under paging.

          +
        • inp (str, EvTable, Paginator or iterator) –

          The text or data to put under paging.

          • If a string, paginage normally. If this text contains -one or more \f (backslash + f) format symbol, automatic pagination is disabled -and page-breaks will only happen after each \f.

          • +one or more \f format symbol, automatic pagination and justification +are force-disabled and page-breaks will only happen after each \f.

          • If EvTable, the EvTable will be paginated with the same setting on each page if it is too long. The table decorations will be considered in the size of the page.

          • -
          • Otherwise text is converted to an iterator, where each step is -is expected to be a line in the final display, and each line -will be run through repr().

          • +
          • Otherwise inp is converted to an iterator, where each step is +expected to be a line in the final display. Each line +will be run through iter_callable.

        • always_page (bool, optional) – If False, the -pager will only kick in if text is too big +pager will only kick in if inp is too big to fit the screen.

        • session (Session, optional) – If given, this session will be used to determine the screen width and will receive all output.

        • -
        • justify (bool, optional) – If set, justify long lines in output. Disable for -fixed-format output, like tables.

        • -
        • justify_kwargs (dict, bool or None, optional) – If given, this should -be valid keyword arguments to the utils.justify() function. If False, -no justification will be done.

        • -
        • exit_on_lastpage (bool, optional) – Immediately exit pager when reaching the last page.

        • -
        • use_evtable (bool, optional) – If True, each page will be rendered as an -EvTable. For this to work, text must be an iterable, where each element -is the table (list of list) to render on that page.

        • -
        • evtable_args (tuple, optional) – The args to use for EvTable on each page.

        • -
        • evtable_kwargs (dict, optional) – The kwargs to use for EvTable on each -page (except table, which is supplied by EvMore per-page).

        • -
        • kwargs (any, optional) – These will be passed on -to the caller.msg method.

        • +
        • justify (bool, optional) – If set, auto-justify long lines. This must be turned +off for fixed-width or formatted output, like tables. It’s force-disabled +if inp is an EvTable.

        • +
        • justify_kwargs (dict, optional) – Keywords for the justifiy function. Used only +if justify is True. If this is not set, default arguments will be used.

        • +
        • exit_on_lastpage (bool, optional) – If reaching the last page without the +page being completely filled, exit pager immediately. If unset, +another move forward is required to exit. If set, the pager +exit message will not be shown.

        • +
        • exit_cmd (str, optional) – If given, this command-string will be executed on +the caller when the more page exits. Note that this will be using whatever +cmdset the user had before the evmore pager was activated (so none of +the evmore commands will be available when this is run).

        • +
        • kwargs (any, optional) – These will be passed on to the caller.msg method.

        +

        Examples

        +
        super_long_text = " ... "
        +EvMore(caller, super_long_text)
        +
        +
        +

        Paginator

        +
        from django.core.paginator import Paginator
        +query = ObjectDB.objects.all()
        +pages = Paginator(query, 10)  # 10 objs per page
        +EvMore(caller, pages)
        +
        +
        +

        Every page an EvTable

        +
        from evennia import EvTable
        +def _to_evtable(page):
        +    table = ... # convert page to a table
        +    return EvTable(*headers, table=table, ...)
        +EvMore(caller, pages, page_formatter=_to_evtable)
        +
        +
        @@ -526,7 +544,6 @@ to the caller.msg method.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -543,6 +560,7 @@ to the caller.msg method.

        +
        develop branch
        @@ -39,13 +40,15 @@

        evennia.utils.evtable

        -

        This is an advanced ASCII table creator. It was inspired by -[prettytable](https://code.google.com/p/prettytable/) but shares no code.

        +

        This is an advanced ASCII table creator. It was inspired by Prettytable +(https://code.google.com/p/prettytable/) but shares no code and is considerably +more advanced, supporting auto-balancing of incomplete tables and ANSI colors among +other things.

        Example usage:

        from evennia.utils import evtable
         
         table = evtable.EvTable("Heading1", "Heading2",
        -              table=[[1,2,3],[4,5,6],[7,8,9]], border="cells")
        +                table=[[1,2,3],[4,5,6],[7,8,9]], border="cells")
         table.add_column("This is long data", "This is even longer data")
         table.add_row("This is a single row")
         print table
        @@ -99,8 +102,9 @@ Here we change the width and alignment of the column at index 3
         (Python starts from 0):

        table.reformat_column(3, width=30, align="r")
         print table
        -
        -+-----------+-------+-----+-----------------------------+---------+
        +
        +
        +
        +-----------+-------+-----+-----------------------------+---------+
         | Heading1  | Headi |     |                             |         |
         |           | ng2   |     |                             |         |
         +~~~~~~~~~~~+~~~~~~~+~~~~~+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+~~~~~~~~~+
        @@ -121,14 +125,13 @@ Here we change the width and alignment of the column at index 3
         

        If the height is restricted, cells will be restricted from expanding vertically. This will lead to text contents being cropped. Each cell can only shrink to a minimum width and height of 1.

        -

        EvTable is intended to be used with [ANSIString](evennia.utils.ansi#ansistring) -for supporting ANSI-coloured string types.

        -

        When a cell is auto-wrapped across multiple lines, ANSI-reset -sequences will be put at the end of each wrapped line. This means that -the colour of a wrapped cell will not “bleed”, but it also means that -eventual colour outside the table will not transfer “across” a table, -you need to re-set the color to have it appear on both sides of the -table string.

        +

        EvTable is intended to be used with ANSIString for supporting ANSI-coloured +string types.

        +

        When a cell is auto-wrapped across multiple lines, ANSI-reset sequences will be +put at the end of each wrapped line. This means that the colour of a wrapped +cell will not “bleed”, but it also means that eventual colour outside the table +will not transfer “across” a table, you need to re-set the color to have it +appear on both sides of the table string.


        @@ -476,8 +479,9 @@ resize individual columns in the vertical direction to fit.

      • height (int, optional) – Fixed height of table. Defaults to being unset. Width is still given precedence. If given, table cells will crop text rather than expand vertically.

      • -
      • evenwidth (bool, optional) – Used with the width keyword. Adjusts columns to have as even width as -possible. This often looks best also for mixed-length tables. Default is False.

      • +
      • evenwidth (bool, optional) – Used with the width keyword. Adjusts columns to have as +even width as possible. This often looks best also for mixed-length tables. Default +is False.

      • maxwidth (int, optional) – This will set a maximum width of the table while allowing it to be smaller. Only if it grows wider than this size will it be resized by expanding horizontally (or crop height is given). @@ -649,7 +653,6 @@ given from 0 to Ncolumns-1.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -666,6 +669,7 @@ given from 0 to Ncolumns-1.

        +
        develop branch
        @@ -37,8 +38,615 @@
        -
        -

        evennia.utils.funcparser

        +
        +

        evennia.utils.funcparser

        +

        Generic function parser for functions embedded in a string, on the form +$funcname(*args, **kwargs), for example:

        +

        “A string $foo() with $bar(a, b, c, $moo(), d=23) etc.”

        +

        Each arg/kwarg can also be another nested function. These will be executed +inside-out and their return will used as arguments for the enclosing function +(so the same as for regular Python function execution).

        +

        This is the base for all forms of embedded func-parsing, like inlinefuncs and +protfuncs. Each function available to use must be registered as a ‘safe’ +function for the parser to accept it. This is usually done in a module with +regular Python functions on the form:

        +
        # in a module whose path is passed to the parser
        +
        +def _helper(x):
        +    # use underscore to NOT make the function available as a callable
        +
        +def funcname(*args, **kwargs):
        +    # this can be accecssed as $funcname(*args, **kwargs)
        +    # it must always accept *args and **kwargs.
        +    ...
        +    return something
        +
        +
        +

        Usage:

        +
        from evennia.utils.funcparser
        +
        +parser = FuncParser("path.to.module_with_callables")
        +result = parser.parse("String with $funcname() in it")
        +
        +
        +

        The FuncParser also accepts a direct dict mapping of {‘name’: callable, …}.

        +

        +
        +
        +exception evennia.utils.funcparser.ParsingError[source]
        +

        Bases: RuntimeError

        +

        Failed to parse for some reason.

        +
        + +
        +
        +class evennia.utils.funcparser.FuncParser(callables, start_char='$', escape_char='\\', max_nesting=20, **default_kwargs)[source]
        +

        Bases: object

        +

        Sets up a parser for strings containing $funcname(*args, **kwargs) +substrings.

        +
        +
        +__init__(callables, start_char='$', escape_char='\\', max_nesting=20, **default_kwargs)[source]
        +

        Initialize the parser.

        +
        +
        Parameters
        +
          +
        • callables (str, module, list or dict) – Where to find +‘safe’ functions to make available in the parser. If a dict, +it should be a direct mapping {“funcname”: callable, …}. If +one or mode modules or module-paths, the module(s) are first checked +for a dict FUNCPARSER_CALLABLES = {“funcname”, callable, …}. If +no such variable exists, all callables in the module (whose name does +not start with an underscore) will be made available to the parser.

        • +
        • start_char (str, optional) – A character used to identify the beginning +of a parseable function. Default is $.

        • +
        • escape_char (str, optional) – Prepend characters with this to have +them not count as a function. Default is the backtick, \.

        • +
        • max_nesting (int, optional) – How many levels of nested function calls +are allowed, to avoid exploitation. Default is 20.

        • +
        • **default_kwargs – These kwargs will be passed into all callables. These +kwargs can be overridden both by kwargs passed direcetly to .parse and +by kwargs given directly in the string $funcname call. They are +suitable for global defaults that is intended to be changed by the +user. To guarantee a call always gets a particular kwarg, pass it +into .parse as **reserved_kwargs instead.

        • +
        +
        +
        +
        + +
        +
        +validate_callables(callables)[source]
        +

        Validate the loaded callables. Each callable must support at least +funcname(*args, **kwargs). +property.

        +
        +
        Parameters
        +

        callables (dict) – A mapping {“funcname”: callable, …} to validate

        +
        +
        Raises
        +

        AssertionError – If invalid callable was found.

        +
        +
        +

        Notes

        +

        This is also a good method to override for individual parsers +needing to run any particular pre-checks.

        +
        + +
        +
        +execute(parsedfunc, raise_errors=False, **reserved_kwargs)[source]
        +

        Execute a parsed function

        +
        +
        Parameters
        +
          +
        • parsedfunc (_ParsedFunc) – This dataclass holds the parsed details +of the function.

        • +
        • raise_errors (bool, optional) – Raise errors. Otherwise return the +string with the function unparsed.

        • +
        • **reserved_kwargs – These kwargs are _guaranteed_ to always be passed into +the callable on every call. It will override any default kwargs +_and_ also a same-named kwarg given manually in the $funcname +call. This is often used by Evennia to pass required data into +the callable, for example the current Session for inlinefuncs.

        • +
        +
        +
        Returns
        +

        any

        +
        +
        The result of the execution. If this is a nested function, it

        can be anything, otherwise it will be converted to a string later. +Always a string on un-raised error (the unparsed function string).

        +
        +
        +

        +
        +
        Raises
        +
          +
        • ParsingError, any – A ParsingError if the function could not be

        • +
        • found, otherwise error from function definition. Only raised if

        • +
        • raise_errors

        • +
        +
        +
        +

        Notes

        +

        The kwargs passed into the callable will be a mixture of the +default_kwargs passed into FuncParser.__init__, kwargs given +directly in the $funcdef string, and the reserved_kwargs this +function gets from .parse(). For colliding keys, funcdef-defined +kwargs will override default kwargs while reserved kwargs will always +override the other two.

        +
        + +
        +
        +parse(string, raise_errors=False, escape=False, strip=False, return_str=True, **reserved_kwargs)[source]
        +

        Use parser to parse a string that may or may not have +$funcname(*args, **kwargs) - style tokens in it. Only the callables +used to initiate the parser will be eligible for parsing.

        +
        +
        Parameters
        +
          +
        • string (str) – The string to parse.

        • +
        • raise_errors (bool, optional) – By default, a failing parse just +means not parsing the string but leaving it as-is. If this is +True, errors (like not closing brackets) will lead to an +ParsingError.

        • +
        • escape (bool, optional) – If set, escape all found functions so they +are not executed by later parsing.

        • +
        • strip (bool, optional) – If set, strip any inline funcs from string +as if they were not there.

        • +
        • return_str (bool, optional) – If set (default), always convert the +parse result to a string, otherwise return the result of the +latest called inlinefunc (if called separately).

        • +
        • **reserved_kwargs – If given, these are guaranteed to _always_ pass +as part of each parsed callable’s kwargs. These override +same-named default options given in **__init__ as well as any +same-named kwarg given in the string function. This is because +it is often used by Evennia to pass necessary kwargs into each +callable (like the current Session object for inlinefuncs).

        • +
        +
        +
        Returns
        +

        str or any

        +
        +
        The parsed string, or the same string on error (if

        raise_errors is False). This is always a string

        +
        +
        +

        +
        +
        Raises
        +

        ParsingError – If a problem is encountered and raise_errors is True.

        +
        +
        +
        + +
        +
        +parse_to_any(string, raise_errors=False, **reserved_kwargs)[source]
        +

        This parses a string and if the string only contains a “$func(…)”, +the return will be the return value of that function, even if it’s not +a string. If mixed in with other strings, the result will still always +be a string.

        +
        +
        Parameters
        +
          +
        • string (str) – The string to parse.

        • +
        • raise_errors (bool, optional) – If unset, leave a failing (or +unrecognized) inline function as unparsed in the string. If set, +raise an ParsingError.

        • +
        • **reserved_kwargs – If given, these are guaranteed to _always_ pass +as part of each parsed callable’s kwargs. These override +same-named default options given in **__init__ as well as any +same-named kwarg given in the string function. This is because +it is often used by Evennia to pass necessary kwargs into each +callable (like the current Session object for inlinefuncs).

        • +
        +
        +
        Returns
        +

        any

        +
        +
        The return from the callable. Or string if the callable is not

        given alone in the string.

        +
        +
        +

        +
        +
        Raises
        +

        ParsingError – If a problem is encountered and raise_errors is True.

        +
        +
        +

        Notes

        +

        This is a convenience wrapper for self.parse(…, return_str=False) which +accomplishes the same thing.

        +

        Examples

        +
        from ast import literal_eval
        +from evennia.utils.funcparser import FuncParser
        +
        +
        +def ret1(*args, **kwargs):
        +    return 1
        +
        +parser = FuncParser({"lit": lit})
        +
        +assert parser.parse_to_any("$ret1()" == 1
        +assert parser.parse_to_any("$ret1() and text" == '1 and text'
        +
        +
        +
        + +
        + +
        +
        +evennia.utils.funcparser.funcparser_callable_eval(*args, **kwargs)[source]
        +

        Funcparser callable. This will combine safe evaluations to try to parse the +incoming string into a python object. If it fails, the return will be same +as the input.

        +
        +
        Parameters
        +

        string (str) – The string to parse. Only simple literals or operators are allowed.

        +
        +
        Returns
        +

        any – The string parsed into its Python form, or the same as input.

        +
        +
        +

        Examples

        +
          +
        • $py(1) -> 1

        • +
        • $py([1,2,3,4] -> [1, 2, 3]

        • +
        • $py(3 + 4) -> 7

        • +
        +
        + +
        +
        +evennia.utils.funcparser.funcparser_callable_toint(*args, **kwargs)[source]
        +

        Usage: toint(43.0) -> 43

        +
        + +
        +
        +evennia.utils.funcparser.funcparser_callable_add(*args, **kwargs)[source]
        +

        Usage: $add(val1, val2) -> val1 + val2

        +
        + +
        +
        +evennia.utils.funcparser.funcparser_callable_sub(*args, **kwargs)[source]
        +

        Usage: **$sub(val1, val2) -> val1 - val2

        +
        + +
        +
        +evennia.utils.funcparser.funcparser_callable_mult(*args, **kwargs)[source]
        +

        Usage: $mult(val1, val2) -> val1 * val2

        +
        + +
        +
        +evennia.utils.funcparser.funcparser_callable_div(*args, **kwargs)[source]
        +

        Usage: $mult(val1, val2) -> val1 / val2

        +
        + +
        +
        +evennia.utils.funcparser.funcparser_callable_round(*args, **kwargs)[source]
        +

        Funcparser callable. Rounds an incoming float to a +certain number of significant digits.

        +
        +
        Parameters
        +
          +
        • inp (str or number) – If a string, it will attempt +to be converted to a number first.

        • +
        • significant (int) – The number of significant digits. Default is None - +this will turn the result into an int.

        • +
        +
        +
        Returns
        +

        any – The rounded value or inp if inp was not a number.

        +
        +
        +

        Examples

        +
          +
        • $round(3.5434343, 3) -> 3.543

        • +
        • $round($random(), 2) - rounds random result, e.g 0.22

        • +
        +
        + +
        +
        +evennia.utils.funcparser.funcparser_callable_random(*args, **kwargs)[source]
        +

        Funcparser callable. Returns a random number between 0 and 1, from 0 to a +maximum value, or within a given range (inclusive).

        +
        +
        Parameters
        +
          +
        • minval (str, optional) – Minimum value. If not given, assumed 0.

        • +
        • maxval (str, optional) – Maximum value.

        • +
        +
        +
        +

        Notes

        +

        If either of the min/maxvalue has a ‘.’ in it, a floating-point random +value will be returned. Otherwise it will be an +integer value in the given range.

        +

        Examples

        +
          +
        • $random() - random value [0 .. 1) (float).

        • +
        • $random(5) - random value [0..5] (int)

        • +
        • $random(5.0) - random value [0..5] (float)

        • +
        • $random(5, 10) - random value [5..10] (int)

        • +
        • $random(5, 10.0) - random value [5..10] (float)

        • +
        +
        + +
        +
        +evennia.utils.funcparser.funcparser_callable_randint(*args, **kwargs)[source]
        +

        Usage: $randint(start, end):

        +

        Legacy alias - always returns integers.

        +
        + +
        +
        +evennia.utils.funcparser.funcparser_callable_choice(*args, **kwargs)[source]
        +

        FuncParser callable. Picks a random choice from a list.

        +
        +
        Parameters
        +

        listing (list) – A list of items to randomly choose between. +This will be converted from a string to a real list.

        +
        +
        Returns
        +

        any – The randomly chosen element.

        +
        +
        +

        Example

        +
          +
        • $choice([key, flower, house])

        • +
        • $choice([1, 2, 3, 4])

        • +
        +
        + +
        +
        +evennia.utils.funcparser.funcparser_callable_pad(*args, **kwargs)[source]
        +

        FuncParser callable. Pads text to given width, optionally with fill-characters

        +
        +
        Parameters
        +
          +
        • text (str) – Text to pad.

        • +
        • width (int) – Width of padding.

        • +
        • align (str, optional) – Alignment of padding; one of ‘c’, ‘l’ or ‘r’.

        • +
        • fillchar (str, optional) – Character used for padding. Defaults to a space.

        • +
        +
        +
        +

        Example

        +
          +
        • $pad(text, 12, r, ‘ ‘) -> ” text”

        • +
        • $pad(text, width=12, align=c, fillchar=-) -> “—-text—-”

        • +
        +
        + +
        +
        +evennia.utils.funcparser.funcparser_callable_crop(*args, **kwargs)[source]
        +

        FuncParser callable. Crops ingoing text to given widths.

        +
        +
        Parameters
        +
          +
        • text (str, optional) – Text to crop.

        • +
        • width (str, optional) – Will be converted to an integer. Width of +crop in characters.

        • +
        • suffix (str, optional) – End string to mark the fact that a part +of the string was cropped. Defaults to […].

        • +
        +
        +
        +

        Example

        +
          +
        • $crop(A long text, 10, […]) -> “A lon[…]”

        • +
        • $crop(text, width=11, suffix=’[…]) -> “A long[…]”

        • +
        +
        + +
        +
        +evennia.utils.funcparser.funcparser_callable_space(*args, **kwarg)[source]
        +

        Usage: $space(43)

        +

        Insert a length of space.

        +
        + +
        +
        +evennia.utils.funcparser.funcparser_callable_justify(*args, **kwargs)[source]
        +

        Justify text across a width, default across screen width.

        +
        +
        Parameters
        +
          +
        • text (str) – Text to justify.

        • +
        • width (int, optional) – Defaults to default screen width.

        • +
        • align (str, optional) – One of ‘l’, ‘c’, ‘r’ or ‘f’ for ‘full’.

        • +
        • indent (int, optional) – Intendation of text block, if any.

        • +
        +
        +
        Returns
        +

        str – The justified text.

        +
        +
        +

        Examples

        +
          +
        • $just(text, width=40)

        • +
        • $just(text, align=r, indent=2)

        • +
        +
        + +
        +
        +evennia.utils.funcparser.funcparser_callable_left_justify(*args, **kwargs)[source]
        +

        Usage: $ljust(text)

        +
        + +
        +
        +evennia.utils.funcparser.funcparser_callable_right_justify(*args, **kwargs)[source]
        +

        Usage: $rjust(text)

        +
        + +
        +
        +evennia.utils.funcparser.funcparser_callable_center_justify(*args, **kwargs)[source]
        +

        Usage: $cjust(text)

        +
        + +
        +
        +evennia.utils.funcparser.funcparser_callable_clr(*args, **kwargs)[source]
        +

        FuncParser callable. Colorizes nested text.

        +
        +
        Parameters
        +
          +
        • startclr (str, optional) – An ANSI color abbreviation without the +prefix |, such as r (red foreground) or [r (red background).

        • +
        • text (str, optional) – Text

        • +
        • endclr (str, optional) – The color to use at the end of the string. Defaults +to |n (reset-color).

        • +
        +
        +
        +
        +
        Kwargs:

        color (str, optional): If given,

        +
        +
        +

        Example

        +
          +
        • $clr(r, text, n) -> “|rtext|n”

        • +
        • $clr(r, text) -> “|rtext|n

        • +
        • $clr(text, start=r, end=n) -> “|rtext|n”

        • +
        +
        + +
        + +

        FuncParser callable. Finds an object based on name or #dbref. Note that +this requries the parser be called with the caller’s Session for proper +security. If called without session, the call is aborted.

        +
        +
        Parameters
        +

        query (str) – The key or dbref to search for.

        +
        +
        Keyword Arguments
        +
          +
        • return_list (bool) – If set, return a list of objects with +0, 1 or more matches to query. Defaults to False.

        • +
        • type (str) – One of ‘obj’, ‘account’, ‘script’

        • +
        • caller (Entity) – Supplied to Parser. This is required and will +be passed into the access check for the entity being searched for. +The ‘control’ permission is required.

        • +
        • access (str) – Which locktype access to check. Unset to disable the +security check.

        • +
        +
        +
        Returns
        +

        any – An entity match or None if no match or a list if return_list is set.

        +
        +
        Raises
        +

        ParsingError – If zero/multimatch and return_list is False, or caller was not +passed into parser.

        +
        +
        +

        Examples

        +
          +
        • “$search(#233)”

        • +
        • “$search(Tom, type=account)”

        • +
        • “$search(meadow, return_list=True)”

        • +
        +
        + +
        +
        +evennia.utils.funcparser.funcparser_callable_search_list(*args, caller=None, access='control', **kwargs)[source]
        +

        Usage: $objlist(#123)

        +

        Legacy alias for search with a return_list=True kwarg preset.

        +
        + +
        +
        +evennia.utils.funcparser.funcparser_callable_you(*args, caller=None, receiver=None, mapping=None, capitalize=False, **kwargs)[source]
        +

        Usage: $you() or $you(key)

        +

        Replaces with you for the caller of the string, with the display_name +of the caller for others.

        +
        +
        Keyword Arguments
        +
          +
        • caller (Object) – The ‘you’ in the string. This is used unless another +you-key is passed to the callable in combination with mapping.

        • +
        • receiver (Object) – The recipient of the string.

        • +
        • mapping (dict, optional) – This is a mapping {key:Object, …} and is +used to find which object $you(key) refers to. If not given, the +caller kwarg is used.

        • +
        • capitalize (bool) – Passed by the You helper, to capitalize you.

        • +
        +
        +
        Returns
        +

        str – The parsed string.

        +
        +
        Raises
        +

        ParsingError – If caller and receiver were not supplied.

        +
        +
        +

        Notes

        +

        The kwargs should be passed the to parser directly.

        +

        Examples

        +

        This can be used by the say or emote hooks to pass actor stance +strings. This should usually be combined with the $inflect() callable.

        +
          +
        • With a grin, $you() $conj(jump) at $you(tommy).

        • +
        +

        The caller-object will see “With a grin, you jump at Tommy.” +Tommy will see “With a grin, CharName jumps at you.” +Others will see “With a grin, CharName jumps at Tommy.”

        +
        + +
        +
        +evennia.utils.funcparser.funcparser_callable_You(*args, you=None, receiver=None, mapping=None, capitalize=True, **kwargs)[source]
        +

        Usage: $You() - capitalizes the ‘you’ output.

        +
        + +
        +
        +evennia.utils.funcparser.funcparser_callable_conjugate(*args, caller=None, receiver=None, **kwargs)[source]
        +

        Conjugate a verb according to if it should be 2nd or third person.

        +
        +
        Keyword Arguments
        +
          +
        • caller (Object) – The object who represents ‘you’ in the string.

        • +
        • receiver (Object) – The recipient of the string.

        • +
        +
        +
        Returns
        +

        str – The parsed string.

        +
        +
        Raises
        +

        ParsingError – If you and recipient were not both supplied.

        +
        +
        +

        Notes

        +

        Note that the verb will not be capitalized. It also +assumes that the active party (You) is the one performing the verb. +This automatic conjugation will fail if the active part is another person +than ‘you’. The caller/receiver must be passed to the parser directly.

        +

        Examples

        +

        This is often used in combination with the $you/You( callables.

        +
          +
        • With a grin, $you() $conj(jump)

        • +
        +

        You will see “With a grin, you jump.” +Others will see “With a grin, CharName jumps.”

        +
        +
        @@ -84,7 +692,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +708,7 @@ +
        develop branch
        @@ -273,7 +274,6 @@ the epoch set by settings.TIME_GAME_EPOCH will still apply.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -290,6 +290,7 @@ the epoch set by settings.TIME_GAME_EPOCH will still apply.

        +
        develop branch
        @@ -151,6 +160,7 @@ functionality.

        +
        develop branch
        @@ -92,7 +93,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -109,6 +109,7 @@ +
        develop branch
        @@ -97,7 +98,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -114,6 +114,7 @@ +
        develop branch
        @@ -309,7 +310,6 @@ catch in an easy way here. Ideas are appreciated. /Griatch

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -326,6 +326,7 @@ catch in an easy way here. Ideas are appreciated. /Griatch

        +
        develop branch
        @@ -406,7 +407,6 @@ object the first time, the query is executed.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -423,6 +423,7 @@ object the first time, the query is executed.

        +
        develop branch
        @@ -319,7 +320,7 @@ to preserve a continuous chat history for channel log files.

        -rotate()[source]
        +rotate(num_lines_to_append=None)[source]

        Rotates our log file and appends some number of lines from the previous log to the start of the new one.

        @@ -328,21 +329,31 @@ the previous log to the start of the new one.

        seek(*args, **kwargs)[source]

        Convenience method for accessing our _file attribute’s seek method, -which is used in tail_log_function. -:param *args: Same args as file.seek -:param **kwargs: Same kwargs as file.seek

        +which is used in tail_log_function.

        +
        +
        Parameters
        +
          +
        • *args – Same args as file.seek

        • +
        • **kwargs – Same kwargs as file.seek

        • +
        +
        +
        readlines(*args, **kwargs)[source]

        Convenience method for accessing our _file attribute’s readlines method, -which is used in tail_log_function. -:param *args: same args as file.readlines -:param **kwargs: same kwargs as file.readlines

        +which is used in tail_log_function.

        -
        Returns
        -

        lines (list) – lines from our _file attribute.

        +
        Parameters
        +
          +
        • *args – same args as file.readlines

        • +
        • **kwargs – same kwargs as file.readlines

        • +
        +
        +
        Returns
        +

        lines (list) – lines from our _file attribute.

        @@ -365,6 +376,36 @@ on new lines following datetime info.

        +
        +
        +evennia.utils.logger.log_file_exists(filename='game.log')[source]
        +

        Determine if a log-file already exists.

        +
        +
        Parameters
        +

        filename (str) – The filename (within the log-dir).

        +
        +
        Returns
        +

        bool – If the log file exists or not.

        +
        +
        +
        + +
        +
        +evennia.utils.logger.rotate_log_file(filename='game.log', num_lines_to_append=None)[source]
        +

        Force-rotate a log-file, without

        +
        +
        Parameters
        +
          +
        • filename (str) – The log file, located in settings.LOG_DIR.

        • +
        • num_lines_to_append (int, optional) – Include N number of +lines from previous file in new one. If None, use default. +Set to 0 to include no lines.

        • +
        +
        +
        +
        +
        evennia.utils.logger.tail_log_file(filename, offset, nlines, callback=None)[source]
        @@ -440,7 +481,6 @@ all if the file is shorter than nlines.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -457,6 +497,7 @@ all if the file is shorter than nlines.

        +
        develop branch
        @@ -39,8 +40,6 @@

        evennia.utils.optionclasses

        -

        Option classes store user- or server Options in a generic way -while also providing validation.

        class evennia.utils.optionclasses.BaseOption(handler, key, description, default)[source]
        @@ -117,8 +116,8 @@ passing extra instructions into the validator.

        save(**kwargs)[source]

        Stores the current value using .handler.save_handler(self.key, value, **kwargs) -where kwargs are a combination of those passed into this function and the -ones specified by the OptionHandler.

        +where kwargs are a combination of those passed into this function and +the ones specified by the OptionHandler.

        Keyword Arguments

        any (any) – Not used by default. These are passed in from self.set @@ -901,7 +900,6 @@ entries are processed.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -918,6 +916,7 @@ entries are processed.

        +
        develop branch
        @@ -207,7 +208,6 @@ than their values.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -224,6 +224,7 @@ than their values.

        +
        develop branch
        @@ -251,7 +252,6 @@ This is used by the serialization framework.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -268,6 +268,7 @@ This is used by the serialization framework.

        +
        develop branch
        @@ -147,7 +148,7 @@ one of the arguments must be given to do a search.

        Parameters
          -
        • sender (Object or Account, optional) – Get messages sent by a particular account or object

        • +
        • sender (Object, Account or Script, optional) – Get messages sent by a particular sender.

        • receiver (Object, Account or Channel, optional) – Get messages received by a certain account,object or channel

        • freetext (str) – Search for a text string in a message. NOTE: @@ -159,7 +160,7 @@ always gives only one match.

        Returns
        -

        messages (list or Msg) – A list of message matches or a single match if dbref was given.

        +

        Queryset – Message matches.

        @@ -193,6 +194,36 @@ case sensitive) match.

        +
        +
        +evennia.utils.search.search_tag(key=None, category=None, tagtype=None, **kwargs)
        +

        Find object based on tag or category.

        +
        +
        Parameters
        +
          +
        • key (str, optional) – The tag key to search for.

        • +
        • category (str, optional) – The category of tag +to search for. If not set, uncategorized +tags will be searched.

        • +
        • tagtype (str, optional) – ‘type’ of Tag, by default +this is either None (a normal Tag), alias or +permission. This always apply to all queried tags.

        • +
        • kwargs (any) – Other optional parameter that may be supported +by the manager method.

        • +
        +
        +
        Returns
        +

        matches (list)

        +
        +
        List of Objects with tags matching

        the search criteria, or an empty list if no +matches were found.

        +
        +
        +

        +
        +
        +
        +
        evennia.utils.search.search_script_tag(key=None, category=None, tagtype=None, **kwargs)[source]
        @@ -328,7 +359,6 @@ matches were found.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -345,6 +375,7 @@ matches were found.

        +
        develop branch
        @@ -70,7 +71,6 @@ should directly give the module pathname to unload.

        ... # test code using foo.GLOBALTHING, now set to 'mockval'
        -

        Notes

        This allows for mocking constants global to the module, since otherwise those would not be mocked (since a module is only loaded once).

        @@ -214,7 +214,6 @@ It helps ensure your tests are run with your own objects.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -231,6 +230,7 @@ It helps ensure your tests are run with your own objects.

        +
        develop branch
        @@ -191,7 +192,7 @@ snippet #577349 on
        -re_url = re.compile('((?:ftp|www|https?)\\W+(?:(?!\\.(?:\\s|$)|&\\w+;)[^"\\\',;$*^\\\\(){}<>\\[\\]\\s])+)(\\.(?:\\s|$)|&\\w+;|)')
        +re_url = re.compile('(?<!=")((?:ftp|www|https?)\\W+(?:(?!\\.(?:\\s|$)|&\\w+;)[^"\\\',;$*^\\\\(){}<>\\[\\]\\s])+)(\\.(?:\\s|$)|&\\w+;|)')
        @@ -199,6 +200,11 @@ snippet #577349 on re_mxplink = re.compile('\\|lc(.*?)\\|lt(.*?)\\|le', re.DOTALL)
        +
        +
        +re_mxpurl = re.compile('\\|lu(.*?)\\|lt(.*?)\\|le', re.DOTALL)
        +
        +
        re_color(text)[source]
        @@ -349,6 +355,20 @@ replaces MXP links with HTML code.

        +
        +
        +sub_mxp_urls(match)[source]
        +

        Helper method to be passed to re.sub, +replaces MXP links with HTML code. +:param match: Match for substitution. +:type match: re.Matchobject

        +
        +
        Returns
        +

        text (str) – Processed text.

        +
        +
        +
        +
        sub_text(match)[source]
        @@ -441,7 +461,6 @@ into html statements.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -458,6 +477,7 @@ into html statements.

        +
        develop branch
        @@ -160,16 +161,18 @@ suffix, the suffix will be dropped.

        -evennia.utils.utils.dedent(text, baseline_index=None)[source]
        +evennia.utils.utils.dedent(text, baseline_index=None, indent=None)[source]

        Safely clean all whitespace at the left of a paragraph.

        Parameters
        • text (str) – The text to dedent.

        • -
        • baseline_index (int or None, optional) – Which row to use as a ‘base’ +

        • baseline_index (int, optional) – Which row to use as a ‘base’ for the indentation. Lines will be dedented to this level but no further. If None, indent so as to completely deindent the least indented text.

        • +
        • indent (int, optional) – If given, force all lines to this indent. +This bypasses baseline_index.

        Returns
        @@ -231,8 +234,8 @@ Defaults to client’s default width.

        -
        -evennia.utils.utils.iter_to_string(initer, endsep='and', addquote=False)[source]
        +
        +evennia.utils.utils.iter_to_str(initer, endsep='and', addquote=False)[source]

        This pretty-formats an iterable list as string output, adding an optional alternative separator to the second to last entry. If addquote is True, the outgoing strings will be surrounded by quotes.

        @@ -249,16 +252,16 @@ values with double quotes.

        Returns
        -

        liststr (str) – The list represented as a string.

        +

        str – The list represented as a string.

        Examples

        -
        # no endsep:
        -   [1,2,3] -> '1, 2, 3'
        -# with endsep=='and':
        -   [1,2,3] -> '1, 2 and 3'
        -# with addquote and endsep
        -   [1,2,3] -> '"1", "2" and "3"'
        +
        >>> list_to_string([1,2,3], endsep='')
        +'1, 2, 3'
        +>>> list_to_string([1,2,3], ensdep='and')
        +'1, 2, and 3'
        +>>> list_to_string([1,2,3], endsep='and', addquote=True)
        +'"1", "2", and "3"'
         
        @@ -282,16 +285,49 @@ values with double quotes.

        Returns
        -

        liststr (str) – The list represented as a string.

        +

        str – The list represented as a string.

        Examples

        -
        # no endsep:
        -   [1,2,3] -> '1, 2, 3'
        -# with endsep=='and':
        -   [1,2,3] -> '1, 2 and 3'
        -# with addquote and endsep
        -   [1,2,3] -> '"1", "2" and "3"'
        +
        >>> list_to_string([1,2,3], endsep='')
        +'1, 2, 3'
        +>>> list_to_string([1,2,3], ensdep='and')
        +'1, 2, and 3'
        +>>> list_to_string([1,2,3], endsep='and', addquote=True)
        +'"1", "2", and "3"'
        +
        +
        + + +
        +
        +evennia.utils.utils.iter_to_string(initer, endsep='and', addquote=False)
        +

        This pretty-formats an iterable list as string output, adding an optional +alternative separator to the second to last entry. If addquote +is True, the outgoing strings will be surrounded by quotes.

        +
        +
        Parameters
        +
          +
        • initer (any) – Usually an iterable to print. Each element must be possible to +present with a string. Note that if this is a generator, it will be +consumed by this operation.

        • +
        • endsep (str, optional) – If set, the last item separator will +be replaced with this value.

        • +
        • addquote (bool, optional) – This will surround all outgoing +values with double quotes.

        • +
        +
        +
        Returns
        +

        str – The list represented as a string.

        +
        +
        +

        Examples

        +
        >>> list_to_string([1,2,3], endsep='')
        +'1, 2, 3'
        +>>> list_to_string([1,2,3], ensdep='and')
        +'1, 2, and 3'
        +>>> list_to_string([1,2,3], endsep='and', addquote=True)
        +'"1", "2", and "3"'
         
        @@ -550,10 +586,8 @@ be found, the protocol flag is reset to utf-8. In any case, returns bytes.

        -
        -

        Note

        +

        Notes

        If text is already bytes, return it as is.

        -
        @@ -574,10 +608,8 @@ falling back to settings.ENCODINGS.

        decoded_text (str) – The decoded text.

        -
        -

        Note

        +

        Notes

        If text is already str, return it as is.

        -
        @@ -603,9 +635,10 @@ distance from parent.

        Parameters
          -
        • obj (any) – Object to analyze. This may be either an instance -or a class.

        • -
        • parent (any) – Can be either instance, class or python path to class.

        • +
        • obj (any) – Object to analyze. This may be either an instance or +a class.

        • +
        • parent (any) – Can be either an instance, a class or the python +path to the class.

        Returns
        @@ -613,10 +646,8 @@ or a class.

        Notes

        -

        What differs this function from e.g. isinstance() is that obj -may be both an instance and a class, and parent may be an -instance, a class, or the python path to a class (counting from -the evennia root directory).

        +

        What differentiates this function from Python’s isinstance() is the +flexibility in the types allowed for the object and parent being compared.

        @@ -639,10 +670,7 @@ any results if called from inside the game.

        shortcut to having to use the full backend name.

        Parameters
        -
          -
        • name (str) – One of ‘sqlite3’, ‘mysql’, ‘postgresql’

        • -
        • 'oracle'. (or) –

        • -
        +

        name (str) – One of ‘sqlite3’, ‘mysql’, ‘postgresql’ or ‘oracle’.

        Returns

        uses (bool) – If the given database is used or not.

        @@ -660,7 +688,7 @@ shortcut to having to use the full backend name.

      • timedelay (int or float) – The delay in seconds.

      • callback (callable) – Will be called as callback(*args, **kwargs) after timedelay seconds.

      • -
      • args (any) – Will be used as arguments to callback.

      • +
      • *args – Will be used as arguments to callback

      • Keyword Arguments
        @@ -679,8 +707,7 @@ persistent is False by default.

        -
        -

        Note

        +

        Notes

        The task handler (evennia.scripts.taskhandler.TASK_HANDLER) will be called for persistent or non-persistent tasks. If persistent is set to True, the callback, its arguments @@ -694,7 +721,63 @@ If persistent is set to True the delay function will return an int which is the task’s id itended for use with TASK_HANDLER’s do_task and remove methods. All persistent tasks whose time delays have passed will be called on server startup.

        -
        +
        + +
        +
        +evennia.utils.utils.repeat(interval, callback, persistent=True, idstring='', stop=False, store_key=None, *args, **kwargs)[source]
        +

        Start a repeating task using the TickerHandler.

        +
        +
        Parameters
        +
          +
        • interval (int) – How often to call callback.

        • +
        • callback (callable) – This will be called with *args, **kwargs every +interval seconds. This must be possible to pickle regardless +of if persistent is set or not!

        • +
        • persistent (bool, optional) – If ticker survives a server reload.

        • +
        • idstring (str, optional) – Separates multiple tickers. This is useful +mainly if wanting to set up multiple repeats for the same +interval/callback but with different args/kwargs.

        • +
        • stop (bool, optional) – If set, use the given parameters to _stop_ a running +ticker instead of creating a new one.

        • +
        • store_key (tuple, optional) – This is only used in combination with stop and +should be the return given from the original repeat call. If this +is given, all other args except stop are ignored.

        • +
        • *args – Used as arguments to callback.

        • +
        • **kwargs – Keyword-arguments to pass to callback.

        • +
        +
        +
        Returns
        +

        tuple or None – The tuple is the store_key - the identifier for the +created ticker. Store this and pass into unrepat() in order to to stop +this ticker later. Returns None if stop=True.

        +
        +
        Raises
        +

        KeyError – If trying to stop a ticker that was not found.

        +
        +
        +
        + +
        +
        +evennia.utils.utils.unrepeat(store_key)[source]
        +

        This is used to stop a ticker previously started with repeat.

        +
        +
        Parameters
        +

        store_key (tuple) – This is the return from repeat, used to uniquely +identify the ticker to stop. Without the store_key, the ticker +must be stopped by passing its parameters to TICKER_HANDLER.remove +directly.

        +
        +
        Returns
        +

        bool

        +
        +
        True if a ticker was stopped, False if not (for example because no

        matching ticker was found or it was already stopped).

        +
        +
        +

        +
        +
        @@ -758,7 +841,7 @@ some checks for runtime libraries.

        evennia.utils.utils.has_parent(basepath, obj)[source]
        -

        Checks if basepath is somewhere in obj’s parent tree.

        +

        Checks if basepath is somewhere in obj’s parent tree.

        Parameters
          @@ -818,7 +901,7 @@ parsed and imported. Returns None and logs error if import fail already imported module object (e.g. models)

        Returns
        -

        variables (dict)

        +

        dict

        A dict of {variablename: variable} for all

        variables in the given module.

        @@ -827,7 +910,8 @@ already imported module object (e.g. models)

        Notes

        -

        Ignores modules and variable names starting with an underscore.

        +

        Ignores modules and variable names starting with an underscore, as well +as variables imported into the module from other modules.

        @@ -942,7 +1026,7 @@ importing directly from path doesn’t work.

        evennia.utils.utils.class_from_module(path, defaultpaths=None, fallback=None)[source]
        -

        Return a class from a module, given the module’s path. This is +

        Return a class from a module, given the class’ full python path. This is primarily used to convert db_typeclass_path:s to classes.

        Parameters
        @@ -968,7 +1052,7 @@ evennia repo itself.

        evennia.utils.utils.object_from_module(path, defaultpaths=None, fallback=None)
        -

        Return a class from a module, given the module’s path. This is +

        Return a class from a module, given the class’ full python path. This is primarily used to convert db_typeclass_path:s to classes.

        Parameters
        @@ -1039,15 +1123,11 @@ the value, the more exact a match is required).

        Returns
        -

        suggestions (list)

        -
        -
        Suggestions from vocabulary with a

        similarity-rating that higher than or equal to cutoff. +

        suggestions (list) – Suggestions from vocabulary with a +similarity-rating that higher than or equal to cutoff. Could be empty if there are no matches.

        -

        -
        -
        @@ -1078,47 +1158,126 @@ array) instead of strings.

        evennia.utils.utils.format_table(table, extra_space=1)[source]
        -

        Note: evennia.utils.evtable is more powerful than this, but this function -can be useful when the number of columns and rows are unknown and must be -calculated on the fly.

        -
        -
        Args.
        -
        table (list): A list of lists to represent columns in the

        table: [[val,val,val,…], [val,val,val,…], …], where +

        Format a 2D array of strings into a multi-column table.

        +
        +
        Parameters
        +
          +
        • table (list) – A list of lists to represent columns in the +table: [[val,val,val,…], [val,val,val,…], …], where each val will be placed on a separate row in the column. All columns must have the same number of rows (some -positions may be empty though).

          +positions may be empty though).

        • +
        • extra_space (int, optional) – Sets how much minimum extra +padding (in characters) should be left between columns.

        • +
        -
        extra_space (int, optional): Sets how much minimum extra

        padding (in characters) should be left between columns.

        -
        -
        -
        -
        -
        -
        Returns
        -

        table (list)

        -
        -
        A list of lists representing the rows to print

        out one by one.

        -
        -
        -

        +
        Returns
        +

        list – A list of lists representing the rows to print out one by one.

        Notes

        The function formats the columns to be as wide as the widest member of each column.

        -

        Example

        -
        ftable = format_table([[...], [...], ...])
        +

        evennia.utils.evtable is more powerful than this, but this +function can be useful when the number of columns and rows are +unknown and must be calculated on the fly.

        +

        Examples:

        +
        ftable = format_table([[1,2,3], [4,5,6]])
        +string = ""
         for ir, row in enumarate(ftable):
             if ir == 0:
                 # make first row white
        -        string += "\\n|w" + ""join(row) + "|n"
        +        string += "\n|w" + "".join(row) + "|n"
             else:
        -        string += "\\n" + "".join(row)
        +        string += "\n" + "".join(row)
         print(string)
         
        +
        +
        +evennia.utils.utils.percent(value, minval, maxval, formatting='{:3.1f}%')[source]
        +

        Get a value in an interval as a percentage of its position +in that interval. This also understands negative numbers.

        +
        +
        Parameters
        +
          +
        • value (number) – This should be a value minval<=value<=maxval.

        • +
        • minval (number or None) – Smallest value in interval. This could be None +for an open interval (then return will always be 100%)

        • +
        • maxval (number or None) – Biggest value in interval. This could be None +for an open interval (then return will always be 100%)

        • +
        • formatted (str, optional) – This is a string that should +accept one formatting tag. This will receive the +current value as a percentage. If None, the +raw float will be returned instead.

        • +
        +
        +
        Returns
        +

        str or float – The formatted value or the raw percentage as a float.

        +
        +
        +

        Notes

        +

        We try to handle a weird interval gracefully.

        +
          +
        • If either maxval or minval is None (open interval), we (aribtrarily) assume 100%.

        • +
        • If minval > maxval, we return 0%.

        • +
        • If minval == maxval == value we are looking at a single value match and return 100%.

        • +
        • If minval == maxval != value we return 0%.

        • +
        • If value not in [minval..maxval], we set value to the closest +boundary, so the result will be 0% or 100%, respectively.

        • +
        +
        + +
        +
        +evennia.utils.utils.percentile(iterable, percent, key=<function <lambda>>)[source]
        +

        Find the percentile of a list of values.

        +
        +
        Parameters
        +
          +
        • iterable (iterable) – A list of values. Note N MUST BE already sorted.

        • +
        • percent (float) – A value from 0.0 to 1.0.

        • +
        • key (callable, optional) –

        • +
        +
        +
        Returns
        +

        float – The percentile of the values

        +
        +
        +
        + +
        +
        +evennia.utils.utils.format_grid(elements, width=78, sep=' ', verbatim_elements=None)[source]
        +

        This helper function makes a ‘grid’ output, where it distributes the given +string-elements as evenly as possible to fill out the given width. +will not work well if the variation of length is very big!

        +
        +
        Parameters
        +
          +
        • elements (iterable) – A 1D list of string elements to put in the grid.

        • +
        • width (int, optional) – The width of the grid area to fill.

        • +
        • sep (str, optional) – The extra separator to put between words. If +set to the empty string, words may run into each other.

        • +
        • verbatim_elements (list, optional) – This is a list of indices pointing to +specific items in the elements list. An element at this index will +not be included in the calculation of the slot sizes. It will still +be inserted into the grid at the correct position and may be surrounded +by padding unless filling the entire line. This is useful for embedding +decorations in the grid, such as horizontal bars.

        • +
        • ignore_ansi (bool, optional) – Ignore ansi markups when calculating white spacing.

        • +
        +
        +
        Returns
        +

        list – The grid as a list of ready-formatted rows. We return it +like this to make it easier to insert decorations between rows, such +as horizontal bars.

        +
        +
        +
        +
        evennia.utils.utils.get_evennia_pids()[source]
        @@ -1135,8 +1294,7 @@ Server by trying to access a PID file.

        Examples

        -

        This can be used to determine if we are in a subprocess by -something like:

        +

        This can be used to determine if we are in a subprocess by

        self_pid = os.getpid()
         server_pid, portal_pid = get_evennia_pids()
         is_subprocess = self_pid not in (server_pid, portal_pid)
        @@ -1293,16 +1451,12 @@ on errors.

        Returns
        -

        processed_result (Object or None)

        -
        -
        This is always a single result

        or None. If None, any error reporting/handling should +

        processed_result (Object or None) – This is always a single result +or None. If None, any error reporting/handling should already have happened. The returned object is of the type we are checking multimatches for (e.g. Objects or Commands)

        -

        -
        -
        @@ -1357,27 +1511,55 @@ of the game directory.

        List available typeclasses from all available modules.

        Parameters
        -

        parent (str, optional) – If given, only return typeclasses inheriting (at any distance) -from this parent.

        +

        parent (str, optional) – If given, only return typeclasses inheriting +(at any distance) from this parent.

        Returns
        -

        typeclasses (dict) – On the form {“typeclass.path”: typeclass, …}

        +

        dict – On the form {“typeclass.path”: typeclass, …}

        Notes

        -

        This will dynamicall retrieve all abstract django models inheriting at any distance -from the TypedObject base (aka a Typeclass) so it will work fine with any custom +

        This will dynamically retrieve all abstract django models inheriting at +any distance from the TypedObject base (aka a Typeclass) so it will +work fine with any custom classes being added.

        +
        + +
        +
        +evennia.utils.utils.get_all_cmdsets(parent=None)[source]
        +

        List available cmdsets from all available modules.

        +
        +
        Parameters
        +

        parent (str, optional) – If given, only return cmdsets inheriting (at +any distance) from this parent.

        +
        +
        Returns
        +

        dict – On the form {“cmdset.path”: cmdset, …}

        +
        +
        +

        Notes

        +

        This will dynamically retrieve all abstract django models inheriting at +any distance from the CmdSet base so it will work fine with any custom classes being added.

        evennia.utils.utils.interactive(func)[source]
        -

        Decorator to make a method pausable with yield(seconds) and able to ask for -user-input with response=yield(question). For the question-asking to -work, ‘caller’ must the name of an argument or kwarg to the decorated -function.

        -

        Example:

        +

        Decorator to make a method pausable with yield(seconds) +and able to ask for user-input with response=yield(question). +For the question-asking to work, one of the args or kwargs to the +decorated function must be named ‘caller’.

        +
        +
        Raises
        +
          +
        • ValueError – If asking an interactive question but the decorated +function has no arg or kwarg named ‘caller’.

        • +
        • ValueError – If passing non int/float to yield using for pausing.

        • +
        +
        +
        +

        Examples

        @interactive
         def myfunc(caller):
             caller.msg("This is a test")
        @@ -1392,7 +1574,57 @@ function.

        Notes

        -

        This turns the method into a generator!

        +

        This turns the decorated function or method into a generator.

        +
        + +
        +
        +evennia.utils.utils.safe_convert_to_types(converters, *args, raise_errors=True, **kwargs)[source]
        +

        Helper function to safely convert inputs to expected data types.

        +
        +
        Parameters
        +
          +
        • converters (tuple) – A tuple ((converter, converter,…), {kwarg: converter, …}) to +match a converter to each element in *args and **kwargs. +Each converter will will be called with the arg/kwarg-value as the only argument. +If there are too few converters given, the others will simply not be converter. If the +converter is given as the string ‘py’, it attempts to run +safe_eval/literal_eval on the input arg or kwarg value. It’s possible to +skip the arg/kwarg part of the tuple, an empty tuple/dict will then be assumed.

        • +
        • *args – The arguments to convert with argtypes.

        • +
        • raise_errors (bool, optional) – If set, raise any errors. This will +abort the conversion at that arg/kwarg. Otherwise, just skip the +conversion of the failing arg/kwarg. This will be set by the FuncParser if +this is used as a part of a FuncParser callable.

        • +
        • **kwargs – The kwargs to convert with kwargtypes

        • +
        +
        +
        Returns
        +

        tuple(args, kwargs) in converted form.

        +
        +
        Raises
        +
          +
        • utils.funcparser.ParsingError – If parsing failed in the ‘py’ +converter. This also makes this compatible with the FuncParser +interface.

        • +
        • any – Any other exception raised from other converters, if raise_errors is True.

        • +
        +
        +
        +

        Notes

        +

        This function is often used to validate/convert input from untrusted sources. For +security, the “py”-converter is deliberately limited and uses safe_eval/literal_eval +which only supports simple expressions or simple containers with literals. NEVER +use the python eval or exec methods as a converter for any untrusted input! Allowing +untrusted sources to execute arbitrary python on your server is a severe security risk,

        +

        Example:

        +
        $funcname(1, 2, 3.0, c=[1,2,3])
        +
        +def _funcname(*args, **kwargs):
        +    args, kwargs = safe_convert_input(((int, int, float), {'c': 'py'}), *args, **kwargs)
        +    # ...
        +
        +
        @@ -1440,7 +1672,6 @@ function.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -1457,6 +1688,7 @@ function.

        +
        develop branch
        @@ -66,7 +67,7 @@ inputer’s timezone. Always returns a result in UTC.

      • account (AccountDB) – The Account performing this lookup. Unless from_tz is provided, the account’s timezone option will be used.

      • from_tz (pytz.timezone) – An instance of a pytz timezone object from the -user. If not provided, tries to use the timezone option of the account. +user. If not provided, tries to use the timezone option of account. If neither one is provided, defaults to UTC.

      • @@ -86,8 +87,9 @@ If neither one is provided, defaults to UTC.

        Parameters
          -
        • entry (string) – This is a string from user-input. The intended format is, for example: “5d 2w 90s” for -‘five days, two weeks, and ninety seconds.’ Invalid sections are ignored.

        • +
        • entry (string) – This is a string from user-input. The intended format is, for example: +“5d 2w 90s” for ‘five days, two weeks, and ninety seconds.’ Invalid sections are +ignored.

        • option_key (str) – Name to display this query as.

        @@ -120,14 +122,16 @@ If neither one is provided, defaults to UTC.

        evennia.utils.validatorfuncs.boolean(entry, option_key='True/False', **kwargs)[source]
        -

        Simplest check in computer logic, right? This will take user input to flick the switch on or off -:param entry: A value such as True, On, Enabled, Disabled, False, 0, or 1. -:type entry: str -:param option_key: What kind of Boolean we are setting. What Option is this for? -:type option_key: str

        +

        Simplest check in computer logic, right? This will take user input to flick the switch on or off

        -
        Returns
        -

        Boolean

        +
        Parameters
        +
          +
        • entry (str) – A value such as True, On, Enabled, Disabled, False, 0, or 1.

        • +
        • option_key (str) – What kind of Boolean we are setting. What Option is this for?

        • +
        +
        +
        Returns
        +

        Boolean

        @@ -204,7 +208,6 @@ If neither one is provided, defaults to UTC.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -221,6 +224,7 @@ If neither one is provided, defaults to UTC.

        +
        develop branch
        @@ -37,8 +38,262 @@
        -
        -

        evennia.utils.verb_conjugation.conjugate

        +
        +

        evennia.utils.verb_conjugation.conjugate

        +

        English verb conjugation

        +

        Original Author: Tom De Smedt <tomdesmedt@organisms.be> of Nodebox +Refactored by Griatch 2021, for Evennia.

        +

        This is distributed under the GPL2 license. See ./LICENSE.txt for details.

        +

        The verb.txt morphology was adopted from the XTAG morph_englis.flat: +http://www.cis.upenn.edu/~xtag/

        +
        +
        +evennia.utils.verb_conjugation.conjugate.verb_infinitive(verb)[source]
        +

        Returns the uninflected form of the verb, like ‘are’ -> ‘be’

        +
        +
        Parameters
        +

        verb (str) – The verb to get the uninflected form of.

        +
        +
        Returns
        +

        str – The uninflected verb form of verb.

        +
        +
        +
        + +
        +
        +evennia.utils.verb_conjugation.conjugate.verb_conjugate(verb, tense='infinitive', negate=False)[source]
        +

        Inflects the verb to the given tense.

        +
        +
        Parameters
        +
          +
        • verb (str) – The single verb to conjugate.

        • +
        • tense (str) – The tense to convert to. This can be given either as a long or short form +- “infinitive” (“inf”) - be +- “1st/2nd/3rd singular present” (“1/2/3sgpres”) - am/are/is +- “present plural” (“pl”) - are +- “present participle” (“prog”) - being +- “1st/2nd/3rd singular past” (“1/2/3sgpast”) - was/were/was +- “past plural” (“pastpl”) - were +- “past” - were +- “past participle” (“ppart”) - been

        • +
        • negate (bool) – Negates the verb. This only supported +for a limited number of verbs: be, can, do, will, must, have, may, +need, dare, ought.

        • +
        +
        +
        Returns
        +

        str – The conjugated verb. If conjugation fails, the original verb is returned.

        +
        +
        +

        Examples

        +

        The verb ‘be’: +- present: I am, you are, she is, +- present participle: being, +- past: I was, you were, he was, +- past participle: been, +- negated present: I am not, you aren’t, it isn’t.

        +
        + +
        +
        +evennia.utils.verb_conjugation.conjugate.verb_present(verb, person='', negate=False)[source]
        +

        Inflects the verb in the present tense.

        +
        +
        Parameters
        +
          +
        • person (str or int) – This can be 1, 2, 3, “1st”, “2nd”, “3rd”, “plural” or “*”.

        • +
        • negate (bool) – Some verbs like be, have, must, can be negated.

        • +
        +
        +
        Returns
        +

        str – The present tense verb.

        +
        +
        +

        Example

        +

        had -> have

        +
        + +
        +
        +evennia.utils.verb_conjugation.conjugate.verb_present_participle(verb)[source]
        +

        Inflects the verb in the present participle.

        +
        +
        Parameters
        +

        verb (str) – The verb to inflect.

        +
        +
        Returns
        +

        str – The inflected verb.

        +
        +
        +

        Examples

        +

        give -> giving, be -> being, swim -> swimming

        +
        + +
        +
        +evennia.utils.verb_conjugation.conjugate.verb_past(verb, person='', negate=False)[source]
        +

        Inflects the verb in the past tense.

        +
        +
        Parameters
        +
          +
        • verb (str) – The verb to inflect.

        • +
        • person (str, optional) – The person can be specified with 1, 2, 3, +“1st”, “2nd”, “3rd”, “plural”, “*”.

        • +
        • negate (bool, optional) – Some verbs like be, have, must, can be negated.

        • +
        +
        +
        Returns
        +

        str – The inflected verb.

        +
        +
        +

        Examples

        +

        give -> gave, be -> was, swim -> swam

        +
        + +
        +
        +evennia.utils.verb_conjugation.conjugate.verb_past_participle(verb)[source]
        +

        Inflects the verb in the present participle.

        +
        +
        Parameters
        +

        verb (str) – The verb to inflect.

        +
        +
        Returns
        +

        str – The inflected verb.

        +
        +
        +

        Examples

        +

        give -> given, be -> been, swim -> swum

        +
        + +
        +
        +evennia.utils.verb_conjugation.conjugate.verb_all_tenses()[source]
        +

        Get all all possible verb tenses.

        +
        +
        Returns
        +

        list – A list if string names.

        +
        +
        +
        + +
        +
        +evennia.utils.verb_conjugation.conjugate.verb_tense(verb)[source]
        +

        Returns a string from verb_tenses_keys representing the verb’s tense.

        +
        +
        Parameters
        +

        verb (str) – The verb to check the tense of.

        +
        +
        Returns
        +

        str – The tense.

        +
        +
        +

        Example

        +

        given -> “past participle”

        +
        + +
        +
        +evennia.utils.verb_conjugation.conjugate.verb_is_tense(verb, tense)[source]
        +

        Checks whether the verb is in the given tense.

        +
        +
        Parameters
        +
          +
        • verb (str) – The verb to check.

        • +
        • tense (str) – The tense to check.

        • +
        +
        +
        Returns
        +

        bool – If verb matches given tense.

        +
        +
        +
        + +
        +
        +evennia.utils.verb_conjugation.conjugate.verb_is_present(verb, person='', negated=False)[source]
        +

        Checks whether the verb is in the present tense.

        +
        +
        Parameters
        +
          +
        • verb (str) – The verb to check.

        • +
        • person (str) – Check which person.

        • +
        • negated (bool) – Check if verb was negated.

        • +
        +
        +
        Returns
        +

        bool – If verb was in present tense.

        +
        +
        +
        + +
        +
        +evennia.utils.verb_conjugation.conjugate.verb_is_present_participle(verb)[source]
        +

        Checks whether the verb is in present participle.

        +
        +
        Parameters
        +

        verb (str) – The verb to check.

        +
        +
        Returns
        +

        bool – Result of check.

        +
        +
        +
        + +
        +
        +evennia.utils.verb_conjugation.conjugate.verb_is_past(verb, person='', negated=False)[source]
        +

        Checks whether the verb is in the past tense.

        +
        +
        Parameters
        +
          +
        • verb (str) – The verb to check.

        • +
        • person (str) – The person to check.

        • +
        • negated (bool) – Check if verb is negated.

        • +
        +
        +
        Returns
        +

        bool – Result of check.

        +
        +
        +
        + +
        +
        +evennia.utils.verb_conjugation.conjugate.verb_is_past_participle(verb)[source]
        +

        Checks whether the verb is in past participle.

        +
        +
        Parameters
        +

        verb (str) – The verb to check.

        +
        +
        Returns
        +

        bool – The result of the check.

        +
        +
        +
        + +
        +
        +evennia.utils.verb_conjugation.conjugate.verb_actor_stance_components(verb)[source]
        +

        Figure out actor stance components of a verb.

        +
        +
        Parameters
        +

        verb (str) – The verb to analyze

        +
        +
        Returns
        +

        tuple

        +
        +
        The 2nd person (you) and 3rd person forms of the verb,

        in the same tense as the ingoing verb.

        +
        +
        +

        +
        +
        +
        +
        @@ -84,7 +339,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +355,7 @@ +
        develop branch
        @@ -90,7 +91,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -107,6 +107,7 @@ +
        develop branch
        @@ -37,8 +38,711 @@
        -
        -

        evennia.utils.verb_conjugation.tests

        +
        +

        evennia.utils.verb_conjugation.tests

        +

        Unit tests for verb conjugation.

        +
        +
        +class evennia.utils.verb_conjugation.tests.TestVerbConjugate(methodName='runTest')[source]
        +

        Bases: django.test.testcases.TestCase

        +

        Test the conjugation.

        +
        +
        +test_verb_infinitive = None
        +
        + +
        +
        +test_verb_conjugate = None
        +
        + +
        +
        +test_verb_present = None
        +
        + +
        +
        +test_verb_present_participle = None
        +
        + +
        +
        +test_verb_past = None
        +
        + +
        +
        +test_verb_past_participle = None
        +
        + +
        +
        +test_verb_get_all_tenses()[source]
        +

        Test getting all tenses.

        +
        + +
        +
        +test_verb_tense = None
        +
        + +
        +
        +test_verb_is_tense = None
        +
        + +
        +
        +test_verb_is_present = None
        +
        + +
        +
        +test_verb_is_present_participle = None
        +
        + +
        +
        +test_verb_is_past = None
        +
        + +
        +
        +test_verb_is_past_participle = None
        +
        + +
        +
        +test_verb_actor_stance_components = None
        +
        + +
        +
        +test_verb_actor_stance_components_00_have()
        +

        Test the tense-checker [with verb=’have’, expected=(‘have’, ‘has’)]

        +
        + +
        +
        +test_verb_actor_stance_components_01_swimming()
        +

        Test the tense-checker [with verb=’swimming’, expected=(‘swimming’, ‘swimming’)]

        +
        + +
        +
        +test_verb_actor_stance_components_02_give()
        +

        Test the tense-checker [with verb=’give’, expected=(‘give’, ‘gives’)]

        +
        + +
        +
        +test_verb_actor_stance_components_03_given()
        +

        Test the tense-checker [with verb=’given’, expected=(‘given’, ‘given’)]

        +
        + +
        +
        +test_verb_actor_stance_components_04_am()
        +

        Test the tense-checker [with verb=’am’, expected=(‘are’, ‘is’)]

        +
        + +
        +
        +test_verb_actor_stance_components_05_doing()
        +

        Test the tense-checker [with verb=’doing’, expected=(‘doing’, ‘doing’)]

        +
        + +
        +
        +test_verb_actor_stance_components_06_are()
        +

        Test the tense-checker [with verb=’are’, expected=(‘are’, ‘is’)]

        +
        + +
        +
        +test_verb_actor_stance_components_07_had()
        +

        Test the tense-checker [with verb=’had’, expected=(‘had’, ‘had’)]

        +
        + +
        +
        +test_verb_actor_stance_components_08_grin()
        +

        Test the tense-checker [with verb=’grin’, expected=(‘grin’, ‘grins’)]

        +
        + +
        +
        +test_verb_actor_stance_components_09_smile()
        +

        Test the tense-checker [with verb=’smile’, expected=(‘smile’, ‘smiles’)]

        +
        + +
        +
        +test_verb_actor_stance_components_10_vex()
        +

        Test the tense-checker [with verb=’vex’, expected=(‘vex’, ‘vexes’)]

        +
        + +
        +
        +test_verb_actor_stance_components_11_thrust()
        +

        Test the tense-checker [with verb=’thrust’, expected=(‘thrust’, ‘thrusts’)]

        +
        + +
        +
        +test_verb_conjugate_0_inf()
        +

        Test conjugation for different tenses [with tense=’inf’, verb=’have’, expected=’have’].

        +
        + +
        +
        +test_verb_conjugate_1_inf()
        +

        Test conjugation for different tenses [with tense=’inf’, verb=’swim’, expected=’swim’].

        +
        + +
        +
        +test_verb_conjugate_2_inf()
        +

        Test conjugation for different tenses [with tense=’inf’, verb=’give’, expected=’give’].

        +
        + +
        +
        +test_verb_conjugate_3_inf()
        +

        Test conjugation for different tenses [with tense=’inf’, verb=’given’, expected=’give’].

        +
        + +
        +
        +test_verb_conjugate_4_inf()
        +

        Test conjugation for different tenses [with tense=’inf’, verb=’am’, expected=’be’].

        +
        + +
        +
        +test_verb_conjugate_5_inf()
        +

        Test conjugation for different tenses [with tense=’inf’, verb=’doing’, expected=’do’].

        +
        + +
        +
        +test_verb_conjugate_6_inf()
        +

        Test conjugation for different tenses [with tense=’inf’, verb=’are’, expected=’be’].

        +
        + +
        +
        +test_verb_conjugate_7_2sgpres()
        +

        Test conjugation for different tenses [with tense=’2sgpres’, verb=’am’, expected=’are’].

        +
        + +
        +
        +test_verb_conjugate_8_3sgpres()
        +

        Test conjugation for different tenses [with tense=’3sgpres’, verb=’am’, expected=’is’].

        +
        + +
        +
        +test_verb_infinitive_0_have()
        +

        Test the infinite-getter [with verb=’have’, expected=’have’].

        +
        + +
        +
        +test_verb_infinitive_1_swim()
        +

        Test the infinite-getter [with verb=’swim’, expected=’swim’].

        +
        + +
        +
        +test_verb_infinitive_2_give()
        +

        Test the infinite-getter [with verb=’give’, expected=’give’].

        +
        + +
        +
        +test_verb_infinitive_3_given()
        +

        Test the infinite-getter [with verb=’given’, expected=’give’].

        +
        + +
        +
        +test_verb_infinitive_4_am()
        +

        Test the infinite-getter [with verb=’am’, expected=’be’].

        +
        + +
        +
        +test_verb_infinitive_5_doing()
        +

        Test the infinite-getter [with verb=’doing’, expected=’do’].

        +
        + +
        +
        +test_verb_infinitive_6_are()
        +

        Test the infinite-getter [with verb=’are’, expected=’be’].

        +
        + +
        +
        +test_verb_is_past_0_1st()
        +

        Test the tense-checker [with person=’1st’, verb=’have’, expected=False]

        +
        + +
        +
        +test_verb_is_past_1_1st()
        +

        Test the tense-checker [with person=’1st’, verb=’swim’, expected=False]

        +
        + +
        +
        +test_verb_is_past_2_1st()
        +

        Test the tense-checker [with person=’1st’, verb=’give’, expected=False]

        +
        + +
        +
        +test_verb_is_past_3_1st()
        +

        Test the tense-checker [with person=’1st’, verb=’given’, expected=False]

        +
        + +
        +
        +test_verb_is_past_4_1st()
        +

        Test the tense-checker [with person=’1st’, verb=’am’, expected=False]

        +
        + +
        +
        +test_verb_is_past_5_1st()
        +

        Test the tense-checker [with person=’1st’, verb=’doing’, expected=False]

        +
        + +
        +
        +test_verb_is_past_6_1st()
        +

        Test the tense-checker [with person=’1st’, verb=’are’, expected=False]

        +
        + +
        +
        +test_verb_is_past_7_2nd()
        +

        Test the tense-checker [with person=’2nd’, verb=’were’, expected=True]

        +
        + +
        +
        +test_verb_is_past_participle_0_have()
        +

        Test the tense-checker [with verb=’have’, expected=False]

        +
        + +
        +
        +test_verb_is_past_participle_1_swimming()
        +

        Test the tense-checker [with verb=’swimming’, expected=False]

        +
        + +
        +
        +test_verb_is_past_participle_2_give()
        +

        Test the tense-checker [with verb=’give’, expected=False]

        +
        + +
        +
        +test_verb_is_past_participle_3_given()
        +

        Test the tense-checker [with verb=’given’, expected=True]

        +
        + +
        +
        +test_verb_is_past_participle_4_am()
        +

        Test the tense-checker [with verb=’am’, expected=False]

        +
        + +
        +
        +test_verb_is_past_participle_5_doing()
        +

        Test the tense-checker [with verb=’doing’, expected=False]

        +
        + +
        +
        +test_verb_is_past_participle_6_are()
        +

        Test the tense-checker [with verb=’are’, expected=False]

        +
        + +
        +
        +test_verb_is_past_participle_7_had()
        +

        Test the tense-checker [with verb=’had’, expected=False]

        +
        + +
        +
        +test_verb_is_present_0_1st()
        +

        Test the tense-checker [with person=’1st’, verb=’have’, expected=False]

        +
        + +
        +
        +test_verb_is_present_1_1st()
        +

        Test the tense-checker [with person=’1st’, verb=’swim’, expected=False]

        +
        + +
        +
        +test_verb_is_present_2_1st()
        +

        Test the tense-checker [with person=’1st’, verb=’give’, expected=False]

        +
        + +
        +
        +test_verb_is_present_3_1st()
        +

        Test the tense-checker [with person=’1st’, verb=’given’, expected=False]

        +
        + +
        +
        +test_verb_is_present_4_1st()
        +

        Test the tense-checker [with person=’1st’, verb=’am’, expected=True]

        +
        + +
        +
        +test_verb_is_present_5_1st()
        +

        Test the tense-checker [with person=’1st’, verb=’doing’, expected=False]

        +
        + +
        +
        +test_verb_is_present_6_1st()
        +

        Test the tense-checker [with person=’1st’, verb=’are’, expected=False]

        +
        + +
        +
        +test_verb_is_present_7_1st()
        +

        Test the tense-checker [with person=’1st’, verb=’had’, expected=False]

        +
        + +
        +
        +test_verb_is_present_participle_0_have()
        +

        Test the tense-checker [with verb=’have’, expected=False]

        +
        + +
        +
        +test_verb_is_present_participle_1_swim()
        +

        Test the tense-checker [with verb=’swim’, expected=False]

        +
        + +
        +
        +test_verb_is_present_participle_2_give()
        +

        Test the tense-checker [with verb=’give’, expected=False]

        +
        + +
        +
        +test_verb_is_present_participle_3_given()
        +

        Test the tense-checker [with verb=’given’, expected=False]

        +
        + +
        +
        +test_verb_is_present_participle_4_am()
        +

        Test the tense-checker [with verb=’am’, expected=False]

        +
        + +
        +
        +test_verb_is_present_participle_5_doing()
        +

        Test the tense-checker [with verb=’doing’, expected=True]

        +
        + +
        +
        +test_verb_is_present_participle_6_are()
        +

        Test the tense-checker [with verb=’are’, expected=False]

        +
        + +
        +
        +test_verb_is_tense_0_inf()
        +

        Test the tense-checker [with tense=’inf’, verb=’have’, expected=True]

        +
        + +
        +
        +test_verb_is_tense_1_inf()
        +

        Test the tense-checker [with tense=’inf’, verb=’swim’, expected=True]

        +
        + +
        +
        +test_verb_is_tense_2_inf()
        +

        Test the tense-checker [with tense=’inf’, verb=’give’, expected=True]

        +
        + +
        +
        +test_verb_is_tense_3_inf()
        +

        Test the tense-checker [with tense=’inf’, verb=’given’, expected=False]

        +
        + +
        +
        +test_verb_is_tense_4_inf()
        +

        Test the tense-checker [with tense=’inf’, verb=’am’, expected=False]

        +
        + +
        +
        +test_verb_is_tense_5_inf()
        +

        Test the tense-checker [with tense=’inf’, verb=’doing’, expected=False]

        +
        + +
        +
        +test_verb_is_tense_6_inf()
        +

        Test the tense-checker [with tense=’inf’, verb=’are’, expected=False]

        +
        + +
        +
        +test_verb_past_0_1st()
        +

        Test the past getter [with person=’1st’, verb=’have’, expected=’had’].

        +
        + +
        +
        +test_verb_past_1_1st()
        +

        Test the past getter [with person=’1st’, verb=’swim’, expected=’swam’].

        +
        + +
        +
        +test_verb_past_2_1st()
        +

        Test the past getter [with person=’1st’, verb=’give’, expected=’gave’].

        +
        + +
        +
        +test_verb_past_3_1st()
        +

        Test the past getter [with person=’1st’, verb=’given’, expected=’gave’].

        +
        + +
        +
        +test_verb_past_4_1st()
        +

        Test the past getter [with person=’1st’, verb=’am’, expected=’was’].

        +
        + +
        +
        +test_verb_past_5_1st()
        +

        Test the past getter [with person=’1st’, verb=’doing’, expected=’did’].

        +
        + +
        +
        +test_verb_past_6_1st()
        +

        Test the past getter [with person=’1st’, verb=’are’, expected=’was’].

        +
        + +
        +
        +test_verb_past_7_2nd()
        +

        Test the past getter [with person=’2nd’, verb=’were’, expected=’were’].

        +
        + +
        +
        +test_verb_past_participle_0_have()
        +

        Test the past participle [with verb=’have’, expected=’had’].

        +
        + +
        +
        +test_verb_past_participle_1_swim()
        +

        Test the past participle [with verb=’swim’, expected=’swum’].

        +
        + +
        +
        +test_verb_past_participle_2_give()
        +

        Test the past participle [with verb=’give’, expected=’given’].

        +
        + +
        +
        +test_verb_past_participle_3_given()
        +

        Test the past participle [with verb=’given’, expected=’given’].

        +
        + +
        +
        +test_verb_past_participle_4_am()
        +

        Test the past participle [with verb=’am’, expected=’been’].

        +
        + +
        +
        +test_verb_past_participle_5_doing()
        +

        Test the past participle [with verb=’doing’, expected=’done’].

        +
        + +
        +
        +test_verb_past_participle_6_are()
        +

        Test the past participle [with verb=’are’, expected=’been’].

        +
        + +
        +
        +test_verb_present_0_1st()
        +

        Test the present [with person=’1st’, verb=’have’, expected=’have’].

        +
        + +
        +
        +test_verb_present_1_1st()
        +

        Test the present [with person=’1st’, verb=’swim’, expected=’swim’].

        +
        + +
        +
        +test_verb_present_2_1st()
        +

        Test the present [with person=’1st’, verb=’give’, expected=’give’].

        +
        + +
        +
        +test_verb_present_3_1st()
        +

        Test the present [with person=’1st’, verb=’given’, expected=’give’].

        +
        + +
        +
        +test_verb_present_4_1st()
        +

        Test the present [with person=’1st’, verb=’am’, expected=’am’].

        +
        + +
        +
        +test_verb_present_5_1st()
        +

        Test the present [with person=’1st’, verb=’doing’, expected=’do’].

        +
        + +
        +
        +test_verb_present_6_1st()
        +

        Test the present [with person=’1st’, verb=’are’, expected=’am’].

        +
        + +
        +
        +test_verb_present_7_2nd()
        +

        Test the present [with person=’2nd’, verb=’were’, expected=’are’].

        +
        + +
        +
        +test_verb_present_8_3rd()
        +

        Test the present [with person=’3rd’, verb=’am’, expected=’is’].

        +
        + +
        +
        +test_verb_present_participle_0_have()
        +

        Test the present_participle [with verb=’have’, expected=’having’]

        +
        + +
        +
        +test_verb_present_participle_1_swim()
        +

        Test the present_participle [with verb=’swim’, expected=’swimming’]

        +
        + +
        +
        +test_verb_present_participle_2_give()
        +

        Test the present_participle [with verb=’give’, expected=’giving’]

        +
        + +
        +
        +test_verb_present_participle_3_given()
        +

        Test the present_participle [with verb=’given’, expected=’giving’]

        +
        + +
        +
        +test_verb_present_participle_4_am()
        +

        Test the present_participle [with verb=’am’, expected=’being’]

        +
        + +
        +
        +test_verb_present_participle_5_doing()
        +

        Test the present_participle [with verb=’doing’, expected=’doing’]

        +
        + +
        +
        +test_verb_present_participle_6_are()
        +

        Test the present_participle [with verb=’are’, expected=’being’]

        +
        + +
        +
        +test_verb_tense_0_have()
        +

        Test the tense retriever [with verb=’have’, expected=’infinitive’].

        +
        + +
        +
        +test_verb_tense_1_swim()
        +

        Test the tense retriever [with verb=’swim’, expected=’infinitive’].

        +
        + +
        +
        +test_verb_tense_2_give()
        +

        Test the tense retriever [with verb=’give’, expected=’infinitive’].

        +
        + +
        +
        +test_verb_tense_3_given()
        +

        Test the tense retriever [with verb=’given’, expected=’past participle’].

        +
        + +
        +
        +test_verb_tense_4_am()
        +

        Test the tense retriever [with verb=’am’, expected=’1st singular present’].

        +
        + +
        +
        +test_verb_tense_5_doing()
        +

        Test the tense retriever [with verb=’doing’, expected=’present participle’].

        +
        + +
        +
        +test_verb_tense_6_are()
        +

        Test the tense retriever [with verb=’are’, expected=’2nd singular present’].

        +
        + +
        +
        @@ -84,7 +788,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +804,7 @@ +
        develop branch
        @@ -37,8 +38,392 @@
        -
        -

        evennia.web.admin.accounts

        +
        +

        evennia.web.admin.accounts

        +
        +
        +class evennia.web.admin.accounts.AccountChangeForm(*args, **kwargs)[source]
        +

        Bases: django.contrib.auth.forms.UserChangeForm

        +

        Modify the accountdb class.

        +
        +
        +class Meta[source]
        +

        Bases: object

        +
        +
        +model
        +

        alias of evennia.accounts.models.AccountDB

        +
        + +
        +
        +fields = '__all__'
        +
        + +
        + +
        +
        +clean_username()[source]
        +

        Clean the username and check its existence.

        +
        + +
        +
        +__init__(*args, **kwargs)[source]
        +

        Tweak some fields dynamically.

        +
        + +
        +
        +base_fields = {'date_joined': <django.forms.fields.DateTimeField object>, 'db_attributes': <django.forms.models.ModelMultipleChoiceField object>, 'db_cmdset_storage': <django.forms.fields.CharField object>, 'db_is_bot': <django.forms.fields.BooleanField object>, 'db_is_connected': <django.forms.fields.BooleanField object>, 'db_key': <django.forms.fields.CharField object>, 'db_lock_storage': <django.forms.fields.CharField object>, 'db_tags': <django.forms.models.ModelMultipleChoiceField object>, 'db_typeclass_path': <django.forms.fields.ChoiceField object>, 'email': <django.forms.fields.EmailField object>, 'first_name': <django.forms.fields.CharField object>, 'groups': <django.forms.models.ModelMultipleChoiceField object>, 'is_active': <django.forms.fields.BooleanField object>, 'is_staff': <django.forms.fields.BooleanField object>, 'is_superuser': <django.forms.fields.BooleanField object>, 'last_login': <django.forms.fields.DateTimeField object>, 'last_name': <django.forms.fields.CharField object>, 'password': <django.contrib.auth.forms.ReadOnlyPasswordHashField object>, 'user_permissions': <django.forms.models.ModelMultipleChoiceField object>, 'username': <django.forms.fields.RegexField object>}
        +
        + +
        +
        +declared_fields = {'db_cmdset_storage': <django.forms.fields.CharField object>, 'db_lock_storage': <django.forms.fields.CharField object>, 'db_typeclass_path': <django.forms.fields.ChoiceField object>, 'is_superuser': <django.forms.fields.BooleanField object>, 'password': <django.contrib.auth.forms.ReadOnlyPasswordHashField object>, 'username': <django.forms.fields.RegexField object>}
        +
        + +
        +
        +property media
        +

        Return all media required to render the widgets on this form.

        +
        + +
        + +
        +
        +class evennia.web.admin.accounts.AccountCreationForm(*args, **kwargs)[source]
        +

        Bases: django.contrib.auth.forms.UserCreationForm

        +

        Create a new AccountDB instance.

        +
        +
        +class Meta[source]
        +

        Bases: object

        +
        +
        +model
        +

        alias of evennia.accounts.models.AccountDB

        +
        + +
        +
        +fields = '__all__'
        +
        + +
        + +
        +
        +clean_username()[source]
        +

        Cleanup username.

        +
        + +
        +
        +base_fields = {'date_joined': <django.forms.fields.DateTimeField object>, 'db_attributes': <django.forms.models.ModelMultipleChoiceField object>, 'db_cmdset_storage': <django.forms.fields.CharField object>, 'db_is_bot': <django.forms.fields.BooleanField object>, 'db_is_connected': <django.forms.fields.BooleanField object>, 'db_key': <django.forms.fields.CharField object>, 'db_lock_storage': <django.forms.fields.CharField object>, 'db_tags': <django.forms.models.ModelMultipleChoiceField object>, 'db_typeclass_path': <django.forms.fields.CharField object>, 'email': <django.forms.fields.EmailField object>, 'first_name': <django.forms.fields.CharField object>, 'groups': <django.forms.models.ModelMultipleChoiceField object>, 'is_active': <django.forms.fields.BooleanField object>, 'is_staff': <django.forms.fields.BooleanField object>, 'is_superuser': <django.forms.fields.BooleanField object>, 'last_login': <django.forms.fields.DateTimeField object>, 'last_name': <django.forms.fields.CharField object>, 'password': <django.forms.fields.CharField object>, 'password1': <django.forms.fields.CharField object>, 'password2': <django.forms.fields.CharField object>, 'user_permissions': <django.forms.models.ModelMultipleChoiceField object>, 'username': <django.forms.fields.RegexField object>}
        +
        + +
        +
        +declared_fields = {'password1': <django.forms.fields.CharField object>, 'password2': <django.forms.fields.CharField object>, 'username': <django.forms.fields.RegexField object>}
        +
        + +
        +
        +property media
        +

        Return all media required to render the widgets on this form.

        +
        + +
        + +
        +
        +class evennia.web.admin.accounts.AccountTagInline(parent_model, admin_site)[source]
        +

        Bases: evennia.web.admin.tags.TagInline

        +

        Inline Account Tags.

        +
        +
        +model
        +

        alias of evennia.accounts.models.AccountDB_db_tags

        +
        + +
        +
        +related_field = 'accountdb'
        +
        + +
        +
        +property media
        +
        + +
        + +
        +
        +class evennia.web.admin.accounts.AccountAttributeInline(parent_model, admin_site)[source]
        +

        Bases: evennia.web.admin.attributes.AttributeInline

        +

        Inline Account Attributes.

        +
        +
        +model
        +

        alias of evennia.accounts.models.AccountDB_db_attributes

        +
        + +
        +
        +related_field = 'accountdb'
        +
        + +
        +
        +property media
        +
        + +
        + +
        +
        +class evennia.web.admin.accounts.ObjectPuppetInline(parent_model, admin_site)[source]
        +

        Bases: django.contrib.admin.options.StackedInline

        +

        Inline creation of puppet-Object in Account.

        +
        +
        +class ObjectCreateForm(*args, **kwargs)
        +

        Bases: django.forms.models.ModelForm

        +

        This form details the look of the fields.

        +
        +
        +class Meta
        +

        Bases: object

        +
        +
        +fields = '__all__'
        +
        + +
        +
        +model
        +

        alias of evennia.objects.models.ObjectDB

        +
        + +
        + +
        +
        +__init__(*args, **kwargs)
        +

        Tweak some fields dynamically.

        +
        + +
        +
        +base_fields = {'db_account': <django.forms.models.ModelChoiceField object>, 'db_attributes': <django.forms.models.ModelMultipleChoiceField object>, 'db_cmdset_storage': <django.forms.fields.CharField object>, 'db_destination': <django.forms.models.ModelChoiceField object>, 'db_home': <django.forms.models.ModelChoiceField object>, 'db_key': <django.forms.fields.CharField object>, 'db_location': <django.forms.models.ModelChoiceField object>, 'db_lock_storage': <django.forms.fields.CharField object>, 'db_sessid': <django.forms.fields.CharField object>, 'db_tags': <django.forms.models.ModelMultipleChoiceField object>, 'db_typeclass_path': <django.forms.fields.ChoiceField object>}
        +
        + +
        +
        +declared_fields = {'db_cmdset_storage': <django.forms.fields.CharField object>, 'db_destination': <django.forms.models.ModelChoiceField object>, 'db_home': <django.forms.models.ModelChoiceField object>, 'db_key': <django.forms.fields.CharField object>, 'db_location': <django.forms.models.ModelChoiceField object>, 'db_lock_storage': <django.forms.fields.CharField object>, 'db_typeclass_path': <django.forms.fields.ChoiceField object>}
        +
        + +
        +
        +property media
        +

        Return all media required to render the widgets on this form.

        +
        + +
        + +
        +
        +verbose_name = 'Puppeted Object'
        +
        + +
        +
        +model
        +

        alias of evennia.objects.models.ObjectDB

        +
        + +
        +
        +view_on_site = False
        +
        + +
        + +
        + +
        +
        +form
        +

        alias of evennia.web.admin.objects.ObjectCreateForm

        +
        + +
        +
        +fieldsets = ((None, {'fields': (('db_key', 'db_typeclass_path'), ('db_location', 'db_home', 'db_destination'), 'db_cmdset_storage', 'db_lock_storage'), 'description': 'Object currently puppeted by the account (note that this will go away if account logs out or unpuppets)'}),)
        +
        + +
        +
        +extra = 0
        +
        + +
        +
        +readonly_fields = ('db_key', 'db_typeclass_path', 'db_destination', 'db_location', 'db_home', 'db_account', 'db_cmdset_storage', 'db_lock_storage')
        +
        + +
        +
        +has_add_permission(request, obj=None)[source]
        +

        Return True if the given request has permission to add an object. +Can be overridden by the user in subclasses.

        +
        + +
        +
        +has_delete_permission(request, obj=None)[source]
        +

        Return True if the given request has permission to change the given +Django model instance, the default implementation doesn’t examine the +obj parameter.

        +

        Can be overridden by the user in subclasses. In such case it should +return True if the given request has permission to delete the obj +model instance. If obj is None, this should return True if the given +request has permission to delete any object of the given type.

        +
        + +
        +
        +property media
        +
        + +
        + +
        +
        +class evennia.web.admin.accounts.AccountAdmin(model, admin_site)[source]
        +

        Bases: django.contrib.auth.admin.UserAdmin

        +

        This is the main creation screen for Users/accounts

        +
        +
        +list_display = ('id', 'username', 'is_staff', 'is_superuser', 'db_typeclass_path', 'db_date_created')
        +
        + +
        + +
        + +
        +
        +form
        +

        alias of AccountChangeForm

        +
        + +
        +
        +add_form
        +

        alias of AccountCreationForm

        +
        + +
        +
        +search_fields = ['=id', '^username', 'db_typeclass_path']
        +
        + +
        +
        +ordering = ['-db_date_created', 'id']
        +
        + +
        +
        +list_filter = ['is_superuser', 'is_staff', 'db_typeclass_path']
        +
        + +
        +
        +inlines = [<class 'evennia.web.admin.accounts.AccountTagInline'>, <class 'evennia.web.admin.accounts.AccountAttributeInline'>]
        +
        + +
        +
        +readonly_fields = ['db_date_created', 'serialized_string', 'puppeted_objects']
        +
        + +
        +
        +view_on_site = False
        +
        + +
        +
        +fieldsets = ((None, {'fields': (('username', 'db_typeclass_path'), 'password', 'email', 'db_date_created', 'db_lock_storage', 'db_cmdset_storage', 'puppeted_objects', 'serialized_string')}), ('Admin/Website properties', {'fields': (('first_name', 'last_name'), 'last_login', 'date_joined', 'is_active', 'is_staff', 'is_superuser', 'user_permissions', 'groups'), 'description': '<i>Used by the website/Django admin. Except for `superuser status`, the permissions are not used in-game.</i>'}))
        +
        + +
        +
        +add_fieldsets = ((None, {'fields': ('username', 'password1', 'password2', 'email'), 'description': '<i>These account details are shared by the admin system and the game.</i>'}),)
        +
        + +
        +
        +serialized_string(obj)[source]
        +

        Get the serialized version of the object.

        +
        + +
        +
        +puppeted_objects(obj)[source]
        +

        Get any currently puppeted objects (read only list)

        +
        + +
        +
        +get_form(request, obj=None, **kwargs)[source]
        +

        Overrides help texts.

        +
        + +
        +
        +user_change_password(request, id, form_url='')[source]
        +
        + +
        +
        +save_model(request, obj, form, change)[source]
        +

        Custom save actions.

        +
        +
        Parameters
        +
          +
        • request (Request) – Incoming request.

        • +
        • obj (Object) – Object to save.

        • +
        • form (Form) – Related form instance.

        • +
        • change (bool) – False if this is a new save and not an update.

        • +
        +
        +
        +
        + +
        +
        +response_add(request, obj, post_url_continue=None)[source]
        +

        Determine the HttpResponse for the add_view stage. It mostly defers to +its superclass implementation but is customized because the User model +has a slightly different workflow.

        +
        + +
        +
        +property media
        +
        + +
        +
        @@ -84,7 +469,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +485,7 @@ +
        develop branch
        @@ -37,8 +38,151 @@
        -
        -

        evennia.web.admin.attributes

        +
        +

        evennia.web.admin.attributes

        +

        Attribute admin.

        +

        Note that we don’t present a separate admin for these, since they are only +relevant together with a specific object.

        +
        +
        +class evennia.web.admin.attributes.AttributeForm(*args, **kwargs)[source]
        +

        Bases: django.forms.models.ModelForm

        +

        This form overrides the base behavior of the ModelForm that would be used for a Attribute-through-model. +Since the through-models only have access to the foreignkeys of the Attribute and the Object that they’re +attached to, we need to spoof the behavior of it being a form that would correspond to its Attribute, +or the creation of an Attribute. Instead of being saved, we’ll call to the Object’s handler, which will handle +the creation, change, or deletion of an Attribute for us, as well as updating the handler’s cache so that all +changes are instantly updated in-game.

        +
        +
        +class Meta[source]
        +

        Bases: object

        +
        +
        +fields = ('attr_key', 'attr_value', 'attr_category', 'attr_lockstring', 'attr_type')
        +
        + +
        + +
        +
        +__init__(*args, **kwargs)[source]
        +

        If we have an Attribute, then we’ll prepopulate our instance with the fields we’d expect it +to have based on the Attribute. attr_key, attr_category, attr_value, attr_type, +and attr_lockstring all refer to the corresponding Attribute fields. The initial data of the form fields will +similarly be populated.

        +
        + +
        +
        +save(commit=True)[source]
        +

        One thing we want to do here is the or None checks, because forms are saved with an empty +string rather than null from forms, usually, and the Handlers may handle empty strings +differently than None objects. So for consistency with how things are handled in game, +we’ll try to make sure that empty form fields will be None, rather than ‘’.

        +
        + +
        +
        +clean_attr_value()[source]
        +

        Prevent certain data-types from being cleaned due to literal_eval +failing on them. Otherwise they will be turned into str.

        +
        + +
        +
        +base_fields = {'attr_category': <django.forms.fields.CharField object>, 'attr_key': <django.forms.fields.CharField object>, 'attr_lockstring': <django.forms.fields.CharField object>, 'attr_type': <django.forms.fields.ChoiceField object>, 'attr_value': <evennia.utils.picklefield.PickledFormField object>}
        +
        + +
        +
        +declared_fields = {'attr_category': <django.forms.fields.CharField object>, 'attr_key': <django.forms.fields.CharField object>, 'attr_lockstring': <django.forms.fields.CharField object>, 'attr_type': <django.forms.fields.ChoiceField object>, 'attr_value': <evennia.utils.picklefield.PickledFormField object>}
        +
        + +
        +
        +property media
        +

        Return all media required to render the widgets on this form.

        +
        + +
        + +
        +
        +class evennia.web.admin.attributes.AttributeFormSet(data=None, files=None, instance=None, save_as_new=False, prefix=None, queryset=None, **kwargs)[source]
        +

        Bases: django.forms.models.BaseInlineFormSet

        +

        Attribute version of TagFormSet, as above.

        +
        +
        +save(commit=True)[source]
        +

        Save model instances for every form, adding and changing instances +as necessary, and return the list of instances.

        +
        + +
        + +
        +
        +class evennia.web.admin.attributes.AttributeInline(parent_model, admin_site)[source]
        +

        Bases: django.contrib.admin.options.TabularInline

        +

        A handler for inline Attributes. This class should be subclassed in the admin of your models, +and the ‘model’ and ‘related_field’ class attributes must be set. model should be the +through model (ObjectDB_db_tag’, for example), while related field should be the name +of the field on that through model which points to the model being used: ‘objectdb’, +‘msg’, ‘accountdb’, etc.

        +
        +
        +model = None
        +
        + +
        +
        +verbose_name = 'Attribute'
        +
        + +
        +
        +verbose_name_plural = 'Attributes'
        +
        + +
        +
        +form
        +

        alias of AttributeForm

        +
        + +
        +
        +formset
        +

        alias of AttributeFormSet

        +
        + +
        +
        +related_field = None
        +
        + +
        +
        +extra = 0
        +
        + +
        +
        +get_formset(request, obj=None, **kwargs)[source]
        +

        get_formset has to return a class, but we need to make the class that we return +know about the related_field that we’ll use. Returning the class itself rather than +a proxy isn’t threadsafe, since it’d be the base class and would change if multiple +people used the admin at the same time

        +
        + +
        +
        +property media
        +
        + +
        +
        @@ -84,7 +228,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +244,7 @@ +
        develop branch
        @@ -37,8 +38,392 @@
        -
        -

        evennia.web.admin.comms

        +
        +

        evennia.web.admin.comms

        +

        This defines how Comm models are displayed in the web admin interface.

        +
        +
        +class evennia.web.admin.comms.MsgTagInline(parent_model, admin_site)[source]
        +

        Bases: evennia.web.admin.tags.TagInline

        +

        Inline display for Msg-tags.

        +
        +
        +model
        +

        alias of evennia.comms.models.Msg_db_tags

        +
        + +
        +
        +related_field = 'msg'
        +
        + +
        +
        +property media
        +
        + +
        + +
        +
        +class evennia.web.admin.comms.MsgForm(data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=<class 'django.forms.utils.ErrorList'>, label_suffix=None, empty_permitted=False, instance=None, use_required_attribute=None, renderer=None)[source]
        +

        Bases: django.forms.models.ModelForm

        +

        Custom Msg form.

        +
        +
        +class Meta[source]
        +

        Bases: object

        +
        +
        +models
        +

        alias of evennia.comms.models.Msg

        +
        + +
        +
        +fields = '__all__'
        +
        + +
        + +
        +
        +base_fields = {'db_header': <django.forms.fields.CharField object>, 'db_lock_storage': <django.forms.fields.CharField object>}
        +
        + +
        +
        +declared_fields = {'db_header': <django.forms.fields.CharField object>, 'db_lock_storage': <django.forms.fields.CharField object>}
        +
        + +
        +
        +property media
        +

        Return all media required to render the widgets on this form.

        +
        + +
        + +
        +
        +class evennia.web.admin.comms.MsgAdmin(model, admin_site)[source]
        +

        Bases: django.contrib.admin.options.ModelAdmin

        +

        Defines display for Msg objects

        +
        +
        +inlines = [<class 'evennia.web.admin.comms.MsgTagInline'>]
        +
        + +
        +
        +form
        +

        alias of MsgForm

        +
        + +
        +
        +list_display = ('id', 'db_date_created', 'sender', 'receiver', 'start_of_message')
        +
        + +
        + +
        + +
        +
        +ordering = ['-db_date_created', '-id']
        +
        + +
        +
        +search_fields = ['=id', '^db_date_created', '^db_message', '^db_sender_accounts__db_key', '^db_sender_objects__db_key', '^db_sender_scripts__db_key', '^db_sender_external', '^db_receivers_accounts__db_key', '^db_receivers_objects__db_key', '^db_receivers_scripts__db_key', '^db_receiver_external']
        +
        + +
        +
        +readonly_fields = ['db_date_created', 'serialized_string']
        +
        + +
        +
        +save_as = True
        +
        + +
        +
        +save_on_top = True
        +
        + +
        + +
        + +
        +
        +view_on_site = False
        +
        + +
        +
        +raw_id_fields = ('db_sender_accounts', 'db_sender_objects', 'db_sender_scripts', 'db_receivers_accounts', 'db_receivers_objects', 'db_receivers_scripts', 'db_hide_from_accounts', 'db_hide_from_objects')
        +
        + +
        +
        +fieldsets = ((None, {'fields': (('db_sender_accounts', 'db_sender_objects', 'db_sender_scripts', 'db_sender_external'), ('db_receivers_accounts', 'db_receivers_objects', 'db_receivers_scripts', 'db_receiver_external'), ('db_hide_from_accounts', 'db_hide_from_objects'), 'db_header', 'db_message', 'serialized_string')}),)
        +
        + +
        +
        +sender(obj)[source]
        +
        + +
        +
        +receiver(obj)[source]
        +
        + +
        +
        +start_of_message(obj)[source]
        +
        + +
        +
        +serialized_string(obj)[source]
        +

        Get the serialized version of the object.

        +
        + +
        +
        +get_form(request, obj=None, **kwargs)[source]
        +

        Overrides help texts.

        +
        + +
        +
        +property media
        +
        + +
        + +
        +
        +class evennia.web.admin.comms.ChannelAttributeInline(parent_model, admin_site)[source]
        +

        Bases: evennia.web.admin.attributes.AttributeInline

        +

        Inline display of Channel Attribute - experimental

        +
        +
        +model
        +

        alias of evennia.comms.models.ChannelDB_db_attributes

        +
        + +
        +
        +related_field = 'channeldb'
        +
        + +
        +
        +property media
        +
        + +
        + +
        +
        +class evennia.web.admin.comms.ChannelTagInline(parent_model, admin_site)[source]
        +

        Bases: evennia.web.admin.tags.TagInline

        +

        Inline display of Channel Tags - experimental

        +
        +
        +model
        +

        alias of evennia.comms.models.ChannelDB_db_tags

        +
        + +
        +
        +related_field = 'channeldb'
        +
        + +
        +
        +property media
        +
        + +
        + +
        +
        +class evennia.web.admin.comms.ChannelForm(data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=<class 'django.forms.utils.ErrorList'>, label_suffix=None, empty_permitted=False, instance=None, use_required_attribute=None, renderer=None)[source]
        +

        Bases: django.forms.models.ModelForm

        +

        Form for accessing channels.

        +
        +
        +class Meta[source]
        +

        Bases: object

        +
        +
        +model
        +

        alias of evennia.comms.models.ChannelDB

        +
        + +
        +
        +fields = '__all__'
        +
        + +
        + +
        +
        +base_fields = {'db_account_subscriptions': <django.forms.models.ModelMultipleChoiceField object>, 'db_attributes': <django.forms.models.ModelMultipleChoiceField object>, 'db_key': <django.forms.fields.CharField object>, 'db_lock_storage': <django.forms.fields.CharField object>, 'db_object_subscriptions': <django.forms.models.ModelMultipleChoiceField object>, 'db_tags': <django.forms.models.ModelMultipleChoiceField object>, 'db_typeclass_path': <django.forms.fields.CharField object>}
        +
        + +
        +
        +declared_fields = {'db_lock_storage': <django.forms.fields.CharField object>}
        +
        + +
        +
        +property media
        +

        Return all media required to render the widgets on this form.

        +
        + +
        + +
        +
        +class evennia.web.admin.comms.ChannelAdmin(model, admin_site)[source]
        +

        Bases: django.contrib.admin.options.ModelAdmin

        +

        Defines display for Channel objects

        +
        +
        +inlines = [<class 'evennia.web.admin.comms.ChannelTagInline'>, <class 'evennia.web.admin.comms.ChannelAttributeInline'>]
        +
        + +
        +
        +form
        +

        alias of ChannelForm

        +
        + +
        +
        +list_display = ('id', 'db_key', 'no_of_subscribers', 'db_lock_storage', 'db_typeclass_path', 'db_date_created')
        +
        + +
        + +
        + +
        +
        +ordering = ['-db_date_created', '-id', '-db_key']
        +
        + +
        +
        +search_fields = ['id', 'db_key', 'db_tags__db_key']
        +
        + +
        +
        +readonly_fields = ['serialized_string']
        +
        + +
        +
        +save_as = True
        +
        + +
        +
        +save_on_top = True
        +
        + +
        + +
        + +
        +
        +raw_id_fields = ('db_object_subscriptions', 'db_account_subscriptions')
        +
        + +
        +
        +fieldsets = ((None, {'fields': (('db_key',), 'db_lock_storage', 'db_account_subscriptions', 'db_object_subscriptions', 'serialized_string')}),)
        +
        + +
        +
        +subscriptions(obj)[source]
        +

        Helper method to get subs from a channel.

        +
        +
        Parameters
        +

        obj (Channel) – The channel to get subs from.

        +
        +
        +
        + +
        +
        +no_of_subscribers(obj)[source]
        +

        Get number of subs for a a channel .

        +
        +
        Parameters
        +

        obj (Channel) – The channel to get subs from.

        +
        +
        +
        + +
        +
        +serialized_string(obj)[source]
        +

        Get the serialized version of the object.

        +
        + +
        +
        +get_form(request, obj=None, **kwargs)[source]
        +

        Overrides help texts.

        +
        + +
        +
        +save_model(request, obj, form, change)[source]
        +

        Model-save hook.

        +
        +
        Parameters
        +
          +
        • request (Request) – Incoming request.

        • +
        • obj (Object) – Database object.

        • +
        • form (Form) – Form instance.

        • +
        • change (bool) – If this is a change or a new object.

        • +
        +
        +
        +
        + +
        +
        +response_add(request, obj, post_url_continue=None)[source]
        +

        Determine the HttpResponse for the add_view stage.

        +
        + +
        +
        +property media
        +
        + +
        +
        @@ -84,7 +469,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +485,7 @@ +
        develop branch
        @@ -37,8 +38,21 @@
        -
        -

        evennia.web.admin.frontpage

        +
        +

        evennia.web.admin.frontpage

        +

        Admin views.

        +
        +
        +evennia.web.admin.frontpage.evennia_admin(request)[source]
        +

        Helpful Evennia-specific admin page.

        +
        + +
        +
        +evennia.web.admin.frontpage.admin_wrapper(request)[source]
        +

        Wrapper that allows us to properly use the base Django admin site, if needed.

        +
        +
        @@ -84,7 +98,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +114,7 @@ +
        develop branch
        @@ -37,8 +38,144 @@
        -
        -

        evennia.web.admin.help

        +
        +

        evennia.web.admin.help

        +

        This defines how to edit help entries in Admin.

        +
        +
        +class evennia.web.admin.help.HelpTagInline(parent_model, admin_site)[source]
        +

        Bases: evennia.web.admin.tags.TagInline

        +
        +
        +model
        +

        alias of evennia.help.models.HelpEntry_db_tags

        +
        + +
        +
        +related_field = 'helpentry'
        +
        + +
        +
        +property media
        +
        + +
        + +
        +
        +class evennia.web.admin.help.HelpEntryForm(data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=<class 'django.forms.utils.ErrorList'>, label_suffix=None, empty_permitted=False, instance=None, use_required_attribute=None, renderer=None)[source]
        +

        Bases: django.forms.models.ModelForm

        +

        Defines how to display the help entry

        +
        +
        +class Meta[source]
        +

        Bases: object

        +
        +
        +model
        +

        alias of evennia.help.models.HelpEntry

        +
        + +
        +
        +fields = '__all__'
        +
        + +
        + +
        +
        +base_fields = {'db_entrytext': <django.forms.fields.CharField object>, 'db_help_category': <django.forms.fields.CharField object>, 'db_key': <django.forms.fields.CharField object>, 'db_lock_storage': <django.forms.fields.CharField object>, 'db_tags': <django.forms.models.ModelMultipleChoiceField object>}
        +
        + +
        +
        +declared_fields = {'db_help_category': <django.forms.fields.CharField object>, 'db_lock_storage': <django.forms.fields.CharField object>}
        +
        + +
        +
        +property media
        +

        Return all media required to render the widgets on this form.

        +
        + +
        + +
        +
        +class evennia.web.admin.help.HelpEntryAdmin(model, admin_site)[source]
        +

        Bases: django.contrib.admin.options.ModelAdmin

        +

        Sets up the admin manaager for help entries

        +
        +
        +inlines = [<class 'evennia.web.admin.help.HelpTagInline'>]
        +
        + +
        +
        +list_display = ('id', 'db_key', 'db_help_category', 'db_lock_storage', 'db_date_created')
        +
        + +
        + +
        + +
        +
        +search_fields = ['^db_key', 'db_entrytext']
        +
        + +
        +
        +ordering = ['db_help_category', 'db_key']
        +
        + +
        +
        +list_filter = ['db_help_category']
        +
        + +
        +
        +save_as = True
        +
        + +
        +
        +save_on_top = True
        +
        + +
        + +
        + +
        +
        +view_on_site = False
        +
        + +
        +
        +form
        +

        alias of HelpEntryForm

        +
        + +
        +
        +fieldsets = ((None, {'fields': (('db_key', 'db_help_category'), 'db_entrytext', 'db_lock_storage')}),)
        +
        + +
        +
        +property media
        +
        + +
        +
        @@ -84,7 +221,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +237,7 @@ +
        develop branch
        @@ -39,6 +40,7 @@

        evennia.web.admin

        +

        Django-admin code for customizing the web admin for Evennia.

        @@ -116,6 +117,7 @@ +
        develop branch
        @@ -37,8 +38,312 @@
        -
        -

        evennia.web.admin.objects

        +
        +

        evennia.web.admin.objects

        +
        +
        +class evennia.web.admin.objects.ObjectAttributeInline(parent_model, admin_site)[source]
        +

        Bases: evennia.web.admin.attributes.AttributeInline

        +

        Defines inline descriptions of Attributes (experimental)

        +
        +
        +model
        +

        alias of evennia.objects.models.ObjectDB_db_attributes

        +
        + +
        +
        +related_field = 'objectdb'
        +
        + +
        +
        +property media
        +
        + +
        + +
        +
        +class evennia.web.admin.objects.ObjectTagInline(parent_model, admin_site)[source]
        +

        Bases: evennia.web.admin.tags.TagInline

        +

        Defines inline descriptions of Tags (experimental)

        +
        +
        +model
        +

        alias of evennia.objects.models.ObjectDB_db_tags

        +
        + +
        +
        +related_field = 'objectdb'
        +
        + +
        +
        +property media
        +
        + +
        + +
        +
        +class evennia.web.admin.objects.ObjectCreateForm(*args, **kwargs)[source]
        +

        Bases: django.forms.models.ModelForm

        +

        This form details the look of the fields.

        +
        +
        +class Meta[source]
        +

        Bases: object

        +
        +
        +model
        +

        alias of evennia.objects.models.ObjectDB

        +
        + +
        +
        +fields = '__all__'
        +
        + +
        + +
        +
        +__init__(*args, **kwargs)[source]
        +

        Tweak some fields dynamically.

        +
        + +
        +
        +base_fields = {'db_account': <django.forms.models.ModelChoiceField object>, 'db_attributes': <django.forms.models.ModelMultipleChoiceField object>, 'db_cmdset_storage': <django.forms.fields.CharField object>, 'db_destination': <django.forms.models.ModelChoiceField object>, 'db_home': <django.forms.models.ModelChoiceField object>, 'db_key': <django.forms.fields.CharField object>, 'db_location': <django.forms.models.ModelChoiceField object>, 'db_lock_storage': <django.forms.fields.CharField object>, 'db_sessid': <django.forms.fields.CharField object>, 'db_tags': <django.forms.models.ModelMultipleChoiceField object>, 'db_typeclass_path': <django.forms.fields.ChoiceField object>}
        +
        + +
        +
        +declared_fields = {'db_cmdset_storage': <django.forms.fields.CharField object>, 'db_destination': <django.forms.models.ModelChoiceField object>, 'db_home': <django.forms.models.ModelChoiceField object>, 'db_key': <django.forms.fields.CharField object>, 'db_location': <django.forms.models.ModelChoiceField object>, 'db_lock_storage': <django.forms.fields.CharField object>, 'db_typeclass_path': <django.forms.fields.ChoiceField object>}
        +
        + +
        +
        +property media
        +

        Return all media required to render the widgets on this form.

        +
        + +
        + +
        +
        +class evennia.web.admin.objects.ObjectEditForm(*args, **kwargs)[source]
        +

        Bases: evennia.web.admin.objects.ObjectCreateForm

        +

        Form used for editing. Extends the create one with more fields

        +
        +
        +class Meta[source]
        +

        Bases: object

        +
        +
        +model
        +

        alias of evennia.objects.models.ObjectDB

        +
        + +
        +
        +fields = '__all__'
        +
        + +
        + +
        +
        +base_fields = {'db_account': <django.forms.models.ModelChoiceField object>, 'db_attributes': <django.forms.models.ModelMultipleChoiceField object>, 'db_cmdset_storage': <django.forms.fields.CharField object>, 'db_destination': <django.forms.models.ModelChoiceField object>, 'db_home': <django.forms.models.ModelChoiceField object>, 'db_key': <django.forms.fields.CharField object>, 'db_location': <django.forms.models.ModelChoiceField object>, 'db_lock_storage': <django.forms.fields.CharField object>, 'db_sessid': <django.forms.fields.CharField object>, 'db_tags': <django.forms.models.ModelMultipleChoiceField object>, 'db_typeclass_path': <django.forms.fields.ChoiceField object>}
        +
        + +
        +
        +declared_fields = {'db_account': <django.forms.models.ModelChoiceField object>, 'db_cmdset_storage': <django.forms.fields.CharField object>, 'db_destination': <django.forms.models.ModelChoiceField object>, 'db_home': <django.forms.models.ModelChoiceField object>, 'db_key': <django.forms.fields.CharField object>, 'db_location': <django.forms.models.ModelChoiceField object>, 'db_lock_storage': <django.forms.fields.CharField object>, 'db_typeclass_path': <django.forms.fields.ChoiceField object>}
        +
        + +
        +
        +property media
        +

        Return all media required to render the widgets on this form.

        +
        + +
        + +
        +
        +class evennia.web.admin.objects.ObjectAdmin(model, admin_site)[source]
        +

        Bases: django.contrib.admin.options.ModelAdmin

        +

        Describes the admin page for Objects.

        +
        +
        +inlines = [<class 'evennia.web.admin.objects.ObjectTagInline'>, <class 'evennia.web.admin.objects.ObjectAttributeInline'>]
        +
        + +
        +
        +list_display = ('id', 'db_key', 'db_typeclass_path', 'db_location', 'db_destination', 'db_account', 'db_date_created')
        +
        + +
        + +
        + +
        +
        +ordering = ['-db_date_created', '-id']
        +
        + +
        +
        +search_fields = ['=id', '^db_key', 'db_typeclass_path', '^db_account__db_key', '^db_location__db_key']
        +
        + +
        +
        +raw_id_fields = ('db_destination', 'db_location', 'db_home', 'db_account')
        +
        + +
        +
        +readonly_fields = ('serialized_string', 'link_button')
        +
        + +
        +
        +save_as = True
        +
        + +
        +
        +save_on_top = True
        +
        + +
        + +
        + +
        +
        +view_on_site = False
        +
        + +
        +
        +list_filter = ('db_typeclass_path',)
        +
        + +
        +
        +form
        +

        alias of ObjectEditForm

        +
        + +
        +
        +fieldsets = ((None, {'fields': (('db_key', 'db_typeclass_path'), ('db_location', 'db_home', 'db_destination'), ('db_account', 'link_button'), 'db_cmdset_storage', 'db_lock_storage', 'serialized_string')}),)
        +
        + +
        +
        +add_form
        +

        alias of ObjectCreateForm

        +
        + +
        +
        +add_fieldsets = ((None, {'fields': (('db_key', 'db_typeclass_path'), ('db_location', 'db_home', 'db_destination'), 'db_cmdset_storage')}),)
        +
        + +
        +
        +serialized_string(obj)[source]
        +

        Get the serialized version of the object.

        +
        + +
        +
        +get_fieldsets(request, obj=None)[source]
        +

        Return fieldsets.

        +
        +
        Parameters
        +
          +
        • request (Request) – Incoming request.

        • +
        • obj (Object, optional) – Database object.

        • +
        +
        +
        +
        + +
        +
        +get_form(request, obj=None, **kwargs)[source]
        +

        Use special form during creation.

        +
        +
        Parameters
        +
          +
        • request (Request) – Incoming request.

        • +
        • obj (Object, optional) – Database object.

        • +
        +
        +
        +
        + +
        +
        +get_urls()[source]
        +
        + +
        + +
        + +
        + +

        Link object and account when pressing the button.

        +

        This will:

        +
          +
        • Set account.db._last_puppet to this object

        • +
        • Add object to account.db._playable_characters

        • +
        • Change object locks to allow puppeting by account

        • +
        +
        + +
        +
        +save_model(request, obj, form, change)[source]
        +

        Model-save hook.

        +
        +
        Parameters
        +
          +
        • request (Request) – Incoming request.

        • +
        • obj (Object) – Database object.

        • +
        • form (Form) – Form instance.

        • +
        • change (bool) – If this is a change or a new object.

        • +
        +
        +
        +
        + +
        +
        +property media
        +
        + +
        +
        +response_add(request, obj, post_url_continue=None)[source]
        +

        Determine the HttpResponse for the add_view stage.

        +
        + +
        +
        @@ -84,7 +389,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +405,7 @@ +
        develop branch
        @@ -37,8 +38,194 @@
        -
        -

        evennia.web.admin.scripts

        +
        +

        evennia.web.admin.scripts

        +
        +
        +class evennia.web.admin.scripts.ScriptForm(data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=<class 'django.forms.utils.ErrorList'>, label_suffix=None, empty_permitted=False, instance=None, use_required_attribute=None, renderer=None)[source]
        +

        Bases: django.forms.models.ModelForm

        +
        +
        +base_fields = {'db_interval': <django.forms.fields.IntegerField object>, 'db_key': <django.forms.fields.CharField object>, 'db_lock_storage': <django.forms.fields.CharField object>, 'db_persistent': <django.forms.fields.BooleanField object>, 'db_repeats': <django.forms.fields.IntegerField object>, 'db_start_delay': <django.forms.fields.BooleanField object>, 'db_typeclass_path': <django.forms.fields.ChoiceField object>}
        +
        + +
        +
        +declared_fields = {'db_interval': <django.forms.fields.IntegerField object>, 'db_key': <django.forms.fields.CharField object>, 'db_lock_storage': <django.forms.fields.CharField object>, 'db_persistent': <django.forms.fields.BooleanField object>, 'db_repeats': <django.forms.fields.IntegerField object>, 'db_start_delay': <django.forms.fields.BooleanField object>, 'db_typeclass_path': <django.forms.fields.ChoiceField object>}
        +
        + +
        +
        +property media
        +

        Return all media required to render the widgets on this form.

        +
        + +
        + +
        +
        +class evennia.web.admin.scripts.ScriptTagInline(parent_model, admin_site)[source]
        +

        Bases: evennia.web.admin.tags.TagInline

        +

        Inline script tags.

        +
        +
        +model
        +

        alias of evennia.scripts.models.ScriptDB_db_tags

        +
        + +
        +
        +form
        +

        alias of ScriptForm

        +
        + +
        +
        +related_field = 'scriptdb'
        +
        + +
        +
        +property media
        +
        + +
        + +
        +
        +class evennia.web.admin.scripts.ScriptAttributeInline(parent_model, admin_site)[source]
        +

        Bases: evennia.web.admin.attributes.AttributeInline

        +

        Inline attribute tags.

        +
        +
        +model
        +

        alias of evennia.scripts.models.ScriptDB_db_attributes

        +
        + +
        +
        +form
        +

        alias of ScriptForm

        +
        + +
        +
        +related_field = 'scriptdb'
        +
        + +
        +
        +property media
        +
        + +
        + +
        +
        +class evennia.web.admin.scripts.ScriptAdmin(model, admin_site)[source]
        +

        Bases: django.contrib.admin.options.ModelAdmin

        +

        Displaying the main Script page.

        +
        +
        +list_display = ('id', 'db_key', 'db_typeclass_path', 'db_obj', 'db_interval', 'db_repeats', 'db_persistent', 'db_date_created')
        +
        + +
        + +
        + +
        +
        +ordering = ['-db_date_created', '-id']
        +
        + +
        +
        +search_fields = ['=id', '^db_key', 'db_typeclass_path']
        +
        + +
        +
        +readonly_fields = ['serialized_string']
        +
        + +
        +
        +form
        +

        alias of ScriptForm

        +
        + +
        +
        +save_as = True
        +
        + +
        +
        +save_on_top = True
        +
        + +
        + +
        + +
        +
        +view_on_site = False
        +
        + +
        +
        +raw_id_fields = ('db_obj',)
        +
        + +
        +
        +fieldsets = ((None, {'fields': (('db_key', 'db_typeclass_path'), ('db_interval', 'db_repeats', 'db_start_delay', 'db_persistent'), 'db_obj', 'db_lock_storage', 'serialized_string')}),)
        +
        + +
        +
        +inlines = [<class 'evennia.web.admin.scripts.ScriptTagInline'>, <class 'evennia.web.admin.scripts.ScriptAttributeInline'>]
        +
        + +
        +
        +serialized_string(obj)[source]
        +

        Get the serialized version of the object.

        +
        + +
        +
        +get_form(request, obj=None, **kwargs)[source]
        +

        Overrides help texts.

        +
        + +
        +
        +save_model(request, obj, form, change)[source]
        +

        Model-save hook.

        +
        +
        Parameters
        +
          +
        • request (Request) – Incoming request.

        • +
        • obj (Object) – Database object.

        • +
        • form (Form) – Form instance.

        • +
        • change (bool) – If this is a change or a new object.

        • +
        +
        +
        +
        + +
        +
        +property media
        +
        + +
        +
        @@ -84,7 +271,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +287,7 @@ +
        develop branch
        @@ -37,8 +38,57 @@
        -
        -

        evennia.web.admin.server

        +
        +

        evennia.web.admin.server

        +

        This sets up how models are displayed +in the web admin interface.

        +
        +
        +class evennia.web.admin.server.ServerConfigAdmin(model, admin_site)[source]
        +

        Bases: django.contrib.admin.options.ModelAdmin

        +

        Custom admin for server configs

        +
        +
        +list_display = ('db_key', 'db_value')
        +
        + +
        + +
        + +
        +
        +ordering = ['db_key', 'db_value']
        +
        + +
        +
        +search_fields = ['db_key']
        +
        + +
        +
        +save_as = True
        +
        + +
        +
        +save_on_top = True
        +
        + +
        + +
        + +
        +
        +property media
        +
        + +
        +
        @@ -84,7 +134,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +150,7 @@ +
        develop branch
        @@ -37,8 +38,236 @@
        -
        -

        evennia.web.admin.tags

        +
        +

        evennia.web.admin.tags

        +

        Tag admin

        +
        +
        +class evennia.web.admin.tags.TagForm(data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=<class 'django.forms.utils.ErrorList'>, label_suffix=None, empty_permitted=False, instance=None, use_required_attribute=None, renderer=None)[source]
        +

        Bases: django.forms.models.ModelForm

        +

        Form to display fields in the stand-alone Tag display.

        +
        +
        +class Meta[source]
        +

        Bases: object

        +
        +
        +fields = ('tag_key', 'tag_category', 'tag_data', 'tag_type')
        +
        + +
        + +
        +
        +base_fields = {'db_category': <django.forms.fields.CharField object>, 'db_data': <django.forms.fields.CharField object>, 'db_key': <django.forms.fields.CharField object>, 'db_model': <django.forms.fields.ChoiceField object>, 'db_tagtype': <django.forms.fields.ChoiceField object>}
        +
        + +
        +
        +declared_fields = {'db_category': <django.forms.fields.CharField object>, 'db_data': <django.forms.fields.CharField object>, 'db_key': <django.forms.fields.CharField object>, 'db_model': <django.forms.fields.ChoiceField object>, 'db_tagtype': <django.forms.fields.ChoiceField object>}
        +
        + +
        +
        +property media
        +

        Return all media required to render the widgets on this form.

        +
        + +
        + +
        +
        +class evennia.web.admin.tags.InlineTagForm(*args, **kwargs)[source]
        +

        Bases: django.forms.models.ModelForm

        +

        Form for displaying tags inline together with other entities.

        +

        This form overrides the base behavior of the ModelForm that would be used for a +Tag-through-model. Since the through-models only have access to the foreignkeys of the Tag and +the Object that they’re attached to, we need to spoof the behavior of it being a form that would +correspond to its tag, or the creation of a tag. Instead of being saved, we’ll call to the +Object’s handler, which will handle the creation, change, or deletion of a tag for us, as well +as updating the handler’s cache so that all changes are instantly updated in-game.

        +
        +
        +class Meta[source]
        +

        Bases: object

        +
        +
        +fields = ('tag_key', 'tag_category', 'tag_data', 'tag_type')
        +
        + +
        + +
        +
        +__init__(*args, **kwargs)[source]
        +

        If we have a tag, then we’ll prepopulate our instance with the fields we’d expect it +to have based on the tag. tag_key, tag_category, tag_type, and tag_data all refer to +the corresponding tag fields. The initial data of the form fields will similarly be +populated.

        +
        + +
        +
        +save(commit=True)[source]
        +

        One thing we want to do here is the or None checks, because forms are saved with an empty +string rather than null from forms, usually, and the Handlers may handle empty strings +differently than None objects. So for consistency with how things are handled in game, +we’ll try to make sure that empty form fields will be None, rather than ‘’.

        +
        + +
        +
        +base_fields = {'tag_category': <django.forms.fields.CharField object>, 'tag_data': <django.forms.fields.CharField object>, 'tag_key': <django.forms.fields.CharField object>, 'tag_type': <django.forms.fields.ChoiceField object>}
        +
        + +
        +
        +declared_fields = {'tag_category': <django.forms.fields.CharField object>, 'tag_data': <django.forms.fields.CharField object>, 'tag_key': <django.forms.fields.CharField object>, 'tag_type': <django.forms.fields.ChoiceField object>}
        +
        + +
        +
        +property media
        +

        Return all media required to render the widgets on this form.

        +
        + +
        + +
        +
        +class evennia.web.admin.tags.TagFormSet(data=None, files=None, instance=None, save_as_new=False, prefix=None, queryset=None, **kwargs)[source]
        +

        Bases: django.forms.models.BaseInlineFormSet

        +

        The Formset handles all the inline forms that are grouped together on the change page of the +corresponding object. All the tags will appear here, and we’ll save them by overriding the +formset’s save method. The forms will similarly spoof their save methods to return an instance +which hasn’t been saved to the database, but have the relevant fields filled out based on the +contents of the cleaned form. We’ll then use that to call to the handler of the corresponding +Object, where the handler is an AliasHandler, PermissionsHandler, or TagHandler, based on the +type of tag.

        +
        +
        +verbose_name = 'Tag'
        +
        + +
        +
        +verbose_name_plural = 'Tags'
        +
        + +
        +
        +save(commit=True)[source]
        +

        Save model instances for every form, adding and changing instances +as necessary, and return the list of instances.

        +
        + +
        + +
        +
        +class evennia.web.admin.tags.TagInline(parent_model, admin_site)[source]
        +

        Bases: django.contrib.admin.options.TabularInline

        +

        A handler for inline Tags. This class should be subclassed in the admin of your models, +and the ‘model’ and ‘related_field’ class attributes must be set. model should be the +through model (ObjectDB_db_tag’, for example), while related field should be the name +of the field on that through model which points to the model being used: ‘objectdb’, +‘msg’, ‘accountdb’, etc.

        +
        +
        +model = None
        +
        + +
        +
        +verbose_name = 'Tag'
        +
        + +
        +
        +verbose_name_plural = 'Tags'
        +
        + +
        +
        +form
        +

        alias of InlineTagForm

        +
        + +
        +
        +formset
        +

        alias of TagFormSet

        +
        + +
        +
        +related_field = None
        +
        + +
        +
        +extra = 0
        +
        + +
        +
        +get_formset(request, obj=None, **kwargs)[source]
        +

        get_formset has to return a class, but we need to make the class that we return +know about the related_field that we’ll use. Returning the class itself rather than +a proxy isn’t threadsafe, since it’d be the base class and would change if multiple +people used the admin at the same time

        +
        + +
        +
        +property media
        +
        + +
        + +
        +
        +class evennia.web.admin.tags.TagAdmin(model, admin_site)[source]
        +

        Bases: django.contrib.admin.options.ModelAdmin

        +

        A django Admin wrapper for Tags.

        +
        +
        +search_fields = ('db_key', 'db_category', 'db_tagtype')
        +
        + +
        +
        +list_display = ('db_key', 'db_category', 'db_tagtype', 'db_model', 'db_data')
        +
        + +
        +
        +list_filter = ('db_tagtype', 'db_category', 'db_model')
        +
        + +
        +
        +form
        +

        alias of TagForm

        +
        + +
        +
        +view_on_site = False
        +
        + +
        +
        +fieldsets = ((None, {'fields': (('db_key', 'db_category'), ('db_tagtype', 'db_model'), 'db_data')}),)
        +
        + +
        +
        +property media
        +
        + +
        +
        @@ -84,7 +313,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +329,7 @@ +
        develop branch
        @@ -37,8 +38,10 @@
        -
        -

        evennia.web.admin.urls

        +
        +

        evennia.web.admin.urls

        +

        Rerouting admin frontpage to evennia version.

        +

        These patterns are all under the admin/* namespace.

        @@ -84,7 +87,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +103,7 @@ +
        develop branch
        @@ -37,8 +38,49 @@
        -
        -

        evennia.web.admin.utils

        +
        +

        evennia.web.admin.utils

        +

        Helper utils for admin views.

        +
        +
        +evennia.web.admin.utils.get_and_load_typeclasses(parent=None, excluded_parents=None)[source]
        +

        Get all typeclasses. We we need to initialize things here +for them to be actually available in the admin process. +This is intended to be used with forms.ChoiceField.

        +
        +
        Parameters
        +
          +
        • parent (str or class, optional) – Limit selection to this class and its children +(at any distance).

        • +
        • exclude (list) – Class-parents to exclude from the resulting list. All +children of these paretns will be skipped.

        • +
        +
        +
        Returns
        +

        list – A list of (str, str), the way ChoiceField wants it.

        +
        +
        +
        + +
        +
        +evennia.web.admin.utils.get_and_load_cmdsets(parent=None, excluded_parents=None)[source]
        +

        Get all cmdsets available or as children based on a parent cmdset. We need +to initialize things here to make sure as much as possible is loaded in the +admin process. This is intended to be used with forms.ChoiceField.

        +
        +
        Parameters
        +
          +
        • parent (str, optional) – Python-path to the parent cmdset, if any.

        • +
        • excluded_parents (list) – A list of cmset-paths to exclude from the result.

        • +
        +
        +
        Returns
        +

        list – A list of (str, str), the way ChoiceField wants it.

        +
        +
        +
        +
        @@ -84,7 +126,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +142,7 @@ +
        develop branch
        @@ -37,8 +38,219 @@
        -
        -

        evennia.web.api.filters

        +
        +

        evennia.web.api.filters

        +

        FilterSets allow clients to specify querystrings that will determine the data +that is retrieved in GET requests. By default, Django Rest Framework uses the +‘django-filter’ package as its backend. Django-filter also has a section in its +documentation specifically regarding DRF integration.

        +

        https://django-filter.readthedocs.io/en/latest/guide/rest_framework.html

        +
        +
        +evennia.web.api.filters.get_tag_query(tag_type: Optional[str], key: str) → django.db.models.query_utils.Q[source]
        +

        Returns a Q object for searching by tag names for typeclasses +:param tag_type: The type of tag (None, ‘alias’, etc) +:type tag_type: str or None +:param key: The name of the tag +:type key: str

        +
        +
        Returns
        +

        A Q object that for searching by this tag type and name

        +
        +
        +
        + +
        +
        +class evennia.web.api.filters.TagTypeFilter(field_name=None, lookup_expr=None, *, label=None, method=None, distinct=False, exclude=False, **kwargs)[source]
        +

        Bases: django_filters.filters.CharFilter

        +

        This class lets you create different filters for tags of a specified db_tagtype.

        +
        +
        +tag_type = None
        +
        + +
        +
        +filter(qs, value)[source]
        +
        + +
        + +
        +
        +class evennia.web.api.filters.AliasFilter(field_name=None, lookup_expr=None, *, label=None, method=None, distinct=False, exclude=False, **kwargs)[source]
        +

        Bases: evennia.web.api.filters.TagTypeFilter

        +

        A filter for objects by their aliases (tags with a tagtype of ‘alias’

        +
        +
        +tag_type = 'alias'
        +
        + +
        + +
        +
        +class evennia.web.api.filters.PermissionFilter(field_name=None, lookup_expr=None, *, label=None, method=None, distinct=False, exclude=False, **kwargs)[source]
        +

        Bases: evennia.web.api.filters.TagTypeFilter

        +

        A filter for objects by their permissions (tags with a tagtype of ‘permission’

        +
        +
        +tag_type = 'permission'
        +
        + +
        + +
        +
        +class evennia.web.api.filters.BaseTypeclassFilterSet(data=None, queryset=None, *, request=None, prefix=None)[source]
        +

        Bases: django_filters.rest_framework.filterset.FilterSet

        +

        A parent class with filters for aliases and permissions

        +
        +
        +static filter_name(queryset, name, value)[source]
        +

        Filters a queryset by aliases or the key of the typeclass +:param queryset: The queryset being filtered +:param name: The name of the field +:param value: The value passed in from GET params

        +
        +
        Returns
        +

        The filtered queryset

        +
        +
        +
        + +
        +
        +base_filters = {'alias': <evennia.web.api.filters.AliasFilter object>, 'name': <django_filters.filters.CharFilter object>, 'permission': <evennia.web.api.filters.PermissionFilter object>}
        +
        + +
        +
        +declared_filters = {'alias': <evennia.web.api.filters.AliasFilter object>, 'name': <django_filters.filters.CharFilter object>, 'permission': <evennia.web.api.filters.PermissionFilter object>}
        +
        + +
        + +
        +
        +class evennia.web.api.filters.ObjectDBFilterSet(data=None, queryset=None, *, request=None, prefix=None)[source]
        +

        Bases: evennia.web.api.filters.BaseTypeclassFilterSet

        +

        This adds filters for ObjectDB instances - characters, rooms, exits, etc

        +
        +
        +class Meta[source]
        +

        Bases: object

        +
        +
        +model
        +

        alias of evennia.objects.models.ObjectDB

        +
        + +
        +
        +fields = ['db_key', 'db_typeclass_path', 'db_tags__db_key', 'db_tags__db_category', 'db_location__db_key', 'db_home__db_key', 'db_location__id', 'db_home__id']
        +
        + +
        + +
        +
        +base_filters = {'alias': <evennia.web.api.filters.AliasFilter object>, 'db_home__db_key': <django_filters.filters.CharFilter object>, 'db_home__id': <django_filters.filters.NumberFilter object>, 'db_key': <django_filters.filters.CharFilter object>, 'db_location__db_key': <django_filters.filters.CharFilter object>, 'db_location__id': <django_filters.filters.NumberFilter object>, 'db_tags__db_category': <django_filters.filters.CharFilter object>, 'db_tags__db_key': <django_filters.filters.CharFilter object>, 'db_typeclass_path': <django_filters.filters.CharFilter object>, 'name': <django_filters.filters.CharFilter object>, 'permission': <evennia.web.api.filters.PermissionFilter object>}
        +
        + +
        +
        +declared_filters = {'alias': <evennia.web.api.filters.AliasFilter object>, 'name': <django_filters.filters.CharFilter object>, 'permission': <evennia.web.api.filters.PermissionFilter object>}
        +
        + +
        + +
        +
        +class evennia.web.api.filters.AccountDBFilterSet(data=None, queryset=None, *, request=None, prefix=None)[source]
        +

        Bases: evennia.web.api.filters.BaseTypeclassFilterSet

        +

        This adds filters for Account objects

        +
        +
        +class Meta[source]
        +

        Bases: object

        +
        +
        +model
        +

        alias of evennia.accounts.models.AccountDB

        +
        + +
        +
        +fields = ['db_typeclass_path', 'db_tags__db_key', 'db_tags__db_category', 'username', 'db_is_connected', 'db_is_bot']
        +
        + +
        + +
        +
        +base_filters = {'alias': <evennia.web.api.filters.AliasFilter object>, 'db_is_bot': <django_filters.rest_framework.filters.BooleanFilter object>, 'db_is_connected': <django_filters.rest_framework.filters.BooleanFilter object>, 'db_tags__db_category': <django_filters.filters.CharFilter object>, 'db_tags__db_key': <django_filters.filters.CharFilter object>, 'db_typeclass_path': <django_filters.filters.CharFilter object>, 'name': <django_filters.filters.CharFilter object>, 'permission': <evennia.web.api.filters.PermissionFilter object>, 'username': <django_filters.filters.CharFilter object>}
        +
        + +
        +
        +declared_filters = {'alias': <evennia.web.api.filters.AliasFilter object>, 'name': <django_filters.filters.CharFilter object>, 'permission': <evennia.web.api.filters.PermissionFilter object>}
        +
        + +
        + +
        +
        +class evennia.web.api.filters.ScriptDBFilterSet(data=None, queryset=None, *, request=None, prefix=None)[source]
        +

        Bases: evennia.web.api.filters.BaseTypeclassFilterSet

        +

        This adds filters for Script objects

        +
        +
        +class Meta[source]
        +

        Bases: object

        +
        +
        +model
        +

        alias of evennia.scripts.models.ScriptDB

        +
        + +
        +
        +fields = ['db_key', 'db_typeclass_path', 'db_tags__db_key', 'db_tags__db_category', 'db_desc', 'db_obj__db_key', 'db_obj__id', 'db_account__id', 'db_account__username', 'db_is_active', 'db_persistent', 'db_interval']
        +
        + +
        + +
        +
        +base_filters = {'alias': <evennia.web.api.filters.AliasFilter object>, 'db_account__id': <django_filters.filters.NumberFilter object>, 'db_account__username': <django_filters.filters.CharFilter object>, 'db_desc': <django_filters.filters.CharFilter object>, 'db_interval': <django_filters.filters.NumberFilter object>, 'db_is_active': <django_filters.rest_framework.filters.BooleanFilter object>, 'db_key': <django_filters.filters.CharFilter object>, 'db_obj__db_key': <django_filters.filters.CharFilter object>, 'db_obj__id': <django_filters.filters.NumberFilter object>, 'db_persistent': <django_filters.rest_framework.filters.BooleanFilter object>, 'db_tags__db_category': <django_filters.filters.CharFilter object>, 'db_tags__db_key': <django_filters.filters.CharFilter object>, 'db_typeclass_path': <django_filters.filters.CharFilter object>, 'name': <django_filters.filters.CharFilter object>, 'permission': <evennia.web.api.filters.PermissionFilter object>}
        +
        + +
        +
        +declared_filters = {'alias': <evennia.web.api.filters.AliasFilter object>, 'name': <django_filters.filters.CharFilter object>, 'permission': <evennia.web.api.filters.PermissionFilter object>}
        +
        + +
        + +
        +
        +class evennia.web.api.filters.HelpFilterSet(data=None, queryset=None, *, request=None, prefix=None)[source]
        +

        Bases: django_filters.rest_framework.filterset.FilterSet

        +

        Filter for help entries

        +
        +
        +base_filters = {'alias': <evennia.web.api.filters.AliasFilter object>, 'category': <django_filters.filters.CharFilter object>, 'name': <django_filters.filters.CharFilter object>}
        +
        + +
        +
        +declared_filters = {'alias': <evennia.web.api.filters.AliasFilter object>, 'category': <django_filters.filters.CharFilter object>, 'name': <django_filters.filters.CharFilter object>}
        +
        + +
        +
        @@ -84,7 +296,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +312,7 @@ +
        develop branch
        @@ -95,7 +96,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -112,6 +112,7 @@ +
        develop branch
        @@ -37,8 +38,104 @@
        -
        -

        evennia.web.api.permissions

        +
        +

        evennia.web.api.permissions

        +

        Sets up an api-access permission check using the in-game permission hierarchy.

        +
        +
        +class evennia.web.api.permissions.EvenniaPermission[source]
        +

        Bases: rest_framework.permissions.BasePermission

        +

        A Django Rest Framework permission class that allows us to use Evennia’s +permission structure. Based on the action in a given view, we’ll check a +corresponding Evennia access/lock check.

        +
        +
        +MINIMUM_LIST_PERMISSION = 'builder'
        +
        + +
        +
        +MINIMUM_CREATE_PERMISSION = 'builder'
        +
        + +
        +
        +view_locks = ['examine']
        +
        + +
        +
        +destroy_locks = ['delete']
        +
        + +
        +
        +update_locks = ['control', 'edit']
        +
        + +
        +
        +has_permission(request, view)[source]
        +

        Checks for permissions

        +
        +
        Parameters
        +
          +
        • request (Request) – The incoming request object.

        • +
        • view (View) – The django view we are checking permission for.

        • +
        +
        +
        Returns
        +

        bool – If permission is granted or not. If we return False here, a PermissionDenied +error will be raised from the view.

        +
        +
        +

        Notes

        +

        This method is a check that always happens first. If there’s an object involved, +such as with retrieve, update, or delete, then the has_object_permission method +is called after this, assuming this returns True.

        +
        + +
        +
        +static check_locks(obj, user, locks)[source]
        +

        Checks access for user for object with given locks +:param obj: Object instance we’re checking +:param user: User who we’re checking permissions +:type user: Account +:param locks: list of lockstrings +:type locks: list

        +
        +
        Returns
        +

        bool – True if they have access, False if they don’t

        +
        +
        +
        + +
        +
        +has_object_permission(request, view, obj)[source]
        +

        Checks object-level permissions after has_permission

        +
        +
        Parameters
        +
          +
        • request (Request) – The incoming request object.

        • +
        • view (View) – The django view we are checking permission for.

        • +
        • obj – Object we’re checking object-level permissions for

        • +
        +
        +
        Returns
        +

        bool – If permission is granted or not. If we return False here, a PermissionDenied +error will be raised from the view.

        +
        +
        +

        Notes

        +

        This method assumes that has_permission has already returned True. We check +equivalent Evennia permissions in the request.user to determine if they can +complete the action.

        +
        + +
        +
        @@ -84,7 +181,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +197,7 @@ +
        develop branch
        @@ -37,8 +38,28 @@
        -
        -

        evennia.web.api.root

        +
        +

        evennia.web.api.root

        +

        Set a more useful description on the Api root.

        +
        +
        +class evennia.web.api.root.EvenniaAPIRoot(**kwargs)[source]
        +

        Bases: rest_framework.routers.APIRootView

        +

        Root of the Evennia API tree.

        +
        + +
        +
        +class evennia.web.api.root.APIRootRouter(*args, **kwargs)[source]
        +

        Bases: rest_framework.routers.DefaultRouter

        +
        +
        +APIRootView
        +

        alias of EvenniaAPIRoot

        +
        + +
        +
        @@ -84,7 +105,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +121,7 @@ +
        develop branch
        @@ -37,8 +38,458 @@
        -
        -

        evennia.web.api.serializers

        +
        +

        evennia.web.api.serializers

        +

        Serializers in the Django Rest Framework are similar to Forms in normal django. +They’re used for transmitting and validating data, both going to clients and +coming to the server. However, where forms often contained presentation logic, +such as specifying widgets to use for selection, serializers typically leave +those decisions in the hands of clients, and are more focused on converting +data from the server to JSON (serialization) for a response, and validating +and converting JSON data sent from clients to our enpoints into python objects, +often django model instances, that we can use (deserialization).

        +
        +
        +class evennia.web.api.serializers.AttributeSerializer(*args, **kwargs)[source]
        +

        Bases: rest_framework.serializers.ModelSerializer

        +

        Serialize Attribute views.

        +
        +
        +class Meta[source]
        +

        Bases: object

        +
        +
        +model
        +

        alias of evennia.typeclasses.attributes.Attribute

        +
        + +
        +
        +fields = ['db_key', 'db_category', 'db_attrtype', 'value_display', 'db_value']
        +
        + +
        + +
        +
        +static get_value_display(obj: evennia.typeclasses.attributes.Attribute) → str[source]
        +

        Gets the string display of an Attribute’s value for serialization +:param obj: Attribute being serialized

        +
        +
        Returns
        +

        The Attribute’s value in string format

        +
        +
        +
        + +
        + +
        +
        +class evennia.web.api.serializers.TagSerializer(*args, **kwargs)[source]
        +

        Bases: rest_framework.serializers.ModelSerializer

        +
        +
        +class Meta[source]
        +

        Bases: object

        +
        +
        +model
        +

        alias of evennia.typeclasses.tags.Tag

        +
        + +
        +
        +fields = ['db_key', 'db_category', 'db_data', 'db_tagtype']
        +
        + +
        + +
        + +
        +
        +class evennia.web.api.serializers.SimpleObjectDBSerializer(*args, **kwargs)[source]
        +

        Bases: rest_framework.serializers.ModelSerializer

        +
        +
        +class Meta[source]
        +

        Bases: object

        +
        +
        +model
        +

        alias of evennia.objects.objects.DefaultObject

        +
        + +
        +
        +fields = ['id', 'db_key']
        +
        + +
        + +
        + +
        +
        +class evennia.web.api.serializers.TypeclassSerializerMixin[source]
        +

        Bases: object

        +

        Mixin that contains types shared by typeclasses. A note about tags, +aliases, and permissions. You might note that the methods and fields are +defined here, but they’re included explicitly in each child class. What +gives? It’s a DRF error: serializer method fields which are inherited do +not resolve correctly in child classes, and as of this current version +(3.11) you must have them in the child classes explicitly to avoid field +errors. Similarly, the child classes must contain the attribute serializer +explicitly to not have them render PK-related fields.

        +
        +
        +shared_fields = ['id', 'db_key', 'attributes', 'db_typeclass_path', 'aliases', 'tags', 'permissions']
        +
        + +
        +
        +static get_tags(obj)[source]
        +

        Serializes tags from the object’s Tagshandler +:param obj: Typeclassed object being serialized

        +
        +
        Returns
        +

        List of TagSerializer data

        +
        +
        +
        + +
        +
        +static get_aliases(obj)[source]
        +

        Serializes tags from the object’s Aliashandler +:param obj: Typeclassed object being serialized

        +
        +
        Returns
        +

        List of TagSerializer data

        +
        +
        +
        + +
        +
        +static get_permissions(obj)[source]
        +

        Serializes tags from the object’s Permissionshandler +:param obj: Typeclassed object being serialized

        +
        +
        Returns
        +

        List of TagSerializer data

        +
        +
        +
        + +
        +
        +static get_attributes(obj)[source]
        +

        Serializes attributes from the object’s AttributeHandler +:param obj: Typeclassed object being serialized

        +
        +
        Returns
        +

        List of AttributeSerializer data

        +
        +
        +
        + +
        +
        +static get_nicks(obj)[source]
        +

        Serializes attributes from the object’s NicksHandler +:param obj: Typeclassed object being serialized

        +
        +
        Returns
        +

        List of AttributeSerializer data

        +
        +
        +
        + +
        + +
        +
        +class evennia.web.api.serializers.TypeclassListSerializerMixin[source]
        +

        Bases: object

        +

        Shortened serializer for list views.

        +
        +
        +shared_fields = ['id', 'db_key', 'db_typeclass_path']
        +
        + +
        + +
        +
        +class evennia.web.api.serializers.ObjectDBSerializer(*args, **kwargs)[source]
        +

        Bases: evennia.web.api.serializers.TypeclassSerializerMixin, rest_framework.serializers.ModelSerializer

        +

        Serializing Objects.

        +
        +
        +class Meta[source]
        +

        Bases: object

        +
        +
        +model
        +

        alias of evennia.objects.objects.DefaultObject

        +
        + +
        +
        +fields = ['db_location', 'db_home', 'contents', 'exits', 'nicks', 'id', 'db_key', 'attributes', 'db_typeclass_path', 'aliases', 'tags', 'permissions']
        +
        + +
        +
        +read_only_fields = ['id']
        +
        + +
        + +
        +
        +static get_exits(obj)[source]
        +

        Gets exits for the object +:param obj: Object being serialized

        +
        +
        Returns
        +

        List of data from SimpleObjectDBSerializer

        +
        +
        +
        + +
        +
        +static get_contents(obj)[source]
        +

        Gets non-exits for the object +:param obj: Object being serialized

        +
        +
        Returns
        +

        List of data from SimpleObjectDBSerializer

        +
        +
        +
        + +
        + +
        +
        +class evennia.web.api.serializers.ObjectListSerializer(*args, **kwargs)[source]
        +

        Bases: evennia.web.api.serializers.TypeclassListSerializerMixin, rest_framework.serializers.ModelSerializer

        +

        Shortened representation for listings.]

        +
        +
        +class Meta[source]
        +

        Bases: object

        +
        +
        +model
        +

        alias of evennia.objects.objects.DefaultObject

        +
        + +
        +
        +fields = ['db_location', 'db_home', 'id', 'db_key', 'db_typeclass_path']
        +
        + +
        +
        +read_only_fields = ['id']
        +
        + +
        + +
        + +
        +
        +class evennia.web.api.serializers.AccountSerializer(*args, **kwargs)[source]
        +

        Bases: evennia.web.api.serializers.TypeclassSerializerMixin, rest_framework.serializers.ModelSerializer

        +

        This uses the DefaultAccount object to have access to the sessions property

        +
        +
        +static get_session_ids(obj)[source]
        +

        Gets a list of session IDs connected to this Account +:param obj: Account we’re grabbing sessions from +:type obj: DefaultAccount

        +
        +
        Returns
        +

        List of session IDs

        +
        +
        +
        + +
        +
        +class Meta[source]
        +

        Bases: object

        +
        +
        +model
        +

        alias of evennia.accounts.accounts.DefaultAccount

        +
        + +
        +
        +fields = ['username', 'session_ids', 'nicks', 'id', 'db_key', 'attributes', 'db_typeclass_path', 'aliases', 'tags', 'permissions']
        +
        + +
        +
        +read_only_fields = ['id']
        +
        + +
        + +
        + +
        +
        +class evennia.web.api.serializers.AccountListSerializer(*args, **kwargs)[source]
        +

        Bases: evennia.web.api.serializers.TypeclassListSerializerMixin, rest_framework.serializers.ModelSerializer

        +

        A shortened form for listing.

        +
        +
        +class Meta[source]
        +

        Bases: object

        +
        +
        +model
        +

        alias of evennia.accounts.accounts.DefaultAccount

        +
        + +
        +
        +fields = ['username', 'id', 'db_typeclass_path']
        +
        + +
        +
        +read_only_fields = ['id']
        +
        + +
        + +
        + +
        +
        +class evennia.web.api.serializers.ScriptDBSerializer(*args, **kwargs)[source]
        +

        Bases: evennia.web.api.serializers.TypeclassSerializerMixin, rest_framework.serializers.ModelSerializer

        +

        Serializing Account.

        +
        +
        +class Meta[source]
        +

        Bases: object

        +
        +
        +model
        +

        alias of evennia.scripts.models.ScriptDB

        +
        + +
        +
        +fields = ['db_interval', 'db_persistent', 'db_start_delay', 'db_is_active', 'db_repeats', 'id', 'db_key', 'attributes', 'db_typeclass_path', 'aliases', 'tags', 'permissions']
        +
        + +
        +
        +read_only_fields = ['id']
        +
        + +
        + +
        + +
        +
        +class evennia.web.api.serializers.ScriptListSerializer(*args, **kwargs)[source]
        +

        Bases: evennia.web.api.serializers.TypeclassListSerializerMixin, rest_framework.serializers.ModelSerializer

        +

        Shortened form for listing.

        +
        +
        +class Meta[source]
        +

        Bases: object

        +
        +
        +model
        +

        alias of evennia.scripts.models.ScriptDB

        +
        + +
        +
        +fields = ['db_interval', 'db_persistent', 'db_start_delay', 'db_is_active', 'db_repeats', 'id', 'db_key', 'db_typeclass_path']
        +
        + +
        +
        +read_only_fields = ['id']
        +
        + +
        + +
        + +
        +
        +class evennia.web.api.serializers.HelpSerializer(*args, **kwargs)[source]
        +

        Bases: evennia.web.api.serializers.TypeclassSerializerMixin, rest_framework.serializers.ModelSerializer

        +

        Serializers Help entries (not a typeclass).

        +
        +
        +class Meta[source]
        +

        Bases: object

        +
        +
        +model
        +

        alias of evennia.help.models.HelpEntry

        +
        + +
        +
        +fields = ['id', 'db_key', 'db_help_category', 'db_entrytext', 'db_date_created', 'tags', 'aliases']
        +
        + +
        +
        +read_only_fields = ['id']
        +
        + +
        + +
        + +
        +
        +class evennia.web.api.serializers.HelpListSerializer(*args, **kwargs)[source]
        +

        Bases: evennia.web.api.serializers.TypeclassListSerializerMixin, rest_framework.serializers.ModelSerializer

        +

        Shortened form for listings.

        +
        +
        +class Meta[source]
        +

        Bases: object

        +
        +
        +model
        +

        alias of evennia.help.models.HelpEntry

        +
        + +
        +
        +fields = ['id', 'db_key', 'db_help_category', 'db_date_created']
        +
        + +
        +
        +read_only_fields = ['id']
        +
        + +
        + +
        +
        @@ -84,7 +535,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +551,7 @@ +
        develop branch
        @@ -37,8 +38,74 @@
        -
        -

        evennia.web.api.tests

        +
        +

        evennia.web.api.tests

        +

        Tests for the REST API.

        +
        +
        +class evennia.web.api.tests.TestEvenniaRESTApi(methodName='runTest')[source]
        +

        Bases: evennia.utils.test_resources.EvenniaTest

        +
        +
        +client_class
        +

        alias of rest_framework.test.APIClient

        +
        + +
        +
        +maxDiff = None
        +
        + +
        +
        +setUp()[source]
        +

        Sets up testing environment

        +
        + +
        +
        +tearDown()[source]
        +

        Hook method for deconstructing the test fixture after testing it.

        +
        + +
        +
        +get_view_details(action)[source]
        +

        Helper function for generating list of named tuples

        +
        + +
        +
        +test_retrieve()[source]
        +
        + +
        +
        +test_update()[source]
        +
        + +
        +
        +test_delete()[source]
        +
        + +
        +
        +test_list()[source]
        +
        + +
        +
        +test_create()[source]
        +
        + +
        +
        +test_set_attribute()[source]
        +
        + +
        +
        @@ -84,7 +151,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +167,7 @@ +
        develop branch
        @@ -37,8 +38,22 @@
        -
        -

        evennia.web.api.urls

        +
        +

        evennia.web.api.urls

        +

        The Django Rest Framework provides a way of generating urls for different +views that implement standard CRUD operations in a quick way, using ‘routers’ +and ‘viewsets’. A viewset implements standard CRUD actions and any custom actions +that you want, and then a router will automatically generate URLs based on the +actions that it detects for a viewset. For example, below we create a DefaultRouter. +We then register ObjectDBViewSet, a viewset for CRUD operations for ObjectDB +instances, to the ‘objects’ base endpoint. That will generate a number of URLs +like the following:

        +

        list objects: action: GET, url: /objects/, view name: object-list +create object: action: POST, url: /objects/, view name: object-list +retrieve object: action: GET, url: /objects/<:pk>, view name: object-detail +update object: action: POST, url: /objects/<:pk>, view name: object-detail +delete object: action: DELETE, url: /objects/<:pk>, view name: object-detail +set attribute: action: POST, url: /objects/<:pk>/set-attribute, view name: object-set-attribute

        @@ -84,7 +99,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +115,7 @@ +
        develop branch
        @@ -37,8 +38,409 @@
        -
        -

        evennia.web.api.views

        +
        +

        evennia.web.api.views

        +

        Views are the functions that are called by different url endpoints. The Django +Rest Framework provides collections called ‘ViewSets’, which can generate a +number of views for the common CRUD operations.

        +
        +
        +class evennia.web.api.views.GeneralViewSetMixin[source]
        +

        Bases: object

        +

        Mixin for both typeclass- and non-typeclass entities.

        +
        +
        +get_serializer_class()[source]
        +

        Allow different serializers for certain actions.

        +
        + +
        + +
        +
        +class evennia.web.api.views.TypeclassViewSetMixin[source]
        +

        Bases: evennia.web.api.views.GeneralViewSetMixin

        +

        This mixin adds some shared functionality to each viewset of a typeclass. They all use the same +permission classes and filter backend. You can override any of these in your own viewsets.

        +

        The set_atribute action is an example of a custom action added to a +viewset. Based on the name of the method, it will create a default url_name +(used for reversing) and url_path. The ‘pk’ argument is automatically +passed to this action because it has a url path of the format <object +type>/:pk/set-attribute. The get_object method is automatically set in the +expected viewset classes that will inherit this, using the pk that’s passed +along to retrieve the object.

        +
        +
        +permission_classes = [<class 'evennia.web.api.permissions.EvenniaPermission'>]
        +
        + +
        +
        +filter_backends = [<class 'django_filters.rest_framework.backends.DjangoFilterBackend'>]
        +
        + +
        +
        +set_attribute(request, pk=None)[source]
        +

        This action will set an attribute if the db_value is defined, or remove +it if no db_value is provided.

        +
        + +
        + +
        +
        +class evennia.web.api.views.ObjectDBViewSet(**kwargs)[source]
        +

        Bases: evennia.web.api.views.TypeclassViewSetMixin, rest_framework.viewsets.ModelViewSet

        +

        The Object is the parent for all in-game entities that have a location +(rooms, exits, characters etc).

        +
        +
        +serializer_class
        +

        alias of evennia.web.api.serializers.ObjectDBSerializer

        +
        + +
        +
        +queryset
        +
        + +
        +
        +filterset_class
        +

        alias of evennia.web.api.filters.ObjectDBFilterSet

        +
        + +
        +
        +list_serializer_class
        +

        alias of evennia.web.api.serializers.ObjectListSerializer

        +
        + +
        +
        +basename = None
        +
        + +
        +
        +description = None
        +
        + +
        +
        +detail = None
        +
        + +
        +
        +name = None
        +
        + +
        +
        +suffix = None
        +
        + +
        + +
        +
        +class evennia.web.api.views.CharacterViewSet(**kwargs)[source]
        +

        Bases: evennia.web.api.views.ObjectDBViewSet

        +

        Characters are a type of Object commonly used as player avatars in-game.

        +
        +
        +queryset
        +
        + +
        +
        +list_serializer_class
        +

        alias of evennia.web.api.serializers.ObjectListSerializer

        +
        + +
        +
        +basename = None
        +
        + +
        +
        +description = None
        +
        + +
        +
        +detail = None
        +
        + +
        +
        +name = None
        +
        + +
        +
        +suffix = None
        +
        + +
        + +
        +
        +class evennia.web.api.views.RoomViewSet(**kwargs)[source]
        +

        Bases: evennia.web.api.views.ObjectDBViewSet

        +

        Rooms indicate discrete locations in-game.

        +
        +
        +queryset
        +
        + +
        +
        +list_serializer_class
        +

        alias of evennia.web.api.serializers.ObjectListSerializer

        +
        + +
        +
        +basename = None
        +
        + +
        +
        +description = None
        +
        + +
        +
        +detail = None
        +
        + +
        +
        +name = None
        +
        + +
        +
        +suffix = None
        +
        + +
        + +
        +
        +class evennia.web.api.views.ExitViewSet(**kwargs)[source]
        +

        Bases: evennia.web.api.views.ObjectDBViewSet

        +

        Exits are objects with a destination and allows for traversing from one +location to another.

        +
        +
        +queryset
        +
        + +
        +
        +list_serializer_class
        +

        alias of evennia.web.api.serializers.ObjectListSerializer

        +
        + +
        +
        +basename = None
        +
        + +
        +
        +description = None
        +
        + +
        +
        +detail = None
        +
        + +
        +
        +name = None
        +
        + +
        +
        +suffix = None
        +
        + +
        + +
        +
        +class evennia.web.api.views.AccountDBViewSet(**kwargs)[source]
        +

        Bases: evennia.web.api.views.TypeclassViewSetMixin, rest_framework.viewsets.ModelViewSet

        +

        Accounts represent the players connected to the game

        +
        +
        +serializer_class
        +

        alias of evennia.web.api.serializers.AccountSerializer

        +
        + +
        +
        +queryset
        +
        + +
        +
        +filterset_class
        +

        alias of evennia.web.api.filters.AccountDBFilterSet

        +
        + +
        +
        +list_serializer_class
        +

        alias of evennia.web.api.serializers.AccountListSerializer

        +
        + +
        +
        +basename = None
        +
        + +
        +
        +description = None
        +
        + +
        +
        +detail = None
        +
        + +
        +
        +name = None
        +
        + +
        +
        +suffix = None
        +
        + +
        + +
        +
        +class evennia.web.api.views.ScriptDBViewSet(**kwargs)[source]
        +

        Bases: evennia.web.api.views.TypeclassViewSetMixin, rest_framework.viewsets.ModelViewSet

        +

        Scripts are meta-objects for storing system data, running timers etc. They +have no in-game existence.

        +
        +
        +serializer_class
        +

        alias of evennia.web.api.serializers.ScriptDBSerializer

        +
        + +
        +
        +queryset
        +
        + +
        +
        +filterset_class
        +

        alias of evennia.web.api.filters.ScriptDBFilterSet

        +
        + +
        +
        +list_serializer_class
        +

        alias of evennia.web.api.serializers.ScriptListSerializer

        +
        + +
        +
        +basename = None
        +
        + +
        +
        +description = None
        +
        + +
        +
        +detail = None
        +
        + +
        +
        +name = None
        +
        + +
        +
        +suffix = None
        +
        + +
        + +
        +
        +class evennia.web.api.views.HelpViewSet(**kwargs)[source]
        +

        Bases: evennia.web.api.views.GeneralViewSetMixin, rest_framework.viewsets.ModelViewSet

        +

        Database-stored help entries. +Note that command auto-help and file-based help entries are not accessible this way.

        +
        +
        +serializer_class
        +

        alias of evennia.web.api.serializers.HelpSerializer

        +
        + +
        +
        +queryset
        +
        + +
        +
        +filterset_class
        +

        alias of evennia.web.api.filters.HelpFilterSet

        +
        + +
        +
        +list_serializer_class
        +

        alias of evennia.web.api.serializers.HelpListSerializer

        +
        + +
        +
        +basename = None
        +
        + +
        +
        +description = None
        +
        + +
        +
        +detail = None
        +
        + +
        +
        +name = None
        +
        + +
        +
        +suffix = None
        +
        + +
        +
        @@ -84,7 +486,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +502,7 @@ +
        develop branch
        @@ -39,10 +40,8 @@

        evennia.web

        -

        This sub-package holds the web presence of Evennia, using normal -Django to relate the database contents to web pages. Also the basic -webclient and the website are defined in here (the webserver itself is -found under the server package).

        +

        This sub-package holds the web presence of Evennia, using normal Django to +relate the database contents to web pages.

        -
        @@ -172,6 +170,7 @@ found under the server package).

        +
        develop branch
        @@ -37,8 +38,13 @@
        -
        -

        evennia.web.templatetags.addclass

        +
        +

        evennia.web.templatetags.addclass

        +
        +
        +evennia.web.templatetags.addclass.addclass(field, given_class)[source]
        +
        +
        @@ -84,7 +90,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +106,7 @@ +
        develop branch
        @@ -89,7 +90,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -106,6 +106,7 @@ +
        develop branch
        @@ -39,6 +40,21 @@

        evennia.web.urls

        +

        File that determines what each URL points to. This uses Python regular expressions. +This is the starting point when a user enters an URL.

        +
          +
        1. The URL is matched with a regex, tying it to a given view. Note that this central url.py +file includes url.py from all the various web-components found in views/ so the search +space is much larger than what is shown here.

        2. +
        3. The view (a Python function or class is executed)

        4. +
        5. The view uses a template (a HTML file which may contain template markers for dynamically +modifying its contents; the locations of such templates are given by +settings.TEMPLATES[0][‘DIRS’]) and which may in turn may include static +assets (CSS, images etc).

        6. +
        7. The view ‘renders’ the template into a finished HTML page, replacing all +dynamic content as appropriate.

        8. +
        9. The HTML page is returned to the user.

        10. +
        @@ -84,7 +100,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +116,7 @@ +
        develop branch
        @@ -37,8 +38,50 @@
        -
        -

        evennia.web.utils.adminsite

        +
        +

        evennia.web.utils.adminsite

        +

        Custom Evennia admin-site, for better customization of the admin-site +as a whole.

        +

        This must be located outside of the admin/ folder because it must be imported +before any of the app-data (which in turn must be imported in the __init__.py +of that folder for Django to find them).

        +
        +
        +class evennia.web.utils.adminsite.EvenniaAdminApp(app_name, app_module)[source]
        +

        Bases: django.contrib.admin.apps.AdminConfig

        +

        This is imported in INSTALLED_APPS instead of django.contrib.admin.

        +
        +
        +default_site = 'evennia.web.utils.adminsite.EvenniaAdminSite'
        +
        + +
        + +
        +
        +class evennia.web.utils.adminsite.EvenniaAdminSite(name='admin')[source]
        +

        Bases: django.contrib.admin.sites.AdminSite

        +

        The main admin site root (replacing the default from Django). When doing +admin.register in the admin/ folder, this is what is being registered to.

        +
        +
        +site_header = 'Evennia web admin'
        +
        + +
        +
        +app_order = ['accounts', 'objects', 'scripts', 'comms', 'help', 'typeclasses', 'server', 'sites', 'flatpages', 'auth']
        +
        + +
        +
        +get_app_list(request)[source]
        +

        Return a sorted list of all the installed apps that have been +registered in this site.

        +
        + +
        +
        @@ -84,7 +127,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +143,7 @@ +
        develop branch
        @@ -110,7 +111,6 @@ an already authenticated account and bypass authentication.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -127,6 +127,7 @@ an already authenticated account and bypass authentication.

        +
        develop branch
        @@ -39,6 +40,10 @@

        evennia.web.utils.general_context

        +

        This file defines global variables that will always be available in a view +context without having to repeatedly include it.

        +

        For this to work, this file is included in the settings file, in the +TEMPLATES[“OPTIONS”][“context_processors”] list.

        evennia.web.utils.general_context.set_game_name_and_slogan()[source]
        @@ -60,8 +65,8 @@ to webclient settings.

        evennia.web.utils.general_context.general_context(request)[source]
        -

        Returns common Evennia-related context stuff, which -is automatically added to context of all views.

        +

        Returns common Evennia-related context stuff, which is automatically added +to context of all views.

        @@ -109,7 +114,6 @@ is automatically added to context of all views.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -126,6 +130,7 @@ is automatically added to context of all views.

        +
        develop branch
        @@ -93,7 +94,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -110,6 +110,7 @@ +
        develop branch
        @@ -102,7 +103,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -119,6 +119,7 @@ +
        develop branch
        @@ -110,7 +111,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -127,6 +127,7 @@ +
        develop branch
        @@ -90,7 +91,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -107,6 +107,7 @@ +
        develop branch
        @@ -39,8 +40,7 @@

        evennia.web.webclient.urls

        -

        This structures the (simple) structure of the -webpage ‘application’.

        +

        This structures the (simple) structure of the webpage ‘application’.

        @@ -86,7 +86,6 @@ webpage ‘application’.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -103,6 +102,7 @@ webpage ‘application’.

        +
        develop branch
        @@ -92,7 +93,6 @@ page and serve it eventual static content.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -109,6 +109,7 @@ page and serve it eventual static content.

        +
        develop branch
        @@ -322,7 +323,6 @@ wish to allow.

      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -339,6 +339,7 @@ wish to allow.

        +
        develop branch
        @@ -106,7 +107,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -123,6 +123,7 @@ +
        develop branch
        @@ -455,7 +456,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -472,6 +472,7 @@ +
        develop branch
        @@ -39,7 +40,7 @@

        evennia.web.website.urls

        -

        This structures the website.

        +

        This redirects to website sub-pages.

        @@ -85,7 +86,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -102,6 +102,7 @@ +
        develop branch
        @@ -37,8 +38,56 @@
        -
        -

        evennia.web.website.views.accounts

        +
        +

        evennia.web.website.views.accounts

        +

        Views for managing accounts.

        +
        +
        +class evennia.web.website.views.accounts.AccountMixin[source]
        +

        Bases: evennia.web.website.views.mixins.TypeclassMixin

        +

        This is used to grant abilities to classes it is added to.

        +

        Any view class with this in its inheritance list will be modified to work +with Account objects instead of generic Objects or otherwise.

        +
        +
        +model
        +

        alias of evennia.accounts.accounts.DefaultAccount

        +
        + +
        +
        +form_class
        +

        alias of evennia.web.website.forms.AccountForm

        +
        + +
        + +
        +
        +class evennia.web.website.views.accounts.AccountCreateView(**kwargs)[source]
        +

        Bases: evennia.web.website.views.accounts.AccountMixin, evennia.web.website.views.mixins.EvenniaCreateView

        +

        Account creation view.

        +
        +
        +template_name = 'website/registration/register.html'
        +
        + +
        +
        +success_url
        +
        + +
        +
        +form_valid(form)[source]
        +

        Django hook, modified for Evennia.

        +

        This hook is called after a valid form is submitted.

        +

        When an account creation form is submitted and the data is deemed valid, +proceeds with creating the Account object.

        +
        + +
        +
        @@ -84,7 +133,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +149,7 @@ +
        develop branch
        @@ -37,8 +38,131 @@
        -
        -

        evennia.web.website.views.channels

        +
        +

        evennia.web.website.views.channels

        +

        Views for managing channels.

        +
        +
        +class evennia.web.website.views.channels.ChannelMixin[source]
        +

        Bases: evennia.web.website.views.mixins.TypeclassMixin

        +

        This is a “mixin”, a modifier of sorts.

        +

        Any view class with this in its inheritance list will be modified to work +with HelpEntry objects instead of generic Objects or otherwise.

        +
        +
        +model
        +

        alias of evennia.comms.comms.DefaultChannel

        +
        + +
        +
        +page_title = 'Channels'
        +
        + +
        +
        +access_type = 'listen'
        +
        + +
        +
        +get_queryset()[source]
        +

        Django hook; here we want to return a list of only those Channels +and other documentation that the current user is allowed to see.

        +
        +
        Returns
        +

        queryset (QuerySet) – List of Channels available to the user.

        +
        +
        +
        + +
        + +
        +
        +class evennia.web.website.views.channels.ChannelListView(**kwargs)[source]
        +

        Bases: evennia.web.website.views.channels.ChannelMixin, django.views.generic.list.ListView

        +

        Returns a list of channels that can be viewed by a user, authenticated +or not.

        +
        +
        +paginate_by = 100
        +
        + +
        +
        +template_name = 'website/channel_list.html'
        +
        + +
        +
        +page_title = 'Channel Index'
        +
        + +
        + +
        + +
        +
        +get_context_data(**kwargs)[source]
        +

        Django hook; we override it to calculate the most popular channels.

        +
        +
        Returns
        +

        context (dict) – Django context object

        +
        +
        +
        + +
        + +
        +
        +class evennia.web.website.views.channels.ChannelDetailView(**kwargs)[source]
        +

        Bases: evennia.web.website.views.channels.ChannelMixin, evennia.web.website.views.objects.ObjectDetailView

        +

        Returns the log entries for a given channel.

        +
        +
        +template_name = 'website/channel_detail.html'
        +
        + +
        +
        +attributes = ['name']
        +
        + +
        +
        +max_num_lines = 10000
        +
        + +
        +
        +get_context_data(**kwargs)[source]
        +

        Django hook; before we can display the channel logs, we need to recall +the logfile and read its lines.

        +
        +
        Returns
        +

        context (dict) – Django context object

        +
        +
        +
        + +
        +
        +get_object(queryset=None)[source]
        +

        Override of Django hook that retrieves an object by slugified channel +name.

        +
        +
        Returns
        +

        channel (Channel) – Channel requested in the URL.

        +
        +
        +
        + +
        +
        @@ -84,7 +208,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +224,7 @@ +
        develop branch
        @@ -37,8 +38,222 @@
        -
        -

        evennia.web.website.views.characters

        +
        +

        evennia.web.website.views.characters

        +

        Views for manipulating Characters (children of Objects often used for +puppeting).

        +
        +
        +class evennia.web.website.views.characters.CharacterMixin[source]
        +

        Bases: evennia.web.website.views.mixins.TypeclassMixin

        +

        This is a “mixin”, a modifier of sorts.

        +

        Any view class with this in its inheritance list will be modified to work +with Character objects instead of generic Objects or otherwise.

        +
        +
        +model
        +

        alias of evennia.objects.objects.DefaultCharacter

        +
        + +
        +
        +form_class
        +

        alias of evennia.web.website.forms.CharacterForm

        +
        + +
        +
        +success_url
        +
        + +
        +
        +get_queryset()[source]
        +

        This method will override the Django get_queryset method to only +return a list of characters associated with the current authenticated +user.

        +
        +
        Returns
        +

        queryset (QuerySet) – Django queryset for use in the given view.

        +
        +
        +
        + +
        + +
        +
        +class evennia.web.website.views.characters.CharacterListView(**kwargs)[source]
        +

        Bases: django.contrib.auth.mixins.LoginRequiredMixin, evennia.web.website.views.characters.CharacterMixin, django.views.generic.list.ListView

        +

        This view provides a mechanism by which a logged-in player can view a list +of all other characters.

        +

        This view requires authentication by default as a nominal effort to prevent +human stalkers and automated bots/scrapers from harvesting data on your users.

        +
        +
        +template_name = 'website/character_list.html'
        +
        + +
        +
        +paginate_by = 100
        +
        + +
        +
        +page_title = 'Character List'
        +
        + +
        +
        +access_type = 'view'
        +
        + +
        +
        +get_queryset()[source]
        +

        This method will override the Django get_queryset method to return a +list of all characters (filtered/sorted) instead of just those limited +to the account.

        +
        +
        Returns
        +

        queryset (QuerySet) – Django queryset for use in the given view.

        +
        +
        +
        + +
        + +
        +
        +class evennia.web.website.views.characters.CharacterPuppetView(**kwargs)[source]
        +

        Bases: django.contrib.auth.mixins.LoginRequiredMixin, evennia.web.website.views.characters.CharacterMixin, django.views.generic.base.RedirectView, evennia.web.website.views.objects.ObjectDetailView

        +

        This view provides a mechanism by which a logged-in player can “puppet” one +of their characters within the context of the website.

        +

        It also ensures that any user attempting to puppet something is logged in, +and that their intended puppet is one that they own.

        +
        +
        +get_redirect_url(*args, **kwargs)[source]
        +

        Django hook.

        +

        This view returns the URL to which the user should be redirected after +a passed or failed puppet attempt.

        +
        +
        Returns
        +

        url (str) – Path to post-puppet destination.

        +
        +
        +
        + +
        + +
        +
        +class evennia.web.website.views.characters.CharacterManageView(**kwargs)[source]
        +

        Bases: django.contrib.auth.mixins.LoginRequiredMixin, evennia.web.website.views.characters.CharacterMixin, django.views.generic.list.ListView

        +

        This view provides a mechanism by which a logged-in player can browse, +edit, or delete their own characters.

        +
        +
        +paginate_by = 10
        +
        + +
        +
        +template_name = 'website/character_manage_list.html'
        +
        + +
        +
        +page_title = 'Manage Characters'
        +
        + +
        + +
        +
        +class evennia.web.website.views.characters.CharacterUpdateView(**kwargs)[source]
        +

        Bases: evennia.web.website.views.characters.CharacterMixin, evennia.web.website.views.objects.ObjectUpdateView

        +

        This view provides a mechanism by which a logged-in player (enforced by +ObjectUpdateView) can edit the attributes of a character they own.

        +
        +
        +form_class
        +

        alias of evennia.web.website.forms.CharacterUpdateForm

        +
        + +
        +
        +template_name = 'website/character_form.html'
        +
        + +
        + +
        +
        +class evennia.web.website.views.characters.CharacterDetailView(**kwargs)[source]
        +

        Bases: evennia.web.website.views.characters.CharacterMixin, evennia.web.website.views.objects.ObjectDetailView

        +

        This view provides a mechanism by which a user can view the attributes of +a character, owned by them or not.

        +
        +
        +template_name = 'website/object_detail.html'
        +
        + +
        +
        +attributes = ['name', 'desc']
        +
        + +
        +
        +access_type = 'view'
        +
        + +
        +
        +get_queryset()[source]
        +

        This method will override the Django get_queryset method to return a +list of all characters the user may access.

        +
        +
        Returns
        +

        queryset (QuerySet) – Django queryset for use in the given view.

        +
        +
        +
        + +
        + +
        +
        +class evennia.web.website.views.characters.CharacterDeleteView(**kwargs)[source]
        +

        Bases: evennia.web.website.views.characters.CharacterMixin, evennia.web.website.views.objects.ObjectDeleteView

        +

        This view provides a mechanism by which a logged-in player (enforced by +ObjectDeleteView) can delete a character they own.

        +
        + +
        +
        +class evennia.web.website.views.characters.CharacterCreateView(**kwargs)[source]
        +

        Bases: evennia.web.website.views.characters.CharacterMixin, evennia.web.website.views.objects.ObjectCreateView

        +

        This view provides a mechanism by which a logged-in player (enforced by +ObjectCreateView) can create a new character.

        +
        +
        +template_name = 'website/character_form.html'
        +
        + +
        +
        +form_valid(form)[source]
        +

        Django hook, modified for Evennia.

        +

        This hook is called after a valid form is submitted.

        +

        When an character creation form is submitted and the data is deemed valid, +proceeds with creating the Character object.

        +
        + +
        +
        @@ -84,7 +299,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +315,7 @@ +
        develop branch
        @@ -37,8 +38,16 @@
        -
        -

        evennia.web.website.views.errors

        +
        +

        evennia.web.website.views.errors

        +

        Error views.

        +
        +
        +evennia.web.website.views.errors.to_be_implemented(request)[source]
        +

        A notice letting the user know that this particular feature hasn’t been +implemented yet.

        +
        +
        @@ -84,7 +93,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +109,7 @@ +
        develop branch
        @@ -37,8 +38,100 @@
        -
        -

        evennia.web.website.views.help

        +
        +

        evennia.web.website.views.help

        +

        Views to manipulate help entries.

        +
        +
        +class evennia.web.website.views.help.HelpMixin[source]
        +

        Bases: evennia.web.website.views.mixins.TypeclassMixin

        +

        This is a “mixin”, a modifier of sorts.

        +

        Any view class with this in its inheritance list will be modified to work +with HelpEntry objects instead of generic Objects or otherwise.

        +
        +
        +model
        +

        alias of evennia.help.models.HelpEntry

        +
        + +
        +
        +page_title = 'Help'
        +
        + +
        +
        +get_queryset()[source]
        +

        Django hook; here we want to return a list of only those HelpEntries +and other documentation that the current user is allowed to see.

        +
        +
        Returns
        +

        queryset (QuerySet) – List of Help entries available to the user.

        +
        +
        +
        + +
        + +
        +
        +class evennia.web.website.views.help.HelpListView(**kwargs)[source]
        +

        Bases: evennia.web.website.views.help.HelpMixin, django.views.generic.list.ListView

        +

        Returns a list of help entries that can be viewed by a user, authenticated +or not.

        +
        +
        +paginate_by = 500
        +
        + +
        +
        +template_name = 'website/help_list.html'
        +
        + +
        +
        +page_title = 'Help Index'
        +
        + +
        + +
        +
        +class evennia.web.website.views.help.HelpDetailView(**kwargs)[source]
        +

        Bases: evennia.web.website.views.help.HelpMixin, evennia.web.website.views.mixins.EvenniaDetailView

        +

        Returns the detail page for a given help entry.

        +
        +
        +template_name = 'website/help_detail.html'
        +
        + +
        +
        +get_context_data(**kwargs)[source]
        +

        Adds navigational data to the template to let browsers go to the next +or previous entry in the help list.

        +
        +
        Returns
        +

        context (dict) – Django context object

        +
        +
        +
        + +
        +
        +get_object(queryset=None)[source]
        +

        Override of Django hook that retrieves an object by category and topic +instead of pk and slug.

        +
        +
        Returns
        +

        entry (HelpEntry) – HelpEntry requested in the URL.

        +
        +
        +
        + +
        +
        @@ -84,7 +177,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +193,7 @@ +
        develop branch
        @@ -39,793 +40,7 @@

        evennia.web.website.views

        -

        This file contains the generic, assorted views that don’t fall under one of the other applications. -Views are django’s way of processing e.g. html templates on the fly.

        -
        -
        -evennia.web.website.views.to_be_implemented(request)[source]
        -

        A notice letting the user know that this particular feature hasn’t been -implemented yet.

        -
        - -
        -
        -evennia.web.website.views.evennia_admin(request)[source]
        -

        Helpful Evennia-specific admin page.

        -
        - -
        -
        -evennia.web.website.views.admin_wrapper(request)[source]
        -

        Wrapper that allows us to properly use the base Django admin site, if needed.

        -
        - -
        -
        -class evennia.web.website.views.EvenniaIndexView(**kwargs)[source]
        -

        Bases: django.views.generic.base.TemplateView

        -

        This is a basic example of a Django class-based view, which are functionally -very similar to Evennia Commands but differ in structure. Commands are used -to interface with users using a terminal client. Views are used to interface -with users using a web browser.

        -

        To use a class-based view, you need to have written a template in HTML, and -then you write a view like this to tell Django what values to display on it.

        -

        While there are simpler ways of writing views using plain functions (and -Evennia currently contains a few examples of them), just like Commands, -writing views as classes provides you with more flexibility– you can extend -classes and change things to suit your needs rather than having to copy and -paste entire code blocks over and over. Django also comes with many default -views for displaying things, all of them implemented as classes.

        -

        This particular example displays the index page.

        -
        -
        -template_name = 'website/index.html'
        -
        - -
        -
        -get_context_data(**kwargs)[source]
        -

        This is a common Django method. Think of this as the website -equivalent of the Evennia Command.func() method.

        -

        If you just want to display a static page with no customization, you -don’t need to define this method– just create a view, define -template_name and you’re done.

        -

        The only catch here is that if you extend or overwrite this method, -you’ll always want to make sure you call the parent method to get a -context object. It’s just a dict, but it comes prepopulated with all -sorts of background data intended for display on the page.

        -

        You can do whatever you want to it, but it must be returned at the end -of this method.

        -
        -
        Keyword Arguments
        -

        any (any) – Passed through.

        -
        -
        Returns
        -

        context (dict) – Dictionary of data you want to display on the page.

        -
        -
        -
        - -
        - -
        -
        -class evennia.web.website.views.TypeclassMixin[source]
        -

        Bases: object

        -

        This is a “mixin”, a modifier of sorts.

        -

        Django views typically work with classes called “models.” Evennia objects -are an enhancement upon these Django models and are called “typeclasses.” -But Django itself has no idea what a “typeclass” is.

        -

        For the sake of mitigating confusion, any view class with this in its -inheritance list will be modified to work with Evennia Typeclass objects or -Django models interchangeably.

        -
        -
        -property typeclass
        -
        - -
        - -
        -
        -class evennia.web.website.views.EvenniaCreateView(**kwargs)[source]
        -

        Bases: django.views.generic.edit.CreateView, evennia.web.website.views.TypeclassMixin

        -

        This view extends Django’s default CreateView.

        -

        CreateView is used for creating new objects, be they Accounts, Characters or -otherwise.

        -
        -
        -property page_title
        -
        - -
        - -
        -
        -class evennia.web.website.views.EvenniaDetailView(**kwargs)[source]
        -

        Bases: django.views.generic.detail.DetailView, evennia.web.website.views.TypeclassMixin

        -

        This view extends Django’s default DetailView.

        -

        DetailView is used for displaying objects, be they Accounts, Characters or -otherwise.

        -
        -
        -property page_title
        -
        - -
        - -
        -
        -class evennia.web.website.views.EvenniaUpdateView(**kwargs)[source]
        -

        Bases: django.views.generic.edit.UpdateView, evennia.web.website.views.TypeclassMixin

        -

        This view extends Django’s default UpdateView.

        -

        UpdateView is used for updating objects, be they Accounts, Characters or -otherwise.

        -
        -
        -property page_title
        -
        - -
        - -
        -
        -class evennia.web.website.views.EvenniaDeleteView(**kwargs)[source]
        -

        Bases: django.views.generic.edit.DeleteView, evennia.web.website.views.TypeclassMixin

        -

        This view extends Django’s default DeleteView.

        -

        DeleteView is used for deleting objects, be they Accounts, Characters or -otherwise.

        -
        -
        -property page_title
        -
        - -
        - -
        -
        -class evennia.web.website.views.ObjectDetailView(**kwargs)[source]
        -

        Bases: evennia.web.website.views.EvenniaDetailView

        -

        This is an important view.

        -

        Any view you write that deals with displaying, updating or deleting a -specific object will want to inherit from this. It provides the mechanisms -by which to retrieve the object and make sure the user requesting it has -permissions to actually do things to it.

        -
        -
        -model
        -

        alias of evennia.objects.objects.DefaultObject

        -
        - -
        -
        -template_name = 'website/object_detail.html'
        -
        - -
        -
        -access_type = 'view'
        -
        - -
        -
        -attributes = ['name', 'desc']
        -
        - -
        -
        -get_context_data(**kwargs)[source]
        -

        Adds an ‘attributes’ list to the request context consisting of the -attributes specified at the class level, and in the order provided.

        -

        Django views do not provide a way to reference dynamic attributes, so -we have to grab them all before we render the template.

        -
        -
        Returns
        -

        context (dict) – Django context object

        -
        -
        -
        - -
        -
        -get_object(queryset=None)[source]
        -

        Override of Django hook that provides some important Evennia-specific -functionality.

        -

        Evennia does not natively store slugs, so where a slug is provided, -calculate the same for the object and make sure it matches.

        -

        This also checks to make sure the user has access to view/edit/delete -this object!

        -
        - -
        - -
        -
        -class evennia.web.website.views.ObjectCreateView(**kwargs)[source]
        -

        Bases: django.contrib.auth.mixins.LoginRequiredMixin, evennia.web.website.views.EvenniaCreateView

        -

        This is an important view.

        -

        Any view you write that deals with creating a specific object will want to -inherit from this. It provides the mechanisms by which to make sure the user -requesting creation of an object is authenticated, and provides a sane -default title for the page.

        -
        -
        -model
        -

        alias of evennia.objects.objects.DefaultObject

        -
        - -
        - -
        -
        -class evennia.web.website.views.ObjectDeleteView(**kwargs)[source]
        -

        Bases: django.contrib.auth.mixins.LoginRequiredMixin, evennia.web.website.views.ObjectDetailView, evennia.web.website.views.EvenniaDeleteView

        -

        This is an important view for obvious reasons!

        -

        Any view you write that deals with deleting a specific object will want to -inherit from this. It provides the mechanisms by which to make sure the user -requesting deletion of an object is authenticated, and that they have -permissions to delete the requested object.

        -
        -
        -model
        -

        alias of evennia.objects.objects.DefaultObject

        -
        - -
        -
        -template_name = 'website/object_confirm_delete.html'
        -
        - -
        -
        -access_type = 'delete'
        -
        - -
        -
        -delete(request, *args, **kwargs)[source]
        -

        Calls the delete() method on the fetched object and then -redirects to the success URL.

        -

        We extend this so we can capture the name for the sake of confirmation.

        -
        - -
        - -
        -
        -class evennia.web.website.views.ObjectUpdateView(**kwargs)[source]
        -

        Bases: django.contrib.auth.mixins.LoginRequiredMixin, evennia.web.website.views.ObjectDetailView, evennia.web.website.views.EvenniaUpdateView

        -

        This is an important view.

        -

        Any view you write that deals with updating a specific object will want to -inherit from this. It provides the mechanisms by which to make sure the user -requesting editing of an object is authenticated, and that they have -permissions to edit the requested object.

        -

        This functions slightly different from default Django UpdateViews in that -it does not update core model fields, only object attributes!

        -
        -
        -model
        -

        alias of evennia.objects.objects.DefaultObject

        -
        - -
        -
        -access_type = 'edit'
        -
        - -
        -
        -get_success_url()[source]
        -

        Django hook.

        -

        Can be overridden to return any URL you want to redirect the user to -after the object is successfully updated, but by default it goes to the -object detail page so the user can see their changes reflected.

        -
        - -
        -
        -get_initial()[source]
        -

        Django hook, modified for Evennia.

        -

        Prepopulates the update form field values based on object db attributes.

        -
        -
        Returns
        -

        data (dict)

        -
        -
        Dictionary of key:value pairs containing initial form

        data.

        -
        -
        -

        -
        -
        -
        - -
        -
        -form_valid(form)[source]
        -

        Override of Django hook.

        -

        Updates object attributes based on values submitted.

        -

        This is run when the form is submitted and the data on it is deemed -valid– all values are within expected ranges, all strings contain -valid characters and lengths, etc.

        -

        This method is only called if all values for the fields submitted -passed form validation, so at this point we can assume the data is -validated and sanitized.

        -
        - -
        - -
        -
        -class evennia.web.website.views.AccountMixin[source]
        -

        Bases: evennia.web.website.views.TypeclassMixin

        -

        This is a “mixin”, a modifier of sorts.

        -

        Any view class with this in its inheritance list will be modified to work -with Account objects instead of generic Objects or otherwise.

        -
        -
        -model
        -

        alias of evennia.accounts.accounts.DefaultAccount

        -
        - -
        -
        -form_class
        -

        alias of evennia.web.website.forms.AccountForm

        -
        - -
        - -
        -
        -class evennia.web.website.views.AccountCreateView(**kwargs)[source]
        -

        Bases: evennia.web.website.views.AccountMixin, evennia.web.website.views.EvenniaCreateView

        -

        Account creation view.

        -
        -
        -template_name = 'website/registration/register.html'
        -
        - -
        -
        -success_url
        -
        - -
        -
        -form_valid(form)[source]
        -

        Django hook, modified for Evennia.

        -

        This hook is called after a valid form is submitted.

        -

        When an account creation form is submitted and the data is deemed valid, -proceeds with creating the Account object.

        -
        - -
        - -
        -
        -class evennia.web.website.views.CharacterMixin[source]
        -

        Bases: evennia.web.website.views.TypeclassMixin

        -

        This is a “mixin”, a modifier of sorts.

        -

        Any view class with this in its inheritance list will be modified to work -with Character objects instead of generic Objects or otherwise.

        -
        -
        -model
        -

        alias of evennia.objects.objects.DefaultCharacter

        -
        - -
        -
        -form_class
        -

        alias of evennia.web.website.forms.CharacterForm

        -
        - -
        -
        -success_url
        -
        - -
        -
        -get_queryset()[source]
        -

        This method will override the Django get_queryset method to only -return a list of characters associated with the current authenticated -user.

        -
        -
        Returns
        -

        queryset (QuerySet) – Django queryset for use in the given view.

        -
        -
        -
        - -
        - -
        -
        -class evennia.web.website.views.CharacterListView(**kwargs)[source]
        -

        Bases: django.contrib.auth.mixins.LoginRequiredMixin, evennia.web.website.views.CharacterMixin, django.views.generic.list.ListView

        -

        This view provides a mechanism by which a logged-in player can view a list -of all other characters.

        -

        This view requires authentication by default as a nominal effort to prevent -human stalkers and automated bots/scrapers from harvesting data on your users.

        -
        -
        -template_name = 'website/character_list.html'
        -
        - -
        -
        -paginate_by = 100
        -
        - -
        -
        -page_title = 'Character List'
        -
        - -
        -
        -access_type = 'view'
        -
        - -
        -
        -get_queryset()[source]
        -

        This method will override the Django get_queryset method to return a -list of all characters (filtered/sorted) instead of just those limited -to the account.

        -
        -
        Returns
        -

        queryset (QuerySet) – Django queryset for use in the given view.

        -
        -
        -
        - -
        - -
        -
        -class evennia.web.website.views.CharacterPuppetView(**kwargs)[source]
        -

        Bases: django.contrib.auth.mixins.LoginRequiredMixin, evennia.web.website.views.CharacterMixin, django.views.generic.base.RedirectView, evennia.web.website.views.ObjectDetailView

        -

        This view provides a mechanism by which a logged-in player can “puppet” one -of their characters within the context of the website.

        -

        It also ensures that any user attempting to puppet something is logged in, -and that their intended puppet is one that they own.

        -
        -
        -get_redirect_url(*args, **kwargs)[source]
        -

        Django hook.

        -

        This view returns the URL to which the user should be redirected after -a passed or failed puppet attempt.

        -
        -
        Returns
        -

        url (str) – Path to post-puppet destination.

        -
        -
        -
        - -
        - -
        -
        -class evennia.web.website.views.CharacterManageView(**kwargs)[source]
        -

        Bases: django.contrib.auth.mixins.LoginRequiredMixin, evennia.web.website.views.CharacterMixin, django.views.generic.list.ListView

        -

        This view provides a mechanism by which a logged-in player can browse, -edit, or delete their own characters.

        -
        -
        -paginate_by = 10
        -
        - -
        -
        -template_name = 'website/character_manage_list.html'
        -
        - -
        -
        -page_title = 'Manage Characters'
        -
        - -
        - -
        -
        -class evennia.web.website.views.CharacterUpdateView(**kwargs)[source]
        -

        Bases: evennia.web.website.views.CharacterMixin, evennia.web.website.views.ObjectUpdateView

        -

        This view provides a mechanism by which a logged-in player (enforced by -ObjectUpdateView) can edit the attributes of a character they own.

        -
        -
        -form_class
        -

        alias of evennia.web.website.forms.CharacterUpdateForm

        -
        - -
        -
        -template_name = 'website/character_form.html'
        -
        - -
        - -
        -
        -class evennia.web.website.views.CharacterDetailView(**kwargs)[source]
        -

        Bases: evennia.web.website.views.CharacterMixin, evennia.web.website.views.ObjectDetailView

        -

        This view provides a mechanism by which a user can view the attributes of -a character, owned by them or not.

        -
        -
        -template_name = 'website/object_detail.html'
        -
        - -
        -
        -attributes = ['name', 'desc']
        -
        - -
        -
        -access_type = 'view'
        -
        - -
        -
        -get_queryset()[source]
        -

        This method will override the Django get_queryset method to return a -list of all characters the user may access.

        -
        -
        Returns
        -

        queryset (QuerySet) – Django queryset for use in the given view.

        -
        -
        -
        - -
        - -
        -
        -class evennia.web.website.views.CharacterDeleteView(**kwargs)[source]
        -

        Bases: evennia.web.website.views.CharacterMixin, evennia.web.website.views.ObjectDeleteView

        -

        This view provides a mechanism by which a logged-in player (enforced by -ObjectDeleteView) can delete a character they own.

        -
        - -
        -
        -class evennia.web.website.views.CharacterCreateView(**kwargs)[source]
        -

        Bases: evennia.web.website.views.CharacterMixin, evennia.web.website.views.ObjectCreateView

        -

        This view provides a mechanism by which a logged-in player (enforced by -ObjectCreateView) can create a new character.

        -
        -
        -template_name = 'website/character_form.html'
        -
        - -
        -
        -form_valid(form)[source]
        -

        Django hook, modified for Evennia.

        -

        This hook is called after a valid form is submitted.

        -

        When an character creation form is submitted and the data is deemed valid, -proceeds with creating the Character object.

        -
        - -
        - -
        -
        -class evennia.web.website.views.ChannelMixin[source]
        -

        Bases: evennia.web.website.views.TypeclassMixin

        -

        This is a “mixin”, a modifier of sorts.

        -

        Any view class with this in its inheritance list will be modified to work -with HelpEntry objects instead of generic Objects or otherwise.

        -
        -
        -model
        -

        alias of evennia.comms.comms.DefaultChannel

        -
        - -
        -
        -page_title = 'Channels'
        -
        - -
        -
        -access_type = 'listen'
        -
        - -
        -
        -get_queryset()[source]
        -

        Django hook; here we want to return a list of only those Channels -and other documentation that the current user is allowed to see.

        -
        -
        Returns
        -

        queryset (QuerySet) – List of Channels available to the user.

        -
        -
        -
        - -
        - -
        -
        -class evennia.web.website.views.ChannelListView(**kwargs)[source]
        -

        Bases: evennia.web.website.views.ChannelMixin, django.views.generic.list.ListView

        -

        Returns a list of channels that can be viewed by a user, authenticated -or not.

        -
        -
        -paginate_by = 100
        -
        - -
        -
        -template_name = 'website/channel_list.html'
        -
        - -
        -
        -page_title = 'Channel Index'
        -
        - -
        - -
        - -
        -
        -get_context_data(**kwargs)[source]
        -

        Django hook; we override it to calculate the most popular channels.

        -
        -
        Returns
        -

        context (dict) – Django context object

        -
        -
        -
        - -
        - -
        -
        -class evennia.web.website.views.ChannelDetailView(**kwargs)[source]
        -

        Bases: evennia.web.website.views.ChannelMixin, evennia.web.website.views.ObjectDetailView

        -

        Returns the log entries for a given channel.

        -
        -
        -template_name = 'website/channel_detail.html'
        -
        - -
        -
        -attributes = ['name']
        -
        - -
        -
        -max_num_lines = 10000
        -
        - -
        -
        -get_context_data(**kwargs)[source]
        -

        Django hook; before we can display the channel logs, we need to recall -the logfile and read its lines.

        -
        -
        Returns
        -

        context (dict) – Django context object

        -
        -
        -
        - -
        -
        -get_object(queryset=None)[source]
        -

        Override of Django hook that retrieves an object by slugified channel -name.

        -
        -
        Returns
        -

        channel (Channel) – Channel requested in the URL.

        -
        -
        -
        - -
        - -
        -
        -class evennia.web.website.views.HelpMixin[source]
        -

        Bases: evennia.web.website.views.TypeclassMixin

        -

        This is a “mixin”, a modifier of sorts.

        -

        Any view class with this in its inheritance list will be modified to work -with HelpEntry objects instead of generic Objects or otherwise.

        -
        -
        -model
        -

        alias of evennia.help.models.HelpEntry

        -
        - -
        -
        -page_title = 'Help'
        -
        - -
        -
        -get_queryset()[source]
        -

        Django hook; here we want to return a list of only those HelpEntries -and other documentation that the current user is allowed to see.

        -
        -
        Returns
        -

        queryset (QuerySet) – List of Help entries available to the user.

        -
        -
        -
        - -
        - -
        -
        -class evennia.web.website.views.HelpListView(**kwargs)[source]
        -

        Bases: evennia.web.website.views.HelpMixin, django.views.generic.list.ListView

        -

        Returns a list of help entries that can be viewed by a user, authenticated -or not.

        -
        -
        -paginate_by = 500
        -
        - -
        -
        -template_name = 'website/help_list.html'
        -
        - -
        -
        -page_title = 'Help Index'
        -
        - -
        - -
        -
        -class evennia.web.website.views.HelpDetailView(**kwargs)[source]
        -

        Bases: evennia.web.website.views.HelpMixin, evennia.web.website.views.EvenniaDetailView

        -

        Returns the detail page for a given help entry.

        -
        -
        -template_name = 'website/help_detail.html'
        -
        - -
        -
        -get_context_data(**kwargs)[source]
        -

        Adds navigational data to the template to let browsers go to the next -or previous entry in the help list.

        -
        -
        Returns
        -

        context (dict) – Django context object

        -
        -
        -
        - -
        -
        -get_object(queryset=None)[source]
        -

        Override of Django hook that retrieves an object by category and topic -instead of pk and slug.

        -
        -
        Returns
        -

        entry (HelpEntry) – HelpEntry requested in the URL.

        -
        -
        -
        - -
        - +

        Website views.

        -
        @@ -900,6 +114,7 @@ instead of pk and slug.

        +
        develop branch
        @@ -37,8 +38,57 @@
        -
        -

        evennia.web.website.views.index

        +
        +

        evennia.web.website.views.index

        +

        The main index page, including the game stats

        +
        +
        +class evennia.web.website.views.index.EvenniaIndexView(**kwargs)[source]
        +

        Bases: django.views.generic.base.TemplateView

        +

        This is a basic example of a Django class-based view, which are functionally +very similar to Evennia Commands but differ in structure. Commands are used +to interface with users using a terminal client. Views are used to interface +with users using a web browser.

        +

        To use a class-based view, you need to have written a template in HTML, and +then you write a view like this to tell Django what values to display on it.

        +

        While there are simpler ways of writing views using plain functions (and +Evennia currently contains a few examples of them), just like Commands, +writing views as classes provides you with more flexibility– you can extend +classes and change things to suit your needs rather than having to copy and +paste entire code blocks over and over. Django also comes with many default +views for displaying things, all of them implemented as classes.

        +

        This particular example displays the index page.

        +
        +
        +template_name = 'website/index.html'
        +
        + +
        +
        +get_context_data(**kwargs)[source]
        +

        This is a common Django method. Think of this as the website +equivalent of the Evennia Command.func() method.

        +

        If you just want to display a static page with no customization, you +don’t need to define this method– just create a view, define +template_name and you’re done.

        +

        The only catch here is that if you extend or overwrite this method, +you’ll always want to make sure you call the parent method to get a +context object. It’s just a dict, but it comes prepopulated with all +sorts of background data intended for display on the page.

        +

        You can do whatever you want to it, but it must be returned at the end +of this method.

        +
        +
        Keyword Arguments
        +

        any (any) – Passed through.

        +
        +
        Returns
        +

        context (dict) – Dictionary of data you want to display on the page.

        +
        +
        +
        + +
        +
        @@ -84,7 +134,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +150,7 @@ +
        develop branch
        @@ -37,8 +38,83 @@
        -
        -

        evennia.web.website.views.mixins

        +
        +

        evennia.web.website.views.mixins

        +

        These are mixins for class-based views, granting functionality.

        +
        +
        +class evennia.web.website.views.mixins.TypeclassMixin[source]
        +

        Bases: object

        +

        This is a “mixin”, a modifier of sorts.

        +

        Django views typically work with classes called “models.” Evennia objects +are an enhancement upon these Django models and are called “typeclasses.” +But Django itself has no idea what a “typeclass” is.

        +

        For the sake of mitigating confusion, any view class with this in its +inheritance list will be modified to work with Evennia Typeclass objects or +Django models interchangeably.

        +
        +
        +property typeclass
        +
        + +
        + +
        +
        +class evennia.web.website.views.mixins.EvenniaCreateView(**kwargs)[source]
        +

        Bases: django.views.generic.edit.CreateView, evennia.web.website.views.mixins.TypeclassMixin

        +

        This view extends Django’s default CreateView.

        +

        CreateView is used for creating new objects, be they Accounts, Characters or +otherwise.

        +
        +
        +property page_title
        +
        + +
        + +
        +
        +class evennia.web.website.views.mixins.EvenniaDetailView(**kwargs)[source]
        +

        Bases: django.views.generic.detail.DetailView, evennia.web.website.views.mixins.TypeclassMixin

        +

        This view extends Django’s default DetailView.

        +

        DetailView is used for displaying objects, be they Accounts, Characters or +otherwise.

        +
        +
        +property page_title
        +
        + +
        + +
        +
        +class evennia.web.website.views.mixins.EvenniaUpdateView(**kwargs)[source]
        +

        Bases: django.views.generic.edit.UpdateView, evennia.web.website.views.mixins.TypeclassMixin

        +

        This view extends Django’s default UpdateView.

        +

        UpdateView is used for updating objects, be they Accounts, Characters or +otherwise.

        +
        +
        +property page_title
        +
        + +
        + +
        +
        +class evennia.web.website.views.mixins.EvenniaDeleteView(**kwargs)[source]
        +

        Bases: django.views.generic.edit.DeleteView, evennia.web.website.views.mixins.TypeclassMixin

        +

        This view extends Django’s default DeleteView.

        +

        DeleteView is used for deleting objects, be they Accounts, Characters or +otherwise.

        +
        +
        +property page_title
        +
        + +
        +
        @@ -84,7 +160,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +176,7 @@ +
        develop branch
        @@ -37,8 +38,181 @@
        -
        -

        evennia.web.website.views.objects

        +
        +

        evennia.web.website.views.objects

        +

        Views for managing a specific object)

        +
        +
        +class evennia.web.website.views.objects.ObjectDetailView(**kwargs)[source]
        +

        Bases: evennia.web.website.views.mixins.EvenniaDetailView

        +

        This is an important view.

        +

        Any view you write that deals with displaying, updating or deleting a +specific object will want to inherit from this. It provides the mechanisms +by which to retrieve the object and make sure the user requesting it has +permissions to actually do things to it.

        +
        +
        +model
        +

        alias of evennia.objects.objects.DefaultObject

        +
        + +
        +
        +template_name = 'website/object_detail.html'
        +
        + +
        +
        +access_type = 'view'
        +
        + +
        +
        +attributes = ['name', 'desc']
        +
        + +
        +
        +get_context_data(**kwargs)[source]
        +

        Adds an ‘attributes’ list to the request context consisting of the +attributes specified at the class level, and in the order provided.

        +

        Django views do not provide a way to reference dynamic attributes, so +we have to grab them all before we render the template.

        +
        +
        Returns
        +

        context (dict) – Django context object

        +
        +
        +
        + +
        +
        +get_object(queryset=None)[source]
        +

        Override of Django hook that provides some important Evennia-specific +functionality.

        +

        Evennia does not natively store slugs, so where a slug is provided, +calculate the same for the object and make sure it matches.

        +

        This also checks to make sure the user has access to view/edit/delete +this object!

        +
        + +
        + +
        +
        +class evennia.web.website.views.objects.ObjectCreateView(**kwargs)[source]
        +

        Bases: django.contrib.auth.mixins.LoginRequiredMixin, evennia.web.website.views.mixins.EvenniaCreateView

        +

        This is an important view.

        +

        Any view you write that deals with creating a specific object will want to +inherit from this. It provides the mechanisms by which to make sure the user +requesting creation of an object is authenticated, and provides a sane +default title for the page.

        +
        +
        +model
        +

        alias of evennia.objects.objects.DefaultObject

        +
        + +
        + +
        +
        +class evennia.web.website.views.objects.ObjectDeleteView(**kwargs)[source]
        +

        Bases: django.contrib.auth.mixins.LoginRequiredMixin, evennia.web.website.views.objects.ObjectDetailView, evennia.web.website.views.mixins.EvenniaDeleteView

        +

        This is an important view for obvious reasons!

        +

        Any view you write that deals with deleting a specific object will want to +inherit from this. It provides the mechanisms by which to make sure the user +requesting deletion of an object is authenticated, and that they have +permissions to delete the requested object.

        +
        +
        +model
        +

        alias of evennia.objects.objects.DefaultObject

        +
        + +
        +
        +template_name = 'website/object_confirm_delete.html'
        +
        + +
        +
        +access_type = 'delete'
        +
        + +
        +
        +delete(request, *args, **kwargs)[source]
        +

        Calls the delete() method on the fetched object and then +redirects to the success URL.

        +

        We extend this so we can capture the name for the sake of confirmation.

        +
        + +
        + +
        +
        +class evennia.web.website.views.objects.ObjectUpdateView(**kwargs)[source]
        +

        Bases: django.contrib.auth.mixins.LoginRequiredMixin, evennia.web.website.views.objects.ObjectDetailView, evennia.web.website.views.mixins.EvenniaUpdateView

        +

        This is an important view.

        +

        Any view you write that deals with updating a specific object will want to +inherit from this. It provides the mechanisms by which to make sure the user +requesting editing of an object is authenticated, and that they have +permissions to edit the requested object.

        +

        This functions slightly different from default Django UpdateViews in that +it does not update core model fields, only object attributes!

        +
        +
        +model
        +

        alias of evennia.objects.objects.DefaultObject

        +
        + +
        +
        +access_type = 'edit'
        +
        + +
        +
        +get_success_url()[source]
        +

        Django hook.

        +

        Can be overridden to return any URL you want to redirect the user to +after the object is successfully updated, but by default it goes to the +object detail page so the user can see their changes reflected.

        +
        + +
        +
        +get_initial()[source]
        +

        Django hook, modified for Evennia.

        +

        Prepopulates the update form field values based on object db attributes.

        +
        +
        Returns
        +

        data (dict)

        +
        +
        Dictionary of key:value pairs containing initial form

        data.

        +
        +
        +

        +
        +
        +
        + +
        +
        +form_valid(form)[source]
        +

        Override of Django hook.

        +

        Updates object attributes based on values submitted.

        +

        This is run when the form is submitted and the data on it is deemed +valid– all values are within expected ranges, all strings contain +valid characters and lengths, etc.

        +

        This method is only called if all values for the fields submitted +passed form validation, so at this point we can assume the data is +validated and sanitized.

        +
        + +
        +
        @@ -84,7 +258,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -101,6 +274,7 @@ +
        develop branch
        @@ -79,10 +80,12 @@
      • (evennia.commands.command.Command method)
      • (evennia.commands.command.CommandMeta method) -
      • -
      • (evennia.comms.models.Msg method)
      • (evennia.comms.models.TempMsg method) +
      • +
      • (evennia.contrib.awsstorage.aws_s3_cdn.S3Boto3Storage method) +
      • +
      • (evennia.contrib.awsstorage.aws_s3_cdn.S3Boto3StorageFile method)
      • (evennia.contrib.barter.TradeHandler method)
      • @@ -93,6 +96,10 @@
      • (evennia.contrib.building_menu.CmdNoInput method)
      • (evennia.contrib.building_menu.CmdNoMatch method) +
      • +
      • (evennia.contrib.crafting.crafting.CraftingRecipe method) +
      • +
      • (evennia.contrib.crafting.crafting.CraftingRecipeBase method)
      • (evennia.contrib.evscaperoom.state.BaseState method)
      • @@ -105,10 +112,20 @@
      • (evennia.contrib.rpsystem.RecogHandler method)
      • (evennia.contrib.rpsystem.SdescHandler method) +
      • +
      • (evennia.contrib.traits.Trait method) +
      • +
      • (evennia.contrib.traits.TraitException method) +
      • +
      • (evennia.contrib.traits.TraitHandler method)
      • (evennia.contrib.unixcommand.UnixCommand method)
      • (evennia.contrib.unixcommand.UnixCommandParser method) +
      • +
      • (evennia.help.filehelp.FileHelpEntry method) +
      • +
      • (evennia.help.filehelp.FileHelpStorageHandler method)
      • (evennia.locks.lockhandler.LockHandler method)
      • @@ -155,6 +172,16 @@
      • (evennia.server.portal.grapevine.RestartingWebsocketServerFactory method)
      • (evennia.server.portal.irc.IRCBotFactory method) +
      • +
      • (evennia.server.portal.mccp.Mccp method) +
      • +
      • (evennia.server.portal.mssp.Mssp method) +
      • +
      • (evennia.server.portal.mxp.Mxp method) +
      • +
      • (evennia.server.portal.naws.Naws method) +
      • +
      • (evennia.server.portal.portal.Portal method)
      • (evennia.server.portal.portalsessionhandler.PortalSessionHandler method)
      • @@ -167,6 +194,18 @@
      • (evennia.server.portal.ssh.SshProtocol method)
      • (evennia.server.portal.ssh.TerminalSessionTransport_getPeer method) +
      • +
      • (evennia.server.portal.ssl.SSLProtocol method) +
      • +
      • (evennia.server.portal.suppress_ga.SuppressGA method) +
      • +
      • (evennia.server.portal.telnet.TelnetProtocol method) +
      • +
      • (evennia.server.portal.telnet_oob.TelnetOOB method) +
      • +
      • (evennia.server.portal.telnet_ssl.SSLProtocol method) +
      • +
      • (evennia.server.portal.ttype.Ttype method)
      • (evennia.server.portal.webclient.WebSocketClient method)
      • @@ -177,10 +216,6 @@
      • (evennia.server.profiling.dummyrunner.DummyFactory method)
      • (evennia.server.server.Evennia method) -
      • -
      • (evennia.server.serversession.NAttributeHandler method) -
      • -
      • (evennia.server.serversession.NDbHolder method)
      • (evennia.server.serversession.ServerSession method)
      • @@ -198,7 +233,15 @@
      • (evennia.typeclasses.attributes.AttributeHandler method)
      • -
      • (evennia.typeclasses.attributes.NAttributeHandler method) +
      • (evennia.typeclasses.attributes.DbHolder method) +
      • +
      • (evennia.typeclasses.attributes.IAttributeBackend method) +
      • +
      • (evennia.typeclasses.attributes.InMemoryAttribute method) +
      • +
      • (evennia.typeclasses.attributes.InMemoryAttributeBackend method) +
      • +
      • (evennia.typeclasses.attributes.ModelAttributeBackend method)
      • (evennia.typeclasses.attributes.NickHandler method)
      • @@ -227,6 +270,8 @@
      • (evennia.utils.evtable.EvColumn method)
      • (evennia.utils.evtable.EvTable method) +
      • +
      • (evennia.utils.funcparser.FuncParser method)
      • (evennia.utils.logger.WeeklyLogFile method)
      • @@ -243,6 +288,16 @@
      • (evennia.utils.utils.lazy_property method)
      • (evennia.utils.utils.LimitedSizeOrderedDict method) +
      • +
      • (evennia.web.admin.accounts.AccountChangeForm method) +
      • +
      • (evennia.web.admin.accounts.ObjectPuppetInline.ObjectCreateForm method) +
      • +
      • (evennia.web.admin.attributes.AttributeForm method) +
      • +
      • (evennia.web.admin.objects.ObjectCreateForm method) +
      • +
      • (evennia.web.admin.tags.InlineTagForm method)
      • (evennia.web.utils.middleware.SharedLoginMiddleware method)
      • @@ -279,6 +334,8 @@
      • (evennia.comms.models.Msg method)
      • (evennia.comms.models.TempMsg method) +
      • +
      • (evennia.help.filehelp.FileHelpEntry method)
      • (evennia.help.models.HelpEntry method)
      • @@ -286,23 +343,27 @@
      • (evennia.server.serversession.ServerSession method)
      • -
      • (evennia.typeclasses.attributes.Attribute method) +
      • (evennia.typeclasses.attributes.IAttribute method)
      • (evennia.typeclasses.models.TypedObject method)
      • -
      • access_type (evennia.web.website.views.ChannelMixin attribute) +
      • access_key (evennia.contrib.awsstorage.aws_s3_cdn.S3Boto3Storage attribute) +
      • +
      • access_key_names (evennia.contrib.awsstorage.aws_s3_cdn.S3Boto3Storage attribute) +
      • +
      • access_type (evennia.web.website.views.channels.ChannelMixin attribute)
      • account() (evennia.objects.models.ObjectDB property) @@ -344,11 +405,9 @@
      • (evennia.commands.default.comms.CmdCdestroy attribute)
      • -
      • (evennia.commands.default.comms.CmdCemit attribute) +
      • (evennia.commands.default.comms.CmdChannel attribute)
      • (evennia.commands.default.comms.CmdChannelCreate attribute) -
      • -
      • (evennia.commands.default.comms.CmdChannels attribute)
      • (evennia.commands.default.comms.CmdClock attribute)
      • @@ -377,9 +436,21 @@
      • (evennia.web.website.tests.EvenniaWebTest attribute)
      • +
      • AccountAdmin (class in evennia.web.admin.accounts) +
      • +
      • AccountAttributeInline (class in evennia.web.admin.accounts) +
      • +
      • AccountChangeForm (class in evennia.web.admin.accounts) +
      • +
      • AccountChangeForm.Meta (class in evennia.web.admin.accounts) +
      • AccountCmdSet (class in evennia.commands.default.cmdset_account)
      • -
      • AccountCreateView (class in evennia.web.website.views) +
      • AccountCreateView (class in evennia.web.website.views.accounts) +
      • +
      • AccountCreationForm (class in evennia.web.admin.accounts) +
      • +
      • AccountCreationForm.Meta (class in evennia.web.admin.accounts)
      • AccountDB (class in evennia.accounts.models)
      • @@ -393,15 +464,31 @@
      • (evennia.typeclasses.tags.Tag attribute)
      • +
      • AccountDBFilterSet (class in evennia.web.api.filters) +
      • +
      • AccountDBFilterSet.Meta (class in evennia.web.api.filters) +
      • AccountDBPasswordChecker (class in evennia.server.portal.ssh) +
      • +
      • AccountDBViewSet (class in evennia.web.api.views)
      • AccountForm (class in evennia.web.website.forms)
      • AccountForm.Meta (class in evennia.web.website.forms) +
      • +
      • AccountListSerializer (class in evennia.web.api.serializers) +
      • +
      • AccountListSerializer.Meta (class in evennia.web.api.serializers)
      • AccountManager (class in evennia.accounts.manager)
      • -
      • AccountMixin (class in evennia.web.website.views) +
      • AccountMixin (class in evennia.web.website.views.accounts) +
      • +
      • AccountSerializer (class in evennia.web.api.serializers) +
      • +
      • AccountSerializer.Meta (class in evennia.web.api.serializers) +
      • +
      • AccountTagInline (class in evennia.web.admin.accounts)
      • achievement() (evennia.contrib.evscaperoom.room.EvscapeRoom method)
      • @@ -437,6 +524,8 @@
      • (evennia.contrib.rpsystem.RecogHandler method)
      • (evennia.contrib.rpsystem.SdescHandler method) +
      • +
      • (evennia.contrib.traits.TraitHandler method)
      • (evennia.locks.lockhandler.LockHandler method)
      • @@ -455,22 +544,18 @@
      • (evennia.scripts.tickerhandler.TickerHandler method)
      • (evennia.scripts.tickerhandler.TickerPool method) -
      • -
      • (evennia.server.serversession.NAttributeHandler method)
      • (evennia.typeclasses.attributes.AttributeHandler method) -
      • -
      • (evennia.typeclasses.attributes.NAttributeHandler method)
      • (evennia.typeclasses.attributes.NickHandler method)
      • (evennia.typeclasses.tags.TagHandler method)
      • (evennia.utils.optionhandler.InMemorySaveHandler method) -
      • -
      • (in module evennia.prototypes.protfuncs)
      • +
      • add_alias() (evennia.commands.default.comms.CmdChannel method) +
      • add_callback() (evennia.contrib.ingame_python.commands.CmdCallback method)
      • +
      • AliasFilter (class in evennia.web.api.filters) +
      • AliasHandler (class in evennia.typeclasses.tags)
      • all() (evennia.commands.cmdsethandler.CmdSetHandler method) @@ -1023,6 +1150,10 @@
      • (evennia.contrib.random_string_generator.RandomStringGenerator method)
      • (evennia.contrib.rpsystem.RecogHandler method) +
      • +
      • (evennia.contrib.traits.TraitHandler property) +
      • +
      • (evennia.help.filehelp.FileHelpStorageHandler method)
      • (evennia.locks.lockhandler.LockHandler method)
      • @@ -1033,14 +1164,10 @@
      • (evennia.scripts.scripthandler.ScriptHandler method)
      • (evennia.scripts.tickerhandler.TickerHandler method) -
      • -
      • (evennia.server.serversession.NAttributeHandler method) -
      • -
      • (evennia.server.serversession.NDbHolder property)
      • (evennia.typeclasses.attributes.AttributeHandler method)
      • -
      • (evennia.typeclasses.attributes.NAttributeHandler method) +
      • (evennia.typeclasses.attributes.DbHolder property)
      • (evennia.typeclasses.tags.TagHandler method)
      • @@ -1084,6 +1211,10 @@
      • allHeadersReceived() (evennia.server.webserver.HTTPChannelWithXForwardedFor method) +
      • +
      • allow_extra_properties (evennia.contrib.traits.Trait attribute) +
      • +
      • allow_reuse (evennia.contrib.crafting.crafting.CraftingRecipeBase attribute)
      • allowedMethods (evennia.server.portal.webclient_ajax.AjaxWebClient attribute)
      • @@ -1122,11 +1253,11 @@
      • ansi_sub (evennia.utils.ansi.ANSIParser attribute)
      • ansi_xterm256_bright_bg_map (evennia.utils.ansi.ANSIParser attribute) -
      • -
      • ansi_xterm256_bright_bg_map_dict (evennia.utils.ansi.ANSIParser attribute)
      • arguments (evennia.server.evennia_launcher.MsgLauncher2Portal attribute) @@ -1236,6 +1381,8 @@
      • ask_input() (evennia.server.connection_wizard.ConnectionWizard method)
      • ask_node() (evennia.server.connection_wizard.ConnectionWizard method) +
      • +
      • ask_yes_no() (in module evennia.utils.evmenu)
      • ask_yesno() (evennia.server.connection_wizard.ConnectionWizard method)
      • @@ -1371,6 +1518,8 @@
      • (evennia.contrib.chargen.OOCCmdSetCharGen method)
      • (evennia.contrib.clothing.ClothedCharacterCmdSet method) +
      • +
      • (evennia.contrib.crafting.crafting.CraftingCmdSet method)
      • (evennia.contrib.dice.DiceCmdSet method)
      • @@ -1393,6 +1542,12 @@
      • (evennia.contrib.turnbattle.tb_magic.BattleCmdSet method)
      • (evennia.contrib.turnbattle.tb_range.BattleCmdSet method) +
      • +
      • (evennia.contrib.tutorial_examples.red_button.BlindCmdSet method) +
      • +
      • (evennia.contrib.tutorial_examples.red_button.LidClosedCmdSet method) +
      • +
      • (evennia.contrib.tutorial_examples.red_button.LidOpenCmdSet method)
      • (evennia.contrib.tutorial_world.intro_menu.DemoCommandSetComms method)
      • @@ -1421,6 +1576,8 @@
      • (evennia.contrib.tutorial_world.rooms.DarkCmdSet method)
      • (evennia.contrib.tutorial_world.rooms.TutorialRoomCmdSet method) +
      • +
      • (evennia.server.profiling.dummyrunner.DummyRunnerCmdSet method)
      • (evennia.utils.eveditor.EvEditorCmdSet method)
      • @@ -1429,6 +1586,8 @@
      • (evennia.utils.evmenu.EvMenuCmdSet method)
      • (evennia.utils.evmenu.InputCmdSet method) +
      • +
      • (evennia.utils.evmenu.YesNoQuestionCmdSet method)
      • (evennia.utils.evmore.CmdSetMore method)
      • @@ -1585,11 +1744,9 @@
      • at_hit() (evennia.contrib.tutorial_world.mob.Mob method)
      • -
      • at_idmapper_flush() (evennia.scripts.scripts.DefaultScript method) +
      • at_idmapper_flush() (evennia.typeclasses.models.TypedObject method)
      • @@ -1623,6 +1780,8 @@
      • (evennia.server.portal.irc.IRCBot method)
      • (evennia.server.portal.ssh.SshProtocol method) +
      • +
      • (evennia.server.portal.telnet.TelnetProtocol method)
      • (evennia.server.portal.webclient.WebSocketClient method)
      • @@ -1728,9 +1887,9 @@
      • (evennia.contrib.tutorial_world.objects.TutorialReadable method)
      • -
      • (evennia.contrib.tutorial_world.objects.Weapon method) +
      • (evennia.contrib.tutorial_world.objects.TutorialWeapon method)
      • -
      • (evennia.contrib.tutorial_world.objects.WeaponRack method) +
      • (evennia.contrib.tutorial_world.objects.TutorialWeaponRack method)
      • (evennia.contrib.tutorial_world.rooms.BridgeRoom method)
      • @@ -1790,8 +1949,12 @@
      • at_open() (evennia.contrib.evscaperoom.objects.Openable method)
      • at_password_change() (evennia.accounts.accounts.DefaultAccount method) +
      • +
      • at_pause() (evennia.scripts.scripts.DefaultScript method)
      • at_position() (evennia.contrib.evscaperoom.objects.BasePositionable method) +
      • +
      • at_post_channel_msg() (evennia.accounts.accounts.DefaultAccount method)
      • at_post_cmd() (evennia.commands.command.Command method) @@ -1800,8 +1963,18 @@
      • at_post_disconnect() (evennia.accounts.accounts.DefaultAccount method) + +
      • at_post_login() (evennia.accounts.accounts.DefaultAccount method) + +
      • +
      • at_post_msg() (evennia.comms.comms.DefaultChannel method)
      • at_post_portal_sync() (evennia.server.server.Evennia method)
      • @@ -1817,6 +1990,8 @@
      • (evennia.objects.objects.DefaultObject method)
      • +
      • at_pre_channel_msg() (evennia.accounts.accounts.DefaultAccount method) +
      • at_pre_cmd() (evennia.commands.command.Command method)
          @@ -1824,6 +1999,8 @@
      • at_pre_login() (evennia.accounts.accounts.DefaultAccount method) +
      • +
      • at_pre_msg() (evennia.comms.comms.DefaultChannel method)
      • at_pre_puppet() (evennia.objects.objects.DefaultCharacter method) @@ -1921,6 +2098,8 @@
      • (evennia.utils.gametime.TimeScript method)
      • +
      • at_script_delete() (evennia.scripts.scripts.DefaultScript method) +
      • at_search_result() (in module evennia.utils.utils)
      • at_server_cold_start() (evennia.server.server.Evennia method) @@ -1946,6 +2125,8 @@
      • at_server_shutdown() (evennia.accounts.accounts.DefaultAccount method)
      • -
      • at_server_start() (evennia.server.server.Evennia method) +
      • at_server_start() (evennia.contrib.ingame_python.scripts.EventHandler method) + +
      • at_server_stop() (evennia.server.server.Evennia method)
      • at_speech() (evennia.contrib.evscaperoom.objects.EvscaperoomObject method) @@ -1964,8 +2151,6 @@
      • at_start() (evennia.accounts.bots.BotStarter method)
      • +
      • has_add_permission() (evennia.web.admin.accounts.ObjectPuppetInline method) +
      • has_cmdset() (evennia.commands.cmdsethandler.CmdSetHandler method)
      • has_connection() (evennia.comms.comms.DefaultChannel method)
      • has_consumed() (evennia.contrib.evscaperoom.objects.BaseConsumable method) +
      • +
      • has_delete_permission() (evennia.web.admin.accounts.ObjectPuppetInline method) +
      • +
      • has_object_permission() (evennia.web.api.permissions.EvenniaPermission method)
      • has_parent() (in module evennia.utils.utils)
      • has_perm() (evennia.commands.default.muxcommand.MuxCommand method) +
      • +
      • has_permission() (evennia.web.api.permissions.EvenniaPermission method)
      • HasButtons (class in evennia.contrib.evscaperoom.objects)
      • @@ -7047,11 +8411,9 @@
      • (evennia.commands.default.comms.CmdCdestroy attribute)
      • -
      • (evennia.commands.default.comms.CmdCemit attribute) +
      • (evennia.commands.default.comms.CmdChannel attribute)
      • (evennia.commands.default.comms.CmdChannelCreate attribute) -
      • -
      • (evennia.commands.default.comms.CmdChannels attribute)
      • (evennia.commands.default.comms.CmdClock attribute)
      • @@ -7106,8 +8468,6 @@
      • (evennia.commands.default.syscommands.SystemNoInput attribute)
      • (evennia.commands.default.syscommands.SystemNoMatch attribute) -
      • -
      • (evennia.commands.default.syscommands.SystemSendToChannel attribute)
      • (evennia.commands.default.system.CmdAbout attribute)
      • @@ -7126,6 +8486,8 @@
      • (evennia.commands.default.system.CmdService attribute)
      • (evennia.commands.default.system.CmdShutdown attribute) +
      • +
      • (evennia.commands.default.system.CmdTasks attribute)
      • (evennia.commands.default.system.CmdTime attribute)
      • @@ -7182,6 +8544,8 @@
      • (evennia.contrib.clothing.CmdUncover attribute)
      • (evennia.contrib.clothing.CmdWear attribute) +
      • +
      • (evennia.contrib.crafting.crafting.CmdCraft attribute)
      • (evennia.contrib.dice.CmdDice attribute)
      • @@ -7370,6 +8734,22 @@
      • (evennia.contrib.turnbattle.tb_range.CmdStatus attribute)
      • (evennia.contrib.turnbattle.tb_range.CmdWithdraw attribute) +
      • +
      • (evennia.contrib.tutorial_examples.red_button.CmdBlindHelp attribute) +
      • +
      • (evennia.contrib.tutorial_examples.red_button.CmdBlindLook attribute) +
      • +
      • (evennia.contrib.tutorial_examples.red_button.CmdCloseLid attribute) +
      • +
      • (evennia.contrib.tutorial_examples.red_button.CmdNudge attribute) +
      • +
      • (evennia.contrib.tutorial_examples.red_button.CmdOpenLid attribute) +
      • +
      • (evennia.contrib.tutorial_examples.red_button.CmdPushLidClosed attribute) +
      • +
      • (evennia.contrib.tutorial_examples.red_button.CmdPushLidOpen attribute) +
      • +
      • (evennia.contrib.tutorial_examples.red_button.CmdSmashGlass attribute)
      • (evennia.contrib.tutorial_world.mob.CmdMobOnOff attribute)
      • @@ -7412,8 +8792,12 @@
      • (evennia.contrib.tutorial_world.rooms.CmdWest attribute)
      • (evennia.contrib.unixcommand.UnixCommand attribute) +
      • +
      • (evennia.help.filehelp.FileHelpEntry attribute)
      • (evennia.objects.objects.ExitCommand attribute) +
      • +
      • (evennia.server.profiling.dummyrunner.CmdDummyRunnerEchoResponse attribute)
      • (evennia.utils.eveditor.CmdEditorBase attribute)
      • @@ -7426,6 +8810,8 @@
      • (evennia.utils.evmenu.CmdEvMenuNode attribute)
      • (evennia.utils.evmenu.CmdGetInput attribute) +
      • +
      • (evennia.utils.evmenu.CmdYesNoQuestion attribute)
      • (evennia.utils.evmore.CmdMore attribute)
      • @@ -7443,10 +8829,12 @@
      • help_key (evennia.commands.default.building.CmdUnLink attribute)
      • help_more (evennia.commands.default.help.CmdHelp attribute) +
      • +
      • help_search_with_index() (in module evennia.help.utils)
      • HelpAction (class in evennia.contrib.unixcommand)
      • -
      • HelpDetailView (class in evennia.web.website.views) +
      • HelpDetailView (class in evennia.web.website.views.help)
      • HelpEntry (class in evennia.help.models)
      • @@ -7455,12 +8843,30 @@
      • HelpEntry.MultipleObjectsReturned
      • helpentry_set (evennia.typeclasses.tags.Tag attribute) +
      • +
      • HelpEntryAdmin (class in evennia.web.admin.help) +
      • +
      • HelpEntryForm (class in evennia.web.admin.help) +
      • +
      • HelpEntryForm.Meta (class in evennia.web.admin.help)
      • HelpEntryManager (class in evennia.help.manager)
      • -
      • HelpListView (class in evennia.web.website.views) +
      • HelpFilterSet (class in evennia.web.api.filters)
      • -
      • HelpMixin (class in evennia.web.website.views) +
      • HelpListSerializer (class in evennia.web.api.serializers) +
      • +
      • HelpListSerializer.Meta (class in evennia.web.api.serializers) +
      • +
      • HelpListView (class in evennia.web.website.views.help) +
      • +
      • HelpMixin (class in evennia.web.website.views.help) +
      • +
      • HelpSerializer (class in evennia.web.api.serializers) +
      • +
      • HelpSerializer.Meta (class in evennia.web.api.serializers) +
      • +
      • HelpTagInline (class in evennia.web.admin.help)
      • helptext_formatter() (evennia.prototypes.menus.OLCMenu method) @@ -7468,11 +8874,11 @@
      • (evennia.utils.evmenu.EvMenu method)
      • +
      • HelpViewSet (class in evennia.web.api.views) +
      • hide_from() (evennia.comms.models.Msg property)
      • hide_from_accounts_set (evennia.accounts.models.AccountDB attribute) -
      • -
      • hide_from_channels_set (evennia.comms.models.ChannelDB attribute)
      • hide_from_objects_set (evennia.objects.models.ObjectDB attribute)
      • @@ -7498,6 +8904,10 @@

        I

        @@ -10087,10 +12011,14 @@
      • (evennia.commands.command.Command method)
      • (evennia.comms.comms.DefaultChannel method) +
      • +
      • (evennia.contrib.crafting.crafting.CraftingRecipeBase method)
      • (evennia.contrib.evscaperoom.state.BaseState method)
      • (evennia.contrib.gendersub.GenderCharacter method) +
      • +
      • (evennia.contrib.tutorial_examples.mirror.TutorialMirror method)
      • (evennia.objects.objects.DefaultObject method)
      • @@ -10106,6 +12034,8 @@
      • Msg.MultipleObjectsReturned
      • msg_all_sessions (evennia.commands.command.Command attribute) +
      • +
      • msg_channel() (evennia.commands.default.comms.CmdChannel method)
      • msg_char() (evennia.contrib.evscaperoom.objects.EvscaperoomObject method)
      • @@ -10122,6 +12052,12 @@
      • msg_set (evennia.typeclasses.tags.Tag attribute)
      • msg_system() (evennia.contrib.evscaperoom.objects.EvscaperoomObject method) +
      • +
      • MsgAdmin (class in evennia.web.admin.comms) +
      • +
      • MsgForm (class in evennia.web.admin.comms) +
      • +
      • MsgForm.Meta (class in evennia.web.admin.comms)
      • MsgLauncher2Portal (class in evennia.server.evennia_launcher) @@ -10141,19 +12077,31 @@
      • (class in evennia.server.portal.amp)
      • -
      • mult() (in module evennia.prototypes.protfuncs) +
      • MsgTagInline (class in evennia.web.admin.comms) +
      • +
      • Mssp (class in evennia.server.portal.mssp)
      • mute() (evennia.comms.comms.DefaultChannel method) +
      • +
      • mute_channel() (evennia.commands.default.comms.CmdChannel method)
      • mutelist() (evennia.comms.comms.DefaultChannel property)
      • MuxAccountCommand (class in evennia.commands.default.muxcommand)
      • MuxCommand (class in evennia.commands.default.muxcommand) +
      • +
      • Mxp (class in evennia.server.portal.mxp) +
      • +
      • mxp_parse() (in module evennia.server.portal.mxp)
      • mxp_re (evennia.utils.ansi.ANSIParser attribute)
      • mxp_sub (evennia.utils.ansi.ANSIParser attribute) +
      • +
      • mxp_url_re (evennia.utils.ansi.ANSIParser attribute) +
      • +
      • mxp_url_sub (evennia.utils.ansi.ANSIParser attribute)
      • initialize_for_combat() (evennia.contrib.turnbattle.tb_basic.TBBasicTurnHandler method) @@ -7645,6 +9067,28 @@
      • -
      • maxDiff (evennia.web.utils.tests.TestGeneralContext attribute) +
      • maxDiff (evennia.commands.default.tests.TestHelp attribute) + +
      • +
      • Mccp (class in evennia.server.portal.mccp) +
      • +
      • mccp_compress() (in module evennia.server.portal.mccp)
      • media() (evennia.utils.picklefield.PickledWidget property)
      • @@ -10161,9 +12109,33 @@

        N

        + -
        +
      • Naws (class in evennia.server.portal.naws) +
      • ndb() (evennia.server.serversession.ServerSession property)
      • no_exits (evennia.commands.cmdset.CmdSet attribute)
      • +
        -
        @@ -1131,6 +1396,7 @@ +
        develop branch
        @@ -88,7 +89,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -105,6 +105,7 @@ +
        develop branch
        @@ -272,7 +273,6 @@
      • 0.9.5 (v0.9.5 branch)
      • -
        @@ -289,6 +289,7 @@ +
        develop branch