async def lookup_settings(self, ctx, *args): """This command has been replaced by `!servsettings`. If you're used to it, it still works like before!""" guild_settings = await ctx.get_server_settings() if not args: settings_ui = ui.ServerSettingsUI.new(ctx.bot, owner=ctx.author, settings=guild_settings, guild=ctx.guild) await settings_ui.send_to(ctx) return # old deprecated CLI behaviour args = argparse(args) out = [] if 'req_dm_monster' in args: setting = get_positivity(args.last('req_dm_monster', True)) guild_settings.lookup_dm_required = setting out.append(f'req_dm_monster set to {setting}!') if 'pm_dm' in args: setting = get_positivity(args.last('pm_dm', True)) guild_settings.lookup_pm_dm = setting out.append(f'pm_dm set to {setting}!') if 'pm_result' in args: setting = get_positivity(args.last('pm_result', True)) guild_settings.lookup_pm_result = setting out.append(f'pm_result set to {setting}!') if out: await guild_settings.commit(ctx.bot.mdb) await ctx.send("Lookup settings set:\n" + '\n'.join(out)) else: await ctx.send(f"No settings found. Try using `{ctx.prefix}lookup_settings` to open an interactive menu.")
async def transferchar(self, ctx, user: discord.Member): """Gives a copy of the active character to another user.""" character: Character = await Character.from_ctx(ctx) overwrite = '' conflict = await self.bot.mdb.characters.find_one({ "owner": str(user.id), "upstream": character.upstream }) if conflict: overwrite = "**WARNING**: This will overwrite an existing character." await ctx.send( f"{user.mention}, accept a copy of {character.name}? (Type yes/no)\n{overwrite}" ) try: m = await self.bot.wait_for( 'message', timeout=300, check=lambda msg: msg.author == user and msg.channel == ctx. channel and get_positivity(msg.content) is not None) except asyncio.TimeoutError: m = None if m is None or not get_positivity(m.content): return await ctx.send("Transfer not confirmed, aborting.") character.owner = str(user.id) await character.commit(ctx) await ctx.send( f"Copied {character.name} to {user.display_name}'s storage.")
async def lookup_settings(self, ctx, *, args: str): """Changes settings for the lookup module. __Valid Settings__ -req_dm_monster [True/False] - Requires a Game Master role to show a full monster stat block. -pm_dm [True/False] - PMs a DM the full monster stat block instead of outputting to chat, if req_dm_monster is True. -pm_result [True/False] - PMs the result of the lookup to reduce spam. """ args = shlex.split(args.lower()) guild_id = str(ctx.guild.id) guild_settings = await self.bot.mdb.lookupsettings.find_one({"server": guild_id}) if guild_settings is None: guild_settings = {} out = "" if '-req_dm_monster' in args: try: setting = args[args.index('-req_dm_monster') + 1] except IndexError: setting = 'True' setting = get_positivity(setting) guild_settings['req_dm_monster'] = setting if setting is not None else True out += 'req_dm_monster set to {}!\n'.format(str(guild_settings['req_dm_monster'])) if '-pm_dm' in args: try: setting = args[args.index('-pm_dm') + 1] except IndexError: setting = 'True' setting = get_positivity(setting) guild_settings['pm_dm'] = setting if setting is not None else True out += 'pm_dm set to {}!\n'.format(str(guild_settings['pm_dm'])) if '-pm_result' in args: try: setting = args[args.index('-pm_result') + 1] except IndexError: setting = 'False' setting = get_positivity(setting) guild_settings['pm_result'] = setting if setting is not None else False out += 'pm_result set to {}!\n'.format(str(guild_settings['pm_result'])) if '-srd' in args: try: setting = args[args.index('-srd') + 1] except IndexError: setting = 'False' setting = get_positivity(setting) guild_settings['srd'] = setting if setting is not None else False out += 'srd set to {}!\n'.format(str(guild_settings['srd'])) if guild_settings: await self.bot.mdb.lookupsettings.update_one({"server": guild_id}, {"$set": guild_settings}, upsert=True) await ctx.send("Lookup settings set:\n" + out) else: await ctx.send("No settings found. Make sure your syntax is correct.")
async def lookup_settings(self, ctx, *, args: str): """Changes settings for the lookup module. Usage: !lookup_settings -req_dm_monster True Current settings are: -req_dm_monster [True/False] - Requires a Game Master role to show a full monster stat block. -pm_result [True/False] - PMs the result of the lookup to reduce spam. -srd [True/False] - toggles SRD lookup restriction in a server.""" args = shlex.split(args.lower()) guild_id = ctx.message.server.id guild_settings = await self.bot.mdb.lookupsettings.find_one( {"server": guild_id}) if guild_settings is None: guild_settings = {} out = "" if '-req_dm_monster' in args: try: setting = args[args.index('-req_dm_monster') + 1] except IndexError: setting = 'True' setting = get_positivity(setting) guild_settings[ 'req_dm_monster'] = setting if setting is not None else True out += 'req_dm_monster set to {}!\n'.format( str(guild_settings['req_dm_monster'])) if '-pm_result' in args: try: setting = args[args.index('-pm_result') + 1] except IndexError: setting = 'False' setting = get_positivity(setting) guild_settings[ 'pm_result'] = setting if setting is not None else False out += 'pm_result set to {}!\n'.format( str(guild_settings['pm_result'])) if '-srd' in args: try: setting = args[args.index('-srd') + 1] except IndexError: setting = 'False' setting = get_positivity(setting) guild_settings['srd'] = setting if setting is not None else False out += 'srd set to {}!\n'.format(str(guild_settings['srd'])) if guild_settings: await self.bot.mdb.lookupsettings.update_one( {"server": guild_id}, {"$set": guild_settings}, upsert=True) await self.bot.say("Lookup settings set:\n" + out) else: await self.bot.say( "No settings found. Make sure your syntax is correct.")
async def character_delete(self, ctx, *, name): """Deletes a character.""" user_characters = await self.bot.mdb.characters.find( { "owner": str(ctx.author.id) }, ['name', 'upstream']).to_list(None) if not user_characters: return await ctx.send('You have no characters.') selected_char = await search_and_select( ctx, user_characters, name, lambda e: e['name'], selectkey=lambda e: f"{e['name']} (`{e['upstream']}`)") await ctx.send( f"Are you sure you want to delete {selected_char['name']}? (Reply with yes/no)" ) try: reply = await self.bot.wait_for('message', timeout=30, check=auth_and_chan(ctx)) except asyncio.TimeoutError: reply = None reply = get_positivity(reply.content) if reply is not None else None if reply is None: return await ctx.send( 'Timed out waiting for a response or invalid response.') elif reply: await Character.delete(ctx, str(ctx.author.id), selected_char['upstream']) return await ctx.send(f"{selected_char['name']} has been deleted.") else: return await ctx.send("OK, cancelling.")
def set(self, new_value): if self.type == 'color': try: color_val = Color(new_value) r, g, b = color_val.as_rgb_tuple(alpha=False) val = (r << 16) + (g << 8) + b except (ValueError, TypeError): return f'\u274c Invalid {self.description}. ' \ f'Use `{self.ctx.prefix}csettings {self.setting_key} reset` to reset it to {self.default}.' elif self.type == 'number': try: val = int(new_value) except (ValueError, TypeError): return f'\u274c Invalid {self.description}. ' \ f'Use `{self.ctx.prefix}csettings {self.setting_key} reset` to reset it to {self.default}.' elif self.type == 'boolean': try: val = get_positivity(new_value) except AttributeError: return f'\u274c Invalid {self.description}.' \ f'Use `{self.ctx.prefix}csettings {self.setting_key} false` to reset it.' else: log.warning(f"No setting type for {self.type} found") return try: setattr(self.character.options, self.setting_key, val) except ValidationError as e: return f"\u274c Invalid {self.description}: {e!s}.\n" \ f"Use `{self.ctx.prefix}csettings {self.setting_key} reset` to reset it to {self.default}." return f"\u2705 {self.description.capitalize()} set to {self.display_func(val)}.\n"
async def character_delete(self, ctx, *, name): """Deletes a character.""" user_characters = await self.bot.mdb.characters.find({"owner": str(ctx.author.id)}).to_list(None) if not user_characters: return await ctx.send('You have no characters.') _character = await search_and_select(ctx, user_characters, name, lambda e: e.get('stats', {}).get('name', ''), selectkey=lambda e: f"{e['stats'].get('name', '')} (`{e['upstream']}`)") name = _character.get('stats', {}).get('name', 'Unnamed') char_url = _character['upstream'] await ctx.send('Are you sure you want to delete {}? (Reply with yes/no)'.format(name)) try: reply = await self.bot.wait_for('message', timeout=30, check=auth_and_chan(ctx)) except asyncio.TimeoutError: reply = None reply = get_positivity(reply.content) if reply is not None else None if reply is None: return await ctx.send('Timed out waiting for a response or invalid response.') elif reply: # _character = Character(_character, char_url) # if _character.get_combat_id() is not None: # combat = await Combat.from_id(_character.get_combat_id(), ctx) # me = next((c for c in combat.get_combatants() if getattr(c, 'character_id', None) == char_url), # None) # if me: # combat.remove_combatant(me, True) # await combat.commit() await self.bot.mdb.characters.delete_one({"owner": str(ctx.author.id), "upstream": char_url}) return await ctx.send('{} has been deleted.'.format(name)) else: return await ctx.send("OK, cancelling.")
async def lookup_settings(self, ctx, *, args: str): """Changes settings for the lookup module. Usage: !lookup_settings -req_dm_monster True Current settings are: -req_dm_monster [True/False] - Requires a Game Master role to show a full monster stat block. -pm_result [True/False] - PMs the result of the lookup to reduce spam. -srd [True/False] - toggles SRD lookup restriction in a server.""" args = shlex.split(args.lower()) guild_id = ctx.message.server.id self.settings = self.bot.db.not_json_get("lookup_settings", {}) guild_settings = self.settings.get(guild_id, {}) out = "" if '-req_dm_monster' in args: try: setting = args[args.index('-req_dm_monster') + 1] except IndexError: setting = 'True' setting = get_positivity(setting) guild_settings[ 'req_dm_monster'] = setting if setting is not None else True out += 'req_dm_monster set to {}!\n'.format( str(guild_settings['req_dm_monster'])) if '-pm_result' in args: try: setting = args[args.index('-pm_result') + 1] except IndexError: setting = 'False' setting = get_positivity(setting) guild_settings[ 'pm_result'] = setting if setting is not None else False out += 'pm_result set to {}!\n'.format( str(guild_settings['pm_result'])) if '-srd' in args: try: setting = args[args.index('-srd') + 1] except IndexError: setting = 'False' setting = get_positivity(setting) guild_settings['srd'] = setting if setting is not None else False out += 'srd set to {}!\n'.format(str(guild_settings['srd'])) self.settings[guild_id] = guild_settings self.bot.db.not_json_set("lookup_settings", self.settings) await self.bot.say("Lookup settings set:\n" + out)
async def _confirm_overwrite(self, ctx, _id): """Prompts the user if command would overwrite another character. Returns True to overwrite, False or None otherwise.""" conflict = await self.bot.mdb.characters.find_one({"owner": str(ctx.author.id), "upstream": _id}) if conflict: await ctx.channel.send( "Warning: This will overwrite a character with the same ID. Do you wish to continue (reply yes/no)?\n" f"If you only wanted to update your character, run `{ctx.prefix}update` instead.") try: reply = await self.bot.wait_for('message', timeout=30, check=auth_and_chan(ctx)) except asyncio.TimeoutError: reply = None replyBool = get_positivity(reply.content) if reply is not None else None return replyBool return True
async def csettings(self, ctx, *args): """Updates personalization settings for the currently active character. Valid Arguments: `color <hex color>` - Colors all embeds this color. `criton <number>` - Makes attacks crit on something other than a 20. `reroll <number>` - Defines a number that a check will automatically reroll on, for cases such as Halfling Luck. `srslots true/false` - Enables/disables whether spell slots reset on a Short Rest. `embedimage true/false` - Enables/disables whether a character's image is automatically embedded. `critdice <number>` - Adds additional dice for to critical attacks.""" char: Character = await Character.from_ctx(ctx) out = 'Operations complete!\n' index = 0 for arg in args: if arg == 'color': color = list_get(index + 1, None, args) if color is None: current_color = hex(char.get_color()) if char.get_setting( 'color') else "random" out += f'\u2139 Your character\'s current color is {current_color}. ' \ f'Use "{ctx.prefix}csettings color reset" to reset it to random.\n' elif color.lower() == 'reset': char.set_setting('color', None) out += "\u2705 Color reset to random.\n" else: try: color = int(color, base=16) except (ValueError, TypeError): out += f'\u274c Unknown color. Use "{ctx.prefix}csettings color reset" to reset it to random.\n' else: if not 0 <= color <= 0xffffff: out += '\u274c Invalid color.\n' else: char.set_setting('color', color) out += "\u2705 Color set to {}.\n".format( hex(color)) if arg == 'criton': criton = list_get(index + 1, None, args) if criton is None: current = str(char.get_setting( 'criton')) + '-20' if char.get_setting( 'criton') else "20" out += f'\u2139 Your character\'s current crit range is {current}. ' \ f'Use "{ctx.prefix}csettings criton reset" to reset it to 20.\n' elif criton.lower() == 'reset': char.set_setting('criton', None) out += "\u2705 Crit range reset to 20.\n" else: try: criton = int(criton) except (ValueError, TypeError): out += f'\u274c Invalid number. Use "{ctx.prefix}csettings criton reset" to reset it to 20.\n' else: if not 0 < criton <= 20: out += '\u274c Crit range must be between 1 and 20.\n' elif criton == 20: char.set_setting('criton', None) out += "\u2705 Crit range reset to 20.\n" else: char.set_setting('criton', criton) out += "\u2705 Crit range set to {}-20.\n".format( criton) if arg == 'reroll': reroll = list_get(index + 1, None, args) if reroll is None: current = char.get_setting('reroll') out += f'\u2139 Your character\'s current reroll is {current}. ' \ f'Use "{ctx.prefix}csettings reroll reset" to reset it.\n' elif reroll.lower() == 'reset': char.set_setting('reroll', None) out += "\u2705 Reroll reset.\n" else: try: reroll = int(reroll) except (ValueError, TypeError): out += f'\u274c Invalid number. Use "{ctx.prefix}csettings reroll reset" to reset it.\n' else: if not 1 <= reroll <= 20: out += '\u274c Reroll must be between 1 and 20.\n' else: char.set_setting('reroll', reroll) out += "\u2705 Reroll set to {}.\n".format(reroll) if arg == 'critdice': critdice = list_get(index + 1, None, args) if critdice is None: current = char.get_setting('critdice') out += f'\u2139 Extra crit dice are currently set to {current}. ' \ f'Use "{ctx.prefix}csettings critdice reset" to reset it.\n' elif critdice.lower() == 'reset': char.set_setting('critdice', None) out += "\u2705 Extra crit dice reset.\n" else: try: critdice = int(critdice) except (ValueError, TypeError): out += f'\u274c Invalid number. Use "{ctx.prefix}csettings critdice reset" to reset it.\n' else: if not 0 <= critdice <= 20: out += f'\u274c Extra crit dice must be between 1 and 20. Use "{ctx.prefix}csettings critdice reset" to reset it.\n' else: char.set_setting('critdice', critdice) out += "\u2705 Extra crit dice set to {}.\n".format( critdice) if arg == 'srslots': srslots = list_get(index + 1, None, args) if srslots is None: out += '\u2139 Short rest slots are currently {}.\n' \ .format("enabled" if char.get_setting('srslots') else "disabled") else: try: srslots = get_positivity(srslots) except AttributeError: out += f'\u274c Invalid input. Use "{ctx.prefix}csettings srslots false" to reset it.\n' else: char.set_setting('srslots', srslots) out += "\u2705 Short Rest slots {}.\n".format( "enabled" if char.get_setting('srslots' ) else "disabled") if arg == 'embedimage': embedimage = list_get(index + 1, None, args) if embedimage is None: out += '\u2139 Embed Image is currently {}.\n' \ .format("enabled" if char.get_setting('embedimage') else "disabled") else: try: embedimage = get_positivity(embedimage) except AttributeError: out += f'\u274c Invalid input. Use "{ctx.prefix}csettings embedimage true" to reset it.\n' else: char.set_setting('embedimage', embedimage) out += "\u2705 Embed Image {}.\n".format( "enabled" if char.get_setting('embedimage' ) else "disabled") index += 1 await char.commit(ctx) await ctx.send(out)
import os import sys import traceback import discord import motor.motor_asyncio from aiohttp import ClientOSError, ClientResponseError from discord.errors import Forbidden, HTTPException, InvalidArgument, NotFound from discord.ext import commands from discord.ext.commands.errors import CommandInvokeError from cogs5e.models.errors import AvraeException, EvaluationError from utils.functions import discord_trim, gen_error_message, get_positivity from utils.redisIO import RedisIO TESTING = get_positivity(os.environ.get("TESTING", False)) if 'test' in sys.argv: TESTING = True SHARD_COUNT = None if not TESTING else 1 prefix = '!' if not TESTING else '#' # -----COGS----- DYNAMIC_COGS = [ "cogs5e.dice", "cogs5e.charGen", "cogs5e.homebrew", "cogs5e.lookup", "cogs5e.pbpUtils", "cogs5e.gametrack", "cogs5e.initTracker", "cogs5e.sheetManager", "cogsmisc.customization" ] STATIC_COGS = [ "cogsmisc.core", "cogsmisc.publicity", "cogsmisc.stats", "cogsmisc.repl", "cogsmisc.adminUtils", "cogsmisc.permissions", "utils.help" ]
async def create_quest_role(self, ctx): """ Creates a Role for Quests The role created will have the default permissions that \@everyone has at the time of creation. """ author = ctx.author channel = ctx.channel user_mention = discord.AllowedMentions(users=[ctx.author]) color_converter = commands.ColorConverter() def chk(m): return m.author == author and m.channel == channel async def prompt(message: discord.Message, ebd: discord.Embed, content: str, mentions: discord.AllowedMentions = None): if content: ebd.description = content await message.edit(embed=ebd, allowed_mentions=mentions) result = await self.bot.wait_for('message', check=chk, timeout=60) if result is None: return result content = result.content await try_delete(result) return content, ebd def check_stop(content): if content.lower() in ['stop', 'cancel', 'quit', 'exit']: return True else: return False async def stop(question_msg): await try_delete(question_msg) await ctx.send('Operation Cancelled, stopping.', delete_after=10) embed = create_default_embed(ctx) embed.title = 'Quest Role Creation' question_msg = await ctx.send(embed=embed) role_name, embed = await prompt( question_msg, embed, f'{ctx.author.mention}, what would you like this role to be called?', mentions=user_mention) if check_stop(role_name): return await stop(question_msg) role_color, embed = await prompt( question_msg, embed, f'Role Name: `{role_name}`\nWhat color would you like this role to be?' ) if check_stop(role_color): return await stop(question_msg) try: color = await color_converter.convert(ctx=ctx, argument=role_color.lower()) except (commands.CommandError, commands.BadColourArgument): await try_delete(question_msg) return await ctx.send('Invalid Color provided, exiting.', delete_after=10) embed.color = color confirm_content, embed = await prompt( question_msg, embed, f'Role `{role_name}` with the color of this embed ' f'will be created. Please confirm.') if get_positivity(confirm_content): new_role = await ctx.guild.create_role( name=role_name, color=color, reason='Quest Role Creation') await ctx.send( f'Role {new_role.mention} created.', delete_after=10, allowed_mentions=discord.AllowedMentions(roles=[new_role])) return await try_delete(question_msg) else: return await stop(question_msg)