Esempio n. 1
0
 def get_value(self) -> Union[int, float]:
     value = 0
     for mod in self.mods:
         if isinstance(mod, int):
             value += mod
         elif isinstance(mod, str):
             if '$' in mod:
                 # this contains character variables
                 mod = self.character.parse_vars(mod)
             value += basic(mod)
         elif isinstance(mod, list):
             if len(mod) == 0:
                 # Add zero to the value
                 continue
             largest = None
             for candidate in mod:
                 if isinstance(candidate, str):
                     if '$' in mod:
                         # this contains character variables
                         mod = self.character.parse_vars(mod)
                     candidate = basic(candidate)
                 # Take largest seen so far
                 if largest is None:
                     largest = candidate
                 elif candidate > largest:
                     largest = candidate
             value += largest
     return value
Esempio n. 2
0
 def startup_end(self):
     name = self.levelgain['Character Name?']
     cl = self.levelgain['Class to gain a level in?']
     path = 'character/' + h.sanitize_filename(name) + '.character'
     if os.path.exists(iface.JsonInterface.OBJECTSPATH / path):
         self.record = iface.JsonInterface(path)
     else:
         gui.ErrorMessage('A character with that name was not found.')
     clpath = 'class/' + h.sanitize_filename(cl) + '.class'
     if not os.path.exists(iface.JsonInterface.OBJECTSPATH / path):
         gui.ErrorMessage('A class with that name was not found.')
     self.character = c.Character(self.record)
     pattern = r'\s*([a-zA-Z\']+)\s*(\(([a-zA-Z\'\s]+)\))?'
     desc_ = re.match(pattern, cl).groups()
     desc = [str(item) for item in desc_ if item is not None]
     # desc should be a class and possibly a subclass name
     (rec, level) = self.character.classes.level_up(*desc)
     self.core = FeaturesAtLevel(self.f, rec.record, level)
     # Set new number of hit dice
     size = rec.hit_dice
     hdpath = '/HP/HD/' + size + '/maxnumber'
     hdn = self.character.get(hdpath)
     self.character.set(hdpath, hdn + 1)
     # Set new number of hit points
     conmod = h.modifier(self.character.get('/abilities/Constitution'))
     if self.levelgain['Average or roll for HP?'] == 'average':
         gain = d.basic(size, d.Mode.AVERAGE) + .5
     elif self.levelgain['Average or roll for HP?'] == 'roll':
         gain = d.basic(size)
     current = self.character.get('/HP/max')
     self.character.set('/HP/max', current + gain + conmod)
     self.draw_static()
     self.container.deiconify()
Esempio n. 3
0
 def __init__(self, data):
     self.name = data['name']
     self.HP = int(
         d.basic(data['HP'],
                 mode=d.Mode.from_string(
                     'average' if data.get('average') else 'normal')))
     self.maxHP = self.HP
     self.AC = data['AC']
     self.abilities = data['abilities']
     self.initiative = d.basic(h.d20_roll(),
                               modifiers=h.modifier(
                                   data['abilities']['Dexterity']))
     self.saves = data.get('saves', {})
Esempio n. 4
0
 def test_basic(self):
     self.assertEqual(basic('3d4'), 12)
     self.assertEqual(basic('3d4', mode=Mode.AVERAGE), 7.5)
     self.assertEqual(basic('3d6', mode=Mode.MAX), 18)
     self.assertEqual(basic('3d4', mode=Mode.CRIT), 24)
     self.assertEqual(basic('3d4', modifiers=4), 16)
     self.assertEqual(basic(2), 2)
     self.assertEqual(basic(2, modifiers=4), 6)
     with self.assertRaises(InputTypeError):
         basic([40, 2])
Esempio n. 5
0
    def change(self, amount):
        """Change the HP

        :param amount: A rollable amount
        :return: The actual change in HP
        """
        delta = basic(amount)
        if delta == 0:
            return 0
        if delta < 0:
            if abs(delta) > self.temp:
                # overflow beyond temp
                delta += self.temp
                self.temp = 0
                self.current += delta
                return delta
            else:
                # Temp absorbs it all
                self.temp += delta
                return 0
        else:
            # healing
            if self.current + delta > self.max:
                delta = self.max - self.current
            self.current += delta
            return delta
Esempio n. 6
0
    def add_temp(self, amount):
        """Add some temp HP

        :param amount: A rollable amount
        :return: The actual change in HP (always 0 because temp HP is not real)
        """
        delta = basic(amount)
        if delta > self.temp:
            self.temp = delta
        return 0
Esempio n. 7
0
 def use(self, number):
     if self.number < number:
         raise LowOnResource(self)
     self.number -= number
     if isinstance(self.value, str):
         return basic('+'.join([self.value] * number))
     elif isinstance(self.value, int):
         return number * self.value
     else:
         return 0
Esempio n. 8
0
 def death_save(self):
     if self.hp.current > 0:
         return ''
     roll = d.basic(h.d20_roll(luck=self.bonuses.get('lucky')))
     if roll == 20:
         self.hp.current = 1
         self.deathSaveFailures = 0
     if roll < 10:
         self.deathSaveFailures += 1
     if roll == 1:
         # add a second failure
         self.deathSaveFailures += 1
     if self.deathSaveFailures >= 3:
         raise ex.CharacterDead()
Esempio n. 9
0
async def massroll(ctx,
                   amt: int,
                   atk: str,
                   dmg: str = '0',
                   ac: int = 0,
                   short: str = ''):
    text = f'''```Massroll: {amt} rolls against AC {ac}'''
    textEnd = ''
    #emb = discord.Embed(title=f'Mass roll: {amt} rolls against AC {ac}')
    sumNum = 0
    sumCrits = 0
    try:
        dndice.basic(atk)
    except:
        ctx.send(f'{atk} is not valid roll syntax')
    try:
        dndice.basic(dmg)
    except:
        ctx.send(f'{dmg} is not valid roll syntax')

    for x in range(amt):
        atkRoll = dndice.basic(atk)
        dmgRoll = dndice.basic(dmg)

        if atkRoll == dice.roll_max(atk):
            critical = ', Critical!'
            sumCrits += 1
            dmgRoll = dndice.basic(dmg.replace('d', 'dc'))
        else:
            critical = ''

        if dmg != '0':
            textEnd += f"Attack n°{x}: {atkRoll}, damage: {dmgRoll}{critical}\n"
            #emb.add_field(name=f'Attack {x}', value=f'{critical}{atkRoll}, damage: {dmgRoll}')
        else:
            textEnd += f"Attack {x}: {critical}{atkRoll}\n"
            #emb.add_field(name=f'Attack {x}', value=f'{critical}{atkRoll}')

        if (atkRoll >= ac or critical == 'Critical Attack!: '):
            sumNum += dmgRoll
    text += f'''\n Sum of the Damage: {sumNum} damage'''
    text += f"\n Amount of critical attacks: {sumCrits}\n\n"
    if short == "short":
        pass
    elif (len(text) + len(textEnd) <= 1997):
        text += textEnd
    else:
        text += "Text is too long, detail doesnt fit."
    #emb.add_field(name=f'Sum of the Damage', value=f'{sumNum} damage')

    text += "```"
    await ctx.send(text)
Esempio n. 10
0
 def attack(self, which):
     advantage = self.adv.get()
     disadvantage = self.dis.get()
     attack_bonus = self.character.parse_vars(self.atkbonus.get(), False)
     damage_bonus = self.character.parse_vars(self.dambonus.get(), False)
     if which is None:
         attack = h.d20_roll(advantage, disadvantage, self.character.bonuses.get('lucky', False))
         attack += d.compile(attack_bonus)
         attackRoll = attack.evaluate()
         if attack.is_critical():
             attackRoll = 'Critical Hit!'
             damageRoll = d.basic(damage_bonus, mode=d.Mode.CRIT)
         elif attack.is_fail():
             attackRoll = 'Critical Miss.'
             damageRoll = 0
         else:
             # mode = 'execute'
             attackRoll = attack.verbose_result()
             damageRoll = d.basic(damage_bonus)
         result = ('Attack Roll: ' + str(attackRoll), 'Damage Roll: ' + str(damageRoll), '')
         # result = ('Attack Roll: ' + str(atk), 'Damage Roll: ' + str(dam), '')
     else:
         result = which.attack(self.character, advantage, disadvantage, attack_bonus, damage_bonus)
     self.output.update(*result)
Esempio n. 11
0
 def __init__(self,
              jf: DataInterface,
              character: 'char.Character',
              definition: DataInterface = None):
     super().__init__(jf, definition)
     self.owner = character
     val = character.parse_vars(self.value)
     if isinstance(val, str):
         # Evaluate parenthetical expressions for ease & clean expression later
         pattern = r'\(.*\)'
         rep = lambda m: str(basic(m.group(0)))
         new = re.sub(pattern, rep, val)
         self.value = new
     else:
         self.value = val
Esempio n. 12
0
 def __init__(self, data: dict):
     super().__init__(data['name'])
     self.record = iface.DataInterface(data)
     self.abilities = abil.Abilities(self.record.cd('/abilities'))
     self.initiative += self.abilities[abil.AbilityName.DEX].modifier
     self.hpRoll = data['HP']
     mode = Mode.from_string('average' if data.get('average') else 'normal')
     maxHP = int(basic(self.hpRoll, mode=mode))
     self.HP = hp.HP(
         iface.DataInterface({
             "current": maxHP,
             "max": maxHP,
             "temp": 0,
         }))
     self.AC = data['AC']
Esempio n. 13
0
 def alter_HP(self, amount):
     self.HP += d.basic(amount)
     self.HP = 0 if self.HP < 0 else self.maxHP if self.HP > self.maxHP else self.HP
Esempio n. 14
0
 def roll(self, advantage=False, disadvantage=False, lucky=False):
     d20 = d20_roll(advantage, disadvantage, lucky)
     return basic(d20, modifiers=self.ability.modifier)
Esempio n. 15
0
 def __init__(self, field, value, character: 'char.Character'):
     super().__init__(field, value)
     self.owner = character
     self.value = basic(self.owner.parse_vars(self.value))
Esempio n. 16
0
 def rollToHit(self, adv=False, dis=False, luck=False):
     rollstr = h.d20_string(adv, dis, luck) + ''.join(
         self.jf.get(self.path + '/roll_suffix'))
     mod = self.modifiers.get_value()
     return basic(rollstr, modifiers=mod)
Esempio n. 17
0
 def __init__(self, data):
     self.name = data['name']
     self.initiative = d.basic(data['init'])
Esempio n. 18
0
 def roll_initiative(custom=None) -> int:
     if custom:
         return basic(custom)
     else:
         return basic(h.d20_roll())
Esempio n. 19
0
        "(1d4-1)|(1d3-2>0)",
        "1dc8+1dc4+3",
        "1dm6+1d6",
        "2d4c2",
        "2da6",
        "3da6",
        "2d10%2",
        "1d4=4|1d4=3",
        "1d8>=6",
        "10d8r>4",
        "10d8R>4",
        "10d[3,3,3,5]",
        "10d[3, 3, 3, 5]",
        "15d6t5",
        "15d6T1",
    ]
    for expr in testCases:
        tree = EvalTree(expr)
        print('EVALUATING ' + expr)
        print('EVALUATING USING TREE DIRECTLY')
        print(tree.evaluate())
        print('EVALUATING USING ROLL FUNCTION')
        print(basic(expr))
        print('EVALUATING USING ROLL FUNCTION IN VERBOSE MODE')
        print(verbose(expr))
        print('EVALUATING USING ROLL FUNCTION AND MODIFIER')
        print(basic(expr, modifiers=3))
        print('EVALUATING USING ROLL FUNCTION IN VERBOSE MODE AND MODIFIER')
        print(verbose(expr, modifiers=3))
        print()