async def check(self, ctx, check, *args): """Rolls a check for your current active character. __Valid Arguments__ *adv/dis* *-b [conditional bonus]* -phrase [flavor text] -title [title] *note: [name] and [cname] will be replaced automatically* -dc [dc] -mc [minimum roll] -rr [iterations] str/dex/con/int/wis/cha (different skill base; e.g. Strength (Intimidation)) An italicized argument means the argument supports ephemeral arguments - e.g. `-b1` applies a bonus to one check. """ char: Character = await Character.from_ctx(ctx) skill_key = await search_and_select(ctx, SKILL_NAMES, check, lambda s: s) embed = EmbedWithCharacter(char, False) skill = char.skills[skill_key] args = await self.new_arg_stuff(args, ctx, char) checkutils.update_csetting_args(char, args, skill) checkutils.run_check(skill_key, char, args, embed) if args.last('image') is not None: embed.set_thumbnail(url=args.last('image')) await ctx.send(embed=embed) await try_delete(ctx.message)
async def save(self, ctx, skill, *args): """Rolls a save for your current active character. __Valid Arguments__ *adv/dis* *-b [conditional bonus]* -phrase [flavor text] -title [title] *note: [name] 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) An italicized argument means the argument supports ephemeral arguments - e.g. `-b1` applies a bonus to one save. """ 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, *args) char: Character = await Character.from_ctx(ctx) embed = EmbedWithCharacter(char, name=False) args = await self.new_arg_stuff(args, ctx, char) checkutils.update_csetting_args(char, args) checkutils.run_save(skill, char, args, embed) if args.last('image') is not None: embed.set_thumbnail(url=args.last('image')) # send await ctx.send(embed=embed) await try_delete(ctx.message)
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 save(self, ctx, skill, *args): """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, *args) char: Character = await Character.from_ctx(ctx) try: save = char.saves.get(skill) except ValueError: return await ctx.send('That\'s not a valid save.') embed = EmbedWithCharacter(char, name=False) args = await self.new_arg_stuff(args, ctx, char) 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 formatted_d20 = save.d20(base_adv=adv, reroll=char.get_setting('reroll')) if b: roll_str = f"{formatted_d20}+{b}" else: roll_str = formatted_d20 save_name = f"{verbose_stat(skill[:3]).title()} Save" if args.last('title'): embed.title = args.last('title', '') \ .replace('[charname]', char.name) \ .replace('[sname]', save_name) else: embed.title = f'{char.name} makes {a_or_an(save_name)}!' 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"Save {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 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
async def attack(self, ctx, atk_name=None, *, args: str = ''): """Rolls an attack for the current active character. __Valid Arguments__ -t "<target>" - Sets targets for the attack. You can pass as many as needed. Will target combatants if channel is in initiative. -t "<target>|<args>" - Sets a target, and also allows for specific args to apply to them. (e.g, -t "OR1|hit" to force the attack against OR1 to hit) *adv/dis* *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] *-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) -h (hides rolled values) -phrase [flavor text] -title [title] *note: [name] and [aname] will be replaced automatically* -thumb [url] -f "Field Title|Field Text" (see !embed) [user snippet] An italicized argument means the argument supports ephemeral arguments - e.g. `-d1` applies damage to the first hit, `-b1` applies a bonus to one attack, and so on.""" if atk_name is None: return await ctx.invoke(self.attack_list) char: Character = await Character.from_ctx(ctx) args = await self.new_arg_stuff(args, ctx, char) caster, targets, combat = await targetutils.maybe_combat(ctx, char, args) attack = await search_and_select(ctx, caster.attacks, atk_name, lambda a: a.name) embed = EmbedWithCharacter(char, name=False) if args.last('title') is not None: embed.title = args.last('title') \ .replace('[name]', char.name) \ .replace('[aname]', attack.name) else: embed.title = '{} attacks with {}!'.format(char.name, a_or_an(attack.name)) await attack.automation.run(ctx, embed, caster, targets, args, combat=combat, title=embed.title) if combat: await combat.final() _fields = args.get('f') embeds.add_fields_from_args(embed, _fields) if 'thumb' in args: embed.set_thumbnail(url=args.last('thumb')) await ctx.send(embed=embed) try: await ctx.message.delete() except: pass