async def int_dialogue(self, start, end): """ Creates an interactive int dialogue message for a user to react to. :type start: int :type end: int :rtype: DialogueResponse """ response = DialogueResponse(self) ongoing = Ongoing.is_ongoing('dialogue', self.user.id) if not ongoing: Ongoing.set_ongoing('dialogue', self.user.id) start = 0 if start < 0 else start end = 9 if end > 9 else end self.question.set_author(name=self.user.display_name, icon_url=user_avatar(self.user)) # noinspection PyBroadException try: confirmation = await self.channel.send(embed=self.question) [await confirmation.add_reaction(INT_REACTIONS[preac]) for preac in range(start, end + 1)] await confirmation.add_reaction(CANCEL_REACT) except Exception: response.error = True Ongoing.del_ongoing('dialogue', self.user.id) return response def check_emote(reac): """ Checks for a valid message reaction. :type reac: discord.RawReactionActionEvent :rtype: bool """ same_author = reac.user_id == self.msg.author.id same_message = reac.message_id == confirmation.id valid_reaction = (str(reac.emoji) in INT_REACTIONS) or str(reac.emoji) == CANCEL_REACT return same_author and same_message and valid_reaction try: ae = await self.bot.wait_for('raw_reaction_add', timeout=TIMEOUT, check=check_emote) if str(ae.emoji) == CANCEL_REACT: response.cancelled = True else: response.ok = True for react_index, int_react in enumerate(INT_REACTIONS): if int_react == str(ae.emoji): response.value = react_index break except asyncio.TimeoutError: response.timed_out = True try: await confirmation.delete() except discord.NotFound: pass Ongoing.del_ongoing('dialogue', self.user.id) else: response.ongoing = True return response
async def slow_buy(cmd, pld): """ :param cmd: The command object referenced in the command. :type cmd: sigma.core.mechanics.command.SigmaCommand :param pld: The payload with execution data and details. :type pld: sigma.core.mechanics.payload.CommandPayload """ currency = cmd.bot.cfg.pref.currency if not Ongoing.is_ongoing(cmd.name, pld.msg.author.id): Ongoing.set_ongoing(cmd.name, pld.msg.author.id) upgrade_file = await cmd.bot.db.get_profile(pld.msg.author.id, 'upgrades') or {} upgrade_text = '' upgrade_index = 0 for upgrade in upgrade_list: upgrade_index += 1 upgrade_id = upgrade.get('id') upgrade_level = upgrade_file.get(upgrade_id, 0) base_price = upgrade.get('cost') upgrade_price = get_price(base_price, upgrade_level) next_upgrade = upgrade_level + 1 upgrade_text += f'\n**{upgrade_index}**: Level {next_upgrade} {upgrade["name"]}' upgrade_text += f' - {upgrade_price} {currency}' upgrade_text += f'\n > {upgrade["desc"]}' upgrade_list_embed = discord.Embed(color=0xF9F9F9, title='🛍 Profession Upgrade Shop') upgrade_list_embed.description = upgrade_text upgrade_list_embed.set_footer(text='Please input the number of the upgrade you want.') dialogue = DialogueCore(cmd.bot, pld.msg, upgrade_list_embed) dresp = await dialogue.int_dialogue(1, len(upgrade_list)) if dresp.ok and dresp.value is not None: upgrade = upgrade_list[dresp.value - 1] current_kud = await cmd.db.get_resource(pld.msg.author.id, 'currency') current_kud = current_kud.current upgrade_id = upgrade['id'] upgrade_level = upgrade_file.get(upgrade_id, 0) base_price = upgrade['cost'] upgrade_price = get_price(base_price, upgrade_level) if current_kud >= upgrade_price: new_upgrade_level = upgrade_level + 1 upgrade_file.update({upgrade_id: new_upgrade_level}) await cmd.db.set_profile(pld.msg.author.id, 'upgrades', upgrade_file) await cmd.db.del_resource(pld.msg.author.id, 'currency', upgrade_price, cmd.name, pld.msg) response = GenericResponse(f'Upgraded your {upgrade["name"]} to Level {new_upgrade_level}.').ok() else: response = discord.Embed(color=0xa7d28b, title=f'💸 You don\'t have enough {currency}.') else: response = discord.Embed(color=0x696969, title='🕙 Sorry, you timed out.') if Ongoing.is_ongoing(cmd.name, pld.msg.author.id): Ongoing.del_ongoing(cmd.name, pld.msg.author.id) else: response = GenericResponse('You already have a shop open.').error() await pld.msg.channel.send(embed=response)
async def bool_dialogue(self): """ Creates an interactive bool dialogue message for a user to react to. :rtype: DialogueResponse """ response = DialogueResponse(self) ongoing = Ongoing.is_ongoing('dialogue', self.msg.author.id) if not ongoing: Ongoing.set_ongoing('dialogue', self.user.id) self.question.set_author(name=self.user.display_name, icon_url=user_avatar(self.user)) # noinspection PyBroadException try: confirmation = await self.channel.send(embed=self.question) [await confirmation.add_reaction(preac) for preac in BOOL_REACTIONS] except Exception: Ongoing.del_ongoing('dialogue', self.user.id) response.error = True return response def check_emote(reac): """ Checks for a valid message reaction. :type reac: discord.RawReactionActionEvent :rtype: bool """ same_author = reac.user_id == self.msg.author.id same_message = reac.message_id == confirmation.id valid_reaction = str(reac.emoji) in BOOL_REACTIONS return same_author and same_message and valid_reaction try: ae = await self.bot.wait_for('raw_reaction_add', timeout=TIMEOUT, check=check_emote) if str(ae.emoji) == CONFIRM_REACT: response.ok = True else: response.cancelled = True except asyncio.TimeoutError: response.timed_out = True try: await confirmation.delete() except discord.NotFound: pass Ongoing.del_ongoing('dialogue', self.user.id) else: response.ongoing = True return response
async def connect_four_cycler(ev): """ :param ev: The event object referenced in the event. :type ev: sigma.core.mechanics.event.SigmaEvent """ while True: if ev.bot.is_ready(): # noinspection PyBroadException try: games = cf_cache.cache.items() for mid, game in games: expiry = game.expiry now = arrow.utcnow().int_timestamp if now > expiry: channel = await ev.bot.get_channel(game.channel_id) if channel: wait_cycles = 0 while Ongoing.is_ongoing( 'cf_ongoing_turn', channel.id) and wait_cycles < 5: wait_cycles += 1 await asyncio.sleep(1) timeout_title = '🕙 Time\'s up' try: timeout_title += ' ' + game.current_turn.display_name + '!' except AttributeError: timeout_title += '!' timeout_embed = discord.Embed(color=0x696969, title=timeout_title) try: await channel.send(embed=timeout_embed) except (discord.NotFound, discord.Forbidden): pass if Ongoing.is_ongoing('connectfour', channel.id): Ongoing.del_ongoing('connectfour', channel.id) if Ongoing.is_ongoing('cf_ongoing_turn', channel.id): Ongoing.del_ongoing('cf_ongoing_turn', channel.id) await cf_cache.del_cache(mid) except Exception: pass await asyncio.sleep(5)
async def sell(cmd, pld): """ :param cmd: The command object referenced in the command. :type cmd: sigma.core.mechanics.command.SigmaCommand :param pld: The payload with execution data and details. :type pld: sigma.core.mechanics.payload.CommandPayload """ if Ongoing.is_ongoing(cmd.name, pld.msg.author.id): return Ongoing.set_ongoing(cmd.name, pld.msg.author.id) item_core = await get_item_core(cmd.db) currency = cmd.bot.cfg.pref.currency if pld.args: inv = await cmd.db.get_inventory(pld.msg.author.id) if inv: lookup = ' '.join(pld.args) if lookup.lower() == 'all': ender = 's' if len(inv) > 1 else '' worth = sum([item_core.get_item_by_file_id(ient['item_file_id']).value for ient in inv]) question = f'❔ Are you sure you want to sell {len(inv)} item{ender} worth {worth} {currency}?' quesbed = discord.Embed(color=0xF9F9F9, title=question) dialogue = DialogueCore(cmd.bot, pld.msg, quesbed) dresp = await dialogue.bool_dialogue() if dresp.ok: value = 0 count = 0 for invitem in inv.copy(): item_ob_id = item_core.get_item_by_file_id(invitem['item_file_id']) value += item_ob_id.value count += 1 await cmd.db.del_from_inventory(pld.msg.author.id, invitem['item_id']) await cmd.db.add_resource(pld.msg.author.id, 'currency', value, cmd.name, pld.msg) response = discord.Embed(color=0xc6e4b5) response.title = f'💶 You sold {count} item{ender} for {value} {currency}.' else: response = dresp.generic('item sale') elif lookup.lower() == 'duplicates': value = 0 count = 0 existing_ids = [] for invitem in inv.copy(): file_id = invitem['item_file_id'] if file_id in existing_ids: item_ob_id = item_core.get_item_by_file_id(file_id) value += item_ob_id.value count += 1 await cmd.db.del_from_inventory(pld.msg.author.id, invitem['item_id']) else: existing_ids.append(file_id) await cmd.db.add_resource(pld.msg.author.id, 'currency', value, cmd.name, pld.msg) ender = 's' if count > 1 else '' response = discord.Embed(color=0xc6e4b5) response.title = f'💶 You sold {count} duplicate{ender} for {value} {currency}.' else: request_count = 1 if len(pld.args) > 1: if pld.args[0].isdigit(): request_count = int(pld.args[0]) lookup = ' '.join(pld.args[1:]) item_o = item_core.get_item_by_name(lookup) count = 0 value = 0 if item_o: for _ in range(request_count): item = await cmd.db.get_inventory_item(pld.msg.author.id, item_o.file_id) if item: value += item_o.value count += 1 await cmd.db.del_from_inventory(pld.msg.author.id, item['item_id']) else: break if count > 0: await cmd.db.add_resource(pld.msg.author.id, 'currency', value, cmd.name, pld.msg) ender = 's' if count > 1 else '' response = discord.Embed(color=0xc6e4b5) response.title = f'💶 You sold {count} {item_o.name}{ender} for {value} {currency}.' else: if not lookup.isdigit(): response = GenericResponse(f'I didn\'t find any {lookup} in your inventory.').not_found() else: response = GenericResponse(f'Sell {lookup} of what?').not_found() else: response = discord.Embed(color=0xc6e4b5, title='💸 Your inventory is empty...') else: response = GenericResponse('Nothing inputted.').error() if Ongoing.is_ongoing(cmd.name, pld.msg.author.id): Ongoing.del_ongoing(cmd.name, pld.msg.author.id) response.set_author(name=pld.msg.author.display_name, icon_url=user_avatar(pld.msg.author)) await pld.msg.channel.send(embed=response)
async def vnchargame(cmd, pld): """ :param cmd: The command object referenced in the command. :type cmd: sigma.core.mechanics.command.SigmaCommand :param pld: The payload with execution data and details. :type pld: sigma.core.mechanics.payload.CommandPayload """ if not Ongoing.is_ongoing(cmd.name, pld.msg.channel.id): try: Ongoing.set_ongoing(cmd.name, pld.msg.channel.id) vndb_icon = 'https://i.imgur.com/YrK5tQF.png' wait_embed = discord.Embed(color=0x1d439b) wait_embed.set_author(name='Hunting for a good specimen...', icon_url=vndb_icon) working_response = await pld.msg.channel.send(embed=wait_embed) if pld.args: if pld.args[0].lower() == 'hint': hint = True else: hint = False else: hint = False vn_url_list = [] vn_top_list_url = 'https://vndb.org/v/all?q=;fil=tagspoil-0;rfil=;o=d;s=pop;p=1' async with aiohttp.ClientSession() as session: async with session.get(vn_top_list_url) as vn_top_list_session: vn_top_list_html = await vn_top_list_session.text() vn_top_list_data = html.fromstring(vn_top_list_html) list_items = vn_top_list_data.cssselect('.tc1') for list_item in list_items: if 'href' in list_item[0].attrib: vn_url = list_item[0].attrib['href'] if vn_url.startswith( '/v') and not vn_url.startswith('/v/'): vn_url = f'https://vndb.org{vn_url}' vn_url_list.append(vn_url) vn_url_choice = secrets.choice(vn_url_list) async with aiohttp.ClientSession() as session: async with session.get( f'{vn_url_choice}/chars') as vn_details_page_session: vn_details_page_html = await vn_details_page_session.text() vn_details_page = html.fromstring(vn_details_page_html) vn_title = vn_details_page.cssselect( '.stripe')[0][0][1].text_content().strip() vn_image = vn_details_page.cssselect( '.vnimg')[0][0][0][0].attrib['src'] character_objects = vn_details_page.cssselect('.chardetails')[:8] character = secrets.choice(character_objects) char_img = character[0][0][0][0].attrib['src'] char_name = character[1][0][0][0][0].text.strip() kud_reward = None description = None name_split = char_name.split() for name_piece in name_split: if kud_reward is None: kud_reward = len(name_piece) else: if kud_reward >= len(name_piece): kud_reward = len(name_piece) if hint: kud_reward = kud_reward // 2 scrambled_name = scramble(char_name) description = f'Name: {scrambled_name}' reward_mult = streaks.get(pld.msg.channel.id) or 0 kud_reward = int(kud_reward * (1 + (reward_mult * 2.25) / (1.75 + (0.03 * reward_mult)))) try: await working_response.delete() except discord.NotFound: pass question_embed = discord.Embed(color=0x225588) if description: question_embed.description = description question_embed.set_image(url=char_img) question_embed.set_author(name=vn_title, icon_url=vn_image, url=char_img) footer_text = 'You have 30 seconds to guess it.' if reward_mult: footer_text += f' | Streak: {int(reward_mult)}' question_embed.set_footer(text=footer_text) await pld.msg.channel.send(embed=question_embed) def check_answer(msg): """ :type msg: discord.Message :rtype: bool """ if pld.msg.channel.id == msg.channel.id: if msg.content.lower() in char_name.lower().split(): correct = True elif msg.content.lower() == char_name.lower(): correct = True else: correct = False else: correct = False return correct try: answer_message = await cmd.bot.wait_for('message', check=check_answer, timeout=30) await cmd.db.add_resource(answer_message.author.id, 'currency', kud_reward, cmd.name, pld.msg) author = answer_message.author.display_name currency = cmd.bot.cfg.pref.currency streaks.update({pld.msg.channel.id: reward_mult + 1}) win_title = f'🎉 Correct, {author}, it was {char_name}. You won {kud_reward} {currency}!' win_embed = discord.Embed(color=0x77B255, title=win_title) await pld.msg.channel.send(embed=win_embed) except asyncio.TimeoutError: if pld.msg.channel.id in streaks: streaks.pop(pld.msg.channel.id) timeout_title = f'🕙 Time\'s up! It was {char_name} from {vn_title}...' timeout_embed = discord.Embed(color=0x696969, title=timeout_title) await pld.msg.channel.send(embed=timeout_embed) except (IndexError, KeyError): grab_error = GenericResponse( 'I failed to grab a character, try again.').error() await pld.msg.channel.send(embed=grab_error) if Ongoing.is_ongoing(cmd.name, pld.msg.channel.id): Ongoing.del_ongoing(cmd.name, pld.msg.channel.id) else: ongoing_error = GenericResponse( 'There is already one ongoing.').error() await pld.msg.channel.send(embed=ongoing_error)
async def unscramblegame(cmd, pld): """ :param cmd: The command object referenced in the command. :type cmd: sigma.core.mechanics.command.SigmaCommand :param pld: The payload with execution data and details. :type pld: sigma.core.mechanics.payload.CommandPayload """ cache_key = 'unscramble_word_cache' word_cache = await cmd.db.cache.get_cache(cache_key) or {} if not word_cache: dict_docs = await cmd.db[cmd.db.db_nam ].DictionaryData.find({}).to_list(None) for ddoc in dict_docs: word = ddoc.get('word') if len(word) > 3 and len(word.split(' ')) == 1: word_cache.update({word: ddoc.get('description')}) await cmd.db.cache.set_cache(cache_key, word_cache) if not Ongoing.is_ongoing(cmd.name, pld.msg.channel.id): Ongoing.set_ongoing(cmd.name, pld.msg.channel.id) words = list(word_cache.keys()) word_choice = secrets.choice(words) word_description = word_cache.get(word_choice) kud_reward = len(word_choice) scrambled = scramble(word_choice.title()) question_embed = discord.Embed(color=0x3B88C3, title=f'🔣 {scrambled}') await pld.msg.channel.send(embed=question_embed) def check_answer(msg): """ Checks if the answer message is correct. :type msg: discord.Message :rtype: bool """ if pld.msg.channel.id == msg.channel.id: if msg.content.lower() == word_choice.lower(): correct = True else: correct = False else: correct = False return correct try: answer_message = await cmd.bot.wait_for('message', check=check_answer, timeout=30) await cmd.db.add_resource(answer_message.author.id, 'currency', kud_reward, cmd.name, pld.msg) author = answer_message.author.display_name currency = cmd.bot.cfg.pref.currency win_title = f'🎉 Correct, {author}, it was {word_choice}. You won {kud_reward} {currency}!' win_embed = discord.Embed(color=0x77B255, title=win_title) await pld.msg.channel.send(embed=win_embed) except asyncio.TimeoutError: timeout_title = '🕙 Time\'s up!' timeout_embed = discord.Embed(color=0x696969, title=timeout_title) timeout_embed.add_field(name=f'It was {word_choice.lower()}.', value=word_description) await pld.msg.channel.send(embed=timeout_embed) if Ongoing.is_ongoing(cmd.name, pld.msg.channel.id): Ongoing.del_ongoing(cmd.name, pld.msg.channel.id) else: ongoing_error = GenericResponse( 'There is one already ongoing.').error() await pld.msg.channel.send(embed=ongoing_error)
async def addemote(cmd, pld): """ :param cmd: The command object referenced in the command. :type cmd: sigma.core.mechanics.command.SigmaCommand :param pld: The payload with execution data and details. :type pld: sigma.core.mechanics.payload.CommandPayload """ react_msg = None if pld.msg.author.guild_permissions.manage_emojis: if not Ongoing.is_ongoing(cmd.name, pld.msg.channel.id): Ongoing.set_ongoing(cmd.name, pld.msg.guild.id) react_embed = discord.Embed( color=0xF9F9F9, title='💬 React with the desired emote.') react_msg = await pld.msg.channel.send(embed=react_embed) def check_emote(reac, usr): same_author = usr.id == pld.msg.author.id same_message = reac.message.id == react_msg.id return same_author and same_message try: ae, _au = await cmd.bot.wait_for('reaction_add', timeout=30, check=check_emote) working_embed = discord.Embed(title='⬇️ Downloading file...', color=0x3B88C3) try: await react_msg.edit(embed=working_embed) except discord.NotFound: await pld.msg.channel.send(embed=working_embed) react_msg = await pld.msg.channel.fetch_message(react_msg.id) emote_to_add = None for reaction in react_msg.reactions: if str(reaction.emoji) == str(ae): emote_to_add = reaction.emoji break if not isinstance(emote_to_add, str): if pld.args and len(pld.args[0]) > 1: name = pld.args[0] else: # noinspection PyUnresolvedReferences name = emote_to_add.name # noinspection PyUnresolvedReferences image = await get_emote_image(str(emote_to_add.url)) try: emote = await pld.msg.guild.create_custom_emoji( name=name, image=image) response = GenericResponse( f'Added emote {emote.name}.').ok() except discord.errors.HTTPException: response = GenericResponse( 'File size cannot exceed 256kb.').error() else: response = GenericResponse( 'Must be a custom emote.').error() except asyncio.TimeoutError: response = discord.Embed(color=0x696969, title='🕙 The message timed out.') if Ongoing.is_ongoing(cmd.name, pld.msg.channel.id): Ongoing.del_ongoing(cmd.name, pld.msg.channel.id) else: response = GenericResponse('There is already one ongoing.').error() else: response = GenericResponse( 'Access Denied. Manage Emotes needed.').denied() if react_msg: try: await react_msg.edit(embed=response) except discord.NotFound: await pld.msg.channel.send(embed=response) else: await pld.msg.channel.send(embed=response)
async def trivia(cmd, pld): """ :param cmd: The command object referenced in the command. :type cmd: sigma.core.mechanics.command.SigmaCommand :param pld: The payload with execution data and details. :type pld: sigma.core.mechanics.payload.CommandPayload """ global streaks if await cmd.bot.cool_down.on_cooldown(cmd.name, pld.msg.author): timeout = await cmd.bot.cool_down.get_cooldown(cmd.name, pld.msg.author) on_cooldown = discord.Embed( color=0xccffff, title=f'❄ On cooldown for another {timeout} seconds.') await pld.msg.channel.send(embed=on_cooldown) return try: if not Ongoing.is_ongoing(cmd.name, pld.msg.author.id): Ongoing.set_ongoing(cmd.name, pld.msg.author.id) allotted_time = 20 trivia_api_url = 'https://opentdb.com/api.php?amount=1' cat_chosen = False if pld.args: catlook = pld.args[-1].lower() for cat in categories: cat_alts = categories.get(cat) if catlook in cat_alts: trivia_api_url += f'&category={cat}' cat_chosen = True break diflook = pld.args[0].lower() if diflook in ['easy', 'medium', 'hard']: trivia_api_url += f'&difficulty={diflook}' cat_chosen = True async with aiohttp.ClientSession() as session: async with session.get(trivia_api_url) as number_get: number_response = await number_get.read() try: data = json.loads(number_response).get('results')[0] except json.JSONDecodeError: if Ongoing.is_ongoing(cmd.name, pld.msg.author.id): Ongoing.del_ongoing(cmd.name, pld.msg.author.id) decode_error = GenericResponse( 'Could not retrieve a question.').error() await pld.msg.channel.send(embed=decode_error) return await cmd.bot.cool_down.set_cooldown(cmd.name, pld.msg.author, 30) question = data['question'] question = ftfy.fix_text(question) question = re.sub(r'([*_~`])', r'\\\1', question) # escape markdown formatting category = data['category'] correct_answer = data['correct_answer'] correct_answer = ftfy.fix_text(correct_answer) incorrect_answers = data['incorrect_answers'] difficulty = data['difficulty'] reward_mult = streaks.get( pld.msg.author.id) or 0 if not cat_chosen else 0 kud_reward = int( (awards.get(difficulty) or '10') * (1 + (reward_mult * 2.25) / (1.75 + (0.03 * reward_mult)))) choice_list = [correct_answer] + incorrect_answers choice_list = shuffle_questions(choice_list) choice_number = 0 choice_lines = [] for choice in choice_list: choice_number += 1 choice_line = f'[{choice_number}] {choice}' choice_lines.append(choice_line) choice_text = '\n'.join(choice_lines) choice_text = ftfy.fix_text(choice_text) starter = 'An' if difficulty == 'easy' else 'A' question_embed = discord.Embed(color=0xF9F9F9, title='❔ Here\'s a question!') question_embed.description = f'{starter} {difficulty} one from the {category} category.' question_embed.add_field(name='Question', value=question, inline=False) question_embed.add_field(name='Choices', value=f'```py\n{choice_text}\n```', inline=False) question_embed.set_author(name=pld.msg.author.display_name, icon_url=user_avatar(pld.msg.author)) footer_text = 'Input the number of your chosen answer.' if reward_mult: footer_text += f' | Streak: {int(reward_mult)}' question_embed.set_footer(text=footer_text) await pld.msg.channel.send(embed=question_embed) def check_answer(msg): """ :type msg: discord.Message :rtype: bool """ if pld.msg.channel.id != msg.channel.id: return if pld.msg.author.id != msg.author.id: return if msg.content.isdigit(): try: int_content = int(msg.content) except ValueError: return if abs(int_content) <= len(choice_lines): return True else: return elif msg.content.title() in choice_list: return True try: answer_message = await cmd.bot.wait_for('message', check=check_answer, timeout=allotted_time) try: answer_index = int(answer_message.content) - 1 except ValueError: answer_index = None correct_index = get_correct_index(choice_list, correct_answer) if answer_index == correct_index or answer_message.content.lower( ) == correct_answer.lower(): if cat_chosen: streaks.update( {pld.msg.author.id: reward_mult + 0.005}) else: streaks.update({pld.msg.author.id: reward_mult + 1}) await cmd.db.add_resource(answer_message.author.id, 'currency', kud_reward, cmd.name, pld.msg) author = answer_message.author.display_name currency = cmd.bot.cfg.pref.currency win_title = f'🎉 Correct, {author}, it was {correct_answer}. You won {kud_reward} {currency}!' final_embed = discord.Embed(color=0x77B255, title=win_title) else: if pld.msg.author.id in streaks: streaks.pop(pld.msg.author.id) lose_title = f'💣 Ooh, sorry, it was {correct_answer}...' final_embed = discord.Embed(color=0x262626, title=lose_title) await pld.msg.channel.send(embed=final_embed) except asyncio.TimeoutError: if pld.msg.author.id in streaks: streaks.pop(pld.msg.author.id) timeout_title = f'🕙 Time\'s up! It was {correct_answer}...' timeout_embed = discord.Embed(color=0x696969, title=timeout_title) await pld.msg.channel.send(embed=timeout_embed) if Ongoing.is_ongoing(cmd.name, pld.msg.author.id): Ongoing.del_ongoing(cmd.name, pld.msg.author.id) else: ongoing_error = GenericResponse( 'There is already one ongoing.').error() await pld.msg.channel.send(embed=ongoing_error) except Exception: if Ongoing.is_ongoing(cmd.name, pld.msg.author.id): Ongoing.del_ongoing(cmd.name, pld.msg.author.id) raise
async def item_dialogue(self, icons, item): """ Creates an interactive item dialogue message for a user to react to. :type icons: dict :type item: sigma.modules.minigames.professions.nodes.item_object.SigmaRawItem :rtype: DialogueResponse """ response = DialogueResponse(self) ongoing = Ongoing.is_ongoing('dialogue', self.user.id) if not ongoing: Ongoing.set_ongoing('dialogue', self.user.id) icon_list = [icons.get(ic) for ic in icons if icons.get(ic) != item.icon] icon_list.pop(0) possible_proto = [item.icon] while len(possible_proto) < secrets.randbelow(2) + 3: possible_proto.append(icon_list.pop(secrets.randbelow(len(icon_list)))) possible = [] while possible_proto: possible.append(possible_proto.pop(secrets.randbelow(len(possible_proto)))) possible.append(CANCEL_REACT) title = f'{item.icon} Quick! Get the correct {item.type.lower()}!' self.question = discord.Embed(color=item.color, title=title) self.question.set_author(name=self.user.display_name, icon_url=user_avatar(self.user)) # noinspection PyBroadException try: confirmation = await self.channel.send(embed=self.question) [await confirmation.add_reaction(preac) for preac in possible] except Exception: response.error = True Ongoing.del_ongoing('dialogue', self.user.id) return response def check_emote(reac): """ Checks for a valid message reaction. :type reac: discord.RawReactionActionEvent :rtype: bool """ same_author = reac.user_id == self.msg.author.id same_message = reac.message_id == confirmation.id valid_reaction = str(reac.emoji) in possible return same_author and same_message and valid_reaction try: ae = await self.bot.wait_for('raw_reaction_add', timeout=TIMEOUT, check=check_emote) if str(ae.emoji) == item.icon: response.ok = True elif str(ae.emoji) == CANCEL_REACT: response.cancelled = True else: response.cancelled = True except asyncio.TimeoutError: response.timed_out = True try: await confirmation.delete() except discord.NotFound: pass Ongoing.del_ongoing('dialogue', self.user.id) else: response.ongoing = True return response
async def hangman(cmd, pld): """ :param cmd: The command object referenced in the command. :type cmd: sigma.core.mechanics.command.SigmaCommand :param pld: The payload with execution data and details. :type pld: sigma.core.mechanics.payload.CommandPayload """ cache_key = 'hangman_word_cache' word_cache = await cmd.db.cache.get_cache(cache_key) or {} if not word_cache: dict_docs = await cmd.db[cmd.db.db_nam ].DictionaryData.find({}).to_list(None) for ddoc in dict_docs: word = ddoc.get('word') if len(word) > 3 and len(word.split(' ')) == 1 and '-' not in word: word_cache.update({word: ddoc.get('description')}) await cmd.db.cache.set_cache(cache_key, word_cache) if not Ongoing.is_ongoing(cmd.name, pld.msg.channel.id): Ongoing.set_ongoing(cmd.name, pld.msg.channel.id) words = list(word_cache.keys()) gallows = Gallows(secrets.choice(words)) word_description = word_cache.get(gallows.word) kud_reward = gallows.count author = pld.msg.author.display_name hangman_resp = generate_response(gallows) hangman_msg = await pld.msg.channel.send(embed=hangman_resp) def check_answer(msg): """ Checks if the answer message is correct. :type msg: discord.Message :rtype: bool """ if pld.msg.channel.id != msg.channel.id: return if pld.msg.author.id != msg.author.id: return if len(msg.content) == 1: if msg.content.isalpha(): correct = True else: correct = False else: correct = False return correct finished = False timeout = False while not timeout and not finished: try: answer_message = await cmd.bot.wait_for('message', check=check_answer, timeout=30) letter = answer_message.content.lower() if letter in gallows.word: if letter not in gallows.right_letters: gallows.right_letters.append(letter) else: if letter.upper() not in gallows.wrong_letters: gallows.wrong_letters.append(letter.upper()) gallows.use_part() hangman_msg = await send_hangman_msg( pld.msg, hangman_msg, generate_response(gallows)) finished = gallows.victory or gallows.dead except asyncio.TimeoutError: timeout = True timeout_title = '🕙 Time\'s up!' timeout_embed = discord.Embed(color=0x696969, title=timeout_title) timeout_embed.add_field(name=f'It was {gallows.word}.', value=word_description) await pld.msg.channel.send(embed=timeout_embed) if gallows.dead: lose_title = f'💥 Ooh, sorry {author}, it was {gallows.word}.' final_embed = discord.Embed(color=0xff3300, title=lose_title) await pld.msg.channel.send(embed=final_embed) elif gallows.victory: await cmd.db.add_resource(pld.msg.author.id, 'currency', kud_reward, cmd.name, pld.msg) currency = cmd.bot.cfg.pref.currency win_title = f'🎉 Correct, {author}, it was {gallows.word}. You won {kud_reward} {currency}!' win_embed = discord.Embed(color=0x77B255, title=win_title) await pld.msg.channel.send(embed=win_embed) if Ongoing.is_ongoing(cmd.name, pld.msg.channel.id): Ongoing.del_ongoing(cmd.name, pld.msg.channel.id) else: ongoing_error = GenericResponse( 'There is one already ongoing.').error() await pld.msg.channel.send(embed=ongoing_error)
async def connect_four_mechanics(ev, pld): """ :param ev: The event object referenced in the event. :type ev: sigma.core.mechanics.event.SigmaEvent :param pld: The event payload data to process. :type pld: sigma.core.mechanics.payload.RawReactionPayload """ payload = pld.raw uid = payload.user_id cid = payload.channel_id mid = payload.message_id emoji = payload.emoji channel = await ev.bot.get_channel(cid) try: guild = channel.guild except AttributeError: guild = None if guild: # noinspection PyTypeChecker game: ConnectFourGame = await cf_cache.get_cache(mid) if game: if Ongoing.is_ongoing('cf_ongoing_turn', cid): return Ongoing.set_ongoing('cf_ongoing_turn', cid) try: message = await channel.fetch_message(mid) except (discord.NotFound, discord.Forbidden): message = None if message: if ev.event_type == 'raw_reaction_add': if str(emoji.name) in nums and uid == game.current_turn.id: user_av = user_avatar(game.p_one) await check_emotes(ev.bot, message) piece = game.po_piece if game.current_turn.id == game.p_one.id else game.pt_piece opponent = message.guild.me if game.is_bot else game.p_two next_player = game.p_one if game.current_turn != game.p_one else opponent rows = game.board.edit(nums.index(str(emoji.name)), piece) board_resp = generate_response(user_av, next_player, rows) board_msg = await send_board_msg( channel, message, board_resp) full, winner, win = game.board.winner finished = win or full if not finished: if game.is_bot: # Bot takes turn await asyncio.sleep(2) game.last_bot_move = bot_choice = game.board.bot_move( game.last_bot_move) rows = game.board.edit(bot_choice, game.pt_piece) board_resp = generate_response( user_av, game.p_one, rows) await send_board_msg(channel, board_msg, board_resp) full, winner, win = game.board.winner finished = win or full else: if game.current_turn == game.p_one: game.current_turn = game.p_two else: game.current_turn = game.p_one if finished: if winner: if game.is_bot: if winner == getattr(game.board, piece): color, icon, resp = 0x3B88C3, '💎', 'You win' else: color, icon, resp = 0x292929, '💣', 'You lose' else: color, icon, resp = 0x3B88C3, '💎', f'{game.current_turn.display_name} wins' else: color, icon, resp = 0xFFCC4D, '🔥', 'It\'s a draw' response = discord.Embed(color=color, title=f'{icon} {resp}!') await channel.send(embed=response) await cf_cache.del_cache(mid) if Ongoing.is_ongoing('connectfour', channel.id): Ongoing.del_ongoing('connectfour', channel.id) game.expiry = arrow.utcnow().int_timestamp + 120 if Ongoing.is_ongoing('cf_ongoing_turn', cid): Ongoing.del_ongoing('cf_ongoing_turn', cid)
async def bazaar(cmd, pld): """ :param cmd: The command object referenced in the command. :type cmd: sigma.core.mechanics.command.SigmaCommand :param pld: The payload with execution data and details. :type pld: sigma.core.mechanics.payload.CommandPayload """ author_stamp = arrow.get(pld.msg.author.created_at).float_timestamp current_stamp = arrow.utcnow().float_timestamp time_diff = current_stamp - author_stamp if time_diff > 2592000: if not Ongoing.is_ongoing(cmd.name, pld.msg.author.id): Ongoing.set_ongoing(cmd.name, pld.msg.author.id) item_core = await get_item_core(cmd.db) doc = await get_active_shop(cmd.db, pld.msg.author.id) if not doc: doc = await generate_shop(cmd.db, pld.msg.author.id) currency = cmd.bot.cfg.pref.currency lines = [] keys = ['fish', 'plant', 'animal'] for (kx, key) in enumerate(keys): available = not await has_purchased(cmd.db, pld.msg.author.id, key) item = item_core.get_item_by_file_id(doc.get(key)) if available: multi = price_multi(item.file_id) price = int(item.value * multi) item_name = f"{item.icon} {item.rarity_name.title()} {item.name}: **{price} {currency}**" else: item_name = f"{item.icon} ~~{item.rarity_name.title()} {item.name}~~" line = f"**{kx + 1}**: {item_name}" lines.append(line) question = discord.Embed(color=0xffac33, title='🪙 The Item Bazaar') question.description = '\n'.join(lines) dialogue = DialogueCore(cmd.bot, pld.msg, question) dresp = await dialogue.int_dialogue(1, len(keys)) if dresp.ok and dresp.value is not None: key = keys[dresp.value - 1] item = item_core.get_item_by_file_id(doc.get(key)) available = not await has_purchased(cmd.db, pld.msg.author.id, key) if available: curr = (await cmd.db.get_resource(pld.msg.author.id, 'currency')).current multi = price_multi(item.file_id) price = int(item.value * multi) if curr >= price: await cmd.db.del_resource(pld.msg.author.id, 'currency', price, cmd.name, pld.msg) data_for_inv = item.generate_inventory_item() await cmd.db.add_to_inventory(pld.msg.author.id, data_for_inv) await track_purchase(cmd.db, pld.msg.author.id, key, item.file_id, price) await item_core.add_item_statistic( cmd.db, item, pld.msg.author) await cmd.db.add_resource(pld.msg.author.id, 'items', 1, cmd.name, pld.msg, True) response = GenericResponse( f"You have purchased a {item.name} for {price} {currency}." ).ok() else: response = discord.Embed( color=0xa7d28b, title=f'💸 You don\'t have enough {currency}.') else: response = GenericResponse( 'One per customer please.').error() else: response = dresp.generic('bazaar') if Ongoing.is_ongoing(cmd.name, pld.msg.author.id): Ongoing.del_ongoing(cmd.name, pld.msg.author.id) else: response = GenericResponse( 'You already have a bazaar open.').error() else: response = GenericResponse( 'Sorry, your account is too young to visit the bazaar.').error() response.set_author(name=pld.msg.author.display_name, icon_url=user_avatar(pld.msg.author)) await pld.msg.channel.send(embed=response)
async def forage(cmd, pld): """ :param cmd: The command object referenced in the command. :type cmd: sigma.core.mechanics.command.SigmaCommand :param pld: The payload with execution data and details. :type pld: sigma.core.mechanics.payload.CommandPayload """ ongoing = Ongoing.is_ongoing('profession', pld.msg.author.id) if not ongoing: Ongoing.set_ongoing('profession', pld.msg.author.id) item_core = await get_item_core(cmd.db) if not await cmd.bot.cool_down.on_cooldown('profession', pld.msg.author): upgrade_file = await cmd.bot.db.get_profile( pld.msg.author.id, 'upgrades') or {} inv = await cmd.db.get_inventory(pld.msg.author.id) storage = upgrade_file.get('storage', 0) inv_limit = 64 + (8 * storage) if len(inv) < inv_limit: base_cooldown = 20 stamina = upgrade_file.get('stamina', 0) cooldown = int(base_cooldown - ((base_cooldown / 100) * ((stamina * 0.5) / (1.25 + (0.01 * stamina))))) cooldown = 2 if cooldown < 2 else cooldown await cmd.bot.cool_down.set_cooldown('profession', pld.msg.author, cooldown) rarity = await item_core.roll_rarity( await cmd.bot.db.get_profile(pld.msg.author.id)) if pld.args: if pld.msg.author.id in cmd.bot.cfg.dsc.owners: try: if int(pld.args[0]) <= 9: rarity = int(pld.args[0]) except ValueError: pass item = item_core.pick_item_in_rarity('plant', rarity) connector = 'a' if item.rarity_name[0].lower() in ['a', 'e', 'i', 'o', 'u']: connector = 'an' if rarity == 0: if item.name[0].lower() in ['a', 'e', 'i', 'o', 'u']: connector = 'an' response_title = f'{item.icon} You found {connector} {item.name} and threw it away!' response = discord.Embed(color=item.color, title=response_title) else: dialogue = DialogueCore(cmd.bot, pld.msg, None) dresp = await dialogue.item_dialogue( item_icons.get(item.type.lower()), item) if dresp.ok: response_title = f'{item.icon} You found {connector} {item.rarity_name} {item.name}!' data_for_inv = item.generate_inventory_item() await cmd.db.add_to_inventory(pld.msg.author.id, data_for_inv) await item_core.add_item_statistic( cmd.db, item, pld.msg.author) await cmd.db.add_resource(pld.msg.author.id, 'items', 1, cmd.name, pld.msg, True) await cmd.db.add_resource(pld.msg.author.id, 'plant', 1, cmd.name, pld.msg, True) response = discord.Embed(color=item.color, title=response_title) else: if dresp.timed_out: response_title = f'🕙 You forgot where the {item.rarity_name} {item.type.lower()} is...' response = discord.Embed(color=0x696969, title=response_title) elif dresp.cancelled: response_title = '❌ Oh no... You dug too hard and hurt the plant...' response = discord.Embed(color=0xBE1931, title=response_title) else: response = dresp.generic('foraging') else: response = GenericResponse('Your inventory is full.').error() else: timeout = await cmd.bot.cool_down.get_cooldown( 'profession', pld.msg.author) response = discord.Embed( color=0x696969, title=f'🕙 You are resting for another {timeout} seconds.') Ongoing.del_ongoing('profession', pld.msg.author.id) else: response = GenericResponse( "Can't do multiple professions at once.").warn() response.set_author(name=pld.msg.author.display_name, icon_url=user_avatar(pld.msg.author)) await pld.msg.channel.send(embed=response)
async def marketbuy(cmd, pld): """ :param cmd: The command object referenced in the command. :type cmd: sigma.core.mechanics.command.SigmaCommand :param pld: The payload with execution data and details. :type pld: sigma.core.mechanics.payload.CommandPayload """ if await cmd.db.is_sabotaged(pld.msg.author.id): response = GenericResponse('Quarantined users can\'t use the market.').denied() await pld.msg.channel.send(embed=response) return author_stamp = arrow.get(pld.msg.author.created_at).float_timestamp current_stamp = arrow.utcnow().float_timestamp time_diff = current_stamp - author_stamp if time_diff > 2592000: if pld.args: if not Ongoing.is_ongoing(cmd.name, pld.msg.author.id): Ongoing.set_ongoing(cmd.name, pld.msg.author.id) ic = await get_item_core(cmd.db) lookup = ' '.join(pld.args) check_token = len(pld.args) == 1 item = ic.get_item_by_name(lookup) if check_token and item is None: me = await MarketEntry.find(cmd.db, token=lookup) if me: item = ic.get_item_by_file_id(me.item) else: if item is not None: me = await MarketEntry.find(cmd.db, item=item.file_id) else: me = None if me: await me.delete(cmd.db) self_buy = me.uid == pld.msg.author.id curr = cmd.bot.cfg.pref.currency action = 'Retract' if self_buy else 'Buy' questitle = f'❔ {action} the {item.rarity_name} {item.name} for {me.price} {curr}?' stamp = arrow.get(me.stamp).format('DD. MMM. YYYY HH:mm:ss') quesbed = discord.Embed(color=0xf9f9f9, title=questitle) quesbed.description = f'Market entry {me.token} submitted by {me.uname} on {stamp}.' if self_buy: quesbed.set_footer(text="Retracting the item does not pay its price or tax.") dialogue = DialogueCore(cmd.bot, pld.msg, quesbed) dresp = await dialogue.bool_dialogue() if dresp.ok: kud = (await cmd.db.get_resource(pld.msg.author.id, 'currency')).current if self_buy: data_for_inv = item.generate_inventory_item() await cmd.db.add_to_inventory(pld.msg.author.id, data_for_inv) response = GenericResponse(f'Retracted the {item.rarity_name} {item.name}.').ok() else: if kud >= me.price: await cmd.db.del_resource(pld.msg.author.id, 'currency', me.price, cmd.name, pld.msg) profit = int(me.price * (1 - (MARKET_TAX_PERCENT / 100))) await cmd.db.add_resource(me.uid, 'currency', profit, cmd.name, pld.msg, ranked=False) await cmd.db.add_resource( cmd.bot.user.id, 'currency', me.price - profit, cmd.name, pld.msg, ranked=False ) data_for_inv = item.generate_inventory_item() await cmd.db.add_to_inventory(pld.msg.author.id, data_for_inv) response = GenericResponse( f'Purchased the {item.rarity_name} {item.name} for {me.price} {curr}.' ).ok() else: await me.save(cmd.db) response = discord.Embed(color=0xa7d28b, title=f'💸 You don\'t have enough {curr}.') else: await me.save(cmd.db) response = dresp.generic('market purchase') else: response = GenericResponse('Couldn\'t find any entries for that.').not_found() if Ongoing.is_ongoing(cmd.name, pld.msg.author.id): Ongoing.del_ongoing(cmd.name, pld.msg.author.id) else: response = GenericResponse('You already have a market purchase open.').error() else: response = GenericResponse('Not enough arguments, I need a price and item name.').error() else: response = GenericResponse('Sorry, your account is too young to use the market.').error() await pld.msg.channel.send(embed=response)
async def exportincidents(cmd, pld): """ :param cmd: The command object referenced in the command. :type cmd: sigma.core.mechanics.command.SigmaCommand :param pld: The payload with execution data and details. :type pld: sigma.core.mechanics.payload.CommandPayload """ file = None if pld.msg.author.permissions_in(pld.msg.channel).manage_messages: if not Ongoing.is_ongoing(cmd.name, pld.msg.guild.id): Ongoing.set_ongoing(cmd.name, pld.msg.guild.id) icore = get_incident_core(cmd.db) response, target = None, None identifier, incidents = None, None title = '🗃️ Gathering all ' if pld.args: if len(pld.args) == 2: identifier = pld.args[0].lower() if (pld.msg.mentions or identifier == 'variant') and identifier in identifiers: if identifier == 'moderator': target = pld.msg.mentions[0] incidents = await icore.get_all_by_mod(pld.msg.guild.id, target.id) title += f'incidents issued by {target.name}.' elif identifier == 'target': target = pld.msg.mentions[0] incidents = await icore.get_all_by_target(pld.msg.guild.id, target.id) title += f'incidents for {target.name}.' else: target = pld.args[1].lower() if target in variants: incidents = await icore.get_all_by_variant(pld.msg.guild.id, target) title += f'{target} incidents.' else: response = GenericResponse('Invalid variant.').error() else: response = GenericResponse('Invalid identifier.').error() else: incidents = await icore.get_all(pld.msg.guild.id) title += 'incidents.' if not response: if incidents: response = discord.Embed(color=0x226699, title=title) response.set_footer(text='A text file will be sent to you shortly.') if identifier: modifier = f'{identifier.title()}: {target.title() if identifier == "variant" else target.name}' else: modifier = 'All' file_name = make_export_file(pld.msg.guild.name, incidents, modifier) file = discord.File(f'cache/{file_name}', file_name) else: if identifier: response = GenericResponse(f'No incidents found for that {identifier}.').error() else: response = GenericResponse('This server has no incidents.').error() else: response = GenericResponse('There is already one ongoing.').error() else: response = GenericResponse('Access Denied. Manage Messages needed.').denied() if Ongoing.is_ongoing(cmd.name, pld.msg.guild.id): Ongoing.del_ongoing(cmd.name, pld.msg.guild.id) await pld.msg.channel.send(embed=response) if file: try: await pld.msg.author.send(file=file) except (discord.NotFound, discord.Forbidden): denied_response = GenericResponse('I was unable to DM you, please adjust your settings.').error() await pld.msg.channel.send(pld.msg.author.mention, embed=denied_response)
async def sequencegame(cmd, pld): """ :param cmd: The command object referenced in the command. :type cmd: sigma.core.mechanics.command.SigmaCommand :param pld: The payload with execution data and details. :type pld: sigma.core.mechanics.payload.CommandPayload """ if Ongoing.is_ongoing(cmd.name, pld.msg.author.id): ongoing_error = GenericResponse( 'There is already one ongoing.').error() await pld.msg.channel.send(embed=ongoing_error) return try: Ongoing.set_ongoing(cmd.name, pld.msg.author.id) chosen = [secrets.choice(first_symbols) for _ in range(4)] title = f'🎯 {pld.msg.author.display_name}, you have 90 seconds for each attempt.' desc = f'Symbols you can use: {"".join(first_symbols)}' start_embed = discord.Embed(color=0xf9f9f9) start_embed.add_field(name=title, value=desc) await pld.msg.channel.send(embed=start_embed) def answer_check(msg): """ :type msg: discord.Message :rtype: bool """ if pld.msg.author.id != msg.author.id: return if pld.msg.channel.id != msg.channel.id: return message_args = [ char for char in msg.content if char in all_symbols ] if len(message_args) != 4: return for arg in message_args: if arg in all_symbols: return True finished = False victory = False timeout = False tries = 0 while not finished and tries < 6: try: answer = await cmd.bot.wait_for('message', check=answer_check, timeout=90) correct, results = check_answer(answer.content, chosen) tries += 1 if correct: finished = True victory = True currency = cmd.bot.cfg.pref.currency await cmd.db.add_resource(answer.author.id, 'currency', 50, cmd.name, pld.msg) win_title = f'🎉 Correct, {answer.author.display_name}. You won 50 {currency}!' win_embed = discord.Embed(color=0x77B255, title=win_title) await pld.msg.channel.send(embed=win_embed) else: attempt_title = f'💣 {answer.author.display_name} {tries}/6: {"".join(results)}' attempt_embed = discord.Embed(color=0x262626, title=attempt_title) await pld.msg.channel.send(embed=attempt_embed) except asyncio.TimeoutError: finished = True victory = False timeout = True timeout_title = f'🕙 Time\'s up {pld.msg.author.display_name}! It was {"".join(chosen)}' timeout_embed = discord.Embed(color=0x696969, title=timeout_title) await pld.msg.channel.send(embed=timeout_embed) if not victory and not timeout: lose_title = f'💥 Ooh, sorry {pld.msg.author.display_name}, it was {"".join(chosen)}' final_embed = discord.Embed(color=0xff3300, title=lose_title) await pld.msg.channel.send(embed=final_embed) Ongoing.del_ongoing(cmd.name, pld.msg.author.id) except Exception: if Ongoing.is_ongoing(cmd.name, pld.msg.author.id): Ongoing.del_ongoing(cmd.name, pld.msg.author.id) raise
async def marketsell(cmd, pld): """ :param cmd: The command object referenced in the command. :type cmd: sigma.core.mechanics.command.SigmaCommand :param pld: The payload with execution data and details. :type pld: sigma.core.mechanics.payload.CommandPayload """ if await cmd.db.is_sabotaged(pld.msg.author.id): response = GenericResponse( 'Quarantined users can\'t use the market.').denied() await pld.msg.channel.send(embed=response) return author_stamp = arrow.get(pld.msg.author.created_at).float_timestamp current_stamp = arrow.utcnow().float_timestamp time_diff = current_stamp - author_stamp if time_diff > 2592000: if len(pld.args) >= 2: valid = True try: price = int(pld.args[0]) except ValueError: price = 0 valid = False if valid: ic = await get_item_core(cmd.db) item_lookup = ' '.join(pld.args[1:]) item = ic.get_item_by_name(item_lookup) if item: if not Ongoing.is_ongoing(cmd.name, pld.msg.author.id): Ongoing.set_ongoing(cmd.name, pld.msg.author.id) inv_item = await cmd.db.get_inventory_item( pld.msg.author.id, item.file_id) if inv_item: expiration = arrow.get( arrow.utcnow().int_timestamp + MARKET_LIFETIME).format( 'DD. MMM. YYYY HH:mm UTC') cost = int(price * 0.005) cost = cost if cost else 10 curr = cmd.bot.cfg.pref.currency profit = int(price * (1 - (MARKET_TAX_PERCENT / 100))) questitle = f'❔ Sell the {item.rarity_name} {item.name} for {price} {curr}?' quesbed = discord.Embed(color=0xf9f9f9, title=questitle) desc = f'Listing the item costs **{cost}** {curr}.' desc += f' The market has a {MARKET_TAX_PERCENT}% tax so if your item gets sold,' desc += f' you will get {profit} instead of {price} {curr}.' desc += ' Retracting the item is not taxed.' desc += f' The item will be available until {expiration}.' quesbed.description = desc dialogue = DialogueCore(cmd.bot, pld.msg, quesbed) dresp = await dialogue.bool_dialogue() if dresp.ok: wallet = (await cmd.db.get_resource( pld.msg.author.id, 'currency')).current if wallet >= cost: me = MarketEntry.new( pld.msg.author, item.file_id, price) try: await me.save(cmd.db) await cmd.db.del_resource( pld.msg.author.id, 'currency', cost, cmd.name, pld.msg) await cmd.db.del_from_inventory( pld.msg.author.id, inv_item['item_id']) pfx = cmd.db.get_prefix(pld.settings) desc = f'Placed the {item.rarity_name} {item.name}' desc += f' on the market for {price} {curr}.' desc += f' The listing expiry is {expiration}.' desc += f' Your market entry token is `{me.token}`,' desc += ' it can be bought directly using the' desc += f' `{pfx}marketbuy {me.token}` command.' response = GenericResponse( 'Market entry created.').ok() response.description = desc except OverflowError: response = GenericResponse( "Whoa, that number is way too big!" ).error() else: response = GenericResponse( 'You\'re not able to pay the listing fee.' ).error() else: response = dresp.generic('market sale') else: response = GenericResponse( 'You don\'t have this item in your inventory.' ).not_found() if Ongoing.is_ongoing(cmd.name, pld.msg.author.id): Ongoing.del_ongoing(cmd.name, pld.msg.author.id) else: response = GenericResponse( 'You already have a market sale open.').error() else: response = GenericResponse( 'Couldn\'t find that item, did you spell the name correctly?' ).not_found() else: response = GenericResponse('Invalid arguments.').error() response.description = 'Place the price first, and the item name after that.' else: response = GenericResponse( 'Not enough arguments, I need a price and item name.').error() else: response = GenericResponse( 'Sorry, your account is too young to use the market.').error() await pld.msg.channel.send(embed=response)
async def purge(cmd, pld): """ :param cmd: The command object referenced in the command. :type cmd: sigma.core.mechanics.command.SigmaCommand :param pld: The payload with execution data and details. :type pld: sigma.core.mechanics.payload.CommandPayload """ if pld.msg.author.permissions_in(pld.msg.channel).manage_messages: if not Ongoing.is_ongoing(cmd.name, pld.msg.channel.id): Ongoing.set_ongoing(cmd.name, pld.msg.channel.id) pld.args = [a.lower() for a in pld.args] purge_images = 'attachments' in pld.args purge_emotes = 'emotes' in pld.args until_pin = 'untilpin' in pld.args purge_filter = None for i, arg in enumerate(pld.args): if arg.startswith('content:'): purge_filter = ' '.join([arg.split(':')[1]] + pld.args[i + 1:]) break async def get_limit_and_target(): """ :rtype: int, discord.Member """ user = cmd.bot.user limit = 100 if pld.msg.mentions: user = pld.msg.mentions[0] if len(pld.args) == 2: try: limit = int(pld.args[0]) except ValueError: limit = 100 else: if pld.args: user = None try: limit = int(pld.args[0]) except ValueError: limit = 100 if until_pin: channel_hist = await pld.msg.channel.history(limit=limit ).flatten() for n, log in enumerate(channel_hist): if log.pinned: limit = n - 1 if limit > 100: limit = 100 return limit, user count, target = await get_limit_and_target() def is_emotes(msg): """ :type msg: discord.Message :rtype: bool """ clean = False if msg.content: for piece in msg.content.split(): piece = piece.strip() # matches custom emote if re.search(r'<a?:\w+:\d+>', piece): clean = True # matches global emote elif re.search(r':\w+:', piece): clean = True # matches Unicode emote elif len(piece) == 1 and category(piece) == 'So': clean = True else: clean = False break return clean def purge_target_check(msg): """ :type msg: discord.Message :rtype: bool """ clean = False if not msg.pinned: if msg.author.id == target.id: if purge_images: if msg.attachments: clean = True elif purge_emotes: clean = is_emotes(msg) elif purge_filter: if purge_filter.lower() in msg.content.lower(): clean = True else: clean = True return clean def purge_wide_check(msg): """ :type msg: discord.Message :rtype: bool """ clean = False if not msg.pinned: if purge_images: if msg.attachments: clean = True elif purge_emotes: clean = is_emotes(msg) elif purge_filter: if purge_filter.lower() in msg.content.lower(): clean = True else: clean = True return clean try: await pld.msg.delete() except discord.NotFound: pass deleted = [] # noinspection PyBroadException try: if target: deleted = await pld.msg.channel.purge( limit=count, check=purge_target_check) else: deleted = await pld.msg.channel.purge( limit=count, check=purge_wide_check) except Exception: pass response = GenericResponse(f'Deleted {len(deleted)} Messages').ok() log_embed = generate_log_embed(pld.msg, target, pld.msg.channel, deleted) await log_event(cmd.bot, pld.settings, log_embed, 'log_purges') if Ongoing.is_ongoing(cmd.name, pld.msg.channel.id): Ongoing.del_ongoing(cmd.name, pld.msg.channel.id) try: del_response = await pld.msg.channel.send(embed=response) await asyncio.sleep(5) await del_response.delete() except discord.NotFound: pass return else: response = GenericResponse('There is already one ongoing.').error() else: response = GenericResponse( 'Access Denied. Manage Messages needed.').denied() await pld.msg.channel.send(embed=response)
async def mangachargame(cmd, pld): """ :param cmd: The command object referenced in the command. :type cmd: sigma.core.mechanics.command.SigmaCommand :param pld: The payload with execution data and details. :type pld: sigma.core.mechanics.payload.CommandPayload """ if not Ongoing.is_ongoing(cmd.name, pld.msg.channel.id): try: Ongoing.set_ongoing(cmd.name, pld.msg.channel.id) mal_icon = 'https://myanimelist.cdn-dena.com/img/sp/icon/apple-touch-icon-256.png' wait_embed = discord.Embed(color=0x1d439b) wait_embed.set_author(name='Hunting for a good specimen...', icon_url=mal_icon) working_response = await pld.msg.channel.send(embed=wait_embed) if pld.args: if pld.args[0].lower() == 'hint': hint = True else: hint = False else: hint = False ani_order = secrets.randbelow(3) * 50 if ani_order: ani_top_list_url = f'https://myanimelist.net/topmanga.php?limit={ani_order}' else: ani_top_list_url = 'https://myanimelist.net/topmanga.php' async with aiohttp.ClientSession() as session: async with session.get( ani_top_list_url) as ani_top_list_session: ani_top_list_html = await ani_top_list_session.text() ani_top_list_data = html.fromstring(ani_top_list_html) ani_list_objects = ani_top_list_data.cssselect('.ranking-list') ani_choice = secrets.choice(ani_list_objects) ani_url = ani_choice[1][0].attrib['href'] async with aiohttp.ClientSession() as session: async with session.get( f'{ani_url}/characters') as ani_page_session: ani_page_html = await ani_page_session.text() ani_page_data = html.fromstring(ani_page_html) cover_object = ani_page_data.cssselect('.borderClass a')[0][0] manga_cover = cover_object.attrib['data-src'] manga_title = cover_object.attrib['alt'].strip() character_object_list = ani_page_data.cssselect( '.js-scrollfix-bottom-rel')[0] character_list = [] for char_obj_full in character_object_list[5:]: char_obj_full = char_obj_full.cssselect( 'td.borderClass.bgColor2') if len(char_obj_full) != 2: continue char_obj = char_obj_full[0].cssselect('.fw-n')[0] cover_obj = char_obj_full[1].cssselect('.spaceit_pad small')[0] if 'href' in char_obj.attrib: if cover_obj.text_content().strip() == 'Main': character_list.append(char_obj) char_choice = secrets.choice(character_list) char_url = char_choice.attrib['href'] async with aiohttp.ClientSession() as session: async with session.get(char_url) as char_page_session: char_page_html = await char_page_session.text() char_page_data = html.fromstring(char_page_html) char_img_obj = char_page_data.cssselect('.borderClass')[0][0][0][0] char_img = char_img_obj.attrib['data-src'] char_name = ' '.join( char_img_obj.attrib['alt'].strip().split(', ')) kud_reward = None description = None name_split = char_name.split() for name_piece in name_split: if kud_reward is None: kud_reward = len(name_piece) else: if kud_reward >= len(name_piece): kud_reward = len(name_piece) if hint: kud_reward = kud_reward // 2 scrambled_name = scramble(char_name) description = f'Name: {scrambled_name}' reward_mult = streaks.get(pld.msg.channel.id) or 0 kud_reward = int(kud_reward * (1 + (reward_mult * 2.25) / (1.75 + (0.03 * reward_mult)))) try: await working_response.delete() except discord.NotFound: pass question_embed = discord.Embed(color=0x1d439b) if description: question_embed.description = description question_embed.set_image(url=char_img) question_embed.set_author(name=manga_title, icon_url=manga_cover, url=char_img) footer_text = 'You have 30 seconds to guess it.' if reward_mult: footer_text += f' | Streak: {int(reward_mult)}' question_embed.set_footer(text=footer_text) await pld.msg.channel.send(embed=question_embed) def check_answer(msg): """ :type msg: discord.Message :rtype: bool """ if pld.msg.channel.id == msg.channel.id: if msg.content.lower() in char_name.lower().split(): correct = True elif msg.content.lower() == char_name.lower(): correct = True else: correct = False else: correct = False return correct try: answer_message = await cmd.bot.wait_for('message', check=check_answer, timeout=30) await cmd.db.add_resource(answer_message.author.id, 'currency', kud_reward, cmd.name, pld.msg) author = answer_message.author.display_name currency = cmd.bot.cfg.pref.currency streaks.update({pld.msg.channel.id: reward_mult + 1}) win_title = f'🎉 Correct, {author}, it was {char_name}. You won {kud_reward} {currency}!' win_embed = discord.Embed(color=0x77B255, title=win_title) await pld.msg.channel.send(embed=win_embed) except asyncio.TimeoutError: if pld.msg.channel.id in streaks: streaks.pop(pld.msg.channel.id) timeout_title = f'🕙 Time\'s up! It was {char_name} from {manga_title}...' timeout_embed = discord.Embed(color=0x696969, title=timeout_title) await pld.msg.channel.send(embed=timeout_embed) except (IndexError, KeyError): grab_error = GenericResponse( 'I failed to grab a character, try again.').error() await pld.msg.channel.send(embed=grab_error) if Ongoing.is_ongoing(cmd.name, pld.msg.channel.id): Ongoing.del_ongoing(cmd.name, pld.msg.channel.id) else: ongoing_error = GenericResponse( 'There is already one ongoing.').error() await pld.msg.channel.send(embed=ongoing_error)
async def mathgame(cmd, pld): """ :param cmd: The command object referenced in the command. :type cmd: sigma.core.mechanics.command.SigmaCommand :param pld: The payload with execution data and details. :type pld: sigma.core.mechanics.payload.CommandPayload """ if not Ongoing.is_ongoing(cmd.name, pld.msg.channel.id): Ongoing.set_ongoing(cmd.name, pld.msg.channel.id) if pld.args: try: diff = int(pld.args[0]) if diff < 1: diff = 1 elif diff > 9: diff = 9 except ValueError: diff = 3 else: diff = 3 max_num = diff * 8 easy_operators = ['+', '-'] hard_operators = ['*', '/'] math_operators = easy_operators + hard_operators problem_string = str(secrets.randbelow(max_num)) allotted_time = 7 kud_reward = 2 for x in range(0, diff): num = secrets.randbelow(max_num) + 1 oper = secrets.choice(math_operators) if oper in easy_operators: kud_reward += 1 allotted_time += 3 else: kud_reward += 4 allotted_time += 9 problem_string += f' {oper} {num}' result = round(eval(problem_string), 2) problem_string = problem_string.replace('*', 'x').replace('/', '÷') question_embed = discord.Embed( color=0x3B88C3, title=f'#⃣ You have {allotted_time} seconds.') question_embed.description = f'{problem_string} = ?' await pld.msg.channel.send(embed=question_embed) def check_answer(msg): """ :type msg: discord.Message :rtype: bool """ if pld.msg.channel.id == msg.channel.id: try: an_num = float(msg.content) if an_num == result: correct = True else: correct = False except ValueError: correct = False else: correct = False return correct try: answer_message = await cmd.bot.wait_for('message', check=check_answer, timeout=allotted_time) await cmd.db.add_resource(answer_message.author.id, 'currency', kud_reward, cmd.name, pld.msg) author = answer_message.author.display_name currency = cmd.bot.cfg.pref.currency win_title = f'🎉 Correct, {author}, it was {result}. You won {kud_reward} {currency}!' win_embed = discord.Embed(color=0x77B255, title=win_title) await pld.msg.channel.send(embed=win_embed) except asyncio.TimeoutError: timeout_title = f'🕙 Time\'s up! It was {result}...' timeout_embed = discord.Embed(color=0x696969, title=timeout_title) await pld.msg.channel.send(embed=timeout_embed) if Ongoing.is_ongoing(cmd.name, pld.msg.channel.id): Ongoing.del_ongoing(cmd.name, pld.msg.channel.id) else: ongoing_error = GenericResponse( 'There is already one ongoing.').error() await pld.msg.channel.send(embed=ongoing_error)
async def cook(cmd, pld): """ :param cmd: The command object referenced in the command. :type cmd: sigma.core.mechanics.command.SigmaCommand :param pld: The payload with execution data and details. :type pld: sigma.core.mechanics.payload.CommandPayload """ ongoing = Ongoing.is_ongoing('profession', pld.msg.author.id) if not ongoing: Ongoing.set_ongoing('profession', pld.msg.author.id) recipe_core = await get_recipe_core(cmd.db) item_core = await get_item_core(cmd.db) if pld.args: lookup = ' '.join(pld.args) recipe = recipe_core.find_recipe(lookup) used_items = [] if recipe: req_satisfied = True for ingredient in recipe.ingredients: user_inv = await cmd.db.get_inventory(pld.msg.author.id) in_inventory = False for item in user_inv: if item['item_file_id'] == ingredient.file_id: used_items.append(item) in_inventory = True break if not in_inventory: req_satisfied = False if req_satisfied: cooked_item_data = item_core.get_item_by_name( recipe.name).generate_inventory_item() await cmd.db.add_to_inventory(pld.msg.author.id, cooked_item_data) await item_core.add_item_statistic(cmd.db, recipe, pld.msg.author) for req_item in used_items: if req_item.get('transferred'): cooked_item_data.update({'transferred': True}) await cmd.db.del_from_inventory( pld.msg.author.id, req_item['item_id']) quality = cook_quality[cooked_item_data['quality']] connector = 'a' if quality[0].lower() in ['a', 'e', 'i', 'o', 'u']: connector = 'an' await cmd.db.add_resource(pld.msg.author.id, 'items', 1, cmd.name, pld.msg, True) await cmd.db.add_resource(pld.msg.author.id, recipe.type.lower(), 1, cmd.name, pld.msg, True) head_title = f'{recipe.icon} You made {connector} {quality.lower()} {recipe.name}' response = discord.Embed(color=recipe.color, title=head_title) else: response = GenericResponse( 'You\'re missing ingredients.').error() else: response = GenericResponse('Recipe not found.').not_found() else: response = GenericResponse('Nothing inputted.').error() Ongoing.del_ongoing('profession', pld.msg.author.id) else: response = GenericResponse( "Please wait while your previous item is done being prepared." ).warn() response.set_author(name=pld.msg.author.display_name, icon_url=user_avatar(pld.msg.author)) await pld.msg.channel.send(embed=response)
async def blackjack(cmd, pld): """ :param cmd: The command object referenced in the command. :type cmd: sigma.core.mechanics.command.SigmaCommand :param pld: The payload with execution data and details. :type pld: sigma.core.mechanics.payload.CommandPayload """ if not await cmd.bot.cool_down.on_cooldown(cmd.name, pld.msg.author): if not Ongoing.is_ongoing(cmd.name, pld.msg.channel.id): bet = 10 if pld.args: if pld.args[0].isdigit(): bet = abs(int(pld.args[0])) currency_icon = cmd.bot.cfg.pref.currency_icon currency = cmd.bot.cfg.pref.currency author = pld.msg.author.id current_kud = await cmd.db.get_resource(author, 'currency') current_kud = current_kud.current if current_kud >= bet: Ongoing.set_ongoing(cmd.name, pld.msg.channel.id) await set_blackjack_cd(cmd, pld) bljk = BlackJack(pld.msg) if bljk.check_blackjack(): if Ongoing.is_ongoing(cmd.name, pld.msg.channel.id): Ongoing.del_ongoing(cmd.name, pld.msg.channel.id) await cmd.db.add_resource(author, 'currency', bet * BJ_RATIO, cmd.name, pld.msg, False) title = f'🎉 You got a BlackJack and won {int(bet * BJ_RATIO)} {currency}!' bj_embed = discord.Embed(color=0xDE2A42, title=title) bj_embed.set_footer(text=f'You won {int(100 * BJ_RATIO)}% of your original bet.') await pld.msg.channel.send(embed=bj_embed) return game_embed = bljk.generate_embed() game_msg = await pld.msg.channel.send(embed=game_embed) [await game_msg.add_reaction(e) for e in GAME_EMOTES] def check_emote(reac): """ Checks for a valid message reaction. :type reac: discord.RawReactionActionEvent :rtype: bool """ same_author = reac.user_id == pld.msg.author.id same_message = reac.message_id == game_msg.id valid_reaction = str(reac.emoji) in GAME_EMOTES return same_author and same_message and valid_reaction finished, bust, win = False, False, False while not finished and not bust and not win: try: ae = await cmd.bot.wait_for('raw_reaction_add', timeout=60, check=check_emote) # noinspection PyBroadException try: await game_msg.remove_reaction(ae.emoji, pld.msg.author) except Exception: pass if str(ae.emoji) == '🔵': game_msg = await bljk.add_card(game_msg) finished = bljk.check_bust() elif str(ae.emoji) == '🔴': finished = True elif str(ae.emoji) == '⏫': if len(bljk.player_hand) == 2: if current_kud >= bet * 2: bet += bet game_msg = await bljk.add_card(game_msg) finished = True else: embed = bljk.generate_embed() embed.set_footer(text=f'Insufficient {currency} to double down.') game_msg = await send_game_msg(pld.msg.channel, game_msg, embed) else: embed = bljk.generate_embed() embed.set_footer(text='You can only double down on your first turn.') game_msg = await send_game_msg(pld.msg.channel, game_msg, embed) except asyncio.TimeoutError: if Ongoing.is_ongoing(cmd.name, pld.msg.channel.id): Ongoing.del_ongoing(cmd.name, pld.msg.channel.id) await cmd.db.del_resource(pld.msg.author.id, 'currency', bet, cmd.name, pld.msg) timeout_title = f'🕙 Time\'s up {pld.msg.author.display_name}!' timeout_embed = discord.Embed(color=0x696969, title=timeout_title) timeout_embed.set_footer(text=f'You lost {bet} {currency}.') await pld.msg.channel.send(embed=timeout_embed) return await bljk.dealer_hit(game_msg) if bljk.check_bust(): await cmd.db.del_resource(pld.msg.author.id, 'currency', bet, cmd.name, pld.msg) title = f'💣 Your hand bust and you lost {bet} {currency}.' response = discord.Embed(color=0x232323, title=title) elif bljk.check_dealer_bust(): await cmd.db.add_resource(pld.msg.author.id, 'currency', bet, cmd.name, pld.msg, False) title = f'{currency_icon} The dealer bust and you won {bet} {currency}!' response = discord.Embed(color=0x66cc66, title=title) elif bljk.check_push(): title = '🔵 You pushed and broke even.' response = discord.Embed(color=0x3B88C3, title=title) elif bljk.check_win(): await cmd.db.add_resource(pld.msg.author.id, 'currency', bet, cmd.name, pld.msg, False) title = f'{currency_icon} You beat the dealer and won {bet} {currency}!' response = discord.Embed(color=0x66cc66, title=title) else: await cmd.db.del_resource(pld.msg.author.id, 'currency', bet, cmd.name, pld.msg) title = f'💣 The dealer won and you lost {bet} {currency}.' response = discord.Embed(color=0x232323, title=title) if Ongoing.is_ongoing(cmd.name, pld.msg.channel.id): Ongoing.del_ongoing(cmd.name, pld.msg.channel.id) else: response = discord.Embed(color=0xa7d28b, title=f'💸 You don\'t have {bet} {currency}.') else: response = GenericResponse('There is already one ongoing.').error() else: timeout = await cmd.bot.cool_down.get_cooldown(cmd.name, pld.msg.author) response = discord.Embed(color=0x696969, title=f'🕙 You can play again in {timeout} seconds.') await pld.msg.channel.send(embed=response)