Expand conversation with the Door Knocker

This commit is contained in:
Howard Abrams 2025-04-14 16:39:34 -07:00
parent 11785cd534
commit bc380928e7
2 changed files with 151 additions and 75 deletions

View file

@ -1,6 +1,7 @@
#!/usr/bin/env python
from random import choice, random
from enum import Enum
from evennia import create_script
from evennia.utils import logger, delay
@ -91,6 +92,18 @@ class Puddle(Object):
exclude=player)
class Knocker_Convo(Enum):
"What topics have we covered?"
ANY = 0
GREETED = 1
DOOR = 2
LOCK = 3
PASS = 4
HINT = 5
RIDDLE = 6
ANSWERED = 7
class Knocker(Object):
"""
Knocker
@ -107,62 +120,94 @@ class Knocker(Object):
"Umf! Umfmmmf mmm mmmuufffmm mff mmuuummph.",
]
yes_msg = r"\byes|yeah|yah|sure|please\b"
no_msg = r"\bno|nope\b"
question_msg = r"\?$"
greet_msg = r"\bhello|\bgreet|\bhey\b"
# Each state of conversation is listed:
close_responses = [
"Oooo...good guess, but we are looking for something more specific.",
]
answered_responses = [
"Alright, I'll open the door for yah.",
"I heard my favorite, let's get this door unlocked.",
]
# Note that the responses are ordered from most specific to least.
knocker_responses = [
"[Sorry.|What was that?|Did you say something?] I'm hard of hearing on account of the brass ears.",
"Yes, I suppose I'm this amazing puzzle you get to in Chapter Three. Wait, does that mean I'm just an NPC?",
"Who me? I thought you were talking to the goblin in the bushes.",
"Why yes, I am hard of hearing.",
]
password_responses = [
"Of course this door is protected by a super complicated encrypted password.",
"If I tell you, it wouldn't be a secret now.",
"The password? You just have to guess...unless you want a hint?",
"Well, I suppose I could give you a |bhint|n.",
]
hint_responses = [
"A hint does sound fair. [Should I|I should] come up with a |briddle|n[|, huh]?"
]
riddle_responses = [
"Aged in barrels, smooth and neat, in a glass by the fire, I'm a treat.",
"A scent of oak, a whiff of grain, a drop of expertise from the cask remains.",
"""
In oaken halls, I sleep and bide,
till I'm called to warm your insides...
hrm, that's a little vague, but kinda nice.
""",
"""
Alright, alright, the riddle should be clever.
It should refer to its golden hue, and I should make it obvious
that it isn't gold, and adding a reference to quest of the Argonauts
would be a complete red herring, and quite a mean thing to do,
so I shouldn't add that,
but what about barrels? Yeah, need to include barrels, but not the
way Bilbo road barrels, for that was definitely intended as a misleading
riddle for Smaug, but of course, a smart dragon would always figure such
things out, wait, where was I?
"""
]
locked_responses = [
"Yes, I'm familiar with the door and the fact that it is locked.",
"This locked door is to protect the theft of Dabbler's scones.",
]
all_responses = [
# The password must be the first entry here, as we "act" on it:
["whiske?y", [
"Alright, I'll open the door for yah.",
"I heard my favorite, let's get this door unlocked.",
]],
[r"knocker|goblin", [
"[Sorry.|What was that?|Did you say something?] I'm hard of hearing on account of the brass ears.",
"Yes, I suppose I'm this amazing puzzle you get to in Chapter Three. Wait, does that mean I'm just an NPC?",
"Who me? I thought you were talking to the goblin in the bushes.",
"Why yes, I am hard of hearing.",
]],
["password", [
"Of course this door is protected by a super complicated encrypted password.",
"If I tell you, it wouldn't be a secret now.",
"The password? You just have to guess.",
"Well, I suppose I could give you a |bhint|n.",
]],
["hint", [
"A hint does sound fair. [Should I|I should] come up with a |briddle|n[|, huh]?"
]],
["riddle", [
"Aged in barrels, smooth and neat, in a glass by the fire, I'm a treat.",
"A scent of oak, a whiff of grain, a drop of expertise from the cask remains.",
"""
In oaken halls, I sleep and bide,
till I'm called to warm your insides...
hrm, that's a little vague, but kinda nice.
""",
"""
Alright, alright, the riddle should be clever.
It should refer to its golden hue, and I should make it obvious
that it isn't gold, and adding a reference to quest of the Argonauts
would be a complete red herring, and quite a mean thing to do,
so I shouldn't add that,
but what about barrels? Yeah, need to include barrels, but not the
way Bilbo road barrels, for that was definitely intended as a misleading
riddle for Smaug, but of course, a smart dragon would always figure such
things out, wait, where was I?
"""
]],
[r"\bhello|\bgreet|\bhey\b", [
"How's it going?",
"How's it?",
"'Sup.",
"How are you?",
]],
[r"\bass\b", [
"Why yes, I am made of brass."
]],
[r"\block", [
"Yes, I'm familiar with the door and the fact that it is locked.",
"This locked door is to protect the theft of Dabbler's scones.",
]],
[r"\bdoor\b", [
[r"whiske?y", Knocker_Convo.ANY, answered_responses, Knocker_Convo.ANSWERED],
[r"scotch|bourbon", Knocker_Convo.ANY, [
"A little more specific than needed, but that will do."],
Knocker_Convo.ANSWERED],
# A _sequence_ of responses, from what is this password business, to give me a hint, to give me the riddle ...
[question_msg, Knocker_Convo.RIDDLE, [
"Nope. Would [ya|you] like another riddle?",
"You [really|] think that is the answer?",
"Personally, [|I think] that riddle could not [be|have been] more clear."
], None],
[yes_msg, Knocker_Convo.HINT, riddle_responses, Knocker_Convo.RIDDLE],
["riddle", Knocker_Convo.ANY, riddle_responses, Knocker_Convo.RIDDLE],
["another", Knocker_Convo.RIDDLE, riddle_responses, Knocker_Convo.RIDDLE],
["hint", Knocker_Convo.ANY, hint_responses, Knocker_Convo.HINT],
["\btell\b", Knocker_Convo.PASS, hint_responses, Knocker_Convo.HINT],
[yes_msg, Knocker_Convo.PASS, hint_responses, Knocker_Convo.HINT],
[question_msg, Knocker_Convo.PASS, hint_responses, Knocker_Convo.HINT],
[yes_msg, Knocker_Convo.DOOR, password_responses, Knocker_Convo.PASS],
["password", Knocker_Convo.ANY, password_responses, Knocker_Convo.PASS],
["get in", Knocker_Convo.LOCK, password_responses, Knocker_Convo.PASS],
["get in", Knocker_Convo.DOOR, [
"Well, you see. The door is locked."
], Knocker_Convo.LOCK],
[question_msg, Knocker_Convo.DOOR, locked_responses, Knocker_Convo.LOCK],
[r"\block", Knocker_Convo.ANY, locked_responses, Knocker_Convo.LOCK],
[r"\bdoor\b", Knocker_Convo.ANY, [
"What door? I don't see a door. Ha!",
"That's right, I am the clever puzzle hanging on a door.",
"I'm hanging on a door? Really? Let's see, can I roll my eyes?",
@ -172,18 +217,41 @@ class Knocker(Object):
but I like the cut of your [suit|cloak|jib].
So, you see, if you speak the |bpassword|n, wait, I've said too much.
"""
]],
[r"\byes|yeah|yah\b", [
], Knocker_Convo.DOOR],
[greet_msg, Knocker_Convo.GREETED, [
"Didn't we just exchanged pleasantries?",
"Just so you know, I'm not much into small talk."
], None],
[greet_msg, Knocker_Convo.ANY, [
"How's it going?",
"How's it?",
"'Sup.",
"How are you?",
], Knocker_Convo.GREETED],
[r"knocker|goblin", Knocker_Convo.ANY, knocker_responses, None],
[r"\bass\b", Knocker_Convo.ANY, [
"Why yes, I am made of brass."
], None],
[r"thanks|thank you", Knocker_Convo.ANY, [
"You're [very|] welcome.",
"Glad to be of service."
], None],
[yes_msg, Knocker_Convo.ANY, [
"Really? You agree?",
"Excellent",
]],
[r"\bno|nope\b", [
"Excellent.",
], None],
[no_msg, Knocker_Convo.ANY, [
"Well, it's true. Just ask the [raven|trees|gnome].",
]],
[r"\?$", [
], None],
[question_msg, Knocker_Convo.ANY, [
"What about [me|it|'im]?",
"I dunno...",
]],
], None],
]
after_unlocked_responses = [
@ -248,31 +316,42 @@ class Knocker(Object):
else:
self.at_say("Doesn't appear that anyone is home.")
def at_heard_say(self, message, from_obj):
def at_heard_say(self, message, talker):
"""
A simple listener and response. This makes it easy to change for
subclasses of NPCs reacting differently to says.
"""
curr_state = Knocker_Convo(talker.db.knocker_conversation_state or 0)
# message will be on the form `<Person> says, "say_text"`
# we want to get only say_text without the quotes and any spaces
message = message.split('says, ')[1].strip(' "')
# Let's see if a keyword gives a good response:
for idx, [regex, responses] in enumerate(self.all_responses):
for [regex, convo_state, responses, new_state] in self.all_responses:
full_regex = r".*" + regex + r".*"
if re.match(full_regex, message, re.IGNORECASE):
# The first match is the password, so we set a tag on
# the character, so that they can go through the door:
if idx == 0:
from_obj.tags.add("open_red_door", category="mp")
if re.match(full_regex, message, re.IGNORECASE) \
and curr_state.value >= convo_state.value:
logger.info(f"Spoke: {message}, matched: {full_regex} and {curr_state} >= {convo_state}")
# If we have the ring in our mouth, we are muffled:
if self.has("brass ring"):
return choice(self.muffled_responses)
else:
if new_state and new_state.value > curr_state.value:
talker.db.knocker_conversation_state = new_state
# The first match is the password, so we set a tag
# on the character, so that they can go through
# the door:
if talker.db.knocker_conversation_state == Knocker_Convo.ANSWERED:
talker.tags.add("open_red_door", category="mp")
return routput(choice(responses))
# We can not do a random response. Of course, we are
# pretending we are hard of hearing, so we don't spam the room
# _every_ time:
@ -286,7 +365,7 @@ class Knocker(Object):
# track and alternate the responses:
elif self.db.hard:
self.db.hard = False
if from_obj.tags.get(key="open_red_door", category="mp"):
if talker.tags.get(key="open_red_door", category="mp"):
return routput(choice(self.after_unlocked_responses))
else:
return routput(choice(self.unknown_responses))
@ -305,9 +384,6 @@ class Knocker(Object):
return routput(response)
def at_desc(self, looker):
return "what" # self.get_display_desc(looker)
def get_display_things(self, looker):
return ""

View file

@ -483,7 +483,7 @@ lair
# [[file:../../../Dropbox/org/projects/mud.org::*The Lair of the Beast][The Lair of the Beast:9]]
@desc leave = You can see the waterfall cascading just outside the cave entrance.
@desc leave = You can see the waterfall cascading outside the cave entrance.
# The Lair of the Beast:9 ends here
@ -1106,7 +1106,7 @@ west
# [[file:../../../Dropbox/org/projects/mud.org::*Knocker][Knocker:9]]
@lock ring = tethered:id(#21)
@lock ring = tethered:id(#27)
#
@set ring/tethered_msg = You put the ring back in the knocker's mouth. "Mmmuufffmm," says the door knocker.
# Knocker:9 ends here