Muttering and or, Singing NPCs

NPCs can, after a delay, state or do a few things from a file.
This commit is contained in:
Howard Abrams 2025-06-30 22:18:44 -07:00
parent a5d88da4a8
commit c7825731f2

View file

@ -12,12 +12,16 @@ just overloads its hooks to have it perform its function.
""" """
from enum import Enum from enum import Enum
from itertools import cycle
from pathlib import Path
from random import choice
from evennia.scripts.scripts import DefaultScript from evennia.scripts.scripts import DefaultScript
from evennia.prototypes.spawner import spawn from evennia.prototypes.spawner import spawn
from evennia.utils import logger from evennia.utils import logger, delay
from typeclasses.characters import Character
from .characters import Character
class Script(DefaultScript): class Script(DefaultScript):
""" """
@ -159,6 +163,7 @@ class Spell(Script):
target.attributes.clear(category="effect") target.attributes.clear(category="effect")
self.delete() self.delete()
class DonkeyHeadSpell(Spell): class DonkeyHeadSpell(Spell):
def at_start(self, **kwargs): def at_start(self, **kwargs):
target = self.attributes.get("target") target = self.attributes.get("target")
@ -174,3 +179,120 @@ class DonkeyHeadSpell(Spell):
def at_repeat(self, **kwargs): def at_repeat(self, **kwargs):
self.stop() self.stop()
class Muttering(Script):
"""
Script to have an objects 'emote' phrases in sequence.
First add settings to the 'npc', for instance:
@set npc/muttering_interval = 120 # for 2 minutes
@set npc/muttering_gap = 5 # for 5 seconds per sequence
@set npc/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}\"|/",
]
@set npc/muttering_file = "song-lyrics.txt"
Then start the script by running the following:
@script npc = typeclasses.scripts.Muttering
"""
def at_script_creation(self):
self.key = "muttering"
self.desc = "NPCs that Mutter"
self.interval = self.obj.db.muttering_interval or 300 # seconds
self.start_delay = False
self.persistent = True
self.reload()
def reload(self):
self.db.mutter_delay_gap = self.obj.db.muttering_gap or 7
self.db.mutter_sequence_index = 0
mutter_file = self.obj.db.muttering_file
if mutter_file:
logger.info(f"Reading muttering file, {mutter_file}")
self.db.mutters = self.load_mutter(mutter_file)
def at_repeat(self, **kwargs):
"""
If we have passengers, we need to sail...
"""
self.mutter_sequence()
def mutter_sequence(self):
# if not hasattr(self, 'mutter_sequence_index'):
# self.db.mutter_sequence_index = 0
if self.db.mutter_sequence_index < len(self.db.mutters):
sequences = self.db.mutters[self.db.mutter_sequence_index]
self.db.mutter_sequence_index += 1
else:
sequences = self.db.mutters[0]
self.db.mutter_sequence_index = 1
formats = self.refresh_mutter_formats()
zip_list = zip(sequences, cycle(formats)) \
if len(sequences) > len(formats) \
else zip(sequences, formats[:len(sequences)])
for idx, tup in enumerate(zip_list):
logger.info(f"delay({idx} * {self.db.mutter_delay_gap}, self.mutter, {tup[0]}, {tup[1]})")
delay(idx * self.db.mutter_delay_gap,
self.mutter, tup[0], tup[1])
def mutter(self, phrase, msg_format):
"""
Mutter something aloud to the room the NPC resides.
Why wait for input from other characters when the NPC can
pretend to be real.
"""
thing = self.obj
room = thing.location
name = choice([
thing.key,
thing.db._sdesc or thing.name,
thing.key.split(" ")[-1]
])
if thing.db.article:
prefix = f"{thing.db.article} {name} {msg_format}"
else:
prefix = f"{name} {msg_format}"
if phrase:
room.msg_contents(
prefix.format(phrase),
from_obj=self.obj)
def refresh_mutter_formats(self):
return self.obj.db.muttering_formats or [
"mutters as if no one is listening, \"{0}\"",
"grumbles to |oself, \"{0}\"",
"continues to mutter to |oself, \"{0}\"",
"murmurs to |oself, \"{0}\"",
"mutters to |oself, \"{0}\"|/",
]
def load_mutter(self, data_file):
"""
Return 'data_file' and return a list of lists.
Where a blank line in the data file separates the list of
lines from others.
"""
path = Path(__file__).with_name(data_file)
mutters = []
with open(path) as file:
curr_mutter = []
for line in file:
if line.strip() == "":
mutters = mutters + [curr_mutter]
curr_mutter = []
else:
curr_mutter.append(line.strip())
return mutters