Exemplo n.º 1
0
    async def monster_atk(self,
                          ctx,
                          monster_name,
                          atk_name='list',
                          *,
                          args=''):
        """Rolls a monster's attack.
        Attack name can be "list" for a list of all of the monster's attacks.
        Valid Arguments: adv/dis
                         -ac [target ac]
                         -b [to hit bonus]
                         -d [damage bonus]
                         -d# [applies damage to the first # hits]
                         -rr [times to reroll]
                         -t [target]
                         -phrase [flavor text]
                         crit (automatically crit)"""

        try:
            await self.bot.delete_message(ctx.message)
        except:
            pass

        monster = await select_monster_full(ctx, monster_name)
        self.bot.rdb.incr('monsters_looked_up_life')
        attacks = monster.attacks
        monster_name = monster.get_title_name()
        if atk_name == 'list':
            attacks_string = '\n'.join(
                "**{0}:** +{1} To Hit, {2} damage.".format(
                    a['name'], a['attackBonus'], a['damage'] or 'no')
                for a in attacks)
            return await self.bot.say("{}'s attacks:\n{}".format(
                monster_name, attacks_string))
        attack = fuzzy_search(attacks, 'name', atk_name)
        if attack is None:
            return await self.bot.say("No attack with that name found.",
                                      delete_after=15)

        args = shlex.split(args)
        args = argparse(args)
        args['name'] = [monster_name]
        args['image'] = args.get('image') or [monster.get_image_url()]
        attack['details'] = attack.get('desc') or attack.get('details')

        result = sheet_attack(attack, args)
        embed = result['embed']
        embed.colour = random.randint(0, 0xffffff)
        embeds.add_fields_from_args(embed, args.get('f'))

        if monster.source == 'homebrew':
            embed.set_footer(text="Homebrew content.",
                             icon_url="https://avrae.io/static/homebrew.png")

        await self.bot.say(embed=embed)
Exemplo n.º 2
0
    async def monster_atk(self, ctx, monster_name, atk_name='list', *, args=''):
        """Rolls a monster's attack.
        Attack name can be "list" for a list of all of the monster's attacks.
        __Valid Arguments__
        adv/dis
        -ac [target ac]
        -b [to hit bonus]
        -d [damage bonus]
        -d# [applies damage to the first # hits]
        -rr [times to reroll]
        -t [target]
        -phrase [flavor text]
        crit (automatically crit)
        -h (hides monster name, image, and attack details)"""

        try:
            await ctx.message.delete()
        except:
            pass

        monster = await select_monster_full(ctx, monster_name)
        self.bot.rdb.incr('monsters_looked_up_life')
        attacks = monster.attacks
        monster_name = monster.get_title_name()
        if atk_name == 'list':
            attacks_string = '\n'.join("**{0}:** +{1} To Hit, {2} damage.".format(a['name'],
                                                                                  a['attackBonus'],
                                                                                  a['damage'] or 'no') for a in attacks)
            return await ctx.send("{}'s attacks:\n{}".format(monster_name, attacks_string))
        attack = await search_and_select(ctx, attacks, atk_name, lambda a: a['name'])
        args = await scripting.parse_snippets(args, ctx)
        args = argparse(args)
        if not args.last('h', type_=bool):
            args['name'] = monster_name
            args['image'] = args.get('image') or monster.get_image_url()
        else:
            args['name'] = "An unknown creature"
        attack['details'] = attack.get('desc') or attack.get('details')

        result = sheet_attack(attack, args)
        embed = result['embed']
        embed.colour = random.randint(0, 0xffffff)
        embeds.add_fields_from_args(embed, args.get('f'))

        if monster.source == 'homebrew':
            embed.set_footer(text="Homebrew content.", icon_url="https://avrae.io/assets/img/homebrew.png")

        if args.last('h', type_=bool):
            try:
                await ctx.author.send(embed=result['full_embed'])
            except:
                pass

        await ctx.send(embed=embed)
Exemplo n.º 3
0
    async def _attack(self, ctx, combatant_name, target_name, atk_name, args):
        args = await scripting.parse_snippets(args, ctx)
        combat = await Combat.from_ctx(ctx)

        try:
            target = await combat.select_combatant(target_name, "Select the target.")
            if target is None:
                return await ctx.send("Target not found.")
        except SelectionException:
            return await ctx.send("Target not found.")

        if combatant_name is None:
            combatant = combat.current_combatant
            if combatant is None:
                return await ctx.send(f"You must start combat with `{ctx.prefix}init next` first.")
        else:
            try:
                combatant = await combat.select_combatant(combatant_name, "Select the attacker.")
                if combatant is None:
                    return await ctx.send("Combatant not found.")
            except SelectionException:
                return await ctx.send("Combatant not found.")

        attacks = combatant.attacks
        if '-custom' in args:
            attack = {'attackBonus': None, 'damage': None, 'name': atk_name}
        else:
            try:
                attack = await get_selection(ctx,
                                             [(a['name'], a) for a in attacks if atk_name.lower() in a['name'].lower()],
                                             message="Select your attack.")
            except SelectionException:
                return await ctx.send("Attack not found.")

        is_player = isinstance(combatant, PlayerCombatant)

        if is_player and combatant.character_owner == str(ctx.author.id):
            args = await combatant.character.parse_cvars(args, ctx)

        args = argparse(shlex.split(args))  # set up all the arguments
        args['name'] = combatant.name
        if target.ac is not None: args['ac'] = target.ac
        args['t'] = target.name
        args['resist'] = args.get('resist') or target.resists['resist']
        args['immune'] = args.get('immune') or target.resists['immune']
        args['vuln'] = args.get('vuln') or target.resists['vuln']
        args['neutral'] = args.get('neutral') or target.resists['neutral']
        if is_player:
            args['c'] = combatant.character.get_setting('critdmg') or args.get('c')
            args['reroll'] = combatant.character.get_setting('reroll') or 0
            args['crittype'] = combatant.character.get_setting('crittype') or 'default'
            args['critdice'] = (combatant.character.get_setting('critdice') or 0) + int(
                combatant.character.get_setting('hocrit', False))
            args['criton'] = combatant.character.get_setting('criton') or args.get('criton')

        result = sheet_attack(attack, args)
        embed = result['embed']

        if args.last('h', type_=bool):
            try:
                controller = ctx.guild.get_member(int(combatant.controller))
                await controller.send(embed=result['full_embed'])
            except:
                pass

        if is_player:
            embed.colour = combatant.character.get_color()
        else:
            embed.colour = random.randint(0, 0xffffff)
        if target.ac is not None and target.hp is not None:
            target.mod_hp(-result['total_damage'], overheal=False)

        if target.ac is not None:
            if target.hp is not None:
                embed.set_footer(text="{}: {}".format(target.name, target.get_hp_str()))
                if target.isPrivate:
                    try:
                        controller = ctx.guild.get_member(int(target.controller))
                        await controller.send(
                            f"{combatant.name} attacked with a {attack['name']}!"
                            f"\n{target.name}'s HP: {target.get_hp_str(True)}")
                    except:
                        pass
            else:
                embed.set_footer(text="Dealt {} damage to {}!".format(result['total_damage'], target.name))
            if target.is_concentrating() and result['total_damage'] > 0:
                dcs = []
                for atk in result['raw_attacks']:
                    if atk['crit'] == 2:
                        continue
                    dcs.append(int(max(atk['damage'] / 2, 10)))
                if len(dcs) > 1:
                    dcs = ', '.join(map(str, dcs))
                    embed.add_field(name="Concentration",
                                    value=f"Check your concentration (DCs {dcs})!")
                else:
                    embed.add_field(name="Concentration",
                                    value=f"Check your concentration (DC {dcs[0]})!")
        else:
            embed.set_footer(text="Target AC not set.")

        embeds.add_fields_from_args(embed, args.get('f', []))

        await ctx.send(embed=embed)
        await combat.final()
Exemplo n.º 4
0
    async def attack(self, ctx, atk_name=None, *, args: str = ''):
        """Rolls an attack for the current active character.
        __Valid Arguments__
        adv/dis
        adv#/dis# (applies adv to the first # attacks)
        ea (Elven Accuracy double advantage)
        
        -ac [target ac]
        -t [target]
        
        -b [to hit bonus]
        -criton [a number to crit on if rolled on or above]
        -d [damage bonus]
        -d# [applies damage to the first # hits]
        -c [damage bonus on crit]
        -rr [times to reroll]
        -mi [minimum weapon dice roll]
        
        -resist [damage resistance]
        -immune [damage immunity]
        -vuln [damage vulnerability]
        -neutral [damage non-resistance]
        
        hit (automatically hits)
        miss (automatically misses)
        crit (automatically crit)
        max (deals max damage)
        
        -phrase [flavor text]
        -title [title] *note: [charname], [aname], and [target] will be replaced automatically*
        -f "Field Title|Field Text" (see !embed)
        -h (hides attack details)
        [user snippet]"""
        if atk_name is None:
            return await ctx.invoke(self.attack_list)

        char: Character = await Character.from_ctx(ctx)

        attack = await search_and_select(ctx, char.attacks, atk_name,
                                         lambda a: a.name)

        args = await self.new_arg_stuff(args, ctx, char)
        args['name'] = char.name
        args['criton'] = args.last('criton') or char.get_setting('criton', 20)
        args['reroll'] = char.get_setting('reroll', 0)
        args['critdice'] = char.get_setting('critdice', 0)
        args['crittype'] = char.get_setting('crittype', 'default')

        result = sheet_attack(attack.to_old(), args,
                              EmbedWithCharacter(char, name=False))
        embed = result['embed']
        if args.last('h', type_=bool):
            try:
                await ctx.author.send(embed=result['full_embed'])
            except:
                pass

        _fields = args.get('f')
        embeds.add_fields_from_args(embed, _fields)

        await ctx.send(embed=embed)
        try:
            await ctx.message.delete()
        except:
            pass
    async def attack(self, ctx, atk_name=None, *, args: str = ''):
        """Rolls an attack for the current active character.
        __Valid Arguments__
        adv/dis
        adv#/dis# (applies adv to the first # attacks)
        ea (Elven Accuracy double advantage)
        
        -ac [target ac]
        -t [target]
        
        -b [to hit bonus]
        -criton [a number to crit on if rolled on or above]
        -d [damage bonus]
        -d# [applies damage to the first # hits]
        -c [damage bonus on crit]
        -rr [times to reroll]
        -mi [minimum weapon dice roll]
        -rd [extra dice rolled for damage]
        -rh [extra dice rolled for to hit]
        
        -resist [damage resistance]
        -immune [damage immunity]
        -vuln [damage vulnerability]
        -neutral [damage non-resistance]
        
        hit (automatically hits)
        miss (automatically misses)
        crit (automatically crit)
        max (deals max damage)
        
        -phrase [flavor text]
        -title [title] *note: [charname], [aname], and [target] will be replaced automatically*
        -f "Field Title|Field Text" (see !embed)
        -h (hides attack details)
        [user snippet]"""
        if atk_name is None:
            return await ctx.invoke(self.attack_list)

        char = await Character.from_ctx(ctx)
        attacks = char.get_attacks()

        try:  # fuzzy search for atk_name
            attack = next(a for a in attacks if atk_name.lower() == a.get('name').lower())
        except StopIteration:
            try:
                attack = next(a for a in attacks if atk_name.lower() in a.get('name').lower())
            except StopIteration:
                return await ctx.send('No attack with that name found.')

        args = await self.new_arg_stuff(args, ctx, char)
        args['name'] = char.get_name()
        args['criton'] = args.last('criton') or char.get_setting('criton', 20)
        args['reroll'] = char.get_setting('reroll', 0)
        args['critdice'] = int(char.get_setting('hocrit', False)) + char.get_setting('critdice', 0)
        args['crittype'] = char.get_setting('crittype', 'default')
        if attack.get('details') is not None:
            try:
                attack['details'] = await char.parse_cvars(attack['details'], ctx)
            except AvraeException:
                pass  # failed to eval, probably DDB nonsense

        if args.last('rd') is not None:
            attack["damage"] = (attack.get("damage") + "+" + args.last('rd'))

        result = sheet_attack(attack, args, EmbedWithCharacter(char, name=False))
        embed = result['embed']
        if args.last('h', type_=bool):
            try:
                await ctx.author.send(embed=result['full_embed'])
            except:
                pass

        _fields = args.get('f')
        embeds.add_fields_from_args(embed, _fields)

        await ctx.send(embed=embed)
        try:
            await ctx.message.delete()
        except:
            pass