import random from typing import Optional from irc.client import NickMask from edmond.plugin import Plugin from edmond.utils import proc class MiscReactionsPlugin(Plugin): """This plugin implements various reactions to the last message posted. Enable reactions you want by setting the IDs from REACTIONS in the reactions field on the plugin configuration. As all reactions are optional, configurations for each reactions are optional as well and can be safely removed from the configuration (as usual except fields in REQUIRED_CONFIGS). The types of reactions can appear with a different probability if the configured reaction has a suffix of ":n", n being a number defining the reaction weight. The default weight when no suffix is used is 1. """ REQUIRED_CONFIGS = ["reactions", "rate"] REACTIONS = set( [ "sentence", "stop", "king", "mmm", "ooo", "detector", "repeat_letters", "nudge", "pfouah", "flumzo", ] ) def __init__(self, bot): super().__init__(bot) self.priority = -10 self.reactions = [] self.weights = [] def on_welcome(self, event): self.reactions, self.weights = self.get_reactions() def get_reactions(self): """Get configured reactions in a method list, maybe with weights.""" reactions = [] weights = [] for reaction in self.config["reactions"]: weight = 1 if ":" in reaction: reaction, weight_str = reaction.split(":", maxsplit=1) try: weight = int(weight_str) except ValueError: pass if reaction not in self.REACTIONS: continue reactions.append(getattr(self, f"react_with_{reaction}")) weights.append(weight) # Normalize weights. total_weight = sum(weights) weights = list(map(lambda w: w / total_weight, weights)) self.bot.log_d(f"Reactions: {[r.__name__ for r in reactions]}") self.bot.log_d(f"Reaction weights: {weights}") return reactions, weights def on_pubmsg(self, event): if not self.respects_handling_conditions(): return False if proc(self.config["rate"]): self.bot.log_d("Proc random reaction.") self.react(event) return True return False def react(self, event): if self.weights: method = random.choices(self.reactions, self.weights)[0] else: method = random.choice(self.reactions) self.bot.log_d(f"Using reaction {method.__name__}.") method(event) def react_with_sentence(self, event): """React with a random sentence from config list.""" sentences = self.config.get("sentences") if not sentences: return self.bot.say(event.target, random.choice(sentences)) def react_with_stop(self, event): """Threaten someone that it did its last... (insert last word here).""" stop_message = self.config.get("stop_message") if not stop_message: return words = event.arguments[0].split() if len(words) == 0: return self.bot.say(event.target, stop_message.format(subject=words[-1])) def react_with_king(self, event): """Tell the world that some emoji is the king of the last word.""" king_message = self.config.get("king_message") if not king_message: return kings = self.config.get("kings") if not kings or len(kings) == 0: return words = event.arguments[0].split() if len(words) == 0: return king = random.choice(kings) reply = king_message.format(king=king, subject=words[-1]) self.bot.say(event.target, reply) def react_with_mmm(self, event): """Say a mixed (mm) Skype emote.""" num_chars = random.randint(1, 8) mmm = "" for _ in range(num_chars): mmm += random.choice("(mmm)") self.bot.say(event.target, mmm) def react_with_ooo(self, event): """Just yell some Os.""" self.bot.say(event.target, "O" * random.randint(1, 10)) def react_with_detector(self, event): """Get the last word detector and react to it.""" words = event.arguments[0].split() if len(words) == 0: return detector_message = self.config.get("detector_message") detector_process = self.config.get("detector_process") detector_pos = self.config.get("detector_pos") detector_neg = self.config.get("detector_neg") if any( s is None for s in ( detector_message, detector_process, detector_pos, detector_neg, ) ): return self.bot.say(event.target, detector_message.format(subject=words[-1])) self.bot.say(event.target, detector_process) if proc(50): self.bot.say(event.target, detector_pos) else: self.bot.say(event.target, detector_neg) def react_with_repeat_letters(self, event): """Make sure you understood the biggest word in a stupid way.""" words = event.arguments[0].split() if len(words) == 0: return biggest_word = sorted(words, key=lambda w: len(w))[-1] num_repeats = 2 repeated_prefix = biggest_word[:num_repeats] while ( (not any(letter in repeated_prefix for letter in "aeiouy")) and len(repeated_prefix) < len(biggest_word) ): num_repeats += 1 repeated_prefix = biggest_word[:num_repeats] word = repeated_prefix + biggest_word question_mark = self.config["question_mark"] reply = f"{word}{question_mark}" self.bot.say(event.target, reply) def react_with_nudge(self, event): """Nudge the last person who talked (unsure how or why).""" nick = NickMask(event.source).nick reply = self.config.get("nudging") if reply is None: return self.bot.say(event.target, reply.format(target=nick)) def _generate_flumzo(self) -> Optional[str]: """I'm gonna stop writing docstrings for this shit.""" if any( k not in self.config for k in ("pfouah_sentence", "pfouah1", "pfouah2", "pfouah3") ): return None length = random.choice((2, 3)) word = random.choice(self.config["pfouah1"]) if length == 3: word += random.choice(self.config["pfouah2"]) word += random.choice(self.config["pfouah3"]) return word def react_with_pfouah(self, event): """Sigh and say you're feeling like a made-up word.""" suffix = self.config.get("pfouah_suffix") if suffix is None: return flumzo = self._generate_flumzo() if flumzo is None: return flumzo += suffix text = self.config["pfouah_sentence"].format(word=flumzo) self.bot.say(event.target, text) def react_with_flumzo(self, event): """Same as "pfouah" but the word is said on its own.""" flumzo = self._generate_flumzo() if flumzo is not None: self.bot.say(event.target, flumzo)