You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

217 lines
7.4 KiB

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)