示例#1
0
    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)
示例#2
0
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}')
示例#3
0
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}'
示例#4
0
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}')
示例#5
0
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}")
示例#6
0
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}")
示例#7
0
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}'