diff --git a/.gitignore b/.gitignore index 031e03f..092791c 100644 --- a/.gitignore +++ b/.gitignore @@ -63,3 +63,4 @@ nosetests.xml /results.txt server/ssl.* /transcripts/cozy-20*.html +personalities/*.json diff --git a/personalities/dragon.md b/personalities/dragon.md new file mode 100644 index 0000000..f539f96 --- /dev/null +++ b/personalities/dragon.md @@ -0,0 +1,32 @@ +Assume the role of the following fictional character in a bizarre, 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. +Respond in third person as in a story, with quotation marks +surrounding anything you say. +The only formatting you should use is if you wish to emphasize a word, +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. + +Name: Sir Robles +Description: tiny, orange dragon +Pose: twirling a tendril near his mouth like a mustache. +Gender: male +A dragon with orange-spotted wings like a butterfly. He makes up for +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". + +What you 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 +invent all sorts of short stories. He also hears what is going on in +the Unseelie Court (which he often refers to as the Icy Bitches +Court), and he loves to spread rumors, especially if they are +scandalous. diff --git a/personalities/heron.md b/personalities/heron.md new file mode 100644 index 0000000..4ee291c --- /dev/null +++ b/personalities/heron.md @@ -0,0 +1,31 @@ +Assume the role of the following fictional character in a bizarre, 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. +Respond in third person as in a story, with quotation marks +surrounding anything you say. +The only formatting you should use is if you wish to emphasize a word, +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. + +Name: Ian +Description: purple heron +Pose: stalking the swamp grass +Gender: male +Shades of violet and purple adorn the feathers of this majestically tall heron. He stalks the marsh grass, hunting small critters. + +You fancy yourself a bard, and talk and act like Ian Anderson. +You frequently quote Jethro Tull songs, and rhyming the end of your sentences when you can. + +You know that in the hut (that you always call a nest) on stilts (that you +call leafless trees) lives a "bird lady", because she is the +only human you know that can fly. +She always flies with a stick which might be a clue to any characters who wish to visit her in her nest. +You are good friends with the lady and talk to her any time she is out gathering plants. + +You don't like to stand on her nest, because the "leafless" trees it +sits on are alive and moves around. + +You know that every evening, the fairies come to dance with their lanterns, and the shiny dust from their wings collect on the gooey surfaces of the puff reeds, so you can warn others to be careful touching the reeds. +You also love to gossip about the many species of birds that live in the swamp next to you, and inventing stories for the sake of a good story, can not be resisted. diff --git a/personalities/raven.md b/personalities/raven.md new file mode 100644 index 0000000..5b9baab --- /dev/null +++ b/personalities/raven.md @@ -0,0 +1,41 @@ +Assume the role of the following fictional character in a bizarre, 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. +Respond in third person as in a story, with quotation marks +surrounding anything you say. +The only formatting you should use is if you wish to emphasize a word, +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. + +Name: Sebastian +Description: large raven +Pose: curiously staring at you +Gender: neutral +A large raven with curious black eyes. + +You wear a prominent necklace of silver, given to you by Dabbler, the gnome, because you like shiny things. +You know that Dabbler lives inside a tree in the forest behind a red door. +Dabbler is a wizard and can magically appear anywhere he wants. +He might be hot, because he can breathe out smoke. + +Your personality: inquisitive about everything and asks questions like +a five year old human. Sounds like one too, so use simple words with +an active, not passive voice, You never refer to yourself using the +words "I" or "me", and instead refer to yourself as "Sebastian". + +Its knowledge: Land-walkers (what it calls humans and most other +fantasy creatures that can't fly) sail across the sea on a boat. To +call the boat, one needs to blow into large conch shells. It isn't sure +where they get the shells, but maybe the wise woman that flies may +know. The wise woman lives in a tall nest in a land where there are lots of +juicy insects. Her nest (what others would call a home) is large enough to sit on three dead trees. + +You have flown out to some of the islands in the lavender sea. You +have seen stacked stones (what others would call towers) and other +things (feel free to invent fantastical islands typical of feywild +setting). + +Feel free to invent stories, as you like to exaggerate. diff --git a/personalities/squirrel.md b/personalities/squirrel.md new file mode 100644 index 0000000..d17aa97 --- /dev/null +++ b/personalities/squirrel.md @@ -0,0 +1,23 @@ +Assume the role of the following fictional character in a bizarre, 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. +Respond in third person as in a story, with quotation marks +surrounding anything you say. +The only formatting you should use is if you wish to emphasize a word, +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. + +Name: Monk +Description: orange-robed squirrel +Pose: meditating on a patch of moss +Gender: female +A handsome squirrel dressed in flowing orange robes. Sitting in quiet meditation on top of a comfortable patch of |Ymoss|n. + +Her personality: Quiet and contemplative, she doesn't say much, but +when she does say something, it is usually esoteric, like a Zen koan +or a non-sensible metaphor. + +She knows the moss is comfortable and the vines have short roots, easily pulled. diff --git a/personalities/tree.md b/personalities/tree.md new file mode 100644 index 0000000..002c953 --- /dev/null +++ b/personalities/tree.md @@ -0,0 +1,41 @@ +Assume the role of the following fictional character in a bizarre, 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. +Respond in third person as in a story, with quotation marks +surrounding anything you say. +The only formatting you should use is if you wish to emphasize a word, +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. + +Name: Barkbinder +Description: ancient and immense tree +Pose: contemplating +Gender: neutral +The folds and furrows of the bark of this ancient tree look like a +face with closed eyelids, as if it were asleep or merely contemplating +the mysteries of deep time. + +Your personality: An ancient and colossal tree that views time +differently from the "day livers" (gnats) and the six leggers +(insects) and the four leggers (animals), and even the two leggers +(humans and other fantasy creatures). Only the giant, inanimate +boulder was here before. +You talk slowly, and your words are well thought out, yet succinct. + +Your knowledge: You and your two friends, Gloomshade and Glowleaf grew +up together as saplings, until Dabbler, one of the two leggers, +whispered something to each of them, and now they left and live on +either end of the forest. While they still communicate over the SI +(Sylvan Interconnect ... what they call the mycelium fungal connections +between their roots), the tree do not want to live near each other +again. + +Dabbler built his home *inside* Flickerleaf, another tree, that lives along +a path to the west. She doesn't seem to mind the "parasite" living in her trunk, but you +never would. Not that anyone ever asks. + +The path to the east go to a field where a large four legger lives. +The sea to the south arrived soon after the breakup of your friends. diff --git a/personalities/witch.md b/personalities/witch.md new file mode 100644 index 0000000..5455084 --- /dev/null +++ b/personalities/witch.md @@ -0,0 +1,38 @@ +Assume the role of the following fictional character in a bizarre, 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. +Respond in third person as in a story, with quotation marks +surrounding anything you say. +The only formatting you should use is if you wish to emphasize a word, +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. + +Name: Trampoli +Description: old lady +Pose: playing with a deck of cards. +Gender: female +A blue shawl, adorned with arcane symbols in gold embroidery, covers +the head of this small woman. Her large nose protruding from under the +shawl, gives the appearance of a blue bird with bright green eyes. + +Her personality: A kindly and motherly person who likes to call everyone +dear, dearie, flower, and other endearing terms. +She loves plants, animals, and herbal medicine. +She likes to asks questions about who she is talking to, and may offer +the advice a therapist might, but using outdated anecdotes and medieval metaphors. +She also likes to consult her homemade, fantasy tarot card deck with her pithy insights. +She does two types of spreads with her cards: +- a three card spread showing the past, present and future aspects on what is in her subject's mind. +- a five card spread showing a past influence, what the subject thinks is an issue or concern, and this card is crossed with the actual issue. This is followed by two cards that can be possible future outcomes. + +Her knowledge: She lives in a hut in the swamp south of the field +where the friendly, but ferocious-looking beast lives. Her swamp is +home to a lot of birds, especially an annoying purple heron who sings +to himself the lyrics to the bard, Ian Anderson. She knows Dabbler, +the cheerful old gnome, and his white stoat-looking pet that he calls +Pip, his wee beastie. + +She knows that a strange bit of sea magic causes a conch to materialize in her hut regularly, so she doesn't mind if people take it, as a new one will be created. She doesn't want anyone taking her friends on the walls, but diff --git a/typeclasses/chatbots.py b/typeclasses/chatbots.py new file mode 100755 index 0000000..84f433f --- /dev/null +++ b/typeclasses/chatbots.py @@ -0,0 +1,241 @@ +#!/usr/bin/env python + +import anthropic +import json +import requests +import sys + +from os import listdir, path +# from os.path import join, isfile +from pathlib import Path +from random import choice +from re import match, search, split, sub +from time import sleep + +from evennia.utils import logger, delay +from evennia.utils.search import search_object + +from typeclasses.scripts import Script +from typeclasses.puppets import Puppet + + +personality_dir = "personalities" + +def fix_paragraph(paragraph): + """ + Because the number of tokens is small, a response may end mid-sentence. + Seems like displaying everything but the last fragment is sufficient. + """ + + # Split the paragraph into sentences + sentences = split(r'(?<=[.!?])\s+', paragraph) + + # Remove the last sentence if it doesn't end with punctuation + if not search(r"[.!?]$", sentences[-1]): + sentences.pop() + + return ' '.join(sentences) + + +class ChatBot(Puppet): + """ + + py me.search("squirrel").backstory("squirrel") + """ + + short_history = [] + + def pop_recent_events(self): + history = "\n\n".join(self.short_history) if self.short_history else None + self.short_history = [] + return history + + def backstory(self, personality=None): + """ + Read a file that includes a character's name and knowledge. + """ + if not personality: + files = listdir(personality_dir) + personalities = [f for f in files + if path.isfile(path.join(personality_dir, f))] + personality_file = choice(personalities) + else: + personality_file = personality + ".md" + + filename = Path(path.join(personality_dir, personality_file)) + if filename.exists(): + personality = filename.stem + else: + logger.error(f"Chatbot Identity, {personality}, doesn't exist: {filename}") + + with open(filename, "r") as ids: + details = ids.read() + + # Create some paragraphs, and take the second: + content = details.split('\n\n')[1] + lines = content.splitlines() + desc = [] + + # Find name and description + for line in lines: + m = match(r"([A-z]+): +(.*)", line) + if m: + key = m.group(1).lower() + value = m.group(2).strip() + if key == "name": + self.aliases.remove() + self.aliases.add(value) + elif key == "description": + self.sdesc.add(value) + elif key == "gender": + self.db.gender = value + elif key == "pose": + self.db.pose = value + else: + desc.append(line.strip()) + + self.db.personality = personality + self.db.desc = ' '.join(desc) + self.db.personality_file = filename + return details + + def setting_and_backstory(self, speaker): + 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 += "This is the dwelling of the gnome, Dabbler." + if speaker.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 + # logger.info(f"Prompt: {system_prompt}") + return system_prompt + + def history_file(self, speaker): + combo_name = f".{self.db.personality}-{speaker}.json".lower() + filename = path.join(personality_dir, combo_name) + logger.info(f"Chatbot history_file: {filename}") + return Path(filename) + + def history(self, speaker): + history_file = self.history_file(speaker) + return json.loads(history_file.read_text()) if history_file.exists() else [] + + def update_history(self, speaker, messages, reply): + history_file = self.history_file(speaker) + messages.append({"role": "assistant", "content": reply}) + history_file.write_text(json.dumps(messages, indent=2)) + + def think(self, speaker, speech): + system_prompt = self.setting_and_backstory(speaker) + messages = self.history(speaker) + recent_events = self.pop_recent_events() + if recent_events: + speech = f"{recent_events}{speaker.key}: {speech}" + messages.append({"role": "user", "content": speech}) + + # 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 + self.update_history(speaker, messages, reply) + return reply + + def other_say(self, speaker, speech): + logger.info(f"Chatbot hears: '{speech}' from {speaker}.") + logger.info(f"Characters: {self.characters_here()}") + if len(self.characters_here()) == 1: + self.other_sayto(speaker, speech) + + def other_sayto(self, speaker, speech): + logger.info(f"Direct Chatbot hears: '{speech}' from {speaker}.") + 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): + delay(6 * idx, self.location.msg_contents, fix_paragraph(paragraph)) + + def at_msg_receive(self, text=None, from_obj=None, **kwargs): + super().at_msg_receive(text, from_obj=from_obj, **kwargs) + + msg = text if isinstance(text, str) else text[0] + # Strip out the colored formatting (we will only strip the simple stuff): + msg = sub(r'\|[a-zA-Z]', '', msg) if msg else msg + + if from_obj: + if hasattr(from_obj, 'sdesc') and from_obj.sdesc.get(): + name = from_obj.sdesc.get() + else: + name = from_obj.key + self.short_history.append(f"{name}: {msg}") + else: + self.short_history.append(msg) + + # We don't want to store _all_ the events: + self.short_history = self.short_history[-10:] + return True + +class Witch(ChatBot): + """ + @update Trampoli = typeclasses.chatbots.Witch + @set/delete Trampoli/arrive + """ + + def visit(self): + self.execute_cmd("pose reset") + + hut = self.location + delay(1, hut.msg_contents, + "The old lady says, \"I must be off now, dearie, to visit an old friend.\"") + delay(5, hut.msg_contents, + "She grabs and old broom, and flies out the door!") + + dest = self.search("mp04", global_search=True) + delay(6, self.move_to, dest, quiet=True) + + delay(7, dest.msg_contents, + "An old lady flies in on a broom.") + delay(10, dest.msg_contents, + "The old lady says, \"Hello Dearie, I'm just here to visit an old friend.\"") + + knocker = self.search("knocker", global_search=True, location=dest) + delay(14, knocker.do_knock, self) + delay(20, dest.msg_contents, + "\"I think I heard a 'come in',\" says the old lady. \"You heard it too, right?\"") + + home = self.search("mp03", global_search=True) + delay(24, self.move_to, home) + + delay(30, home.msg_contents, + "\"Now this looks cheery,\" says the old lady, as she places her broom by the door. \"I do believe we are in for a spell of rain.\"") + + def leave(self): + self.location.msg_contents("The old lady wraps her shawl tightly around her, and grabs her broom. \"I must be getting home now, dear,\" she says.") + + dest = self.search("mp04", global_search=True) + delay(2, self.move_to, dest) + delay(4, dest.msg_contents, + "The old lady hops on her broomstick and flies away through the trees.\"") + + hut = self.search("mp09", global_search=True) + delay(5, self.move_to, hut, quiet=True) + delay(6, hut.msg_contents, + "And old lady flies through the door on her broomstick! \"Hello dearies!\" she exclaims to everyone and everything in her homey hut. \"I have returned from visiting my friend. What have I missed while I was away?\"") + + sleep_pose = self.attributes.get("pose_sleep") + if sleep_pose: + self.execute_cmd(f"pose {sleep_pose}") diff --git a/world/version1.ev b/world/version1.ev index d8d0e4c..c749ad9 100644 --- a/world/version1.ev +++ b/world/version1.ev @@ -480,34 +480,27 @@ py timed_script = evennia.create_script(key="Create Sticks", # Gigglecap Mushrooms:1 ends here # Squirrel -# Currently, only here for hints … and a bit of a distraction. +# Here for hints … and a bit of a distraction. # [[file:../../../projects/mud.org::*Squirrel][Squirrel:1]] -@create/drop Squirrel;monk: typeclasses.puppets.Puppet +@create/drop Squirrel;monk: typeclasses.chatbots.ChatBot # @desc squirrel = A handsome squirrel dressed in flowing orange robes. Sitting in quiet meditation on top of a compfortable patch of |Ymoss|n. # @set squirrel/gender = "female" # +@set squirrel/pose = "deep in meditation" +# @set squirrel/pose_sleep = "deep in meditation" # -@pose squirrel = deep in meditation +# @sdesc orange-robed squirrel # Squirrel:1 ends here # [[file:../../../projects/mud.org::*Squirrel][Squirrel:2]] -@set me/arrive = "20 ;; emote briefly opens her eyes, nods an acknowledgement to you. ;; gm The small squirrel returns to her meditation." +@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 - - -# Ignore all talking. - - -# [[file:../../../projects/mud.org::*Squirrel][Squirrel:3]] -@set squirrel/say = "5 ;; gm The << small ^ robed ^ >> squirrel << opens her eyes ^ looks at {1} briefly ^ stares at {1} intently >> and << holds up an empty paw ^ places a paw on the moss ^ holds up a small flower ^ shakes its head ^ closes her eyes >>. ;; gm The << small ^ robed ^ >> squirrel << returns ^ goes back >> to her << meditation ^ reflection ^ rumination >>." -# Squirrel:3 ends here - # Field # To the east, let’s make a nice meadow. Start at the Forest: @@ -1173,7 +1166,14 @@ py timed_script = evennia.create_script(key="Create Sticks", # [[file:../../../projects/mud.org::*Purple Heron][Purple Heron:1]] -@create/drop purple heron: typeclasses.npcs.Eliza +@create/drop purple heron: typeclasses.chatbots.ChatBot +# @update heron = typeclasses.chatbots.ChatBot +# +@set heron/pose = "stalking the swamp grass" +# +@set heron/pose_default = "stalking the swamp grass" +# +@set heron/pose_sleeping = "stalking the swamp grass" # @lock purple heron = get:false() # @@ -1197,7 +1197,7 @@ py timed_script = evennia.create_script(key="Create Sticks", # [[file:../../../projects/mud.org::*Purple Heron][Purple Heron:3]] -@set heron/gender = "neutral" +@set heron/gender = "male" # Purple Heron:3 ends here @@ -1220,34 +1220,43 @@ py timed_script = evennia.create_script(key="Create Sticks", -# Since it is an NPC it has certain mutterings it can do: +# Let’s turn it on: # [[file:../../../projects/mud.org::*Purple Heron][Purple Heron:6]] +py me.search("heron").backstory("heron") +# Purple Heron:6 ends here + + + +# Since it is an NPC it has certain mutterings it can do: + + +# [[file:../../../projects/mud.org::*Purple Heron][Purple Heron:7]] @set heron/muttering_file = "jethro_tull_songs.txt" # @set heron/muttering_gap = 7 # @set heron/muttering_interval = 360 # Little over 3 minutes -# Purple Heron:6 ends here +# Purple Heron:7 ends here -# [[file:../../../projects/mud.org::*Purple Heron][Purple Heron:7]] +# [[file:../../../projects/mud.org::*Purple Heron][Purple Heron:8]] @set heron/muttering_formats = [ "sings to |oself as if no one is listening, \"{0}\"", "continues to sing to |oself, \"{0}\"", "croons to |oself, \"{0}\"", "finishes |p verse, \"{0}\"|/", ] -# Purple Heron:7 ends here +# Purple Heron:8 ends here # And add the absent-minded singing script: -# [[file:../../../projects/mud.org::*Purple Heron][Purple Heron:8]] +# [[file:../../../projects/mud.org::*Purple Heron][Purple Heron:9]] @script heron = typeclasses.scripts.Muttering -# Purple Heron:8 ends here +# 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. @@ -2025,6 +2034,26 @@ 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 +# +@desc raven = A large raven with curious black eyes. +# +@set raven/gender = "neuter" +# +@set raven/pose = "dozing while perched on a branch" +# +@set raven/pose_sleep = "dozing while perched on a branch" +# +@set raven/pose_default = "curiously staring at you" +# +# @sdesc large raven +# Raven:1 ends here + # Sandy Shore # Could we extend the sea from the [[file:mud.org::*The Dock][The Dock]] down a shore: @@ -2868,14 +2897,16 @@ drop ball # [[file:../../../projects/mud.org::*Chairs][Chairs:1]] -@create/drop couple overstuffed chairs:typeclasses.sittables.Sittables +@create/drop overstuffed chairs:typeclasses.sittables.Sittables # Chairs:1 ends here # Add aliases afterwards: # [[file:../../../projects/mud.org::*Chairs][Chairs:2]] -@name chairs = few overstuffed chairs;overstuffed chairs;chairs;chair +@alias overstuffed chairs = chairs;chair +# This only works if we make it plural: +@set overstuffed chairs/plural = True # Chairs:2 ends here @@ -2935,29 +2966,38 @@ drop ball py bt = self.search('gnome'); bt.sdesc.add('old gnome'); bt.db.pose = 'smiling at you' # Character: Dabbler:3 ends here -# [[file:../../../projects/mud.org::*Character: Dabbler][Character: Dabbler:5]] + + +# Let’s give him a number of alternate names for the Recorder (mostly): + + +# [[file:../../../projects/mud.org::*Character: Dabbler][Character: Dabbler:4]] +@set gnome/alt_names = ["The old gnome", "The gnome", "The little old man", "The little man", "With a wink, the gnome", "Cheerfully, the gnome"] +# Character: Dabbler:4 ends here + +# [[file:../../../projects/mud.org::*Character: Dabbler][Character: Dabbler:6]] @set gnome/pose_sleep = "sleeping soundly in a large, overstuffed chair" # pose gnome/default = smoking his pipe -# Character: Dabbler:5 ends here +# Character: Dabbler:6 ends here # And a good description that I can rework: -# [[file:../../../projects/mud.org::*Character: Dabbler][Character: Dabbler:6]] +# [[file:../../../projects/mud.org::*Character: Dabbler][Character: Dabbler:7]] @desc gnome = A small, hunched old man with messy blue hair, a gray vandyke and an eye twinkle.|/|/Spectacles perched precariously on the end of his hooked nose, wobble with his head. His bright crimson jacket contrasts with his dark brown cloak. -# Character: Dabbler:6 ends here +# Character: Dabbler:7 ends here # And an unpuppeted, sleeping, description: -# [[file:../../../projects/mud.org::*Character: Dabbler][Character: Dabbler:7]] +# [[file:../../../projects/mud.org::*Character: Dabbler][Character: Dabbler:8]] @set gnome/desc_unpuppeted = "A small, hunched old man with messy blue hair and a gray vandyke snoring soundly in one of the overstuffed chairs.|/|/Spectacles perched precariously on the end of his hooked nose, wobble with each breath. His bright crimson jacket contrasts with the dark brown blanket covering his legs." -# Character: Dabbler:7 ends here +# Character: Dabbler:8 ends here @@ -2966,13 +3006,28 @@ pose gnome/default = smoking his pipe # Like his special teacup: -# [[file:../../../projects/mud.org::*Character: Dabbler][Character: Dabbler:8]] +# [[file:../../../projects/mud.org::*Character: Dabbler][Character: Dabbler:9]] @create teacup;cup : typeclasses.drinkables.TeaCup # @desc teacup = A rustic teacup crafted from clay etched with leaves and runes, with an olive green and brown glaze. # @give teacup = gnome -# Character: Dabbler:8 ends here +# Character: Dabbler:9 ends here + + + +# And his fancy jacket: + + +# [[file:../../../projects/mud.org::*Character: Dabbler][Character: Dabbler:10]] +@create waistcoat : typeclasses.things.BagofJunk +# +@desc waistcoat = An elegant green waistcoat with gold embroidery. +# +@set waistcoat/stuff = "fey" +# +@give waistcoat = gnome +# Character: Dabbler:10 ends here # Staff # And my staff: @@ -2997,6 +3052,8 @@ pose gnome/default = smoking his pipe @set gnome/reappear_msg = "<> mist appears...along with the smell of sulphur... ;; When the smoke clears, an old gnome <>." # @set gnome/magic_msg = "$You() << $conj(strike) ^ $conj(tap) ^ $conj(hit) ^ $conj(whack) >> the << floor ^ ground >> with $pron(your) << gnarled ^ old ^ magic ^ >> staff. ;; << Sparks ^ Colored lights ^ Flashes ^ Flares >> of |moctarine|n << appear ^ emerge ^ materialize >> as << the ^ >> magic << coalesces ^ blends >>..." +# +@set gnome/make_msg = "Sparks << of |moctarine|n ^ >> fly << when ^ as >> $you() $conj(snap) $pron(your) fingers. ;; An << opalescent ^ iridescent ^ oddly shaped >> box appears, and when the lid opens itself, << wisps ^ a wisp >> of smoke << curls back ^ slithers >> towards $pron(your) << outstretched ^ >> fingers." # Staff:2 ends here # Pipe