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