async def one_from(ctx,user,list): #user needs to be a discord.member object. list is a namestring of a droplist of items here. chance = getattr(Treasure, list) itemname = random.choice(list(chance.keys())) item = chance[itemname] if item['slot'] == ['consumable']: item['uses'] = random.randint(1,item['uses']) await ctx.send("```css\n{} found {} ({}x).```".format(user.display_name,itemname,item['uses'])) msg = await ctx.send("Do you want to use, put in backpack or sell this item?") start_adding_reactions(msg, Treasure.controls.keys()) if hasattr(user, "id"): pred = ReactionPredicate.with_emojis(tuple(Treasure.controls.keys()), msg, user) else: pred = ReactionPredicate.with_emojis(tuple(Treasure.controls.keys()), msg, ctx.author) react = None try: react, user = await ctx.bot.wait_for("reaction_add", check=pred, timeout=60) except asyncio.TimeoutError: await ctx.send("Item claim timed out after one minute. Selling...") react_emoji = "💰" try: await msg.clear_reactions() except discord.Forbidden: # cannot remove all reactions for key in Treasure.controls.keys(): await msg.remove_reaction(key, ctx.bot.user) if react != None: react_emoji = react.emoji return {"itemname": itemname,"item":item,"equip":Treasure.controls[react_emoji]} else: if len(item["slot"]) == 2: # two handed weapons add their bonuses twice hand = "two handed" att = item["att"]*2 cha = item["cha"]*2 else: if item["slot"][0] == "right" or item["slot"][0] == "left": hand = item["slot"][0] + " handed" else: hand = item["slot"][0] + " slot" att = item["att"] cha = item["cha"] await ctx.send("```css\n{} found a {}. (Attack: {}, Charisma: {} [{}])```".format(user.display_name,itemname,str(att),str(cha),hand)) msg = await ctx.send("Do you want to equip, put in backpack or sell this item?") start_adding_reactions(msg, Treasure.controls.keys()) pred = ReactionPredicate.with_emojis(tuple(Treasure.controls.keys()), msg, user) react = None try: react, user = await ctx.bot.wait_for("reaction_add", check=pred, timeout=60) except asyncio.TimeoutError: await ctx.send("Item claim timed out after one minute. Selling...") react_emoji = "💰" try: await msg.clear_reactions() except discord.Forbidden: # cannot remove all reactions for key in Treasure.controls.keys(): await msg.remove_reaction(key, ctx.bot.user) if react != None: react_emoji = react.emoji return {"itemname": itemname,"item":item,"equip":Treasure.controls[react_emoji]}
async def convert( self, ctx: Context, argument: str ) -> Optional[Union[List[Dict[str, dict]], str]]: result: Optional[Union[List[Dict[str, dict]], str]] = [] team_list = await check_valid_team(argument) my_perms = ctx.channel.permissions_for(ctx.guild.me) if team_list == []: raise BadArgument('Team "{}" not found'.format(argument)) if len(team_list) == 1: result = team_list[0] else: # This is just some extra stuff to correct the team picker msg = _("There's multiple teams with that name, pick one of these:\n") new_msg = None if my_perms.add_reactions and my_perms.use_external_emojis: new_msg = await ctx.send(msg) team_emojis = [ await EmojiConverter().convert(ctx, "<:" + TEAMS[team]["emoji"] + ">") for team in team_list ] log.debug(team_emojis) log.debug(team_list) pred = ReactionPredicate.with_emojis(team_emojis, message=new_msg) start_adding_reactions(new_msg, team_emojis) try: reaction, user = await ctx.bot.wait_for("reaction_add", check=pred, timeout=60) except asyncio.TimeoutError: await new_msg.edit(content=_("I guess not.")) return None else: result = team_list[pred.result] log.debug(result) else: for i, team_name in enumerate(team_list): msg += "{}: {}\n".format(i + 1, team_name) def msg_check(m): return m.author == ctx.message.author try: msg = await ctx.bot.wait_for("message", check=msg_check, timeout=60) except asyncio.TimeoutError: await new_msg.edit(content=_("I guess not.")) return None if msg.content.isdigit(): msg = int(msg.content) - 1 try: result = team_list[msg] except (IndexError, ValueError, AttributeError): pass else: return_team = None for team in team_list: if msg.content.lower() in team.lower(): return_team = team result = return_team if new_msg: await new_msg.delete() return result
async def _choose_player( self, ctx: commands.Context, players: Tuple[rlapi.Player, ...] ) -> rlapi.Player: players_len = len(players) if players_len > 1: description = "" for idx, player in enumerate(players, 1): description += "\n{}. {} account with username: {}".format( idx, player.platform, player.user_name ) msg = await ctx.send( embed=discord.Embed( title="There are multiple accounts with provided name:", description=description, ) ) emojis = ReactionPredicate.NUMBER_EMOJIS[1 : players_len + 1] start_adding_reactions(msg, emojis) pred = ReactionPredicate.with_emojis(emojis, msg) try: await ctx.bot.wait_for("reaction_add", check=pred, timeout=15) except asyncio.TimeoutError: raise errors.NoChoiceError( "User didn't choose profile he wants to check" ) finally: await msg.delete() return players[pred.result] return players[0]
async def add_reactions_with_cancel( ctx: Context, msg: discord.Message, emojis: Iterable[Union[str, discord.Emoji]], timeout: int = 30, with_keep: bool = False, ): """Add reactions with, for a limited time, author-only cancel.""" _emojis = [emojis] if isinstance(emojis, str) else list(emojis) extra_emojis = [] cancel = "\N{CROSS MARK}" _emojis.append(cancel) extra_emojis.append(cancel) if with_keep: keep = "\N{WHITE HEAVY CHECK MARK}" _emojis.append(keep) extra_emojis.append(keep) start_adding_reactions(msg, _emojis) pred = ReactionPredicate.with_emojis(extra_emojis, msg, user=ctx.author) try: await ctx.bot.wait_for("reaction_add", check=pred, timeout=timeout) if pred.result == 0: with contextlib.suppress(discord.HTTPException): await msg.delete() return True except asyncio.TimeoutError: pass with contextlib.suppress(discord.HTTPException): for emoji in extra_emojis: await msg.clear_reaction(emoji) return False
async def choose_cog(self, ctx: commands.Context, cogs: List[commands.Cog]) -> Optional[commands.Cog]: """Ask user to choose a cog from provided `cogs` list.""" if len(cogs) == 1: return cogs[0] cogs = sorted(cogs[:9], key=lambda cog: cog.qualified_name) emojis = ReactionPredicate.NUMBER_EMOJIS[1:len(cogs) + 1] use_embeds = await ctx.embed_requested() lines = [] if use_embeds: for idx, cog in enumerate(cogs, 1): cog_name = cog.qualified_name short_doc, *_ = cog.format_help_for_context(ctx).partition( "\n\n") if len(short_doc) > 70: short_doc = f"{short_doc[:67]}..." lines.append(f"{idx}. {bold(cog_name)} - {short_doc}") description = "\n".join(lines) embed = discord.Embed( title="There are multiple categories with provided name:", description=description, ) msg = await ctx.send(embed=embed) else: # all cog names should have the same width since only casing differs doc_max_width = 80 - len(cogs[0].qualified_name) for idx, cog in enumerate(cogs, 1): cog_name = cog.qualified_name short_doc, *_ = cog.format_help_for_context(ctx).partition( "\n\n") if len(short_doc) > doc_max_width: short_doc = f"{short_doc[: doc_max_width - 3]}..." lines.append(f"{idx}. {cog_name}: {short_doc}") description = "\n".join(lines) msg = await ctx.send( f"There are multiple categories with provided name: {box(description)}" ) start_adding_reactions(msg, emojis) pred = ReactionPredicate.with_emojis(emojis, msg) try: await ctx.bot.wait_for("reaction_add", check=pred, timeout=30) except asyncio.TimeoutError: return None finally: await msg.delete() result = cast(int, pred.result) return cogs[result]
async def _wait_for_game(self, ctx): # TODO: Seperate Teams embed = discord.Embed(title="Respond with the 🏁 when the game is done") msg = await self.village_channel.send(embed=embed) start_adding_reactions(msg, "🏁") pred = ReactionPredicate.with_emojis(emojis="🏁", message=msg) await ctx.bot.wait_for("reaction_add", check=pred) await msg.delete()
async def message_type_reaction(ctx, embed: discord.Embed, emojis: list = None): msg: discord.Message = await ctx.send(embed=embed) if emojis is None: emojis = ["⚠", "💬"] start_adding_reactions(msg, emojis) pred = ReactionPredicate.with_emojis(emojis, msg) await ctx.bot.wait_for("reaction_add", check=pred) await msg.delete() await ctx.send("Thank-you. Someone will reply shortly, please be patient") return pred.result
async def coinhunt(self, ctx): """Start a game of coinhunt""" game = CoinGame() msg = await ctx.send("```\nLoading...\n```") try: for emoji in EMOJIS: await msg.add_reaction(emoji) except discord.HTTPException: await ctx.send("```/nThere was an error! Please try again./n```") return while game.stats['moves'] > 0 and game.stats['coins'] != game.stats[ 'max_coins']: await msg.edit(content=f"```\n{game.render()}\n```") pred = ReactionPredicate.with_emojis(EMOJIS, message=msg, user=ctx.author) try: await ctx.bot.wait_for("reaction_add", check=pred, timeout=60) except asyncio.TimeoutError: await msg.clear_reactions() break emoji = EMOJIS[int(pred.result)] if emoji == '❌': await msg.clear_reactions() await msg.edit(content="```\nGame was cancelled\n```") break elif emoji == '🔼': direction = Direction.up elif emoji == '🔽': direction = Direction.down elif emoji == '▶️': direction = Direction.right elif emoji == '◀️': direction = Direction.left game.move_player(direction) try: await msg.remove_reaction(emoji, ctx.author) except discord.HTTPException: pass score = game.stats['coins'] + game.stats['moves'] if game.stats['moves'] == 0: await msg.edit( content=f"```\nUh oh, Game Over. Your score: {score}\n```") elif game.stats['coins'] == game.stats['max_coins']: await msg.edit( content= f"```\nCongratulations! You Win. Your score: {score}\n```") await msg.clear_reactions()
async def get_confirmation(self, ctx: commands.Context, msg: discord.Message) -> Optional[bool]: """Get confirmation from user with reactions""" emojis = ["❌", "✅"] start_adding_reactions(msg, emojis) try: reaction, _ = await self.bot.wait_for( "reaction_add", timeout=180.0, check=ReactionPredicate.with_emojis(emojis, msg, ctx.author) ) except asyncio.TimeoutError: await msg.clear_reactions() return else: await msg.clear_reactions() return bool(emojis.index(reaction.emoji))
async def quickcast(self, ctx:commands.Context, bait_type:str): """Rolls for a fish - similar to cast, but you do not get to choose the fish to reel in, instead instantly rolling and choosing to keep/release a fish - Must be used in a channel registered as a pool""" if not await self.IsSpecialized(ctx.guild, ctx.channel.id, POOL_CHANNEL): return profile = self.config.member(ctx.message.author) await profile.currently_fishing.set(True) modified_fish_weights = await self.startfishing(ctx, profile, bait_type) rarity = choices(FISH_RARITIES, modified_fish_weights)[0] rarity_list = self.fishing_rarities.get(rarity) curr_fish = rarity_list[randint(0, len(rarity_list) - 1)] if not await profile.bryan_mode() else self.SEA_BASS new_fish = curr_fish.ToFishCatch(RARITY_VALUES[rarity]) embed = Embed(title=f'{ctx.message.author.display_name} cast their rod into the shimmering waves at {ctx.channel}', color=0x7300ff) embed.set_footer(text=f'You pulled a {new_fish["name"]} ({new_fish["size"]} inches) out of the water!\nDo you want to keep or release?') embed.set_thumbnail(url=curr_fish.image) msg = await ctx.send(embed=embed) start_adding_reactions(msg, ['🥤', '🐟']) pred = ReactionPredicate.with_emojis(['🥤', '🐟'], msg, ctx.author) try: await ctx.bot.wait_for('reaction_add', check=pred, timeout=15) except asyncio.TimeoutError: pred.result = 0 if pred.result == 0: if await self.AddFish(ctx.message.author, new_fish): embed.set_footer(text=f'{new_fish["name"]} was added to your bucket!') else: embed.set_footer(text=f'Your bucket was full, so you had to release {new_fish["name"]} :(') else: embed.set_footer(text=f'You let {new_fish["name"]} swim away...') await msg.edit(embed=embed) await msg.clear_reactions() user_bait = await profile.bait() user_bait[bait_type] -= 1 await profile.bait.set(user_bait) await profile.currently_fishing.set(False) #if not await profile.mawiam_mode(): #await profile.nextcast.set(time() + await self.GetSetting(ctx.guild, 'fishing_delay')) await self.CheckSchools(ctx)
async def sex_select(self, ctx: commands.Context, embed: Embed, message: discord.Message) -> bool: """Requests information from the member about the sex of the character being registered. Args: ctx (commands.Context): Same as `RegisterSession.ctx` embed (Embed): Same as `RegisterSession.embed` message (discord.Message): Same as `RegisterSession.message` Returns: bool: Whether the correct information is received or not. """ embed.description = "**Выберите пол персонажа**\n\n" await message.edit(embed=embed) genders = {"👨": "male", "👩": "female"} try: for gender in genders.keys(): await message.add_reaction(gender) react, member = await self.ctx.bot.wait_for( "reaction_add", timeout=60.0, check=ReactionPredicate.with_emojis(tuple(genders.keys()), message, ctx.author), ) await message.clear_reactions() self.char["sex"] = genders[react.emoji] embed.add_field( name="Пол", value=config.humanize.genders[genders[react.emoji]].title(), inline=True, ) await message.edit(embed=embed) return True except asyncio.TimeoutError: try: await message.clear_reactions() except discord.Forbidden: # cannot remove all reactions for gender in genders.keys(): await message.remove_reaction(gender, ctx.bot.user) except discord.NotFound: return False await self.cancel(embed, message) return False
async def convert(self, ctx, argument): try: c = await Character._from_json(ctx.bot.get_cog("Adventure").config, ctx.author) except Exception: log.exception("Error with the new character sheet") return no_markdown = Item._remove_markdowns(argument) lookup = list(i for x, i in c.backpack.items() if no_markdown.lower() in x.lower()) lookup_m = list(i for x, i in c.backpack.items() if argument.lower() == str(i).lower()) if len(lookup) == 1: return lookup[0] elif len(lookup_m) == 1: return lookup_m[0] elif len(lookup) == 0 and len(lookup_m) == 0: raise BadArgument( _("`{}` doesn't seem to match any items in your backpack.").format(argument) ) else: if len(lookup) > 10: raise BadArgument( _("You have too many items matching the name `{}`," " please be more specific").format( argument ) ) items = "" for number, item in enumerate(lookup): items += f"{number}. {str(item)} (owned {item.owned})\n" msg = await ctx.send( _("Multiple items share that name, which one would you like?\n{items}").format( items=box(items, lang="css") ) ) emojis = ReactionPredicate.NUMBER_EMOJIS[:len(lookup)] start_adding_reactions(msg, emojis) pred = ReactionPredicate.with_emojis(emojis, msg, user=ctx.author) try: await ctx.bot.wait_for("reaction_add", check=pred, timeout=30) except asyncio.TimeoutError: raise BadArgument(_("Alright then.")) return lookup[pred.result]
async def drop(self, ctx): # ?drop command # locations without picture (labeled) marked_list = [ 'shark!', 'yacht!', 'grotto!', 'rig!', 'craggy cliffs!', 'steamy stacks!', 'pleasant park!', 'sweaty sands!', 'frenzy farm!', 'dirty docks!', 'holly hedges!', 'weeping woods!', 'lazy lake!', 'retail row!', 'slurpy swamp!', 'misty meadows!' ] # before '!' has to correspond with picture in /map/ unmarked_list = [ 'apres ski! D8', 'box factory! G7', 'compact cars! G4', 'coral cove! A2', 'crash site! B2', 'fancy view! A4', 'fn radio! F2', 'hydro 16! D7', 'lockies lighthouse! C1', 'logjam woodworks! B6', 'orchard! F3', 'pristine point! G1', 'risky reels! E4' ] if random.randint(1, 2) == 1: the_drop = random.choice(marked_list) unmarked = False else: the_drop = random.choice(unmarked_list) drop_filename = the_drop[:-4] unmarked = True drop_map = f'map/{drop_filename}.png' if unmarked == False: repeat = await ctx.send(the_drop) if unmarked == True: await ctx.send(the_drop) my_path = os.path.abspath(os.path.dirname(__file__)) path = os.path.join(my_path, drop_map) repeat = await ctx.send(file=discord.File(path)) start_adding_reactions(repeat, "🔁") pred = ReactionPredicate.with_emojis("🔁", repeat) await ctx.bot.wait_for("reaction_add", check=pred) await ctx.invoke(self.drop)
async def get_user_choice(self, ctx: Context, embed, end, first_player, second_player): try: msg = await first_player.send(embed=embed) react_emojis = ReactionPredicate.NUMBER_EMOJIS[1:end + 1] start_adding_reactions(msg, react_emojis) pred = ReactionPredicate.with_emojis(react_emojis, msg) await ctx.bot.wait_for("reaction_add", check=pred, timeout=30) # pred.result is the index of the number in `emojis` return pred.result + 1 except asyncio.TimeoutError: await ctx.send(f"{first_player.name} took too long to respond.") raise asyncio.TimeoutError except discord.Forbidden: await ctx.send(f"{first_player.mention} {second_player.mention}" f" Reason: Unable to DM {first_player.name}." " DMs are required to brawl!") raise
async def menu(ctx, update=None, timeout=30): perms = ctx.channel.permissions_for(ctx.me) if not perms.embed_links or not perms.add_reactions: raise BMP(embed_links=True, add_reactions=True) update = update or Update(ctx.message.created_at) message = await ctx.send(embed=update.embed(now=ctx.message.created_at)) start_adding_reactions(message, reactions, loop=ctx.bot.loop) first = True while True: if first: first = False else: await message.edit(embed=update.embed(now=ctx.message.created_at)) pred = ReactionPredicate.with_emojis(reactions, message, ctx.author) try: await ctx.bot.wait_for("reaction_add", check=pred, timeout=timeout) except asyncio.TimeoutError: with suppress(discord.HTTPException): await message.delete() return None if pred.result == 0: upd = update[-1] if upd.end.timestamp() >= ctx.message.created_at.timestamp(): update = upd elif pred.result == 1: with suppress(discord.HTTPException): await message.clear_reactions() return update elif pred.result == 2: with suppress(discord.HTTPException): await message.delete() return None elif pred.result == 3: update = update[1] with suppress(discord.HTTPException): # pylint: disable=E1126 await message.remove_reaction(reactions[pred.result], ctx.author)
def _give_me_tasks(self) -> list: def leave_check(u): return u.id == self.member.id return [ asyncio.create_task( self.bot.wait_for( "reaction_add", check=ReactionPredicate.with_emojis( "🔁", message=self.messages["bot_challenge"], user=self.member), )), asyncio.create_task( self.bot.wait_for( "message", check=MessagePredicate.same_context( channel=self.channel, user=self.member, ), )), asyncio.create_task( self.bot.wait_for("user_remove", check=leave_check)), ]
async def get_option_reaction( ctx, message: str = None, embed: discord.Embed = None, ): if not embed: msg = await ctx.send( message, delete_after=30, ) else: msg = await ctx.send( embed=embed, delete_after=30, ) emojis = ReactionPredicate.NUMBER_EMOJIS[1:6] # Action 1: Do Nothing (still fire event) # Action 2: Message # Action 3 : Add Role # Action 4: Kick # Action 5: Ban start_adding_reactions( msg, emojis, ) pred = ReactionPredicate.with_emojis( emojis, msg, ctx.author, ) react = await ctx.bot.wait_for( "reaction_add", check=pred, ) return await action_to_take_mapping(pred.result)
async def _open_chest(self, ctx: commands.Context, user, chest_type, character): if hasattr(user, "display_name"): chest_msg = _( "{} is opening a treasure chest. What riches lay inside?" ).format(escape(user.display_name)) else: chest_msg = _( "{user}'s {f} is foraging for treasure. What will it find?" ).format(user=escape(ctx.author.display_name), f=(user[:1] + user[1:])) open_msg = await ctx.send(box(chest_msg, lang="css")) await asyncio.sleep(2) item = await self._roll_chest(chest_type, character) if chest_type == "pet" and not item: await open_msg.edit(content=box( _("{c_msg}\nThe {user} found nothing of value.").format( c_msg=chest_msg, user=(user[:1] + user[1:])), lang="css", )) return None slot = item.slot[0] old_item = getattr(character, item.slot[0], None) old_stats = "" if old_item: old_slot = old_item.slot[0] if len(old_item.slot) > 1: old_slot = _("two handed") att = old_item.att * 2 cha = old_item.cha * 2 intel = old_item.int * 2 luck = old_item.luck * 2 dex = old_item.dex * 2 else: att = old_item.att cha = old_item.cha intel = old_item.int luck = old_item.luck dex = old_item.dex old_stats = (_( "You currently have {item} [{slot}] equipped | Lvl req {lv} equipped." ).format(item=old_item, slot=old_slot, lv=character.equip_level(old_item)) + f" (ATT: {str(att)}, " f"CHA: {str(cha)}, " f"INT: {str(intel)}, " f"DEX: {str(dex)}, " f"LUCK: {str(luck)}) ") if len(item.slot) > 1: slot = _("two handed") att = item.att * 2 cha = item.cha * 2 intel = item.int * 2 luck = item.luck * 2 dex = item.dex * 2 else: att = item.att cha = item.cha intel = item.int luck = item.luck dex = item.dex if hasattr(user, "display_name"): chest_msg2 = ( _("{user} found {item} [{slot}] | Lvl req {lv}.").format( user=escape(user.display_name), item=str(item), slot=slot, lv=character.equip_level(item), ) + f" (ATT: {str(att)}, " f"CHA: {str(cha)}, " f"INT: {str(intel)}, " f"DEX: {str(dex)}, " f"LUCK: {str(luck)}) ") await open_msg.edit(content=box( _("{c_msg}\n\n{c_msg_2}\n\nDo you want to equip " "this item, put in your backpack, or sell this item?\n\n" "{old_stats}").format(c_msg=chest_msg, c_msg_2=chest_msg2, old_stats=old_stats), lang="css", )) else: chest_msg2 = ( _("The {user} found {item} [{slot}] | Lvl req {lv}.").format( user=user, item=str(item), slot=slot, lv=character.equip_level(item)) + f" (ATT: {str(att)}, " f"CHA: {str(cha)}, " f"INT: {str(intel)}, " f"DEX: {str(dex)}, " f"LUCK: {str(luck)}), ") await open_msg.edit(content=box( _("{c_msg}\n{c_msg_2}\nDo you want to equip " "this item, put in your backpack, or sell this item?\n\n{old_stats}" ).format(c_msg=chest_msg, c_msg_2=chest_msg2, old_stats=old_stats), lang="css", )) start_adding_reactions(open_msg, self._treasure_controls.keys()) if hasattr(user, "id"): pred = ReactionPredicate.with_emojis( tuple(self._treasure_controls.keys()), open_msg, user) else: pred = ReactionPredicate.with_emojis( tuple(self._treasure_controls.keys()), open_msg, ctx.author) try: react, user = await self.bot.wait_for("reaction_add", check=pred, timeout=60) except asyncio.TimeoutError: await self._clear_react(open_msg) await character.add_to_backpack(item) await open_msg.edit(content=(box( _("{user} put the {item} into their backpack.").format( user=escape(ctx.author.display_name), item=item), lang="css", ))) await self.config.user(ctx.author ).set(await character.to_json(ctx, self.config)) return await self._clear_react(open_msg) if self._treasure_controls[react.emoji] == "sell": price = _sell(character, item) price = max(price, 0) if price > 0: try: await bank.deposit_credits(ctx.author, price) except BalanceTooHigh as e: await bank.set_balance(ctx.author, e.max_balance) currency_name = await bank.get_currency_name(ctx.guild, ) if str(currency_name).startswith("<"): currency_name = "credits" await open_msg.edit(content=(box( _("{user} sold the {item} for {price} {currency_name}."). format( user=escape(ctx.author.display_name), item=item, price=humanize_number(price), currency_name=currency_name, ), lang="css", ))) await self._clear_react(open_msg) character.last_known_currency = await bank.get_balance(ctx.author) character.last_currency_check = time.time() await self.config.user(ctx.author ).set(await character.to_json(ctx, self.config)) elif self._treasure_controls[react.emoji] == "equip": equiplevel = character.equip_level(item) if is_dev(ctx.author): equiplevel = 0 if not character.can_equip(item): await character.add_to_backpack(item) await self.config.user(ctx.author).set(await character.to_json( ctx, self.config)) return await smart_embed( ctx, f"**{escape(ctx.author.display_name)}**, you need to be level " f"`{equiplevel}` to equip this item. I've put it in your backpack.", ) if not getattr(character, item.slot[0]): equip_msg = box( _("{user} equipped {item} ({slot} slot).").format( user=escape(ctx.author.display_name), item=item, slot=slot), lang="css", ) else: equip_msg = box( _("{user} equipped {item} ({slot} slot) and put {old_item} into their backpack." ).format( user=escape(ctx.author.display_name), item=item, slot=slot, old_item=getattr(character, item.slot[0]), ), lang="css", ) await open_msg.edit(content=equip_msg) character = await character.equip_item(item, False, is_dev(ctx.author)) await self.config.user(ctx.author ).set(await character.to_json(ctx, self.config)) else: await character.add_to_backpack(item) await open_msg.edit(content=(box( _("{user} put the {item} into their backpack.").format( user=escape(ctx.author.display_name), item=item), lang="css", ))) await self._clear_react(open_msg) await self.config.user(ctx.author ).set(await character.to_json(ctx, self.config))
async def command_now(self, ctx: commands.Context): """Now playing.""" if not self._player_check(ctx): return await self.send_embed_msg(ctx, title=_("Nothing playing.")) emoji = { "prev": "\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}\N{VARIATION SELECTOR-16}", "stop": "\N{BLACK SQUARE FOR STOP}\N{VARIATION SELECTOR-16}", "pause": "\N{BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR}\N{VARIATION SELECTOR-16}", "next": "\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}\N{VARIATION SELECTOR-16}", "close": "\N{CROSS MARK}", } expected = tuple(emoji.values()) player = lavalink.get_player(ctx.guild.id) player.store("notify_channel", ctx.channel.id) if player.current: arrow = await self.draw_time(ctx) pos = self.format_time(player.position) if player.current.is_stream: dur = "LIVE" else: dur = self.format_time(player.current.length) song = (await self.get_track_description( player.current, self.local_folder_current_path) or "") song += _("\n Requested by: **{track.requester}**").format( track=player.current) song += "\n\n{arrow}`{pos}`/`{dur}`".format(arrow=arrow, pos=pos, dur=dur) else: song = _("Nothing.") if player.fetch("np_message") is not None: with contextlib.suppress(discord.HTTPException): await player.fetch("np_message").delete() embed = discord.Embed(title=_("Now Playing"), description=song) guild_data = await self.config.guild(ctx.guild).all() if guild_data[ "thumbnail"] and player.current and player.current.thumbnail: embed.set_thumbnail(url=player.current.thumbnail) shuffle = guild_data["shuffle"] repeat = guild_data["repeat"] autoplay = guild_data["auto_play"] text = "" text += ( _("Auto-Play") + ": " + ("\N{WHITE HEAVY CHECK MARK}" if autoplay else "\N{CROSS MARK}")) text += ( (" | " if text else "") + _("Shuffle") + ": " + ("\N{WHITE HEAVY CHECK MARK}" if shuffle else "\N{CROSS MARK}")) text += ( (" | " if text else "") + _("Repeat") + ": " + ("\N{WHITE HEAVY CHECK MARK}" if repeat else "\N{CROSS MARK}")) message = await self.send_embed_msg(ctx, embed=embed, footer=text) player.store("np_message", message) dj_enabled = self._dj_status_cache.setdefault( ctx.guild.id, await self.config.guild(ctx.guild).dj_enabled()) vote_enabled = await self.config.guild(ctx.guild).vote_enabled() if ((dj_enabled or vote_enabled) and not await self._can_instaskip(ctx, ctx.author) and not await self.is_requester_alone(ctx)): return if not player.queue and not autoplay: expected = (emoji["stop"], emoji["pause"], emoji["close"]) task: Optional[asyncio.Task] if player.current: task = start_adding_reactions(message, expected[:5]) else: task = None try: (r, u) = await self.bot.wait_for( "reaction_add", check=ReactionPredicate.with_emojis(expected, message, ctx.author), timeout=30.0, ) except asyncio.TimeoutError: return await self._clear_react(message, emoji) else: if task is not None: task.cancel() reacts = {v: k for k, v in emoji.items()} react = reacts[r.emoji] if react == "prev": await self._clear_react(message, emoji) await ctx.invoke(self.command_prev) elif react == "stop": await self._clear_react(message, emoji) await ctx.invoke(self.command_stop) elif react == "pause": await self._clear_react(message, emoji) await ctx.invoke(self.command_pause) elif react == "next": await self._clear_react(message, emoji) await ctx.invoke(self.command_skip) elif react == "close": await message.delete()
async def command_queue(self, ctx: commands.Context, *, page: int = 1): """List the songs in the queue.""" # Check to avoid an IndexError further down in the code. if page < 1: page = 1 async def _queue_menu( ctx: commands.Context, pages: list, controls: MutableMapping, message: discord.Message, page: int, timeout: float, emoji: str, ): if message: await ctx.send_help(self.command_queue) with contextlib.suppress(discord.HTTPException): await message.delete() return None queue_controls = { "\N{LEFTWARDS BLACK ARROW}\N{VARIATION SELECTOR-16}": prev_page, "\N{CROSS MARK}": close_menu, "\N{BLACK RIGHTWARDS ARROW}\N{VARIATION SELECTOR-16}": next_page, "\N{INFORMATION SOURCE}\N{VARIATION SELECTOR-16}": _queue_menu, } if not self._player_check(ctx): return await self.send_embed_msg( ctx, title=_("There's nothing in the queue.")) player = lavalink.get_player(ctx.guild.id) if player.current and not player.queue: arrow = await self.draw_time(ctx) pos = self.format_time(player.position) if player.current.is_stream: dur = "LIVE" else: dur = self.format_time(player.current.length) song = (await self.get_track_description( player.current, self.local_folder_current_path) or "") song += _("\n Requested by: **{track.requester}**").format( track=player.current) song += f"\n\n{arrow}`{pos}`/`{dur}`" embed = discord.Embed(title=_("Now Playing"), description=song) guild_data = await self.config.guild(ctx.guild).all() if guild_data[ "thumbnail"] and player.current and player.current.thumbnail: embed.set_thumbnail(url=player.current.thumbnail) shuffle = guild_data["shuffle"] repeat = guild_data["repeat"] autoplay = guild_data["auto_play"] text = "" text += (_("Auto-Play") + ": " + ("\N{WHITE HEAVY CHECK MARK}" if autoplay else "\N{CROSS MARK}")) text += ((" | " if text else "") + _("Shuffle") + ": " + ("\N{WHITE HEAVY CHECK MARK}" if shuffle else "\N{CROSS MARK}")) text += ( (" | " if text else "") + _("Repeat") + ": " + ("\N{WHITE HEAVY CHECK MARK}" if repeat else "\N{CROSS MARK}")) embed.set_footer(text=text) message = await self.send_embed_msg(ctx, embed=embed) dj_enabled = self._dj_status_cache.setdefault( ctx.guild.id, guild_data["dj_enabled"]) vote_enabled = guild_data["vote_enabled"] if ((dj_enabled or vote_enabled) and not await self._can_instaskip(ctx, ctx.author) and not await self.is_requester_alone(ctx)): return emoji = { "prev": "\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}\N{VARIATION SELECTOR-16}", "stop": "\N{BLACK SQUARE FOR STOP}\N{VARIATION SELECTOR-16}", "pause": "\N{BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR}\N{VARIATION SELECTOR-16}", "next": "\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}\N{VARIATION SELECTOR-16}", "close": "\N{CROSS MARK}", } expected = tuple(emoji.values()) if not player.queue and not autoplay: expected = (emoji["stop"], emoji["pause"], emoji["close"]) if player.current: task: Optional[asyncio.Task] = start_adding_reactions( message, expected[:5]) else: task: Optional[asyncio.Task] = None try: (r, u) = await self.bot.wait_for( "reaction_add", check=ReactionPredicate.with_emojis( expected, message, ctx.author), timeout=30.0, ) except asyncio.TimeoutError: return await self._clear_react(message, emoji) else: if task is not None: task.cancel() reacts = {v: k for k, v in emoji.items()} react = reacts[r.emoji] if react == "prev": await self._clear_react(message, emoji) await ctx.invoke(self.command_prev) elif react == "stop": await self._clear_react(message, emoji) await ctx.invoke(self.command_stop) elif react == "pause": await self._clear_react(message, emoji) await ctx.invoke(self.command_pause) elif react == "next": await self._clear_react(message, emoji) await ctx.invoke(self.command_skip) elif react == "close": await message.delete() return elif not player.current and not player.queue: return await self.send_embed_msg( ctx, title=_("There's nothing in the queue.")) async with ctx.typing(): limited_queue = player.queue[: 500] # TODO: Improve when Toby menu's are merged len_queue_pages = math.ceil(len(limited_queue) / 10) queue_page_list = [] async for page_num in AsyncIter(range(1, len_queue_pages + 1)): embed = await self._build_queue_page(ctx, limited_queue, player, page_num) queue_page_list.append(embed) if page > len_queue_pages: page = len_queue_pages return await menu(ctx, queue_page_list, queue_controls, page=(page - 1))
async def coinhunt(self, ctx): """ A Small Minigame where main objective is to collect coins in limited number of moves. [@] : Player [·] : Visited [○] : Coin [+] : Power-Ups [R] : Reveal-Shard """ game = CoinGame() msg = await ctx.send("```\nLoading...\n```") try: for emoji in EMOJIS: await msg.add_reaction(emoji) except discord.HTTPException: await ctx.send("```/nThere was an error! Please try again./n```") return while game.stats['moves'] > 0 and game.stats['coins'] != game.stats[ 'max_coins']: await msg.edit(content=f"```\n{game.render()}\n```") pred = ReactionPredicate.with_emojis(EMOJIS, message=msg, user=ctx.author) try: await ctx.bot.wait_for("reaction_add", check=pred) except asyncio.TimeoutError: await msg.clear_reactions() return emoji = EMOJIS[pred.result] if emoji == '❌': await msg.clear_reactions() await msg.edit(content="```\nGame was cancelled\n```") return elif emoji == '🔼': direction = Direction.up elif emoji == '🔽': direction = Direction.down elif emoji == '▶️': direction = Direction.right elif emoji == '◀️': direction = Direction.left game.move_player(direction) try: await msg.remove_reaction(emoji, ctx.author) except discord.HTTPException: pass score = game.stats['coins'] + game.stats['moves'] if game.stats['moves'] == 0: await msg.edit( content=f"```\nUh oh, Game Over. Your score: {score}\n```") await msg.clear_reactions() return elif game.stats['coins'] == game.stats['max_coins']: await msg.edit( content= f"```\nCongratulations! You Win. Your score: {score}\n```") await msg.clear_reactions() return
async def menu( ctx: commands.Context, pages: Union[List[str], List[discord.Embed]], controls: dict, message: discord.Message = None, page: int = 0, timeout: float = 30.0, **kwargs, ): """ An emoji-based menu .. note:: All pages should be of the same type .. note:: All functions for handling what a particular emoji does should be coroutines (i.e. :code:`async def`). Additionally, they must take all of the parameters of this function, in addition to a string representing the emoji reacted with. This parameter should be the last one, and none of the parameters in the handling functions are optional Parameters ---------- ctx: commands.Context The command context pages: `list` of `str` or `discord.Embed` The pages of the menu. controls: dict A mapping of emoji to the function which handles the action for the emoji. message: discord.Message The message representing the menu. Usually :code:`None` when first opening the menu page: int The current page number of the menu timeout: float The time (in seconds) to wait for a reaction Raises ------ RuntimeError If either of the notes above are violated """ if not isinstance(pages[0], (discord.Embed, str)): raise RuntimeError("Pages must be of type discord.Embed or str") if not all(isinstance(x, discord.Embed) for x in pages) and not all( isinstance(x, str) for x in pages ): raise RuntimeError("All pages must be of the same type") for key, value in controls.items(): maybe_coro = value if isinstance(value, functools.partial): maybe_coro = value.func if not asyncio.iscoroutinefunction(maybe_coro): raise RuntimeError("Function must be a coroutine") current_page = pages[page] if not message: if isinstance(current_page, discord.Embed): message = await ctx.send(embed=current_page, **kwargs) else: message = await ctx.send(current_page, **kwargs) # Don't wait for reactions to be added (GH-1797) # noinspection PyAsyncCall start_adding_reactions(message, controls.keys()) else: try: if isinstance(current_page, discord.Embed): await message.edit(embed=current_page, **kwargs) else: await message.edit(content=current_page, **kwargs) except discord.NotFound: return try: predicates = ReactionPredicate.with_emojis(tuple(controls.keys()), message, ctx.author) tasks = [ asyncio.ensure_future(ctx.bot.wait_for("reaction_add", check=predicates)), asyncio.ensure_future(ctx.bot.wait_for("reaction_remove", check=predicates)), ] done, pending = await asyncio.wait( tasks, timeout=timeout, return_when=asyncio.FIRST_COMPLETED ) for task in pending: task.cancel() if len(done) == 0: raise asyncio.TimeoutError() react, user = done.pop().result() except asyncio.TimeoutError: if not ctx.me: return try: if message.channel.permissions_for(ctx.me).manage_messages: await message.clear_reactions() else: raise RuntimeError except (discord.Forbidden, RuntimeError): # cannot remove all reactions for key in controls: try: await message.remove_reaction(key, ctx.bot.user) except discord.Forbidden: return except discord.HTTPException: pass except discord.NotFound: return else: return await controls[react.emoji]( ctx, pages, controls, message, page, timeout, react.emoji )
async def command_now(self, ctx: commands.Context): """Now playing.""" if not self._player_check(ctx): return await self.send_embed_msg(ctx, title=_("Nothing playing.")) expected: Union[Tuple[str, ...]] = ( "⏮", "⏹", "⏯", "⏭", self.get_cross_emoji(ctx), ) emoji = { "prev": "⏮", "stop": "⏹", "pause": "⏯", "next": "⏭", "close": self.get_cross_emoji(ctx), } player = lavalink.get_player(ctx.guild.id) if player.current: arrow = await self.draw_time(ctx) pos = self.format_time(player.position) if player.current.is_stream: dur = "LIVE" else: dur = self.format_time(player.current.length) song = (await self.get_track_description( player.current, self.local_folder_current_path) or "") song += _("\n Requested by: **{track.requester}**") song += "\n\n{arrow}`{pos}`/`{dur}`" song = song.format(track=player.current, arrow=arrow, pos=pos, dur=dur) else: song = _("Nothing.") if player.fetch("np_message") is not None: with contextlib.suppress(discord.HTTPException): await player.fetch("np_message").delete() embed = discord.Embed(description=song) embed.set_author( name=_("Now Playing"), icon_url="https://cdn.discordapp.com/emojis/572861527049109515.gif", ) guild_data = await self.config.guild(ctx.guild).all() if guild_data[ "thumbnail"] and player.current and player.current.thumbnail: embed.set_thumbnail(url=player.current.thumbnail) shuffle = guild_data["shuffle"] repeat = guild_data["repeat"] autoplay = guild_data["auto_play"] text = "" text += ( _("Auto-Play") + ": " + ("\N{WHITE HEAVY CHECK MARK}" if autoplay else "\N{CROSS MARK}")) text += ( (" | " if text else "") + _("Shuffle") + ": " + ("\N{WHITE HEAVY CHECK MARK}" if shuffle else "\N{CROSS MARK}")) text += ( (" | " if text else "") + _("Repeat") + ": " + ("\N{WHITE HEAVY CHECK MARK}" if repeat else "\N{CROSS MARK}")) message = await self.send_embed_msg(ctx, embed=embed, footer=text) player.store("np_message", message) dj_enabled = self._dj_status_cache.setdefault( ctx.guild.id, await self.config.guild(ctx.guild).dj_enabled()) vote_enabled = await self.config.guild(ctx.guild).vote_enabled() if ((dj_enabled or vote_enabled) and not await self._can_instaskip(ctx, ctx.author) and not await self.is_requester_alone(ctx)): return if not player.queue and not autoplay: expected = ("⏹", "⏯", "\N{CROSS MARK}") task: Optional[asyncio.Task] if player.current: task = start_adding_reactions(message, expected[:5]) else: task = None try: (r, u) = await self.bot.wait_for( "reaction_add", check=ReactionPredicate.with_emojis(expected, message, ctx.author), timeout=30.0, ) except asyncio.TimeoutError: return await self._clear_react(message, emoji) else: if task is not None: task.cancel() reacts = {v: k for k, v in emoji.items()} react = reacts[r.emoji] if react == "prev": await self._clear_react(message, emoji) await ctx.invoke(self.command_prev) elif react == "stop": await self._clear_react(message, emoji) await ctx.invoke(self.command_stop) elif react == "pause": await self._clear_react(message, emoji) await ctx.invoke(self.command_pause) elif react == "next": await self._clear_react(message, emoji) await ctx.invoke(self.command_skip) elif react == "close": await message.delete()
async def lfg(self, ctx: commands.Context): """Make an LFG request.""" author = ctx.author bot = self.bot gamemode1 = bot.get_emoji(658426489636651051) gamemode2 = bot.get_emoji(658426504186691598) gamemode3 = bot.get_emoji(658426519437443093) gamemodeo = bot.get_emoji(658426530715926528) rank1 = bot.get_emoji(658431823935832064) rank2 = bot.get_emoji(658431824342548510) rank3 = bot.get_emoji(658431823746957313) rank4 = bot.get_emoji(658431824279896064) rank5 = bot.get_emoji(658431824065986562) rank6 = bot.get_emoji(658431823931506710) rank7 = bot.get_emoji(658431823608545294) region1 = bot.get_emoji(658435948513722399) region2 = bot.get_emoji(658435948572442635) region3 = bot.get_emoji(658435948425641994) region4 = bot.get_emoji(658435948492750869) region5 = bot.get_emoji(658435948236767236) region6 = bot.get_emoji(658435948631162880) region7 = bot.get_emoji(658435948211601422) region8 = bot.get_emoji(658435948589088787) region9 = bot.get_emoji(658435948610191366) region10 = bot.get_emoji(658435948983353377) platform1 = bot.get_emoji(658438656826015775) platform2 = bot.get_emoji(658438656570294314) platform3 = bot.get_emoji(658438656872415262) platform4 = bot.get_emoji(658438656863895562) gamemodes = (gamemode1, gamemode2, gamemode3, gamemodeo) gamemodeemoji = { "ones": gamemode1, "twos": gamemode2, "threes": gamemode3, "other": gamemodeo } ranks = (rank1, rank2, rank3, rank4, rank5, rank6, rank7) rankemoji = { "bronze": rank1, "silver": rank2, "gold": rank3, "platinum": rank4, "diamond": rank5, "champion": rank6, "grandchampion": rank7 } regions = (region1, region2, region3, region4, region5, region6, region7, region8, region9, region10) regionemoji = { "usw": region1, "use": region2, "sam": region3, "saf": region4, "oce": region5, "me": region6, "jpn": region7, "eu": region8, "asm": region9, "asc": region10 } platforms = (platform1, platform2, platform3, platform4) platformemoji = { "pc": platform1, "xbox": platform2, "ps": platform3, "switch": platform4 } players = ("1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6️⃣", "7️⃣") playeremoji = { "1": "1️⃣", "2": "2️⃣", "3": "3️⃣", "4": "4️⃣", "5": "5️⃣", "6": "6️⃣", "7": "7️⃣" } try: game = await author.send( "**You have a maximum of 2 minutes to answer each question, " "Please specify what gamemode you are playing.**") except discord.Forbidden: return await ctx.send( "I can't seem to be able to DM you. Do you have DM's closed?") message = await ctx.send("Okay, {0}, I've sent you a DM.".format( author.mention)) try: task = start_adding_reactions(game, gamemodes[:4], ctx.bot.loop) (r, u) = await bot.wait_for("reaction_add", timeout=120, check=ReactionPredicate.with_emojis( gamemodes, game, ctx.author)) reacts = {v: k for k, v in gamemodeemoji.items()} react = reacts[r.emoji] if react == "ones": gamemode = "1's" elif react == "twos": gamemode = "2's" elif react == "threes": gamemode = "3's" elif react == "other": gamemode = "Other" except asyncio.TimeoutError: return await author.send("You took too long. Try again.") rank = await author.send("**What rank are you in this gamemode?**") try: task = start_adding_reactions(rank, ranks[:7], ctx.bot.loop) (r, u) = await bot.wait_for("reaction_add", timeout=120, check=ReactionPredicate.with_emojis( ranks, rank, ctx.author)) reacts = {v: k for k, v in rankemoji.items()} react = reacts[r.emoji] if react == "bronze": rank = "Bronze" elif react == "silver": rank = "Silver" elif react == "gold": rank = "Gold" elif react == "platinum": rank = "Platinum" elif react == "diamond": rank = "Diamond" elif react == "champion": rank = "Champion" elif react == "grandchampion": rank = "Grand Champion" except asyncio.TimeoutError: return await author.send("You took too long. Try again.") region = await author.send("**What servers are you playing on?**") try: task = start_adding_reactions(region, regions[:10], ctx.bot.loop) (r, u) = await bot.wait_for("reaction_add", timeout=120, check=ReactionPredicate.with_emojis( regions, region, ctx.author)) reacts = {v: k for k, v in regionemoji.items()} react = reacts[r.emoji] if react == "usw": region = "US-West" elif react == "use": region = "US-East" elif react == "sam": region = "South America" elif react == "saf": region = "South African" elif react == "oce": region = "Oceana" elif react == "me": region = "Middle East" elif react == "jpn": region = "Japan" elif react == "eu": region = "Europe" elif react == "asm": region = "Asia Mainlane" elif react == "asc": region = "Asia East" except asyncio.TimeoutError: return await author.send("You took too long. Try again.") platform = await author.send("**What platform are you using?**") try: task = start_adding_reactions(platform, platforms[:4], ctx.bot.loop) (r, u) = await bot.wait_for("reaction_add", timeout=120, check=ReactionPredicate.with_emojis( platforms, platform, ctx.author)) reacts = {v: k for k, v in platformemoji.items()} react = reacts[r.emoji] if react == "pc": platform = "PC" elif react == "xbox": platform = "Xbox" elif react == "ps": platform = "PlayStation" elif react == "switch": platform = "Nintendo Switch" except asyncio.TimeoutError: return await author.send("You took too long. Try again.") player = await author.send("**How many people are you looking for?**") try: task = start_adding_reactions(player, players[:7], ctx.bot.loop) (r, u) = await bot.wait_for("reaction_add", timeout=120, check=ReactionPredicate.with_emojis( players, player, ctx.author)) reacts = {v: k for k, v in playeremoji.items()} react = reacts[r.emoji] if react == "1": player = "1" elif react == "2": player = "2" elif react == "3": player = "3" elif react == "4": player = "4" elif react == "5": player = "5" elif react == "6": player = "6" elif react == "7": player = "7" except asyncio.TimeoutError: return await author.send("You took too long. Try again.") embed = discord.Embed(color=await ctx.embed_colour(), timestamp=datetime.now()) embed.set_author( name=f"{ctx.author.name} is looking for a Rocket League group", icon_url=author.avatar_url) embed.set_footer(text="{0}#{1} ({2})".format( author.name, author.discriminator, author.id)) embed.add_field(name="GameMode:", value=gamemode, inline=True) embed.add_field(name="Rank:", value=rank, inline=True) embed.add_field(name="Server:", value=region, inline=True) embed.add_field(name="Platform:", value=platform, inline=True) embed.add_field(name="Looking for:", value=player, inline=True) await message.delete() try: if await self.config.lfg_channel() is None: await author.send( "It apprears that this hasn't been set up correctly on this server" ) else: channel = self.bot.get_channel(await self.config.lfg_channel()) please = await channel.send(embed=embed) await author.send("**Your LFG request has been made!**") await asyncio.sleep(1800) await please.delete() except discord.Forbidden: await author.send("That didn't work for some reason")
async def cast(self, ctx:commands.Context, bait_type:str): """Rolls for a fish Fish will periodically bite the pole, at which point the message can be reacted to to catch the fish After reeling in the rod, you will have the option to keep or release the fish - Must be used in a channel registered as a pool""" if not await self.IsSpecialized(ctx.guild, ctx.channel.id, POOL_CHANNEL): return profile = self.config.member(ctx.message.author) await profile.currently_fishing.set(True) modified_fish_weights = await self.startfishing(ctx, profile, bait_type) embed = Embed(title=f'{ctx.message.author.display_name} cast their rod into the shimmering waves at {ctx.channel}', color=0x7300ff) embed.set_footer(text='Not even a nibble yet...') msg = await ctx.send(embed=embed) start_adding_reactions(msg, ['🎣']) pred = ReactionPredicate.with_emojis(['🎣'], msg, ctx.author) time_left = await self.GetSetting(ctx.guild, 'max_fishing_length') min_pause = await self.GetSetting(ctx.guild, 'min_fishing_wait') max_pause = await self.GetSetting(ctx.guild, 'max_fishing_wait') curr_fish = None rarity = None while time_left >= 0: try: timer = time_left if time_left < max_pause else randint(min_pause, max_pause) time_left -= timer await ctx.bot.wait_for('reaction_add', check=pred, timeout=timer) except asyncio.TimeoutError: if curr_fish is None: rarity = choices(FISH_RARITIES, modified_fish_weights)[0] rarity_list = self.fishing_rarities.get(rarity) curr_fish = rarity_list[randint(0, len(rarity_list) - 1)] if not await profile.bryan_mode() else self.SEA_BASS embed.set_footer(text=RARITY_DESCRIPTIONS[rarity]) else: curr_fish = None embed.set_footer(text='The rod drifts in the water') await msg.edit(embed=embed) if pred.result == 0: break if curr_fish is None or time_left <= 0: embed.set_footer(text='You feel a twist as the line snaps :(') await msg.edit(embed=embed) await msg.clear_reactions() else: new_fish = curr_fish.ToFishCatch(RARITY_VALUES[rarity]) embed.set_footer(text=f'You pulled a {new_fish["name"]} ({new_fish["size"]} inches) out of the water!\nDo you want to keep or release?') embed.set_thumbnail(url=curr_fish.image) await msg.edit(embed=embed) await msg.clear_reactions() start_adding_reactions(msg, ['🥤', '🐟']) pred = ReactionPredicate.with_emojis(['🥤', '🐟'], msg, ctx.author) try: await ctx.bot.wait_for("reaction_add", check=pred, timeout=15) except asyncio.TimeoutError: if await self.AddFish(ctx.message.author, new_fish): embed.set_footer(text=f'Timed out, {new_fish["name"]} was added to your bucket') else: embed.set_footer(text=f'Timed out and your bucket was full, so {new_fish["name"]} was released :(') await msg.edit(embed=embed) await msg.clear_reactions() else: if pred.result == 0: if await self.AddFish(ctx.message.author, new_fish): embed.set_footer(text=f'{new_fish["name"]} was added to your bucket!') else: embed.set_footer(text=f'Your bucket was full, so you had to release {new_fish["name"]} :(') else: embed.set_footer(text=f'You let {new_fish["name"]} swim away...') await msg.edit(embed=embed) await msg.clear_reactions() if randint(0, 100) < 100 * await self.GetSetting(ctx.guild, 'bait_recovery_chance'): await ctx.send(f'Your {bait_type} is still on the end of the rod! (+1 {bait_type})') else: user_bait = await profile.bait() user_bait[bait_type] -= 1 await profile.bait.set(user_bait) await profile.currently_fishing.set(False) #if not await profile.mawiam_mode(): #await profile.nextcast.set(time() + await self.GetSetting(ctx.guild, 'fishing_delay')) await self.CheckSchools(ctx)
async def open_chest(ctx, user, type): if hasattr(user, "display_name"): await ctx.send("{} is opening a treasure chest. What riches lay inside?".format(user.display_name)) else: #this is when a pet is foraging. await ctx.send("{} is foraging for treasure. What will it find?".format(user[:1].upper() + user[1:])) await asyncio.sleep(2) if hasattr(user, "display_name"): luckbonus = Userdata.users[str(user.id)]['buffs'].get('luck', {'bonus':0})['bonus'] roll = random.randint(1,100)-luckbonus else: luckbonus = 0 roll = random.randint(1,100) if type == "pet": if roll <= 1: await ctx.send("{} found something precious!".format(user[:1].upper() + user[1:])) chance = Treasure.quest elif roll <= 11: chance = Treasure.unique elif roll > 11 and roll <= 50: chance = Treasure.rare elif roll > 50 and roll <= 75: chance = Treasure.common else: await ctx.send("{} found nothing of value.".format(user[:1].upper() + user[1:])) return None elif type == "normal": if roll <= 5: chance = Treasure.unique elif roll > 5 and roll <= 25: chance = Treasure.rare else: chance = Treasure.common elif type == "rare": if roll <= 15: chance = Treasure.unique elif roll > 15 and roll <= 45: chance = Treasure.rare else: chance = Treasure.common elif type == "epic": if roll <= 1: await ctx.send("This was no ordinary epic chest!") chance = Treasure.quest elif roll <= 25: chance = Treasure.unique else: chance = Treasure.rare elif type == "quest": if roll <= 10: chance = Treasure.quest else: chance = Treasure.unique itemname = random.choice(list(chance.keys())) item = chance[itemname] if item['slot'] == ['consumable']: item['uses'] = random.randint(1,item['uses']) if hasattr(user, "display_name"): await ctx.send("```css\n{} found {} ({}x).```".format(user.display_name,itemname,item['uses'])) else: await ctx.send("```css\nYour {} found {} ({}x).```".format(user,itemname,item['uses'])) msg = await ctx.send("Do you want to use, put in backpack or sell this item?") start_adding_reactions(msg, Treasure.controls.keys()) if hasattr(user, "id"): pred = ReactionPredicate.with_emojis(tuple(Treasure.controls.keys()), msg, user) else: pred = ReactionPredicate.with_emojis(tuple(Treasure.controls.keys()), msg, ctx.author) react = None try: react, user = await ctx.bot.wait_for("reaction_add", check=pred, timeout=60) except asyncio.TimeoutError: await ctx.send("Item claim timed out after one minute. Selling...") react_emoji = "💰" try: await msg.clear_reactions() except discord.Forbidden: # cannot remove all reactions for key in Treasure.controls.keys(): await msg.remove_reaction(key, ctx.bot.user) if luckbonus != 0: if Userdata.users[str(user.id)]['buffs']['luck']['duration'] <= 1: Userdata.users[str(user.id)]['buffs'].pop('luck') luckbonus = 0 else: Userdata.users[str(user.id)]['buffs']['luck']['duration'] = Userdata.users[str(user.id)]['buffs']['luck']['duration'] - 1 await Userdata.save() if react != None: react_emoji = react.emoji return {"itemname": itemname,"item":item,"equip":Treasure.controls[react_emoji]} else: if len(item["slot"]) == 2: # two handed weapons add their bonuses twice hand = "two handed" att = item["att"]*2 cha = item["cha"]*2 else: if item["slot"][0] == "right" or item["slot"][0] == "left": hand = item["slot"][0] + " handed" else: hand = item["slot"][0] + " slot" att = item["att"] cha = item["cha"] if hasattr(user, "display_name"): await ctx.send("```css\n{} found a {}. (Attack: {}, Charisma: {} [{}])```".format(user.display_name,itemname,str(att),str(cha),hand)) else: await ctx.send("```css\nYour {} found a {}. (Attack: {}, Charisma: {} [{}])```".format(user,itemname,str(att),str(cha),hand)) msg = await ctx.send("Do you want to equip, put in backpack or sell this item?") start_adding_reactions(msg, Treasure.controls.keys()) if hasattr(user, "id"): pred = ReactionPredicate.with_emojis(tuple(Treasure.controls.keys()), msg, user) else: pred = ReactionPredicate.with_emojis(tuple(Treasure.controls.keys()), msg, ctx.author) react = None try: react, user = await ctx.bot.wait_for("reaction_add", check=pred, timeout=60) except asyncio.TimeoutError: await ctx.send("Item claim timed out after one minute. Selling...") react_emoji = "💰" try: await msg.clear_reactions() except discord.Forbidden: # cannot remove all reactions for key in Treasure.controls.keys(): await msg.remove_reaction(key, ctx.bot.user) if luckbonus != 0: if Userdata.users[str(user.id)]['buffs']['luck']['duration'] <= 1: Userdata.users[str(user.id)]['buffs'].pop('luck') luckbonus = 0 else: Userdata.users[str(user.id)]['buffs']['luck']['duration'] = Userdata.users[str(user.id)]['buffs']['luck']['duration'] - 1 await Userdata.save() if react != None: react_emoji = react.emoji return {"itemname": itemname,"item":item,"equip":Treasure.controls[react_emoji]}
async def watch2gether(self, ctx, link=None): ''' Create a watch2gether room. If a link is provided then the room will be opened for that resource ''' api_keys = await self.bot.get_shared_api_tokens("watch2gether") if api_keys.get("api_key") is None: return await ctx.send( "The Watch2Gether API key has not been set. Set it with " f"`{ctx.prefix}set api watch2gether api_key,<api_key>` command" ) api_key = api_keys["api_key"] if link is None: running_rooms = await self.db.guild(ctx.guild).rooms() if running_rooms: now = datetime.utcnow() room_strs = [] i = 1 for room in running_rooms: created_at = discord.utils.snowflake_time( room["message_id"]) expires = await self.db.guild(ctx.guild).expires() if expires: if (now - created_at).total_seconds() > expires: async with self.db.guild( ctx.guild).rooms() as rooms: rooms.remove(room) running_rooms.remove(room) continue time_delta = human_timedelta(created_at, accuracy=1) string = f"[Room {i}]({room['room_url']}) (Created By - <@{room['author_id']}>, {time_delta})" i = i + 1 room_strs.append(string) if room_strs: embed_color = await ctx.embed_color() embed = discord.Embed(color=embed_color, title="Currently running rooms:") embed.description = "\n".join(room_strs) embed.set_footer( text= "Click on any of the URLs above to enter the room.\n" 'If you want to create a new room, react with "+" on this message' ) message = await ctx.send(embed=embed) emojis = [ "\N{HEAVY PLUS SIGN}", "\N{HEAVY MULTIPLICATION X}\N{VARIATION SELECTOR-16}" ] start_adding_reactions(message, emojis) pred = ReactionPredicate.with_emojis(emojis, message=message, user=ctx.author) try: await self.bot.wait_for("reaction_add", check=pred, timeout=60.0) except asyncio.exceptions.TimeoutError: return await message.clear_reactions() else: if pred.result == 1: return await message.delete() url = "https://www.watch2gether.com/rooms/create.json" data = {"api_key": api_key, "share": link} async with self.session.post(url, data=data) as resp: jsondata = await resp.json() room_key = jsondata["streamkey"] room_url = f"https://www.watch2gether.com/rooms/{room_key}" async with self.db.guild(ctx.guild).rooms() as rooms: rooms.append({ "room_key": room_key, "room_url": room_url, "message_id": ctx.message.id, "author_id": ctx.author.id }) await ctx.send(f"New Watch2Gether room created: {room_url}")
async def daily(self, ctx): """View the daily deals. These will come at a lower price than the store, but can only be bought once per day. Status guide: A: Available to be bought and put in backyard B: Already purchased S: Available to be bought, but will be put in stash because you either do not have the space for the, or above your level threshold""" async with self.lock: data = await self.conf.user(ctx.author).all() animals = data["animals"] animal = data["animal"] if animal in ["", "P"]: return await ctx.send("Finish starting your evolution first") multiplier = data["multiplier"] highest = max(list(map(int, animals.keys()))) e = 6 + math.ceil((multiplier - 1) * 5) display = [] deals = await self.conf.daily() for did, deal in deals.items(): status = "" amount = deal["details"]["amount"] level = deal["details"]["level"] if ctx.author.id in deal["bought"]: status = "[B]" elif (level > int(highest) - 3 and level != 1) or (amount + animals.get(str(level), 0) > e): status = "#S " else: status = " A " price = self.utils.get_total_price(level, 0, amount, False) * 0.75 display.append([ did, status, humanize_number(price), f"{amount} Level {level} {animal}{'s' if amount != 1 else ''}", ]) message = await ctx.send( f"{box(tabulate(display, tablefmt='psql'), lang='css')}Would you like to buy any of these fine animals? Click the corresponding reaction below." ) emojis = ReactionPredicate.NUMBER_EMOJIS[1:7] start_adding_reactions(message, emojis) pred = ReactionPredicate.with_emojis(emojis, message, ctx.author) try: await self.bot.wait_for("reaction_add", check=pred, timeout=60.0) except asyncio.TimeoutError: return await ctx.send( "The vendor grew uncomfortable with you there, and told you to leave and come back later." ) if ctx.author.id in self.inmarket: return await ctx.send( "Complete your current transaction or evolution first.") self.inmarket.append(ctx.author.id) buying = pred.result + 1 deal = deals[str(buying)] if ctx.author.id in deal["bought"]: # ;no self.inmarket.remove(ctx.author.id) return await ctx.send( "You already bought this deal. You cannot buy daily deals multiple times." ) level = deal["details"]["level"] amount = deal["details"]["amount"] price = self.utils.get_total_price(level, 0, amount, False) * 0.75 balance = await bank.get_balance(ctx.author) if balance < price: self.inmarket.remove(ctx.author.id) return await ctx.send( f"You need {humanize_number(price - balance)} more credits to buy that deal." ) stashing = 0 delivering = amount if level > int(highest) - 3 and level != 1: stashing = amount delivering = 0 elif amount + animals.get(str(level), 0) > e: delivering = e - animals[str(level)] stashing = amount - delivering async with self.lock: async with self.conf.user(ctx.author).all() as data: data["animals"][str(level)] = animals.get(str(level), 0) + delivering if stashing: current_stash = data["stash"]["animals"].get(str(level), 0) data["stash"]["animals"][str( level)] = current_stash + stashing self.cache[ctx.author.id] = data async with self.conf.daily( ) as data: # In case someone buys at the same time, we need to re-read the data data[str(buying)]["bought"].append(ctx.author.id) await bank.withdraw_credits(ctx.author, int(price)) await ctx.send( box( (f"[Transaction Complete]\nYou spent {humanize_number(price)} credits to buy {amount} Level {str(level)} {animal}{'s' if amount != 1 else ''}." f"\n\n{delivering} have been added to your backyard, {stashing} have been sent to your stash." ), "css", )) self.inmarket.remove(ctx.author.id)
async def get_playlist_match( self, context: commands.Context, matches: MutableMapping, scope: str, author: discord.User, guild: discord.Guild, specified_user: bool = False, ) -> Tuple[Optional[Playlist], str, str]: """ Parameters ---------- context: commands.Context The context in which this is being called. matches: dict A dict of the matches found where key is scope and value is matches. scope:str The custom config scope. A value from :code:`PlaylistScope`. author: discord.User The user. guild: discord.Guild The guild. specified_user: bool Whether or not a user ID was specified via argparse. Returns ------- Tuple[Optional[Playlist], str, str] Tuple of Playlist or None if none found, original user input and scope. Raises ------ `TooManyMatches` When more than 10 matches are found or When multiple matches are found but none is selected. """ correct_scope_matches: List[Playlist] original_input = matches.get("arg") lazy_match = False if scope is None: correct_scope_matches_temp: MutableMapping = matches.get("all") lazy_match = True else: correct_scope_matches_temp: MutableMapping = matches.get(scope) guild_to_query = guild.id user_to_query = author.id correct_scope_matches_user = [] correct_scope_matches_guild = [] correct_scope_matches_global = [] if not correct_scope_matches_temp: return None, original_input, scope or PlaylistScope.GUILD.value if lazy_match or (scope == PlaylistScope.USER.value): correct_scope_matches_user = [ p for p in matches.get(PlaylistScope.USER.value) if user_to_query == p.scope_id ] if lazy_match or (scope == PlaylistScope.GUILD.value and not correct_scope_matches_user): if specified_user: correct_scope_matches_guild = [ p for p in matches.get(PlaylistScope.GUILD.value) if guild_to_query == p.scope_id and p.author == user_to_query ] else: correct_scope_matches_guild = [ p for p in matches.get(PlaylistScope.GUILD.value) if guild_to_query == p.scope_id ] if lazy_match or (scope == PlaylistScope.GLOBAL.value and not correct_scope_matches_user and not correct_scope_matches_guild): if specified_user: correct_scope_matches_global = [ p for p in matches.get(PlaylistScope.GLOBAL.value) if p.author == user_to_query ] else: correct_scope_matches_global = [ p for p in matches.get(PlaylistScope.GLOBAL.value) ] correct_scope_matches = [ *correct_scope_matches_global, *correct_scope_matches_guild, *correct_scope_matches_user, ] match_count = len(correct_scope_matches) if match_count > 1: correct_scope_matches2 = [ p for p in correct_scope_matches if p.name == str(original_input).strip() ] if correct_scope_matches2: correct_scope_matches = correct_scope_matches2 elif original_input.isnumeric(): arg = int(original_input) correct_scope_matches3 = [ p for p in correct_scope_matches if p.id == arg ] if correct_scope_matches3: correct_scope_matches = correct_scope_matches3 match_count = len(correct_scope_matches) # We done all the trimming we can with the info available time to ask the user if match_count > 10: if original_input.isnumeric(): arg = int(original_input) correct_scope_matches = [ p for p in correct_scope_matches if p.id == arg ] if match_count > 10: raise TooManyMatches( _("{match_count} playlists match {original_input}: " "Please try to be more specific, or use the playlist ID." ).format(match_count=match_count, original_input=original_input)) elif match_count == 1: return correct_scope_matches[ 0], original_input, correct_scope_matches[0].scope elif match_count == 0: return None, original_input, scope or PlaylistScope.GUILD.value # TODO : Convert this section to a new paged reaction menu when Toby Menus are Merged pos_len = 3 playlists = f"{'#':{pos_len}}\n" number = 0 correct_scope_matches = sorted(correct_scope_matches, key=lambda x: x.name.lower()) async for number, playlist in AsyncIter( correct_scope_matches).enumerate(start=1): author = self.bot.get_user( playlist.author) or playlist.author or _("Unknown") line = _("{number}." " <{playlist.name}>\n" " - Scope: < {scope} >\n" " - ID: < {playlist.id} >\n" " - Tracks: < {tracks} >\n" " - Author: < {author} >\n\n").format( number=number, playlist=playlist, scope=self.humanize_scope(playlist.scope), tracks=len(playlist.tracks), author=author, ) playlists += line embed = discord.Embed( title=_("{playlists} playlists found, which one would you like?"). format(playlists=number), description=box(playlists, lang="md"), colour=await context.embed_colour(), ) msg = await context.send(embed=embed) avaliable_emojis = ReactionPredicate.NUMBER_EMOJIS[1:] avaliable_emojis.append("🔟") emojis = avaliable_emojis[:len(correct_scope_matches)] close_emoji = self.get_cross_emoji(context) emojis.append(close_emoji) start_adding_reactions(msg, emojis) pred = ReactionPredicate.with_emojis(emojis, msg, user=context.author) try: await context.bot.wait_for("reaction_add", check=pred, timeout=60) except asyncio.TimeoutError: with contextlib.suppress(discord.HTTPException): await msg.delete() raise TooManyMatches( _("Too many matches found and you did not select which one you wanted." )) if emojis[pred.result] == close_emoji: with contextlib.suppress(discord.HTTPException): await msg.delete() raise TooManyMatches( _("Too many matches found and you did not select which one you wanted." )) with contextlib.suppress(discord.HTTPException): await msg.delete() return ( correct_scope_matches[pred.result], original_input, correct_scope_matches[pred.result].scope, )
async def open_chest(ctx, user, type): if hasattr(user, "display_name"): await ctx.send( "{} is opening a treasure chest. What riches lay inside?". format(user.display_name)) else: await ctx.send( "{} is foraging for treasure. What will it find?".format( user[:1].upper() + user[1:])) await asyncio.sleep(2) roll = random.randint(1, 100) if type == "pet": if roll <= 5: chance = Treasure.unique elif roll > 5 and roll <= 25: chance = Treasure.rare elif roll > 25 and roll <= 75: chance = Treasure.common else: await ctx.send( "{} found nothing of value.".format(user[:1].upper() + user[1:])) return None if type == "normal": if roll <= 5: chance = Treasure.unique elif roll > 5 and roll <= 25: chance = Treasure.rare else: chance = Treasure.common if type == "rare": if roll <= 15: chance = Treasure.unique elif roll > 15 and roll <= 45: chance = Treasure.rare else: chance = Treasure.common if type == "epic": if roll <= 25: chance = Treasure.unique else: chance = Treasure.rare itemname = random.choice(list(chance.keys())) item = chance[itemname] if len(item["slot"] ) == 2: # two handed weapons add their bonuses twice hand = "two handed" att = item["att"] * 2 cha = item["cha"] * 2 else: if item["slot"][0] == "right" or item["slot"][0] == "left": hand = item["slot"][0] + " handed" else: hand = item["slot"][0] + " slot" att = item["att"] cha = item["cha"] if hasattr(user, "display_name"): await ctx.send( "{} found a {}. (Attack: {}, Charisma: {} [{}])".format( user.display_name, itemname, str(att), str(cha), hand)) else: await ctx.send( "Your {} found a {}. (Attack: {}, Charisma: {} [{}])".format( user, itemname, str(att), str(cha), hand)) msg = await ctx.send( "Do you want to equip, put in backpack or sell this item?") start_adding_reactions(msg, Treasure.controls.keys()) if hasattr(user, "id"): pred = ReactionPredicate.with_emojis( tuple(Treasure.controls.keys()), msg, user) else: pred = ReactionPredicate.with_emojis( tuple(Treasure.controls.keys()), msg, ctx.author) react, user = await ctx.bot.wait_for("reaction_add", check=pred) try: await msg.clear_reactions() except discord.Forbidden: # cannot remove all reactions for key in Treasure.controls.keys(): await msg.remove_reaction(key, ctx.bot.user) return { "itemname": itemname, "item": item, "equip": Treasure.controls[react.emoji] }