[Snacktime] Initial commit

Thanks to irdumb for making such an excellent, fun cog. This was long overdue to get this bad boy on v3.
This commit is contained in:
aikaterna
2019-11-01 09:49:29 -07:00
parent ccad084b2b
commit c64252de6e
4 changed files with 555 additions and 0 deletions

5
snacktime/__init__.py Executable file
View File

@@ -0,0 +1,5 @@
from .snacktime import Snacktime
async def setup(bot):
bot.add_cog(Snacktime(bot))

9
snacktime/info.json Normal file
View File

@@ -0,0 +1,9 @@
{
"NAME" : "Snacktime",
"AUTHOR" : ["irdumb", "aikaterna"],
"SHORT" : "ʕ •ᴥ•ʔ < It's snacktime, who wants snacks?",
"DESCRIPTION" : "snackburr will come around every-so-often if you've asked him to.\nI hear snackburr likes to come around more often when people are partyin.",
"INSTALL_MSG" : "A snack delivery bear has ʕ•ᴥ• ʔ",
"TAGS" : ["snack", "snacktime", "snackburr", "party", "party time"],
"DISABLED" : false
}

73
snacktime/phrases.py Normal file
View File

@@ -0,0 +1,73 @@
FRIENDS = {
"Snackburr": "ʕ •ᴥ•ʔ <",
"Pancakes": "₍⸍⸌̣ʷ̣̫⸍̣⸌₎ <",
"Mr Pickles": "(=`ェ´=) <",
"Satin": "▼・ᴥ・▼ <",
"Thunky": "ᘛ⁐̤ᕐᐷ <",
"Jingle": "꒰∗´꒳`꒱ <",
"FluffButt": "/ᐠ。ꞈ。ᐟ\ <",
"Staplefoot": "( ̄(エ) ̄) <",
}
SNACKBURR_PHRASES = {
"SNACKTIME": [
"It's snack time!",
"I'm back with s'more snacks! Who wants!?",
"I'm back errbody! Who wants some snacks!?",
"Woo man those errands are crazy! Anyways, anybody want some snacks?",
"I got snacks! If nobody wants em, I'm gonna eat em all!!",
"Hey, I'm back! Anybody in the mood for some snacks?!",
"Heyyaaayayyyaya! I say Hey, I got snacks!",
"Heyyaaayayyyaya! I say Hey, What's goin on?... I uh.. I got snacks.",
"If anybody has reason why these snacks and my belly should not be wed, speak now or forever hold your peace!",
"Got another snack delivery guys!",
"Did somebody say snacks?!?! o/",
"Choo Choo! it's the pb train! Come on over guys!",
"Snacks are here! Dig in! Who wants a plate?",
"Pstt.. I got the snacks you were lookin for. <.<",
"I hope you guys are hungry! Cause i'm loaded to the brim with snacks!!!",
"I was hungry on the way over so I kinda started without you guys :3 Who wants snacks!?!",
"Beep beep! I got a snack delivery comin in! Who wants snacks!",
"Guess what time it is?! It's snacktime!! Who wants?!",
"Hey check out this sweet stach o' snacks I found! Who wants a cut?",
"Who's ready to gobble down some snacks!?",
"So who's gonna help me eat all these snacks? :3",
],
"OUT": [
"I'm out of snacks! I'll be back with more soon.",
"I'm out of snacks :( I'll be back soon with more!",
"Aight, I gotta head out! I'll be back with more, don worry :3",
"Alright, I gotta get back to my errands. I'll see you guys soon!",
],
"LONELY": ["I guess you guys don't like snacktimes.. I'll stop comin around."],
"NO_TAKERS": [
"I guess nobody wants snacks... more for me!",
"Guess nobody's here.. I'll just head out then",
"I don't see anybody.. <.< ... >.> ... All the snacks for me!!",
"I guess nobody wants snacks huh.. Well, I'll come back later",
"I guess i'll just come back later..",
],
"GIVE": [
"Here ya go, {0}, here's {1} pb!",
"Alright here ya go, {0}, {1} pb for you!",
"Yeah! Here you go, {0}! {1} pb!",
"Of course {0}! Here's {1} pb!",
"Ok {0}, here's {1} pb for you. Anyone else want some?",
"Alllright, {1} pb for {0}!",
"Hold your horses {0}! Alright, {1} pb for you :)",
],
"LAST_SECOND": [
"Fine fine, {0}, I'll give you {1} of my on-the-road pb.. Cya!",
"Oh! {0}, you caught me right before I left! Alright, i'll give you {1} of my own pb",
],
"GREEDY": [
"Don't be greedy now! you already got some pb {0}!",
"You already got your snacks {0}!",
"Come on {0}, you already got your snacks! We gotta make sure there's some for errbody!",
],
"ENABLE": [
"Oh you guys want snacks?! Aight, I'll come around every so often to hand some out!"
],
"DISABLE": ["You guys don't want snacks anymore? Alright, I'll stop comin around."],
}

468
snacktime/snacktime.py Normal file
View File

@@ -0,0 +1,468 @@
import asyncio
import discord
import logging
from random import randint
from random import choice as randchoice
from redbot.core import bank, checks, commands, Config
from redbot.core.utils.chat_formatting import box, humanize_list, pagify
from .phrases import FRIENDS, SNACKBURR_PHRASES
log = logging.getLogger("red.aikaterna.snacktime")
class Snacktime(commands.Cog):
"""Snackburr's passing out pb jars!"""
def __init__(self, bot):
self.bot = bot
self.config = Config.get_conf(self, 2712291001, force_registration=True)
self.snackSchedule = {}
self.snacktimePrediction = {}
self.previousSpeaker = {}
self.snackInProgress = {}
self.acceptInput = {}
self.alreadySnacked = {}
self.msgsPassed = {}
self.startLock = {}
self.snacktimeCheckLock = {}
self.lockRequests = {}
self.channel_persona = {}
default_guild = {
"DELIVER_CHANNELS": [],
"FRIENDS": False,
"EVENT_START_DELAY": 1800,
"EVENT_START_DELAY_VARIANCE": 900,
"SNACK_DURATION": 240,
"SNACK_DURATION_VARIANCE": 120,
"MSGS_BEFORE_EVENT": 8,
"SNACK_AMOUNT": 200,
}
default_channel = {"repeatMissedSnacktimes": 0}
self.config.register_guild(**default_guild)
self.config.register_channel(**default_channel)
async def persona_choice(self, msg):
invite_friends = await self.config.guild(msg.guild).FRIENDS()
personas = FRIENDS
if not invite_friends:
return "Snackburr"
elif invite_friends is True:
del personas["Snackburr"]
return randchoice(list(personas.keys()))
async def get_response(self, msg, phrase_type):
scid = f"{msg.guild.id}-{msg.channel.id}"
persona = self.channel_persona[scid]
persona_phrase = FRIENDS.get(persona)
phrase = randchoice(SNACKBURR_PHRASES[phrase_type])
return f"`{persona_phrase} {phrase}`"
@commands.guild_only()
@commands.group()
@checks.mod_or_permissions(manage_guild=True)
async def snackset(self, ctx):
"""snack stuff"""
if ctx.invoked_subcommand is None:
guild_data = await self.config.guild(ctx.guild).all()
if not guild_data["DELIVER_CHANNELS"]:
channel_names = ["No channels set."]
else:
channel_names = []
for channel_id in guild_data["DELIVER_CHANNELS"]:
channel_obj = self.bot.get_channel(channel_id)
channel_names.append(channel_obj.name)
if guild_data["FRIENDS"] is True:
invite_friends = "Friends only"
elif guild_data["FRIENDS"] is False:
invite_friends = "Snackburr only"
else:
invite_friends = "Everyone's invited!"
msg = f"[Delivering in]: {humanize_list(channel_names)}\n"
msg += f"[Event start delay]: {guild_data['EVENT_START_DELAY']} seconds\n"
msg += (
f"[Event start variance]: {guild_data['EVENT_START_DELAY_VARIANCE']} seconds\n"
)
msg += f"[Friends status]: {invite_friends}\n"
msg += f"[Messages before event]: {guild_data['MSGS_BEFORE_EVENT']}\n"
msg += f"[Snack amount limit]: {guild_data['SNACK_AMOUNT']} pb\n"
msg += f"[Snack duration]: {guild_data['SNACK_DURATION']} seconds\n"
msg += f"[Snack duration variance]: {guild_data['SNACK_DURATION_VARIANCE']} seconds\n"
for page in pagify(msg, delims=["\n"]):
await ctx.send(box(page, lang="ini"))
@snackset.command()
async def errandtime(self, ctx, seconds: int):
"""How long snackburr needs to be out doin errands.. more or less."""
event_start_delay_variance = await self.config.guild(
ctx.guild
).EVENT_START_DELAY_VARIANCE()
if seconds <= event_start_delay_variance:
await ctx.send("errandtime must be greater than errandvariance!")
elif seconds <= 0:
await ctx.send("errandtime must be greater than 0")
else:
await self.config.guild(ctx.guild).EVENT_START_DELAY.set(seconds)
await ctx.send(
f"snackburr's errands will now take around {round(seconds/60, 2)} minutes!"
)
@snackset.command()
async def errandvariance(self, ctx, seconds: int):
"""How early or late snackburr might be to snacktime"""
event_start_delay = await self.config.guild(ctx.guild).EVENT_START_DELAY()
if seconds >= event_start_delay:
await ctx.send("errandvariance must be less than errandtime!")
elif seconds < 0:
await ctx.send("errandvariance must be 0 or greater!")
else:
await self.config.guild(ctx.guild).EVENT_START_DELAY_VARIANCE.set(seconds)
await ctx.send(
f"snackburr now might be {round(seconds/60, 2)} minutes early or late to snacktime"
)
@snackset.command(name="snacktime")
async def snacktimetime(self, ctx, seconds: int):
"""How long snackburr will hang out giving out snacks!.. more or less."""
snack_duration_variance = await self.config.guild(ctx.guild).SNACK_DURATION_VARIANCE()
if seconds <= snack_duration_variance:
await ctx.send("snacktime must be greater than snackvariance!")
elif seconds <= 0:
await ctx.send("snacktime must be greater than 0")
else:
await self.config.guild(ctx.guild).SNACK_DURATION.set(seconds)
await ctx.send(f"snacktimes will now last around {round(seconds/60, 2)} minutes!")
@snackset.command(name="snackvariance")
async def snacktimevariance(self, ctx, seconds: int):
"""How early or late snackburr might have to leave for errands"""
snack_duration = await self.config.guild(ctx.guild).SNACK_DURATION()
if seconds >= snack_duration:
await ctx.send("snackvariance must be less than snacktime!")
elif seconds < 0:
await ctx.send("snackvariance must be 0 or greater!")
else:
await self.config.guild(ctx.guild).SNACK_DURATION_VARIANCE.set(seconds)
await ctx.send(
f"snackburr now may have to leave snacktime {round(seconds/60, 2)} minutes early or late"
)
@snackset.command()
async def msgsneeded(self, ctx, amt: int):
"""How many messages must pass in a conversation before a snacktime can start"""
if amt <= 0:
await ctx.send("msgsneeded must be greater than 0")
else:
await self.config.guild(ctx.guild).MSGS_BEFORE_EVENT.set(amt)
await ctx.send(
f"snackburr will now wait until {amt} messages pass until he comes with snacks"
)
@snackset.command()
async def amount(self, ctx, amt: int):
"""How much pb max snackburr should give out to each person per snacktime"""
if amt <= 0:
await ctx.send("amount must be greater than 0")
else:
await self.config.guild(ctx.guild).SNACK_AMOUNT.set(amt)
await ctx.send(f"snackburr will now give out {amt} pb max per person per snacktime.")
@snackset.command(name="friends")
async def snackset_friends(self, ctx, choice: int):
"""snackburr's friends wanna know what all the hub-bub's about!
Do you want to
1: invite them to the party,
2: only allow snackburr to chillax with you guys, or
3: kick snackburr out on the curb in favor of his obviously cooler friends?
"""
if choice not in (1, 2, 3):
return await ctx.send_help()
choices = {
1: ("both", "Everybody's invited!"),
2: (False, "You chose to not invite snackburr's friends."),
3: (True, "You kick snackburr out in favor of his friends! Ouch. Harsh..."),
}
choice = choices[choice]
await self.config.guild(ctx.guild).FRIENDS.set(choice[0])
await ctx.send(choice[1])
@snackset.command()
async def deliver(self, ctx):
"""Asks snackburr to start delivering to this channel"""
deliver_channels = await self.config.guild(ctx.guild).DELIVER_CHANNELS()
if not deliver_channels:
deliver_channels = []
if ctx.channel.id not in deliver_channels:
deliver_channels.append(ctx.channel.id)
await self.config.guild(ctx.guild).DELIVER_CHANNELS.set(deliver_channels)
await ctx.send("snackburr will start delivering here!")
else:
deliver_channels.remove(ctx.channel.id)
await self.config.guild(ctx.guild).DELIVER_CHANNELS.set(deliver_channels)
await ctx.send("snackburr will stop delivering here!")
@commands.command(pass_context=True)
async def snacktime(self, ctx):
"""Man i'm hungry! When's snackburr gonna get back with more snacks?"""
scid = f"{ctx.message.guild.id}-{ctx.message.channel.id}"
if self.snacktimePrediction.get(scid, None) == None:
if self.acceptInput.get(scid, False):
return
else:
phrases = [
"Don't look at me. I donno where snackburr's at ¯\_(ツ)_/¯",
"I hear snackburr likes parties. *wink wink",
"I hear snackburr is attracted to channels with active conversations",
"If you party, snackburr will come! 〈( ^o^)",
]
await ctx.send(randchoice(phrases))
return
seconds = self.snacktimePrediction[scid] - self.bot.loop.time()
if self.snacktimeCheckLock.get(scid, False):
if randint(1, 4) == 4:
await ctx.send("Hey, snackburr's on errands. I ain't his keeper Kappa")
return
self.snacktimeCheckLock[scid] = True
if seconds < 0:
await ctx.send(
f"I'm not sure where snackburr is.. He's already {seconds / 60} minutes late!"
)
else:
await ctx.send(
f"snackburr's out on errands! I think he'll be back in {seconds / 60} minutes"
)
await asyncio.sleep(40)
self.snacktimeCheckLock[scid] = False
async def startSnack(self, message):
scid = f"{message.guild.id}-{message.channel.id}"
if self.acceptInput.get(scid, False):
return
self.channel_persona[scid] = await self.persona_choice(message)
await message.channel.send(await self.get_response(message, "SNACKTIME"))
self.acceptInput[scid] = True
self.alreadySnacked[scid] = []
guild_data = await self.config.guild(message.guild).all()
duration = guild_data["SNACK_DURATION"] + randint(
-guild_data["SNACK_DURATION_VARIANCE"], guild_data["SNACK_DURATION_VARIANCE"]
)
await asyncio.sleep(duration)
# sometimes fails sending messages and stops all future snacktimes. Hopefully this fixes it.
try:
# list isn't empty
if self.alreadySnacked.get(scid, False):
await message.channel.send(await self.get_response(message, "OUT"))
await self.config.channel(message.channel).repeatMissedSnacktimes.set(0)
else:
await message.channel.send(await self.get_response(message, "NO_TAKERS"))
repeat_missed_snacktimes = await self.config.channel(
message.channel
).repeatMissedSnacktimes()
await self.config.channel(message.channel).repeatMissedSnacktimes.set(
repeat_missed_snacktimes + 1
)
await asyncio.sleep(2)
if (repeat_missed_snacktimes + 1) > 9: # move to a setting
await message.channel.send(await self.get_response(message, "LONELY"))
deliver_channels = await self.config.guild(message.guild).DELIVER_CHANNELS()
new_deliver_channels = deliver_channels.remove(message.channel.id)
await self.config.guild(message.guild).DELIVER_CHANNELS.set(
new_deliver_channels
)
await self.config.channel(message.channel).repeatMissedSnacktimes.set(0)
except:
log.error("Snacktime: Failed to send message in startSnack")
self.acceptInput[scid] = False
self.snackInProgress[scid] = False
@commands.Cog.listener()
async def on_message(self, message):
if not message.guild:
return
if message.author.bot:
return
if not message.channel.permissions_for(message.guild.me).send_messages:
return
deliver_channels = await self.config.guild(message.guild).DELIVER_CHANNELS()
if not deliver_channels:
return
if message.channel.id not in deliver_channels:
return
scid = f"{message.guild.id}-{message.channel.id}"
if message.author.id != self.bot.user.id:
# if nobody has said anything since start
if self.previousSpeaker.get(scid, None) == None:
self.previousSpeaker[scid] = message.author.id
# if new speaker
elif self.previousSpeaker[scid] != message.author.id:
self.previousSpeaker[scid] = message.author.id
msgTime = self.bot.loop.time()
# if there's a scheduled snack
if self.snackSchedule.get(scid, None) != None:
# if it's time for a snack
if msgTime > self.snackSchedule[scid]:
# 1 schedule at a time, so remove schedule
self.snackSchedule[scid] = None
self.snackInProgress[scid] = True
# wait to make it more natural
naturalWait = randint(30, 240)
log.debug(f"Snacktime: snack trigger msg: {message.content}")
log.debug(f"Snacktime: Waiting {str(naturalWait)} seconds")
await asyncio.sleep(naturalWait)
# start snacktime
await self.startSnack(message)
# if no snack coming, schedule one
elif self.snackInProgress.get(scid, False) == False and not self.startLock.get(
scid, False
):
self.msgsPassed[scid] = self.msgsPassed.get(scid, 0) + 1
# check for collisions
msgs_before_event = await self.config.guild(message.guild).MSGS_BEFORE_EVENT()
if self.msgsPassed[scid] > msgs_before_event:
self.startLock[scid] = True
if self.lockRequests.get(scid, None) == None:
self.lockRequests[scid] = []
self.lockRequests[scid].append(message)
await asyncio.sleep(1)
log.debug(
f"Snacktime: :-+-|||||-+-: Lock request: {str(self.lockRequests[scid][0] == message)}"
)
if self.lockRequests[scid][0] == message:
await asyncio.sleep(5)
log.debug(f"Snacktime: {message.author.name} - I got the Lock")
self.lockRequests[scid] = []
# someone got through already
if self.msgsPassed[
scid
] < msgs_before_event or self.snackInProgress.get(scid, False):
log.debug("Snacktime: Lock: someone got through already.")
return
else:
log.debug(
"Snacktime: Lock: looks like i'm in the clear. lifting lock. If someone comes now, they should get the lock"
)
self.msgsPassed[scid] = msgs_before_event
self.startLock[scid] = False
else:
log.debug(f"Snacktime: {message.author.name} Failed lock")
return
if self.msgsPassed[scid] == msgs_before_event:
# schedule a snack
log.debug(f"Snacktime: activity: {message.content}")
guild_data = await self.config.guild(message.guild).all()
timeTillSnack = guild_data["EVENT_START_DELAY"] + randint(
-guild_data["EVENT_START_DELAY_VARIANCE"],
guild_data["EVENT_START_DELAY_VARIANCE"],
)
log.debug(f"Snacktime: {str(timeTillSnack)} seconds till snacktime")
self.snacktimePrediction[scid] = msgTime + guild_data["EVENT_START_DELAY"]
self.snackSchedule[scid] = msgTime + timeTillSnack
self.msgsPassed[scid] = 0
# it's snacktime! who want's snacks?
if self.acceptInput.get(scid, False):
if message.author.id not in self.alreadySnacked.get(scid, []):
agree_phrases = [
"holds out hand",
"im ready",
"i'm ready",
"hit me up",
"hand over",
"hand me",
"kindly",
"i want",
"i'll have",
"ill have",
"yes",
"pls",
"plz",
"please",
"por favor",
"can i",
"i'd like",
"i would",
"may i",
"in my mouth",
"in my belly",
"snack me",
"gimme",
"give me",
"i'll take",
"ill take",
"i am",
"about me",
"me too",
"of course",
]
userWants = False
for agreePhrase in agree_phrases:
# no one word answers
if (
agreePhrase in message.content.lower()
and len(message.content.split()) > 1
):
userWants = True
break
if userWants:
if self.alreadySnacked.get(scid, None) == None:
self.alreadySnacked[scid] = []
self.alreadySnacked[scid].append(message.author.id)
await asyncio.sleep(randint(1, 6))
snack_amount = await self.config.guild(message.guild).SNACK_AMOUNT()
snackAmt = randint(1, snack_amount)
try:
if self.acceptInput.get(scid, False):
resp = await self.get_response(message, "GIVE")
resp = resp.format(message.author.name, snackAmt)
await message.channel.send(resp)
else:
resp = await self.get_response(message, "LAST_SECOND")
resp = resp.format(message.author.name, snackAmt)
await message.channel.send(resp)
await bank.deposit_credits(message.author, snackAmt)
except:
log.info(
f"Snacktime: Failed to send pb message. {message.author.name} didn't get pb"
)
else:
more_phrases = [
"more pl",
"i have some more",
"i want more",
"i have another",
"i have more",
"more snack",
]
userWants = False
for morePhrase in more_phrases:
if morePhrase in message.content.lower():
userWants = True
break
if userWants:
await asyncio.sleep(randint(1, 6))
if self.acceptInput.get(scid, False):
await message.channel.send(
await self.get_response(message, "GREEDY").format(
message.author.name
)
)