From b63cb4c74d0f58304b5d5986ffb81f3cabd76881 Mon Sep 17 00:00:00 2001 From: Howard Abrams Date: Fri, 8 May 2026 23:21:45 -0700 Subject: [PATCH] Do other people want to see the this? Never see how the sausage is made. Especially if you are a vegetarian. --- README.md | 137 +- moss-n-puddles-map.svg | 157 + moss-n-puddles.org | 7211 ++++++++++++++++++++++++++++++++++++++++ requirements.txt | 2 + 4 files changed, 7480 insertions(+), 27 deletions(-) create mode 100644 moss-n-puddles-map.svg create mode 100644 moss-n-puddles.org create mode 100644 requirements.txt diff --git a/README.md b/README.md index fe62bd3..70b6fa1 100644 --- a/README.md +++ b/README.md @@ -1,40 +1,123 @@ -# Welcome to Evennia! +# Welcome to the World of Moss and Puddles -This is your game directory, set up to let you start with -your new game right away. An overview of this directory is found here: -https://github.com/evennia/evennia/wiki/Directory-Overview#the-game-directory +This contains the code, based on the [Evennia game engine][1] for +running a Multiuser Shared Story Experiment (MUSSE). -You can delete this readme file when you've read it and you can -re-arrange things in this game-directory to suit your own sense of -organisation (the only exception is the directory structure of the -`server/` directory, which Evennia expects). If you change the structure -you must however also edit/add to your settings file to tell Evennia -where to look for things. +The details in this document are technical and assume proficiency with +a Terminal emulator, e.g. `Terminal` app on MacOS and `PowerShell` on +Windows. -Your game's main configuration file is found in -`server/conf/settings.py` (but you don't need to change it to get -started). If you just created this directory (which means you'll already -have a `virtualenv` running if you followed the default instructions), -`cd` to this directory then initialize a new database using +## Running Locally + +These instructions assume that you have [Git][2] installed, +and you can `clone`this repository. + + git clone https://howardabrams.com/git/howard/moss-n-puddles + +This may be a slight chicken/egg scenario, since I store this file in +the repository. + +To get a local copy running on your system, follow these steps. + +### Install Python + +Follow the [online instructions][3] if you don't have the Python +language engine installed. + +### Create Virtual Environment (Optional) + +While optional, you may not want to pollute your global Python +environment, so create a "virtual environments" to insure that module +libraries don't compete. + + python -m venv .venv + +For further details on this, follow these instructions: +https://www.geeksforgeeks.org/python/create-virtual-environment-using-venv-python/ + +### Activate the Virtual Environment (Optional) + +Each time you enter this directory folder, `activate` the virtual +environment with the command: + + source .venv/bin/activate + +To make this easier, you can install [direnv][4]. + +### Install Support Modules + +Install [Evennia][1] and other needed modules with the command: + + pip install -r requirements.txt + +### Configure Database + +Before you can start this program, you need to initialize the database +using the command: evennia migrate -To start the server, stand in this directory and run +Any time you want to re-initialize the database from scratch, type: + + rm server/evennia.db + +To make my life easier, I issue: + + cp server/evennia-reset.db3 server/evennia.db3 + +### Start the Server + +Start the server with the command: evennia start -This will start the server, logging output to the console. Make -sure to create a superuser when asked. By default you can now connect -to your new game using a MUD client on `localhost`, port `4000`. You can -also log into the web client by pointing a browser to -`http://localhost:4001`. +When you first do this, you will need to create a account for the +superuser account, we call **The Avatar**. The question about email is +optional. -# Getting started +You can stop the server using the command: `evennia stop` -From here on you might want to look at one of the beginner tutorials: -http://github.com/evennia/evennia/wiki/Tutorials. +### Load the World -Evennia's documentation is here: -https://github.com/evennia/evennia/wiki. +Log into the system. The easiest way is to use a browser and this URL: -Enjoy! + http://localhost:4001 + +You can also use a MUD client connecting to the `localhost` on port 4000. + +You will need to connect with the user and password you created in the +Terminal (described above). + +At this point, you won't see anything because the database is empty. +To populate the world, type the following command in the game (not in +your Terminal window): + + batchcommand version1.ev + +A lot of text will fly by and it [recreates the world][9] described in +[Org-formatted document](moss-n-puddles.org). Those are my *notes* for +the game, which I should probably clean up for public consumption. You +will probably want to use [Emacs][5] get the most out of that text +document. + +Check out [my map](moss-n-puddles-map.svg) I made (shame this isn't +dynamically generated). + +## Technical Details + +Peruse the [directory structure overview][6]. + +Read the logs in the file: `server/logs/server.log` + +You might want to look at Evennia's [beginner tutorials][7], or the +complete [documentation][8]. + + [1]: evennia.com + [2]: git-scm.com + [3]: https://www.python.org/downloads/windows/ + [4]: direnv.net + [5]: https://www.gnu.org/software/emacs + [6]: https://github.com/evennia/evennia/wiki/Directory-Overview#the-game-directory + [7]: http://github.com/evennia/evennia/wiki/Tutorials. + [8]: https://github.com/evennia/evennia/wiki + [9]: moss-n-puddles.html diff --git a/moss-n-puddles-map.svg b/moss-n-puddles-map.svg new file mode 100644 index 0000000..0ab46ac --- /dev/null +++ b/moss-n-puddles-map.svg @@ -0,0 +1,157 @@ + + +Prairie +(mp14) + +Bedroom +(mp13) + + + +up +down + +Cozy Room +(mp03) + +Boulder Top +(mp02) + +Lair +(mp07) + +Wyldwood +Bar +(mp10) + +Dark Tunnel +(mp20) + +Cramped +Kitchen +(mp11) + +Grotto +(mp04) + + + +east +west + +Matriarch +Grove +(mp01) + + + +east +west + +Frog +Meadow +(mp05) + + + +east +west + +Glittering +Glade +(mp19) + +Secret +Room +(mp12) + +Sandy +Shore +(mp15) + + + + +Lazy +Dock +(mp06) + +Mellow +Marsh +(mp08) + +Old +Shack +(mp16) + +Boat & +Islands +(grXX) + +Homey +Hut +(mp09) + +Deep +Forest +(mp00) + + + + + + wardrobe + + + +  ladder +trapdoor   + + + +archway + + + +??  + + + +red  + door + + + + climb + + + + south +north  + + + +waterfall   + + + + south +north  + + + +??  + + + +??  + + + +door  + + + +blue  door + + diff --git a/moss-n-puddles.org b/moss-n-puddles.org new file mode 100644 index 0000000..0d803f4 --- /dev/null +++ b/moss-n-puddles.org @@ -0,0 +1,7211 @@ +#+TITLE: Wonderful World of Mud : Moss and Puddles Edition +#+AUTHOR: Howard Abrams +#+EMAIL: howard@howardabrams.com +#+DATE: 2025-01-18 Sat +#+LASTMOD: [2025-01-18 Sat] +#+FILETAGS: projects computer technical evennia +#+STARTUP: inlineimages +#+PROPERTY: header-args:evennia :tangle ~/src/moss-n-puddles/world/version1.ev :comments both +#+PROPERTY: header-args:tcl :tangle ~/src/moss-n-puddles/world/test-run.exp +#+PROPERTY: header-args:yaml :tangle ~/src/moss-n-puddles/world/hints.yaml +#+PROPERTY: header-args :results none :eval no-export :comments no + + + - [ ] Create goggles to show /gold tint/, and remove the /tint/ otherwise + - [ ] Create /Picker/, the goblin janitor that sweeps through land, deleting all items that /should not/ be there. + - Should I have a YAML file that lists what /should/ be in each room? + - Would the file also show the order and what rooms to follow? + - Perhaps he moves it to tunnels under the Lair? + - [ ] Create /Peddler/, the goblin, and his Emporium and Home Furnishings + - A new =buy= command that exchanges money for an item. + - Need a sign with the items and money … come from a YAML file? + - [ ] The Troll’s gambling den … part of the bar? under the bridge? + +* Evennia Server +** Background +While I believe I could use any MUD server, I’m trying out [[https://www.evennia.com/][Evennia]]. Based on Python, but I won’t hold that against it. Evennia comes up fast, has great features, and good documentation. Python-based projects inspires people, I guess. This file started out as my /notes/ about the process, but grew. Started with writing the Evennia commands I used to create my world (wasn’t sure if when I needed to wipe the database), but realized I could /tangle/ these commands (in org blocks) to an =.ev= file that I could load with the =batchcommands= command. I organized this file mostly around the “rooms” in the game, with “objects” nested inside. Next, I added YAML snippets to create the hint file (since the hints are based on the room location). Then, I included [[Testing the World Experience][Expect/Tcl code]] to have a /test character/ walk through the game testing the features I coded. + +When I decided to expand my world to be more /role play centric/, I created a [[file:mud-rpg.org][mud-rpg.org]] file, that tangles its code to =version2.ev=. Then, when adding escape rooms, I created [[file:mud-adventure.org][mud-adventure.org]], and tangle it to =adventure1.ev=. +** Installation +Follow the online instructions for Evennia: + +#+BEGIN_SRC sh + pip install cryptography paramiko evennia ipython requests +#+END_SRC + +Seems like the SSL with the telnet protocol, install: + +#+BEGIN_SRC sh + pip install pyopenssl +#+END_SRC + +For SSH, do: + +#+BEGIN_SRC sh + pip install paramiko service_identity +#+END_SRC + +I was hoping that the databases between my local world and the one on my server would /sync/. Wishful thinking, so to start over, delete =server/evennia.db= and issue: + +#+BEGIN_SRC sh + evennia migrate +#+END_SRC + +Feel free to delete the old database in order to restart (as this file should contain everything we need). + +#+BEGIN_SRC sh + mv server/evennia.db3 server/evennia-v1.db3 +#+END_SRC + +And then start or restart (or reload, I think): + +#+BEGIN_SRC sh + evennia start +#+END_SRC + +** Shell +Start the shell to test Python changes in a REPL. Note: If the Evennia /virtual environment/ contains =ipython=, it can use it as its shell. + +#+BEGIN_src evennia :tangle no +evennia shell +#+end_src + +Load all the necessary libraries to make REPL stuff workable. This could be tangled to =~/.conf/ipython/profiles/default.py= so the libraries would be available to that shell. + +#+BEGIN_SRC python :tangle no +from typeclasses.characters import Character +#+end_src + +And set some good variables: + +#+BEGIN_SRC python :tangle no +me = Character.characters.searchdbref("#1") +#+end_src + +** Create an Avatar +The first character is special, as it can really /own/ the server. I don’t use it except to build the world, otherwise, I will puppet a creation. + +An avatar in the original sense of a housing for a god-like entity. + +#+BEGIN_src evennia + @name self = Avatar +#+END_SRC + +#+BEGIN_src evennia + @setdesc A translucent being of light and energy. The surrounding world seems vivid and vibrant as it basks in the radience. +#+END_SRC + +#+BEGIN_src evennia + @sdesc angelic being +#+END_SRC + +And to pose: + +#+BEGIN_src evennia + py self.db.pose = True + # + pose looking awesome +#+END_SRC + +* World: Moss and Puddles +** Starting Introduction +Would love to have the following /introduction/. Done by editing [[file:~/src/moss-n-puddles/server/conf/connection_screens.py::CONNECTION_SCREEN = """][connection_screens.py]]: + +#+begin_example +Wha...what is this place? + +You followed his instructions. Head to the Gladstone city park, and on the woodsy side, turn left at the lamp post. Peer in the brambles and when you see the red handkerchief tied to branch, follow it ... + +Just keep following the red kerchiefs, until... +#+end_example + +To give someone a special _log on_ message the /first time/, I have updated the =Character= [[file:~/src/moss-n-puddles/typeclasses/characters.py::def at_object_creation(self):][creation function]] to give them a letter. + +I also thought they could type =help start=, to see, but this is easier to [[file:~/src/moss-n-puddles/world/help_entries.py][edit in source]]. + +** Title Sequence + +#+begin_example +• ▌ ▄ ·. .▄▄ · .▄▄ · ▄▄▄· ▐ ▄ ·▄▄▄▄ +·██ ▐███▪▪ ▐█ ▀. ▐█ ▀. ▐█ ▀█ •█▌▐███▪ ██ +▐█ ▌▐▌▐█· ▄█▀▄ ▄▀▀▀█▄▄▀▀▀█▄ ▄█▀▀█ ▐█▐▐▌▐█· ▐█▌ +██ ██▌▐█▌▐█▌.▐▌▐█▄▪▐█▐█▄▪▐█ ▐█ ▪▐▌██▐█▌██. ██ +▀▀ █▪▀▀▀ ▀█▄▀▪ ▀▀▀▀ ▀▀▀▀ ▀ ▀ ▀▀ █▪▀▀▀▀▀• + ▄▄▄·▄• ▄▌·▄▄▄▄ ·▄▄▄▄ ▄▄▌ ▄▄▄ ..▄▄ · + ▐█ ▄██▪██▌██▪ ██ ██▪ ██ ██• ▀▄.▀·▐█ ▀. + ██▀·█▌▐█▌▐█· ▐█▌▐█· ▐█▌██▪ ▐▀▀▪▄▄▀▀▀█▄ + ▐█▪·•▐█▄█▌██. ██ ██. ██ ▐█▌▐▌▐█▄▄▌▐█▄▪▐█ + .▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀▀▀• .▀▀▀ ▀▀▀ ▀▀▀▀ +#+end_example +** Map Locations + +#+begin_src pikchr :file moss-n-puddles-map.svg :results file :exports both :dark-mode + # bgcolor = 0x1d2021 + # fgcolor = 0xeeeeee + + Prairie: box rad 5px "Prairie" "(mp14)" + + # Top row: + Bedroom: box rad 5px "Bedroom" "(mp13)" at 1 below Prairie + arrow <-> "up" "down" + CozyRoom: box thick rad 5px "Cozy Room" "(mp03)" + move + Boulder: box rad 5px "Boulder Top" "(mp02)" + move + Lair: box rad 5px "Lair" "(mp07)" + move + Bar: box thick rad 5px "Wyldwood" "Bar" "(mp10)" + + Tunnel: box rad 5px "Dark Tunnel" "(mp20)" at 1 above Lair + + # Second row: + Kitchen: box rad 5px "Cramped" "Kitchen" "(mp11)" at 1 below Bedroom + move + Grotto: box rad 5px "Grotto" "(mp04)" + arrow <-> "east" "west" + Grove: box thick thick rad 5px "Matriarch" "Grove" "(mp01)" + arrow <-> "east" "west" + Meadow: box rad 5px "Frog" "Meadow" "(mp05)" + arrow <-> "east" "west" + Glade: box rad 5px "Glittering" "Glade" "(mp19)" + + # Third row: + Secret: box rad 5px "Secret" "Room" "(mp12)" at 1 below Kitchen + move + Shore: box rad 5px "Sandy" "Shore" "(mp15)" + arrow <-> + Dock: box rad 5px "Lazy" "Dock" "(mp06)" + move + Marsh: box rad 5px "Mellow" "Marsh" "(mp08)" + + # Fourth row: + Shack: box rad 5px "Old" "Shack" "(mp16)" at 1 below Shore + move + Boat: box rad 5px "Boat &" "Islands" "(grXX)" + move + Hut: box rad 5px "Homey" "Hut" "(mp09)" + + OOB: circle thick "Deep" "Forest" "(mp00)" fit at 1.5 right of Prairie + arrow -> thin from OOB.se to 0.65 right of CozyRoom to Grotto.ne + + arrow <-> " wardrobe" ljust from Prairie.s to Bedroom.n + arrow <-> " ladder" above ljust "trapdoor " below rjust from Tunnel.s to Lair.n + arrow <-> "archway" aligned above from Kitchen.n to CozyRoom.sw + arrow <-> "?? " rjust from Secret.ne to CozyRoom.sw + arrow <-> "red " rjust " door" ljust from CozyRoom.s to Grotto.n + arrow <-> " climb" ljust from Boulder.s to Grove.n + arrow <-> " south" above ljust "north " below rjust from Grove.s to Dock.n + arrow <-> "waterfall " rjust from Lair.s to Meadow.n + arrow <-> " south" above ljust "north " below rjust from Meadow.s to Marsh.n + arrow <-> "?? " rjust from Marsh.s to Hut.n + arrow <-> "?? " rjust from Dock.s to Boat.n + arrow <-> "door " rjust from Shore.s to Shack.n + arrow <-> "blue door" from Bar.s to Glade.n +#+end_src + +[[file:mud-map.svg]] +** Testing the World Experience +Using the infamous [[https://core.tcl-lang.org/expect/index][Tcl/Expect system]], I can log on with a /test account/ and use it to generate commands and validate the output. + +#+BEGIN_SRC tcl :shebang #!/usr/bin/expect :chmod 0755 + # Set timeout for expect commands + set timeout 30 + + # Open the log file + log_file results.txt +#+END_SRC + +If I don’t find what I’m looking for, instead of just /continuing/, I want it to fail. I create the =expectit= function as a replacement for =expect=: + +#+BEGIN_SRC tcl + # Rename the original 'send' to 'real_send' + rename send real_send + + # Define a new 'send' procedure + proc send {args} { + puts -nonewline ">> " + flush stdout + # 'uplevel' ensures it executes in the right context + uplevel 1 real_send $args + } + + proc expectit {pattern} { + expect { + $pattern { + return + } + timeout { + puts "ERROR: Expected response '$pattern' not received." + send "quit\n" + exit 1 + } + eof { + puts "ERROR: Connection closed unexpectedly." + send "quit\n" + exit 1 + } + } + } +#+END_SRC + +Since some objects in my world /don’t/ appear until /triggered/, I would like to test for that /negative/ case, but I don’t know Expect well enough to figure that out programmatically, so I create a function, and call out what to /visually look at/: + +#+BEGIN_SRC tcl + proc dont_expect {trigger pattern} { + send "look\n" + puts "NOTE: At this point, ** $pattern ** should not be here!" + } +#+END_SRC + +That is, until I can get the following code to work: + +#+BEGIN_SRC tcl :tangle no + proc dont_expect {trigger pattern} { + send "look\n" + puts "Entering dont_expect with trigger: '$trigger' and pattern: '$pattern'" + expect { + -re {.*$trigger.*$pattern.*} { + puts "FAILURES!" + send "quit\n" + exit 1 + } + -re {.*$trigger.*} { + puts "Goodness" + } + timeout { + puts "Error: Expected output not received within the timeout period." + send "quit\n" + exit 1 + } + eof { + puts "Error: Connection closed unexpectedly." + send "quit\n" + exit 1 + } + } + } +#+END_SRC + +I would like to log on locally via =telnet= and on my /real server/ using =ssh=, so a command line option, =there= tells me what to =spawn=: + +#+BEGIN_SRC tcl + # Get command line parameters + set there [lindex $argv 0] ; # First parameter (boolean) here/there + set tutorial [lindex $argv 1] ; # Second parameter (optional) yes/no + set create [lindex $argv 2] ; # Third parameter (optional) yes/no + + if {$there eq "there"} { + spawn ssh -p 4004 user@howardabrams.com + # Handle the un-used password prompt: + expectit "password:" + send "\r" ; # Send an empty password + } else { + spawn telnet localhost 4000 + } +#+END_SRC + +The testing account is currently the =guest= account: + +#+BEGIN_SRC tcl + # Handle the prompt after logging in + expectit "enclose it in quotes" + + if {$create eq "true"} { + send "create rob backinqa\n" + expectit "Is this what you intended?" + send "y\n" + expectit "You can now log with the command" + } + + send "connect rob backinqa\n" + + if {$create eq "true"} { + expectit "begin creating your character" + send "\n" + + expectit "Let's begin with a two or three word description" + send "spry goblin\n" + + expectit "Specifying the gender" + send "n\n" + + expectit "Enter an initial pose" + send "curiously looking at everything\n" + + expectit "Enter your character's full description" + send "A short, skinny goblin wearing a dirty tunic cinched with an elaborate belt bejeweled with gems and gold filigree. Unclear whether his green ears or nose are longer, but surely it must be the few hairs he combs over on top of his head.\n" + + expectit "Enter a name here to check if it's available." + send "Speedy Gonzoblin\n" + + expectit "Shall I create your character" + send "y\n" + } else { + send "sdesc spry goblin\n" + expectit "sdesc was set" + + send "pose zipping about\n" + expectit "Pose will read" + } +#+END_SRC + +Note that creating the testing character is not sufficient in and of itself (works the first time, obviously), but while it is logged in, we need to give the command: + +#+BEGIN_src evennia :tangle no + @teleport/quiet mp01 + # + @set goblin/guest_account = True +#+END_SRC + +How much of the tutorial do we want to test? + +#+BEGIN_SRC tcl + if {[string match "tutor*" $tutorial]} { + # Handle the game command prompt + expectit "In this story game, you type commands" + send "look\n" + + # Handle the prompt to examine the puddle + expectit "You can now type" + send "look puddle\n" + + # Handle the response about flying + expectit "Yes, I could fly myself" + send "look boulder\n" + + # Handle the prompt about climbing the boulder + expectit "You can climb this boulder!" + send "climb\n" + + # Handle the prompt about typing + expectit "Go ahead, just typing" + send "say Hello there, little birdie.\n" + } else { + expectit "perches on your shoulder" + } +#+END_SRC + +At this point, stop the bird shenanigans, and get moving… + +#+BEGIN_SRC tcl + # That should be enough of the birdie ... + send "shoo\n" +#+END_SRC + +Let’s get the server’s =time=, as we can use this information to adjust our tests. + +#+BEGIN_SRC tcl + # Send the time command and handle the response + expectit "Have fun, and I'll leave you here" + + send "time\n" + expect { + "in the evening" { + set phase "evening" + } + "in the afternoon" { + set phase "afternoon" + } + "in the morning" { + set phase "morning" + } + "in the night" { + set phase "night" + } + timeout { + puts "ERROR: Expected time response not received." + send "quit\n" + exit 1 + } + } +#+END_SRC + +Let’s get building this world! +** The Grove of the Matriarchs +Rename the Limbo (or starting place) with the name *Grove of the Matriarchs*. Note the term =mp01= as a global label that matches my map. My original term for “forest” is too general, as it sounds like the place should be /named/ with some sort of title. + +#+BEGIN_src evennia + @name here = Grove of the Matriarchs;mp01 +#+END_SRC + +The description will take advantage of the /seasons/ and /times/ of the day: + +#+BEGIN_src evennia + @desc here = A giant, moss-covered |Yboulder|n hides a |Yhollow recess|n as it stands among immense |Ytrees|n that etch the sky and slice the clouds in the darkening twilightawakening dawnlazy afternoonnight sky. With the morning light, you can hear the dawn chorus of birdsThe afternoon breeze carries the buzzing of insects around giant colorful |Yflowers|nYou can't hear much now as most of the forest creatures are settling down for the nightIn the darkness, you can hear crickets and an occasional owl. A footpath winds around the giant, moss-covered tree roots to the East and West. To the south, a dock juts into a lavender sea. +#+end_src + +And a brief test of the time states in the output of the =look= command: + +#+BEGIN_SRC tcl + send "look\n" + + # Expect different responses based on the phase variable + switch $phase { + "evening" { + expect "darkening twilight" + } + "afternoon" { + expect "lazy afternoon" + } + "morning" { + expect "awakening dawn" + } + "night" { + expect "night sky" + } + default { + puts "ERROR: Unexpected phase value '$phase'." + send "quit\n" + exit 1 + } + } +#+END_SRC + +Need to add weather and time data to this: +#+begin_src evennia + @update here = typeclasses.rooms_weather.TimeWeatherRoom +#+end_src + +Derived from the original [[~/src/moss-n-puddles/.venv/lib/python3.12/site-packages/evennia/contrib/tutorials/tutorial_world/rooms.py][rooms.py]], but now stored in [[file:~/src/moss-n-puddles/typeclasses/rooms_weather.py][rooms_weather.py]]. + +Describe the trees, flowers, and of course, the alcove: + +#+BEGIN_src evennia + @detail tree;trees = You feel dwarfed by colossal trees whose moss-covered roots are difficult to peer over. An occassional breeze often smells of flowers and at other times earthy. While the leafy canopy hides the sky, you certainly can |wfeel|n the weather. + # + @detail flower;flowers = Beautiful, but giant flowers look down on you and nod a friendly greeting. + # + @detail hollow recess;recess;hollow;alcove = Underneath the boulder, you see a dry alcove full of mushrooms. On the largest, is a |Yleather-bound book|n. +#+END_SRC + +We don’t need to test all the =details=, but the first one: + +#+BEGIN_SRC tcl + send "look trees\n" + expectit "You feel dwarfed by colossal trees" + + send "look flowers\n" + expectit "Beautiful, but giant flowers look down on you and nod a friendly greeting." +#+END_SRC + +And an image for it. + +#+begin_example +Generate a watercolor with pen and ink outlining in vibrant colors, depicting a +path meandering between the roots of tall trees past a giant boulder covered in moss and vines of ivy. +There is a puddle by the path. +Under the roots of a tree is a large mushroom supporting an opened book and a feather quill. +The style should have elements of fantasy. +#+end_example +*** Barkbinder the Tree +When you first log into the game, you can immediately chat with an unfriendly, overly boring tree. +#+BEGIN_SRC evennia + @create/drop tree;trees: typeclasses.chatbots.ChatBot + # + @set tree/gender = "neutral" + # + @set tree/pose = "contemplating...or sleeping" + # + @set tree/pose_sleep = "contemplating...or sleeping" +#+END_SRC + +Then wake it. + +#+BEGIN_SRC evennia + py tree = me.search("tree") ; tree.sdesc.add("especially large tree") ; tree.backstory("tree") +#+END_SRC + + +*** Hints +What about /hints/? Since this is the /first room/, I didn’t want it complicated or clever, but we could mention that they should =look boulder=: + +#+BEGIN_SRC yaml + --- + grove_of_the_matriarchs: + narrative: >- + << Bubba Joe Washington ^ That cockatiel >> returns, and perches on your shoulder, + "Heya," it chirps. "I know I gave you a lot of information when you started. + So here's a bit of a hint. {0} Good luck, again." It flies off. + hints: + default: >- + Look at everything. For instance, if you |glook boulder|n you + might notice something new that becomes available. +#+END_SRC + +And we can have our test account verify that =hint= works: + +#+BEGIN_SRC tcl + send "hint\n" + expectit "Look at everything" +#+END_SRC + +*** Puddle +With my name, I need to have an object to go with it. + +#+BEGIN_src evennia + @create/drop puddle : typeclasses.things.Puddle +#+END_SRC + +And an elusive description: + +#+BEGIN_src evennia + @desc puddle = A large puddle, formed from a recent rain shower, invites you to shed your years and |gjump|n in and splash around to reconnect with your youth. +#+END_SRC + +And keep it locked down: + +#+BEGIN_src evennia + @lock puddle = get:false() + # + @set puddle/get_err_msg = "As the water slips through your fingers, you realize the apt metaphor of attempting to grasp at your youth." +#+END_SRC + +And a test of our ability to jump in the puddle: + +#+BEGIN_SRC tcl + send "look puddle\n" + expectit "A large puddle" + + send "get puddle\n" + expectit "As the water slips through your fingers" + + send "jump\n" + expectit "You jump in the puddle!" +#+END_SRC + +*** Sticks +I will have a script auto generate the sticks on a regular basis, but for now, let’s just make one that I can drop. + +#+BEGIN_src evennia + py timed_script = evennia.create_script(key="Create Sticks", + typeclass='typeclasses.scripts.CreateSticks', + interval=86800, # more than a day + start_delay=False, # wait interval before first call + autostart=True, + attributes=[("destination", here)] ) +#+END_SRC + +And let’s see if the stick behaves: + +#+BEGIN_SRC tcl + send "get stick\n" + expect { + "Could not find 'stick'." { + # Print warning in red + # send_user "\033[31mNo stick, check the stick script.\033[0m\n" + send_user "No stick, check the stick script.\n" + } + "You pick up a stick." { + # If stick is found, throw it + send "throw stick\n" + expect "it comes back to you" + + send "drop stick\n" + expect "You drop a stick." + } + timeout { + puts "ERROR: Expected response for 'get stick' not received." + send "quit\n" + exit 1 + } + } +#+END_SRC + +*** Guest Book +Players can leave messages in this book. We’ll see how long I want to leave this. + +#+BEGIN_src evennia + @create/drop guest book:typeclasses.readables.WriteableBook + # + @set guest book/inside = "file:world/guest-book.md" + # + @set guest book/prefix = "You open the leather-bound book, and begin to read from page one..." +#+END_SRC + +Note that we don’t mention this in the area’s description. + +#+BEGIN_src evennia + @desc guest book = In a hollow recess underneath the boulder, you find a leather-bound book entitled |wGuest Book|n perched atop a giant mushroom. Protected from the elements, this natural desk includes a feather |Yquill|n and an |Yink|n |Ywell|n inviting you to |gread|n and even |gwrite|n a note for other travelers. +#+END_SRC + +Can’t get it: + +#+BEGIN_src evennia + @lock guest book = get:false() + # + @set guest book/get_err_msg = "The owner designed a guest book to be read and written by guests. Pocketing it for selfish interests sort of defeats the purpose." +#+END_SRC + +And some details: + +#+BEGIN_src evennia + @detail quill = The black feathered quill may once belonged to a raven, but if so, it must have been large. + # + @detail ink = Black, like the ichor of the gods ... or perhaps, someone just started a squid. + # + @detail well;ink well = The well appears to be little more than a depression on the back of the mushroom's cap. +#+END_SRC + +How should the book start? + +#+begin_src markdown :tangle ~/src/moss-n-puddles/world/guest-book.md + # Introduction + + For repayment of a boon, The Summer Queen granted a charter to me, The + Dabbler, for the land between the two trees, |wErui|n and |wVedui|n, + and what you see comprise the results, |wMossydór|n. I can't be blamed + that while siblings, both trees detest each other, and work to retreat + from each other's company, expanding my domain. + + If you have arrived here through trials and travels, please leave us a + note, introducing yourself and your land of origin. And + |walatulya|n, that is, welcome. + + > From: Dabber + > User: howard + + # Flicker Glimmerwing + + What a nice place. I come from a land called Delight, but I'm not sure + how I came here. If any one reads this, do you think we can do + something about the rain? Bit dreary, don't you think? + + Please don't tell the owner of the hut that I |wborrowed|n her horn, + and used it to travel over the Lavender Sea. I promise I'll return it + when I'm done adventuring. + + Also, what's up with the monster in the meadow? Friend or foe? + + --Flicker Glimmerwing, Esq. + + > User: darol + + # Chomper + + Good place. Wet place. Where food? Berries not food. + + Beast in field like berries. Nice fellow. + + --Tealees Tahloos-ah + + > User: rick + + # Sir Roblees + + As a humble vassal of Her Magnificence, the Summer Queen and a + knight-errant of the Seelie Court, I bring news of a rare celestial + event, the Starflowers will bloom under the light of the next full + moon. The Queen Titania has decreed a Festival including grand + tournaments of skill and wit, to compete for the favor of the court. + + If interested, please meet me in the Wyldwood Bar. I am the good + looking one with the shiny jacket and magical sword. + + --Sir Roblees + + > User: george +#+end_src + +Let’s test that we can read the book: + +#+BEGIN_SRC tcl + send "look book\n" + expectit "In a hollow recess underneath the boulder" + + send "look quill\n" + expectit "The black feathered quill may once belonged to a raven" + + send "look ink\n" + expectit "Black, like the ichor of the gods" + + send "look ink well\n" + expectit "The well appears to be little more than a depression" + + send "read book\n" + # expect -re "You open the leather-bound book, and begin to read\[.\n\r\]*For repayment of a boon, The Summer Queen" + expectit "You open the leather-bound book, and begin to read" + expectit "For repayment of a boon, The Summer Queen" + + expectit "revious" + # quit reading the book: + send "q\n" + expectit "Exited pager" + sleep 1 + + send "get book\n" + expectit "The owner designed a guest book to be read and written by guests" +#+END_SRC + +*** Hidden Things + +When we look at something hidden, i.e. the /thing/ has a view lock of a particular tag, and if so, we interpret this as ‘since you are looking at something by name, you /now/ can see it.’ We give the looker the right to see it from now on. + +To use this to hide an object, add the following lock: + +#+BEGIN_src evennia :tangle no + @lock thing = view:tag(hidden_thing) +#+END_SRC + +Where /thing/ is the single name of the hidden object. Find the code [[file:~/src/moss-n-puddles/typeclasses/objects.py::o][in objects.py]]. + +#+BEGIN_src evennia :tangle no + @create/drop duck + @set duck/hidden_tag = "hidden_ducky" + @lock duck = view:tag(hidden_ducky) + look duck +#+END_SRC + +*** Boulder +More details about the room that describes aspects of the boulder in the =desc= above. First, the symbol: +#+BEGIN_src evennia + @detail symbol = You move an ivy runner to see three curves join together as if it were three legs. +#+END_SRC + +The moss is purdy: +#+BEGIN_src evennia + @detail moss = "Even in this light, the moss radiates a surreal color of green." +#+END_SRC + +And the ivy is … uh. +#+BEGIN_src evennia + @detail ivy = "You see...well, ivy. Uhm, it's green, and..." +#+END_SRC + +The runes use multi-byte Unicode which screws up the =telnet= client. +#+BEGIN_src evennia + @detail runes;rune = The runes read ᛞ ᚪ ᛒ ᛚ ᚱ +#+END_SRC + +The top of the boulder should be another room, accessible by the =climb=, but maybe it isn’t “seen” until the boulder has been looked? First, we put some weather at the top of the boulder: + +#+BEGIN_src evennia + @dig Boulder Top;mp02 : typeclasses.rooms_weather.TimeWeatherRoom = climb boulder;boulder;climb,climb down;climb;down +#+END_SRC + +The ability to /climb/ the boulder isn’t immediately obvious, so let’s make it a bit of a secret: +#+BEGIN_src evennia + @desc boulder = A boulder with patches of |Ymoss|n and delicate clover. A carved |Ysymbol|n and even some |Yrunes|n try to hide behind rope-like |Yvines|n and tendrils of |Yivy|n as if keeping a secret.|/|/You notice a foot hold, and then another. You can |Gclimb|n this boulder! +#+END_SRC + +To take advantage of our [[Hidden Things]], we put the right tag on it: +#+BEGIN_src evennia + @set boulder/hidden_tag = "hidden_boulder" + # + @lock boulder = view:tag(hidden_boulder) +#+END_SRC + +And give it some aliases: +#+BEGIN_src evennia + @name boulder = climb the boulder;boulder;climb;climb up;climb boulder +#+END_SRC + +And a description: +#+BEGIN_src evennia + @set boulder/traverse_msg = "You grab hold of some the |Yvines|n and ivy and pick your way up the boulder from one hold to another... Hrm, these vines would make a great rope." +#+END_SRC + +And tests to look at all the details; + +#+BEGIN_SRC tcl + send "look symbol\n" + expectit "You move an ivy runner to see three curves join together as if it were three legs." + + send "look moss\n" + expectit "Even in this light, the moss radiates a surreal color of green." + + send "look ivy\n" + expectit "You see...well, ivy. Uhm, it's green, and..." + + send "look rune\n" + expectit "The runes read ᛞ ᚪ ᛒ ᛚ ᚱ" + #+END_SRC + +Let’s test that the boulder (which we create in the next section), is indeed hidden. + +#+BEGIN_SRC tcl + dont_expect "Exits" "boulder" + + send "look boulder\n" + expectit "You notice a foot hold" + + send "look\n" + expect -re "Exits:.*climb.*boulder" +#+END_SRC +*** Lower Vines +In case they attempt to get vines here: + +Let’s make a nice spot to sit down on: +#+BEGIN_src evennia + @create/drop dangling vine;vines;vine +#+END_SRC + +With a nice description: +#+BEGIN_src evennia + @desc vines = Strong vines twisted to look like rope. This could be helpful. +#+END_SRC + +Can’t take it here, you have to climb the boulder first: +#+BEGIN_src evennia + @lock vines = get:false() + # + @set vines/get_err_msg = "The vines are too strong to break or cut. Perhaps they could be detached from the top of the |Yboulder|n?" +#+END_SRC + +Can we hide it too? +#+BEGIN_src evennia + @lock vines = view:tag(hidden_vines) + # + @set vines/hidden_tag = "hidden_vines" +#+END_SRC + +What about pushing and pulling messages? + +#+BEGIN_src evennia + @set vines/pull_msg = "You pull the vines, but they don't let go. Perhaps you could detach them if you were on |wtop|n of the |Yboulder|n?" + # + @set vines/push_msg = "That doesn't seem to do much." +#+END_SRC + +And the vines as well: + +#+BEGIN_SRC tcl + dont_expect "You notice.*" "vine" + + send "look vine\n" + expectit "Strong vines twisted to look like rope" + + send "look\n" + expect -re "You notice.*vines" + + send "get vine\n" + expectit "The vines are too strong to break or cut." + + send "pull vine\n" + expectit "You pull the vines, but they don't let go." + + send "push vine\n" + expectit "That doesn't seem to do much." +#+END_SRC +** Top of Boulder + +Let’s jump to the top of the boulder to proceed: +#+BEGIN_src evennia + @teleport mp02 +#+END_SRC + +And to test to see if we can climb the boulder: + +#+BEGIN_SRC tcl + send "climb boulder\n" + expectit "You grab hold of some" + + # Did we arrive? + expectit "Boulder Top" +#+END_SRC + +And the description: +#+BEGIN_src evennia + @desc here = While high, the |Ytrees|n still tower over you. Still, a nice view. Lots of patches of |Ymoss|n to |gsit|n down and relax. +#+END_SRC + +More details: +#+BEGIN_src evennia + @detail tree;trees = You feel dwarfed by colossal trees whose moss-covered roots are difficult to peer over. An occassional breeze often smells of flowers and other times earthy. While the leafy canopy hides the sky, you certainly can |wfeel|n the weather. +#+END_SRC + +And a description of the climb: +#+BEGIN_src evennia + @desc climb = The climb seemed easy, but you're not sure you can handle the footholds going the other way around. +#+END_SRC + +And describe the journey: +#+BEGIN_src evennia + @set climb/traverse_msg = "You crawl backwards, feeling with your foot for a hold. Got it! Then another one...hoping the vines and the moss' rhizoids hold..." +#+end_src + +#+BEGIN_SRC tcl + send "look trees\n" + expectit "You feel dwarfed by colossal trees" + + send "look down\n" + expectit "The climb seemed easy, but you're not sure you can handle the footholds going the other way around." + #+END_SRC + +A description? + +#+begin_example +Generate a watercolor with pen and ink outlining in vibrant colors, depicting the top of a boulder covered in ivy branches and a patch of orange mushrooms. +Sitting on a patch of moss is a squirrel dressed in Buddhist monk robes with closed eyes in meditation. +#+end_example +*** Moss +Let’s make a nice spot to sit down on: +#+BEGIN_src evennia + @create/drop patch of moss;moss:typeclasses.sittables.Sittable +#+END_SRC + +With a nice description: +#+BEGIN_src evennia + @desc patch of moss = A cushioned patch of moss of the most vibrant green. +#+END_SRC +Can’t take the moss with you: +#+BEGIN_src evennia + @lock patch of moss = get:false() +#+END_SRC +Can we hide it too? +#+BEGIN_src evennia + @lock patch of moss = view:tag(hidden_moss) + # + @set patch of moss/hidden_tag = "hidden_moss" +#+END_SRC + +And a lovely message about why you can’t steal moss: +#+BEGIN_src evennia + @set moss/get_err_msg = "The moss is a bryophyte, and as such, has attached itself to boulder by rhizoids, which are one cell thick root structures. While this helps with water absorption, you didn't think you were going to get a biology lesson, did you? tl;dr You can't get it." +#+END_SRC + +Is /pulling/ on moss the same as attempting to =get= it? + +#+BEGIN_src evennia + @set moss/pull_msg = "The moss is a bryophyte, and as such, has attached itself firmly to boulder by rhizoids. So pulling on it doesn't do much good." +#+END_SRC + +Let’s test if we can sit on the moss: + +#+BEGIN_SRC tcl + send "look moss\n" + expectit "A cushioned patch of moss of the most vibrant green." + + send "sit moss\n" + expectit "You sit on the patch" + + # We can't get this stuff: + send "get moss\n" + expectit "The moss is a bryophyte" +#+END_SRC + +*** Upper Vines +Let’s cover top of the boulder with rope-like vines. The vine can be a [[file:~/src/moss-n-puddles/typeclasses/consumables.py::class Producer(Object):][producer]] that makes ropes … needed to get into the hut. + +#+BEGIN_src evennia + @teleport mp02 + # + @create/drop lot of vines;vine;rope: typeclasses.consumables.Producer +#+END_SRC + +With a description: + +#+BEGIN_src evennia + @desc vines = While difficult to cut, the study and tough vines are easy to pull from this point on the boulder. You could probably make a sturdy rope from them. +#+END_SRC + +We have to have the vines describe what it /makes/: + +#+BEGIN_src evennia + @set vines/make_name = "coil of rope" +#+END_SRC + +And a verb when they /get/ the consumable: + +#+BEGIN_src evennia + @set vines/make_verb = "$conj(yank) and $conj(shape) a" +#+END_SRC + +And a commentary: + +#+BEGIN_src evennia + @set vines/make_note = " from the vines" +#+END_SRC + +This one is optional as it defaults to Consumable: +#+BEGIN_src evennia + @set vines/make_class = "typeclasses.things.Rope" +#+END_SRC + +And the vines needs to know the /description/ of the Consumable, so that it can attach that: +#+BEGIN_src evennia + @set vines/make_desc = "Made from vines, but could be a good lasso." +#+END_SRC + +How much is there when you pick them? +#+BEGIN_src evennia + @set vines/make_amount = 1 +#+END_SRC + +What if they do something other than =get= the vines? + +#+BEGIN_src evennia + @set vines/pull_msg = "You pull the vines, and notice they detach easily from the rock. Perhaps you should |gget|n these and make something with them." + # + @set vines/push_msg = "You push the vines out of the way showing the rock boulder below. Perhaps you should |gget|n these and make something with them." +#+END_SRC + +Let’s make sure that we can get the vines from this producer: + +#+BEGIN_SRC tcl + send "look vines\n" + expectit "While difficult to cut, the study and tough vines are easy to pull" + + send "pull vines\n" + expectit "You pull the vines" + + send "get vines\n" + expectit "You yank and shape a coil of rope from the vines" + + send "inv\n" + expectit "Made from vines" + + # Let's get another length of rope to try lassoing the hut twice: + send "get vines\n" + expectit "You yank and shape a coil of rope from the vines" + + # Let's head back to the grove... + send "down\n" + expectit "You stand up first" + + # Wait until we've arrived + expectit "Grove of the Matriarchs" +#+END_SRC + +Let’s have the room’s hint be about these vines: + +#+BEGIN_SRC yaml +boulder_top: + narrative: >- + The squirrel opens her eyes and stares at you intently for some time. + She then looks up at you, and says, "{0}" + hints: + default: >- + Now that you are here, you should sit down an contemplate + the |Ymoss|n, the |Yivy|n, the |Ymushrooms|n, and all living beings. + moss: Please, |gsit|n down on that |gmoss|n. + ivy: As these vines can be used to bind us and others, so too, can our thoughts. + vines: Like these vines can be used to bind us, so too, can our thoughts. + mushrooms: >- + Beautiful and joyous creatures. Literally. They laugh when you pick them up. +#+END_SRC + +*** Gigglecap Mushrooms + +Part of the [[Potions and their Ingredients][Alchemist Path]], we use /gigglecaps/ to create a [[Laughing Potion]]. + +Note the Alchemist Tome: +#+begin_quote +Colorful gigglecaps prefer well drained locations to grow, like on the top of rock terrain. +#+end_quote + +And we create a /patch/ of them for the picking: + +#+BEGIN_src evennia + # @teleport/quiet mp02 + # + @create/drop patch of mushrooms;mushrooms;mushroom: typeclasses.consumables.Producer + # + @desc mushrooms = A vibrant patch of mushrooms bursts forth like a painter's palette, each cap shimmering with iridescent hues of violet, emerald, and gold. Their delicate stems sway gently in the enchanted breeze...wait, you feel no breeze. They seem to be undulating with unheard laughter. + # + @set mushrooms/make_name = "gigglecap mushroom" + # + @set mushrooms/make_verb = "$conj(harvest) a" + # + @set mushrooms/make_class = "typeclasses.consumables.Edible" + # + @set mushrooms/make_desc = "A whimsical fungi emits a soft, melodic laughter when touched." + # + @set mushrooms/make_amount = 1 + # + @set mushrooms/make_spell_msgs = "10 ;; $You() << $conj(giggle) ^ $conj(chuckle) ^ $conj(chortle) >> out loud." + # + # And we can't see them until we are an alchemist: + @lock mushrooms = view:tag(alchemist) +#+END_SRC + +Until we are an alchemist, we shouldn't see the mushrooms... + +#+BEGIN_SRC tcl + dont_expect "You notice" "mushrooms" +#+END_SRC + +*** Squirrel +Here for hints … and a bit of a distraction. + +#+BEGIN_SRC evennia + @create/drop Squirrel;monk: typeclasses.chatbots.ChatBot + # @update squirrel = typeclasses.chatbots.ChatBot + # + @desc squirrel = A handsome squirrel dressed in flowing orange robes. Sitting in quiet meditation on top of a compfortable patch of |Ymoss|n. + # + @set squirrel/gender = "female" + # + @set squirrel/pose = "deep in meditation" + # + @set squirrel/pose_sleep = "deep in meditation" + # + # @sdesc orange-robed squirrel +#+END_SRC + +#+BEGIN_SRC evennia + @set squirrel/arrive = "20 ;; emote briefly opens her eyes, nods an acknowledgement to you. ;; gm The small squirrel returns to her meditation." +#+END_SRC + +Ignore all talking. + +#+BEGIN_SRC evennia :tangle no + @set squirrel/say = "5 ;; gm The << small ^ robed ^ >> squirrel << opens her eyes ^ looks at {1} briefly ^ stares at {1} intently >> and << holds up an empty paw ^ places a paw on the moss ^ holds up a small flower ^ shakes its head ^ closes her eyes >>. ;; gm The << small ^ robed ^ >> squirrel << returns ^ goes back >> to her << meditation ^ reflection ^ rumination >>." +#+END_SRC + +And turn on the real sayings: + +#+BEGIN_SRC evennia + py me.search("squirrel").backstory("squirrel") +#+END_SRC + +** Frog Meadow +To the east, let’s make a nice meadow. Start at the Forest: +#+BEGIN_src evennia + @teleport mp01 +#+END_SRC + +And we use the =tunnel= command this time: +#+BEGIN_src evennia + @dig Frog Meadow;mp05 : typeclasses.rooms_weather.TimeWeatherRoom = east footpath to meadow;east;e;path;footpath,west footpath to forest;footpath;west;w;path +#+END_SRC + +A description if they look east: +#+BEGIN_src evennia + @desc east = A winding footpath that may lead out of the forest... Is that a meadow? +#+END_SRC + +And a nice journey message to go east out of the forest: +#+BEGIN_src evennia + @set east/traverse_msg = "The mossy tree roots that borders this footpath begin to thin out to clover and flowers..." +#+END_SRC + +Before we label it, we follow =east=: +#+BEGIN_src evennia + @teleport mp05 +#+END_SRC + +And a description that takes advantage of the time of day. We should get busy and get some seasonal description here. + +#+BEGIN_src evennia + @desc here = A large |Ywaterfall|n cascades on the far side of this meadow creating a |Ystream|n that meanders through the tall grass and large yellow |Yflowers|n. They nod their sleepy heads to you as you pass by in the darkening twilightawakening dawnlazy afternoondark night. A gap in the trees show how you can return to the footpath in the forest. +#+END_SRC + +Along with a message: +#+BEGIN_src evennia + @set footpath/traverse_msg = "You leave the open meadow for the footpath through the giant trees. The yellow flowers nod goodbye to you..." +#+end_src + +And a description: +#+BEGIN_src evennia + @desc footpath = This footpath goes in a forest of immense trees. +#+END_SRC + +And details of the field. + +#+BEGIN_src evennia + @detail stream = The slow-moving |Ystream|n meanders like a snake in the grassy field. Little green |Yfrogs|n cling to grass stems hanging over the water. +#+END_SRC + +And detail the frogs: + +#+BEGIN_src evennia + @detail frog;frogs = Cute little guys with their big black eyes and tiny gold crowns. Too quick to catch. + # + @detail flowers;yellow flowers = "Aren't daffodils just flowers with big ol' schnozzes?" +#+END_SRC + +Testing this location: + +#+BEGIN_SRC tcl + send "e\n" + expectit "Frog Meadow" + + # Until we are an alchemist, we shouldn't see the tickleweeds... + dont_expect "You notice" "tickleweed" + + send "look frogs\n" + expectit "Cute little guys" +#+END_SRC + +And a prompt to generate an image from Midjourney and possibly AI Studio with Gemini. + +#+begin_example +Generate a watercolor with pen and ink outlining with vibrant colors and in the style of David Brayne, depicting a grassy field full of smiling yellow flowers and purple weeds. +Beyond the field is a waterfall that creates a stream. +Show a couple of small green frogs with tiny crowns on their heads. +Hiding in the grass is a friendly looking big hairy beast reminiscent of Where the Wild Things Are. +#+end_example +*** Waterfall +This is special, in that it should be hidden: + +#+BEGIN_src evennia + @create/drop waterfall +#+END_SRC + +And the description: + +#+BEGIN_src evennia + @desc waterfall = Cascading down the cliff in three sections, each section of this giant waterfall widens ending in a large |Ypool|n.|/|/Wait! Is there a large |Ycave|n entrance hidden behind the water? +#+END_SRC + +#+BEGIN_src evennia + @lock waterfall = get:false() +#+END_SRC + +Looking at the waterfall, shows the cave entrance: +#+BEGIN_src evennia + @set waterfall/hidden_tag = "hidden_cave;hidden_waterfall" + # + @lock waterfall = view:tag(hidden_waterfall) +#+END_SRC + +#+BEGIN_src evennia + @detail pool = A pool of cool, clear water. +#+END_SRC + +Test the cave entrance invisibility: + +#+BEGIN_SRC tcl + dont_expect "Exits" "cave entrance" + + dont_expect "You notice" "waterfall" +#+END_SRC + +Once seen, we should see both: + +#+BEGIN_SRC tcl + send "look pool\n" + expectit "A pool of cool, clear water." + + send "look waterfall\n" + expectit "entrance hidden behind the water?" + + # water == waterfall ... eh. + # send "look water\n" + # expectit "Could not find 'water'" + + send "look\n" + expect -re "Exits:.*cave entrance" + expect -re "You notice.*waterfall" + + send "get waterfall\n" + expectit "You can't get that" +#+END_SRC + +*** Fizzy Water +The waterfall causes the water in the stream to be /fizzy/, to be part of the [[Potions and their Ingredients][Alchemist Path]] to create a [[Laughing Potion]]. + +#+BEGIN_src evennia + # @teleport/quiet mp05 + # + @create/drop stream;water: typeclasses.drinkables.Water + # + @desc stream = A slow-moving stream meanders like a snake in the grassy field. The water, fizzy with bubbles from the waterfall torrent, creates an efforvesent aroma. Little green |Yfrogs|n cling to grass stems hanging over the sparkling water. + # + @lock stream = get:false() + # + @set stream/get_err_msg = "Seriously? You can't get that. Perhaps you can |gfill|n a |gbottle|n, or at least a cup, could hold the fizzy water." + # + @set stream/fill_name = "fizzy water" + # + @set stream/fill_desc = "sparkling water from waterfall turbulence." + # + @set stream/fill_msgs = ["$You() << $conj(get) ^ $conj(kneel) >> down, and $conj(fill) $pron(your) {2} with sparkling efforvesence.", "$You() << $conj(get) ^ $conj(kneel) >> down, and $conj(put) $pron(your) {2} in the cool water, filling it."] +#+END_SRC + +Make sure we can’t /get/ the fizzy water. Gotta issue where the name, =stream=, and /alias/, =water= should be the same: + +#+BEGIN_SRC tcl + send "look stream\n" + expectit "A slow-moving stream meanders like a snake in the grassy field." + + send "get stream\n" + expectit "Seriously? You can't get that." + #+END_SRC + +We will have to test the ability to “get” some water later, when we have a bottle. +*** Tickleweed + +Part of the [[Potions and their Ingredients][Alchemist Path]], we use /tickleweed grass/ to create a [[Laughing Potion]]. + +We put this location hint in the Alchemy Tome: +#+begin_quote +A purple grass, often called tickleweed since it vibrates as if laughing. The herb hunter can find this in fields and meadows throughout the area. +#+end_quote + +And we create it: + +#+BEGIN_src evennia + # @teleport/quiet mp05 + # + @create/drop patch of tickleweed;tickleweed: typeclasses.consumables.Producer + # + @desc tickleweed = Patches of this vivid grass vibrates as if giggling. + # + @set tickleweed/make_name = "bunch of tickleweed" + # + @set tickleweed/make_verb = "$conj(harvest) a" + # + @set tickleweed/make_class = "typeclasses.consumables.Herb" + # + @set tickleweed/make_desc = "This grass vibrates as if giggling." + # + @set tickleweed/make_amount = 1 + # + # And we can't see them until we are an alchemist: + @lock tickleweed = view:tag(alchemist) +#+END_SRC + +Until we are an alchemist, we shouldn't see the mushrooms... + +#+BEGIN_SRC tcl + dont_expect "You notice" "tickleweed" +#+END_SRC + +We’ll test the ability to get it later. + +*** Hints +We could have the /frogs/ talk, perhaps a migrating murder of crows? + +#+BEGIN_SRC yaml + frog_meadow: + narrative: >- + "<< Psst. ^ Heya. ^ Down here. ^ Ribbit... ^ Hey buddy. >>" + You << stoop ^ look down ^ bend down >> and see + a << tiny ^ small ^ >> << green ^ >> frog + with a << teeny ^ >> << gold ^ >> crown. It says, + "<< I see ya gawking. ^ You look confused. ^ Need some help? >> {0}" + And with that, he hops away. + ;; + A << flock ^ couple >> of crows fly into the meadow. + One of them, hops << next to ^ near >> you. + "<< I see ya gawking. ^ You look confused. ^ Need some help? >> {0}" + ;; + A cricket, sporting a nice top hat and waistcoat, eyes you curiously. + "You seem << confused ^ bewildered ^ befuddled ^ disoriented ^ perplexed >>," + it says. "Perhaps I can help. {0} + Hope that helps. Good-bye << and good luck ^ >>." + And with a mighty jump, hops to the other side of the << meadow ^ field >>. + hints: + default: >- + The |Ybeast|n over there is << actually ^ quite >> friendly, + but scared of everything and everyone. + That's why he doesn't venture in to the forest. + That, and he loves the fizzy water from the |Ystream|n. + beast: >- + The beast doesn't like new people. Sometimes you can |Yfeed|n him + to get 'im to warm up to you. Sometimes takes a bit of food for him + to trust you. + feed: >- + |YBerries|n are good, but he loves Dabbler's |Yscones|n. + Just hard to get into his house. + berries: You'll find a bush of them to the west in the Grotto. + scones: Dabbler lives in a tree to the west, behind a red door. + stream: Yes, the fizzy water is drinkable, so you can |Ycollect|n some. + collect: To collect the water, you will need a |Ybottle|n. + bottle: You want to |gfill bottle|n to collect the water. +#+END_SRC + +And some tests of the hint system? + +#+BEGIN_SRC tcl + send "hint\n" + expectit "but scared of everything and everyone" + send "hint beast\n" + expectit "The beast doesn't like new people" + send "hint feed\n" + expectit "Just hard to get into his house" + send "hint berries\n" + expectit "You'll find a bush of them to the west in the Grotto" + send "hint scones\n" + expectit "Dabbler lives in a tree to the west, behind a red door" + send "hint stream\n" + expectit "Yes, the fizzy water is drinkable" + send "hint collect\n" + expectit "To collect the water, you will need" + send "hint bottle\n" + expectit "to collect the water." +#+END_SRC + +** The Lair of the Beast +To create a place for our big, hairy beast to sleep, first jump to the Meadow: +#+BEGIN_src evennia + @teleport mp05 +#+END_SRC + +From the Meadow, we create a lair /behind/ the water. +#+BEGIN_src evennia + @dig Lair;mp07 = cave entrance;cave;lair;inside,outside;leave;meadow +#+END_SRC + +And we make it hidden: +#+BEGIN_src evennia + @set cave/hidden_tag = "hidden_cave" + # + @lock cave = view:tag(hidden_cave) +#+END_SRC + +And a description if they look: +#+BEGIN_src evennia + @desc cave = A large entrance to a dark, and foul-smelling cave. The waterfall is so loud, you can't hear anything that may live there. +#+END_SRC + +And a description when entering … +#+BEGIN_src evennia + @set cave/traverse_msg = "You venture inside the dark cave." +#+END_SRC + +Let’s step inside to finish this: + +#+BEGIN_src evennia + @teleport mp07 +#+END_SRC + +And a description: + +#+BEGIN_src evennia + @desc here = Vaulted stone ceiling harbors the darkness that hovers over a large |Ymattress|n. +#+END_SRC + +And a description of leaving: + +#+BEGIN_src evennia + @desc leave = You can see the waterfall cascading outside the cave entrance. +#+END_SRC + +And the leaving message: + +#+BEGIN_src evennia + @set leave/traverse_msg = "You leave the dark cave and pass behind the waterfall for the meadow beyond." +#+END_SRC + +Test the cave entrance: +#+BEGIN_SRC tcl + send "look cave\n" + expectit "A large entrance to a dark, and foul-smelling cave." + + send "lair\n" + expectit "Lair" + + send "look outside\n" + expectit "You can see the waterfall cascading outside the cave entrance." + #+END_SRC + +*** Mattress +Create a mattress you can sit on (and maybe /push/ to get to a secret door): + +#+BEGIN_src evennia + @create/drop mattress:typeclasses.sittables.Sittables +#+END_SRC + +And the description: +#+BEGIN_src evennia + @desc mattress = Looks comfortable, albeit tall, but doesn't smell good. Perhaps that is due to the |Ymushrooms|n sprouting from its base?|/|/The corner of the mattress covers a |Ytrapdoor|n!? +#+END_SRC + +And a /detail/ of the mushrooms that may show if are not an alchemist: + +#+BEGIN_src evennia + @detail mushrooms;fungus = Slender blue tendrils of a fungus encircle the base of the mattress. Subtle white dots on the cap suggests caution. +#+END_SRC + +Can’t steal ‘it: +#+BEGIN_src evennia + @lock mattress = get:false() + # + @set mattress/get_err_msg = "It's way too heavy for you to lift." +#+END_SRC + +Can you /push/ or /pull/ it? + +#+BEGIN_SRC evennia + @set mattress/pull_msg = "Mattresses are such difficult creatures to manipulate. When you pull on a corner, it slips from your hands. Perhaps you could |guse|n something to help?" + # + @set mattress/push_msg = "Mattresses are such difficult creatures to manipulate. Such a heavy beast. Your pushing allows you to reach and pull on the trapdoor, but not enough to keep it open. Perhaps you could |guse|n something to prop it out of the way?" +#+END_SRC + +And textual descriptions the object can use: +#+BEGIN_src evennia + @set mattress/adjective = "on" + # + @set mattress/article = "the" + # + @set mattress/singular = "the mattress" + # + @set mattress/extra = "This feels << ^ very ^ quite>> <>, even if it smells bad.|n" +#+end_src + +And a better description when sitting down: + +#+BEGIN_SRC evennia + @set mattress/response = "$You() $conj(sit) on the large mattress." +#+END_SRC + +And a trim on the things to see: + +#+BEGIN_src evennia + @lock mattress = view:tag(hidden_mattress) + # + @set mattress/hidden_tag = "hidden_mattress" +#+END_SRC + +Testing this location. + +#+BEGIN_SRC tcl + dont_expect "You notice" "mattress" + + send "look mattress\n" + expectit "Looks comfortable" + + send "look\n" + expect -re "You notice.*mattress" + + send "sit\n" + expectit "You sit on the mattress." + + send "get mattress\n" + expectit "too heavy" +#+END_SRC + +*** Dream Mushrooms +Part of the [[Potions and their Ingredients][Alchemist Path]], we use /dream mushrooms/ to create a [[Trippy Potion]]. + +#+begin_quote +Dreamshade mushrooms feed on floating dreams, and often congregate where dreamers sleep. +#+end_quote + +#+BEGIN_src evennia + # @teleport/quiet mp07 + # + @create/drop cluster of mushrooms;mushroom;mushrooms: typeclasses.consumables.Producer + # + @desc mushrooms = Slender blue tendrils of a fungus encircle the base of the mattress. You note that these look like the |wDreamshade mushrooms|n mentioned in the |wAlchemy Lab|n. + # + @set mushrooms/make_name = "dreamshade mushroom" + # + @set mushrooms/make_verb = "$conj(pluck) and $conj(pocket) a " + # + @set mushrooms/make_class = "typeclasses.consumables.Edible" + # + @set mushrooms/make_desc = "A slender, blue mushroom. Glowing?" + # + @set mushrooms/make_amount = 1 + # + @set mushrooms/make_spell_msgs = "10 ;; $You() $conj(nod) off, as $pron(your) head bobbles and bounces. ;; 5 ;; $You() $conj(awaken) with a start." + # + # And we can't see them "fully" until we are an alchemist: + @lock mushrooms = view:tag(alchemist) +#+END_SRC + +And test that we can’t see them right now. + +#+BEGIN_SRC tcl + dont_expect "You notice" "mushrooms" +#+END_SRC +*** Beast +And we create the Big, Hairy Beast: + +#+BEGIN_src evennia + @create/drop big hairy beast;bhb;beast;hairy beast;monster;shadow: typeclasses.pets.BHB +#+END_SRC + +And a general description that will be /expanded/ with its current reaction. + +#+BEGIN_src evennia + @desc beast = A big, hairy beast with long claws and teeth. +#+END_SRC + +Can’t get this: +#+BEGIN_src evennia + @lock beast = get:false() + # + @set beast/get_err_msg = "You can't pick that up, as that beast is far larger than you." +#+END_SRC + +And set its sleepy time at 8pm … + +#+BEGIN_src evennia + @set beast/sleep_hour = 21 +#+END_SRC + +It will wake at 8am … + +#+BEGIN_src evennia + @set beast/wake_hour = 8 +#+END_SRC + +Let’s set some behavior levels. For instance, the beast is sad when he doesn’t see its friends: + +#+BEGIN_src evennia + @set beast/loneliness_amount = -2 +#+END_SRC + +It seem to warm up the to new characters hanging around the area, but not as much as those that would interact with it: + +#+BEGIN_src evennia + @set beast/shyness_amount = 3 +#+END_SRC + +How active should this pet be? Seems like at the moment, it shouldn’t be too obnoxious. This setting is a percentage, so 12 is /12%/, which returns a message only 12% of the /ticks/ (where a tick is about a minute). + +#+BEGIN_src evennia + @set beast/active_amount = 10 +#+END_SRC + +It isn’t that scared of new people, as it will ignore them when someone it knows is around. + +#+BEGIN_src evennia + @set beast/new_character_reaction = 'ignores' +#+END_SRC + +Seems we should make descriptions for all the states that happen when you look at them. These are appended to the standard description. + +#+BEGIN_src evennia + @set beast/scared_msg = "It seems <> as it tries to hide behind a tall clump of grass. Yeah, it doesn't do a good job of hiding." +#+END_SRC + +Concerned level: + +#+BEGIN_src evennia + @set beast/concerned_msg = "Its large, yellow eyes stare at you from a safe distance." +#+END_SRC + +Interested level: + +#+BEGIN_src evennia + @set beast/interested_msg = "It seems <> in what you are doing <>. ;; Its << ^ large, ^ big,>> yellow eyes watch your every move." +#+END_SRC + +Friendly level: + +#+BEGIN_src evennia + @set beast/friendly_msg = "It sits next to you, as its big, friendly eyes gaze as you. ;; It <> to you, wagging its tail-less behind. ;; It lays down next to you." +#+END_SRC + +When the beast is sleeping, we can some times spam the room with the snores: + +#+begin_src evennia + @set beast/sleeping_actions = "The <> <> <> lets loose a <> snore. ;; The <> <> <> growls in its sleep. ;; The <> <> <> twitches its <>. ;; The <> <> <> <> on its <> mattress." +#+end_src + +We base the actions of the beast on the most friendly person in the area. + +The scared level doesn’t last long, so let’s just leave one message: + +#+begin_src evennia + @set beast/scared_actions = "A tremendously large and hairy beast attempts to nervously (and almost comically) hide" +#+end_src + + +Concerned actions: + +#+begin_src evennia + @set beast/concerned_actions = "The <> <> <> <> concerned by your presence in the <>. ;; The <> <> <> seems concerned. Maybe it's hungry. ;; The <> <> <> seems concerned and keeps its distance." +#+end_src + +Interested actions: + +#+begin_src evennia + @set beast/interested_actions = "The <> <> <> seems <> in $you(). ;; The <> <> <> seems curious about $you(). ;; The <> <> <> stands on its hind legs. ;; The <> <> <> <> $you() with its <> yellow eyes." +#+end_src + +Friendly actions: + +#+begin_src evennia + @set beast/friendly_actions = "The <> <> <> <> <> wagging its backend<<, ^ as it seems>> happy to see $you(). ;; The <> <> <> <> <> hoping to play with $you(). ;; The <> <> <> flops over in front of $you() wriggling <> on the ground. ;; The <> <> <> <> <> next to $you(). ;; The <> <> <> chases butterflies around the <>." +#+end_src + +The ecstatic states are just a bit more than friendly. + +#+begin_src evennia + @set beast/ecstatic_actions = "The <> <> <> <> <> to give $you() a sloppy <>. ;; The <> <> <> <> <> wagging its backend as it seems <> excited to see $you(). ;; The <> <> <> <> <> hoping to play with $you(). ;; The <> <> <> flops over in front of $you() happily wriggling on the ground. ;; The <> <> <> excitedly <> <> next to you. ;; The <> <> <> <> leaps into air. ;; The <> <> <> chases butterflies around the <>." +#+end_src + +And the responses to being /pet/: + +#+BEGIN_src evennia + @set beast/pet_sleeping_response = "Petting a sleeping beast of that size isn't your best idea." + # + @set beast/pet_scared_response = "$You() can't get near the wild beast to pet it. It seems scared." + # + @set beast/pet_concerned_response = "$You() can't get near the big, hairy beast to pet it. It seems concerned." + # + @set beast/pet_interested_response = "The big hairy beastie keeps its distance, but seems curious about $you()." + # + @set beast/pet_friendly_response = "The << big, ^ huge, ^ large, ^ tremendous, ^ >> << hairy ^ slobbery ^ horned ^ clawed ^ >> << brute ^ beast ^ monster>> << flops ^ rolls >> over << in the grass ^>> as $you() $conj(give) it belly rubs. ;; The << big, ^ huge, ^ large, ^ tremendous, ^ >> << hairy ^ slobbery ^ horned ^ clawed ^ >> << brute ^ beast ^ monster>> << flops ^ rolls >> over << in the grass ^>> as $you() $conj(rub) its belly. ;; $You() $conj(pet) the << big, ^ huge, ^ large, ^ tremendous, ^ >> << hairy ^ slobbery ^ horned ^ clawed ^ >> << brute ^ beast ^ monster>> . ;; $You() $conj(scratch) the << nose ^ ears >> of the << big, ^ huge, ^ large, ^ tremendous, ^ >> << hairy ^ slobbery ^ horned ^ clawed ^ >> << brute ^ beast ^ monster>>. ;; The << big, ^ huge, ^ large, ^ tremendous, ^ >> << hairy ^ slobbery ^ horned ^ clawed ^ >> << brute ^ beast ^ monster>> leans forward as $you() $conj(scratch) its nose." + # + @set beast/pet_ecstatic_response = "While << excited ^ ecstatic ^ squirmy >>, the << big, ^ huge, ^ large, ^ tremendous, ^ >> << hairy ^ slobbery ^ horned ^ clawed ^ >> << brute ^ beast ^ monster>> << lays ^ gets >> down so $you() can << pet ^ scratch >> << the top of its head ^ the back of its neck ^ its nose ^ the sides of its face >>. It closes its eyes and purrs. ;; << The squirmy little devil. ^ >> $conj(You) << can ^ >> << barely ^ hardly >> scratch the << nose ^ ears ^ neck ^ top of the head >> of the << big, ^ huge, ^ large, ^ tremendous, ^ >> << hairy ^ slobbery ^ horned ^ clawed ^ >> << brute ^ beast ^ monster>> as it << squirms around ^ wriggles it backend >>. It << can hardly ^ can't >> contain its excitement. ;; The << big, ^ huge, ^ large, ^ tremendous, ^ >> << hairy ^ slobbery ^ horned ^ clawed ^ >> << brute ^ beast ^ monster>> wriggles around before << flopping ^ rolling >> over << in the grass ^>> as $you() $conj(give) it belly rubs. ;; The << big, ^ huge, ^ large, ^ tremendous, ^ >> << hairy ^ slobbery ^ horned ^ clawed ^ >> << brute ^ beast ^ monster>> wriggles and squirms excitedly before it << flops ^ rolls >> over << in the grass ^>> as $you() $conj(rub) its belly." +#+END_SRC + +I want to make sure that when someone new sees the beast, the see it hiding behind the grass… + +#+BEGIN_SRC tcl + send "leave\n" + expectit "Frog Meadow" + + expect { + "a big hairy beast" { + send "look beast\n" + expectit "it tries to hide behind a tall clump of grass" + + send "pet bhb\n" + expectit "can't get near" + + send "get hairy beast\n" + expectit "beast is far larger than you." + + send "feed beast\n" + expectit "doesn't appear interested in anything you have." + } + timeout { + if {$phase == "night"} { + puts "NOTE: The beast is in bed now." + } else { + puts "NOTE: Where is the beast? It is $phase?" + } + } + } +#+END_SRC +*** Hints +This is an /under construction/ sort of room, and isn’t that interesting at the moment. I’m not sure what sort of /narrator/ could give a hint; a spider? + +#+BEGIN_SRC yaml + lair: + hints: + default: >- + This is the bedroom for the |wBig Hairy Beast|n, and little + else. Eventually, I will expand this room into something more + interesting, but at the moment, pretend there is a |wPardon our + Dust|n sign or something. + |/|/Of course I will install a secret door here, but not yet. +#+END_SRC + +** Glittering Glade +To the east of the meadow, let’s make a glade back inside the Forest: +#+BEGIN_src evennia + @teleport mp05 +#+END_SRC + +And we use the =tunnel= command this time: +#+BEGIN_src evennia + @dig Glittering Glade;mp19 : typeclasses.rooms.Room = east footpath into another forest;east;glade;e,west footpath to meadow;footpath;west;w;path +#+END_SRC + +A description if they look east: +#+BEGIN_src evennia + @desc east = Looking at the forest on the east side shows a footpath illuminated by dancing glowing orbs. +#+END_SRC + +#+BEGIN_SRC evennia + @detail orbs = The orbs swirl around in a circular pattern creating a mesmerizing vortex of light leading deep into the forest. +#+END_SRC + +And a nice journey message to go east out of the forest: +#+BEGIN_src evennia + @set east/traverse_msg = "You step into this dark forest onto a footpath illuminated by swirling orbs of light. You follow the path until it opens into a glade." +#+END_SRC + +Before we label it, we follow =east=: + +#+BEGIN_src evennia + @teleport mp19 +#+END_SRC + +And the description won’t have day/night, but we can /reference/ it: + +#+BEGIN_SRC evennia + @desc here = The footpath ends in a beautiful glade. While the thick canopy above blocks the morning lightthe daylightthe glowing twilightany light that might show, the glade is illuminated by swirling |Yorbs|n of light. You see a round, stone |Ytable|n and a blue painted |Ydoor|n embedded in a giant tree. +#+END_SRC + +#+BEGIN_SRC evennia + @detail orbs = The orbs swirl above illuminating the glade. +#+END_SRC + +#+BEGIN_SRC evennia + @detail trees = Ancient trees surround this glade like walls. +#+END_SRC + +#+BEGIN_SRC evennia + @detail tree = The largest tree stands at one end of the glade, forms steps from this roots that lead to a |Ydoor|n embedded in its bark. +#+END_SRC + +A description if they look back towards the west: +#+BEGIN_src evennia + @desc west = The footpath leads out of the forest to a meadow. +#+END_SRC + +And a nice journey message to go east out of the forest: +#+BEGIN_src evennia + @set west/traverse_msg = "You followed the illuminated footpath until you exit the forest into a meadow." +#+END_SRC + +Assume the Goblin tester is in Frog Meadow, so let’s head east: + +#+BEGIN_SRC tcl + send "east\n" + expectit "Glittering Glade" +#+END_SRC +*** Stone Table +Not only does the /table/ in this glade offers a riddle, but also arbitrates the answer of the puzzle to unlock the blue door into the tavern. As a special object, it can listen for words, and perform commands: + +#+BEGIN_SRC evennia + @create/drop stone table:typeclasses.puzzles.StoryCube +#+END_SRC + +And a description must be careful with the newlines to make the verse work: + +#+BEGIN_SRC evennia + @desc table = Moss fills four |Yrunes|n carved along the edge of this weathered table. In the center, you can read a message:|/|/ Born of rain and ground combined,|/ No solid form, yet firm when dried.|/ Clinging to feet. Adored by boar.|/ Speak my name to open the door. +#+END_SRC + +Can we read it? + +#+BEGIN_SRC ruby + @set table/inside = "While you can't read the |Yrunes|n, you can read the message in the middle of the table:|/|/ Born of rain and ground combined,|/ No solid form, yet firm when dried.|/ Clinging to feet. Adored by boar.|/ Speak my name to open the door." +#+END_SRC + +And some flavor that offers a hint to the answer of the riddle, to combine Water and Earth: + +#+BEGIN_SRC evennia + @detail runes;rune = While you've never before encountered these stanges runes, etched into the ancient stone, yet somehow you know that they represent the elements of |wEarth|n, |wAir|n, |wFire|n and |wWater|n. +#+END_SRC + +The table shouldn’t be steal-able: +#+BEGIN_src evennia + @lock table = get:false() + # + @set table/get_err_msg = "That table is much too big for you to lift." +#+END_SRC + +Answer the riddle to be able to go to the Tavern: + +#+BEGIN_SRC evennia + @set table/say = {r".*\bmud\b.*": "gm You hear an audible click, and find the blue door, that was closed before, now is ajar. ;; tag_all open_blue_door"} +#+END_SRC + +Assume the Goblin tester is in Frog Meadow, so let’s head east: + +#+BEGIN_SRC tcl + send "get table\n" + expectit "too big" +#+END_SRC +*** Hints +Shall we bring back Bubba? + +#+BEGIN_SRC yaml + glittering_glade: + narrative: >- + << Bubba Joe Washington ^ That cockatiel >> returns, and perches on your shoulder, + "Heya," it chirps. "<< Stuck on this puzzle? ^ >> Here's a << bit of ^ >> a hint. {0} Good luck << , again ^ >>." It flies off. + ;; + A << yellow ^ orange ^ large ^ >> butterfly lands on your + shoulder. "You look like you << could use some ^ need ^ would like + some >> help," it says, "{0}" As it flies away, it says, "Good + luck!" + hints: + default: >- + To get through that |Ydoor|n, you'll need to figure out the |Ypassword|n. + password: >- + Don't abandon hope. The |Ytable|n contains a |Yriddle|n. + Don't forget to |glook|n at the |Yrunes|n around the outside. + table: >- + You could |gread|n the message in the middle of the table. + That is a good ol' fashion |Yriddle|n. + The answer to the riddle, is the |Ypassword|n. + Don't forget to |glook|n at the |Yrunes|n around the outside. + riddle: + You've |gread|n the message in the middle of the table, right? + Do you want the |Yanswer|n? + runes: >- + Those unreadable runes hint at the answer to the |Yriddle|n + you can see in the message in the middle of the |Ytable|n. + Think about combining two elements to get the answer. + door: >- + That door leads to |wWyldwood Tavern|n... + A lovely place that serves fascinating cocktails. + answer: mud +#+END_SRC + +And let’s not test /everything/ here: + +#+BEGIN_SRC tcl + send "hint\n" + expectit "To get through that" + + send "hint password\n" + expectit "Don't abandon hope." +#+END_SRC + +** Tavern: Wyldwood Bar +This now needs to be transferred from the [[file:mud-rpg.org][mud-rpg]] file. + +#+BEGIN_src evennia + @dig Wyldwood Bar;mp10 = blue door;door,blue door to forest;leave;outside +#+end_src +*** Blue Door +The door in the tree connects to the Tavern that may have already been created: + +#+BEGIN_SRC evennia :tangle no + @open blue door;door,blue door to forest;leave;outside = Wyldwood Bar +#+END_SRC + +And describe it: +#+BEGIN_SRC evennia + @desc door = A painted blue door where the round top of the door fits snugly in the bark of the tree. The comically large doorknob in the center of the door looks ornamental. +#+END_SRC + +The dock is locked: + +#+BEGIN_SRC evennia + @set blue door/err_traverse = "The door seems locked...or at least, won't budge." +#+END_SRC + +Open-able if you have the correct tag: +#+BEGIN_SRC evennia + @lock blue door = traverse:tag(open_blue_door) +#+END_SRC + +Make sure it is locked: +#+BEGIN_SRC tcl + send "blue door\n" + expectit "The door seems locked" +#+END_SRC + +And give the password to open the blue door: +#+BEGIN_SRC tcl + send "say mud\n" + expectit "You hear an audible click" + + # Need to wait for the tagging magic to take effect: + sleep 1 +#+END_SRC + +Let’s have an interesting phrase entering the bar … +#+BEGIN_src evennia + @set door/traverse_msg = "You open the blue door and enter inside the tree... and find yourself in a mirror copy of the glade you just left, but this glade looks like a |wtavern|n." +#+END_SRC + +And test to make sure we can get to the bar… +#+BEGIN_SRC tcl + send "blue door\n" + expectit "Wyldwood Bar" +#+END_SRC +*** Inside the Bar +Let’s hop into the Bar in order to work it over: +#+BEGIN_SRC evennia + @tel mp10 +#+END_SRC + +Describe it: + +#+BEGIN_SRC ruby + @desc here = An amazing room formed from a ring of living |Ytrees|n. The canopy of |Yboughs|n above twinkle with the |Ylights|n of small, glowing orbs. Working the bar, a haughty-looking |Yelf|n; waiting on tables, a smiling |Ymushroom man|n, er...person. +#+END_SRC + +And some ambiance. +#+BEGIN_SRC ruby + @detail trees;tree;trunk;trunks = You've never see black elder tree trunks so large or that grow so close together. The course, dark gray trunks absorb the soft light from the |Yorbs|n making the room appear much larger. +#+END_SRC + +#+BEGIN_SRC ruby + @detail boughs;bough;branches;canopy = The branches of the black elder |Ytrees|n sport slender leaves and cluster of elder |Yberries|n. +#+END_SRC + +#+BEGIN_SRC ruby + @detail berries;berry = The cluster of berries from the |Ycanopy|n above are high and out of reach. +#+END_SRC + +#+BEGIN_SRC ruby + @detail lights;light;orbs = Hundreds of small, dancing orbs float around the |Ycanopy|n above the room, casting a soft glow of light. +#+END_SRC + +And describe the door leaving the bar: + +#+BEGIN_SRC evennia + @desc blue door = The painted blue door you used to enter this tavern, looks the same on this side too...a door that fits snugly in the bark of the tree. Going through this door again may take you back to the forest, but who knows? +#+END_SRC + +Let’s have an interesting phrase entering the bar … +#+BEGIN_src evennia + @set blue door/traverse_msg = "You open the blue door and enter inside the tree... and find yourself back in the first glade, with a path that leads through a forest." +#+END_SRC + + +*** Cocktails +Let’s create a sign for the list of cocktails: + +#+BEGIN_SRC ruby + @create/drop sign above the bar;sign;list:typeclasses.readables.Readable +#+END_SRC + +And the description: + +#+BEGIN_SRC ruby + @desc sign = You see a large sign made of wood over the bar, hanging from a branch of one of the living trees. Painted words at the top read, |wWyldwood Cocktails|n, and a list of drinks you can order. +#+END_SRC + +Might as well allow the user to read it: + +#+BEGIN_SRC ruby + @set sign/inside = "|wCocktails|n|/ - Moonlit Mirage|/ - Puck's Revenge|/ - Glimmering Gossamer|/ - Whimsical Willow|/ - Charmed Chalice|/ - Enchanted Elixir|/ - Sylvan Serenade|/ - Brambleberry Bliss|/ - Twilight Tonic|/" +#+END_SRC + +And lock down the sign: +#+BEGIN_SRC ruby + @lock sign = get:false() + # + @set sign/get_err_msg = "The tree trunk that holds the sign has grown around it making it impossible to remove." +#+END_SRC + +Let’s test out the sign: + +#+BEGIN_SRC tcl + send "read sign\n" + expectit "Cocktails" + + send "get sign\n" + expectit "impossible to remove" +#+END_SRC + +Needs the ability to create a drink. + +#+BEGIN_SRC ruby + @set bartender/currentgame = "session1" +#+END_SRC + +The preps come in three forms with how detailed we want to spam the room. + + +#+BEGIN_SRC ruby + @set bartender/triggers:session1 = { + "prep1": { + "desc": "Single preparation step for making a cocktail", + "timer": 1, + "events": [ + "The bartender grabs a << few ^ couple of >> << bottles ^ jars ^ bottles ^ odd containers >> from << the shelf ^ a locked chest ^ a wooden box >>." + ] + }, + "prep2": { + "desc": "Preparation steps for making a cocktail", + "timer": 5, + "events": [ + "The bartender grabs a << few ^ couple of >> << bottles ^ jars ^ bottles ^ odd containers >> from << the shelf ^ a locked chest ^ a wooden box >>.", + "<< He ^ The bartender >> shakes and strains the << drink ^ concoction ^ elixir >> into a cocktail glass." + ] + }, + "prep3": { + "desc": "Preparation steps for making a cocktail", + "timer": 4, + "events": [ + "The bartender grabs a << few ^ couple of >> << bottles ^ jars ^ bottles ^ odd containers >> from << the shelf ^ a locked chest ^ a wooden box >>.", + "<< He ^ The bartender >> then shakes and strains the << drink ^ concoction ^ elixir >> into a cocktail glass.", + "He carefully, garnishes the << drink ^ cocktail >>." + ] + } + } +#+END_SRC + +**** Moonlit Mirage +A shimmering drink that changes color with each sip, garnished with edible glitter and a twist of lemon +#+BEGIN_SRC ruby :tangle no + gm The bartender grabs a pixie flying by and shakes the glitter from its wings into the glass. +#+END_SRC + +**** Puck’s Revenge +A vibrant concoction of fruit juices and sparkling fairy dust, served in a glass shaped like a flower. + +#+BEGIN_SRC ruby :tangle no + cast donkey on char +#+END_SRC +**** Glimmering Gossamer +A delicate blend of elderflower liqueur and sparkling wine, adorned with a butterfly-shaped ice cube. + +#+BEGIN_SRC ruby :tangle no + gm The bartender uses a butterfly net to catch an ice cube that he then places in the glass. +#+END_SRC +**** Whimsical Willow +A herbal infusion of gin, rosemary, and elderberry, served with a sprig of fresh mint and a splash of tonic. + +#+BEGIN_SRC ruby :tangle no + gm As the bartender hands over the cocktail, the garnish of a sprig of mint grows a long twisting vine that he casually clips off. +#+END_SRC +**** Charmed Chalice +A mysterious potion that glows softly, made with enchanted spirits and a hint of honey, served in a chalice that changes shape. + +#+BEGIN_SRC ruby :tangle no + gm Ghostly apparitions appear in the air, as the bartender grabs one, twists it, and adds a drop of ectoplasm to the drink. +#+END_SRC +**** Enchanted Elixir +A deep blue drink with hints of blueberry and a touch of magic, served with a glowing ice sphere. + +#+BEGIN_SRC ruby :tangle no + gm The bartender opens a box that bathes the bar in light. He takes a glowing sphere of ice and garnishes the cocktail before passing it over. + shake elixir = +#+END_SRC +**** Sylvan Serenade +A melodic blend of apple cider and spiced rum, garnished with a cinnamon stick and a slice of star fruit. + +#+BEGIN_SRC ruby :tangle no + gm The bartender plays a flute as the jars and ingredients line up and pour themselves into a cocktail shaker. +#+END_SRC +**** Brambleberry Bliss +A sweet and tart mix of brambleberries and gin, served over crushed ice with a sprinkle of edible flowers. + +#+BEGIN_SRC ruby :tangle no + gm The bartender garnishes the cocktail with a flower pulled from a pot on the bar. The plant immediately wilts and drops away. +#+END_SRC +**** Twilight Tonic +A dark, mysterious drink made with blackcurrant and tonic water, served with a slice of lime and a hint of mint." + +#+BEGIN_SRC ruby :tangle no + gm After the cocktail is complete, the branches above part, and the light from the moon shines directly on the glass causing bubbles to form. The bartender hands it to you with a wink. +#+END_SRC +*** Bartender +Return to the Bar … +#+BEGIN_SRC ruby + @teleport Wyldwood Bar +#+END_SRC + +A haughty elf named Elendil +#+BEGIN_SRC ruby + @create/drop Bartender;barkeep;Elendil: typeclasses.chatbots.Bartender + # @update Bartender = typeclasses.chatbots.Bartender +#+END_SRC + +And all the RP system stuff: + +#+BEGIN_SRC evennia + @set bartender/gender = "male" +#+END_SRC + +#+BEGIN_SRC ruby + py bt = self.search('Bartender'); bt.sdesc.add('blonde elf'); bt.db.pose = 'working behind the bar' +#+END_SRC + +And default pose: + +#+BEGIN_SRC ruby + @pose default bartender = working behind the bar +#+END_SRC + +And an un-puppeted pose: + +#+BEGIN_SRC ruby + @set bartender/pose_sleep = "fiddling with something behind the bar" + # + @set bartender/pose_default = "working behind the bar" +#+END_SRC + +And a good description: + +#+BEGIN_SRC ruby + @desc Bartender = A haughty-looking elf with green eyes and long blond hair with two intricate braids accentuating incredibly pointed ears. His nose, pointed, often points straight up in order to look down on you. +#+END_SRC + +And give him the powers he deserves: + +#+BEGIN_SRC ruby :tangle no + @perm Bartender = Admin +#+END_SRC + +As well as the automation: +#+BEGIN_SRC evennia + py me.search("bartender").backstory("tavern") +#+END_SRC + +And let’s make him initially invisible: + +#+BEGIN_SRC ruby + @set Bartender/hidden_tag = "hidden_bartender" + # + @lock Bartender = view:tag(hidden_bartender) +#+END_SRC + +Let’s see if we can talk the bartender into a drink: +#+BEGIN_SRC tcl + # Since this is still problematic getting an actual drink + # from our AI server, we will pretend and just work through it. + + send "say to bartender Good day, sir. May I have that delicious serenade drink, again, please?\n" + sleep 10 + + send "drink\n" + expectit "You" + + send "drink\n" + expectit "You" + + send "drink\n" + expectit "You" + + send "drink\n" + expectit "You" + + send "drink\n" + expectit "You have nothing to drink" + + send "say Thank you, sir\n" + expectit "Thank you" +#+END_SRC + +Helpful commands: + +#+BEGIN_SRC ruby :tangle no + nick write $1 = py me.search('shrub').write("$1") + nick hi $1 = say to $1 = Greetings and welcome to the Wyldwood. + nick ticket = say regrettably All ticket holders drink free here. +#+END_SRC + +**** Automated Responses +Seems that different triggering hooks could have different delayed responses. What sort of events? And do we bother if we convert the Bartender to a Chatbot? + +#+BEGIN_SRC ruby + @set bartender/arrive:dabbler = "5 ;; say to old gnome Ah, welcome, sir. I've acquired another one of those whiskys from the Mud World. This one claims to taste like a... hrm... << burning hosptial ^ seagull's armpit, er wingpit, I guess ^ going down on a mermaid, wait, I believe you've done that ^ licking a salty ashtray >>. ;; 10 ;; emote takes a brown glass bottle from a chest, and pours some into a glass. ;; shake whisky = gnome" +#+END_SRC + +#+BEGIN_SRC evennia + @set bartender/arrive = "4 ;; say Welcome to the |wWyldwood Bar|n. Read the sign for a list of our cocktails, and let me know what you'd like to drink." +#+END_SRC + + +And: +@set bartender/leave:character +@set bartender/say::character = “reg expression” +@set bartender/sayto::character = “reg expression” +@set bartender/leave:character +@set bartender/leave:character + +#+BEGIN_SRC ruby :tangle no + @set bartender/sayto = {r"\bthanks?( you)?": "gm The << bartender ^ barkeep >> << mumbles ^ mutters ^ softly replies >> << back ^ >> to {1}, \"You're << very ^ >> welcome.\""} +#+END_SRC + +#+BEGIN_SRC ruby :tangle no + @set bartender/say = {r"\bthanks?( you)?.*bar(tend|keep)": "gm The << bartender ^ barkeep >> << mumbles ^ mutters ^ softly replies >> << back ^ >> to {1}, \"You're << very ^ >> welcome.\""} +#+END_SRC + +First, split the line into its parts, and if: + + - Single number? That is the amount to wait between that, and another other command following. Default to 2? + - We =execute_cmd= for everything else. + +To do this, we need to update =announce_move_from= and =announce_move_to= to send a trigger message to the =Puppets= in the room. +**** Puppeting +Let’s convert the Bartender to a Chatbot using [[file:~/src/moss-n-puddles/personalities/tavern.md][tavern.md]]. This way, talking to the Bartender *answers* from everyone. + +#+BEGIN_SRC evennia + @set bartender/personality = "tavern" + # + @set bartender/personality_file = "personalities/tavern.md" +#+END_SRC + +**** Hide and Seek +First create a number of magic rings equal to the number of players, minus one: + +#+BEGIN_SRC evennia :tangle no + @create magic ring:typeclasses.things.MagicRing + # + @desc magic ring = Octarine sparks fly when you don this ring.|/Commands: |gtransform|n and |guntransform|n. + # + give magic ring to _char_ +#+END_SRC + +And create a monocle: + +#+BEGIN_SRC evennia :tangle no + @create monocle:typeclasses.things.MagicMonocle + # + @desc monocle = Allows you to see past magical illusions. |/Command: |gpeer |n + # + give monocle to _char_ +#+END_SRC + +Reset the game: + +#+BEGIN_SRC evennia :tangle no + # Who has the monocle + py me.search('monocle', typeclass="typeclasses.things.MagicMonocle", global_search=True).reset_counts() +#+END_SRC + +Get the scoreboard: + +#+BEGIN_SRC evennia :tangle no + # Who has the monocle + py me.search('monocle', typeclass="typeclasses.things.MagicMonocle", global_search=True).report_score() +#+END_SRC + +Need a global clock, right? + +#+BEGIN_SRC evennia :tangle no + @create clock:typeclasses.things.GlobalAlarmClock + # + @desc clock = Strange round clock with four hands and twenty symbols. +#+END_SRC + +Need a channel to chat about the game: + +#+BEGIN_SRC evennia + @channel/create Hide and Seek Game;hide;game = Messages to people playing the Hide and Seek game + # + # Others would type: + # channel/sub game +#+END_SRC + +Start the hiders … +#+BEGIN_SRC evennia :tangle no + say Alright everyone ready to play the game? + # + py me.search('clock').start_timer(60, "Ready, get set ... and |wgo hide!|n|/Seeker will start the count-down.", "Ready or not, here comes the seeker!") + # + py me.search('clock').start_timer(300, finish="The round of the game is done! Let's return and see the score.") + # + @tel = here +#+END_SRC + +*** Bowl of Candy +Gives out candy, as there is a never-ending bowl of them on the bar. +Gotta have something to munch on. + +#+BEGIN_SRC ruby + @create/drop bowl of candies;bowl;candy : typeclasses.consumables.Producer +#+END_SRC + +With a description: +#+BEGIN_SRC ruby + @desc bowl = A large white daisy forms a bowl holding a collection of colored hard candies. +#+END_SRC + +The bowl shouldn’t be steal-able, but a =get= on a Producer now calls it =do_make= function: + +#+BEGIN_SRC ruby :tangle no + @lock bowl = get:true() + # + @set bowl/get_err_msg = "Don't think you could grab the entire bowl of candy. Just |gpick|n one candy." +#+END_SRC +Hold off on the viewing: + +#+BEGIN_SRC ruby + @set bowl/hidden_tag = "hidden_bowl" + # + @lock bowl = view:tag(hidden_bowl) +#+END_SRC + +We have to have the bowl of candy describe what it /makes/: + +#+BEGIN_SRC ruby + @set bowl/make_name = "candy" +#+END_SRC +Including some plural aliases: +#+BEGIN_SRC ruby + @set bowl/make_aliases = ["candies"] +#+END_SRC + +And a verb when they /get/ the consumable: +#+BEGIN_SRC ruby + @set bowl/make_verb = "$conj(grab) a" + # + @set bowl/make_note = " from the bowl" +#+END_SRC + +This one is optional as it defaults to Consumable: +#+BEGIN_SRC ruby :tangle no + @set bowl/make_class = "typeclasses.consumables.Consumable" +#+END_SRC + +And the bowl needs to know the /description/ of the Consumable, so that it can attach that: +#+BEGIN_SRC ruby + @set bowl/make_desc = "Bright << red ^ orange ^ yellow ^ blue ^ violet >> candy with << flecks ^ spots ^ stripes >> of << red ^ orange ^ purple ^ violet ^ orange >>." +#+END_SRC + +How many candies are there when you pick them? +#+BEGIN_SRC ruby + @set bowl/make_amount = 1 +#+END_SRC + +How many candies do you eat at a time: +#+BEGIN_SRC ruby + @set bowl/make_eat_amount = 1 +#+END_SRC + +Messages can be randomly selected: +#+BEGIN_SRC ruby + @set bowl/make_eat_msgs = [ + "Tastes of elderberry. Do I even know what that tastes like?", + "Tastes of elderflower...certainly not youngerflower.", + "Tastes of forest berry. I believe I got lucky with this one.", + "Wildflower, as that intense flavor is not tame.", + "Tastes of eggnog, with an aftertaste of Cousin Eddie's RV.", + "Tastes like pickled cucumber.", + "Tastes like maple bacon.", + "That burning horseradish is clearing the sinuses!", + "Sriracha flavor!? Wow!", + "Taste of cotton candy covered bacon. Two flavors distinct flavors for sure.", + "Tastes like a bowl of borscht.", + "Dill pickle candy!?", + "Curry flavored candy!?", + "Tastes uniquely of smoked paprika.", + "Tastes of blue cheese, without all the calories.", + "Tastes like charcoal.", + "Tastes like olive oil.", + "Tastes like honeycomb... with bits of bee.", + "Tastes like cereal milk.", + "Tastes like avocado. A very ripe avocado.", + "Tastes like dirt...and worm.", + "Tastes like fish sauce...anchovy? mackeral? carp?", + "Garlic flavored hard candy, a favorite of witches.", + "Tastes like fermented soybean. I'm sure this is a delicacy somewhere.", + "Tastes like tomato... sauce.", + "Tastes like sauerkraut.", + "Tastes like honey mustard.", + "Tastes like charred pineapple.", + "Tastes like smoked salmon.", + "Tastes like pumpkin curry, and rice...with a hint of spice.", + "Tastes like miso caramel and wasp. Candy-covered insects is an odd choice.", + "Tastes like celery.", + "Tastes like pumpernickel.", + "Tastes like spicy kimchi.", + ] +#+END_SRC + +And a brief test … and since this is the last thing in the bar, let’s have our test account leave as well. + +#+BEGIN_SRC tcl + send "get candy\n" + expectit "You grab a candy" + + send "eat candy\n" + expectit "\n" + + # Let's keep a candy to feed the wee beastie + send "get candy\n" + expectit "You grab a candy" + + # Until we write tests for the bar... + send "leave\n" + expectit "Glittering Glade" + + # Let's get back to the Meadow ... + send "west\n" + expectit "Frog Meadow" +#+END_SRC +** Mellow Marsh +The river from the flows into a marsh: + +#+BEGIN_src evennia + @teleport mp05 + # + @dig Mellow Marsh;mp08 :typeclasses.rooms_weather.TimeWeatherRoom = south to marsh;south;marsh;s,north to meadow;n;north;meadow +#+END_SRC + +And =look south= should show: + +#+BEGIN_src evennia + @desc south = Looks like the river spreads into a marsh. Is that a hut you can see? +#+END_SRC + +Describe the muddy marsh: + +#+BEGIN_src evennia + @set south/traverse_msg = "The ground gets muddier and harder to walk the further into the marsh you go..." +#+END_SRC + +And a description of the marsh: + +#+BEGIN_src evennia + @teleport mp08 + # + @desc here = The river spreads into a muddy marsh full of |Ygrass|n and tall, white-topped |Yreeds|n. Colorful |Ybirds|n in the sparse tree surrounding the marsh yell out a loud chorus. Purple herons and other marsh |Ybirds|n hunt in the tall swamp grass. Glowing |Yfireflies|n create a synchronized light show over the swamp grass in the deepening dusk. Giant pink and purple |Ymoths|n flutter over the dark flowers.|/A small |Yhut|n, perched on three |Ystilts|n to keep it dry, stands in middle of the slough. +#+END_SRC + +And a new state when the house is bound: + +#+BEGIN_src evennia + @desc/bound here = The river spreads into a muddy marsh full of |Ygrass|n and tall, white-topped |Yreeds|n. Colorful |Ybirds|n in the sparse tree surrounding the marsh yell out a loud chorus. Purple herons and other marsh |Ybirds|n hunt in the tall swamp grass. Glowing |Yfireflies|n create a synchronized light show over the swamp grass in the deepening dusk. Giant pink and purple |Ymoths|n flutter over the dark flowers.|/|/A pissed-off looking |Yhut|n, with its lasso'd stilt-like legs, struggles against its bounds in the middle of the slough. +#+END_SRC + +And =look north= should show: + +#+BEGIN_src evennia + @desc north = The meadow to the north looks easier to walk around. +#+END_SRC + +Describe the muddy marsh: + +#+BEGIN_src evennia + @set north/traverse_msg = "The ground gets drier and easier to walk as you approach the meadow..." +#+END_SRC + +Details for a more immersive experience: + +#+BEGIN_src evennia + @detail stilts;stilt = Those stilts are scaly...and clawed...and, are they chicken legs? How expected. +#+END_SRC + + +#+BEGIN_src evennia + @detail birds = Birds of every color on the rainbow and beyond fly and squawk around you, but keep their distance. +#+END_SRC + +#+BEGIN_src evennia + @detail moths;moth = On closer inspection, the moths are really |Ysprites|n playing a strange chasing game. +#+END_SRC + +#+BEGIN_src evennia + @detail sprites;sprite = Seems that sprites with pink wings are on one team, and purple winged sprits on the other. The game became exciting as one sprite, holding aloft a flag is trying to avoid others as it streaks to the far side of the marsh. +#+END_SRC + +#+BEGIN_src evennia + @detail fireflies = A passing firefly shows it to actually be a |Ypixie|n holding two colorful lanterns. +#+END_SRC + +#+BEGIN_src evennia + @detail pixie;pixies = The pixies ignore you as their choreography keeps them focused on their dance. +#+END_SRC + +#+BEGIN_src evennia + @detail grass = Guess this kind of grass doesn't mind the wet environment. +#+END_SRC + +#+BEGIN_src evennia + @detail mud = Pretty brown and sticky. +#+END_SRC + +And we test this normal /state/: + +#+BEGIN_SRC tcl + send "look south\n" + expectit "Looks like the river spreads into a marsh." + + send "south\n" + expectit "perched on three" + + send "look north\n" + expectit "The meadow to the north looks easier to walk around." + + send "look birds\n" + expectit "Birds of every color on the rainbow and beyond fly and squawk around you" + + send "look moth\n" + expectit "On closer inspection, the moths are really" + + send "look sprite\n" + expectit "Seems that sprites with pink wings are on one team" + + send "look fireflies\n" + expectit "A passing firefly shows it to actually be" + + send "look pixies\n" + expectit "The pixies ignore you as their choreography keeps them focused on their dance." + + send "look grass\n" + expectit "Guess this kind of grass doesn't mind the wet environment." +#+END_SRC + +Let’s change and test this new the state (granted, we define the hut later): + +#+BEGIN_SRC tcl + send "hut\n" + expectit "the hut scurries away" + + send "use 1-rope\n" + expectit "Something tells you that the rope won't last for long." + + send "look\n" + expectit "A pissed-off looking" + + send "look hut\n" + expectit "straining at its bonds" + + send "hut\n" + expectit "The door, and its landing, are still too high and out of reach" + + # Let's wait to make sure that the hut eventually breaks free ... + puts "NOTE: Waiting for the hut to break free of its bonds..." + set timeout 90 + expectit "The hut, straining against its bounds, finally breaks free" + set timeout 30 +#+END_SRC + +Finally, let’s attempt to describe a prompt for some generative AI images: + +#+begin_example +Generate a watercolor with pen and ink outlining with vibrant colors depicting a muddy marsh of grass and tall, white-topped reeds. +Add a small hut with herb boxes and hanging baskets of flowers stand on three stilts reminiscent of bird legs. +Add a purple-feathered heron. +#+end_example +*** Muddy Water +As a future idea of making potions, we can collect /muddy water/, which needs to be turned to wine. + +#+BEGIN_src evennia + # @teleport/quiet mp08 + # + @create/drop muddy river;river;stream;water: typeclasses.drinkables.Water + # + @lock river = get:false() + # + @set river/get_err_msg = "Slippery things, those rivers. Seems you would need |gfill|n a |gbottle|n, or at least a cup to hold the muddy water." + # + @desc river = A muddy, almost stagnant river. Smells like a fecund stew of moist dirt and decomposing swamp herbage. + # + @set river/fill_name = "muddy water" + # + @set river/fill_desc = "muddy water from the marsh." + # + @set river/fill_msgs = ["$You() << $conj(get) ^ $conj(kneel) >> down, and $conj(fill) $pron(your) {2} with the muddy water."] +#+END_SRC + +And test looking at it: + +#+BEGIN_SRC tcl + send "look river\n" + expectit "A muddy, almost stagnant river." + + # The 'get water' should work, but issues with aliases... + send "get river\n" + expectit "Slippery things, those rivers." +#+END_SRC + +*** Purple Heron +Create a puppet of the bird hunting frogs and pixies. :-D + +#+BEGIN_src evennia + @create/drop purple heron: typeclasses.chatbots.ChatBot + # @update heron = typeclasses.chatbots.ChatBot + # + @set heron/pose = "stalking the swamp grass" + # + @set heron/pose_default = "stalking the swamp grass" + # + @set heron/pose_sleeping = "stalking the swamp grass" + # + @lock purple heron = get:false() + # + @set purple heron/get_err_msg = "You try to get it, but it just flies out of reach." +#+END_SRC + +What data file of responses should we use? + +#+BEGIN_src evennia + @set heron/data_file = "npcs.txt" + # + @set heron/speech_vocalizations = ["says", "croaks", "squawks"] +#+END_SRC + +Note that we give him a male gender: + +#+BEGIN_src evennia + @set heron/gender = "male" +#+END_SRC + +Prefix article? + +#+BEGIN_src evennia + @set heron/article = "The" +#+END_SRC + +And a good description that I can rework: + +#+BEGIN_src evennia + @desc heron = Shades of violet and purple adorn the feathers of this majestically tall heron, that stalks the marsh |Ygrass|n, hunting small critters. +#+END_SRC + +Let’s turn it on: + +#+BEGIN_SRC evennia + py me.search("heron").backstory("heron") +#+END_SRC + +Since it is an NPC it has certain mutterings it can do: + +#+BEGIN_src evennia + @set heron/muttering_file = "jethro_tull_songs.txt" + # + @set heron/muttering_gap = 7 + # + @set heron/muttering_interval = 360 # Little over 3 minutes +#+END_SRC + +#+BEGIN_src evennia + @set heron/muttering_formats = [ + "sings to |oself as if no one is listening, \"{0}\"", + "continues to sing to |oself, \"{0}\"", + "croons to |oself, \"{0}\"", + "finishes |p verse, \"{0}\"|/", + ] +#+END_SRC + +And add the absent-minded singing script: + +#+BEGIN_src evennia + @script heron = typeclasses.scripts.Muttering +#+END_SRC + +Test that the heron can talk: + +#+BEGIN_SRC tcl + send "say Hello there, big bird.\n" + expectit "heron" + + send "get heron\n" + expectit "flies out of reach" +#+END_SRC + +*** Ten-foot Poles +The reed can be a [[file:~/src/moss-n-puddles/typeclasses/consumables.py::class Producer(Object):][producer]] that makes ten foot poles … needed to get into the hut. + +#+BEGIN_src evennia + @create/drop lot of tall reeds;tall reeds;reeds: typeclasses.consumables.Producer +#+END_SRC + +With a description: +#+BEGIN_src evennia + @desc reeds = Extremely tall, white reeds tipped with white gooey clumps. One could hazzard a guess that with a little manipulation, one could make something from them. +#+END_SRC + +We have to have the reeds describe what it /makes/: +#+BEGIN_src evennia + @set reeds/make_name = "ten-foot pole" +#+END_SRC + +And a verb when they /get/ the consumable: +#+BEGIN_src evennia + @set reeds/make_verb = "$conj(pluck) and $conj(shape) a" +#+END_SRC + +And a commentary: + +#+BEGIN_src evennia + @set reeds/make_note = " from a marsh reed." +#+END_SRC + +They shouldn’t be able to make too many poles: + +#+BEGIN_SRC evennia + @set reeds/make_limit = 1 + # + @set reeds/make_limit_msg = "You can't make more poles when you are already holding one." +#+END_SRC + +A ten-foot pole should act like a stick: + +#+BEGIN_src evennia :tangle no + @set reeds/make_class = "typeclasses.things.Stick" +#+END_SRC + +And the reeds needs to know the /description/ of the Consumable, so that it can attach that: +#+BEGIN_src evennia + @set reeds/make_desc = "A long pole shaved from a marsh reed." +#+END_SRC + +How much is there when you pick them? +#+BEGIN_src evennia + @set reeds/make_amount = 1 +#+END_SRC + +And let’s test that we can get a pole: + +#+BEGIN_SRC tcl + send "look reeds\n" + expectit "Extremely tall, white reeds tipped with white gooey clumps." + + send "get reeds\n" + expectit "You pluck and shape a ten-foot pole from a marsh reed" +#+END_SRC + +*** Pixie Dust +Part of the [[Potions and their Ingredients][Alchemist Path]], we use /pixie dust/ to create a [[Trippy Potion]]. + +We put this quote in the book: +#+begin_quote +I’ve noticed Pixies often dance in the marshlands to the East, but are often invisible except in the evenings. I’ve attempted to discuss a trade for pixie dust, but often luck out as they often pay more attention to their choreography than any trinkets I could produce. +#+end_quote + +And create it here in the Marsh: + +#+BEGIN_src evennia + # @teleport/quiet mp08 + # + @create/drop patch of glitter;pixie dust;dust: typeclasses.consumables.Producer + # + @desc pixie dust = As you look at reeds and marsh grass, you notice the shiny glitter is actually dander from pixies... pixie dust. With a little effort, you could gather a small sack of it. + # + @set pixie dust/make_class = "typeclasses.consumables.Herb" + # + @set pixie dust/make_name = "wad of pixie dust" + # + @set pixie dust/make_verb = "$conj(collect) a sticky" + # + @set pixie dust/make_desc = "wad of the good, shiny stuff." + # + @set pixie dust/make_amount = 1 + # + # And we can't see them until we are an alchemist: + @lock pixie dust = view:tag(alchemist) +#+END_SRC + +And test that we can’t see it now: + +#+BEGIN_SRC tcl + dont_expect "You notice" "pixie dust" +#+END_SRC +*** Hints +The heron should give the hints, but we need to make it different enough, for getting into the hut is the reason I build the hint system. + +#+BEGIN_SRC yaml + mellow_marsh: + narrative: >- + The << purple ^ large ^ >> heron + << gives you a sideways glance ^ raises a feathery eyebrow ^ stops its hunting >>, + and << mentions ^ says >>, "{0}" ;; + "Hrm," says the << purple ^ large ^ >> heron. + "You seem << puzzled ^ confused ^ perplexed >>. {0}" ;; + "You seem << puzzled ^ confused ^ perplexed >>," + says the << purple ^ large ^ >> heron. "{0}" ;; + hints: + default: >- + Perhaps you can |Ylasso|n the legs, er, stilts, so they don't + run off? Then, you can |Yjump|n in. + lasso: If you don't have a rope, perhaps strong greenery, like |Yvines|n? + vines: I flew over a |Yboulder|n once. It was covered in vines. + boulder: >- + I think the boulder was north and west of here, in the forest, + in the Grove of the Matriarchs. + jump: >- + Yeah, your legs are too short, and your featherless arms can't + lift you. Perhaps you should find something to |Ylaunch|n you + higher in the air? + launch: Yeah, launch, as in a |Ypole|n or something. + pole: Those reeds are pretty tall. You could possibly use them. + river: Wizards come her to |Ycollect|n the river water for use in potions. + collect: To collect the water, you will need a |Ybottle|n. + bottle: You want to |gfill bottle|n to collect the water. +#+END_SRC + +** Trampoli’s Hut on Stilts + +#+BEGIN_src evennia + @teleport mp08 + # + @dig Homey Hut;mp09 = hut on stilts;hut,leave;outside;marsh +#+END_SRC + +And describe it as =hut=: + +#+BEGIN_src evennia + @desc hut on stilts = Apparently made from swamp |Ygrass|n, the homey-looking hut has a wood door high above ground. Baskets of potted flowers and herbs garnish every window. +#+END_SRC + +Let’s keep most characters out of the hut. The idea is you need to fly to get in. But we have a sequence For the initial exit, it is just always impossible to use: + +#+BEGIN_src evennia + @lock hut on stilts = traverse:tag(enter_hut_nope, mp) +#+END_SRC + +Let’s add an alias: + +#+BEGIN_src evennia + @alias hut on stilts = hut +#+END_SRC + +#+BEGIN_src evennia + @set hut on stilts/err_traverse = "Upon approaching the hut, the hut scurries away on its stilt-like legs." +#+END_SRC + +And we need to create a second exit: + +#+BEGIN_src evennia + @open rope-bound hut = Homey Hut +#+END_SRC + +Let’s add an alias: + +#+BEGIN_src evennia + @alias rope-bound hut = hut +#+END_SRC + +And describe it: + +#+BEGIN_src evennia + @desc rope-bound hut = The hut doesn't look happy, straining at its bonds that keep somewhat in place. The wood door to the hut, and its landing, continue to be too hign and out of your reach. +#+END_SRC + +If the other exit is here, you just need the pole: + +#+BEGIN_src evennia + @lock rope-bound hut = traverse:holds('ten-foot pole') +#+END_SRC + +And a good reason why you need the pole: + +#+BEGIN_src evennia + @set rope-bound hut/err_traverse = "The door, and its landing, are still too high and out of reach, and riding a bucking owlbear may be easier than climbing the stilt-legs that immediately throw you to the ground." +#+END_SRC + +If you do figure out how to get through the hut: + +#+BEGIN_src evennia + @set rope-bound hut/traverse_msg = "You use your pole to vault yourself up through the door of the hut..." +#+END_SRC + +Let’s put this second exit away until the [[file:~/src/moss-n-puddles/typeclasses/things.py::class Rope(Object):][rope calls]] it: + +#+BEGIN_src evennia + @teleport/tonone rope-bound hut +#+END_SRC + +We have a rope and the ten-foot pole, let’s see if we can get in: + +#+BEGIN_SRC tcl + send "use rope on hut\n" + expectit "Something tells you that the rope won't last for long." + + send "hut\n" + expectit "Homey Hut" +#+END_SRC + +*** Inside Trampoli’s Hut +Let’s go inside to decorate: + +#+BEGIN_src evennia + @teleport mp09 + # + @desc here = A homey room cluttered with drying |Yherbs|n, |Yjars|n of preserves, and natural made |Ytalismans|n. Even the table and chairs, covered in jars, |Ybags|n and boxes, indicate the owner doesn't entertain much. Stairs lead up to a spacious loft with a bed. +#+END_SRC + +And describe leaving: + +#+BEGIN_src evennia + @desc leave = From the doorway, you see the marshland below. +#+END_SRC + +#+BEGIN_src evennia + @set leave/traverse_msg = "You open the door of the hut, and scramble down to the marsh below. Surely the ground the moist and soft to break your fall." +#+END_SRC + +And the details: + +#+BEGIN_src evennia + @detail herbs = Clusters of plants, a mixture of flowers and herbal leaves, all bound with twine and reeds, hang from spots around the room, fragranting the air. +#+END_SRC + +#+BEGIN_src evennia + @detail jars = Sealed jars of fruits, vegetables, herbs and spices. +#+END_SRC + +*** Chair +A chair to sit while working +#+BEGIN_src evennia + @create/drop chair:typeclasses.sittables.Sittable +#+END_SRC + +How descriptive: +#+BEGIN_src evennia + @desc chair = A chair next to the table. +#+END_SRC + +Can’t steal this chair either: +#+BEGIN_src evennia + @lock chair = get:false() +#+END_SRC + +Let’s do a funnier message: +#+BEGIN_src evennia + @set chair/get_err_msg = "Stop trying to steal everything not nailed down." +#+end_src + +And test this out; + +#+BEGIN_SRC tcl + send "look chair\n" + expectit "A chair next to the table." + + send "sit\n" + expectit "You sit on the chair." + + send "stand\n" + expectit "You stand up" + + send "get chair\n" + expectit "Stop trying to steal everything not nailed down." +#+END_SRC +*** Jars +Every time we look at a jar, we see something else … that we can’t take. This creates ambiance without adding too much complexity? + +#+BEGIN_SRC evennia + @tel/quiet Homey Hut + # + @create/drop assortment of jars;jars;jar: typeclasses.puzzles.Changling +#+END_SRC + +Can’t get them: + +#+BEGIN_SRC evennia + @lock jars = get:false() + # + @set jars/get_err_msg = "\"Do not steal our winter provisionings,\" the horned wolf skull says. \"What are you a thief?\"" +#+END_SRC + +And the generate description: + +#+BEGIN_SRC evennia + @set jars/desc_first_prefix = "<< Fascinating ^ Interesting ^ Curious >> << collection of ^ assortment of ^ >> << jars ^ contents ^ ingredients >>. You look at one << jar ^ >> with << an afixed ^ an attached >> label of << scrawling ^ scribbling ^ squiggling >> << ink ^ writing ^ letters >>,|w" + # + @set jars/desc_prefix = "You look at another << jar ^ >> with << an afixed ^ an attached >> label of << scrawling ^ scribbling ^ squiggling >> << ink ^ writing ^ letters >>,|w" + # + @set jars/desc_postfix = "" +#+END_SRC + +And now for a list of the contents: + + #+BEGIN_SRC evennia + @set jars/descs = ( + "Dragon's Breath|n. A swirling mist of iridescent smoke that changes color, said to contain the essence of fire.", + "Phoenix Ashes|n. A small jar filled with fine, red and gold ash, said to have the power of rebirth.", + "Enchanted Rose Petals|n. Dried petals that change color with the phases of the moon, said to attract love.", + "Eye of Newt|n. Filled with many small eyeballs.", + "Timekeeper's Sand|n. Fine, golden sand that flows slowly, rumored to have the power to manipulate time.", + "Cursed Bone Shards|n. Jagged pieces of bone, each one etched with strange symbols and glowing faintly.", + "Enchanted Honey|n. Thick, golden honey that glimmers with tiny flecks of light, like captured sunlight.", + "Faerie Wings|n. Delicate, translucent wings that shimmer in various colors, said to grant agility.", + "Elemental Stones|n. Small, smooth stones representing earth, air, fire, and water, each with a unique glow.", + "Owlbear Hair|n. Strands of shimmering hair from various magical creatures, said to enhance spells.", + "Frosted Rose Petals|n. Dried flowers that appear to be covered in frost, said to bring winter's magic.", + "Toadstool Caps|n. Vibrant mushroom caps of red, orange, and yellow, and adorned with delicate white speckles that catch the light.", + "Glowcaps|n. Clusters of tiny, bioluminescent mushrooms that emit a soft, greenish glow.", + "Dream|n. Fluffy, cotton-like wisps gently floating, resembling miniature clouds in the jar.", + "Mandrake Root|n. A twisted, gnarled root with a faintly green hue, nestled in a jar of dark soil.", + ) +#+END_SRC + +How can we test this cool feature? + +#+BEGIN_SRC tcl + send "look jar\n" + expect -re "You look at one.*labeled" +#+END_SRC + +*** Herbs +Like the [[*Jars][Jars]], the herbs return a different response each time they are viewed. + +#+BEGIN_SRC evennia + @create/drop collection of herbs;herbs;herb: typeclasses.puzzles.Changling +#+END_SRC + +While the skull protects the jars, we will have the demon stop the herbs from being pinched. + +#+BEGIN_SRC evennia + @lock herbs = get:false() + # + @set herbs/get_err_msg = "On the wall, the carving comes to life, and flies next to you. \"Do not take her harvest,\" it says as it bats your hand away." +#+END_SRC + +#+BEGIN_SRC evennia + @set herbs/desc_first_prefix = "<< Plenty ^ Many >> bundles around the room. One << particular ^ peculiar ^ >> << bundle ^ bouquet garni >> of " + # + @set herbs/desc_prefix = "<< Another ^ This >> << particular ^ peculiar ^ >> << bundle ^ bouquet garni >> of " + # + @set herbs/desc_postfix = " Tied with << twine ^ string ^ lace >> and << hanging from a rafter ^ hung from a nail ^ dangling from a post of a chair >>." +#+END_SRC + +And the individual choices are more appearance, and possibly smell, without claiming to be /worldly herbs/. Would like to add some dried red and other colored leaves to make it more fantastical. + +#+BEGIN_SRC evennia + @set herbs/descs = ( + "grayish-green, crinkled leaves, and has a strong, earthy aroma, like sage.", + "small, purple flowers, with that sweet, lavender scent.", + "thin, woody needles, and has a strong, pine-like fragrance, like rosemary.", + "small, white flowers with yellow centers, resembling tiny daisies.", + "tiny, greenish-brown leaves, with a robust, herbal scent, like thyme.", + "dark green leaves with a refreshing, minty aroma.", + "brown leaves, with a refreshing, minty aroma.", + "dark green and crinkled leaves, and have a sweet, peppery scent" + "brown, crinkled leaves, with a sweet, peppery, almost basil-like scent" + "grayish-green, feathery leaves, with a slightly bitter, mugwort-like aroma.", + "small, white and yellow flowers that have a feathery appearance, like yarrow.", + "dark green, almost brown leaves, with a slightly bitter aroma.", + "dark green leaves, some almost brown, with a coarse texture and earthy scent, like nettle.", + "feathery fronds, ranging from light green to brown, with a sweet, anise-like scent.", + "purple flowers (some brown), with a spiky center and a slightly sweet aroma, like echinacea.", + "bright orange to yellow flowers, with a slightly sweet, herbal scent.", + "dark green, smooth leaves, and have a strong, aromatic scent, like bay.", + "grayish-green, feathery leaves with a distinctive, bitter aroma.", + "brown and woody roots, with a strong, earthy Valerian-like smell.", + "brown, woody root with a sweet, distinct aroma, like licorice.", + ) +#+END_SRC + +*** Bag of Mermaid Tears + +#+BEGIN_src evennia + @create/drop couple of bags of dried Mermaid Tears;bags;bag: typeclasses.consumables.Producer +#+END_SRC + +With a description: +#+BEGIN_src evennia + @desc bags = The bags, tied with a string, has a paper tag that reads |wMermaid Tears, dried.|n. The back of the tag has a note, |wIf I have to listen to another sob story about a clueless prince who just doesn't understand...|n +#+END_SRC + +We have to have the bush describe what it /makes/: +#+BEGIN_src evennia + @set bags/make_name = "bag" + # + @set bags/make_verb = "$conj(pick up) a" + # + @set bags/make_class = "typeclasses.consumables.Herb" + # + @set bags/make_desc = "A burlap bag, full of clear, crystalline droplets that shimmer with a hint of blue." + # + @set bags/make_amount = 1 + # + @lock bags = view:tag(alchemist) +#+END_SRC + +*** Talismans +To give some character, we create some interesting art that decorates this hut. + +#+BEGIN_src evennia + @detail talismans;talisman = A wood |Ycarving|n, a painted |Yskull|n, and curiously shaped |Ysculpture|n made from bundles of reeds, give the impression of inducing luck while showing a level of respect for the land. +#+END_SRC + +**** Horned Wolf Skull +For each talisman, we could create an object, but it wouldn’t be able to be taken, and instead of “can’t find skull”, we could give a better error message. + +#+BEGIN_src evennia + @create/drop painted skull + #ve + @desc skull = Painted with arcane symbols, a wolf skull sports curving, corrugated goat horns. + # + @lock skull = get:false() + # + @set skull/get_err_msg = "It appears firmly attached to the wall where it hangs." + # + @set skull/hidden_tag = "hidden_wolf_skull" + # + @lock skull = view:tag(hidden_wolf_skull) +#+END_SRC + +And test it: + +#+BEGIN_SRC tcl + dont_expect "You notice" "skull" + + send "look skull\n" + expectit "Painted with arcane symbols, a wolf skull sports" + + send "look\n" + expect -re "You notice.*skull" + + send "get skull\n" + expectit "It appears firmly attached to the wall where it hangs." +#+END_SRC + +**** Demon Carving +Perhaps the carving is actually the maid or something that could give hints. + +#+BEGIN_src evennia + @create/drop wood carving;carvings;daemon;imp + # + @desc carving = While rustic, the carving shows exquisite craftsmanship and artistry in its rendering of an daemon creature, less sinister and more impish. + # + @lock carving = get:false() + # + @set carving/get_err_msg = "As you reach for the carving, it promptly runs away." + # + @set carving/hidden_tag = "hidden_demon_carving" + # + @lock carving = view:tag(hidden_demon_carving) +#+END_SRC + +And test it: + +#+BEGIN_SRC tcl + dont_expect "You notice" "carving" + + send "look carving\n" + expectit "the carving shows exquisite craftsmanship and artistry" + + send "look\n" + expect -re "You notice.*carving" + + send "get carving\n" + expectit "As you reach for the carving, it promptly runs away." +#+END_SRC + +**** Reed Sculpture +The reeds should give a subtle hint to something that could be /spoken/ aloud. + +#+BEGIN_src evennia + @create/drop reed sculpture;reed;sculpture + # + @desc reed = The reed bundle, twisted and shaped in a six-spoke star, sports a blue tie. + # + @lock reed = get:false() + # + @set reed/get_err_msg = "It appears firmly attached to the wall where it hangs." + # + @detail tie = A blue ribbon with gold embroidery that spells: B U I O + # + @set reed/hidden_tag = "hidden_reed_sculpture" + # + @lock reed = view:tag(hidden_reed_sculpture) +#+END_SRC + +And test it: + +#+BEGIN_SRC tcl + dont_expect "You notice" "reed" + + send "look reed\n" + expectit "twisted and shaped in a six-spoke star" + + send "look\n" + expect -re "You notice.*reed" + + send "get sculpture\n" + expectit "It appears firmly attached to the wall where it hangs." +#+END_SRC + +The primary treasure is the horn. Anyone can acquire it, and keep it as a way to control the Leaf Boat. We generate them every 4 hours: + +#+BEGIN_src evennia + py timed_script = evennia.create_script(key="Create Horns", + typeclass='typeclasses.scripts.CreateHorns', + interval=600, + start_delay=False, + autostart=True, + attributes=[("destination", here)] ) +#+END_SRC + +*** Torches +The reed can be a [[file:~/src/moss-n-puddles/typeclasses/consumables.py::class Producer(Object):][producer]] that makes ten foot poles … needed to get into the hut. + +#+BEGIN_src evennia + @create/drop a bucket of torches: typeclasses.consumables.Producer +#+END_SRC + +With a description: + +#+BEGIN_src evennia + @desc bucket = A tall wood bucket full of resin-coated torches. +#+END_SRC + +We have to have the bucket describe what it /makes/: + +#+BEGIN_src evennia + @set bucket/make_name = "torch" +#+END_SRC + +And a verb when they /get/ the consumable: + +#+BEGIN_src evennia + @set bucket/make_verb = "$conj(take) a" +#+END_SRC + +And a commentary: + +#+BEGIN_src evennia + @set bucket/make_note = " from the bucket" +#+END_SRC + +The torches are special in that they last longer. +#+BEGIN_src evennia + @set bucket/make_class = "typeclasses.lightables.Torch" +#+END_SRC + +And the bucket needs to know the /description/ of the Consumable, so that it can attach that: + +#+BEGIN_src evennia + @set bucket/make_desc = "Made from marsh grass and reeds." +#+END_SRC + +How much is there when you pick them? +#+BEGIN_src evennia + @set bucket/make_amount = 1 +#+END_SRC + +Let’s get two: + +#+BEGIN_SRC tcl + send "get torch\n" + expectit "You take a torch from the bucket." + + send "inv\n" + expectit "Made from marsh grass" +#+END_SRC + +*** Trampoli the Witch +Create a puppet of the lady that owns the hut. + +#+BEGIN_src evennia + @create/drop Trampoli;old lady: typeclasses.chatbots.Witch + # @update Trampoli = typeclasses.chatbots.Witch +#+END_SRC + +Note that we give him a male gender: + +#+BEGIN_src evennia + @set old lady/gender = 'female' +#+END_SRC + +Work around the =pose= bug: + +#+BEGIN_src evennia + @py bt = self.search('old lady'); bt.sdesc.add('old lady'); bt.db.pose = 'playing with a deck of cards' +#+END_SRC + +Let’s set this Chatbot to use [[file:~/src/moss-n-puddles/personalities/witch.md][witch.md]]. + +#+BEGIN_SRC evennia + @set bartender/personality = "witch" + # + @set bartender/personality_file = "personalities/witch.md" +#+END_SRC + +And some poses: + +#+BEGIN_src evennia + @set old lady/pose_sleep = "napping soundly in bed on the upstairs loft" + # + @pose default old lady = playing with a deck of cards +#+END_SRC + +And a good description that I can rework: + +#+BEGIN_src evennia + @desc old lady = A blue shawl, adorned with arcane symbols in gold embroidery, covers the head of this small woman. Her large nose protruding from under the shawl, gives the appearance of a blue bird with bright green eyes. +#+END_SRC + +And an un-puppeted, sleeping, description: + +#+BEGIN_src evennia + @set old lady/desc_unpuppeted = "A blue shawl, adorned with arcane symbols in gold embroidery, covers the head of this small, napping woman. Her large nose protruding from under the shawl, as she snores loudly." +#+END_SRC + +If I do this, then she can’t really be puppeted. + +#+BEGIN_src evennia :tangle no + @set old lady/arrive = "5 ;; gm The old lady, seated at a table notices you, and smiles. \"Welcome, dearie,\" she says, \"What can I do for you?\"" +#+END_SRC + +And the old sleeping lady … + +#+BEGIN_src evennia :tangle no + @set old lady/arrive = "45 ;; gm You hear someone in the loft up the stairs stirring in their bed. ;; 55 ;; pose looking confused ;; emote The /me wakes up and says, \"What's all this then?\" ;; 5 ;; say Who are you, dearie? ;; 10 ;; say I'd think I have an intruder in my home! ;; 1 ;; emote grabs her broom and with a sweeping motion from the stairs, sends her intruder flying out the door! ;; teleport {3} = Mellow Marsh ;; 3 ;; gm/#457 You hear a voice coming from the hut, \"Scat!\" ;; emote heads up the stairs to bed. ;; pose sleeping in a bed up in the loft" +#+END_SRC +Turn it off when needed. + +#+BEGIN_src evennia :tangle no + @set old lady/arrive = None +#+END_SRC + +Perhaps … eventually, we can give her a gift, and she’ll allow the character to stay for tea. But then she would need to talk and interact. LLM? + +#+BEGIN_SRC evennia + @script old lady = typeclasses.chatbots.TravelingNPC +#+END_SRC + +*** Trampoli’s Tarot Deck +I’ve been wanting this woman to be able to put out a spread of Tarot-ish cards to entertain others. + +*** Mist Horn +The [[file:~/src/moss-n-puddles/typeclasses/scripts.py::class CreateHorns(Script):][CreateHorns script]] will generate a horn. Let’s have our Goblin tester get it: + +#+BEGIN_SRC tcl + send "look horn\n" + expectit "this curved horn" + + send "get horn\n" + expectit "You pick up a horn" +#+END_SRC + +*** Hints +Both the skull and the wood carving of a small daemon should be good narrators: + +#+BEGIN_SRC yaml + homey_hut: + narrative: >- + A wolf skull << attached to ^ on >> the wall says, "{0}." ;; + A wood carving of a small demon, << attached to ^ on >> the wall says, "{0}." + hints: + default: >- + I can see you might need |Ylight|n in the dark dungeons across + the sea. Of course, to travel there, you need to |Ycall|n for a + boat. But be quick, before the lady of the house wakes up! + light: >- + You can |gget|n a |gtorch|, and when you need it, |glight|n it. + call: >- + Don't worry about stealing, as you can |gget|n the |ghorn|n. + The sea mist will create another. +#+END_SRC + +And we can test these hints: + +#+BEGIN_SRC tcl :tangle no + send "hint\n" + expectit "I can see you might need" + + send "hint light\n" + expectit "when you need it" + + send "hint call\n" + expectit "The sea mist will create another" +#+END_SRC + +At this point, we need to get our testing character where we can migrate them over to the *Lazy Dock*. + +#+BEGIN_SRC tcl + send "leave\n" + expect "Mellow Marsh" + + send "north\n" + expectit "Frog Meadow" + + send "west\n" + expectit "Grove of the Matriarchs" +#+END_SRC + +** Lazy Dock +The dock leads out into a strange sea. The break in the trees lets you see the sky. Looks like a nice place to relax. + +Return to the Forest: +#+BEGIN_src evennia + @teleport mp01 +#+END_SRC + +And tunnel to the dock: +#+BEGIN_src evennia + @dig Lazy Dock;mp06 :typeclasses.rooms_weather.TimeWeatherRoom = south to dock;south;s,north to forest;north;n;footpath +#+END_SRC + +With a message about leaving the trees so that I don’t have to repeat that in the room description: +#+BEGIN_src evennia + @set south/traverse_msg = "You follow a path down and step out from under giant trees to see the sky." +#+END_SRC +And a description: +#+BEGIN_src evennia + @desc south = You see a dock on a lavender sea... Is that a comfortable-looking chair you can |gsit|n on? +#+END_SRC + +And move ourselves there: +#+BEGIN_src evennia + @teleport mp06 +#+END_SRC + +And describe this. +#+BEGIN_src evennia + @desc here = The dock you stand on juts into a |Ysea|n the color of |Ylavender flowers|n. Mesmerizing and calming from the way the sound of the |Ywaves|n lap along the |Yshore|n. + Someone has set a nice |Ychair|n for viewing. +#+end_src + +And details? + +#+BEGIN_src evennia + @detail waves = Despite the inclement weather, the waves ripple softly against the shore. Seems nice for fishing. + # + @detail boat;ship = The mastless ship looks like a giant leaf. Wonder if it comes to shore? + # + @detail lavender;flowers;flower;lavender flowers = The water is the |wcolor|n of lavender, not actually lavender. Hrm. Could it possibly be |wlavender tea|n? +#+END_SRC + +And describe the walk back into the forest: +#+BEGIN_src evennia + @set north/traverse_msg = "You walk up a path and back into the forest of giant trees." +#+END_SRC + + And a description: +#+BEGIN_src evennia + @desc north = This path leads into the forest of collosal trees. +#+END_SRC + +#+BEGIN_SRC tcl + send "look south\n" + expectit "You see a dock on a lavender sea" + + send "south\n" + expectit "Lazy Dock" + + send "look north\n" + expectit "This path leads into the forest of collosal trees." + + send "look boat\n" + expectit "The mastless ship looks like a giant leaf. Wonder if it comes to shore?" + + send "look waves\n" + expectit "Despite the inclement weather, the waves ripple softly against the shore." + #+END_SRC + +*** Lavender Sea +We’ll get ready for making potions by allowing one to collect water from _all_ the places, like the salty sea: + +#+BEGIN_src evennia + # @teleport/quiet mp06 + # + @create/drop lavender sea;sea;water;bay: typeclasses.drinkables.Water + # + @desc sea = A gently waving sea. Too bad the shore doesn't respond with a greeting of its own. Is that a |Yboat|n you see sailing in the distance? + # + @lock sea = get:false() + # + @set sea/get_err_msg = "You can only hold the sea in your heart. Perhaps a bottle, or at least a cup, could hold the salty water." + # + @set sea/fill_name = "salt water" + # + @set sea/fill_desc = "salty water with a purple hue." + # + @set sea/fill_msgs = ["$You() $conj(reach) down from the dock, and $conj(fill) $pron(your) {2} with the << salty ^ lavender ^ fragrant >> water."] +#+END_SRC + +And we’ll test looking at it: + +#+BEGIN_SRC tcl + send "look sea\n" + expectit "A gently waving sea." + + # This should be 'get water'! + send "get sea\n" + expectit "You can only hold the sea in your heart." +#+END_SRC + +*** Chair +A nice chair to sit on the dock by the bay, watching the clouds as they drift away. +#+BEGIN_src evennia + @create/drop chair;lounge chair:typeclasses.sittables.Sittable +#+END_SRC + +How descriptive: +#+BEGIN_src evennia + @desc chair = A cushioned wood chair of craftsmanship.|/Looks good for being out in the weather. +#+END_SRC + +Can’t steal this chair either: +#+BEGIN_src evennia + @lock chair = get:false() + # + @set chair/get_err_msg = "It's way too heavy for you to lift." +#+end_src + +Let’s see if we can sit down: + +#+BEGIN_SRC tcl + send "look chair\n" + expectit "A cushioned wood chair of craftsmanship" + + send "sit\n" + expectit "You sit on the chair." + + send "stand\n" + expectit "You stand up" + + send "get chair\n" + expectit "way too heavy for you to lift." +#+END_SRC + +*** Fishing Pole +It we are going to sit on a chair by the dock, why not go fishing? +#+BEGIN_src evennia + @create/drop fishing pole;pole:typeclasses.fishing.FishingPole +#+end_src + +With a description: +#+BEGIN_src evennia + @desc pole = A nice pole for catching fish. It even has a hook, and is ready to go! +#+END_SRC + +And tether it to the Dock, which we need to reset if the ID numbers ever change. + +#+BEGIN_src evennia + @lock pole = tethered:id(Lazy Dock) + # + @set pole/tethered_msg = "Let's leave the fishing pole here at the dock for others to fish...besides, where else are you going to go fishing around here?" +#+END_SRC + +Issues? + +#+BEGIN_src evennia :tangle no + @teleport/quiet fishing pole = Lazy Dock +#+END_SRC + +What about some details: +#+BEGIN_src evennia + @detail hook;bait = One of those shiny lures, made from gold coins. Curiouser. Seems you don't need to bait this hook. +#+END_SRC + +Let’s see if we can fish: + +#+BEGIN_SRC tcl + send "get pole\n" + expectit "You pick up a fishing pole." + + send "cast\n" + expectit "You cast" + + send "reel\n" + # Too many messages to expect. + + send "drop fishing pole\n" + expectit "You drop a fishing pole." +#+END_SRC + +*** Sign +Need to make the fishing pole “stay” at the Dock. Maybe with a message about sticking around for the next person. + +#+BEGIN_src evennia + @create/drop sign:typeclasses.readables.Readable +#+END_SRC + +Should the description also be the message? +#+BEGIN_src evennia + @desc sign = You see a wood sign tied with a rope around the back of the chair. It reads, |wFish at your own annoyance. Please return pole when finished.|n +#+END_SRC + +Might as well allow the user to read it: +#+BEGIN_src evennia + @set sign/inside = "Fish at your own annoyance. Please return pole when finished." +#+END_SRC + +And lock down the sign: +#+BEGIN_src evennia + @lock sign = get:false() + # + @set sign/get_err_msg = "This granny knot holding the sign to the chair is serious. You can't take it." +#+END_SRC + +Test if it is readable: + +#+BEGIN_SRC tcl + send "look sign\n" + expectit "You see a wood sign tied with a rope around the back of the chair" + + send "read sign\n" + expectit "Fish at your own annoyance. Please return pole when finished." + + send "get sign\n" + expectit "This granny knot" +#+END_SRC + +*** Raven +Here for hints … and a bit of a distraction. + +#+BEGIN_SRC evennia + @create/drop Raven;bird: typeclasses.chatbots.ChatBot + # + # @update raven = typeclasses.chatbots.ChatBot + # + @desc raven = A large raven with curious black eyes. + # + @set raven/gender = "neutral" + # + @set raven/pose = "dozing while perched on a branch" + # + @set raven/pose_sleep = "dozing while perched on a branch" + # + @set raven/pose_default = "curiously staring at you" + # + # @sdesc large raven +#+END_SRC + +Let’s load the goodies: + +#+BEGIN_SRC evennia + py me.search("raven").backstory("raven") +#+END_SRC + + +*** Hints +We should keep the /raven puppet/ here to give out the hints. + +#+BEGIN_SRC yaml + lazy_dock: + narrative: >- + The << black ^ large ^ >> raven + << gives you a sideways glance ^ raises a feathery eyebrow ^ + looks curiously at you >>, and + << mentions ^ says ^ croaks >>, "{0}" + hints: + default: >- + Docks are good for |Yfishing|n and traveling by |Yboat|n. + fishing: >- + If you dare catch a |Yfish|n, repeat the commands |gcast|n + and |greel|n. + fish: You can get rid of obnoxious fish using the |gthrow|n command. + boat: A magical boat appears here, but only if you |Ycall|n it. + call: To call the boat, |gblow|n a |Yhorn|n. + swamp: I think the swamp is called |wMellow Marsh|n. + horn: >- + The mystical south wind gathers the mystical mist from the sea + to create a calling horn. Trampolina's hut in the |Yswamp|n + often is a conduit for the creation of these horns. Good luck + getting in there. +#+END_SRC + +How much do we want to test? + +#+BEGIN_SRC tcl + send "hint\n" + expectit "Docks are good" + send "hint fishing\n" + expectit "If you dare catch" + send "hint fish\n" + expectit "You can get rid of obnoxious fish" + send "hint boat\n" + expectit "A magical boat appears here" + send "hint call\n" + expectit "To call the boat" + send "hint swamp\n" + expectit "I think the swamp is called" + send "hint horn\n" + expectit "The mystical south wind gathers the mystical mist from the sea" +#+END_SRC + +** Sandy Shore +Could we extend the sea from the [[file:mud.org::*The Dock][The Dock]] down a shore: + +#+BEGIN_SRC evennia + @teleport/quiet mp06 + # + @dig Shore;mp15 :typeclasses.rooms_weather.TimeWeatherRoom = south along shore;shore;south;s,north to dock;north;n;dock +#+END_SRC + +With a message about leaving the trees so that I don’t have to repeat that in the room description: +#+BEGIN_SRC evennia + @set south/traverse_msg = "Leaving the dock, you want along the soft sandy shore next to the Lavender Sea, enjoying the mesmerizing sound of the surf... until you come to a shack that blocks your stroll." +#+END_SRC + +And a description: +#+BEGIN_SRC evennia + @desc south = You see a shack down along the sandy shore. +#+END_SRC + +And move ourselves there: +#+BEGIN_SRC evennia + @teleport mp15 +#+END_SRC + +And describe the walk back to the dock: +#+BEGIN_SRC evennia + @set north/traverse_msg = "You walk along the shore of the lavender sea back to the dock." +#+END_SRC + + And a description: +#+BEGIN_SRC evennia + @desc north = The sandy shore to the north ends at a dock, jutting into the lavender sea. +#+END_SRC +And describe this. +#+BEGIN_SRC evennia + @desc here = Puppy-dog |Ywaves|n on a lavender |Ysea|n, snap your heels half-heartedly. Walking hard steps, punching crusted |Ysand|n, difficulty crossing land. Robust |Yshack|n squatting below a |Ypine|n, locked door holding painted |Ysign|n. +#+end_src + +And details? + +#+BEGIN_SRC evennia + @detail waves = Despite the inclement weather, the waves ripple gently against the shore. + # + @detail sea;lavender sea = Is that a |Yboat|n you see sailing in the distance? + # + @detail boat;ship = The mastless ship looks like a giant leaf. Wonder if it comes to shore? + # + @detail shack = Standing crookedly at the edge of the sandy shore, this shack's weathered planks, bleached by the salty mist, imparts a ghostly appearance. The roof, adorned with seashells and driftwood, appears to be a patchwork of nature's treasures, inviting curious souls to uncover the secrets hidden within. +#+END_SRC + +What sort of hints should be here? + +#+BEGIN_SRC yaml + shore: + narrative: >- + A << small ^ green ^ >> crab, + << scurrying ^ crawling >> << along ^ in >> the surf, + << gives you a sideways glance ^ blinks its eyestalks ^ + looks curiously at you >>, and + << mentions ^ says ^ croaks >>, "{0}" + hints: + default: >- + Are you looking for the palace beneath the waves? You don't look + like a |Ymermaid|n or the sort of creature that can travel under + the water that far... at least, not without the deep |Ykelp|n. + mermaids: >- + Those drama queens are always crying. Why do you think the sea + is so salty? Drying them, now that's a challenge. Only + |YTrampoli|n can do that. + trampoli: >- + Trampoli lives inland. I heard her house has legs! + kelp: >- + We call it deep kelp because it grows deep in the sea. + Sure, sometimes it washes up on shore, but the last + time that happened, I saw an |Yelf|n with blonde hair, + gathering up the rest of it. + elf: >- + What was unique about the elf? He had a pointed ears and nose, + that pointed straight up. Does that help? Oh, he was talking + to a large mushroom that was walking with him about ... drinking? + You land creatures seem obsessed with drinking. +#+END_SRC +And test the details: + +#+BEGIN_SRC tcl + # Currently at Lazy Dock + send "look south\n" + expectit "You see a shack down along the sandy shore." + + send "south\n" + expectit "Shore" + + send "look north\n" + expectit "The sandy shore to the north ends at a dock, jutting into the lavender sea." + + send "look waves\n" + expectit "Despite the inclement weather, the waves ripple gently against the shore." + + send "look lavender sea\n" + expectit "you see sailing" + + send "look boat\n" + expectit "The mastless ship looks like a giant leaf. Wonder if it comes to shore?" + + send "look shack\n" + expectit "Standing crookedly at the edge of the sandy shore, this shack's weathered planks" + #+END_SRC + +*** Sand +Part of the [[Potions and their Ingredients][Alchemist Path]], we use sand as an ingredient in a potion we want to make. + +#+BEGIN_SRC evennia + @create/drop lot of sand;sand : typeclasses.consumables.Producer + # + @desc sand = Glittery sand with small flecks of lavender-colored gems. + # + @set sand/make_name = "bag of sand" + # + @set sand/make_verb = "$conj(fill) a small" + # + @set sand/make_desc = "Small leather pouch of sand with lavender gems." + # + @lock sand = view:tag(hidden_sand) +#+END_SRC + +And testing: + +#+BEGIN_SRC tcl + dont_expect "You notice" "sand" + + send "look sand\n" + expect -re "You notice.*sand" + + send "get sand\n" + expectit "You fill a small bag of sand" + #+END_SRC + +*** Pine Flowers +Part of the [[Potions and their Ingredients][Alchemist Path]], we use /pine flowers/ to create a potion TBD, and feed the stoat in Dabbler’s House. + +#+BEGIN_SRC evennia + @create/drop pine tree;pine;tree;flowers;flower = typeclasses.consumables.Producer + # + @desc pine = Windswept pine leans to shade the shack, protecting it somewhat from the regular occuring rain. Interesting, that the pine has beautiful, yellow |Yflowers|n. + # + @set pine/make_class = "typeclasses.consumables.Herb" + # + @set pine/make_name = "yellow flower" + # + @set pine/make_verb = "$conj(pick) a small" + # + @set pine/make_desc = "Briny smelling flower with purple spots." + # + @lock pine = view:tag(alchemist) # We want the user to be able to "look pine" as a detail? +#+END_SRC + +*** Sign +We make the sign as an “object” for others to read: + +#+BEGIN_SRC evennia + @create/drop sign = typeclasses.readables.Readable + # + @desc sign = A hand-painted sign with beautiful calligraphy reads: |wFor Rent. See Dabbler for details.|n + # + @set sign/inside = "For Rent. See Dabbler for details." + # + @lock sign = get:false() +#+END_SRC + +And testing: + +#+BEGIN_SRC tcl + send "look sign\n" + expectit "A hand-painted sign with beautiful calligraphy reads" + + send "read sign\n" + expectit "For Rent. See Dabbler for details." + + send "get sign\n" + expectit "You can't get that." +#+END_SRC +** Salty Shack +Let’s keep this pretty empty. + +#+BEGIN_SRC evennia + @teleport/quiet mp15 + # + @dig Salty Shack;mp16 = locked door;door;inside,door to outside;door;outside;leave;exit +#+END_SRC + +And described the exit: + +#+BEGIN_SRC evennia + @desc door = Barnacle encrusted door with rusty irons bands and a comically large padlock. The door sports a hand-painted |Ysign|n that reads: |wFor Rent. See Dabbler for details. + # + @set door/traverse_msg = "The lock opens when you touch it, and the door opens with loud sigh. You step inside and close the door behind you." +#+END_SRC + +And lock the exit: + +#+BEGIN_SRC evennia + @lock door = traverse:tag(open_shack_door, mp) + # + @set door/err_traverse = "The door is obviously locked." +#+END_SRC + +Generic description of the insides of this house: + +#+BEGIN_SRC evennia + @teleport/quiet mp16 + # + @desc here = The shack is curiously bare and devoid of all personality. +#+END_SRC + +And describe the exit: + +#+BEGIN_SRC evennia + @desc door = Large wood door with iron bands. + # + @set door/traverse_msg = "You open the door and step out on the sand, closing the door behind you." +#+END_SRC + +While we can’t get into the shack, we can test that: + +#+BEGIN_SRC tcl + send "look door\n" + expectit "Barnacle encrusted door with rusty irons bands and a comically large padlock." + # + send "door\n" + expectit "The door is obviously locked." + #+END_SRC + +Back to the Grove: + +#+BEGIN_SRC tcl + send "north\n" + expectit "Lazy Dock" + + send "north\n" + expectit "Grove of the Matriarchs" +#+END_SRC + +** Grotto + +Return to the forest: +#+BEGIN_src evennia + @teleport mp01 +#+END_SRC +Let’s travel west along the path in the forest: +#+BEGIN_src evennia + @dig Grotto;mp04 :typeclasses.rooms_weather.TimeWeatherRoom = west footpath;west;w,east footpath;east;e;path;footpath +#+END_SRC + +With a nice message about wandering: +#+BEGIN_src evennia + @set west/traverse_msg = "You meander between mossy tree roots along a footpath for a while until it ends in a grotto." +#+END_SRC + +And a description: +#+BEGIN_src evennia + @desc west = A footpath winds between the roots of a tree. You try to jump to look over the roots, and something red catches your eye. +#+END_SRC + +Jump into the new room: +#+BEGIN_src evennia + @teleport mp04 +#+END_SRC + +And describe the tree and the door: + +#+BEGIN_src evennia + @desc here = The trickling sound of a small stream drops down a lush hill between |Yferns|n and brambleberry |Ybushes|n. The path ends at a small |Ybridge|n that leads to a red door embedded at the base of a giant |Ytree|n. A carved sign over the door reads, |wDabblers|n. +#+end_src + +A description if they look east: +#+BEGIN_src evennia + @desc east = A winding footpath leads through the forest of giant trees. +#+END_SRC + +And a nice journey message to go east in of the forest: +#+BEGIN_src evennia + @set east/traverse_msg = "The mossy tree roots makes for an interesting path..." +#+END_SRC + +And extra things to see: + +#+BEGIN_src evennia + @detail trees;tree = The trees in this forest are massive, but a smaller tree has a red door. Must lead to a closet! +#+END_SRC + +And the bridge: + +#+BEGIN_src evennia + @detail bridge = A small wooden bridge leads over a tiny |Ystream|n. Hard to see the water on account of the giant leafed skunk |Ycabbages|n. +#+END_SRC + +And the cabbages? And ferns? + +#+BEGIN_src evennia + @detail cabbage;cabbages;skunk cabbage;skunk cabbages = Large glossy green leaves with big yellow flowers that looks like cobras in drag. They hiss as you cross the |Ybridge|n. + # + @detail fern;ferns = Sword ferns rattling sabers against the wards from the Maiden Hairs' flailing their fronds. +#+END_SRC + +Let’s move our testing character to this room to finish this room’s tests: + +#+BEGIN_SRC tcl + send "look west\n" + expectit "A footpath winds between the roots of a tree." + + send "west\n" + expectit "Grotto" + + send "look east\n" + expectit "A winding footpath leads through the forest of giant trees." + + send "look tree\n" + expectit "The trees in this forest are massive, but a smaller tree has a red door." + + send "look bridge\n" + expectit "bridge leads over a tiny" + + send "look cabbage\n" + expectit "Large glossy green leaves with big yellow flowers that looks like cobras in drag" + + send "look ferns\n" + expectit "Sword ferns rattling sabers against the wards from the Maiden Hairs' flailing their fronds." +#+END_SRC + +And generate an image: + +#+begin_example +Generate a watercolor with pen and ink outlining in the style of David Brayne, depicting a lush grotto of ferns and red berry bushes. A small wood bridge crosses a stream surround by skunk cabbage to a large tree that has a red door. On the door is a brass door knocker in the shape of a goblin's head with a ring in its mouth. +#+end_example +*** Berry Bush +The berry bush is a [[file:~/src/moss-n-puddles/typeclasses/consumables.py::class Producer(Object):][producer]] that makes /berries/, which is something to eat and use to feed the wildlife. + +#+BEGIN_src evennia + @create/drop berry bush;bush : typeclasses.consumables.Producer +#+END_SRC + +With a description: +#+BEGIN_src evennia + @desc bush = A bush laden with bright red brambleberries. You've heard that they are good. +#+END_SRC + +We have to have the bush describe what it /makes/: +#+BEGIN_src evennia + @set bush/make_name = "berry" +#+END_SRC +Including some plural aliases: +#+BEGIN_src evennia + @set bush/make_aliases = ["berries", "brambleberry", "brambleberries"] +#+END_SRC + +And a verb when they /get/ the consumable: +#+BEGIN_src evennia + @set bush/make_verb = "$conj(pick) a" +#+END_SRC + +This one is optional as it defaults to Consumable: +#+BEGIN_src evennia :tangle no + @set bush/make_class = "typeclasses.consumables.Consumable" +#+END_SRC + +And the bush needs to know the /description/ of the Consumable, so that it can attach that: +#+BEGIN_src evennia + @set bush/make_desc = "Bright red with flecks of orange, about grape-sized" +#+END_SRC + +How many berries are there when you pick them? +#+BEGIN_src evennia + @set bush/make_amount = 1 +#+END_SRC + +How many berries do you eat at a time: +#+BEGIN_src evennia + @set bush/make_eat_amount = 1 +#+END_SRC + +We can either have a single /eat/ message: +#+BEGIN_src evennia + @set bush/make_eat_msg = "Sweet and slightly tart. <>." +#+END_SRC + +Or many messages that can be randomly selected: +#+BEGIN_src evennia + @set bush/make_eat_msgs = [ "Sweet and slightly tart.", "<>.", "Ooo...quite sour.", "A bit ripe, but still good.", "So sweet with a hint of <>." ] +#+END_SRC + +Let the user know when they consumed them all. +#+BEGIN_src evennia + @set bush/make_finish_msg = + #"Those were <>." +#+END_SRC + +Can we get and eat them? + +#+BEGIN_SRC tcl + send "pick berries\n" + expectit "You pick" + + send "eat berry\n" + + send "get berry\n" + expectit "You pick" + + send "eat berry\n" +#+END_SRC +*** Spring Water +Part of the [[Potions and their Ingredients][Alchemist Path]], we use spring water to create a [[Trippy Potion]]. + +#+BEGIN_src evennia + # @teleport/quiet mp04 + # + @create/drop stream of spring water;stream;spring;water: typeclasses.drinkables.Water + # + @lock stream = get:false() + # + @set stream/get_err_msg = "Seriously? You can't get that. Perhaps a bottle, or at least a cup, could hold the fresh water." + # + @desc stream = A small stream, almost hidden behind the ferns and brambleberry bushes, drops down a lush hill, creating a lush, relaxing feeling. The water looks fresh and pure. + # + @set stream/fill_name = "still water" + # + @set stream/fill_desc = "fresh spring water." + # + @set stream/fill_msgs = ["$You() << $conj(get) ^ $conj(kneel) >> down, and $conj(fill) $pron(your) {2} with the << spring ^ fresh ^ refreshing >> water.", "$You() << $conj(get) ^ $conj(kneel) >> down, and $conj(put) $pron(your) {2} in the cool water, filling it."] +#+END_SRC + +Test that we can’t get it … without a bottle. + +#+BEGIN_SRC tcl + send "look stream\n" + expectit "A small stream, almost hidden behind the ferns and brambleberry bushes" + + # send "get water\n" + send "get stream\n" + expectit "Seriously? You can't get that." +#+END_SRC + +TODO: What happens if we drink it? + +*** Knocker +The knocker has the ability to make the door “open” using [[https://www.evennia.com/docs/latest/api/evennia.objects.objects.html][on_traverse]] hooks? + +Most of the work of the /knocker/ is in the Python code: +#+BEGIN_src evennia + @create/drop knocker: typeclasses.things.Knocker +#+END_SRC + +Let’s make the knocker be a surprise. +#+BEGIN_src evennia + @set knocker/hidden_tag = "hidden_knocker" + # + @lock knocker = view:tag(hidden_knocker) +#+END_SRC + +The knocker shouldn’t be steal-able: +#+BEGIN_src evennia + @lock knocker = get:false() + # + @set knocker/get_err_msg = "It appears firmly attached to the door." +#+END_SRC + +The description is dynamic from the Python code, so we don’t need this statement: +#+BEGIN_src evennia + @desc knocker = The brass face looks at you and winks. +#+end_src + +In order for us to /knock/ on the door, we have to give a =knock= command to the /room/. + +#+BEGIN_src evennia + @set knocker/room_to_msg = "mp03" +#+END_SRC + +The python object has all the knowledge about knocking and whatnot, but we should have the descriptions here. First, what the knocker reads: + +#+BEGIN_src evennia + @set here/knock_msg = "You grab the ring" +#+END_SRC + +Then, what the other’s in the room read: +#+BEGIN_src evennia + @set here/knock_other_msg = "grabs the ring and knocks firmly on the door." +#+END_SRC + +And an error message if the ring is not with the goblin: +#+BEGIN_src evennia + @set here/knock_err_msg = "This door knocker is defective, as it doesn't have a ring to...er, do the knockin'." +#+END_SRC + +Actually, these =@set= commands do nothing, as all the messages are in the code. + +Can we knock on the door? + +#+BEGIN_SRC tcl + send "knock\n" + expectit "You grab the ring" +#+END_SRC + +The rest of testing the knocker will come later… +*** Ring + +Since we can remove the ring, let’s create it: +#+BEGIN_src evennia + @create ring: typeclasses.things.Ring +#+END_SRC + +And give it an alias: +#+BEGIN_src evennia + @name ring = brass ring;ring +#+END_SRC + +And a description: +#+BEGIN_src evennia + @desc ring = A brass ring that should be in the door knocker's mouth. How else are you going to knock on a door? +#+END_SRC + +Although we can interact with it, let’s not make it obvious that it is an object: +#+BEGIN_src evennia + @set ring/hidden_tag = "hidden_ring" + # + @lock ring = view:tag(hidden_ring) +#+END_SRC + +And let’s make it so we can take that: + +#+BEGIN_src evennia + @set ring/can_take = True +#+END_SRC + +Let’s tether the ring to the knocker … + +#+BEGIN_src evennia + @lock ring = tethered:id(knocker) + # + @set ring/tethered_msg = "You put the ring back in the knocker's mouth. \"Mmmuufffmm,\" says the door knocker." +#+END_SRC + +And put the ring in the knocker’s mouth: +#+BEGIN_src evennia + @teleport/quiet ring = knocker +#+END_SRC + +Might be difficult to test the interaction with the knocker? + +#+BEGIN_SRC tcl + send "get ring\n" + expectit "From whom do you want to get this ring?" + + send "get ring from knocker\n" + expectit "You take brass ring from knocker." + + send "say Give me a hint, please.\n" + expectit "A hint does sound fair." + + send "say Is the answer, whiskey?\n" + + send "give ring to knocker\n" + expectit "You give a brass ring to knocker." +#+END_SRC + +*** Hints +The berry bush should bring in birds and other pickers, right? + +#+BEGIN_SRC yaml + grotto: + narrative: >- + A << flock ^ couple >> of sparrows fly into the berrybush. One of + them, hops << next to ^ near >> you. It says, "<< I see that + expression. ^ You look confused. ^ Need some help? >>" << Turning + its head ^ Hopping to a higher branch >>, it says, "{0}" Soon the + flock flee for other bushes. ;; + A << yellow ^ orange ^ large ^ >> butterfly lands on your + shoulder. "You look like you << could use some ^ need ^ would like + some >> help," it says, "{0}" As it flies away, it says, "Good + luck!" ;; + A <> goblin walks down the footpath, and starts picking + berries. "Hiya," he says. "I see ya << staring ^ gawking >>, so + I'll give ya a bit o' advice. {0}" When finished, he says, "Hope + that helps." And retreats back down the path with his bucket of + berries. + hints: + default: >- + That |Ydoor|n leads to an interesting place, but the |Yknocker|n + won't let you in without knowing the |Ysecret|n. So try to talk + to it. + knocker: >- + While not good at listening, he can't talk with that |Yring|n in + his mouth. + ring: Since it has it, you will want to |gget ring from knocker|n + door: That door leads to |wDabbler's House|n. + secret: >- + If you say the secret |Ypassword|n, the |Yknocker|n will let you + in. + password: >- + The |Yknocker|n knows the password, but might give you a + |Yhint|n if you ask for one. + hint: >- + The hint will be in the form of a not-so challenging |Yriddle|n. + riddle: Ask the |Yknocker|n for the riddle. +#+END_SRC + +And let’s not test /everything/ here: + +#+BEGIN_SRC tcl + send "hint\n" + expectit "So try to talk to it." +#+END_SRC + +** Cozy House + +Add the Python /special-ness/ for [[file:~/src/moss-n-puddles/typeclasses/rooms.py::class DabblersRoom(Room):][this room]]: +#+BEGIN_src evennia + @dig Cozy House;mp03: typeclasses.rooms.DabblersRoom = red door;door;inside,outside;leave +#+end_src + +Let’s get our testing character inside, shall we? + +#+BEGIN_SRC tcl + send "inside\n" + expectit "Cozy House" +#+END_SRC + +*** Red Door +The door description should match the artwork on the website: +#+BEGIN_src evennia + @desc red door = A painted red door where the round top of the door fits snugly in the bark of the tree. Along with a large brass doorknob, the door sports the most curious door knocker in the shape of a goblin's face. +#+END_SRC + +This exit should be special. First, it is locked unless a character has the =open_red_door= tag. +#+BEGIN_src evennia + @lock door = traverse:tag(open_red_door, mp) +#+END_SRC +Needs a message why one can’t walk through: +#+BEGIN_src evennia + @set door/err_traverse = "The door seems locked." +#+END_SRC + +If you do figure out how to get through the door: +#+BEGIN_src evennia + @set door/traverse_msg = "You stoop as you step through the doorway..." +#+END_SRC + +We described [[Knocker][the knocker]] earlier, as it holds the /virtual key/ for unlocking the door. But looking at the door, should show the knocker too. + +#+BEGIN_src evennia + @set door/hidden_tag = "hidden_knocker" +#+END_SRC + +*** Inside + +Fix the inside of the “House”: +#+BEGIN_src evennia + @teleport mp03 +#+END_SRC + +And the best description ever that we don’t use: + +#+BEGIN_src evennia + @desc here = An enormous stone hearth overshadows this round room with dark paneling. A subtle smell of tea and incense. Large, overstuffed chairs sit invitingly by the fireplace. Oddly angled shelves with books and knickknackery adorn the walls and the smell of fresh-baked scones come from the kitchen. +#+END_SRC + +Since we want the description to include the state of the fire, we need some /parts/ to assemble. Still not sure how this should be done. + +#+BEGIN_src evennia + @set here/initial_desc = "You found a cozy, cornerless room." + + # Ravenous State + @set here/fire_out = "The room is dim, lit by a single |Ycandle|n in a |Ysconce|n attached to the wall. You see large, overstuffed |Ychairs|n placed by a dark |Yfireplace|n in a large stone |Yhearth|n. Perhaps you could light a fire?" + + # Hungry State + @set here/fire_dim = "Large, overstuffed |Ychairs|n sit invitingly close to the dimly glowing embers in the |Yfireplace|n of a stone |Yhearth|n." + + # Fed State + @set here/fire_on = "Large, overstuffed |Ychairs|n sit invitingly by a |Yfire|n casting shadows that dance on the dark paneling." + + # Full State + @set here/fire_full = "Large, overstuffed |Ychairs|n slightly shield you from the bright light of the roaring fire in the |Yfireplace|n of a stone |Yhearth|n." + + # And a final description: + @set here/final_desc = "Oddly angled |Yshelves|n with |Ybooks|n and |Yknickknackery|n adorn the walls around a |Ytapestry|n. The subtle smell of wood smoke, incense and fresh-baked scones from the |Ykitchen|n." +#+END_SRC + +And details: + +#+BEGIN_src evennia + @detail hearth = An enormous stone hearth overshadows this round room with dark |Ypaneling|n. |YStairs|n lead up and behind it. + # + @detail paneling = The seamless paneling, stretches from floor up into the darkness above. +#+END_SRC + +Touch up the exit: +#+BEGIN_src evennia + @desc leave = A wood door with a large brass knob leads to the outside. + # + @set leave/traverse_msg = "You open the door and step outside..." +#+end_src + +Add some initial ambiance: + +#+BEGIN_SRC evennia + @set here/arrive = "45 ;; gm The rain << patters ^ chatters ^ drums >> against a window << sill ^ pane >>. Nice to be << indoors ^ inside >>." +#+END_SRC + +To test, let’s make sure we show the final description: + +#+BEGIN_SRC tcl + expectit "The subtle smell of wood smoke, incense and fresh-baked scones" +#+END_SRC + +Granted, none of the dynamic description will work until we create the [[Fire]]. + +Generate a picture: +#+begin_quote +Generate a painting of a dark, cozy room using the style of the uploaded image. A large stone fireplace contains a roaring fire. In front are two overstuffed chairs. Sitting in one is a small, sleeping old man with unkempt hair (like Albert Einstein) but with blue streaks. He has round spectacles a white goatee beard, and a brown blanket over his legs. Curled up like a snake in his lap is a long white stoat, also sleeping. The other overstuffed chair should have a folded blanket. The dark paneling to either side fo the fireplace has oddly angled shelves covered in books and knickknacks that include things like a crystal ball, a statues of black dragon, and a stone owl and a skull of a saber-toothed tiger with three fangs. On the stone fireplace above the fire is a tapestry divided into four quadrants. +#+end_quote +*** Tapestry Story +The tapestry should tell our /creation myth/. +#+BEGIN_src evennia + @detail tapestry = The muted colors of the tapestry either show its age or its location over the sometimes smokey |Yhearth|n. It depicts four scenes... |/|/The first scene shows a small, old |Yman|n with blue hair watering a wilted |Yrose|n in a desert landscape. |/|/The second scene shows the man and the rose next to a radiant |Yqueen|n handing the man a |Ypaper|n with a gold seal. |/|/The third scene shows the man standing between two |Ytrees|n, The final scene shows the man |Ywhispering|n to one of the trees, now visually further apart than in the third scene. + # + @detail man = The old man in the |Ytapestry|n is small, sporting a white vandyke-styles beard and blue tipped hair. He wears spectacles and a brown cloak covering his bright red jacket. Looks familiar. + # + @detail rose = The rose in both scenes of the |Ytapestry|n has gold petals, but curiously, not depicted in a pot. + # + @detail queen = The beautiful queen shown in the second scene of the |Ytapestry|n, adorned in a flowing gown of shimmering petals and leaves, has hair cascading like a waterfall of flowers. + # + @detail paper = The paper with a gold seal in the |Ytapestry|n sure looks like a contract. + # + @detail trees = The trees shown in the third and fourth scenes in the |Ytapestry|n are the same, and in one scene, they are named, |wErui|n and |wVedui|n. + # + @detail whispering = This curious aspect in the |Ytapestry|n seems ... odd. +#+END_SRC + +Make sure we can see all of this. + +#+BEGIN_SRC tcl + send "look tapestry\n" + expectit "The muted colors of the tapestry" + + send "look man\n" + expectit "The old man in the" + + send "look rose\n" + expectit "The rose in both scenes" + + send "look queen\n" + expectit "The beautiful queen shown in the second scene" + + send "look paper\n" + expectit "The paper with a gold seal" + + send "look trees\n" + expectit "The trees shown in the third and fourth scenes" + + send "look whispering\n" + expectit "This curious aspect" +#+END_SRC +*** Fireplace +And a fire in the fireplace is a type of /pet/, since we can feed it: +#+BEGIN_src evennia + @create/drop fireplace;fire;embers : typeclasses.pets.Fire +#+END_SRC +How about some aliases: +#+BEGIN_src evennia + @lock fire = get:false() +#+END_SRC + +And a description that will be overridden: +#+BEGIN_src evennia + @desc fireplace = A stone fireplace with a carved wooden mantel supporting small |Ypictures|n, some |Ybooks|n and a black |Ystatue|n. +#+END_SRC + +Since we mentioned some details, we better mention them: +#+BEGIN_src evennia + @detail pictures = Two small framed pictures perch above the fireplace mantle. One is of a satyr playing a saxophone, and the other is of a fish with a big smile. +#+end_src + +This reference in this detail is obviously, only for me: +#+BEGIN_src evennia + @detail statue = A small, black statue of a salamander curled around a book, engraved with a title, "Seeing Stones". +#+END_SRC + +I imagine a giant picture over the fireplace … need to do something interesting with it. +#+BEGIN_src evennia + @detail picture = Above the |Yfireplace|n is a large, somewhat abstract |Ypainting|n stretching its arm-like branches with shadowing that looks like a yawn. +#+END_SRC + +Accessing it directly: + +#+BEGIN_SRC python +fire = me.search("fire"); fire.ndb.hunger_level = 50; print(fire.ndb.hunger_level) +#+end_src + +We need to fix it so that =feed fire= just works. + +#+BEGIN_SRC tcl :tangle no + send "get fireplace\n" + expectit "You can't get that." + + send "feed fire\n" + expectit "fire in the fireplace" +#+END_SRC +*** Wood Rack +Need a way to produce wood for the fireplace. + +#+BEGIN_src evennia + @create/drop wood rack;log rack;log holder;wood holder;wood;log :typeclasses.consumables.Producer +#+END_SRC + +#+BEGIN_src evennia + @desc wood rack = Steel and leather hammock for a small pile of cut logs, perfect for |gfeed|ning to the |gfire|n. +#+END_SRC + +We have to have the wood rack describe what it /makes/: + +#+BEGIN_src evennia + @set wood rack/make_name = "log" + # + @set wood rack/make_aliase = ["wood"] +#+END_SRC + +And a verb when they /get/ the consumable: + +#+BEGIN_src evennia + @set wood rack/make_verb = "$conj(get) a small" +#+END_SRC + +And a commentary: + +#+BEGIN_src evennia + @set wood rack/make_note = " from the wood rack" +#+END_SRC + +This one is optional as it defaults to Consumable: +#+BEGIN_src evennia + @set wood rack/make_class = "typeclasses.things.Wood" +#+END_SRC + +And the wood rack needs to know the /description/ of the Consumable, so that it can attach that: +#+BEGIN_src evennia + @set wood rack/make_desc = "Cut wood, perfect for feeding to the fire." +#+END_SRC + +How much is there when you pick them? +#+BEGIN_src evennia + @set wood rack/make_amount = 1 +#+END_SRC + +Hide from immediate view: +#+BEGIN_src evennia + @set wood rack/hidden_tag = "hidden_woodrack" + # + @lock wood rack = view:tag(hidden_woodrack) +#+END_SRC + +And testing this: + +#+BEGIN_SRC tcl + send "get wood\n" + expectit "You get a small log from the wood rack." + + send "feed log to fire\n" + expect "You start a fire" +#+END_SRC +*** Knickknacks +What sort of non-books do we want to look at? + +#+BEGIN_src evennia + @create/drop few trinkets;trinkets;trinket;knickknacks;knickknackery;doodads;doodad;knick-knacks: typeclasses.things.Trinket +#+END_SRC + +Let’s not let anything of this sort be picked up: + +#+BEGIN_src evennia + @lock trinkets = get:false() + # + @set trinkets/get_err_msg = "While interesting, perhaps you shouldn't steal Dabbler's personal collection." +#+END_SRC + +Let’s make sure a new person always sees a trinket: + +#+BEGIN_SRC tcl + send "look trinkets\n" + expectit "." +#+END_SRC + +*** Magic 8 Ball +One trinket we might create to give to people as a souvenir. + +#+BEGIN_src evennia + @create crystal ball;ball;magic ball: typeclasses.things.CrystalBall +#+END_SRC + +And its description: + +#+BEGIN_src evennia + @desc ball = A glass orb of billowing mist and patterns. |/When the << ^ swirling blue patterns ^ spinning octarine swirls ^ revolving stars>> clear, the glass reads, +#+END_SRC + +And we should hide it: + +#+BEGIN_src evennia + @set ball/hidden_tag = "hidden_ball" + # + @lock ball = view:tag(hidden_ball) + # + drop ball +#+END_SRC + +*** Bookshelf + +Since we mentioned shelves of books, we should create a Producer that makes a random book. + +#+BEGIN_src evennia + @create/drop number of bookshelves;bookshelf;shelves;bookcase;books;book:typeclasses.readables.Bookshelf +#+END_SRC + +With a good description: +#+BEGIN_src evennia + @desc books = Shelves at various angles embellish the walls of this small, cozy room. Leatherbound books weigh down each shelf, while some stacks of books support other shelves. +#+end_src + +Most of the work is actually in the creation of the [[file:~/src/moss-n-puddles/typeclasses/readables.py::class Book(Object):][individual books]], in the Python code in the [[file:~/src/moss-n-puddles/typeclasses/readables.py::class Books(Object):][Books]] class. + +Can we do the song and dance of getting a book? Should we simplify this? + +#+BEGIN_SRC tcl + # First time, we get the full description: + send "look books\n" + expectit "Shelves at various angles embellish the walls of this small, cozy room." + + # Second time, we get a shorter message: + send "look book\n" + expect -re "You .*book.*titled" + + send "get book\n" + expectit "You pick up the book" + + send "read book\n" + expect -re "You.*open your book" + + send "drop book\n" + expectit "flies" +#+END_SRC + +*** Chairs +And [[file:~/src/moss-n-puddles/typeclasses/sittables.py::class Sittables(Sittable):][the chairs]] is a /plural/ location to sit, allowing anyone to sit down. + +#+BEGIN_src evennia + @create/drop overstuffed chairs:typeclasses.sittables.Sittables +#+END_SRC +Add aliases afterwards: +#+BEGIN_src evennia + @alias overstuffed chairs = chairs;chair + # This only works if we make it plural: + @set overstuffed chairs/plural = True +#+END_SRC +And the description: +#+BEGIN_src evennia + @desc chairs = A few, dark leather, overstuffed chairs, each with a soft, colorful blanket and pillow. An invitation for a cozy nap. +#+END_SRC + +Can’t steal ‘em: +#+BEGIN_src evennia + @lock chairs = get:false() + # + @set chairs/get_err_msg = "It's way too heavy for you to lift." +#+END_SRC + +And textual descriptions the object can use: +#+BEGIN_src evennia + @set chairs/adjective = "in" + # + @set chairs/article = "the" + # + @set chairs/singular = "an overstuffed chair" + # + @set chairs/extra = "This feels << ^ very ^ quite>> <>.|n" +#+end_src + +Since we have unlimited seating, sitting down is always available: + +#+BEGIN_SRC tcl + send "sit\n" + expectit "You sit in " +#+END_SRC + + +*** Dabbler’s Butterfly +This golden NPC always hangs around our gnome, recording all that transpires. + +#+BEGIN_SRC ruby + @create/drop golden butterfly;butterfly;recorder: typeclasses.things.Scribe +#+END_SRC + +And describe it: + +#+BEGIN_SRC ruby + @desc butterfly = A flying insect with iridescent wings that flicker a golden hue. Is it carrying a tiny a notepad and pen? +#+END_SRC + +Let’s make it hidden for the moment: + +#+BEGIN_SRC ruby + @lock butterfly = view:tag(hidden_butterfly) +#+END_SRC + +And let’s not let anyone pick it up: + +#+BEGIN_SRC ruby + @set butterfly/get_err_msg = "It quickly flutters away, only to land a few feet away." +#+END_SRC + +Let’s set the location where it will store its transcripts: + +#+BEGIN_SRC ruby + @set butterfly/transcripts_path = 'transcripts/cozy-%Y-%m-%d.html' + # + @set butterfly/header_file = "transcripts/cozy-header-template.html" +#+END_SRC + +*** Hints +While this room has a lot of /stuff/, I don’t feel we need to drop a lot of hints … just on the candle sconce: + +#+BEGIN_SRC yaml +cozy_house: + narrative: >- + "<< Psst. ^ Heya. ^ Over here. ^ Hey buddy. >>" + You << look down ^ look down ^ bend down >> and see a + << tiny ^ small ^ >> << brown ^ >> worm on a bookshelf. It says, + "<< I see ya gawking. ^ You look confused. ^ Need some help? >> {0}" + He goes back between some books, and yells in its tiny voice, + "Good luck!" + ;; + After a brief yawn, the << white-furred ^ wee >> beastie, << curled up ^ >> + on the << overstuffed ^ >> chair, << opens its eyes and ^ >> says, + "<< Wondering I see. ^ Curious? ^ Overwhelmed? >> {0}" + With that, it stretches and curls itself up << and resumes its nap ^ >>. + hints: + default: >- + You are in a cozy and casual place, but it has a few |Ysecrets|n. + When the |Yfire|n is out, the only light is from a |Ycandle|n. + When bright, you could get and read a |Ybook|n. + secrets: The room has a secret door, if you can find the mechanism. + fire: >- + While you can |gget wood|n and |ggive|n it to the fireplace, + the easiest way is to |gfeed fire|n. + candle: Notice the curious holder, the |Ysconce|n, for the candle. + sconce: Since the sconce has hinges, you can |gpull sconce|n. + book: >- + Each time you |glook book|n, you will see a new book. + Type |gget book|n, to put it in your |ginventory|n. + Type |gread book|n, to get a summary. + No, we did not feel like writing multiple novels for this game. +#+END_SRC + +And let’s not test /everything/ here: + +#+BEGIN_SRC tcl + send "hint\n" + expectit "You are in a cozy and casual place" +#+END_SRC + +*** Character: Dabbler +My characters should be NPCs, so they can stick around if I’m not logged in. + +#+BEGIN_src evennia + @create/drop Dabbler;gnome;old gnome: typeclasses.puppets.Puppet +#+END_SRC + +Note that we give him a male gender: + +#+BEGIN_src evennia + @set gnome/gender = 'male' +#+END_SRC + +Work around the =pose= bug: + +#+BEGIN_src evennia + py bt = self.search('gnome'); bt.sdesc.add('old gnome'); bt.db.pose = 'smiling at you' +#+END_SRC + +Let’s give him a number of alternate names for the Recorder (mostly): + +#+BEGIN_SRC evennia + @set gnome/alt_names = ["The old gnome", "The gnome", "The little old man", "The little man", "With a wink, the gnome", "Cheerfully, the gnome"] +#+END_SRC + +And give him the powers he deserves: + +#+BEGIN_src evennia :tangle no + @perm gnome = Admin +#+END_SRC + +#+BEGIN_src evennia + @set gnome/pose_sleep = "sleeping soundly in a large, overstuffed chair" + # + pose gnome/default = smoking his pipe +#+END_SRC + +And a good description that I can rework: + +#+BEGIN_src evennia + @desc gnome = A small, hunched old man with messy blue hair, a gray vandyke and an eye twinkle.|/|/Spectacles perched precariously on the end of his hooked nose, wobble with his head. His bright crimson jacket contrasts with his dark brown cloak. +#+end_src + +And an un-puppeted, sleeping, description: + +#+BEGIN_src evennia + @set gnome/desc_unpuppeted = "A small, hunched old man with messy blue hair and a gray vandyke snoring soundly in one of the overstuffed chairs.|/|/Spectacles perched precariously on the end of his hooked nose, wobble with each breath. His bright crimson jacket contrasts with the dark brown blanket covering his legs." +#+END_SRC + +And we create a couple of objects: + +Like his special teacup: + +#+BEGIN_src evennia + @create teacup;cup : typeclasses.drinkables.TeaCup + # + @desc teacup = A rustic teacup crafted from clay etched with leaves and runes, with an olive green and brown glaze. + # + @give teacup = gnome +#+END_SRC + +And his fancy jacket: + +#+BEGIN_SRC evennia + @create waistcoat : typeclasses.things.BagofJunk + # + @desc waistcoat = An elegant green waistcoat with gold embroidery. + # + @set waistcoat/stuff = "fey" + # + @give waistcoat = gnome +#+END_SRC + +**** Staff +And my staff: + +#+BEGIN_src evennia + @create gnarled staff;staff: typeclasses.things.Wand + # + @desc staff = An oaken staff with a sprig of two leaves next to a swirling ball of crystal embedded near the top. + # + @give staff = gnome +#+END_SRC + +And his spells that go with the staff: + +#+BEGIN_src evennia + @set gnome/disappear_msg = "After a raspberry sound, the gnome, Dabbler, disappears in a wisp of smoke." + # + @set gnome/reappear_msg = "<> mist appears...along with the smell of sulphur... ;; When the smoke clears, an old gnome <>." + # + @set gnome/magic_msg = "$You() << $conj(strike) ^ $conj(tap) ^ $conj(hit) ^ $conj(whack) >> the << floor ^ ground >> with $pron(your) << gnarled ^ old ^ magic ^ >> staff. ;; << Sparks ^ Colored lights ^ Flashes ^ Flares >> of |moctarine|n << appear ^ emerge ^ materialize >> as << the ^ >> magic << coalesces ^ blends >>..." + # + @set gnome/make_msg = "Sparks << of |moctarine|n ^ >> fly << when ^ as >> $you() $conj(snap) $pron(your) fingers. ;; An << opalescent ^ iridescent ^ oddly shaped >> box appears, and when the lid opens itself, << wisps ^ a wisp >> of smoke << curls back ^ slithers >> towards $pron(your) << outstretched ^ >> fingers." +#+END_SRC + +And help with the =fly= spell: + +#+BEGIN_src evennia :tangle no + nick meadow = fly Frog Meadow + nick bar = fly Wyldwood Bar +#+END_SRC + +**** Scrying Ball +This /crystal ball/ can be used to see what is going on in any area of the realm. +#+BEGIN_SRC evennia + @create scrying ball: typeclasses.things.Scryer +#+END_SRC + +And a description: + +#+BEGIN_src evennia + @desc scrying ball = A crystal orb that shows what's abroad. + # + @give scrying ball = gnome +#+END_SRC + + +**** Pipe +The pipe is little more than messages to the smoker and everyone else in the room. + +#+BEGIN_src evennia + @create pipe: typeclasses.things.Pipe +#+END_SRC + +And a description: + +#+BEGIN_src evennia + @desc pipe = As tall as its owner with etchings of birds, leaves and magical symbols. + # + @give pipe = gnome +#+END_SRC + +The light command will incorporate the description, just so everyone can get a good look at it. + +Commands: + - light pipe (how should this be different from lighting a candle or a fire in the fireplace)? + - puff (if the pipe is out, perhaps it calls the =do_light= function)? + - snuff (to put it out). This would require the start. +**** Journal +The pipe is little more than messages to the smoker and everyone else in the room. + +#+BEGIN_src evennia + @create large book;journal: typeclasses.readables.Journal +#+END_SRC + +Writing descriptions: + +#+BEGIN_src evennia + @set journal/pre_write_msg = "With a small octarine spark, a quill appears in the air. $You() $conj(grab) the quill and begin to write in $pron(your) large book." + # + @set journal/post_write_msg = "The quill disappears in a small puff of smoke, as $you() $conj(close) $pron(your) book." +#+END_SRC + +And a description: + +#+BEGIN_src evennia + @desc journal = Leather-bound book, cracked and worn from ages. + # + @give journal = gnome +#+END_SRC +*** Stoat the Wee Beastie +Need an interesting creature that likes to sleep by the fire, and perhaps give hints to the workings inside. + + - feed :: ignores all food. + - pet :: likes all pets + +Do I match the Big Hairy Beast, or do I create it as a puppet? + +#+BEGIN_src evennia + @create/drop wee beastie;Mochi;stoat: typeclasses.pets.WeeBeastie +#+END_SRC + +And its description: + +#+BEGIN_src evennia + @desc stoat = A charming creature with a slender, elongated body covered in soft, white fur that glistens like freshly fallen snow. When open, its large, round eyes are a striking shade of lavender, and its bushy tail, tipped with a hint of violet. +#+END_SRC + +Can’t get this guy: + +#+BEGIN_src evennia + @lock stoat = get:false() + # + @set stoat/get_err_msg = "Each time you try to pick it up, it serpentines it way back to the chair." +#+END_SRC + +Let’s get a bit more interaction with this pet: + +#+BEGIN_src evennia + @set stoat/active_amount = 8 +#+END_SRC + +It’s level doesn’t change much. :-D It is always less interested, just like a cat. + +#+BEGIN_src evennia + @set stoat/scared_msg = "Currently, coiled like a sleeping snake on one of the chairs." +#+END_SRC + +And petting it when someone first comes in? + +#+BEGIN_src evennia + @set stoat/pet_scared_response = "While it doesn't stop $you() << from petting it ^ >>, the beastie flashes its long teeth." +#+END_SRC + +And actions if a friendly person isn’t around: + +#+BEGIN_src evennia + @set stoat/scared_actions = "The wee beastie << asleep on the chair ^ >> let's out a yawn brandishing its large canines. ;; The wee beastie << asleep on the chair ^ >> uncoils itself, stretches, and recoils again. ;; You hear a deep throated rumbling from the wee beastie << asleep on the chair ^ >> . ;; The wee beastie twitches in its sleep, as if chasing down imaginary prey." +#+END_SRC + +Concerned level: + +#+BEGIN_src evennia + @set stoat/concerned_msg = "Currently, curled into a ball on one of the chairs." +#+END_SRC + +Pets? + +#+BEGIN_src evennia + @set stoat/pet_concerned_response = "$You() get little response from << your pets of ^ >> << the wee beastie ^ the beastie >>. " +#+END_SRC + +And actions at this level are more cute than sinister: + +#+BEGIN_src evennia + @set stoat/concerned_actions = "The wee beastie << asleep on the chair ^ >> let's out an adorable yawn. ;; The wee beastie << asleep on the chair ^ >> uncurls itself, stretches, and recurls again. ;; You hear a deep purring sounds from the wee beastie << asleep on the chair ^ >>. ;; The wee beastie twitches in its sleep, as if playing with dream toys." +#+END_SRC + +Interested level: + +#+BEGIN_src evennia + @set stoat/interested_msg = "<< Currently ^ It is >> curled into a ball asleep." +#+END_SRC + +Pets + +#+BEGIN_src evennia + @set stoat/pet_interested_response = "The << wee ^ >> beastie adorably moves its head into $your() pets." +#+END_SRC + +And actions at this level are about as cute as a cat can be: + +#+BEGIN_src evennia + @set stoat/interested_actions = "The << sleepy ^ wee >> beastie << on $your() lap ^ >> let's out an adorable yawn. ;; The << sleepy ^ wee >> beastie << on $your() lap ^ >> uncurls itself, stretches, and recurls again. ;; $You() $conj(pet) the << sleepy ^ wee >> beastie << on |p lap ^ >> as it snuggles << close ^ >>. ;; You hear a deep purring sounds from the << sleepy ^ wee >> beastie << on $your() lap ^ >>. ;; The << sleepy ^ wee >> beastie twitches in its sleep, as if playing with dream toys." +#+END_SRC + +Friendly level: + +#+BEGIN_src evennia + @set stoat/friendly_msg = "<< Currently ^ It is >> purring while curled up sleep." +#+END_SRC + +Pets + +#+BEGIN_src evennia + @set stoat/pet_friendly_response = "The << wee ^ >> beastie adorably moves its head into $your() pets. ;; $You() << $conj(rub) ^ $conj(pet) >> the stubby but soft ears of the << wee ^ >> beastie, as it lets out a little purr. ;; The << wee ^ >> beastie rolls onto its back while $you() $conj(rub) its tummy. It lets out a little purr. ;; $You() << $conj(scratch) ^ $conj(massage) >> the soft << back ^ rump >> of the << wee ^ >> beastie. It wriggles around trying to get the most of this attention." +#+END_SRC + +And actions at this level are about as cute as a cat can be: + +#+BEGIN_src evennia + @set stoat/friendly_actions = "The << sleepy ^ wee >> beastie << on $your() lap ^ >> let's out an adorable yawn. ;; The << sleepy ^ wee >> beastie << on $your() lap ^ >> uncurls itself, stretches, and recurls again. ;; $You() $conj(pet) the << sleepy ^ wee >> beastie << on |p lap ^ >> as it snuggles << close ^ >>. ;; You hear a deep purring sounds from the << sleepy ^ wee >> beastie << on $your() lap ^ >>. ;; The << sleepy ^ wee >> beastie twitches in its sleep, as if playing with dream toys." +#+END_SRC + +And this pet loves his gnome. + +#+BEGIN_src evennia + @set gnome/wee_beastie_friendly_level=500 +#+END_SRC + +Trigger some events … which can’t work at the moment, since a Pet is not a Puppet … yet: + +#+BEGIN_SRC evennia + @set stoat/arrive = "5 ;; gma {0} = A sleeping << wee ^ >> beastie, opens one curious eye to look at $you()." + # + # @set stoat/sit = "3 ;; gm A sleeping << wee ^ >> beastie, opens one curious eye to see who arrived." +#+END_SRC + +Let’s also hook it to our AI system: + +#+BEGIN_SRC evennia + @set stoat/personality = "wee-beastie" + # + @set stoat/personality_file = "personalities/wee-beastie.md" +#+END_SRC + +Let’s test this creature: + +#+BEGIN_SRC tcl + send "pet beastie\n" + expectit "beastie" + + send "feed beastie\n" + expectit "candy" + + send "feed beastie\n" + expectit "beastie doesn't appear interested in anything you have." +#+END_SRC + +** Kitchen +Better place to put the tea and scones. + +#+BEGIN_src evennia + @dig Cramped Kitchen;mp11 = archway to kitchen;kitchen;archway,back to main room;leave;main;back + #+END_SRC + +And describe the exit: + +#+BEGIN_src evennia + @desc archway = Knarled roots of a tree forms an opening where you can see cabinets, a stove and even a teapot. + # + @set archway/traverse_msg = "You stoop again to enter the cramped room." + #+END_SRC + +And describing the room: + +#+BEGIN_src evennia + @teleport mp11 + # + @desc here = This small, oddly shaped room contains low |Ycabinets|n. The |Yteapot|n on the |Ystove|n seems warm as if finishing the ritual of brewing tea. A |Yplate|n of |Yscones|n on the |Ycountertop|n smell inviting. +#+END_SRC + +And the exit: + +#+BEGIN_src evennia + @desc leave = Knarled roots of a tree forms an opening where you can see cabinets, a stove and even a teapot. + # + @set leave/traverse_msg = "You stoop again and leave the cramped room." + #+END_SRC + +And some details: + +#+BEGIN_src evennia + @detail stove = Black, iron stove with rounded corners trimmed in gold. While cold, the |Yteapot|n on the |Ystove|n seems like it just made a tea. And yeah, the |Yscones|n seem fresh baked as well. +#+END_SRC + +#+BEGIN_src evennia + @detail countertop;countertops;counter = Covered in hand-sized black tiles with gold flecks match the |Ystove|n. The |Yplate|n of |Yscones|n look freshly baked. +#+END_SRC + +#+BEGIN_src evennia + @detail plate = On the tiled |Ycountertop|n, a large plate carries a stack of fresh-baked |Yscones|n. + # + @detail scone;scones = A scones look tempting. Perhaps no one will miss one... +#+END_SRC + +#+BEGIN_SRC tcl + send "kitchen\n" + expectit "Cramped Kitchen" + + send "look scones\n" + expectit "look tempting" +#+END_SRC + +#+begin_example +Generate a watercolor with pen and ink outlining in the style of David Brayne, depicting a cramped, windowless kitchen for a gnome. On a black stove is an orange teapot. On the counter is a plate of scones. An open cabinet is filled with an assortment of teacups. Some of an English variety with flower ornaments, while other teacups are plan clay mugs. A single candle provides light, as the scene should be dark. +The style is a blend of Anglo-Saxon, fantasy elements. +#+end_example +*** Cabinets and Counter-tops +The Trolley [[file:~/src/moss-n-puddles/typeclasses/consumables.py::class Producer(Object):][produces]] teacups and random scones, which, like the [[Berry Trolley][berries]] can be eaten or fed to the wildlife. + +#+BEGIN_src evennia + @create/drop cabinet;cabinets : typeclasses.consumables.Trolley +#+END_SRC + +We mentioned a /trolley/ with tea, cups and scones: +#+BEGIN_src evennia + @desc cabinet = The cabinets contain an assortment of tea cups. +#+END_SRC + +We have to have the trolley bake something with the Python command: +#+BEGIN_src evennia + py here.search("cabinet").do_bake() +#+END_SRC + +And let’s not clutter up the scene too much: + +And let’s have the test grab a scone: + +#+BEGIN_SRC tcl + send "get scone\n" + expect -re "You get.*scone" + + send "eat scone\n" + # Too much variableness here. + # expectit "You" + + # Get another scone for the road ... and to feed the beast. + send "get scone\n" + expect -re "You get.*scone" +#+END_SRC + +*** Tea Service + +The “room” gives the teacups, and the “teapot” fills the cups, so we just need descriptions: +#+BEGIN_src evennia + @detail teacups = An odd, yet interesting assortment of teacups. Take one. + # + @detail teacup = Each cup is unique. Take one to look further. +#+end_src + +A [[file:~/src/moss-n-puddles/typeclasses/drinkables.py::class Teapot(Object):][teapot]] will contain a type of tea … either given or randomly chosen. +A teapot will “fill” a teacup forever, until it is “remade”. + +#+BEGIN_src evennia + @create/drop teapot;pot;tea pot:typeclasses.drinkables.Teapot + # + @desc teapot = An adorable brown teapot, full of tea. You feel you could |gmake|n a fresh pot. +#+END_SRC + +And of course, you can’t steal the tea pot: + +#+BEGIN_src evennia + @lock teapot = get:false() + # + @set teapot/get_err_msg = "You don't need to carry it around to make tea." +#+end_src + +And test that anyone can make it: + +#+BEGIN_SRC tcl + send "make green\n" + expectit "You make a teapot" + + send "pour tea\n" + expectit "Command 'pour tea' is not available." + + send "get teacup\n" + expectit "You pick up a teacup." + + send "look teacup\n" + expectit "teacup" + + send "pour tea\n" + expect -re "You pour some.*cup" + + send "drink tea\n" + expect -re "You.*cup" + + send "pour tea\n" + expect -re "You empty your teacup" +#+END_SRC + + +*** Hints +I guess the hints here are how to use the teapot? + +#+BEGIN_SRC yaml +cramped_kitchen: + hints: + default: >- + Grab yourself some breakfast or an evening snack of |Yscones|n and |Ytea|n. + scones: Type |gget scone|n. Every day a new flavor arrives. + tea: >- + You can |gmake tea|n and the teapot chooses, or you can |gmake|n + your favorite kind of tea, like |wgreen|n or |wherbal|n. + Please, don't make coffee, as could alter the taste of tea. + Then after you have a |Yteacup|n, you can |gpour|n yourself a cup. + teacup: The cabinet is full of cups, so |gget teacup|n. +#+END_SRC + +And test the hints, just to be sure: + +#+BEGIN_SRC tcl + send "hint\n" + expectit "Grab yourself some breakfast" +#+END_SRC + +** Secret Room +Pulling on a candle opens a secret staircase! + +#+BEGIN_src evennia + @teleport/quiet mp03 + # + @dig Secret Room;mp12:typeclasses.rooms_dark.DarkRoom = stairs behind bookcase;down;down stairs;secret passage;bookcase;passage,up the stairs;stairs;leave;up +#+END_SRC + +Look and traverse: + +#+BEGIN_src evennia + @desc stairs = Behind the protruding bookcase, you see a staircase leading down into the darkness. + # + @set stairs/traverse_msg = "You carefully creep down the stairs behind the bookcase, lit by the candle in its holder. You hear the bookcase shut behind you." +#+END_SRC + +We left the tester in the kitchen, let’s get him in the Cozy Room: + +#+BEGIN_SRC tcl + send "leave\n" + expectit "Cozy House" +#+END_SRC + +*** Sconce +The Candle holder must be both an Opener (with a =do_pull= method) and a Producer (making long-lasting candles). + +#+BEGIN_src evennia + @create/drop sconce;candle holder;candle: typeclasses.consumables.Sconce +#+END_SRC + +#+BEGIN_src evennia + @desc sconce = A black iron sconce holding a single lit |Ycandle|n. On closer examination, the bottom of this fixture appears to have a hinge? +#+END_SRC + +Connect the exit: + +#+BEGIN_src evennia + @set sconce/exit = $search(stairs behind bookcase) + # + @set sconce/room = $search(Cozy House) +#+END_SRC + +Hide it a bit? + +#+BEGIN_src evennia + @set sconce/hidden_tag = "hidden_sconce" + # + @lock sconce = view:tag(hidden_sconce) +#+END_SRC + +We can =get= an endless supply of candles here: + +#+BEGIN_src evennia + @set sconce/make_name = "candle" +#+END_SRC + +And a verb when they /get/ the consumable: + +#+BEGIN_src evennia + @set sconce/make_verb = "$conj(take) the" + # + @set sconce/make_note = ", but another magically appears in its place" +#+END_SRC + +This one is optional as it defaults to Consumable: +#+BEGIN_src evennia + @set sconce/make_class = "typeclasses.lightables.Candle" +#+END_SRC + +And the sconce needs to know the /description/ of the Consumable, so that it can attach that: + +#+BEGIN_src evennia + @set sconce/make_desc = "Curiously shaped taper with scales like a snake." +#+END_SRC + +How much is there when you pick them? +#+BEGIN_src evennia + @set sconce/make_amount = 1 +#+END_SRC + +Can we see it? + +#+BEGIN_SRC tcl + dont_expect "You notice" "sconce" + + send "look sconce\n" + expectit "A black iron sconce holding a single" + + send "look\n" + expect -re "You notice.*sconce" + + send "get candle\n" + expectit "You take the candle, but another magically appears in its place" +#+END_SRC + +*** Pulling Sconce +Temporarily move the exit into the room. + +#+BEGIN_src evennia + @set sconce/pull_msg = "You hear a click, and the bookcase next to the candle swings forward revealing a |Ysecret passage|n." +#+END_SRC + +Let’s reset it to start: + +#+BEGIN_src evennia + @teleport/tonone stairs behind bookcase + #+END_SRC + +Can we pull the sconce to reveal the secret bookcase? + +#+BEGIN_SRC tcl + send "pull sconce\n" + expectit "You hear a click, and the bookcase next to the candle swings forward revealing" + + send "look\n" + expect -re "Exits:.*stairs behind bookcase" + + send "look stairs behind bookcase\n" + expectit "Behind the protruding bookcase, you see a staircase leading down into the darkness." +#+END_SRC + +*** Inside the Secret Room +Time to create the secret lab, the *Secret Room*. + +#+BEGIN_src evennia + @teleport mp12 + # + @desc here = A curious little room containing a |Ystool|n next to a |Ytable|n covered with alchemical |Yequipment|n--a testament to the arcane arts--cluttered yet meticulously organized. +#+END_SRC + +Add aliases that make sense: + +#+BEGIN_src evennia + @desc stairs = Stone steps leading back to the surface. You are sure you will be able to find the latch to let yourself out. + # + @set stairs/traverse_msg = "You climb the stone stairs. Feeling around, you find the latch and let yourself out." +#+END_SRC + +Until we decide if we want to do something with the table: + +#+BEGIN_src evennia + @detail table = Made from a polish black wood, etched with intricate runes that shimmer faintly in the candlelight. +#+END_SRC + +Are the equipment stuff we could =use=? + +#+BEGIN_src evennia + @detail equipment;alchemical;alchemical equipment = A |Ymortar|n and |Ypestle|n, |Yvials|n, crystal |Yphials|n, |Yjars|n, and |Ytools|n all surround a black |Ycauldron|n. +#+END_SRC + +#+BEGIN_src evennia + @detail mortar;pestle;mortar and pestle = An obsidian mortar, its surface smooth and cool to the touch. Beside it, a pestle carved from a single piece of ancient bone, adorned with carvings of arcane symbols. +#+END_SRC + +#+BEGIN_src evennia + @detail vials = Scattered across a small shelf, an array of empty glass vials. Perhaps you could fill these with potions yet to be created? +#+END_SRC + +#+BEGIN_src evennia + @detail phials = Delicate crystal phials, each shaped like a teardrop, attach to a wrought iron rack. Each contain vibrant liquids that swirl with colors not found in nature. Magically sealed, these phials may store volatile substances, which require special containment to prevent their magical properties from dissipating. +#+END_SRC + +And tools that definitely need to /stay here/: + +#+BEGIN_src evennia + @detail tools = A set of finely crafted tools lies neatly arranged on a velvet cloth: a pair of tweezers for handling delicate ingredients, a small scalpel for precise cutting, and a set of measuring spoons made from silver, each engraved with different symbols representing the elements. +#+END_SRC + +And let’s descend and check it all out: + +#+BEGIN_SRC tcl + send "down\n" + expectit "Secret Room" + + send "look stairs\n" + expectit "Stone steps leading back to the surface." + + send "look table\n" + expectit "Made from a polish black wood, etched with intricate runes that shimmer faintly in the candlelight." + + send "look alchemical equipment\n" + expectit "all surround a black" + + send "look mortar and pestle\n" + expectit "An obsidian mortar, its surface smooth and cool to the touch." + + send "look vials\n" + expectit "Scattered across a small shelf, an array of empty glass vials." + + send "look phials\n" + expectit "Delicate crystal phials, each shaped like a teardrop, attach to a wrought iron rack." + + send "look tools\n" + expectit "A set of finely crafted tools lies neatly arranged on a velvet cloth" +#+END_SRC + +And let’s generate an image: + +#+begin_example +Using the same style as the first uploaded image, generate a picture where the bottom third contains a tabletop. In the center of the tabletop is a black cauldron surrounded with a ring of salt. On the left side of the cauldron is an old-looking leather grimoire. It is closed. To the right of the cauldron are a mortal and pestle as well as some tools, like tweezers and a scalpel. On the left side above the table are two shelves. On one shelf is a collection of empty, brown glassed bottles. On the other shelf is a collection of jars with interesting contents. One jar should contain small eyeballs. On the right side of the image above the table is an iron wrought bird perch where a lizard-looking imp sits holding a wooden spoon. Its prehensile tail curves around the perch. It looks bored. +#+end_example +*** Jars +Can jars be a producer that returns a random jar with a “content”? + +Every time we look at a jar, we see something else … that we can’t take. This creates ambiance without adding too much complexity? + +#+BEGIN_SRC evennia + @tel/quiet Secret Room + # + @create/drop collection of jars;jars;jar: typeclasses.puzzles.Changling +#+END_SRC + +Can’t get them: + +#+BEGIN_SRC evennia + @lock jars = get:false() + # + @set jars/get_err_msg = "The imp slaps your hand away and shakes his head. While you can take an empty |Ybottle|n, you can't take the currated ingredients. Guess you can always find your own ingredients, eh?" +#+END_SRC + +And the generate description: + +#+BEGIN_SRC evennia + @set jars/desc_first_prefix = "<< Fascinating ^ Interesting ^ Curious >> << collection of ^ assortment of ^ >> << jars ^ contents ^ ingredients >>. You look at one << jar ^ >>, << elegantly ^ hastily ^ legibly ^ >> labeled,|w" + # + @set jars/desc_prefix = "You look at another << jar ^ >>, << elegantly ^ hastily ^ legibly ^ >> labeled,|w" + # + @set jars/desc_postfix = "" +#+END_SRC + +And now for a list of the contents: + +#+BEGIN_SRC evennia + @set jars/descs = ( + "Glimmering Dust|n. A jar filled with fine, shimmering powder that sparkles like a thousand stars.", + "Dragon Blood|n. A deep red liquid that swirls with hints of gold, resembling liquid rubies.", + "Crystalized Stardust|n. Tiny, sparkling crystals that twinkle like stars, believed to hold the essence of the cosmos.", + "Moonstone Crystals|n. Iridescent stones that glow softly in the dark, casting a gentle light.", + "Bottled Lightning|n. A swirling blue liquid that crackles with energy, contained within a glass jar.", + "Dragon Scale Powder|n. A fine, metallic powder that shifts colors with the light, reminiscent of dragon scales.", + "Essence of Shadow|n. A dark, swirling liquid that seems to absorb light, creating an eerie atmosphere.", + "Shadow Essence|n. A dark, swirling liquid that absorbs light, said to grant invisibility.", + "Starflower Petals|n. Delicate, translucent petals that shimmer like the night sky, layered in a glass jar.", + "Whispering Seeds|n. Tiny, dark seeds that seem to rustle softly when the jar is moved, as if alive.", + "Golden Sand|n. A jar filled with fine, shimmering sand that glows warmly, reminiscent of a sunset.", + "Wisp of Smoke|n. A swirling, grayish substance that drifts lazily within the confines of its jar.", + "Nightshade Berries|n. Dark, glossy berries that glisten ominously, nestled in a jar of dark liquid.", + "Phoenix Ashes|n. A fine, gray powder that sparkles faintly, as if containing remnants of a fiery rebirth.", + "Silver Thread|n. A spool of shimmering thread that glows softly, appearing almost ethereal in nature.", + "Timekeeper Sand|n. A jar filled with golden sand that flows slowly, as if measuring the passage of time.", + "Elven Wine|n. A deep green liquid that sparkles with tiny bubbles.", + "Ghostly Essence|n. A pale, translucent ichor that swirls with a soft glow.", + "Celestial Oil|n. A shimmering oil that glows with a soft light.", + "Cat Shadow|n. A swirling, inky blackness that pulses and shifts.", + ) +#+END_SRC + +How can we test this cool feature? + +#+BEGIN_SRC tcl + send "look jar\n" + expect -re "You look at one.*labeled" + # + send "look jar\n" + expect -re "You look at one.*labeled" +#+END_SRC + +*** Stool +A stool to sit while working +#+BEGIN_src evennia + @create/drop stool:typeclasses.sittables.Sittable +#+END_SRC + +How descriptive: +#+BEGIN_src evennia + @desc stool = A place to sit while synthesizing experiments. +#+END_SRC + +Can’t steal this stool either: +#+BEGIN_src evennia + @lock stool = get:false() +#+END_SRC + +Let’s do a funnier message: +#+BEGIN_src evennia + @set stool/get_err_msg = "Stop trying to steal everything not nailed down." +#+end_src + +And test this out; + +#+BEGIN_SRC tcl + send "look stool\n" + expectit "A place to sit while synthesizing experiments." + + send "sit\n" + expectit "You sit on the stool." + + send "stand\n" + expectit "You stand up" + + send "get stool\n" + expectit "Stop trying to steal everything not nailed down." +#+END_SRC +*** Grimoire + +A mystic book of potions can add a new dimension to the game. + +#+BEGIN_src evennia +@create/drop leather-bound book;book;grimoire:typeclasses.readables.Book +#+END_SRC + +The book’s title and description: + +#+BEGIN_src evennia + @desc grimoire = An old brown book where even the cover has seen considerable wear with stains and scratches in the leather. The band connect to a gold ring, itself attached to a chain that hooks it to the table. The title reads, |MFavorite Potions|n. Inside, written in beautiful penmanship, the book contains recipes. +#+END_SRC + +Lock it down. + +#+BEGIN_src evennia + @lock grimoire = get:false() + # + @set grimoire/get_err_msg = "The book is chained to the table." +#+END_SRC + +And of course, the inside. + +#+BEGIN_src evennia + @set grimoire/inside = "file:world/alchemy-book.md" +#+END_SRC + +The contents must be in a file, and we need to add a pager. + +The prefix can be: + +#+BEGIN_src evennia + @set grimoire/prefix = "Undoing the brass clasp that bind the old leather book, you open to page one and begin reading the elegant calligraphy..." +#+END_SRC + +Test out reading, but not stealing it: + +#+BEGIN_SRC tcl + send "look grimoire\n" + expectit "An old brown book where even the cover has seen considerable wear with stains and scratches in the leather." + + send "read book\n" + expectit "Undoing the brass clasp that bind the old leather book" + + send "get book\n" + expectit "The book is chained to the table." +#+END_SRC + +*** Cauldron +The cauldron should have a special =look= so a character knows what ingredients they added, and the follow commands: + +- =empty= … the imp will empty the contents +- =add= (or =give=) an item from the inventory. +- =create=, =cook= or =mix= +- =bottle= to create a vial + +What about these commands? + + - =crush= for use in mortal and pestle + +#+BEGIN_src evennia + @create/drop black cauldron: typeclasses.alchemy.Cauldron +#+END_SRC + +And the details: + +#+BEGIN_src evennia + @desc cauldron = A small, cast-iron cauldron sits on an iron stand, its interior stained from countless brews. Someone surrounded the cauldron with a ring of salt, a protective barrier against unwanted energies. A small fire burns beneath it, ready to heat concoctions. +#+END_SRC + +Lock it down: +#+BEGIN_src evennia + @lock cauldron = get:false() +#+END_SRC + +Make sure we can’t take it: + +#+BEGIN_SRC tcl + send "look cauldron\n" + expectit "A small, cast-iron cauldron sits on an iron stand, its interior stained from countless brews." + + send "get cauldron\n" + expectit "You can't get that." +#+END_SRC + +*** Shelf of Bottles + +The table is a producer of /bottles/. + +#+BEGIN_src evennia + @create/drop shelf of empty bottles;shelf;bottles;bottle: typeclasses.consumables.Producer +#+END_SRC + +With a description: +#+BEGIN_src evennia + @desc shelf = Cluttered with some empty brown |Ybottles|n. Perhaps you can fill these with liquid ingredients and bring them back here. +#+END_SRC + +We have to have the bush describe what it /makes/: +#+BEGIN_src evennia + @set shelf/make_name = "bottle" + # + @set shelf/make_verb = "$conj(pick up) a" +#+END_SRC + +This one is optional as it defaults to Consumable: +#+BEGIN_src evennia + @set shelf/make_class = "typeclasses.drinkables.Bottle" + # + @set shelf/make_desc = "A brown glass bottle. Currently empty." + # + @set shelf/make_amount = 1 +#+END_SRC + +Our tests from here on out demand a bottle… + +#+BEGIN_SRC tcl + send "look shelf\n" + expectit "Cluttered with some empty brown" + + send "get bottle\n" + expectit "You pick up a bottle." +#+END_SRC + + +*** Imp +Every secret alchemical lab should have an Imp familiar. + +#+BEGIN_src evennia + @create/drop Impetus;imp: typeclasses.puppets.Puppet +#+END_SRC + +Note that we give him a male gender: + +#+BEGIN_src evennia + @set imp/gender = "neutral" +#+END_SRC + +Work around the =pose= bug: + +#+BEGIN_src evennia + py bt = self.search('imp'); bt.sdesc.add('imp'); bt.db.pose = 'sitting on an ornate perch' +#+END_SRC + +#+BEGIN_src evennia + @set imp/pose_sleep = "sitting on an ornate perch" + # + @pose default imp = sitting on an ornate perch +#+END_SRC + +And a good description that I can rework: + +#+BEGIN_src evennia + @desc imp = Peculiar little fellow gives you a quizical look from its roost on a wrought iron perch that it clutches with its clawed feet and barbed, prehensile tail. +#+END_SRC + +And an un-puppeted, sleeping, description: + +#+BEGIN_src evennia :tangle no + @set imp/desc_unpuppeted = "... not used ..." +#+END_SRC + +When any one arrives, we assume that they are no longer a beginner, and have /graduated/ to see the world in a different way, and we use the tag, =alchemist= as a view lock on all the ingredients. + +#+BEGIN_src evennia + @set imp/arrive = "tag_all alchemist ;; untag_all beginner ;; 240 ;; emote yawns." +#+END_SRC + +Would be nice if it has a variety of responses to speech. + +#+BEGIN_src evennia + @set imp/say = "1 ;; emote << nods ^ looks at you quizically ^ stares at you curiously ^ shrugs ^ investigates its fingerclaws ^ winks ^ smirks ^ raises an eyebrow ... well, if it had one, it would ^ stares at you ^ squints its eyes >>." + #+END_SRC + +Let’s interact with the little fellow: + +#+BEGIN_SRC tcl + send "look imp\n" + expectit "little fellow gives you a quizical look" + + send "say Hello there, little guy.\n" + expect -re "Imp" +#+END_SRC + +*** Potions +Alright! I have finished the _crafting phase_ where the player can go around the world collecting ingredients, and then, after finding the secret alchemy lab, can read a grimoire to figure out what ingredients to add to the cauldron, and the magic words to use, and you end up with a potions. Drinking the potions have effects, of course, so great fun if you want to give them to your friends. + +I’ve got the first potion in place, and I like it; pretty cute, even if the effect isn’t that interesting (but I’ve got more up my sleeve). + +Anyway, I’ve got a couple of questions for you: + + - Should the grimoire have “clear” names of the potions or esoteric Latin-sounding ones? + - Should the grimoire explicitly state the potion’s effects? Or a vague description and you have to drink ‘em to find out? + - Should the vial have the name of the potion? Could spoil the fun when giving to your friends. Of course, they would never drink some strange vial of glowing red liquid… + - Given the limitations of a “text adventure” game, what potions (and their effects) should I make? Do you want to know what I’ve come up with so far, or should I surprise you? + +Another question … during play-test with friends I could into playing together on Tuesday nights, some had trouble realizing all the “hidden features”. Because I said there was a boulder, if you “look boulder”, you find that you can climb it. Someone said that I could _color_ those nouns that could be “look”ed at. But because I describe _all the nouns_ whether they are super secret or interesting or interactive or not, there is a lot of colored text. What do you think? + +If you go to the east to the Meadow and then south to the Meadow, I colored everything there, in an attempt to help people figure out the puzzle of getting into the Hut (which you must do or you can’t get a horn that you can use to call the boat to take you to all the islands where I’ve put the escape rooms … so). + +**** Laughing Potion +Ingesting this potion causes outward expressions of glee and laughter. + +Ingredients: + + - [[Gigglecap Mushrooms]] + - [[Tickleweed]] + - [[Fizzy Water]] + +Make a list of effects for these spells. + +Could these be a sequence like what puppets do? We need a “msg” and an “announce” additions. +**** Trippy Potion +After ingesting this potion, they may see hallucinations and nightmares. It would be nice if these dreams could incorporate the room state. + +Ingredients: + + - [[Pixie Dust]] + - [[Dream Mushrooms]] + - [[Spring Water ]] + - [[file:mud-adventure.org::*Moonberries][Moonberries]] + +The moonberries grow under conifers, and I find I often have to travel to one of the islands on the Lavender Sea to collect these. + +And we need to come up with a list of effects: + +#+begin_example +You catch a glimpse of a Beholder hovering ominously, its spherical body covered in a mottled, iridescent skin that shifts colors like a living kaleidoscope! Its eyestalks, each ending in a glimmering orb, swivel independently, scan the surroundings with a predatory gaze... + +It unleashes its disintegration ray, a brilliant beam of energy erupting from one of its eyes, slicing through the air with a crackling intensity that seems to warp reality itself, leaving a trail of shimmering particles in its wake! + +The ray engulfs you in a radiant light, dissolving the boundaries of individuality and merging your essence with the cosmos, revealing a profound interconnectedness that transcends existence itself. + +This potion packs a punch, you say to yourself. +#+end_example + +Butterfly dreams with no meaning: + +#+begin_example +The air thick with the scent of blooming flowers, a soft, melodic whisper beckons you. You want to follow, but not sure where the whispers come from... + +You see a luminescent creature flit by...a butterfly with wings like stained glass! + +The colorful butterfly lands near your feet and grows as large as you. It then removes its mask revealing the face of an old man. \"Vezof is jēda, se vestri est vestri,\" it says before flying off. + +This potion packs a punch, you say to yourself. +#+end_example + +Harken back to Alice in Wonderland with the Caterpillar: + +#+begin_example +You hear a languid, sleepy voice say, \"Skoros nūm?\" Turning around, you see a large caterpillar smoking a hookah on a mushroom cap. + +The caterpillar shakes its head and continues smoking, blowing large smoke rings into the air. + +The caterpillar yawns, and then asks, \"Vezof?\" + +As the caterpillar crawls off, it says, \"Er haer indóme care-tye alta. Bo haer indóme care-tye ince.\" + +This potion packs a punch, you say to yourself. +#+end_example + +More elvish words … should there be a point? + +#+begin_example +Behind you, you hear a young woman's voice. \"H' ambar na-siniath,\" she says. + +The young woman shakes her long green hair, thick like vines, and looks at you curiously with emerald eyes, and says, \"Im tur-fel ha in i nen.\" + +\"Im tur-fel ha in i coe,\" the young woman says as she looks down, squishing the ground with her bare toes. + +Looking up and taking a big breath, the young woman says, \"Im tur-fel ha in i gwilith.\" + +Again she looks at you curiously, shakes her head and disappears. + +This potion packs a punch, you say to yourself. +#+end_example + +#+BEGIN_SRC python :tangle no +py c=me.search("black cauldron", global_search=True); c.do_empty(); c.create_drugtrip() ; c.do_bottle(me) ; c.do_empty() +#+END_SRC + +**** Puck’s Revenge + - Muddy water + - Donkeytail grass … could that be in Uktah? + - Essence of Puck … sack of dust? This would be the prize from completing a quest. +**** Water Breathing +Called Pneumaqua or Piscispneuma +This potion would allow you to go see a castle or something in the sea. + + - salt water + - purple, gem-colored sand + - dried mermaid tears (witch’s hut) + - deep kelp (can be found in the storeroom in the Bar) + - sea-grass (found on an island) +*** Hints +Where to begin here! + +How can the Imp help here? Telepathy? Pointing? + +#+BEGIN_SRC yaml + secret_room: + narrative: >- + The << wee ^ small ^ tiny >> << demon ^ imp ^ helper >> + << perched ^ roosting ^ poised >> on its iron stand looks + << curiously ^ quizically ^ inquisitively >> at you. |/|/ + The creature raises an eyebrow as you << then ^ >> hear a voice in your head... + "<< Wondering I see. ^ Curious? ^ Overwhelmed? ^ Confused ^ >> {0}" + hints: + default: >- + Can't figure out how to use the |Ycauldron|n and the |Ytools|n + in this secret alchemical lab to creation |Ypotions|n? + Here you can learn to bewitch the mind and ensnare the senses, + bottle fame, brew glory and even put a stopper in |Ydeath|n. + death: + You see, to stop death, you simply need to..."|/|/ + Wʜᴀᴛ ᴅɪᴅ Yᴏᴜ ꜱᴀʏ?|/|/ + The small imp squeaks, and attempts to be small.|/|/ + Rᴇᴍᴇᴍʙᴇʀ WHO ʜᴀꜱ ᴛʜᴇ Uʟᴛɪᴍᴀᴛᴇ Sᴀʏ ᴀʀᴏᴜɴᴅ ʜᴇʀᴇ|/|/ + The perched imp nods emphatically, "Yes, sir. + potions: >- + Find the potions and their |Yingredients|n in the grimoire... er, + large brown |Ybook|n there. I suggest, making the potions |win order|n. + book: >- + While the book stays here, you can |gread|n it to learn the + |Yingredients|n to add to the |Ycauldron|n. Just follow the + |Ysequence|n of commands to make the potion. + cauldron: >- + Place the specific |Yingredients|n listed in the grimoire... er, + large brown |Ybook|n there. + You do know how to |gread|n a |gbook|n, right? + tools: >- + Don't worry about the tools right now. Just the |Ysequence|n of + commands. + ingredients: >- + The alchemical components necessary for transubstantiation and + the creation of potions are located around the area. Once you + have all the ingredients, follow the |Ysequence|n of commands to + make a potion. + sequence: >- + First, |gempty|n the cauldron. |/ + After you have |wgathered|n a component, |gadd|n the component. |/ + With all the ingredients, |gcreate|n the concoction. + I will tell you if it is right. |/ + Finally, |gbottle|n it in the empty vials. +#+END_SRC + +** Bedroom +A bedroom with a wardrobe that goes to another land sounds great. + +#+BEGIN_src evennia + @teleport/quiet mp03 + # + @dig Bedroom;mp13:typeclasses.rooms.OpenableRoom = stairs up to a loft;up stairs;up;loft;bedroom,down the stairs;down;stairs;leave + #+END_SRC + +Look see: + +#+BEGIN_src evennia + @desc loft = Ornate black irons banister outline the thick wood planks that form steps leading to some lofty alcove. + # + @set loft/traverse_msg = "You walk up the shadowy stairs..." +#+END_SRC + +And a description: +#+BEGIN_src evennia + @teleport/quiet mp13 + # + @desc here = Like the shadows that dance here, this oddly shaped room hugs its contents: a thick wooden framed |Ybed|n piled high with warm |Yblankets|n and fluffy |Ypillows|n, keep out the chill; a thick burgundy |Ycarpet|n sporting a pair of |Yslippers|n; and a |Ywardrobe|n decorated with ornate leaves and berries. +#+END_SRC + +And describe the exit: + +#+BEGIN_src evennia + @desc down the stairs = Ornate black irons banister outline the thick wood planks that form steps leading down to living space below. + # + @set down the stairs/traverse_msg = "You walk down the stairs to the living space below." + #+END_SRC + +And of course, you can see more details: + +#+BEGIN_src evennia + @detail bed = Cozy and inviting, like most things in this house, someone covered this bed in warm blankets and fluffy pillows in rich, warm colors. The frame, formed from a single tree that grew to hold this bed. + # + @detail blankets = Thick and warm to ward off the outside rain and chill. + # + @detail pillows = While fluffy, these long pillows could certainly make fine posts for a blanket fort. + # + @detail carpet = The dark red rug has a curious whirlpool pattern. +#+END_SRC + +Are the slippers just a red herring? + +#+BEGIN_src evennia + @create/drop pair slippers + # + @desc slippers = Red-leather and worn with an ornate tassel on top. + # + @lock slippers = tethered:id(mp13) + # + @set slippers/tethered_msg = "The slippers are having none of this adventuring outside of this cozy room, and walk back to the side of the bed." + #+END_SRC + +Let’s validate all the details: + +#+BEGIN_SRC tcl + # We left our tester in the Secret room, so ... + send "leave\n" + expect "Cozy House" + + send "look up stairs\n" + expectit "Ornate black irons banister outline the thick wood planks that form steps leading to some lofty alcove." + + send "up\n" + expectit "Bedroom" + + send "look down stairs\n" + expectit "Ornate black irons banister outline the thick wood planks that form steps leading down to living space below." + + send "look slippers\n" + expectit "Red-leather and worn with an ornate tassel on top." + + send "get slippers\n" + expectit "You pick up a pair slippers." +#+END_SRC + +And generate an image: + +#+begin_example +Generate a watercolor with pen and ink outlining in the style of David Brayne, depicting an small bedroom for a gnome. The walls are dark paneling with no visible ceiling. It has a thick wooden rustic bed. The bed is piled high with warm blankets and fluffy pillows. A thick burgundy carpet has a pair of slippers. A wooden wardrobe is decorated with ornate leaves and berries. The style is a blend of anglo-saxon, fantasy elements. +#+end_example +*** Wardrobe +One needs to open it to go to another world. + +#+BEGIN_src evennia + @dig Prairie;mp14 = through the wardrobe;wardrobe,copse of pinion pines;pines;copse;trees;leave +#+END_SRC + +And describe the exit: + +#+BEGIN_src evennia + @desc wardrobe = Behind the cloaks and jackets, you see long, green needles from pine trees, and beyond that, a clearing! + # + @set wardrobe/traverse_msg = "You part and push through the cloaks, jackets and waistcoats, and into a copse of pinion trees, to reach a wide open space of grass." + # + @alias through the wardrobe = the exit + # + @alias through the wardrobe = wardrobe + # + @set here/open_exit = $search(through the wardrobe) + # + @teleport/tonone through the wardrobe +#+END_SRC + +And messages for opening and closing the wardrobe: + +#+BEGIN_src evennia + @set here/open_exit_msg = "$You() $conj(open) the wardrobe, revealing the cloaks, jackets, and ... green needles from pine trees? What is going on here? Between the trees, you see a clearing!" + # + # Not sure if the door closed automatically, or if someone closed it, so we use a passive sentence: + @set here/close_exit_msg = "The wardrobe door is closed." + #+END_SRC + +How will we distinguish between the wardrobe, the exit and the object that controls the exit? The room could have an “open” and “close” that could teleport and remove the exit. + +#+BEGIN_src evennia + @create/drop wardrobe + # + @desc wardrobe = While resting on the floor, this wardrobe scratches the ceiling. Large furniture, or perhaps a small room? Gorgeously ornate with carvings of leaves and berries. Carved above the doors, are the words, |wUKRAH|n. The latch is undone, and can be |gopen|ned. +#+END_SRC + +The =look= command could be distinguishing using aliases of “the exit” and “the furniture”? + +#+BEGIN_src evennia + @alias wardrobe = the object + #+END_SRC + +Don’t allow it to get taken: + +#+BEGIN_src evennia + @lock wardrobe = get:false() + # + @set wardrobe/get_err_msg = "The wardrobe is way too big to lift." + #+END_SRC + +Let’s test this secret door … + +#+BEGIN_SRC tcl + # Make sure we start this test with a closed wardrobe: + send "close wardrobe\n" + expectit "closed." + + send "look wardrobe\n" + expectit "While resting on the floor, this wardrobe scratches the ceiling. Large furniture, or perhaps a small room?" + + send "get wardrobe\n" + expectit "The wardrobe is way too big to lift." + + send "open wardrobe\n" + expectit "You open the wardrobe, revealing the cloaks, jackets, and" + + send "look through the wardrobe\n" + expectit "Behind the cloaks and jackets, you see long, green needles from pine trees, and beyond that, a clearing!" +#+END_SRC + +*** Hints +Sooo obvious. But what is the narrator here? + +#+BEGIN_SRC yaml + bedroom: + hints: + default: >- + Don't steal the slippers, as they are decoration (as even + Dabbler can't keep them on his toes). The |Ywardrobe|n is + obviously interesting. + wardrobe: If you |gopen|n the |gwardrobe|n, you will find a new exit. +#+END_SRC + +** Southwest Prairie +What am I doing here? + +#+BEGIN_src evennia + @teleport/quiet mp14 + # + @desc here = On the edge of a small |Yknoll|n with a |Ycopse|n of trees, the space stretches to a rolling dawnclear, blue skies pushing down the horizona distant sunset attempting to pull the sky down with it bright, star painted skies. +#+END_SRC + +Describe the exit: + +#+BEGIN_src evennia + @desc copse = A copse of trees covers the top of the knoll. Hanging from a tree, a lit |Ylantern|n, as if showing the way to another world. + # + @set copse/traverse_msg = "You push through the tree's long pine needles to then push through the cloaks and jackets to exit the wardrobe." +#+END_SRC + +Details? + +#+BEGIN_src evennia + @detail knoll;hillock;knell = The land stretches and buckles in small rolls. You find yourself and one of the high points, allowing you to absorb the immense view. + # + @detail lantern = Curious iron worked lantern sways in the subtle breeze. + # + @detail campfire;fire = Only a thin wisp of smoke escapes to the skies; fragrating the air. +#+END_SRC + +Test this place: + +#+BEGIN_SRC tcl + send "wardrobe\n" + expectit "Prairie" + + send "look copse\n" + expectit "A copse of trees covers the top of the knoll." + + send "look knoll\n" + expectit "The land stretches and buckles in small rolls." + + send "look lantern\n" + expectit "Curious iron worked lantern sways in the subtle breeze." + + send "look campfire\n" + expectit "Only a thin wisp of smoke escapes to the skies; fragrating the air." +#+END_SRC + +And let’s illustrate this scene: + +#+begin_example +Create a watercolor image of a grassy prairie during the evening with a small campfire with two logs for sitting. On one log sits a figure in black robes wearing a horse skull and holding a pipe. The other log is empty. +#+end_example +*** Mare’s Head +Taken from [[https://en.wikipedia.org/wiki/Mare%27s_Head][Wikipedia]]. + +#+BEGIN_src evennia + @create/drop Mares Head;head: typeclasses.puppets.Puppet +#+END_SRC + +Note that we give him a male gender: + +#+BEGIN_src evennia + @set mares head/gender = "neutral" +#+END_SRC + +Work around the =pose= bug: + +#+BEGIN_src evennia + py bt = self.search('head'); bt.sdesc.add('curious figure'); bt.db.pose = 'sitting next to a small |Ycampfire|n' +#+END_SRC + +#+BEGIN_src evennia + @set mares head/pose_sleep = "sitting next to a small |Ycampfire|n" + # + @set mares head/pose_default = "sitting next to a small |Ycampfire|n" + # + @pose default mares head = sitting next to a small campfire +#+END_SRC + +And a good description that I can rework: + +#+BEGIN_src evennia + @desc mares head = A curious figure wearing dark robes and a gleaming white skull of a mare. Interestingly, the skull has velvety horse |Years|n. +#+END_SRC + +#+BEGIN_src evennia + @detail ears;ear = They look real, and twitch as if alive. + #+END_SRC + +And when someone arrives: + +#+BEGIN_src evennia + @set mares head/arrive = "4 ;; emote nods its skull in greeting. ;; 30 ;; emote stares at you with its empty sockets. ;; emote reaches into the fire, pulls out a branch, and brushes off the soot. ;; scoring get_pipe to {0} ;; gift pipe to {0}" + #+END_SRC + +And what if they attempt to interact? + +#+BEGIN_src evennia + @set mares head/say = "3 ;; emote << nods ^ shakes it head...er, skull ^ looks at you with its empty eye sockets ^ shrugs ^ pokes the fire with a stick ^ raises an eyebrow ... well, if it had one, it would ^ shifts from his log seat. As it does, its black cloak billows ^ squints its eyes...er, eye sockets? Best not think about it ^ A fuzzy ear on the skull of the /me twitches >>." + #+END_SRC + +Should we wait to get a pipe? + +#+BEGIN_SRC tcl + send "look figure\n" + expectit "A curious figure wearing dark robes and a gleaming white skull of a mare." + + send "look ears\n" + expectit "They look real, and twitch as if alive." + + puts "NOTE: Waiting to get a pipe as a gift." + set timeout 240 + expectit "gives you a pipe" + set timeout 20 +#+END_SRC + +*** Hints +I shouldn’t think the Mare’s Head could /talk/ in order to give hints. +Because this is a under construction section, we will: + +#+BEGIN_SRC yaml + prairie: + hints: + default: >- + This place should have a sign that reads, |wUnder + Construction|n, as nothing much happens here now ... well, except + for the gift you received as a reward for finding this place. +#+END_SRC + +*** Pull up a Log + +Let’s allow anyone here to sit on a log next to the campfire .. + +#+BEGIN_src evennia + @create/drop couple long log;log:typeclasses.sittables.Sittables +#+END_SRC + +And the description: +#+BEGIN_src evennia + @desc log = A long, smooth log rests next to the inviting campfire. +#+END_SRC + +Can’t steal ‘em: +#+BEGIN_src evennia + @lock log = get:false() + # + @set chairs/get_err_msg = "It's way too heavy for you to lift. Besides, were you planning on burning it or something?" +#+END_SRC + +And textual descriptions the object can use: +#+BEGIN_src evennia + @set log/article = "the" + # + @set log/singular = "the log next to the campfire" +#+end_src + +Since we have unlimited seating, sitting down is always available: + +#+BEGIN_SRC tcl + send "sit\n" + expectit "You sit on the log" +#+END_SRC + +** Dark Tunnel + +The entrance to the dungeon experience will be under the mattress in [[Lair][the Lair]]. + +#+BEGIN_SRC evennia + @tel/quiet mp07 + # + @dig Dark Tunnel;mp20:typeclasses.rooms_dark.DarkRoom = ladder down into the dark;down;ladder;tunnel,ladder to trapdoor;trapdoor;up;ladder + # + @desc ladder = Through the open trapdoor, you see a ladder that you can climb down into a cold, damp darkness. + # + @set ladder/traverse_msg = "With the trapdoor open, you climb down the ladder into the darkness... Suddenly, your foot slips, and you fall, landing on the stone floor!" + # + # @set here/open_exit = $search(ladder down into the dark) + # + # @set here/open_item = "trapdoor" + # + @teleport/tonone ladder down into the dark +#+END_SRC + +And we create a trapdoor in the Lair: + +#+BEGIN_src evennia + @create/drop trapdoor:typeclasses.things.ClosingDoor + # + @desc trapdoor = A wood door with reinforced iron bands on the floor, under the heavy mattress. + # + @lock trapdoor = get:false() + # + @set trapdoor/get_err_msg = "Are you mad? The trapdoor is securely attached to the floor ... and under the heavy mattress." + # + @set trapdoor/pull_msg = "Sorry, you can't open the trapdoor when the mattress is resting on it." + # + @set trapdoor/hidden_tag = "hidden_trapdoor" + # + @lock trapdoor = view:tag(hidden_trapdoor) +#+END_SRC + +What does it take to open it? + +#+BEGIN_SRC evennia + @lock trapdoor = traverse:tag(enter_dungeon, mp) + # + # Trapdoor should stay open for 5 minutes: + @set trapdoor/open_for = 300 + # + @set trapdoor/exit = $search(ladder down into the dark) + # + @set trapdoor/exit_close_msg = "The trapdoor slams shut from above. Uh oh." + # + @set trapdoor/room = $search(Lair) + # + @set trapdoor/room_close_msg = "The stick breaks, and the trapdoor slams shut from the weight of the mattress." +#+END_SRC + +Let’s get into the Dungeon and work from it there. + +#+BEGIN_SRC evennia + @teleport/quiet mp18 + # + @desc here = A cold, musty tunnel made of |Ystone blocks|n, tapered to form an large dome overhead. You hear a slight whistling sound, which may explain why this unground place is neither dusty or musty. + # + @desc ladder = A metal ladder where a slimy mildew of sorts has grown on the bottom rungs. Better be careful. + # + @set ladder/traverse_msg = "You carefully ascend up the ladder, but you find the trapdoor hard to open, as if something heavy is on top of it. With all your might, you manage to push and squeeze through it." + # + @detail trapdoor = A wood door with reinforced iron bands on the floor. + # + @detail stone blocks;stone;blocks = The stone blocks that support the tunnel are well made, and for the most part, keep out water. But the crevises seem mortared with a green mildew. +#+END_SRC + +** Dungeon WIP +Let’s connect the Bar to the Lair through a labyrinth of tunnels. + +#+BEGIN_SRC evennia + @teleport/quiet mp21 + # + # Create the next room... + @desc down = The tunnel continues down into the darkness. + # + @set down/traverse_msg = "You carefully pick your way down the tunnel. It curves. It veers. It corners...." + # + @dig Tunnel End;mp18:typeclasses.rooms_dark.DarkRoom = ladder down into the dark;down;ladder;tunnel,ladder to trapdoor;trapdoor;up;ladder;door + # + @desc ladder = Through the open trapdoor, you see a ladder that you can climb down into a cold, damp darkness. + # + @set ladder/traverse_msg = "With the trapdoor open, you climb down the ladder into the darkness... Suddenly, your foot slips, and you fall, landing on the stone floor!" + # + @set here/open_exit = $search(ladder down into the dark) + # + @set here/open_item = "trapdoor" + # + @teleport/tonone ladder down into the dark +#+END_SRC + +Let’s bring the “ladder” exit back by opening and closing the trapdoor: + +#+BEGIN_SRC evennia + @set here/open_exit_msg = "$You() $conj(open) the trapdoor, revealing a ladder leading down into darkness." + # + @set here/close_exit_msg = "$You() $conj(close) the trapdoor. Don't want anyone to fall in." +#+END_SRC + +And let’s create the trapdoor: + +#+BEGIN_src evennia + @create/drop trapdoor + # + @desc trapdoor = A wood door with reinforced iron bands on the floor. An iron ring allows you to |gopen|n it. + # + @lock trapdoor = get:false() + # + @set trapdoor/get_err_msg = "The hinges of the trapdoor allows you to |gopen|n the door, but not take it." + # + @set trapdoor/pull_msg = "Sorry, the command you are looking for is |gopen|n...not pull. Good guess, though." +#+END_SRC + +Let’s enter the belly of this beast. + +#+BEGIN_SRC evennia + @teleport/quiet mp18 + # + @desc here = A cold, musty tunnel made of stone blocks, tapered to form an arch overhead. A ladder here leads up to a trapdoor, and the tunnel continues on into the distance. + # + @desc ladder = A metal ladder where a slimy mildew of sorts has grown on the bottom rungs. Better be careful. + # + @set ladder/traverse_msg = "You carefully ascend up the ladder, opening the trapdoor." + # + @detail trapdoor = A wood door with reinforced iron bands on the floor. An iron ring allows you to |gopen|n it. + # + @detail stone;blocks = The stone blocks that support the tunnel are well made, and for the most part, keep out water. But the crevises seem mortared with a green mildew. +#+END_SRC + + +Let’s make the end of the tunnel look a lot like the beginning: + + +Let’s create another trapdoor and a ladder leading to the Lair: + +#+BEGIN_SRC evennia + @open ladder to trapdoor;trapdoor;up;ladder;climb,ladder down into the dark;down;ladder = mp07 + # + @desc ladder = A metal ladder where a slimy mildew of sorts has grown on the bottom rungs. Better be careful. + # + @set ladder/traverse_msg = "You carefully ascend up the ladder, opening the trapdoor." + # + # + @detail trapdoor = A wood door with reinforced iron bands on the floor. An iron ring allows you to |gopen|n it. + # + @detail stone;blocks = The stone blocks that support the tunnel are well made, and for the most part, keep out water. But the crevises seem mortared with a green mildew. +#+END_SRC + +#+BEGIN_SRC evennia + @desc down = The tunnel continues down into the darkness. + # + @set down/traverse_msg = "You carefully pick your way down the tunnel. It curves. It veers. It corners...." +#+END_SRC +** Deep Forest +The deep forest is a place where all the Puppets can hang out when not in use. +#+BEGIN_SRC evennia + @dig the Deep Forest;mp00 + # + @teleport mp00 +#+END_SRC + +What do we have left to describe: + +#+BEGIN_SRC evennia + @desc here = Mists swirl 'round giant standing stones carved with ancient, cryptic symbols. A lintel perch precariously over two stones, creating a portal to the Wyldwood.|/|/You see a few characters sitting on stone benches as if on a smoking break. They look up with puzzled expressions, as if you had found your way backstage to the prop department. +#+END_SRC + +And create an easy exit back to the game: + +#+BEGIN_SRC evennia + @open portal;leave;enter;exit = Grotto +#+END_SRC + +And do the usual tricks on Exits: + +#+BEGIN_src evennia + @desc portal = Octarine sparks spiral in the mists that swirl between the stones. +#+END_SRC + +And a nice journey message to go east out of the forest: +#+BEGIN_src evennia + @set portal/traverse_msg = "As soon as you step between the stones, you feel like you are carried away..." +#+END_SRC +*** Darol the Flamboyant Dragon +This dragon is hard-coded to walk from the Mysterious Stone Circle (=mp00=) to the Tavern, and back again, chatting with anyone he meets. + +I’ve hardcoded the path of this =Traveler=, but it would be nice to be able to have different Travelers follow different paths. + +#+BEGIN_SRC evennia + @create/drop Darol: typeclasses.chatbots.Dragon + # + @set Darol/gender = "him" + # + @set Darol/pose = "twirling a tendril like a mustache" + # + @set Darol/pose_sleep = "twirling a tendril like a mustache" + # + @set Darol/pose_default = "twirling a tendril like a mustache" +#+END_SRC + +Then wake it. + +#+BEGIN_SRC evennia + py darol = me.search("Darol") ; darol.sdesc.add("tiny, orange dragon") ; darol.backstory("dragon") +#+END_SRC + +Moving attributes: + +#+BEGIN_SRC evennia + @set Darol/traveling_direction = "east" +#+END_SRC + +And get it moving: + +#+BEGIN_SRC evennia + @script Sir Roblees = typeclasses.chatbots.TravelingNPC +#+END_SRC +*** Rick the Barbarian + +#+BEGIN_SRC evennia :tangle no + @create/drop Rick: typeclasses.chatbots.Traveler + # + @set Rick/gender = "her" + # + @set Rick/pose = "twirling a tendril like a mustache" + # + @set Rick/pose_sleep = "twirling a tendril like a mustache" +#+END_SRC + +Then wake her. + +#+BEGIN_SRC evennia :tangle no + py rick = me.search("rick") ; rick.sdesc.add("large barbarian") ; rick.backstory("barbarian") +#+END_SRC + +*** George the Dwarf Tinkerer +This Dwarf will be in the dungeons, but I would like them to come out at times. +#+BEGIN_SRC evennia :tangle no + @create/drop George: typeclasses.chatbots.Chatbot + # + @set George/gender = "him" + # + @set George/pose = "looking at some blueprints" + # + @set George/pose_sleep = "snoozing" +#+END_SRC + +Then wake it. + +#+BEGIN_SRC evennia :tangle no + py george = me.search("george") ; george.sdesc.add("white-haired dwarf") ; george.backstory("dwarf") +#+END_SRC + +** Bugs + +And now that we are done, say it: + +#+BEGIN_src evennia + say I have finished this, the first version, of my creation. +#+END_SRC + +** Finish Testing +Can we quickly walk back through the world, gathering ingredients, and then going back into the Secret Room to make potions? + +#+BEGIN_SRC tcl + send "copse\n" + expectit "Bedroom" + + send "close wardrobe\n" + expectit "The wardrobe door is closed." + + send "down\n" + expectit "Cozy House" + + send "leave\n" + expectit "Grotto" + + send "east\n" + expectit "Grove of the Matriarchs" + + send "climb boulder\n" + expectit "Boulder Top" + + # Elixir Risorium ... Laughing Potion ... + send "look mushrooms\n" + + expectit "A vibrant patch of mushrooms bursts forth like a painter's palette, each cap shimmering with iridescent hues of violet, emerald, and gold" + + send "get mushroom\n" + expectit "You harvest a gigglecap mushroom." + + send "climb down\n" + expectit "Grove of the Matriarchs" + + send "east\n" + expectit "Frog Meadow" + + send "feed beast\n" + expectit "scone" + + send "look tickleweed\n" + expectit "Patches of this vivid grass vibrates as if giggling." + + send "get tickleweed\n" + expectit "You harvest a bunch of tickleweed." + + send "fill bottle\n" + expectit "you fill it with sparkling water" + + # Head to secret lab... + send "west\n" + expectit "Grove of the Matriarchs" + + send "west\n" + expectit "Grotto" + + send "red door\n" + expectit "Cozy House" + + send "pull sconce\n" + expectit "You hear a click" + + send "down stairs\n" + expectit "Secret Room" + + send "empty\n" + expectit "empty" + + send "add mushroom\n" + expectit "You add gigglecap mushroom to black cauldron." + + send "add tickleweed\n" + expectit "You add bunch of tickleweed to black cauldron." + + send "add bottle\n" + expectit "You pour the fizzy water from your bottle into the black cauldron." + + send "create\n" + expectit "making it ready" + + send "bottle\n" + expectit "You fill a small vial" + + send "inventory\n" + expectit "vial" + + send "empty\n" + # Since almost anything can be written, we look for a period + expectit "." + + send "empty\n" + expectit "The black cauldron is already empty." + + send "up\n" + expectit "Cozy House" + + send "score\n" + expectit "Total:" + + send "give potion to gnome\n" + expectit "You give a potion" +#+END_SRC + +Let’s try the next potion, the /Somnium Illusorium/: + + - 1 handful of Moonberries + - 1 Dreamshade mushroom + - 1 small sack of Pixie Dust + - 1 cup of fresh, still water + +#+BEGIN_SRC tcl + send "leave\n" + expectit "Grotto" + + send "fill bottle\n" + expectit "still water" + + send "east\n" + expectit "Grove" + + send "east\n" + expectit "Frog Meadow" + + send "lair\n" + expectit "Lair" + + send "look mushrooms\n" + expectit "Slender blue tendrils" + + send "get mushroom\n" + expectit "dreamshade mushroom" + + send "leave\n" + expectit "Frog Meadow" + + send "south\n" + expectit "Mellow Marsh" + + send "get glitter\n" + expectit "wad of pixie dust" + + send "north\n" + expectit "Frog Meadow" + + send "west\n" + expectit "Grove" + + send "south\n" + expectit "Lazy Dock" + + set timeout 120 + send "blow horn\n" + # expectit "You blow your horn" + expectit "The giant leaf slows as it arrives next to the dock." + + send "boat\n" + expectit "The giant leaf gently bobs in the surf of this island, allowing you to disembark." + + send "disembark\n" + expectit "Lonely Island" + + send "get moonberry\n" + expectit "You collect a handful of moonberries" + + # While we are here, we should solve the puzzle...but... + # we will just jump back on the boat before it leaves. + + send "boat\n" + expectit "The giant leaf slows as it arrives and docks allowing you to disembark" + + send "disembark\n" + expectit "Lazy Dock" + set timeout 30 + + send "north\n" + expectit "Grove" + + send "west\n" + expectit "Grotto" + + send "red door\n" + expectit "Cozy House" + + send "pull sconce\n" + expectit "You hear a click" + + send "down stairs\n" + expectit "Secret Room" + + send "empty\n" + expectit "empty" + + send "add mushroom\n" + expectit "You add dreamshade mushroom to black cauldron." + + send "add moonberries\n" + expectit "You add handful of moonberries to black cauldron." + + send "add pixie dust\n" + expectit "You add wad of pixie dust to black cauldron." + + send "add bottle\n" + expectit "You pour the still water from your bottle into the black cauldron." + + send "create\n" + expectit "making it ready" + + send "bottle\n" + expectit "You fill a small vial" + + send "inventory\n" + expectit "vial" + + send "empty\n" + # Since almost anything can be written, we look for a period + expectit "." + + send "empty\n" + expectit "The black cauldron is already empty." + + send "up\n" + expectit "Cozy House" + + send "score\n" + expectit "Total:" + + send "give potion to gnome\n" + expectit "You give a potion" +#+END_SRC + +Let’s close up the test. + +#+BEGIN_SRC tcl + # Close the log file + log_file + + sleep 1 + send "quit\n" + + # Handle the connection closed message without logging it + expect { + "Connection closed by foreign host" { + # Ignore this response + exp_continue + } + eof { + # End the session + return + } + } + +#+END_SRC + +** Example +What does it look like? + +*Dabbler's House* \\ +You found a cozy, cornerless room. Large, overstuffed chairs sit invitingly by a fire casting shadows that dance on the dark paneling. Oddly angled shelves with books and knickknackery adorn the walls around a tapestry. The subtle smell of wood smoke, incense and tea leads you to a trolley supporting a large teapot, cups and freshly baked scones. \\ +*Exits*: outside \\ +*You see*: a collection of books, a few overstuffed chairs, a fireplace, and a teapot + +> =look doodads= + +An odd assortment of knickknacks and doodads that decorate the minimal space between the askew-ed books on the skewampus shelves. + +> =look fire= + +A stone fireplace with a carved wooden mantel supporting small pictures, some books and a black statue. The fire in the fireplace crackles and pops with warmth and light. + +> =look pictures= + +Two small framed pictures perch above the fireplace mantle. One is of a satyr playing a saxophone, and the other is of a fish with a big smile. + +> =look statue= + +A small, black statue of a salamander curled around a book, engraved with a title, "Seeing Stones". + +> =feed fire= + +You get up and put some wood on the fire in the fireplace. +The fire in the fireplace burns brightly and is very hot. You feel the need to move back a bit. + +> =say I forgot about the tapestry!= + +You say, "I forgot about the tapestry!" + +> =look tapestry= + +The muted colors of the tapestry either show its age or its location over the sometimes smokey hearth. It shows a gallant stag surrounded by woodland creatures. A raccoon holds aloft a gold box while a wolf has a gnarled staff. A raven perched on the stag's antlers grips a blue ball in its beak. + +> =pose puts his hands on his hips and stares.= + +Traveler puts his hands on his hips and stares. + +> =look raven= + +The raven winks at you, and says, "Nevermore." Really? It probably didn't. Your eyes must be playing trickster. + +> =rubs his eyes.= + +Traveler rubs his eyes. + +> =look trolley= + +A tea trolley, complete with a small collection of teacups, a magical teapot, as well as an assortment of scones and pastries. + +> ="Nice= + +You say, "Nice" + +> =look teapot= + +*teapot* \\ +A large, brown teapot full of a roasted herbal infusion of dandelions that tastes a bit like coffee. + +> =look teacups= + +An odd, yet interesting assortment of teacups. Take one. + +> =look teacup= + +Each cup is unique. Take one to look further. + +> =get cup= + +You pick up a teacup. + +> =look cup= + +*teacup* \\ +A Wings of Grace style teacup with blue butterflies. Perfect for some Earl Grey. + +> =make tea= + +You make a teapot of a roasted herbal infusion of dandelions that tastes a bit like coffee. + +> =make earl gray= + +You make a teapot of a flowery Earl Grey tea. + +> =pour tea= + +You pour some dandelion tea into your cup. + +/The fire in the fireplace crackles and pops with warmth and light./ + +> =look bookshelf= + +Shelves at various angles embellish the walls of this small, cozy room. Leatherbound books weigh each shelf, while some stacks of books support other shelves. Dabbler has decorated some shelves with odd trinkets. + +> =look books= + +*collection of books* \\ +Books of different sizes and colors. So many books. Perhaps you want to simply look at a book at random? + +> =look book= + +You see a worn book, titled, /Do Golems Dream of Awakened Sheep?/. + +> =get book= + +You pick up the book. + +> =look chairs= + +*overstuffed chairs* \\ +A few, dark leather, overstuffed chairs, each with a soft, colorful blanket and pillow. An invitation for a cozy nap. + +> =sit= + +You sit in an overstuffed chair. This feels cozy. + +> =drink= + +You sip from your cup. + +> =read book= + +You crack open your book, entitled, /Do Golems Dream of Awakened Sheep?/, and read the plot twisting tale of a golem reaches out to its creator after years of therapy reveal his anger of his existential crisis is justified. + +> =drink tea= + +You sample from your teacup. + +> =throw book in fire= + +You drop the book, and it flaps its pages, and flies back to a section on the shelf. Gotta keep the room organized. +* Scoring +I would like a =score= command that gives them a tally based on the activities they have participated in. This will be a hashtable, stored as an attribute. Perhaps it increments a value? Should I simplify the number of items, and then list them all, so they have goals? + + - jump + - throw stick + - catch fish + - feed bhb + - get traveling horn + - make tea + - read a book + - eat candy + - get pipe + - get blue medal + - finish cocktail (all cocktails?) + - make potion (laughing) + + Should the score be something be shown when one issues a =look= at another character? + +* Tutorial Bird +If a person creates a character, instead of giving them a personal letter, let’s have a little bird land on their shoulder, and talk them through the game. I’m thinking a “state machine” triggered by actions that someone does. + +#+begin_example + ╭────────────╮ ╭────────────╮ + │ created ├──┬shoo───→│ tutored │←─╮ + ╰─────┬──────╯ │ ╰────────────╯ │ + look │ ↑ │ + ↓ │ done │ + ╭────────────╮ │ ╭─────┴──────╮ │ + │ looked ├──┤ │ helped │ shoo + ╰─────┬──────╯ │ ╰────────────╯ │ + look trees │ ↑ │ + ↓ │ help │ + ╭────────────╮ │ ╭─────┴──────╮ │ + │ looked-at ├──╯ │ moved ├──╯ + ╰─────┬──────╯ ╰────────────╯ + south ↑ + ╰────────────────────────╯ + +#+end_example + +Each section should have a list of phrases spoken or “done” on a timer. + +#+BEGIN_src evennia :tangle no + You see a tiny bird with blue feathers trimmed with white. It's large black eyes looks at you quizically. It seems friendly, and overly helpful. +#+END_SRC + +** Created + - A little blue bird flies by you, almost grazing your ear! + - It flies over to you, and perches on your shoulder. “Hello,” it says in your ear. + - “I’m the Tutorial Bird,” it chirps, “and I’m here to break the fourth wall, and help you figure out this game. Feel free to |bshoo|n me away, and I’ll leave you alone to explore.” + - The bird says, “In this story game, you type commands (verbs) to do things. For instance, type the word |blook|n, and press the |wReturn|n key to look around at your surroundings and to see where you are, what you can do, and where you can go.” + - The bird perched on your shoulder looks at you expectantly. + - “Go ahead,” says the bird, “Type |blook|n. If you are on the web site, you may need to click in the box in the lower part of the screen.” + - The bird preens itself. + - The bird says, “Would you like me to stay and help you out?” + - “If so,” says the bird, “type |blook|n to look around at your surroundings.” + +** Looked + - “That’s great,” says the little blue bird. “From that, you know you are standing in a grove of trees. You can now type |blook trees|n to examine them.” + - “You can also |blook ivy|n, |blook moss|n, or … well, you get the idea,” it says. +** Looked At + - “You seem to be getting the hang of this,” chirps the bird. “When you typed |blook|n before, you noticed exits. These are directions or places you can go. For instance, if you type |bsouth|n (or just |bs|n as a shortcut), you can check out our pond.” + - “The path to the |bwest|n leads to Dabbler’s place,” the little bird on your shoulder says. + - “Yes, I could fly myself,” warbles the little bird, “but I’m trying to help you get around.” + - The bird looks at you expectantly. + - “Shall we explore other places?” asks the bird on your shoulder. + - “I hope I’m not rushing you,” the bird mentions, “as you can always come back to explore more.” + +** Moved + + - "Thanks for lift. This is a nice place," says the bird on your shoulder. "When you come to a new area, the game shows you what you are seeing, so you don’t have to type |blook|n … even though you still can." + - "Another interesting command," it chirps, "is the |bsay|n command, that lets you talk to anyone in the area. Usually, we use this command for talking to other players in the game, but some creatures listen to what you say." + - "Go ahead, just typing |bsay Hello.|n" + +** Said + - “How’s it going?” the bird asks, “Are you enjoying this game so far?” + - The bird says, “This place has been a respite from the outside turbulence.” + - "A shortcut to |bsay|n is to type either a double or single quote, and then your message." + - "You can also use |bpose|n to state something about yourself." + - "For instance, type |bpose smiles.|n" +** Posed + - The bird stands on one leg. + - “See,” says the bird, “I can pose too.” + - “A shortcut to that command is typing |b:|n (a colon character).” + - The bird says, "The game has more commands. Typing |bhelp|n gives you a list of commands. That list changes depending on where you are and what you are carrying. For instance, you could type |bshoo|n for me to fly away, and then that command wouldn’t be available again." + - "Go ahead," chirps the little bird, "Type |bhelp|n to see the Help Menu." + +** Helped + + - “Yes, tables are easier to read,” says the bird, “but not as immersive as prose.” + - The bird chirps, "You can learn more about the individual commands. For instance, type |bhelp say|n and you would see about the shortcuts I told you about. You can also see new commands, like |bhelp get|n.“ + - “Type |bhelp start|n for a repeat of much of what we’ve talked about,” says the bird. + +** Tutored + - “I’m guessing your last question,” chirps the little bird on your shoulder, “is the goal of this game.” + - “That is a good question,” says the bird, “and I’m not sure what to say. This game has no goal, nor point. I guess you could look at it as a philosophical metaphor for existential existence in a post-modern world in the death throes of capitalism, but…” + - The bird says, “This is a cozy, little game about exploring and looking for eggs… no, that’s not right. Something about eggs. Easter eggs? Something like that.” + - “Wander and look around. Find a cozy place to chat with others who have logged in,” says the bird. + - “If you’re interested in |wbuilding|n and expanding this world,” chirps the bird, “talk to Dabbler.” + - The bird says, “Oh, see if you can find Dabbler, the guy that made most of this. That is a great goal.” + +** Ended +- “Have fun, and I’ll leave you here,” chirps the bird, as it flies away. + +** Waiting + - The <> bird <> preens itself. + - The <> bird <> <> at you <>. + - The bird looks up at the sky. “It rains here often,” it says. + - The bird looks up at the sky. “Looks like rain is coming,” it says. + - “I like the rain,” the bird says, “as it keeps the moss green and the puddles full.” + - “They say if you don’t like the weather,” tweets the bird, “just wait.” + +* Evennia Details +** Scripts +This is an obnoxious, but interesting effects: +#+BEGIN_src evennia :tangle no +script self = tutorials.bodyfunctions.BodyFunctions +#+end_src + +And stop it with: +#+BEGIN_src evennia :tangle no +script/stop self = tutorials.bodyfunctions.BodyFunctions +#+end_src + +** Accounts +Can we fix the permissions for our friends: + +#+BEGIN_src evennia :tangle no + perm/account steve = Builders +#+END_SRC + +Who is logged in? Use the =who= command, or something like: + +#+BEGIN_SRC python + import evennia + + people = [ + " - " + account.name + " :: " + \ + ", ".join([character.name for character in account.characters]) + + for account in evennia.SESSION_HANDLER.all_connected_accounts()] +#+END_SRC + +** Python +Run stuff: + +#+BEGIN_EXAMPLE +py print("|gHello World!|n") +py me.msg("|gHello world!|n") +#+END_EXAMPLE + +The python approach to =@create= is: + +#+BEGIN_SRC python +py evennia.create_object("typeclasses.sittables.Sittable", key="chair", location=here) +py self.search("armchair").do_sit(me) +#+END_SRC + +Assuming we have created something: + +#+BEGIN_SRC python :tangle no +from typeclasses.objects import Object + +class Monster(Object): + """ + This is a base class for Monsters. + """ + def move_around(self): + print(f"{self.key} is moving!") + + +class Dragon(Monster): + """ + This is a dragon-specific Monster. + """ + + def move_around(self): + super().move_around() + print("The world trembles.") + + def firebreath(self): + """ + Let our dragon breathe fire. + """ + print(f"{self.key} breathes fire!") +#+END_SRC + +Create stuff, first go into the inline Python REPL: + +#+begin_example + @reload + @py +#+end_example + +#+BEGIN_SRC python + from typeclasses.monsters import Dragon + smaug = Dragon(db_key="Smaug", db_location=here) + smaug.save() + smaug.move_around() +#+end_src + +Or better yet: + +#+BEGIN_EXAMPLE +py evennia.create_object('typeclasses.monsters.Monster', key="Cuddly", location=here) +py cuddly = evennia.search_object("Cuddly")[0] ; cuddly.move_around() +#+end_example + +Or: + +#+BEGIN_src evennia :tangle no + @create/drop Fluffy:typeclasses.monsters.Dragon +#+end_src +* Server Deployment +Created the following section in =/etc/apache2/sites-enabled/howardabrams.conf=: + +#+BEGIN_SRC conf + # Proxy all websocket traffic to port 4002 in Evennia + ProxyPass /ws ws://127.0.0.1:4002/ + ProxyPassReverse /ws ws://127.0.0.1:4002/ + + # Proxy all HTTP traffic to port 4001 in Evennia + ProxyPass /moss http://127.0.0.1:4001 + ProxyPassReverse /moss http://127.0.0.1:4001 +#+END_SRC + +Notice the lack of a =/= at the end, something their [[https://www.evennia.com/docs/4.x/Setup/Config-Apache-Proxy.html][configuration suggestions]] added. + +Next, I need to make sure that everything prepends =/moss= to all references. + +This could be any of the following: + +#+BEGIN_SRC conf +# Where users are redirected after logging in via contrib.auth.login. +LOGIN_REDIRECT_URL = "/" +#+END_SRC +* Images +** Cozy House +Style: +“Watercolor painting” +(as you want that soft, fluid texture) + +Setting/Composition: +“A cozy interior centered on a stone hearth with glowing firelight, backed by dark wood-paneled walls lined with subtly crooked bookshelves.” + +Foreground Characters: +“Two comfortable, overstuffed armchairs. In the left chair sits an elderly man—sleeping—with a white Van Dyke beard, blue hair, and on his lap, a curled-up white stoat, both pictured peacefully.” + +Tapestry Detail (central over the hearth): +A tapestry with four quadrants, each depicting a scene: + +Top left: a small old man with a Van Dyke beard standing beside a wilted yellow rose bush. + +Top right: the old man, a robust yellow rose bush and a smile, and a magnificent queen. + +Bottom left: the old man standing near two trees close together. + +Bottom right: the two trees slightly farther apart, with the old man leaning in, whispering to one of the trees. + +Overall Mood & Lighting: +Golden, soft firelight illuminating the hearth and tapestry, casting cozy shadows in the room. + +⸺ +A watercolor illustration of a cozy room at dusk, featuring a glowing stone hearth in the center. Two plush, overstuffed armchairs face the fire—one holds a sleeping elderly man with a white Van Dyke beard and blue hair; a curled‑up white stoat rests gently on his lap. The dark wood-paneled walls are lined with slightly crooked bookshelves. Above the hearth hangs a richly detailed four‑panel tapestry: top‑left shows a small old man with a Van Dyke beard beside a yellow rose bush; top‑right shows the man, the rose bush, and a magnificent queen; bottom‑left shows the old man with two closely standing trees; bottom‑right shows the two trees more spaced apart, with the old man whispering to one tree. The entire scene is painted in the delicate, fluid style of watercolor, with warm firelight casting soft glows and shadows throughout. + +Tips for Better Results in DALL·E + +Be explicit about style and mood — “watercolor” + “warm, soft lighting”. + +Specify relative placement — e.g. “above the hearth,” “left chair,” etc. + +Use visual references — include “Van Dyke beard,” “white stoat curled up” to help the model. + +Iterate — If the tapestry details aren't clear, you might generate each quadrant in separate prompts or highlight “four‑panel tapestry with distinct scenes” to ensure clarity. + +Include atmosphere — terms like “cozy,” “glowing,” or “soft shadow” can enhance the feel. + +Let me know if you'd like help tweaking the prompt further—perhaps adjusting the color palette, chair styles, or additional environmental elements! + +# Local Variables: +# jinx-local-words: "Barkbinder Beastie Brambleberry Brayne Dreamshade Elendil Evennia Illusorium Puppeting Risorium Scrying Somnium Tickleweed Trampoli Trampoli’s Trippy Wha brambleberries brambleberry drinkables expectit gigglecap gigglecaps grimoire ish moonberries msg puppeted purdy sayto skewampus tickleweed typeclasses un" +# End: diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..2b1f4df --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +evennia +anthropic