mirror of
https://github.com/Threnklyn/dungeon-sheets.git
synced 2026-06-07 13:15:53 +02:00
Features added and tested for all classes/subclasses in bens campaign
This commit is contained in:
@@ -105,3 +105,5 @@ ENV/
|
|||||||
|
|
||||||
# mypy
|
# mypy
|
||||||
.mypy_cache/
|
.mypy_cache/
|
||||||
|
|
||||||
|
add_spell.sh
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
"""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.9.0"
|
|
||||||
|
|
||||||
name = "Ben"
|
|
||||||
player_name = "Ben"
|
|
||||||
|
|
||||||
# Be sure to list Primary class first
|
|
||||||
classes = ['Bard', 'Paladin'] # ex: ['Wizard'] or ['Rogue', 'Fighter']
|
|
||||||
levels = [10, 2] # ex: [10] or [3, 2]
|
|
||||||
subclasses = ['', ''] # ex: ['Necromacy'] or ['Thief', None]
|
|
||||||
background = "Sailor"
|
|
||||||
race = "Half-Orc"
|
|
||||||
alignment = "Neutral good"
|
|
||||||
xp = 0
|
|
||||||
hp_max = 10
|
|
||||||
|
|
||||||
# Ability Scores
|
|
||||||
strength = 20
|
|
||||||
dexterity = 13
|
|
||||||
constitution = 14
|
|
||||||
intelligence = 12
|
|
||||||
wisdom = 10
|
|
||||||
charisma = 9
|
|
||||||
|
|
||||||
# Select what skills you're proficient with
|
|
||||||
# ex: skill_proficiencies = ('athletics', 'acrobatics', 'arcana')
|
|
||||||
skill_proficiencies = ('arcana', 'medicine', 'athletics', 'perception', 'intimidation')
|
|
||||||
|
|
||||||
# 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, Orc"""
|
|
||||||
|
|
||||||
# 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')
|
|
||||||
magic_items = () # Example: ('ring of protection',)
|
|
||||||
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."""
|
|
||||||
+91
-77
@@ -60,9 +60,7 @@ class Character():
|
|||||||
player_name = ""
|
player_name = ""
|
||||||
alignment = "Neutral"
|
alignment = "Neutral"
|
||||||
dungeonsheets_version = __version__
|
dungeonsheets_version = __version__
|
||||||
class_list = []
|
class_list = list()
|
||||||
_level = 1 # Keep internal check of total level
|
|
||||||
_hit_dice_faces = 2
|
|
||||||
_race = None
|
_race = None
|
||||||
_background = None
|
_background = None
|
||||||
xp = 0
|
xp = 0
|
||||||
@@ -77,13 +75,11 @@ class Character():
|
|||||||
charisma = Ability()
|
charisma = Ability()
|
||||||
armor_class = ArmorClass()
|
armor_class = ArmorClass()
|
||||||
speed = Speed()
|
speed = Speed()
|
||||||
_saving_throw_proficiencies = []
|
inspiration = 0
|
||||||
other_weapon_proficiencies = tuple()
|
_saving_throw_proficiencies = tuple() # use to overwrite class proficiencies
|
||||||
skill_proficiencies = tuple()
|
other_weapon_proficiencies = tuple() # add to class/race proficiencies
|
||||||
skill_expertise = tuple()
|
skill_proficiencies = list()
|
||||||
class_skill_choices = tuple()
|
skill_expertise = list()
|
||||||
num_skill_choices = 2
|
|
||||||
proficiencies_extra = tuple()
|
|
||||||
languages = ""
|
languages = ""
|
||||||
# Skills
|
# Skills
|
||||||
acrobatics = Skill(ability='dexterity')
|
acrobatics = Skill(ability='dexterity')
|
||||||
@@ -118,30 +114,36 @@ class Character():
|
|||||||
gp = 0
|
gp = 0
|
||||||
pp = 0
|
pp = 0
|
||||||
equipment = ""
|
equipment = ""
|
||||||
weapons = [] # Replaced in __init__ constructor
|
weapons = list()
|
||||||
magic_items = []
|
magic_items = list()
|
||||||
armor = None
|
armor = None
|
||||||
shield = None
|
shield = None
|
||||||
_proficiencies_text = tuple()
|
_proficiencies_text = list()
|
||||||
# Magic
|
# Magic
|
||||||
spellcasting_ability = None
|
spellcasting_ability = None
|
||||||
_spells = tuple()
|
_spells = list()
|
||||||
_spells_prepared = tuple()
|
_spells_prepared = list()
|
||||||
# Features IN MAJOR DEVELOPMENT
|
# Features IN MAJOR DEVELOPMENT
|
||||||
custom_features = ()
|
custom_features = list()
|
||||||
feature_choices = ()
|
feature_choices = list()
|
||||||
|
|
||||||
def __init__(self, **attrs):
|
def __init__(self, **attrs):
|
||||||
"""Takes a bunch of attrs and passes them to ``set_attrs``"""
|
"""Takes a bunch of attrs and passes them to ``set_attrs``"""
|
||||||
|
self.clear()
|
||||||
# make sure class, race, background are set first
|
# make sure class, race, background are set first
|
||||||
my_classes = attrs.pop('classes', [])
|
my_classes = attrs.pop('classes', [])
|
||||||
my_levels = attrs.pop('levels', [])
|
my_levels = attrs.pop('levels', [])
|
||||||
my_subclasses = attrs.pop('subclasses', [])
|
my_subclasses = attrs.pop('subclasses', [])
|
||||||
# backwards compatability
|
# backwards compatability
|
||||||
if (len(my_classes) == 0) and ('class' in attrs):
|
if (len(my_classes) == 0):
|
||||||
my_classes = [attrs.pop('class')]
|
if ('class' in attrs):
|
||||||
my_levels = [attrs.pop('level', 1)]
|
my_classes = [attrs.pop('class')]
|
||||||
my_subclasses = [attrs.pop('subclass', None)]
|
my_levels = [attrs.pop('level', 1)]
|
||||||
|
my_subclasses = [attrs.pop('subclass', None)]
|
||||||
|
else: # if no classes or levels given, default to Lvl 1 Fighter
|
||||||
|
my_classes = ['Fighter']
|
||||||
|
my_levels = [1]
|
||||||
|
my_subclasses = [None]
|
||||||
# Generate the list of class objects
|
# Generate the list of class objects
|
||||||
self.add_classes(
|
self.add_classes(
|
||||||
my_classes, my_levels, my_subclasses,
|
my_classes, my_levels, my_subclasses,
|
||||||
@@ -151,6 +153,21 @@ class Character():
|
|||||||
self.background = attrs.pop('background', None)
|
self.background = attrs.pop('background', None)
|
||||||
# parse all other attributes
|
# parse all other attributes
|
||||||
self.set_attrs(**attrs)
|
self.set_attrs(**attrs)
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
# reset class-definied items
|
||||||
|
self.class_list = list()
|
||||||
|
self.weapons = list()
|
||||||
|
self.magic_items = list()
|
||||||
|
self._saving_throw_proficiencies = tuple()
|
||||||
|
self.other_weapon_proficiencies = tuple()
|
||||||
|
self.skill_proficiencies = list()
|
||||||
|
self.skill_expertise = list()
|
||||||
|
self._proficiencies_text = list()
|
||||||
|
self._spells = list()
|
||||||
|
self._spells_prepared = list()
|
||||||
|
self.custom_features = list()
|
||||||
|
self.feature_choices = list()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
@@ -166,16 +183,15 @@ class Character():
|
|||||||
cls = getattr(classes, cls)
|
cls = getattr(classes, cls)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise AttributeError(
|
raise AttributeError(
|
||||||
'class was not recognized from classes.py: {:s}'.format(c))
|
'class was not recognized from classes.py: {:s}'.format(cls))
|
||||||
if isinstance(level, str):
|
if isinstance(level, str):
|
||||||
level = int(level)
|
level = int(level)
|
||||||
params = {}
|
|
||||||
params['feature_choices'] = feature_choices
|
|
||||||
self.class_list.append(cls(level, owner=self,
|
self.class_list.append(cls(level, owner=self,
|
||||||
subclass=subclass, **params))
|
subclass=subclass,
|
||||||
|
feature_choices=feature_choices))
|
||||||
|
|
||||||
def add_classes(self, classes_list=[], levels=[], subclasses=[],
|
def add_classes(self, classes_list=[], levels=[], subclasses=[],
|
||||||
feature_choices=[]):
|
feature_choices=[]):
|
||||||
if isinstance(classes_list, str):
|
if isinstance(classes_list, str):
|
||||||
classes_list = [classes_list]
|
classes_list = [classes_list]
|
||||||
if isinstance(levels, int) or isinstance(levels, float) or isinstance(levels, str):
|
if isinstance(levels, int) or isinstance(levels, float) or isinstance(levels, str):
|
||||||
@@ -265,20 +281,14 @@ class Character():
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def level(self):
|
def level(self):
|
||||||
if self.num_classes == 0:
|
return sum(c.level for c in self.class_list)
|
||||||
return self._level
|
|
||||||
else:
|
|
||||||
return sum(c.level for c in self.class_list)
|
|
||||||
|
|
||||||
@level.setter
|
@level.setter
|
||||||
def level(self, new_level):
|
def level(self, new_level):
|
||||||
if self.num_classes == 0:
|
self.primary_class.level = new_level
|
||||||
self._level = new_level
|
if self.num_classes > 1:
|
||||||
else:
|
warnings.warn("Unable to tell which level to set. Updating "
|
||||||
self.primary_class.level = new_level
|
"level of primary class {:s}".format(self.primary_class.name))
|
||||||
if self.num_classes > 1:
|
|
||||||
warnings.warn("Unable to tell which level to set. Updating "
|
|
||||||
"level of primary class {:s}".format(self.primary_class.name))
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def num_classes(self):
|
def num_classes(self):
|
||||||
@@ -314,6 +324,10 @@ class Character():
|
|||||||
def weapon_proficiencies(self, new_weapons):
|
def weapon_proficiencies(self, new_weapons):
|
||||||
self.other_weapon_proficiencies = tuple(new_weapons)
|
self.other_weapon_proficiencies = tuple(new_weapons)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def other_weapon_proficiencies_text(self):
|
||||||
|
return tuple(w.name for w in self.other_weapon_proficiencies)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def features(self):
|
def features(self):
|
||||||
fts = set(self.custom_features)
|
fts = set(self.custom_features)
|
||||||
@@ -334,6 +348,9 @@ class Character():
|
|||||||
@property
|
@property
|
||||||
def custom_features_text(self):
|
def custom_features_text(self):
|
||||||
return tuple([f.name for f in self.custom_features])
|
return tuple([f.name for f in self.custom_features])
|
||||||
|
|
||||||
|
def has_feature(self, feat):
|
||||||
|
return any([isinstance(f, feat) for f in self.features])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def saving_throw_proficiencies(self):
|
def saving_throw_proficiencies(self):
|
||||||
@@ -419,18 +436,17 @@ class Character():
|
|||||||
for mitem in val:
|
for mitem in val:
|
||||||
self.magic_items.append(mitem(owner=self))
|
self.magic_items.append(mitem(owner=self))
|
||||||
elif attr == 'weapon_proficiencies':
|
elif attr == 'weapon_proficiencies':
|
||||||
self.other_weapon_proficiencies = tuple([findattr(weapons, w)
|
self.other_weapon_proficiencies = ()
|
||||||
for w in val])
|
wps = set([findattr(weapons, w) for w in val])
|
||||||
|
wps -= set(self.weapon_proficiencies)
|
||||||
|
self.other_weapon_proficiencies = list(wps)
|
||||||
elif attr == 'armor':
|
elif attr == 'armor':
|
||||||
self.wear_armor(val)
|
self.wear_armor(val)
|
||||||
elif attr == 'shield':
|
elif attr == 'shield':
|
||||||
self.wield_shield(val)
|
self.wield_shield(val)
|
||||||
elif attr == 'circle':
|
elif attr == 'circle':
|
||||||
for c in self.class_list:
|
if hasattr(self, 'Druid'):
|
||||||
if isinstance(c, classes.Druid) and (c.circle == ''):
|
self.Druid.circle = val
|
||||||
c.circle = val
|
|
||||||
self.circle = val
|
|
||||||
break
|
|
||||||
elif attr == 'features':
|
elif attr == 'features':
|
||||||
if isinstance(val, str):
|
if isinstance(val, str):
|
||||||
val = [val]
|
val = [val]
|
||||||
@@ -483,6 +499,17 @@ class Character():
|
|||||||
def spell_attack_bonus(self, class_type):
|
def spell_attack_bonus(self, class_type):
|
||||||
ability_mod = getattr(self, class_type.spellcasting_ability).modifier
|
ability_mod = getattr(self, class_type.spellcasting_ability).modifier
|
||||||
return (self.proficiency_bonus + ability_mod)
|
return (self.proficiency_bonus + ability_mod)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def initiative(self) -> str:
|
||||||
|
ini = self.dexterity.modifier
|
||||||
|
if self.has_feature(features.QuickDraw):
|
||||||
|
ini += self.proficiency_bonus
|
||||||
|
ini = '{:+d}'.format(ini)
|
||||||
|
if self.has_feature(features.NaturalExplorerRevised):
|
||||||
|
ini += '(A)'
|
||||||
|
return ini
|
||||||
|
|
||||||
|
|
||||||
def is_proficient(self, weapon: Weapon):
|
def is_proficient(self, weapon: Weapon):
|
||||||
"""Is the character proficient with this item?
|
"""Is the character proficient with this item?
|
||||||
@@ -516,7 +543,6 @@ class Character():
|
|||||||
all_proficiencies += tuple(self.race.proficiencies_text)
|
all_proficiencies += tuple(self.race.proficiencies_text)
|
||||||
if self.background is not None:
|
if self.background is not None:
|
||||||
all_proficiencies += tuple(self.background.proficiencies_text)
|
all_proficiencies += tuple(self.background.proficiencies_text)
|
||||||
all_proficiencies += tuple(self.proficiencies_extra)
|
|
||||||
# Create a single string out of all the proficiencies
|
# Create a single string out of all the proficiencies
|
||||||
for txt in all_proficiencies:
|
for txt in all_proficiencies:
|
||||||
if not final_text:
|
if not final_text:
|
||||||
@@ -536,7 +562,7 @@ class Character():
|
|||||||
s = '\n\n--'.join([f.name + ("**" if f.needs_implementation else "")
|
s = '\n\n--'.join([f.name + ("**" if f.needs_implementation else "")
|
||||||
for f in self.features])
|
for f in self.features])
|
||||||
if s != '':
|
if s != '':
|
||||||
s = '(See Features and Traits Page)\n\n--' + s
|
s = '(See Features Page)\n\n--' + s
|
||||||
s += '\n\n=================\n\n'
|
s += '\n\n=================\n\n'
|
||||||
return s
|
return s
|
||||||
|
|
||||||
@@ -593,7 +619,7 @@ class Character():
|
|||||||
weapon_ = NewWeapon()
|
weapon_ = NewWeapon()
|
||||||
# check if features add any bonuses
|
# check if features add any bonuses
|
||||||
for f in self.features:
|
for f in self.features:
|
||||||
weapon_ = f.weapon_func(weapon_, char=self)
|
weapon_ = f.weapon_func(weapon_)
|
||||||
# Set weapon attributes based on character
|
# Set weapon attributes based on character
|
||||||
if weapon_.is_finesse:
|
if weapon_.is_finesse:
|
||||||
ability_mod = max(self.strength.modifier, self.dexterity.modifier)
|
ability_mod = max(self.strength.modifier, self.dexterity.modifier)
|
||||||
@@ -612,27 +638,19 @@ class Character():
|
|||||||
"""What type and how many dice to use for re-gaining hit points.
|
"""What type and how many dice to use for re-gaining hit points.
|
||||||
|
|
||||||
To change, set hit_dice_num and hit_dice_faces."""
|
To change, set hit_dice_num and hit_dice_faces."""
|
||||||
if self.num_classes == 0:
|
return ' + '.join([f'{c.level}d{c.hit_dice_faces}'
|
||||||
return '{:d}d{:d}'.format(self.level, self._hit_dice_faces)
|
for c in self.class_list])
|
||||||
else:
|
|
||||||
return ' + '.join([f'{c.level}d{c.hit_dice_faces}'
|
|
||||||
for c in self.class_list])
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def hit_dice_faces(self):
|
def hit_dice_faces(self):
|
||||||
if self.num_classes == 0:
|
# Not a valid function if multiclass
|
||||||
return self._hit_dice_faces
|
if self.num_classes > 1:
|
||||||
else: # Not a valid function if multiclass
|
warnings.warn("hit_dice_faces is not valid for multiclass characters")
|
||||||
if self.num_classes > 1:
|
return self.primary_class.hit_dice_faces
|
||||||
warnings.warn("hit_dice_faces is not valid for multiclass characters")
|
|
||||||
return self.primary_class.hit_dice_faces
|
|
||||||
|
|
||||||
@hit_dice_faces.setter
|
@hit_dice_faces.setter
|
||||||
def hit_dice_faces(self, faces):
|
def hit_dice_faces(self, faces):
|
||||||
if self.num_classes == 0:
|
self.primary_class.hit_dice_faces = faces
|
||||||
self._hit_dice_faces = faces
|
|
||||||
else:
|
|
||||||
self.primary_class.hit_dice_faces = faces
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def proficiency_bonus(self):
|
def proficiency_bonus(self):
|
||||||
@@ -649,30 +667,26 @@ class Character():
|
|||||||
return prof
|
return prof
|
||||||
|
|
||||||
def can_assume_shape(self, shape: monsters.Monster):
|
def can_assume_shape(self, shape: monsters.Monster):
|
||||||
for c in self.class_list:
|
return hasattr(self, 'Druid') and self.Druid.can_assume_shape(shape)
|
||||||
if isinstance(c, classes.Druid):
|
|
||||||
return c.can_assume_shape(shape)
|
|
||||||
return False
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def all_wild_shapes(self):
|
def all_wild_shapes(self):
|
||||||
for c in self.class_list:
|
if hasattr(self, 'Druid'):
|
||||||
if isinstance(c, classes.Druid):
|
return self.Druid.all_wild_shapes
|
||||||
return c.all_wild_shapes
|
else:
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def wild_shapes(self):
|
def wild_shapes(self):
|
||||||
for c in self.class_list:
|
if hasattr(self, 'Druid'):
|
||||||
if isinstance(c, classes.Druid):
|
return self.Druid.wild_shapes
|
||||||
return c.wild_shapes
|
else:
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
@wild_shapes.setter
|
@wild_shapes.setter
|
||||||
def wild_shapes(self, new_shapes):
|
def wild_shapes(self, new_shapes):
|
||||||
for c in self.class_list:
|
if hasattr(self, 'Druid'):
|
||||||
if isinstance(c, classes.Druid):
|
self.Druid.wild_shapes = new_shapes
|
||||||
c.wild_shapes = new_shapes
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load(cls, character_file):
|
def load(cls, character_file):
|
||||||
|
|||||||
@@ -47,11 +47,13 @@ class CharClass():
|
|||||||
self.features_by_level[i] = fs
|
self.features_by_level[i] = fs
|
||||||
for k, v in params.items():
|
for k, v in params.items():
|
||||||
setattr(self, k, v)
|
setattr(self, k, v)
|
||||||
|
self.spells_known = [S() for S in cls.spells_known]
|
||||||
|
self.spells_prepared = [S() for S in cls.spells_prepared]
|
||||||
|
|
||||||
# Apply subclass
|
# Apply subclass
|
||||||
self.subclass = self.select_subclass(subclass)
|
self.subclass = self.select_subclass(subclass)
|
||||||
if isinstance(self.subclass, SubClass):
|
if isinstance(self.subclass, SubClass):
|
||||||
self.apply_subclass()
|
self.apply_subclass(feature_choices=feature_choices)
|
||||||
|
|
||||||
def select_subclass(self, subclass_str):
|
def select_subclass(self, subclass_str):
|
||||||
"""
|
"""
|
||||||
@@ -67,23 +69,31 @@ class CharClass():
|
|||||||
return sc(owner=self.owner)
|
return sc(owner=self.owner)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def apply_subclass(self):
|
def apply_subclass(self, feature_choices=[]):
|
||||||
if self.subclass is None:
|
if not isinstance(self.subclass, SubClass):
|
||||||
return
|
return
|
||||||
|
subcls = self.subclass
|
||||||
for i in range(1, 21):
|
for i in range(1, 21):
|
||||||
self.features_by_level[i] += ([f(owner=self.owner) for f in
|
fs = []
|
||||||
self.subclass.features_by_level[i]])
|
for f in subcls.features_by_level[i]:
|
||||||
for attr in ('weapon_proficiencies', '_proficiencies_text',
|
if issubclass(f, FeatureSelector):
|
||||||
'spells_known', 'spells_prepared'):
|
fs.append(f(owner=self.owner,
|
||||||
new_list = getattr(self, attr, ()) + getattr(self.subclass, attr, ())
|
feature_choices=feature_choices))
|
||||||
|
elif issubclass(f, Feature):
|
||||||
|
fs.append(f(owner=self.owner))
|
||||||
|
self.features_by_level[i].extend(fs)
|
||||||
|
for attr in ('weapon_proficiencies', '_proficiencies_text'):
|
||||||
|
new_list = tuple(getattr(self, attr, ())) + tuple(getattr(self.subclass, attr, ()))
|
||||||
setattr(self, attr, new_list)
|
setattr(self, attr, new_list)
|
||||||
# All subclass proficiencies transfer, regardless of if this is primary class
|
# All subclass proficiencies transfer, regardless of if this is primary class
|
||||||
self.multiclass_weapon_proficiencies += (self.subclass.weapon_proficiencies)
|
self.multiclass_weapon_proficiencies += tuple(subcls.weapon_proficiencies)
|
||||||
self._multiclass_proficiencies_text += (self._proficiencies_text)
|
self._multiclass_proficiencies_text += tuple(subcls._proficiencies_text)
|
||||||
self.spellcasting_ability = (self.spellcasting_ability or
|
self.spellcasting_ability = (self.spellcasting_ability or
|
||||||
self.subclass.spellcasting_ability)
|
subcls.spellcasting_ability)
|
||||||
self.spell_slots_by_level = (self.spell_slots_by_level or
|
self.spell_slots_by_level = (self.spell_slots_by_level or
|
||||||
self.subclass.spell_slots_by_level)
|
subcls.spell_slots_by_level)
|
||||||
|
self.spells_known.extend([S() for S in subcls.spells_known])
|
||||||
|
self.spells_prepared.extend([S() for S in subcls.spells_prepared])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def features(self):
|
def features(self):
|
||||||
@@ -104,6 +114,15 @@ class CharClass():
|
|||||||
else:
|
else:
|
||||||
return self.spell_slots_by_level[self.level][spell_level]
|
return self.spell_slots_by_level[self.level][spell_level]
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
s = 'Level {:d} {:s}'.format(self.level, self.name)
|
||||||
|
if isinstance(self.subclass, SubClass):
|
||||||
|
s += ' ({:s})'.format(str(self.subclass))
|
||||||
|
return s
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '\"{:s}\"'.format(str(self))
|
||||||
|
|
||||||
|
|
||||||
class SubClass():
|
class SubClass():
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -1,9 +1,31 @@
|
|||||||
from .. import (weapons, features)
|
from .. import (weapons, features, spells)
|
||||||
from .classes import CharClass, SubClass
|
from .classes import CharClass, SubClass
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
|
|
||||||
class KnowledgeDomain(SubClass):
|
class ClericDomain(SubClass):
|
||||||
|
name = "Generic Cleric Domain"
|
||||||
|
_domain_spells = {1: [], 3: [], 5: [], 7: [], 9: []}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def level(self):
|
||||||
|
return self.owner.Cleric.level
|
||||||
|
|
||||||
|
@property
|
||||||
|
def spells_known(self):
|
||||||
|
spells = []
|
||||||
|
for lvl, sps in self._domain_spells.items():
|
||||||
|
if self.level >= lvl:
|
||||||
|
spells.extend(sps)
|
||||||
|
return spells
|
||||||
|
|
||||||
|
# All Domain spells are both known and prepared
|
||||||
|
@property
|
||||||
|
def spells_prepared(self):
|
||||||
|
return self.spells_known
|
||||||
|
|
||||||
|
|
||||||
|
class KnowledgeDomain(ClericDomain):
|
||||||
"""The gods of knowledge—including Oghma, Boccob, Gilean, Aureon, and
|
"""The gods of knowledge—including Oghma, Boccob, Gilean, Aureon, and
|
||||||
Thoth—value learning and understanding above all. Some teach that knowledge
|
Thoth—value learning and understanding above all. Some teach that knowledge
|
||||||
is to be gathered and shared in libraries and universities, or promote the
|
is to be gathered and shared in libraries and universities, or promote the
|
||||||
@@ -18,10 +40,11 @@ class KnowledgeDomain(SubClass):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
name = "Knowledge Domain"
|
name = "Knowledge Domain"
|
||||||
|
_domain_spells = {1: [], 3: [], 5: [], 7: [], 9: []}
|
||||||
features_by_level = defaultdict(list)
|
features_by_level = defaultdict(list)
|
||||||
|
|
||||||
|
|
||||||
class LifeDomain(SubClass):
|
class LifeDomain(ClericDomain):
|
||||||
"""The Life domain focuses on the vibrant positive energy—one of the
|
"""The Life domain focuses on the vibrant positive energy—one of the
|
||||||
fundamental forces of the universe— that sustains all life. The gods of
|
fundamental forces of the universe— that sustains all life. The gods of
|
||||||
life promote vitality and health through healing the sick and wounded,
|
life promote vitality and health through healing the sick and wounded,
|
||||||
@@ -34,10 +57,11 @@ class LifeDomain(SubClass):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
name = "Life Domain"
|
name = "Life Domain"
|
||||||
|
_domain_spells = {1: [], 3: [], 5: [], 7: [], 9: []}
|
||||||
features_by_level = defaultdict(list)
|
features_by_level = defaultdict(list)
|
||||||
|
|
||||||
|
|
||||||
class LightDomain(SubClass):
|
class LightDomain(ClericDomain):
|
||||||
"""Gods of light—including Helm, Lathander, Pholtus, Branchala, the Silver
|
"""Gods of light—including Helm, Lathander, Pholtus, Branchala, the Silver
|
||||||
Flame, Belenus, Apollo, and Re-Horakhty—promote the ideals of rebirth and
|
Flame, Belenus, Apollo, and Re-Horakhty—promote the ideals of rebirth and
|
||||||
renewal, truth, vigilance, and beauty, often using the symbol of the
|
renewal, truth, vigilance, and beauty, often using the symbol of the
|
||||||
@@ -51,10 +75,11 @@ class LightDomain(SubClass):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
name = "Light Domain"
|
name = "Light Domain"
|
||||||
|
_domain_spells = {1: [], 3: [], 5: [], 7: [], 9: []}
|
||||||
features_by_level = defaultdict(list)
|
features_by_level = defaultdict(list)
|
||||||
|
|
||||||
|
|
||||||
class NatureDomain(SubClass):
|
class NatureDomain(ClericDomain):
|
||||||
"""Gods of nature are as varied as the natural world itself, from inscrutable
|
"""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
|
gods of the deep forests (such as Silvanus, Obad-Hai, Chislev, Balinor, and
|
||||||
Pan) to friendly deities associated with particular springs and groves
|
Pan) to friendly deities associated with particular springs and groves
|
||||||
@@ -68,10 +93,11 @@ class NatureDomain(SubClass):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
name = "Nature Domain"
|
name = "Nature Domain"
|
||||||
|
_domain_spells = {1: [], 3: [], 5: [], 7: [], 9: []}
|
||||||
features_by_level = defaultdict(list)
|
features_by_level = defaultdict(list)
|
||||||
|
|
||||||
|
|
||||||
class TempestDomain(SubClass):
|
class TempestDomain(ClericDomain):
|
||||||
"""Gods whose portfolios include the Tempest domain - including Talos,
|
"""Gods whose portfolios include the Tempest domain - including Talos,
|
||||||
Umberlee, Kord, Zeboim, the Devourer, Zeus, and Thor — govern storms, sea,
|
Umberlee, Kord, Zeboim, the Devourer, Zeus, and Thor — govern storms, sea,
|
||||||
and sky. They include gods of lightning and thunder, gods of earthquakes,
|
and sky. They include gods of lightning and thunder, gods of earthquakes,
|
||||||
@@ -86,10 +112,22 @@ class TempestDomain(SubClass):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
name = "Tempest Domain"
|
name = "Tempest Domain"
|
||||||
|
_domain_spells = {1: [spells.FogCloud, spells.Thunderwave],
|
||||||
|
3: [spells.GustOfWind, spells.Shatter],
|
||||||
|
5: [spells.CallLightning, spells.SleetStorm],
|
||||||
|
7: [spells.ControlWater, spells.IceStorm],
|
||||||
|
9: [spells.DestructiveWave, spells.InsectPlague]}
|
||||||
|
weapon_proficiencies = (weapons.MartialWeapon,)
|
||||||
|
_proficiencies_text = ('martial weapons', 'heavy armor')
|
||||||
features_by_level = defaultdict(list)
|
features_by_level = defaultdict(list)
|
||||||
|
features_by_level[1] = (features.WrathOfTheStorm,)
|
||||||
|
features_by_level[2] = (features.DestructiveWrath,)
|
||||||
|
features_by_level[6] = (features.ThunderboltStrike,)
|
||||||
|
features_by_level[8] = (features.DivineStrikeTempest,)
|
||||||
|
features_by_level[17] = (features.Stormborn,)
|
||||||
|
|
||||||
|
|
||||||
class TrickeryDomain(SubClass):
|
class TrickeryDomain(ClericDomain):
|
||||||
"""Gods of trickery—such as Tymora, Beshaba, Olidammara, the Traveler, Garl
|
"""Gods of trickery—such as Tymora, Beshaba, Olidammara, the Traveler, Garl
|
||||||
Glittergold, and Loki—are mischief-makers and instigators who stand as a
|
Glittergold, and Loki—are mischief-makers and instigators who stand as a
|
||||||
constant challenge to the accepted order among both gods and
|
constant challenge to the accepted order among both gods and
|
||||||
@@ -101,10 +139,11 @@ class TrickeryDomain(SubClass):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
name = "Trickery Domain"
|
name = "Trickery Domain"
|
||||||
|
_domain_spells = {1: [], 3: [], 5: [], 7: [], 9: []}
|
||||||
features_by_level = defaultdict(list)
|
features_by_level = defaultdict(list)
|
||||||
|
|
||||||
|
|
||||||
class WarDomain(SubClass):
|
class WarDomain(ClericDomain):
|
||||||
"""War has many manifestations. It can make heroes of ordinary people. It can
|
"""War has many manifestations. It can make heroes of ordinary people. It can
|
||||||
be desperate and horrific, with acts of cruelty and cowardice eclipsing
|
be desperate and horrific, with acts of cruelty and cowardice eclipsing
|
||||||
instances of excellence and courage. In either case, the gods of war watch
|
instances of excellence and courage. In either case, the gods of war watch
|
||||||
@@ -120,11 +159,12 @@ class WarDomain(SubClass):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
name = "War Domain"
|
name = "War Domain"
|
||||||
|
_domain_spells = {1: [], 3: [], 5: [], 7: [], 9: []}
|
||||||
features_by_level = defaultdict(list)
|
features_by_level = defaultdict(list)
|
||||||
|
|
||||||
|
|
||||||
# SCAG
|
# SCAG
|
||||||
class ArcanaDomain(SubClass):
|
class ArcanaDomain(ClericDomain):
|
||||||
"""Magic is an energy that suffuses the multiverse and that fuels both
|
"""Magic is an energy that suffuses the multiverse and that fuels both
|
||||||
destruction and creation. Gods of the Arcana domain know the secrets and
|
destruction and creation. Gods of the Arcana domain know the secrets and
|
||||||
potential of magic intimately. For some of these gods, magical knowledge
|
potential of magic intimately. For some of these gods, magical knowledge
|
||||||
@@ -141,11 +181,12 @@ class ArcanaDomain(SubClass):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
name = "Arcana Domain"
|
name = "Arcana Domain"
|
||||||
|
_domain_spells = {1: [], 3: [], 5: [], 7: [], 9: []}
|
||||||
features_by_level = defaultdict(list)
|
features_by_level = defaultdict(list)
|
||||||
|
|
||||||
|
|
||||||
# XGTE
|
# XGTE
|
||||||
class ForgeDomain(SubClass):
|
class ForgeDomain(ClericDomain):
|
||||||
"""The gods of the forge are patrons of artisans who work with metal, from a
|
"""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
|
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
|
mighty elf artisan whose diamond-tipped arrows of mithral have felled demon
|
||||||
@@ -163,7 +204,7 @@ class ForgeDomain(SubClass):
|
|||||||
features_by_level = defaultdict(list)
|
features_by_level = defaultdict(list)
|
||||||
|
|
||||||
|
|
||||||
class GraveDomain(SubClass):
|
class GraveDomain(ClericDomain):
|
||||||
"""Gods of the grave watch over the line between life and death. To these
|
"""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
|
deities, death and the afterlife are a foundational part of the
|
||||||
multiverse. To desecrate the peace of the dead is an abomination. Deities
|
multiverse. To desecrate the peace of the dead is an abomination. Deities
|
||||||
@@ -177,6 +218,7 @@ class GraveDomain(SubClass):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
name = "Grave Domain"
|
name = "Grave Domain"
|
||||||
|
_domain_spells = {1: [], 3: [], 5: [], 7: [], 9: []}
|
||||||
features_by_level = defaultdict(list)
|
features_by_level = defaultdict(list)
|
||||||
|
|
||||||
|
|
||||||
@@ -194,6 +236,9 @@ class Cleric(CharClass):
|
|||||||
class_skill_choices = ('History', 'Insight', 'Medicine',
|
class_skill_choices = ('History', 'Insight', 'Medicine',
|
||||||
'Persuasion', 'Religion')
|
'Persuasion', 'Religion')
|
||||||
features_by_level = defaultdict(list)
|
features_by_level = defaultdict(list)
|
||||||
|
features_by_level[2] = (features.ChannelDivinity, features.TurnUndead,)
|
||||||
|
features_by_level[5] = (features.DestroyUndead, )
|
||||||
|
features_by_level[10] = (features.DivineIntervention,)
|
||||||
subclasses_available = (KnowledgeDomain, LifeDomain, LightDomain,
|
subclasses_available = (KnowledgeDomain, LifeDomain, LightDomain,
|
||||||
NatureDomain, TempestDomain, TrickeryDomain,
|
NatureDomain, TempestDomain, TrickeryDomain,
|
||||||
WarDomain, ArcanaDomain, ForgeDomain,
|
WarDomain, ArcanaDomain, ForgeDomain,
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
from .. import (weapons, features, spells)
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
|
||||||
|
# Custom Classes
|
||||||
@@ -13,6 +13,11 @@ class Champion(SubClass):
|
|||||||
"""
|
"""
|
||||||
name = "Champion"
|
name = "Champion"
|
||||||
features_by_level = defaultdict(list)
|
features_by_level = defaultdict(list)
|
||||||
|
features_by_level[3] = [features.ImprovedCritical]
|
||||||
|
features_by_level[7] = [features.RemarkableAthelete]
|
||||||
|
features_by_level[10] = [features.AdditionalFightingStyle]
|
||||||
|
features_by_level[15] = [features.SuperiorCritical]
|
||||||
|
features_by_level[18] = [features.Survivor]
|
||||||
|
|
||||||
|
|
||||||
class BattleMaster(SubClass):
|
class BattleMaster(SubClass):
|
||||||
@@ -26,6 +31,9 @@ class BattleMaster(SubClass):
|
|||||||
"""
|
"""
|
||||||
name = "Battle Master"
|
name = "Battle Master"
|
||||||
features_by_level = defaultdict(list)
|
features_by_level = defaultdict(list)
|
||||||
|
features_by_level[3] = [features.CombatSuperiority, features.StudentOfWar]
|
||||||
|
features_by_level[7] = [features.KnowYourEnemy]
|
||||||
|
features_by_level[15] = [features.Relentless]
|
||||||
|
|
||||||
|
|
||||||
class EldritchKnight(SubClass):
|
class EldritchKnight(SubClass):
|
||||||
@@ -41,6 +49,12 @@ class EldritchKnight(SubClass):
|
|||||||
"""
|
"""
|
||||||
name = "Eldritch Knight"
|
name = "Eldritch Knight"
|
||||||
features_by_level = defaultdict(list)
|
features_by_level = defaultdict(list)
|
||||||
|
features_by_level[3] = [features.EldritchKnightSpellcasting,
|
||||||
|
features.WeaponBond]
|
||||||
|
features_by_level[7] = [features.WarMagic]
|
||||||
|
features_by_level[10] = [features.EldritchStrike]
|
||||||
|
features_by_level[15] = [features.ArcaneCharge]
|
||||||
|
features_by_level[18] = [features.ImprovedWarMagic]
|
||||||
spellcasting_ability = 'intelligence'
|
spellcasting_ability = 'intelligence'
|
||||||
multiclass_spellslots_by_level = {
|
multiclass_spellslots_by_level = {
|
||||||
# char_lvl: (cantrips, 1st, 2nd, 3rd, ...)
|
# char_lvl: (cantrips, 1st, 2nd, 3rd, ...)
|
||||||
@@ -157,9 +171,15 @@ class Gunslinger(SubClass):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
name = "Gunslinger"
|
name = "Gunslinger"
|
||||||
features_by_level = defaultdict(list)
|
|
||||||
weapon_proficiencies = (weapons.firearms)
|
weapon_proficiencies = (weapons.firearms)
|
||||||
_proficiencies_text = ('firearms')
|
_proficiencies_text = ('firearms', "tinker's tools")
|
||||||
|
features_by_level = defaultdict(list)
|
||||||
|
features_by_level[3] = [features.Gunsmith, features.AdeptMarksman]
|
||||||
|
features_by_level[7] = [features.QuickDraw]
|
||||||
|
features_by_level[10] = [features.RapidRepair]
|
||||||
|
features_by_level[15] = [features.LightningReload]
|
||||||
|
features_by_level[18] = [features.ViciousIntent,
|
||||||
|
features.HemorrhagingCritical]
|
||||||
|
|
||||||
|
|
||||||
class Fighter(CharClass):
|
class Fighter(CharClass):
|
||||||
@@ -179,6 +199,10 @@ class Fighter(CharClass):
|
|||||||
'Athletics', 'History', 'Insight', 'Intimidation',
|
'Athletics', 'History', 'Insight', 'Intimidation',
|
||||||
'Perception', 'Survival')
|
'Perception', 'Survival')
|
||||||
features_by_level = defaultdict(list)
|
features_by_level = defaultdict(list)
|
||||||
|
features_by_level[1] = [features.FighterFightingStyle, features.SecondWind]
|
||||||
|
features_by_level[2] = [features.ActionSurge]
|
||||||
|
features_by_level[5] = [features.ExtraAttackFighter]
|
||||||
|
features_by_level[9] = [features.Indomitable]
|
||||||
subclasses_available = (Champion, BattleMaster, EldritchKnight,
|
subclasses_available = (Champion, BattleMaster, EldritchKnight,
|
||||||
PurpleDragonKnight, ArcaneArcher, Cavalier,
|
PurpleDragonKnight, ArcaneArcher, Cavalier,
|
||||||
Samurai, Gunslinger)
|
Samurai, Gunslinger)
|
||||||
|
|||||||
@@ -1,9 +1,31 @@
|
|||||||
from .. import (weapons, features)
|
from .. import (weapons, features, spells)
|
||||||
from .classes import CharClass, SubClass
|
from .classes import CharClass, SubClass
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
|
|
||||||
class OathOfDevotion(SubClass):
|
class PaladinOath(SubClass):
|
||||||
|
name = "Generic Paladin Oath"
|
||||||
|
_oath_spells = {3: [], 5: [], 9: [], 13: [], 17: []}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def level(self):
|
||||||
|
return self.owner.Paladin.level
|
||||||
|
|
||||||
|
@property
|
||||||
|
def spells_known(self):
|
||||||
|
spells = []
|
||||||
|
for lvl, sps in self._oath_spells.items():
|
||||||
|
if self.level >= lvl:
|
||||||
|
spells.extend(sps)
|
||||||
|
return spells
|
||||||
|
|
||||||
|
# All Oath spells are both known and prepared
|
||||||
|
@property
|
||||||
|
def spells_prepared(self):
|
||||||
|
return self.spells_known
|
||||||
|
|
||||||
|
|
||||||
|
class OathOfDevotion(PaladinOath):
|
||||||
"""The Oath of Devotion binds a paladin to the loftiest ideals of justice,
|
"""The Oath of Devotion binds a paladin to the loftiest ideals of justice,
|
||||||
virtue, and order. Sometim es called cavaliers, white knights, or holy
|
virtue, and order. Sometim es called cavaliers, white knights, or holy
|
||||||
warriors, these paladins meet the ideal of the knight in shining armor,
|
warriors, these paladins meet the ideal of the knight in shining armor,
|
||||||
@@ -35,10 +57,20 @@ class OathOfDevotion(SubClass):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
name = "Oath of Devotion"
|
name = "Oath of Devotion"
|
||||||
|
_oath_spells = {3: [spells.ProtectionFromEvilAndGood,
|
||||||
|
spells.Sanctuary],
|
||||||
|
5: [spells.LesserRestoration, spells.ZoneOfTruth],
|
||||||
|
9: [spells.BeaconOfHope, spells.DispelMagic],
|
||||||
|
13: [spells.FreedomOfMovement, spells.GuardianOfFaith],
|
||||||
|
17: [spells.Commune, spells.FlameStrike]}
|
||||||
features_by_level = defaultdict(list)
|
features_by_level = defaultdict(list)
|
||||||
|
features_by_level[3] = [features.SacredWeapon, features.TurnTheUnholy]
|
||||||
|
features_by_level[7] = [features.AuraOfDevotion]
|
||||||
|
features_by_level[15] = [features.PurityOfSpirit]
|
||||||
|
features_by_level[20] = [features.HolyNimbus]
|
||||||
|
|
||||||
|
|
||||||
|
class OathOfAncients(PaladinOath):
|
||||||
class OathOfAncients(SubClass):
|
|
||||||
"""The Oath of the Ancients is as old as the race of elves and the rituals of
|
"""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,
|
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
|
paladins who swear this oath cast their lot with the side of the light in
|
||||||
@@ -69,10 +101,15 @@ class OathOfAncients(SubClass):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
name = "Oath of The Ancients"
|
name = "Oath of The Ancients"
|
||||||
|
_oath_spells = {3: [spells.EnsnaringStrike, spells.SpeakWithAnimals],
|
||||||
|
5: [spells.Moonbeam, spells.MistyStep],
|
||||||
|
9: [spells.PlantGrowth, spells.ProtectionFromEnergy],
|
||||||
|
13: [spells.IceStorm, spells.Stoneskin],
|
||||||
|
17: [spells.CommuneWithNature, spells.TreeStride]}
|
||||||
features_by_level = defaultdict(list)
|
features_by_level = defaultdict(list)
|
||||||
|
|
||||||
|
|
||||||
class OathOfVengance(SubClass):
|
class OathOfVengance(PaladinOath):
|
||||||
"""The Oath of Vengeance is a solemn commitment to punish those who have
|
"""The Oath of Vengeance is a solemn commitment to punish those who have
|
||||||
committed a grievous sin. When evil forces slaughter helpless villagers,
|
committed a grievous sin. When evil forces slaughter helpless villagers,
|
||||||
when an entire people turns against the will of the gods, when a thieves’
|
when an entire people turns against the will of the gods, when a thieves’
|
||||||
@@ -103,10 +140,15 @@ class OathOfVengance(SubClass):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
name = "Oath of Vengance"
|
name = "Oath of Vengance"
|
||||||
|
_oath_spells = {3: [spells.Bane, spells.HuntersMark],
|
||||||
|
5: [spells.HoldPerson, spells.MistyStep],
|
||||||
|
9: [spells.Haste, spells.ProtectionFromEnergy],
|
||||||
|
13: [spells.Banishment, spells.DimensionDoor],
|
||||||
|
17: [spells.HoldMonster, spells.Scrying]}
|
||||||
features_by_level = defaultdict(list)
|
features_by_level = defaultdict(list)
|
||||||
|
|
||||||
|
|
||||||
class OathOfCrown(SubClass):
|
class OathOfCrown(PaladinOath):
|
||||||
"""The Oath of the Crown is sworn to the ideals of civilization, be it the
|
"""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
|
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
|
rulership. The paladins who swear this oath dedicate themselves to serving
|
||||||
@@ -137,10 +179,15 @@ class OathOfCrown(SubClass):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
name = "Oath of The Crown"
|
name = "Oath of The Crown"
|
||||||
|
_oath_spells = {3: [spells.Command, spells.CompelledDuel],
|
||||||
|
5: [spells.WardingBond, spells.ZoneOfTruth],
|
||||||
|
9: [spells.AuraOfVitality, spells.SpiritGuardians],
|
||||||
|
13: [spells.Banishment, spells.GuardianOfFaith],
|
||||||
|
17: [spells.CircleOfPower, spells.Geas]}
|
||||||
features_by_level = defaultdict(list)
|
features_by_level = defaultdict(list)
|
||||||
|
|
||||||
|
|
||||||
class OathOfConquest(SubClass):
|
class OathOfConquest(PaladinOath):
|
||||||
"""The Oath of Conquest calls to paladins who seek glory in battle and the
|
"""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
|
subjugation of their enemies. It isn’t enough for these paladins to
|
||||||
establish order. They must crush the forces of chaos. Sometimes called
|
establish order. They must crush the forces of chaos. Sometimes called
|
||||||
@@ -173,10 +220,15 @@ class OathOfConquest(SubClass):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
name = "Oath of Conquest"
|
name = "Oath of Conquest"
|
||||||
|
_oath_spells = {3: [spells.ArmorOfAgathys, spells.Command],
|
||||||
|
5: [spells.HoldPerson, spells.SpiritualWeapon],
|
||||||
|
9: [spells.BestowCurse, spells.Fear],
|
||||||
|
13: [spells.DominateBeast, spells.Stoneskin],
|
||||||
|
17: [spells.Cloudkill, spells.DominatePerson]}
|
||||||
features_by_level = defaultdict(list)
|
features_by_level = defaultdict(list)
|
||||||
|
|
||||||
|
|
||||||
class OathOfRedemption(SubClass):
|
class OathOfRedemption(PaladinOath):
|
||||||
"""The Oath of Redemption sets a paladin on a difficult path, one that requires
|
"""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
|
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
|
themselves to this oath believe that any person can be redeemed and that
|
||||||
@@ -216,7 +268,56 @@ class OathOfRedemption(SubClass):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
name = "Oath of Redemption"
|
name = "Oath of Redemption"
|
||||||
|
_oath_spells = {3: [spells.Sanctuary, spells.Sleep],
|
||||||
|
5: [spells.CalmEmotions, spells.HoldPerson],
|
||||||
|
9: [spells.Counterspell, spells.HypnoticPattern],
|
||||||
|
13: [spells.OtilukesResilientSphere, spells.Stoneskin],
|
||||||
|
17: [spells.HoldMonster, spells.WallOfForce]}
|
||||||
features_by_level = defaultdict(list)
|
features_by_level = defaultdict(list)
|
||||||
|
features_by_level[3] = [features.EmissaryOfPeace,
|
||||||
|
features.RebukeTheViolent]
|
||||||
|
features_by_level[7] = [features.AuraOfTheGuardian]
|
||||||
|
features_by_level[15] = [features.ProtectiveSpirit]
|
||||||
|
features_by_level[20] = [features.EmissaryOfRedemption]
|
||||||
|
|
||||||
|
|
||||||
|
# Custom
|
||||||
|
class OathOfZor(PaladinOath):
|
||||||
|
"""The Oath of Zor
|
||||||
|
|
||||||
|
**Tenets of Zor**:
|
||||||
|
|
||||||
|
--Courage. Never fear to act, though caution is wise.
|
||||||
|
|
||||||
|
--Honesty. Don’t lie or cheat. Let your word be your promise.
|
||||||
|
|
||||||
|
--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.
|
||||||
|
|
||||||
|
--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.
|
||||||
|
|
||||||
|
--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.
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Oath of Zor"
|
||||||
|
_oath_spells = {3: [spells.Sanctuary, spells.Sleep],
|
||||||
|
5: [spells.CalmEmotions, spells.HoldPerson],
|
||||||
|
9: [spells.Counterspell, spells.HypnoticPattern],
|
||||||
|
13: [spells.OtilukesResilientSphere, spells.Stoneskin],
|
||||||
|
17: [spells.HoldMonster, spells.WallOfForce]}
|
||||||
|
features_by_level = defaultdict(list)
|
||||||
|
features_by_level[3] = [features.EmissaryOfPeace,
|
||||||
|
features.RebukeTheViolent]
|
||||||
|
features_by_level[7] = [features.AuraOfTheGuardian]
|
||||||
|
features_by_level[15] = [features.ProtectiveSpirit]
|
||||||
|
features_by_level[20] = [features.EmissaryOfRedemption]
|
||||||
|
|
||||||
|
|
||||||
class Paladin(CharClass):
|
class Paladin(CharClass):
|
||||||
@@ -234,8 +335,19 @@ class Paladin(CharClass):
|
|||||||
class_skill_choices = ("Athletics", 'Insight', 'Intimidation',
|
class_skill_choices = ("Athletics", 'Insight', 'Intimidation',
|
||||||
'Medicine', 'Persuasion', 'Religion')
|
'Medicine', 'Persuasion', 'Religion')
|
||||||
features_by_level = defaultdict(list)
|
features_by_level = defaultdict(list)
|
||||||
|
features_by_level[1] = [features.DivineSense, features.LayOnHands]
|
||||||
|
features_by_level[2] = [features.PaladinFightingStyle,
|
||||||
|
features.DivineSmite]
|
||||||
|
features_by_level[3] = [features.DivineHealth,
|
||||||
|
features.ChannelDivinityPaladin]
|
||||||
|
features_by_level[5] = [features.ExtraAttackPaladin]
|
||||||
|
features_by_level[6] = [features.AuraOfProtection]
|
||||||
|
features_by_level[10] = [features.AuraOfCourage]
|
||||||
|
features_by_level[11] = [features.ImprovedDivineSmite]
|
||||||
|
features_by_level[14] = [features.CleansingTouch]
|
||||||
subclasses_available = (OathOfDevotion, OathOfAncients, OathOfVengance,
|
subclasses_available = (OathOfDevotion, OathOfAncients, OathOfVengance,
|
||||||
OathOfCrown, OathOfConquest, OathOfRedemption)
|
OathOfCrown, OathOfConquest, OathOfRedemption,
|
||||||
|
OathOfZor)
|
||||||
spellcasting_ability = 'charisma'
|
spellcasting_ability = 'charisma'
|
||||||
spell_slots_by_level = {
|
spell_slots_by_level = {
|
||||||
# char_lvl: (cantrips, 1st, 2nd, 3rd, ...)
|
# char_lvl: (cantrips, 1st, 2nd, 3rd, ...)
|
||||||
|
|||||||
@@ -115,12 +115,6 @@ class Ranger(CharClass):
|
|||||||
20: (0, 4, 3, 3, 3, 2, 0, 0, 0, 0),
|
20: (0, 4, 3, 3, 3, 2, 0, 0, 0, 0),
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, level, subclass=None, **params):
|
|
||||||
super().__init__(level, subclass=subclass, **params)
|
|
||||||
fighting_style = features.select_ranger_fighting_style(
|
|
||||||
feature_choices=params.get('feature_choices', []))
|
|
||||||
self.features_by_level[2].append(fighting_style)
|
|
||||||
|
|
||||||
|
|
||||||
# Revised Ranger
|
# Revised Ranger
|
||||||
class BeastConclave(SubClass):
|
class BeastConclave(SubClass):
|
||||||
@@ -132,6 +126,11 @@ class BeastConclave(SubClass):
|
|||||||
"""
|
"""
|
||||||
name = "Beast Conclave"
|
name = "Beast Conclave"
|
||||||
features_by_level = defaultdict(list)
|
features_by_level = defaultdict(list)
|
||||||
|
features_by_level[3] = [features.AnimalCompanion, features.CompanionsBond]
|
||||||
|
features_by_level[5] = [features.CoordinatedAttack]
|
||||||
|
features_by_level[7] = [features.BeastsDefense]
|
||||||
|
features_by_level[11] = [features.StormOfClawsAndFangs]
|
||||||
|
features_by_level[15] = [features.SuperiorBeastsDefense]
|
||||||
|
|
||||||
|
|
||||||
class HunterConclave(SubClass):
|
class HunterConclave(SubClass):
|
||||||
@@ -160,5 +159,15 @@ class DeepStalkerConclave(SubClass):
|
|||||||
class RevisedRanger(Ranger):
|
class RevisedRanger(Ranger):
|
||||||
name = 'Revised Ranger'
|
name = 'Revised Ranger'
|
||||||
features_by_level = defaultdict(list)
|
features_by_level = defaultdict(list)
|
||||||
|
features_by_level[1] = [features.FavoredEnemyRevised,
|
||||||
|
features.NaturalExplorerRevised]
|
||||||
|
features_by_level[2] = [features.RangerFightingStyle]
|
||||||
|
features_by_level[3] = [features.PrimevalAwarenessRevised]
|
||||||
|
features_by_level[6] = [features.GreaterFavoredEnemy]
|
||||||
|
features_by_level[8] = [features.FleetOfFoot]
|
||||||
|
features_by_level[10] = [features.HideInPlainSight]
|
||||||
|
features_by_level[14] = [features.Vanish]
|
||||||
|
features_by_level[18] = [features.FeralSenses]
|
||||||
|
features_by_level[20] = [features.FoeSlayer]
|
||||||
subclasses_available = (BeastConclave, HunterConclave, DeepStalkerConclave)
|
subclasses_available = (BeastConclave, HunterConclave, DeepStalkerConclave)
|
||||||
|
|
||||||
|
|||||||
@@ -134,6 +134,23 @@ class Rogue(CharClass):
|
|||||||
'Insight', 'Intimidation', 'Investigation',
|
'Insight', 'Intimidation', 'Investigation',
|
||||||
'Perception', 'Performance', 'Persuasion',
|
'Perception', 'Performance', 'Persuasion',
|
||||||
'Sleight of Hand', 'Stealth')
|
'Sleight of Hand', 'Stealth')
|
||||||
|
num_skill_choices = 4
|
||||||
features_by_level = defaultdict(list)
|
features_by_level = defaultdict(list)
|
||||||
|
features_by_level[1] = [features.Expertise, features.SneakAttack]
|
||||||
|
features_by_level[2] = [features.CunningAction]
|
||||||
|
features_by_level[5] = [features.UncannyDodge]
|
||||||
|
features_by_level[7] = [features.Evasion]
|
||||||
|
features_by_level[11] = [features.ReliableTalent]
|
||||||
|
features_by_level[14] = [features.BlindSense]
|
||||||
|
features_by_level[15] = [features.SlipperyMind]
|
||||||
|
features_by_level[18] = [features.Elusive]
|
||||||
|
features_by_level[20] = [features.StrokeOfLuck]
|
||||||
subclasses_available = (Thief, Assassin, ArcaneTrickster,
|
subclasses_available = (Thief, Assassin, ArcaneTrickster,
|
||||||
Inquisitive, Mastermind, Scout, Swashbuckler)
|
Inquisitive, Mastermind, Scout, Swashbuckler)
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
# slippery mind feature
|
||||||
|
if self.owner.Rogue.level >= 15:
|
||||||
|
self.saving_throw_proficiencies = ('dexterity', 'intelligence',
|
||||||
|
'wisdom')
|
||||||
|
|||||||
@@ -30,6 +30,10 @@ class WildMagic(SubClass):
|
|||||||
"""
|
"""
|
||||||
name = "Wild Magic"
|
name = "Wild Magic"
|
||||||
features_by_level = defaultdict(list)
|
features_by_level = defaultdict(list)
|
||||||
|
features_by_level[1] = [features.WildMagicSurge, features.TidesOfChaos]
|
||||||
|
features_by_level[6] = [features.BendLuck]
|
||||||
|
features_by_level[14] = [features.ControlledChaos]
|
||||||
|
features_by_level[18] = [features.SpellBombardment]
|
||||||
|
|
||||||
|
|
||||||
# XGTE
|
# XGTE
|
||||||
@@ -107,6 +111,9 @@ class Sorceror(CharClass):
|
|||||||
class_skill_choices = ('Arcana', 'Deception', 'Insight',
|
class_skill_choices = ('Arcana', 'Deception', 'Insight',
|
||||||
'Intimidation', 'Persuasion', 'Religion')
|
'Intimidation', 'Persuasion', 'Religion')
|
||||||
features_by_level = defaultdict(list)
|
features_by_level = defaultdict(list)
|
||||||
|
features_by_level[2] = [features.FontOfMagic]
|
||||||
|
features_by_level[3] = [features.Metamagic]
|
||||||
|
features_by_level[20] = [features.SorcerousRestoration]
|
||||||
subclasses_available = (DraconicBloodline, WildMagic, DivineSoul,
|
subclasses_available = (DraconicBloodline, WildMagic, DivineSoul,
|
||||||
ShadowMagic, StormSorcery)
|
ShadowMagic, StormSorcery)
|
||||||
spellcasting_ability = 'charisma'
|
spellcasting_ability = 'charisma'
|
||||||
|
|||||||
@@ -31,6 +31,10 @@ class Fiend(SubClass):
|
|||||||
"""
|
"""
|
||||||
name = "The Fiend Patron"
|
name = "The Fiend Patron"
|
||||||
features_by_level = defaultdict(list)
|
features_by_level = defaultdict(list)
|
||||||
|
features_by_level[1] = [features.DarkOnesBlessing]
|
||||||
|
features_by_level[6] = [features.DarkOnesOwnLuck]
|
||||||
|
features_by_level[10] = [features.FiendishResilience]
|
||||||
|
features_by_level[14] = [features.HurlThroughHell]
|
||||||
|
|
||||||
|
|
||||||
class GreatOldOne(SubClass):
|
class GreatOldOne(SubClass):
|
||||||
@@ -109,7 +113,13 @@ class Hexblade(SubClass):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
name = "Hexblade Patron"
|
name = "Hexblade Patron"
|
||||||
|
weapon_proficiencies = (weapons.MartialWeapon,)
|
||||||
|
_proficiencies_text = ['martial weapons', 'medium armor', 'shields']
|
||||||
features_by_level = defaultdict(list)
|
features_by_level = defaultdict(list)
|
||||||
|
features_by_level[1] = [features.HexbladesCurse, features.HexWarrior]
|
||||||
|
features_by_level[6] = [features.AccursedSpecter]
|
||||||
|
features_by_level[10] = [features.ArmorOfHexes]
|
||||||
|
features_by_level[14] = [features.MasterOfHexes]
|
||||||
|
|
||||||
|
|
||||||
class Warlock(CharClass):
|
class Warlock(CharClass):
|
||||||
@@ -126,6 +136,10 @@ class Warlock(CharClass):
|
|||||||
multiclass_weapon_proficiencies = weapon_proficiencies
|
multiclass_weapon_proficiencies = weapon_proficiencies
|
||||||
_multiclass_proficiencies_text = ('light armor', 'simple weapons')
|
_multiclass_proficiencies_text = ('light armor', 'simple weapons')
|
||||||
features_by_level = defaultdict(list)
|
features_by_level = defaultdict(list)
|
||||||
|
features_by_level[2] = [features.EldritchInvocation]
|
||||||
|
features_by_level[3] = [features.PactBoon]
|
||||||
|
features_by_level[11] = [features.MysticArcanum]
|
||||||
|
features_by_level[20] = [features.EldritchMaster]
|
||||||
subclasses_available = (Archfey, Fiend, GreatOldOne, Undying, Celestial,
|
subclasses_available = (Archfey, Fiend, GreatOldOne, Undying, Celestial,
|
||||||
Hexblade)
|
Hexblade)
|
||||||
spellcasting_ability = 'charisma'
|
spellcasting_ability = 'charisma'
|
||||||
|
|||||||
@@ -486,7 +486,7 @@ class SkillForm(LinkedListForm):
|
|||||||
self.update_remaining()
|
self.update_remaining()
|
||||||
|
|
||||||
def update_remaining(self, widget=None):
|
def update_remaining(self, widget=None):
|
||||||
num_choices = (self.parentApp.character.num_skill_choices +
|
num_choices = (self.parentApp.character.primary_class.num_skill_choices +
|
||||||
self.parentApp.character.race.num_skill_choices +
|
self.parentApp.character.race.num_skill_choices +
|
||||||
self.parentApp.character.background.num_skill_choices)
|
self.parentApp.character.background.num_skill_choices)
|
||||||
num_selected = len(self.skill_proficiencies.value)
|
num_selected = len(self.skill_proficiencies.value)
|
||||||
@@ -507,7 +507,7 @@ class SkillForm(LinkedListForm):
|
|||||||
value=0, editable=False)
|
value=0, editable=False)
|
||||||
self.skill_proficiencies = self.add(
|
self.skill_proficiencies = self.add(
|
||||||
npyscreen.TitleMultiSelect, name="Skill Proficiencies:",
|
npyscreen.TitleMultiSelect, name="Skill Proficiencies:",
|
||||||
values=self.parentApp.character.class_skill_choices,
|
values=(),
|
||||||
value_changed_callback=self.update_remaining)
|
value_changed_callback=self.update_remaining)
|
||||||
|
|
||||||
def on_ok(self):
|
def on_ok(self):
|
||||||
|
|||||||
@@ -1,3 +1,167 @@
|
|||||||
from .features import Feature
|
from .features import Feature
|
||||||
|
|
||||||
|
|
||||||
|
# Cleric Features
|
||||||
|
class ChannelDivinity(Feature):
|
||||||
|
"""At 2nd level, you gain the ability to channel divine energy directly from
|
||||||
|
your deity, using that energy to fuel magical effects. You start with two
|
||||||
|
such effects: Turn Undead and an effect determined by your domain. Some
|
||||||
|
domains grant you additional effects as you advance in levels, as noted in
|
||||||
|
the domain description.
|
||||||
|
|
||||||
|
When you use your Channel Divinity, you choose which effect to create. You
|
||||||
|
must then finish a short or long rest to use your Channel Divinity again.
|
||||||
|
|
||||||
|
Some Channel Divinity effects require saving throws. When you use such an
|
||||||
|
effect from this class, the DC equals your cleric spell save DC.
|
||||||
|
|
||||||
|
Beginning at 6th level, you can use your Channel Divinity twice between
|
||||||
|
rests, and beginning at 18th level you can use it three times between
|
||||||
|
rests. When you finish a short or long rest, you regain your expended uses.
|
||||||
|
|
||||||
|
"""
|
||||||
|
_name = "Channel Divinity"
|
||||||
|
source = "Cleric"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
level = self.owner.Cleric.level
|
||||||
|
if level < 6:
|
||||||
|
return "Channel Divinity (1x/SR)"
|
||||||
|
elif level < 18:
|
||||||
|
return "Channel Divinity (2x/SR)"
|
||||||
|
else:
|
||||||
|
return "Channel Divinity (3x/SR)"
|
||||||
|
|
||||||
|
|
||||||
|
class TurnUndead(Feature):
|
||||||
|
"""As an action, you present your holy symbol and speak a prayer censuring the
|
||||||
|
undead. Each undead that can see or hear you within 30 feet of you must
|
||||||
|
make a Wisdom saving throw. If the creature fails its saving throw, it is
|
||||||
|
turned for 1 minute or until it takes any damage.
|
||||||
|
|
||||||
|
A turned creature must spend its turns trying to move as far away from you
|
||||||
|
as it can, and it can’t willingly move to a space within 30 feet of you. It
|
||||||
|
also can’t take reactions. For its action, it can use only the Dash action
|
||||||
|
or try to escape from an effect that prevents it from moving. If there’s
|
||||||
|
nowhere to move, the creature can use the Dodge action.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Channel Divinity: Turn Undead"
|
||||||
|
source = "Cleric"
|
||||||
|
|
||||||
|
|
||||||
|
class DestroyUndead(Feature):
|
||||||
|
"""Starting at 5th level, when an undead fails its saving throw against your
|
||||||
|
Turn Undead feature, the creature is instantly destroyed if its challenge
|
||||||
|
rating is at or below a certain threshold, as shown in the Destroy Undead
|
||||||
|
table.
|
||||||
|
|
||||||
|
"""
|
||||||
|
_name = "Destroy Undead"
|
||||||
|
source = "Cleric"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
level = self.owner.Cleric.level
|
||||||
|
name = self._name + ' (CR 1/2)'
|
||||||
|
if level >= 8:
|
||||||
|
name = self._name + ' (CR 1)'
|
||||||
|
if level >= 11:
|
||||||
|
name = self._name + ' (CR 2)'
|
||||||
|
if level >= 14:
|
||||||
|
name = self._name + ' (CR 3)'
|
||||||
|
if level >= 17:
|
||||||
|
name = self._name + ' (CR 4)'
|
||||||
|
return name
|
||||||
|
|
||||||
|
|
||||||
|
class DivineIntervention(Feature):
|
||||||
|
"""Beginning at 10th level, you can call on your deity to intervene on your
|
||||||
|
behalf when your need is great.
|
||||||
|
|
||||||
|
Imploring your deity’s aid requires you to use your action. Describe the
|
||||||
|
assistance you seek, and roll percentile dice. If you roll a number equal
|
||||||
|
to or lower than your cleric level, your deity intervenes. The DM chooses
|
||||||
|
the nature of the intervention; the effect of any cleric spell or cleric
|
||||||
|
domain spell would be appropriate.
|
||||||
|
|
||||||
|
If your deity intervenes, you can’t use this feature again for 7
|
||||||
|
days. Otherwise, you can use it again after you finish a long rest.
|
||||||
|
|
||||||
|
At 20th level, your call for intervention succeeds automatically, no roll
|
||||||
|
required.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Divine Intervention"
|
||||||
|
source = "Cleric"
|
||||||
|
|
||||||
|
|
||||||
|
# Tempest Domain
|
||||||
|
class WrathOfTheStorm(Feature):
|
||||||
|
"""Also at 1st level, you can thunderously rebuke attackers. When a creature
|
||||||
|
within 5 feet of you that you can see hits you with an attack, you can use
|
||||||
|
your reaction to cause the creature to make a Dexterity saving throw. The
|
||||||
|
creature takes 2d8 lightning or thunder damage (your choice) on a failed
|
||||||
|
saving throw, and half as much damage on a successful one.
|
||||||
|
|
||||||
|
You can use this feature a number of times equal to your Wisdom modifier (a
|
||||||
|
minimum of once). You regain all expended uses when you finish a long rest.
|
||||||
|
|
||||||
|
"""
|
||||||
|
_name = "Wrath of the Storm"
|
||||||
|
source = "Cleric (Tempest Domain)"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
num_uses = max(1, self.owner.wisdom.modifier)
|
||||||
|
return self._name + ' ({:d}x/LR)'.format(num_uses)
|
||||||
|
|
||||||
|
|
||||||
|
class DestructiveWrath(ChannelDivinity):
|
||||||
|
"""Starting at 2nd level, you can use your Channel Divinity to wield the power
|
||||||
|
of the storm with unchecked ferocity.
|
||||||
|
|
||||||
|
When you roll lightning or thunder damage, you can use your Channel
|
||||||
|
Divinity to deal maximum damage, instead of rolling.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Channel Divinity: Destructive Wrath"
|
||||||
|
source = "Cleric (Tempest Domain)"
|
||||||
|
|
||||||
|
|
||||||
|
class ThunderboltStrike(Feature):
|
||||||
|
"""At 6th level, when you deal lightning damage to a Large or smaller
|
||||||
|
creature, you can also push it up to 10 feet away from you.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Thunderbolt Strike"
|
||||||
|
source = "Cleric (Tempest Domain)"
|
||||||
|
|
||||||
|
|
||||||
|
class DivineStrikeTempest(Feature):
|
||||||
|
"""At 8th level, you gain the ability to infuse your weapon strikes with
|
||||||
|
divine energy. Once on each of your turns when you hit a creature with a
|
||||||
|
weapon attack, you can cause the attack to deal an extra 1d8 thunder damage
|
||||||
|
to the target. When you reach 14th level, the extra damage increases to
|
||||||
|
2d8.
|
||||||
|
|
||||||
|
"""
|
||||||
|
_name = "Divine Strike"
|
||||||
|
source = "Cleric (Tempest Domain)"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
level = self.owner.Cleric.level
|
||||||
|
if level < 14:
|
||||||
|
return self._name + " (1d8)"
|
||||||
|
else:
|
||||||
|
return self._name + " (2d8)"
|
||||||
|
|
||||||
|
|
||||||
|
class Stormborn(Feature):
|
||||||
|
"""At 17th level, you have a flying speed equal to your current walking speed
|
||||||
|
whenever you are not underground or indoors.
|
||||||
|
"""
|
||||||
|
name = "Stormborn"
|
||||||
|
source = "Cleric (Tempest Domain)"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
from .. import weapons
|
from .. import weapons
|
||||||
|
|
||||||
|
|
||||||
@@ -34,6 +35,9 @@ class Feature():
|
|||||||
|
|
||||||
def __init__(self, owner=None):
|
def __init__(self, owner=None):
|
||||||
self.owner = owner
|
self.owner = owner
|
||||||
|
cls = type(self)
|
||||||
|
self.spells_known = [S() for S in cls.spells_known]
|
||||||
|
self.spells_prepared = [S() for S in cls.spells_prepared]
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
return (self.name == other.name) and (self.source == other.source)
|
return (self.name == other.name) and (self.source == other.source)
|
||||||
@@ -72,16 +76,17 @@ class FeatureSelector(Feature):
|
|||||||
A feature with multiple possible choices.
|
A feature with multiple possible choices.
|
||||||
"""
|
"""
|
||||||
options = dict()
|
options = dict()
|
||||||
|
name = ''
|
||||||
|
source = ''
|
||||||
|
|
||||||
def __init__(self, owner, feature_choices=[]):
|
def __new__(t, owner, feature_choices=[]):
|
||||||
self.owner = owner
|
|
||||||
keep_source = self.source
|
|
||||||
# Look for matching feature_choices
|
# Look for matching feature_choices
|
||||||
|
new_feat = Feature.__new__(Feature, owner=owner)
|
||||||
|
new_feat.__doc__ = t.__doc__
|
||||||
|
new_feat.name = t.name
|
||||||
|
new_feat.source = t.source
|
||||||
for selection in feature_choices:
|
for selection in feature_choices:
|
||||||
if selection.lower() in self.options():
|
if selection.lower() in t.options:
|
||||||
feature_choices.remove(selection)
|
new_feat = t.options[selection.lower()](owner=owner)
|
||||||
new_feat = self.options[selection.lower()]
|
new_feat.source = t.source
|
||||||
self.__dict__.update(new_feat.__dict__)
|
return new_feat
|
||||||
new_feat.__init__(self)
|
|
||||||
break
|
|
||||||
self.source = keep_source
|
|
||||||
|
|||||||
@@ -0,0 +1,751 @@
|
|||||||
|
from .ranger import Archery, Defense, Dueling, TwoWeaponFighting
|
||||||
|
from .features import Feature, FeatureSelector
|
||||||
|
from .. import (weapons, armor)
|
||||||
|
|
||||||
|
# Features added for all PHB classes
|
||||||
|
# SCAG and XGTE needed
|
||||||
|
|
||||||
|
|
||||||
|
# PHB
|
||||||
|
class GreatWeaponFighting(Feature):
|
||||||
|
"""When you roll a 1 or 2 on a damage die for an attack you make with a melee
|
||||||
|
weapon that you are wielding with two hands, you can reroll the die and
|
||||||
|
must use the new roll, even if the new roll is a 1 or a 2. The weapon must
|
||||||
|
have the two-handed or versatile property for you to gain this benefit.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Fighting Style (Great Weapon Fighting)"
|
||||||
|
source = "Fighter"
|
||||||
|
|
||||||
|
|
||||||
|
class Protection(Feature):
|
||||||
|
"""When a creature you can see attacks a target other than you that is within
|
||||||
|
5 feet of you, you can use your reaction to impose disadvantage on the
|
||||||
|
attack roll. You must be wielding a shield.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Fighting Style (Protection)"
|
||||||
|
source = "Fighter"
|
||||||
|
|
||||||
|
|
||||||
|
class FighterFightingStyle(FeatureSelector):
|
||||||
|
"""
|
||||||
|
Select a Fighting Style by choosing in feature_choices:
|
||||||
|
|
||||||
|
archery
|
||||||
|
|
||||||
|
defense
|
||||||
|
|
||||||
|
dueling
|
||||||
|
|
||||||
|
great-weapon fighting
|
||||||
|
|
||||||
|
protection
|
||||||
|
|
||||||
|
two-weapon fighting
|
||||||
|
"""
|
||||||
|
options = {'archery': Archery,
|
||||||
|
'defense': Defense,
|
||||||
|
'dueling': Dueling,
|
||||||
|
'great': GreatWeaponFighting,
|
||||||
|
'great-weapon fighting': GreatWeaponFighting,
|
||||||
|
'projection': Protection,
|
||||||
|
'two-weapon fighting': TwoWeaponFighting,
|
||||||
|
'two-weapon': TwoWeaponFighting,
|
||||||
|
'dual wield': TwoWeaponFighting}
|
||||||
|
name = "Fighting Style (Select One)"
|
||||||
|
source = "Fighter"
|
||||||
|
|
||||||
|
|
||||||
|
class SecondWind(Feature):
|
||||||
|
"""You have a limited well of stamina that you can draw on to protect yourself
|
||||||
|
from harm. On your turn, you can use a bonus action to regain hit points
|
||||||
|
equal to 1d10 + your fighter level. Once you use this feature, you must
|
||||||
|
finish a short or long rest before you can use it again
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Second Wind"
|
||||||
|
source = "Fighter"
|
||||||
|
|
||||||
|
|
||||||
|
class ActionSurge(Feature):
|
||||||
|
"""Starting at 2nd level, you can push yourself beyond your normal limits for a
|
||||||
|
moment. On your turn, you can take one additional action on top of your
|
||||||
|
regular action and a possible bonus action.
|
||||||
|
|
||||||
|
Once you use this feature, you must finish a short or long rest before you
|
||||||
|
can use it again. Starting at 17th level, you can use it twice before a
|
||||||
|
rest, but only once on the same turn.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Action Surge"
|
||||||
|
source = "Fighter"
|
||||||
|
|
||||||
|
|
||||||
|
class ExtraAttackFighter(Feature):
|
||||||
|
"""Beginning at 5th level, you can attack twice, instead of once, whenever you
|
||||||
|
take the Attack action on your turn. The number of attacks increases to
|
||||||
|
three when you reach 11th level in this class and to four when you reach
|
||||||
|
20th level in this class.
|
||||||
|
|
||||||
|
"""
|
||||||
|
_name = "Extra Attack"
|
||||||
|
source = "Fighter"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
level = self.owner.Fighter.level
|
||||||
|
if level < 11:
|
||||||
|
return self._name + ' (2x)'
|
||||||
|
elif level < 20:
|
||||||
|
return self._name + ' (3x)'
|
||||||
|
else:
|
||||||
|
return self._name + ' (4x)'
|
||||||
|
|
||||||
|
|
||||||
|
class Indomitable(Feature):
|
||||||
|
"""Beginning at 9th level, you can reroll a saving throw that you fail. If you
|
||||||
|
do so, you must use the new roll, and you can’t use this feature again
|
||||||
|
until you finish a long rest.
|
||||||
|
|
||||||
|
You can use this feature twice between long rests starting at 13th level
|
||||||
|
and three times between long rests starting at 17th level.
|
||||||
|
|
||||||
|
"""
|
||||||
|
_name = "Indomitable"
|
||||||
|
source = "Fighter"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
level = self.owner.Fighter.level
|
||||||
|
if level < 13:
|
||||||
|
return self._name + ' (1x/LR)'
|
||||||
|
elif level < 17:
|
||||||
|
return self._name + ' (2x/LR)'
|
||||||
|
else:
|
||||||
|
return self._name + ' (3x/LR)'
|
||||||
|
|
||||||
|
|
||||||
|
# Champion
|
||||||
|
class ImprovedCritical(Feature):
|
||||||
|
"""Beginning when you choose this archetype at 3rd level, your weapon attacks
|
||||||
|
score a critical hit on a roll of 19 or 20.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Improved Critical"
|
||||||
|
source = "Fighter (Champion)"
|
||||||
|
|
||||||
|
|
||||||
|
class RemarkableAthelete(Feature):
|
||||||
|
"""Starting at 7th level, you can add half your proficiency bonus (round up)
|
||||||
|
to any Strength, Dexterity, or Constitution check you make that doesn’t
|
||||||
|
already use your proficiency bonus.
|
||||||
|
|
||||||
|
In addition, when you make a running long jump, the distance you can cover
|
||||||
|
increases by a number of feet equal to your Strength modifier.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Remarkable Athelete"
|
||||||
|
source = "Fighter (Champion)"
|
||||||
|
|
||||||
|
|
||||||
|
class AdditionalFightingStyle(FeatureSelector):
|
||||||
|
"""
|
||||||
|
Select a Fighting Style by choosing in feature_choices:
|
||||||
|
|
||||||
|
archery 2
|
||||||
|
|
||||||
|
defense 2
|
||||||
|
|
||||||
|
dueling 2
|
||||||
|
|
||||||
|
great-weapon fighting 2
|
||||||
|
|
||||||
|
protection 2
|
||||||
|
|
||||||
|
two-weapon fighting 2
|
||||||
|
"""
|
||||||
|
options = {'archery 2': Archery,
|
||||||
|
'defense 2': Defense,
|
||||||
|
'dueling 2': Dueling,
|
||||||
|
'great 2': GreatWeaponFighting,
|
||||||
|
'great-weapon fighting 2': GreatWeaponFighting,
|
||||||
|
'projection 2': Protection,
|
||||||
|
'two-weapon fighting 2': TwoWeaponFighting,
|
||||||
|
'two-weapon 2': TwoWeaponFighting,
|
||||||
|
'dual wield 2': TwoWeaponFighting}
|
||||||
|
name = "Fighting Style (Select One)"
|
||||||
|
source = "Fighter (Champion)"
|
||||||
|
|
||||||
|
|
||||||
|
class SuperiorCritical(Feature):
|
||||||
|
"""Starting at 15th level, your weapon attacks score a critical hit on a roll
|
||||||
|
of 18-20 .
|
||||||
|
"""
|
||||||
|
name = "Superior Critical"
|
||||||
|
source = "Fighter (Champion)"
|
||||||
|
|
||||||
|
|
||||||
|
class Survivor(Feature):
|
||||||
|
"""At 18th level, you attain the pinnacle of resilience in battle. At the
|
||||||
|
start of each of your turns, you regain hit points equal to 5 + your
|
||||||
|
Constitution modifier if you have no more than half of your hit points
|
||||||
|
left. You don’t gain this benefit if you have 0 hit points.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Survivor"
|
||||||
|
source = "Fighter (Champion)"
|
||||||
|
|
||||||
|
|
||||||
|
# Battle Master
|
||||||
|
class CombatSuperiority(Feature):
|
||||||
|
"""When you choose this archetype at 3rd level, you learn maneuvers that are
|
||||||
|
fueled by special dice called superiority dice.
|
||||||
|
|
||||||
|
**Maneuvers**: You learn three maneuvers of your choice, which are detailed
|
||||||
|
under “Maneuvers” below. Many maneuvers enhance an attack in some way. You
|
||||||
|
can use only one maneuver per attack. You learn two additional maneuvers
|
||||||
|
of your choice at 7th, 10th, and 15th level. Each time you learn new
|
||||||
|
maneuvers, you can also replace one maneuver you know with a different one.
|
||||||
|
|
||||||
|
**Superiority Dice**: You have four superiority dice, which are d8s. A
|
||||||
|
superiority die is expended when you use it. You regain all of your
|
||||||
|
expended superiority dice when you finish a short or long rest. You gain
|
||||||
|
another superiority die at 7th level and one more at 15th level.
|
||||||
|
|
||||||
|
**Saving Throws**: Some of your maneuvers require your target to make a
|
||||||
|
saving throw to resist the maneuver’s effects. The saving throw DC is
|
||||||
|
calculated as follows:
|
||||||
|
|
||||||
|
Maneuver save DC = 8 + your proficiency bonus + your Strength or Dexterity
|
||||||
|
modifier (your choice)
|
||||||
|
|
||||||
|
"""
|
||||||
|
_name = "Combat Superiority"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
level = self.owner.Fighter.level
|
||||||
|
if level < 10:
|
||||||
|
return self._name + ' (d8)'
|
||||||
|
elif level < 18:
|
||||||
|
return self._name + ' (d10)'
|
||||||
|
else:
|
||||||
|
return self._name + ' (d12)'
|
||||||
|
|
||||||
|
|
||||||
|
class StudentOfWar(Feature):
|
||||||
|
"""At 3rd level, you gain proficiency with one type of artisan’s tools of your
|
||||||
|
choice.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Student of War"
|
||||||
|
source = "Fighter (Battle Master)"
|
||||||
|
|
||||||
|
|
||||||
|
class KnowYourEnemy(Feature):
|
||||||
|
"""Starting at 7th level, if you spend at least 1 minute observing or
|
||||||
|
interacting with another creature outside combat, you can learn certain
|
||||||
|
information about its capabilities compared to your own. The DM tells you
|
||||||
|
if the creature is your equal, superior, or inferior in regard to two of
|
||||||
|
the following characteristics of your choice:
|
||||||
|
|
||||||
|
--Strength score
|
||||||
|
|
||||||
|
--Dexterity score
|
||||||
|
|
||||||
|
--Constitution score
|
||||||
|
|
||||||
|
--Armor Class
|
||||||
|
|
||||||
|
--Current hit points
|
||||||
|
|
||||||
|
--Total class levels (if any)
|
||||||
|
|
||||||
|
--Fighter class levels (if any)
|
||||||
|
"""
|
||||||
|
name = "Know Your Enemy"
|
||||||
|
source = "Fighter (Battle Master)"
|
||||||
|
|
||||||
|
|
||||||
|
class Relentless(Feature):
|
||||||
|
"""Starting at 15th level, when you roll initiative and have no superiority
|
||||||
|
dice remaining, you regain 1 superiority die.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Relentless"
|
||||||
|
source = "Fighter (Battle Master)"
|
||||||
|
|
||||||
|
|
||||||
|
# Maneuvers
|
||||||
|
class Maneuver(Feature):
|
||||||
|
"""
|
||||||
|
A generic Maneuver
|
||||||
|
"""
|
||||||
|
name = "Maneuver"
|
||||||
|
source = "Fighter Maneuver (Battle Master)"
|
||||||
|
|
||||||
|
|
||||||
|
class CommandersStrike(Maneuver):
|
||||||
|
"""When you take the Attack action on your turn, you can forgo one of your
|
||||||
|
attacks and use a bonus action to direct one of your companions to
|
||||||
|
strike. When you do so, choose a friendly creature who can see or hear you
|
||||||
|
and expend one superiority die. That creature can immediately use its
|
||||||
|
reaction to make one weapon attack, adding the superiority die to the
|
||||||
|
attack’s damage roll.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Commander's Strike"
|
||||||
|
|
||||||
|
|
||||||
|
class DisarmingStrike(Maneuver):
|
||||||
|
"""When you hit a creature with a weapon attack, you can expend one
|
||||||
|
superiority die to attempt to disarm the target, forcing it to drop one
|
||||||
|
item o f your choice that it’s holding. You add the superiority die to the
|
||||||
|
attack’s damage roll, and the target must make a Strength saving throw. On
|
||||||
|
a failed save, it drops the object you choose. The object lands at its
|
||||||
|
feet.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Disarming Strike"
|
||||||
|
|
||||||
|
|
||||||
|
class DistractingStrike(Maneuver):
|
||||||
|
"""When you hit a creature with a weapon attack, you can expend one
|
||||||
|
superiority die to distract the creature, giving your allies an
|
||||||
|
opening. You add the superiority die to the attack’s damage roll. The next
|
||||||
|
attack roll against the target by an attacker other than you has advantage
|
||||||
|
if the attack is made before the start of your next turn.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Distracting Strike"
|
||||||
|
|
||||||
|
|
||||||
|
class EvasiveFootwork(Maneuver):
|
||||||
|
"""When you move, you can expend one superiority die, rolling the die and
|
||||||
|
adding the number rolled to your AC until you stop moving.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Evasive Footwork"
|
||||||
|
|
||||||
|
|
||||||
|
class FeintingAttack(Maneuver):
|
||||||
|
"""You can expend one superiority die and use a bonus action on your turn to
|
||||||
|
feint, choosing one creature within 5 feet of you as your target. You have
|
||||||
|
advantage on your next attack roll against that creature. If that attack
|
||||||
|
hits, add the superiority die to the attack’s damage roll.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Feinting Attack"
|
||||||
|
|
||||||
|
|
||||||
|
class GoadingAttack(Maneuver):
|
||||||
|
"""When you hit a creature with a weapon attack, you can expend one
|
||||||
|
superiority die to attempt to goad the target into attacking you. You add
|
||||||
|
the superiority die to the attack’s damage roll, and the target must make a
|
||||||
|
W isdom saving throw. On a failed save, the target has disadvantage on all
|
||||||
|
attack rolls against targets other than you until the end of your next
|
||||||
|
turn.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Goading Attack"
|
||||||
|
|
||||||
|
|
||||||
|
class LungingAttack(Maneuver):
|
||||||
|
"""When you make a melee weapon attack on your turn, you can expend one
|
||||||
|
superiority die to increase your reach for that attack by 5 feet. If you
|
||||||
|
hit, you add the superiority die to the attack’s damage roll.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Lunging Attack"
|
||||||
|
|
||||||
|
|
||||||
|
class ManeuveringAttack(Maneuver):
|
||||||
|
"""When you hit a creature with a weapon attack, you can expend one
|
||||||
|
superiority die to maneuver one o f your comrades into a more advantageous
|
||||||
|
position. You add the superiority die to the attack’s damage roll, and you
|
||||||
|
choose a friendly creature who can see or hear you. That creature can use
|
||||||
|
its reaction to move up to half its speed without provoking opportunity
|
||||||
|
attacks from the target of your attack.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Maneuvering Attack"
|
||||||
|
|
||||||
|
|
||||||
|
class MenacingAttack(Maneuver):
|
||||||
|
"""When you hit a creature with a weapon attack, you can expend one
|
||||||
|
superiority die to attempt to frighten the target. You add the superiority
|
||||||
|
die to the attack’s damage roll, and the target must make a Wisdom saving
|
||||||
|
throw. On a failed save, it is frightened of you until the end o f your
|
||||||
|
next turn.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Menacing Attack"
|
||||||
|
|
||||||
|
|
||||||
|
class Parry(Maneuver):
|
||||||
|
"""When another creature damages you with a melee attack, you can use your
|
||||||
|
reaction and expend one superiority die to reduce the damage by the number
|
||||||
|
you roll on your superiority die + your Dexterity modifier.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Parry"
|
||||||
|
|
||||||
|
|
||||||
|
class PrecisionAttack(Maneuver):
|
||||||
|
"""When you make a weapon attack roll against a creature, you can expend one
|
||||||
|
superiority die to add it to the roll. You can use this maneuver before or
|
||||||
|
after making the attack roll, but before any effects of the attack are
|
||||||
|
applied
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Precision Attack"
|
||||||
|
|
||||||
|
|
||||||
|
class PushingAttack(Maneuver):
|
||||||
|
"""When you hit a creature with a weapon attack, you can expend one
|
||||||
|
superiority die to attempt to drive the target back. You add the
|
||||||
|
superiority die to the attack's damage roll, and if the target is Large or
|
||||||
|
smaller, it must make a Strength saving throw. On a failed save, you push
|
||||||
|
the target up to 15 feet away from you.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Pushing Attack"
|
||||||
|
|
||||||
|
|
||||||
|
class Rally(Maneuver):
|
||||||
|
"""On your turn, you can use a bonus action and expend one superiority die to
|
||||||
|
bolster the resolve of one of your companions. When you do so, choose a
|
||||||
|
friendly creature who can see or hear you. That creature gains temporary
|
||||||
|
hit points equal to the superiority die roll + your Charisma modifier.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Rally"
|
||||||
|
|
||||||
|
|
||||||
|
class Riposte(Maneuver):
|
||||||
|
"""When a creature misses you with a melee attack, you can use your reaction
|
||||||
|
and expend one superiority die to make a melee weapon attack against the
|
||||||
|
creature. If you hit, you add the superiority die to the attack's damage
|
||||||
|
roll
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Riposte"
|
||||||
|
|
||||||
|
|
||||||
|
class SweepingAttack(Maneuver):
|
||||||
|
"""When you hit a creature with a melee weapon attack, you can expend one
|
||||||
|
superiority die to attempt to damage another creature with the same
|
||||||
|
attack. Choose another creature within 5 feet of the original target and
|
||||||
|
within your reach. If the original attack roll would hit the second
|
||||||
|
creature, it takes damage equal to the number you roll on your superiority
|
||||||
|
die. The damage is of the same type dealt by the original attack. Trip
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Sweeping Attack"
|
||||||
|
|
||||||
|
|
||||||
|
class TripingAttack(Maneuver):
|
||||||
|
"""When you hit a creature with a weapon attack, you can expend one
|
||||||
|
superiority die to attempt to knock the target down. You add the
|
||||||
|
superiority die to the attack’s damage roll, and if the target is Large or
|
||||||
|
smaller, it must make a Strength saving throw. On a failed save, you knock
|
||||||
|
the target prone
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Triping Attack"
|
||||||
|
|
||||||
|
|
||||||
|
# Eldritch Knight
|
||||||
|
class EldritchKnightSpellcasting(Feature):
|
||||||
|
"""You know three 1st-level wizard spells of your choice, two of which you
|
||||||
|
must choose from the abjuration and evocation spells on the wizard spell
|
||||||
|
list.
|
||||||
|
|
||||||
|
The Spells Known column of the Eldritch Knight Spellcasting table shows
|
||||||
|
when you learn more wizard spells of 1st level or higher. Each of these
|
||||||
|
spells must be an abjuration or evocation spell of your choice, and must be
|
||||||
|
of a level for which you have spell slots. For instance, when you reach 7th
|
||||||
|
level in this class, you can learn one new spell of 1st or 2nd level.
|
||||||
|
|
||||||
|
The spells you learn at 8th, 14th, and 20th level can come from any school
|
||||||
|
of magic.
|
||||||
|
|
||||||
|
Whenever you gain a level in this class, you can replace one of the wizard
|
||||||
|
spells you know with another spell o f your choice from the wizard spell
|
||||||
|
list. The new spell must be of a level for which you have spell slots, and
|
||||||
|
it must be an abjuration or evocation spell, unless you’re replacing the
|
||||||
|
spell you gained at 8th, 14th, or 20th level.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Spellcasting"
|
||||||
|
source = "Fighter (Eldritch Knight)"
|
||||||
|
|
||||||
|
|
||||||
|
class WeaponBond(Feature):
|
||||||
|
"""At 3rd level, you learn a ritual that creates a magical bond between
|
||||||
|
yourself and one weapon. You perform the ritual over the course of 1 hour,
|
||||||
|
which can be done during a short rest. The weapon must be within your reach
|
||||||
|
throughout the ritual, at the conclusion of which you touch the weapon and
|
||||||
|
forge the bond.
|
||||||
|
|
||||||
|
Once you have bonded a weapon to yourself, you can’t be disarmed of that
|
||||||
|
weapon unless you are incapacitated. If it is on the same plane of
|
||||||
|
existence, you can summon that weapon as a bonus action on your turn,
|
||||||
|
causing it to teleport instantly to your hand.
|
||||||
|
|
||||||
|
You can have up to two bonded weapons, but can summon only one at a time
|
||||||
|
with your bonus action. If you attempt to bond with a third weapon, you
|
||||||
|
must break the bond with one of the other two.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Weapon Bond"
|
||||||
|
source = "Fighter (Eldritch Knight)"
|
||||||
|
|
||||||
|
|
||||||
|
class WarMagic(Feature):
|
||||||
|
"""Beginning at 7th level, when you use your action to cast a cantrip, you can
|
||||||
|
make one weapon attack as a bonus action.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "War Magic"
|
||||||
|
source = "Fighter (Eldritch Knight)"
|
||||||
|
|
||||||
|
|
||||||
|
class EldritchStrike(Feature):
|
||||||
|
"""At 10th level, you learn how to make your weapon strikes undercut a
|
||||||
|
creature’s resistance to your spells. When you hit a creature with a weapon
|
||||||
|
attack, that creature has disadvantage on the next saving throw it makes
|
||||||
|
against a spell you cast before the end of your next turn.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Eldritch Strike"
|
||||||
|
source = "Fighter (Eldritch Knight)"
|
||||||
|
|
||||||
|
|
||||||
|
class ArcaneCharge(Feature):
|
||||||
|
"""At 15th level, you gain the ability to teleport up to 30 feet to an
|
||||||
|
unoccupied space you can see when you use your Action Surge. You can
|
||||||
|
teleport before or after the additional action.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Arcane Charge"
|
||||||
|
source = "Fighter (Eldritch Knight)"
|
||||||
|
|
||||||
|
|
||||||
|
class ImprovedWarMagic(Feature):
|
||||||
|
"""Starting at 18th level, when you use your action to cast a spell, you can
|
||||||
|
make one weapon attack as a bonus action.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Improved War Magic"
|
||||||
|
source = "Fighter (Eldritch Knight)"
|
||||||
|
|
||||||
|
|
||||||
|
# Gunslinger
|
||||||
|
class Gunsmith(Feature):
|
||||||
|
"""Upon choosing this archetype at 3rd level, you gain proficiency with
|
||||||
|
Tinker's Tools. You may use them to craft ammunition at half the cost,
|
||||||
|
repair damaged firearms, or even draft and create new ones (DM's
|
||||||
|
discretion). Some extremely experimental and intricate firearms are only
|
||||||
|
available through crafting.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Gunsmith"
|
||||||
|
source = "Fighter (Gunslinger)"
|
||||||
|
|
||||||
|
|
||||||
|
class AdeptMarksman(Feature):
|
||||||
|
"""When you choose this archetype at 3rd level, you learn to perform powerful
|
||||||
|
trick shots to disable or damage your opponents using your firearms.
|
||||||
|
|
||||||
|
**Trick Shots**: You learn two trick shots of your choice, which are detailed under "Trick Shots" below.
|
||||||
|
If you have not already, add them by name to "features" in your character's .py file.
|
||||||
|
|
||||||
|
Many maneuvers enhance an attack in some way. Each use of a trick shot must be declared before the attack roll is made. You can use only one trick shot per attack.
|
||||||
|
|
||||||
|
You learn an additional trick shot of your choice at 7th, 10th, 15th, and
|
||||||
|
18th level. Each time you learn a new trick shot, you can also replace one
|
||||||
|
trick shot you know with a different one.
|
||||||
|
|
||||||
|
Grit. You gain a number of grit points equal to your Wisdom modifier
|
||||||
|
(minimum of 1). You regain 1 expended grit point each time you roll a 20 on
|
||||||
|
the d20 roll for an attack with a firearm, or deal a killing blow with a
|
||||||
|
firearm to a creature of significant threat (DM’s discretion). You regain
|
||||||
|
all expended grit points after a short or long rest.
|
||||||
|
|
||||||
|
Saving Throws. Some of your trick shots require your targets to make a
|
||||||
|
saving throw to resist the trick shot’s effects. The saving throw DC is
|
||||||
|
calculated as follows:
|
||||||
|
|
||||||
|
Trick Shot save DC = 8 + your proficiency bonus + your Dexterity modifier
|
||||||
|
|
||||||
|
Firearm Properties Firearms are a new and volatile technology, and as such
|
||||||
|
bring their own unique set of weapon properties. Some properties are
|
||||||
|
followed by a number, and this number signifies an element of that property
|
||||||
|
(outlined below). These properties replace the optional ones presented in
|
||||||
|
the Dungeon Master’s Guide. Firearms are ranged weapons.
|
||||||
|
|
||||||
|
Reload. The weapon can be fired a number of times equal to its Reload score
|
||||||
|
before you must spend 1 attack or 1 action to reload. You must have one
|
||||||
|
free hand to reload a firearm.
|
||||||
|
|
||||||
|
Misfire. Whenever you make an attack roll with a firearm, and the dice roll
|
||||||
|
is equal to or lower than the weapon’s Misfire score, the weapon
|
||||||
|
misfires. The attack misses, and the weapon cannot be used again until you
|
||||||
|
spend an action to try and repair it. To repair your firearm, you must make
|
||||||
|
a successful Tinker’s Tools check (DC equal to 8 + misfire score). If your
|
||||||
|
check fails, the weapon is broken and must be mended out of combat at a
|
||||||
|
quarter of the cost of the firearm. Creatures who use a firearm without
|
||||||
|
being proficient increase the weapon’s misfire score by 1.
|
||||||
|
|
||||||
|
Explosive. Upon a hit, everything within 5 ft of the target must make a
|
||||||
|
Dexterity saving throw (DC equal to 8 + your proficiency bonus + your
|
||||||
|
Dexterity modifier) or suffer 1d8 fire damage. If the weapon misses, the
|
||||||
|
ammunition fails to detonate, or bounces away harmlessly before doing so.
|
||||||
|
|
||||||
|
Ammunition All firearms require ammunition to make an attack, and due to
|
||||||
|
their rare nature, ammunition may be near impossible to find or
|
||||||
|
purchase. However, if materials are gathered, you can craft ammunition
|
||||||
|
yourself using your Tinker’s Tools at half the cost. Each firearm uses its
|
||||||
|
own unique ammunition and is generally sold or crafted in batches listed
|
||||||
|
below next to the price.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Adept Marksman"
|
||||||
|
source = "Fighter (Gunslinger"
|
||||||
|
|
||||||
|
|
||||||
|
class QuickDraw(Feature):
|
||||||
|
"""When you reach 7th level, you add your proficiency bonus to your
|
||||||
|
initiative. You can also stow a firearm, then draw another firearm as a
|
||||||
|
single object interaction on your turn.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Quick Draw"
|
||||||
|
source = "Fighter (Gunslinger)"
|
||||||
|
|
||||||
|
|
||||||
|
class RapidRepair(Feature):
|
||||||
|
"""Upon reaching 10th level, you learn how to quickly attempt to fix a jammed
|
||||||
|
gun. You can spend a grit point to attempt to repair a misfired (but not
|
||||||
|
broken) firearm as a bonus action.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Rapid Repair"
|
||||||
|
source = "Fighter (Gunslinger)"
|
||||||
|
|
||||||
|
|
||||||
|
class LightningReload(Feature):
|
||||||
|
"""Starting at 15th level, you can reload any firearm as a bonus action.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Lightning Repaid"
|
||||||
|
source = "Fighter (Gunslinger)"
|
||||||
|
|
||||||
|
|
||||||
|
class ViciousIntent(Feature):
|
||||||
|
"""At 18th level, your firearm attacks score a critical hit on a roll of 19-20,
|
||||||
|
and you regain a grit point on a roll of 19 or 20 on a d20 attack roll.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Vicious Intent"
|
||||||
|
source = "Fighter (Gunslinger)"
|
||||||
|
|
||||||
|
|
||||||
|
class HemorrhagingCritical(Feature):
|
||||||
|
"""Upon reaching 18th level, whenever you score a critical hit on an attack
|
||||||
|
with a firearm, the target additionally suffers half of the damage from the
|
||||||
|
attack at the end of its next turn.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Hemorrhaging Critical"
|
||||||
|
source = "Fighter (Gunslinger)"
|
||||||
|
|
||||||
|
|
||||||
|
class BullyingShot(Feature):
|
||||||
|
"""You can use the powerful blast and thundering sound of your firearm to shake
|
||||||
|
the resolve of a creature. You can expend one grit point while making a
|
||||||
|
Charisma (Intimidation) check to gain advantage on the roll.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Bullying Shot"
|
||||||
|
source = "Gunslinger (Trick Shot)"
|
||||||
|
|
||||||
|
|
||||||
|
class DazingShot(Feature):
|
||||||
|
"""When you make a firearm attack against a creature, you can expend one grit
|
||||||
|
point to attempt to dizzy your opponent. On a hit, the creature suffers
|
||||||
|
normal damage and must make a Constitution saving throw or suffer
|
||||||
|
disadvantage on attacks until the end of their next turn.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Dazing Shot"
|
||||||
|
source = "Gunslinger (Trick Shot)"
|
||||||
|
|
||||||
|
|
||||||
|
class DeadeyeShot(Feature):
|
||||||
|
"""When you make a firearm attack against a creature, you can expend one grit
|
||||||
|
point to gain advantage on the attack roll.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Deadeye Shot"
|
||||||
|
source = "Gunslinger (Trick Shot)"
|
||||||
|
|
||||||
|
|
||||||
|
class DisarmingShot(Feature):
|
||||||
|
"""When you make a firearm attack against a creature, you can expend one grit
|
||||||
|
point to attempt to shoot an object from their hands. On a hit, the
|
||||||
|
creature suffers normal damage and must succeed on a Strength saving throw
|
||||||
|
or drop 1 held object of your choice and have that object be pushed 10 feet
|
||||||
|
away from you.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Disarming Shot"
|
||||||
|
source = "Gunslinger (Trick Shot)"
|
||||||
|
|
||||||
|
|
||||||
|
class ForcefulShot(Feature):
|
||||||
|
"""When you make a firearm attack against a creature, you can expend one grit
|
||||||
|
point to attempt to trip them up and force them back. On a hit, the
|
||||||
|
creature suffers normal damage and must succeed on a Strength saving throw
|
||||||
|
or be pushed 15 feet away from you.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Forceful Shot"
|
||||||
|
source = "Gunslinger (Trick Shot)"
|
||||||
|
|
||||||
|
|
||||||
|
class PiercingShot(Feature):
|
||||||
|
"""When you make a firearm attack against a creature, you can expend one grit
|
||||||
|
point to attempt to fire through multiple opponents. The initial attack
|
||||||
|
gains a +1 to the firearm’s misfire score. On a hit, the creature suffers
|
||||||
|
normal damage and you make an attack roll with disadvantage against every
|
||||||
|
creature in a line directly behind the target within your first range
|
||||||
|
increment. Only the initial attack can misfire.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Piercing Shot"
|
||||||
|
source = "Gunslinger (Trick Shot)"
|
||||||
|
|
||||||
|
|
||||||
|
class WingingShot(Feature):
|
||||||
|
"""When you make a firearm attack against a creature, you can expend one grit
|
||||||
|
point to attempt to topple a moving target. On a hit, the creature suffers
|
||||||
|
normal damage and must make a Strength saving throw or be knocked prone.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Winging Shot"
|
||||||
|
source = "Gunslinger (Trick Shot)"
|
||||||
|
|
||||||
|
|
||||||
|
class ViolentShot(Feature):
|
||||||
|
"""When you make a firearm attack against a creature, you can expend one or
|
||||||
|
more grit points to enhance the volatility of the attack. For each grit
|
||||||
|
point expended, the attack gains a +2 to the firearm’s misfire score. If
|
||||||
|
the attack hits, you can roll one additional weapon damage die per grit
|
||||||
|
point spent when determining the damage.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Violent Shot"
|
||||||
|
source = "Gunslinger (Trick Shot)"
|
||||||
|
|||||||
@@ -44,30 +44,25 @@ class MartialArts(Feature):
|
|||||||
source = 'Monk'
|
source = 'Monk'
|
||||||
die = 'd4'
|
die = 'd4'
|
||||||
|
|
||||||
def __init__(self, owner):
|
def weapon_func(self, weapon: weapons.Weapon, **kwargs):
|
||||||
self.owner = owner
|
|
||||||
self.level = owner.Monk.level
|
|
||||||
|
|
||||||
def weapon_func(self, weapon: weapons.Weapon, char=None, **kwargs):
|
|
||||||
"""
|
"""
|
||||||
Update increasing damage dice and DEX mod of Monk weapons
|
Update increasing damage dice and DEX mod of Monk weapons
|
||||||
"""
|
"""
|
||||||
is_monk_weapon = any([isinstance(weapon, w)
|
is_monk_weapon = any([isinstance(weapon, w)
|
||||||
for w in weapons.monk_weapons])
|
for w in weapons.monk_weapons])
|
||||||
|
level = self.owner.Monk.level
|
||||||
if not is_monk_weapon:
|
if not is_monk_weapon:
|
||||||
return weapon
|
return weapon
|
||||||
if char is None:
|
|
||||||
return weapon
|
|
||||||
self.die = 'd4'
|
self.die = 'd4'
|
||||||
if self.level >= 5:
|
if level >= 5:
|
||||||
self.die = 'd6'
|
self.die = 'd6'
|
||||||
if self.level >= 11:
|
if level >= 11:
|
||||||
self.die = 'd8'
|
self.die = 'd8'
|
||||||
if self.level >= 17:
|
if level >= 17:
|
||||||
self.die = 'd10'
|
self.die = 'd10'
|
||||||
# check if new damage is better than default
|
# check if new damage is better than default
|
||||||
if self.die > int(weapon.base_damage.split('d')[-1]):
|
if int(self.die[1:]) > int(weapon.base_damage.split('d')[-1]):
|
||||||
weapon.base_damage = '1d' + str(self.die)
|
weapon.base_damage = '1' + str(self.die)
|
||||||
weapon.is_finesse = True
|
weapon.is_finesse = True
|
||||||
return weapon
|
return weapon
|
||||||
|
|
||||||
@@ -84,19 +79,16 @@ class UnarmoredMovement(Feature):
|
|||||||
name = "Unarmored Movement"
|
name = "Unarmored Movement"
|
||||||
source = "Monk"
|
source = "Monk"
|
||||||
|
|
||||||
def __init__(self, owner):
|
|
||||||
self.owner = owner
|
|
||||||
self.level = owner.Monk.level
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def speed_bonus(self):
|
def speed_bonus(self):
|
||||||
|
level = self.owner.Monk.level
|
||||||
_speed_bonus = 10
|
_speed_bonus = 10
|
||||||
if self.level >= 6:
|
if level >= 6:
|
||||||
_speed_bonus = 15
|
_speed_bonus = 15
|
||||||
if self.level >= 10:
|
if level >= 10:
|
||||||
_speed_bonus = 20
|
_speed_bonus = 20
|
||||||
if self.level >= 14:
|
if level >= 14:
|
||||||
_speed_bonus = 25
|
_speed_bonus = 25
|
||||||
if self.level >= 18:
|
if level >= 18:
|
||||||
_speed_bonus = 30
|
_speed_bonus = 30
|
||||||
return _speed_bonus
|
return _speed_bonus
|
||||||
|
|||||||
@@ -0,0 +1,311 @@
|
|||||||
|
from .features import Feature, FeatureSelector
|
||||||
|
from .ranger import Defense, Dueling
|
||||||
|
from .fighter import GreatWeaponFighting, Protection
|
||||||
|
from .. import (weapons, armor)
|
||||||
|
|
||||||
|
|
||||||
|
# PHB
|
||||||
|
class DivineSense(Feature):
|
||||||
|
"""The presence of strong evil registers on your senses like a noxious odor,
|
||||||
|
and powerful good rings like heavenly music in your ears. As an action, you
|
||||||
|
can open your awareness to detect such forces. Until the end of your next
|
||||||
|
turn, you know the location of any celestial, fiend, or undead within 60
|
||||||
|
feet of you that is not behind total cover. You know the type (celestial,
|
||||||
|
fiend, or undead) of any being whose presence you sense, but not its
|
||||||
|
identity (the vampire Count Strahd von Zarovich, for instance). Within the
|
||||||
|
same radius, you also detect the presence of any place or object that has
|
||||||
|
been consecrated or desecrated, as with the hallow spell.
|
||||||
|
|
||||||
|
You can use this feature a number of times equal to 1 + your Charisma
|
||||||
|
modifier. When you finish a long rest, you regain all expended uses.
|
||||||
|
|
||||||
|
"""
|
||||||
|
_name = "Divine Sense"
|
||||||
|
source = "Paladin"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
num_uses = max(1, 1+self.owner.charisma.modifier)
|
||||||
|
return self._name + ' ({:d}x/LR)'.format(num_uses)
|
||||||
|
|
||||||
|
|
||||||
|
class LayOnHands(Feature):
|
||||||
|
"""Your blessed touch can heal wounds. You have a pool of healing power that
|
||||||
|
replenishes when you take a long rest. With that pool, you can restore a
|
||||||
|
total number of hit points equal to your paladin level x 5.
|
||||||
|
|
||||||
|
As an action, you can touch a creature and draw power from the pool to
|
||||||
|
restore a number of hit points to that creature, up to the maximum amount
|
||||||
|
remaining in your pool.
|
||||||
|
|
||||||
|
Alternatively, you can expend 5 hit points from your pool of healing to
|
||||||
|
cure the target of one disease or neutralize one poison affecting it. You
|
||||||
|
can cure multiple diseases and neutralize multiple poisons with a single
|
||||||
|
use of Lay on Hands, expending hit points separately for each one.
|
||||||
|
|
||||||
|
This feature has no effect on undead and constructs
|
||||||
|
|
||||||
|
"""
|
||||||
|
_name = "Lay on Hands"
|
||||||
|
source = "Paladin"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
level = self.owner.Paladin.level
|
||||||
|
return self._name + " ({:d}HP/LR)".format(level*5)
|
||||||
|
|
||||||
|
|
||||||
|
class PaladinFightingStyle(FeatureSelector):
|
||||||
|
"""
|
||||||
|
Select a Fighting Style by choosing in feature_choices:
|
||||||
|
|
||||||
|
defense
|
||||||
|
|
||||||
|
dueling
|
||||||
|
|
||||||
|
great-weapon fighting
|
||||||
|
|
||||||
|
protection
|
||||||
|
"""
|
||||||
|
options = {'defense': Defense,
|
||||||
|
'dueling': Dueling,
|
||||||
|
'great': GreatWeaponFighting,
|
||||||
|
'great-weapon fighting': GreatWeaponFighting,
|
||||||
|
'projection': Protection}
|
||||||
|
name = "Fighting Style (Select One)"
|
||||||
|
source = "Paladin"
|
||||||
|
|
||||||
|
|
||||||
|
class DivineSmite(Feature):
|
||||||
|
"""Starting at 2nd level, when you hit a creature with a melee weapon attack,
|
||||||
|
you can expend one paladin spell slot to deal radiant damage to the target,
|
||||||
|
in addition to the weapon’s damage. The extra damage is 2d8 for a 1st-level
|
||||||
|
spell slot, plus 1d8 for each spell level higher than 1st, to a maximum of
|
||||||
|
5d8. The damage increases by 1d8 if the target is an undead or a fiend.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Divine Smite"
|
||||||
|
source = "Paladin"
|
||||||
|
|
||||||
|
|
||||||
|
class DivineHealth(Feature):
|
||||||
|
"""By 3rd level, the divine magic flowing through you makes you immune to
|
||||||
|
disease """
|
||||||
|
name = "Divine Health"
|
||||||
|
source = "Paladin"
|
||||||
|
|
||||||
|
|
||||||
|
class ExtraAttackPaladin(Feature):
|
||||||
|
"""Beginning at 5th level, you can attack twice, instead of once, whenever you
|
||||||
|
take the Attack action on your turn
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Extra Attack (2x)"
|
||||||
|
source = "Paladin"
|
||||||
|
|
||||||
|
|
||||||
|
class AuraOfProtection(Feature):
|
||||||
|
"""Starting at 6th level, whenever you or a friendly creature within 10 feet
|
||||||
|
of you must make a saving throw, the creature gains a bonus to the saving
|
||||||
|
throw equal to your Charisma modifier (with a minimum bonus of +1). You
|
||||||
|
must be conscious to grant this bonus.
|
||||||
|
|
||||||
|
At 18th level, the range of this aura increases to 30 feet.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Aura of Protection"
|
||||||
|
source = "Paladin"
|
||||||
|
|
||||||
|
|
||||||
|
class AuraOfCourage(Feature):
|
||||||
|
"""Starting at 10th level, you and friendly creatures within 10 feet of you
|
||||||
|
can’t be frightened while you are conscious.
|
||||||
|
|
||||||
|
At 18th level, the range of this aura increases to 30 feet
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Aura of Courage"
|
||||||
|
source = "Paladin"
|
||||||
|
|
||||||
|
|
||||||
|
class ImprovedDivineSmite(Feature):
|
||||||
|
"""By 11th level, you are so suffused with righteous might that all your melee
|
||||||
|
weapon strikes carry divine power with them. Whenever you hit a creature
|
||||||
|
with a melee weapon, the creature takes an extra 1d8 radiant damage. If you
|
||||||
|
also use your Divine Smite with an attack, you add this damage to the extra
|
||||||
|
damage of your Divine Smite.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Improved Divine Smite"
|
||||||
|
source = "Paladin"
|
||||||
|
|
||||||
|
|
||||||
|
class CleansingTouch(Feature):
|
||||||
|
"""Beginning at 14th level, you can use your action to end one spell on
|
||||||
|
yourself or on one willing creature that you touch. You can use this
|
||||||
|
feature a number of times equal to your Charisma modifier (a minimum of
|
||||||
|
once). You regain expended uses when you finish a long rest.
|
||||||
|
|
||||||
|
"""
|
||||||
|
_name = "Cleansing Touch"
|
||||||
|
source = "Paladin"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
num_uses = max(1, 1+self.owner.charisma.modifier)
|
||||||
|
return self._name + ' ({:d}x/LR)'.format(num_uses)
|
||||||
|
|
||||||
|
|
||||||
|
class ChannelDivinityPaladin(Feature):
|
||||||
|
"""Your oath allows you to channel divine energy to fuel magical effects. Each
|
||||||
|
Channel Divinity option provided by your oath explains how to use it.
|
||||||
|
|
||||||
|
When you use your Channel Divinity, you choose which option to use. You
|
||||||
|
must then finish a short or long rest to use your Channel Divinity
|
||||||
|
again.
|
||||||
|
|
||||||
|
Some Channel Divinity effects require saving throws. When you use such an
|
||||||
|
effect from this class, the DC equals your paladin spell save DC.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Channel Divinity (1x/SR)"
|
||||||
|
source = "Paladin"
|
||||||
|
|
||||||
|
|
||||||
|
# Oath of Devotion
|
||||||
|
class SacredWeapon(Feature):
|
||||||
|
"""As an action, you can imbue one weapon that you are holding with positive
|
||||||
|
energy, using your Channel Divinity. For 1 minute, you add your Charisma
|
||||||
|
modifier to attack rolls made with that weapon (with a minimum bonus of
|
||||||
|
+1). The weapon also emits bright light in a 20-foot radius and dim light
|
||||||
|
20 feet beyond that. If the weapon is not already magical, it becomes
|
||||||
|
magical for the duration.
|
||||||
|
|
||||||
|
You can end this effect on your turn as part of any other action. If you
|
||||||
|
are no longer holding or carrying this weapon, or if you fall unconscious,
|
||||||
|
this effect ends.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Channel Divinity: Sacred Weapon"
|
||||||
|
source = "Paladin (Oath of Devotion)"
|
||||||
|
|
||||||
|
|
||||||
|
class TurnTheUnholy(Feature):
|
||||||
|
"""As an action, you present your holy symbol and speak a prayer censuring
|
||||||
|
fiends and undead, using your Channel Divinity. Each fiend or undead that
|
||||||
|
can see or hear you within 30 feet of you must make a W isdom saving
|
||||||
|
throw. If the creature fails its saving throw, it is turned for 1 minute or
|
||||||
|
until it takes damage.
|
||||||
|
|
||||||
|
A turned creature must spend its turns trying to move as far away from you
|
||||||
|
as it can, and it can’t willingly move to a space within 30 feet of you. It
|
||||||
|
also can’t take reactions. For its action, it can use only the Dash action
|
||||||
|
or try to escape from an effect that prevents it from moving. If there’s
|
||||||
|
nowhere to move, the creature can use the Dodge action.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Channel Divinity: Turn the Unholy"
|
||||||
|
source = "Paladin (Oath of Devotion)"
|
||||||
|
|
||||||
|
|
||||||
|
class AuraOfDevotion(Feature):
|
||||||
|
"""Starting at 7th level, you and friendly creatures within 10 feet of you
|
||||||
|
can’t be charmed while you are conscious. At 18th level, the range of this
|
||||||
|
aura increases to 30 feet.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Aura of Devotion"
|
||||||
|
source = "Paladin (Oath of Devotion)"
|
||||||
|
|
||||||
|
|
||||||
|
class PurityOfSpirit(Feature):
|
||||||
|
"""Beginning at 15th level, you are always under the effects of a protection
|
||||||
|
from evil and good spell.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Purity of Spirit"
|
||||||
|
source = "Paladin (Oath of Devotion)"
|
||||||
|
|
||||||
|
|
||||||
|
class HolyNimbus(Feature):
|
||||||
|
"""At 20th level, as an action, you can emanate an aura of sunlight. For 1
|
||||||
|
minute, bright light shines from you in a 30-foot radius, and dim light
|
||||||
|
shines 30 feet beyond that.
|
||||||
|
|
||||||
|
Whenever an enemy creature starts its turn in the bright light, the
|
||||||
|
creature takes 10 radiant damage.
|
||||||
|
|
||||||
|
In addition, for the duration, you have advantage on saving throws against
|
||||||
|
spells cast by fiends or undead. Once you use this feature, you can’t use
|
||||||
|
it again until you finish a long rest.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Holy Nimbus"
|
||||||
|
source = "Paladin (Oath of Devotion)"
|
||||||
|
|
||||||
|
|
||||||
|
# Oath of the Ancients
|
||||||
|
# Oath of Redemption
|
||||||
|
class EmissaryOfPeace(Feature):
|
||||||
|
"""You can use your Channel Divinity to augment your presence with divine
|
||||||
|
power. As a bonus action, you grant yourself a +5 bonus to Charisma
|
||||||
|
(Persuasion) checks for the next 10 minutes.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Channel Divinity: Emissary of Peace"
|
||||||
|
source = "Paladin (Oath of Redemption)"
|
||||||
|
|
||||||
|
|
||||||
|
class RebukeTheViolent(Feature):
|
||||||
|
"""You can use your Channel Divinity to rebuke those who use
|
||||||
|
violence. Immediately after an attacker within 30 feet ofyou deals damage
|
||||||
|
with an attack against a creature other than you, you can use your reaction
|
||||||
|
to force the attacker to make a Wisdom saving throw. On a failed save, the
|
||||||
|
attacker takes radiant damage equal to the damage it just dealt. On a
|
||||||
|
successful save, it takes half as much damage.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Channel Divinity: Rebuke the Violent"
|
||||||
|
source = "Paladin (Oath of Redemption)"
|
||||||
|
|
||||||
|
|
||||||
|
class AuraOfTheGuardian(Feature):
|
||||||
|
"""Starting at 7th level, you can shield others from harm at the cost of your
|
||||||
|
own health. When a creature within 10 feet of you takes damage, you can use
|
||||||
|
your reaction to magically take that damage, instead of that creature tak—
|
||||||
|
ing it. This feature doesn't transfer any other effects that might
|
||||||
|
accompany the damage, and this damage can't be reduced in any way. At 18th
|
||||||
|
level, the range of this aura increases to 30 feet.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Aura of the Guardian"
|
||||||
|
source = "Paladin (Oath of Redemption)"
|
||||||
|
|
||||||
|
|
||||||
|
class ProtectiveSpirit(Feature):
|
||||||
|
"""Starting at 15th level, a holy presence mends your wounds in battle. You
|
||||||
|
regain hit points equal to 1d6 + half your paladin level if you end your
|
||||||
|
turn in combat with fewer than half of your hit points remaining and you
|
||||||
|
aren't incapacitated.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Protective Spirit"
|
||||||
|
source = "Paladin (Oath of Redemption)"
|
||||||
|
|
||||||
|
|
||||||
|
class EmissaryOfRedemption(Feature):
|
||||||
|
"""At 20th level, you become an avatar of peace, which gives you two benefits:
|
||||||
|
|
||||||
|
--You have resistance to all damage dealt by other crea— tures (their
|
||||||
|
attacks, spells, and other effects).
|
||||||
|
|
||||||
|
--Whenever a creature hits you with an attack, it takes radiant damage
|
||||||
|
equal to half the damage you take from the attack.
|
||||||
|
|
||||||
|
If you attack a creature, cast a spell on it, or deal dam- age to it by any
|
||||||
|
means but this feature, neither benefit works against that creature until
|
||||||
|
you finish a long rest
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Emissary of Redemption"
|
||||||
|
source = "Paladin (Oath of Redemption)"
|
||||||
|
|||||||
@@ -2,24 +2,10 @@ from .features import Feature, FeatureSelector
|
|||||||
from .. import (weapons, armor)
|
from .. import (weapons, armor)
|
||||||
|
|
||||||
|
|
||||||
def select_ranger_fighting_style(char=None, feature_choices=[]):
|
|
||||||
lower_choices = [fc for fc in map(str.lower, feature_choices)]
|
|
||||||
if 'archery' in lower_choices:
|
|
||||||
return Archery(owner=char)
|
|
||||||
elif 'defense' in lower_choices:
|
|
||||||
return Defense(owner=char)
|
|
||||||
elif 'dueling' in lower_choices:
|
|
||||||
return Dueling(owner=char)
|
|
||||||
elif 'two-weapon fighting' in lower_choices:
|
|
||||||
return TwoWeaponFighting(owner=char)
|
|
||||||
else:
|
|
||||||
return RangerFightingStyle(owner=char)
|
|
||||||
|
|
||||||
|
|
||||||
class Archery(Feature):
|
class Archery(Feature):
|
||||||
"""
|
"""
|
||||||
You gain a +2 bonus to attack rolls you make
|
You gain a +2 bonus to attack rolls you make
|
||||||
with ranged weapons.
|
with ranged weapons (included in stats on Character Sheet).
|
||||||
"""
|
"""
|
||||||
name = "Fighting Style (Archery)"
|
name = "Fighting Style (Archery)"
|
||||||
source = "Ranger"
|
source = "Ranger"
|
||||||
@@ -28,14 +14,15 @@ class Archery(Feature):
|
|||||||
"""
|
"""
|
||||||
+2 attack roll bonus if weapon is ranged
|
+2 attack roll bonus if weapon is ranged
|
||||||
"""
|
"""
|
||||||
if weapon.is_ranged:
|
if isinstance(weapon, weapons.RangedWeapon):
|
||||||
weapon.attack_bonus += 2
|
weapon.attack_bonus += 2
|
||||||
return weapon
|
return weapon
|
||||||
|
|
||||||
|
|
||||||
class Defense(Feature):
|
class Defense(Feature):
|
||||||
"""
|
"""
|
||||||
While you are wearing armor, you gain a +1 bonus to AC.
|
While you are wearing armor, you gain a +1 bonus to AC (included in
|
||||||
|
stats on Character Sheet).
|
||||||
"""
|
"""
|
||||||
name = "Fighting Style (Defense)"
|
name = "Fighting Style (Defense)"
|
||||||
source = "Ranger"
|
source = "Ranger"
|
||||||
@@ -48,7 +35,15 @@ class Dueling(Feature):
|
|||||||
"""
|
"""
|
||||||
name = "Fighting Style (Dueling)"
|
name = "Fighting Style (Dueling)"
|
||||||
source = "Ranger"
|
source = "Ranger"
|
||||||
needs_implementation = True
|
|
||||||
|
def weapon_func(self, weapon: weapons.Weapon, **kwargs):
|
||||||
|
"""
|
||||||
|
+2 attack roll bonus if melee weapon is not two handed
|
||||||
|
"""
|
||||||
|
if (isinstance(weapon, weapons.MeleeWeapon)
|
||||||
|
and "two-handed" in weapon.properties.lower()):
|
||||||
|
weapon.attack_bonus += 2
|
||||||
|
return weapon
|
||||||
|
|
||||||
|
|
||||||
class TwoWeaponFighting(Feature):
|
class TwoWeaponFighting(Feature):
|
||||||
@@ -58,7 +53,6 @@ class TwoWeaponFighting(Feature):
|
|||||||
"""
|
"""
|
||||||
name = "Fighting Style (Two-Weapon Fighting)"
|
name = "Fighting Style (Two-Weapon Fighting)"
|
||||||
source = "Ranger"
|
source = "Ranger"
|
||||||
needs_implementation = True
|
|
||||||
|
|
||||||
|
|
||||||
class RangerFightingStyle(FeatureSelector):
|
class RangerFightingStyle(FeatureSelector):
|
||||||
@@ -81,3 +75,271 @@ class RangerFightingStyle(FeatureSelector):
|
|||||||
'dual wield': TwoWeaponFighting}
|
'dual wield': TwoWeaponFighting}
|
||||||
name = "Fighting Style (Select One)"
|
name = "Fighting Style (Select One)"
|
||||||
source = "Ranger"
|
source = "Ranger"
|
||||||
|
|
||||||
|
|
||||||
|
# Revised Ranger
|
||||||
|
class FavoredEnemyRevised(Feature):
|
||||||
|
"""Beginning at 1st level, you have significant experience studying, tracking,
|
||||||
|
hunting, and even talking to a certain type of enemy commonly encountered
|
||||||
|
in the wilds.
|
||||||
|
|
||||||
|
Choose a type of favored enemy: beasts, fey, humanoids, monstrosities, or
|
||||||
|
undead. You gain a +2 bonus to damage rolls with weapon attacks against
|
||||||
|
creatures of the chosen type. Additionally, you have advantage on Wisdom
|
||||||
|
(Survival) checks to track your favored enemies, as well as on Intelligence
|
||||||
|
checks to recall information about them.
|
||||||
|
|
||||||
|
When you gain this feature, you also learn one language of your choice,
|
||||||
|
typically one spoken by your favored enemy or creatures associated with
|
||||||
|
it. However, you are free to pick any language you wish to learn
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Favored Enemy"
|
||||||
|
source = "Revised Ranger"
|
||||||
|
|
||||||
|
|
||||||
|
class NaturalExplorerRevised(Feature):
|
||||||
|
"""You are a master of navigating the natural world, and you react with swift
|
||||||
|
and decisive action when attacked. This grants you the following benefits:
|
||||||
|
|
||||||
|
--You ignore difficult terrain.
|
||||||
|
|
||||||
|
--You have advantage on initiative rolls.
|
||||||
|
|
||||||
|
--On your first turn during combat, you have advantage on attack rolls
|
||||||
|
against creatures that have not yet acted.
|
||||||
|
|
||||||
|
In addition, you are skilled at navigating the wilderness. You gain the
|
||||||
|
following benefits when traveling for an hour or more:
|
||||||
|
|
||||||
|
--Difficult terrain doesn’t slow your group’s travel.
|
||||||
|
|
||||||
|
--Your group can’t become lost except by magical means.
|
||||||
|
|
||||||
|
--Even when you are engaged in another activity while traveling (such as
|
||||||
|
foraging, navigating, or tracking), you remain alert to danger.
|
||||||
|
|
||||||
|
--If you are traveling alone, you can move stealthily at a normal pace.
|
||||||
|
|
||||||
|
--When you forage, you find twice as much food as you normally would.
|
||||||
|
|
||||||
|
--While tracking other creatures, you also learn their exact number, their
|
||||||
|
sizes, and how long ago they passed through the area.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Natural Explorer"
|
||||||
|
source = "Revised Ranger"
|
||||||
|
|
||||||
|
|
||||||
|
class PrimevalAwarenessRevised(Feature):
|
||||||
|
"""Beginning at 3rd level, your mastery of ranger lore allows you to establish
|
||||||
|
a powerful link to beasts and to the land around you.
|
||||||
|
|
||||||
|
You have an innate ability to communicate with beasts, and they recognize
|
||||||
|
you as a kindred spirit. Through sounds and gestures, you can communicate
|
||||||
|
simple ideas to a beast as an action, and can read its basic mood and
|
||||||
|
intent. You learn its emotional state, whether it is affected by magic of
|
||||||
|
any sort, its short-term needs (such as food or safety), and actions you
|
||||||
|
can take (if any) to persuade it to not attack.
|
||||||
|
|
||||||
|
You cannot use this ability against a creature that you have attacked
|
||||||
|
within the past 10 minutes.
|
||||||
|
|
||||||
|
Additionally, you can attune your senses to determine if any of your
|
||||||
|
favored enemies lurk nearby. By spending 1 uninterrupted minute in
|
||||||
|
concentration (as if you were concentrating on a spell), you can sense
|
||||||
|
whether any of your favored enemies are present within 5 miles of you. This
|
||||||
|
feature reveals which of your favored enemies are present, their numbers,
|
||||||
|
and the creatures’ general direction and distance (in miles) from you.
|
||||||
|
|
||||||
|
If there are multiple groups of your favored enemies within range, you
|
||||||
|
learn this information for each group.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Primeval Awareness"
|
||||||
|
source = "Revised Ranger"
|
||||||
|
|
||||||
|
|
||||||
|
class GreaterFavoredEnemy(Feature):
|
||||||
|
"""At 6th level, you are ready to hunt even deadlier game. Choose a type of
|
||||||
|
greater favored enemy: aberrations, celestials, constructs, dragons,
|
||||||
|
elementals, fiends, or giants. You gain all the benefits against this
|
||||||
|
chosen enemy that you normally gain against your favored enemy, including
|
||||||
|
an additional language. Your bonus to damage rolls against all your favored
|
||||||
|
enemies increases to +4.
|
||||||
|
|
||||||
|
Additionally, you have advantage on saving throws against the spells and
|
||||||
|
abilities used by a greater favored enemy.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Greated Favored Enemy"
|
||||||
|
source = "Revised Ranger"
|
||||||
|
|
||||||
|
|
||||||
|
class FleetOfFoot(Feature):
|
||||||
|
"""Beginning at 8th level, you can use the Dash action as a bonus action on
|
||||||
|
your turn.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Fleet of Foot"
|
||||||
|
source = "Revised Ranger"
|
||||||
|
|
||||||
|
|
||||||
|
class HideInPlainSight(Feature):
|
||||||
|
"""Starting at 10th level, you can remain perfectly still for long periods of
|
||||||
|
time to set up ambushes.
|
||||||
|
|
||||||
|
When you attempt to hide on your turn, you can opt to not move on that
|
||||||
|
turn. If you avoid moving, creatures that attempt to detect you take a −10
|
||||||
|
penalty to their Wisdom (Perception) checks until the start of your next
|
||||||
|
turn. You lose this benefit if you move or fall prone, either 4 voluntarily
|
||||||
|
or because of some external effect. You are still automatically detected if
|
||||||
|
any effect or action causes you to no longer be hidden.
|
||||||
|
|
||||||
|
If you are still hidden on your next turn, you can continue to remain
|
||||||
|
motionless and gain this benefit until you are detected
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Hide in Plain Sight"
|
||||||
|
source = "Revised Ranger"
|
||||||
|
|
||||||
|
|
||||||
|
class Vanish(Feature):
|
||||||
|
"""Starting at 14th level, you can use the Hide action as a bonus action on
|
||||||
|
your turn. Also, you can’t be tracked by nonmagical means, unless you
|
||||||
|
choose to leave a trail
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Vanish"
|
||||||
|
source = "Revised Ranger"
|
||||||
|
|
||||||
|
|
||||||
|
class FeralSenses(Feature):
|
||||||
|
"""At 18th level, you gain preternatural senses that help you fight creatures
|
||||||
|
you can’t see. When you attack a creature you can’t see, your inability to
|
||||||
|
see it doesn’t impose disadvantage on your attack rolls against it.
|
||||||
|
|
||||||
|
You are also aware of the location of any invisible creature within 30 feet
|
||||||
|
of you, provided that the creature isn’t hidden from you and you aren’t
|
||||||
|
blinded or deafened
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Feral Senses"
|
||||||
|
source = "Revised Ranger"
|
||||||
|
|
||||||
|
|
||||||
|
class FoeSlayer(Feature):
|
||||||
|
"""At 20th level, you become an unparalleled hunter. Once on each of your
|
||||||
|
turns, you can add your Wisdom modifier to the attack roll or the damage
|
||||||
|
roll of an attack you make. You can choose to use this feature before or
|
||||||
|
after the roll, but before any effects of the roll are applied
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Foe Slayer"
|
||||||
|
source = "Revised Ranger"
|
||||||
|
|
||||||
|
|
||||||
|
class AnimalCompanion(Feature):
|
||||||
|
"""At 3rd level, you learn to use your magic to create a powerful bond with a
|
||||||
|
creature of the natural world.
|
||||||
|
|
||||||
|
With 8 hours of work and the expenditure of 50 gp worth of rare herbs and
|
||||||
|
fine food, you call forth an animal from the wilderness to serve as your
|
||||||
|
faithful companion. You normally select you companion from among the
|
||||||
|
following animals: an ape, a black bear, a boar, a giant badger, a giant
|
||||||
|
weasel, a mule, a panther, or a wolf. However, your DM might pick one of
|
||||||
|
these animals for you, based on the surrounding terrain and on what types
|
||||||
|
of creatures would logically be present in the area.
|
||||||
|
|
||||||
|
At the end of the 8 hours, your animal companion appears and gains all the
|
||||||
|
benefits of your Companion’s Bond ability. You can have only one animal
|
||||||
|
companion at a time.
|
||||||
|
|
||||||
|
If your animal companion is ever slain, the magical bond you share allows
|
||||||
|
you to return it to life. With 8 hours of work and the expenditure of 25 gp
|
||||||
|
worth of rare herbs and fine food, you call forth your companion’s spirit
|
||||||
|
and use your magic to create a new body for it. You can return an animal
|
||||||
|
companion to life in this manner even if you do not possess any part of its
|
||||||
|
body.
|
||||||
|
|
||||||
|
If you use this ability to return a former animal companion to life while
|
||||||
|
you have a current animal companion, your current companion leaves you and
|
||||||
|
is replaced by the restored companion
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Animal Companion"
|
||||||
|
source = "Revised Ranger (Animal Companion)"
|
||||||
|
|
||||||
|
|
||||||
|
class CompanionsBond(Feature):
|
||||||
|
"""Your animal companion gains a variety of benefits while it is linked to
|
||||||
|
you. The animal companion loses its Multiattack action, if it has one.
|
||||||
|
|
||||||
|
The companion obeys your commands as best it can. It rolls for initiative
|
||||||
|
like any other creature, but you determine its actions, decisions,
|
||||||
|
attitudes, and so on. If you are incapacitated or absent, your companion
|
||||||
|
acts on its own. When using your Natural Explorer feature, you and your
|
||||||
|
animal companion can both move stealthily at a normal pace.
|
||||||
|
|
||||||
|
Your animal companion has abilities and game statistics determined in part
|
||||||
|
by your level. Your companion uses your proficiency bonus rather than its
|
||||||
|
own. In addition to the areas where it normally uses its proficiency bonus,
|
||||||
|
an animal companion also adds its proficiency bonus to its AC and to its
|
||||||
|
damage rolls.
|
||||||
|
|
||||||
|
Your animal companion gains proficiency in two skills of your choice. It
|
||||||
|
also becomes proficient with all saving throws. For each level you gain
|
||||||
|
after 3rd, your animal companion gains an additional hit die and increases
|
||||||
|
its hit points accordingly. Whenever you gain the Ability Score Improvement
|
||||||
|
class feature, your companion’s abilities also improve. Your companion can
|
||||||
|
increase one ability score of your choice by 2, or it can increase two
|
||||||
|
ability scores of your choice by 1. As normal, your companion can’t
|
||||||
|
increase an ability score above 20 using this feature unless its
|
||||||
|
description specifies otherwise.
|
||||||
|
|
||||||
|
Your companion shares your alignment, and has a personality trait and a
|
||||||
|
flaw that you can roll for or select from the tables below. Your companion
|
||||||
|
shares your ideal, and its bond is always, \“The ranger who travels with me
|
||||||
|
is a beloved companion for whom I would gladly give my life.\”
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Companions Bond"
|
||||||
|
source = "Revised Ranger (Beast Conclave)"
|
||||||
|
|
||||||
|
|
||||||
|
class CoordinatedAttack(Feature):
|
||||||
|
"""Beginning at 5th level, you and your animal companion form a more potent
|
||||||
|
fighting team. When you use the Attack action on your turn, if your
|
||||||
|
companion can see you, it can use its reaction to make a melee attack.
|
||||||
|
"""
|
||||||
|
name = "Coordinated Attack"
|
||||||
|
source = "Revised Ranger (Beast Conclave)"
|
||||||
|
|
||||||
|
|
||||||
|
class BeastsDefense(Feature):
|
||||||
|
"""At 7th level, while your companion can see you, it has advantage on all
|
||||||
|
saving throw
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Beast's Defense"
|
||||||
|
source = "Revised Ranger (Beast Conclave)"
|
||||||
|
|
||||||
|
|
||||||
|
class StormOfClawsAndFangs(Feature):
|
||||||
|
"""At 11th level, your companion can use its action to make a melee attack
|
||||||
|
against each creature of its choice within 5 feet of it, with a separate
|
||||||
|
attack roll for each target
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Storm of Claws and Fangs"
|
||||||
|
source = "Revised Ranger (Beast Conclave)"
|
||||||
|
|
||||||
|
|
||||||
|
class SuperiorBeastsDefense(Feature):
|
||||||
|
"""At 15th level, whenever an attacker that your companion can see hits it
|
||||||
|
with an attack, it can use its reaction to halve the attack’s damage
|
||||||
|
against it.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Superior Beast's Defense"
|
||||||
|
source = "Revised Ranger (Beast Conclave)"
|
||||||
|
|||||||
@@ -0,0 +1,126 @@
|
|||||||
|
from .features import Feature
|
||||||
|
from math import ceil
|
||||||
|
|
||||||
|
|
||||||
|
# PHB
|
||||||
|
class Expertise(Feature):
|
||||||
|
"""At 1st level, choose two of your skill proficiencies, or one of your skill
|
||||||
|
proficiencies and your proficiency with thieves’ tools. Your proficiency
|
||||||
|
bonus is doubled for any ability check you make that uses either of the
|
||||||
|
chosen proficiencies.
|
||||||
|
|
||||||
|
At 6th level, you can choose two more of your
|
||||||
|
proficiencies (in skills or with thieves’ tools) to gain this benefit.
|
||||||
|
|
||||||
|
Add these skills to "skill_expertise" in your character.py file
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Expertise"
|
||||||
|
source = "Rogue"
|
||||||
|
|
||||||
|
|
||||||
|
class SneakAttack(Feature):
|
||||||
|
"""Beginning at 1st level, you know how to strike subtly and exploit a foe’s
|
||||||
|
distraction. Once per turn, you can deal an extra 1d6 damage to one
|
||||||
|
creature you hit with an attack if you have advantage on the attack
|
||||||
|
roll. The attack must use a finesse or a ranged weapon.
|
||||||
|
|
||||||
|
You don’t need advantage on the attack roll if another enemy of the target
|
||||||
|
is within 5 feet of it, that enemy isn’t incapacitated, and you don’t have
|
||||||
|
disadvantage on the attack roll.
|
||||||
|
|
||||||
|
The amount of the extra damage increases as you gain levels in this class,
|
||||||
|
as shown in the Sneak Attack column of the Rogue table.
|
||||||
|
"""
|
||||||
|
_name = "Sneak Attack"
|
||||||
|
source = "Rogue"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
level = self.owner.Rogue.level
|
||||||
|
dice = ceil(level / 2.)
|
||||||
|
name = self._name + " ({:d}d6)".format(dice)
|
||||||
|
return name
|
||||||
|
|
||||||
|
|
||||||
|
class CunningAction(Feature):
|
||||||
|
"""Starting at 2nd level, your quick thinking and agility allow you to move
|
||||||
|
and act quickly. You can take a bonus action on each of your turns in
|
||||||
|
combat. This action can be used only to take the Dash, Disengage, or Hide
|
||||||
|
action.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Cunning Action"
|
||||||
|
source = "Rogue"
|
||||||
|
|
||||||
|
|
||||||
|
class UncannyDodge(Feature):
|
||||||
|
"""Starting at 5th level, when an attacker that you can see hits you with an
|
||||||
|
attack, you can use your reaction to halve the attack’s damage against you.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Uncanny Dodge"
|
||||||
|
source = "Rogue"
|
||||||
|
|
||||||
|
|
||||||
|
class Evasion(Feature):
|
||||||
|
"""Beginning at 7th level, you can nimbly dodge out o f the way of certain
|
||||||
|
area effects, such as a red dragon’s fiery breath or an ice storm
|
||||||
|
spell. When you are subjected to an effect that allows you to make a
|
||||||
|
Dexterity saving throw to take only half damage, you instead take no damage
|
||||||
|
if you succeed on the saving throw, and only half damage if you fail.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Evasion"
|
||||||
|
source = "Rogue"
|
||||||
|
|
||||||
|
|
||||||
|
class ReliableTalent(Feature):
|
||||||
|
"""By 11th level, you have refined your chosen skills until they approach
|
||||||
|
perfection. Whenever you make an ability check that lets you add your
|
||||||
|
proficiency bonus, you can treat a d20 roll of 9 or lower as a 10.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Reliable Talent"
|
||||||
|
source = "Rogue"
|
||||||
|
|
||||||
|
|
||||||
|
class BlindSense(Feature):
|
||||||
|
"""Starting at 14th level, if you are able to hear, you are aware of the
|
||||||
|
location of any hidden or invisible creature within 10 feet of you.
|
||||||
|
"""
|
||||||
|
name = "Blind Sense"
|
||||||
|
source = "Rogue"
|
||||||
|
|
||||||
|
|
||||||
|
class SlipperyMind(Feature):
|
||||||
|
"""By 15th level, you have acquired greater mental strength. You gain
|
||||||
|
proficiency in W isdom saving throws.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = 'Slippery Mind'
|
||||||
|
source = "Rogue"
|
||||||
|
|
||||||
|
|
||||||
|
class Elusive(Feature):
|
||||||
|
"""Beginning at 18th level, you are so evasive that attackers rarely gain the
|
||||||
|
upper hand against you. No attack roll has advantage against you while you
|
||||||
|
aren’t incapacitated.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Elusive"
|
||||||
|
source = "Rogue"
|
||||||
|
|
||||||
|
|
||||||
|
class StrokeOfLuck(Feature):
|
||||||
|
"""At 20th level, you have an uncanny knack for succeeding when you need
|
||||||
|
to. If your attack m isses a target within range, you can turn the miss
|
||||||
|
into a hit. Alternatively, if you fail an ability check, you can treat the
|
||||||
|
d20 roll as a 20.
|
||||||
|
|
||||||
|
Once you use this feature, you can’t use it again until you finish a short
|
||||||
|
or long rest.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Stroke of Luck"
|
||||||
|
source = "Rogue"
|
||||||
|
|||||||
@@ -1,6 +1,199 @@
|
|||||||
from .features import Feature
|
from .features import Feature
|
||||||
|
|
||||||
|
|
||||||
|
# PHB
|
||||||
|
class FontOfMagic(Feature):
|
||||||
|
"""At 2nd level, you tap into a deep wellspring of magic within yourself. This
|
||||||
|
wellspring is represented by sorcery points, which allow you to create a
|
||||||
|
variety of magical effects.
|
||||||
|
|
||||||
|
**Sorcery Points**: You have sorcery points equal to your Sorceror
|
||||||
|
Level. You can never have more sorcery points than shown on the table for
|
||||||
|
your level. You regain all spent sorcery points when you finish a long
|
||||||
|
rest.
|
||||||
|
|
||||||
|
**Flexible Casting**: You can use your sorcery points to gain additional
|
||||||
|
spell slots, or sacrifice spell slots to gain additional sorcery
|
||||||
|
points. You learn other ways to use your sorcery points as you reach higher
|
||||||
|
levels. You can transform unexpended sorcery points into one spell slot as
|
||||||
|
a bonus action on your turn. The Creating Spell Slots table shows the cost
|
||||||
|
of creating a spell slot of a given level. You can create spell slots no
|
||||||
|
higher in level than 5th. As a bonus action on your turn, you can expend
|
||||||
|
one spell slot and gain a number of sorcery points equal to the slot’s
|
||||||
|
level.
|
||||||
|
|
||||||
|
1st Level Slot <--> 2 sorcery points
|
||||||
|
|
||||||
|
2nd Level Slot <--> 3 sorcery points
|
||||||
|
|
||||||
|
3rd Level Slot <--> 5 sorcery points
|
||||||
|
|
||||||
|
4th Level Slot <--> 6 sorcery points
|
||||||
|
|
||||||
|
5th Level Slot <--> 7 sorcery points
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Font of Magic"
|
||||||
|
source = "Sorceror"
|
||||||
|
|
||||||
|
|
||||||
|
class Metamagic(Feature):
|
||||||
|
"""At 3rd level, you gain the ability to twist your spells to suit your
|
||||||
|
needs. You gain two of the following Metamagic options of your choice. You
|
||||||
|
gain another one at 10th and 17th level. You can use only one Metamagic
|
||||||
|
option on a spell when you cast it, unless otherwise noted
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Metamagic"
|
||||||
|
source = "Sorceror (Metamagic)"
|
||||||
|
|
||||||
|
|
||||||
|
class SorcerousRestoration(Feature):
|
||||||
|
"""At 20th level, you regain 4 expended sorcery points whenever you finish a
|
||||||
|
short rest.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
# Metamagic
|
||||||
|
class CarefulSpell(Metamagic):
|
||||||
|
"""When you cast a spell that forces other creatures to make a saving throw,
|
||||||
|
you can protect some of those creatures from the spell’s full force. To do
|
||||||
|
so, you spend 1 sorcery point and choose a number o f those creatures up to
|
||||||
|
your Charisma modifier (minimum of one creature). A chosen creature
|
||||||
|
automatically succeeds on its saving throw against the spell.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Careful Spell"
|
||||||
|
|
||||||
|
|
||||||
|
class DistantSpell(Metamagic):
|
||||||
|
"""When you cast a spell that has a range of 5 feet or greater, you can spend
|
||||||
|
1 sorcery point to double the range of the spell. When you cast a spell
|
||||||
|
that has a range of touch, you can spend 1 sorcery point to make the range
|
||||||
|
of the spell 30 feet
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Distant Spell"
|
||||||
|
|
||||||
|
|
||||||
|
class EmpoweredSpell(Metamagic):
|
||||||
|
"""When you roll damage for a spell, you can spend 1 sorcery point to reroll a
|
||||||
|
number of the damage dice up to your Charisma modifier (minimum of
|
||||||
|
one). You must use the new rolls. You can use Empowered Spell even if you
|
||||||
|
have already used a different Metamagic option during the casting of the
|
||||||
|
spell.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Empowered Spell"
|
||||||
|
|
||||||
|
|
||||||
|
class ExtendedSpell(Metamagic):
|
||||||
|
"""When you cast a spell that has a duration of 1 minute or longer, you can
|
||||||
|
spend 1 sorcery point to double its duration, to a maximum duration of 24
|
||||||
|
hours.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Extended Spell"
|
||||||
|
|
||||||
|
|
||||||
|
class HeightenedSpell(Metamagic):
|
||||||
|
"""When you cast a spell that forces a creature to make a saving throw to
|
||||||
|
resist its effects, you can spend 3 sorcery points to give one target of
|
||||||
|
the spell disadvantage on its first saving throw made against the spell
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Heightened Spell"
|
||||||
|
|
||||||
|
|
||||||
|
class QuickenedSpell(Metamagic):
|
||||||
|
"""When you cast a spell that has a casting time of 1 action, you can spend 2
|
||||||
|
sorcery points to change the casting time to 1 bonus action for this
|
||||||
|
casting.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Quickened Spell"
|
||||||
|
|
||||||
|
|
||||||
|
class SubtleSpell(Metamagic):
|
||||||
|
"""When you cast a spell, you can spend 1 sorcery point to cast it without any
|
||||||
|
somatic or verbal components.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Subtle Spell"
|
||||||
|
|
||||||
|
|
||||||
|
class TwinnedSpell(Metamagic):
|
||||||
|
"""When you cast a spell that targets only one creature and doesn’t have a
|
||||||
|
range of self, you can spend a number of sorcery points equal to the
|
||||||
|
spell’s level to target a second creature in range with the same spell (1
|
||||||
|
sorcery point if the spell is a cantrip)
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Twinned Spell"
|
||||||
|
|
||||||
|
|
||||||
|
# Wild Magic
|
||||||
|
class WildMagicSurge(Feature):
|
||||||
|
"""Starting when you choose this origin at 1st level, your spellcasting can
|
||||||
|
unleash surges of untamed magic. Immediately after you cast a sorcerer
|
||||||
|
spell of 1st level or higher, the DM can have you roll a d20. If you roll a
|
||||||
|
1, roll on the Wild Magic Surge table to create a random magical effect.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Wild Magic Surge"
|
||||||
|
source = "Sorceror (Wild Magic)"
|
||||||
|
|
||||||
|
|
||||||
|
class TidesOfChaos(Feature):
|
||||||
|
"""Starting at 1st level, you can manipulate the forces of chance and chaos to
|
||||||
|
gain advantage on one attack roll, ability check, or saving throw. Once you
|
||||||
|
do so, you must finish a long rest before you can use this feature again.
|
||||||
|
|
||||||
|
Any time before you regain the use of this feature, the DM can have you
|
||||||
|
roll on the Wild Magic Surge table immediately after you cast a sorcerer
|
||||||
|
spell of 1st level or higher. You then regain the use of this feature.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Tides of Chaos"
|
||||||
|
source = "Sorceror (Wild Magic)"
|
||||||
|
|
||||||
|
|
||||||
|
class BendLuck(Feature):
|
||||||
|
"""Starting at 6th level, you have the ability to twist fate using your wild
|
||||||
|
magic. When another creature you can see makes an attack roll, an ability
|
||||||
|
check, or a saving throw, you can use your reaction and spend 2 sorcery
|
||||||
|
points to roll 1d4 and apply the number rolled as a bonus or penalty (your
|
||||||
|
choice) to the creature’s roll. You can do so after the creature rolls but
|
||||||
|
before any effects of the roll occur.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = 'Bend Luck'
|
||||||
|
source = 'Sorceror (Wild Magic)'
|
||||||
|
|
||||||
|
|
||||||
|
class ControlledChaos(Feature):
|
||||||
|
"""At 14th level, you gain a modicum of control over the surges of your wild
|
||||||
|
magic. Whenever you roll on the Wild Magic Surge table, you can roll twice
|
||||||
|
and use either number.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = 'Controlled Chaos'
|
||||||
|
source = "Sorceror (Wild Magic)"
|
||||||
|
|
||||||
|
|
||||||
|
class SpellBombardment(Feature):
|
||||||
|
"""Beginning at 18th level, the harmful energy of your spells
|
||||||
|
intensifies. When you roll damage for a spell and roll the highest number
|
||||||
|
possible on any of the dice, choose one of those dice, roll it again and
|
||||||
|
add that roll to the damage. You can use the feature only once per turn.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Spell Bombardment"
|
||||||
|
source = "Sorceror (Wild Magic)"
|
||||||
|
|
||||||
|
|
||||||
|
# Draconic Ancestry
|
||||||
class DraconicResilience(Feature):
|
class DraconicResilience(Feature):
|
||||||
"""As magic flows through your body, it causes physical traits of your dragon
|
"""As magic flows through your body, it causes physical traits of your dragon
|
||||||
ancestors to emerge. At 1st level, your hit point maximum increases by 1
|
ancestors to emerge. At 1st level, your hit point maximum increases by 1
|
||||||
|
|||||||
@@ -1,7 +1,291 @@
|
|||||||
from .features import Feature
|
from .features import (Feature, FeatureSelector)
|
||||||
from .. import spells
|
from .. import spells, weapons
|
||||||
|
|
||||||
|
|
||||||
|
# Features
|
||||||
|
class EldritchInvocation(Feature):
|
||||||
|
"""In your study of occult lore, you have unearthed eldritch invocations,
|
||||||
|
fragments of forbidden knowledge that imbue you with an abiding magical
|
||||||
|
ability.
|
||||||
|
|
||||||
|
At 2nd level, you gain two eldritch invocations of your choice. Your
|
||||||
|
invocation options are detailed at the end of the class description. When
|
||||||
|
you gain certain warlock levels, you gain additional invocations of your
|
||||||
|
choice, as shown in the Invocations Known column of the Warlock table.
|
||||||
|
|
||||||
|
Additionally, when you gain a level in this class, you can choose one of
|
||||||
|
the invocations you know and replace it with another invocation that you
|
||||||
|
could learn at that level.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Eldritch Invocations"
|
||||||
|
source = "Warlock"
|
||||||
|
|
||||||
|
|
||||||
|
class PactOfTheChain(Feature):
|
||||||
|
"""You learn the find familiar spell and can cast it as a ritual. The spell
|
||||||
|
doesn’t count against your number of spells known.
|
||||||
|
|
||||||
|
When you cast the spell, you can choose one of the normal forms for your
|
||||||
|
familiar or one of the following special forms: imp, pseudodragon, quasit,
|
||||||
|
or sprite. Additionally, when you take the Attack action, you can forgo one
|
||||||
|
of your own attacks to allow your familiar to make one attack of its own.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Pact of the Chain"
|
||||||
|
source = "Warlock"
|
||||||
|
spells_known = spells_prepared = (spells.FindFamiliar,)
|
||||||
|
|
||||||
|
|
||||||
|
class PactOfTheBlade(Feature):
|
||||||
|
"""You can use your action to create a pact weapon in your empty hand. You can
|
||||||
|
choose the form that this melee weapon takes each time you create it (see
|
||||||
|
chapter 5 for weapon options). You are proficient with it while you wield
|
||||||
|
it. This weapon counts as magical for the purpose o f overcoming resistance
|
||||||
|
and immunity to nonmagical attacks and damage.
|
||||||
|
|
||||||
|
Your pact weapon disappears if it is more than 5 feet away from you for 1
|
||||||
|
minute or more. It also disappears if you use this feature again, if you
|
||||||
|
dismiss the weapon (no action required), or if you die.
|
||||||
|
|
||||||
|
You can transform one magic weapon into your pact weapon by performing a
|
||||||
|
special ritual while you hold the weapon. You perform the ritual over the
|
||||||
|
course of 1 hour, which can be done during a short rest. You can then
|
||||||
|
dismiss the weapon, shunting it into an extradimensional space, and it
|
||||||
|
appears whenever you create your pact weapon thereafter. You can’t affect
|
||||||
|
an artifact or a sentient weapon in this way. The weapon ceases being your
|
||||||
|
pact weapon if you die, if you perform the 1-hour ritual on a different
|
||||||
|
weapon, or if you use a 1-hour ritual to break your bond to it. The weapon
|
||||||
|
appears at your feet if it is in the extradimensional space when the bond
|
||||||
|
breaks.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Pact of the Blade"
|
||||||
|
source = "Warlock"
|
||||||
|
|
||||||
|
|
||||||
|
class PactOfTheTome(Feature):
|
||||||
|
"""Your patron gives you a grimoire called a Book of Shadows. When you gain
|
||||||
|
this feature, choose three cantrips from any class’s spell list. While the
|
||||||
|
book is on your person, you can cast those cantrips at will. They don’t
|
||||||
|
count against your number of cantrips known.
|
||||||
|
|
||||||
|
If you lose your Book of Shadows, you can perform a 1-hour ceremony to
|
||||||
|
receive a replacement from your patron. This ceremony can be performed
|
||||||
|
during a short or long rest, and it destroys the previous book. The book
|
||||||
|
turns to ash when you die.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Pact of the Tome"
|
||||||
|
source = "Warlock"
|
||||||
|
|
||||||
|
|
||||||
|
class PactBoon(FeatureSelector):
|
||||||
|
"""Select a Pact Boon by choosing in feature_choices:
|
||||||
|
|
||||||
|
pact of the chain
|
||||||
|
|
||||||
|
pact of the blade
|
||||||
|
|
||||||
|
pact of the tome
|
||||||
|
|
||||||
|
"""
|
||||||
|
options = {'chain': PactOfTheChain,
|
||||||
|
'pact of the chain': PactOfTheChain,
|
||||||
|
'blade': PactOfTheBlade,
|
||||||
|
'pact of the blade': PactOfTheBlade,
|
||||||
|
'tome': PactOfTheTome,
|
||||||
|
'pact of the tome': PactOfTheTome}
|
||||||
|
name = "Pact Boon (Select One)"
|
||||||
|
source = "Warlock"
|
||||||
|
|
||||||
|
|
||||||
|
class MysticArcanum(Feature):
|
||||||
|
"""At 11th level, your patron bestows upon you a magical secret called an
|
||||||
|
arcanum. Choose one 6th-level spell from the warlock spell list as this
|
||||||
|
arcanum.
|
||||||
|
|
||||||
|
You can cast your arcanum spell once without expending a spell slot. You
|
||||||
|
must finish a long rest before you can do so again.
|
||||||
|
|
||||||
|
At higher levels, you gain more warlock spells of your choice that can be
|
||||||
|
cast in this way: one 7th-level spell at 13th level, one 8th-level spell at
|
||||||
|
15th level, and one 9th-level spell at 17th level. You regain all uses of
|
||||||
|
your Mystic Arcanum when you finish a long rest.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Mystic Arcanum"
|
||||||
|
source = "Warlock"
|
||||||
|
|
||||||
|
|
||||||
|
class EldritchMaster(Feature):
|
||||||
|
"""At 20th level, you can draw on your inner reserve of mystical power while
|
||||||
|
entreating your patron to regain expended spell slots. You can spend 1
|
||||||
|
minute entreating your patron for aid to regain all your expended spell
|
||||||
|
slots from your Pact Magic feature. Once you regain spell slots with this
|
||||||
|
feature, you must finish a long rest before you can do so again.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Eldritch Master"
|
||||||
|
source = "Warlock"
|
||||||
|
|
||||||
|
|
||||||
|
# The Fiend Patron
|
||||||
|
class DarkOnesBlessing(Feature):
|
||||||
|
"""Starting at 1st level, when you reduce a hostile creature to 0 hit points,
|
||||||
|
you gain temporary hit points equal to your Charisma modifier + your
|
||||||
|
warlock level (minimum of 1)
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Dark One's Blessing"
|
||||||
|
source = "Warlock (The Fiend Patron)"
|
||||||
|
|
||||||
|
|
||||||
|
class DarkOnesOwnLuck(Feature):
|
||||||
|
"""Starting at 6th level, you can call on your patron to alter fate in your
|
||||||
|
favor. When you make an ability check or a saving throw, you can use this
|
||||||
|
feature to add a d10 to your roll. You can do so after seeing the initial
|
||||||
|
roll but before any o f the roll’s effects occur.
|
||||||
|
|
||||||
|
Once you use this feature, you can’t use it again until you finish a short
|
||||||
|
or long rest.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Dark One's Own Luck"
|
||||||
|
source = "Warlock (The Fiend Patron)"
|
||||||
|
|
||||||
|
|
||||||
|
class FiendishResilience(Feature):
|
||||||
|
"""Starting at 10th level, you can choose one damage type when you finish a
|
||||||
|
short or long rest. You gain resistance to that damage type until you
|
||||||
|
choose a different one with this feature. Damage from magical weapons or
|
||||||
|
silver weapons ignores this resistance.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Fiendish Resilience"
|
||||||
|
source = "Warlock (The Fiend Patron)"
|
||||||
|
|
||||||
|
|
||||||
|
class HurlThroughHell(Feature):
|
||||||
|
"""Starting at 14th level, when you hit a creature with an attack, you can use
|
||||||
|
this feature to instantly transport the target through the lower
|
||||||
|
planes. The creature disappears and hurtles through a nightmare landscape.
|
||||||
|
|
||||||
|
At the end of your next turn, the target returns to the space it previously
|
||||||
|
occupied, or the nearest unoccupied space. If the target is not a fiend, it
|
||||||
|
takes 10d10 psychic damage as it reels from its horrific experience.
|
||||||
|
|
||||||
|
Once you use this feature, you can’t use it again until you finish a long
|
||||||
|
rest.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Hurl Through Hell"
|
||||||
|
source = "Warlock (The Fiend Patron)"
|
||||||
|
|
||||||
|
|
||||||
|
# Hexblade
|
||||||
|
class HexbladesCurse(Feature):
|
||||||
|
"""Starting at lst level, you gain the ability to place a bale— ful curse on
|
||||||
|
someone. As a bonus action, choose one creature you can see within 30 feet
|
||||||
|
of you. The target is cursed for 1 minute. The curse ends early if the
|
||||||
|
target dies, you die, or you are incapacitated. Until the curse ends, you
|
||||||
|
gain the following benefits:
|
||||||
|
|
||||||
|
-- You gain a bonus to damage rolls against the
|
||||||
|
cursed target. The bonus equals your proficiency bonus.
|
||||||
|
|
||||||
|
-- Any attack roll you make against the cursed target is a critical hit on
|
||||||
|
a roll of 19 or 20 on the d20.
|
||||||
|
|
||||||
|
--If the cursed target dies, you regain hit points equal to your warlock
|
||||||
|
level + your Charisma modifier (mini- mum of 1 hit point).
|
||||||
|
|
||||||
|
You can’t use this feature again until you finish a short or long rest.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Hexblades Curse"
|
||||||
|
source = "Warlock (Hexblade)"
|
||||||
|
|
||||||
|
|
||||||
|
class HexWarrior(Feature):
|
||||||
|
"""At lst level, you acquire the training necessary to effec- tively arm
|
||||||
|
yourself for battle. You gain proficiency with medium armor, shields, and
|
||||||
|
martial weapons.
|
||||||
|
|
||||||
|
The influence of your patron also allows you to mystically channel your
|
||||||
|
will through a particular weapon. Whenever you finish a long rest, you can
|
||||||
|
touch one weapon that you are proficient with and that lacks the two-handed
|
||||||
|
property. When you attack with that weapon, you can use your Charisma
|
||||||
|
modifier, instead of Strength or Dexterity, for the attack and damage
|
||||||
|
rolls. This benefit lasts until you finish a long rest. If you later gain
|
||||||
|
the Pact of the Blade feature, this benefit extends to every pact weapon
|
||||||
|
you conjure with that feature, no matter the weapon’s type
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = 'Hex Warrior'
|
||||||
|
source = "Warlock (Hexblade)"
|
||||||
|
|
||||||
|
def weapon_func(self, weapon: weapons.Weapon, **kwargs):
|
||||||
|
"""
|
||||||
|
Swap the weapon's attack bonus modifier for Charisma if
|
||||||
|
it is higher than STR/DEX bonus
|
||||||
|
"""
|
||||||
|
if weapon.is_finesse:
|
||||||
|
existing_mod = max(self.owner.strength.modifier,
|
||||||
|
self.owner.dexterity.modifier)
|
||||||
|
else:
|
||||||
|
existing_mod = self.owner.strength.modifier
|
||||||
|
cha_mod = self.owner.charisma.modifier
|
||||||
|
if cha_mod > existing_mod:
|
||||||
|
weapon.attack_bonus += (cha_mod - existing_mod)
|
||||||
|
return weapon
|
||||||
|
|
||||||
|
|
||||||
|
class AccursedSpecter(Feature):
|
||||||
|
"""Starting at 6th level, you can curse the soul of a person you slay,
|
||||||
|
temporarily binding it to your service. When you slay a humanoid, you can
|
||||||
|
cause its Spirit to rise from its corpse as a specter, the statistics for
|
||||||
|
which are in the Monster Manual. When the specter appears, it gains
|
||||||
|
temporary hit points equal to halfyour warlock level. Roll initiative for
|
||||||
|
the specter, which has its own turns. It obeys your verbal commands, and it
|
||||||
|
gains a special bonus to its attack rolls equal to your Charisma modifier
|
||||||
|
(minimum of +0).
|
||||||
|
|
||||||
|
The specter remains in your service until the end of your next long rest,
|
||||||
|
at which point it vanishes to the afterlife.
|
||||||
|
|
||||||
|
Once you bind a specter with this feature, you can’t use the feature again
|
||||||
|
until you finish a long rest.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Accursed Specter"
|
||||||
|
source = "Warlock (Hexblade)"
|
||||||
|
|
||||||
|
|
||||||
|
class ArmorOfHexes(Feature):
|
||||||
|
"""At 10th level, your hex grows more powerful. If the tar- get cursed by your
|
||||||
|
Hexblade’s Curse hits you with an attack roll, you can use your reaction to
|
||||||
|
roll a d6. On a 4 or higher, the attack instead misses you, regardless of
|
||||||
|
its roll.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Armor of Hexes"
|
||||||
|
source = "Warlock (Hexblade)"
|
||||||
|
|
||||||
|
|
||||||
|
class MasterOfHexes(Feature):
|
||||||
|
"""Starting at 14th level, you can spread your Hexblade’s Curse from a slain
|
||||||
|
creature to another creature. When the creature cursed by your Hexblade’s
|
||||||
|
Curse dies, you can apply the curse to a different creature you can see
|
||||||
|
within 30 feet of you, provided you aren’t incapacitated. When you apply
|
||||||
|
the curse in this way, you don’t regain hit points from the death of the
|
||||||
|
previously cursed creature.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Master of Hexes"
|
||||||
|
source = "Warlock (Hexblade)"
|
||||||
|
|
||||||
|
|
||||||
# All Invocations
|
# All Invocations
|
||||||
class Invocation(Feature):
|
class Invocation(Feature):
|
||||||
"""
|
"""
|
||||||
@@ -21,7 +305,8 @@ class Invocation(Feature):
|
|||||||
self.spells_known += (s,)
|
self.spells_known += (s,)
|
||||||
self.spells_prepared += (s,)
|
self.spells_prepared += (s,)
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, owner):
|
||||||
|
super().__init__(owner)
|
||||||
for s in self.at_will_spells:
|
for s in self.at_will_spells:
|
||||||
self.cast_spell_at_will(s)
|
self.cast_spell_at_will(s)
|
||||||
|
|
||||||
@@ -33,7 +318,6 @@ class AgonizingBlast(Invocation):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
name = "Agonizing Blast"
|
name = "Agonizing Blast"
|
||||||
needs_implementation = True
|
|
||||||
|
|
||||||
|
|
||||||
class ArmorOfShadows(Invocation):
|
class ArmorOfShadows(Invocation):
|
||||||
@@ -281,7 +565,6 @@ class ThiefOfFiveFates(Invocation):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
name = "Thief of Five Fates"
|
name = "Thief of Five Fates"
|
||||||
needs_implementation = True
|
|
||||||
|
|
||||||
|
|
||||||
class ThirstingBlade(Invocation):
|
class ThirstingBlade(Invocation):
|
||||||
@@ -333,3 +616,184 @@ class WitchSight(Invocation):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
name = "Witch Sight"
|
name = "Witch Sight"
|
||||||
|
|
||||||
|
|
||||||
|
# XGTE
|
||||||
|
class AspectOfTheMoon(Invocation):
|
||||||
|
"""You no longer need to sleep and can’t be forced to sleep by any means. To
|
||||||
|
gain the benefits of a long rest, you can spend all 8 hours doing light
|
||||||
|
activity, such as read- ing your Book of Shadows and keeping watch.
|
||||||
|
|
||||||
|
**Prerequisite**: Pact of the Tome
|
||||||
|
"""
|
||||||
|
name = "Aspect of the Moon"
|
||||||
|
|
||||||
|
|
||||||
|
class CloakOfFiles(Invocation):
|
||||||
|
"""As a bonus action, you can surround yourselfwith a magical aura that looks
|
||||||
|
like buzzing flies. The aura ex- tends 5 feet from you in every direction,
|
||||||
|
but not through total cover. It lasts until you’re incapacitated or you
|
||||||
|
dismiss it as a bonus action.
|
||||||
|
|
||||||
|
The aura grants you advantage on Charisma
|
||||||
|
(Intimidation) checks but disadvantage on all other Charisma checks. Any
|
||||||
|
other creature that starts its turn in the aura takes poison damage equal
|
||||||
|
to your Charisma mod- ifier (minimum of O damage).
|
||||||
|
|
||||||
|
Once you use this invocation, you can’t use it again until you finish a
|
||||||
|
short or long rest.
|
||||||
|
|
||||||
|
**Prerequisite**: 5th level
|
||||||
|
"""
|
||||||
|
name = "Cloak of Flies"
|
||||||
|
|
||||||
|
|
||||||
|
class EldritchSmite(Invocation):
|
||||||
|
"""Once per turn when you hit a creature with your pact weapon, you can expend
|
||||||
|
a warlock spell slot to deal an extra 1d8 force damage to the target, plus
|
||||||
|
another 1d8 per level of the spell slot, and you can knock the target
|
||||||
|
prone if it is Huge or smaller.
|
||||||
|
|
||||||
|
**Prerequisite**: 5th level, Pact of the Blade
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Eldritch Smite"
|
||||||
|
|
||||||
|
|
||||||
|
class GhostlyGaze(Invocation):
|
||||||
|
"""As an action, you gain the ability to see through solid objects to a range
|
||||||
|
of 30 feet. Within that range, you have darkvision if you don’t already
|
||||||
|
have it. This special sight lasts for 1 minute or until your concentration
|
||||||
|
ends (as if you were concentrating on a spell). During that time, you
|
||||||
|
perceive objects as ghostly, transparent images.
|
||||||
|
|
||||||
|
Once you use this invocation, you can’t use it again until you finish a
|
||||||
|
short or long rest.
|
||||||
|
|
||||||
|
**Prerequisite**: 7th level
|
||||||
|
"""
|
||||||
|
name = "Ghostly Gaze"
|
||||||
|
|
||||||
|
|
||||||
|
class GiftOfTheDepths(Invocation):
|
||||||
|
"""You can breathe underwater, and you gain a swimming speed equal to your
|
||||||
|
walking speed. You can also cast water breathing once without ex- pending a
|
||||||
|
spell slot. You regain the ability to do so when you finish a long rest.
|
||||||
|
|
||||||
|
**Prerequisite**: 5th level
|
||||||
|
"""
|
||||||
|
name = "Gift of the Depths"
|
||||||
|
|
||||||
|
|
||||||
|
class GiftOfTheEverLivingOnes(Invocation):
|
||||||
|
"""Whenever you regain hit points while your familiar is within 100 feet
|
||||||
|
ofyou, treat any dice rolled to determine the hit points you regain as
|
||||||
|
having rolled their maxi- mum value for you.
|
||||||
|
|
||||||
|
**Prerequisite**: Pact of the Chain
|
||||||
|
"""
|
||||||
|
name = "Gift of the Ever-Living Ones"
|
||||||
|
|
||||||
|
|
||||||
|
class GraspOfHadar(Invocation):
|
||||||
|
"""Once on each ofyour turns when you hit a creature with your eldritcli
|
||||||
|
blast, you can move that creature in a straight line 10 feet closer to you
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Grasp of Hadar"
|
||||||
|
|
||||||
|
|
||||||
|
class ImprovedPactWeapon(Invocation):
|
||||||
|
"""You can use any weapon you summon with your Pact of the Blade feature as a
|
||||||
|
spellcasting focus for your waru lock spells.
|
||||||
|
|
||||||
|
In addition, the weapon gains a +1 bonus to its attack and damage rolls,
|
||||||
|
unless it is a magic weapon that already has a bonus to those rolls.
|
||||||
|
|
||||||
|
Finally, the weapon you conjure can be a shortbow, longbow, light crossbow,
|
||||||
|
or heavy crossbow.
|
||||||
|
|
||||||
|
**Prerequisite**: Pact of the Blade
|
||||||
|
"""
|
||||||
|
name = "Improved Pact Weapon"
|
||||||
|
|
||||||
|
def weapon_func(self, weapon: weapons.Weapon, **kwargs):
|
||||||
|
"""
|
||||||
|
Add +1 to attack and damage if magic is not already magic
|
||||||
|
"""
|
||||||
|
if weapon.magic_bonus <= 1:
|
||||||
|
weapon.magic_bonus = 1
|
||||||
|
weapon.attack_bonus += 1
|
||||||
|
weapon.bonus_damage += 1
|
||||||
|
return weapon
|
||||||
|
|
||||||
|
|
||||||
|
class LanceOfLethargy(Invocation):
|
||||||
|
"""Once on each of your turns when you hit a creature with your eldritch
|
||||||
|
blast, you can reduce that creature’s speed by 10 feet until the end ofyour
|
||||||
|
next turn.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Lance of Lethargy"
|
||||||
|
|
||||||
|
|
||||||
|
class MaddeningHex(Invocation):
|
||||||
|
"""As a bonus action, you cause a psychic disturbance around the target cursed
|
||||||
|
by your hex spell or by a warlock feature of yours, such as Hexblade’s
|
||||||
|
Curse or Sign of Ill Omen. When you do so, you deal psychic damage to the
|
||||||
|
cursed target and each creature of your choice that you can see within 5
|
||||||
|
feet of it. The psychic damage equals your Charisma modifier (minimum of 1
|
||||||
|
dam- age). To use this invocation, you must be able to see the cursed
|
||||||
|
target, and it must be within 30 feet ofyou.
|
||||||
|
|
||||||
|
**Prerequisite**: 5th level
|
||||||
|
"""
|
||||||
|
name = "Maddening Hex"
|
||||||
|
|
||||||
|
|
||||||
|
class RelentlessHex(Invocation):
|
||||||
|
"""Your curse creates a temporary bond between you and your target. As a bonus
|
||||||
|
action, you can magically telerport up to 30 feet to an unoccupied space
|
||||||
|
you can see within 5 feet of the target cursed by your hex spell or by a
|
||||||
|
warlock feature ofyours, such as Hexblade’s Curse or Sign of 111 Omen. To
|
||||||
|
teleport in this way, you must be able to see the cursed target.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Relentless Hex"
|
||||||
|
|
||||||
|
|
||||||
|
class ShroudOfShadow(Invocation):
|
||||||
|
"""You can cast invisibility at will, without expending a spell slot.
|
||||||
|
|
||||||
|
**Prerequisite**: 15th Level
|
||||||
|
|
||||||
|
"""
|
||||||
|
at_will_spells = (spells.Invisibility,)
|
||||||
|
name = "Shroud of Shadow"
|
||||||
|
|
||||||
|
|
||||||
|
class TombOfLevistus(Invocation):
|
||||||
|
"""As a reaction when you take damage, you can entomb yourself in ice, which
|
||||||
|
melts away at the end ofyour next turn. You gain 10 temporary hit points
|
||||||
|
per warlock level, which take as much of the triggering damage as
|
||||||
|
possible. Immediately after you take the damage, you gain vulnerability to
|
||||||
|
fire damage, your speed is reduced to 0, and you are incapacitated. These
|
||||||
|
effects, including any remaining temporary hit points, all end when the ice
|
||||||
|
melts.
|
||||||
|
|
||||||
|
Once you use this invocation, you can’t use it again until you finish a
|
||||||
|
short or long rest.
|
||||||
|
|
||||||
|
**Prerequisite**: 5th Level
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Tomb of Levistus"
|
||||||
|
|
||||||
|
|
||||||
|
class TrickstersEscape(Invocation):
|
||||||
|
"""You can cast freedom ofmovement once on yourself without expending a spell
|
||||||
|
slot. You regain the ability to do so when you finish a long rest
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Tricksters Escape"
|
||||||
|
|
||||||
|
|||||||
@@ -17,8 +17,10 @@ subclasses = {{ char.subclasses }} # ex: ['Necromacy'] or ['Thief', None]
|
|||||||
background = "{{ char.background.name }}"
|
background = "{{ char.background.name }}"
|
||||||
race = "{{ char.race.name }}"
|
race = "{{ char.race.name }}"
|
||||||
alignment = "{{ char.alignment }}"
|
alignment = "{{ char.alignment }}"
|
||||||
|
|
||||||
xp = {{ char.xp }}
|
xp = {{ char.xp }}
|
||||||
hp_max = {{ char.hp_max }}
|
hp_max = {{ char.hp_max }}
|
||||||
|
inspiration = {{ char.inspiration }} # integer inspiration value
|
||||||
|
|
||||||
# Ability Scores
|
# Ability Scores
|
||||||
strength = {{ char.strength.value }}
|
strength = {{ char.strength.value }}
|
||||||
@@ -32,10 +34,15 @@ charisma = {{ char.charisma.value }}
|
|||||||
# ex: skill_proficiencies = ('athletics', 'acrobatics', 'arcana')
|
# ex: skill_proficiencies = ('athletics', 'acrobatics', 'arcana')
|
||||||
skill_proficiencies = {{ char.skill_proficiencies }}
|
skill_proficiencies = {{ char.skill_proficiencies }}
|
||||||
|
|
||||||
# Named features / feats that aren't part of your classes,
|
# Any skills you have "expertise" (Bard/Rogue) in
|
||||||
# race, or background. Also include Eldritch Invocations.
|
skill_expertise = {{ char.skill_expertise }}
|
||||||
|
|
||||||
|
# Named features / feats that aren't part of your classes, race, or background.
|
||||||
|
# Also include Eldritch Invocations and features you make multiple selection of
|
||||||
|
# (like Maneuvers for Fighter, Metamagic for Sorcerors, Trick Shots for
|
||||||
|
# Gunslinger, etc.)
|
||||||
# Example:
|
# Example:
|
||||||
# features = ('Tavern Brawler',) # take the optional Feat from PHB
|
# features = ('Tavern Brawler',) # take the optional Feat from PHB
|
||||||
features = {{ char.custom_features }}
|
features = {{ char.custom_features }}
|
||||||
|
|
||||||
# If selecting among multiple feature options: ex Fighting Style
|
# If selecting among multiple feature options: ex Fighting Style
|
||||||
@@ -43,6 +50,10 @@ features = {{ char.custom_features }}
|
|||||||
# feature_choices = ('Archery',)
|
# feature_choices = ('Archery',)
|
||||||
feature_choices = {{ char.feature_choices }}
|
feature_choices = {{ char.feature_choices }}
|
||||||
|
|
||||||
|
# Weapons/other proficiencies not given by class/race/background
|
||||||
|
weapon_proficiencies = {{ char.other_weapon_proficiencies_text }}
|
||||||
|
_proficiencies_text = {{ char._proficiencies_text }}
|
||||||
|
|
||||||
# Proficiencies and languages
|
# Proficiencies and languages
|
||||||
languages = """{{ char.languages }}"""
|
languages = """{{ char.languages }}"""
|
||||||
|
|
||||||
@@ -55,10 +66,10 @@ gp = 0
|
|||||||
pp = 0
|
pp = 0
|
||||||
|
|
||||||
# TODO: Put your equipped weapons and armor here
|
# TODO: Put your equipped weapons and armor here
|
||||||
weapons = {{ char.weapons }} # Example: ('shortsword', 'longsword')
|
weapons = {{ char.weapons }} # Example: ('shortsword', 'longsword')
|
||||||
magic_items = {{ char.magic_items }} # Example: ('ring of protection',)
|
magic_items = {{ char.magic_items }} # Example: ('ring of protection',)
|
||||||
armor = "{{ char.armor }}" # Eg "light leather armor"
|
armor = "{{ char.armor }}" # Eg "light leather armor"
|
||||||
shield = "{{ char.shield }}" # Eg "shield"
|
shield = "{{ char.shield }}" # Eg "shield"
|
||||||
|
|
||||||
equipment = """{{ char.equipment }}"""
|
equipment = """{{ char.equipment }}"""
|
||||||
|
|
||||||
@@ -66,7 +77,7 @@ attacks_and_spellcasting = """{{ char.attacks_and_spellcasting }}"""
|
|||||||
|
|
||||||
# List of known spells
|
# List of known spells
|
||||||
# Example: spells = ('magic missile', 'mage armor')
|
# Example: spells = ('magic missile', 'mage armor')
|
||||||
spells = {{ char.spells }} # Todo: Learn some spells
|
spells = {{ char.spells }}
|
||||||
|
|
||||||
# Which spells have been prepared (not including cantrips)
|
# Which spells have been prepared (not including cantrips)
|
||||||
spells_prepared = {{ char.spells_prepared }}
|
spells_prepared = {{ char.spells_prepared }}
|
||||||
|
|||||||
@@ -20,8 +20,10 @@ subclasses = {{ char.subclasses }} # ex: ['Necromacy'] or ['Thief', None]
|
|||||||
background = "{{ char.background.name }}"
|
background = "{{ char.background.name }}"
|
||||||
race = "{{ char.race.name }}"
|
race = "{{ char.race.name }}"
|
||||||
alignment = "{{ char.alignment }}"
|
alignment = "{{ char.alignment }}"
|
||||||
|
|
||||||
xp = {{ char.xp }}
|
xp = {{ char.xp }}
|
||||||
hp_max = {{ char.hp_max }}
|
hp_max = {{ char.hp_max }}
|
||||||
|
inspiration = 0 # integer inspiration value
|
||||||
|
|
||||||
# Ability Scores
|
# Ability Scores
|
||||||
strength = {{ char.strength.value }}
|
strength = {{ char.strength.value }}
|
||||||
@@ -35,9 +37,15 @@ charisma = {{ char.charisma.value }}
|
|||||||
# ex: skill_proficiencies = ('athletics', 'acrobatics', 'arcana')
|
# ex: skill_proficiencies = ('athletics', 'acrobatics', 'arcana')
|
||||||
skill_proficiencies = {{ char.skill_proficiencies }}
|
skill_proficiencies = {{ char.skill_proficiencies }}
|
||||||
|
|
||||||
|
# Any skills you have "expertise" (Bard/Rogue) in
|
||||||
|
skill_expertise = ()
|
||||||
|
|
||||||
# Named features / feats that aren't part of your classes, race, or background.
|
# Named features / feats that aren't part of your classes, race, or background.
|
||||||
|
# Also include Eldritch Invocations and features you make multiple selection of
|
||||||
|
# (like Maneuvers for Fighter, Metamagic for Sorcerors, Trick Shots for
|
||||||
|
# Gunslinger, etc.)
|
||||||
# Example:
|
# Example:
|
||||||
# features = ('Tavern Brawler',) # take the optional Feat from PHB
|
# features = ('Tavern Brawler',) # take the optional Feat from PHB
|
||||||
features = ()
|
features = ()
|
||||||
|
|
||||||
# If selecting among multiple feature options: ex Fighting Style
|
# If selecting among multiple feature options: ex Fighting Style
|
||||||
@@ -45,6 +53,10 @@ features = ()
|
|||||||
# feature_choices = ('Archery',)
|
# feature_choices = ('Archery',)
|
||||||
feature_choices = ()
|
feature_choices = ()
|
||||||
|
|
||||||
|
# Weapons/other proficiencies not given by class/race/background
|
||||||
|
weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff')
|
||||||
|
_proficiencies_text = () # ex: ("thieves' tools",)
|
||||||
|
|
||||||
# Proficiencies and languages
|
# Proficiencies and languages
|
||||||
languages = """{{ char.languages }}"""
|
languages = """{{ char.languages }}"""
|
||||||
|
|
||||||
@@ -57,10 +69,10 @@ gp = 0
|
|||||||
pp = 0
|
pp = 0
|
||||||
|
|
||||||
# TODO: Put your equipped weapons and armor here
|
# TODO: Put your equipped weapons and armor here
|
||||||
weapons = () # Example: ('shortsword', 'longsword')
|
weapons = () # Example: ('shortsword', 'longsword')
|
||||||
magic_items = () # Example: ('ring of protection',)
|
magic_items = () # Example: ('ring of protection',)
|
||||||
armor = "" # Eg "light leather armor"
|
armor = "" # Eg "light leather armor"
|
||||||
shield = "" # Eg "shield"
|
shield = "" # Eg "shield"
|
||||||
|
|
||||||
equipment = """TODO: list the equipment and magic items your character carries"""
|
equipment = """TODO: list the equipment and magic items your character carries"""
|
||||||
|
|
||||||
@@ -69,7 +81,7 @@ or uses spells."""
|
|||||||
|
|
||||||
# List of known spells
|
# List of known spells
|
||||||
# Example: spells_prepared = ('magic missile', 'mage armor')
|
# Example: spells_prepared = ('magic missile', 'mage armor')
|
||||||
spells_prepared = () # Todo: Learn some spells
|
spells_prepared = () # Todo: Learn some spells
|
||||||
|
|
||||||
# Which spells have not been prepared
|
# Which spells have not been prepared
|
||||||
__spells_unprepared = ()
|
__spells_unprepared = ()
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
[% for sc in character.subclasses if sc not in ['', None, 'None', 'none']%]
|
[% for sc in character.subclasses if sc not in ['', None, 'None', 'none']%]
|
||||||
|
|
||||||
\section*{[[ sc.name ]]}
|
\section*{Subclass: [[ sc.name ]]}
|
||||||
|
|
||||||
[[ sc.__doc__|rst_to_latex ]]
|
[[ sc.__doc__|rst_to_latex ]]
|
||||||
|
|
||||||
|
|||||||
@@ -200,6 +200,7 @@ def create_character_pdf(character, basename, flatten=False):
|
|||||||
'Race ': str(character.race),
|
'Race ': str(character.race),
|
||||||
'Alignment': character.alignment,
|
'Alignment': character.alignment,
|
||||||
'XP': str(character.xp),
|
'XP': str(character.xp),
|
||||||
|
'Inspiration': str(character.inspiration),
|
||||||
# Abilities
|
# Abilities
|
||||||
'ProfBonus': mod_str(character.proficiency_bonus),
|
'ProfBonus': mod_str(character.proficiency_bonus),
|
||||||
'STRmod': str(character.strength.value),
|
'STRmod': str(character.strength.value),
|
||||||
@@ -215,7 +216,7 @@ def create_character_pdf(character, basename, flatten=False):
|
|||||||
'CHamod': str(character.charisma.value),
|
'CHamod': str(character.charisma.value),
|
||||||
'CHA': mod_str(character.charisma.modifier),
|
'CHA': mod_str(character.charisma.modifier),
|
||||||
'AC': str(character.armor_class),
|
'AC': str(character.armor_class),
|
||||||
'Initiative': mod_str(character.dexterity.modifier),
|
'Initiative': str(character.initiative),
|
||||||
'Speed': str(character.speed),
|
'Speed': str(character.speed),
|
||||||
'Passive': 10 + character.perception,
|
'Passive': 10 + character.perception,
|
||||||
# Saving throws (proficiencies handled later)
|
# Saving throws (proficiencies handled later)
|
||||||
|
|||||||
+10
-10
@@ -24,7 +24,6 @@ class Race():
|
|||||||
charisma_bonus = 0
|
charisma_bonus = 0
|
||||||
hit_point_bonus = 0
|
hit_point_bonus = 0
|
||||||
spells_known = ()
|
spells_known = ()
|
||||||
spells_prepared = ()
|
|
||||||
|
|
||||||
def __init__(self, owner=None):
|
def __init__(self, owner=None):
|
||||||
self.owner = owner
|
self.owner = owner
|
||||||
@@ -35,12 +34,17 @@ class Race():
|
|||||||
for i in range(1, 21):
|
for i in range(1, 21):
|
||||||
self.features_by_level[i] = [f(owner=self.owner)for f in
|
self.features_by_level[i] = [f(owner=self.owner)for f in
|
||||||
cls.features_by_level[i]]
|
cls.features_by_level[i]]
|
||||||
|
self.spells_known = [S() for S in cls.spells_known]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def spells_prepared(self):
|
||||||
|
return self.spells_known
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<self.name>"
|
return "\"{:s}\"".format(self.name)
|
||||||
|
|
||||||
|
|
||||||
# Dwarves
|
# Dwarves
|
||||||
@@ -107,8 +111,7 @@ class DarkElf(Elf):
|
|||||||
charisma_bonus = 1
|
charisma_bonus = 1
|
||||||
features = (feats.SuperiorDarkvision, feats.FeyAncestry, feats.Trance,
|
features = (feats.SuperiorDarkvision, feats.FeyAncestry, feats.Trance,
|
||||||
feats.SunlightSensitivity, feats.DrowMagic)
|
feats.SunlightSensitivity, feats.DrowMagic)
|
||||||
spells_known = (spells.DancingLights(),)
|
spells_known = (spells.DancingLights,)
|
||||||
spells_prepared = (spells.DancingLights(),)
|
|
||||||
|
|
||||||
|
|
||||||
# Halflings
|
# Halflings
|
||||||
@@ -174,8 +177,7 @@ class ForestGnome(Gnome):
|
|||||||
dexterity_bonus = 1
|
dexterity_bonus = 1
|
||||||
features = Gnome.features + (feats.NaturalIllusionist,
|
features = Gnome.features + (feats.NaturalIllusionist,
|
||||||
feats.SpeakWithSmallBeasts)
|
feats.SpeakWithSmallBeasts)
|
||||||
spells_known = (spells.MinorIllusion(),)
|
spells_known = (spells.MinorIllusion,)
|
||||||
spells_prepared = (spells.MinorIllusion(),)
|
|
||||||
|
|
||||||
|
|
||||||
class RockGnome(Gnome):
|
class RockGnome(Gnome):
|
||||||
@@ -242,8 +244,7 @@ class Aasimar(Race):
|
|||||||
languages = ("Common", "Celestial")
|
languages = ("Common", "Celestial")
|
||||||
features = (feats.Darkvision, feats.CelestialResistance,
|
features = (feats.Darkvision, feats.CelestialResistance,
|
||||||
feats.HealingHands, feats.LightBearer)
|
feats.HealingHands, feats.LightBearer)
|
||||||
spells_known = (spells.Light(),)
|
spells_known = (spells.Light,)
|
||||||
spells_prepared = (spells.Light(),)
|
|
||||||
|
|
||||||
|
|
||||||
# Protector Aasimar
|
# Protector Aasimar
|
||||||
@@ -348,8 +349,7 @@ class Triton(Race):
|
|||||||
features = (feats.Amphibious, feats.ControlAirAndWater,
|
features = (feats.Amphibious, feats.ControlAirAndWater,
|
||||||
feats.EmissaryOfTheSea, feats.GuardiansOfTheDepths)
|
feats.EmissaryOfTheSea, feats.GuardiansOfTheDepths)
|
||||||
languages = ("Common", "Primordial")
|
languages = ("Common", "Primordial")
|
||||||
spells_known = (spells.FogCloud(),)
|
spells_known = (spells.FogCloud,)
|
||||||
spells_prepared = (spells.FogCloud(),)
|
|
||||||
|
|
||||||
|
|
||||||
# Aarakocra
|
# Aarakocra
|
||||||
|
|||||||
@@ -5,3 +5,4 @@ from .spells_j_m import *
|
|||||||
from .spells_n_r import *
|
from .spells_n_r import *
|
||||||
from .spells_s_u import *
|
from .spells_s_u import *
|
||||||
from .spells_v_z import *
|
from .spells_v_z import *
|
||||||
|
from .unsorted_spells import *
|
||||||
|
|||||||
@@ -1221,6 +1221,40 @@ class BurningHands(Spell):
|
|||||||
classes = ('Wizard', )
|
classes = ('Wizard', )
|
||||||
|
|
||||||
|
|
||||||
|
class CallLightning(Spell):
|
||||||
|
"""A storm cloud appears in the shape of a cylinder that is 10 feet tall with a
|
||||||
|
60-foot radius, centered on a point you can see 100 feet directly above
|
||||||
|
you. The spell fails if you can't see a point in the air where the storm
|
||||||
|
cloud could appear (for example, if you are in a room that can't
|
||||||
|
accommodate the cloud).
|
||||||
|
|
||||||
|
When you cast the spell, choose a point you can see within range. A bolt of
|
||||||
|
lightning flashes down from the cloud to that point. Each creature within 5
|
||||||
|
feet of that point must make a Dexterity saving throw. A creature takes
|
||||||
|
3d10 lightning damage on a failed save, or half as much damage on a
|
||||||
|
successful one. On each of your turns until the spell ends, you can use
|
||||||
|
your action to call down lightning in this way again, targeting the same
|
||||||
|
point or a different one.
|
||||||
|
|
||||||
|
If you are outdoors in stormy conditions when you cast this spell, the
|
||||||
|
spell gives you control over the existing storm instead of creating a new
|
||||||
|
one. Under such conditions, the spell's damage increases by 1d10.
|
||||||
|
|
||||||
|
At Higher Levels: When you cast this spell using a spell slot of 4th level
|
||||||
|
or higher level, the damage increases by 1d10 for each slot level above
|
||||||
|
3rd.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Call Lightning"
|
||||||
|
level = 3
|
||||||
|
casting_time = "1 action"
|
||||||
|
components = ('V', 'S')
|
||||||
|
materials = ""
|
||||||
|
duration = "Up to 10 minutes"
|
||||||
|
magic_school = "Conjuration"
|
||||||
|
classes = ('Druid',)
|
||||||
|
|
||||||
|
|
||||||
class ChainLightning(Spell):
|
class ChainLightning(Spell):
|
||||||
"""You create a bolt of lightning that arcs toward a target of your
|
"""You create a bolt of lightning that arcs toward a target of your
|
||||||
choice that you can see within range. Three bolts then leap from
|
choice that you can see within range. Three bolts then leap from
|
||||||
|
|||||||
@@ -0,0 +1,793 @@
|
|||||||
|
from .spells import Spell
|
||||||
|
|
||||||
|
class ControlWater(Spell):
|
||||||
|
"""Until the spell ends, you control any freestanding water inside an area you
|
||||||
|
choose that is a cube up to 100 feet on a side. You can choose from any of the
|
||||||
|
following effects when you cast this spell. As an action on your turn, you can
|
||||||
|
repeat the same effect or choose a different one.
|
||||||
|
|
||||||
|
Flood: You cause the water
|
||||||
|
level of all standing water in the area to rise by as much as 20 feet. If the
|
||||||
|
area includes a shore, the flooding water spills over onto dry land. If you
|
||||||
|
choose an area in a large body of water, you instead create a 20-foot tall wave
|
||||||
|
that travels from one side of the area to the other and then crashes down. Any
|
||||||
|
Huge or smaller vehicles in the wave's path are carried with it to the other
|
||||||
|
side. Any Huge or smaller vehicles struck by the wave have a 25 percent chance
|
||||||
|
of capsizing. The water level remains elevated until the spell ends or you
|
||||||
|
choose a different effect. If this effect produced a wave, the wave repeats on
|
||||||
|
the start of your next turn while the flood effect lasts.
|
||||||
|
|
||||||
|
Part Water: You cause
|
||||||
|
water in the area to move apart and create a trench. The trench extends across
|
||||||
|
the spell's area, and the separated water forms a wall to either side. The
|
||||||
|
trench remains until the spell ends or you choose a different effect. The water
|
||||||
|
then slowly fills in the trench over the course of the next round until the
|
||||||
|
normal water level is restored.
|
||||||
|
|
||||||
|
Redirect Flow: You cause flowing water in the
|
||||||
|
area to move in a direction you choose, even if the water has to flow over
|
||||||
|
obstacles, up walls, or in other unlikely directions. The water in the area
|
||||||
|
moves as you direct it, but once it moves beyond the spell's area, it resumes
|
||||||
|
its flow based on the terrain conditions. The water continues to move in the
|
||||||
|
direction you chose until the spell ends or you choose a different effect.
|
||||||
|
|
||||||
|
|
||||||
|
Whirlpool: This effect requires a body of water at least 50 feet square and 25
|
||||||
|
feet deep. You cause a whirlpool to form in the center of the area. The
|
||||||
|
whirlpool forms a vortex that is 5 feet wide at the base, up to 50 feet wide at
|
||||||
|
the top, and 25 feet tall. Any creature or object in the water and within 25
|
||||||
|
feet of the vortex is pulled 10 feet toward it. A creature can swim away from
|
||||||
|
the vortex by making a Strength (Athletics) check against your spell save DC.
|
||||||
|
When a creature enters the vortex for the first time on a turn or starts its
|
||||||
|
turn there, it must make a Strength saving throw. On a failed save, the creature
|
||||||
|
takes 2d8 bludgeoning damage and is caught in the vortex until the spell ends.
|
||||||
|
On a successful save, the creature takes half damage, and isn't caught in the
|
||||||
|
vortex. A creature caught in the vortex can use its action to try to swim away
|
||||||
|
from the vortex as described above, but has disadvantage on the Strength
|
||||||
|
(Athletics) check to do so. The first time each turn that an object enters the
|
||||||
|
vortex, the object takes 2d8 bludgeoning damage, this damage occurs each round
|
||||||
|
it remains in the vortex.
|
||||||
|
"""
|
||||||
|
name = "Control Water"
|
||||||
|
level = 4
|
||||||
|
casting_time = "1 action"
|
||||||
|
casting_range = "300 feet"
|
||||||
|
components = ('V', 'S', 'M')
|
||||||
|
materials = "A drop of water and a pinch of dust"
|
||||||
|
duration = "Concentration, up to 10 minutes"
|
||||||
|
magic_school = "Transmutation"
|
||||||
|
classes = ('Cleric', 'Druid', 'Wizard')
|
||||||
|
|
||||||
|
class SleetStorm(Spell):
|
||||||
|
"""Until the spell ends, freezing rain and sleet fall in a 20-foot-tall cylinder
|
||||||
|
with a 40-foot radius centered on a point you choose within range. The area is
|
||||||
|
heavily obscured, and exposed flames in the area are doused.
|
||||||
|
|
||||||
|
The ground in the
|
||||||
|
area is covered with slick ice, making it difficult terrain. When a creature
|
||||||
|
enters the spell's area for the first time on a turn or starts its turn there,
|
||||||
|
it must make a Dexterity saving throw. On a failed save, it falls prone.
|
||||||
|
|
||||||
|
If a
|
||||||
|
creature is concentrating in the spell's area, the creature must make a
|
||||||
|
successful Constitution saving throw against your spell save DC or lose
|
||||||
|
concentration.
|
||||||
|
"""
|
||||||
|
name = "Sleet Storm"
|
||||||
|
level = 3
|
||||||
|
casting_time = "1 action"
|
||||||
|
casting_range = "150 feet"
|
||||||
|
components = ('V', 'S', 'M')
|
||||||
|
materials = "A pinch of dust and a few drops of water"
|
||||||
|
duration = "Concentration, up to 1 minute"
|
||||||
|
magic_school = "Conjuration"
|
||||||
|
classes = ('Druid', 'Sorcerer', 'Wizard')
|
||||||
|
|
||||||
|
|
||||||
|
class DestructiveWave(Spell):
|
||||||
|
"""You strike the ground, creating a burst of divine energy that ripples
|
||||||
|
outward from you. Each creature you choose within 30 feet of you must
|
||||||
|
succeed on a Constitution saving throw or take 5d6 thunder damage, as well
|
||||||
|
as 5d6 radiant or necrotic damage (your choice), and be knocked prone. A
|
||||||
|
creature that succeeds on its saving throw takes half as much damage and
|
||||||
|
isn’t knocked prone.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Destructive Wave"
|
||||||
|
level = 5
|
||||||
|
casting_time = "1 action"
|
||||||
|
casting_range = "Self (30 foot radius)"
|
||||||
|
components = ("V",)
|
||||||
|
magic_school = "Evocation"
|
||||||
|
classes = ("Paladin",)
|
||||||
|
|
||||||
|
|
||||||
|
class InsectPlague(Spell):
|
||||||
|
"""Swarming, biting locusts fill a 20-foot-radius sphere centered on a point you
|
||||||
|
choose within range. The sphere spreads around corners. The sphere remains for
|
||||||
|
the duration, and its area is lightly obscured. The sphere's area is difficult
|
||||||
|
terrain.
|
||||||
|
|
||||||
|
When the area appears, each creature in it must make a Constitution
|
||||||
|
saving throw. A creature takes 4d10 piercing damage on a failed save, or half as
|
||||||
|
much damage on a successful one. A creature must also make this saving throw
|
||||||
|
when it enters the spell's area for the first time on a turn or ends its turn
|
||||||
|
there.
|
||||||
|
|
||||||
|
At Higher Levels: When you cast this spell using a spell slot of 6th
|
||||||
|
level or higher, the damage increases by 1d10 for each slot level above 5th.
|
||||||
|
"""
|
||||||
|
name = "Insect Plague"
|
||||||
|
level = 5
|
||||||
|
casting_time = "1 action"
|
||||||
|
casting_range = "300 feet"
|
||||||
|
components = ('V', 'S', 'M')
|
||||||
|
materials = "A few grains of sugar, some kernels of grain, and a smear of fat"
|
||||||
|
duration = "Concentration, Up to 10 minutes"
|
||||||
|
magic_school = "Conjuration"
|
||||||
|
classes = ('Cleric', 'Druid', 'Sorcerer')
|
||||||
|
|
||||||
|
|
||||||
|
class FindFamiliar(Spell):
|
||||||
|
"""You gain the service of a familiar, a spirit that takes an animal form you
|
||||||
|
choose: bat, cat, crab, frog (toad), hawk, lizard, octopus, owl, poisonous
|
||||||
|
snake, fish (quipper), rat, raven, sea horse, spider, or weasel. Appearing in an
|
||||||
|
unoccupied space within range, the familiar has the statistics of the chosen
|
||||||
|
form, though it is a celestial, fey, or fiend (your choice) instead of a beast.
|
||||||
|
|
||||||
|
|
||||||
|
Your familiar acts independently of you, but it always obeys your commands. In
|
||||||
|
combat, it rolls its own initiative and acts on its own turn. A familiar can't
|
||||||
|
attack, but it can take other actions as normal.
|
||||||
|
|
||||||
|
When the familiar drops to 0
|
||||||
|
hit points, it disappears, leaving behind no physical form. It reappears after
|
||||||
|
you cast this spell again.
|
||||||
|
|
||||||
|
While your familiar is within 100 feet of you, you
|
||||||
|
can communicate with it telepathically. Additionally, as an action, you can see
|
||||||
|
through your familiar's eyes and hear what it hears until the start of your next
|
||||||
|
turn, gaining the benefits of any special senses that the familiar has. During
|
||||||
|
this time, you are deaf and blind with regard to your own senses.
|
||||||
|
|
||||||
|
As an action,
|
||||||
|
you can temporarily dismiss your familiar. It disappears into a pocket
|
||||||
|
dimension where it awaits your summons. Alternatively, you can dismiss it
|
||||||
|
forever. As an action while it is temporarily dismissed, you can cause it to
|
||||||
|
reappear in any unoccupied space within 30 feet of you.
|
||||||
|
|
||||||
|
You can't have more
|
||||||
|
than one familiar at a time. If you cast this spell while you already have a
|
||||||
|
familiar, you instead cause it to adopt a new form. Choose one of the forms from
|
||||||
|
the above list. Your familiar transforms into the chosen creature.
|
||||||
|
|
||||||
|
Finally,
|
||||||
|
when you cast a spell with a range of touch, your familiar can deliver the spell
|
||||||
|
as if it had cast the spell. Your familiar must be within 100 feet of you, and
|
||||||
|
it must use its reaction to deliver the spell when you cast it. If the spell
|
||||||
|
requires an attack roll, you use your attack modifier for the roll.
|
||||||
|
"""
|
||||||
|
name = "Find Familiar"
|
||||||
|
level = 1
|
||||||
|
casting_time = "1 hour"
|
||||||
|
casting_range = "10 feet"
|
||||||
|
components = ('V', 'S', 'M')
|
||||||
|
materials = ("10 gp worth of charcoal, incense, and herbs that must be"
|
||||||
|
"consumed by fire in a brass brazier")
|
||||||
|
duration = "Instantaneous"
|
||||||
|
magic_school = "Conjuration"
|
||||||
|
classes = ('Wizard',)
|
||||||
|
|
||||||
|
|
||||||
|
class ProtectionFromEvilAndGood(Spell):
|
||||||
|
"""Until the spell ends, one willing creature you touch is protected against
|
||||||
|
certain types of creatures - aberrations, celestials, elementals, fey, fiends,
|
||||||
|
and undead.
|
||||||
|
|
||||||
|
The protection grants several benefits. Creatures of those types
|
||||||
|
have disadvantage on attack rolls against the target. The target also can't be
|
||||||
|
charmed, frightened, or possessed by them. If the target is already charmed,
|
||||||
|
frightened, or possessed by such a creature, the target has advantage on any new
|
||||||
|
saving throw against the relevant effect.
|
||||||
|
"""
|
||||||
|
name = "Protection From Evil And Good"
|
||||||
|
level = 1
|
||||||
|
casting_time = "1 action"
|
||||||
|
casting_range = "Touch"
|
||||||
|
components = ('V', 'S', 'M')
|
||||||
|
materials = "Holy water or powdered silver and iron, which the spell consumes"
|
||||||
|
duration = "Concentration, Up to 10 minutes"
|
||||||
|
magic_school = "Abjuration"
|
||||||
|
classes = ('Cleric', 'Paladin', 'Warlock', 'Wizard')
|
||||||
|
|
||||||
|
|
||||||
|
class ZoneOfTruth(Spell):
|
||||||
|
"""You create a magical zone that guards against deception in a 15-foot-radius
|
||||||
|
sphere centered on a point of your choice within range. Until the spell ends, a
|
||||||
|
creature that enters the spell's area for the first time on a turn or starts its
|
||||||
|
turn there must make a Charisma saving throw. On a failed save, a creature
|
||||||
|
can't speak a deliberate lie while in the radius. You know whether each creature
|
||||||
|
succeeds or fails on its saving throw.
|
||||||
|
|
||||||
|
An affected creature is aware of the
|
||||||
|
spell and can thus avoid answering questions to which it would normally respond
|
||||||
|
with a lie. Such creatures can be evasive in its answers as long as it remains
|
||||||
|
within the boundaries of the truth.
|
||||||
|
"""
|
||||||
|
name = "Zone Of Truth"
|
||||||
|
level = 2
|
||||||
|
casting_time = "1 action"
|
||||||
|
casting_range = "60 feet"
|
||||||
|
components = ('V', 'S')
|
||||||
|
materials = ""
|
||||||
|
duration = "10 minutes"
|
||||||
|
magic_school = "Enchantment"
|
||||||
|
classes = ('Bard', 'Cleric', 'Paladin')
|
||||||
|
|
||||||
|
|
||||||
|
class EnsnaringStrike(Spell):
|
||||||
|
"""The next time you hit a creature with a weapon attack before this spell
|
||||||
|
ends, a writhing mass of thorny vines appears at the point of impact, and
|
||||||
|
the target must succeed on a Strength saving throw or be restrained by the
|
||||||
|
magical vines until the spell ends. A Large or larger creature has
|
||||||
|
advantage on this saving throw. If the target succeeds on the save, the
|
||||||
|
vines shrivel away.
|
||||||
|
|
||||||
|
While restrained by this spell, the target takes 1d6 piercing damage at the
|
||||||
|
start of each of its turns. A creature restrained by the vines or one that
|
||||||
|
can touch the creature can use its action to make a Strength check against
|
||||||
|
your spell save DC. On a success, the target is freed.
|
||||||
|
|
||||||
|
At Higher Level:
|
||||||
|
|
||||||
|
If you cast this spell using a spell slot of 2nd level or higher, the
|
||||||
|
damage increases by 1d6 for each slot level above 1st.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Ensnaring Strike"
|
||||||
|
level = 1
|
||||||
|
casting_time = '1 bonus action'
|
||||||
|
casting_range = 'Self'
|
||||||
|
components = ('V')
|
||||||
|
duration = 'Concentration, up to 1 minute'
|
||||||
|
magic_school = 'Conjuration'
|
||||||
|
classes = ("Ranger",)
|
||||||
|
|
||||||
|
|
||||||
|
class Moonbeam(Spell):
|
||||||
|
"""A silvery beam of pale light shines down in a 5-foot radius, 40-foot-high
|
||||||
|
cylinder centered on a point within range. Until the spell ends, dim light fills
|
||||||
|
the cylinder.
|
||||||
|
|
||||||
|
When a creature enters the spell's area for the first time on a
|
||||||
|
turn or starts its turn there, it is engulfed in ghostly flames that cause
|
||||||
|
searing pain, and it must make a Constitution saving throw. It takes 2d10
|
||||||
|
radiant damage on a failed save, or half as much damage on a successful one.
|
||||||
|
|
||||||
|
A
|
||||||
|
shapechanger makes its saving throw with disadvantage. If it fails, it also
|
||||||
|
instantly reverts to its original form and can't assume a different form until
|
||||||
|
it leaves the spell's light.
|
||||||
|
|
||||||
|
On each of your turns after you cast this spell,
|
||||||
|
you can use an action to move the beam 60 feet in any direction.
|
||||||
|
|
||||||
|
At Higher
|
||||||
|
Levels: When you cast this spell using a spell slot of 3rd level or higher, the
|
||||||
|
damage increases by 1d10 for each slot level above 2nd.
|
||||||
|
"""
|
||||||
|
name = "Moonbeam"
|
||||||
|
level = 2
|
||||||
|
casting_time = "1 action"
|
||||||
|
casting_range = "120 feet"
|
||||||
|
components = ('V', 'S', 'M')
|
||||||
|
materials = "Several seeds of any moonseed plant and a piece of opalescent feldspar"
|
||||||
|
duration = "Concentration, Up to 1 minute"
|
||||||
|
magic_school = "Evocation"
|
||||||
|
classes = ('Druid',)
|
||||||
|
|
||||||
|
|
||||||
|
class PlantGrowth(Spell):
|
||||||
|
"""This spell channels vitality into plants within a specific area. There are two
|
||||||
|
possible uses for the spell, granting either immediate or long-term benefits.
|
||||||
|
|
||||||
|
|
||||||
|
If you cast this spell using 1 action, choose a point within range. All normal
|
||||||
|
plants in a 100-foot radius centered on that point become thick and overgrown. A
|
||||||
|
creature moving through the area must spend 4 feet of movement for every 1 foot
|
||||||
|
it moves.
|
||||||
|
|
||||||
|
You can exclude one or more areas of any size within the spell's
|
||||||
|
area from being affected.
|
||||||
|
|
||||||
|
If you cast this spell over 8 hours, you enrich the
|
||||||
|
land. All plants in a half-mile radius centered on a point within range become
|
||||||
|
enriched for 1 year. The plants yield twice the normal amount of food when
|
||||||
|
harvested.
|
||||||
|
"""
|
||||||
|
name = "Plant Growth"
|
||||||
|
level = 3
|
||||||
|
casting_time = "1 action or 8 hours"
|
||||||
|
casting_range = "150 feet"
|
||||||
|
components = ('V', 'S')
|
||||||
|
materials = ""
|
||||||
|
duration = "Instantaneous"
|
||||||
|
magic_school = "Transmutation"
|
||||||
|
classes = ('Bard', 'Druid', 'Ranger')
|
||||||
|
|
||||||
|
|
||||||
|
class IceStorm(Spell):
|
||||||
|
"""A hail of rock-hard ice pounds to the ground in a 20-foot-radius, 40-foot-high
|
||||||
|
cylinder centered on a point within range. Each creature in the cylinder must
|
||||||
|
make a Dexterity saving throw. A creature takes 2d8 bludgeoning damage and 4d6
|
||||||
|
cold damage on a failed save, or half as much damage on a successful one.
|
||||||
|
|
||||||
|
|
||||||
|
Hailstones turn the storm's area of effect into difficult terrain until the end
|
||||||
|
of your next turn.
|
||||||
|
|
||||||
|
At Higher Levels: When you cast this spell using a spell
|
||||||
|
slot of 5th level or higher, the bludgeoning damage increases by 1d8 for each
|
||||||
|
slot level above 4th.
|
||||||
|
"""
|
||||||
|
name = "Ice Storm"
|
||||||
|
level = 4
|
||||||
|
casting_time = "1 action"
|
||||||
|
casting_range = "300 feet"
|
||||||
|
components = ('V', 'S', 'M')
|
||||||
|
materials = "A pinch of dust and a few drops of water"
|
||||||
|
duration = "Instantaneous"
|
||||||
|
magic_school = "Evocation"
|
||||||
|
classes = ('Druid', 'Sorcerer', 'Wizard')
|
||||||
|
|
||||||
|
|
||||||
|
class CommuneWithNature(Spell):
|
||||||
|
"""You briefly become one with nature and gain knowledge of the surrounding
|
||||||
|
territory. In the outdoors, the spell gives you knowledge of the land within 3
|
||||||
|
miles of you. In caves and other natural underground settings, the radius is
|
||||||
|
limited to 300 feet. The spell doesn't function where nature has been replaced
|
||||||
|
by construction, such as in dungeons and towns.
|
||||||
|
|
||||||
|
You instantly gain knowledge of
|
||||||
|
up to three facts of your choice about any of the following subjects as they
|
||||||
|
relate to the area - terrain and bodies of water; prevalent plants, minerals,
|
||||||
|
animals, or peoples; powerful celestials, fey, fiends, elementals, or undead;
|
||||||
|
influence from other planes of existence; buildings.
|
||||||
|
|
||||||
|
For example, you could
|
||||||
|
determine the location of powerful undead in the area, the location of major
|
||||||
|
sources of safe drinking water, and the location of any nearby towns.
|
||||||
|
"""
|
||||||
|
name = "Commune With Nature"
|
||||||
|
level = 5
|
||||||
|
casting_time = "1 minute"
|
||||||
|
casting_range = "Self"
|
||||||
|
components = ('V', 'S')
|
||||||
|
materials = ""
|
||||||
|
duration = "Instantaneous"
|
||||||
|
magic_school = "Divination"
|
||||||
|
classes = ('Druid', 'Ranger')
|
||||||
|
|
||||||
|
|
||||||
|
class TreeStride(Spell):
|
||||||
|
"""You gain the ability to enter a tree and move from inside it to inside another
|
||||||
|
tree of the same kind within 500 feet. Both trees must be living and at least
|
||||||
|
the same size as you. You must use 5 feet of movement to enter a tree. You
|
||||||
|
instantly know the location of all other trees of the same kind within 500 feet
|
||||||
|
and, as part of the move used to enter the tree, can either pass into one of
|
||||||
|
those trees or step out of the tree you're in. You appear in a spot of your
|
||||||
|
choice within 5 feet of the destination tree, using another 5 feet of movement.
|
||||||
|
If you have no movement left, you appear within 5 feet of the tree you entered.
|
||||||
|
|
||||||
|
|
||||||
|
You can use this transportation ability once per round for the duration. You
|
||||||
|
must end each turn outside a tree.
|
||||||
|
"""
|
||||||
|
name = "Tree Stride"
|
||||||
|
level = 5
|
||||||
|
casting_time = "1 action"
|
||||||
|
casting_range = "Self"
|
||||||
|
components = ('V', 'S')
|
||||||
|
materials = ""
|
||||||
|
duration = "Concentration, Up to 1 minute"
|
||||||
|
magic_school = "Conjuration"
|
||||||
|
classes = ('Druid', 'Ranger')
|
||||||
|
|
||||||
|
|
||||||
|
class HoldMonster(Spell):
|
||||||
|
"""Choose a creature that you can see within range. The target must succeed on a
|
||||||
|
Wisdom saving throw or be paralyzed for the duration. This spell has no effect
|
||||||
|
on undead. At the end of each of its turns, the target can make another Wisdom
|
||||||
|
saving throw. On a success, the spell ends on the target.
|
||||||
|
|
||||||
|
At Higher Levels:
|
||||||
|
When you cast this spell using a spell slot of 6th level or higher, you can
|
||||||
|
target on additional creature for each slot level above 5th. The creatures must
|
||||||
|
be within 30 feet of each other when you target them.
|
||||||
|
"""
|
||||||
|
name = "Hold Monster"
|
||||||
|
level = 5
|
||||||
|
casting_time = "1 action"
|
||||||
|
casting_range = "90 feet"
|
||||||
|
components = ('V', 'S', 'M')
|
||||||
|
materials = "A small, straight piece of iron"
|
||||||
|
duration = "Concentration, Up to 1 minute"
|
||||||
|
magic_school = "Enchantment"
|
||||||
|
classes = ('Bard', 'Sorcerer', 'Warlock', 'Wizard')
|
||||||
|
|
||||||
|
|
||||||
|
class Scrying(Spell):
|
||||||
|
"""You can see and hear a particular creature you choose that is on the same plane
|
||||||
|
of existence as you. The target must make a Wisdom saving throw, which is
|
||||||
|
modified by how well you know the target and the sort of physical connection you
|
||||||
|
have to it. If a target knows you're casting this spell, it can fail the saving
|
||||||
|
throw voluntarily if it wants to be observed.
|
||||||
|
|
||||||
|
Knowledge - Save Modifier
|
||||||
|
|
||||||
|
|
||||||
|
Secondhand (you have heard of the target) - +5
|
||||||
|
|
||||||
|
Firsthand (you have met the
|
||||||
|
target) +0
|
||||||
|
Familiar (you know the target well) - -5
|
||||||
|
|
||||||
|
Connection - Save Modifier
|
||||||
|
|
||||||
|
|
||||||
|
Likeness or picture - -2
|
||||||
|
|
||||||
|
Possession or garment - -4
|
||||||
|
|
||||||
|
Body part, lock of hair,
|
||||||
|
bit of nail, or the like - -10
|
||||||
|
|
||||||
|
On a successful save, the target isn't affected, and you can't use this
|
||||||
|
spell against it again for 24 hours.
|
||||||
|
|
||||||
|
On a failed save, the spell creates an invisible sensor within 10 feet of
|
||||||
|
the target. You can see and hear through the sensor as if you were
|
||||||
|
there. The sensor moves with the target, remaining within 10 feet of it for
|
||||||
|
the duration. A creature that can see invisible objects sees the sensor as
|
||||||
|
a luminous orb about the size of your fist.
|
||||||
|
|
||||||
|
Instead of targeting a creature, you can choose a location you
|
||||||
|
have seen before as the target of this spell. When you do, the sensor appears at
|
||||||
|
that location and doesn't move.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Scrying"
|
||||||
|
level = 5
|
||||||
|
casting_time = "10 minutes"
|
||||||
|
casting_range = "Self"
|
||||||
|
components = ('V', 'S', 'M')
|
||||||
|
materials = ("A focus worth at least 1,000 gp, such as a crystal ball, "
|
||||||
|
"a silver mirror, or a font filled with holy water")
|
||||||
|
duration = "Concentration, Up to 10 minutes"
|
||||||
|
magic_school = "Divination"
|
||||||
|
classes = ('Bard', 'Cleric', 'Druid', 'Warlock', 'Wizard')
|
||||||
|
|
||||||
|
|
||||||
|
class CompelledDuel(Spell):
|
||||||
|
"""You attempt to compel a creature into a duel. One creature that you can
|
||||||
|
see within range must make a Wisdom saving throw. On a failed save, the
|
||||||
|
creature is drawn to you, compelled by your divine demand. For the
|
||||||
|
duration, it has disadvantage on attack rolls against creatures other than
|
||||||
|
you, and must make a Wisdom saving throw each time it attempts to move to a
|
||||||
|
space that is more than 30 feet away from you; if it succeeds on this
|
||||||
|
saving throw, this spell doesn’t restrict the target’s movement for that
|
||||||
|
turn.
|
||||||
|
|
||||||
|
The spell ends if you attack any other creature, if you cast a spell that
|
||||||
|
targets a hostile creature other than the target, if a creature friendly to
|
||||||
|
you damages the target or casts a harmful spell on it, or if you end your
|
||||||
|
turn more than 30 feet away from the target.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Compelled Duel"
|
||||||
|
level = 1
|
||||||
|
casting_time = "1 bonus action"
|
||||||
|
casting_range = "30 feet"
|
||||||
|
components = ("V",)
|
||||||
|
duration = "Concentration, up to 10 minutes"
|
||||||
|
magic_school = "Enchantment"
|
||||||
|
classes = ('Paladin',)
|
||||||
|
|
||||||
|
|
||||||
|
class CircleOfPower(Spell):
|
||||||
|
"""Divine energy radiates from you, distorting and diffusing magical energy
|
||||||
|
within 30 feet of you. Until the spell ends, the sphere moves with you,
|
||||||
|
centered on you. For the duration, each friendly creature in the area
|
||||||
|
(including you) has advantage on saving throws against spells and other
|
||||||
|
magical effects.
|
||||||
|
|
||||||
|
Additionally, when an affected creature succeeds on a saving throw made
|
||||||
|
against a spell or magical effect that allows it to make a saving throw to
|
||||||
|
take only half damage, it instead takes no damage if it succeeds on the
|
||||||
|
saving throws. """
|
||||||
|
name = "Circle of Power"
|
||||||
|
level = 5
|
||||||
|
casting_time = '1 action'
|
||||||
|
casting_range = 'Self (30 foot radius)'
|
||||||
|
components = ('V',)
|
||||||
|
duration = "Concentration, up to 10 minutes"
|
||||||
|
magic_school = "Abjuration"
|
||||||
|
classes = ('Paladin',)
|
||||||
|
|
||||||
|
|
||||||
|
class Geas(Spell):
|
||||||
|
"""You place a magical command on a creature that you can see within range, forcing
|
||||||
|
it to carry out some service or refrain from some action or course of activity
|
||||||
|
as you decide. If the creature can understand you, it must succeed on a Wisdom
|
||||||
|
saving throw or become charmed by you for the duration. While the creature is
|
||||||
|
charmed by you, it takes 5d10 psychic damage each time it acts in a manner
|
||||||
|
directly counter to your instructions, but no more than once each day. A
|
||||||
|
creature that can't understand you is unaffected by the spell.
|
||||||
|
|
||||||
|
You can issue
|
||||||
|
any command you choose, short of an activity that would result in certain death.
|
||||||
|
Should you issue a suicidal command, the spell ends.
|
||||||
|
|
||||||
|
You can end the spell
|
||||||
|
early by using an action to dismiss it. A remove curse, greater restoration, or
|
||||||
|
wish spell also ends it.
|
||||||
|
|
||||||
|
At Higher Levels: When you cast this spell using a
|
||||||
|
spell slot of 7th or 8th level, the duration is 1 year. When you cast this spell
|
||||||
|
using a spell slot of 9th level, the spell lasts until it is ended by one of
|
||||||
|
the spells mentioned above.
|
||||||
|
"""
|
||||||
|
name = "Geas"
|
||||||
|
level = 5
|
||||||
|
casting_time = "1 minute"
|
||||||
|
casting_range = "60 feet"
|
||||||
|
components = ('V',)
|
||||||
|
materials = ""
|
||||||
|
duration = "30 days"
|
||||||
|
magic_school = "Enchantment"
|
||||||
|
classes = ('Bard', 'Cleric', 'Druid', 'Paladin', 'Wizard')
|
||||||
|
class BestowCurse(Spell):
|
||||||
|
"""You touch a creature, and that creature must succeed on a Wisdom saving throw or
|
||||||
|
become cursed for the duration of the spell. When you cast this spell, choose
|
||||||
|
the nature of the curse from the following options.
|
||||||
|
|
||||||
|
• Choose one ability score.
|
||||||
|
While cursed, the target has disadvantage on ability checks and saving throws
|
||||||
|
made with that ability score.
|
||||||
|
|
||||||
|
• While cursed, the target has disadvantage on
|
||||||
|
attack rolls against you.
|
||||||
|
|
||||||
|
• While cursed, the target must make a Wisdom saving
|
||||||
|
throw at the start of each of its turns. If it fails, it wastes its action that
|
||||||
|
turn doing nothing.
|
||||||
|
|
||||||
|
• While the target is cursed, your attacks and spells deal
|
||||||
|
an extra 1d8 necrotic damage to the target.
|
||||||
|
|
||||||
|
A remove curse spell ends this
|
||||||
|
effect. At the DM's option, you may choose an alternative curse effect, but it
|
||||||
|
should be no more powerful than those described above. The DM has final say on
|
||||||
|
such a curse's effect.
|
||||||
|
|
||||||
|
At Higher Levels: If you cast this spell using a spell
|
||||||
|
slot of 4th level or higher, the duration is concentration, up to 10 minutes. If
|
||||||
|
you use a spell slot of 5th level or higher, the duration is 8 hours. If you
|
||||||
|
use a spell slot of 7th level or higher, the duration is 24 hours. If you use a
|
||||||
|
9th level spell slot, the spell lasts until it is dispelled. Using a spell slot
|
||||||
|
of 5th level or higher grants a duration that doesn't require concentration.
|
||||||
|
"""
|
||||||
|
name = "Bestow Curse"
|
||||||
|
level = 3
|
||||||
|
casting_time = "1 action"
|
||||||
|
casting_range = "Touch"
|
||||||
|
components = ('V', 'S')
|
||||||
|
materials = ""
|
||||||
|
duration = "Concentration, Up to 1 minute"
|
||||||
|
magic_school = "Necromancy"
|
||||||
|
classes = ('Bard', 'Cleric', 'Wizard')
|
||||||
|
|
||||||
|
|
||||||
|
class Fear(Spell):
|
||||||
|
"""You project a phantasmal image of a creature's worst fears. Each creature in a
|
||||||
|
30-foot cone must succeed on a Wisdom saving throw or drop whatever it is
|
||||||
|
holding and become frightened for the duration.
|
||||||
|
|
||||||
|
While frightened by this spell,
|
||||||
|
a creature must take the Dash action and move away from you by the safest
|
||||||
|
available route on each of its turns, unless there is nowhere to move. If the
|
||||||
|
creature ends its turn in a location where it doesn't have line of sight to you,
|
||||||
|
the creature can make a Wisdom saving throw. On a successful save, the spell
|
||||||
|
ends for that creature.
|
||||||
|
"""
|
||||||
|
name = "Fear"
|
||||||
|
level = 3
|
||||||
|
casting_time = "1 action"
|
||||||
|
casting_range = "Self (30-foot radius)"
|
||||||
|
components = ('V', 'S', 'M')
|
||||||
|
materials = "A white feather or the heart of a hen"
|
||||||
|
duration = "Concentration, Up to 1 minute"
|
||||||
|
magic_school = "Illusion"
|
||||||
|
classes = ('Bard', 'Sorcerer', 'Warlock', 'Wizard')
|
||||||
|
|
||||||
|
|
||||||
|
class DominateBeast(Spell):
|
||||||
|
"""You attempt to beguile a beast that you can see within range. It must succeed on
|
||||||
|
a Wisdom saving throw or be charmed by you for the duration. If you or
|
||||||
|
creatures that are friendly to you are fighting it, it has advantage on the
|
||||||
|
saving throw.
|
||||||
|
|
||||||
|
While the beast is charmed, you have a telepathic link with it as
|
||||||
|
long as the two of you are on the same plane of existence. You can use this
|
||||||
|
telepathic link to issue commands to the creature while you are conscious (no
|
||||||
|
action required), which it does its best to obey. You can specify a simple and
|
||||||
|
general course of action, such as Attack that creature, Run over there, or Fetch
|
||||||
|
that object. If the creature completes the order and doesn't receive further
|
||||||
|
direction from you, it defends and preserves itself to the best of its ability.
|
||||||
|
|
||||||
|
|
||||||
|
You can use your action to take total and precise control of the target. Until
|
||||||
|
the end of your next turn, the creature takes only the actions you choose, and
|
||||||
|
doesn't do anything that you don't allow it to do. During this time, you can
|
||||||
|
also cause the creature to use a reaction, but this requires you to use your own
|
||||||
|
reaction as well.
|
||||||
|
|
||||||
|
Each time the target takes damage, it makes a new Wisdom
|
||||||
|
saving throw against the spell. If the saving throw succeeds, the spell ends.
|
||||||
|
|
||||||
|
|
||||||
|
At Higher Levels: When you cast this spell with a 5th-level spell slot, the
|
||||||
|
duration is concentration, up to 10 minutes. When you use a 6th-level spell
|
||||||
|
slot, the duration is concentration, up to 1 hour. When you use a spell slot of
|
||||||
|
7th level or higher, the duration is concentration, up to 8 hours.
|
||||||
|
"""
|
||||||
|
name = "Dominate Beast"
|
||||||
|
level = 4
|
||||||
|
casting_time = "1 action"
|
||||||
|
casting_range = "60 feet"
|
||||||
|
components = ('V', 'S')
|
||||||
|
materials = ""
|
||||||
|
duration = "Concentration, Up to 1 minute"
|
||||||
|
magic_school = "Enchantment"
|
||||||
|
classes = ('Druid', 'Sorcerer')
|
||||||
|
|
||||||
|
|
||||||
|
class Cloudkill(Spell):
|
||||||
|
"""You create a 20-foot-radius sphere of poisonous, yellow-green fog centered on a
|
||||||
|
point you choose within range. The fog spreads around corners. It lasts for the
|
||||||
|
duration or until strong wind disperses the fog, ending the spell. Its area is
|
||||||
|
heavily obscured.
|
||||||
|
|
||||||
|
When a creature enters the spell's area for the first time on
|
||||||
|
a turn or starts its turn there, that creature must make a Constitution saving
|
||||||
|
throw. The creature takes 5d8 poison damage on a failed save, or half as much
|
||||||
|
damage on a successful one. Creatures are affected even if they hold their
|
||||||
|
breath or don't need to breathe.
|
||||||
|
|
||||||
|
The fog moves 10 feet away from you at the
|
||||||
|
start of each of your turns, rolling along the surface of the ground. The
|
||||||
|
vapors, being heavier than air, sink to the lowest level of the land, even
|
||||||
|
pouring down openings.
|
||||||
|
|
||||||
|
At Higher Levels: When you cast this spell using a spell
|
||||||
|
slot of 6th level or higher, the damage increases by 1d8 for each slot level
|
||||||
|
above 5th.
|
||||||
|
"""
|
||||||
|
name = "Cloudkill"
|
||||||
|
level = 5
|
||||||
|
casting_time = "1 action"
|
||||||
|
casting_range = "120 feet"
|
||||||
|
components = ('V', 'S')
|
||||||
|
materials = ""
|
||||||
|
duration = "Concentration, Up to 10 minutes"
|
||||||
|
magic_school = "Conjuration"
|
||||||
|
classes = ('Sorcerer', 'Wizard')
|
||||||
|
|
||||||
|
|
||||||
|
class CalmEmotions(Spell):
|
||||||
|
"""You attempt to suppress strong emotions in a group of people. Each humanoid in a
|
||||||
|
20-foot-radius sphere centered on a point you choose within range must make a
|
||||||
|
Charisma saving throw a creature can choose to fail this saving throw if it
|
||||||
|
wishes. If a creature fails its saving throw, choose one of the following two
|
||||||
|
effects.
|
||||||
|
|
||||||
|
You can suppress any effect causing a target to be charmed or
|
||||||
|
frightened. When this spell ends, any suppressed effect resumes, provided that
|
||||||
|
its duration has not expired in the meantime.
|
||||||
|
|
||||||
|
Alternatively, you can make a
|
||||||
|
target indifferent about creatures of your choice that it is hostile toward.
|
||||||
|
This indifference ends if the target is attacked or harmed by a spell or if it
|
||||||
|
witnesses any of its friends being harmed. When the spell ends, the creature
|
||||||
|
becomes hostile again, unless the DM rules otherwise.
|
||||||
|
"""
|
||||||
|
name = "Calm Emotions"
|
||||||
|
level = 2
|
||||||
|
casting_time = "1 action"
|
||||||
|
casting_range = "60 feet"
|
||||||
|
components = ('V', 'S')
|
||||||
|
materials = ""
|
||||||
|
duration = "Concentration, Up to 1 minute"
|
||||||
|
magic_school = "Enchantment"
|
||||||
|
classes = ('Bard', 'Cleric')
|
||||||
|
|
||||||
|
|
||||||
|
class HypnoticPattern(Spell):
|
||||||
|
"""You create a twisting pattern of colors that weaves through the air inside a
|
||||||
|
30-foot cube within range. The pattern appears for a moment and vanishes. Each
|
||||||
|
creature in the area who sees the pattern must make a Wisdom saving throw. On a
|
||||||
|
failed save, the creature becomes charmed for the duration. While charmed by
|
||||||
|
this spell, the creature is incapacitated and has a speed of 0.
|
||||||
|
|
||||||
|
The spell ends
|
||||||
|
for an affected creature if it takes any damage or if someone else uses an
|
||||||
|
action to shake the creature out of its stupor.
|
||||||
|
"""
|
||||||
|
name = "Hypnotic Pattern"
|
||||||
|
level = 3
|
||||||
|
casting_time = "1 action"
|
||||||
|
casting_range = "120 feet"
|
||||||
|
components = ('S', 'M')
|
||||||
|
materials = "A glowing stick of incense or a crystal vial filled with phosphorescent material"
|
||||||
|
duration = "Concentration, Up to 1 minute"
|
||||||
|
magic_school = "Illusion"
|
||||||
|
classes = ('Bard', 'Sorcerer', 'Warlock', 'Wizard')
|
||||||
|
|
||||||
|
|
||||||
|
class OtilukesResilientSphere(Spell):
|
||||||
|
"""A sphere of shimmering force encloses a creature or object of Large size or
|
||||||
|
smaller within range. An unwilling creature must make a Dexterity saving
|
||||||
|
throw. On a failed save, the creature is enclosed for the duration.
|
||||||
|
|
||||||
|
Nothing---not physical objects, energy, or other spell effects---can pass
|
||||||
|
through the barrier, in or out, though a creature in the sphere can breathe
|
||||||
|
there. The sphere is immune to all damage, and a creature or object inside
|
||||||
|
can’t be damaged by attacks or effects originating from outside, nor can a
|
||||||
|
creature inside the sphere damage anything outside it.
|
||||||
|
|
||||||
|
The sphere is weightless and just large enough to contain the creature or
|
||||||
|
object inside. An enclosed creature can use its action to push against the
|
||||||
|
sphere’s walls and thus roll the sphere at up to half the creature’s
|
||||||
|
speed. Similarly, the globe can be picked up and moved by other creatures.
|
||||||
|
|
||||||
|
A disintegrate spell targeting the globe destroys it without harming
|
||||||
|
anything inside it. """
|
||||||
|
name = "Otiluke's Resilient Sphere"
|
||||||
|
level = 4
|
||||||
|
casting_time = "1 action"
|
||||||
|
casting_range = "30 feet"
|
||||||
|
components = ('V', 'S', 'M')
|
||||||
|
materials = ("a hemispherical piece of clear crystal and a matching "
|
||||||
|
"hemispherical piece of gum arabic")
|
||||||
|
duration = "Concentration, up to 1 minute"
|
||||||
|
magic_school = "Evocation"
|
||||||
|
classes = ('Wizard',)
|
||||||
|
|
||||||
|
|
||||||
|
class WallOfForce(Spell):
|
||||||
|
"""An invisible wall of force springs into existence at a point you choose within
|
||||||
|
range. The wall appears in any orientation you choose, as a horizontal or
|
||||||
|
vertical barrier or at an angle. It can be free floating or resting on a solid
|
||||||
|
surface. You can form it into a hemispherical dome or a sphere with a radius of
|
||||||
|
up to 10 feet, or you can shape a flat surface made up of ten 10-foot-by-10-foot
|
||||||
|
panels. Each panel must be contiguous with another panel. In any form, the wall
|
||||||
|
is 1/4 inch thick. It lasts for the duration. If the wall cuts through a
|
||||||
|
creature's space when it appears, the creature is pushed to one side of the wall
|
||||||
|
(your choice which side).
|
||||||
|
|
||||||
|
Nothing can physically pass through the wall. It is
|
||||||
|
immune to all damage and can't be dispelled by dispel magic. A disintegrate
|
||||||
|
spell destroys the wall instantly, however. The wall also extends into the
|
||||||
|
Ethereal Plane, blocking ethereal travel through the wall.
|
||||||
|
"""
|
||||||
|
name = "Wall Of Force"
|
||||||
|
level = 5
|
||||||
|
casting_time = "1 action"
|
||||||
|
casting_range = "120 feet"
|
||||||
|
components = ('V', 'S', 'M')
|
||||||
|
materials = "A pinch of powder made by crushing a clear gemstone"
|
||||||
|
duration = "Concentration, Up to 10 minutes"
|
||||||
|
magic_school = "Evocation"
|
||||||
|
classes = ('Wizard',)
|
||||||
|
|
||||||
|
|
||||||
+16
-8
@@ -3,7 +3,8 @@ from collections import namedtuple
|
|||||||
from .armor import NoArmor, NoShield, HeavyArmor
|
from .armor import NoArmor, NoShield, HeavyArmor
|
||||||
from .features import (UnarmoredDefenseMonk, UnarmoredDefenseBarbarian,
|
from .features import (UnarmoredDefenseMonk, UnarmoredDefenseBarbarian,
|
||||||
DraconicResilience, Defense, FastMovement,
|
DraconicResilience, Defense, FastMovement,
|
||||||
UnarmoredMovement)
|
UnarmoredMovement, GiftOfTheDepths, RemarkableAthelete)
|
||||||
|
from math import ceil
|
||||||
|
|
||||||
|
|
||||||
def findattr(obj, name):
|
def findattr(obj, name):
|
||||||
@@ -94,6 +95,10 @@ class Skill():
|
|||||||
is_proficient = self.skill_name in character.skill_proficiencies
|
is_proficient = self.skill_name in character.skill_proficiencies
|
||||||
if is_proficient:
|
if is_proficient:
|
||||||
modifier += character.proficiency_bonus
|
modifier += character.proficiency_bonus
|
||||||
|
elif any([isinstance(f, RemarkableAthelete) for f in character.features]):
|
||||||
|
if self.ability_name.lower() in ('strength',
|
||||||
|
'dexterity', 'constitution'):
|
||||||
|
modifier += ceil(character.proficiencies_bonus / 2.)
|
||||||
# Check for expertise
|
# Check for expertise
|
||||||
is_expert = self.skill_name in character.skill_expertise
|
is_expert = self.skill_name in character.skill_expertise
|
||||||
if is_expert:
|
if is_expert:
|
||||||
@@ -142,16 +147,19 @@ class Speed():
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __get__(self, char, Character):
|
def __get__(self, char, Character):
|
||||||
base_speed = char.race.speed
|
speed = char.race.speed
|
||||||
other_speed = ''
|
other_speed = ''
|
||||||
if isinstance(base_speed, str):
|
if isinstance(speed, str):
|
||||||
base_speed = int(base_speed[:2]) # ignore other speeds, like fly
|
other_speed = speed[2:]
|
||||||
other_speed = base_speed[2:]
|
speed = int(speed[:2]) # ignore other speeds, like fly
|
||||||
if any([isinstance(f, FastMovement) for f in char.features]):
|
if any([isinstance(f, FastMovement) for f in char.features]):
|
||||||
if not isinstance(char.armor, HeavyArmor):
|
if not isinstance(char.armor, HeavyArmor):
|
||||||
base_speed += 10
|
speed += 10
|
||||||
if isinstance(char.armor, NoArmor) or (char.armor is None):
|
if isinstance(char.armor, NoArmor) or (char.armor is None):
|
||||||
for f in char.features:
|
for f in char.features:
|
||||||
if isinstance(f, UnarmoredMovement):
|
if isinstance(f, UnarmoredMovement):
|
||||||
base_speed += f.speed_bonus
|
speed += f.speed_bonus
|
||||||
return '{:d}{:s}'.format(base_speed, other_speed)
|
if any([isinstance(f, GiftOfTheDepths) for f in char.features]):
|
||||||
|
if 'swim' not in other_speed:
|
||||||
|
other_speed += ' ({:d} swim)'.format(speed)
|
||||||
|
return '{:d}{:s}'.format(speed, other_speed)
|
||||||
|
|||||||
@@ -5,10 +5,15 @@ class Weapon():
|
|||||||
bonus_damage = 0
|
bonus_damage = 0
|
||||||
damage_type = "p"
|
damage_type = "p"
|
||||||
attack_bonus = 0
|
attack_bonus = 0
|
||||||
weight = 1 # In lbs
|
magic_bonus = 0
|
||||||
|
weight = 1 # In lbs
|
||||||
properties = "Light"
|
properties = "Light"
|
||||||
ability = 'strength'
|
ability = 'strength'
|
||||||
is_finesse = False
|
is_finesse = False
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.attack_bonus += self.magic_bonus
|
||||||
|
self.bonus_damage += self.magic_bonus
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def damage(self):
|
def damage(self):
|
||||||
@@ -437,22 +442,14 @@ class Unarmed(MeleeWeapon):
|
|||||||
|
|
||||||
|
|
||||||
# Custom weapons
|
# Custom weapons
|
||||||
class HeavyRight(MeleeWeapon):
|
class HeavyPunch(MeleeWeapon):
|
||||||
base_damage = "1d4"
|
base_damage = "1d4"
|
||||||
name = "Heavy Right"
|
name = "Heavy Punch"
|
||||||
damage_type = 'b'
|
damage_type = 'b'
|
||||||
bonus_damage = 10 + 2 # Heavy weapon master + Dueling
|
bonus_damage = 10 + 2 # Heavy weapon master + Dueling
|
||||||
attack_bonus = -5 # Heavy weapon master
|
attack_bonus = -5 # Heavy weapon master
|
||||||
|
|
||||||
|
|
||||||
class HeavyLeft(MeleeWeapon):
|
|
||||||
base_damage = "1d4"
|
|
||||||
name = "Heavy Left"
|
|
||||||
damage_type = 'b'
|
|
||||||
bonus_damage = 10 + 2 - 2 # No proficiency bonus
|
|
||||||
attack_bonus = -5 # Heavy weapon master
|
|
||||||
|
|
||||||
|
|
||||||
class Bite(MeleeWeapon):
|
class Bite(MeleeWeapon):
|
||||||
name = "Bite"
|
name = "Bite"
|
||||||
base_damage = "1d4"
|
base_damage = "1d4"
|
||||||
|
|||||||
Reference in New Issue
Block a user