From 0d50f9bcf88a9359c798cdb5672af61dcaf126b0 Mon Sep 17 00:00:00 2001 From: InspectorCaracal Date: Mon, 26 Sep 2022 12:34:42 -0600 Subject: [PATCH] cleanup and revisions --- .../character_creator/README.md | 21 +++--- .../character_creator/character_creator.py | 8 ++- .../character_creator/example_menu.py | 71 ++++++++++++++----- .../character_creator/tests.py | 0 4 files changed, 70 insertions(+), 30 deletions(-) rename evennia/contrib/{base_systems => rpg}/character_creator/README.md (82%) rename evennia/contrib/{base_systems => rpg}/character_creator/character_creator.py (97%) rename evennia/contrib/{base_systems => rpg}/character_creator/example_menu.py (88%) rename evennia/contrib/{base_systems => rpg}/character_creator/tests.py (100%) diff --git a/evennia/contrib/base_systems/character_creator/README.md b/evennia/contrib/rpg/character_creator/README.md similarity index 82% rename from evennia/contrib/base_systems/character_creator/README.md rename to evennia/contrib/rpg/character_creator/README.md index 9807f3a0f1..16965b7e9f 100644 --- a/evennia/contrib/base_systems/character_creator/README.md +++ b/evennia/contrib/rpg/character_creator/README.md @@ -8,8 +8,8 @@ This contrib is designed to be used in MULTISESSION_MODE = 2 or higher, where ch In your game folder `commands/default_cmdsets.py`, import and add `ContribCmdCharCreate` to your `AccountCmdSet`. Example: -```py -from evennia.contrib.base_systems.character_creator.character_creator import ContribCmdCharCreate +```python +from evennia.contrib.rpg.character_creator.character_creator import ContribCmdCharCreate class AccountCmdSet(default_cmds.AccountCmdSet): @@ -23,18 +23,21 @@ In your game folder `typeclasses/accounts.py`, import and inherit from `ContribC (Alternatively, you can copy the `at_look` method directly into your own class.) Example: -```py -from evennia.contrib.base_systems.character_creator.character_creator import ContribChargenAccount +```python +from evennia.contrib.rpg.character_creator.character_creator import ContribChargenAccount class Account(ContribChargenAccount): # your Account class code ``` -Lastly, in your `settings.py` file, define `CHARGEN_MENU` to your character creation menu module's location. +By default, the new `charcreate` command will reference the example menu provided by the contrib, so you can test it +out before building your own menu. You can reference [the example menu here]() for ideas on how to build your own. -Example: -```py -CHARGEN_MENU = "evennia.contrib.base_systems.character_creator.example_menu" +Once you have your own menu, just add it to your settings to use it. e.g. if your menu is in mygame/word/chargen_menu.py, +you'd add the following to your settings file: + +```python +CHARGEN_MENU = "world.chargen_menu" ``` ## Usage @@ -75,7 +78,7 @@ The contrib overrides the character creation command - `charcreate` - to use a c ### Changes to `Account.at_look` The contrib version works mostly the same as core evennia, but adds an additional check to recognize an in-progress character. If you've modified your own `at_look` hook, it's an easy addition to make: just add this section to the playable character list loop. -```py +```python for char in characters: # contrib code starts here if char.db.chargen_step: diff --git a/evennia/contrib/base_systems/character_creator/character_creator.py b/evennia/contrib/rpg/character_creator/character_creator.py similarity index 97% rename from evennia/contrib/base_systems/character_creator/character_creator.py rename to evennia/contrib/rpg/character_creator/character_creator.py index 976b2b176e..4a8328f3cb 100644 --- a/evennia/contrib/base_systems/character_creator/character_creator.py +++ b/evennia/contrib/rpg/character_creator/character_creator.py @@ -27,7 +27,11 @@ from evennia.objects.models import ObjectDB from evennia.utils import create, search from evennia.utils.evmenu import EvMenu -_CHARACTER_TYPECLASS = settings.BASE_CHARACTER_TYPECLASS +_CHARACTER_TYPECLASS = settings.BASE_CHARACTER_TYPECLASS +try: + _CHARGEN_MENU = settings.CHARGEN_MENU +except AttributeError: + _CHARGEN_MENU = "evennia.contrib.rpg.character_creator.example_menu" class ContribCmdCharCreate(MuxAccountCommand): """ @@ -97,7 +101,7 @@ class ContribCmdCharCreate(MuxAccountCommand): account.execute_cmd("ic {}".format(char.key)) EvMenu(session, - settings.CHARGEN_MENU, + _CHARGEN_MENU, startnode=startnode, cmd_on_exit=finish_char_callback) diff --git a/evennia/contrib/base_systems/character_creator/example_menu.py b/evennia/contrib/rpg/character_creator/example_menu.py similarity index 88% rename from evennia/contrib/base_systems/character_creator/example_menu.py rename to evennia/contrib/rpg/character_creator/example_menu.py index 5217b1431e..2a1a6b175c 100644 --- a/evennia/contrib/base_systems/character_creator/example_menu.py +++ b/evennia/contrib/rpg/character_creator/example_menu.py @@ -76,7 +76,7 @@ def menunode_welcome(caller): game wiki if you have one. """) help = "You can explain the commands for exiting and resuming more specifically here." - options = [{"desc": "Let's begin!", "goto": "menunode_info_base"}] + options = {"desc": "Let's begin!", "goto": "menunode_info_base"} return (text, help), options @@ -231,7 +231,6 @@ def _set_category_opt(caller, raw_string, category, value, **kwargs): # go back to the base node for the categories choice to pick another return "menunode_categories" - ######################################################### # Multiple Choice ######################################################### @@ -301,6 +300,18 @@ def _set_multichoice(caller, raw_string, selected=[], **kwargs): return ("menunode_multi_choice", {"selected": selected}) +######################################################### +# Simple List Options +######################################################### + +# If you just want a straightforward list of options, without any of the +# back-and-forth navigation or modifying of option text, evennia has an +# easy to use decorator available: `@list_node` + +# For an example of how to use it, check out the documentation for +# evennia.utils.evmenu - there's lots of other useful EvMenu tools too! + + ######################################################### # Starting Objects ######################################################### @@ -381,47 +392,69 @@ def menunode_choose_name(caller, raw_string, **kwargs): # another decision, so save the resume point char.db.chargen_step = "menunode_choose_name" - - text = dedent("""\ + + # check if an error message was passed to the node. if so, you'll want to include it + # into your "name prompt" at the end of the node text. + if error := kwargs.get("error"): + prompt_text = f"{error}. Enter a different name." + else: + # there was no error, so just ask them to enter a name. + prompt_text = "Enter a name here to check if it's available." + + # this will print every time the player is prompted to choose a name, + # including the prompt text defined above + text = dedent(f"""\ |wChoosing a Name|n Especially for roleplaying-centric games, being able to choose your character's name after deciding everything else, instead of before, is really useful. - Enter a name here to check if it's available. + {prompt_text} """) + help = "You'll have a chance to change your mind before confirming, even if the name is free." # since this is a free-text field, we just have the one - options = [ { "key": "_default", "goto": "menunode_check_charname" } ] + options = { "key": "_default", "goto": "_check_charname" } return (text, help), options -def menunode_check_charname(caller, raw_string, **kwargs): +def _check_charname(caller, raw_string, **kwargs): """Check and confirm name choice""" # strip any extraneous whitespace from the raw text # if you want to do any other validation on the name, e.g. no punctuation allowed, this is the place! charname = raw_string.strip() + # aside from validation, the built-in normalization function from the caller's Account does + # some useful cleanup on the input, just in case they try something sneaky + charname = caller.account.normalize_username(charname) + # check to make sure that the name doesn't already exist candidates = Character.objects.filter_family(db_key__iexact=charname) if len(candidates): - # the name is already taken - loop this node with new input to enter another name - text = f"|w{charname}|n is unavailable.\n\nEnter a different name." - options = [ { "key": "_default", "goto": "menunode_check_charname" } ] - return text, options + # the name is already taken - report back with the error + return ("menunode_choose_name", {"error": f"|w{charname}|n is unavailable.\n\nEnter a different name."}) else: # it's free! set the character's key to the name to reserve it caller.new_char.key = charname - text = f"|w{charname}|n is available! Confirm?" - # let players change their mind and go back to the name choice, if they want - options = [ - { "key": ("Yes", "y"), "goto": "menunode_end" }, - { "key": ("No", "n"), "goto": "menunode_choose_name" }, - ] - return text, options + # continue on to the confirmation node + return "menunode_confirm_name" + +def menunode_confirm_name(caller, raw_string, **kwargs): + """Confirm the name choice""" + char = caller.new_char + + # since we reserved the name by assigning it, you can reference the character key + # if you have any extra validation or normalization that changed the player's input + # this also serves to show the player exactly what name they'll get + text = f"|w{char.key}|n is available! Confirm?" + # let players change their mind and go back to the name choice, if they want + options = [ + { "key": ("Yes", "y"), "goto": "menunode_end" }, + { "key": ("No", "n"), "goto": "menunode_choose_name" }, + ] + return text, options - ######################################################### # The End diff --git a/evennia/contrib/base_systems/character_creator/tests.py b/evennia/contrib/rpg/character_creator/tests.py similarity index 100% rename from evennia/contrib/base_systems/character_creator/tests.py rename to evennia/contrib/rpg/character_creator/tests.py