moss-n-puddles/moss-n-puddles.org
Howard Abrams b63cb4c74d Do other people want to see the this?
Never see how the sausage is made.

Especially if you are a vegetarian.
2026-05-08 23:21:45 -07:00

247 KiB
Raw Blame History

Wonderful World of Mud : Moss and Puddles Edition

  • 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 Trolls gambling den … part of the bar? under the bridge?

Evennia Server

Background

While I believe I could use any MUD server, Im trying out Evennia. Based on Python, but I wont 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 (wasnt 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 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 mud-rpg.org file, that tangles its code to version2.ev. Then, when adding escape rooms, I created mud-adventure.org, and tangle it to adventure1.ev.

Installation

Follow the online instructions for Evennia:

  pip install cryptography paramiko evennia ipython requests

Seems like the SSL with the telnet protocol, install:

  pip install pyopenssl

For SSH, do:

  pip install paramiko service_identity

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:

  evennia migrate

Feel free to delete the old database in order to restart (as this file should contain everything we need).

  mv server/evennia.db3 server/evennia-v1.db3

And then start or restart (or reload, I think):

  evennia start

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.

evennia shell

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.

from typeclasses.characters import Character

And set some good variables:

me = Character.characters.searchdbref("#1")

Create an Avatar

The first character is special, as it can really own the server. I dont 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.

  @name self = Avatar
  @setdesc A translucent being of light and energy. The surrounding world seems vivid and vibrant as it basks in the radience.
  @sdesc angelic being

And to pose:

  py self.db.pose = True
  #
  pose looking awesome

World: Moss and Puddles

Starting Introduction

Would love to have the following introduction. Done by editing connection_screens.py:

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...

To give someone a special log on message the first time, I have updated the Character creation function to give them a letter.

I also thought they could type help start, to see, but this is easier to edit in source.

Title Sequence

• ▌ ▄ ·.       .▄▄ · .▄▄ ·      ▄▄▄·  ▐ ▄ ·▄▄▄▄
·██ ▐███▪▪     ▐█ ▀. ▐█ ▀.     ▐█ ▀█ •█▌▐███▪ ██
▐█ ▌▐▌▐█· ▄█▀▄ ▄▀▀▀█▄▄▀▀▀█▄    ▄█▀▀█ ▐█▐▐▌▐█· ▐█▌
██ ██▌▐█▌▐█▌.▐▌▐█▄▪▐█▐█▄▪▐█    ▐█ ▪▐▌██▐█▌██. ██
▀▀  █▪▀▀▀ ▀█▄▀▪ ▀▀▀▀  ▀▀▀▀      ▀  ▀ ▀▀ █▪▀▀▀▀▀•
     ▄▄▄·▄• ▄▌·▄▄▄▄  ·▄▄▄▄  ▄▄▌  ▄▄▄ ..▄▄ ·
    ▐█ ▄██▪██▌██▪ ██ ██▪ ██ ██•  ▀▄.▀·▐█ ▀.
     ██▀·█▌▐█▌▐█· ▐█▌▐█· ▐█▌██▪  ▐▀▀▪▄▄▀▀▀█▄
    ▐█▪·•▐█▄█▌██. ██ ██. ██ ▐█▌▐▌▐█▄▄▌▐█▄▪▐█
    .▀    ▀▀▀ ▀▀▀▀▀• ▀▀▀▀▀• .▀▀▀  ▀▀▀  ▀▀▀▀

Map Locations

  # 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

/git/howard/moss-n-puddles/media/commit/b63cb4c74d0f58304b5d5986ffb81f3cabd76881/mud-map.svg

Testing the World Experience

Using the infamous Tcl/Expect system, I can log on with a test account and use it to generate commands and validate the output.

  # Set timeout for expect commands
  set timeout 30

  # Open the log file
  log_file results.txt

If I dont find what Im looking for, instead of just continuing, I want it to fail. I create the expectit function as a replacement for expect:

  # 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
          }
      }
  }

Since some objects in my world dont appear until triggered, I would like to test for that negative case, but I dont know Expect well enough to figure that out programmatically, so I create a function, and call out what to visually look at:

  proc dont_expect {trigger pattern} {
      send "look\n"
      puts "NOTE: At this point, ** $pattern ** should not be here!"
  }

That is, until I can get the following code to work:

  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
          }
      }
  }

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:

  # 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
  }

The testing account is currently the guest account:

  # 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"
  }

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:

  @teleport/quiet mp01
  #
  @set goblin/guest_account = True

How much of the tutorial do we want to test?

  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"
  }

At this point, stop the bird shenanigans, and get moving…

  # That should be enough of the birdie ...
  send "shoo\n"

Lets get the servers time, as we can use this information to adjust our tests.

  # 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
      }
  }

Lets 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.

  @name here = Grove of the Matriarchs;mp01

The description will take advantage of the seasons and times of the day:

  @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 <evening>darkening twilight</evening><morning>awakening dawn</morning><afternoon>lazy afternoon</afternoon><night>night sky</night>. <morning>With the morning light, you can hear the dawn chorus of birds</morning><afternoon>The afternoon breeze carries the buzzing of insects around giant colorful |Yflowers|n</afternoon><evening>You can't hear much now as most of the forest creatures are settling down for the night</evening><night>In the darkness, you can hear crickets and an occasional owl</night>. 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.

And a brief test of the time states in the output of the look command:

  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
      }
  }

Need to add weather and time data to this:

  @update here = typeclasses.rooms_weather.TimeWeatherRoom

Derived from the original rooms.py, but now stored in rooms_weather.py.

Describe the trees, flowers, and of course, the alcove:

  @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.

We dont need to test all the details, but the first one:

  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."

And an image for it.

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.

Barkbinder the Tree

When you first log into the game, you can immediately chat with an unfriendly, overly boring tree.

  @create/drop tree;trees: typeclasses.chatbots.ChatBot
  #
  @set tree/gender = "neutral"
  #
  @set tree/pose = "contemplating...or sleeping"
  #
  @set tree/pose_sleep = "contemplating...or sleeping"

Then wake it.

  py tree = me.search("tree") ; tree.sdesc.add("especially large tree") ; tree.backstory("tree")

Hints

What about hints? Since this is the first room, I didnt want it complicated or clever, but we could mention that they should look boulder:

  ---
  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.        

And we can have our test account verify that hint works:

  send "hint\n"
  expectit "Look at everything"

Puddle

With my name, I need to have an object to go with it.

  @create/drop puddle : typeclasses.things.Puddle

And an elusive description:

  @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.

And keep it locked down:

  @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."

And a test of our ability to jump in the puddle:

  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!"

Sticks

I will have a script auto generate the sticks on a regular basis, but for now, lets just make one that I can drop.

  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)] )

And lets see if the stick behaves:

  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
      }
  }

Guest Book

Players can leave messages in this book. Well see how long I want to leave this.

  @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..."

Note that we dont mention this in the areas description.

  @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.

Cant get it:

  @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."

And some details:

  @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.

How should the book start?

  # 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

Lets test that we can read the book:

  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"

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:

  @lock thing = view:tag(hidden_thing)

Where thing is the single name of the hidden object. Find the code in objects.py.

  @create/drop duck
  @set duck/hidden_tag = "hidden_ducky"
  @lock duck = view:tag(hidden_ducky)
  look duck

Boulder

More details about the room that describes aspects of the boulder in the desc above. First, the symbol:

  @detail symbol = You move an ivy runner to see three curves join together as if it were three legs.

The moss is purdy:

  @detail moss = "Even in this light, the moss radiates a surreal color of green."

And the ivy is … uh.

  @detail ivy = "You see...well, ivy. Uhm, it's green, and..."

The runes use multi-byte Unicode which screws up the telnet client.

  @detail runes;rune = The runes read ᛞ ᚪ ᛒ ᛚ ᚱ

The top of the boulder should be another room, accessible by the climb, but maybe it isnt “seen” until the boulder has been looked? First, we put some weather at the top of the boulder:

  @dig Boulder Top;mp02 : typeclasses.rooms_weather.TimeWeatherRoom = climb boulder;boulder;climb,climb down;climb;down

The ability to climb the boulder isnt immediately obvious, so lets make it a bit of a secret:

  @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!

To take advantage of our /git/howard/moss-n-puddles/src/commit/b63cb4c74d0f58304b5d5986ffb81f3cabd76881/Hidden%20Things, we put the right tag on it:

  @set boulder/hidden_tag = "hidden_boulder"
  #
  @lock boulder = view:tag(hidden_boulder)

And give it some aliases:

  @name boulder = climb the boulder;boulder;climb;climb up;climb boulder

And a description:

  @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."

And tests to look at all the details;

  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 ᛞ ᚪ ᛒ ᛚ ᚱ"

Lets test that the boulder (which we create in the next section), is indeed hidden.

  dont_expect "Exits" "boulder"

  send "look boulder\n"
  expectit "You notice a foot hold"

  send "look\n"
  expect -re "Exits:.*climb.*boulder"

Lower Vines

In case they attempt to get vines here:

Lets make a nice spot to sit down on:

  @create/drop dangling vine;vines;vine

With a nice description:

  @desc vines = Strong vines twisted to look like rope. This could be helpful.

Cant take it here, you have to climb the boulder first:

  @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?"

Can we hide it too?

  @lock vines = view:tag(hidden_vines)
  #
  @set vines/hidden_tag = "hidden_vines"

What about pushing and pulling messages?

  @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."

And the vines as well:

  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."

Top of Boulder

Lets jump to the top of the boulder to proceed:

  @teleport mp02

And to test to see if we can climb the boulder:

  send "climb boulder\n"
  expectit "You grab hold of some"

  # Did we arrive?
  expectit "Boulder Top"

And the description:

  @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.

More details:

  @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.

And a description of the climb:

  @desc climb = The climb seemed easy, but you're not sure you can handle the footholds going the other way around.

And describe the journey:

  @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..."
  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."

A description?

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.

Moss

Lets make a nice spot to sit down on:

  @create/drop patch of moss;moss:typeclasses.sittables.Sittable

With a nice description:

  @desc patch of moss = A cushioned patch of moss of the most vibrant green.

Cant take the moss with you:

  @lock patch of moss = get:false()

Can we hide it too?

  @lock patch of moss = view:tag(hidden_moss)
  #
  @set patch of moss/hidden_tag = "hidden_moss"

And a lovely message about why you cant steal moss:

  @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."

Is pulling on moss the same as attempting to get it?

  @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."

Lets test if we can sit on the moss:

  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"

Upper Vines

Lets cover top of the boulder with rope-like vines. The vine can be a producer that makes ropes … needed to get into the hut.

  @teleport mp02
  #
  @create/drop lot of vines;vine;rope: typeclasses.consumables.Producer

With a description:

  @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.

We have to have the vines describe what it makes:

  @set vines/make_name = "coil of rope"

And a verb when they get the consumable:

  @set vines/make_verb = "$conj(yank) and $conj(shape) a"

And a commentary:

  @set vines/make_note = " from the vines"

This one is optional as it defaults to Consumable:

  @set vines/make_class = "typeclasses.things.Rope"

And the vines needs to know the description of the Consumable, so that it can attach that:

  @set vines/make_desc = "Made from vines, but could be a good lasso."

How much is there when you pick them?

  @set vines/make_amount = 1

What if they do something other than get the vines?

  @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."

Lets make sure that we can get the vines from this producer:

  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"

Lets have the rooms hint be about these vines:

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.      

Gigglecap Mushrooms

Part of the Alchemist Path, we use gigglecaps to create a /git/howard/moss-n-puddles/src/commit/b63cb4c74d0f58304b5d5986ffb81f3cabd76881/Laughing%20Potion.

Note the Alchemist Tome:

Colorful gigglecaps prefer well drained locations to grow, like on the top of rock terrain.

And we create a patch of them for the picking:

  # @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)

Until we are an alchemist, we shouldn't see the mushrooms…

  dont_expect "You notice" "mushrooms"

Squirrel

Here for hints … and a bit of a distraction.

  @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
  @set squirrel/arrive = "20 ;; emote briefly opens her eyes, nods an acknowledgement to you. ;; gm The small squirrel returns to her meditation."

Ignore all talking.

  @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 >>."

And turn on the real sayings:

  py me.search("squirrel").backstory("squirrel")

Frog Meadow

To the east, lets make a nice meadow. Start at the Forest:

  @teleport mp01

And we use the tunnel command this time:

  @dig Frog Meadow;mp05 : typeclasses.rooms_weather.TimeWeatherRoom = east footpath to meadow;east;e;path;footpath,west footpath to forest;footpath;west;w;path

A description if they look east:

  @desc east = A winding footpath that may lead out of the forest... Is that a meadow?

And a nice journey message to go east out of the forest:

  @set east/traverse_msg = "The mossy tree roots that borders this footpath begin to thin out to clover and flowers..."

Before we label it, we follow east:

  @teleport mp05

And a description that takes advantage of the time of day. We should get busy and get some seasonal description here.

  @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 <night>sleepy </night>heads to you as you pass by in the <evening>darkening twilight</evening><morning>awakening dawn</morning><afternoon>lazy afternoon</afternoon><night>dark night</night>. A gap in the trees show how you can return to the footpath in the forest.

Along with a message:

  @set footpath/traverse_msg = "You leave the open meadow for the footpath through the giant trees. The yellow flowers nod goodbye to you..."

And a description:

  @desc footpath = This footpath goes in a forest of immense trees.

And details of the field.

  @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.

And detail the frogs:

  @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?"

Testing this location:

  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"

And a prompt to generate an image from Midjourney and possibly AI Studio with Gemini.

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.

Waterfall

This is special, in that it should be hidden:

  @create/drop waterfall

And the description:

  @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?
  @lock waterfall = get:false()

Looking at the waterfall, shows the cave entrance:

  @set waterfall/hidden_tag = "hidden_cave;hidden_waterfall"
  #
  @lock waterfall = view:tag(hidden_waterfall)
  @detail pool = A pool of cool, clear water.

Test the cave entrance invisibility:

  dont_expect "Exits" "cave entrance"

  dont_expect "You notice" "waterfall"

Once seen, we should see both:

  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"

Fizzy Water

The waterfall causes the water in the stream to be fizzy, to be part of the Alchemist Path to create a /git/howard/moss-n-puddles/src/commit/b63cb4c74d0f58304b5d5986ffb81f3cabd76881/Laughing%20Potion.

  # @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."]

Make sure we cant get the fizzy water. Gotta issue where the name, stream, and alias, water should be the same:

  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."

We will have to test the ability to “get” some water later, when we have a bottle.

Tickleweed

Part of the Alchemist Path, we use tickleweed grass to create a /git/howard/moss-n-puddles/src/commit/b63cb4c74d0f58304b5d5986ffb81f3cabd76881/Laughing%20Potion.

We put this location hint in the Alchemy Tome:

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.

And we create it:

  # @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)

Until we are an alchemist, we shouldn't see the mushrooms…

  dont_expect "You notice" "tickleweed"

Well test the ability to get it later.

Hints

We could have the frogs talk, perhaps a migrating murder of crows?

  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.

And some tests of the hint system?

  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."

The Lair of the Beast

To create a place for our big, hairy beast to sleep, first jump to the Meadow:

  @teleport mp05

From the Meadow, we create a lair behind the water.

  @dig Lair;mp07 = cave entrance;cave;lair;inside,outside;leave;meadow

And we make it hidden:

  @set cave/hidden_tag = "hidden_cave"
  #
  @lock cave = view:tag(hidden_cave)

And a description if they look:

  @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.

And a description when entering …

  @set cave/traverse_msg = "You venture inside the dark cave."

Lets step inside to finish this:

  @teleport mp07

And a description:

  @desc here = Vaulted stone ceiling harbors the darkness that hovers over a large |Ymattress|n.

And a description of leaving:

  @desc leave = You can see the waterfall cascading outside the cave entrance.

And the leaving message:

  @set leave/traverse_msg = "You leave the dark cave and pass behind the waterfall for the meadow beyond."

Test the cave entrance:

  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."

Mattress

Create a mattress you can sit on (and maybe push to get to a secret door):

  @create/drop mattress:typeclasses.sittables.Sittables

And the description:

  @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!?

And a detail of the mushrooms that may show if are not an alchemist:

  @detail mushrooms;fungus = Slender blue tendrils of a fungus encircle the base of the mattress. Subtle white dots on the cap suggests caution.

Cant steal it:

  @lock mattress = get:false()
  #
  @set mattress/get_err_msg = "It's way too heavy for you to lift."

Can you push or pull it?

  @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?"

And textual descriptions the object can use:

  @set mattress/adjective = "on"
  #
  @set mattress/article = "the"
  #
  @set mattress/singular = "the mattress"
  #
  @set mattress/extra = "This feels << ^ very ^ quite>> <<nice ^ cozy ^ comfortable>>, even if it smells bad.|n"

And a better description when sitting down:

  @set mattress/response = "$You() $conj(sit) on the large mattress."

And a trim on the things to see:

  @lock mattress = view:tag(hidden_mattress)
  #
  @set mattress/hidden_tag = "hidden_mattress"

Testing this location.

  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"

Dream Mushrooms

Part of the Alchemist Path, we use dream mushrooms to create a /git/howard/moss-n-puddles/src/commit/b63cb4c74d0f58304b5d5986ffb81f3cabd76881/Trippy%20Potion.

Dreamshade mushrooms feed on floating dreams, and often congregate where dreamers sleep.

  # @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)

And test that we cant see them right now.

  dont_expect "You notice" "mushrooms"

Beast

And we create the Big, Hairy Beast:

  @create/drop big hairy beast;bhb;beast;hairy beast;monster;shadow: typeclasses.pets.BHB

And a general description that will be expanded with its current reaction.

  @desc beast = A big, hairy beast with long claws and teeth.

Cant get this:

  @lock beast = get:false()
  #
  @set beast/get_err_msg = "You can't pick that up, as that beast is far larger than you."

And set its sleepy time at 8pm …

  @set beast/sleep_hour = 21

It will wake at 8am …

  @set beast/wake_hour = 8

Lets set some behavior levels. For instance, the beast is sad when he doesnt see its friends:

  @set beast/loneliness_amount = -2

It seem to warm up the to new characters hanging around the area, but not as much as those that would interact with it:

  @set beast/shyness_amount = 3

How active should this pet be? Seems like at the moment, it shouldnt 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).

  @set beast/active_amount = 10

It isnt that scared of new people, as it will ignore them when someone it knows is around.

  @set beast/new_character_reaction = 'ignores'

Seems we should make descriptions for all the states that happen when you look at them. These are appended to the standard description.

  @set beast/scared_msg = "It seems <<skiddish ^ afraid ^ skiddish and afraid>> as it tries to hide behind a tall clump of grass. Yeah, it doesn't do a good job of hiding."

Concerned level:

  @set beast/concerned_msg = "Its large, yellow eyes stare at you from a safe distance."

Interested level:

  @set beast/interested_msg = "It seems <<curious ^ interested>> in what you are doing <<here ^ >>. ;; Its << ^ large, ^ big,>> yellow eyes watch your every move."

Friendly level:

  @set beast/friendly_msg = "It sits next to you, as its big, friendly eyes gaze as you. ;; It <<leaps over ^ runs up ^ bounces up ^ >> to you, wagging its tail-less behind. ;; It lays down next to you."

When the beast is sleeping, we can some times spam the room with the snores:

  @set beast/sleeping_actions = "The <<big, ^ huge, ^ large, ^ tremendous, ^ >> <<hairy ^ slobbery ^ horned ^ clawed ^ >> <<brute ^ beast ^ monster>> lets loose a <<big, ^ huge, ^ large, ^ tremendous, ^ >> snore. ;; The <<big, ^ huge, ^ large, ^ tremendous, ^ >> <<hairy ^ slobbery ^ horned ^ clawed ^ >> <<brute ^ beast ^ monster>> growls in its sleep. ;; The <<big, ^ huge, ^ large, ^ tremendous, ^ >> <<hairy ^ slobbery ^ horned ^ clawed ^ >> <<brute ^ beast ^ monster>> twitches its <<leg ^ legs ^ paw ^ nose>>. ;; The <<big, ^ huge, ^ large, ^ tremendous, ^ >> <<hairy ^ slobbery ^ horned ^ clawed ^ >> <<brute ^ beast ^ monster>> <<shifts ^ rolls>> on its <<big, ^ huge, ^ large, ^ tremendous, ^ >> mattress."

We base the actions of the beast on the most friendly person in the area.

The scared level doesnt last long, so lets just leave one message:

  @set beast/scared_actions = "A tremendously large and hairy beast attempts to nervously (and almost comically) hide"

Concerned actions:

  @set beast/concerned_actions = "The <<big, ^ huge, ^ large, ^ tremendous, ^ >> <<hairy ^ slobbery ^ horned ^ clawed ^ >> <<brute ^ beast ^ monster>> <<is ^ seems>> concerned by your presence in the <<meadow ^ field>>. ;; The <<big, ^ huge, ^ large, ^ tremendous, ^ >> <<hairy ^ slobbery ^ horned ^ clawed ^ >> <<brute ^ beast ^ monster>> seems concerned. Maybe it's hungry. ;; The <<big, ^ huge, ^ large, ^ tremendous, ^ >> <<hairy ^ slobbery ^ horned ^ clawed ^ >> <<brute ^ beast ^ monster>> seems concerned and keeps its distance."

Interested actions:

  @set beast/interested_actions = "The <<big, ^ huge, ^ large, ^ tremendous, ^ >> <<hairy ^ slobbery ^ horned ^ clawed ^ >> <<brute ^ beast ^ monster>> seems <<curious ^ interested>> in $you(). ;; The <<big, ^ huge, ^ large, ^ tremendous, ^ >> <<hairy ^ slobbery ^ horned ^ clawed ^ >> <<brute ^ beast ^ monster>> seems curious about $you(). ;; The <<big, ^ huge, ^ large, ^ tremendous, ^ >> <<hairy ^ slobbery ^ horned ^ clawed ^ >> <<brute ^ beast ^ monster>> stands on its hind legs. ;; The <<big, ^ huge, ^ large, ^ tremendous, ^ >> <<hairy ^ slobbery ^ horned ^ clawed ^ >> <<brute ^ beast ^ monster>> <<stares at ^ watches ^ follows>> $you() with its <<large, ^ big, ^ >> yellow eyes."

Friendly actions:

  @set beast/friendly_actions = "The <<big, ^ huge, ^ large, ^ tremendous, ^ >> <<hairy ^ slobbery ^ horned ^ clawed ^ >> <<brute ^ beast ^ monster>> <<thunders ^ stomps ^ tramps ^ clomps ^ rumbles ^ rolls>> <<across the field ^ across the meadow ^ over>> wagging its backend<<, ^ as it seems>> happy to see $you(). ;; The <<big, ^ huge, ^ large, ^ tremendous, ^ >> <<hairy ^ slobbery ^ horned ^ clawed ^ >> <<brute ^ beast ^ monster>> <<thunders ^ stomps ^ tramps ^ clomps ^ rumbles ^ rolls>> <<across the field ^ across the meadow ^ over>> hoping to play with $you(). ;; The <<big, ^ huge, ^ large, ^ tremendous, ^ >> <<hairy ^ slobbery ^ horned ^ clawed ^ >> <<brute ^ beast ^ monster>> flops over in front of $you() wriggling <<its back ^ >> on the ground. ;; The <<big, ^ huge, ^ large, ^ tremendous, ^ >> <<hairy ^ slobbery ^ horned ^ clawed ^ >> <<brute ^ beast ^ monster>> <<thunders ^ stomps ^ tramps ^ clomps ^ rumbles ^ rolls>> <<across the field ^ across the meadow ^ over>> next to $you(). ;; The <<big, ^ huge, ^ large, ^ tremendous, ^ >> <<hairy ^ slobbery ^ horned ^ clawed ^ >> <<brute ^ beast ^ monster>> chases butterflies around the <<field ^ meadow ^ grass ^ flowers>>."

The ecstatic states are just a bit more than friendly.

  @set beast/ecstatic_actions = "The <<big, ^ huge, ^ large, ^ tremendous, ^ >> <<hairy ^ slobbery ^ horned ^ clawed ^ >> <<brute ^ beast ^ monster>> <<thunders ^ stomps ^ tramps ^ clomps ^ rumbles ^ rolls>> <<across the field ^ across the meadow ^ over>> to give $you() a sloppy <<kiss ^ lick>>. ;; The <<big, ^ huge, ^ large, ^ tremendous, ^ >> <<hairy ^ slobbery ^ horned ^ clawed ^ >> <<brute ^ beast ^ monster>> <<thunders ^ stomps ^ tramps ^ clomps ^ rumbles ^ rolls>> <<across the field ^ across the meadow ^ over>> wagging its backend as it seems <<very ^ >> excited to see $you(). ;; The <<big, ^ huge, ^ large, ^ tremendous, ^ >> <<hairy ^ slobbery ^ horned ^ clawed ^ >> <<brute ^ beast ^ monster>> <<thunders ^ stomps ^ tramps ^ clomps ^ rumbles ^ rolls>> <<across the field ^ across the meadow ^ over>> hoping to play with $you(). ;; The <<big, ^ huge, ^ large, ^ tremendous, ^ >> <<hairy ^ slobbery ^ horned ^ clawed ^ >> <<brute ^ beast ^ monster>> flops over in front of $you() happily wriggling on the ground. ;; The <<big, ^ huge, ^ large, ^ tremendous, ^ >> <<hairy ^ slobbery ^ horned ^ clawed ^ >> <<brute ^ beast ^ monster>> excitedly <<thunders ^ stomps ^ tramps ^ clomps ^ rumbles ^ rolls>> <<across the field ^ across the meadow ^ over>> next to you. ;; The <<big, ^ huge, ^ large, ^ tremendous, ^ >> <<hairy ^ slobbery ^ horned ^ clawed ^ >> <<brute ^ beast ^ monster>> <<happily ^ joyfully>> leaps into air. ;; The <<big, ^ huge, ^ large, ^ tremendous, ^ >> <<hairy ^ slobbery ^ horned ^ clawed ^ >> <<brute ^ beast ^ monster>> chases butterflies around the <<field ^ meadow ^ grass ^ flowers>>."

And the responses to being pet:

  @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."

I want to make sure that when someone new sees the beast, the see it hiding behind the grass…

  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?"
          }
      }
  }

Hints

This is an under construction sort of room, and isnt that interesting at the moment. Im not sure what sort of narrator could give a hint; a spider?

  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.        

Glittering Glade

To the east of the meadow, lets make a glade back inside the Forest:

  @teleport mp05

And we use the tunnel command this time:

  @dig Glittering Glade;mp19 : typeclasses.rooms.Room = east footpath into another forest;east;glade;e,west footpath to meadow;footpath;west;w;path

A description if they look east:

  @desc east = Looking at the forest on the east side shows a footpath illuminated by dancing glowing orbs.
  @detail orbs = The orbs swirl around in a circular pattern creating a mesmerizing vortex of light leading deep into the forest.

And a nice journey message to go east out of the forest:

  @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."

Before we label it, we follow east:

  @teleport mp19

And the description wont have day/night, but we can reference it:

  @desc here = The footpath ends in a beautiful glade. While the thick canopy above blocks <morning>the morning light</morning><afternoon>the daylight</afternoon><evening>the glowing twilight</evening><night>any light that might show</night>, 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.
  @detail orbs = The orbs swirl above illuminating the glade.
  @detail trees = Ancient trees surround this glade like walls.
  @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.

A description if they look back towards the west:

  @desc west = The footpath leads out of the forest to a meadow.

And a nice journey message to go east out of the forest:

  @set west/traverse_msg = "You followed the illuminated footpath until you exit the forest into a meadow."

Assume the Goblin tester is in Frog Meadow, so lets head east:

  send "east\n"
  expectit "Glittering Glade"

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:

  @create/drop stone table:typeclasses.puzzles.StoryCube

And a description must be careful with the newlines to make the verse work:

  @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.

Can we read it?

  @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."

And some flavor that offers a hint to the answer of the riddle, to combine Water and Earth:

  @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.

The table shouldnt be steal-able:

  @lock table = get:false()
  #
  @set table/get_err_msg = "That table is much too big for you to lift."

Answer the riddle to be able to go to the Tavern:

  @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"}

Assume the Goblin tester is in Frog Meadow, so lets head east:

  send "get table\n"
  expectit "too big"

Hints

Shall we bring back Bubba?

  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

And lets not test everything here:

  send "hint\n"
  expectit "To get through that"

  send "hint password\n"
  expectit "Don't abandon hope."

Tavern: Wyldwood Bar

This now needs to be transferred from the mud-rpg file.

  @dig Wyldwood Bar;mp10 = blue door;door,blue door to forest;leave;outside

Blue Door

The door in the tree connects to the Tavern that may have already been created:

  @open blue door;door,blue door to forest;leave;outside = Wyldwood Bar

And describe it:

  @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.

The dock is locked:

  @set blue door/err_traverse = "The door seems locked...or at least, won't budge."

Open-able if you have the correct tag:

  @lock blue door = traverse:tag(open_blue_door)

Make sure it is locked:

  send "blue door\n"
  expectit "The door seems locked"

And give the password to open the blue door:

  send "say mud\n"
  expectit "You hear an audible click"

  # Need to wait for the tagging magic to take effect:
  sleep 1

Lets have an interesting phrase entering the bar …

  @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."

And test to make sure we can get to the bar…

  send "blue door\n"
  expectit "Wyldwood Bar"

Inside the Bar

Lets hop into the Bar in order to work it over:

  @tel mp10

Describe it:

  @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.

And some ambiance.

  @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.
  @detail boughs;bough;branches;canopy = The branches of the black elder |Ytrees|n sport slender leaves and cluster of elder |Yberries|n.
  @detail berries;berry = The cluster of berries from the |Ycanopy|n above are high and out of reach.
  @detail lights;light;orbs = Hundreds of small, dancing orbs float around the |Ycanopy|n above the room, casting a soft glow of light.

And describe the door leaving the bar:

  @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?

Lets have an interesting phrase entering the bar …

  @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."

Cocktails

Lets create a sign for the list of cocktails:

  @create/drop sign above the bar;sign;list:typeclasses.readables.Readable

And the description:

  @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.

Might as well allow the user to read it:

  @set sign/inside = "|wCocktails|n|/ - Moonlit Mirage|/ - Puck's Revenge|/ - Glimmering Gossamer|/ - Whimsical Willow|/ - Charmed Chalice|/ - Enchanted Elixir|/ - Sylvan Serenade|/ - Brambleberry Bliss|/ - Twilight Tonic|/"

And lock down the sign:

  @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."

Lets test out the sign:

  send "read sign\n"
  expectit "Cocktails"

  send "get sign\n"
  expectit "impossible to remove"

Needs the ability to create a drink.

  @set bartender/currentgame = "session1"

The preps come in three forms with how detailed we want to spam the room.

  @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 >>."
      ]
    }
  }
Moonlit Mirage

A shimmering drink that changes color with each sip, garnished with edible glitter and a twist of lemon

  gm The bartender grabs a pixie flying by and shakes the glitter from its wings into the glass.
Pucks Revenge

A vibrant concoction of fruit juices and sparkling fairy dust, served in a glass shaped like a flower.

  cast donkey on char
Glimmering Gossamer

A delicate blend of elderflower liqueur and sparkling wine, adorned with a butterfly-shaped ice cube.

  gm The bartender uses a butterfly net to catch an ice cube that he then places in the glass.
Whimsical Willow

A herbal infusion of gin, rosemary, and elderberry, served with a sprig of fresh mint and a splash of tonic.

  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.
Charmed Chalice

A mysterious potion that glows softly, made with enchanted spirits and a hint of honey, served in a chalice that changes shape.

  gm Ghostly apparitions appear in the air, as the bartender grabs one, twists it, and adds a drop of ectoplasm to the drink.
Enchanted Elixir

A deep blue drink with hints of blueberry and a touch of magic, served with a glowing ice sphere.

  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 =
Sylvan Serenade

A melodic blend of apple cider and spiced rum, garnished with a cinnamon stick and a slice of star fruit.

  gm The bartender plays a flute as the jars and ingredients line up and pour themselves into a cocktail shaker.
Brambleberry Bliss

A sweet and tart mix of brambleberries and gin, served over crushed ice with a sprinkle of edible flowers.

  gm The bartender garnishes the cocktail with a flower pulled from a pot on the bar. The plant immediately wilts and drops away.
Twilight Tonic

A dark, mysterious drink made with blackcurrant and tonic water, served with a slice of lime and a hint of mint."

  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.

Bartender

Return to the Bar …

  @teleport Wyldwood Bar

A haughty elf named Elendil

  @create/drop Bartender;barkeep;Elendil: typeclasses.chatbots.Bartender
  # @update Bartender = typeclasses.chatbots.Bartender

And all the RP system stuff:

  @set bartender/gender = "male"
  py bt = self.search('Bartender'); bt.sdesc.add('blonde elf');  bt.db.pose = 'working behind the bar'

And default pose:

  @pose default bartender = working behind the bar

And an un-puppeted pose:

  @set bartender/pose_sleep = "fiddling with something behind the bar"
  #
  @set bartender/pose_default = "working behind the bar"

And a good description:

  @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.

And give him the powers he deserves:

  @perm Bartender = Admin

As well as the automation:

  py me.search("bartender").backstory("tavern")

And lets make him initially invisible:

  @set Bartender/hidden_tag = "hidden_bartender"
  #
  @lock Bartender = view:tag(hidden_bartender)

Lets see if we can talk the bartender into a drink:

  # 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"

Helpful commands:

  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.
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?

  @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"
  @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."

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

  @set bartender/sayto = {r"\bthanks?( you)?": "gm The << bartender ^ barkeep >> << mumbles ^ mutters ^ softly replies >> << back ^ >> to {1}, \"You're << very ^ >> welcome.\""}
  @set bartender/say = {r"\bthanks?( you)?.*bar(tend|keep)": "gm The << bartender ^ barkeep >> << mumbles ^ mutters ^ softly replies >> << back ^ >> to {1}, \"You're << very ^ >> welcome.\""}

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

Lets convert the Bartender to a Chatbot using tavern.md. This way, talking to the Bartender answers from everyone.

  @set bartender/personality = "tavern"
  #
  @set bartender/personality_file = "personalities/tavern.md"
Hide and Seek

First create a number of magic rings equal to the number of players, minus one:

  @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_

And create a monocle:

  @create monocle:typeclasses.things.MagicMonocle
  #
  @desc monocle = Allows you to see past magical illusions.  |/Command: |gpeer <object>|n
  #
  give monocle to _char_

Reset the game:

  # Who has the monocle
  py me.search('monocle', typeclass="typeclasses.things.MagicMonocle", global_search=True).reset_counts()

Get the scoreboard:

  # Who has the monocle
  py me.search('monocle', typeclass="typeclasses.things.MagicMonocle", global_search=True).report_score()

Need a global clock, right?

  @create clock:typeclasses.things.GlobalAlarmClock
  #
  @desc clock = Strange round clock with four hands and twenty symbols.

Need a channel to chat about the game:

  @channel/create Hide and Seek Game;hide;game = Messages to people playing the Hide and Seek game
  #
  # Others would type:
  # channel/sub game

Start the hiders …

  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 <char> = here

Bowl of Candy

Gives out candy, as there is a never-ending bowl of them on the bar. Gotta have something to munch on.

  @create/drop bowl of candies;bowl;candy : typeclasses.consumables.Producer

With a description:

  @desc bowl = A large white daisy forms a bowl holding a collection of colored hard candies.

The bowl shouldnt be steal-able, but a get on a Producer now calls it do_make function:

  @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."

Hold off on the viewing:

  @set bowl/hidden_tag = "hidden_bowl"
  #
  @lock bowl = view:tag(hidden_bowl)

We have to have the bowl of candy describe what it makes:

  @set bowl/make_name = "candy"

Including some plural aliases:

  @set bowl/make_aliases = ["candies"]

And a verb when they get the consumable:

  @set bowl/make_verb = "$conj(grab) a"
  #
  @set bowl/make_note = " from the bowl"

This one is optional as it defaults to Consumable:

  @set bowl/make_class = "typeclasses.consumables.Consumable"

And the bowl needs to know the description of the Consumable, so that it can attach that:

  @set bowl/make_desc = "Bright << red ^ orange ^ yellow ^ blue ^ violet >> candy with << flecks ^ spots ^ stripes >> of << red ^ orange ^ purple ^ violet ^ orange >>."

How many candies are there when you pick them?

  @set bowl/make_amount = 1

How many candies do you eat at a time:

  @set bowl/make_eat_amount = 1

Messages can be randomly selected:

  @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.",
       ]

And a brief test … and since this is the last thing in the bar, lets have our test account leave as well.

  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"

Mellow Marsh

The river from the flows into a marsh:

  @teleport mp05
  #
  @dig Mellow Marsh;mp08 :typeclasses.rooms_weather.TimeWeatherRoom = south to marsh;south;marsh;s,north to meadow;n;north;meadow

And look south should show:

  @desc south = Looks like the river spreads into a marsh. Is that a hut you can see?

Describe the muddy marsh:

  @set south/traverse_msg = "The ground gets muddier and harder to walk the further into the marsh you go..."

And a description of the marsh:

  @teleport mp08
  #
  @desc here = The river spreads into a muddy marsh full of |Ygrass|n and tall, white-topped |Yreeds|n. <morning>Colorful |Ybirds|n in the sparse tree surrounding the marsh yell out a loud chorus.</morning> <afternoon>Purple herons and other marsh |Ybirds|n hunt in the tall swamp grass.</afternoon> <evening>Glowing |Yfireflies|n create a synchronized light show over the swamp grass in the deepening dusk.</evening> <night>Giant pink and purple |Ymoths|n flutter over the dark flowers.</night>|/A small |Yhut|n, perched on three |Ystilts|n to keep it dry, stands in middle of the slough.

And a new state when the house is bound:

  @desc/bound here = The river spreads into a muddy marsh full of |Ygrass|n and tall, white-topped |Yreeds|n. <morning>Colorful |Ybirds|n in the sparse tree surrounding the marsh yell out a loud chorus.</morning> <afternoon>Purple herons and other marsh |Ybirds|n hunt in the tall swamp grass.</afternoon> <evening>Glowing |Yfireflies|n create a synchronized light show over the swamp grass in the deepening dusk.</evening> <night>Giant pink and purple |Ymoths|n flutter over the dark flowers.</night>|/|/A pissed-off looking |Yhut|n, with its lasso'd stilt-like legs, struggles against its bounds in the middle of the slough.

And look north should show:

  @desc north = The meadow to the north looks easier to walk around.

Describe the muddy marsh:

  @set north/traverse_msg = "The ground gets drier and easier to walk as you approach the meadow..."

Details for a more immersive experience:

  @detail stilts;stilt = Those stilts are scaly...and clawed...and, are they chicken legs? How expected.
  @detail birds = Birds of every color on the rainbow and beyond fly and squawk around you, but keep their distance.
  @detail moths;moth = On closer inspection, the moths are really |Ysprites|n playing a strange chasing game.
  @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.
  @detail fireflies = A passing firefly shows it to actually be a |Ypixie|n holding two colorful lanterns.
  @detail pixie;pixies = The pixies ignore you as their choreography keeps them focused on their dance.
  @detail grass = Guess this kind of grass doesn't mind the wet environment.
  @detail mud = Pretty brown and sticky.

And we test this normal state:

  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."

Lets change and test this new the state (granted, we define the hut later):

  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

Finally, lets attempt to describe a prompt for some generative AI images:

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.

Muddy Water

As a future idea of making potions, we can collect muddy water, which needs to be turned to wine.

  # @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."]

And test looking at it:

  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."

Purple Heron

Create a puppet of the bird hunting frogs and pixies. :-D

  @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."

What data file of responses should we use?

  @set heron/data_file = "npcs.txt"
  #
  @set heron/speech_vocalizations = ["says", "croaks", "squawks"]

Note that we give him a male gender:

  @set heron/gender = "male"

Prefix article?

  @set heron/article = "The"

And a good description that I can rework:

  @desc heron = Shades of violet and purple adorn the feathers of this majestically tall heron, that stalks the marsh |Ygrass|n, hunting small critters.

Lets turn it on:

  py me.search("heron").backstory("heron")

Since it is an NPC it has certain mutterings it can do:

  @set heron/muttering_file = "jethro_tull_songs.txt"
  #
  @set heron/muttering_gap = 7
  #
  @set heron/muttering_interval = 360  # Little over 3 minutes
  @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}\"|/",
    ]

And add the absent-minded singing script:

  @script heron = typeclasses.scripts.Muttering

Test that the heron can talk:

  send "say Hello there, big bird.\n"
  expectit "heron"

  send "get heron\n"
  expectit "flies out of reach"

Ten-foot Poles

The reed can be a producer that makes ten foot poles … needed to get into the hut.

  @create/drop lot of tall reeds;tall reeds;reeds: typeclasses.consumables.Producer

With a description:

  @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.

We have to have the reeds describe what it makes:

  @set reeds/make_name = "ten-foot pole"

And a verb when they get the consumable:

  @set reeds/make_verb = "$conj(pluck) and $conj(shape) a"

And a commentary:

  @set reeds/make_note = " from a marsh reed."

They shouldnt be able to make too many poles:

  @set reeds/make_limit = 1
  #
  @set reeds/make_limit_msg = "You can't make more poles when you are already holding one."

A ten-foot pole should act like a stick:

  @set reeds/make_class = "typeclasses.things.Stick"

And the reeds needs to know the description of the Consumable, so that it can attach that:

  @set reeds/make_desc = "A long pole shaved from a marsh reed."

How much is there when you pick them?

  @set reeds/make_amount = 1

And lets test that we can get a pole:

  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"

Pixie Dust

Part of the Alchemist Path, we use pixie dust to create a /git/howard/moss-n-puddles/src/commit/b63cb4c74d0f58304b5d5986ffb81f3cabd76881/Trippy%20Potion.

We put this quote in the book:

Ive noticed Pixies often dance in the marshlands to the East, but are often invisible except in the evenings. Ive 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.

And create it here in the Marsh:

  # @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)

And test that we cant see it now:

  dont_expect "You notice" "pixie dust"

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.

  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.

Trampolis Hut on Stilts

  @teleport mp08
  #
  @dig Homey Hut;mp09 = hut on stilts;hut,leave;outside;marsh

And describe it as hut:

  @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.

Lets 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:

  @lock hut on stilts = traverse:tag(enter_hut_nope, mp)

Lets add an alias:

  @alias hut on stilts = hut
  @set hut on stilts/err_traverse = "Upon approaching the hut, the hut scurries away on its stilt-like legs."

And we need to create a second exit:

  @open rope-bound hut = Homey Hut

Lets add an alias:

  @alias rope-bound hut = hut

And describe it:

  @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.

If the other exit is here, you just need the pole:

  @lock rope-bound hut = traverse:holds('ten-foot pole')

And a good reason why you need the pole:

  @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."

If you do figure out how to get through the hut:

  @set rope-bound hut/traverse_msg = "You use your pole to vault yourself up through the door of the hut..."

Lets put this second exit away until the rope calls it:

  @teleport/tonone rope-bound hut

We have a rope and the ten-foot pole, lets see if we can get in:

  send "use rope on hut\n"
  expectit "Something tells you that the rope won't last for long."

  send "hut\n"
  expectit "Homey Hut"

Inside Trampolis Hut

Lets go inside to decorate:

  @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.

And describe leaving:

  @desc leave = From the doorway, you see the marshland below.
  @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."

And the details:

  @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.
  @detail jars = Sealed jars of fruits, vegetables, herbs and spices.

Chair

A chair to sit while working

  @create/drop chair:typeclasses.sittables.Sittable

How descriptive:

  @desc chair = A chair next to the table.

Cant steal this chair either:

  @lock chair = get:false()

Lets do a funnier message:

  @set chair/get_err_msg = "Stop trying to steal everything not nailed down."

And test this out;

  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."

Jars

Every time we look at a jar, we see something else … that we cant take. This creates ambiance without adding too much complexity?

  @tel/quiet Homey Hut
  #
  @create/drop assortment of jars;jars;jar: typeclasses.puzzles.Changling

Cant get them:

  @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?\""

And the generate description:

  @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 = ""

And now for a list of the contents:

  @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.",
       )

How can we test this cool feature?

  send "look jar\n"
  expect -re "You look at one.*labeled"

Herbs

Like the Jars, the herbs return a different response each time they are viewed.

  @create/drop collection of herbs;herbs;herb: typeclasses.puzzles.Changling

While the skull protects the jars, we will have the demon stop the herbs from being pinched.

  @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."
  @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 >>."

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.

  @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.",
       )

Bag of Mermaid Tears

  @create/drop couple of bags of dried Mermaid Tears;bags;bag: typeclasses.consumables.Producer

With a description:

  @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

We have to have the bush describe what it makes:

  @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)

Talismans

To give some character, we create some interesting art that decorates this hut.

  @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.
Horned Wolf Skull

For each talisman, we could create an object, but it wouldnt be able to be taken, and instead of “cant find skull”, we could give a better error message.

  @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)

And test it:

  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."
Demon Carving

Perhaps the carving is actually the maid or something that could give hints.

  @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)

And test it:

  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."
Reed Sculpture

The reeds should give a subtle hint to something that could be spoken aloud.

  @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)

And test it:

  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."

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:

  py timed_script = evennia.create_script(key="Create Horns",
                                          typeclass='typeclasses.scripts.CreateHorns',
                                          interval=600,
                                          start_delay=False,
                                          autostart=True,
                                          attributes=[("destination", here)] )

Torches

The reed can be a producer that makes ten foot poles … needed to get into the hut.

  @create/drop a bucket of torches: typeclasses.consumables.Producer

With a description:

  @desc bucket = A tall wood bucket full of resin-coated torches.

We have to have the bucket describe what it makes:

  @set bucket/make_name = "torch"

And a verb when they get the consumable:

  @set bucket/make_verb = "$conj(take) a"

And a commentary:

  @set bucket/make_note = " from the bucket"

The torches are special in that they last longer.

  @set bucket/make_class = "typeclasses.lightables.Torch"

And the bucket needs to know the description of the Consumable, so that it can attach that:

  @set bucket/make_desc = "Made from marsh grass and reeds."

How much is there when you pick them?

  @set bucket/make_amount = 1

Lets get two:

  send "get torch\n"
  expectit "You take a torch from the bucket."

  send "inv\n"
  expectit "Made from marsh grass"

Trampoli the Witch

Create a puppet of the lady that owns the hut.

  @create/drop Trampoli;old lady: typeclasses.chatbots.Witch
  # @update Trampoli = typeclasses.chatbots.Witch

Note that we give him a male gender:

  @set old lady/gender = 'female'

Work around the pose bug:

  @py bt = self.search('old lady'); bt.sdesc.add('old lady'); bt.db.pose = 'playing with a deck of cards'

Lets set this Chatbot to use witch.md.

  @set bartender/personality = "witch"
  #
  @set bartender/personality_file = "personalities/witch.md"

And some poses:

  @set old lady/pose_sleep = "napping soundly in bed on the upstairs loft"
  #
  @pose default old lady = playing with a deck of cards

And a good description that I can rework:

  @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.

And an un-puppeted, sleeping, description:

  @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."

If I do this, then she cant really be puppeted.

  @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?\""

And the old sleeping lady …

  @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"

Turn it off when needed.

  @set old lady/arrive = None

Perhaps … eventually, we can give her a gift, and shell allow the character to stay for tea. But then she would need to talk and interact. LLM?

  @script old lady = typeclasses.chatbots.TravelingNPC

Trampolis Tarot Deck

Ive been wanting this woman to be able to put out a spread of Tarot-ish cards to entertain others.

Mist Horn

The CreateHorns script will generate a horn. Lets have our Goblin tester get it:

  send "look horn\n"
  expectit "this curved horn"

  send "get horn\n"
  expectit "You pick up a horn"

Hints

Both the skull and the wood carving of a small daemon should be good narrators:

  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.        

And we can test these hints:

  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"

At this point, we need to get our testing character where we can migrate them over to the Lazy Dock.

  send "leave\n"
  expect "Mellow Marsh"

  send "north\n"
  expectit "Frog Meadow"

  send "west\n"
  expectit "Grove of the Matriarchs"

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:

  @teleport mp01

And tunnel to the dock:

  @dig Lazy Dock;mp06 :typeclasses.rooms_weather.TimeWeatherRoom = south to dock;south;s,north to forest;north;n;footpath

With a message about leaving the trees so that I dont have to repeat that in the room description:

  @set south/traverse_msg = "You follow a path down and step out from under giant trees to see the sky."

And a description:

  @desc south = You see a dock on a lavender sea... Is that a comfortable-looking chair you can |gsit|n on?

And move ourselves there:

  @teleport mp06

And describe this.

  @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.

And details?

  @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?

And describe the walk back into the forest:

  @set north/traverse_msg = "You walk up a path and back into the forest of giant trees."

And a description:

  @desc north = This path leads into the forest of collosal trees.
  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."

Lavender Sea

Well get ready for making potions by allowing one to collect water from all the places, like the salty sea:

  # @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."]

And well test looking at it:

  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."

Chair

A nice chair to sit on the dock by the bay, watching the clouds as they drift away.

  @create/drop chair;lounge chair:typeclasses.sittables.Sittable

How descriptive:

  @desc chair = A cushioned wood chair of craftsmanship.|/Looks good for being out in the weather.

Cant steal this chair either:

  @lock chair = get:false()
  #
  @set chair/get_err_msg = "It's way too heavy for you to lift."

Lets see if we can sit down:

  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."

Fishing Pole

It we are going to sit on a chair by the dock, why not go fishing?

  @create/drop fishing pole;pole:typeclasses.fishing.FishingPole

With a description:

  @desc pole = A nice pole for catching fish. It even has a hook, and is ready to go!

And tether it to the Dock, which we need to reset if the ID numbers ever change.

  @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?"

Issues?

  @teleport/quiet fishing pole = Lazy Dock

What about some details:

  @detail hook;bait = One of those shiny lures, made from gold coins. Curiouser. Seems you don't need to bait this hook.

Lets see if we can fish:

  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."

Sign

Need to make the fishing pole “stay” at the Dock. Maybe with a message about sticking around for the next person.

  @create/drop sign:typeclasses.readables.Readable

Should the description also be the message?

  @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

Might as well allow the user to read it:

  @set sign/inside = "Fish at your own annoyance. Please return pole when finished."

And lock down the sign:

  @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."

Test if it is readable:

  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"

Raven

Here for hints … and a bit of a distraction.

  @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

Lets load the goodies:

  py me.search("raven").backstory("raven")

Hints

We should keep the raven puppet here to give out the hints.

  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.        

How much do we want to test?

  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"

Sandy Shore

Could we extend the sea from the The Dock down a shore:

  @teleport/quiet mp06
  #
  @dig Shore;mp15 :typeclasses.rooms_weather.TimeWeatherRoom = south along shore;shore;south;s,north to dock;north;n;dock

With a message about leaving the trees so that I dont have to repeat that in the room description:

  @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."

And a description:

  @desc south = You see a shack down along the sandy shore.

And move ourselves there:

  @teleport mp15

And describe the walk back to the dock:

  @set north/traverse_msg = "You walk along the shore of the lavender sea back to the dock."

And a description:

  @desc north = The sandy shore to the north ends at a dock, jutting into the lavender sea.

And describe this.

  @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.

And details?

  @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.

What sort of hints should be here?

  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.        

And test the details:

  # 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"

Sand

Part of the Alchemist Path, we use sand as an ingredient in a potion we want to make.

  @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)

And testing:

  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"

Pine Flowers

Part of the Alchemist Path, we use pine flowers to create a potion TBD, and feed the stoat in Dabblers House.

  @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?

Sign

We make the sign as an “object” for others to read:

  @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()

And testing:

  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."

Salty Shack

Lets keep this pretty empty.

  @teleport/quiet mp15
  #
  @dig Salty Shack;mp16 = locked door;door;inside,door to outside;door;outside;leave;exit

And described the exit:

  @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."

And lock the exit:

  @lock door = traverse:tag(open_shack_door, mp)
  #
  @set door/err_traverse = "The door is obviously locked."

Generic description of the insides of this house:

  @teleport/quiet mp16
  #
  @desc here = The shack is curiously bare and devoid of all personality.

And describe the exit:

  @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."

While we cant get into the shack, we can test that:

  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."

Back to the Grove:

  send "north\n"
  expectit "Lazy Dock"

  send "north\n"
  expectit "Grove of the Matriarchs"

Grotto

Return to the forest:

  @teleport mp01

Lets travel west along the path in the forest:

  @dig Grotto;mp04 :typeclasses.rooms_weather.TimeWeatherRoom = west footpath;west;w,east footpath;east;e;path;footpath

With a nice message about wandering:

  @set west/traverse_msg = "You meander between mossy tree roots along a footpath for a while until it ends in a grotto."

And a description:

  @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.

Jump into the new room:

  @teleport mp04

And describe the tree and the door:

  @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.

A description if they look east:

  @desc east = A winding footpath leads through the forest of giant trees.

And a nice journey message to go east in of the forest:

  @set east/traverse_msg = "The mossy tree roots makes for an interesting path..."

And extra things to see:

  @detail trees;tree = The trees in this forest are massive, but a smaller tree has a red door. Must lead to a closet!

And the bridge:

  @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.

And the cabbages? And ferns?

  @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.

Lets move our testing character to this room to finish this rooms tests:

  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."

And generate an image:

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.

Berry Bush

The berry bush is a producer that makes berries, which is something to eat and use to feed the wildlife.

  @create/drop berry bush;bush : typeclasses.consumables.Producer

With a description:

  @desc bush = A bush laden with bright red brambleberries. You've heard that they are good.

We have to have the bush describe what it makes:

  @set bush/make_name = "berry"

Including some plural aliases:

  @set bush/make_aliases = ["berries", "brambleberry", "brambleberries"]

And a verb when they get the consumable:

  @set bush/make_verb = "$conj(pick) a"

This one is optional as it defaults to Consumable:

  @set bush/make_class = "typeclasses.consumables.Consumable"

And the bush needs to know the description of the Consumable, so that it can attach that:

  @set bush/make_desc = "Bright red with flecks of orange, about grape-sized"

How many berries are there when you pick them?

  @set bush/make_amount = 1

How many berries do you eat at a time:

  @set bush/make_eat_amount = 1

We can either have a single eat message:

  @set bush/make_eat_msg = "Sweet and slightly tart. <<Delicious ^ Tangy ^ Mmmm>>."

Or many messages that can be randomly selected:

  @set bush/make_eat_msgs = [ "Sweet and slightly tart.", "<<Delicious ^ Tangy ^ Mmmm>>.", "Ooo...quite sour.", "A bit ripe, but still good.", "So sweet with a hint of <<orange ^ maple>>." ]

Let the user know when they consumed them all.

  @set bush/make_finish_msg =
  #"Those were <<delicious ^ great>>."

Can we get and eat them?

  send "pick berries\n"
  expectit "You pick"

  send "eat berry\n"

  send "get berry\n"
  expectit "You pick"

  send "eat berry\n"

Spring Water

Part of the Alchemist Path, we use spring water to create a /git/howard/moss-n-puddles/src/commit/b63cb4c74d0f58304b5d5986ffb81f3cabd76881/Trippy%20Potion.

  # @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."]

Test that we cant get it … without a bottle.

  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."

TODO: What happens if we drink it?

Knocker

The knocker has the ability to make the door “open” using on_traverse hooks?

Most of the work of the knocker is in the Python code:

  @create/drop knocker: typeclasses.things.Knocker

Lets make the knocker be a surprise.

  @set knocker/hidden_tag = "hidden_knocker"
  #
  @lock knocker = view:tag(hidden_knocker)

The knocker shouldnt be steal-able:

  @lock knocker = get:false()
  #
  @set knocker/get_err_msg = "It appears firmly attached to the door."

The description is dynamic from the Python code, so we dont need this statement:

  @desc knocker = The brass face looks at you and winks.

In order for us to knock on the door, we have to give a knock command to the room.

  @set knocker/room_to_msg = "mp03"

The python object has all the knowledge about knocking and whatnot, but we should have the descriptions here. First, what the knocker reads:

  @set here/knock_msg = "You grab the ring"

Then, what the others in the room read:

  @set here/knock_other_msg = "grabs the ring and knocks firmly on the door."

And an error message if the ring is not with the goblin:

  @set here/knock_err_msg = "This door knocker is defective, as it doesn't have a ring to...er, do the knockin'."

Actually, these @set commands do nothing, as all the messages are in the code.

Can we knock on the door?

  send "knock\n"
  expectit "You grab the ring"

The rest of testing the knocker will come later…

Ring

Since we can remove the ring, lets create it:

  @create ring: typeclasses.things.Ring

And give it an alias:

  @name ring = brass ring;ring

And a description:

  @desc ring = A brass ring that should be in the door knocker's mouth. How else are you going to knock on a door?

Although we can interact with it, lets not make it obvious that it is an object:

  @set ring/hidden_tag = "hidden_ring"
  #
  @lock ring = view:tag(hidden_ring)

And lets make it so we can take that:

  @set ring/can_take = True

Lets tether the ring to the knocker …

  @lock ring = tethered:id(knocker)
  #
  @set ring/tethered_msg = "You put the ring back in the knocker's mouth. \"Mmmuufffmm,\" says the door knocker."

And put the ring in the knockers mouth:

  @teleport/quiet ring = knocker

Might be difficult to test the interaction with the knocker?

  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."

Hints

The berry bush should bring in birds and other pickers, right?

  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 <<little ^ >> 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.

And lets not test everything here:

  send "hint\n"
  expectit "So try to talk to it."

Cozy House

Add the Python special-ness for this room:

  @dig Cozy House;mp03: typeclasses.rooms.DabblersRoom = red door;door;inside,outside;leave

Lets get our testing character inside, shall we?

  send "inside\n"
  expectit "Cozy House"

Red Door

The door description should match the artwork on the website:

  @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.

This exit should be special. First, it is locked unless a character has the open_red_door tag.

  @lock door = traverse:tag(open_red_door, mp)

Needs a message why one cant walk through:

  @set door/err_traverse = "The door seems locked."

If you do figure out how to get through the door:

  @set door/traverse_msg = "You stoop as you step through the doorway..."

We described the knocker earlier, as it holds the virtual key for unlocking the door. But looking at the door, should show the knocker too.

  @set door/hidden_tag = "hidden_knocker"

Inside

Fix the inside of the “House”:

  @teleport mp03

And the best description ever that we dont use:

  @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.

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.

  @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."

And details:

  @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.

Touch up the exit:

  @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..."

Add some initial ambiance:

  @set here/arrive = "45 ;; gm The rain << patters ^ chatters ^ drums >> against a window << sill ^ pane >>. Nice to be << indoors ^ inside >>."

To test, lets make sure we show the final description:

  expectit "The subtle smell of wood smoke, incense and fresh-baked scones"

Granted, none of the dynamic description will work until we create the /git/howard/moss-n-puddles/src/commit/b63cb4c74d0f58304b5d5986ffb81f3cabd76881/Fire.

Generate a picture:

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.

Tapestry Story

The tapestry should tell our creation myth.

  @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.

Make sure we can see all of this.

  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"

Fireplace

And a fire in the fireplace is a type of pet, since we can feed it:

  @create/drop fireplace;fire;embers : typeclasses.pets.Fire

How about some aliases:

  @lock fire = get:false()

And a description that will be overridden:

  @desc fireplace = A stone fireplace with a carved wooden mantel supporting small |Ypictures|n, some |Ybooks|n and a black |Ystatue|n.

Since we mentioned some details, we better mention them:

  @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.

This reference in this detail is obviously, only for me:

  @detail statue = A small, black statue of a salamander curled around a book, engraved with a title, "Seeing Stones".

I imagine a giant picture over the fireplace … need to do something interesting with it.

  @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.

Accessing it directly:

fire = me.search("fire"); fire.ndb.hunger_level = 50; print(fire.ndb.hunger_level)

We need to fix it so that feed fire just works.

  send "get fireplace\n"
  expectit "You can't get that."

  send "feed fire\n"
  expectit "fire in the fireplace"

Wood Rack

Need a way to produce wood for the fireplace.

  @create/drop wood rack;log rack;log holder;wood holder;wood;log :typeclasses.consumables.Producer
  @desc wood rack = Steel and leather hammock for a small pile of cut logs, perfect for |gfeed|ning to the |gfire|n.

We have to have the wood rack describe what it makes:

  @set wood rack/make_name = "log"
  #
  @set wood rack/make_aliase = ["wood"]

And a verb when they get the consumable:

  @set wood rack/make_verb = "$conj(get) a small"

And a commentary:

  @set wood rack/make_note = " from the wood rack"

This one is optional as it defaults to Consumable:

  @set wood rack/make_class = "typeclasses.things.Wood"

And the wood rack needs to know the description of the Consumable, so that it can attach that:

  @set wood rack/make_desc = "Cut wood, perfect for feeding to the fire."

How much is there when you pick them?

  @set wood rack/make_amount = 1

Hide from immediate view:

  @set wood rack/hidden_tag = "hidden_woodrack"
  #
  @lock wood rack = view:tag(hidden_woodrack)

And testing this:

  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"

Knickknacks

What sort of non-books do we want to look at?

  @create/drop few trinkets;trinkets;trinket;knickknacks;knickknackery;doodads;doodad;knick-knacks: typeclasses.things.Trinket

Lets not let anything of this sort be picked up:

  @lock trinkets = get:false()
  #
  @set trinkets/get_err_msg = "While interesting, perhaps you shouldn't steal Dabbler's personal collection."

Lets make sure a new person always sees a trinket:

  send "look trinkets\n"
  expectit "."

Magic 8 Ball

One trinket we might create to give to people as a souvenir.

  @create crystal ball;ball;magic ball: typeclasses.things.CrystalBall

And its description:

  @desc ball = A glass orb of billowing mist and patterns. |/When the << ^ swirling blue patterns ^ spinning octarine swirls ^ revolving stars>> clear, the glass reads,

And we should hide it:

  @set ball/hidden_tag = "hidden_ball"
  #
  @lock ball = view:tag(hidden_ball)
  #
  drop ball

Bookshelf

Since we mentioned shelves of books, we should create a Producer that makes a random book.

  @create/drop number of bookshelves;bookshelf;shelves;bookcase;books;book:typeclasses.readables.Bookshelf

With a good description:

  @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.

Most of the work is actually in the creation of the individual books, in the Python code in the Books class.

Can we do the song and dance of getting a book? Should we simplify this?

  # 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"

Chairs

And the chairs is a plural location to sit, allowing anyone to sit down.

  @create/drop overstuffed chairs:typeclasses.sittables.Sittables

Add aliases afterwards:

  @alias overstuffed chairs = chairs;chair
  # This only works if we make it plural:
  @set overstuffed chairs/plural = True

And the description:

  @desc chairs = A few, dark leather, overstuffed chairs, each with a soft, colorful blanket and pillow. An invitation for a cozy nap.

Cant steal em:

  @lock chairs = get:false()
  #
  @set chairs/get_err_msg = "It's way too heavy for you to lift."

And textual descriptions the object can use:

  @set chairs/adjective = "in"
  #
  @set chairs/article = "the"
  #
  @set chairs/singular = "an overstuffed chair"
  #
  @set chairs/extra = "This feels << ^ very ^ quite>> <<nice ^ cozy ^ comfortable>>.|n"

Since we have unlimited seating, sitting down is always available:

  send "sit\n"
  expectit "You sit in "

Dabblers Butterfly

This golden NPC always hangs around our gnome, recording all that transpires.

  @create/drop golden butterfly;butterfly;recorder: typeclasses.things.Scribe

And describe it:

  @desc butterfly = A flying insect with iridescent wings that flicker a golden hue. Is it carrying a tiny a notepad and pen?

Lets make it hidden for the moment:

  @lock butterfly = view:tag(hidden_butterfly)

And lets not let anyone pick it up:

  @set butterfly/get_err_msg = "It quickly flutters away, only to land a few feet away."

Lets set the location where it will store its transcripts:

  @set butterfly/transcripts_path = 'transcripts/cozy-%Y-%m-%d.html'
  #
  @set butterfly/header_file = "transcripts/cozy-header-template.html"

Hints

While this room has a lot of stuff, I dont feel we need to drop a lot of hints … just on the candle sconce:

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.      

And lets not test everything here:

  send "hint\n"
  expectit "You are in a cozy and casual place"

Character: Dabbler

My characters should be NPCs, so they can stick around if Im not logged in.

  @create/drop Dabbler;gnome;old gnome: typeclasses.puppets.Puppet

Note that we give him a male gender:

  @set gnome/gender = 'male'

Work around the pose bug:

  py bt = self.search('gnome'); bt.sdesc.add('old gnome'); bt.db.pose = 'smiling at you'

Lets give him a number of alternate names for the Recorder (mostly):

  @set gnome/alt_names = ["The old gnome", "The gnome", "The little old man", "The little man", "With a wink, the gnome", "Cheerfully, the gnome"]

And give him the powers he deserves:

  @perm gnome = Admin
  @set gnome/pose_sleep = "sleeping soundly in a large, overstuffed chair"
  #
  pose gnome/default = smoking his pipe

And a good description that I can rework:

  @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.

And an un-puppeted, sleeping, description:

  @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."

And we create a couple of objects:

Like his special teacup:

  @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

And his fancy jacket:

  @create waistcoat : typeclasses.things.BagofJunk
  #
  @desc waistcoat = An elegant green waistcoat with gold embroidery.
  #
  @set waistcoat/stuff = "fey"
  #
  @give waistcoat = gnome
Staff

And my staff:

  @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

And his spells that go with the staff:

  @set gnome/disappear_msg = "After a raspberry sound, the gnome, Dabbler, disappears in a wisp of smoke."
  #
  @set gnome/reappear_msg = "<<White ^ Light blue ^ Gray>> mist appears...along with the smell of sulphur... ;; When the smoke clears, an old gnome <<emerges ^ materializes ^ shows up, looking a bit confused>>."
  #
  @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."

And help with the fly spell:

  nick meadow = fly Frog Meadow
  nick bar = fly Wyldwood Bar
Scrying Ball

This crystal ball can be used to see what is going on in any area of the realm.

  @create scrying ball: typeclasses.things.Scryer

And a description:

  @desc scrying ball = A crystal orb that shows what's abroad.
  #
  @give scrying ball = gnome
Pipe

The pipe is little more than messages to the smoker and everyone else in the room.

  @create pipe: typeclasses.things.Pipe

And a description:

  @desc pipe = As tall as its owner with etchings of birds, leaves and magical symbols.
  #
  @give pipe = gnome

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.

  @create large book;journal: typeclasses.readables.Journal

Writing descriptions:

  @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."

And a description:

  @desc journal = Leather-bound book, cracked and worn from ages.
  #
  @give journal = gnome

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?

  @create/drop wee beastie;Mochi;stoat: typeclasses.pets.WeeBeastie

And its description:

  @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.

Cant get this guy:

  @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."

Lets get a bit more interaction with this pet:

  @set stoat/active_amount = 8

Its level doesnt change much. :-D It is always less interested, just like a cat.

  @set stoat/scared_msg = "Currently, coiled like a sleeping snake on one of the chairs."

And petting it when someone first comes in?

  @set stoat/pet_scared_response = "While it doesn't stop $you() << from petting it ^ >>, the beastie flashes its long teeth."

And actions if a friendly person isnt around:

  @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."

Concerned level:

  @set stoat/concerned_msg = "Currently, curled into a ball on one of the chairs."

Pets?

  @set stoat/pet_concerned_response = "$You() get little response from << your pets of ^ >> << the wee beastie ^ the beastie >>. "

And actions at this level are more cute than sinister:

  @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."

Interested level:

  @set stoat/interested_msg = "<< Currently ^ It is >> curled into a ball asleep."

Pets

  @set stoat/pet_interested_response = "The << wee ^ >> beastie adorably moves its head into $your() pets."

And actions at this level are about as cute as a cat can be:

  @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."

Friendly level:

  @set stoat/friendly_msg = "<< Currently ^ It is >> purring while curled up sleep."

Pets

  @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."

And actions at this level are about as cute as a cat can be:

  @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."

And this pet loves his gnome.

  @set gnome/wee_beastie_friendly_level=500

Trigger some events … which cant work at the moment, since a Pet is not a Puppet … yet:

  @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."

Lets also hook it to our AI system:

  @set stoat/personality = "wee-beastie"
  #
  @set stoat/personality_file = "personalities/wee-beastie.md"

Lets test this creature:

  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."

Kitchen

Better place to put the tea and scones.

  @dig Cramped Kitchen;mp11 = archway to kitchen;kitchen;archway,back to main room;leave;main;back

And describe the exit:

  @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."

And describing the room:

  @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.

And the exit:

  @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."

And some details:

  @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.
  @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.
  @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...
  send "kitchen\n"
  expectit "Cramped Kitchen"

  send "look scones\n"
  expectit "look tempting"
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.

Cabinets and Counter-tops

The Trolley produces teacups and random scones, which, like the berries can be eaten or fed to the wildlife.

  @create/drop cabinet;cabinets : typeclasses.consumables.Trolley

We mentioned a trolley with tea, cups and scones:

  @desc cabinet = The cabinets contain an assortment of tea cups.

We have to have the trolley bake something with the Python command:

  py here.search("cabinet").do_bake()

And lets not clutter up the scene too much:

And lets have the test grab a scone:

  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"

Tea Service

The “room” gives the teacups, and the “teapot” fills the cups, so we just need descriptions:

  @detail teacups = An odd, yet interesting assortment of teacups. Take one.
  #
  @detail teacup = Each cup is unique. Take one to look further.

A teapot will contain a type of tea … either given or randomly chosen. A teapot will “fill” a teacup forever, until it is “remade”.

  @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.

And of course, you cant steal the tea pot:

  @lock teapot = get:false()
  #
  @set teapot/get_err_msg = "You don't need to carry it around to make tea."

And test that anyone can make it:

  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"

Hints

I guess the hints here are how to use the teapot?

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.

And test the hints, just to be sure:

  send "hint\n"
  expectit "Grab yourself some breakfast"

Secret Room

Pulling on a candle opens a secret staircase!

  @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

Look and traverse:

  @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."

We left the tester in the kitchen, lets get him in the Cozy Room:

  send "leave\n"
  expectit "Cozy House"

Sconce

The Candle holder must be both an Opener (with a do_pull method) and a Producer (making long-lasting candles).

  @create/drop sconce;candle holder;candle: typeclasses.consumables.Sconce
  @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?

Connect the exit:

  @set sconce/exit = $search(stairs behind bookcase)
  #
  @set sconce/room = $search(Cozy House)

Hide it a bit?

  @set sconce/hidden_tag = "hidden_sconce"
  #
  @lock sconce = view:tag(hidden_sconce)

We can get an endless supply of candles here:

  @set sconce/make_name = "candle"

And a verb when they get the consumable:

  @set sconce/make_verb = "$conj(take) the"
  #
  @set sconce/make_note = ", but another magically appears in its place"

This one is optional as it defaults to Consumable:

  @set sconce/make_class = "typeclasses.lightables.Candle"

And the sconce needs to know the description of the Consumable, so that it can attach that:

  @set sconce/make_desc = "Curiously shaped taper with scales like a snake."

How much is there when you pick them?

  @set sconce/make_amount = 1

Can we see it?

  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"

Pulling Sconce

Temporarily move the exit into the room.

  @set sconce/pull_msg = "You hear a click, and the bookcase next to the candle swings forward revealing a |Ysecret passage|n."

Lets reset it to start:

  @teleport/tonone stairs behind bookcase

Can we pull the sconce to reveal the secret bookcase?

  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."

Inside the Secret Room

Time to create the secret lab, the Secret Room.

  @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.

Add aliases that make sense:

  @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."

Until we decide if we want to do something with the table:

  @detail table = Made from a polish black wood, etched with intricate runes that shimmer faintly in the candlelight.

Are the equipment stuff we could use?

  @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.
  @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.
  @detail vials = Scattered across a small shelf, an array of empty glass vials. Perhaps you could fill these with potions yet to be created?
  @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.

And tools that definitely need to stay here:

  @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.

And lets descend and check it all out:

  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"

And lets generate an image:

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.

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 cant take. This creates ambiance without adding too much complexity?

  @tel/quiet Secret Room
  #
  @create/drop collection of jars;jars;jar: typeclasses.puzzles.Changling

Cant get them:

  @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?"

And the generate description:

  @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 = ""

And now for a list of the contents:

  @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.",
       )

How can we test this cool feature?

  send "look jar\n"
  expect -re "You look at one.*labeled"
  #
  send "look jar\n"
  expect -re "You look at one.*labeled"

Stool

A stool to sit while working

  @create/drop stool:typeclasses.sittables.Sittable

How descriptive:

  @desc stool = A place to sit while synthesizing experiments.

Cant steal this stool either:

  @lock stool = get:false()

Lets do a funnier message:

  @set stool/get_err_msg = "Stop trying to steal everything not nailed down."

And test this out;

  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."

Grimoire

A mystic book of potions can add a new dimension to the game.

@create/drop leather-bound book;book;grimoire:typeclasses.readables.Book

The books title and description:

  @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.

Lock it down.

  @lock grimoire = get:false()
  #
  @set grimoire/get_err_msg = "The book is chained to the table."

And of course, the inside.

  @set grimoire/inside = "file:world/alchemy-book.md"

The contents must be in a file, and we need to add a pager.

The prefix can be:

  @set grimoire/prefix = "Undoing the brass clasp that bind the old leather book, you open to page one and begin reading the elegant calligraphy..."

Test out reading, but not stealing it:

  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."

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
  @create/drop black cauldron: typeclasses.alchemy.Cauldron

And the details:

  @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.

Lock it down:

  @lock cauldron = get:false()

Make sure we cant take it:

  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."

Shelf of Bottles

The table is a producer of bottles.

  @create/drop shelf of empty bottles;shelf;bottles;bottle: typeclasses.consumables.Producer

With a description:

  @desc shelf = Cluttered with some empty brown |Ybottles|n. Perhaps you can fill these with liquid ingredients and bring them back here.

We have to have the bush describe what it makes:

  @set shelf/make_name = "bottle"
  #
  @set shelf/make_verb = "$conj(pick up) a"

This one is optional as it defaults to Consumable:

  @set shelf/make_class = "typeclasses.drinkables.Bottle"
  #
  @set shelf/make_desc = "A brown glass bottle. Currently empty."
  #
  @set shelf/make_amount = 1

Our tests from here on out demand a bottle…

  send "look shelf\n"
  expectit "Cluttered with some empty brown"

  send "get bottle\n"
  expectit "You pick up a bottle."

Imp

Every secret alchemical lab should have an Imp familiar.

  @create/drop Impetus;imp: typeclasses.puppets.Puppet

Note that we give him a male gender:

  @set imp/gender = "neutral"

Work around the pose bug:

  py bt = self.search('imp'); bt.sdesc.add('imp'); bt.db.pose = 'sitting on an ornate perch'
  @set imp/pose_sleep = "sitting on an ornate perch"
  #
  @pose default imp = sitting on an ornate perch

And a good description that I can rework:

  @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.

And an un-puppeted, sleeping, description:

  @set imp/desc_unpuppeted = "... not used ..."

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.

  @set imp/arrive = "tag_all alchemist ;; untag_all beginner ;; 240 ;; emote yawns."

Would be nice if it has a variety of responses to speech.

  @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 >>."

Lets interact with the little fellow:

  send "look imp\n"
  expectit "little fellow gives you a quizical look"

  send "say Hello there, little guy.\n"
  expect -re "Imp"

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.

Ive got the first potion in place, and I like it; pretty cute, even if the effect isnt that interesting (but Ive got more up my sleeve).

Anyway, Ive 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 potions 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 Ive 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 cant get a horn that you can use to call the boat to take you to all the islands where Ive put the escape rooms … so).

Laughing Potion

Ingesting this potion causes outward expressions of glee and laughter.

Ingredients:

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:

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:

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.

Butterfly dreams with no meaning:

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.

Harken back to Alice in Wonderland with the Caterpillar:

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.

More elvish words … should there be a point?

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.
py c=me.search("black cauldron", global_search=True); c.do_empty(); c.create_drugtrip() ; c.do_bottle(me) ; c.do_empty()
Pucks 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 (witchs 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?

  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.        

Bedroom

A bedroom with a wardrobe that goes to another land sounds great.

  @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

Look see:

  @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..."

And a description:

  @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.

And describe the exit:

  @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."

And of course, you can see more details:

  @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.

Are the slippers just a red herring?

  @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."

Lets validate all the details:

  # 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."

And generate an image:

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.

Wardrobe

One needs to open it to go to another world.

  @dig Prairie;mp14 = through the wardrobe;wardrobe,copse of pinion pines;pines;copse;trees;leave

And describe the exit:

  @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

And messages for opening and closing the wardrobe:

  @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."

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.

  @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.

The look command could be distinguishing using aliases of “the exit” and “the furniture”?

  @alias wardrobe = the object

Dont allow it to get taken:

  @lock wardrobe = get:false()
  #
  @set wardrobe/get_err_msg = "The wardrobe is way too big to lift."

Lets test this secret door …

  # 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!"

Hints

Sooo obvious. But what is the narrator here?

  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.

Southwest Prairie

What am I doing here?

  @teleport/quiet mp14
  #
  @desc here = On the edge of a small |Yknoll|n with a |Ycopse|n of trees, the space stretches to <morning>a rolling dawn</morning><afternoon>clear, blue skies pushing down the horizon</afternoon><evening>a distant sunset attempting to pull the sky down with it</evening><night> bright, star painted skies</night>.

Describe the exit:

  @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."

Details?

  @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.

Test this place:

  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."

And lets illustrate this scene:

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.

Mares Head

Taken from Wikipedia.

  @create/drop Mares Head;head: typeclasses.puppets.Puppet

Note that we give him a male gender:

  @set mares head/gender = "neutral"

Work around the pose bug:

  py bt = self.search('head'); bt.sdesc.add('curious figure'); bt.db.pose = 'sitting next to a small |Ycampfire|n'
  @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

And a good description that I can rework:

  @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.
  @detail ears;ear = They look real, and twitch as if alive.

And when someone arrives:

  @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}"

And what if they attempt to interact?

  @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 >>."

Should we wait to get a pipe?

  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

Hints

I shouldnt think the Mares Head could talk in order to give hints. Because this is a under construction section, we will:

  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.        

Pull up a Log

Lets allow anyone here to sit on a log next to the campfire ..

  @create/drop couple long log;log:typeclasses.sittables.Sittables

And the description:

  @desc log = A long, smooth log rests next to the inviting campfire.

Cant steal em:

  @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?"

And textual descriptions the object can use:

  @set log/article = "the"
  #
  @set log/singular = "the log next to the campfire"

Since we have unlimited seating, sitting down is always available:

  send "sit\n"
  expectit "You sit on the log"

Dark Tunnel

The entrance to the dungeon experience will be under the mattress in the Lair.

  @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

And we create a trapdoor in the Lair:

  @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)

What does it take to open it?

  @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."

Lets get into the Dungeon and work from it there.

  @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.

Dungeon WIP

Lets connect the Bar to the Lair through a labyrinth of tunnels.

  @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

Lets bring the “ladder” exit back by opening and closing the trapdoor:

  @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."

And lets create the trapdoor:

  @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."

Lets enter the belly of this beast.

  @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.

Lets make the end of the tunnel look a lot like the beginning:

Lets create another trapdoor and a ladder leading to the Lair:

  @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.
  @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...."

Deep Forest

The deep forest is a place where all the Puppets can hang out when not in use.

  @dig the Deep Forest;mp00
  #
  @teleport mp00

What do we have left to describe:

  @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.

And create an easy exit back to the game:

  @open portal;leave;enter;exit = Grotto

And do the usual tricks on Exits:

  @desc portal = Octarine sparks spiral in the mists that swirl between the stones.

And a nice journey message to go east out of the forest:

  @set portal/traverse_msg = "As soon as you step between the stones, you feel like you are carried away..."

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.

Ive hardcoded the path of this Traveler, but it would be nice to be able to have different Travelers follow different paths.

  @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"

Then wake it.

  py darol = me.search("Darol") ; darol.sdesc.add("tiny, orange dragon") ; darol.backstory("dragon")

Moving attributes:

  @set Darol/traveling_direction = "east"

And get it moving:

  @script Sir Roblees = typeclasses.chatbots.TravelingNPC

Rick the Barbarian

  @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"

Then wake her.

  py rick = me.search("rick") ; rick.sdesc.add("large barbarian") ; rick.backstory("barbarian")

George the Dwarf Tinkerer

This Dwarf will be in the dungeons, but I would like them to come out at times.

  @create/drop George: typeclasses.chatbots.Chatbot
  #
  @set George/gender = "him"
  #
  @set George/pose = "looking at some blueprints"
  #
  @set George/pose_sleep = "snoozing"

Then wake it.

  py george = me.search("george") ; george.sdesc.add("white-haired dwarf") ; george.backstory("dwarf")

Bugs

And now that we are done, say it:

  say I have finished this, the first version, of my creation.

Finish Testing

Can we quickly walk back through the world, gathering ingredients, and then going back into the Secret Room to make potions?

  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"

Lets 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
  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"

Lets close up the test.

  # 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
      }
  }

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, lets have a little bird land on their shoulder, and talk them through the game. Im thinking a “state machine” triggered by actions that someone does.

  ╭────────────╮           ╭────────────╮
  │  created   ├──┬shoo───→│  tutored   │←─╮
  ╰─────┬──────╯  │        ╰────────────╯  │
       look       │              ↑         │
        ↓         │            done        │
  ╭────────────╮  │        ╭─────┴──────╮  │
  │   looked   ├──┤        │   helped   │ shoo
  ╰─────┬──────╯  │        ╰────────────╯  │
    look trees    │              ↑         │
        ↓         │             help       │
  ╭────────────╮  │        ╭─────┴──────╮  │
  │ looked-at  ├──╯        │   moved    ├──╯
  ╰─────┬──────╯           ╰────────────╯
      south                      ↑
        ╰────────────────────────╯

Each section should have a list of phrases spoken or “done” on a timer.

  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.

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.
  • “Im the Tutorial Bird,” it chirps, “and Im here to break the fourth wall, and help you figure out this game. Feel free to |bshoo|n me away, and Ill 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

  • “Thats 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 Dabblers place,” the little bird on your shoulder says.
  • “Yes, I could fly myself,” warbles the little bird, “but Im 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 Im 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 dont 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

  • “Hows 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 wouldnt 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 weve talked about,” says the bird.

Tutored

  • “Im 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 Im 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, thats 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 youre 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 Ill leave you here,” chirps the bird, as it flies away.

Waiting

  • The <<little ^ blue ^ >> bird <<on your shoulder ^ >> preens itself.
  • The <<little ^ blue ^ >> bird <<on your shoulder ^ >> <<looks ^ stares>> at you <<expectantly ^ waiting ^ patiently>>.
  • 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 dont like the weather,” tweets the bird, “just wait.”

Evennia Details

Scripts

This is an obnoxious, but interesting effects:

script self = tutorials.bodyfunctions.BodyFunctions

And stop it with:

script/stop self = tutorials.bodyfunctions.BodyFunctions

Accounts

Can we fix the permissions for our friends:

  perm/account steve = Builders

Who is logged in? Use the who command, or something like:

  import evennia

  people = [
      " - " + account.name + " :: " + \
      ", ".join([character.name for character in account.characters])

      for account in evennia.SESSION_HANDLER.all_connected_accounts()]

Python

Run stuff:

py print("|gHello World!|n")
py me.msg("|gHello world!|n")

The python approach to @create is:

py evennia.create_object("typeclasses.sittables.Sittable", key="chair", location=here)
py self.search("armchair").do_sit(me)

Assuming we have created something:

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!")

Create stuff, first go into the inline Python REPL:

  @reload
  @py
  from typeclasses.monsters import Dragon
  smaug = Dragon(db_key="Smaug", db_location=here)
  smaug.save()
  smaug.move_around()

Or better yet:

py evennia.create_object('typeclasses.monsters.Monster', key="Cuddly", location=here)
py cuddly = evennia.search_object("Cuddly")[0] ; cuddly.move_around()

Or:

  @create/drop Fluffy:typeclasses.monsters.Dragon

Server Deployment

Created the following section in /etc/apache2/sites-enabled/howardabrams.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

Notice the lack of a / at the end, something their configuration suggestions added.

Next, I need to make sure that everything prepends /moss to all references.

This could be any of the following:

# Where users are redirected after logging in via contrib.auth.login.
LOGIN_REDIRECT_URL = "/"

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 VanDyke 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 VanDyke 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 VanDyke beard and blue hair; a curledup 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 fourpanel tapestry: topleft shows a small old man with a VanDyke beard beside a yellow rose bush; topright shows the man, the rose bush, and a magnificent queen; bottomleft shows the old man with two closely standing trees; bottomright 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 “VanDyke 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 “fourpanel 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!