mirror of
https://github.com/Threnklyn/dungeon-sheets.git
synced 2026-06-07 13:15:53 +02:00
version 0.9.0: added PHB warlock invocations
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
"""This file describes the heroic adventurer Ben.
|
||||
|
||||
It's used primarily for saving characters from create-character,
|
||||
where there will be many missing sections.
|
||||
|
||||
Modify this file as you level up and then re-generate the character
|
||||
sheet by running ``makesheets`` from the command line.
|
||||
|
||||
"""
|
||||
|
||||
dungeonsheets_version = "0.8.3"
|
||||
|
||||
name = "Ben"
|
||||
classes_levels = ['paladin 1']
|
||||
subclasses = ["Oath of The Ancients"]
|
||||
player_name = "Ben"
|
||||
background = "Charlatan"
|
||||
race = "Hill Dwarf"
|
||||
alignment = "Neutral good"
|
||||
xp = 0
|
||||
hp_max = 10
|
||||
|
||||
# Ability Scores
|
||||
strength = 15
|
||||
dexterity = 14
|
||||
constitution = 15
|
||||
intelligence = 12
|
||||
wisdom = 11
|
||||
charisma = 8
|
||||
|
||||
# Select what skills you're proficient with
|
||||
skill_proficiencies = ('intimidation', 'athletics', 'deception', 'sleight of hand')
|
||||
|
||||
# Named features / feats that aren't part of your classes,
|
||||
# race, or background.
|
||||
# Example:
|
||||
# features = ('Tavern Brawler',) # take the optional Feat from PHB
|
||||
features = ()
|
||||
|
||||
# If selecting among multiple feature options: ex Fighting Style
|
||||
# Example (Fighting Style):
|
||||
# feature_choices = ('Archery',)
|
||||
feature_choices = ()
|
||||
|
||||
# Proficiencies and languages
|
||||
languages = """Common, Dwarvish"""
|
||||
|
||||
# Inventory
|
||||
# TODO: Get yourself some money
|
||||
cp = 0
|
||||
sp = 0
|
||||
ep = 0
|
||||
gp = 0
|
||||
pp = 0
|
||||
|
||||
# TODO: Put your equipped weapons and armor here
|
||||
weapons = () # Example: ('shortsword', 'longsword')
|
||||
armor = "" # Eg "light leather armor"
|
||||
shield = "" # Eg "shield"
|
||||
|
||||
equipment = """TODO: list the equipment and magic items your character carries"""
|
||||
|
||||
attacks_and_spellcasting = """TODO: Describe how your character usually attacks
|
||||
or uses spells."""
|
||||
|
||||
# List of known spells
|
||||
# Example: spells_prepared = ('magic missile', 'mage armor')
|
||||
spells_prepared = () # Todo: Learn some spells
|
||||
|
||||
# Which spells have not been prepared
|
||||
__spells_unprepared = ()
|
||||
|
||||
# all spells known
|
||||
spells = spells_prepared + __spells_unprepared
|
||||
|
||||
# Backstory
|
||||
# Describe your backstory here
|
||||
personality_traits = """TODO: How does your character behave? See the PHB for
|
||||
examples of all the sections below"""
|
||||
|
||||
ideals = """TODO: What does your character believe in?"""
|
||||
|
||||
bonds = """TODO: Describe what debts your character has to pay,
|
||||
and other commitments or ongoing quests they have."""
|
||||
|
||||
flaws = """TODO: Describe your characters interesting flaws.
|
||||
"""
|
||||
|
||||
features_and_traits = """TODO: Describe other features and abilities your
|
||||
character has."""
|
||||
@@ -1,5 +1,4 @@
|
||||
Add multiclass proficiencies to classes
|
||||
|
||||
Add Warlock Incantations
|
||||
Add Warlock multiclass spell slots
|
||||
|
||||
@@ -7,11 +6,6 @@ Add disadvantage on STEALTH with armor
|
||||
|
||||
Add race / class AC bonuses
|
||||
|
||||
Add subclasses
|
||||
Add features
|
||||
Auto-add features to PDF
|
||||
Add features description LaTeX page
|
||||
**hard** integrate features automatically into math
|
||||
|
||||
Add Character.save() option to save to text file
|
||||
Add Inspiration points
|
||||
|
||||
@@ -12,7 +12,8 @@ class Background():
|
||||
languages = ()
|
||||
|
||||
def __init__(self):
|
||||
self.features = tuple([f() for f in self.features])
|
||||
cls = type(self)
|
||||
self.features = tuple([f() for f in cls.features])
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
+15
-13
@@ -137,10 +137,6 @@ class Character():
|
||||
'race': race,
|
||||
'background': background})
|
||||
self.set_attrs(**attrs)
|
||||
# instantiate any spells not listed properly
|
||||
for S in self.spells_prepared:
|
||||
if S not in [type(spl) for spl in self.spells]:
|
||||
self._spells += (S(),)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
@@ -153,6 +149,10 @@ class Character():
|
||||
return ' / '.join([f'{c.class_name} {c.class_level}'
|
||||
for c in self.class_list])
|
||||
|
||||
@property
|
||||
def subclasses(self):
|
||||
return list([c.subclass or '' for c in self.class_list])
|
||||
|
||||
@property
|
||||
def speed(self):
|
||||
return getattr(self.race, 'speed', 30)
|
||||
@@ -259,7 +259,7 @@ class Character():
|
||||
|
||||
@property
|
||||
def spells(self):
|
||||
spells = set(self._spells)
|
||||
spells = set(self._spells) | set(self._spells_prepared)
|
||||
for f in self.features:
|
||||
spells |= set(f.spells_known) | set(f.spells_prepared)
|
||||
for c in self.spellcasting_classes:
|
||||
@@ -333,7 +333,7 @@ class Character():
|
||||
name=f, source='Unknown',
|
||||
__doc__="""Unknown Feature. Add to features.py"""))
|
||||
warnings.warn(msg)
|
||||
self.custom_features = tuple(F() for F in _features)
|
||||
self.custom_features += tuple(F() for F in _features)
|
||||
elif (attr == 'spells') or (attr == 'spells_prepared'):
|
||||
# Create a list of actual spell objects
|
||||
_spells = []
|
||||
@@ -555,16 +555,18 @@ class Character():
|
||||
assert len(classes_levels) == len(subclasses), (
|
||||
'the length of classes_levels {:d} does not match length of '
|
||||
'subclasses {:d}'.format(len(classes_levels), len(subclasses)))
|
||||
circle = char_props.pop('circle', None)
|
||||
class_list = []
|
||||
for cl, sub in zip(classes_levels, subclasses):
|
||||
try:
|
||||
c, lvl = cl.strip().split(' ') # " wizard 3 " => "wizard", "3"
|
||||
c, _, lvl = cl.strip().rpartition(' ') # " wizard 3 " => "wizard", "3"
|
||||
c = c.title().replace(' ', '')
|
||||
except ValueError:
|
||||
raise ValueError(
|
||||
'classes_levels not properly formatted. Each entry should '
|
||||
'be formatted \"class level\", but got {:s}'.format(cl))
|
||||
try:
|
||||
this_class = getattr(classes, c.capitalize())
|
||||
this_class = getattr(classes, c)
|
||||
this_level = int(lvl)
|
||||
except AttributeError:
|
||||
raise AttributeError(
|
||||
@@ -572,6 +574,8 @@ class Character():
|
||||
except ValueError:
|
||||
raise ValueError(
|
||||
'level was not recognizable as an int: {:s}'.format(lvl))
|
||||
if issubclass(this_class, classes.Druid):
|
||||
sub = circle or sub
|
||||
params = {}
|
||||
params['feature_choices'] = char_props.get('feature_choices', [])
|
||||
class_list += [this_class(this_level, subclass=sub, **params)]
|
||||
@@ -592,7 +596,7 @@ class Character():
|
||||
char=self,
|
||||
)
|
||||
# Render the template
|
||||
src_path = os.path.dirname(__file__)
|
||||
src_path = os.path.join(os.path.dirname(__file__), 'forms/')
|
||||
text = jinja2.Environment(
|
||||
loader=jinja2.FileSystemLoader(src_path or './')
|
||||
).get_template(template_file).render(context)
|
||||
@@ -601,12 +605,10 @@ class Character():
|
||||
f.write(text)
|
||||
|
||||
def to_pdf(self, filename, **kwargs):
|
||||
from .make_sheets import make_sheet
|
||||
if filename.endswith('.pdf'):
|
||||
filename = filename.replace('pdf', 'py')
|
||||
self.save(filename,
|
||||
template_file=kwargs.get('template_file',
|
||||
'character_template.txt'))
|
||||
subprocess.call(['makesheets', filename)
|
||||
make_sheet(filename, char=self, flatten=kwargs.get('flatten', True))
|
||||
|
||||
|
||||
def read_character_file(filename):
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
__all__ = ('CharClass', 'Barbarian', 'Bard', 'Cleric', 'Druid', 'Fighter',
|
||||
'Monk', 'Paladin', 'Ranger', 'Rogue', 'Sorceror', 'Warlock',
|
||||
'Wizard', 'Revisedranger', 'available_classes')
|
||||
'Wizard', 'RevisedRanger', 'available_classes')
|
||||
|
||||
from .classes import CharClass
|
||||
from .barbarian import Barbarian
|
||||
@@ -10,11 +10,11 @@ from .druid import Druid
|
||||
from .fighter import Fighter
|
||||
from .monk import Monk
|
||||
from .paladin import Paladin
|
||||
from .ranger import (Ranger, Revisedranger)
|
||||
from .ranger import (Ranger, RevisedRanger)
|
||||
from .rogue import Rogue
|
||||
from .sorceror import Sorceror
|
||||
from .warlock import Warlock
|
||||
from .wizard import Wizard
|
||||
|
||||
available_classes = [Barbarian, Bard, Cleric, Druid, Fighter, Monk, Ranger,
|
||||
Rogue, Sorceror, Warlock, Wizard, Revisedranger]
|
||||
available_classes = [Barbarian, Bard, Cleric, Druid, Fighter, Monk, Paladin,
|
||||
Ranger, Rogue, Sorceror, Warlock, Wizard, RevisedRanger]
|
||||
|
||||
@@ -1,15 +1,113 @@
|
||||
from .. import (weapons)
|
||||
from .. import features as feats
|
||||
from .classes import CharClass
|
||||
from .. import (features, weapons)
|
||||
from .classes import (CharClass, SubClass)
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
# PHB
|
||||
class BerserkerPath(SubClass):
|
||||
"""For some barbarians, rage is a means to an end-—that end being
|
||||
violence. The Path of the Berserker is a path of untrammeled fury, slick
|
||||
with blood. As you enter the berserker’s rage, you thrill in the chaos of
|
||||
battle, heedless of your own health or well-being.
|
||||
|
||||
"""
|
||||
name = "Path of the Berserker"
|
||||
class_features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class TotemWarriorPath(SubClass):
|
||||
"""The Path of the Totem Warrior is a spiritual journey, as the barbarian
|
||||
accepts a spirit animal as guide, protector, and inspiration. In battle,
|
||||
your totem spirit fills you with supernatural might, adding magical fuel to
|
||||
your barbarian rage.
|
||||
|
||||
Most barbarian tribes consider a totem animal to be kin to a particular
|
||||
clan. In such cases, it is unusual for an individual to have more than one
|
||||
totem animal spirit, though exceptions exist.
|
||||
|
||||
"""
|
||||
name = "Path of the Totem Warrior"
|
||||
class_features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
# SCAG
|
||||
class BattleragerPath(SubClass):
|
||||
"""Known as Kuldjargh (literally "axe idiot") in Dwarvish, battleragers are
|
||||
dwarf followers of the gods of war and take the Path of the
|
||||
Battlerager. They specialize in wearing bulky, spiked armor and throwing
|
||||
themselves into combat, striking with their body itself and giving
|
||||
themselves over to the fury of battle.
|
||||
|
||||
"""
|
||||
name = "Path of the Battlerager"
|
||||
class_features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
# XGTE
|
||||
class AncestralGuardianPath(SubClass):
|
||||
"""Some barbarians hail from cultures that revere their ancestors. These
|
||||
tribes teach that the warriors of the past linger in the world as mighty
|
||||
spirits, who can guide and protect the living. When a barbarian who follows
|
||||
this path rages, the barbarian contacts the spirit world and calls on these
|
||||
guardian spirits for aid.
|
||||
|
||||
Barbarians who draw on their ancestral guardians can better fight to
|
||||
protect their tribes and their allies. In order to cement ties to their
|
||||
ancestral guardians, barbarians who follow this path cover themselves in
|
||||
elabo— rate tattoos that celebrate their ancestors’ deeds. These tattoos
|
||||
tell sagas of victories against terrible monsters and other fearsome
|
||||
rivals.
|
||||
|
||||
"""
|
||||
name = "Path of the Ancestral Guardian"
|
||||
class_features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class StormHeraldPath(SubClass):
|
||||
"""All barbarians harbor a fury within. Their rage grants them superior
|
||||
strength, durability, and speed. Barbarians who follow the Path of the
|
||||
Storm Herald learn to transform that rage into a mantle of primal magic,
|
||||
which swirls around them. When in a fury, a barbarian ofthis path taps into
|
||||
the forces of nature to create powerful magical effects.
|
||||
|
||||
Storm heralds are typically elite champions who train alongside druids,
|
||||
rangers, and others sworn to protect nature. Other storm heralds hone their
|
||||
craft in lodges in regions wracked by storms, in the frozen reaches at the
|
||||
world’s end, or deep in the hottest deserts.
|
||||
|
||||
"""
|
||||
name = "Path of the Storm Herald"
|
||||
class_features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class ZealotPath(SubClass):
|
||||
"""Some deities inspire their followers to pitch themselves into a ferocious
|
||||
battle fury. These barbarians are zealots—warriors who channel their rage
|
||||
into powerful disn plays of divine power.
|
||||
|
||||
A variety of gods across the worlds of D&D inspire their followers to
|
||||
embrace this path. Tempus from the Forgotten Realms and Hextor and Erythnul
|
||||
of Greyhawk are all prime examples. In general, the gods who inspire
|
||||
zealots are deities of combat, destruction, and violence. Not all are evil,
|
||||
but few are good
|
||||
|
||||
"""
|
||||
name = "Path of the Zealot"
|
||||
class_features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class Barbarian(CharClass):
|
||||
class_name = 'Barbarian'
|
||||
hit_dice_faces = 12
|
||||
saving_throw_proficiencies = ('strength', 'constitution')
|
||||
weapon_proficiencies = (weapons.simple_weapons + weapons.martial_weapons)
|
||||
_proficiencies_text = ('light armor', 'medium armor', 'shields',
|
||||
'simple weapons', 'martial weapons')
|
||||
weapon_proficiencies = (weapons.simple_weapons + weapons.martial_weapons)
|
||||
multiclass_weapon_proficiencies = weapon_proficiencies
|
||||
_multiclass_proficiencies_text = ('shields', 'simple weapons', 'martial weapons')
|
||||
class_skill_choices = ('Animal Handling', 'Athletics',
|
||||
'Intimidation', 'Nature', 'Perception', 'Survival')
|
||||
subclasses_available = (BerserkerPath, TotemWarriorPath, BattleragerPath,
|
||||
AncestralGuardianPath, StormHeraldPath, ZealotPath)
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
@@ -1,6 +1,116 @@
|
||||
from .. import (weapons)
|
||||
from .. import features as feats
|
||||
from .classes import CharClass
|
||||
from .. import (weapons, features)
|
||||
from .classes import CharClass, SubClass
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
# PHB
|
||||
class CollegeOfLore(SubClass):
|
||||
"""Bards of the College o f Lore know something about most things, collecting
|
||||
bits of knowledge from sources as diverse as scholarly tomes and peasant
|
||||
tales. Whether singing folk ballads in taverns or elaborate compositions in
|
||||
royal courts, these bards use their gifts to hold audiences
|
||||
spellbound. When the applause dies down, the audience members might find
|
||||
themselves questioning everything they held to be true, from their faith in
|
||||
the priesthood of the local temple to their loyalty to the king.
|
||||
|
||||
The loyalty of these bards lies in the pursuit of beauty and truth, not in
|
||||
fealty to a monarch or following the tenets of a deity. A noble who keeps
|
||||
such a bard as a herald or advisor knows that the bard would rather be
|
||||
honest than politic.
|
||||
|
||||
The college’s members gather in libraries and sometimes in actual colleges,
|
||||
complete with classrooms and dormitories, to share their lore with one
|
||||
another. They also meet at festivals or affairs of state, where they can
|
||||
expose corruption, unravel lies, and poke fun at selfimportant figures of
|
||||
authority.
|
||||
|
||||
"""
|
||||
name = "College of Lore"
|
||||
class_features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class CollegeOfValor(SubClass):
|
||||
"""Bards of the College of Valor are daring skalds whose tales keep alive the
|
||||
memory of the great heroes of the past, and thereby inspire a new
|
||||
generation of heroes. These bards gather in mead halls or around great
|
||||
bonfires to sing the deeds of the mighty, both past and present. They
|
||||
travel the land to witness great events firsthand and to ensure that the
|
||||
memory of those events doesn’t pass from the world. With their songs, they
|
||||
inspire others to reach the same heights of accomplishment as the heroes of
|
||||
old
|
||||
|
||||
"""
|
||||
name = "College of Valor"
|
||||
class_features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
# XGTE
|
||||
class CollegeOfGlamour(SubClass):
|
||||
"""The College of Glamour is the home Of bards who mas— tered their craft in
|
||||
the vibrant realm of the Feywild or under the tutelage Of someone who
|
||||
dwelled there. Tutored by satyrs, eladrin, and other fey, these bards
|
||||
learn to use their magic to delight and captivate others.
|
||||
|
||||
The bards of this college are regarded with a mixture of awe and
|
||||
fear. Their performances are the stuff of legend. These bards are so
|
||||
eloquent that a speech or song that one of them performs can cause captors
|
||||
tO release the bard unharmed and can lull a furious dragon into
|
||||
complacency. The same magic that allows them to quell beasts can also bend
|
||||
minds. Villainous bards Of this college can leech Off a community for
|
||||
weeks, misusing their magic to turn their hosts into thralls. Heroic bards
|
||||
of this college instead use this power to gladden the downtrodden and
|
||||
undermine oppressors.
|
||||
|
||||
"""
|
||||
name = "College of Glamour"
|
||||
class_features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class CollegeOfSwords(SubClass):
|
||||
"""Bards of the College of Swords are called blades, and they entertain
|
||||
through daring feats of weapon prowess. Blades perform stunts such as sword
|
||||
swallowing, knife throwing and juggling, and mock combats. Though they use
|
||||
their weapons to entertain, they are also highly trained and skilled
|
||||
warriors in their own right.
|
||||
|
||||
Their talent with weapons inspires many blades to lead double lives. One
|
||||
blade might use a circus troupe as cover for nefarious deeds such as
|
||||
assassination, robbery, and blackmail. Other blades strike at the wicked,
|
||||
bringingjustice to bear against the cruel and powerful. Most troupes are
|
||||
happy to accept a blade’s talent for the excitement it adds to a
|
||||
performance, but few entertainers fully trust a blade in their ranks.
|
||||
|
||||
Blades who abandon their lives as entertainers have often run into trouble
|
||||
that makes maintaining their secret activities impossible. A blade caught
|
||||
stealing or engaging in vigilante justice is too great a liability for most
|
||||
troupes. With their weapon skills and magic, these blades either take up
|
||||
work as enforcers for thieves’ guilds or strike out on their own as
|
||||
adventurers.
|
||||
|
||||
"""
|
||||
name = "College of Swords"
|
||||
class_features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class CollegeOfWhispers(SubClass):
|
||||
"""Most folk are happy to welcome a bard into their midst. Bards of the
|
||||
College of Whispers use this to their advantage. They appear to be like
|
||||
other bards, sharing news, singing songs, and telling tales to the
|
||||
audiences they gather. In truth, the College of Whispers teaches its
|
||||
students that they are wolves among sheep. These bards use their knowledge
|
||||
and magic to uncover secrets and turn them against others through extortion
|
||||
and threats.
|
||||
|
||||
Many other bards hate the College of Whispers, viewing it as a parasite
|
||||
that uses a bard’s reputation to acquire wealth and power. For this reason,
|
||||
members of this college rarely reveal their true nature. They typically
|
||||
claim to follow some other college, or they keep their actual calling
|
||||
secret in order to infiltrate and exploit royal courts and other settings
|
||||
of power
|
||||
|
||||
"""
|
||||
name = "College of Whispers"
|
||||
class_features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class Bard(CharClass):
|
||||
@@ -19,7 +129,13 @@ class Bard(CharClass):
|
||||
'Nature', 'Perception', 'Performance', 'Persuasion',
|
||||
'Religion', 'Sleight of Hand', 'Stealth',
|
||||
'Survival')
|
||||
multiclass_weapon_proficiencies = ()
|
||||
_multiclass_proficiencies_text = ('Light Armor', '[choose one skill]',
|
||||
'[choose one musical instrument]')
|
||||
num_skill_choices = 3
|
||||
features_by_level = defaultdict(list)
|
||||
subclasses_available = (CollegeOfLore, CollegeOfValor, CollegeOfGlamour,
|
||||
CollegeOfSwords, CollegeOfWhispers)
|
||||
spellcasting_ability = 'charisma'
|
||||
spell_slots_by_level = {
|
||||
# char_lvl: (cantrips, 1st, 2nd, 3rd, ...)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from collections import defaultdict
|
||||
from ..features import Feature, FeatureSelector
|
||||
|
||||
|
||||
class CharClass():
|
||||
@@ -23,25 +24,66 @@ class CharClass():
|
||||
subclasses_available = ()
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
def __init__(self, level, subclass=None, **params):
|
||||
def __init__(self, level, subclass=None, feature_choices=[],
|
||||
**params):
|
||||
self.class_level = level
|
||||
if subclass in [None, '', 'None']:
|
||||
self.subclass = None
|
||||
else:
|
||||
self.subclass = subclass
|
||||
# Instantiate the features
|
||||
self.features_by_level = defaultdict(list)
|
||||
cls = type(self)
|
||||
for i in range(1, 21):
|
||||
fs = []
|
||||
for f in cls.features_by_level[i]:
|
||||
if issubclass(f, FeatureSelector):
|
||||
fs.append(f(feature_choices=feature_choices))
|
||||
elif issubclass(f, Feature):
|
||||
fs.append(f())
|
||||
fs = [f() for f in cls.features_by_level[i]]
|
||||
self.features_by_level[i] = fs
|
||||
for k, v in params.items():
|
||||
setattr(self, k, v)
|
||||
# Instantiate the features
|
||||
|
||||
# Apply subclass
|
||||
self.subclass = self.select_subclass(subclass)
|
||||
if isinstance(self.subclass, SubClass):
|
||||
self.apply_subclass()
|
||||
|
||||
def select_subclass(self, subclass_str):
|
||||
"""
|
||||
Return a SubClass object corresponding to given string.
|
||||
|
||||
Intended to be replaced by classes so they can
|
||||
define their own methods of picking subclass by string.
|
||||
"""
|
||||
if subclass_str in ['', 'None', 'none', None]:
|
||||
return None
|
||||
for sc in self.subclasses_available:
|
||||
if subclass_str.lower() in sc.name.lower():
|
||||
return sc(level=self.class_level)
|
||||
return None
|
||||
|
||||
def apply_subclass(self):
|
||||
if self.subclass is None:
|
||||
return
|
||||
for i in range(1, 21):
|
||||
self.features_by_level[i] = [f() for f in self.features_by_level[i]]
|
||||
self.features_by_level[i] += ([f() for f in
|
||||
self.subclass.features_by_level[i]])
|
||||
for attr in ('weapon_proficiencies', '_proficiencies_text',
|
||||
'spells_known', 'spells_prepared'):
|
||||
new_list = getattr(self, attr, ()) + getattr(self.subclass, attr, ())
|
||||
setattr(self, attr, new_list)
|
||||
# All subclass proficiencies transfer, regardless of if this is primary class
|
||||
self.multiclass_weapon_proficiencies += (self.subclass.weapon_proficiencies)
|
||||
self._multiclass_proficiencies_text += (self._proficiencies_text)
|
||||
self.spellcasting_ability = (self.spellcasting_ability or
|
||||
self.subclass.spellcasting_ability)
|
||||
self.spell_slots_by_level = (self.spell_slots_by_level or
|
||||
self.subclass.spell_slots_by_level)
|
||||
|
||||
@property
|
||||
def features(self):
|
||||
features = ()
|
||||
for lvl in range(1, self.class_level+1):
|
||||
features += tuple(self.features_by_level[lvl])
|
||||
if self.subclass is not None and not isinstance(self.subclass, str):
|
||||
features += tuple(self.subclass.features_by_level[lvl])
|
||||
return features
|
||||
|
||||
@property
|
||||
@@ -55,3 +97,27 @@ class CharClass():
|
||||
return 0
|
||||
else:
|
||||
return self.spell_slots_by_level[self.class_level][spell_level]
|
||||
|
||||
|
||||
class SubClass():
|
||||
"""
|
||||
A generic subclass object. Add more detail in the __doc__ attribute.
|
||||
"""
|
||||
name = ''
|
||||
features_by_level = defaultdict(list)
|
||||
weapon_proficiencies = ()
|
||||
_proficiencies_text = ()
|
||||
spellcasting_ability = None
|
||||
spell_slots_by_level = None
|
||||
spells_known = ()
|
||||
spells_prepared = ()
|
||||
|
||||
def __init__(self, level):
|
||||
self.__doc__ = self.__doc__ or SubClass.__doc__
|
||||
self.class_level = level
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def __repr__(self):
|
||||
return "\"{:s}\"".format(self.name)
|
||||
|
||||
@@ -1,6 +1,183 @@
|
||||
from .. import (weapons)
|
||||
from .. import features as feats
|
||||
from .classes import CharClass
|
||||
from .. import (weapons, features)
|
||||
from .classes import CharClass, SubClass
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
class KnowledgeDomain(SubClass):
|
||||
"""The gods of knowledge—including Oghma, Boccob, Gilean, Aureon, and
|
||||
Thoth—value learning and understanding above all. Some teach that knowledge
|
||||
is to be gathered and shared in libraries and universities, or promote the
|
||||
practical knowledge of craft and invention. Some deities hoard knowledge
|
||||
and keep its secrets to themselves. And some promise their followers that
|
||||
they will gain tremendous power if they unlock the secrets of the
|
||||
multiverse. Followers of these gods study esoteric lore, collect old tomes,
|
||||
delve into the secret places of the earth, and learn all they can. Some
|
||||
gods of knowledge promote the practical knowledge of craft and invention,
|
||||
including smith deities like Gond, Reorx, Onatar, Moradin, Hephaestus, and
|
||||
Goibhniu.
|
||||
|
||||
"""
|
||||
name = "Knowledge Domain"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class LifeDomain(SubClass):
|
||||
"""The Life domain focuses on the vibrant positive energy—one of the
|
||||
fundamental forces of the universe— that sustains all life. The gods of
|
||||
life promote vitality and health through healing the sick and wounded,
|
||||
caring for those in need, and driving away the forces of death and
|
||||
undeath. Almost any non-evil deity can claim influence over this domain,
|
||||
particularly agricultural deities (such as Chauntea, Arawai, and Demeter),
|
||||
sun gods (such as Lathander, Pelor, and Re-Horakhty), gods of healing or
|
||||
endurance (such as Ilmater, Mishakal, Apollo, and Diancecht), and gods of
|
||||
home and community (such as Hestia, Hathor, and Boldrei).
|
||||
|
||||
"""
|
||||
name = "Life Domain"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class LightDomain(SubClass):
|
||||
"""Gods of light—including Helm, Lathander, Pholtus, Branchala, the Silver
|
||||
Flame, Belenus, Apollo, and Re-Horakhty—promote the ideals of rebirth and
|
||||
renewal, truth, vigilance, and beauty, often using the symbol of the
|
||||
sun. Some of these gods are portrayed as the sun itself or as a charioteer
|
||||
who guides the sun across the sky. Others are tireless sentinels whose eyes
|
||||
pierce every shadow and see through every deception. Some are deities of
|
||||
beauty and artistry, who teach that art is a vehicle for the soul's
|
||||
improvement. Clerics of a god of light are enlightened souls infused with
|
||||
radiance and the power of their gods’ discerning vision, charged with
|
||||
chasing away lies and burning away darkness.
|
||||
|
||||
"""
|
||||
name = "Light Domain"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class NatureDomain(SubClass):
|
||||
"""Gods of nature are as varied as the natural world itself, from inscrutable
|
||||
gods of the deep forests (such as Silvanus, Obad-Hai, Chislev, Balinor, and
|
||||
Pan) to friendly deities associated with particular springs and groves
|
||||
(such as Eldath). Druids revere nature as a whole and might serve one of
|
||||
these deities, practicing mysterious rites and reciting all-but-forgotten
|
||||
prayers in their own secret tongue. But many of these gods have clerics as
|
||||
well, champions who take a more active role in advancing the interests of
|
||||
a particular nature god. These clerics might hunt the evil monstrosities
|
||||
that despoil the woodlands, bless the harvest of the faithful, or wither
|
||||
the crops of those who anger their gods.
|
||||
|
||||
"""
|
||||
name = "Nature Domain"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class TempestDomain(SubClass):
|
||||
"""Gods whose portfolios include the Tempest domain - including Talos,
|
||||
Umberlee, Kord, Zeboim, the Devourer, Zeus, and Thor — govern storms, sea,
|
||||
and sky. They include gods of lightning and thunder, gods of earthquakes,
|
||||
some fire gods, and certain gods of violence, physical strength, and
|
||||
courage. In some pantheons, a god of this domain rules over other deities
|
||||
and is known for swift justice delivered by thunderbolts. In the pantheons
|
||||
of seafaring people, gods of this domain are ocean deities and the patrons
|
||||
of sailors. Tempest gods send their clerics to inspire fear in the common
|
||||
folk, either to keep those folk on the path of righteousness or to
|
||||
encourage them to offer sacrifices of propitiation to ward off divine
|
||||
wrath.
|
||||
|
||||
"""
|
||||
name = "Tempest Domain"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class TrickeryDomain(SubClass):
|
||||
"""Gods of trickery—such as Tymora, Beshaba, Olidammara, the Traveler, Garl
|
||||
Glittergold, and Loki—are mischief-makers and instigators who stand as a
|
||||
constant challenge to the accepted order among both gods and
|
||||
mortals. They’re patrons of thieves, scoundrels, gamblers, rebels, and
|
||||
liberators. Their clerics are a disruptive force in the world, puncturing
|
||||
pride, mocking tyrants, stealing from the rich, freeing captives, and
|
||||
flouting hollow traditions. They prefer subterfuge, pranks, deception, and
|
||||
theft rather than direct confrontation.
|
||||
|
||||
"""
|
||||
name = "Trickery Domain"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class WarDomain(SubClass):
|
||||
"""War has many manifestations. It can make heroes of ordinary people. It can
|
||||
be desperate and horrific, with acts of cruelty and cowardice eclipsing
|
||||
instances of excellence and courage. In either case, the gods of war watch
|
||||
over warriors and reward them for their great deeds. The clerics of such
|
||||
gods excel in battle, inspiring others to fight the good fight or offering
|
||||
acts of violence as prayers. Gods of war include champions of honor and
|
||||
chivalry (such as Torm, Heironeous, and KiriJolith) as well as gods of
|
||||
destruction and pillage (such as Erythnul, the Fury, Gruumsh, and Ares) and
|
||||
gods of conquest and domination (such as Bane, Hextor, and
|
||||
Maglubiyet). Other war gods (such as Tempus, Nike, and Nuada) take a more
|
||||
neutral stance, promoting war in all its manifestations and supporting
|
||||
warriors in any circumstance.
|
||||
|
||||
"""
|
||||
name = "War Domain"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
# SCAG
|
||||
class ArcanaDomain(SubClass):
|
||||
"""Magic is an energy that suffuses the multiverse and that fuels both
|
||||
destruction and creation. Gods of the Arcana domain know the secrets and
|
||||
potential of magic intimately. For some of these gods, magical knowledge
|
||||
is a great responsibility that comes with a special understanding of the
|
||||
nature of reality. Other gods of Arcana see magic as pure power, to be used
|
||||
as its wielder sees fit.
|
||||
|
||||
The gods of this domain are often associated with knowledge, as learning
|
||||
and arcane power tend to go hand-in-hand. In the Realms, deities of this
|
||||
domain include Azuth and Mystra, as well as Corellon Larethian of the
|
||||
elven pantheon. In other worlds, this domain includes Hecate, Math
|
||||
Mathonwy, and Isis; the triple moon gods of Solinari , Lunitari, and
|
||||
Nuitari of Krynn; and Boccob, Vecna, and WeeJas of Greyhawk.
|
||||
|
||||
"""
|
||||
name = "Arcana Domain"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
# XGTE
|
||||
class ForgeDomain(SubClass):
|
||||
"""The gods of the forge are patrons of artisans who work with metal, from a
|
||||
humble blacksmith who keeps a village in horseshoes and plow blades to the
|
||||
mighty elf artisan whose diamond-tipped arrows of mithral have felled demon
|
||||
lords. The gods of the forge teach that, with patience and hard work, even
|
||||
the most intractable metal can be transformed from a lump of ore to a beau—
|
||||
tifully wrought object. Clerics of these deities search for objects lost to
|
||||
the forces of darkness, liberate mines overrun by ores, and uncover rare
|
||||
and wondrous materials necessary to create potent magic items. Followers
|
||||
of these gods take great pride in their work, and they are willing to craft
|
||||
and use heavy armor and powerful weapons to protect them. Deities of this
|
||||
domain include Gond, Reorx, Onatar, Moradin, Hephaestus, and Goibhniu.
|
||||
|
||||
"""
|
||||
name = "Forge Domain"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class GraveDomain(SubClass):
|
||||
"""Gods of the grave watch over the line between life and death. To these
|
||||
deities, death and the afterlife are a foundational part of the
|
||||
multiverse. To desecrate the peace of the dead is an abomination. Deities
|
||||
of the grave include Kelemvor, Wee jas, the ancestral spirits of the
|
||||
Undying Court, Hades, Anubis, and Osiris. Followers of these deities seek
|
||||
to put wandering spirits to rest, destroy the undead, and ease the
|
||||
suffering of the dying. Their magic also allows them to stave off death for
|
||||
a time. particularly for a person who still has some great work to
|
||||
accomplish in the world. This is a delay of death, not a denial of it, for
|
||||
death will eventually get its due.
|
||||
|
||||
"""
|
||||
name = "Grave Domain"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class Cleric(CharClass):
|
||||
@@ -10,8 +187,15 @@ class Cleric(CharClass):
|
||||
_proficiencies_text = ('light armor', 'medium armor', 'shields',
|
||||
'all simple weapons')
|
||||
weapon_proficiencies = weapons.simple_weapons
|
||||
multiclass_weapon_proficiencies = ()
|
||||
_multiclass_proficiencies_text = ('light armor', 'medium armor', 'shields')
|
||||
class_skill_choices = ('History', 'Insight', 'Medicine',
|
||||
'Persuasion', 'Religion')
|
||||
features_by_level = defaultdict(list)
|
||||
subclasses_available = (KnowledgeDomain, LifeDomain, LightDomain,
|
||||
NatureDomain, TempestDomain, TrickeryDomain,
|
||||
WarDomain, ArcanaDomain, ForgeDomain,
|
||||
GraveDomain)
|
||||
spellcasting_ability = 'wisdom'
|
||||
spell_slots_by_level = {
|
||||
# char_lvl: (cantrips, 1st, 2nd, 3rd, ...)
|
||||
|
||||
+102
-16
@@ -1,18 +1,91 @@
|
||||
from ..stats import findattr
|
||||
from .. import (weapons, monsters, exceptions)
|
||||
from .. import features as feats
|
||||
from .classes import CharClass
|
||||
from .. import (weapons, monsters, exceptions, features)
|
||||
from .classes import CharClass, SubClass
|
||||
from collections import defaultdict
|
||||
import warnings
|
||||
import math
|
||||
|
||||
|
||||
# PHB
|
||||
class LandCircle(SubClass):
|
||||
"""The Circle of the Land is made up of mystics and sages who safeguard
|
||||
ancient knowledge and rites through a vast oral tradition. These druids
|
||||
meet within sacred circles of trees or standing stones to whisper primal
|
||||
secrets in Druidic. The circle’s wisest members preside as the chief
|
||||
priests of communities that hold to the Old Faith and serve as advisors to
|
||||
the rulers of those folk. As a member of this circle, your magic is
|
||||
influenced by the land where you were initiated into the circle’s
|
||||
mysterious rites
|
||||
|
||||
"""
|
||||
name = "Circle of the Land"
|
||||
circle = "land"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class MoonCircle(SubClass):
|
||||
"""Druids of the Circle of the Moon are fierce guardians of the wilds. Their
|
||||
order gathers under the full moon to share news and trade warnings. They
|
||||
haunt the deepest parts of the wilderness, where they might go for weeks on
|
||||
end before crossing paths with another humanoid creature, let alone another
|
||||
druid.
|
||||
|
||||
Changeable as the moon, a druid of this circle might prowl as a great cat
|
||||
one night, soar over the treetops as an eagle the next day, and crash
|
||||
through the undergrowth in bear form to drive off a trespassing
|
||||
monster. The wild is in the druid's blood.
|
||||
|
||||
"""
|
||||
name = "Circle of the Moon"
|
||||
circle = "moon"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
# XGTE
|
||||
class DreamsCircle(SubClass):
|
||||
"""Druids who are members of the Circle of Dreams hail from regions that have
|
||||
strong ties to the Feywild and its dreamlike realms. The druids’
|
||||
guardianship of the natural world makes for a natural alliance between them
|
||||
and good-aligned fey. These druids seek to fill the world with dreamy
|
||||
wonder. Their magic mends wounds and brings joy to downcast hearts, and the
|
||||
realms they protect are gleaming, fruitful places, where dream and reality
|
||||
blur together and where the weary can find rest.
|
||||
|
||||
"""
|
||||
name = "Circle of Dreams"
|
||||
circle = "dreams"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class ShepherdCircle(SubClass):
|
||||
"""Druids of the Circle of the Shepherd commune with the spirits of nature,
|
||||
especially the spirits of beasts and the fey, and call to those spirits for
|
||||
aid. These druids recognize that all living things play a role in the
|
||||
natural world, yet they focus on protecting animals and fey creatures that
|
||||
have difficulty defending themselves. Shepherds, as they are known, see
|
||||
such creatures as their charges. They ward off monsters that threaten them,
|
||||
rebuke hunters who kill more prey than necessary, and prevent civilization
|
||||
from encroaching on rare animal habitats and on sites sacred to the
|
||||
fey. Many of these druids are happiest far from cities and towns, content
|
||||
to spend their days in the company of animals and the fey creatures of the
|
||||
wilds.
|
||||
|
||||
Members of this circle become adventurers to oppose forces that threaten
|
||||
their charges or to seek knowledge and power that will help them safeguard
|
||||
their charges better. Wherever these druids go, the spirits of the wil—
|
||||
derness are with them
|
||||
|
||||
"""
|
||||
name = "Circle of the Shepherd"
|
||||
circle = "shepherd"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class Druid(CharClass):
|
||||
class_name = 'Druid'
|
||||
circle = "" # moon, land
|
||||
_wild_shapes = ()
|
||||
hit_dice_faces = 8
|
||||
saving_throw_proficiencies = ('intelligence', 'wisdom')
|
||||
spellcasting_ability = 'wisdom'
|
||||
languages = 'Druidic'
|
||||
_proficiencies_text = (
|
||||
'Light armor', 'medium armor',
|
||||
@@ -23,9 +96,17 @@ class Druid(CharClass):
|
||||
weapons.Javelin, weapons.Mace,
|
||||
weapons.Quarterstaff, weapons.Scimitar,
|
||||
weapons.Sickle, weapons.Sling, weapons.Spear)
|
||||
multiclass_weapon_proficiencies = ()
|
||||
_multiclass_proficiencies_text = (
|
||||
'Light armor', 'medium armor',
|
||||
'shields (druids will not wear armor or use shields made of metal)')
|
||||
class_skill_choices = ('Arcana', 'Animal Handling', 'Insight',
|
||||
'Medicine', 'Nature', 'Perception', 'Religion',
|
||||
'Survival')
|
||||
features_by_class = defaultdict(list)
|
||||
subclasses_available = (LandCircle, MoonCircle, DreamsCircle,
|
||||
ShepherdCircle)
|
||||
spellcasting_ability = 'wisdom'
|
||||
spell_slots_by_level = {
|
||||
1: (2, 2, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
2: (2, 3, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
@@ -49,16 +130,21 @@ class Druid(CharClass):
|
||||
20: (4, 4, 3, 3, 3, 3, 2, 2, 1, 1),
|
||||
}
|
||||
|
||||
def __init__(self, level, subclass=None, **params):
|
||||
if subclass is not None:
|
||||
sc = str(subclass).lower()
|
||||
if 'moon' in sc:
|
||||
self.circle = 'moon'
|
||||
params.pop('circle', '')
|
||||
elif 'land' in sc:
|
||||
self.circle = 'land'
|
||||
params.pop('circle', '')
|
||||
super().__init__(level, **params)
|
||||
def select_subclass(self, subclass_str):
|
||||
if subclass_str in ['', 'None', 'none', None]:
|
||||
return None
|
||||
for sc in self.subclasses_available:
|
||||
if ((subclass_str.lower() == sc.circle.lower())
|
||||
or (subclass_str.lower() in sc.name.lower())):
|
||||
return sc(level=self.class_level)
|
||||
return None
|
||||
|
||||
@property
|
||||
def circle(self):
|
||||
if isinstance(self.subclass, SubClass):
|
||||
return self.subclass.circle.lower()
|
||||
else:
|
||||
return ''
|
||||
|
||||
@property
|
||||
def all_wild_shapes(self):
|
||||
@@ -130,7 +216,7 @@ class Druid(CharClass):
|
||||
max_swim = None
|
||||
max_fly = None
|
||||
# Make adjustments for moon circle druids
|
||||
if self.circle.lower() == "moon":
|
||||
if self.circle == "moon":
|
||||
if 2 <= self.class_level < 6:
|
||||
max_cr = 1
|
||||
elif self.class_level >= 6:
|
||||
|
||||
@@ -1,6 +1,165 @@
|
||||
from .. import (weapons)
|
||||
from .. import features as feats
|
||||
from .classes import CharClass
|
||||
from .. import (weapons, features)
|
||||
from .classes import CharClass, SubClass
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
# PHB
|
||||
class Champion(SubClass):
|
||||
"""The archetypal Champion focuses on the development of raw physical power
|
||||
honed to deadly perfection. Those who model themselves on this archetype
|
||||
combine rigorous training with physical excellence to deal devastating
|
||||
blows.
|
||||
|
||||
"""
|
||||
name = "Champion"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class BattleMaster(SubClass):
|
||||
"""Those who emulate the archetypal Battle Master employ martial techniques
|
||||
passed down through generations. To a Battle Master, combat is an academic
|
||||
field, sometimes including subjects beyond battle such as weaponsmithing
|
||||
and calligraphy. Not every fighter absorbs the lessons of history, theory,
|
||||
and artistry that are reflected in the Battle Master archetype, but those
|
||||
who do are well-rounded fighters of great skill and knowledge
|
||||
|
||||
"""
|
||||
name = "Battle Master"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class EldritchKnight(SubClass):
|
||||
"""The archetypal Eldritch Knight combines the martial mastery common to all
|
||||
fighters with a careful study of magic. Eldritch Knights use magical
|
||||
techniques similar to those practiced by wizards. They focus their study on
|
||||
two of the eight schools of magic: abjuration and evocation. Abjuration
|
||||
spells grant an Eldritch Knight additional protection in battle, and
|
||||
evocation spells deal damage to many foes at once, extending the fighter’s
|
||||
reach in combat. These knights learn a comparatively small number of
|
||||
spells, committing them to memory instead of keeping them in a spellbook.
|
||||
|
||||
"""
|
||||
name = "Eldritch Knight"
|
||||
features_by_level = defaultdict(list)
|
||||
spellcasting_ability = 'intelligence'
|
||||
multiclass_spellslots_by_level = {
|
||||
# char_lvl: (cantrips, 1st, 2nd, 3rd, ...)
|
||||
1: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
2: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
3: (2, 2, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
4: (2, 3, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
5: (2, 3, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
6: (2, 3, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
7: (2, 4, 2, 0, 0, 0, 0, 0, 0, 0),
|
||||
8: (2, 4, 2, 0, 0, 0, 0, 0, 0, 0),
|
||||
9: (2, 4, 2, 0, 0, 0, 0, 0, 0, 0),
|
||||
10: (3, 4, 3, 0, 0, 0, 0, 0, 0, 0),
|
||||
11: (3, 4, 3, 0, 0, 0, 0, 0, 0, 0),
|
||||
12: (3, 4, 3, 0, 0, 0, 0, 0, 0, 0),
|
||||
13: (3, 4, 3, 2, 0, 0, 0, 0, 0, 0),
|
||||
14: (3, 4, 3, 2, 0, 0, 0, 0, 0, 0),
|
||||
15: (3, 4, 3, 2, 0, 0, 0, 0, 0, 0),
|
||||
16: (3, 4, 3, 3, 0, 0, 0, 0, 0, 0),
|
||||
17: (3, 4, 3, 3, 0, 0, 0, 0, 0, 0),
|
||||
18: (3, 4, 3, 3, 0, 0, 0, 0, 0, 0),
|
||||
19: (3, 4, 3, 3, 1, 0, 0, 0, 0, 0),
|
||||
20: (3, 4, 3, 3, 1, 0, 0, 0, 0, 0),
|
||||
}
|
||||
|
||||
|
||||
# SCAG
|
||||
class PurpleDragonKnight(SubClass):
|
||||
"""Purple Dragon knights are warriors who hail from the kingdom of
|
||||
Cormyr. Pledged to protect the crown, they take the fight against evil
|
||||
beyond their kingdom's borders. They are tasked with wandering the land as
|
||||
knights errant, relying on their judgment, bravery, and fidelity to the
|
||||
code of chivalry to guide them in defeating evildoers.
|
||||
|
||||
A Purple Dragon knight inspires greatness in others by committing brave
|
||||
deeds in battle. The mere presence of a knight in a hamlet is enough to
|
||||
cause some ores and bandits to seek easier prey. A lone knight is a skilled
|
||||
warrior, but a knight leading a band of allies can transform even the most
|
||||
poorly equipped militia into a ferocious war band.
|
||||
|
||||
A knight prefers to lead through deeds, not words. As a knight spearheads
|
||||
an attack, the knight's actions can awaken reserves of courage and
|
||||
conviction in allies that they never suspected they had.
|
||||
|
||||
"""
|
||||
name = "Purple Dragon Knight"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
# XGTE
|
||||
class ArcaneArcher(SubClass):
|
||||
"""An Arcane Archer studies a unique elven method of archery that weaves magic
|
||||
into attacks to produce supernatural effects. Arcane Archers are some of
|
||||
the most elite warriors among the elves. They stand watch over the fringes
|
||||
of elven domains, keeping a keen eye out for trespassers and using
|
||||
magic—infused arrows to defeat monsters and invaders before they can reach
|
||||
elven set— tlements. Over the centuries, the methods of these elf archers
|
||||
have been learned by members of other races who can also balance arcane
|
||||
aptitude with archery.
|
||||
|
||||
"""
|
||||
name = "Arcane Archer"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class Cavalier(SubClass):
|
||||
"""The archetypal Cavalier excels at mounted combat. Usually born among the
|
||||
nobility and raised at court, a Cavalier is equally at home leading a
|
||||
cavalry charge or exchanging repartee at a state dinner. Cavaliers also
|
||||
learn how to guard those in their charge from harm, often serving as the
|
||||
protectors of their superiors and of the weak. Compelled to right wrongs or
|
||||
earn prestige, many of these fighters leave their lives of comfort to
|
||||
embark on glorious adventure
|
||||
|
||||
"""
|
||||
name = "Cavalier"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class Samurai(SubClass):
|
||||
"""The Samurai is a fighter who draws on an implacable fighting spirit to
|
||||
overcome enemies. A Samurai’s resolve is nearly unbreakable, and the
|
||||
enemies in a Samurai's path have two choices: yield or die fighting
|
||||
|
||||
"""
|
||||
name = "Samurai"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
# Custom
|
||||
class Gunslinger(SubClass):
|
||||
"""Most warriors and combat specialists spend their years perfecting the
|
||||
classic arts of swordplay, archery, or polearm tactics. Whether duelist or
|
||||
infantry, martial weapons were seemingly perfected long ago, and the true
|
||||
challenge is to master them.
|
||||
|
||||
However, some minds couldn't stop with the innovation of the
|
||||
crossbow. Experimentation with alchemical components and rare metals have
|
||||
unlocked the secrets of controlled explosive force. The few who survive
|
||||
these trials of ingenuity may become the first to create, and deftly wield,
|
||||
the first firearms.
|
||||
|
||||
This archetype focuses on the ability to design, craft, and utilize
|
||||
powerful, yet dangerous ranged weapons. Through creative innovation and
|
||||
immaculate aim, you become a distance force of death on the
|
||||
battlefield. However, not being a perfect science, firearms carry an
|
||||
inherent instability that can occastionally leave you without a functional
|
||||
means of attack. This is the danger of new, untested technologies in a
|
||||
world where arcane energies that rule the elements are ever present.
|
||||
|
||||
Should this path of powder, fire, and metal call to you, keep your wits
|
||||
about you, hold on to your convictions as a fighter, and let skill meet
|
||||
luck to guide your bullets to strike true.
|
||||
|
||||
"""
|
||||
name = "Gunslinger"
|
||||
features_by_level = defaultdict(list)
|
||||
weapon_proficiencies = (weapons.firearms)
|
||||
_proficiencies_text = ('firearms')
|
||||
|
||||
|
||||
class Fighter(CharClass):
|
||||
@@ -17,4 +176,7 @@ class Fighter(CharClass):
|
||||
class_skill_choices = ('Acrobatics', 'Animal Handling',
|
||||
'Athletics', 'History', 'Insight', 'Intimidation',
|
||||
'Perception', 'Survival')
|
||||
|
||||
features_by_level = defaultdict(list)
|
||||
subclasses_available = (Champion, BattleMaster, EldritchKnight,
|
||||
PurpleDragonKnight, ArcaneArcher, Cavalier,
|
||||
Samurai, Gunslinger)
|
||||
|
||||
+110
-18
@@ -1,10 +1,112 @@
|
||||
__all__ = ('Monk')
|
||||
|
||||
from .. import (features, weapons)
|
||||
from .classes import CharClass
|
||||
from .classes import CharClass, SubClass
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
# PHB
|
||||
class OpenHandWay(SubClass):
|
||||
"""Monks of the Way of the Open Hand are the ultimate masters of martial arts
|
||||
combat, whether armed or unarmed. They learn techniques to push and trip
|
||||
their opponents, manipulate ki to heal damage to their bodies, and practice
|
||||
advanced meditation that can protect them from harm.
|
||||
|
||||
"""
|
||||
name = "Way of the Open Hand"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class ShadowWay(SubClass):
|
||||
"""Monks of the Way of Shadow follow a tradition that values stealth and
|
||||
subterfuge. These monks might be called ninjas or shadowdancers, and they
|
||||
serve as spies and assassins. Sometimes the members of a ninja monastery
|
||||
are family members, forming a clan sworn to secrecy about their arts and
|
||||
missions. Other monasteries are more like thieves’ guilds, hiring out their
|
||||
services to nobles, rich merchants, or anyone else who can pay their
|
||||
fees. Regardless of their methods, the heads of these monasteries expect
|
||||
the unquestioning obedience of their students
|
||||
|
||||
"""
|
||||
name = "Way of Shadow"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class FourElementsWay(SubClass):
|
||||
"""You follow a monastic tradition that teaches you to harness the
|
||||
elements. When you focus your ki, you can align yourself with the forces of
|
||||
creation and bend the four elements to your will, using them as an
|
||||
extension of your body. Some members of this tradition dedicate themselves
|
||||
to a single element, but others weave the elements together.
|
||||
|
||||
Many monks of this tradition tattoo their bodies with representations of
|
||||
their ki powers, commonly imagined as coiling dragons, but also as
|
||||
phoenixes, fish, plants, mountains, and cresting waves.
|
||||
|
||||
"""
|
||||
name = "Way of the Four Elements"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
# SCAG
|
||||
class SunSoulWay(SubClass):
|
||||
"""Monks of the Way of the Sun Soul learn to channel their own life energy
|
||||
into searing bolts of light. They teach that meditation can unlock the
|
||||
ability to unleash the indomitable light shed by the soul of every living
|
||||
creature
|
||||
|
||||
"""
|
||||
name = "Way of the Sun Soul"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class LongDeathWay(SubClass):
|
||||
"""Monks of the Way of the Long Death are obsessed with the meaning and
|
||||
mechanics of dying. They capture creatures and prepare elaborate
|
||||
experiments to capture, record, and understand the moments of their
|
||||
demise. They then use this knowledge to guide their understanding of
|
||||
martial arts, yielding a deadly fighting style.
|
||||
|
||||
"""
|
||||
name = "Way of the Long Death"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
# XGTE
|
||||
class DrunkenMasterWay(SubClass):
|
||||
"""The Way of the Drunken Master teaches its students to move with the jerky,
|
||||
unpredictable movements of a drunkard. A drunken master sways, tottering on
|
||||
unsteady feet, to present what seems like an incompetent combatant who
|
||||
proves frustrating to engage. The drunken master’s erratic stumbles conceal
|
||||
a carefully executed dance of blocks, parries, advances, attacks, and
|
||||
retreats.
|
||||
|
||||
A drunken master often enjoys playing the fool to bring gladness to the
|
||||
despondent or to demonstrate humility to the arrogant, but when battle is
|
||||
joined, the drunken master can be a maddening, masterful foe
|
||||
|
||||
"""
|
||||
name = "Way of the Drunken Master"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class KenseiWay(SubClass):
|
||||
"""Monks of the Way of the Kensei train relentlessly with their weapons, to
|
||||
the point where the weapon becomes an extension of the body. Founded on a
|
||||
mastery of sword fighting, the tradition has expanded to include many
|
||||
different weapons.
|
||||
|
||||
A kensei sees a weapon in much the same way a calligrapher or painter
|
||||
regards a pen or brush. Whatever the weapon, the kensei views it as a tool
|
||||
used to express the beauty and precision of the martial arts. That such
|
||||
mastery makes a kensei a peerless warrior is but a side effect of intense
|
||||
devotion, practice, and study.
|
||||
|
||||
"""
|
||||
name = "Way of the Kensei"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class Monk(CharClass):
|
||||
class_name = 'Monk'
|
||||
hit_dice_faces = 8
|
||||
@@ -13,9 +115,15 @@ class Monk(CharClass):
|
||||
'simple weapons', 'shortswords', 'unarmed',
|
||||
"one type of artisan's tools or one musical instrument")
|
||||
weapon_proficiencies = (weapons.Shortsword, weapons.Unarmed) + weapons.simple_weapons
|
||||
multiclass_weapon_proficiencies = weapon_proficiencies
|
||||
_multiclass_proficiencies_text = ('simple weapons', 'shortswords',
|
||||
'unarmed')
|
||||
class_skill_choices = ('Acrobatics', 'Athletics', 'History', 'Insight',
|
||||
'Religion', 'Stealth')
|
||||
subclasses_available = ('SunSoul', 'OpenHand')
|
||||
subclasses_available = (OpenHandWay, ShadowWay,
|
||||
FourElementsWay, SunSoulWay,
|
||||
LongDeathWay, DrunkenMasterWay,
|
||||
KenseiWay)
|
||||
features_by_level = defaultdict(list)
|
||||
features_by_level[1] = [features.UnarmoredDefense,
|
||||
features.MartialArts]
|
||||
@@ -25,19 +133,3 @@ class Monk(CharClass):
|
||||
for f in self.features_by_level[1]:
|
||||
if isinstance(f, features.MartialArts):
|
||||
f.level = self.class_level
|
||||
if subclass == 'sunsoul':
|
||||
self.subclass = SunSoul(level=self.class_level)
|
||||
else:
|
||||
self.subclass = None
|
||||
if self.subclass is not None:
|
||||
self._proficiencies_text += self.subclass._proficiencies_text
|
||||
self.weapon_proficiences += self.subclass.weapon_proficiencies
|
||||
|
||||
|
||||
class SunSoul:
|
||||
class_features_by_level = defaultdict(list)
|
||||
weapon_proficiencies = ()
|
||||
_profiencies_text = ()
|
||||
|
||||
def __init__(self, level):
|
||||
self.class_level = level
|
||||
|
||||
@@ -1,6 +1,222 @@
|
||||
from .. import (weapons)
|
||||
from .. import features as feats
|
||||
from .classes import CharClass
|
||||
from .. import (weapons, features)
|
||||
from .classes import CharClass, SubClass
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
class OathOfDevotion(SubClass):
|
||||
"""The Oath of Devotion binds a paladin to the loftiest ideals of justice,
|
||||
virtue, and order. Sometim es called cavaliers, white knights, or holy
|
||||
warriors, these paladins meet the ideal of the knight in shining armor,
|
||||
acting with honor in pursuit o f justice and the greater good. They hold
|
||||
themselves to the highest standards of conduct, and some, for better or
|
||||
worse, hold the rest of the world to the same standards. Many who swear
|
||||
this oath are devoted to gods of law and good and use their gods’ tenets as
|
||||
the measure o f their devotion. They hold angels—the perfect servants o f
|
||||
good—as their ideals, and incorporate images of angelic wings into their
|
||||
helmets or coats of arms.
|
||||
|
||||
**Tenets of Devotion**: Though the exact words and strictures of the Oath
|
||||
of Devotion vary, paladins of this oath share these tenets.
|
||||
|
||||
--Honesty. Don’t lie or cheat. Let your word be your promise.
|
||||
|
||||
--Courage. Never fear to act, though caution is wise.
|
||||
|
||||
--Compassion. Aid others, protect the weak, and punish those who threaten
|
||||
them. Show mercy to your foes, but temper it with wisdom.
|
||||
|
||||
--Honor. Treat others with fairness, and let your honorable deeds be an
|
||||
example to them. Do as much good as possible while causing the least amount
|
||||
of harm.
|
||||
|
||||
--Duty. Be responsible for your actions and their consequences, protect
|
||||
those entrusted to your care, and obey those who have just authority over
|
||||
you.
|
||||
|
||||
"""
|
||||
name = "Oath of Devotion"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class OathOfAncients(SubClass):
|
||||
"""The Oath of the Ancients is as old as the race of elves and the rituals of
|
||||
the druids. Sometimes called fey knights, green knights, or horned knights,
|
||||
paladins who swear this oath cast their lot with the side of the light in
|
||||
the cosm ic struggle against darkness because they love the beautiful and
|
||||
life-giving things of the world, not necessarily because they believe in
|
||||
principles of honor, courage, and justice. They adorn their armor and
|
||||
clothing with images of growing things—leaves, antlers, or flowers—to
|
||||
reflect their commitment to preserving life and light in the world.
|
||||
|
||||
**Tenets of the Ancients**: The tenets of the Oath of the Ancients have
|
||||
been preserved for uncounted centuries. This oath emphasizes the
|
||||
principles of good above any concerns of law or chaos. Its four central
|
||||
principles are simple.
|
||||
|
||||
--Kindle the Light. Through your acts of mercy, kindness, and forgiveness,
|
||||
kindle the light of hope in the world, beating back despair.
|
||||
|
||||
--Shelter the Light. Where there is good, beauty, love, and laughter in the
|
||||
world, stand against the w ickedness that would swallow it. Where life
|
||||
flourishes, stand against the forces that would render it barren.
|
||||
|
||||
--Preserve Your Own Light. Delight in song and laughter, in beauty and
|
||||
art. If you allow the light to die in your own heart, you can’t preserve it
|
||||
in the world.
|
||||
|
||||
--Be the Light. Be a glorious beacon for all who live in despair. Let the
|
||||
light of your joy and courage shine forth in all your deeds.
|
||||
|
||||
"""
|
||||
name = "Oath of The Ancients"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class OathOfVengance(SubClass):
|
||||
"""The Oath of Vengeance is a solemn commitment to punish those who have
|
||||
committed a grievous sin. When evil forces slaughter helpless villagers,
|
||||
when an entire people turns against the will of the gods, when a thieves’
|
||||
guild grows too violent and powerful, when a dragon rampages through the
|
||||
countryside—at times like these, paladins arise and swear an Oath of
|
||||
Vengeance to set right that which has gone wrong. To these paladins—
|
||||
sometimes called avengers or dark knights—their own purity is not as
|
||||
important as delivering justice.
|
||||
|
||||
**Tenets of Vengance**: The tenets of the Oath of Vengeance vary by
|
||||
paladin, but all the tenets revolve around punishing wrongdoers by any
|
||||
means necessary. Paladins who uphold these tenets are willing to sacrifice
|
||||
even their own righteousness to mete out justice upon those who do evil, so
|
||||
the paladins are often neutral or lawful neutral in alignment. The core
|
||||
principles of the tenets are brutally simple.
|
||||
|
||||
--Fight the Greater Evil. Faced with a choice of fighting my sworn foes or
|
||||
combating a lesser evil. I choose the greater evil.
|
||||
|
||||
--No Mercy for the Wicked. Ordinary foes might win my mercy, but my sworn
|
||||
enemies do not.
|
||||
|
||||
--By Any Means Necessary. My qualms can’t get in the way of exterminating
|
||||
my foes.
|
||||
|
||||
--Restitution. If my foes wreak ruin on the world, it is because I failed
|
||||
to stop them. I must help those harmed by their misdeeds.
|
||||
|
||||
"""
|
||||
name = "Oath of Vengance"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class OathOfCrown(SubClass):
|
||||
"""The Oath of the Crown is sworn to the ideals of civilization, be it the
|
||||
spirit of a nation, fealty to a sovereign, or service to a deity of law and
|
||||
rulership. The paladins who swear this oath dedicate themselves to serving
|
||||
society and, in particular, the just laws that hold society together. These
|
||||
paladins are the watchful guardians on the walls, standing against the
|
||||
chaotic tides of barbarism that threaten to tear down all that
|
||||
civilization has built, and are commonly known as guardians, exemplars,
|
||||
or sentinels. Often, paladins who swear this oath are members of an order
|
||||
of knighthood in service to a nation or a sovereign, and undergo their oath
|
||||
as part of their admission to the order's ranks.
|
||||
|
||||
**Tenets of the Crown**: The tenets of the Oath of the Crown are often set
|
||||
by the sovereign to which their oath is sworn, but generally emphasize
|
||||
the following tenets.
|
||||
|
||||
--Law. The law is paramount. It is the mortar that holds the stones of
|
||||
civilization together, and it must be respected.
|
||||
|
||||
--Loyalty. Your word is your bond. Without loyalty, oaths and laws are
|
||||
meaningless.
|
||||
|
||||
--Courage. You must be willing to do what needs to be done for the sake of
|
||||
order, even in the face of overwhelming odds. If you don't act, then who
|
||||
will?
|
||||
|
||||
--Responsibility. You must deal with the consequences of your actions, and
|
||||
you are responsible for fulfilling your duties and obligations.
|
||||
|
||||
"""
|
||||
name = "Oath of The Crown"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class OathOfConquest(SubClass):
|
||||
"""The Oath of Conquest calls to paladins who seek glory in battle and the
|
||||
subjugation of their enemies. It isn’t enough for these paladins to
|
||||
establish order. They must crush the forces of chaos. Sometimes called
|
||||
knight ty- rants or iron mongers, those who swear this oath gather into
|
||||
grim orders that serve gods or philosophies of war and well-ordered might.
|
||||
|
||||
Some of these paladins go so far as to consort with the powers of the Nine
|
||||
Hells, valuing the rule of law over the balm of mercy. The archdevil Bel,
|
||||
warlord of Avernus, counts many of these paladins—called hell knights—as
|
||||
his most ardent supporters. Hell knights cover their armor with trophies
|
||||
taken from fallen en— emies, a grim~warning to any who dare oppose them and
|
||||
the decrees of their lords. These knights are often most fiercely resisted
|
||||
by other paladins of this oath, who believe that the hell knights have
|
||||
wandered too far into darkness.
|
||||
|
||||
**Tenets of Conquest**: A paladin who takes this oath has the tenets of
|
||||
conquest seared on the upper arm.
|
||||
|
||||
--Douse the Flame of Hope. It is not enough
|
||||
to merely defeat an enemy in battle. Your victory must be so over- whelming
|
||||
that your enemies' will to fight is shattered forever. A blade can end a
|
||||
life. Fear can end an empire.
|
||||
|
||||
--Rule with an Iron Fist. Once you have conquered, tolerate no
|
||||
dissent. Your word is law. Those who obey it shall be favored. Those who
|
||||
defy it shall be punished as an example to all who might follow.
|
||||
|
||||
--Strength Above All. You shall rule until a stronger one arises. Then you
|
||||
must grow mightier and meet the challenge, or fall to your own ruin.
|
||||
|
||||
"""
|
||||
name = "Oath of Conquest"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class OathOfRedemption(SubClass):
|
||||
"""The Oath of Redemption sets a paladin on a difficult path, one that requires
|
||||
a holy warrior to use violence only as a last resort. Paladins who dedicate
|
||||
themselves to this oath believe that any person can be redeemed and that
|
||||
the path of benevolence and justice is one that anyone can walk. These
|
||||
paladins face evil creatures in the hope of turning their foes to the
|
||||
light, and they slay their enemies only when such a deed will clearly save
|
||||
other lives. Paladins who follow this path are known as redeemers.
|
||||
|
||||
While redeemers are idealists, they are no fools. Re— deemers know that
|
||||
undead, demons, devils, and other supernatural threats can be inherently
|
||||
evil. Against such fees, paladins who swear this oath bring the full wrath
|
||||
of their weapons and spells to bear. Yet the re- deemers still pray that,
|
||||
one day, even creatures of wick- edness will invite their own redemption.
|
||||
|
||||
**Tenets of Redemption**: The tenets of the Oath of Redemption hold a
|
||||
paladin to a high standard of peace and justice.
|
||||
|
||||
--Peace. Violence is a weapon of last resort. Diplomacy and understanding
|
||||
are the paths to long-lasting peace.
|
||||
|
||||
--Innocence. All people begin life in an innocent state, and it is their
|
||||
environment or the influence of dark forces that drives them to evil. By
|
||||
setting the proper example, and working to heal the wounds of a deeply
|
||||
flawed world, you can set anyone on a righteous path.
|
||||
|
||||
--Patience. Change takes time. Those who have walked the path of the wicked
|
||||
must be given reminders to keep them honest and true. Once you have planted
|
||||
the seed of righteousness in a creature, you must work day after day to
|
||||
allow that seed to survive and flourish.
|
||||
|
||||
--Wisdom. Your heart and mind must stay clear, for eventually you will be
|
||||
forced to admit defeat. While ev- ery creature can be redeemed, some are so
|
||||
far along the path of evil that you have no choice but to end their lives
|
||||
for the greater good. Any such action must be carefully weighed and the
|
||||
consequences fully understood, but once you have made the decision, follow
|
||||
through with it knowing your path is just.
|
||||
|
||||
"""
|
||||
name = "Oath of Redemption"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class Paladin(CharClass):
|
||||
@@ -10,8 +226,14 @@ class Paladin(CharClass):
|
||||
_proficiencies_text = ('All armor', 'shields', 'simple weapons',
|
||||
'martial weapons')
|
||||
weapon_proficiencies = weapons.simple_weapons + weapons.martial_weapons
|
||||
multiclass_weapon_proficiencies = weapon_proficiencies
|
||||
_multiclass_proficiencies_text = ('light armor', 'medium armor', 'shields',
|
||||
'simple weapons', 'martial weapons')
|
||||
class_skill_choices = ("Athletics", 'Insight', 'Intimidation',
|
||||
'Medicine', 'Persuasion', 'Religion')
|
||||
features_by_level = defaultdict(list)
|
||||
subclasses_available = (OathOfDevotion, OathOfAncients, OathOfVengance,
|
||||
OathOfCrown, OathOfConquest, OathOfRedemption)
|
||||
spellcasting_ability = 'charisma'
|
||||
spell_slots_by_level = {
|
||||
# char_lvl: (cantrips, 1st, 2nd, 3rd, ...)
|
||||
|
||||
@@ -1,10 +1,76 @@
|
||||
__all__ = ('Ranger', 'Revisedranger')
|
||||
__all__ = ('Ranger', 'RevisedRanger')
|
||||
|
||||
from .. import (weapons, features)
|
||||
from .classes import CharClass
|
||||
from .classes import CharClass, SubClass
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
# PHB
|
||||
class Hunter(SubClass):
|
||||
"""Emulating the Hunter archetype means accepting your place as a bulwark
|
||||
between civilization and the terrors of the wilderness. As you walk the
|
||||
Hunter’s path, you learn specialized techniques for fighting the threats
|
||||
you face, from rampaging ogres and hordes of orcs to towering giants and
|
||||
terrifying dragons.
|
||||
|
||||
"""
|
||||
name = "Hunter"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class BeastMaster(SubClass):
|
||||
"""The Beast Master archetype embodies a friendship between the civilized
|
||||
races and the beasts of the world. United in focus, beast and ranger work
|
||||
as one to fight the monstrous foes that threaten civilization and the
|
||||
wilderness alike. Emulating the Beast Master archetype means committing
|
||||
yourself to this ideal, working in partnership with an animal as its
|
||||
companion and friend.
|
||||
|
||||
"""
|
||||
name = "Beast Master"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
# XGTE
|
||||
class GloomStalker(SubClass):
|
||||
"""Gloom Stalkers are at home in the darkest places: deep under the earth, in
|
||||
gloomy alleyways, in primeval forests, and wherever else the light
|
||||
dims. Most folk enter such places with trepidation, but a Gloom Stalker
|
||||
ventures boldly into the darkness, seeking to ambush threats before they
|
||||
can reach the broader world. Such rangers are often found in the Underdark,
|
||||
but they will go any place Where evil lurks in the shadows
|
||||
|
||||
"""
|
||||
name = "Gloom Stalker"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class HorizonWalker(SubClass):
|
||||
"""Horizon Walkers guard the world against threats that originate from other
|
||||
planes or that seek to ravage the mortal realm with otherworldly
|
||||
magic. They seek out planar portals and keep watch over them, venturing to
|
||||
the Inner Planes and the Outer Planes as needed to pursue their foes. These
|
||||
rangers are also friends to any forces in the multiverse—especially
|
||||
benevolent dragons, fey, and elementals—that work to preserve life and the
|
||||
order of the planes
|
||||
|
||||
"""
|
||||
name = "Horizon Walker"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class MonsterSlayer(SubClass):
|
||||
"""You have dedicated yourself to hunting down creatures of the night and
|
||||
wielders of grim magic. A Monster Slayer seeks out vampires, dragons, evil
|
||||
fey, fiends, and other magical threats. Trained in supernatural tech-
|
||||
niques to overcome such monsters, Slayers are experts at unearthing and
|
||||
defeating mighty, mystical foes.
|
||||
|
||||
"""
|
||||
name = "Monster Slayer"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class Ranger(CharClass):
|
||||
class_name = 'Ranger'
|
||||
hit_dice_faces = 10
|
||||
@@ -12,12 +78,18 @@ class Ranger(CharClass):
|
||||
_proficiencies_text = ("light armor", "medium armor", "shields",
|
||||
"simple weapons", "martial weapons")
|
||||
weapon_proficiencies = weapons.simple_weapons + weapons.martial_weapons
|
||||
multiclass_weapon_proficiencies = weapon_proficiencies
|
||||
_multiclass_proficiencies_text = ('light armor', 'medium armor', 'shields',
|
||||
'simple weapons', 'martial weapons',
|
||||
'[choose one skill from Ranger list]')
|
||||
class_skill_choices = ('Animal Handling', 'Athletics', 'Insight',
|
||||
'Investigation', 'Nature', 'Perception', 'Stealth',
|
||||
'Survival')
|
||||
num_skill_choices = 3
|
||||
spellcasting_ability = 'wisdom'
|
||||
features_by_level = defaultdict(list)
|
||||
subclasses_available = (Hunter, BeastMaster, GloomStalker,
|
||||
HorizonWalker, MonsterSlayer)
|
||||
spellcasting_ability = 'wisdom'
|
||||
spell_slots_by_level = {
|
||||
# char_lvl: (cantrips, 1st, 2nd, 3rd, ...)
|
||||
1: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
@@ -49,6 +121,43 @@ class Ranger(CharClass):
|
||||
self.features_by_level[2].append(fighting_style)
|
||||
|
||||
|
||||
# Custom Classes
|
||||
class Revisedranger(Ranger):
|
||||
class_name = 'Revisedranger'
|
||||
# Revised Ranger
|
||||
class BeastConclave(SubClass):
|
||||
"""Many rangers are more at home in the wilds than in civilization, to the
|
||||
point where animals consider them kin. Rangers of the Beast Conclave
|
||||
develop a close bond with a beast, then further strengthen that bond
|
||||
through the use of magic.
|
||||
|
||||
"""
|
||||
name = "Beast Conclave"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class HunterConclave(SubClass):
|
||||
"""Some rangers seek to master weapons to better protect civilization from the
|
||||
terrors of the wilderness. Members of the Hunter Conclave learn specialized
|
||||
fighting techniques for use against the most dire threats, from rampaging
|
||||
ogres and hordes of orcs to towering giants and terrifying dragons
|
||||
|
||||
"""
|
||||
name = "Hunter Conclave"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class DeepStalkerConclave(SubClass):
|
||||
"""Most folk descend into the depths of the Underdark only under the most
|
||||
pressing conditions, undertaking some desperate quest or following the
|
||||
promise of vast riches. All too often, evil festers beneath the earth
|
||||
unnoticed, and rangers of the Deep Stalker Conclave strive to uncover and
|
||||
defeat such threats before they can reach the surface.
|
||||
|
||||
"""
|
||||
name = "Deep Stalker Conclave"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class RevisedRanger(Ranger):
|
||||
class_name = 'Revised Ranger'
|
||||
features_by_level = defaultdict(list)
|
||||
subclasses_available = (BeastConclave, HunterConclave, DeepStalkerConclave)
|
||||
|
||||
|
||||
@@ -1,6 +1,118 @@
|
||||
from .. import (weapons)
|
||||
from .. import features as feats
|
||||
from .classes import CharClass
|
||||
from .. import (weapons, features)
|
||||
from .classes import CharClass, SubClass
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
# PHB
|
||||
class Thief(SubClass):
|
||||
"""You hone your skills in the larcenous arts. Burglars, bandits, cutpurses,
|
||||
and other criminals typically follow this archetype, but so do rogues who
|
||||
prefer to think of themselves as professional treasure seekers, explorers,
|
||||
delvers, and investigators. In addition to improving your agility and
|
||||
stealth, you learn skills useful for delving into ancient ruins, reading
|
||||
unfamiliar languages, and using magic items you normally couldn’t employ
|
||||
|
||||
"""
|
||||
name = "Thief"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class Assassin(SubClass):
|
||||
"""You focus your training on the grim art of death. Those who adhere to this
|
||||
archetype are diverse: hired killers, spies, bounty hunters, and even
|
||||
specially anointed priests trained to exterminate the enemies of their
|
||||
deity. Stealth, poison, and disguise help you eliminate your foes with
|
||||
deadly efficiency
|
||||
|
||||
"""
|
||||
name = "Assassin"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class ArcaneTrickster(SubClass):
|
||||
"""Some rogues enhance their fine-honed skills of stealth and agility with
|
||||
magic, learning tricks of enchantment and illusion. These rogues include
|
||||
pickpockets and burglars, but also pranksters, mischief-makers, and a
|
||||
significant number of adventurers.
|
||||
|
||||
"""
|
||||
name = "Arcane Trickster"
|
||||
features_by_level = defaultdict(list)
|
||||
spellcasting_ability = 'intelligence'
|
||||
multiclass_spellslots_by_level = {
|
||||
# char_lvl: (cantrips, 1st, 2nd, 3rd, ...)
|
||||
1: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
2: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
3: (3, 2, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
4: (3, 3, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
5: (3, 3, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
6: (3, 3, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
7: (3, 4, 2, 0, 0, 0, 0, 0, 0, 0),
|
||||
8: (3, 4, 2, 0, 0, 0, 0, 0, 0, 0),
|
||||
9: (3, 4, 2, 0, 0, 0, 0, 0, 0, 0),
|
||||
10: (4, 4, 3, 0, 0, 0, 0, 0, 0, 0),
|
||||
11: (4, 4, 3, 0, 0, 0, 0, 0, 0, 0),
|
||||
12: (4, 4, 3, 0, 0, 0, 0, 0, 0, 0),
|
||||
13: (4, 4, 3, 2, 0, 0, 0, 0, 0, 0),
|
||||
14: (4, 4, 3, 2, 0, 0, 0, 0, 0, 0),
|
||||
15: (4, 4, 3, 2, 0, 0, 0, 0, 0, 0),
|
||||
16: (4, 4, 3, 3, 0, 0, 0, 0, 0, 0),
|
||||
17: (4, 4, 3, 3, 0, 0, 0, 0, 0, 0),
|
||||
18: (4, 4, 3, 3, 0, 0, 0, 0, 0, 0),
|
||||
19: (4, 4, 3, 3, 1, 0, 0, 0, 0, 0),
|
||||
20: (4, 4, 3, 3, 1, 0, 0, 0, 0, 0),
|
||||
}
|
||||
|
||||
|
||||
# XGTE
|
||||
class Inquisitive(SubClass):
|
||||
"""As an archetypal Inquisitive, you excel at rooting out se- crets and
|
||||
unraveling mysteries. You rely on your sharp eye for detail, but also on
|
||||
your finely honed ability to read the words and deeds of other creatures to
|
||||
deter- mine their true intent. You excel at defeating creatures that hide
|
||||
among and prey upon ordinary folk, and your mastery of lore and your keen
|
||||
deductions make you well equipped to expose and end hidden evils
|
||||
|
||||
"""
|
||||
name = "Inquisitive"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class Mastermind(SubClass):
|
||||
"""Your focus is on people and on the influence and secrets they have. Many
|
||||
spies, courtiers, and schemers follow this archetype, leading lives of
|
||||
intrigue. Words are your weapons as often as knives or poison, and secrets
|
||||
and favors are some of your favorite treasures.
|
||||
|
||||
"""
|
||||
name = "Mastermind"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class Scout(SubClass):
|
||||
"""You are skilled in stealth and surviving far from the streets of a city,
|
||||
allowing you to scout ahead of your companions during expeditions. Rogues
|
||||
who embrace this archetype are at home in the wilderness and among
|
||||
barbarians and rangers, and many Scouts serve as the eyes and ears of war
|
||||
bands. Ambusher, spy, bounty hunter#these are just a few of the roles that
|
||||
Scouts as- sume as they range the world.
|
||||
|
||||
"""
|
||||
name = "Scout"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class Swashbuckler(SubClass):
|
||||
"""You focus your training on the art of the blade, relying on speed,
|
||||
elegance, and charm in equal parts. While some warriors are brutes clad in
|
||||
heavy armor, your method of fighting looks almost like a performance. Du—
|
||||
elists and pirates typically belong to this archetype. A Swashbuckler
|
||||
excels in single combat, and can fight with two weapons while safely
|
||||
darting away from an opponent
|
||||
|
||||
"""
|
||||
name = "Swashbuckler"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class Rogue(CharClass):
|
||||
@@ -13,8 +125,13 @@ class Rogue(CharClass):
|
||||
weapon_proficiencies = weapons.simple_weapons + (
|
||||
weapons.HandCrossbow, weapons.Longsword, weapons.Rapier,
|
||||
weapons.Shortsword)
|
||||
multiclass_weapon_proficiencies = ()
|
||||
_multiclass_proficiencies_text = ('light armor', "thieves' tools",
|
||||
'[choose one skill from Rogue list]')
|
||||
class_skill_choices = ('Acrobatics', 'Athletics', 'Deception',
|
||||
'Insight', 'Intimidation', 'Investigation',
|
||||
'Perception', 'Performance', 'Persuasion',
|
||||
'Sleight of Hand', 'Stealth')
|
||||
|
||||
features_by_level = defaultdict(list)
|
||||
subclasses_available = (Thief, Assassin, ArcaneTrickster,
|
||||
Inquisitive, Mastermind, Scout, Swashbuckler)
|
||||
|
||||
@@ -1,6 +1,94 @@
|
||||
from .. import (weapons)
|
||||
from .. import features as feats
|
||||
from .classes import CharClass
|
||||
from .. import (weapons, features)
|
||||
from .classes import CharClass, SubClass
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
# PHB
|
||||
class DraconicBloodline(SubClass):
|
||||
"""Your innate magic comes from draconic magic that was mingled with your
|
||||
blood or that of your ancestors. Most often, sorcerers with this origin
|
||||
trace their descent back to a mighty sorcerer of ancient times who made a
|
||||
bargain with a dragon or who might even have claimed a dragon parent. Some
|
||||
of these bloodlines are well established in the world, but most are
|
||||
obscure. Any given sorcerer could be the first of a new bloodline, as a
|
||||
result of a pact or some other exceptional circumstance.
|
||||
|
||||
"""
|
||||
name = "Draconic Bloodline"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class WildMagic(SubClass):
|
||||
"""Your innate magic comes from the wild forces of chaos that underlie the
|
||||
order of creation. You might have endured exposure to some form o f raw
|
||||
magic, perhaps through a planar portal leading to Limbo, the Elemental
|
||||
Planes, or the mysterious Far Realm. Perhaps you were blessed by a powerful
|
||||
fey creature or marked by a demon. Or your magic could be a fluke of your
|
||||
birth, with no apparent cause or reason. However it came to be, this
|
||||
chaotic magic churns within you, waiting for any outlet.
|
||||
|
||||
"""
|
||||
name = "Wild Magic"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
# XGTE
|
||||
class DivineSoul(SubClass):
|
||||
"""Sometimes the spark of magic that fuels a sorcerer comes from a divine
|
||||
source that glimmers within the soul. Having such a blessed soul is a sign
|
||||
that your innate magic might come from a distant but powerful familial
|
||||
connection to a divine being. Perhaps your ances— tor was an angel,
|
||||
transformed into a mortal and sent to fight in a god’s name. Or your birth
|
||||
might align with an ancient prophecy, marking you as a servant of the gods
|
||||
or a chosen vessel of divine magic.
|
||||
|
||||
A Divine Soul, with a natural magnetism, is seen as a threat by some
|
||||
religious hierarchies. As an outsider who commands sacred power, a Divine
|
||||
Soul can undermine an existing order by claiming a direct tie to the
|
||||
divine.
|
||||
|
||||
In some cultures, only those who can claim the power of a Divine Soul may
|
||||
command religious power. In these lands, ecclesiastical positions are
|
||||
dominated by a few bloodlines and preserved over generations
|
||||
|
||||
"""
|
||||
name = "Divine Soul"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class ShadowMagic(SubClass):
|
||||
"""You are a creature of shadow, for your innate magic comes from the
|
||||
Shadowfell itself. You might trace your lineage to an entity from that
|
||||
place, or perhaps you were exposed to its fell energy and transformed by
|
||||
it.
|
||||
|
||||
The power of shadow magic casts a strange pall over your physical
|
||||
presence. The spark of life that sustains you is muffled, as if it
|
||||
struggles to remain viable against the dark energy that imbues your
|
||||
soul. At your option, you can pick from or roll on the Shadow Sorcerer
|
||||
Quirks table to create a quirk for your character
|
||||
|
||||
"""
|
||||
name = "Shadow Magic"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class StormSorcery(SubClass):
|
||||
"""Your innate magic comes from the power of elemental air. Many with this
|
||||
power can trace their magic back to a near-death experience caused by the
|
||||
Great Rain, but perhaps you were born during a howling gale so powerful
|
||||
that folk still tell stories of it, or your lineage might include the
|
||||
influence of potent air creatures such as djinn. Whatever the case, the
|
||||
magic of the storm permeates your being.
|
||||
|
||||
Storm sorcerers are invaluable members of a ship’s crew. Their magic allows
|
||||
them to exert control over wind and weather in their immediate area. Their
|
||||
abilities also prove useful in repelling attacks by sahuagin, pirates,
|
||||
and other waterborne threats.
|
||||
|
||||
"""
|
||||
name = "Storm Sorcery"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class Sorceror(CharClass):
|
||||
@@ -12,8 +100,13 @@ class Sorceror(CharClass):
|
||||
weapon_proficiencies = (weapons.Dagger, weapons.Dart,
|
||||
weapons.Sling, weapons.Quarterstaff,
|
||||
weapons.LightCrossbow)
|
||||
multiclass_weapon_proficiencies = ()
|
||||
_multiclass_proficiencies_text = ()
|
||||
class_skill_choices = ('Arcana', 'Deception', 'Insight',
|
||||
'Intimidation', 'Persuasion', 'Religion')
|
||||
features_by_level = defaultdict(list)
|
||||
subclasses_available = (DraconicBloodline, WildMagic, DivineSoul,
|
||||
ShadowMagic, StormSorcery)
|
||||
spellcasting_ability = 'charisma'
|
||||
spell_slots_by_level = {
|
||||
# char_lvl: (cantrips, 1st, 2nd, 3rd, ...)
|
||||
|
||||
@@ -1,6 +1,115 @@
|
||||
from .. import (weapons)
|
||||
from .. import features as feats
|
||||
from .classes import CharClass
|
||||
from .. import (weapons, features)
|
||||
from .classes import CharClass, SubClass
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
# PHB
|
||||
class Archfey(SubClass):
|
||||
"""Your patron is a lord or lady of the fey, a creature of legend who holds
|
||||
secrets that were forgotten before the mortal races were born. This being’s
|
||||
motivations are often inscrutable, and sometimes whimsical, and might
|
||||
involve a striving for greater magical power or the settling of age-old
|
||||
grudges. Beings of this sort include the Prince of Frost; the Queen of Air
|
||||
and Darkness, ruler of the Gloaming Court; Titania of the Summer Court; her
|
||||
consort Oberon, the Green Lord; Hyrsam, the Prince of Fools; and ancient
|
||||
hags
|
||||
|
||||
"""
|
||||
name = "The Archfey Patron"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class Fiend(SubClass):
|
||||
"""You have made a pact with a fiend from the lower planes o f existence, a
|
||||
being whose aims are evil, even if you strive against those aims. Such
|
||||
beings desire the corruption or destruction of all things, ultimately
|
||||
including you. Fiends powerful enough to forge a pact include demon lords
|
||||
such as Demogorgon, Orcus, Fraz’Urb-luu, and Baphomet; archdevils such as
|
||||
Asmodeus, Dispater, Mephistopheles, and Belial; pit fiends and balors that
|
||||
are especially mighty; and ultroloths and other lords of the yugoloths
|
||||
|
||||
"""
|
||||
name = "The Fiend Patron"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class GreatOldOne(SubClass):
|
||||
"""Your patron is a mysterious entity whose nature is utterly foreign to the
|
||||
fabric of reality. It might come from the Far Realm, the space beyond
|
||||
reality, or it could be one of the elder gods known only in legends. Its
|
||||
motives are incomprehensible to mortals, and its knowledge so immense and
|
||||
ancient that even the greatest libraries pale in comparison to the vast
|
||||
secrets it holds. The Great Old One might be unaware of your existence or
|
||||
entirely indifferent to you, but the secrets you have learned allow you to
|
||||
draw your magic from it.
|
||||
|
||||
Entities of this type include Ghaunadar, called That Which Lurks;
|
||||
Tharizdun, the Chained God; Dendar, the Night Serpent; Zargon, the
|
||||
Returner; Great Cthulhu; and other unfathomable beings.
|
||||
|
||||
"""
|
||||
name = "The Great Old One Patron"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
# SCAG
|
||||
class Undying(SubClass):
|
||||
"""Death holds no sway over your patron, who has un- locked the secrets of
|
||||
everlasting life, although such a prize- like all power- comes at a
|
||||
price. Once mortal, the Undying has seen mortal lifetimes pass like the
|
||||
sea- sons, like the flicker of endless days and nights. It has the secrets
|
||||
of the ages to share, secrets of life and death. Beings of this sort
|
||||
include Vecna, Lord of the Hand and the Eye; the dread Iuz; the lich-queen
|
||||
Vol; the Undying Court of Aerenal; Vlaakith, lich-queen of the githyanki;
|
||||
and the deathless wizard Fistandantalus.
|
||||
|
||||
In the Realms, Undying patrons include Larloch the Shadow King, legendary
|
||||
master of Warlock's Crypt, and Gilgeam, the God-King of Unther
|
||||
|
||||
"""
|
||||
name = "The Undying Patron"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
# XGTE
|
||||
class Celestial(SubClass):
|
||||
"""Your patron is a powerful being of the Upper Planes. You have bound yourself
|
||||
to an ancient empyrean, solar, ki-rin, unicorn, or other entity that
|
||||
resides in the planes of everlasting bliss. Your pact with that being
|
||||
allows you to experience the barest touch of the holy light that illu—
|
||||
minates the multiverse.
|
||||
|
||||
Being connected to such power can cause changes in your behavior and
|
||||
beliefs. You might find yourself driven to annihilate the undead, to defeat
|
||||
fiends, and to protect the innocent. At times, your heart might also be
|
||||
filled with a longing for the celestial realm of your patron, and a desire
|
||||
to wander that paradise for the rest of your days. But you know that your
|
||||
mission is among mortals for now, and that your pact binds you to bring
|
||||
light to the dark places of the world.
|
||||
|
||||
"""
|
||||
name = "The Celestial Patron"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class Hexblade(SubClass):
|
||||
"""You have made your pact with a mysterious entity from the Shadowfell—a force
|
||||
that manifests in sentient magic weapons carved from the stuff of
|
||||
shadow. The mighty sword Blackrazor is the most notable of these weapons,
|
||||
which have been spread across the multiverse over the ages. The shadowy
|
||||
force behind these weapons can offer power to warlocks who form pacts with
|
||||
it. Many hexhlade warlocks create weapons that emulate those formed in the
|
||||
Shadowfell. Others forgo such arms, content to weave the dark magic of that
|
||||
plane into their spellcasting.
|
||||
|
||||
Because the Raven Queen is known to have forged the first of these weapons,
|
||||
many sages speculate that she and the force are one and that the weapons,
|
||||
along with hexblade warlocks, are tools she uses to manipulate events on
|
||||
the Material Plane to her inscrutable ends
|
||||
|
||||
"""
|
||||
name = "Hexblade Patron"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class Warlock(CharClass):
|
||||
@@ -12,6 +121,11 @@ class Warlock(CharClass):
|
||||
'Intimidation', 'Investigation', 'Nature',
|
||||
'Religion')
|
||||
weapon_proficiencies = weapons.simple_weapons
|
||||
multiclass_weapon_proficiencies = weapon_proficiencies
|
||||
_multiclass_proficiencies_text = ('light armor', 'simple weapons')
|
||||
features_by_level = defaultdict(list)
|
||||
subclasses_available = (Archfey, Fiend, GreatOldOne, Undying, Celestial,
|
||||
Hexblade)
|
||||
spellcasting_ability = 'charisma'
|
||||
spell_slots_by_level = {
|
||||
1: (2, 1, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
|
||||
@@ -1,6 +1,159 @@
|
||||
from .. import (weapons)
|
||||
from .. import features as feats
|
||||
from .classes import CharClass
|
||||
from .. import (weapons, features)
|
||||
from .classes import CharClass, SubClass
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
# PHB
|
||||
class Abjuration(SubClass):
|
||||
"""The School of Abjuration emphasizes magic that blocks, banishes, or
|
||||
protects. Detractors of this school say that its tradition is about denial,
|
||||
negation rather than positive assertion. You understand, however, that
|
||||
ending harmful effects, protecting the weak, and banishing evil influences
|
||||
is anything but a philosophical void. It is a proud and respected vocation.
|
||||
|
||||
Called abjurers, members of this school are sought when baleful spirits
|
||||
require exorcism, when important locations must be guarded against magical
|
||||
spying, and when portals to other planes of existence must be closed.
|
||||
|
||||
"""
|
||||
name = "School of Abjuration"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class Conjuration(SubClass):
|
||||
"""As a conjurer, you favor spells that produce objects and creatures out o f
|
||||
thin air. You can conjure billowing clouds of killing fog or summon
|
||||
creatures from elsewhere to fight on your behalf. As your mastery grows,
|
||||
you learn spells of transportation and can teleport yourself across vast
|
||||
distances, even to other planes of existence, in an instant
|
||||
|
||||
"""
|
||||
name = "School of Conjuration"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class Divination(SubClass):
|
||||
"""The counsel of a diviner is sought by royalty and commoners alike, for all
|
||||
seek a clearer understanding of the past, present, and future. As a
|
||||
diviner, you strive to part the veils of space, time, and consciousness so
|
||||
that you can see clearly. You work to master spells of discernment, remote
|
||||
viewing, supernatural knowledge, and foresight.
|
||||
|
||||
"""
|
||||
name = "School of Divination"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class Enchantment(SubClass):
|
||||
"""As a member of the School of Enchantment, you have honed your ability to
|
||||
magically entrance and beguile other people and monsters. Some enchanters
|
||||
are peacemakers who bewitch the violent to lay down their arms and charm
|
||||
the cruel into showing mercy. Others are tyrants who magically bind the
|
||||
unwilling into their service. Most enchanters fall somewhere in between.
|
||||
|
||||
"""
|
||||
name = "School of Enchantment"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class Evocation(SubClass):
|
||||
"""You focus your study on magic that creates powerful elemental effects such
|
||||
as bitter cold, searing flame, rolling thunder, crackling lightning, and
|
||||
burning acid. Some evokers find employment in military forces, serving as
|
||||
artillery to blast enemy armies from afar. Others use their spectacular
|
||||
power to protect the weak, while some seek their own gain as bandits,
|
||||
adventurers, or aspiring tyrants.
|
||||
|
||||
"""
|
||||
name = "School of Evocation"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class Illusion(SubClass):
|
||||
"""You focus your studies on magic that dazzles the senses, befuddles the
|
||||
mind, and tricks even the wisest folk. Your magic is subtle, but the
|
||||
illusions crafted by your keen mind make the impossible seem real. Some
|
||||
illusionists—including many gnome w izards—are benign tricksters who use
|
||||
their spells to entertain. Others are more sinister masters of deception,
|
||||
using their illusions to frighten and fool others for their personal gain.
|
||||
|
||||
"""
|
||||
name = "School of Illusion"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class Necromancy(SubClass):
|
||||
"""The School of Necromancy explores the cosm ic forces of life, death, and
|
||||
undeath. As you focus your studies in this tradition, you learn to
|
||||
manipulate the energy that animates all living things. As you progress, you
|
||||
learn to sap the life force from a creature as your magic destroys its
|
||||
body, transforming that vital energy into magical power you can manipulate.
|
||||
|
||||
Most people see necromancers as menacing, or even villainous, due to the
|
||||
close association with death. Not all necromancers are evil, but the forces
|
||||
they manipulate are considered taboo by many societies
|
||||
|
||||
"""
|
||||
name = "School of Necromancy"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class Transmutation(SubClass):
|
||||
"""You are a student of spells that modify energy and matter. To you, the
|
||||
world is not a fixed thing, but eminently mutable, and you delight in being
|
||||
an agent of change. You wield the raw stuff of creation and learn to alter
|
||||
both physical forms and mental qualities. Your magic gives you the tools to
|
||||
become a smith on reality’s forge.
|
||||
|
||||
Some transmuters are tinkerers and pranksters, turning people into toads
|
||||
and transforming copper into silver for fun and occasional profit. Others
|
||||
pursue their magical studies with deadly seriousness, seeking the power of
|
||||
the gods to make and destroy worlds
|
||||
|
||||
"""
|
||||
name = "School of Transmutation"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
# SCAG
|
||||
class Bladeslinging(SubClass):
|
||||
"""**Restriction: Elves Only**
|
||||
|
||||
Bladesingers are elves who bravely defend their people and lands. They are
|
||||
elf wizards who master a school of sword fighting grounded in a tradition
|
||||
of arcane magic. In combat, a bladesinger uses a series of intricate,
|
||||
elegant maneuvers that fend off harm and allow the bladesinger to channel
|
||||
magic into devastating attacks and a cunning defense
|
||||
|
||||
"""
|
||||
name = "School of Bladeslinging"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
# XGTE
|
||||
class WarMagic(SubClass):
|
||||
"""A variety of arcane colleges specialize in training wiz— ards for war. The
|
||||
tradition of War Magic blends principles of evocation and abjuration,
|
||||
rather than specializing in either of those schools. It teaches
|
||||
techniques that empower a caster’s spells, while also providing methods for
|
||||
wizards to bolster their own defenses.
|
||||
|
||||
Followers of this tradition are known as war mages. They see their magic
|
||||
as both a weapon and armor, a resource superior to any piece of steel. War
|
||||
mages act fast in battle, using their spells to seize tactical control of a
|
||||
situation. Their spells strike hard, while their defensive skills foil
|
||||
their opponents“ attempts to counterattack. War mages are also adept at
|
||||
turning other spellcasters’ magical energy against them.
|
||||
|
||||
In great battles, a war mage often works with evokers, abjurers, and other
|
||||
types of wizards. Evokers, in particular, sometimes tease war mages for
|
||||
splitting their attention between offense and defense. A war mage’s typical
|
||||
response: “What good is being able to throw a mighty fireball if I die
|
||||
before I can cast it?
|
||||
|
||||
"""
|
||||
name = "School of War Magic"
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class Wizard(CharClass):
|
||||
@@ -12,8 +165,14 @@ class Wizard(CharClass):
|
||||
weapon_proficiencies = (weapons.Dagger, weapons.Dart,
|
||||
weapons.Sling, weapons.Quarterstaff,
|
||||
weapons.LightCrossbow)
|
||||
multiclass_weapon_proficiencies = ()
|
||||
_multiclass_proficiencies_text = ()
|
||||
class_skill_choices = ('Arcana', 'History', 'Investigation',
|
||||
'Medicine', 'Religion')
|
||||
features_by_level = defaultdict(list)
|
||||
subclasses_available = (Abjuration, Conjuration, Divination, Enchantment,
|
||||
Evocation, Illusion, Necromancy, Transmutation,
|
||||
Bladeslinging, WarMagic)
|
||||
spellcasting_ability = 'intelligence'
|
||||
spell_slots_by_level = {
|
||||
# char_lvl: (cantrips, 1st, 2nd, 3rd, ...)
|
||||
|
||||
@@ -38,11 +38,11 @@ class App(npyscreen.NPSAppManaged):
|
||||
def save_character(self):
|
||||
# Save the file
|
||||
filename = self.getForm("SAVE").filename.value
|
||||
self.character.save(filename, template_file='empty_template.tex')
|
||||
self.character.save(filename, template_file='empty_template.txt')
|
||||
# Create the PDF character sheet
|
||||
if self.getForm('SAVE').make_pdf.value:
|
||||
log.debug("Creating PDF")
|
||||
self.character.to_pdf(filename, template_file='empty_template.tex')
|
||||
self.character.to_pdf(filename, template_file='empty_template.txt')
|
||||
subprocess.call(['makesheets', filename])
|
||||
|
||||
def update_max_hp(self):
|
||||
@@ -243,7 +243,10 @@ class SubclassForm(npyscreen.ActionForm):
|
||||
def __init__(self, newclass, level, num=1, **kwargs):
|
||||
self.class_num = num
|
||||
self.parent_class = newclass
|
||||
self.subclass_options = newclass.subclasses_available or ('None',)
|
||||
if len(newclass.subclasses_available) > 0:
|
||||
self.subclass_options = [sc.name for sc in newclass.subclasses_available]
|
||||
else:
|
||||
self.subclass_options = ('None',)
|
||||
self.level = level
|
||||
super().__init__(**kwargs)
|
||||
|
||||
|
||||
@@ -14,3 +14,4 @@ from .warlock import *
|
||||
from .wizard import *
|
||||
from .races import *
|
||||
from .backgrounds import *
|
||||
from .feats import *
|
||||
|
||||
@@ -193,7 +193,7 @@ class CitySecrets(Feature):
|
||||
|
||||
# Swords Coast Adventurer's Guide
|
||||
class AllEyesOnYou(Feature):
|
||||
"""Your accent, mannerisms, figures of speech, and per- haps even your
|
||||
"""Your accent, mannerisms, figures of speech, and perhaps even your
|
||||
appearance all mark you as foreign. Curious glances are directed your way
|
||||
wherever you go, which can be a nuisance, but you also gain the friendly
|
||||
interest of scholars and others intrigued by far-off lands, to say nothing
|
||||
@@ -224,7 +224,7 @@ class EarToTheGround(Feature):
|
||||
|
||||
class WatchersEye(Feature):
|
||||
"""Your experience in enforcing the law, and dealing with lawbreakers, gives
|
||||
you a feel for local laws and crimi- nals. You can easily find the local
|
||||
you a feel for local laws and criminals. You can easily find the local
|
||||
outpost of the watch or a simila r organization, and just as easily pick
|
||||
out the dens of criminal activity in a community, although you're more
|
||||
likely to be welcome in the former locations rather than the latter.
|
||||
@@ -237,9 +237,9 @@ class WatchersEye(Feature):
|
||||
class RespectOfTheStoutFolk(Feature):
|
||||
"""As well respected as clan crafters are among outsiders, no one esteems them
|
||||
quite so highly as dwarves do. You always have free room and board in any
|
||||
place where shield dwarves or gold dwarves dwell, and the individu- als in
|
||||
place where shield dwarves or gold dwarves dwell, and the individuals in
|
||||
such a settlement might vie among themselves to determine who can offer you
|
||||
(and possibly your compa- triots) the finest accommodations and assistance.
|
||||
(and possibly your compatriots) the finest accommodations and assistance.
|
||||
|
||||
"""
|
||||
name = "Respect of the Stout Folk"
|
||||
@@ -257,7 +257,7 @@ class LibraryAccess(Feature):
|
||||
and you know how to navigate those connections with some ease.
|
||||
|
||||
Additionally, you are likely to gain preferential treatment at other
|
||||
libraries across the Realms, as profes- sional courtesy shown to a fellow
|
||||
libraries across the Realms, as professional courtesy shown to a fellow
|
||||
scholar.
|
||||
|
||||
"""
|
||||
@@ -267,7 +267,7 @@ class LibraryAccess(Feature):
|
||||
|
||||
class CourtFunctionary(Feature):
|
||||
"""Your knowledge of how bureaucracies function lets you gain access to the
|
||||
records and inner workings of any no- ble court or government you
|
||||
records and inner workings of any noble court or government you
|
||||
encounter. You know who the movers and shakers are, whom to go to for the
|
||||
favors you seek, and what the current intrigues of interest in the group
|
||||
are.
|
||||
@@ -279,10 +279,10 @@ class CourtFunctionary(Feature):
|
||||
|
||||
class SafeHaven(Feature):
|
||||
"""As a faction agent, you have access to a secret network of supporters and
|
||||
operatives who can provide assis- tance on your adventures. You know a set
|
||||
operatives who can provide assistance on your adventures. You know a set
|
||||
of secret signs and passwords you can use to identify such operatives , who
|
||||
can provide you with access to a hidden safe house, free room and board, or
|
||||
assistance in finding informa- tion. These agents never risk their lives
|
||||
assistance in finding information. These agents never risk their lives
|
||||
for you or risk revealing their true identities.
|
||||
|
||||
"""
|
||||
@@ -321,7 +321,7 @@ class KnightlyRegard(Feature):
|
||||
"""You receive shelter and succor from members of your knightly order and those
|
||||
who are sympathetic to its aims. If your order is a religious one, you can
|
||||
gain aid from temples and other religious communities of your
|
||||
deity. Knights of civic orders can get help from the com- munity- whether a
|
||||
deity. Knights of civic orders can get help from the community- whether a
|
||||
lone settlement or a great nation- that they serve, and knights of
|
||||
philosophical orders can find help from those they have aided in pursuit of
|
||||
their ideals , and those who share those ideals.
|
||||
@@ -329,7 +329,7 @@ class KnightlyRegard(Feature):
|
||||
This help comes in the form of shelter and meals, and healing when
|
||||
appropriate, as well as occasionally risky assistance, such as a band of
|
||||
local citizens rallying to aid a sorely pressed knight in a fight , or
|
||||
those who sup- port the order helping to smuggle a knight out of town when
|
||||
those who support the order helping to smuggle a knight out of town when
|
||||
he or she is being hunted unjustly.
|
||||
|
||||
"""
|
||||
@@ -343,7 +343,7 @@ class MercenaryLife(Feature):
|
||||
little about any such company, including the names and reputations of its
|
||||
commanders and leaders, and who has hired them recently. You can find the
|
||||
taverns and festhalls where mercenaries abide in any area, as long as you
|
||||
speak the language. You can find mercenary work between adven- tures
|
||||
speak the language. You can find mercenary work between adventures
|
||||
sufficient to maintain a comfortable lifestyle (see "Practicing a
|
||||
Profession" under "Downtime Activities" in chapter 8 of the Player's
|
||||
Handbook).
|
||||
@@ -376,7 +376,7 @@ class KeptInStyle(Feature):
|
||||
cord your debt and send an accounting to your family's estate in Waterdeep
|
||||
to settle what you owe.
|
||||
|
||||
This advantage enables you to live a comfortable life- style without having
|
||||
This advantage enables you to live a comfortable lifestyle without having
|
||||
to pay 2 gp a day for it, or reduces the cost of a wealthy or aristocratic
|
||||
lifestyle by that amount. You may not maintain a less affluent lifestyle
|
||||
and use the difference as income-the benefit is a line of credit, not an
|
||||
|
||||
@@ -83,3 +83,19 @@ class Feature():
|
||||
return -100
|
||||
|
||||
|
||||
class FeatureSelector(Feature):
|
||||
"""
|
||||
A feature with multiple possible choices.
|
||||
"""
|
||||
options = dict()
|
||||
|
||||
def __init__(self, feature_choices=[]):
|
||||
keep_source = self.source
|
||||
# Look for matching feature_choices
|
||||
for selection in feature_choices:
|
||||
if selection.lower() in self.options():
|
||||
new_feat = self.options[selection.lower()]
|
||||
self.__dict__.update(new_feat.__dict__)
|
||||
new_feat.__init__(self)
|
||||
break
|
||||
self.source = keep_source
|
||||
|
||||
@@ -395,7 +395,7 @@ class RadiantSoul(Feature):
|
||||
|
||||
Your transformation lasts for 1 minute or until you end it as a bonus
|
||||
action. During it, you have a flying speed of 30 feet, and once on each of
|
||||
your turns, you can deal ex- tra radiant damage to one target when you deal
|
||||
your turns, you can deal extra radiant damage to one target when you deal
|
||||
damage to it with an attack or a spell. The extra radiant damage equals
|
||||
your level.
|
||||
|
||||
@@ -409,13 +409,13 @@ class RadiantSoul(Feature):
|
||||
|
||||
class RadiantConsumption(Feature):
|
||||
"""Starting at 3rd level, you can use your action to unleash the divine energy
|
||||
within your- self, causing a searing light to radiate from you, pour out of
|
||||
within yourself, causing a searing light to radiate from you, pour out of
|
||||
your eyes and mouth, and threaten to char you.
|
||||
|
||||
Your transformation lasts for 1 minute or until you end ii as a bonus
|
||||
action. During it, you shed bright light in a 10-foot radius and dim light
|
||||
for an additional 10 feet,and at the end of each of your turns, you and
|
||||
each crea- ture within 10 feet of you take radiant damage equal to half
|
||||
each creature within 10 feet of you take radiant damage equal to half
|
||||
your level (rounded up). In addition, once on each of your turns, you can
|
||||
deal extra radiant damage to one target when you deal damage to it with an
|
||||
attack or a spell. The extra radiant damage equals your level.
|
||||
@@ -489,7 +489,7 @@ class SpeechOfBeastAndLeaf(Feature):
|
||||
|
||||
# Goliath
|
||||
class StonesEndurance(Feature):
|
||||
"""You can focus yourself to occa- sionally shrug off injury. When you take
|
||||
"""You can focus yourself to occasionally shrug off injury. When you take
|
||||
damage, you can use your reaction to roll a dl2. Add your Constitution
|
||||
modifier to the number rolled, and reduce the damage by that total. After
|
||||
you use this trait, you can't use it again until you finish a short or long
|
||||
@@ -614,7 +614,7 @@ class ControlAirAndWater(Feature):
|
||||
|
||||
|
||||
class EmissaryOfTheSea(Feature):
|
||||
"""Aquatic beasts have an extraor- dinary affinity with your people. You can
|
||||
"""Aquatic beasts have an extraordinary affinity with your people. You can
|
||||
communicate simple ideas with beasts that can breathe water. They can
|
||||
understand the meaning of your words, though you have no special ability to
|
||||
understand them in return.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from .features import Feature
|
||||
from .features import Feature, FeatureSelector
|
||||
from .. import (weapons, armor)
|
||||
|
||||
|
||||
@@ -16,22 +16,6 @@ def select_ranger_fighting_style(feature_choices=[]):
|
||||
return RangerFightingStyle()
|
||||
|
||||
|
||||
class RangerFightingStyle(Feature):
|
||||
"""
|
||||
Select a Fighting Style by choosing in feature_choices:
|
||||
|
||||
archery
|
||||
|
||||
defense
|
||||
|
||||
dueling
|
||||
|
||||
two-weapon fighting
|
||||
"""
|
||||
name = "Fighting Style (Select One)"
|
||||
source = "Ranger"
|
||||
|
||||
|
||||
class Archery(Feature):
|
||||
"""
|
||||
You gain a +2 bonus to attack rolls you make
|
||||
@@ -84,3 +68,25 @@ class TwoWeaponFighting(Feature):
|
||||
name = "Fighting Style (Two-Weapon Fighting)"
|
||||
source = "Ranger"
|
||||
needs_implementation = True
|
||||
|
||||
|
||||
class RangerFightingStyle(FeatureSelector):
|
||||
"""
|
||||
Select a Fighting Style by choosing in feature_choices:
|
||||
|
||||
archery
|
||||
|
||||
defense
|
||||
|
||||
dueling
|
||||
|
||||
two-weapon fighting
|
||||
"""
|
||||
options = {'archery': Archery,
|
||||
'defense': Defense,
|
||||
'dueling': Dueling,
|
||||
'two-weapon fighting': TwoWeaponFighting,
|
||||
'two-weapon': TwoWeaponFighting,
|
||||
'dual wield': TwoWeaponFighting}
|
||||
name = "Fighting Style (Select One)"
|
||||
source = "Ranger"
|
||||
|
||||
@@ -0,0 +1,335 @@
|
||||
from .features import Feature
|
||||
from .. import spells
|
||||
|
||||
|
||||
# All Invocations
|
||||
class Invocation(Feature):
|
||||
"""
|
||||
A generic Eldritch Invocation. Add details in features/warlock.py
|
||||
"""
|
||||
name = 'Unnamed Invocation'
|
||||
source = "Warlock (Eldritch Invocations)"
|
||||
at_will_spells = ()
|
||||
|
||||
def cast_spell_at_will(self, spell):
|
||||
s = spell()
|
||||
s.level = 0
|
||||
if 'M' in s.components:
|
||||
c = list(s.components)
|
||||
c.remove('M')
|
||||
s.components = tuple(c)
|
||||
self.spells_known += (s,)
|
||||
self.spells_prepared += (s,)
|
||||
|
||||
def __init__(self):
|
||||
for s in self.at_will_spells:
|
||||
self.cast_spell_at_will(s)
|
||||
|
||||
|
||||
# PHB
|
||||
class AgonizingBlast(Invocation):
|
||||
"""When you cast eldritch blast, add your Charisma modifier to the damage it
|
||||
deals on a hit.
|
||||
|
||||
"""
|
||||
name = "Agonizing Blast"
|
||||
needs_implementation = True
|
||||
|
||||
|
||||
class ArmorOfShadows(Invocation):
|
||||
"""You can cast mage armor on yourself at will, without expending a spell slot
|
||||
or material components
|
||||
|
||||
"""
|
||||
name = "Armor of Shadows"
|
||||
at_will_spells = (spells.MageArmor,)
|
||||
|
||||
|
||||
class AscendantStep(Invocation):
|
||||
"""You can cast levitate on yourself at will, without expending a spell slot
|
||||
or material components.
|
||||
|
||||
**Prerequisite: 9th level**
|
||||
|
||||
"""
|
||||
name = 'Ascendant Step'
|
||||
at_will_spells = (spells.Levitate,)
|
||||
|
||||
|
||||
class BeastSpeech(Invocation):
|
||||
"""You can cast speak with animals at will, without expending a spell slot.
|
||||
|
||||
"""
|
||||
name = "Beast Speech"
|
||||
at_will_spells = (spells.SpeakWithAnimals,)
|
||||
|
||||
|
||||
class BeguilingInfluence(Invocation):
|
||||
"""You gain proficiency in the Deception and Persuasion skills.
|
||||
|
||||
"""
|
||||
name = "Beguiling Influence"
|
||||
needs_implementation = True
|
||||
|
||||
|
||||
class BewitchingWhispers(Invocation):
|
||||
"""You can cast compulsion once using a warlock spell slot. You can’t do so
|
||||
again until you finish a long rest
|
||||
|
||||
**Prerequisite**: 7th Level
|
||||
"""
|
||||
name = "Bewitching Whispers"
|
||||
|
||||
|
||||
class BookOfAncientSecrets(Invocation):
|
||||
"""You can now inscribe magical rituals in your Book of Shadows. Choose two
|
||||
1st-level spells that have the ritual tag from any class’s spell list. The
|
||||
spells appear in the book and don’t count against the number of spells you
|
||||
know. With your Book of Shadows in hand, you can cast the chosen spells as
|
||||
rituals. You can’t cast the spells except as rituals, unless you’ve learned
|
||||
them by some other means. You can also cast a warlock spell you know as a
|
||||
ritual if it has the ritual tag.
|
||||
|
||||
On your adventures, you can add other ritual spells to your Book o f
|
||||
Shadows. When you find such a spell, you can add it to the book if the
|
||||
spell’s level is equal to or less than half your warlock level (rounded up)
|
||||
and if you can spare the time to transcribe the spell. For each level of
|
||||
the spell, the transcription process takes 2 hours and costs 50 gp for the
|
||||
rare inks needed to inscribe it
|
||||
|
||||
"""
|
||||
name = "Book of Ancient Secrets"
|
||||
|
||||
|
||||
class ChainsOfCarceri(Invocation):
|
||||
"""You can cast hold monster at will—targeting a celestial, fiend, or
|
||||
elemental—without expending a spell slot or material components. You must
|
||||
finish a long rest before you can use this invocation on the same creature
|
||||
again.
|
||||
|
||||
**Prerequisites**: 15th level, Pact of the Chain Feature
|
||||
"""
|
||||
name = "Chains of Carceri"
|
||||
|
||||
|
||||
class DevilsSight(Invocation):
|
||||
"""You can see normally in darkness, both magical and nonmagical, to a
|
||||
distance of 120 feet.
|
||||
|
||||
"""
|
||||
name = "Devil's Sight"
|
||||
|
||||
|
||||
class DreadfulWord(Invocation):
|
||||
"""You can cast confusion once using a warlock spell slot. You can’t do so
|
||||
again until you finish a long rest.
|
||||
|
||||
"""
|
||||
name = "Dreadful Word"
|
||||
|
||||
|
||||
class EldritchSight(Invocation):
|
||||
"""You can cast detect magic at will, without expending a spell slot.
|
||||
|
||||
"""
|
||||
name = "Eldritch Sight"
|
||||
at_will_spells = (spells.DetectMagic,)
|
||||
|
||||
|
||||
class EldritchSpear(Invocation):
|
||||
"""When you cast eldritch blast, its range is 300 feet.
|
||||
|
||||
"""
|
||||
name = "Eldritch Spear"
|
||||
needs_implementation = True
|
||||
|
||||
|
||||
class EyesOfTheRuneKeeper(Invocation):
|
||||
"""
|
||||
You can read all writing.
|
||||
|
||||
"""
|
||||
name = "Eyes of the Rune Keeper"
|
||||
|
||||
|
||||
class FiendishVigor(Invocation):
|
||||
"""You can cast false life on yourself at will as a 1st-level spell, without
|
||||
expending a spell slot or material components.
|
||||
|
||||
"""
|
||||
name = "Fiendish Vigor"
|
||||
at_will_spells = (spells.FalseLife,)
|
||||
|
||||
|
||||
class GazeOfTwoMinds(Invocation):
|
||||
"""You can use your action to touch a willing humanoid and perceive through
|
||||
its senses until the end of your next turn. As long as the creature is on
|
||||
the same plane of existence as you, you can use your action on subsequent
|
||||
turns to maintain this connection, extending the duration until the end of
|
||||
your next turn. While perceiving through the other creature’s senses, you
|
||||
benefit from any special senses possessed by that creature, and you are
|
||||
blinded and deafened to your own surroundings.
|
||||
|
||||
"""
|
||||
name = "Gaze of Two Minds"
|
||||
|
||||
|
||||
class LifeDrinker(Invocation):
|
||||
"""When you hit a creature with your pact weapon, the creature takes extra
|
||||
necrotic damage equal to your Charisma modifier (minimum 1).
|
||||
|
||||
**Prerequisite**: 12th Level, Pact of the Blade
|
||||
"""
|
||||
name = "Life Drinker"
|
||||
needs_implementation = True
|
||||
|
||||
|
||||
class MaskOfManyFaces(Invocation):
|
||||
"""You can cast disguise self at will, without expending a spell slot.
|
||||
|
||||
"""
|
||||
name = "Mask of Many Faces"
|
||||
at_will_spells = (spells.DisguiseSelf,)
|
||||
|
||||
|
||||
class MasterOfMyriadForms(Invocation):
|
||||
"""
|
||||
You can cast alter self at will, without expending a spell slot.
|
||||
|
||||
**Prerequisite**: 15th Level
|
||||
"""
|
||||
name = "Master of Myriad Forms"
|
||||
at_will_spells = (spells.AlterSelf,)
|
||||
|
||||
|
||||
class MinionsOfChaos(Invocation):
|
||||
"""You can cast conjure elemental once using a warlock spell slot. You can’t
|
||||
do so again until you finish a long rest.
|
||||
|
||||
**Prerequisite**: 9th Level
|
||||
"""
|
||||
name = "Minions of Chaos"
|
||||
|
||||
|
||||
class MireTheMind(Invocation):
|
||||
"""You can cast slow once using a warlock spell slot. You can’t do so again
|
||||
until you finish a long rest.
|
||||
|
||||
"""
|
||||
name = "Mire the Mind"
|
||||
|
||||
|
||||
class MistyVisions(Invocation):
|
||||
"""You can cast silent image at will, without expending a spell slot or
|
||||
material components.
|
||||
|
||||
"""
|
||||
name = "Misty Visions"
|
||||
at_will_spells = (spells.SilentImage,)
|
||||
|
||||
|
||||
class OneWithShadows(Invocation):
|
||||
"""When you are in an area of dim light or darkness, you can use your action
|
||||
to become invisible until you move or take an action or a reaction.
|
||||
|
||||
**Prerequisite**: 5th Level
|
||||
"""
|
||||
name = "One with Shadows"
|
||||
|
||||
|
||||
class OtherworldlyLeap(Invocation):
|
||||
"""You can cast jump on yourself at will, without expending a spell slot or
|
||||
material components.
|
||||
|
||||
**Prerequisite**: 9th Level
|
||||
|
||||
"""
|
||||
name = "Otherworldly Leap"
|
||||
at_will_spells = (spells.Jump,)
|
||||
|
||||
|
||||
class RepellingBlast(Invocation):
|
||||
"""When you hit a creature with eldritch blast, you can push the creature up
|
||||
to 10 feet away from you in a straight line.
|
||||
|
||||
"""
|
||||
name = "Repelling Blast"
|
||||
|
||||
|
||||
class SculptorOfFlesh(Invocation):
|
||||
"""You can cast polymorph once using a warlock spell slot. You can’t do so
|
||||
again until you finish a long rest.
|
||||
|
||||
**Prerequisite**: 7th Level
|
||||
"""
|
||||
name = "Sculptor of Flesh"
|
||||
|
||||
|
||||
class SignOfIllOmen(Invocation):
|
||||
"""You can cast bestow curse once using a warlock spell slot. You can’t do so
|
||||
again until you finish a long rest.
|
||||
|
||||
**Prerequisite**: 5th Level
|
||||
|
||||
"""
|
||||
name = "Sign of Ill Omen"
|
||||
|
||||
|
||||
class ThiefOfFiveFates(Invocation):
|
||||
"""You can cast bane once using a warlock spell slot. You can’t do so again
|
||||
until you finish a long rest.
|
||||
|
||||
"""
|
||||
name = "Thief of Five Fates"
|
||||
needs_implementation = True
|
||||
|
||||
|
||||
class ThirstingBlade(Invocation):
|
||||
"""You can attack with your pact weapon twice, instead of once, whenever you
|
||||
take the Attack action on your turn.
|
||||
|
||||
**Prerequisite**: 5th Level, Pact of the Blade
|
||||
"""
|
||||
name = "Thirsting Blade"
|
||||
|
||||
|
||||
class VisionsOfDistantRealms(Invocation):
|
||||
"""
|
||||
You can cast arcane eye at will, without expending a spell slot
|
||||
|
||||
**Prerequisite**: 15th level
|
||||
"""
|
||||
name = "Visions of Distant Realms"
|
||||
at_will_spells = (spells.ArcaneEye,)
|
||||
|
||||
|
||||
class VoiceOfTheChain(Invocation):
|
||||
"""You can communicate telepathically with your familiar and perceive through
|
||||
your familiar’s senses as long as you are on the same plane of
|
||||
existence. Additionally, while perceiving through your familiar’s senses,
|
||||
you can also speak through your familiar in your own voice, even if your
|
||||
familiar is normally incapable of speech.
|
||||
|
||||
**Prerequisite**: Pact of the Chain
|
||||
|
||||
"""
|
||||
name = "Voice of the Chain"
|
||||
|
||||
|
||||
class WhispersOfTheGrave(Invocation):
|
||||
"""You can cast speak with dead at will, without expending a spell slot
|
||||
|
||||
**Prerequsite**: 9th Level
|
||||
|
||||
"""
|
||||
name = "Whispers of the Grave"
|
||||
at_will_spells = (spells.SpeakWithDead,)
|
||||
|
||||
|
||||
class WitchSight(Invocation):
|
||||
"""You can see the true form of any shapechanger or creature concealed by
|
||||
illusion or transmutation magic while the creature is within 30 feet of you
|
||||
and within line of sight.
|
||||
|
||||
"""
|
||||
name = "Witch Sight"
|
||||
|
||||
@@ -9,6 +9,7 @@ dungeonsheets_version = "{{ char.dungeonsheets_version }}"
|
||||
|
||||
name = "{{ char.name }}"
|
||||
classes_levels = {{ char.classes_levels }}
|
||||
subclasses = {{ char.subclasses }}
|
||||
player_name = "{{ char.player_name }}"
|
||||
background = "{{ char.background.name }}"
|
||||
race = "{{ char.race.name }}"
|
||||
@@ -28,7 +29,7 @@ charisma = {{ char.charisma.value }}
|
||||
skill_proficiencies = {{ char.skill_proficiencies }}
|
||||
|
||||
# Named features / feats that aren't part of your classes,
|
||||
# race, or background.
|
||||
# race, or background. Also include Eldritch Invocations.
|
||||
# Example:
|
||||
# features = ('Tavern Brawler',) # take the optional Feat from PHB
|
||||
features = {{ char.custom_features }}
|
||||
@@ -12,6 +12,7 @@ dungeonsheets_version = "{{ char.dungeonsheets_version }}"
|
||||
|
||||
name = "{{ char.name }}"
|
||||
classes_levels = {{ char.classes_levels }}
|
||||
subclasses = {{ char.subclasses }}
|
||||
player_name = "{{ char.player_name }}"
|
||||
background = "{{ char.background.name }}"
|
||||
race = "{{ char.race.name }}"
|
||||
@@ -5,7 +5,7 @@
|
||||
\usepackage[dvipsnames]{color}
|
||||
\definecolor{mygrey}{gray}{0.7}
|
||||
|
||||
\title{Features and Traits}
|
||||
\title{Features and Subclass}
|
||||
\author{[[ character.name ]]}
|
||||
\date{}
|
||||
|
||||
@@ -13,6 +13,14 @@
|
||||
|
||||
\maketitle
|
||||
|
||||
[% for sc in character.subclasses if sc not in ['', None, 'None', 'none']%]
|
||||
|
||||
\section*{[[ sc.name ]]}
|
||||
|
||||
[[ sc.__doc__|rst_to_latex ]]
|
||||
|
||||
[% endfor %]
|
||||
|
||||
[% for feat in character.features %]
|
||||
|
||||
\section*{[[ feat.name ]]}
|
||||
@@ -5,7 +5,7 @@
|
||||
\usepackage[dvipsnames]{color}
|
||||
\definecolor{mygrey}{gray}{0.7}
|
||||
|
||||
\title{Spells and Incantations}
|
||||
\title{Spell Descriptions}
|
||||
\author{[[ character.name ]]}
|
||||
\date{}
|
||||
|
||||
@@ -45,7 +45,7 @@ def rst_to_latex(rst):
|
||||
|
||||
|
||||
jinja_env = Environment(
|
||||
loader=PackageLoader('dungeonsheets', ''),
|
||||
loader=PackageLoader('dungeonsheets', 'forms'),
|
||||
block_start_string='[%',
|
||||
block_end_string='%]',
|
||||
variable_start_string='[[',
|
||||
@@ -183,7 +183,7 @@ def create_spells_pdf(char, basename, flatten=False):
|
||||
# for field in field_names:
|
||||
# fields.append((field, field))
|
||||
# Make the actual pdf
|
||||
dirname = os.path.dirname(os.path.abspath(__file__))
|
||||
dirname = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'forms/')
|
||||
src_pdf = os.path.join(dirname, 'blank-spell-sheet-default.pdf')
|
||||
make_pdf(fields, src_pdf=src_pdf, basename=basename, flatten=flatten)
|
||||
|
||||
@@ -318,7 +318,7 @@ def create_character_pdf(char, basename, flatten=False):
|
||||
prof_text += "\n\nLanguages:\n" + text_box(char.languages)
|
||||
fields['ProficienciesLang'] = prof_text
|
||||
# Prepare the actual PDF
|
||||
dirname = os.path.dirname(os.path.abspath(__file__))
|
||||
dirname = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'forms/')
|
||||
src_pdf = os.path.join(dirname, 'blank-character-sheet-default.pdf')
|
||||
return make_pdf(fields, src_pdf=src_pdf, basename=basename,
|
||||
flatten=flatten)
|
||||
|
||||
@@ -26,9 +26,13 @@ class Race():
|
||||
spells_prepared = ()
|
||||
|
||||
def __init__(self):
|
||||
self.features = tuple([f() for f in self.features])
|
||||
cls = type(self)
|
||||
# Instantiate the features
|
||||
self.features = tuple([f() for f in cls.features])
|
||||
self.features_by_level = defaultdict(list)
|
||||
for i in range(1, 21):
|
||||
self.features_by_level[i] = [f() for f in self.features_by_level[i]]
|
||||
self.features_by_level[i] = [f()for f in
|
||||
cls.features_by_level[i]]
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@@ -1,6 +1,22 @@
|
||||
from .spells import Spell
|
||||
|
||||
|
||||
class Jump(Spell):
|
||||
"""You touch a creature. The creature’s jump distance is tripled until the
|
||||
spell ends.
|
||||
|
||||
"""
|
||||
name = "Jump"
|
||||
level = 1
|
||||
casting_time = '1 action'
|
||||
casting_range = "Touch"
|
||||
components = ("V", "S", "M")
|
||||
materials = "A grasshoppers hind leg"
|
||||
duration = "1 minute"
|
||||
magic_school = "Transmutation"
|
||||
classes = ("Druid", 'Ranger', 'Sorceror', 'Wizard')
|
||||
|
||||
|
||||
class Knock(Spell):
|
||||
"""Choose an object that you can see within range. The object can be a
|
||||
door, a box, a chest, a set of manacles, a padlock, or another
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -20,11 +20,8 @@ setup(name='dungeonsheets',
|
||||
download_url = 'https://github.com/canismarko/dungeon-sheets/archive/master.zip',
|
||||
packages=find_packages(),
|
||||
package_data={
|
||||
'dungeonsheets': ['blank-character-sheet-default.pdf',
|
||||
'blank-spell-sheet-default.pdf',
|
||||
'spellbook_template.tex', '../VERSION',
|
||||
'character_template.txt', 'features_template.tex',
|
||||
'druid_shapes_template.tex']
|
||||
'dungeonsheets': ['forms/*pdf', 'forms/*.tex', 'forms/*.txt',
|
||||
'../VERSION']
|
||||
},
|
||||
install_requires=[
|
||||
'fdfgen', 'npyscreen', 'jinja2', 'pdfrw',
|
||||
|
||||
Reference in New Issue
Block a user