mirror of
https://github.com/Threnklyn/dungeon-sheets.git
synced 2026-05-18 20:23:27 +02:00
622 lines
14 KiB
Python
622 lines
14 KiB
Python
from collections import defaultdict
|
|
|
|
from dungeonsheets import features as feats
|
|
from dungeonsheets import spells, weapons
|
|
from dungeonsheets.content_registry import default_content_registry
|
|
|
|
|
|
default_content_registry.add_module(__name__)
|
|
|
|
|
|
class Race:
|
|
name = "Unknown"
|
|
size = "medium"
|
|
speed = 30
|
|
owner = None
|
|
languages = ("Common",)
|
|
proficiencies_text = tuple()
|
|
weapon_proficiences = tuple()
|
|
skill_proficiencies = ()
|
|
skill_choices = ()
|
|
num_skill_choices = 0
|
|
features = tuple()
|
|
features_by_level = defaultdict(list)
|
|
strength_bonus = 0
|
|
dexterity_bonus = 0
|
|
constitution_bonus = 0
|
|
intelligence_bonus = 0
|
|
wisdom_bonus = 0
|
|
charisma_bonus = 0
|
|
hit_point_bonus = 0
|
|
spells_known = ()
|
|
|
|
def __init__(self, owner=None):
|
|
self.owner = owner
|
|
cls = type(self)
|
|
# Instantiate the features
|
|
self.features = tuple([f(owner=self.owner) for f in cls.features])
|
|
self.features_by_level = defaultdict(list)
|
|
for i in range(1, 21):
|
|
self.features_by_level[i] = [
|
|
f(owner=self.owner) for f in cls.features_by_level[i]
|
|
]
|
|
self.spells_known = [S() for S in cls.spells_known]
|
|
|
|
@property
|
|
def spells_prepared(self):
|
|
return self.spells_known
|
|
|
|
def __str__(self):
|
|
return self.name
|
|
|
|
def __repr__(self):
|
|
return '"{:s}"'.format(self.name)
|
|
|
|
|
|
# Dwarves
|
|
class _Dwarf(Race):
|
|
name = "Dwarf"
|
|
size = "medium"
|
|
speed = 25
|
|
languages = ("Common", "Dwarvish")
|
|
constitution_bonus = 2
|
|
proficiencies_text = ("battleaxes", "handaxes", "throwing hammers", "warhammers")
|
|
weapon_proficiences = (
|
|
weapons.Battleaxe,
|
|
weapons.Handaxe,
|
|
weapons.ThrowingHammer,
|
|
weapons.Warhammer,
|
|
)
|
|
features = (feats.Darkvision, feats.DwarvenResilience, feats.Stonecunning)
|
|
|
|
|
|
class HillDwarf(_Dwarf):
|
|
name = "Hill Dwarf"
|
|
wisdom_bonus = 1
|
|
hit_point_bonus = 1
|
|
features = _Dwarf.features + (feats.DwarvenToughness,)
|
|
|
|
|
|
class MountainDwarf(_Dwarf):
|
|
name = "Mountain Dwarf"
|
|
strength_bonus = 2
|
|
|
|
|
|
# Elves
|
|
class _Elf(Race):
|
|
name = "Elf"
|
|
size = "medium"
|
|
speed = 30
|
|
dexterity_bonus = 2
|
|
skill_proficiencies = ("perception",)
|
|
languages = ("Common", "Elvish")
|
|
features = (feats.Darkvision, feats.FeyAncestry, feats.Trance)
|
|
|
|
|
|
class HighElf(_Elf):
|
|
name = "High Elf"
|
|
weapon_proficiencies = (
|
|
weapons.Longsword,
|
|
weapons.Shortsword,
|
|
weapons.Shortbow,
|
|
weapons.Longbow,
|
|
)
|
|
proficiencies_text = ("longswords", "shortswords", "shortbows", "longbows")
|
|
intelligence_bonus = 1
|
|
languages = ("Common", "Elvish", "[choose one]")
|
|
features = _Elf.features + (feats.ElfCantrip,)
|
|
|
|
|
|
class WoodElf(_Elf):
|
|
name = "Wood Elf"
|
|
weapon_proficiencies = (
|
|
weapons.Longsword,
|
|
weapons.Shortsword,
|
|
weapons.Shortbow,
|
|
weapons.Longbow,
|
|
)
|
|
proficiencies_text = ("longswords", "shortswords", "shortbows", "longbows")
|
|
wisdom_bonus = 1
|
|
speed = 35
|
|
features = _Elf.features + (feats.MaskOfTheWild,)
|
|
|
|
|
|
class DarkElf(_Elf):
|
|
name = "Dark Elf"
|
|
weapon_proficiencies = (weapons.Rapier, weapons.Shortsword, weapons.HandCrossbow)
|
|
proficiencies_text = ("rapiers", "shortswords", "hand crossbows")
|
|
charisma_bonus = 1
|
|
features = (
|
|
feats.SuperiorDarkvision,
|
|
feats.FeyAncestry,
|
|
feats.Trance,
|
|
feats.SunlightSensitivity,
|
|
feats.DrowMagic,
|
|
)
|
|
spells_known = (spells.DancingLights,)
|
|
|
|
|
|
Drow = DarkElf
|
|
|
|
|
|
# Halflings
|
|
class _Halfling(Race):
|
|
name = "Halfling"
|
|
size = "small"
|
|
speed = 25
|
|
dexterity_bonus = 2
|
|
languages = ("Common", "Halfling")
|
|
features = (feats.Lucky, feats.Brave, feats.HalflingNimbleness)
|
|
|
|
|
|
class LightfootHalfling(_Halfling):
|
|
name = "Lightfoot Halfling"
|
|
charisma_bonus = 1
|
|
features = _Halfling.features + (feats.NaturallyStealthy,)
|
|
|
|
|
|
class StoutHalfling(_Halfling):
|
|
name = "Stout Halfling"
|
|
constitution_bonus = 1
|
|
features = _Halfling.features + (feats.StoutResilience,)
|
|
|
|
|
|
# Humans
|
|
class Human(Race):
|
|
name = "Human"
|
|
size = "medium"
|
|
speed = 30
|
|
strength_bonus = 1
|
|
dexterity_bonus = 1
|
|
constitution_bonus = 1
|
|
intelligence_bonus = 1
|
|
wisdom_bonus = 1
|
|
charisma_bonus = 1
|
|
languages = ("Common", "[choose one]")
|
|
|
|
|
|
class Rashemi(Human):
|
|
name = "Rashemi"
|
|
|
|
|
|
# Dragonborn
|
|
class Dragonborn(Race):
|
|
name = "Dragonborn"
|
|
size = "medium"
|
|
speed = 30
|
|
strength_bonus = 2
|
|
charisma_bonus = 1
|
|
languages = ("Common", "Draconic")
|
|
features = (feats.DraconicAncestry, feats.BreathWeapon, feats.DraconicResistance)
|
|
|
|
|
|
# Gnomes
|
|
class _Gnome(Race):
|
|
name = "Gnome"
|
|
size = "small"
|
|
speed = 25
|
|
intelligence_bonus = 2
|
|
languages = ("Common", "Gnomish")
|
|
features = (feats.Darkvision, feats.GnomeCunning)
|
|
|
|
|
|
class ForestGnome(_Gnome):
|
|
name = "Forest Gnome"
|
|
dexterity_bonus = 1
|
|
features = _Gnome.features + (feats.NaturalIllusionist, feats.SpeakWithSmallBeasts)
|
|
spells_known = (spells.MinorIllusion,)
|
|
|
|
|
|
class RockGnome(_Gnome):
|
|
name = "Rock Gnome"
|
|
constitution_bonus = 1
|
|
features = _Gnome.features + (feats.ArtificersLore, feats.Tinker)
|
|
|
|
|
|
class DeepGnome(_Gnome):
|
|
name = "Deep Gnome"
|
|
dexterity_bonus = 1
|
|
languages = ("Common", "Gnomish", "Undercommon")
|
|
features = (feats.SuperiorDarkvision, feats.GnomeCunning, feats.StoneCamouflage)
|
|
|
|
|
|
# Half-elves
|
|
class HalfElf(Race):
|
|
name = "Half-Elf"
|
|
size = "medium"
|
|
speed = 30
|
|
charisma_bonus = 2
|
|
skill_choices = (
|
|
"acrobatics",
|
|
"animal handling",
|
|
"arcana",
|
|
"athletics",
|
|
"deception",
|
|
"history",
|
|
"insight",
|
|
"intimidation",
|
|
"investigation",
|
|
"medicine",
|
|
"nature",
|
|
"perception",
|
|
"performance",
|
|
"persuasion",
|
|
"religion",
|
|
"sleight of hand",
|
|
"stealth",
|
|
"survival",
|
|
)
|
|
num_skill_choices = 2
|
|
languages = ("Common", "Elvish", "[choose one]")
|
|
features = (feats.Darkvision, feats.FeyAncestry)
|
|
|
|
|
|
# Half-Orcs
|
|
class HalfOrc(Race):
|
|
name = "Half-Orc"
|
|
size = "medium"
|
|
speed = 30
|
|
strength_bonus = 2
|
|
constitution_bonus = 1
|
|
skill_proficiencies = ("intimidation",)
|
|
languages = ("Common", "Orc")
|
|
features = (feats.Darkvision, feats.RelentlessEndurance, feats.SavageAttacks)
|
|
|
|
|
|
# Tieflings
|
|
class Tiefling(Race):
|
|
name = "Tiefling"
|
|
size = "medium"
|
|
speed = 30
|
|
intelligence_bonus = 1
|
|
charisma_bonus = 2
|
|
languages = ("Common", "Infernal")
|
|
features = (feats.Darkvision, feats.HellishResistance, feats.InfernalLegacy)
|
|
|
|
|
|
# Aasimar
|
|
class _Aasimar(Race):
|
|
name = "Aasimar"
|
|
size = "medium"
|
|
speed = 30
|
|
charisma_bonus = 2
|
|
languages = ("Common", "Celestial")
|
|
features = (
|
|
feats.Darkvision,
|
|
feats.CelestialResistance,
|
|
feats.HealingHands,
|
|
feats.LightBearer,
|
|
)
|
|
spells_known = (spells.Light,)
|
|
|
|
|
|
# Protector Aasimar
|
|
class ProtectorAasimar(_Aasimar):
|
|
name = "Protector Aasimar"
|
|
wisdom_bonus = 1
|
|
features_by_level = defaultdict(list)
|
|
features_by_level[3] += [feats.RadiantSoul]
|
|
|
|
|
|
# Fallen Aasimar
|
|
class ScourgeAasimar(_Aasimar):
|
|
name = "Scourge Aasimar"
|
|
constitution_bonus = 1
|
|
features_by_level = defaultdict(list)
|
|
features_by_level[3] += [feats.RadiantConsumption]
|
|
|
|
|
|
# Fallen Aasimar
|
|
class FallenAasimar(_Aasimar):
|
|
name = "Fallen Aasimar"
|
|
strength_bonus = 1
|
|
features_by_level = defaultdict(list)
|
|
features_by_level[3] += [feats.NecroticShroud]
|
|
|
|
|
|
# Firbolg
|
|
class Firbolg(Race):
|
|
name = "Firbolg"
|
|
size = "medium"
|
|
speed = 30
|
|
wisdom_bonus = 2
|
|
strength_bonus = 1
|
|
features = (
|
|
feats.FirbolgMagic,
|
|
feats.HiddenStep,
|
|
feats.PowerfulBuild,
|
|
feats.SpeechOfBeastAndLeaf,
|
|
)
|
|
languages = ("Common", "Elvish", "Giant")
|
|
|
|
|
|
# Goliath
|
|
class Goliath(Race):
|
|
name = "Goliath"
|
|
size = "Medium"
|
|
speed = 30
|
|
skill_proficiencies = ("athletics",)
|
|
languages = ("Common", "Giant")
|
|
features = (feats.StonesEndurance, feats.PowerfulBuild, feats.MountainBorn)
|
|
|
|
|
|
# Lizardfolk
|
|
class Lizardfolk(Race):
|
|
name = "Lizardfolk"
|
|
size = "medium"
|
|
speed = """30 (30 swim)"""
|
|
constitution_bonus = 2
|
|
wisdom_bonus = 1
|
|
languages = ("Common", "Draconic")
|
|
weapon_proficiencies = (weapons.Bite,)
|
|
proficiencies_text = ("bite",)
|
|
features = (
|
|
feats.CunningArtisan,
|
|
feats.HoldBreath,
|
|
feats.NaturalArmor,
|
|
feats.HungryJaws,
|
|
)
|
|
skill_choices = ("animal handling", "nature", "perception", "stealth", "survival")
|
|
|
|
def __init__(self, owner=None):
|
|
super().__init__(owner=owner)
|
|
self.owner.wield_weapon("bite")
|
|
|
|
|
|
# Kenku
|
|
class Kenku(Race):
|
|
name = "Kenku"
|
|
size = "medium"
|
|
speed = 30
|
|
dexterity_bonus = 2
|
|
wisdom_bonus = 1
|
|
languages = ("Common", "Auran")
|
|
skill_choices = ("acrobatics", "deception", "stealth", "sleight of hand")
|
|
num_skill_choices = 2
|
|
features = (
|
|
feats.ExpertForgery,
|
|
feats.Mimicry,
|
|
)
|
|
|
|
|
|
# Tabaxi
|
|
class Tabaxi(Race):
|
|
name = "Tabaxi"
|
|
size = "medium"
|
|
dexterity_bonus = 2
|
|
charisma_bonus = 1
|
|
speed = "30 (20 climb)"
|
|
languages = ("Common", "[Choose One]")
|
|
weapon_proficiencies = (weapons.Claws,)
|
|
proficiences_text = ("Claws",)
|
|
skill_proficiencies = ("perception", "stealth")
|
|
features = (
|
|
feats.Darkvision,
|
|
feats.FelineAgility,
|
|
)
|
|
|
|
def __init__(self, owner=None):
|
|
super().__init__(owner=owner)
|
|
self.owner.wield_weapon("claws")
|
|
|
|
|
|
# Triton
|
|
class Triton(Race):
|
|
name = "Triton"
|
|
size = "medium"
|
|
strength_bonus = 1
|
|
constitution_bonus = 1
|
|
charisma_bonus = 1
|
|
speed = "30 (30 swim)"
|
|
features = (
|
|
feats.Amphibious,
|
|
feats.ControlAirAndWater,
|
|
feats.EmissaryOfTheSea,
|
|
feats.GuardiansOfTheDepths,
|
|
)
|
|
languages = ("Common", "Primordial")
|
|
spells_known = (spells.FogCloud,)
|
|
|
|
|
|
# Aarakocra
|
|
class Aarakocra(Race):
|
|
name = "Aarakocra"
|
|
size = "medium"
|
|
speed = "25 (50 fly)"
|
|
dexterity_bonus = 2
|
|
wisdom_bonus = 1
|
|
languages = ("Common", "Aarakocra", "Auran")
|
|
weapon_proficiencies = (weapons.Talons,)
|
|
proficiences_text = ("Talons",)
|
|
|
|
def __init__(self, owner=None):
|
|
super().__init__(owner=owner)
|
|
self.owner.wield_weapon("talons")
|
|
|
|
|
|
# Genasi
|
|
class _Genasi(Race):
|
|
name = "Genasi"
|
|
constitution_bonus = 2
|
|
size = "medium"
|
|
speed = 30
|
|
languages = ("Common", "Primoridal")
|
|
|
|
|
|
class AirGenasi(_Genasi):
|
|
name = "Air Genasi"
|
|
dexterity_bonus = 1
|
|
features = (feats.UnendingBreath, feats.MingleWithTheWind)
|
|
|
|
|
|
class EarthGenasi(_Genasi):
|
|
name = "Earth Genasi"
|
|
strength_bonus = 1
|
|
features = (feats.EarthWalk, feats.MergeWithStone)
|
|
|
|
|
|
class FireGenasi(_Genasi):
|
|
name = "Fire Genasi"
|
|
intelligence_bonus = 1
|
|
features = (feats.Darkvision, feats.FireResistance, feats.ReachToTheBlaze)
|
|
|
|
|
|
class WaterGenasi(_Genasi):
|
|
name = "Water Genasi"
|
|
wisdom_bonus = 1
|
|
speed = "30 (30 swim)"
|
|
features = (feats.AcidResistance, feats.Amphibious, feats.CallToTheWave)
|
|
|
|
|
|
# Eberron Races
|
|
class Kalashtar(Race):
|
|
name = "Kalashtar"
|
|
wisdom_bonus = 2
|
|
charisma_bonus = 1
|
|
size = "medium"
|
|
speed = 30
|
|
languages = (
|
|
"Common",
|
|
"Quori",
|
|
) # Not sure how to have a "+1 language of your choice" - naviabbot
|
|
features = (
|
|
feats.DualMind,
|
|
feats.MentalDiscipline,
|
|
feats.MindLink,
|
|
feats.SeveredFromDreams,
|
|
)
|
|
|
|
|
|
class BugBear(Race):
|
|
name = "BugBear"
|
|
strength_bonus = 2
|
|
dexterity_bonus = 1
|
|
size = "medium"
|
|
speed = 30
|
|
features = (
|
|
feats.Darkvision,
|
|
feats.LongLimbed,
|
|
feats.PowerfulBuild,
|
|
feats.SupriseAttack,
|
|
)
|
|
skill_proficiencies = ("stealth",)
|
|
languages = ("Common", "Goblin")
|
|
|
|
|
|
class Goblin(Race):
|
|
name = "Goblin"
|
|
dexterity_bonus = 2
|
|
constitution_bonus = 1
|
|
size = "small"
|
|
speed = 30
|
|
features = (feats.Darkvision, feats.FuryOfTheSmall, feats.NimbleEscape)
|
|
languages = ("Common", "Goblin")
|
|
|
|
|
|
class HobGoblin(Race):
|
|
name = "HobGoblin"
|
|
constitution_bonus = 2
|
|
intelligence_bonus = 1
|
|
size = "medium"
|
|
speed = 30
|
|
features = (feats.Darkvision, feats.SavingFace)
|
|
proficiencies_text = ("light armor", "[Chose two martial melee weapons]")
|
|
languages = ("Common", "Goblin")
|
|
|
|
|
|
class Kobold(Race):
|
|
name = "Kobold"
|
|
dexterity_bonus = 2
|
|
strength_bonus = -2
|
|
size = "small"
|
|
speed = 30
|
|
features = (
|
|
feats.Darkvision,
|
|
feats.PackTactics,
|
|
feats.GrovelCowerAndBeg,
|
|
feats.SunlightSensitivity,
|
|
)
|
|
languages = ("Common", "Draconic")
|
|
|
|
|
|
class Orc(Race):
|
|
name = "Orc"
|
|
strength_bonus = 2
|
|
constitution_bonus = 1
|
|
intelligence_bonus = -2
|
|
size = "medium"
|
|
speed = 30
|
|
skill_proficiencies = ("intimidation",)
|
|
features = (feats.Darkvision, feats.Aggressive, feats.PowerfulBuild)
|
|
languages = ("Common", "Orc")
|
|
|
|
|
|
class PureBlood(Race):
|
|
name = "Yuan-Ti Pureblood"
|
|
charisma_bonus = 2
|
|
intelligence_bonus = 1
|
|
size = "medium"
|
|
speed = 30
|
|
features = (
|
|
feats.Darkvision,
|
|
feats.InnateSpellcasting,
|
|
feats.MagicResistance,
|
|
feats.PoisonImmunity,
|
|
)
|
|
spells_known = (spells.PoisonSpray,)
|
|
languages = ("Common", "Abyssal", "Draconic")
|
|
|
|
|
|
PHB_races = [
|
|
HillDwarf,
|
|
MountainDwarf,
|
|
HighElf,
|
|
WoodElf,
|
|
DarkElf,
|
|
LightfootHalfling,
|
|
StoutHalfling,
|
|
Rashemi,
|
|
Dragonborn,
|
|
ForestGnome,
|
|
RockGnome,
|
|
HalfElf,
|
|
HalfOrc,
|
|
Tiefling,
|
|
Human,
|
|
]
|
|
|
|
VOLO_races = [
|
|
ProtectorAasimar,
|
|
ScourgeAasimar,
|
|
FallenAasimar,
|
|
Firbolg,
|
|
Goliath,
|
|
Lizardfolk,
|
|
Kenku,
|
|
Tabaxi,
|
|
Triton,
|
|
]
|
|
|
|
EE_races = [Aarakocra, DeepGnome, AirGenasi, FireGenasi, EarthGenasi, WaterGenasi]
|
|
|
|
MONSTER_races = [BugBear, Goblin, HobGoblin, Kobold, Orc, PureBlood]
|
|
|
|
RFTLW_races = [Kalashtar]
|
|
|
|
# Guildmaster's Guide to Ravnica
|
|
GGTR_races = [Goblin]
|
|
|
|
available_races = (
|
|
PHB_races + VOLO_races + EE_races + MONSTER_races + RFTLW_races + GGTR_races
|
|
)
|
|
|
|
__all__ = tuple([r.name for r in available_races]) + (
|
|
"available_races",
|
|
"PHB_races",
|
|
"VOLO_races",
|
|
"EE_races",
|
|
"MONSTER_races",
|
|
"RFTLW_races",
|
|
"GGTR_races",
|
|
)
|