Complete tutorial-intro menu

This commit is contained in:
Griatch 2020-10-04 19:11:55 +02:00
parent 32a13b63e7
commit abeace4e9e
2 changed files with 239 additions and 55 deletions

View file

@ -107,17 +107,18 @@ _ROOM_DESC = """
This is a small and comfortable wood cabin. Bright sunlight is shining in
through the windows.
Use |ylook box|n or |yl box|n to examine the box in this room.
Use |ylook sign|n or |yl sign|n to examine the wooden sign nailed to the wall.
"""
_BOX_DESC = """
The box is made of wood. On it, letters are engraved, reading:
_SIGN_DESC = """
The small sign reads:
Good! Now try '|ylook small|n'.
You'll get an error! There are two things that 'small' could refer to here
- the 'small box' or the 'small, cozy cabin' itself. You will get a list of the
possibilities.
... You'll get a multi-match error! There are two things that 'small' could
refer to here - the 'small wooden sign' or the 'small, cozy cabin' itself. You will
get a list of the possibilities.
You could either tell Evennia which one you wanted by picking a unique part
of their name (like '|ylook cozy|n') or use the number in the list to pick
@ -133,7 +134,7 @@ The box is made of wood. On it, letters are engraved, reading:
it's because you are playing with Builder-privileges or higher. Regular
players will not see the numbers.
Next look at the |wdoor|n.
Next try |ylook door|n.
"""
@ -162,7 +163,7 @@ _MEADOW_DESC = """
This is a lush meadow, just outside a cozy cabin. It's surrounded
by trees and sunlight filters down from a clear blue sky.
There is a |wstone|n here. Try looking at it.
There is a |wstone|n here. Try looking at it!
"""
@ -198,9 +199,9 @@ def _maintain_demo_room(caller, delete=False):
# we delete directly for simplicity. We need to delete
# in specific order to avoid deleting rooms moves
# its contents to their default home-location
prev_loc, room1, box, room2, stone, door_out, door_in = roomdata
prev_loc, room1, sign, room2, stone, door_out, door_in = roomdata
caller.location = prev_loc
box.delete()
sign.delete()
stone.delete()
door_out.delete()
door_in.delete()
@ -210,15 +211,17 @@ def _maintain_demo_room(caller, delete=False):
elif not roomdata:
# create and describe the cabin and box
room1 = create_object("evennia.objects.objects.DefaultRoom", key="A small, cozy cabin")
room1.db.desc = _ROOM_DESC.strip()
box = create_object(
"evennia.objects.objects.DefaultObject", key="small wooden box", location=room1
room1.db.desc = _ROOM_DESC.lstrip()
sign = create_object(
"evennia.objects.objects.DefaultObject", key="small wooden sign", location=room1
)
box.db.desc = _BOX_DESC.strip()
sign.db.desc = _SIGN_DESC.strip()
sign.locks.add("get:false()")
sign.db.get_err_msg = "The sign is nailed to the wall. It's not budging."
# create and describe the meadow and stone
room2 = create_object("evennia.objects.objects.DefaultRoom", key="A lush summer meadow")
room2.db.desc = _MEADOW_DESC.strip()
room2.db.desc = _MEADOW_DESC.lstrip()
stone = create_object(
"evennia.objects.objects.DefaultObject", key="carved stone", location=room2
)
@ -226,7 +229,8 @@ def _maintain_demo_room(caller, delete=False):
# make the linking exits
door_out = create_object(
"evennia.objects.objects.DefaultExit", key="Door", location=room1, destination=room2
"evennia.objects.objects.DefaultExit", key="Door", location=room1,
destination=room2, locks=["get:false()"],
)
door_out.db.desc = _DOOR_DESC_OUT.strip()
door_in = create_object(
@ -235,6 +239,7 @@ def _maintain_demo_room(caller, delete=False):
aliases=["door", "in", "entrance"],
location=room2,
destination=room1,
locks=["get:false()"]
)
door_in.db.desc = _DOOR_DESC_IN.strip()
@ -242,7 +247,7 @@ def _maintain_demo_room(caller, delete=False):
caller.db.tutorial_world_demo_room_data = (
caller.location,
room1,
box,
sign,
room2,
stone,
door_out,
@ -303,62 +308,110 @@ MENU_TEMPLATE = """
## NODE start
Welcome to the |cEvennia|n intro! From this menu you can learn some more about
the system and also the basics of how to play a text-based game. You can exit
this menu at any time by using "q" or "quit".
|g** Evennia introduction wizard **|n
For (a lot) more help, check out the documentation at http://www.evennia.com.
If you feel lost you can learn some of the basics of how to play a text-based
game here. You can also learn a little about the system and how to find more
help. You can exit this tutorial-wizard at any time by entering '|yq|n' or '|yquit|n'.
Write |wnext|n to continue or select a number to jump to that lesson.
Press |y<return>|n or write |ynext|n to step forward. Or select a number to jump to.
## OPTIONS
1 (next);1;next;n: About Evennia -> about_evennia
2: What is a MUD/MU*? -> about_muds
1 (next);1;next;n: What is a MUD/MU*? -> about_muds
2: About Evennia -> about_evennia
3: Using the webclient -> using webclient
4: The help command -> goto_command_demo_help()
5: Communicating with others -> goto_command_demo_help(gotonode='talk on channels')
6: Using colors -> goto_command_demo_comms(gotonode='testing_colors')
7: Moving and exploring -> goto_command_demo_room()
# ---------------------------------------------------------------------------------
## NODE about_evennia
Evennia is a game engine for creating multiplayer online text-games.
## OPTIONS
back;b: Start -> start
next;n: About MUDs -> about_muds
8: Conclusions & next steps-> conclusions
>: about_muds
# ---------------------------------------------------------------------------------
## NODE about_muds
The term MUD stands for Multi-user-Dungeon or -Dimension. These are the precursor
to graphical MMORPG-style games like World of Warcraft.
|g** About MUDs **|n
The term '|wMUD|n' stands for Multi-user-Dungeon or -Dimension. A MUD is
primarily played by inserting text |wcommands|n and getting text back.
MUDS were the |wprecursors|n to graphical MMORPG-style games like World of
Warcraft. While not as mainstream as they once were, comparing a text-game to a
graphical game is like comparing a book to a movie - it's just a different
experience altogether.
MUDs are |wdifferent|n from Interactive Fiction (IF) in that they are multiplayer
and usually has a consistent game world with many stories and protagonists
acting at the same time.
Like there are many different styles of graphical MMOs, there are |wmany
variations|n of MUDs: They can be slow-paced or fast. They can cover fantasy,
sci-fi, horror or other genres. They can allow PvP or not and be casual or
hardcore, strategic, tactical, turn-based or play in real-time.
Whereas 'MUD' is arguably the most well-known term, there are other terms
centered around particular game engines - such as MUSH, MOO, MUX, MUCK, LPMuds,
ROMs, Diku and others. Many people that played MUDs in the past used one of
these existing families of text game-servers, whether they knew it or not.
|cEvennia|n is a newer text game engine designed to emulate almost any existing
gaming style you like and possibly any new ones you can come up with!
## OPTIONS
back;b: About Evennia -> about_evennia
next;n: Using the webclient -> using webclient
next;n: About Evennia -> about_evennia
back to start;start;t: start
>: about_evennia
# ---------------------------------------------------------------------------------
## NODE about_evennia
|g** About Evennia **|n
|cEvennia|n is a Python game engine for creating multiplayer online text-games
(aka MUDs, MUSHes, MUX, MOOs...). It is open-source and |wfree to use|n, also for
commercial projects (BSD license).
Out of the box, Evennia provides a |wfull, if empty game|n. Whereas you can play
via traditional telnet MUD-clients, the server runs your game's website and
offers a |wHTML5 webclient|n so that people can play your game in their browser
without downloading anything extra.
Evennia deliberately |wdoes not|n hard-code any game-specific things like
combat-systems, races, skills, etc. They would not match what just you wanted
anyway! Whereas we do have optional contribs with many examples, most of our
users use them as inspiration to make their own thing.
Evennia is developed entirely in |wPython|n, using modern developer practices.
The advantage of text is that even a solo developer or small team can
realistically make a competitive multiplayer game (as compared to a graphical
MMORPG which is one of the most expensive game types in existence to develop).
Many also use Evennia as a |wfun way to learn Python|n!
## OPTIONS
next;n: Using the webclient -> using webclient
back;b: About MUDs -> about_muds
>: using webclient
# ---------------------------------------------------------------------------------
## NODE using webclient
|rNote: This is only relevant if you use Evennia's HTML5 web client. If you use a
|g** Using the Webclient **|n
|RNote: This is only relevant if you use Evennia's HTML5 web client. If you use a
third-party (telnet) mud-client, you can skip this section.|n
Evennia's web client is (when you install the server locally) found by pointing
your web browser to
Evennia's web client is (for a local install) found by pointing your browser to
|yhttp://localhost:4001/webclient|n
For a live example, the public Evennia demo can be found at
|yhttps://demo.evennia.com/webclient|n
The web client starts out having two panes - the input-pane for entering commands
@ -373,9 +426,9 @@ There is also some |wextra|n info to learn about customizing the webclient.
## OPTIONS
back;b: About MUDs -> about_muds
extra: Customizing the webclient -> customizing the webclient
next;n: Playing the game -> goto_command_demo_help()
back;b: About Evennia -> about_evennia
back to start;start: start
>: goto_command_demo_help()
@ -385,6 +438,8 @@ There is also some |wextra|n info to learn about customizing the webclient.
## NODE customizing the webclient
|g** Extra hints on customizing the Webclient **|n
|y1)|n The panes of the webclient can be resized and you can create additional panes.
- Press the little plus (|w+|n) sign in the top left and a new tab will appear.
@ -410,6 +465,7 @@ to a web client pane with a specific tag that you set yourself.
back;b: using webclient
> test *: send tagged message to new pane -> send_testing_tagged()
>: using webclient
# ---------------------------------------------------------------------------------
@ -417,7 +473,9 @@ to a web client pane with a specific tag that you set yourself.
## NODE command_demo_help
Evennia has about 90 default commands. They include useful administration/building
|g** Playing the game **|n
Evennia has about |w90 default commands|n. They include useful administration/building
commands and a few limited "in-game" commands to serve as examples. They are intended
to be changed, extended and modified as you please.
@ -436,8 +494,8 @@ those channels ...
## OPTIONS
back;b: Using the webclient -> using webclient
next;n: Talk on Channels -> talk on channels
back;b: Using the webclient -> using webclient
back to start;start: start
>: talk on channels
@ -445,6 +503,8 @@ those channels ...
## NODE talk on channels
|g** Talk on Channels **|n
|wChannels|n are like in-game chatrooms. The |wChannel Names|n help-category
holds the names of the channels available to you right now. One such channel is
|wpublic|n. Use |yhelp public|n to see how to use it. Try it:
@ -461,9 +521,10 @@ IRC support channel.
## OPTIONS
back;b: Finding help -> goto_command_demo_help()
next;n: Talk to people in-game -> goto_command_demo_comms()
back;b: Finding help -> goto_command_demo_help()
back to start;start: start
>: goto_command_demo_comms()
# ---------------------------------------------------------------------------------
@ -471,14 +532,16 @@ IRC support channel.
## NODE comms_demo_start
|g** Talk to people in-game **|n
You can also chat with people inside the game. If you try |yhelp|n now you'll
find you have a few more commands available for trying this out.
|ysay Hello there!|n
|y"Hello there!|n
|y'Hello there!|n
|wsay|n is used to talk to people in the same location you are. Everyone in the
room will see what you have to say. A single quote |y"|n is a convenient shortcut.
room will see what you have to say. A single quote |y'|n is a convenient shortcut.
|ypose smiles|n
|y:smiles|n
@ -492,11 +555,14 @@ include other people/objects in the emote, reference things by a short-descripti
next;n: Paging people -> paging_people
back;b: Talk on Channels -> talk on channels
back to start;start: start
>: paging_people
# ---------------------------------------------------------------------------------
## NODE paging_people
|g** Paging people **|n
Halfway between talking on a |wChannel|n and chatting in your current location
with |wsay|n and |wpose|n, you can also |wpage|n people. This is like a private
message only they can see.
@ -518,11 +584,14 @@ game by simply changing how the |wpose|n command parses its input.)
next;n: Using colors -> testing_colors
back;b: Talk to people in-game -> comms_demo_start
back to start;start: start
>: testing_colors
# ---------------------------------------------------------------------------------
## NODE testing_colors
|g** U|rs|yi|gn|wg |c|yc|wo|rl|bo|gr|cs |g**|n
You can add color in your text by the help of tags. However, remember that not
everyone will see your colors - it depends on their client (and some use
screenreaders). Using color can also make text harder to read. So use it
@ -558,6 +627,7 @@ color codes printed, try
next;n: Moving and Exploring -> goto_command_demo_room()
back;b: Paging people -> paging_people
back to start;start: start
>: goto_command_demo_room()
# ---------------------------------------------------------------------------------
@ -565,6 +635,8 @@ color codes printed, try
## NODE command_demo_room
|gMoving and Exploring|n
For exploring the game, a very important command is '|ylook|n'. It's also
abbreviated '|yl|n' since it's used so much. Looking displays/redisplays your
current location. You can also use it to look closer at items in the world. So
@ -575,16 +647,76 @@ around in. Explore a little and use |ynext|n when you are done.
## OPTIONS
back;b: Channel commands -> talk on channels
next;n: end
next;n: Conclusions -> conclusions
back;b: Channel commands -> testing_colors
back to start;start: start
>: conclusions
# ---------------------------------------------------------------------------------
## NODE conclusions
|gConclusions|n
That concludes this little quick-intro to using the base game commands of
Evennia. With this you should be able to continue exploring and also find help
if you get stuck!
Write |ynext|n to end this wizard and continue to the tutorial-world quest!
If you want there is also some |wextra|n info for where to go beyond that.
Good luck!
## OPTIONS
extra: Some more help on where to go next -> post scriptum
next;next;n: end
back;b: goto_command_demo_room()
back to start;start: start
>: end
# ---------------------------------------------------------------------------------
## NODE post scriptum
|gWhere to next?|n
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://github.com/evennia/evennia/wiki|n
- You can start by trying to build some stuff by following the |wBuilder quick-start|n:
|yhttps://github.com/evennia/evennia/wiki/Building-Quickstart|n
- The tutorial-world may or may not be your cup of tea, but it does show off
several |wuseful tools|n of Evennia. You may want to check out how it works:
|yhttps://github.com/evennia/evennia/wiki/Tutorial-World-Introduction|n
- You can then continue looking through the |wTutorials|n and pick one that
fits your level of understanding.
|yhttps://github.com/evennia/evennia/wiki/Tutorials|n
- Make sure to |wjoin our forum|n and connect to our |wsupport chat|n! The
Evennia community is very active and friendly and no question is too simple.
You will often quickly get help. You can everything you need linked from
|yhttp://www.evennia.com|n
# ---------------------------------------------------------------------------------
## OPTIONS
back: conclusions
>: conclusions
## NODE end
Thank you for going through the tutorial!
Thanks for trying out the tutorial!
"""
@ -598,6 +730,27 @@ class TutorialEvMenu(EvMenu):
_maintain_demo_room(self.caller, delete=True)
super().close_menu()
def options_formatter(self, optionslist):
navigation_keys = ("next", "back", "back to start")
other = []
navigation = []
for key, desc in optionslist:
if key in navigation_keys:
desc = f" ({desc})" if desc else ""
navigation.append(f"|lc{key}|lt|w{key}|n|le{desc}")
else:
other.append((key, desc))
navigation = (
(" " + " |W|||n ".join(navigation) + " |W|||n " + "|wQ|Wuit|n")
if navigation
else ""
)
other = super().options_formatter(other)
sep = "\n\n" if navigation and other else ""
return f"{navigation}{sep}{other}"
def testmenu(caller):
menutree = parse_menu_template(caller, MENU_TEMPLATE, GOTO_CALLABLES)

View file

@ -1651,6 +1651,13 @@ _OPTION_COMMENT_START = "#"
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
callable registered with the template generator. This involves parsing the
func-name and running literal-eval on its kwargs.
"""
match = _RE_CALLABLE.match(goto)
if match:
gotofunc = match.group("funcname")
@ -1681,6 +1688,12 @@ def _process_callable(caller, goto, goto_callables, raw_string,
def _generated_goto_func(caller, raw_string, **kwargs):
"""
This rerouter handles normal direct goto func call matches.
key : ... -> goto_callable(**kwargs)
"""
goto = kwargs["evmenu_goto"]
goto_callables = kwargs["evmenu_goto_callables"]
current_nodename = kwargs["evmenu_current_nodename"]
@ -1689,9 +1702,18 @@ def _generated_goto_func(caller, raw_string, **kwargs):
def _generated_input_goto_func(caller, raw_string, **kwargs):
"""
This goto-func acts as a rerouter for >-type line parsing (by acting as the
_default option). The patterns discovered in the menu maps to different
*actual* goto-funcs. We map to those here.
>pattern: ... -> goto_callable
"""
gotomap = kwargs["evmenu_gotomap"]
goto_callables = kwargs["evmenu_goto_callables"]
current_nodename = kwargs["evmenu_current_nodename"]
raw_string = raw_string.strip("\n") # strip is necessary to catch empty return
# start with glob patterns
for pattern, goto in gotomap.items():
@ -1704,18 +1726,23 @@ def _generated_input_goto_func(caller, raw_string, **kwargs):
return _process_callable(caller, goto, goto_callables, raw_string,
current_nodename, kwargs)
# no match, show error
raise EvMenuGotoAbortMessage(_HELP_NO_OPTION_MATCH)
def _generated_node(caller, raw_string, **kwargs):
"""
Every node in the templated menu will be this node, but with dynamically
changing text/options. It must be a global function like this because
otherwise we could not make the templated-menu persistent.
"""
text, options = caller.db._evmenu_template_contents[kwargs["_current_nodename"]]
return text, options
def parse_menu_template(caller, menu_template, goto_callables=None):
"""
Parse menu-template string
Parse menu-template string. The main function of the EvMenu templating system.
Args:
caller (Object or Account): Entity using the menu.
@ -1724,6 +1751,9 @@ def parse_menu_template(caller, menu_template, goto_callables=None):
on the form `callable(caller, raw_string, **kwargs)`. These are what is
available to use in the `menu_template` string.
Returns:
dict: A `{"node": nodefunc}` menutree suitable to pass into EvMenu.
"""
def _parse_options(nodename, optiontxt, goto_callables):
@ -1828,7 +1858,8 @@ def template2menu(
):
"""
Helper function to generate and start an EvMenu based on a menu template
string.
string. This will internall call `parse_menu_template` and run a default
EvMenu with its results.
Args:
caller (Object or Account): The entity using the menu.