Example #1
0
    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.")
Example #2
0
    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.")
Example #3
0
    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.")
Example #4
0
    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.")
Example #5
0
    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.")
Example #6
0
 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.")
Example #8
0
    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)
Example #9
0
 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
Example #10
0
    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)
Example #11
0
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"
]
Example #12
0
    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)