def run_check(skill_key, caster, args, embed): """ Runs a caster's skill check, building on an existing embed and handling most arguments. :type skill_key: str :type caster: cogs5e.models.sheet.statblock.StatBlock :type args: utils.argparser.ParsedArguments :type embed: discord.Embed :return: The total of each check. :rtype: list of int """ skill = caster.skills[skill_key] skill_name = camel_to_title(skill_key) mod = skill.value # str/dex/con/int/wis/cha if any(args.last(s, type_=bool) for s in STAT_ABBREVIATIONS): base = next(s for s in STAT_ABBREVIATIONS if args.last(s, type_=bool)) mod = mod + caster.stats.get_mod(base) skill_name = f"{verbose_stat(base)} ({skill_name})" # -title if args.last('title'): embed.title = args.last('title', '') \ .replace('[name]', caster.get_title_name()) \ .replace('[cname]', skill_name) elif args.last('h'): embed.title = f"An unknown creature makes {a_or_an(skill_name)} check!" else: embed.title = f'{caster.get_title_name()} makes {a_or_an(skill_name)} check!' return _run_common(skill, args, embed, mod_override=mod)
def run_check(skill_key, caster, args, embed): """ Runs a caster's skill check, building on an existing embed and handling most arguments. :type skill_key: str :type caster: cogs5e.models.sheet.statblock.StatBlock :type args: utils.argparser.ParsedArguments :type embed: discord.Embed :return: The total of each check. :rtype: CheckResult """ skill = caster.skills[skill_key] skill_name = camel_to_title(skill_key) mod = skill.value # str/dex/con/int/wis/cha if any(args.last(s, type_=bool) for s in STAT_ABBREVIATIONS): base = next(s for s in STAT_ABBREVIATIONS if args.last(s, type_=bool)) mod = mod - caster.stats.get_mod( SKILL_MAP[skill_key]) + caster.stats.get_mod(base) skill_name = f"{verbose_stat(base)} ({skill_name})" # -title if args.last('title'): embed.title = args.last('title', '') \ .replace('[name]', caster.get_title_name()) \ .replace('[cname]', skill_name) elif args.last('h'): embed.title = f"An unknown creature makes {a_or_an(skill_name)} check!" else: embed.title = f'{caster.get_title_name()} makes {a_or_an(skill_name)} check!' # ieffect -cb if isinstance(caster, init.Combatant): args['b'] = args.get('b') + caster.active_effects('cb') result = _run_common(skill, args, embed, mod_override=mod) return CheckResult(rolls=result.rolls, skill=skill, skill_name=skill_name, skill_roll_result=result)
def run_check(skill_key, caster, args, embed): skill = caster.skills[skill_key] skill_name = camel_to_title(skill_key) mod = skill.value # str/dex/con/int/wis/cha if any(args.last(s, type_=bool) for s in STAT_ABBREVIATIONS): base = next(s for s in STAT_ABBREVIATIONS if args.last(s, type_=bool)) mod = mod - caster.stats.get_mod( SKILL_MAP[skill_key]) + caster.stats.get_mod(base) skill_name = f"{verbose_stat(base)} ({skill_name})" # -title if args.last('title'): embed.title = args.last('title', '') \ .replace('[name]', caster.get_title_name()) \ .replace('[cname]', skill_name) elif args.last('h'): embed.title = f"An unknown creature makes {a_or_an(skill_name)} check!" else: embed.title = f'{caster.get_title_name()} makes {a_or_an(skill_name)} check!' _run_common(skill, args, embed, mod_override=mod)
async def check(self, ctx, check, *args): """Rolls a check for your current active character. __Valid Arguments__ adv/dis -b [conditional bonus] -mc [minimum roll] -phrase [flavor text] -title [title] *note: [charname] and [cname] will be replaced automatically* -dc [dc] -rr [iterations] str/dex/con/int/wis/cha (different skill base; e.g. Strength (Intimidation)) """ char: Character = await Character.from_ctx(ctx) skill_key = await search_and_select(ctx, SKILL_NAMES, check, lambda s: s) skill_name = camel_to_title(skill_key) embed = EmbedWithCharacter(char, False) skill = char.skills[skill_key] args = await self.new_arg_stuff(args, ctx, char) # advantage adv = args.adv(boolwise=True) # roll bonus b = args.join('b', '+') # phrase phrase = args.join('phrase', '\n') # num rolls iterations = min(args.last('rr', 1, int), 25) # dc dc = args.last('dc', type_=int) # reliable talent (#654) rt = char.get_setting('talent', 0) and skill.prof >= 1 mc = args.last('mc') or 10 * rt # halfling luck ro = char.get_setting('reroll') num_successes = 0 mod = skill.value formatted_d20 = skill.d20(base_adv=adv, reroll=ro, min_val=mc, base_only=True) if any(args.last(s, type_=bool) for s in STAT_ABBREVIATIONS): base = next(s for s in STAT_ABBREVIATIONS if args.last(s, type_=bool)) mod = mod - char.get_mod(SKILL_MAP[skill_key]) + char.get_mod(base) skill_name = f"{verbose_stat(base)} ({skill_name})" if b is not None: roll_str = f"{formatted_d20}{mod:+}+{b}" else: roll_str = f"{formatted_d20}{mod:+}" if args.last('title'): embed.title = args.last('title', '') \ .replace('[charname]', char.name) \ .replace('[cname]', skill_name) else: embed.title = f'{char.name} makes {a_or_an(skill_name)} check!' if iterations > 1: embed.description = (f"**DC {dc}**\n" if dc else '') + ( '*' + phrase + '*' if phrase is not None else '') for i in range(iterations): result = roll(roll_str, inline=True) if dc and result.total >= dc: num_successes += 1 embed.add_field(name=f"Check {i + 1}", value=result.skeleton) if dc: embed.set_footer( text= f"{num_successes} Successes | {iterations - num_successes} Failures" ) else: result = roll(roll_str, inline=True) if dc: embed.set_footer( text="Success!" if result.total >= dc else "Failure!") embed.description = ( f"**DC {dc}**\n" if dc else '') + result.skeleton + ( '\n*' + phrase + '*' if phrase is not None else '') embeds.add_fields_from_args(embed, args.get('f')) if args.last('image') is not None: embed.set_thumbnail(url=args.last('image')) await ctx.send(embed=embed) try: await ctx.message.delete() except: pass
async def monster_check(self, ctx, monster_name, check, *args): """Rolls a check for a monster. __Valid Arguments__ adv/dis -b [conditional bonus] -phrase [flavor text] -title [title] *note: [mname] and [cname] will be replaced automatically* -dc [dc] -rr [iterations] str/dex/con/int/wis/cha (different skill base; e.g. Strength (Intimidation)) -h (hides name and image of monster)""" monster: Monster = await select_monster_full(ctx, monster_name) self.bot.rdb.incr('monsters_looked_up_life') monster_name = monster.get_title_name() skill_key = await search_and_select(ctx, SKILL_NAMES, check, lambda s: s) skill_name = camel_to_title(skill_key) embed = discord.Embed() embed.colour = random.randint(0, 0xffffff) args = await scripting.parse_snippets(args, ctx) args = argparse(args) adv = args.adv(boolwise=True) b = args.join('b', '+') phrase = args.join('phrase', '\n') iterations = min(args.last('rr', 1, int), 25) dc = args.last('dc', type_=int) num_successes = 0 skill = monster.skills[skill_key] mod = skill.value formatted_d20 = skill.d20(base_adv=adv, base_only=True) if any( args.last(s, type_=bool) for s in ("str", "dex", "con", "int", "wis", "cha")): base = next(s for s in ("str", "dex", "con", "int", "wis", "cha") if args.last(s, type_=bool)) mod = mod - monster.get_mod( SKILL_MAP[skill_key]) + monster.get_mod(base) skill_name = f"{verbose_stat(base)} ({skill_name})" skill_name = skill_name.title() if not args.last('h', type_=bool): default_title = '{} makes {} check!'.format( monster_name, a_or_an(skill_name)) else: default_title = f"An unknown creature makes {a_or_an(skill_name)} check!" if b is not None: roll_str = formatted_d20 + '{:+}'.format(mod) + '+' + b else: roll_str = formatted_d20 + '{:+}'.format(mod) embed.title = args.last('title', '') \ .replace('[mname]', monster_name) \ .replace('[cname]', skill_name) \ or default_title if iterations > 1: embed.description = (f"**DC {dc}**\n" if dc else '') + ( '*' + phrase + '*' if phrase is not None else '') for i in range(iterations): result = roll(roll_str, inline=True) if dc and result.total >= dc: num_successes += 1 embed.add_field(name=f"Check {i + 1}", value=result.skeleton) if dc: embed.set_footer( text= f"{num_successes} Successes | {iterations - num_successes} Failues" ) else: result = roll(roll_str, inline=True) if dc: embed.set_footer( text="Success!" if result.total >= dc else "Failure!") embed.description = ( f"**DC {dc}**\n" if dc else '') + result.skeleton + ( '\n*' + phrase + '*' if phrase is not None else '') embeds.add_fields_from_args(embed, args.get('f')) if args.last('image') is not None: embed.set_thumbnail(url=args.last('image')) elif not args.last('h', type_=bool): embed.set_thumbnail(url=monster.get_image_url()) if monster.source == 'homebrew': embed.set_footer( text="Homebrew content.", icon_url="https://avrae.io/assets/img/homebrew.png") await ctx.send(embed=embed) try: await ctx.message.delete() except: pass
async def monster_save(self, ctx, monster_name, save, *args): """Rolls a save for a monster. Args: adv/dis -b [conditional bonus] -phrase [flavor text] -title [title] *note: [mname] and [cname] will be replaced automatically* -dc [dc] -rr [iterations]""" monster: Monster = await select_monster_full(ctx, monster_name) self.bot.rdb.incr('monsters_looked_up_life') monster_name = monster.get_title_name() saves = monster.saves try: save = next(a for a in saves.keys() if save.lower() == a.lower()) except StopIteration: try: save = next(a for a in saves.keys() if save.lower() in a.lower()) except StopIteration: return await self.bot.say('That\'s not a valid save.') embed = discord.Embed() embed.colour = random.randint(0, 0xffffff) args = argparse(args) adv = args.adv() b = args.join('b', '+') phrase = args.join('phrase', '\n') iterations = min(args.last('rr', 1, int), 25) dc = args.last('dc', type_=int) num_successes = 0 if b is not None: roll_str = '1d20{:+}'.format(saves[save]) + '+' + b else: roll_str = '1d20{:+}'.format(saves[save]) default_title = f'{monster_name} makes {a_or_an(camel_to_title(save))}!' embed.title = args.last('title', '') \ .replace('[mname]', monster_name) \ .replace('[sname]', camel_to_title(save)) \ or default_title if iterations > 1: embed.description = (f"**DC {dc}**\n" if dc else '') + ( '*' + phrase + '*' if phrase is not None else '') for i in range(iterations): result = roll(roll_str, adv=adv, inline=True) if dc and result.total >= dc: num_successes += 1 embed.add_field(name=f"Check {i+1}", value=result.skeleton) if dc: embed.set_footer( text= f"{num_successes} Successes | {iterations - num_successes} Failues" ) else: result = roll(roll_str, adv=adv, inline=True) if dc: embed.set_footer( text="Success!" if result.total >= dc else "Failure!") embed.description = ( f"**DC {dc}**\n" if dc else '') + result.skeleton + ( '\n*' + phrase + '*' if phrase is not None else '') embeds.add_fields_from_args(embed, args.get('f')) if args.last('image') is not None: embed.set_thumbnail(url=args.last('image')) else: embed.set_thumbnail(url=monster.get_image_url()) if monster.source == 'homebrew': embed.set_footer(text="Homebrew content.", icon_url="https://avrae.io/static/homebrew.png") await self.bot.say(embed=embed) try: await self.bot.delete_message(ctx.message) except: pass
async def check(self, ctx, check, *, args: str = ''): """Rolls a check for your current active character. __Valid Arguments__ adv/dis -b [conditional bonus] -mc [minimum roll] -phrase [flavor text] -title [title] *note: [charname] and [cname] will be replaced automatically* -dc [dc] -rr [iterations] str/dex/con/int/wis/cha (different skill base; e.g. Strength (Intimidation)) """ char = await Character.from_ctx(ctx) skills = char.get_skills() if not skills: return await ctx.send('You must update your character sheet first.') try: skill = next(a for a in skills.keys() if check.lower() == a.lower())#this checks for the skill exactly except StopIteration: try: skill = next(a for a in skills.keys() if check.lower() in a.lower())#this checks for the partial name of the skill except StopIteration: try: # Probably will be fairly slow, but whatever skill = next(SKILL_ALIASES[alias] for alias in SKILL_ALIASES.keys() if check.lower() == alias.lower())#go through our alias names except StopIteration: return await ctx.send('That\'s not a valid check.') embed = EmbedWithCharacter(char, False) skill_effects = char.get_skill_effects() args += ' ' + skill_effects.get(skill, '') # dicecloud v7 - autoadv args = await self.new_arg_stuff(args, ctx, char) adv = args.adv() b = args.join('b', '+') phrase = args.join('phrase', '\n') iterations = min(args.last('rr', 1, int), 25) dc = args.last('dc', type_=int) num_successes = 0 formatted_d20 = format_d20(adv, char.get_setting('reroll')) mc = args.last('mc', None) if mc: formatted_d20 = f"{formatted_d20}mi{mc}" mod = skills[skill] skill_name = skill if any(args.last(s, type_=bool) for s in ("str", "dex", "con", "int", "wis", "cha")): base = next(s for s in ("str", "dex", "con", "int", "wis", "cha") if args.last(s, type_=bool)) mod = mod - char.get_mod(SKILL_MAP[skill]) + char.get_mod(base) skill_name = f"{verbose_stat(base)} ({skill})" skill_name = camel_to_title(skill_name) default_title = '{} makes {} check!'.format(char.get_name(), a_or_an(skill_name)) if b is not None: roll_str = formatted_d20 + '{:+}'.format(mod) + '+' + b else: roll_str = formatted_d20 + '{:+}'.format(mod) embed.title = args.last('title', '') \ .replace('[charname]', char.get_name()) \ .replace('[cname]', skill_name) \ or default_title if iterations > 1: embed.description = (f"**DC {dc}**\n" if dc else '') + ('*' + phrase + '*' if phrase is not None else '') for i in range(iterations): result = roll(roll_str, adv=adv, inline=True) if dc and result.total >= dc: num_successes += 1 embed.add_field(name=f"Check {i+1}", value=result.skeleton) if dc: embed.set_footer(text=f"{num_successes} Successes | {iterations - num_successes} Failues") else: result = roll(roll_str, adv=adv, inline=True) if dc: embed.set_footer(text="Success!" if result.total >= dc else "Failure!") embed.description = (f"**DC {dc}**\n" if dc else '') + result.skeleton + ( '\n*' + phrase + '*' if phrase is not None else '') embeds.add_fields_from_args(embed, args.get('f')) if args.last('image') is not None: embed.set_thumbnail(url=args.last('image')) await ctx.send(embed=embed) try: await ctx.message.delete() except: pass
async def save(self, ctx, skill, *, args: str = ''): """Rolls a save for your current active character. __Valid Arguments__ adv/dis -b [conditional bonus] -phrase [flavor text] -title [title] *note: [charname] and [sname] will be replaced automatically* -image [image URL] -dc [dc] (does not apply to Death Saves) -rr [iterations] (does not apply to Death Saves)""" if skill == 'death': ds_cmd = self.bot.get_command('game deathsave') if ds_cmd is None: return await ctx.send("Error: GameTrack cog not loaded.") return await ctx.invoke(ds_cmd, *shlex.split(args)) char = await Character.from_ctx(ctx) saves = char.get_saves() if not saves: return await ctx.send('You must update your character sheet first.') try: save = next(a for a in saves.keys() if skill.lower() == a.lower()) except StopIteration: try: save = next(a for a in saves.keys() if skill.lower() in a.lower()) except StopIteration: return await ctx.send('That\'s not a valid save.') embed = EmbedWithCharacter(char, name=False) skill_effects = char.get_skill_effects() args += ' ' + skill_effects.get(save, '') # dicecloud v11 - autoadv args = await self.new_arg_stuff(args, ctx, char) adv = args.adv() b = args.join('b', '+') phrase = args.join('phrase', '\n') iterations = min(args.last('rr', 1, int), 25) dc = args.last('dc', type_=int) num_successes = 0 formatted_d20 = format_d20(adv, char.get_setting('reroll')) if b is not None: roll_str = formatted_d20 + '{:+}'.format(saves[save]) + '+' + b else: roll_str = formatted_d20 + '{:+}'.format(saves[save]) embed.title = args.last('title', '') \ .replace('[charname]', char.get_name()) \ .replace('[sname]', camel_to_title(save)) \ or '{} makes {}!'.format(char.get_name(), a_or_an(camel_to_title(save))) if iterations > 1: embed.description = (f"**DC {dc}**\n" if dc else '') + ('*' + phrase + '*' if phrase is not None else '') for i in range(iterations): result = roll(roll_str, adv=adv, inline=True) if dc and result.total >= dc: num_successes += 1 embed.add_field(name=f"Save {i+1}", value=result.skeleton) if dc: embed.set_footer(text=f"{num_successes} Successes | {iterations - num_successes} Failues") else: result = roll(roll_str, adv=adv, inline=True) if dc: embed.set_footer(text="Success!" if result.total >= dc else "Failure!") embed.description = (f"**DC {dc}**\n" if dc else '') + result.skeleton + ( '\n*' + phrase + '*' if phrase is not None else '') embeds.add_fields_from_args(embed, args.get('f')) if args.last('image') is not None: embed.set_thumbnail(url=args.last('image')) await ctx.send(embed=embed) try: await ctx.message.delete() except: pass