def __init__(self, cr, room_name="Any", name=None):
     super().__init__(cr, room_name, name)
     self.name = random_monster("villain") if not name else name
     self.dam_type = self.find_dam_type()
     self.background = random_background()
     self.treasure = get_loot(self.cr_val, monster_name=self.name, room_name=room_name, is_villain=True)
     self.special = self.special_abilities()
     self.weakness = self.special_weaknesses()
     self.at_will_dam = f"{smart_clamp(self.cr_val // 3, 1, 10)}d8 + {self.prof_bonus} {self.dam_type}"
     self.total_specials = 3
     self.stats = {
         ability: ability_dice(6) for ability in self.abilities
     }
     self.stats[random_value(list(self.stats.keys()))] += dice(2, 4)
     for key, val in self.stats.items():
         self.stats[key] = smart_clamp(self.stats[key], 3, 24)
     self.set_stat_mods()
     self.special_damage = f"{self.damage} {damage_types()}"
 def __init__(self, cr, room_name="Any", name=None):
     self.name = random_monster('monster') if not name else name
     self.cr = CR(cr)
     self.cr_val = self.cr.val
     self.tier = self.cr.tier
     self.cr_key = self.cr.key
     self.total_hp = self.set_hit_points(self.cr_val)
     self.current_hp = self.total_hp
     self.damage = (
         "1d2", "1d2 + 1", "1d2 + 2", "1d2 + 3",
         "1d6 + 8", "1d6 + 14", "1d6 + 20", "1d6 + 26", "1d6 + 32",
         "1d6 + 40", "1d6 + 45", "1d6 + 50", "1d6 + 65", "1d6 + 70",
         "1d8 + 75", "1d8 + 80", "1d8 + 85", "1d8 + 90", "1d8 + 95",
         "1d10 + 100", "1d10 + 105", "1d10 + 110", "1d10 + 115", "1d10 + 120",
         "1d12 + 140", "1d12 + 150", "1d12 + 160", "1d12 + 180", "1d12 + 200",
         "1d20 + 260", "1d20 + 270", "1d20 + 280", "1d20 + 290", "1d20 + 300",
     )[self.cr_key]
     self.xp = self.set_xp_by_cr(self.cr_val)
     self.motive = motivation()
     self.treasure = get_loot(self.cr_val, monster_name=self.name, room_name=room_name, is_villain=False)
     self.prof_bonus = self.set_prof_bonus(self.cr_val)
     variance = plus_or_minus_gauss(3)
     self.ac = self.set_ac(self.cr_val) + variance
     self.att_bonus = self.set_att_bonus(self.cr_val) + -variance
     self.save_dc = self.set_save_dc(self.cr_val)
     self.num_appearing = 1
     self.dam_type = self.find_dam_type()
     self.at_will_dam = f"{smart_clamp(self.cr_val // 3, 1, 10)}d6 + {self.prof_bonus} {self.dam_type}"
     self.rank_by_cr = tuple(x // 5 for x in range(34))
     self.abilities = ["STR", "DEX", "INT", "WIS", "CHA", "CON"]
     self.rank = self.rank_by_cr[self.cr.key]
     self.stats = {
         ability: ability_dice(4) for ability in self.abilities
     }
     self.stat_mod = {}
     self.stat_mod_str = {}
     self.set_stat_mods()
     self.special_damage = f"{self.damage} {damage_types()}"
 def __init__(self, cr, room_name="Any", name=None):
     super().__init__(cr, room_name, name=None)
     self.name = random_monster("boss") if not name else name
     self.dam_type = self.find_dam_type()
     while (len(self.treasure) - self.num_potions()) < 3:
         self.treasure += no_coin(get_loot(cr, monster_name=self.name, room_name="Lair", is_villain=True))
     self.total_specials = 5
     if "Legendary" in self.name:
         self.treasure += get_loot(cr, monster_name=self.name, room_name=room_name, is_villain=True)
         second_ability = self.special_abilities()
         while second_ability is self.special:
             second_ability = self.special_abilities()
         self.special += f"\nSpecial Ability: {second_ability}"
     self.at_will_dam = f"{smart_clamp(self.cr_val // 3, 1, 10)}d10 + {self.prof_bonus} {self.dam_type}"
     self.stats = {
         ability: ability_dice(7) for ability in self.abilities
     }
     for _ in range(3):
         self.stats[random_value(list(self.stats.keys()))] += dice(2, 6)
     for key, val in self.stats.items():
         self.stats[key] = smart_clamp(self.stats[key], 3, 30)
     self.set_stat_mods()
     self.special_damage = f"{self.damage} {damage_types()}"
 def __init__(self, cr, room_name="Any", name=None):
     minion_cr = cr - 3 if cr < 6 else cr // 2
     minion_cr = smart_clamp(minion_cr, -3, 17)
     minion_name = name or random_monster("minion")
     super().__init__(minion_cr, room_name, minion_name)
     self.dam_type = self.find_dam_type()
     self.num_appearing = dice(2, 2)
     self.stats = {
         ability: ability_dice(7) for ability in self.abilities
     }
     self.set_stat_mods()
     self.individual_hp = max(1, int(self.total_hp // self.num_appearing))
     self.treasure = Loot()
     self.damage_dice = (
         "1d2", "1d2", "1d4", "1d4",
         "1d6", "1d6", "1d6", "1d6", "1d6",
         "1d6", "1d6", "1d6", "1d6", "1d6",
         "1d8", "1d8", "1d8", "1d8", "1d8",
         "1d10", "1d10", "1d10", "1d10", "1d10",
         "1d12", "1d12", "1d12", "1d12", "1d12",
         "1d20", "1d20", "1d20", "1d20", "1d20"
     )[minion_cr + 3]
     self.damage_bonus = (
         0, 2, 4, 6,
         8, 14, 20, 26, 32,
         40, 45, 50, 65, 70,
         75, 80, 85, 90, 95,
         100, 105, 110, 115, 120,
         140, 150, 160, 180, 200,
         260, 270, 280, 290, 300
     )[minion_cr + 3]
     actual_damage_bonus = self.damage_bonus // self.num_appearing
     if actual_damage_bonus > 0:
         self.individual_dam = f"{self.damage_dice} + {actual_damage_bonus}"
     else:
         self.individual_dam = f"{self.damage_dice}"
     self.at_will_dam = f"{smart_clamp(self.cr_val // 5, 1, 5)}d4 + {self.prof_bonus} {self.dam_type}"
 def __init__(self, cr, name=None):
     n = name if name else random_monster("campaign boss")
     super().__init__(cr, name=n)
     while (len(self.treasure) - self.num_potions()) < self.tier:
         self.treasure += no_coin(get_loot(cr, monster_name=self.name, room_name="Lair", is_villain=True))