Expand conversation with the Door Knocker
This commit is contained in:
parent
11785cd534
commit
bc380928e7
2 changed files with 151 additions and 75 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
from random import choice, random
|
from random import choice, random
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
from evennia import create_script
|
from evennia import create_script
|
||||||
from evennia.utils import logger, delay
|
from evennia.utils import logger, delay
|
||||||
|
|
@ -91,6 +92,18 @@ class Puddle(Object):
|
||||||
exclude=player)
|
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):
|
class Knocker(Object):
|
||||||
"""
|
"""
|
||||||
Knocker
|
Knocker
|
||||||
|
|
@ -107,29 +120,37 @@ class Knocker(Object):
|
||||||
"Umf! Umfmmmf mmm mmmuufffmm mff mmuuummph.",
|
"Umf! Umfmmmf mmm mmmuufffmm mff mmuuummph.",
|
||||||
]
|
]
|
||||||
|
|
||||||
# Note that the responses are ordered from most specific to least.
|
yes_msg = r"\byes|yeah|yah|sure|please\b"
|
||||||
all_responses = [
|
no_msg = r"\bno|nope\b"
|
||||||
# The password must be the first entry here, as we "act" on it:
|
question_msg = r"\?$"
|
||||||
["whiske?y", [
|
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.",
|
"Alright, I'll open the door for yah.",
|
||||||
"I heard my favorite, let's get this door unlocked.",
|
"I heard my favorite, let's get this door unlocked.",
|
||||||
]],
|
]
|
||||||
[r"knocker|goblin", [
|
|
||||||
|
# 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.",
|
"[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?",
|
"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.",
|
"Who me? I thought you were talking to the goblin in the bushes.",
|
||||||
"Why yes, I am hard of hearing.",
|
"Why yes, I am hard of hearing.",
|
||||||
]],
|
]
|
||||||
["password", [
|
password_responses = [
|
||||||
"Of course this door is protected by a super complicated encrypted password.",
|
"Of course this door is protected by a super complicated encrypted password.",
|
||||||
"If I tell you, it wouldn't be a secret now.",
|
"If I tell you, it wouldn't be a secret now.",
|
||||||
"The password? You just have to guess.",
|
"The password? You just have to guess...unless you want a hint?",
|
||||||
"Well, I suppose I could give you a |bhint|n.",
|
"Well, I suppose I could give you a |bhint|n.",
|
||||||
]],
|
]
|
||||||
["hint", [
|
hint_responses = [
|
||||||
"A hint does sound fair. [Should I|I should] come up with a |briddle|n[|, huh]?"
|
"A hint does sound fair. [Should I|I should] come up with a |briddle|n[|, huh]?"
|
||||||
]],
|
]
|
||||||
["riddle", [
|
riddle_responses = [
|
||||||
"Aged in barrels, smooth and neat, in a glass by the fire, I'm a treat.",
|
"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.",
|
"A scent of oak, a whiff of grain, a drop of expertise from the cask remains.",
|
||||||
"""
|
"""
|
||||||
|
|
@ -148,21 +169,45 @@ class Knocker(Object):
|
||||||
riddle for Smaug, but of course, a smart dragon would always figure such
|
riddle for Smaug, but of course, a smart dragon would always figure such
|
||||||
things out, wait, where was I?
|
things out, wait, where was I?
|
||||||
"""
|
"""
|
||||||
]],
|
]
|
||||||
[r"\bhello|\bgreet|\bhey\b", [
|
|
||||||
"How's it going?",
|
locked_responses = [
|
||||||
"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.",
|
"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.",
|
"This locked door is to protect the theft of Dabbler's scones.",
|
||||||
]],
|
]
|
||||||
[r"\bdoor\b", [
|
all_responses = [
|
||||||
|
# The password must be the first entry here, as we "act" on it:
|
||||||
|
[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!",
|
"What door? I don't see a door. Ha!",
|
||||||
"That's right, I am the clever puzzle hanging on a door.",
|
"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?",
|
"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].
|
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.
|
So, you see, if you speak the |bpassword|n, wait, I've said too much.
|
||||||
"""
|
"""
|
||||||
]],
|
], Knocker_Convo.DOOR],
|
||||||
[r"\byes|yeah|yah\b", [
|
|
||||||
|
[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?",
|
"Really? You agree?",
|
||||||
"Excellent",
|
"Excellent.",
|
||||||
]],
|
], None],
|
||||||
[r"\bno|nope\b", [
|
[no_msg, Knocker_Convo.ANY, [
|
||||||
"Well, it's true. Just ask the [raven|trees|gnome].",
|
"Well, it's true. Just ask the [raven|trees|gnome].",
|
||||||
]],
|
], None],
|
||||||
[r"\?$", [
|
[question_msg, Knocker_Convo.ANY, [
|
||||||
"What about [me|it|'im]?",
|
"What about [me|it|'im]?",
|
||||||
"I dunno...",
|
"I dunno...",
|
||||||
]],
|
], None],
|
||||||
]
|
]
|
||||||
|
|
||||||
after_unlocked_responses = [
|
after_unlocked_responses = [
|
||||||
|
|
@ -248,31 +316,42 @@ class Knocker(Object):
|
||||||
else:
|
else:
|
||||||
self.at_say("Doesn't appear that anyone is home.")
|
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
|
A simple listener and response. This makes it easy to change for
|
||||||
subclasses of NPCs reacting differently to says.
|
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"`
|
# message will be on the form `<Person> says, "say_text"`
|
||||||
# we want to get only say_text without the quotes and any spaces
|
# we want to get only say_text without the quotes and any spaces
|
||||||
message = message.split('says, ')[1].strip(' "')
|
message = message.split('says, ')[1].strip(' "')
|
||||||
|
|
||||||
# Let's see if a keyword gives a good response:
|
# 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".*"
|
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
|
if re.match(full_regex, message, re.IGNORECASE) \
|
||||||
# the character, so that they can go through the door:
|
and curr_state.value >= convo_state.value:
|
||||||
if idx == 0:
|
logger.info(f"Spoke: {message}, matched: {full_regex} and {curr_state} >= {convo_state}")
|
||||||
from_obj.tags.add("open_red_door", category="mp")
|
|
||||||
|
|
||||||
# If we have the ring in our mouth, we are muffled:
|
# If we have the ring in our mouth, we are muffled:
|
||||||
if self.has("brass ring"):
|
if self.has("brass ring"):
|
||||||
return choice(self.muffled_responses)
|
return choice(self.muffled_responses)
|
||||||
else:
|
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))
|
return routput(choice(responses))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# We can not do a random response. Of course, we are
|
# We can not do a random response. Of course, we are
|
||||||
# pretending we are hard of hearing, so we don't spam the room
|
# pretending we are hard of hearing, so we don't spam the room
|
||||||
# _every_ time:
|
# _every_ time:
|
||||||
|
|
@ -286,7 +365,7 @@ class Knocker(Object):
|
||||||
# track and alternate the responses:
|
# track and alternate the responses:
|
||||||
elif self.db.hard:
|
elif self.db.hard:
|
||||||
self.db.hard = False
|
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))
|
return routput(choice(self.after_unlocked_responses))
|
||||||
else:
|
else:
|
||||||
return routput(choice(self.unknown_responses))
|
return routput(choice(self.unknown_responses))
|
||||||
|
|
@ -305,9 +384,6 @@ class Knocker(Object):
|
||||||
|
|
||||||
return routput(response)
|
return routput(response)
|
||||||
|
|
||||||
def at_desc(self, looker):
|
|
||||||
return "what" # self.get_display_desc(looker)
|
|
||||||
|
|
||||||
def get_display_things(self, looker):
|
def get_display_things(self, looker):
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -483,7 +483,7 @@ lair
|
||||||
|
|
||||||
|
|
||||||
# [[file:../../../Dropbox/org/projects/mud.org::*The Lair of the Beast][The Lair of the Beast:9]]
|
# [[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
|
# The Lair of the Beast:9 ends here
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1106,7 +1106,7 @@ west
|
||||||
|
|
||||||
|
|
||||||
# [[file:../../../Dropbox/org/projects/mud.org::*Knocker][Knocker:9]]
|
# [[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.
|
@set ring/tethered_msg = You put the ring back in the knocker's mouth. "Mmmuufffmm," says the door knocker.
|
||||||
# Knocker:9 ends here
|
# Knocker:9 ends here
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue