Exemplo n.º 1
0
 def test_side_effects(self):
     set_values([20, 15, 10, 3])
     with patch('game_engine.dice._random_int', side_effect=value):
         self.assertEqual(dice.d20(), 20)
         self.assertEqual(dice.d20(), 15)
         self.assertEqual(dice.d20(), 10)
         self.assertEqual(dice.d20(), 3)
Exemplo n.º 2
0
def roll_to_hit(attacker, target, attack, arena):
    # defaults
    hit = HitType.MISS

    # differences between weapons and monster attacks
    is_weapon = isinstance(attack, Weapon)

    if is_weapon:
        # get proficiency bonus for this weapon
        to_hit_mod = attacker.get_proficiency_bonus(attack)

        # pick either str or dex modifier as appropriate
        if attack.get_finesse():
            to_hit_mod += max(attacker.get_dex_mod(), attacker.get_str_mod())
        elif attack.is_melee():
            to_hit_mod += attacker.get_str_mod()
        elif attack.is_ranged():
            to_hit_mod += attacker.get_dex_mod()
    else:
        to_hit_mod = attack.get_to_hit()

    # TODO: determine advantage / disadvantage; flanking, etc.

    roll_type = RollType.NORMAL
    if is_weapon and attacker.wearing_unproficient_armor():
        roll_type = RollType.DISADVANTAGE

    # make the roll
    roll = dice.d20(roll_type)

    # if lucky can re-roll ones
    if roll == 1 and attacker.has_trait(Trait.LUCKY):
        roll = dice.d20()

    # natural rolls checked before applying modifiers
    if roll == 20:
        return HitType.CRITICAL_HIT
    elif roll == 1:
        return HitType.CRITICAL_MISS

    # fighting style modifications
    if attacker.has_trait(Trait.FIGHTING_STYLE_ARCHERY) and attack.is_ranged():
        roll += 2

    # defense fighting style applies to the defender
    ac_mod = 0
    if target.has_trait(Trait.FIGHTING_STYLE_DEFENCE) and target.get_armor() is not None:
        ac_mod += 1

    # determine outcome
    elif roll + to_hit_mod >= target.get_ac() + ac_mod:
        hit = HitType.HIT

    return hit
Exemplo n.º 3
0
 def roll_to_hit(self, target):
     # a natural 20 is always a hit, a critical hit
     # a natural 1 is always a miss
     # if modified roll >= AC its a hit
     roll = dice.d20()
     if roll == 20:
         return HitType.CRITICAL_HIT
     elif roll == 1:
         return HitType.CRITICAL_MISS
     else:
         if roll + self.to_hit >= target.get_ac():
             return HitType.HIT
     return HitType.MISS
Exemplo n.º 4
0
 def test_disadvantage(self):
     set_values([10, 15])
     with patch('game_engine.dice._random_int', side_effect=value):
         self.assertEqual(dice.d20(RollType.DISADVANTAGE), 10)
Exemplo n.º 5
0
 def test_d20_mock(self):
     with patch('game_engine.dice._random_int') as mock_roll:
         mock_roll.return_value = 35
         self.assertEqual(dice.d20(), 35)
Exemplo n.º 6
0
 def test_d20(self):
     self.assertTrue(1 <= dice.d20() <= 20)