#!/usr/bin/env python from random import randint from re import split from typeclasses.objects import Object from commands.misc import CmdSetCat, CmdSetOctopus from utils.word_list import routput class NPC(Object): """ An NPC is an NPC because it can react to what it _hears_. To do this, implement 'at_heard_say', a function that returns a string for a response. """ def at_heard_say(self, message, from_obj, is_say=True, is_whisper=False): "Override to return a string in response to message." pass def msg(self, text=None, from_obj=None, **kwargs): "Custom msg() method reacting to say." # make sure to not repeat what we ourselves said or we'll # create a loop if from_obj != self: is_say = False is_whisper = False try: say_text, is_say = text[0], text[1]['type'] == 'say' is_whisper = text[1]['type'] == 'whisper' except Exception: pass try: # message will be on the form ` says, "say_text"` # we want to get only say_text without the quotes and any spaces message = text.split('says, ')[1].strip(' "') shout, response = self.at_heard_say(message, from_obj, is_say, is_whisper) if response != None: self.at_say(response, just_owner=(shout == "shout")) except Exception: pass # this is needed if anyone ever puppets this NPC - without it # you would never get any feedback from the server (not even # the results of look) super().msg(text=text, from_obj=from_obj, **kwargs) class CarriableNPC(NPC): """ A carriable NPC is like any other NPC, except that since it can be carried and isn't locked down, it can't hear conversation in a room. """ def at_say(self, message, msg_self=None, msg_location=None, receivers=None, msg_receivers=None, just_owner=True, **kwargs): "Does the best it can to speak out loud." owner = self.location if self.location.is_typeclass("typeclasses.rooms.Room"): super().at_say(message, msg_self=msg_self, msg_location=msg_location, receivers=receivers, msg_receivers=msg_receivers) elif just_owner: owner.msg(f"The {self.name} says, \"{message}\"") else: owner.msg( f"The {self.name}, you are carrying, says, \"{message}\"") owner.location.msg( f"The {self.name}, carried by {self.location.name}, says, \"{message}\"", exclude=owner) class Familiar(NPC): """ Parent class for all familiars. These are pets that can be controlled by their owner to do antics. """ def at_do(self, owner, antics): """ Issue a 'send_emote' into the room with a antic. """ def new_name(name): """ Take a long name, like: fat, black cat And return _part_ of the name, like: - fat, black cat - black cat - cat """ parts = list(filter(lambda s: s != "", split(r"[, ]+", name))) num_adjs = len(parts)-1 lst_adjs = parts[randint(0, num_adjs):num_adjs] noun = parts[-1] adjs = ', '.join(lst_adjs) return f"{adjs} {noun}" if len(adjs) > 0 else noun # The familiar's name: name = self.db._sdesc or self.name if antics.startswith("'"): owner.announce_action(f"$Your() {new_name(name)}{antics}") else: owner.announce_action(f"$Your() {new_name(name)} {antics}") class Cat(Familiar): """ A puppetable 'cat' that acts based on that 'command'. """ def at_object_creation(self): "Called when a cat is first created." self.cmdset.add(CmdSetCat, persistent=True) class Octopus(Familiar): """ A puppetable 'octopus' that acts based on that 'command'. """ def at_object_creation(self): "Called when a octopus is first created." self.cmdset.add(CmdSetOctopus, persistent=True)