2020-04-02 15:07:43 -04:00
|
|
|
import asyncio
|
|
|
|
|
import datetime
|
2021-04-06 19:11:00 +02:00
|
|
|
from logging import warning
|
2020-04-02 15:07:43 -04:00
|
|
|
import math
|
|
|
|
|
import random
|
|
|
|
|
import time
|
2021-04-06 19:11:00 +02:00
|
|
|
from typing import Literal
|
2020-04-02 15:07:43 -04:00
|
|
|
|
2021-04-06 19:11:00 +02:00
|
|
|
import discord
|
2022-04-04 15:19:49 -04:00
|
|
|
from redbot.core import Config, checks, commands, bank
|
|
|
|
|
from redbot.core.errors import BalanceTooHigh
|
2021-04-06 19:11:00 +02:00
|
|
|
from redbot.core.utils.chat_formatting import (bold, box, humanize_list,
|
|
|
|
|
humanize_number, pagify)
|
|
|
|
|
from redbot.core.utils.menus import DEFAULT_CONTROLS, menu
|
|
|
|
|
from redbot.core.utils.predicates import MessagePredicate
|
2020-04-02 15:07:43 -04:00
|
|
|
|
2022-10-27 13:35:03 -04:00
|
|
|
__version__ = "3.1.9"
|
2020-04-02 15:07:43 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class Hunting(commands.Cog):
|
|
|
|
|
"""Hunting, it hunts birds and things that fly."""
|
|
|
|
|
|
2020-08-26 17:57:43 +01:00
|
|
|
async def red_delete_data_for_user(
|
|
|
|
|
self, *, requester: Literal["discord", "owner", "user", "user_strict"], user_id: int,
|
|
|
|
|
):
|
|
|
|
|
await self.config.user_from_id(user_id).clear()
|
|
|
|
|
|
2020-04-02 15:07:43 -04:00
|
|
|
def __init__(self, bot):
|
|
|
|
|
self.bot = bot
|
|
|
|
|
self.config = Config.get_conf(self, 2784481002, force_registration=True)
|
|
|
|
|
|
|
|
|
|
self.animals = {
|
|
|
|
|
"dove": ":dove: **_Coo!_**",
|
|
|
|
|
"penguin": ":penguin: **_Noot!_**",
|
|
|
|
|
"chicken": ":chicken: **_Bah-gawk!_**",
|
|
|
|
|
"duck": ":duck: **_Quack!_**",
|
|
|
|
|
}
|
|
|
|
|
self.in_game = []
|
|
|
|
|
self.paused_games = []
|
|
|
|
|
self.next_bang = {}
|
2020-05-15 10:20:08 -07:00
|
|
|
self.game_tasks = []
|
2020-04-02 15:07:43 -04:00
|
|
|
|
|
|
|
|
default_guild = {
|
|
|
|
|
"hunt_interval_minimum": 900,
|
|
|
|
|
"hunt_interval_maximum": 3600,
|
|
|
|
|
"wait_for_bang_timeout": 20,
|
|
|
|
|
"channels": [],
|
2020-05-15 10:20:08 -07:00
|
|
|
"bang_time": False,
|
2020-05-15 16:26:16 -07:00
|
|
|
"bang_words": True,
|
2022-04-04 15:19:49 -04:00
|
|
|
"reward_range": [],
|
|
|
|
|
}
|
|
|
|
|
default_global = {
|
|
|
|
|
"reward_range": [], # For bots with global banks
|
2020-04-02 15:07:43 -04:00
|
|
|
}
|
2020-06-01 23:12:37 +04:00
|
|
|
default_user = {"score": {}, "total": 0}
|
2020-04-02 15:07:43 -04:00
|
|
|
self.config.register_user(**default_user)
|
|
|
|
|
self.config.register_guild(**default_guild)
|
2022-04-19 12:46:57 -07:00
|
|
|
self.config.register_global(**default_global)
|
2020-04-02 15:07:43 -04:00
|
|
|
|
|
|
|
|
@commands.guild_only()
|
|
|
|
|
@commands.group()
|
|
|
|
|
async def hunting(self, ctx):
|
|
|
|
|
"""Hunting, it hunts birds and things that fly."""
|
|
|
|
|
if ctx.invoked_subcommand is None:
|
|
|
|
|
guild_data = await self.config.guild(ctx.guild).all()
|
|
|
|
|
if not guild_data["channels"]:
|
|
|
|
|
channel_names = ["No channels set."]
|
|
|
|
|
else:
|
|
|
|
|
channel_names = []
|
|
|
|
|
for channel_id in guild_data["channels"]:
|
|
|
|
|
channel_obj = self.bot.get_channel(channel_id)
|
2021-04-29 18:28:07 -07:00
|
|
|
if channel_obj:
|
|
|
|
|
channel_names.append(channel_obj.name)
|
2020-04-02 15:07:43 -04:00
|
|
|
|
2020-05-15 16:26:16 -07:00
|
|
|
hunting_mode = "Words" if guild_data["bang_words"] else "Reactions"
|
2020-06-02 03:10:34 +04:00
|
|
|
reaction_time = "On" if guild_data["bang_time"] else "Off"
|
2020-05-15 16:26:16 -07:00
|
|
|
|
|
|
|
|
msg = f"[Hunting in]: {humanize_list(channel_names)}\n"
|
|
|
|
|
msg += f"[Bang timeout]: {guild_data['wait_for_bang_timeout']} seconds\n"
|
|
|
|
|
msg += f"[Hunt interval minimum]: {guild_data['hunt_interval_minimum']} seconds\n"
|
|
|
|
|
msg += f"[Hunt interval maximum]: {guild_data['hunt_interval_maximum']} seconds\n"
|
|
|
|
|
msg += f"[Hunting mode]: {hunting_mode}\n"
|
|
|
|
|
msg += f"[Bang response time message]: {reaction_time}\n"
|
2020-04-02 15:07:43 -04:00
|
|
|
|
2022-04-04 15:19:49 -04:00
|
|
|
if await bank.is_global():
|
|
|
|
|
reward = await self.config.reward_range()
|
|
|
|
|
if reward:
|
|
|
|
|
reward = f"{reward[0]} - {reward[1]}"
|
|
|
|
|
msg += f"[Hunting reward range]: {reward if reward else 'None'}\n"
|
|
|
|
|
else:
|
|
|
|
|
reward = guild_data['reward_range']
|
|
|
|
|
if reward:
|
|
|
|
|
reward = f"{reward[0]} - {reward[1]}"
|
|
|
|
|
msg += f"[Hunting reward range]: {reward if reward else 'None'}\n"
|
|
|
|
|
|
2020-04-02 15:07:43 -04:00
|
|
|
for page in pagify(msg, delims=["\n"]):
|
|
|
|
|
await ctx.send(box(page, lang="ini"))
|
|
|
|
|
|
|
|
|
|
@hunting.command()
|
2020-04-22 11:01:37 -07:00
|
|
|
async def leaderboard(self, ctx, global_leaderboard=False):
|
|
|
|
|
"""
|
|
|
|
|
This will show the top 50 hunters for the server.
|
|
|
|
|
Use True for the global_leaderboard variable to show the global leaderboard.
|
|
|
|
|
"""
|
2020-04-02 15:07:43 -04:00
|
|
|
userinfo = await self.config._all_from_scope(scope="USER")
|
|
|
|
|
if not userinfo:
|
|
|
|
|
return await ctx.send(bold("Please shoot something before you can brag about it."))
|
|
|
|
|
|
|
|
|
|
async with ctx.typing():
|
|
|
|
|
sorted_acc = sorted(userinfo.items(), key=lambda x: (x[1]["total"]), reverse=True)[:50]
|
|
|
|
|
|
2020-06-02 03:10:34 +04:00
|
|
|
if not hasattr(ctx.guild, "members"):
|
|
|
|
|
global_leaderboard = True
|
|
|
|
|
|
2020-04-02 15:07:43 -04:00
|
|
|
pound_len = len(str(len(sorted_acc)))
|
|
|
|
|
score_len = 10
|
2020-04-23 12:51:37 -07:00
|
|
|
header = "{score:{score_len}}{name:2}\n".format(
|
|
|
|
|
score="# Birds Shot",
|
2020-04-02 15:07:43 -04:00
|
|
|
score_len=score_len + 5,
|
2020-08-26 17:57:43 +01:00
|
|
|
name="Name" if not str(ctx.author.mobile_status) in ["online", "idle", "dnd"] else "Name",
|
2020-04-02 15:07:43 -04:00
|
|
|
)
|
|
|
|
|
temp_msg = header
|
2020-04-23 12:51:37 -07:00
|
|
|
for account in sorted_acc:
|
2020-04-02 15:07:43 -04:00
|
|
|
if account[1]["total"] == 0:
|
|
|
|
|
continue
|
2020-06-02 03:10:34 +04:00
|
|
|
if global_leaderboard or (account[0] in [member.id for member in ctx.guild.members]):
|
|
|
|
|
user_obj = self.bot.get_user(account[0]) or account[0]
|
|
|
|
|
else:
|
|
|
|
|
continue
|
2020-06-01 23:12:37 +04:00
|
|
|
if isinstance(user_obj, discord.User) and len(str(user_obj)) > 28:
|
|
|
|
|
user_name = f"{user_obj.name[:19]}...#{user_obj.discriminator}"
|
|
|
|
|
else:
|
2020-04-02 15:07:43 -04:00
|
|
|
user_name = str(user_obj)
|
|
|
|
|
if user_obj == ctx.author:
|
2020-04-23 12:51:37 -07:00
|
|
|
temp_msg += f"{humanize_number(account[1]['total']) + ' ': <{score_len + 4}} <<{user_name}>>\n"
|
2020-04-02 15:07:43 -04:00
|
|
|
else:
|
2020-04-23 12:51:37 -07:00
|
|
|
temp_msg += f"{humanize_number(account[1]['total']) + ' ': <{score_len + 4}} {user_name}\n"
|
2020-04-02 15:07:43 -04:00
|
|
|
|
|
|
|
|
page_list = []
|
|
|
|
|
pages = 1
|
2020-04-22 11:01:37 -07:00
|
|
|
for page in pagify(temp_msg, delims=["\n"], page_length=800):
|
2020-04-23 12:51:37 -07:00
|
|
|
if global_leaderboard:
|
|
|
|
|
title = "Global Hunting Leaderboard"
|
|
|
|
|
else:
|
|
|
|
|
title = f"Hunting Leaderboard For {ctx.guild.name}"
|
2020-04-02 15:07:43 -04:00
|
|
|
embed = discord.Embed(
|
|
|
|
|
colour=await ctx.bot.get_embed_color(location=ctx.channel),
|
2020-04-23 12:51:37 -07:00
|
|
|
description=box(title, lang="prolog") + (box(page, lang="md")),
|
2020-04-02 15:07:43 -04:00
|
|
|
)
|
2020-08-26 17:57:43 +01:00
|
|
|
embed.set_footer(text=f"Page {humanize_number(pages)}/{humanize_number(math.ceil(len(temp_msg) / 800))}")
|
2020-04-02 15:07:43 -04:00
|
|
|
pages += 1
|
|
|
|
|
page_list.append(embed)
|
2020-04-23 12:51:37 -07:00
|
|
|
if len(page_list) == 1:
|
|
|
|
|
await ctx.send(embed=page_list[0])
|
|
|
|
|
else:
|
|
|
|
|
await menu(ctx, page_list, DEFAULT_CONTROLS)
|
2020-04-02 15:07:43 -04:00
|
|
|
|
2020-05-15 10:20:08 -07:00
|
|
|
@checks.mod_or_permissions(manage_guild=True)
|
|
|
|
|
@hunting.command()
|
|
|
|
|
async def bangtime(self, ctx):
|
|
|
|
|
"""Toggle displaying the bang response time from users."""
|
|
|
|
|
toggle = await self.config.guild(ctx.guild).bang_time()
|
|
|
|
|
await self.config.guild(ctx.guild).bang_time.set(not toggle)
|
2020-05-15 16:26:16 -07:00
|
|
|
toggle_text = "will not" if toggle else "will"
|
|
|
|
|
await ctx.send(f"Bang reaction time {toggle_text} be shown.\n")
|
|
|
|
|
|
|
|
|
|
@checks.mod_or_permissions(manage_guild=True)
|
|
|
|
|
@hunting.command()
|
|
|
|
|
async def mode(self, ctx):
|
|
|
|
|
"""Toggle whether the bot listens for 'bang' or a reaction."""
|
|
|
|
|
toggle = await self.config.guild(ctx.guild).bang_words()
|
|
|
|
|
await self.config.guild(ctx.guild).bang_words.set(not toggle)
|
|
|
|
|
toggle_text = "Use the reaction" if toggle else "Type 'bang'"
|
|
|
|
|
await ctx.send(f"{toggle_text} to react to the bang message when it appears.\n")
|
2020-05-15 10:20:08 -07:00
|
|
|
|
2022-04-04 15:19:49 -04:00
|
|
|
@checks.mod_or_permissions(manage_guild=True)
|
|
|
|
|
@hunting.command()
|
|
|
|
|
async def reward(self, ctx, min_reward: int = None, max_reward: int = None):
|
|
|
|
|
"""
|
|
|
|
|
Set a credit reward range for successfully shooting a bird
|
|
|
|
|
|
|
|
|
|
Leave the options blank to disable bang rewards
|
|
|
|
|
"""
|
|
|
|
|
bank_is_global = await bank.is_global()
|
|
|
|
|
if ctx.author.id not in self.bot.owner_ids and bank_is_global:
|
|
|
|
|
return await ctx.send("Bank is global, only bot owner can set a reward range.")
|
|
|
|
|
if not min_reward or not max_reward:
|
|
|
|
|
if min_reward != 0 and not max_reward: # Maybe they want users to sometimes not get rewarded
|
|
|
|
|
if bank_is_global:
|
|
|
|
|
await self.config.reward_range.set([])
|
|
|
|
|
else:
|
|
|
|
|
await self.config.guild(ctx.guild).reward_range.set([])
|
|
|
|
|
msg = "Reward range reset to default(None)."
|
|
|
|
|
return await ctx.send(msg)
|
|
|
|
|
if min_reward > max_reward:
|
|
|
|
|
return await ctx.send("Your minimum reward is greater than your max reward...")
|
|
|
|
|
reward_range = [min_reward, max_reward]
|
|
|
|
|
currency_name = await bank.get_currency_name(ctx.guild)
|
|
|
|
|
if bank_is_global:
|
|
|
|
|
await self.config.reward_range.set(reward_range)
|
|
|
|
|
else:
|
|
|
|
|
await self.config.guild(ctx.guild).reward_range.set(reward_range)
|
|
|
|
|
msg = f"Users can now get {min_reward} to {max_reward} {currency_name} for shooting a bird."
|
|
|
|
|
await ctx.send(msg)
|
|
|
|
|
|
2020-04-03 09:55:30 -07:00
|
|
|
@checks.mod_or_permissions(manage_guild=True)
|
2020-04-02 15:07:43 -04:00
|
|
|
@hunting.command()
|
|
|
|
|
async def next(self, ctx):
|
|
|
|
|
"""When will the next occurrence happen?"""
|
|
|
|
|
try:
|
2022-10-27 13:35:03 -04:00
|
|
|
hunt = self.next_bang[ctx.guild.id]
|
|
|
|
|
time = abs(datetime.datetime.utcnow() - hunt)
|
2020-04-02 15:07:43 -04:00
|
|
|
total_seconds = int(time.total_seconds())
|
|
|
|
|
hours, remainder = divmod(total_seconds, 60 * 60)
|
|
|
|
|
minutes, seconds = divmod(remainder, 60)
|
|
|
|
|
message = f"The next occurrence will be in {hours} hours and {minutes} minutes."
|
|
|
|
|
except KeyError:
|
|
|
|
|
message = "There is currently no hunt."
|
|
|
|
|
await ctx.send(bold(message))
|
|
|
|
|
|
|
|
|
|
@hunting.command(name="score")
|
|
|
|
|
async def score(self, ctx, member: discord.Member = None):
|
|
|
|
|
"""This will show the score of a hunter."""
|
|
|
|
|
if not member:
|
|
|
|
|
member = ctx.author
|
|
|
|
|
score = await self.config.user(member).score()
|
|
|
|
|
total = 0
|
|
|
|
|
kill_list = []
|
|
|
|
|
if not score:
|
|
|
|
|
message = "Please shoot something before you can brag about it."
|
|
|
|
|
|
|
|
|
|
for animal in score.items():
|
|
|
|
|
total = total + animal[1]
|
2020-07-06 19:03:43 +04:00
|
|
|
if animal[1] == 1 or animal[0][-1] == "s":
|
2020-04-02 15:07:43 -04:00
|
|
|
kill_list.append(f"{animal[1]} {animal[0].capitalize()}")
|
|
|
|
|
else:
|
|
|
|
|
kill_list.append(f"{animal[1]} {animal[0].capitalize()}s")
|
|
|
|
|
message = f"{member.name} shot a total of {total} animals ({humanize_list(kill_list)})"
|
|
|
|
|
await ctx.send(bold(message))
|
|
|
|
|
|
2020-04-03 09:55:30 -07:00
|
|
|
@checks.mod_or_permissions(manage_guild=True)
|
2020-04-02 15:07:43 -04:00
|
|
|
@hunting.command()
|
|
|
|
|
async def start(self, ctx, channel: discord.TextChannel = None):
|
|
|
|
|
"""Start the hunt."""
|
|
|
|
|
if not channel:
|
|
|
|
|
channel = ctx.channel
|
|
|
|
|
|
|
|
|
|
if not channel.permissions_for(ctx.guild.me).send_messages:
|
|
|
|
|
return await ctx.send(bold("I can't send messages in that channel!"))
|
|
|
|
|
|
|
|
|
|
channel_list = await self.config.guild(ctx.guild).channels()
|
|
|
|
|
if channel.id in channel_list:
|
|
|
|
|
message = f"We're already hunting in {channel.mention}!"
|
|
|
|
|
else:
|
|
|
|
|
channel_list.append(channel.id)
|
|
|
|
|
message = f"The hunt has started in {channel.mention}. Good luck to all."
|
|
|
|
|
await self.config.guild(ctx.guild).channels.set(channel_list)
|
|
|
|
|
|
|
|
|
|
await ctx.send(bold(message))
|
|
|
|
|
|
2020-04-03 09:55:30 -07:00
|
|
|
@checks.mod_or_permissions(manage_guild=True)
|
2020-04-02 15:07:43 -04:00
|
|
|
@hunting.command()
|
|
|
|
|
async def stop(self, ctx, channel: discord.TextChannel = None):
|
|
|
|
|
"""Stop the hunt."""
|
|
|
|
|
if not channel:
|
|
|
|
|
channel = ctx.channel
|
|
|
|
|
channel_list = await self.config.guild(ctx.guild).channels()
|
|
|
|
|
|
|
|
|
|
if channel.id not in channel_list:
|
|
|
|
|
message = f"We're not hunting in {channel.mention}!"
|
|
|
|
|
else:
|
|
|
|
|
channel_list.remove(channel.id)
|
|
|
|
|
message = f"The hunt has stopped in {channel.mention}."
|
|
|
|
|
await self.config.guild(ctx.guild).channels.set(channel_list)
|
|
|
|
|
|
|
|
|
|
await ctx.send(bold(message))
|
|
|
|
|
|
2021-04-06 19:11:00 +02:00
|
|
|
@checks.is_owner()
|
|
|
|
|
@hunting.command()
|
|
|
|
|
async def clearleaderboard(self, ctx):
|
|
|
|
|
"""
|
|
|
|
|
Clear all the scores from the leaderboard.
|
|
|
|
|
"""
|
|
|
|
|
warning_string = (
|
|
|
|
|
"Are you sure you want to clear all the scores from the leaderboard?\n"
|
|
|
|
|
"This is a global wipe and **cannot** be undone!\n"
|
|
|
|
|
"Type \"Yes\" to confirm, or \"No\" to cancel."
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
await ctx.send(warning_string)
|
|
|
|
|
pred = MessagePredicate.yes_or_no(ctx)
|
|
|
|
|
try:
|
|
|
|
|
await self.bot.wait_for("message", check=pred, timeout=15)
|
|
|
|
|
if pred.result is True:
|
|
|
|
|
await self.config.clear_all_users()
|
|
|
|
|
return await ctx.send("Done!")
|
|
|
|
|
else:
|
|
|
|
|
return await ctx.send("Alright, not clearing the leaderboard.")
|
|
|
|
|
except asyncio.TimeoutError:
|
|
|
|
|
return await ctx.send("Response timed out.")
|
|
|
|
|
|
2020-04-03 09:55:30 -07:00
|
|
|
@checks.mod_or_permissions(manage_guild=True)
|
2020-04-02 15:07:43 -04:00
|
|
|
@hunting.command()
|
|
|
|
|
async def timing(self, ctx, interval_min: int, interval_max: int, bang_timeout: int):
|
|
|
|
|
"""
|
|
|
|
|
Change the hunting timing.
|
2021-04-06 19:11:00 +02:00
|
|
|
|
2020-04-02 15:07:43 -04:00
|
|
|
`interval_min` = Minimum time in seconds for a new bird. (120s min)
|
|
|
|
|
`interval_max` = Maximum time in seconds for a new bird. (240s min)
|
|
|
|
|
`bang_timeout` = Time in seconds for users to shoot a bird before it flies away. (10s min)
|
|
|
|
|
"""
|
|
|
|
|
message = ""
|
|
|
|
|
if interval_min > interval_max:
|
|
|
|
|
return await ctx.send("`interval_min` needs to be lower than `interval_max`.")
|
|
|
|
|
if interval_min < 0 and interval_max < 0 and bang_timeout < 0:
|
|
|
|
|
return await ctx.send("Please no negative numbers!")
|
|
|
|
|
if interval_min < 120:
|
|
|
|
|
interval_min = 120
|
|
|
|
|
message += "Minimum interval set to minimum of 120s.\n"
|
|
|
|
|
if interval_max < 240:
|
|
|
|
|
interval_max = 240
|
|
|
|
|
message += "Maximum interval set to minimum of 240s.\n"
|
|
|
|
|
if bang_timeout < 10:
|
|
|
|
|
bang_timeout = 10
|
|
|
|
|
message += "Bang timeout set to minimum of 10s.\n"
|
|
|
|
|
|
|
|
|
|
await self.config.guild(ctx.guild).hunt_interval_minimum.set(interval_min)
|
|
|
|
|
await self.config.guild(ctx.guild).hunt_interval_maximum.set(interval_max)
|
|
|
|
|
await self.config.guild(ctx.guild).wait_for_bang_timeout.set(bang_timeout)
|
2020-08-26 17:57:43 +01:00
|
|
|
message += (
|
|
|
|
|
f"Timing has been set:\nMin time {interval_min}s\nMax time {interval_max}s\nBang timeout {bang_timeout}s"
|
|
|
|
|
)
|
2020-04-02 15:07:43 -04:00
|
|
|
await ctx.send(bold(message))
|
|
|
|
|
|
|
|
|
|
@hunting.command()
|
|
|
|
|
async def version(self, ctx):
|
|
|
|
|
"""Show the cog version."""
|
|
|
|
|
await ctx.send(f"Hunting version {__version__}.")
|
|
|
|
|
|
|
|
|
|
async def _add_score(self, guild, author, avian):
|
|
|
|
|
user_data = await self.config.user(author).all()
|
|
|
|
|
try:
|
|
|
|
|
user_data["score"][avian] += 1
|
|
|
|
|
except KeyError:
|
|
|
|
|
user_data["score"][avian] = 1
|
|
|
|
|
user_data["total"] += 1
|
|
|
|
|
await self.config.user(author).set_raw(value=user_data)
|
|
|
|
|
|
|
|
|
|
async def _latest_message_check(self, channel):
|
|
|
|
|
hunt_int_max = await self.config.guild(channel.guild).hunt_interval_maximum()
|
|
|
|
|
async for message in channel.history(limit=5):
|
|
|
|
|
delta = datetime.datetime.utcnow() - message.created_at
|
|
|
|
|
if delta.total_seconds() < hunt_int_max * 2 and message.author.id != self.bot.user.id:
|
|
|
|
|
if channel.id in self.paused_games:
|
|
|
|
|
self.paused_games.remove(channel.id)
|
|
|
|
|
return True
|
|
|
|
|
if channel.id not in self.paused_games:
|
|
|
|
|
self.paused_games.append(channel.id)
|
|
|
|
|
await channel.send(
|
2020-08-26 17:57:43 +01:00
|
|
|
bold("It seems there are no hunters here. The hunt will be resumed when someone treads here again.")
|
2020-04-02 15:07:43 -04:00
|
|
|
)
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def _next_sorter(self, guild_id, value):
|
|
|
|
|
try:
|
|
|
|
|
self.next_bang[guild_id]
|
|
|
|
|
except KeyError:
|
|
|
|
|
self.next_bang[guild_id] = value
|
|
|
|
|
|
|
|
|
|
async def _wait_for_bang(self, guild, channel):
|
|
|
|
|
animal = random.choice(list(self.animals.keys()))
|
2020-05-15 16:26:16 -07:00
|
|
|
animal_message = await channel.send(self.animals[animal])
|
2020-05-15 10:20:08 -07:00
|
|
|
now = time.time()
|
2020-04-02 15:07:43 -04:00
|
|
|
timeout = await self.config.guild(guild).wait_for_bang_timeout()
|
|
|
|
|
|
2020-05-15 16:26:16 -07:00
|
|
|
shooting_type = await self.config.guild(guild).bang_words()
|
|
|
|
|
if shooting_type:
|
|
|
|
|
|
|
|
|
|
def check(message):
|
|
|
|
|
if guild != message.guild:
|
|
|
|
|
return False
|
|
|
|
|
if channel != message.channel:
|
|
|
|
|
return False
|
2020-08-26 17:57:43 +01:00
|
|
|
return message.content.lower().split(" ")[0] == "bang" if message.content else False
|
2020-05-15 16:26:16 -07:00
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
bang_msg = await self.bot.wait_for("message", check=check, timeout=timeout)
|
|
|
|
|
except asyncio.TimeoutError:
|
|
|
|
|
self.in_game.remove(channel.id)
|
|
|
|
|
return await channel.send(f"The {animal} got away!")
|
|
|
|
|
author = bang_msg.author
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
emoji = "\N{COLLISION SYMBOL}"
|
|
|
|
|
await animal_message.add_reaction(emoji)
|
|
|
|
|
|
|
|
|
|
def check(reaction, user):
|
|
|
|
|
if user.bot:
|
|
|
|
|
return False
|
2020-05-25 12:32:58 -07:00
|
|
|
if guild != reaction.message.guild:
|
|
|
|
|
return False
|
|
|
|
|
if channel != reaction.message.channel:
|
|
|
|
|
return False
|
2020-05-15 16:26:16 -07:00
|
|
|
return user and str(reaction.emoji) == "💥"
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
await self.bot.wait_for("reaction_add", check=check, timeout=timeout)
|
|
|
|
|
except asyncio.TimeoutError:
|
|
|
|
|
self.in_game.remove(channel.id)
|
|
|
|
|
return await channel.send(f"The {animal} got away!")
|
|
|
|
|
|
|
|
|
|
message_with_reacts = await animal_message.channel.fetch_message(animal_message.id)
|
|
|
|
|
reacts = message_with_reacts.reactions[0]
|
|
|
|
|
async for user in reacts.users():
|
|
|
|
|
if user.bot:
|
|
|
|
|
continue
|
|
|
|
|
author = user
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
bang_now = time.time()
|
|
|
|
|
time_for_bang = "{:.3f}".format(bang_now - now)
|
2020-08-26 17:57:43 +01:00
|
|
|
bangtime = "" if not await self.config.guild(guild).bang_time() else f" in {time_for_bang}s"
|
2020-05-15 16:26:16 -07:00
|
|
|
|
|
|
|
|
if random.randrange(0, 17) > 1:
|
|
|
|
|
await self._add_score(guild, author, animal)
|
2022-04-04 15:19:49 -04:00
|
|
|
reward = await self.maybe_send_reward(guild, author)
|
|
|
|
|
if reward:
|
|
|
|
|
cur_name = await bank.get_currency_name(guild)
|
|
|
|
|
msg = f"{author.display_name} shot a {animal}{bangtime} and earned {reward} {cur_name}!"
|
|
|
|
|
else:
|
|
|
|
|
msg = f"{author.display_name} shot a {animal}{bangtime}!"
|
2020-05-15 16:26:16 -07:00
|
|
|
else:
|
|
|
|
|
msg = f"{author.display_name} missed the shot and the {animal} got away!"
|
2020-04-02 15:07:43 -04:00
|
|
|
|
|
|
|
|
self.in_game.remove(channel.id)
|
|
|
|
|
await channel.send(bold(msg))
|
|
|
|
|
|
2022-04-04 15:19:49 -04:00
|
|
|
async def maybe_send_reward(self, guild, author) -> int:
|
|
|
|
|
max_bal = await bank.get_max_balance(guild)
|
|
|
|
|
user_bal = await bank.get_balance(author)
|
|
|
|
|
if await bank.is_global():
|
|
|
|
|
range_to_give = await self.config.reward_range()
|
|
|
|
|
else:
|
|
|
|
|
range_to_give = await self.config.guild(guild).reward_range()
|
|
|
|
|
to_give = random.choice(range(range_to_give[0], range_to_give[1] + 1))
|
|
|
|
|
if to_give + user_bal > max_bal:
|
|
|
|
|
to_give = max_bal - user_bal
|
|
|
|
|
try:
|
|
|
|
|
await bank.deposit_credits(author, to_give)
|
|
|
|
|
except BalanceTooHigh as e: # This shouldn't throw since we already compare to max bal
|
|
|
|
|
await bank.set_balance(author, e.max_balance)
|
|
|
|
|
return to_give
|
|
|
|
|
|
2020-04-02 15:07:43 -04:00
|
|
|
@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
|
|
|
|
|
if message.channel.id in self.in_game:
|
|
|
|
|
return
|
|
|
|
|
channel_list = await self.config.guild(message.guild).channels()
|
|
|
|
|
if not channel_list:
|
|
|
|
|
return
|
|
|
|
|
if message.channel.id not in channel_list:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
if await self._latest_message_check(message.channel):
|
|
|
|
|
self.in_game.append(message.channel.id)
|
|
|
|
|
|
|
|
|
|
guild_data = await self.config.guild(message.guild).all()
|
2020-08-26 17:57:43 +01:00
|
|
|
wait_time = random.randrange(guild_data["hunt_interval_minimum"], guild_data["hunt_interval_maximum"])
|
2020-04-02 15:07:43 -04:00
|
|
|
self.next_bang[message.guild.id] = datetime.datetime.fromtimestamp(
|
|
|
|
|
int(time.mktime(datetime.datetime.utcnow().timetuple())) + wait_time
|
|
|
|
|
)
|
|
|
|
|
await asyncio.sleep(wait_time)
|
2020-05-25 11:37:45 -07:00
|
|
|
task = self.bot.loop.create_task(self._wait_for_bang(message.guild, message.channel))
|
|
|
|
|
self.game_tasks.append(task)
|
2020-05-15 16:26:16 -07:00
|
|
|
try:
|
|
|
|
|
del self.next_bang[message.guild.id]
|
2022-10-27 13:35:03 -04:00
|
|
|
except (KeyError, AttributeError):
|
2020-05-15 16:26:16 -07:00
|
|
|
pass
|
2020-05-25 11:37:45 -07:00
|
|
|
|
|
|
|
|
def cog_unload(self):
|
|
|
|
|
for task in self.game_tasks:
|
|
|
|
|
task.cancel()
|