Beispiel #1
0
    async def spell(self, ctx, *, name: str):
        """Looks up a spell."""
        choices = await get_spell_choices(ctx, filter_by_license=False)
        spell = await self._lookup_search3(ctx, {'spell': choices}, name)

        embed = EmbedWithAuthor(ctx)
        embed.url = spell.url
        color = embed.colour

        embed.title = spell.name
        school_level = f"{spell.get_level()} {spell.get_school().lower()}" if spell.level > 0 \
            else f"{spell.get_school().lower()} cantrip"
        embed.description = f"*{school_level}. " \
                            f"({', '.join(itertools.chain(spell.classes, spell.subclasses))})*"
        if spell.ritual:
            time = f"{spell.time} (ritual)"
        else:
            time = spell.time

        meta = f"**Casting Time**: {time}\n" \
               f"**Range**: {spell.range}\n" \
               f"**Components**: {spell.components}\n" \
               f"**Duration**: {spell.duration}"
        embed.add_field(name="Meta", value=meta)

        text = spell.description
        higher_levels = spell.higherlevels

        if len(text) > 1020:
            pieces = [text[:1020]] + [
                text[i:i + 2040] for i in range(1020, len(text), 2040)
            ]
        else:
            pieces = [text]

        embed.add_field(name="Description", value=pieces[0], inline=False)

        embed_queue = [embed]
        if len(pieces) > 1:
            for piece in pieces[1:]:
                temp_embed = discord.Embed()
                temp_embed.colour = color
                temp_embed.description = piece
                embed_queue.append(temp_embed)

        if higher_levels:
            add_fields_from_long_text(embed_queue[-1], "At Higher Levels",
                                      higher_levels)

        embed_queue[-1].set_footer(text=f"Spell | {spell.source_str()}")
        if spell.homebrew:
            add_homebrew_footer(embed_queue[-1])

        if spell.image:
            embed_queue[0].set_thumbnail(url=spell.image)

        await Stats.increase_stat(ctx, "spells_looked_up_life")
        destination = await self._get_destination(ctx)
        for embed in embed_queue:
            await destination.send(embed=embed)
Beispiel #2
0
    async def subscribe(self, ctx, url):
        coll_match = re.match(WORKSHOP_ADDRESS_RE, url)
        if coll_match is None:
            return await ctx.send("This is not an Alias Workshop link.")

        if self.before_edit_check:
            await self.before_edit_check(ctx)

        collection_id = coll_match.group(1)
        the_collection = await workshop.WorkshopCollection.from_id(
            ctx, collection_id)
        # private and duplicate logic handled here, also loads aliases/snippets
        if self.is_server:
            await the_collection.set_server_active(ctx)
        else:
            await the_collection.subscribe(ctx)

        embed = EmbedWithAuthor(ctx)
        embed.title = f"Subscribed to {the_collection.name}"
        embed.url = the_collection.url
        embed.description = the_collection.description
        if the_collection.aliases:
            embed.add_field(
                name="Server Aliases" if self.is_server else "Aliases",
                value=", ".join(sorted(a.name
                                       for a in the_collection.aliases)))
        if the_collection.snippets:
            embed.add_field(
                name="Server Snippets" if self.is_server else "Snippets",
                value=", ".join(sorted(a.name
                                       for a in the_collection.snippets)))
        await ctx.send(embed=embed)
Beispiel #3
0
    async def classfeat(self, ctx, *, name: str):
        """Looks up a class feature."""
        choices = compendium.cfeats + compendium.ncfeat_names
        result = await self._lookup_search(ctx, choices, name, lambda e: e['name'], search_type='classfeat')
        if not result:
            return

        embed = EmbedWithAuthor(ctx)
        embed.title = result['name']
        set_maybe_long_desc(embed, result['text'])

        await (await self._get_destination(ctx)).send(embed=embed)
Beispiel #4
0
    async def classfeat(self, ctx, *, name: str):
        """Looks up a class feature."""
        result: SourcedTrait = await self._lookup_search3(ctx, {'class': compendium.cfeats}, name,
                                                          query_type='classfeat')

        embed = EmbedWithAuthor(ctx)
        embed.title = result.name
        embed.url = result.url
        set_maybe_long_desc(embed, result.text)
        handle_source_footer(embed, result, "Class Feature")

        await (await self._get_destination(ctx)).send(embed=embed)
Beispiel #5
0
    async def racefeat(self, ctx, *, name: str):
        """Looks up a racial feature."""
        result: SourcedTrait = await self._lookup_search3(ctx,
                                                          {'race': compendium.rfeats, 'subrace': compendium.subrfeats},
                                                          name, 'racefeat')

        embed = EmbedWithAuthor(ctx)
        embed.title = result.name
        embed.url = result.url
        set_maybe_long_desc(embed, result.text)
        handle_source_footer(embed, result, "Race Feature")

        await (await self._get_destination(ctx)).send(embed=embed)
Beispiel #6
0
    async def subclass(self, ctx, name: str):
        """Looks up a subclass."""
        guild_settings = await self.get_settings(ctx.guild)
        pm = guild_settings.get("pm_result", False)
        srd = guild_settings.get("srd", False)

        destination = ctx.author if pm else ctx.channel

        result, metadata = await search_and_select(ctx, c.subclasses, name, lambda e: e['name'], srd=srd,
                                                   return_metadata=True)

        metadata['srd'] = srd
        await self.add_training_data("subclass", name, result['name'], metadata=metadata)

        if not result.get('srd') and srd:
            return await self.send_srd_error(ctx, result)

        embed = EmbedWithAuthor(ctx)
        embed.title = result['name']
        embed.description = f"*Source: {result['source']}*"

        for level_features in result['subclassFeatures']:
            for feature in level_features:
                for entry in feature['entries']:
                    if not isinstance(entry, dict): continue
                    if not entry.get('type') == 'entries': continue
                    text = parse_data_entry(entry['entries'])
                    embed.add_field(name=entry['name'], value=(text[:1019] + "...") if len(text) > 1023 else text)

        embed.set_footer(text=f"Use {ctx.prefix}classfeat to look up a feature if it is cut off.")

        await destination.send(embed=embed)
Beispiel #7
0
    async def randname(self, ctx, race=None, option=None):
        """Generates a random name, optionally from a given race."""
        if race is None:
            return await ctx.send(f"Your random name: {self.old_name_gen()}")

        embed = EmbedWithAuthor(ctx)
        race_names = await search_and_select(ctx, compendium.names, race, lambda e: e['race'])
        if option is None:
            table = await get_selection(ctx, [(t['name'], t) for t in race_names['tables']])
        else:
            table = await search_and_select(ctx, race_names['tables'], option, lambda e: e['name'])
        embed.title = f"{table['name']} {race_names['race']} Name"
        embed.description = random.choice(table['choices'])
        await ctx.send(embed=embed)
Beispiel #8
0
    async def _non_srd(self, ctx, result, search_type=None):
        if search_type is not None:
            await self.bot.mdb.analytics_nsrd_lookup.update_one({"type": search_type, "name": result.name},
                                                                {"$inc": {"num_lookups": 1}},
                                                                upsert=True)

        embed = EmbedWithAuthor(ctx)
        embed.title = f"{result.name} is not available in the SRD!"
        embed.description = f"Unfortunately, {result.name} is not available in the SRD (what Wizards of the Coast " \
                            f"offers for free). You can see everything that is available in the SRD [here](" \
                            f"http://dnd.wizards.com/articles/features/systems-reference-document-srd).\n\n" \
                            f"In the near future, you will be able to connect your D&D Beyond account to Avrae to " \
                            f"view the non-SRD content you own on D&D Beyond; stay tuned!"
        await ctx.send(embed=embed)
Beispiel #9
0
    async def _view(self, ctx, name):
        collectable = await helpers.get_collectable_named(
            ctx, name, self.personal_cls, self.workshop_cls,
            self.workshop_sub_meth, self.is_alias, self.obj_name,
            self.obj_name_pl, self.name)
        if collectable is None:
            return await ctx.send(f"No {self.obj_name} named {name} found.")
        elif isinstance(collectable, self.personal_cls):  # personal
            out = f'**{name}**: ```py\n{ctx.prefix}{self.obj_copy_command} {collectable.name} {collectable.code}\n```'
            out = out if len(
                out
            ) <= 2000 else f'**{collectable.name}**:\nCommand output too long to display.'
            return await ctx.send(out)
        else:  # collection
            embed = EmbedWithAuthor(ctx)
            the_collection = await collectable.load_collection(ctx)
            owner = await user_from_id(ctx, the_collection.owner)
            embed.title = f"{ctx.prefix}{name}" if self.is_alias else name
            embed.description = f"From {the_collection.name} by {owner}.\n" \
                                f"[View on Workshop]({the_collection.url})"
            embed.add_field(name="Help",
                            value=collectable.docs or "No documentation.",
                            inline=False)

            if isinstance(collectable, workshop.WorkshopAlias):
                await collectable.load_subcommands(ctx)
                if collectable.subcommands:
                    subcommands = "\n".join(f"**{sc.name}** - {sc.short_docs}"
                                            for sc in collectable.subcommands)
                    embed.add_field(name="Subcommands",
                                    value=subcommands,
                                    inline=False)

            return await ctx.send(embed=embed)
Beispiel #10
0
    async def condition(self, ctx, *, name: str):
        """Looks up a condition."""
        guild_settings = await self.get_settings(ctx.message.server)
        pm = guild_settings.get("pm_result", False)

        destination = ctx.message.author if pm else ctx.message.channel

        result = await search_and_select(ctx, c.conditions, name,
                                         lambda e: e['name'])

        embed = EmbedWithAuthor(ctx)
        embed.title = result['name']
        embed.description = result['desc']

        await self.bot.send_message(destination, embed=embed)
Beispiel #11
0
    async def condition(self, ctx, *, name: str):
        """Looks up a condition."""
        guild_settings = await self.get_settings(ctx.guild)
        pm = guild_settings.get("pm_result", False)

        destination = ctx.author if pm else ctx.channel

        result, metadata = await search_and_select(ctx, c.conditions, name, lambda e: e['name'], return_metadata=True)

        await self.add_training_data("condition", name, result['name'], metadata=metadata)

        embed = EmbedWithAuthor(ctx)
        embed.title = result['name']
        embed.description = result['desc']

        await destination.send(embed=embed)
Beispiel #12
0
    async def list(self, ctx):
        embed = first_embed = EmbedWithAuthor(ctx)
        fields = 0
        out = [embed]

        has_at_least_1 = False

        user_objs = await self.personal_cls.get_ctx_map(ctx)
        user_obj_names = list(user_objs.keys())
        if user_obj_names:
            has_at_least_1 = True
            fields += embeds.add_fields_from_long_text(
                embed, f"Your {self.obj_name_pl.title()}",
                ', '.join(sorted(user_obj_names)))

        async for subscription_doc in self.workshop_sub_meth(ctx):
            try:
                the_collection = await workshop.WorkshopCollection.from_id(
                    ctx, subscription_doc['object_id'])
            except workshop.CollectionNotFound:
                continue
            if bindings := subscription_doc[self.binding_key]:
                has_at_least_1 = True
                embed.add_field(name=the_collection.name,
                                value=', '.join(
                                    sorted(ab['name'] for ab in bindings)),
                                inline=False)
                fields += 1
                if fields > embeds.MAX_NUM_FIELDS:
                    embed = discord.Embed(colour=embed.colour)
                    fields = 0
                    out.append(embed)
Beispiel #13
0
    async def race(self, ctx, *, name: str):
        """Looks up a race."""
        result: gamedata.Race = await self._lookup_search3(
            ctx, {
                'race': compendium.races,
                'subrace': compendium.subraces
            }, name, 'race')

        embed = EmbedWithAuthor(ctx)
        embed.title = result.name
        embed.url = result.url
        embed.add_field(name="Speed", value=result.speed)
        embed.add_field(name="Size", value=result.size)
        for t in result.traits:
            add_fields_from_long_text(embed, t.name, t.text)
        embed.set_footer(text=f"Race | {result.source_str()}")
        await (await self._get_destination(ctx)).send(embed=embed)
Beispiel #14
0
    async def background(self, ctx, *, name: str):
        """Looks up a background."""
        guild_settings = await self.get_settings(ctx.guild)
        pm = guild_settings.get("pm_result", False)
        srd = guild_settings.get("srd", False)

        result, metadata = await search_and_select(ctx, c.backgrounds, name, lambda e: e.name,
                                                   srd=srd and (lambda e: e.srd), return_metadata=True)

        metadata['srd'] = srd
        await self.add_training_data("background", name, result.name, metadata=metadata)

        if not result.srd and srd:
            return await self.send_srd_error(ctx, result)

        embed = EmbedWithAuthor(ctx)
        embed.title = result.name
        embed.set_footer(text=f"Background | {result.source} {result.page}")

        ignored_fields = ['suggested characteristics', 'personality trait', 'ideal', 'bond', 'flaw', 'specialty',
                          'harrowing event']
        for trait in result.traits:
            if trait['name'].lower() in ignored_fields: continue
            text = trait['text']
            text = textwrap.shorten(text, width=1020, placeholder="...")
            embed.add_field(name=trait['name'], value=text)

        # do stuff here
        if pm:
            await ctx.author.send(embed=embed)
        else:
            await ctx.send(embed=embed)
Beispiel #15
0
    async def subclass(self, ctx, name: str):
        """Looks up a subclass."""
        guild_settings = await self.get_settings(ctx.message.server)
        pm = guild_settings.get("pm_result", False)
        srd = guild_settings.get("srd", False)

        destination = ctx.message.author if pm else ctx.message.channel

        result = await search_and_select(ctx,
                                         c.subclasses,
                                         name,
                                         lambda e: e['name'],
                                         srd=srd)

        if not result.get('srd') and srd:
            return await self.send_srd_error(ctx, result)

        embed = EmbedWithAuthor(ctx)
        embed.title = result['name']

        for level_features in result['subclassFeatures']:
            for feature in level_features:
                for entry in feature['entries']:
                    if not isinstance(entry, dict): continue
                    if not entry.get('type') == 'entries': continue
                    text = parse_data_entry(entry['entries'])
                    embed.add_field(
                        name=entry['name'],
                        value=(text[:1019] +
                               "...") if len(text) > 1023 else text)

        embed.set_footer(
            text="Use !classfeat to look up a feature if it is cut off.")

        await self.bot.send_message(destination, embed=embed)
Beispiel #16
0
    async def race(self, ctx, *, name: str):
        """Looks up a race."""
        choices = compendium.fancyraces + compendium.nrace_names
        result = await self._lookup_search(ctx, choices, name, lambda e: e.name, search_type='race', is_obj=True)
        if not result:
            return

        embed = EmbedWithAuthor(ctx)
        embed.title = result.name
        embed.description = f"Source: {result.source}"
        embed.add_field(name="Speed", value=result.get_speed_str())
        embed.add_field(name="Size", value=result.size)
        if result.ability:
            embed.add_field(name="Ability Bonuses", value=result.get_asi_str())
        for t in result.get_traits():
            add_fields_from_long_text(embed, t['name'], t['text'])

        await (await self._get_destination(ctx)).send(embed=embed)
Beispiel #17
0
    async def token(self, ctx, *, name=None):
        """Shows a token for a monster or player. May not support all monsters."""

        if name is None:
            token_cmd = self.bot.get_command('playertoken')
            if token_cmd is None:
                return await ctx.send("Error: SheetManager cog not loaded.")
            return await ctx.invoke(token_cmd)

        monster, metadata = await select_monster_full(ctx,
                                                      name,
                                                      return_metadata=True)

        metadata['homebrew'] = monster.source == 'homebrew'
        await self.add_training_data("monster",
                                     name,
                                     monster.name,
                                     metadata=metadata)

        url = monster.get_image_url()
        embed = EmbedWithAuthor(ctx)
        embed.title = monster.name
        embed.description = f"{monster.size} monster."

        if not monster.source == 'homebrew':
            embed.set_image(url=url)
            embed.set_footer(text="This command may not support all monsters.")

            await ctx.send(embed=embed)
        else:
            if not url:
                return await ctx.channel.send("This monster has no image.")

            try:
                processed = await generate_token(url)
            except Exception as e:
                return await ctx.channel.send(f"Error generating token: {e}")

            file = discord.File(processed, filename="image.png")
            embed.set_image(url="attachment://image.png")
            await ctx.send(file=file, embed=embed)
Beispiel #18
0
    async def classfeat(self, ctx, *, name: str):
        """Looks up a class feature."""
        guild_settings = await self.get_settings(ctx.guild)
        pm = guild_settings.get("pm_result", False)
        srd = guild_settings.get("srd", False)

        destination = ctx.author if pm else ctx.channel

        result, metadata = await search_and_select(ctx, c.cfeats, name, lambda e: e['name'], srd=srd,
                                                   return_metadata=True)

        metadata['srd'] = srd
        await self.add_training_data("classfeat", name, result['name'], metadata=metadata)

        if not result['srd'] and srd:
            return await self.send_srd_error(ctx, result)

        embed = EmbedWithAuthor(ctx)
        embed.title = result['name']
        desc = result['text']
        desc = [desc[i:i + 1024] for i in range(0, len(desc), 1024)]
        embed.description = ''.join(desc[:2])
        for piece in desc[2:]:
            embed.add_field(name="** **", value=piece)

        await destination.send(embed=embed)
Beispiel #19
0
    async def rule(self, ctx, *, name: str = None):
        """Looks up a rule."""
        destination = await self._get_destination(ctx)

        if name is None:
            return await self._show_reference_options(ctx, destination)

        options = []
        for actiontype in compendium.rule_references:
            if name == actiontype['type']:
                return await self._show_action_options(ctx, actiontype,
                                                       destination)
            else:
                options.extend(actiontype['items'])

        result, metadata = await search_and_select(ctx,
                                                   options,
                                                   name,
                                                   lambda e: e['fullName'],
                                                   return_metadata=True)
        await self._add_training_data("reference",
                                      name,
                                      result['fullName'],
                                      metadata=metadata)

        embed = EmbedWithAuthor(ctx)
        embed.title = result['fullName']
        embed.description = f"*{result['short']}*"
        add_fields_from_long_text(embed, "Description", result['desc'])
        embed.set_footer(text=f"Rule | {result['source']}")

        await destination.send(embed=embed)
Beispiel #20
0
    async def _view(self, ctx, name):
        collectable = await helpers.get_collectable_named(
            ctx, name, self.personal_cls, self.workshop_cls,
            self.workshop_sub_meth, self.is_alias, self.obj_name,
            self.obj_name_pl, self.name)
        if collectable is None:
            return await ctx.send(f"No {self.obj_name} named {name} found.")
        elif isinstance(collectable, self.personal_cls):  # personal
            await send_long_code_text(
                ctx,
                outside_codeblock=f'**{name}**:',
                inside_codeblock=
                f"{ctx.prefix}{self.obj_copy_command} {collectable.name} {collectable.code}",
                codeblock_language='py')
            return
        else:  # collection
            embed = EmbedWithAuthor(ctx)
            the_collection = await collectable.load_collection(ctx)
            owner = await user_from_id(ctx, the_collection.owner)
            embed.title = f"{ctx.prefix}{name}" if self.is_alias else name
            embed.description = f"From {the_collection.name} by {owner}.\n" \
                                f"[View on Workshop]({the_collection.url})"
            embeds.add_fields_from_long_text(
                embed, "Help", collectable.docs or "No documentation.")

            if isinstance(collectable, workshop.WorkshopAlias):
                await collectable.load_subcommands(ctx)
                if collectable.subcommands:
                    subcommands = "\n".join(f"**{sc.name}** - {sc.short_docs}"
                                            for sc in collectable.subcommands)
                    embed.add_field(name="Subcommands",
                                    value=subcommands,
                                    inline=False)

            return await ctx.send(embed=embed)
Beispiel #21
0
    async def classfeat(self, ctx, *, name: str):
        """Looks up a class feature."""
        try:
            guild_id = ctx.message.server.id
            pm = self.settings.get(guild_id, {}).get("pm_result", False)
            srd = self.settings.get(guild_id, {}).get("srd", False)
        except:
            pm = False
            srd = False
        destination = ctx.message.author if pm else ctx.message.channel

        result = await search_and_select(ctx,
                                         c.cfeats,
                                         name,
                                         lambda e: e['name'],
                                         srd=srd)

        if not result['srd'] and srd:
            return await self.send_srd_error(ctx, result)

        embed = EmbedWithAuthor(ctx)
        embed.title = result['name']
        desc = result['text']
        desc = [desc[i:i + 1024] for i in range(0, len(desc), 1024)]
        embed.description = ''.join(desc[:2])
        for piece in desc[2:]:
            embed.add_field(name="** **", value=piece)

        await self.bot.send_message(destination, embed=embed)
Beispiel #22
0
    async def list(self, ctx):
        embed = EmbedWithAuthor(ctx)

        has_at_least_1 = False

        user_objs = await self.personal_cls.get_ctx_map(ctx)
        user_obj_names = list(user_objs.keys())
        if user_obj_names:
            has_at_least_1 = True
            embeds.add_fields_from_long_text(
                embed, f"Your {self.obj_name_pl.title()}",
                ', '.join(sorted(user_obj_names)))

        async for subscription_doc in self.workshop_sub_meth(ctx):
            try:
                the_collection = await workshop.WorkshopCollection.from_id(
                    ctx, subscription_doc['object_id'])
            except workshop.CollectionNotFound:
                continue
            if bindings := subscription_doc[self.binding_key]:
                has_at_least_1 = True
                embed.add_field(name=the_collection.name,
                                value=', '.join(
                                    sorted(ab['name'] for ab in bindings)),
                                inline=False)
            else:
                embed.add_field(
                    name=the_collection.name,
                    value=f"This collection has no {self.obj_name_pl}.",
                    inline=False)
Beispiel #23
0
    async def background(self, ctx, *, name: str):
        """Looks up a background."""
        guild_settings = await self.get_settings(ctx.message.server)
        pm = guild_settings.get("pm_result", False)
        srd = guild_settings.get("srd", False)

        result = await search_and_select(ctx,
                                         c.backgrounds,
                                         name,
                                         lambda e: e['name'],
                                         srd=srd)

        if not result['srd'] and srd:
            return await self.send_srd_error(ctx, result)

        embed = EmbedWithAuthor(ctx)
        embed.title = result['name']
        embed.description = f"*Source: {result.get('source', 'Unknown')}*"

        ignored_fields = [
            'suggested characteristics', 'personality trait', 'ideal', 'bond',
            'flaw', 'specialty', 'harrowing event'
        ]
        for trait in result['trait']:
            if trait['name'].lower() in ignored_fields: continue
            text = '\n'.join(t for t in trait['text'] if t)
            text = textwrap.shorten(text, width=1020, placeholder="...")
            embed.add_field(name=trait['name'], value=text)

        # do stuff here
        if pm:
            await self.bot.send_message(ctx.message.author, embed=embed)
        else:
            await self.bot.say(embed=embed)
    async def rule(self, ctx, *, name: str):
        """Looks up a rule."""
        guild_settings = await self.get_settings(ctx.guild)
        pm = guild_settings.get("pm_result", False)

        destination = ctx.author if pm else ctx.channel

        result, metadata = await search_and_select(ctx,
                                                   c.rules,
                                                   name,
                                                   lambda e: e['name'],
                                                   return_metadata=True)

        await self.add_training_data("rule",
                                     name,
                                     result['name'],
                                     metadata=metadata)

        embed = EmbedWithAuthor(ctx)
        embed.title = result['name']
        desc = result['desc']
        desc = [desc[i:i + 1024] for i in range(0, len(desc), 1024)]
        embed.description = ''.join(desc[:2])
        for piece in desc[2:]:
            embed.add_field(name="** **", value=piece)

        await destination.send(embed=embed)
Beispiel #25
0
    async def feat(self, ctx, *, name: str):
        """Looks up a feat."""
        choices = compendium.feats + compendium.nfeat_names
        result = await self._lookup_search(ctx, choices, name, lambda e: e['name'], search_type='feat')
        if not result:
            return

        embed = EmbedWithAuthor(ctx)
        embed.title = result['name']
        if result['prerequisite']:
            embed.add_field(name="Prerequisite", value=result['prerequisite'], inline=False)
        if result['ability']:
            embed.add_field(name="Ability Improvement",
                            value=f"Increase your {result['ability']} score by 1, up to a maximum of 20.", inline=False)

        add_fields_from_long_text(embed, "Description", result['desc'])
        embed.set_footer(text=f"Feat | {result['source']} {result['page']}")
        await (await self._get_destination(ctx)).send(embed=embed)
Beispiel #26
0
    async def feat(self, ctx, *, name: str):
        """Looks up a feat."""
        result: gamedata.Feat = await self._lookup_search3(
            ctx, {'feat': compendium.feats}, name)

        embed = EmbedWithAuthor(ctx)
        embed.title = result.name
        embed.url = result.url
        if result.prerequisite:
            embed.add_field(name="Prerequisite",
                            value=result.prerequisite,
                            inline=False)
        add_fields_from_long_text(embed, "Description", result.desc)
        embed.set_footer(text=f"Feat | {result.source_str()}")
        await (await self._get_destination(ctx)).send(embed=embed)
Beispiel #27
0
    async def background(self, ctx, *, name: str):
        """Looks up a background."""
        result: gamedata.Background = await self._lookup_search3(
            ctx, {'background': compendium.backgrounds}, name)

        embed = EmbedWithAuthor(ctx)
        embed.url = result.url
        embed.title = result.name
        embed.set_footer(text=f"Background | {result.source_str()}")

        for trait in result.traits:
            text = trim_str(trait.text, 1024)
            embed.add_field(name=trait.name, value=text, inline=False)

        await (await self._get_destination(ctx)).send(embed=embed)
Beispiel #28
0
    async def spell(self, ctx, *, name: str):
        """Looks up a spell."""
        choices = await get_spell_choices(ctx, filter_by_license=False)
        spell = await self._lookup_search3(ctx, {'spell': choices}, name)

        embed = EmbedWithAuthor(ctx)
        embed.url = spell.url
        color = embed.colour

        embed.title = spell.name
        school_level = f"{spell.get_level()} {spell.get_school().lower()}" if spell.level > 0 \
            else f"{spell.get_school().lower()} cantrip"
        embed.description = f"*{school_level}. " \
                            f"({', '.join(itertools.chain(spell.classes, spell.subclasses))})*"
        if spell.ritual:
            time = f"{spell.time} (ritual)"
        else:
            time = spell.time

        meta = f"**Casting Time**: {time}\n" \
               f"**Range**: {spell.range}\n" \
               f"**Components**: {spell.components}\n" \
               f"**Duration**: {spell.duration}"
        embed.add_field(name="Meta", value=meta)

        higher_levels = spell.higherlevels
        pieces = chunk_text(spell.description)

        embed.add_field(name="Description", value=pieces[0], inline=False)

        embed_queue = [embed]
        if len(pieces) > 1:
            for i, piece in enumerate(pieces[1::2]):
                temp_embed = discord.Embed()
                temp_embed.colour = color
                if (next_idx := (i + 1) * 2) < len(
                        pieces
                ):  # this is chunked into 1024 pieces, and descs can handle 2
                    temp_embed.description = piece + pieces[next_idx]
                else:
                    temp_embed.description = piece
                embed_queue.append(temp_embed)
Beispiel #29
0
    async def subclass(self, ctx, *, name: str):
        """Looks up a subclass."""
        result: gamedata.Subclass = await self._lookup_search3(
            ctx, {'class': compendium.subclasses}, name, query_type='subclass')

        embed = EmbedWithAuthor(ctx)
        embed.url = result.url
        embed.title = result.name
        embed.description = f"*Source: {result.source_str()}*"

        for level in result.levels:
            for feature in level:
                text = trim_str(feature.text, 1024)
                embed.add_field(name=feature.name, value=text, inline=False)

        embed.set_footer(
            text=
            f"Use {ctx.prefix}classfeat to look up a feature if it is cut off."
        )

        await (await self._get_destination(ctx)).send(embed=embed)
Beispiel #30
0
 async def tutorial_list(self, ctx):
     """Lists the available tutorials."""
     embed = EmbedWithAuthor(ctx)
     embed.title = "Available Tutorials"
     embed.description = f"Use `{ctx.prefix}tutorial <name>` to select a tutorial from the ones available below!\n" \
                         f"First time here? Try `{ctx.prefix}tutorial quickstart`!"
     for tutorial in self.tutorials.values():
         embed.add_field(name=tutorial.name,
                         value=tutorial.description,
                         inline=False)
     await ctx.send(embed=embed)