moss-n-puddles/typeclasses/puppets.py
2025-05-25 22:06:52 -07:00

133 lines
4.7 KiB
Python
Executable file

#!/usr/bin/env python
from re import split, match, IGNORECASE
from evennia.utils import logger
from typeclasses.characters import Character
from utils.word_list import routput
class Puppet(Character):
"""
Special character that if not puppetable, stays put.
Perhaps responding or logging information to the GM.
"""
def at_post_puppet(self, **kwargs):
"""
Called just after puppeting has been completed and all
Account<->Object links have been established.
Args:
**kwargs (dict): Arbitrary, optional arguments for users
overriding the call (unused by default).
Notes:
You can use `self.account` and `self.sessions.get()` to get
account and sessions at this point; the last entry in the
list from `self.sessions.get()` is the latest Session
puppeting this Object.
"""
self.msg(f"\nYou are puppeting |c{self.key}|n.")
self.msg((self.at_look(self.location), {"type": "look"}), options=None)
def at_pre_unpuppet(self, **kwargs):
"""
Reset our pose.
"""
super().at_pre_unpuppet()
self.execute_cmd("pose reset")
def at_post_unpuppet(self, account=None, session=None, **kwargs):
"""
Make the character object remain in the room.
Args:
account (DefaultAccount): The account object that just disconnected
from this object.
session (Session): Session controlling the connection that
just disconnected.
Keyword Args:
reason (str): If given, adds a reason for the unpuppet. This
is set when the user is auto-unpuppeted due to being link-dead.
**kwargs: Arbitrary, optional arguments for users
overriding the call (unused by default).
"""
self.msg(f"\nNo longer puppeting |c{self.key}|n.\n")
def get_display_desc(self, _, **kwargs):
"""
Return one of two appearances based on if it is being puppeted or not.
Set either or both:
@set me/desc_puppeted = "A clown bouncing up and down from a box."
@set me/desc_uppuppeted = "A colorful box with a closed lid."
If either is not specified, it uses the standard description.
"""
if self.tags.get(key='puppeted', category='account'):
return self.db.desc_puppeted if self.db.desc_puppeted else self.db.desc
else:
return self.db.desc_unpuppeted if self.db.desc_unpuppeted else self.db.desc
# ----------------------------------------------------------------------
# TRIGGERS
def get_character_label(self, character):
return character.get_display_name(self).split(' ')[-1]
def trigger_sequence(self, seq, character, *other_stuff):
self.delay_sequence(seq, 1, character.key, character.get_display_name(self),
self.get_character_label(character), *other_stuff)
def get_attribute_trigger(self, label, character):
"""
Return the attribute where 'key' is the label, and the
category can by either the 'character' or its display name.
"""
name = self.get_character_label(character)
return (self.attributes.get(key=label, category=character.key) or
self.attributes.get(key=label, category=name) or
self.attributes.get(key=label))
def move_triggers(self, label, character):
"""
Return a list of triggers matching 'label' and 'character'.
"""
seq = self.get_attribute_trigger(label, character)
if seq:
self.trigger_sequence(seq, character)
def other_arrive(self, character):
"""
Execute a command when a character arrives in the same location.
"""
self.move_triggers('arrive', character)
def other_leave(self, character):
"""
Execute a command when a character arrives in the same location.
"""
self.move_triggers('leave', character)
def say_triggers(self, label, character, speech):
trigs = self.get_attribute_trigger(label, character)
if trigs:
for _, trigger in enumerate(dict(trigs)):
seq = trigs[trigger]
if match(trigger, speech, IGNORECASE):
self.trigger_sequence(seq, character)
def other_say(self, speaker, speech):
self.say_triggers('say', speaker, speech)
def other_sayto(self, speaker, speech):
self.say_triggers('sayto', speaker, speech)
def other_given(self, giver, obj):
target = giver.get_display_name(self).split(' ')[-1]
self.execute_cmd(f"emote /Me says to /{target}, \"Thanks for the {obj.name}.\"")