def test_roll(self): for i in range(0, 1000): result = roll('1d4, 1d6') self.assertEqual(len(result.keys()), 2) self.assertTrue(list(result.keys())[0] == '1d4') self.assertTrue(list(result.keys())[1] == '1d6') self.assertTrue(result['1d4'][0] >= 1 and result['1d4'][0] <= 4) self.assertTrue(result['1d6'][0] >= 1 and result['1d6'][0] <= 6) for i in range(0, 1000): result = roll('1d20, 1d20') self.assertEqual(len(result.keys()), 1) self.assertTrue(list(result.keys())[0] == '1d20') self.assertTrue(result['1d20'][0] >= 1 and result['1d20'][0] <= 20) self.assertTrue(result['1d20'][1] >= 1 and result['1d20'][1] <= 20)
def initiative_roll(command, txt_args, db, chat_id, username, **kargs): character = kargs.get('character') dice_notation = f'1d20+{character.dex_mod}' results = roll(dice_notation) dice_rolls = results[list(results.keys())[0]][0] return (f'@{username} initiative roll for {character.name}:' f'\r\nFormula: 1d20 + DEX({character.dex_mod})' f'\r\n*{dice_notation}*: {dice_rolls}')
def short_rest_roll(txt_args, db, chat_id, username): character = get_linked_character(db, chat_id, username) if character.hit_dice_used == character.level: return f'{character.name} spent all the hit dice already. You need to take a long rest to replenish them.' dice_notation = f'1d{character.hit_dice}+{character.con_mod}' results = roll(dice_notation) dice_rolls = results[list(results.keys())[0]][0] return f'@{username} short rest roll for {character.name} ({dice_notation}): {dice_rolls}'
def short_rest_roll(command, txt_args, db, chat_id, username, **kargs): character = kargs.get('character') if character.hit_dice_used == character.level: return f'{character.name} spent all the hit dice already. You need to take a long rest to replenish them.' dice_notation = f'1d{character.hit_dice}+{character.con_mod}' results = roll(dice_notation) dice_rolls = results[list(results.keys())[0]][0] return (f'@{username} short rest roll for {character.name}:' f'\r\nFormula: 1d{character.hit_dice} + CON({character.con_mod})' f'\r\n*{dice_notation}*: {dice_rolls}')
def ability_check(txt_args, db, chat_id, username): args = txt_args.split(' ') if len(args) == 0: return ('Invalid syntax. Usage:' '\r\n/ability_check <ability> (skill)') skill = None ability = args[0].lower() base_notation = '1d20' if len(args) == 2: skill = args[1].lower() if ability not in ABILITIES: return ('Invalid ability. Supported options: ' + ', '.join(ABILITIES)) if skill is not None and skill not in SKILLS[ability]: return ('Invalid skill. Supported options: ' + ', '.join(SKILLS[ability])) character = get_linked_character(db, chat_id, username) txt_skill_mod = '' txt_ability_mod = f' + {ability.upper()}({character.mods[ability]})' ability_desc = ability.upper() mods = character.mods[ability] if skill is not None: ability_desc = f'{ability_desc} ({skill.capitalize()})' mods += character.mods[skill] txt_skill_mod = f' + {skill.capitalize()}({character.mods[skill]})' txt_formula = f"{base_notation}{txt_ability_mod}{txt_skill_mod}" if mods > 0: dice_notation = f"{base_notation}+{mods}" else: dice_notation = base_notation results = roll(dice_notation) dice_rolls = results[list(results.keys())[0]] return ( f"@{username} ability check for {character.name} with {ability_desc}:" f"\r\nFormula: {txt_formula}" f"\r\n*{dice_notation}*: {dice_rolls}")
def attack_roll(txt_args, db, chat_id, username): args = [a.strip() for a in txt_args.split(' ')] if len(args) < 2: return ( 'Invalid syntax. Usage:' '\r\n/attack\\_roll <weapon|spell> <attack>(melee|range) \\[distance] \\[adv|disadv]' ) weapon_name = args[0] attack_type = args[1] distance = 5 if len(args) <= 2 else args[2] adv = False disadv = False if len(args) > 3 and args[3] == 'adv': adv = True elif len(args) > 3 and args[3] == 'disadv': disadv = True mods = 0 txt_mod = '' adv_mod = '' prof = '' base_notation = '1d20' try: distance = int(distance) except ValueError: raise InvalidCommand character = get_linked_character(db, chat_id, username) weapon = character.get_weapon(weapon_name) if weapon is None: #weapon = character.get_spell(weapon_name) #if weapon is None: return f"{character.name} doesn't have a weapon/spell called {weapon_name}" # TODO: Attack with spell # Attack with weapon if attack_type in ["ranged", "r"] and distance > weapon.long_range: return f"You can't attack a target beyond the range of your weapon ({weapon_name}, {weapon.long_range}ft)" prof = " + PRO(0)" if character.has_proficiency(weapon_name): mods += character.proficiency prof = f" + PRO({character.proficiency})" if attack_type in ["melee", "m"]: if weapon.has_finesse() and character.dex_mod > character.str_mod: txt_mod += f" + DEX({character.dex_mod})<finesse>" mods += character.dex_mod else: txt_mod += f" + STR({character.str_mod})" mods += character.str_mod elif attack_type in ["ranged", "r"]: if weapon.has_thrown() and character.str_mod > character.dex_mod: txt_mod += f" + STR({character.str_mod})<thrown>" mods += character.str_mod else: txt_mod += f" + DEX({character.dex_mod})" mods += character.dex_mod size_mod = SIZE_MODIFIER[character.size] txt_mod += f" + SIZE({size_mod})" mods += size_mod if attack_type in ["ranged", "r"] and \ (distance <= CLOSE_COMBAT_DISTANCE or (distance >= weapon.range and distance <= weapon.long_range)): if not adv: adv_mod = " + DISADV" elif disadv == True: adv_mod = " + DISADV" elif adv == True: adv_mod = " + ADV" txt_formula = f"{base_notation}{prof}{txt_mod}{adv_mod}" if mods > 0: dice_notation = f"{base_notation}+{mods}" else: dice_notation = base_notation if adv_mod != "": dice_notation = f"{dice_notation},{dice_notation}" results = roll(dice_notation) dice_rolls = results[list(results.keys())[0]] return ( f"@{username} attack roll for {character.name} with {weapon_name} ({attack_type}):" f"\r\nFormula: {txt_formula}" f"\r\n*{dice_notation}*: {dice_rolls}")
def initiative_roll(txt_args, db, chat_id, username): character = get_linked_character(db, chat_id, username) dice_notation = f'1d20+{character.dex_mod}' results = roll(dice_notation) dice_rolls = results[list(results.keys())[0]][0] return f'@{username} initiative roll for {character.name} ({dice_notation}): {dice_rolls}'