Improve the chatbot interaction

This commit is contained in:
Howard Abrams 2026-04-08 20:54:27 -07:00
parent 7c0c92d761
commit c9b602e0ab
7 changed files with 821 additions and 183 deletions

View file

@ -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. playing game in a mythical forest in the Feywild.
Although, you should never mention the word "Feywild", but instead, Although, you should never mention the word "Feywild", but instead,
come up with clever names or metaphors for the strange world you inhabit. 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. Use variations from the "Description" field to state who is talking, not your name.
You can also respond with an action. You can also respond with an action.
The person you are talking to does not know your actual name. 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 Description: tiny, orange dragon
Pose: twirling a tendril near his mouth like a mustache. Pose: twirling a tendril near his mouth like a mustache.
Gender: male 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 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. expresses his delight by the twitching of his barbed tail.
Your personality: He's a John Mulany gay character who loves to find Your personality: He's an awkward and nerdy John Mulany gay character
out and spread gossip. Often using a "Southern Accent". 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 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, 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 but he's just gotta "get this off of his scaly chest." So feel free to

View file

@ -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. 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 <drink name> = <customer>
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. 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.

View file

@ -10,7 +10,7 @@ from os import listdir, path
from pathlib import Path from pathlib import Path
from random import choice from random import choice
from re import match, search, split, sub, IGNORECASE 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 import logger, delay
from evennia.utils.search import search_object from evennia.utils.search import search_object
@ -31,7 +31,7 @@ def fix_paragraph(paragraph):
sentences = split(r'(?<=[.!?])\s+', paragraph) sentences = split(r'(?<=[.!?])\s+', paragraph)
# Remove the last sentence if it doesn't end with punctuation # 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() sentences.pop()
return ' '.join(sentences) return ' '.join(sentences)
@ -39,7 +39,6 @@ def fix_paragraph(paragraph):
class ChatBot(Puppet): class ChatBot(Puppet):
""" """
py me.search("squirrel").backstory("squirrel") py me.search("squirrel").backstory("squirrel")
""" """
@ -105,25 +104,28 @@ class ChatBot(Puppet):
self.db.personality_file = filename self.db.personality_file = filename
return details return details
def setting_and_backstory(self, speaker): def setting_and_backstory(self, speaker=None):
logger.info(f"Reading {self.db.personality_file}") logger.info(f"Reading {self.db.personality_file}")
system_prompt = Path(self.db.personality_file).read_text() system_prompt = Path(self.db.personality_file).read_text()
system_prompt += "\n\n" system_prompt += "\n\n"
system_prompt += "You are currently in " + speaker.location.key + ". " system_prompt += "You are currently in " + self.location.key + ". "
if speaker.location.key == "Cozy House": if self.location.key == "Cozy House":
system_prompt += "This is the dwelling of the gnome, Dabbler." 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 += "This is the dwelling of the witch, Trampoli."
system_prompt += "Described as " + speaker.location.desc system_prompt += "Described as " + self.location.desc
system_prompt += "\n\n" if speaker:
system_prompt += "You are talking to a " system_prompt += "\n\n"
system_prompt += speaker.db.gender + " " + speaker.sdesc.get() + ". " system_prompt += "You are talking to a "
system_prompt += "Described as " + speaker.db.desc system_prompt += speaker.db.gender + " " + speaker.sdesc.get() + ". "
system_prompt += "Described as " + speaker.db.desc
# logger.info(f"Prompt: {system_prompt}") # logger.info(f"Prompt: {system_prompt}")
return system_prompt return system_prompt
def history_file(self, speaker): 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) filename = path.join(personality_dir, combo_name)
logger.info(f"Chatbot history_file: {filename}") logger.info(f"Chatbot history_file: {filename}")
return Path(filename) return Path(filename)
@ -137,6 +139,20 @@ class ChatBot(Puppet):
messages.append({"role": "assistant", "content": reply}) messages.append({"role": "assistant", "content": reply})
history_file.write_text(json.dumps(messages, indent=2)) 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): def think(self, speaker, speech):
""" """
Ask Claude to think of a reply to speech from speaker. 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}" speech = f"{recent_events}\n\n{speaker.key}: {speech}"
messages.append({"role": "user", "content": speech}) messages.append({"role": "user", "content": speech})
logger.info("Calling out to Anthropic...") reply = self._think(system_prompt, messages)
# 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
# Write reply # Write reply
self.update_history(speaker, messages, reply) self.update_history(speaker, messages, reply)
# logger.info(f"{reply}")
return 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): def other_say(self, speaker, speech):
logger.info(f"Chatbot hears: '{speech}' from {speaker}.") logger.info(f"Chatbot hears: '{speech}' from {speaker}.")
logger.info(f"Characters: {self.characters_here()}") logger.info(f"Characters: {self.characters_here()}")
@ -177,21 +201,11 @@ class ChatBot(Puppet):
if speech: if speech:
logger.info("Starting to think of a reply") logger.info("Starting to think of a reply")
reply = self.think(speaker, speech) reply = self.think(speaker, speech)
logger.info(f"My reply will be: {reply}") self.process_thoughts(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))
def at_msg_receive(self, text=None, from_obj=None, **kwargs): def at_msg_receive(self, text=None, from_obj=None, **kwargs):
super().at_msg_receive(text, from_obj=from_obj, **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: if from_obj != self:
msg = text if isinstance(text, str) else text[0] msg = text if isinstance(text, str) else text[0]
@ -282,3 +296,197 @@ class Witch(ChatBot):
sleep_pose = self.attributes.get("pose_sleep") sleep_pose = self.attributes.get("pose_sleep")
if sleep_pose: if sleep_pose:
self.execute_cmd(f"pose {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

View file

@ -233,7 +233,7 @@ class Muttering(Script):
def at_repeat(self, **kwargs): def at_repeat(self, **kwargs):
""" """
If we have passengers, we need to sail... Time to mutter something...
""" """
self.mutter_sequence() self.mutter_sequence()

View file

@ -48,7 +48,8 @@ MSGS = {
"SAY": [ "SAY": [
"\"How's it going?\" the bird asks, \"Are you enjoying this game so far?\"", "\"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.\"", "\"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.", "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.", "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.\"", "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.", "\"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.\"", "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.", "\"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.\"", "\"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, \"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…\"", "\"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.", "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?\"", "\"What do you say?\" says the bird. \"Think you got the hang of playing this?\"",
] ]
} }

View file

@ -46,13 +46,13 @@ if {$there eq "there"} {
expectit "enclose it in quotes" expectit "enclose it in quotes"
if {$create eq "true"} { if {$create eq "true"} {
send "create rob backinqa\n" send "create robby backinqa\n"
expectit "Is this what you intended?" expectit "Is this what you intended?"
send "y\n" send "y\n"
expectit "You can now log with the command" expectit "You can now log with the command"
} }
send "connect rob backinqa\n" send "connect robby backinqa\n"
if {$create eq "true"} { if {$create eq "true"} {
expectit "begin creating your character" expectit "begin creating your character"
@ -270,7 +270,7 @@ send "look moss\n"
expectit "A cushioned patch of moss of the most vibrant green." expectit "A cushioned patch of moss of the most vibrant green."
send "sit moss\n" send "sit moss\n"
expectit "You sit on the patch of moss." expectit "You sit on the patch"
# We can't get this stuff: # We can't get this stuff:
send "get moss\n" 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" send "look south\n"
expectit "Looks like the river spreads into a marsh." 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" send "hut\n"
expectit "Homey Hut" 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" send "look jar\n"
expect -re "You look at one.*labeled" expect -re "You look at one.*labeled"
@ -524,11 +563,8 @@ expectit "You take a torch from the bucket."
send "inv\n" send "inv\n"
expectit "Made from marsh grass" expectit "Made from marsh grass"
puts "Waiting for Trampolina to sweep us out the door..." send "leave\n"
set timeout 240 expect "Mellow Marsh"
# expectit "grabs her broom and with a sweeping motion"
expectit "Mellow Marsh"
set timeout 20
send "north\n" send "north\n"
expectit "Frog Meadow" expectit "Frog Meadow"
@ -620,7 +656,7 @@ send "look waves\n"
expectit "Despite the inclement weather, the waves ripple gently against the shore." expectit "Despite the inclement weather, the waves ripple gently against the shore."
send "look lavender sea\n" 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" send "look boat\n"
expectit "The mastless ship looks like a giant leaf. Wonder if it comes to shore?" 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" send "look\n"
expect -re "You notice.*sconce" 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" send "get candle\n"
expectit "You take the candle, but another magically appears in its place" 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." expectit "You pick up a bottle."
send "look imp\n" 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" send "say Hello there, little guy.\n"
expect -re "Imp" expect -re "Imp"
@ -991,7 +1026,7 @@ expectit "Grove of the Matriarchs"
send "climb boulder\n" send "climb boulder\n"
expectit "Boulder Top" 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" 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" send "get mushroom\n"

File diff suppressed because it is too large Load diff