291 lines
12 KiB
Python
291 lines
12 KiB
Python
import asyncio
|
|
import datetime
|
|
import discord
|
|
import logging
|
|
import random
|
|
from redbot.core import commands, checks, Config, bank
|
|
from redbot.core.errors import BalanceTooHigh
|
|
from redbot.core.utils.chat_formatting import box, humanize_list, pagify
|
|
|
|
|
|
log = logging.getLogger("red.aikaterna.pupper")
|
|
|
|
|
|
class Pupper(commands.Cog):
|
|
def __init__(self, bot):
|
|
self.bot = bot
|
|
self.config = Config.get_conf(self, 2767241393, force_registration=True)
|
|
self.pets = {}
|
|
|
|
default_guild = {
|
|
"borf_msg": "borf! (thank for pats h00man, have a doggocoin)",
|
|
"channel": [],
|
|
"cooldown": 3600,
|
|
"credits": [100, 500],
|
|
"hello_msg": "Hi! Can someone pet me?",
|
|
"last_pet": "2019-08-01 00:00:00.000001",
|
|
"toggle": False,
|
|
"delete_after": 10,
|
|
}
|
|
|
|
self.config.register_guild(**default_guild)
|
|
|
|
@commands.guild_only()
|
|
@checks.mod_or_permissions(administrator=True)
|
|
@commands.group()
|
|
async def pets(self, ctx):
|
|
"""Manage your pet."""
|
|
if ctx.invoked_subcommand is None:
|
|
guild_data = await self.config.guild(ctx.guild).all()
|
|
if not guild_data["channel"]:
|
|
channel_names = ["No channels set."]
|
|
else:
|
|
channel_names = []
|
|
for channel_id in guild_data["channel"]:
|
|
channel_obj = self.bot.get_channel(channel_id)
|
|
channel_names.append(channel_obj.name)
|
|
|
|
space = "\N{EN SPACE}"
|
|
toggle = "Active" if guild_data["toggle"] else "Inactive"
|
|
delete_after = (
|
|
"No deletion" if not guild_data["delete_after"] else guild_data["delete_after"]
|
|
)
|
|
|
|
msg = f"[Channels]: {humanize_list(channel_names)}\n"
|
|
msg += f"[Cooldown]: {guild_data['cooldown']} seconds\n"
|
|
msg += f"[Credit range]: {guild_data['credits'][0]} - {guild_data['credits'][1]} credits\n"
|
|
msg += f"[Delete after]: {delete_after}\n"
|
|
msg += f"[Toggle]: {toggle}\n"
|
|
msg += f"{space}\n"
|
|
msg += f"[Hello message]: {guild_data['hello_msg']}\n"
|
|
msg += f"[Thanks message]: {guild_data['borf_msg']}\n"
|
|
|
|
for page in pagify(msg, delims=["\n"]):
|
|
await ctx.send(box(page, lang="ini"))
|
|
|
|
@pets.command()
|
|
async def toggle(self, ctx):
|
|
"""Toggle pets on the server."""
|
|
toggle = await self.config.guild(ctx.guild).toggle()
|
|
await self.config.guild(ctx.guild).toggle.set(not toggle)
|
|
await ctx.send(f"The pet is now {'' if not toggle else 'in'}active.")
|
|
|
|
@pets.command()
|
|
async def delete(self, ctx, amount: int = 0):
|
|
"""
|
|
Set how long to wait before deleting the thanks message.
|
|
To leave the thanks message with no deletion, use 0 as the amount.
|
|
10 is the default.
|
|
Max is 5 minutes (300).
|
|
"""
|
|
if amount < 0:
|
|
return await ctx.send("Use a positive number.")
|
|
if 1 <= amount <= 5:
|
|
return await ctx.send("Use a slightly larger number, greater than 5.")
|
|
if amount > 300:
|
|
return await ctx.send("Use a smaller number, less than or equal to 300.")
|
|
|
|
set_amount = None if amount == 0 else amount
|
|
await self.config.guild(ctx.guild).delete_after.set(set_amount)
|
|
msg = f"Timer set to {amount}." if set_amount else "Delete timer has been turned off."
|
|
await ctx.send(msg)
|
|
|
|
@pets.command()
|
|
async def cooldown(self, ctx, seconds: int = None):
|
|
"""Set the pet appearance cooldown in seconds.
|
|
|
|
300s/5 minute minimum. Default is 3600s/1 hour."""
|
|
|
|
if not seconds:
|
|
seconds = 3600
|
|
if seconds < 300:
|
|
seconds = 300
|
|
await self.config.guild(ctx.guild).cooldown.set(seconds)
|
|
await ctx.send(f"Pet appearance cooldown set to {seconds}.")
|
|
|
|
@pets.command()
|
|
async def credits(self, ctx, min_amt: int, max_amt: int):
|
|
"""Set the pet credits range on successful petting."""
|
|
if min_amt > max_amt:
|
|
return await ctx.send("Min must be less than max.")
|
|
if min_amt < 1 or max_amt < 1:
|
|
return await ctx.send("Min and max amounts must be greater than 1.")
|
|
await self.config.guild(ctx.guild).credits.set([min_amt, max_amt])
|
|
await ctx.send(f"Pet credit range set to {min_amt} - {max_amt}.")
|
|
|
|
@pets.command()
|
|
async def hello(self, ctx, *, message: str = None):
|
|
"""Set the pet greeting message."""
|
|
if not message:
|
|
hello = await self.config.guild(ctx.guild).hello_msg()
|
|
return await ctx.send(
|
|
f"Current greeting message: `{hello}`\nUse this command with the message you would like to set."
|
|
)
|
|
if len(message) > 1000:
|
|
return await ctx.send("That dog sure likes to talk a lot. Try a shorter message.")
|
|
await self.config.guild(ctx.guild).hello_msg.set(message)
|
|
await ctx.send(f"Pet hello message set to: `{message}`.")
|
|
|
|
@pets.command()
|
|
async def thanks(self, ctx, *, message: str = None):
|
|
"""Set the pet thanks message."""
|
|
if not message:
|
|
bye = await self.config.guild(ctx.guild).borf_msg()
|
|
return await ctx.send(
|
|
f"Current thanks message: `{bye}`\nUse this command with the message you would like to set."
|
|
)
|
|
if len(message) > 1000:
|
|
return await ctx.send("That dog sure likes to talk a lot. Try a shorter message.")
|
|
await self.config.guild(ctx.guild).borf_msg.set(message)
|
|
await ctx.send(f"Pet thanks message set to: `{message}`.")
|
|
|
|
@commands.guild_only()
|
|
@checks.mod_or_permissions(administrator=True)
|
|
@pets.group(invoke_without_command=True)
|
|
async def channel(self, ctx):
|
|
"""Channel management for pet appearance."""
|
|
await ctx.send_help()
|
|
channel_list = await self.config.guild(ctx.guild).channel()
|
|
channel_msg = "[Petting Channels]:\n"
|
|
if not channel_list:
|
|
channel_msg += "None."
|
|
for chan in channel_list:
|
|
channel_obj = self.bot.get_channel(chan)
|
|
channel_msg += f"{channel_obj.name}\n"
|
|
await ctx.send(box(channel_msg, lang="ini"))
|
|
|
|
@channel.command()
|
|
async def add(self, ctx, channel: discord.TextChannel):
|
|
"""Add a text channel for pets."""
|
|
channel_list = await self.config.guild(ctx.guild).channel()
|
|
if channel.id not in channel_list:
|
|
channel_list.append(channel.id)
|
|
await self.config.guild(ctx.guild).channel.set(channel_list)
|
|
await ctx.send(f"{channel.mention} added to the valid petting channels.")
|
|
else:
|
|
await ctx.send(f"{channel.mention} is already in the list of petting channels.")
|
|
|
|
@channel.command()
|
|
async def addall(self, ctx):
|
|
"""Add all valid channels for the guild that the bot can speak in."""
|
|
bot_text_channels = [
|
|
c
|
|
for c in ctx.guild.text_channels
|
|
if c.permissions_for(ctx.guild.me).send_messages is True
|
|
]
|
|
channel_list = await self.config.guild(ctx.guild).channel()
|
|
channels_appended = []
|
|
channels_in_list = []
|
|
|
|
for text_channel in bot_text_channels:
|
|
if text_channel.id not in channel_list:
|
|
channel_list.append(text_channel.id)
|
|
channels_appended.append(text_channel.mention)
|
|
else:
|
|
channels_in_list.append(text_channel.mention)
|
|
pass
|
|
|
|
first_msg = ""
|
|
second_msg = ""
|
|
await self.config.guild(ctx.guild).channel.set(channel_list)
|
|
if len(channels_appended) > 0:
|
|
first_msg = (
|
|
f"{humanize_list(channels_appended)} added to the valid petting channels.\n"
|
|
)
|
|
if len(channels_in_list) > 0:
|
|
second_msg = (
|
|
f"{humanize_list(channels_in_list)}: already in the list of petting channels."
|
|
)
|
|
await ctx.send(f"{first_msg}{second_msg}")
|
|
|
|
@channel.command()
|
|
async def remove(self, ctx, channel: discord.TextChannel):
|
|
"""Remove a text channel from petting."""
|
|
channel_list = await self.config.guild(ctx.guild).channel()
|
|
if channel.id in channel_list:
|
|
channel_list.remove(channel.id)
|
|
else:
|
|
return await ctx.send(f"{channel.mention} not in the active channel list.")
|
|
await self.config.guild(ctx.guild).channel.set(channel_list)
|
|
await ctx.send(f"{channel.mention} removed from the list of petting channels.")
|
|
|
|
@channel.command()
|
|
async def removeall(self, ctx):
|
|
"""Remove all petting channels from the list."""
|
|
await self.config.guild(ctx.guild).channel.set([])
|
|
await ctx.send("All channels have been removed from the list of petting channels.")
|
|
|
|
def _pet_lock(self, guild_id, tf):
|
|
if tf:
|
|
self.pets[guild_id] = True
|
|
else:
|
|
self.pets[guild_id] = False
|
|
|
|
@commands.Cog.listener()
|
|
async def on_message(self, message):
|
|
try:
|
|
if isinstance(message.channel, discord.abc.PrivateChannel):
|
|
return
|
|
if message.author.bot:
|
|
return
|
|
guild_data = await self.config.guild(message.guild).all()
|
|
if not guild_data["toggle"]:
|
|
return
|
|
if not guild_data["channel"]:
|
|
return
|
|
self.pets.setdefault(message.guild.id, False)
|
|
if self.pets[message.guild.id]:
|
|
return
|
|
|
|
last_time = datetime.datetime.strptime(
|
|
str(guild_data["last_pet"]), "%Y-%m-%d %H:%M:%S.%f"
|
|
)
|
|
now = datetime.datetime.now(datetime.timezone.utc)
|
|
now = now.replace(tzinfo=None)
|
|
if (
|
|
int((now - last_time).total_seconds())
|
|
> await self.config.guild(message.guild).cooldown()
|
|
):
|
|
self._pet_lock(message.guild.id, True)
|
|
rando_channel = random.choice(guild_data["channel"])
|
|
await asyncio.sleep(random.randint(60, 480))
|
|
rando_channel_obj = self.bot.get_channel(rando_channel)
|
|
borf_msg = await rando_channel_obj.send(guild_data["hello_msg"])
|
|
pets = "👋"
|
|
pets_action = {"veryfastpats": "👋"}
|
|
|
|
def check(r, u):
|
|
return r.message.id == borf_msg.id and any(e in str(r.emoji) for e in pets)
|
|
|
|
try:
|
|
r, u = await self.bot.wait_for("reaction_add", check=check, timeout=300.0)
|
|
except asyncio.TimeoutError:
|
|
return await borf_msg.delete()
|
|
|
|
reacts = {v: k for k, v in pets_action.items()}
|
|
react = reacts[r.emoji]
|
|
if react == "veryfastpats":
|
|
await borf_msg.delete()
|
|
deposit = random.randint(guild_data["credits"][0], guild_data["credits"][1])
|
|
try:
|
|
large_bank = False
|
|
await bank.deposit_credits(u, deposit)
|
|
except BalanceTooHigh as e:
|
|
large_bank = True
|
|
await bank.set_balance(u, e.max_balance)
|
|
credits_name = await bank.get_currency_name(message.guild)
|
|
msg = (
|
|
f"{guild_data['borf_msg']} (`+{deposit}` {credits_name})"
|
|
if not large_bank
|
|
else guild_data["borf_msg"]
|
|
)
|
|
await rando_channel_obj.send(
|
|
content=msg, delete_after=guild_data["delete_after"]
|
|
)
|
|
else:
|
|
pass
|
|
self._pet_lock(message.guild.id, False)
|
|
await self.config.guild(message.guild).last_pet.set(str(now))
|
|
except Exception:
|
|
log.error("Error in pupper loop.", exc_info=True)
|