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)
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
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
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)
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)
def test_d20(self): self.assertTrue(1 <= dice.d20() <= 20)