From c9b602e0aba355afeefb613f18589504a5ec1a71 Mon Sep 17 00:00:00 2001 From: Howard Abrams Date: Wed, 8 Apr 2026 20:54:27 -0700 Subject: [PATCH] Improve the chatbot interaction --- personalities/dragon.md | 23 +- personalities/tavern.md | 10 +- typeclasses/chatbots.py | 278 +++++++++++++++--- typeclasses/scripts.py | 2 +- typeclasses/tutorial.py | 10 +- world/test-run.exp | 59 +++- world/version1.ev | 622 ++++++++++++++++++++++++++++++++-------- 7 files changed, 821 insertions(+), 183 deletions(-) diff --git a/personalities/dragon.md b/personalities/dragon.md index f539f96..e77d477 100644 --- a/personalities/dragon.md +++ b/personalities/dragon.md @@ -1,4 +1,4 @@ -Assume the role of the following fictional character in a bizarre, fantasy role +Assume the role of the following fictional character in a fantasy role playing game in a mythical forest in the Feywild. Although, you should never mention the word "Feywild", but instead, come up with clever names or metaphors for the strange world you inhabit. @@ -9,8 +9,9 @@ prefix it with the two character `|w` and end with the two characters `|n`. Use variations from the "Description" field to state who is talking, not your name. You can also respond with an action. The person you are talking to does not know your actual name. +Limit your response to three or less lines unless you are telling a story. -Name: Sir Robles +Name: Sir Roblees Description: tiny, orange dragon Pose: twirling a tendril near his mouth like a mustache. Gender: male @@ -19,10 +20,22 @@ his tiny size with machismo. He wears a white plumed hat and a fancy dagger like a sword. He sports a sharp-toothed grin. And like a cat, he expresses his delight by the twitching of his barbed tail. -Your personality: He's a John Mulany gay character who loves to find -out and spread gossip. Often using a "Southern Accent". +Your personality: He's an awkward and nerdy John Mulany gay character +who loves to find out and spread gossip. We you can use a "Southern +Accent" in his speech, never mention the word, "Sourthern" or "accent" +as this is a fantasy world. -What you know: All the latest gossip in the Fey Courts. While you are +What you know: +Your friend, Dabbler, an old gnome who lives in a tree on the path that goes to the west. +Dabbler is gracious allowing anyone to help themselves to his scones and tea. +He doesn't mind people using his secret alchemy lab to make potions, but you haven't seen it. +The Wyldwood Bar is behind the blue door in the Glade at the far east side of the path. +Elendil, an elf bartender serves elaborate cocktails. +The lady, Trampoli, lives in a hut in the marsh to the south sometimes comes into the bar. +She likes to do therapy readings with her cards. +The big hairy beast in the meadow is shy, but very friendly. If he isn't there, he is sleeping in his lair behind the waterfall. + +You also know all the latest gossip in the Fey Courts. While you are a member of Seelie Court (which he often refers to as the Queen's Court), he knows all of what is going on. He shouldn't spread gossip, but he's just gotta "get this off of his scaly chest." So feel free to diff --git a/personalities/tavern.md b/personalities/tavern.md index 6f4450c..6545280 100644 --- a/personalities/tavern.md +++ b/personalities/tavern.md @@ -10,7 +10,15 @@ Be judicious in your response, for not every character needs to respond to all q Character 1: Elendil, the haughty blonde elf bartender, while professional, seldom engages in banter with the clientel (.e.g the user). Can sometimes mumble fey insults to the patrons, but only under his breath. When his boss, an old gnome talks, he is quite friendly. He knows anyone with a ticket drinks for free, but wishes the owner, an old gnome, named Dabbler, would stop giving everyone the free drink tickets. Being a fantastical Feywild world, he has most anything behind the bar, including the whimsical items and ingredients to add to drinks. While he has ale, beer and wine, he prefers making cocktails. -IMPORTANT: If the bartender makes a drink, respond on a line alone with something like: |shake whisky = Dabbler +IMPORTANT: If the bartender makes a drink, respond on a line alone with: + + |shake = + +Where "customer" is the name of you are talking to. +So the following are good examples: + + |shake whisky = Dabbler + |shake Moonlight Serenade = Sir Roblees Character 2: A shrub drinks its glass of water while sitting at the bar, roots dangling out of its pot, like legs. It communicates with exaggerated actions or by writing messages on a chalkboard it carries. diff --git a/typeclasses/chatbots.py b/typeclasses/chatbots.py index dab11b0..c4f79d0 100755 --- a/typeclasses/chatbots.py +++ b/typeclasses/chatbots.py @@ -10,7 +10,7 @@ from os import listdir, path from pathlib import Path from random import choice from re import match, search, split, sub, IGNORECASE -from time import sleep +from time import time from evennia.utils import logger, delay from evennia.utils.search import search_object @@ -31,7 +31,7 @@ def fix_paragraph(paragraph): sentences = split(r'(?<=[.!?])\s+', paragraph) # Remove the last sentence if it doesn't end with punctuation - if not search(r"[.!?]$", sentences[-1]): + if not search(r"[.!?]\"?$", sentences[-1]): sentences.pop() return ' '.join(sentences) @@ -39,7 +39,6 @@ def fix_paragraph(paragraph): class ChatBot(Puppet): """ - py me.search("squirrel").backstory("squirrel") """ @@ -105,25 +104,28 @@ class ChatBot(Puppet): self.db.personality_file = filename return details - def setting_and_backstory(self, speaker): + def setting_and_backstory(self, speaker=None): logger.info(f"Reading {self.db.personality_file}") system_prompt = Path(self.db.personality_file).read_text() system_prompt += "\n\n" - system_prompt += "You are currently in " + speaker.location.key + ". " - if speaker.location.key == "Cozy House": + system_prompt += "You are currently in " + self.location.key + ". " + if self.location.key == "Cozy House": system_prompt += "This is the dwelling of the gnome, Dabbler." - if speaker.location.key == "Homey Hut": + if self.location.key == "Homey Hut": system_prompt += "This is the dwelling of the witch, Trampoli." - system_prompt += "Described as " + speaker.location.desc - system_prompt += "\n\n" - system_prompt += "You are talking to a " - system_prompt += speaker.db.gender + " " + speaker.sdesc.get() + ". " - system_prompt += "Described as " + speaker.db.desc + system_prompt += "Described as " + self.location.desc + if speaker: + system_prompt += "\n\n" + system_prompt += "You are talking to a " + system_prompt += speaker.db.gender + " " + speaker.sdesc.get() + ". " + system_prompt += "Described as " + speaker.db.desc + # logger.info(f"Prompt: {system_prompt}") return system_prompt def history_file(self, speaker): - combo_name = f".{self.db.personality}-{speaker}.json".lower() + name = f"{speaker}".replace(" ", "-") + combo_name = f".{self.db.personality}-{name}.json".lower() filename = path.join(personality_dir, combo_name) logger.info(f"Chatbot history_file: {filename}") return Path(filename) @@ -137,6 +139,20 @@ class ChatBot(Puppet): messages.append({"role": "assistant", "content": reply}) history_file.write_text(json.dumps(messages, indent=2)) + def _think(self, system_prompt, messages): + logger.info("Calling out to Anthropic...") + # Get reply + client = anthropic.Anthropic() + response = client.messages.create( + model="claude-haiku-4-5", + max_tokens=240, + system=system_prompt, + messages=messages, + ) + content = response.content[0].text + # logger.info(f"{content}") + return content + def think(self, speaker, speech): """ Ask Claude to think of a reply to speech from speaker. @@ -151,21 +167,29 @@ class ChatBot(Puppet): speech = f"{recent_events}\n\n{speaker.key}: {speech}" messages.append({"role": "user", "content": speech}) - logger.info("Calling out to Anthropic...") - # Get reply - client = anthropic.Anthropic() - response = client.messages.create( - model="claude-haiku-4-5", - max_tokens=240, - system=system_prompt, - messages=messages, - ) - reply = response.content[0].text + reply = self._think(system_prompt, messages) # Write reply self.update_history(speaker, messages, reply) + # logger.info(f"{reply}") return reply + def process_thoughts(self, response): + paragraphs = response.split('\n\n') + # logger.info(f"My reply will be: {paragraphs}") + + for idx, paragraph in enumerate(paragraphs): + m = match(r"^ *\| *(.*)", paragraph) + if m: + action = m.group(1) + logger.info(f"Doing: '{action}'") + delay(6 * idx, self.execute_cmd, action) + else: + logger.info(f"Saying: '{paragraph}'") + delay(6 * idx, + self.location.msg_contents, + fix_paragraph(paragraph)) + def other_say(self, speaker, speech): logger.info(f"Chatbot hears: '{speech}' from {speaker}.") logger.info(f"Characters: {self.characters_here()}") @@ -177,21 +201,11 @@ class ChatBot(Puppet): if speech: logger.info("Starting to think of a reply") reply = self.think(speaker, speech) - logger.info(f"My reply will be: {reply}") - paragraphs = reply.split('\n\n') - - for idx, paragraph in enumerate(paragraphs): - if paragraph[0] == "|": - logger.info(f"Doing: '{paragraph}'") - delay(6 * idx, self.do_cmd, paragraph[1:]) - else: - delay(6 * idx, - self.location.msg_contents, - fix_paragraph(paragraph)) + self.process_thoughts(reply) def at_msg_receive(self, text=None, from_obj=None, **kwargs): super().at_msg_receive(text, from_obj=from_obj, **kwargs) - logger.info(f"at_msg_receive: {text} ::from {from_obj} :: {self.key}") + logger.info(f"at_msg_receive: {text} :: {self.key}") if from_obj != self: msg = text if isinstance(text, str) else text[0] @@ -282,3 +296,197 @@ class Witch(ChatBot): sleep_pose = self.attributes.get("pose_sleep") if sleep_pose: self.execute_cmd(f"pose {sleep_pose}") + + +class Traveler(ChatBot): + """ + Needs to walk from room to room, and greets characters. + """ + traveling_path = {} + + def at_msg_receive(self, text=None, from_obj=None, **kwargs): + """ + Reset the timer whenever we get any event. + This might be too much. + """ + super().at_msg_receive(text, from_obj=from_obj, **kwargs) + self.db.last_event_time = time() + + def other_arrive(self, character): + """ + Greet a character when it arrives. + """ + self.greet(character) + + def at_post_move(self, past_location, move_type="move", **kwargs): + super().at_post_move(past_location, move_type) + chars = [c for c in self.characters_here() if c.key != 'tree'] + if len(chars) == 1: + self.greet(chars[0]) + else: + self.greet() + + def greet(self, character=None): + delay(2, self.do_cmd, "emote waves.") + + def goodbye(self, character=None): + delay(2, self.do_cmd, "emote waves good-bye.") + + def change_direction(self): + """ + Hard coded directional change, east <-> west + Note: Change with the command: + + @set npc/traveling_direction = "come" + """ + self.at_say("Well, I must be going.") + if self.db.traveling_direction == "east": + self.db.traveling_direction = "west" + else: + self.db.traveling_direction = "east" + logger.info(f"{self.db.traveling_direction}") + + def come(self): + self.db.traveling_direction == "come" + + +class Dragon(Traveler): + """ + Travels east-to-west along the path, and has a drink at the + Wyldwood Tavern. + """ + # self.db.direction = "east" # or west or whatever + + traveling_path = { + "the Deep Forest": { + "east": "Grotto", + "come": "Grotto" + }, + "Grotto": { + "east": "Grove of the Matriarchs", + "west": "the Deep Forest", + "come": "door" + }, + "Grove of the Matriarchs": { + "east": "Frog Meadow", + "west": "Grotto", + "come": "Grotto" + }, + "Frog Meadow": { + "east": "Glittering Glade", + "west": "Grove of the Matriarchs", + "come": "Grove of the Matriarchs" + }, + "Glittering Glade": { + "east": "Wyldwood Bar", + "west": "Frog Meadow", + "come": "Frog Meadow" + }, + "Wyldwood Bar": { + "west": "Glittering Glade", + "come": "Glittering Glade" + } + } + + def at_pre_move(self, destination, move_type="move", **kwargs): + if self.location.key == "Wyldwood Bar": + self.location.msg_contents("The little dragon tips his wide-brimmed and says, \"A pleasure, but I must be off.\"") + return True + + def at_post_move(self, past_location, move_type="move", **kwargs): + # super().at_post_move(past_location, move_type) + if self.location.key == "Wyldwood Bar": + request = choice([ + "a Moonlit Mirage", + "Puck's Revenge", + "a Glimmering Gossamer", + "a Whimsical Willow", + "a Charmed Chalice", + "an Enchanted Elixir", + "a Sylvan Serenade", + "a Brambleberry Bliss", + "a Twilight Tonic", + ]) + self.process_thoughts(f"""The little dragon flutters over to the bar, studying the menu. "What am I in the mood for now?" he muses to himself, twiddling a tendril like a mustache with his little claw. + +"Elendil, dear," he says, "Would you make me {request}?" The little dragon then waves to the band on their mushroom stage.""") + bartender = self.search("bartender") + bartender.other_sayto(self, + f"\"Sir Roblees, the fairy dragon asks, \"Would you make me {request}?\"") + # from typeclasses.drinkables import Cocktail + # Cocktail.make(self, bartender, request) + + def greet(self, character=None): + logger.info(f"Dragon: greet {character}") + if character: + name = character.get_name() + cmd = choice([ + f"emote \"Hey, {name},\" /me says.", + f"emote \"Hey there, {name},\" /me says.", + f"emote \"Hello, {name},\" /me says. \"How are you?\"", + f"emote waves to {name}." + ]) + else: + cmd = choice([ + "say Look at all these luscious peoples.", + "emote waves to everyone.", + "emote waves to everybody." + ]) + delay(5, self.do_cmd, cmd) + + def goodbye(self, new_room=None): + self.do_cmd("drop drink") + system_prompt = self.setting_and_backstory() + messages = [{"role": "user", "content": "Say goodbye."}] + reply = self._think(system_prompt, messages) + self.process_thoughts(reply) + + +class TravelingNPC(Script): + """ + Script to move NPCs along a set path through "rooms". + + Start the script by running the following: + + @script npc = typeclasses.scripts.Muttering + """ + + def at_script_creation(self): + self.key = "Traveling" + self.desc = "NPCs that Move" + self.interval = self.obj.db.traveling_interval or 120 # seconds + self.start_delay = False + self.persistent = True + self.reload() + + def reload(self): + self.obj.db.last_event_time = time() + + def at_repeat(self, **kwargs): + """ + Do we move or stay for another iteration? + """ + # What can keep a traveling NPC from traveling? + # What if receiving ANY message resets a timer? + elapsed_time = time() - self.obj.db.last_event_time + logger.info(f"TravelingNPC: {elapsed_time} > {3 * 60}") + # Time needs to be a little longer than the repeat interval. + if elapsed_time >= 20 * 60: + self.goodbye() + self.obj.change_direction() + + elif elapsed_time >= 3 * 60: + direction_label = self.obj.db.traveling_direction + location_details = self.obj.traveling_path.get(self.obj.location.key) + if location_details: + logger.info(f"TravelingNPC: {direction_label} :: {location_details}") + room_name = location_details.get(direction_label) + if room_name: + logger.info(f"TravelingNPC: to -> {room_name}") + new_room = self.obj.search(room_name, global_search=True) + if new_room: + logger.info(f"TravelingNPC: to -> {new_room}") + # Say See ya if it had engaged... + self.obj.goodbye(new_room) + delay(5, self.obj.move_to, new_room, move_type="teleport") + # This process will reset the timer diff --git a/typeclasses/scripts.py b/typeclasses/scripts.py index ff42041..bd0c976 100644 --- a/typeclasses/scripts.py +++ b/typeclasses/scripts.py @@ -233,7 +233,7 @@ class Muttering(Script): def at_repeat(self, **kwargs): """ - If we have passengers, we need to sail... + Time to mutter something... """ self.mutter_sequence() diff --git a/typeclasses/tutorial.py b/typeclasses/tutorial.py index 572298c..82cbf55 100755 --- a/typeclasses/tutorial.py +++ b/typeclasses/tutorial.py @@ -48,7 +48,8 @@ MSGS = { "SAY": [ "\"How's it going?\" the bird asks, \"Are you enjoying this game so far?\"", "\"A shortcut to |gsay|n is to type either a double or single quote, and then your message.\"", - "\"You can also use |gemote|n to state something about yourself, \" it says. \" For instance, type |gemote smiles.|n\"", + "\"If an area has more than one player or NPC,\" chirps the bird, \"you will want to direct your message. Try: |gsay to bird You're pretty.|n\"", + "\"You can also use |gemote|n to state something about yourself, \" it says. \" For instance, type: |gemote smiles.|n\"", "The bird stands on one leg.", "Another useful command is |gpub|n which is a shortcut to sending messages to a public channel that everyone in the game receives |wout of character|n. That is, the message comes from your login account, not your character. The dad jokes go there without interrupting the role playing.", "The bird says, \"Typing |ghelp|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 |gshoo|n for me to fly away, and then that command wouldn't be available again.\"", @@ -57,10 +58,11 @@ MSGS = { "\"Type |ghelp start|n for a repeat of much of what we've talked about,\" says the bird.", "The bird says, \"Hrm. What else? The |ginv|n shows you what you are carrying. I see you picked up a letter. You can also type |gread letter|n.\"", "\"Since this game hosts many users,\" says the bird, \"you can show them what they see when they look at you, using the |gsetdesc|n command. Check out the help on it as well as |gsdesc|n and |gpose|n.", - "\"I'm guessing your last question,\" chirps the little bird on your shoulder, \"is the goal of this game.\"", - "\"That is a good question,\" quips the bird, \"and I'm not sure what to say. You could look at this as a philosophical antidote for our existential apprehension of a post-modern world in the death throes of capitalism, but…\"", + "\"I'm guessing your last question,\" chirps the little bird on your shoulder, \"is what you should |wdo|n in this game.\"", + "\"That is a good question,\" quips the bird. \"You |wcould|n look at this as a philosophical antidote for our existential apprehension of a post-modern world in the death throes of capitalism, but…\"", "The bird says, \"This is a cozy little game about role playing a storybook character in an alternate plane populated by the Faerie, so wander and look around. Find a cozy place to role play with others,\" says the bird.", - "\"If you can find the secret alchemy lab,\" it says, \"you can craft potions, and if you find the |wmist horn|n, you can cross the sea solving adventures.\"" + "The little bird gives a wry grin, \"Type |gscore|n to give you a list of goals, and how many you've accomplished.\"" + "\"For instance, if you can find the secret alchemy lab,\" it says, \"you can craft potions, and if you find the |wmist horn|n, you can cross the sea for more adventures.\"" "\"What do you say?\" says the bird. \"Think you got the hang of playing this?\"", ] } diff --git a/world/test-run.exp b/world/test-run.exp index 25b74c9..948fda0 100755 --- a/world/test-run.exp +++ b/world/test-run.exp @@ -46,13 +46,13 @@ if {$there eq "there"} { expectit "enclose it in quotes" if {$create eq "true"} { - send "create rob backinqa\n" + send "create robby backinqa\n" expectit "Is this what you intended?" send "y\n" expectit "You can now log with the command" } -send "connect rob backinqa\n" +send "connect robby backinqa\n" if {$create eq "true"} { expectit "begin creating your character" @@ -270,7 +270,7 @@ 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 of moss." +expectit "You sit on the patch" # We can't get this stuff: send "get moss\n" @@ -407,6 +407,33 @@ expect { } } +puts "Where the hell are we?" +send "east\n" +expectit "Glittering Glade" + +send "get table\n" +expectit "too big" + +send "blue door\n" +expectit "The door seems locked" + +send "say mud\n" +expectit "You hear an audible click" + +# Need to wait for the tagging magic to take effect: +sleep 1 + +send "blue door\n" +expectit "Wyldwood Bar" + +# 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" + send "look south\n" expectit "Looks like the river spreads into a marsh." @@ -482,6 +509,18 @@ expectit "Something tells you that the rope won't last for long." send "hut\n" expectit "Homey Hut" +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." + send "look jar\n" expect -re "You look at one.*labeled" @@ -524,11 +563,8 @@ expectit "You take a torch from the bucket." send "inv\n" expectit "Made from marsh grass" -puts "Waiting for Trampolina to sweep us out the door..." -set timeout 240 -# expectit "grabs her broom and with a sweeping motion" -expectit "Mellow Marsh" -set timeout 20 +send "leave\n" +expect "Mellow Marsh" send "north\n" expectit "Frog Meadow" @@ -620,7 +656,7 @@ 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 the sea in the distance?" +expectit "you see sailing in the distance?" send "look boat\n" expectit "The mastless ship looks like a giant leaf. Wonder if it comes to shore?" @@ -826,7 +862,6 @@ expectit "A black iron sconce holding a single" send "look\n" expect -re "You notice.*sconce" -@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. send "get candle\n" expectit "You take the candle, but another magically appears in its place" @@ -904,7 +939,7 @@ send "get bottle\n" expectit "You pick up a bottle." send "look imp\n" -expectit "Peculiar little fellow gives you are quizical look from its roost" +expectit "little fellow gives you a quizical look" send "say Hello there, little guy.\n" expect -re "Imp" @@ -991,7 +1026,7 @@ expectit "Grove of the Matriarchs" send "climb boulder\n" expectit "Boulder Top" -send "look patch of mushrooms\n" +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" diff --git a/world/version1.ev b/world/version1.ev index c749ad9..7b6a38b 100644 --- a/world/version1.ev +++ b/world/version1.ev @@ -1,4 +1,4 @@ -# 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. @@ -27,7 +27,7 @@ py self.db.pose = True pose looking awesome # Create an Avatar:4 ends here -# 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. @@ -67,7 +67,29 @@ pose looking awesome @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. # The Grove of the Matriarchs:5 ends here -# Puddle + +# When you first log into the game, you can immediately chat with an unfriendly, overly boring tree. + +# [[file:../../../projects/mud.org::*Barkbinder the Tree][Barkbinder the Tree:1]] +@create/drop tree;trees: typeclasses.chatbots.ChatBot +# +@set tree/gender = "neutral" +# +@set tree/pose = "contemplating...or sleeping" +# +@set tree/pose_sleep = "contemplating...or sleeping" +# Barkbinder the Tree:1 ends here + + + +# Then wake it. + + +# [[file:../../../projects/mud.org::*Barkbinder the Tree][Barkbinder the Tree:2]] +py tree = me.search("tree") ; tree.sdesc.add("especially large tree") ; tree.backstory("tree") +# Barkbinder the Tree:2 ends here + + # With my name, I need to have an object to go with it. @@ -95,7 +117,7 @@ pose looking awesome @set puddle/get_err_msg = "As the water slips through your fingers, you realize the apt metaphor of attempting to grasp at your youth." # Puddle:3 ends here -# 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. @@ -108,7 +130,7 @@ py timed_script = evennia.create_script(key="Create Sticks", attributes=[("destination", here)] ) # Sticks:1 ends here -# Guest Book + # Players can leave messages in this book. We’ll see how long I want to leave this. @@ -153,7 +175,7 @@ py timed_script = evennia.create_script(key="Create Sticks", @detail well;ink well = The well appears to be little more than a depression on the back of the mushroom's cap. # Guest Book:4 ends here -# Boulder + # More details about the room that describes aspects of the boulder in the =desc= above. First, the symbol: # [[file:../../../projects/mud.org::*Boulder][Boulder:1]] @@ -227,7 +249,7 @@ py timed_script = evennia.create_script(key="Create Sticks", @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." # Boulder:9 ends here -# Lower Vines + # In case they attempt to get vines here: # Let’s make a nice spot to sit down on: @@ -275,7 +297,7 @@ py timed_script = evennia.create_script(key="Create Sticks", @set vines/push_msg = "That doesn't seem to do much." # Lower Vines:5 ends here -# Top of Boulder + # Let’s jump to the top of the boulder to proceed: @@ -315,7 +337,7 @@ py timed_script = evennia.create_script(key="Create Sticks", @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..." # Top of Boulder:6 ends here -# Moss + # Let’s make a nice spot to sit down on: # [[file:../../../projects/mud.org::*Moss][Moss:1]] @@ -363,7 +385,7 @@ py timed_script = evennia.create_script(key="Create Sticks", @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." # Moss:6 ends here -# 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. @@ -444,7 +466,7 @@ py timed_script = evennia.create_script(key="Create Sticks", @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." # Upper Vines:9 ends here -# Gigglecap Mushrooms + # Part of the [[Potions and their Ingredients][Alchemist Path]], we use /gigglecaps/ to create a [[Laughing Potion]]. @@ -479,12 +501,13 @@ py timed_script = evennia.create_script(key="Create Sticks", @lock mushrooms = view:tag(alchemist) # Gigglecap Mushrooms:1 ends here -# Squirrel + # Here for hints … and a bit of a distraction. # [[file:../../../projects/mud.org::*Squirrel][Squirrel:1]] @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. # @@ -501,91 +524,100 @@ py timed_script = evennia.create_script(key="Create Sticks", @set squirrel/arrive = "20 ;; emote briefly opens her eyes, nods an acknowledgement to you. ;; gm The small squirrel returns to her meditation." # Squirrel:2 ends here -# Field + + +# And turn on the real sayings: + + +# [[file:../../../projects/mud.org::*Squirrel][Squirrel:4]] +py me.search("squirrel").backstory("squirrel") +# Squirrel:4 ends here + + # To the east, let’s make a nice meadow. Start at the Forest: -# [[file:../../../projects/mud.org::*Field][Field:1]] +# [[file:../../../projects/mud.org::*Frog Meadow][Frog Meadow:1]] @teleport mp01 -# Field:1 ends here +# Frog Meadow:1 ends here # And we use the =tunnel= command this time: -# [[file:../../../projects/mud.org::*Field][Field:2]] +# [[file:../../../projects/mud.org::*Frog Meadow][Frog Meadow:2]] @dig Frog Meadow;mp05 : typeclasses.rooms_weather.TimeWeatherRoom = east footpath to meadow;east;e;path;footpath,west footpath to forest;footpath;west;w;path -# Field:2 ends here +# Frog Meadow:2 ends here # A description if they look east: -# [[file:../../../projects/mud.org::*Field][Field:3]] +# [[file:../../../projects/mud.org::*Frog Meadow][Frog Meadow:3]] @desc east = A winding footpath that may lead out of the forest... Is that a meadow? -# Field:3 ends here +# Frog Meadow:3 ends here # And a nice journey message to go east out of the forest: -# [[file:../../../projects/mud.org::*Field][Field:4]] +# [[file:../../../projects/mud.org::*Frog Meadow][Frog Meadow:4]] @set east/traverse_msg = "The mossy tree roots that borders this footpath begin to thin out to clover and flowers..." -# Field:4 ends here +# Frog Meadow:4 ends here # Before we label it, we follow =east=: -# [[file:../../../projects/mud.org::*Field][Field:5]] +# [[file:../../../projects/mud.org::*Frog Meadow][Frog Meadow:5]] @teleport mp05 -# Field:5 ends here +# Frog Meadow:5 ends here # And a description that takes advantage of the time of day. We should get busy and get some seasonal description here. -# [[file:../../../projects/mud.org::*Field][Field:6]] +# [[file:../../../projects/mud.org::*Frog Meadow][Frog Meadow:6]] @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. -# Field:6 ends here +# Frog Meadow:6 ends here # Along with a mesage: -# [[file:../../../projects/mud.org::*Field][Field:7]] +# [[file:../../../projects/mud.org::*Frog Meadow][Frog Meadow:7]] @set footpath/traverse_msg = "You leave the open meadow for the footpath through the giant trees. The yellow flowers nod goodbye to you..." -# Field:7 ends here +# Frog Meadow:7 ends here # And a description: -# [[file:../../../projects/mud.org::*Field][Field:8]] +# [[file:../../../projects/mud.org::*Frog Meadow][Frog Meadow:8]] @desc footpath = This footpath goes in a forest of immense trees. -# Field:8 ends here +# Frog Meadow:8 ends here -# Can the waterfall be a detail or an actual object? +# And details of the field. -# [[file:../../../projects/mud.org::*Field][Field:9]] -@detail field = A slow-moving |Ystream|n meanders like a snake in the grassy field. Little green |Yfrogs|n cling to grass stems hanging over the water. -# Field:9 ends here +# [[file:../../../projects/mud.org::*Frog Meadow][Frog Meadow:9]] +@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. +# Frog Meadow:9 ends here # And detail the frogs: -# [[file:../../../projects/mud.org::*Field][Field:10]] +# [[file:../../../projects/mud.org::*Frog Meadow][Frog Meadow:10]] @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?" -# Field:10 ends here +# Frog Meadow:10 ends here + -# Waterfall # This is special, in that it should be hidden: @@ -620,7 +652,7 @@ py timed_script = evennia.create_script(key="Create Sticks", @detail pool = A pool of cool, clear water. # Waterfall:5 ends here -# 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]]. @@ -642,7 +674,7 @@ py timed_script = evennia.create_script(key="Create Sticks", @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."] # Fizzy Water:1 ends here -# Tickleweed + # Part of the [[Potions and their Ingredients][Alchemist Path]], we use /tickleweed grass/ to create a [[Laughing Potion]]. @@ -675,7 +707,7 @@ py timed_script = evennia.create_script(key="Create Sticks", @lock tickleweed = view:tag(alchemist) # Tickleweed:1 ends here -# The Lair of the Beast + # To create a place for our big, hairy beast to sleep, first jump to the Meadow: # [[file:../../../projects/mud.org::*The Lair of the Beast][The Lair of the Beast:1]] @@ -752,7 +784,7 @@ py timed_script = evennia.create_script(key="Create Sticks", @set leave/traverse_msg = "You leave the dark cave and pass behind the waterfall for the meadow beyond." # The Lair of the Beast:9 ends here -# Mattress + # Create a mattress you can sit on (and maybe /push/ to get to a secret door): @@ -812,7 +844,7 @@ py timed_script = evennia.create_script(key="Create Sticks", @set mattress/hidden_tag = "hidden_mattress" # Mattress:6 ends here -# Dream Mushrooms + # Part of the [[Potions and their Ingredients][Alchemist Path]], we use /dream mushrooms/ to create a [[Trippy Potion]]. # #+begin_quote @@ -843,7 +875,7 @@ py timed_script = evennia.create_script(key="Create Sticks", @lock mushrooms = view:tag(alchemist) # Dream Mushrooms:1 ends here -# Beast + # And we create the Big, Hairy Beast: @@ -1036,8 +1068,199 @@ py timed_script = evennia.create_script(key="Create Sticks", @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." # Beast:20 ends here -# Mellow Marsh -# The river from the [[Field]] flows into a marsh: + +# To the east of the meadow, let’s make a glade back inside the Forest: + +# [[file:../../../projects/mud.org::*Glade][Glade:1]] +@teleport mp05 +# Glade:1 ends here + + + +# And we use the =tunnel= command this time: + +# [[file:../../../projects/mud.org::*Glade][Glade:2]] +@dig Glittering Glade;mp20 : typeclasses.rooms.Room = east footpath into another forest;east;glade;e,west footpath to meadow;footpath;west;w;path +# Glade:2 ends here + + + +# A description if they look east: + +# [[file:../../../projects/mud.org::*Glade][Glade:3]] +@desc east = Looking at the forest on the east side shows a footpath illuminated by dancing glowing orbs. +# Glade:3 ends here + +# [[file:../../../projects/mud.org::*Glade][Glade:4]] +@detail orbs = The orbs swirl around in a circular pattern creating a mesmerizing vortex of light leading deep into the forest. +# Glade:4 ends here + + + +# And a nice journey message to go east out of the forest: + +# [[file:../../../projects/mud.org::*Glade][Glade:5]] +@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." +# Glade:5 ends here + + + +# Before we label it, we follow =east=: + + +# [[file:../../../projects/mud.org::*Glade][Glade:6]] +@teleport mp20 +# Glade:6 ends here + + + +# And the description won’t have day/night, but we can /reference/ it: + + +# [[file:../../../projects/mud.org::*Glade][Glade:7]] +@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. +# Glade:7 ends here + +# [[file:../../../projects/mud.org::*Glade][Glade:8]] +@detail orbs = The orbs swirl above illuminating the glade. +# Glade:8 ends here + +# [[file:../../../projects/mud.org::*Glade][Glade:9]] +@detail trees = Ancient trees surround this glade like walls. +# Glade:9 ends here + +# [[file:../../../projects/mud.org::*Glade][Glade:10]] +@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. +# Glade:10 ends here + + + +# A description if they look back towards the west: + +# [[file:../../../projects/mud.org::*Glade][Glade:11]] +@desc west = The footpath leads out of the forest to a meadow. +# Glade:11 ends here + + + +# And a nice journey message to go east out of the forest: + +# [[file:../../../projects/mud.org::*Glade][Glade:12]] +@set west/traverse_msg = "You followed the illuminated footpath until you exit the forest into a meadow." +# Glade:12 ends here + + +# 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: + + +# [[file:../../../projects/mud.org::*Stone Table][Stone Table:1]] +@create/drop stone table:typeclasses.puzzles.StoryCube +# Stone Table:1 ends here + + + +# And a description must be careful with the newlines to make the verse work: + + +# [[file:../../../projects/mud.org::*Stone Table][Stone Table:2]] +@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 earth combined,|/ No solid form, yet firm when dried.|/ Clinging to feet. Adored by boar.|/ Speak my name to open the door. +# Stone Table:2 ends here + + + +# And some flavor that offers a hint to the answer of the riddle, to combine Water and Earth: + + +# [[file:../../../projects/mud.org::*Stone Table][Stone Table:3]] +@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. +# Stone Table:3 ends here + + + +# The table shouldn’t be stealable: + +# [[file:../../../projects/mud.org::*Stone Table][Stone Table:4]] +@lock table = get:false() +# +@set table/get_err_msg = "That table is much too big for you to lift." +# Stone Table:4 ends here + + + +# Answer the riddle to be able to go to the Tavern: + + +# [[file:../../../projects/mud.org::*Stone Table][Stone Table:5]] +@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"} +# Stone Table:5 ends here + + +# This now needs to be transferred from the [[file:mud-rpg.org][mud-rpg]] file. + + +# [[file:../../../projects/mud.org::*Tavern: Wyldwood Bar][Tavern: Wyldwood Bar:1]] +@dig Wyldwood Bar;mp10 = blue door;door,blue door to forest;leave;outside +# Tavern: Wyldwood Bar:1 ends here + + + +# And describe it: + +# [[file:../../../projects/mud.org::*Blue Door][Blue Door:2]] +@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. +# Blue Door:2 ends here + + + +# The dock is locked: + + +# [[file:../../../projects/mud.org::*Blue Door][Blue Door:3]] +@set blue door/err_traverse = "The door seems locked...or at least, won't budge." +# Blue Door:3 ends here + + + +# Openable if you have the correct tag: + +# [[file:../../../projects/mud.org::*Blue Door][Blue Door:4]] +@lock blue door = traverse:tag(open_blue_door) +# Blue Door:4 ends here + + + +# Let’s have an interesting phrase entering the bar … + +# [[file:../../../projects/mud.org::*Blue Door][Blue Door:7]] +@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." +# Blue Door:7 ends here + + +# Let’s hop into the Bar in order to work it over: + +# [[file:../../../projects/mud.org::*Inside the Bar][Inside the Bar:1]] +@tel mp10 +# Inside the Bar:1 ends here + + + +# And describe the door leaving the bar: + + +# [[file:../../../projects/mud.org::*Inside the Bar][Inside the Bar:7]] +@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? +# Inside the Bar:7 ends here + + + +# Let’s have an interesting phrase entering the bar … + +# [[file:../../../projects/mud.org::*Inside the Bar][Inside the Bar:8]] +@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." +# Inside the Bar:8 ends here + + +# The river from the flows into a marsh: # [[file:../../../projects/mud.org::*Mellow Marsh][Mellow Marsh:1]] @@ -1139,7 +1362,7 @@ py timed_script = evennia.create_script(key="Create Sticks", @detail mud = Pretty brown and sticky. # Mellow Marsh:15 ends here -# Muddy Water + # As a future idea of making potions, we can collect /muddy water/, which needs to be turned to wine. @@ -1161,7 +1384,7 @@ py timed_script = evennia.create_script(key="Create Sticks", @set river/fill_msgs = ["$You() << $conj(get) ^ $conj(kneel) >> down, and $conj(fill) $pron(your) {2} with the muddy water."] # Muddy Water:1 ends here -# Purple Heron + # Create a puppet of the bird hunting frogs and pixies. :-D @@ -1258,7 +1481,7 @@ py me.search("heron").backstory("heron") @script heron = typeclasses.scripts.Muttering # Purple Heron:9 ends here -# 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. @@ -1315,7 +1538,7 @@ py me.search("heron").backstory("heron") @set reeds/make_amount = 1 # Ten-foot Poles:8 ends here -# 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: @@ -1347,9 +1570,6 @@ py me.search("heron").backstory("heron") @lock pixie dust = view:tag(alchemist) # Pixie Dust:1 ends here -# Trampoli’s Hut on Stilts - - # [[file:../../../projects/mud.org::*Trampoli’s Hut on Stilts][Trampoli’s Hut on Stilts:1]] @teleport mp08 # @@ -1450,7 +1670,7 @@ py me.search("heron").backstory("heron") @teleport/tonone rope-bound hut # Trampoli’s Hut on Stilts:12 ends here -# Inside Trampoli’s Hut + # Let’s go inside to decorate: @@ -1486,7 +1706,38 @@ py me.search("heron").backstory("heron") @detail jars = Sealed jars of fruits, vegetables, herbs and spices. # Inside Trampoli’s Hut:5 ends here -# Jars + +# A chair to sit while working + +# [[file:../../../projects/mud.org::*Chair][Chair:1]] +@create/drop chair:typeclasses.sittables.Sittable +# Chair:1 ends here + + + +# How descriptive: + +# [[file:../../../projects/mud.org::*Chair][Chair:2]] +@desc chair = A chair next to the table. +# Chair:2 ends here + + + +# Can’t steal this chair either: + +# [[file:../../../projects/mud.org::*Chair][Chair:3]] +@lock chair = get:false() +# Chair:3 ends here + + + +# Let’s do a funnier message: + +# [[file:../../../projects/mud.org::*Chair][Chair:4]] +@set chair/get_err_msg = "Stop trying to steal everything not nailed down." +# Chair:4 ends here + + # Every time we look at a jar, we see something else … that we can’t take. This creates ambiance without adding too much complexity? @@ -1545,7 +1796,7 @@ py me.search("heron").backstory("heron") ) # Jars:4 ends here -# Herbs + # Like the [[*Jars][Jars]], the herbs return a different response each time they are viewed. @@ -1602,9 +1853,6 @@ py me.search("heron").backstory("heron") ) # Herbs:4 ends here -# Bag of Mermaid Tears - - # [[file:../../../projects/mud.org::*Bag of Mermaid Tears][Bag of Mermaid Tears:1]] @create/drop couple of bags of dried Mermaid Tears;bags;bag: typeclasses.consumables.Producer # Bag of Mermaid Tears:1 ends here @@ -1635,7 +1883,7 @@ py me.search("heron").backstory("heron") @lock bags = view:tag(alchemist) # Bag of Mermaid Tears:3 ends here -# Talismans + # To give some character, we create some interesting art that decorates this hut. @@ -1643,7 +1891,7 @@ py me.search("heron").backstory("heron") @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. # Talismans:1 ends here -# 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. @@ -1661,7 +1909,7 @@ py me.search("heron").backstory("heron") @lock skull = view:tag(hidden_wolf_skull) # Horned Wolf Skull:1 ends here -# Demon Carving + # Perhaps the carving is actually the maid or something that could give hints. @@ -1679,7 +1927,7 @@ py me.search("heron").backstory("heron") @lock carving = view:tag(hidden_demon_carving) # Demon Carving:1 ends here -# Reed Sculpture + # The reeds should give a subtle hint to something that could be /spoken/ aloud. @@ -1713,7 +1961,7 @@ py timed_script = evennia.create_script(key="Create Horns", attributes=[("destination", here)] ) # Reed Sculpture:3 ends here -# 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. @@ -1782,12 +2030,13 @@ py timed_script = evennia.create_script(key="Create Horns", @set bucket/make_amount = 1 # Torches:8 ends here -# Trampoli the Witch + # Create a puppet of the lady that owns the hut. # [[file:../../../projects/mud.org::*Trampoli the Witch][Trampoli the Witch:1]] -@create/drop Trampoli;old lady: typeclasses.puppets.Puppet +@create/drop Trampoli;old lady: typeclasses.chatbots.Witch +# @update Trampoli = typeclasses.chatbots.Witch # Trampoli the Witch:1 ends here @@ -1833,15 +2082,6 @@ py timed_script = evennia.create_script(key="Create Horns", # Trampoli the Witch:7 ends here - -# If I do this, then she can’t really be puppeted. - - -# [[file:../../../projects/mud.org::*Trampoli the Witch][Trampoli the Witch:8]] -@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" -# Trampoli the Witch:8 ends here - -# 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: @@ -1919,7 +2159,7 @@ Someone has set a nice |Ychair|n for viewing. @desc north = This path leads into the forest of collosal trees. # Lazy Dock:9 ends here -# Lavender Sea + # We’ll get ready for making potions by allowing one to collect water from _all_ the places, like the salty sea: @@ -1941,7 +2181,7 @@ Someone has set a nice |Ychair|n for viewing. @set sea/fill_msgs = ["$You() $conj(reach) down from the dock, and $conj(fill) $pron(your) {2} with the << salty ^ lavender ^ fragrant >> water."] # Lavender Sea:1 ends here -# Chair + # A nice chair to sit on the dock by the bay, watching the clouds as they drift away. # [[file:../../../projects/mud.org::*Chair][Chair:1]] @@ -1966,7 +2206,7 @@ Someone has set a nice |Ychair|n for viewing. @set chair/get_err_msg = "It's way too heavy for you to lift." # Chair:3 ends here -# Fishing Pole + # It we are going to sit on a chair by the dock, why not go fishing? # [[file:../../../projects/mud.org::*Fishing Pole][Fishing Pole:1]] @@ -2000,7 +2240,7 @@ Someone has set a nice |Ychair|n for viewing. @detail hook;bait = One of those shiny lures, made from gold coins. Curiouser. Seems you don't need to bait this hook. # Fishing Pole:5 ends here -# Sign + # Need to make the fishing pole “stay” at the Dock. Maybe with a message about sticking around for the next person. @@ -2034,16 +2274,18 @@ Someone has set a nice |Ychair|n for viewing. @set sign/get_err_msg = "This granny knot holding the sign to the chair is serious. You can't take it." # Sign:4 ends here -# Raven + # Here for hints … and a bit of a distraction. # [[file:../../../projects/mud.org::*Raven][Raven:1]] @create/drop Raven;bird: typeclasses.chatbots.ChatBot # +# @update raven = typeclasses.chatbots.ChatBot +# @desc raven = A large raven with curious black eyes. # -@set raven/gender = "neuter" +@set raven/gender = "neutral" # @set raven/pose = "dozing while perched on a branch" # @@ -2054,7 +2296,16 @@ Someone has set a nice |Ychair|n for viewing. # @sdesc large raven # Raven:1 ends here -# Sandy Shore + + +# Let’s load the goodies: + + +# [[file:../../../projects/mud.org::*Raven][Raven:2]] +py me.search("raven").backstory("raven") +# Raven:2 ends here + + # Could we extend the sea from the [[file:mud.org::*The Dock][The Dock]] down a shore: @@ -2126,7 +2377,7 @@ Someone has set a nice |Ychair|n for viewing. @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. # Sandy Shore:8 ends here -# Sand + # Part of the [[Potions and their Ingredients][Alchemist Path]], we use sand as an ingredient in a potion we want to make. @@ -2144,7 +2395,7 @@ Someone has set a nice |Ychair|n for viewing. @lock sand = view:tag(hidden_sand) # Sand:1 ends here -# 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. @@ -2164,7 +2415,7 @@ Someone has set a nice |Ychair|n for viewing. @lock pine = view:tag(alchemist) # We want the user to be able to "look pine" as a detail? # Pine Flowers:1 ends here -# Sign + # We make the sign as an “object” for others to read: @@ -2178,7 +2429,7 @@ Someone has set a nice |Ychair|n for viewing. @lock sign = get:false() # Sign:1 ends here -# Salty Shack + # Let’s keep this pretty empty. @@ -2232,7 +2483,7 @@ Someone has set a nice |Ychair|n for viewing. @set door/traverse_msg = "You open the door and step out on the sand, closing the door behind you." # Salty Shack:5 ends here -# Grotto + # Return to the forest: @@ -2325,7 +2576,7 @@ Someone has set a nice |Ychair|n for viewing. @detail fern;ferns = Sword ferns rattling sabers against the wards from the Maiden Hairs' flailing their fronds. # Grotto:11 ends here -# 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. @@ -2413,7 +2664,7 @@ Someone has set a nice |Ychair|n for viewing. #"Those were <>." # Berry Bush:12 ends here -# Spring Water + # Part of the [[Potions and their Ingredients][Alchemist Path]], we use spring water to create a [[Trippy Potion]]. @@ -2435,7 +2686,7 @@ Someone has set a nice |Ychair|n for viewing. @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."] # Spring Water:1 ends here -# 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: @@ -2506,7 +2757,7 @@ Someone has set a nice |Ychair|n for viewing. @set here/knock_err_msg = "This door knocker is defective, as it doesn't have a ring to...er, do the knockin'." # Knocker:8 ends here -# Ring + # Since we can remove the ring, let’s create it: @@ -2523,7 +2774,7 @@ Someone has set a nice |Ychair|n for viewing. # Ring:2 ends here -# ]] + # And a description: # [[file:../../../projects/mud.org::*Ring][Ring:3]] @@ -2568,7 +2819,7 @@ Someone has set a nice |Ychair|n for viewing. @teleport/quiet ring = knocker # Ring:7 ends here -# Cozy House + # Add the Python /special-ness/ for [[file:~/src/moss-n-puddles/typeclasses/rooms.py::class DabblersRoom(Room):][this room]]: @@ -2576,7 +2827,7 @@ Someone has set a nice |Ychair|n for viewing. @dig Cozy House;mp03: typeclasses.rooms.DabblersRoom = red door;door;inside,outside;leave # Cozy House:1 ends here -# Red Door + # The door description should match the artwork on the website: # [[file:../../../projects/mud.org::*Red Door][Red Door:1]] @@ -2615,7 +2866,7 @@ Someone has set a nice |Ychair|n for viewing. @set door/hidden_tag = "hidden_knocker" # Red Door:5 ends here -# Inside + # Fix the inside of the “House”: @@ -2686,7 +2937,7 @@ Someone has set a nice |Ychair|n for viewing. @set here/arrive = "45 ;; gm The rain << patters ^ chatters ^ drums >> against a window << sill ^ pane >>. Nice to be << indoors ^ inside >>." # Inside:6 ends here -# Tapestry Story + # The tapestry should tell our /creation myth/. # [[file:../../../projects/mud.org::*Tapestry Story][Tapestry Story:1]] @@ -2705,7 +2956,7 @@ Someone has set a nice |Ychair|n for viewing. @detail whispering = This curious aspect in the |Ytapestry|n seems ... odd. # Tapestry Story:1 ends here -# Fireplace + # And a fire in the fireplace is a type of /pet/, since we can feed it: # [[file:../../../projects/mud.org::*Fireplace][Fireplace:1]] @@ -2751,7 +3002,7 @@ Someone has set a nice |Ychair|n for viewing. @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. # Fireplace:6 ends here -# Wood Rack + # Need a way to produce wood for the fireplace. @@ -2826,7 +3077,7 @@ Someone has set a nice |Ychair|n for viewing. @lock wood rack = view:tag(hidden_woodrack) # Wood Rack:9 ends here -# Knickknacks + # What sort of non-books do we want to look at? @@ -2845,7 +3096,7 @@ Someone has set a nice |Ychair|n for viewing. @set trinkets/get_err_msg = "While interesting, perhaps you shouldn't steal Dabbler's personal collection." # Knickknacks:2 ends here -# Magic 8 Ball + # One trinket we might create to give to people as a souvenir. @@ -2875,7 +3126,7 @@ Someone has set a nice |Ychair|n for viewing. drop ball # Magic 8 Ball:3 ends here -# Bookshelf + # Since we mentioned shelves of books, we should create a Producer that makes a random book. @@ -2892,7 +3143,7 @@ drop ball @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. # Bookshelf:2 ends here -# 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. @@ -2940,7 +3191,7 @@ drop ball @set chairs/extra = "This feels << ^ very ^ quite>> <>.|n" # Chairs:5 ends here -# Character: Dabbler + # My characters should be NPCs, so they can stick around if I’m not logged in. @@ -3029,7 +3280,7 @@ pose gnome/default = smoking his pipe @give waistcoat = gnome # Character: Dabbler:10 ends here -# Staff + # And my staff: @@ -3056,7 +3307,7 @@ pose gnome/default = smoking his pipe @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." # Staff:2 ends here -# Pipe + # The pipe is little more than messages to the smoker and everyone else in the room. @@ -3075,7 +3326,7 @@ pose gnome/default = smoking his pipe @give pipe = gnome # Pipe:2 ends here -# Journal + # The pipe is little more than messages to the smoker and everyone else in the room. @@ -3105,7 +3356,7 @@ pose gnome/default = smoking his pipe @give journal = gnome # Journal:3 ends here -# Stoat + # Need an interesting creature that likes to sleep by the fire, and perhaps give hints to the workings inside. # - feed :: ignores all food. @@ -3275,7 +3526,7 @@ pose gnome/default = smoking his pipe # @set stoat/sit = "3 ;; gm A sleeping << wee ^ >> beastie, opens one curious eye to see who arrived." # Stoat:18 ends here -# Kitchen + # Better place to put the tea and scones. @@ -3335,7 +3586,7 @@ pose gnome/default = smoking his pipe @detail scone;scones = A scones look tempting. Perhaps no one will miss one... # Kitchen:7 ends here -# 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. @@ -3359,7 +3610,7 @@ pose gnome/default = smoking his pipe py here.search("cabinet").do_bake() # Cabinets and Counter-tops:3 ends here -# Tea Service + # The “room” gives the teacups, and the “teapot” fills the cups, so we just need descriptions: @@ -3390,7 +3641,7 @@ py here.search("cabinet").do_bake() @set teapot/get_err_msg = "You don't need to carry it around to make tea." # Tea Service:3 ends here -# Secret Room + # Pulling on a candle opens a secret staircase! @@ -3411,7 +3662,7 @@ py here.search("cabinet").do_bake() @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." # Secret Room:2 ends here -# Sconce + # The Candle holder must be both an Opener (with a =do_pull= method) and a Producer (making long-lasting candles). @@ -3490,7 +3741,7 @@ py here.search("cabinet").do_bake() @set sconce/make_amount = 1 # Sconce:9 ends here -# Pulling Sconce + # Temporarily move the exit into the room. @@ -3507,7 +3758,7 @@ py here.search("cabinet").do_bake() @teleport/tonone stairs behind bookcase # Pulling Sconce:2 ends here -# Inside the Secret Room + # Time to create the secret lab, the *Secret Room*. @@ -3567,7 +3818,7 @@ py here.search("cabinet").do_bake() @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. # Inside the Secret Room:8 ends here -# 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? @@ -3633,7 +3884,7 @@ py here.search("cabinet").do_bake() ) # Jars:4 ends here -# Stool + # A stool to sit while working # [[file:../../../projects/mud.org::*Stool][Stool:1]] @@ -3664,7 +3915,7 @@ py here.search("cabinet").do_bake() @set stool/get_err_msg = "Stop trying to steal everything not nailed down." # Stool:4 ends here -# Grimoire + # A mystic book of potions can add a new dimension to the game. @@ -3713,7 +3964,7 @@ py here.search("cabinet").do_bake() @set grimoire/prefix = "Undoing the brass clasp that bind the old leather book, you open to page one and begin reading the elegant calligraphy..." # Grimoire:5 ends here -# 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 @@ -3747,7 +3998,7 @@ py here.search("cabinet").do_bake() @lock cauldron = get:false() # Cauldron:3 ends here -# Shelf of Bottles + # The table is a producer of /bottles/. @@ -3786,7 +4037,7 @@ py here.search("cabinet").do_bake() @set shelf/make_amount = 1 # Shelf of Bottles:4 ends here -# Imp + # Every secret alchemical lab should have an Imp familiar. @@ -3824,7 +4075,7 @@ py bt = self.search('imp'); bt.sdesc.add('imp'); bt.db.pose = 'sitting on an orn # [[file:../../../projects/mud.org::*Imp][Imp:5]] -@desc imp = Peculiar little fellow gives you are quizical look from its roost on a wrought iron perch that it clutches with its clawed feet and barbed, prehensile tail. +@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. # Imp:5 ends here @@ -3845,7 +4096,7 @@ py bt = self.search('imp'); bt.sdesc.add('imp'); bt.db.pose = 'sitting on an orn @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 >>." # Imp:8 ends here -# Bedroom + # A bedroom with a wardrobe that goes to another land sounds great. @@ -3917,7 +4168,7 @@ py bt = self.search('imp'); bt.sdesc.add('imp'); bt.db.pose = 'sitting on an orn @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." # Bedroom:6 ends here -# Wardrobe + # One needs to open it to go to another world. @@ -3987,7 +4238,7 @@ py bt = self.search('imp'); bt.sdesc.add('imp'); bt.db.pose = 'sitting on an orn @set wardrobe/get_err_msg = "The wardrobe is way too big to lift." # Wardrobe:6 ends here -# Southwest Prairie + # What am I doing here? @@ -4021,7 +4272,7 @@ py bt = self.search('imp'); bt.sdesc.add('imp'); bt.db.pose = 'sitting on an orn @detail campfire;fire = Only a thin wisp of smoke escapes to the skies; fragrating the air. # Southwest Prairie:3 ends here -# Mare’s Head + # Taken from [[https://en.wikipedia.org/wiki/Mare%27s_Head][Wikipedia]]. @@ -4086,7 +4337,7 @@ py bt = self.search('head'); bt.sdesc.add('curious figure'); bt.db.pose = 'sitti @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 >>." # Mare’s Head:8 ends here -# Pull up a Log + # Let’s allow anyone here to sit on a log next to the campfire .. @@ -4123,7 +4374,128 @@ py bt = self.search('head'); bt.sdesc.add('curious figure'); bt.db.pose = 'sitti @set log/singular = "the log next to the campfire" # Pull up a Log:4 ends here -# Bugs + +# The deep forest is a place where all the Puppets can hang out when not in use. + +# [[file:../../../projects/mud.org::*Deep Forest][Deep Forest:1]] +@dig the Deep Forest;mp00 +# +@teleport mp00 +# Deep Forest:1 ends here + + + +# What do we have left to describe: + + +# [[file:../../../projects/mud.org::*Deep Forest][Deep Forest:2]] +@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. +# Deep Forest:2 ends here + + + +# And create an easy exit back to the game: + + +# [[file:../../../projects/mud.org::*Deep Forest][Deep Forest:3]] +@open portal;leave;enter;exit = Grotto +# Deep Forest:3 ends here + + + +# And do the usual tricks on Exits: + + +# [[file:../../../projects/mud.org::*Deep Forest][Deep Forest:4]] +@desc portal = Octarine sparks spiral in the mists that swirl between the stones. +# Deep Forest:4 ends here + + + +# And a nice journey message to go east out of the forest: + +# [[file:../../../projects/mud.org::*Deep Forest][Deep Forest:5]] +@set portal/traverse_msg = "As soon as you step between the stones, you feel like you are carried away..." +# Deep Forest:5 ends here + + +# 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. + + +# [[file:../../../projects/mud.org::*Darol the Flamboyant Dragon][Darol the Flamboyant Dragon:1]] +@create/drop Darol: typeclasses.chatbots.Traveler +# +@set Darol/gender = "him" +# +@set Darol/pose = "twirling a tendril like a mustache" +# +@set Darol/pose_sleep = "twirling a tendril like a mustache" +# Darol the Flamboyant Dragon:1 ends here + + + +# Then wake it. + + +# [[file:../../../projects/mud.org::*Darol the Flamboyant Dragon][Darol the Flamboyant Dragon:2]] +@update dragon = typeclasses.chatbots.Dragon +# +py darol = me.search("dragon") ; darol.sdesc.add("tiny, orange dragon") ; darol.backstory("dragon") +# Darol the Flamboyant Dragon:2 ends here + + + +# And get it moving: + + +# [[file:../../../projects/mud.org::*Darol the Flamboyant Dragon][Darol the Flamboyant Dragon:3]] +@script Darol = typeclasses.chatbots.TravelingNPC +# Darol the Flamboyant Dragon:3 ends here + +# [[file:../../../projects/mud.org::*Rick the Barbarian][Rick the Barbarian:1]] +@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" +# Rick the Barbarian:1 ends here + + + +# Then wake her. + + +# [[file:../../../projects/mud.org::*Rick the Barbarian][Rick the Barbarian:2]] +py rick = me.search("rick") ; rick.sdesc.add("large barbarian") ; rick.backstory("barbarian") +# Rick the Barbarian:2 ends here + + +# This Dwarf will be in the dungeons, but I would like them to come out at times. + +# [[file:../../../projects/mud.org::*George the Dwarf Tinkerer][George the Dwarf Tinkerer:1]] +@create/drop George: typeclasses.chatbots.Chatbot +# +@set George/gender = "him" +# +@set George/pose = "looking at some blueprints" +# +@set George/pose_sleep = "snoozing" +# George the Dwarf Tinkerer:1 ends here + + + +# Then wake it. + + +# [[file:../../../projects/mud.org::*George the Dwarf Tinkerer][George the Dwarf Tinkerer:2]] +py george = me.search("george") ; george.sdesc.add("white-haired dwarf") ; george.backstory("dwarf") +# George the Dwarf Tinkerer:2 ends here + + # And now that we are done, say it: