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_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 = ""
|
||||
alignment = "Neutral"
|
||||
dungeonsheets_version = __version__
|
||||
class_list = []
|
||||
_level = 1 # Keep internal check of total level
|
||||
_hit_dice_faces = 2
|
||||
class_list = list()
|
||||
_race = None
|
||||
_background = None
|
||||
xp = 0
|
||||
@@ -77,13 +75,11 @@ class Character():
|
||||
charisma = Ability()
|
||||
armor_class = ArmorClass()
|
||||
speed = Speed()
|
||||
_saving_throw_proficiencies = []
|
||||
other_weapon_proficiencies = tuple()
|
||||
skill_proficiencies = tuple()
|
||||
skill_expertise = tuple()
|
||||
class_skill_choices = tuple()
|
||||
num_skill_choices = 2
|
||||
proficiencies_extra = tuple()
|
||||
inspiration = 0
|
||||
_saving_throw_proficiencies = tuple() # use to overwrite class proficiencies
|
||||
other_weapon_proficiencies = tuple() # add to class/race proficiencies
|
||||
skill_proficiencies = list()
|
||||
skill_expertise = list()
|
||||
languages = ""
|
||||
# Skills
|
||||
acrobatics = Skill(ability='dexterity')
|
||||
@@ -118,30 +114,36 @@ class Character():
|
||||
gp = 0
|
||||
pp = 0
|
||||
equipment = ""
|
||||
weapons = [] # Replaced in __init__ constructor
|
||||
magic_items = []
|
||||
weapons = list()
|
||||
magic_items = list()
|
||||
armor = None
|
||||
shield = None
|
||||
_proficiencies_text = tuple()
|
||||
_proficiencies_text = list()
|
||||
# Magic
|
||||
spellcasting_ability = None
|
||||
_spells = tuple()
|
||||
_spells_prepared = tuple()
|
||||
_spells = list()
|
||||
_spells_prepared = list()
|
||||
# Features IN MAJOR DEVELOPMENT
|
||||
custom_features = ()
|
||||
feature_choices = ()
|
||||
custom_features = list()
|
||||
feature_choices = list()
|
||||
|
||||
def __init__(self, **attrs):
|
||||
"""Takes a bunch of attrs and passes them to ``set_attrs``"""
|
||||
self.clear()
|
||||
# make sure class, race, background are set first
|
||||
my_classes = attrs.pop('classes', [])
|
||||
my_levels = attrs.pop('levels', [])
|
||||
my_subclasses = attrs.pop('subclasses', [])
|
||||
# backwards compatability
|
||||
if (len(my_classes) == 0) and ('class' in attrs):
|
||||
my_classes = [attrs.pop('class')]
|
||||
my_levels = [attrs.pop('level', 1)]
|
||||
my_subclasses = [attrs.pop('subclass', None)]
|
||||
if (len(my_classes) == 0):
|
||||
if ('class' in attrs):
|
||||
my_classes = [attrs.pop('class')]
|
||||
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
|
||||
self.add_classes(
|
||||
my_classes, my_levels, my_subclasses,
|
||||
@@ -151,6 +153,21 @@ class Character():
|
||||
self.background = attrs.pop('background', None)
|
||||
# parse all other attributes
|
||||
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):
|
||||
return self.name
|
||||
@@ -166,16 +183,15 @@ class Character():
|
||||
cls = getattr(classes, cls)
|
||||
except 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):
|
||||
level = int(level)
|
||||
params = {}
|
||||
params['feature_choices'] = feature_choices
|
||||
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=[],
|
||||
feature_choices=[]):
|
||||
feature_choices=[]):
|
||||
if isinstance(classes_list, str):
|
||||
classes_list = [classes_list]
|
||||
if isinstance(levels, int) or isinstance(levels, float) or isinstance(levels, str):
|
||||
@@ -265,20 +281,14 @@ class Character():
|
||||
|
||||
@property
|
||||
def level(self):
|
||||
if self.num_classes == 0:
|
||||
return self._level
|
||||
else:
|
||||
return sum(c.level for c in self.class_list)
|
||||
return sum(c.level for c in self.class_list)
|
||||
|
||||
@level.setter
|
||||
def level(self, new_level):
|
||||
if self.num_classes == 0:
|
||||
self._level = new_level
|
||||
else:
|
||||
self.primary_class.level = new_level
|
||||
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))
|
||||
self.primary_class.level = new_level
|
||||
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
|
||||
def num_classes(self):
|
||||
@@ -314,6 +324,10 @@ class Character():
|
||||
def weapon_proficiencies(self, 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
|
||||
def features(self):
|
||||
fts = set(self.custom_features)
|
||||
@@ -334,6 +348,9 @@ class Character():
|
||||
@property
|
||||
def custom_features_text(self):
|
||||
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
|
||||
def saving_throw_proficiencies(self):
|
||||
@@ -419,18 +436,17 @@ class Character():
|
||||
for mitem in val:
|
||||
self.magic_items.append(mitem(owner=self))
|
||||
elif attr == 'weapon_proficiencies':
|
||||
self.other_weapon_proficiencies = tuple([findattr(weapons, w)
|
||||
for w in val])
|
||||
self.other_weapon_proficiencies = ()
|
||||
wps = set([findattr(weapons, w) for w in val])
|
||||
wps -= set(self.weapon_proficiencies)
|
||||
self.other_weapon_proficiencies = list(wps)
|
||||
elif attr == 'armor':
|
||||
self.wear_armor(val)
|
||||
elif attr == 'shield':
|
||||
self.wield_shield(val)
|
||||
elif attr == 'circle':
|
||||
for c in self.class_list:
|
||||
if isinstance(c, classes.Druid) and (c.circle == ''):
|
||||
c.circle = val
|
||||
self.circle = val
|
||||
break
|
||||
if hasattr(self, 'Druid'):
|
||||
self.Druid.circle = val
|
||||
elif attr == 'features':
|
||||
if isinstance(val, str):
|
||||
val = [val]
|
||||
@@ -483,6 +499,17 @@ class Character():
|
||||
def spell_attack_bonus(self, class_type):
|
||||
ability_mod = getattr(self, class_type.spellcasting_ability).modifier
|
||||
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):
|
||||
"""Is the character proficient with this item?
|
||||
@@ -516,7 +543,6 @@ class Character():
|
||||
all_proficiencies += tuple(self.race.proficiencies_text)
|
||||
if self.background is not None:
|
||||
all_proficiencies += tuple(self.background.proficiencies_text)
|
||||
all_proficiencies += tuple(self.proficiencies_extra)
|
||||
# Create a single string out of all the proficiencies
|
||||
for txt in all_proficiencies:
|
||||
if not final_text:
|
||||
@@ -536,7 +562,7 @@ class Character():
|
||||
s = '\n\n--'.join([f.name + ("**" if f.needs_implementation else "")
|
||||
for f in self.features])
|
||||
if s != '':
|
||||
s = '(See Features and Traits Page)\n\n--' + s
|
||||
s = '(See Features Page)\n\n--' + s
|
||||
s += '\n\n=================\n\n'
|
||||
return s
|
||||
|
||||
@@ -593,7 +619,7 @@ class Character():
|
||||
weapon_ = NewWeapon()
|
||||
# check if features add any bonuses
|
||||
for f in self.features:
|
||||
weapon_ = f.weapon_func(weapon_, char=self)
|
||||
weapon_ = f.weapon_func(weapon_)
|
||||
# Set weapon attributes based on character
|
||||
if weapon_.is_finesse:
|
||||
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.
|
||||
|
||||
To change, set hit_dice_num and hit_dice_faces."""
|
||||
if self.num_classes == 0:
|
||||
return '{:d}d{:d}'.format(self.level, self._hit_dice_faces)
|
||||
else:
|
||||
return ' + '.join([f'{c.level}d{c.hit_dice_faces}'
|
||||
for c in self.class_list])
|
||||
return ' + '.join([f'{c.level}d{c.hit_dice_faces}'
|
||||
for c in self.class_list])
|
||||
|
||||
@property
|
||||
def hit_dice_faces(self):
|
||||
if self.num_classes == 0:
|
||||
return self._hit_dice_faces
|
||||
else: # Not a valid function if multiclass
|
||||
if self.num_classes > 1:
|
||||
warnings.warn("hit_dice_faces is not valid for multiclass characters")
|
||||
return self.primary_class.hit_dice_faces
|
||||
# Not a valid function if multiclass
|
||||
if self.num_classes > 1:
|
||||
warnings.warn("hit_dice_faces is not valid for multiclass characters")
|
||||
return self.primary_class.hit_dice_faces
|
||||
|
||||
@hit_dice_faces.setter
|
||||
def hit_dice_faces(self, faces):
|
||||
if self.num_classes == 0:
|
||||
self._hit_dice_faces = faces
|
||||
else:
|
||||
self.primary_class.hit_dice_faces = faces
|
||||
self.primary_class.hit_dice_faces = faces
|
||||
|
||||
@property
|
||||
def proficiency_bonus(self):
|
||||
@@ -649,30 +667,26 @@ class Character():
|
||||
return prof
|
||||
|
||||
def can_assume_shape(self, shape: monsters.Monster):
|
||||
for c in self.class_list:
|
||||
if isinstance(c, classes.Druid):
|
||||
return c.can_assume_shape(shape)
|
||||
return False
|
||||
return hasattr(self, 'Druid') and self.Druid.can_assume_shape(shape)
|
||||
|
||||
@property
|
||||
def all_wild_shapes(self):
|
||||
for c in self.class_list:
|
||||
if isinstance(c, classes.Druid):
|
||||
return c.all_wild_shapes
|
||||
return ()
|
||||
if hasattr(self, 'Druid'):
|
||||
return self.Druid.all_wild_shapes
|
||||
else:
|
||||
return ()
|
||||
|
||||
@property
|
||||
def wild_shapes(self):
|
||||
for c in self.class_list:
|
||||
if isinstance(c, classes.Druid):
|
||||
return c.wild_shapes
|
||||
return ()
|
||||
if hasattr(self, 'Druid'):
|
||||
return self.Druid.wild_shapes
|
||||
else:
|
||||
return ()
|
||||
|
||||
@wild_shapes.setter
|
||||
def wild_shapes(self, new_shapes):
|
||||
for c in self.class_list:
|
||||
if isinstance(c, classes.Druid):
|
||||
c.wild_shapes = new_shapes
|
||||
if hasattr(self, 'Druid'):
|
||||
self.Druid.wild_shapes = new_shapes
|
||||
|
||||
@classmethod
|
||||
def load(cls, character_file):
|
||||
|
||||
@@ -47,11 +47,13 @@ class CharClass():
|
||||
self.features_by_level[i] = fs
|
||||
for k, v in params.items():
|
||||
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
|
||||
self.subclass = self.select_subclass(subclass)
|
||||
if isinstance(self.subclass, SubClass):
|
||||
self.apply_subclass()
|
||||
self.apply_subclass(feature_choices=feature_choices)
|
||||
|
||||
def select_subclass(self, subclass_str):
|
||||
"""
|
||||
@@ -67,23 +69,31 @@ class CharClass():
|
||||
return sc(owner=self.owner)
|
||||
return None
|
||||
|
||||
def apply_subclass(self):
|
||||
if self.subclass is None:
|
||||
def apply_subclass(self, feature_choices=[]):
|
||||
if not isinstance(self.subclass, SubClass):
|
||||
return
|
||||
subcls = self.subclass
|
||||
for i in range(1, 21):
|
||||
self.features_by_level[i] += ([f(owner=self.owner) for f in
|
||||
self.subclass.features_by_level[i]])
|
||||
for attr in ('weapon_proficiencies', '_proficiencies_text',
|
||||
'spells_known', 'spells_prepared'):
|
||||
new_list = getattr(self, attr, ()) + getattr(self.subclass, attr, ())
|
||||
fs = []
|
||||
for f in subcls.features_by_level[i]:
|
||||
if issubclass(f, FeatureSelector):
|
||||
fs.append(f(owner=self.owner,
|
||||
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)
|
||||
# All subclass proficiencies transfer, regardless of if this is primary class
|
||||
self.multiclass_weapon_proficiencies += (self.subclass.weapon_proficiencies)
|
||||
self._multiclass_proficiencies_text += (self._proficiencies_text)
|
||||
self.multiclass_weapon_proficiencies += tuple(subcls.weapon_proficiencies)
|
||||
self._multiclass_proficiencies_text += tuple(subcls._proficiencies_text)
|
||||
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.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
|
||||
def features(self):
|
||||
@@ -104,6 +114,15 @@ class CharClass():
|
||||
else:
|
||||
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():
|
||||
"""
|
||||
|
||||
@@ -1,9 +1,31 @@
|
||||
from .. import (weapons, features)
|
||||
from .. import (weapons, features, spells)
|
||||
from .classes import CharClass, SubClass
|
||||
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
|
||||
Thoth—value learning and understanding above all. Some teach that knowledge
|
||||
is to be gathered and shared in libraries and universities, or promote the
|
||||
@@ -18,10 +40,11 @@ class KnowledgeDomain(SubClass):
|
||||
|
||||
"""
|
||||
name = "Knowledge Domain"
|
||||
_domain_spells = {1: [], 3: [], 5: [], 7: [], 9: []}
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class LifeDomain(SubClass):
|
||||
class LifeDomain(ClericDomain):
|
||||
"""The Life domain focuses on the vibrant positive energy—one of the
|
||||
fundamental forces of the universe— that sustains all life. The gods of
|
||||
life promote vitality and health through healing the sick and wounded,
|
||||
@@ -34,10 +57,11 @@ class LifeDomain(SubClass):
|
||||
|
||||
"""
|
||||
name = "Life Domain"
|
||||
_domain_spells = {1: [], 3: [], 5: [], 7: [], 9: []}
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class LightDomain(SubClass):
|
||||
class LightDomain(ClericDomain):
|
||||
"""Gods of light—including Helm, Lathander, Pholtus, Branchala, the Silver
|
||||
Flame, Belenus, Apollo, and Re-Horakhty—promote the ideals of rebirth and
|
||||
renewal, truth, vigilance, and beauty, often using the symbol of the
|
||||
@@ -51,10 +75,11 @@ class LightDomain(SubClass):
|
||||
|
||||
"""
|
||||
name = "Light Domain"
|
||||
_domain_spells = {1: [], 3: [], 5: [], 7: [], 9: []}
|
||||
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 the deep forests (such as Silvanus, Obad-Hai, Chislev, Balinor, and
|
||||
Pan) to friendly deities associated with particular springs and groves
|
||||
@@ -68,10 +93,11 @@ class NatureDomain(SubClass):
|
||||
|
||||
"""
|
||||
name = "Nature Domain"
|
||||
_domain_spells = {1: [], 3: [], 5: [], 7: [], 9: []}
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class TempestDomain(SubClass):
|
||||
class TempestDomain(ClericDomain):
|
||||
"""Gods whose portfolios include the Tempest domain - including Talos,
|
||||
Umberlee, Kord, Zeboim, the Devourer, Zeus, and Thor — govern storms, sea,
|
||||
and sky. They include gods of lightning and thunder, gods of earthquakes,
|
||||
@@ -86,10 +112,22 @@ class TempestDomain(SubClass):
|
||||
|
||||
"""
|
||||
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[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
|
||||
Glittergold, and Loki—are mischief-makers and instigators who stand as a
|
||||
constant challenge to the accepted order among both gods and
|
||||
@@ -101,10 +139,11 @@ class TrickeryDomain(SubClass):
|
||||
|
||||
"""
|
||||
name = "Trickery Domain"
|
||||
_domain_spells = {1: [], 3: [], 5: [], 7: [], 9: []}
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
class WarDomain(SubClass):
|
||||
class WarDomain(ClericDomain):
|
||||
"""War has many manifestations. It can make heroes of ordinary people. It can
|
||||
be desperate and horrific, with acts of cruelty and cowardice eclipsing
|
||||
instances of excellence and courage. In either case, the gods of war watch
|
||||
@@ -120,11 +159,12 @@ class WarDomain(SubClass):
|
||||
|
||||
"""
|
||||
name = "War Domain"
|
||||
_domain_spells = {1: [], 3: [], 5: [], 7: [], 9: []}
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
# SCAG
|
||||
class ArcanaDomain(SubClass):
|
||||
class ArcanaDomain(ClericDomain):
|
||||
"""Magic is an energy that suffuses the multiverse and that fuels both
|
||||
destruction and creation. Gods of the Arcana domain know the secrets and
|
||||
potential of magic intimately. For some of these gods, magical knowledge
|
||||
@@ -141,11 +181,12 @@ class ArcanaDomain(SubClass):
|
||||
|
||||
"""
|
||||
name = "Arcana Domain"
|
||||
_domain_spells = {1: [], 3: [], 5: [], 7: [], 9: []}
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
# XGTE
|
||||
class ForgeDomain(SubClass):
|
||||
class ForgeDomain(ClericDomain):
|
||||
"""The gods of the forge are patrons of artisans who work with metal, from a
|
||||
humble blacksmith who keeps a village in horseshoes and plow blades to the
|
||||
mighty elf artisan whose diamond-tipped arrows of mithral have felled demon
|
||||
@@ -163,7 +204,7 @@ class ForgeDomain(SubClass):
|
||||
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
|
||||
deities, death and the afterlife are a foundational part of the
|
||||
multiverse. To desecrate the peace of the dead is an abomination. Deities
|
||||
@@ -177,6 +218,7 @@ class GraveDomain(SubClass):
|
||||
|
||||
"""
|
||||
name = "Grave Domain"
|
||||
_domain_spells = {1: [], 3: [], 5: [], 7: [], 9: []}
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
|
||||
@@ -194,6 +236,9 @@ class Cleric(CharClass):
|
||||
class_skill_choices = ('History', 'Insight', 'Medicine',
|
||||
'Persuasion', 'Religion')
|
||||
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,
|
||||
NatureDomain, TempestDomain, TrickeryDomain,
|
||||
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"
|
||||
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):
|
||||
@@ -26,6 +31,9 @@ class BattleMaster(SubClass):
|
||||
"""
|
||||
name = "Battle Master"
|
||||
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):
|
||||
@@ -41,6 +49,12 @@ class EldritchKnight(SubClass):
|
||||
"""
|
||||
name = "Eldritch Knight"
|
||||
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'
|
||||
multiclass_spellslots_by_level = {
|
||||
# char_lvl: (cantrips, 1st, 2nd, 3rd, ...)
|
||||
@@ -157,9 +171,15 @@ class Gunslinger(SubClass):
|
||||
|
||||
"""
|
||||
name = "Gunslinger"
|
||||
features_by_level = defaultdict(list)
|
||||
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):
|
||||
@@ -179,6 +199,10 @@ class Fighter(CharClass):
|
||||
'Athletics', 'History', 'Insight', 'Intimidation',
|
||||
'Perception', 'Survival')
|
||||
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,
|
||||
PurpleDragonKnight, ArcaneArcher, Cavalier,
|
||||
Samurai, Gunslinger)
|
||||
|
||||
@@ -1,9 +1,31 @@
|
||||
from .. import (weapons, features)
|
||||
from .. import (weapons, features, spells)
|
||||
from .classes import CharClass, SubClass
|
||||
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,
|
||||
virtue, and order. Sometim es called cavaliers, white knights, or holy
|
||||
warriors, these paladins meet the ideal of the knight in shining armor,
|
||||
@@ -35,10 +57,20 @@ class OathOfDevotion(SubClass):
|
||||
|
||||
"""
|
||||
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[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(SubClass):
|
||||
class OathOfAncients(PaladinOath):
|
||||
"""The Oath of the Ancients is as old as the race of elves and the rituals of
|
||||
the druids. Sometimes called fey knights, green knights, or horned knights,
|
||||
paladins who swear this oath cast their lot with the side of the light in
|
||||
@@ -69,10 +101,15 @@ class OathOfAncients(SubClass):
|
||||
|
||||
"""
|
||||
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)
|
||||
|
||||
|
||||
class OathOfVengance(SubClass):
|
||||
class OathOfVengance(PaladinOath):
|
||||
"""The Oath of Vengeance is a solemn commitment to punish those who have
|
||||
committed a grievous sin. When evil forces slaughter helpless villagers,
|
||||
when an entire people turns against the will of the gods, when a thieves’
|
||||
@@ -103,10 +140,15 @@ class OathOfVengance(SubClass):
|
||||
|
||||
"""
|
||||
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)
|
||||
|
||||
|
||||
class OathOfCrown(SubClass):
|
||||
class OathOfCrown(PaladinOath):
|
||||
"""The Oath of the Crown is sworn to the ideals of civilization, be it the
|
||||
spirit of a nation, fealty to a sovereign, or service to a deity of law and
|
||||
rulership. The paladins who swear this oath dedicate themselves to serving
|
||||
@@ -137,10 +179,15 @@ class OathOfCrown(SubClass):
|
||||
|
||||
"""
|
||||
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)
|
||||
|
||||
|
||||
class OathOfConquest(SubClass):
|
||||
class OathOfConquest(PaladinOath):
|
||||
"""The Oath of Conquest calls to paladins who seek glory in battle and the
|
||||
subjugation of their enemies. It isn’t enough for these paladins to
|
||||
establish order. They must crush the forces of chaos. Sometimes called
|
||||
@@ -173,10 +220,15 @@ class OathOfConquest(SubClass):
|
||||
|
||||
"""
|
||||
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)
|
||||
|
||||
|
||||
class OathOfRedemption(SubClass):
|
||||
class OathOfRedemption(PaladinOath):
|
||||
"""The Oath of Redemption sets a paladin on a difficult path, one that requires
|
||||
a holy warrior to use violence only as a last resort. Paladins who dedicate
|
||||
themselves to this oath believe that any person can be redeemed and that
|
||||
@@ -216,7 +268,56 @@ class OathOfRedemption(SubClass):
|
||||
|
||||
"""
|
||||
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[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):
|
||||
@@ -234,8 +335,19 @@ class Paladin(CharClass):
|
||||
class_skill_choices = ("Athletics", 'Insight', 'Intimidation',
|
||||
'Medicine', 'Persuasion', 'Religion')
|
||||
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,
|
||||
OathOfCrown, OathOfConquest, OathOfRedemption)
|
||||
OathOfCrown, OathOfConquest, OathOfRedemption,
|
||||
OathOfZor)
|
||||
spellcasting_ability = 'charisma'
|
||||
spell_slots_by_level = {
|
||||
# char_lvl: (cantrips, 1st, 2nd, 3rd, ...)
|
||||
|
||||
@@ -115,12 +115,6 @@ class Ranger(CharClass):
|
||||
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
|
||||
class BeastConclave(SubClass):
|
||||
@@ -132,6 +126,11 @@ class BeastConclave(SubClass):
|
||||
"""
|
||||
name = "Beast Conclave"
|
||||
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):
|
||||
@@ -160,5 +159,15 @@ class DeepStalkerConclave(SubClass):
|
||||
class RevisedRanger(Ranger):
|
||||
name = 'Revised Ranger'
|
||||
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)
|
||||
|
||||
|
||||
@@ -134,6 +134,23 @@ class Rogue(CharClass):
|
||||
'Insight', 'Intimidation', 'Investigation',
|
||||
'Perception', 'Performance', 'Persuasion',
|
||||
'Sleight of Hand', 'Stealth')
|
||||
num_skill_choices = 4
|
||||
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,
|
||||
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"
|
||||
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
|
||||
@@ -107,6 +111,9 @@ class Sorceror(CharClass):
|
||||
class_skill_choices = ('Arcana', 'Deception', 'Insight',
|
||||
'Intimidation', 'Persuasion', 'Religion')
|
||||
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,
|
||||
ShadowMagic, StormSorcery)
|
||||
spellcasting_ability = 'charisma'
|
||||
|
||||
@@ -31,6 +31,10 @@ class Fiend(SubClass):
|
||||
"""
|
||||
name = "The Fiend Patron"
|
||||
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):
|
||||
@@ -109,7 +113,13 @@ class Hexblade(SubClass):
|
||||
|
||||
"""
|
||||
name = "Hexblade Patron"
|
||||
weapon_proficiencies = (weapons.MartialWeapon,)
|
||||
_proficiencies_text = ['martial weapons', 'medium armor', 'shields']
|
||||
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):
|
||||
@@ -126,6 +136,10 @@ class Warlock(CharClass):
|
||||
multiclass_weapon_proficiencies = weapon_proficiencies
|
||||
_multiclass_proficiencies_text = ('light armor', 'simple weapons')
|
||||
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,
|
||||
Hexblade)
|
||||
spellcasting_ability = 'charisma'
|
||||
|
||||
@@ -486,7 +486,7 @@ class SkillForm(LinkedListForm):
|
||||
self.update_remaining()
|
||||
|
||||
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.background.num_skill_choices)
|
||||
num_selected = len(self.skill_proficiencies.value)
|
||||
@@ -507,7 +507,7 @@ class SkillForm(LinkedListForm):
|
||||
value=0, editable=False)
|
||||
self.skill_proficiencies = self.add(
|
||||
npyscreen.TitleMultiSelect, name="Skill Proficiencies:",
|
||||
values=self.parentApp.character.class_skill_choices,
|
||||
values=(),
|
||||
value_changed_callback=self.update_remaining)
|
||||
|
||||
def on_ok(self):
|
||||
|
||||
@@ -1,3 +1,167 @@
|
||||
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
|
||||
|
||||
|
||||
@@ -34,6 +35,9 @@ class Feature():
|
||||
|
||||
def __init__(self, owner=None):
|
||||
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):
|
||||
return (self.name == other.name) and (self.source == other.source)
|
||||
@@ -72,16 +76,17 @@ class FeatureSelector(Feature):
|
||||
A feature with multiple possible choices.
|
||||
"""
|
||||
options = dict()
|
||||
name = ''
|
||||
source = ''
|
||||
|
||||
def __init__(self, owner, feature_choices=[]):
|
||||
self.owner = owner
|
||||
keep_source = self.source
|
||||
def __new__(t, owner, 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:
|
||||
if selection.lower() in self.options():
|
||||
feature_choices.remove(selection)
|
||||
new_feat = self.options[selection.lower()]
|
||||
self.__dict__.update(new_feat.__dict__)
|
||||
new_feat.__init__(self)
|
||||
break
|
||||
self.source = keep_source
|
||||
if selection.lower() in t.options:
|
||||
new_feat = t.options[selection.lower()](owner=owner)
|
||||
new_feat.source = t.source
|
||||
return new_feat
|
||||
|
||||
@@ -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'
|
||||
die = 'd4'
|
||||
|
||||
def __init__(self, owner):
|
||||
self.owner = owner
|
||||
self.level = owner.Monk.level
|
||||
|
||||
def weapon_func(self, weapon: weapons.Weapon, char=None, **kwargs):
|
||||
def weapon_func(self, weapon: weapons.Weapon, **kwargs):
|
||||
"""
|
||||
Update increasing damage dice and DEX mod of Monk weapons
|
||||
"""
|
||||
is_monk_weapon = any([isinstance(weapon, w)
|
||||
for w in weapons.monk_weapons])
|
||||
level = self.owner.Monk.level
|
||||
if not is_monk_weapon:
|
||||
return weapon
|
||||
if char is None:
|
||||
return weapon
|
||||
self.die = 'd4'
|
||||
if self.level >= 5:
|
||||
if level >= 5:
|
||||
self.die = 'd6'
|
||||
if self.level >= 11:
|
||||
if level >= 11:
|
||||
self.die = 'd8'
|
||||
if self.level >= 17:
|
||||
if level >= 17:
|
||||
self.die = 'd10'
|
||||
# check if new damage is better than default
|
||||
if self.die > int(weapon.base_damage.split('d')[-1]):
|
||||
weapon.base_damage = '1d' + str(self.die)
|
||||
if int(self.die[1:]) > int(weapon.base_damage.split('d')[-1]):
|
||||
weapon.base_damage = '1' + str(self.die)
|
||||
weapon.is_finesse = True
|
||||
return weapon
|
||||
|
||||
@@ -84,19 +79,16 @@ class UnarmoredMovement(Feature):
|
||||
name = "Unarmored Movement"
|
||||
source = "Monk"
|
||||
|
||||
def __init__(self, owner):
|
||||
self.owner = owner
|
||||
self.level = owner.Monk.level
|
||||
|
||||
@property
|
||||
def speed_bonus(self):
|
||||
level = self.owner.Monk.level
|
||||
_speed_bonus = 10
|
||||
if self.level >= 6:
|
||||
if level >= 6:
|
||||
_speed_bonus = 15
|
||||
if self.level >= 10:
|
||||
if level >= 10:
|
||||
_speed_bonus = 20
|
||||
if self.level >= 14:
|
||||
if level >= 14:
|
||||
_speed_bonus = 25
|
||||
if self.level >= 18:
|
||||
if level >= 18:
|
||||
_speed_bonus = 30
|
||||
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)
|
||||
|
||||
|
||||
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):
|
||||
"""
|
||||
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)"
|
||||
source = "Ranger"
|
||||
@@ -28,14 +14,15 @@ class Archery(Feature):
|
||||
"""
|
||||
+2 attack roll bonus if weapon is ranged
|
||||
"""
|
||||
if weapon.is_ranged:
|
||||
if isinstance(weapon, weapons.RangedWeapon):
|
||||
weapon.attack_bonus += 2
|
||||
return weapon
|
||||
|
||||
|
||||
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)"
|
||||
source = "Ranger"
|
||||
@@ -48,7 +35,15 @@ class Dueling(Feature):
|
||||
"""
|
||||
name = "Fighting Style (Dueling)"
|
||||
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):
|
||||
@@ -58,7 +53,6 @@ class TwoWeaponFighting(Feature):
|
||||
"""
|
||||
name = "Fighting Style (Two-Weapon Fighting)"
|
||||
source = "Ranger"
|
||||
needs_implementation = True
|
||||
|
||||
|
||||
class RangerFightingStyle(FeatureSelector):
|
||||
@@ -81,3 +75,271 @@ class RangerFightingStyle(FeatureSelector):
|
||||
'dual wield': TwoWeaponFighting}
|
||||
name = "Fighting Style (Select One)"
|
||||
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
|
||||
|
||||
|
||||
# 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):
|
||||
"""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
|
||||
|
||||
@@ -1,7 +1,291 @@
|
||||
from .features import Feature
|
||||
from .. import spells
|
||||
from .features import (Feature, FeatureSelector)
|
||||
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
|
||||
class Invocation(Feature):
|
||||
"""
|
||||
@@ -21,7 +305,8 @@ class Invocation(Feature):
|
||||
self.spells_known += (s,)
|
||||
self.spells_prepared += (s,)
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, owner):
|
||||
super().__init__(owner)
|
||||
for s in self.at_will_spells:
|
||||
self.cast_spell_at_will(s)
|
||||
|
||||
@@ -33,7 +318,6 @@ class AgonizingBlast(Invocation):
|
||||
|
||||
"""
|
||||
name = "Agonizing Blast"
|
||||
needs_implementation = True
|
||||
|
||||
|
||||
class ArmorOfShadows(Invocation):
|
||||
@@ -281,7 +565,6 @@ class ThiefOfFiveFates(Invocation):
|
||||
|
||||
"""
|
||||
name = "Thief of Five Fates"
|
||||
needs_implementation = True
|
||||
|
||||
|
||||
class ThirstingBlade(Invocation):
|
||||
@@ -333,3 +616,184 @@ class WitchSight(Invocation):
|
||||
|
||||
"""
|
||||
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 }}"
|
||||
race = "{{ char.race.name }}"
|
||||
alignment = "{{ char.alignment }}"
|
||||
|
||||
xp = {{ char.xp }}
|
||||
hp_max = {{ char.hp_max }}
|
||||
inspiration = {{ char.inspiration }} # integer inspiration value
|
||||
|
||||
# Ability Scores
|
||||
strength = {{ char.strength.value }}
|
||||
@@ -32,10 +34,15 @@ charisma = {{ char.charisma.value }}
|
||||
# ex: skill_proficiencies = ('athletics', 'acrobatics', 'arcana')
|
||||
skill_proficiencies = {{ char.skill_proficiencies }}
|
||||
|
||||
# Named features / feats that aren't part of your classes,
|
||||
# race, or background. Also include Eldritch Invocations.
|
||||
# Any skills you have "expertise" (Bard/Rogue) in
|
||||
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:
|
||||
# features = ('Tavern Brawler',) # take the optional Feat from PHB
|
||||
# features = ('Tavern Brawler',) # take the optional Feat from PHB
|
||||
features = {{ char.custom_features }}
|
||||
|
||||
# If selecting among multiple feature options: ex Fighting Style
|
||||
@@ -43,6 +50,10 @@ features = {{ char.custom_features }}
|
||||
# feature_choices = ('Archery',)
|
||||
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
|
||||
languages = """{{ char.languages }}"""
|
||||
|
||||
@@ -55,10 +66,10 @@ gp = 0
|
||||
pp = 0
|
||||
|
||||
# TODO: Put your equipped weapons and armor here
|
||||
weapons = {{ char.weapons }} # Example: ('shortsword', 'longsword')
|
||||
magic_items = {{ char.magic_items }} # Example: ('ring of protection',)
|
||||
armor = "{{ char.armor }}" # Eg "light leather armor"
|
||||
shield = "{{ char.shield }}" # Eg "shield"
|
||||
weapons = {{ char.weapons }} # Example: ('shortsword', 'longsword')
|
||||
magic_items = {{ char.magic_items }} # Example: ('ring of protection',)
|
||||
armor = "{{ char.armor }}" # Eg "light leather armor"
|
||||
shield = "{{ char.shield }}" # Eg "shield"
|
||||
|
||||
equipment = """{{ char.equipment }}"""
|
||||
|
||||
@@ -66,7 +77,7 @@ attacks_and_spellcasting = """{{ char.attacks_and_spellcasting }}"""
|
||||
|
||||
# List of known spells
|
||||
# Example: spells = ('magic missile', 'mage armor')
|
||||
spells = {{ char.spells }} # Todo: Learn some spells
|
||||
spells = {{ char.spells }}
|
||||
|
||||
# Which spells have been prepared (not including cantrips)
|
||||
spells_prepared = {{ char.spells_prepared }}
|
||||
|
||||
@@ -20,8 +20,10 @@ subclasses = {{ char.subclasses }} # ex: ['Necromacy'] or ['Thief', None]
|
||||
background = "{{ char.background.name }}"
|
||||
race = "{{ char.race.name }}"
|
||||
alignment = "{{ char.alignment }}"
|
||||
|
||||
xp = {{ char.xp }}
|
||||
hp_max = {{ char.hp_max }}
|
||||
inspiration = 0 # integer inspiration value
|
||||
|
||||
# Ability Scores
|
||||
strength = {{ char.strength.value }}
|
||||
@@ -35,9 +37,15 @@ charisma = {{ char.charisma.value }}
|
||||
# ex: skill_proficiencies = ('athletics', 'acrobatics', 'arcana')
|
||||
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.
|
||||
# Also include Eldritch Invocations and features you make multiple selection of
|
||||
# (like Maneuvers for Fighter, Metamagic for Sorcerors, Trick Shots for
|
||||
# Gunslinger, etc.)
|
||||
# Example:
|
||||
# features = ('Tavern Brawler',) # take the optional Feat from PHB
|
||||
# features = ('Tavern Brawler',) # take the optional Feat from PHB
|
||||
features = ()
|
||||
|
||||
# If selecting among multiple feature options: ex Fighting Style
|
||||
@@ -45,6 +53,10 @@ features = ()
|
||||
# feature_choices = ('Archery',)
|
||||
feature_choices = ()
|
||||
|
||||
# Weapons/other proficiencies not given by class/race/background
|
||||
weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff')
|
||||
_proficiencies_text = () # ex: ("thieves' tools",)
|
||||
|
||||
# Proficiencies and languages
|
||||
languages = """{{ char.languages }}"""
|
||||
|
||||
@@ -57,10 +69,10 @@ 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"
|
||||
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"""
|
||||
|
||||
@@ -69,7 +81,7 @@ or uses spells."""
|
||||
|
||||
# List of known spells
|
||||
# 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
|
||||
__spells_unprepared = ()
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
[% for sc in character.subclasses if sc not in ['', None, 'None', 'none']%]
|
||||
|
||||
\section*{[[ sc.name ]]}
|
||||
\section*{Subclass: [[ sc.name ]]}
|
||||
|
||||
[[ sc.__doc__|rst_to_latex ]]
|
||||
|
||||
|
||||
@@ -200,6 +200,7 @@ def create_character_pdf(character, basename, flatten=False):
|
||||
'Race ': str(character.race),
|
||||
'Alignment': character.alignment,
|
||||
'XP': str(character.xp),
|
||||
'Inspiration': str(character.inspiration),
|
||||
# Abilities
|
||||
'ProfBonus': mod_str(character.proficiency_bonus),
|
||||
'STRmod': str(character.strength.value),
|
||||
@@ -215,7 +216,7 @@ def create_character_pdf(character, basename, flatten=False):
|
||||
'CHamod': str(character.charisma.value),
|
||||
'CHA': mod_str(character.charisma.modifier),
|
||||
'AC': str(character.armor_class),
|
||||
'Initiative': mod_str(character.dexterity.modifier),
|
||||
'Initiative': str(character.initiative),
|
||||
'Speed': str(character.speed),
|
||||
'Passive': 10 + character.perception,
|
||||
# Saving throws (proficiencies handled later)
|
||||
|
||||
+10
-10
@@ -24,7 +24,6 @@ class Race():
|
||||
charisma_bonus = 0
|
||||
hit_point_bonus = 0
|
||||
spells_known = ()
|
||||
spells_prepared = ()
|
||||
|
||||
def __init__(self, owner=None):
|
||||
self.owner = owner
|
||||
@@ -35,12 +34,17 @@ class Race():
|
||||
for i in range(1, 21):
|
||||
self.features_by_level[i] = [f(owner=self.owner)for f in
|
||||
cls.features_by_level[i]]
|
||||
self.spells_known = [S() for S in cls.spells_known]
|
||||
|
||||
@property
|
||||
def spells_prepared(self):
|
||||
return self.spells_known
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def __repr__(self):
|
||||
return f"<self.name>"
|
||||
return "\"{:s}\"".format(self.name)
|
||||
|
||||
|
||||
# Dwarves
|
||||
@@ -107,8 +111,7 @@ class DarkElf(Elf):
|
||||
charisma_bonus = 1
|
||||
features = (feats.SuperiorDarkvision, feats.FeyAncestry, feats.Trance,
|
||||
feats.SunlightSensitivity, feats.DrowMagic)
|
||||
spells_known = (spells.DancingLights(),)
|
||||
spells_prepared = (spells.DancingLights(),)
|
||||
spells_known = (spells.DancingLights,)
|
||||
|
||||
|
||||
# Halflings
|
||||
@@ -174,8 +177,7 @@ class ForestGnome(Gnome):
|
||||
dexterity_bonus = 1
|
||||
features = Gnome.features + (feats.NaturalIllusionist,
|
||||
feats.SpeakWithSmallBeasts)
|
||||
spells_known = (spells.MinorIllusion(),)
|
||||
spells_prepared = (spells.MinorIllusion(),)
|
||||
spells_known = (spells.MinorIllusion,)
|
||||
|
||||
|
||||
class RockGnome(Gnome):
|
||||
@@ -242,8 +244,7 @@ class Aasimar(Race):
|
||||
languages = ("Common", "Celestial")
|
||||
features = (feats.Darkvision, feats.CelestialResistance,
|
||||
feats.HealingHands, feats.LightBearer)
|
||||
spells_known = (spells.Light(),)
|
||||
spells_prepared = (spells.Light(),)
|
||||
spells_known = (spells.Light,)
|
||||
|
||||
|
||||
# Protector Aasimar
|
||||
@@ -348,8 +349,7 @@ class Triton(Race):
|
||||
features = (feats.Amphibious, feats.ControlAirAndWater,
|
||||
feats.EmissaryOfTheSea, feats.GuardiansOfTheDepths)
|
||||
languages = ("Common", "Primordial")
|
||||
spells_known = (spells.FogCloud(),)
|
||||
spells_prepared = (spells.FogCloud(),)
|
||||
spells_known = (spells.FogCloud,)
|
||||
|
||||
|
||||
# Aarakocra
|
||||
|
||||
@@ -5,3 +5,4 @@ from .spells_j_m import *
|
||||
from .spells_n_r import *
|
||||
from .spells_s_u import *
|
||||
from .spells_v_z import *
|
||||
from .unsorted_spells import *
|
||||
|
||||
@@ -1221,6 +1221,40 @@ class BurningHands(Spell):
|
||||
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):
|
||||
"""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
|
||||
|
||||
@@ -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 .features import (UnarmoredDefenseMonk, UnarmoredDefenseBarbarian,
|
||||
DraconicResilience, Defense, FastMovement,
|
||||
UnarmoredMovement)
|
||||
UnarmoredMovement, GiftOfTheDepths, RemarkableAthelete)
|
||||
from math import ceil
|
||||
|
||||
|
||||
def findattr(obj, name):
|
||||
@@ -94,6 +95,10 @@ class Skill():
|
||||
is_proficient = self.skill_name in character.skill_proficiencies
|
||||
if is_proficient:
|
||||
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
|
||||
is_expert = self.skill_name in character.skill_expertise
|
||||
if is_expert:
|
||||
@@ -142,16 +147,19 @@ class Speed():
|
||||
"""
|
||||
|
||||
def __get__(self, char, Character):
|
||||
base_speed = char.race.speed
|
||||
speed = char.race.speed
|
||||
other_speed = ''
|
||||
if isinstance(base_speed, str):
|
||||
base_speed = int(base_speed[:2]) # ignore other speeds, like fly
|
||||
other_speed = base_speed[2:]
|
||||
if isinstance(speed, str):
|
||||
other_speed = speed[2:]
|
||||
speed = int(speed[:2]) # ignore other speeds, like fly
|
||||
if any([isinstance(f, FastMovement) for f in char.features]):
|
||||
if not isinstance(char.armor, HeavyArmor):
|
||||
base_speed += 10
|
||||
speed += 10
|
||||
if isinstance(char.armor, NoArmor) or (char.armor is None):
|
||||
for f in char.features:
|
||||
if isinstance(f, UnarmoredMovement):
|
||||
base_speed += f.speed_bonus
|
||||
return '{:d}{:s}'.format(base_speed, other_speed)
|
||||
speed += f.speed_bonus
|
||||
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
|
||||
damage_type = "p"
|
||||
attack_bonus = 0
|
||||
weight = 1 # In lbs
|
||||
magic_bonus = 0
|
||||
weight = 1 # In lbs
|
||||
properties = "Light"
|
||||
ability = 'strength'
|
||||
is_finesse = False
|
||||
|
||||
def __init__(self):
|
||||
self.attack_bonus += self.magic_bonus
|
||||
self.bonus_damage += self.magic_bonus
|
||||
|
||||
@property
|
||||
def damage(self):
|
||||
@@ -437,22 +442,14 @@ class Unarmed(MeleeWeapon):
|
||||
|
||||
|
||||
# Custom weapons
|
||||
class HeavyRight(MeleeWeapon):
|
||||
class HeavyPunch(MeleeWeapon):
|
||||
base_damage = "1d4"
|
||||
name = "Heavy Right"
|
||||
name = "Heavy Punch"
|
||||
damage_type = 'b'
|
||||
bonus_damage = 10 + 2 # Heavy weapon master + Dueling
|
||||
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):
|
||||
name = "Bite"
|
||||
base_damage = "1d4"
|
||||
|
||||
Reference in New Issue
Block a user