mirror of
https://github.com/Threnklyn/dungeon-sheets.git
synced 2026-06-07 13:15:53 +02:00
Merge pull request #67 from rkubosz/artificer
Added the Artificer character class
This commit is contained in:
@@ -6,11 +6,13 @@ import os
|
|||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import warnings
|
import warnings
|
||||||
|
import math
|
||||||
|
|
||||||
import jinja2
|
import jinja2
|
||||||
|
|
||||||
from dungeonsheets import (armor, background, classes, exceptions, features,
|
from dungeonsheets import (armor, background, classes, exceptions, features,
|
||||||
magic_items, monsters, race, spells, weapons)
|
infusions, magic_items, monsters, race, spells,
|
||||||
|
weapons)
|
||||||
from dungeonsheets.armor import Armor, NoArmor, NoShield, Shield
|
from dungeonsheets.armor import Armor, NoArmor, NoShield, Shield
|
||||||
from dungeonsheets.dice import read_dice_str
|
from dungeonsheets.dice import read_dice_str
|
||||||
from dungeonsheets.stats import (Ability, ArmorClass, Initiative, Skill, Speed,
|
from dungeonsheets.stats import (Ability, ArmorClass, Initiative, Skill, Speed,
|
||||||
@@ -27,7 +29,7 @@ __version__ = read('../VERSION').strip()
|
|||||||
|
|
||||||
dice_re = re.compile('(\d+)d(\d+)')
|
dice_re = re.compile('(\d+)d(\d+)')
|
||||||
|
|
||||||
__all__ = ('Barbarian', 'Bard', 'Cleric', 'Druid', 'Fighter', 'Monk',
|
__all__ = ('Artificer', 'Barbarian', 'Bard', 'Cleric', 'Druid', 'Fighter', 'Monk',
|
||||||
'Paladin', 'Ranger', 'Rogue', 'Sorcerer', 'Warlock', 'Wizard', )
|
'Paladin', 'Ranger', 'Rogue', 'Sorcerer', 'Warlock', 'Wizard', )
|
||||||
|
|
||||||
multiclass_spellslots_by_level = {
|
multiclass_spellslots_by_level = {
|
||||||
@@ -128,6 +130,7 @@ class Character():
|
|||||||
spellcasting_ability = None
|
spellcasting_ability = None
|
||||||
_spells = list()
|
_spells = list()
|
||||||
_spells_prepared = list()
|
_spells_prepared = list()
|
||||||
|
infusions = list()
|
||||||
# Features IN MAJOR DEVELOPMENT
|
# Features IN MAJOR DEVELOPMENT
|
||||||
custom_features = list()
|
custom_features = list()
|
||||||
feature_choices = list()
|
feature_choices = list()
|
||||||
@@ -171,6 +174,7 @@ class Character():
|
|||||||
self._proficiencies_text = list()
|
self._proficiencies_text = list()
|
||||||
self._spells = list()
|
self._spells = list()
|
||||||
self._spells_prepared = list()
|
self._spells_prepared = list()
|
||||||
|
self.infusions = list()
|
||||||
self.custom_features = list()
|
self.custom_features = list()
|
||||||
self.feature_choices = list()
|
self.feature_choices = list()
|
||||||
|
|
||||||
@@ -417,6 +421,8 @@ class Character():
|
|||||||
eff_level += c.level // 2
|
eff_level += c.level // 2
|
||||||
elif type(c) in [classes.Fighter, classes.Rogue]:
|
elif type(c) in [classes.Fighter, classes.Rogue]:
|
||||||
eff_level += c.level // 3
|
eff_level += c.level // 3
|
||||||
|
elif type(c) is classes.Artificer:
|
||||||
|
eff_level += math.ceil(c.level / 2)
|
||||||
if eff_level == 0:
|
if eff_level == 0:
|
||||||
return 0
|
return 0
|
||||||
else:
|
else:
|
||||||
@@ -516,6 +522,18 @@ class Character():
|
|||||||
else:
|
else:
|
||||||
# Instantiate them all for the spells list
|
# Instantiate them all for the spells list
|
||||||
self._spells_prepared = tuple(S() for S in _spells)
|
self._spells_prepared = tuple(S() for S in _spells)
|
||||||
|
elif attr == 'infusions':
|
||||||
|
if hasattr(self, 'Artificer'):
|
||||||
|
_infusions = []
|
||||||
|
for infusion_name in val:
|
||||||
|
try:
|
||||||
|
_infusions.append(findattr(infusions, infusion_name))
|
||||||
|
except AttributeError:
|
||||||
|
msg = (f'Infusion "{infusion_name}" not defined. '
|
||||||
|
f'Please add it to ``infusions.py``')
|
||||||
|
warnings.warn(msg)
|
||||||
|
_infusions.sort(key=lambda infusion: infusion.name)
|
||||||
|
self.infusions = tuple(i() for i in _infusions)
|
||||||
else:
|
else:
|
||||||
if not hasattr(self, attr):
|
if not hasattr(self, attr):
|
||||||
warnings.warn(f"Setting unknown character attribute {attr}",
|
warnings.warn(f"Setting unknown character attribute {attr}",
|
||||||
@@ -710,6 +728,13 @@ class Character():
|
|||||||
if hasattr(self, 'Druid'):
|
if hasattr(self, 'Druid'):
|
||||||
self.Druid.wild_shapes = new_shapes
|
self.Druid.wild_shapes = new_shapes
|
||||||
|
|
||||||
|
@property
|
||||||
|
def infusions_text(self):
|
||||||
|
if hasattr(self, 'Artificer'):
|
||||||
|
return tuple([i.name for i in self.infusions])
|
||||||
|
else:
|
||||||
|
return ()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load(cls, character_file):
|
def load(cls, character_file):
|
||||||
# Create a character from the character definition
|
# Create a character from the character definition
|
||||||
@@ -788,6 +813,13 @@ def read_character_file(filename):
|
|||||||
|
|
||||||
|
|
||||||
# Add backwards compatability for tests
|
# Add backwards compatability for tests
|
||||||
|
class Artificer(Character):
|
||||||
|
def __init__(self, level=1, **attrs):
|
||||||
|
attrs['classes'] = ['Artificer']
|
||||||
|
attrs['levels'] = [level]
|
||||||
|
super().__init__(**attrs)
|
||||||
|
|
||||||
|
|
||||||
class Barbarian(Character):
|
class Barbarian(Character):
|
||||||
def __init__(self, level=1, **attrs):
|
def __init__(self, level=1, **attrs):
|
||||||
attrs['classes'] = ['Barbarian']
|
attrs['classes'] = ['Barbarian']
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
__all__ = ('CharClass', 'Barbarian', 'Bard', 'Cleric', 'Druid', 'Fighter',
|
__all__ = ('CharClass', 'Artificer', 'Barbarian', 'Bard', 'Cleric', 'Druid', 'Fighter',
|
||||||
'Monk', 'Paladin', 'Ranger', 'Rogue', 'Sorceror', 'Warlock',
|
'Monk', 'Paladin', 'Ranger', 'Rogue', 'Sorceror', 'Warlock',
|
||||||
'Wizard', 'RevisedRanger', 'available_classes')
|
'Wizard', 'RevisedRanger', 'available_classes')
|
||||||
|
|
||||||
|
from dungeonsheets.classes.artificer import Artificer
|
||||||
from dungeonsheets.classes.barbarian import Barbarian
|
from dungeonsheets.classes.barbarian import Barbarian
|
||||||
from dungeonsheets.classes.bard import Bard
|
from dungeonsheets.classes.bard import Bard
|
||||||
from dungeonsheets.classes.classes import CharClass
|
from dungeonsheets.classes.classes import CharClass
|
||||||
@@ -16,5 +17,5 @@ from dungeonsheets.classes.sorceror import Sorceror
|
|||||||
from dungeonsheets.classes.warlock import Warlock
|
from dungeonsheets.classes.warlock import Warlock
|
||||||
from dungeonsheets.classes.wizard import Wizard
|
from dungeonsheets.classes.wizard import Wizard
|
||||||
|
|
||||||
available_classes = [Barbarian, Bard, Cleric, Druid, Fighter, Monk, Paladin,
|
available_classes = [Artificer, Barbarian, Bard, Cleric, Druid, Fighter, Monk, Paladin,
|
||||||
Ranger, Rogue, Sorceror, Warlock, Wizard, RevisedRanger]
|
Ranger, Rogue, Sorceror, Warlock, Wizard, RevisedRanger]
|
||||||
|
|||||||
@@ -0,0 +1,127 @@
|
|||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
from dungeonsheets import features, weapons
|
||||||
|
from dungeonsheets.classes.classes import CharClass, SubClass
|
||||||
|
|
||||||
|
|
||||||
|
# Eberron Rising from the Last War
|
||||||
|
class Alchemist(SubClass):
|
||||||
|
"""An Alchemist is an expert at combining reagents to produce mystical
|
||||||
|
effects. Alchemists use their creations to give life and to leech it away.
|
||||||
|
Alchemy is the oldest of artificer traditions, and its versatility has
|
||||||
|
long been valued during times of war and peace.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Alchemist"
|
||||||
|
features_by_level = defaultdict(list)
|
||||||
|
features_by_level[3] = [features.AlchemistToolProficiency,
|
||||||
|
features.AlchemistSpells,
|
||||||
|
features.ExperimentalElixir]
|
||||||
|
features_by_level[5] = [features.AlchemicalSavant]
|
||||||
|
features_by_level[9] = [features.RestorativeReagents]
|
||||||
|
features_by_level[15] = [features.ChemicalMastery]
|
||||||
|
|
||||||
|
|
||||||
|
class Artillerist(SubClass):
|
||||||
|
"""An Artillerist specializes in using magic to hurl energy, projectiles,
|
||||||
|
and explosions on a battlefield. This destructive power was valued by all
|
||||||
|
the armies of the Last War. Now that the war is over, some members of this
|
||||||
|
specialization have sought to build a more peaceful world by using their
|
||||||
|
powers to fight the resurgence of strife in Khorvaire. The gnome artificer
|
||||||
|
Vi, an unlikely yet key member of House Cannith's warforged project, has
|
||||||
|
been especially vocal about making things right: "It's about time we fixed
|
||||||
|
things instead of blowing them all to hell."
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Artillerist"
|
||||||
|
features_by_level = defaultdict(list)
|
||||||
|
features_by_level[3] = [features.ArtilleristSpells,
|
||||||
|
features.ArtilleristToolProficiency,
|
||||||
|
features.EldritchCannon]
|
||||||
|
features_by_level[5] = [features.ArcaneFirearm]
|
||||||
|
features_by_level[9] = [features.ExplosiveCannon]
|
||||||
|
features_by_level[15] = [features.FortifiedPosition]
|
||||||
|
|
||||||
|
|
||||||
|
class BattleSmith(SubClass):
|
||||||
|
"""Armies require protection, and someone has to put things back together
|
||||||
|
if defenses fail. A combination of protector and medic, a Battle Smith is
|
||||||
|
an expert at defending others and repairing both material and personnel.
|
||||||
|
To aid in their work, Battle Smiths are usually accompanied by a steel
|
||||||
|
defender, a protective companion of their own creation. Many soldiers tell
|
||||||
|
stories of nearly dying before being saved by a Battle Smith and a steel
|
||||||
|
defender.
|
||||||
|
|
||||||
|
Battle Smiths played a key role in House Cannith's work on battle
|
||||||
|
constructs and the original warforged, and after the Last War, these
|
||||||
|
artificers led efforts to aid those who were injured in the war's horrific
|
||||||
|
battles.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Battle Smith"
|
||||||
|
features_by_level = defaultdict(list)
|
||||||
|
features_by_level[3] = [features.BattleSmithSpells,
|
||||||
|
features.BattleSmithToolProficiency,
|
||||||
|
features.BattleReady,
|
||||||
|
features.SteelDefender]
|
||||||
|
features_by_level[5] = [features.ExtraAttackBattleSmith]
|
||||||
|
features_by_level[9] = [features.ArcaneJolt]
|
||||||
|
features_by_level[15] = [features.ImprovedDefender]
|
||||||
|
|
||||||
|
|
||||||
|
class Artificer(CharClass):
|
||||||
|
name = "Artificer"
|
||||||
|
hit_dice_faces = 8
|
||||||
|
subclass_select_level = 3
|
||||||
|
subclasses_available = (Alchemist, Artillerist, BattleSmith)
|
||||||
|
saving_throw_proficiencies = ('intelligence', 'constitution')
|
||||||
|
primary_abilities = ('intelligence',)
|
||||||
|
_proficiencies_text = (
|
||||||
|
'Light armor', 'Medium armor', 'Shields', 'Simple weapons',
|
||||||
|
"Thieve's tools", "Tinker's tools",
|
||||||
|
"One type of artisan's tools of your choice")
|
||||||
|
_multiclass_proficiencies_text = (
|
||||||
|
"Light armor", "Medium armor", "Shields",
|
||||||
|
"Thieve's tools", "Tinker's tools")
|
||||||
|
weapon_proficiencies = (weapons.SimpleWeapon,)
|
||||||
|
infusions = []
|
||||||
|
class_skill_choices = (
|
||||||
|
'Arcana', 'History', 'Investigation',
|
||||||
|
'Medicine', 'Nature', 'Perception', 'Sleight of Hand')
|
||||||
|
features_by_level = defaultdict(list)
|
||||||
|
features_by_level[1] = [features.MagicalTinkering,
|
||||||
|
features.FirearmProficiency,
|
||||||
|
features.ArtificerSpellcasting,
|
||||||
|
features.ArtificerRitualCasting]
|
||||||
|
features_by_level[2] = [features.InfuseItem]
|
||||||
|
features_by_level[3] = [features.TheRightToolForTheJob]
|
||||||
|
features_by_level[6] = [features.ToolExpertise]
|
||||||
|
features_by_level[7] = [features.FlashOfGenius]
|
||||||
|
features_by_level[10] = [features.MagicItemAdept]
|
||||||
|
features_by_level[11] = [features.SpellStoringItem]
|
||||||
|
features_by_level[14] = [features.MagicItemSavant]
|
||||||
|
features_by_level[18] = [features.MagicItemMaster]
|
||||||
|
features_by_level[20] = [features.SoulOfArtifice]
|
||||||
|
spellcasting_ability = 'intelligence'
|
||||||
|
spell_slots_by_level = {
|
||||||
|
1: (2, 2, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||||
|
2: (2, 2, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||||
|
3: (2, 3, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||||
|
4: (2, 3, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||||
|
5: (2, 4, 2, 0, 0, 0, 0, 0, 0, 0),
|
||||||
|
6: (2, 4, 2, 0, 0, 0, 0, 0, 0, 0),
|
||||||
|
7: (2, 4, 3, 0, 0, 0, 0, 0, 0, 0),
|
||||||
|
8: (2, 4, 3, 0, 0, 0, 0, 0, 0, 0),
|
||||||
|
9: (2, 4, 3, 2, 0, 0, 0, 0, 0, 0),
|
||||||
|
10: (3, 4, 3, 2, 0, 0, 0, 0, 0, 0),
|
||||||
|
11: (3, 4, 3, 3, 0, 0, 0, 0, 0, 0),
|
||||||
|
12: (3, 4, 3, 3, 0, 0, 0, 0, 0, 0),
|
||||||
|
13: (3, 4, 3, 3, 1, 0, 0, 0, 0, 0),
|
||||||
|
14: (4, 4, 3, 3, 1, 0, 0, 0, 0, 0),
|
||||||
|
15: (4, 4, 3, 3, 2, 0, 0, 0, 0, 0),
|
||||||
|
16: (4, 4, 3, 3, 2, 0, 0, 0, 0, 0),
|
||||||
|
17: (4, 4, 3, 3, 3, 1, 0, 0, 0, 0),
|
||||||
|
18: (4, 4, 3, 3, 3, 1, 0, 0, 0, 0),
|
||||||
|
19: (4, 4, 3, 3, 3, 2, 0, 0, 0, 0),
|
||||||
|
20: (4, 4, 3, 3, 3, 2, 0, 0, 0, 0)
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
from dungeonsheets.features.artificer import *
|
||||||
from dungeonsheets.features.backgrounds import *
|
from dungeonsheets.features.backgrounds import *
|
||||||
from dungeonsheets.features.barbarian import *
|
from dungeonsheets.features.barbarian import *
|
||||||
from dungeonsheets.features.bard import *
|
from dungeonsheets.features.bard import *
|
||||||
|
|||||||
@@ -0,0 +1,675 @@
|
|||||||
|
from dungeonsheets import spells
|
||||||
|
from dungeonsheets.features.features import Feature
|
||||||
|
|
||||||
|
|
||||||
|
class _SpecialistSpells(Feature):
|
||||||
|
"""Starting at 3rd level, you always have certain spells prepared after
|
||||||
|
you reach particular levels in this class, as shown in the Specialization
|
||||||
|
Spells table. These spells count as artificer spells for you, but they
|
||||||
|
don't count against the number of artificer spells you prepare.
|
||||||
|
"""
|
||||||
|
_name = "Select One"
|
||||||
|
source = "Artificer"
|
||||||
|
_spells = {
|
||||||
|
3: [],
|
||||||
|
5: [],
|
||||||
|
9: [],
|
||||||
|
13: [],
|
||||||
|
17: []
|
||||||
|
}
|
||||||
|
spells_known = []
|
||||||
|
spells_prepared = []
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return "{:s} Spells".format(self._name)
|
||||||
|
|
||||||
|
def __init__(self, owner=None):
|
||||||
|
if owner is not None:
|
||||||
|
level = owner.Artificer.level
|
||||||
|
for lvl, spl in self._spells.items():
|
||||||
|
if level >= lvl:
|
||||||
|
self.spells_known.extend(spl)
|
||||||
|
self.spells_prepared.extend(spl)
|
||||||
|
super().__init__(owner=owner)
|
||||||
|
|
||||||
|
|
||||||
|
# Alchemist
|
||||||
|
class ArtificerSpellcasting(Feature):
|
||||||
|
"""You have studied the workings of magic and how to channel it through
|
||||||
|
objects. As a result, you have gained the ability to cast spells. To
|
||||||
|
observers, you don't appear to be casting spells in a conventional way; you
|
||||||
|
look as if you're producing wonders using mundane items or outlandish
|
||||||
|
inventions.
|
||||||
|
|
||||||
|
**Tools Required** You produce your artificer spell effects through your
|
||||||
|
tools. You must have a spellcasting focus-specifically thieves' tools or
|
||||||
|
some kind of artisan's tool-in hand when you cast any spell with this
|
||||||
|
Spellcasting feature. You must be proficient with the tool to use it in
|
||||||
|
this way. See chapter 5, "Equipment," in the Player's Handbook for
|
||||||
|
descriptions of these tools.
|
||||||
|
|
||||||
|
After you gain the Infuse Item feature at 2nd level, you can also use any
|
||||||
|
item bearing one of your infusions as a spellcasting focus.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Spellcasting"
|
||||||
|
source = "Artificer"
|
||||||
|
|
||||||
|
|
||||||
|
class ArtificerRitualCasting(Feature):
|
||||||
|
"""You can cast an artificer spell as a ritual if that spell has the ritual
|
||||||
|
tag and you have the spell prepared.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Ritual Casting"
|
||||||
|
source = "Artificer"
|
||||||
|
|
||||||
|
|
||||||
|
class FirearmProficiency(Feature):
|
||||||
|
"""The secrets of creating and operating gunpowder weapons have been
|
||||||
|
discovered in various corners of the D&D multiverse. If your Dungeon Master
|
||||||
|
uses the rules on firearms in chapter 9 of the Dungeon Master's Guide and
|
||||||
|
your artificer has been exposed to the operation of such weapons, your
|
||||||
|
artificer is proficient with them.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Optional Rule: Firearm Proficiency"
|
||||||
|
source = "Artificer"
|
||||||
|
|
||||||
|
|
||||||
|
class MagicalTinkering(Feature):
|
||||||
|
"""At 1st level, you learn how to invest a spark of magic into mundane
|
||||||
|
objects. To use this ability, you must have tinker's tools or other
|
||||||
|
artisan's tools in hand. You then touch a Tiny nonmagical object as an
|
||||||
|
action and give it one of the following magical properties of your choice:
|
||||||
|
|
||||||
|
• The object sheds bright light in a 5-foot radius and dim light for an
|
||||||
|
additional 5 fe et.
|
||||||
|
|
||||||
|
• Whenever tapped by a creature, the object emits a recorded message that
|
||||||
|
can be heard up to 10 feet away. You utter the message when you bestow
|
||||||
|
this property on the object, and the recording can be no more than 6
|
||||||
|
seconds long.
|
||||||
|
|
||||||
|
• The object continuously emits your choice of an odor or a nonverbal sound
|
||||||
|
(wind, waves, chirping, or the like). The chosen phenomenon is
|
||||||
|
perceivable up to 10 feet away.
|
||||||
|
|
||||||
|
• A static visual effect appears on one of the object's surfaces. This
|
||||||
|
effect can be a picture, up to 25 words of text, lines and shapes, or a
|
||||||
|
mixture of these elements, as you like. The chosen property lasts
|
||||||
|
indefinitely. As an action, you can touch the object and end the property
|
||||||
|
early. You can bestow magic on multiple objects, touching one object each
|
||||||
|
time you use this feature, though a single object can only bear one
|
||||||
|
property at a time. The maximum number of objects you can affect with
|
||||||
|
this feature at one time is equal to your Intelligence modifier (minimum
|
||||||
|
of one object). If you try to exceed your maximum, the oldest property
|
||||||
|
immediately ends, and then the new property applies.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Magical Tinkering"
|
||||||
|
source = "Artificer"
|
||||||
|
|
||||||
|
|
||||||
|
class InfuseItem(Feature):
|
||||||
|
"""At 2nd level, you gain the ability to imbue mundane items with certain
|
||||||
|
magical infusions. The magic items you create with this feature are
|
||||||
|
effectively prototypes of permanent items.
|
||||||
|
|
||||||
|
**Infusions known**
|
||||||
|
When you gain this feature, pick four artificer infusions
|
||||||
|
to learn, choosing from the "Artificer Infusions" section at the end of the
|
||||||
|
class's description. You learn additional infusions of your choice when you
|
||||||
|
reach certain levels in this class, as shown in the Infusions Known column
|
||||||
|
of the Artificer table. Whenever you gain a level in this class, you can
|
||||||
|
replace one of the artificer infusions you learned with a new one.
|
||||||
|
|
||||||
|
**Infusing an item**
|
||||||
|
Whenever you finish a long rest, you can touch a nonmagical object and
|
||||||
|
imbue it with one of your artificer infusions, turning it into a magic
|
||||||
|
item. An infusion works on only certain kinds of objects, as specified in
|
||||||
|
the infusion's description. If the item requires attunement, you can
|
||||||
|
attune yourself to it the instant you infuse the item. If you decide to
|
||||||
|
attune to the item later, you must do so using the normal process for
|
||||||
|
attunement (see "Attunement" in chapter 7 of the Dungeon Master's Guide).
|
||||||
|
Your infusion remains in an item indefinitely, but when you die, the
|
||||||
|
infusion vanishes after a number of days have passed equal to your
|
||||||
|
Intelligence modifier (minimum of 1 day). The infusion also vanishes if you
|
||||||
|
give up your knowledge of the infusion for another one. You can infuse more
|
||||||
|
than one nonmagical object at the end of a long rest; the maximum number of
|
||||||
|
objects appears in the Infused Items column of the Artificer table. You
|
||||||
|
must touch each of the objects, and each of your infusions can be in only
|
||||||
|
one object at a time. Moreover, no object can bear more than one of your
|
||||||
|
infusions at a time. If you try to exceed your maximum number of
|
||||||
|
infusions, the oldest infusion immediately ends, and then the new
|
||||||
|
infusion applies.
|
||||||
|
"""
|
||||||
|
|
||||||
|
_name = "Infuse Item"
|
||||||
|
source = "Artificer"
|
||||||
|
_infusions = {
|
||||||
|
# level: (infusions known, infused items)
|
||||||
|
2: (4, 2),
|
||||||
|
3: (4, 2),
|
||||||
|
4: (4, 2),
|
||||||
|
5: (4, 2),
|
||||||
|
5: (4, 2),
|
||||||
|
6: (6, 3),
|
||||||
|
7: (6, 3),
|
||||||
|
8: (6, 3),
|
||||||
|
9: (6, 3),
|
||||||
|
10: (8, 4),
|
||||||
|
11: (8, 4),
|
||||||
|
12: (8, 4),
|
||||||
|
13: (8, 4),
|
||||||
|
14: (10, 5),
|
||||||
|
15: (10, 5),
|
||||||
|
16: (10, 5),
|
||||||
|
17: (10, 5),
|
||||||
|
18: (12, 6),
|
||||||
|
19: (12, 6),
|
||||||
|
20: (12, 6),
|
||||||
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
known_infusions = self._infusions[self.owner.Artificer.level][0]
|
||||||
|
infused_items = self._infusions[self.owner.Artificer.level][1]
|
||||||
|
name_ext = " ({:d} Infusions Known, {:d} Infused Items)"
|
||||||
|
return self._name + name_ext.format(known_infusions, infused_items)
|
||||||
|
|
||||||
|
|
||||||
|
class ArtificerSpecialist(Feature):
|
||||||
|
"""At 3rd level, you choose the type of specialist you are: Alchemist,
|
||||||
|
Artillerist, or Battle Smith, each of which is detailed at the end of the
|
||||||
|
class's description. Your choice grants you features at 5th level and again
|
||||||
|
at 9th and 15th level.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Artificer Specialist"
|
||||||
|
source = "Artificer"
|
||||||
|
|
||||||
|
|
||||||
|
class TheRightToolForTheJob(Feature):
|
||||||
|
"""At 3rd level, you learn how to produce exactly the tool you need: with
|
||||||
|
tinker's tools in hand, you can magically create one set of artisan's tools
|
||||||
|
in an unoccupied space within 5 feet of you. This creation requires 1 hour
|
||||||
|
of uninterrupted work, which can coincide with a short or long rest.
|
||||||
|
Though the product of magic, the tools are nonmagical, and they vanish when
|
||||||
|
you use this feature again.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "The Right Tool For The Job"
|
||||||
|
source = "Artificer"
|
||||||
|
|
||||||
|
|
||||||
|
class ToolExpertise(Feature):
|
||||||
|
"""Starting at 6th level, your proficiency bonus is doubled for any ability
|
||||||
|
check you make that uses your proficiency with a tool.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Tool Expertise"
|
||||||
|
source = "Artificer"
|
||||||
|
|
||||||
|
|
||||||
|
class FlashOfGenius(Feature):
|
||||||
|
"""Starting at 7th level, you gain the ability to come up with solutions
|
||||||
|
under pressure. When you or another creature you can see within 30 feet of
|
||||||
|
you makes an ability check or a saving throw, you can use your reaction to
|
||||||
|
add your Intelligence modifier to the roll.
|
||||||
|
|
||||||
|
You can use this feature a number of times equal to your Intelligence
|
||||||
|
modifier (minimum of once). You regain all expended uses when you finish a
|
||||||
|
long rest.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Flash Of Genius"
|
||||||
|
source = "Arificer"
|
||||||
|
|
||||||
|
|
||||||
|
class MagicItemAdept(Feature):
|
||||||
|
"""When you reach 10th level, you achieve a profound understanding of how
|
||||||
|
to use and make magic items:
|
||||||
|
|
||||||
|
• You can attune to up to four magic items at once.
|
||||||
|
|
||||||
|
• If you craft a magic item with a rarity of common or uncommon, it takes
|
||||||
|
you a quarter of the normal time, and it costs you half as much of the
|
||||||
|
usual gold.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Magic Item Adept"
|
||||||
|
source = "Artificer"
|
||||||
|
|
||||||
|
|
||||||
|
class SpellStoringItem(Feature):
|
||||||
|
"""At 11th level, you learn how to store a spell in an object. Whenever you
|
||||||
|
finish a long rest, you can touch one simple or martial weapon or one item
|
||||||
|
that you can use as a spellcasting focus, and you store a spell in it,
|
||||||
|
choosing a 1st• or 2nd-level spell from the artificer spell list that
|
||||||
|
requires 1 action to cast (you needn't have it prepared).
|
||||||
|
|
||||||
|
While holding the object, a creature can take an action to produce the
|
||||||
|
spell's effect from it, using your spellcasting ability modifier. If the
|
||||||
|
spell requires concentration, the creature must concentrate. The spell
|
||||||
|
stays in the object until it's been used a number of times equal to twice
|
||||||
|
your Intelligence modifier (minimum of twice) or until you use this fe
|
||||||
|
ature again to store a spell in an object.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Spell-Storing Item"
|
||||||
|
source = "Artificer"
|
||||||
|
|
||||||
|
|
||||||
|
class MagicItemSavant(Feature):
|
||||||
|
"""At 14th level, your skill with magic items deepens more:
|
||||||
|
|
||||||
|
• You can attune to up to five magic items at once.
|
||||||
|
|
||||||
|
• You ignore all class, race, spell, and level requirements on attuning to
|
||||||
|
or using a magic item.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Magic Item Savant"
|
||||||
|
source = "Artificer"
|
||||||
|
|
||||||
|
|
||||||
|
class MagicItemMaster(Feature):
|
||||||
|
"""Starting at 18th level, you can attune to up to six magic items at
|
||||||
|
once.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Magic Item Master"
|
||||||
|
source = "Artificer"
|
||||||
|
|
||||||
|
|
||||||
|
class SoulOfArtifice(Feature):
|
||||||
|
"""At 20th level, you develop a mystical connection to your magic items,
|
||||||
|
which you can draw on for protection:
|
||||||
|
|
||||||
|
• You gain a +1 bonus to all saving throws per magic item you are currently
|
||||||
|
attuned to.
|
||||||
|
|
||||||
|
• If you're reduced to 0 hit points but not killed outright, you can use
|
||||||
|
your reaction to end one of your artificer infusions, causing you to drop
|
||||||
|
to 1 hit point instead of 0.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Soul of Artifice"
|
||||||
|
source = "Artificer"
|
||||||
|
|
||||||
|
|
||||||
|
# Alchemist
|
||||||
|
class AlchemistToolProficiency(Feature):
|
||||||
|
"""When you adopt this specialization at 3rd level, you gain proficiency
|
||||||
|
with alchemist's supplies. If you already have this proficiency, you gain
|
||||||
|
proficiency with one other type of artisan's tools of your choice.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Tool Proficiency"
|
||||||
|
source = "Artificer (Alchemist)"
|
||||||
|
|
||||||
|
|
||||||
|
class AlchemistSpells(_SpecialistSpells):
|
||||||
|
"""Starting at 3rd level, you always have certain spells prepared after
|
||||||
|
you reach particular levels in this class, as shown in the Alchemist Spells
|
||||||
|
table. These spells count as artificer spells for you, but they don't count
|
||||||
|
against the number of artificer spells you prepare.
|
||||||
|
"""
|
||||||
|
|
||||||
|
_name = "Alchemist"
|
||||||
|
_spells = {
|
||||||
|
3: [spells.HealingWord, spells.RayOfSickness],
|
||||||
|
5: [spells.FlamingSphere, spells.MelfsAcidArrow],
|
||||||
|
9: [spells.GaseousForm, spells.MassHealingWord],
|
||||||
|
13: [spells.Blight, spells.DeathWard],
|
||||||
|
17: [spells.Cloudkill, spells.RaiseDead]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ExperimentalElixir(Feature):
|
||||||
|
"""Beginning at 3rd level, whenever you finish a long rest, you can
|
||||||
|
magically produce an *experimental elixir* in an empty flask you touch.
|
||||||
|
Roll on the Experimental Elixir table for the elixir's effect, which is
|
||||||
|
triggered when someone drinks the elixir. As an action, a creature can
|
||||||
|
drink the elixir or administer it to an incapacitated creature.
|
||||||
|
|
||||||
|
Creating an *experimental elixir* requires you to have alchemist supplies
|
||||||
|
on your person, and any elixir you create with this feature lasts until it
|
||||||
|
is drunk or until the end of your next long rest.
|
||||||
|
|
||||||
|
When you reach certain levels in this class, you can make more elixirs at
|
||||||
|
the end of a long rest: two at 6th level and three at 15th level. Roll for
|
||||||
|
each elixir's effect separately. Each elixir requires its own flask.
|
||||||
|
|
||||||
|
You can create additional *experimental elixirs* by expending a spell slot
|
||||||
|
of 1st level or higher for each one. When you do so, you use your action to
|
||||||
|
create the elixir in an empty flask you touch, and you choose the elixir's
|
||||||
|
effect from the Experimental Elixir table.
|
||||||
|
|
||||||
|
**Experimental Elixir**
|
||||||
|
|
||||||
|
roll d6
|
||||||
|
|
||||||
|
**1 -- Healing.** The drinker regains a number of hit points equal to 2d4 +
|
||||||
|
your Intelligence modifier.
|
||||||
|
|
||||||
|
**2 -- Swiftness.** The drinker's walking speed increases by 10 feet for 1
|
||||||
|
hour.
|
||||||
|
|
||||||
|
**3 -- Resilience.** The drinker gains a +1 bonus to AC for 10 minutes.
|
||||||
|
|
||||||
|
**4 -- Boldness.** The drinker can roll a d4 and add the number rolled to
|
||||||
|
every attack roll and saving throw they make for the next minute.
|
||||||
|
|
||||||
|
**5 -- Flight.** The drinker gains a flying speed of 10 feet for 10
|
||||||
|
minutes.
|
||||||
|
|
||||||
|
**6 -- Transformation.** The drinker's body is transformed as if by the
|
||||||
|
alter self spell. The drinker determines the transformation caused by the
|
||||||
|
spell, the effects of which last for 10 minutes.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Experimental Elixir"
|
||||||
|
source = "Artificer (Alchemist)"
|
||||||
|
|
||||||
|
|
||||||
|
class AlchemicalSavant(Feature):
|
||||||
|
"""At 5th level, you develop masterful command of magical chemicals,
|
||||||
|
enhancing the healing and damage you create through them. Whenever you
|
||||||
|
cast a spell using your alchemist's supplies as the spellcasting focus, you
|
||||||
|
gain a bonus to one roll of the spell. That roll must restore hit points or
|
||||||
|
be a damage roll that deals acid, fire, necrotic, or poison damage, and the
|
||||||
|
bonus equals your Intelligence modifier (minimum of +1).
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Alchemical Savant"
|
||||||
|
source = "Artificer (Alchemist)"
|
||||||
|
|
||||||
|
|
||||||
|
class RestorativeReagents(Feature):
|
||||||
|
"""Starting at 9th level, you can incorporate
|
||||||
|
restorative reagents into some of your works:
|
||||||
|
|
||||||
|
• Whenever a creature drinks an experimental elixir you created, the
|
||||||
|
creature gains temporary hit points equal to 2d6 + your Intelligence
|
||||||
|
modifier (minimum of 1 temporary hit point).
|
||||||
|
|
||||||
|
• You can cast lesser restoration without expending a spell slot and
|
||||||
|
without preparing the spell, provided you use alchemist's supplies as the
|
||||||
|
spellcasting focus. You can do so a number of times equal to your
|
||||||
|
Intelligence modifier (minimum of once), and you regain all expended uses
|
||||||
|
when you finish a long rest.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Restorative Reagents"
|
||||||
|
source = "Artificer (Alchemist)"
|
||||||
|
|
||||||
|
|
||||||
|
class ChemicalMastery(Feature):
|
||||||
|
"""By 15th level, you have been exposed to so many chemicals that they
|
||||||
|
pose little risk to you, and you can use them to quickly end certain
|
||||||
|
ailments:
|
||||||
|
|
||||||
|
• You gain resistance to acid damage and poison damage, and you are immune
|
||||||
|
to the poisoned condition.
|
||||||
|
|
||||||
|
• You can cast greater restoration and heal without expending a spell
|
||||||
|
slot, without preparing the spell, and without material components,
|
||||||
|
provided you use alchemist's supplies as the spellcasting focus. Once
|
||||||
|
you cast either spell with this feature, you can't cast that spell with
|
||||||
|
it again until you finish a long rest.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Chemical Mastery"
|
||||||
|
source = "Artificer (Alchemist)"
|
||||||
|
|
||||||
|
|
||||||
|
# Artillerist
|
||||||
|
class ArtilleristSpells(_SpecialistSpells):
|
||||||
|
"""Starting at 3rd level, you always have certain spells prepared after
|
||||||
|
you reach particular levels in this class, as shown in the Artillerist
|
||||||
|
Spells table. These spells count as artificer spells for you, but they
|
||||||
|
don't count against the number of artificer spells you prepare.
|
||||||
|
"""
|
||||||
|
|
||||||
|
_name = "Artillerist"
|
||||||
|
_spells = {
|
||||||
|
3: [spells.Shield, spells.Thunderwave],
|
||||||
|
5: [spells.ScorchingRay, spells.Shatter],
|
||||||
|
9: [spells.Fireball, spells.WindWall],
|
||||||
|
13: [spells.IceStorm, spells.WallOfFire],
|
||||||
|
17: [spells.ConeOfCold, spells.WallOfForce]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ArtilleristToolProficiency(Feature):
|
||||||
|
"""When you adopt this specialization at 3rd level, you gain proficiency
|
||||||
|
with woodcarver's tools. If you already have this proficiency, you gain
|
||||||
|
proficiency with one other type of artisan's tools of your choice.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Tool Proficiency"
|
||||||
|
source = "Artificer (Artillerist)"
|
||||||
|
|
||||||
|
|
||||||
|
class EldritchCannon(Feature):
|
||||||
|
"""At 3rd level, you learn how to create a magical cannon. Using
|
||||||
|
woodcarver's tools or smith's tools, you can take an action to magically
|
||||||
|
create a Small or Tiny eldritch cannon in an unoccupied space on a
|
||||||
|
horizontal surface within 5 feet of you. A Small eldritch cannon occupies
|
||||||
|
its space, and a Tiny one can be held in one hand.
|
||||||
|
|
||||||
|
Once you create a cannon, you can't do so again until you finish a long
|
||||||
|
rest or until you expend a spell slot of 1st level or higher. You can have
|
||||||
|
only one cannon at a time and can't create one while your cannon is
|
||||||
|
present.
|
||||||
|
|
||||||
|
The cannon is a magical object. Regardless of size, the cannon has an AC of
|
||||||
|
18 and a number of hit points equal to five times your artificer level. It
|
||||||
|
is immune to poison damage, psychic damage, and all conditions. If it is
|
||||||
|
forced to make an ability check or a saving throw, treat all its ability
|
||||||
|
scores as 10 (+O). If the *mending* spell is cast on it, it regains 2d6 hit
|
||||||
|
points. It disappears if it is reduced to 0 hit points or after 1 hour. You
|
||||||
|
can dismiss it early as an action.
|
||||||
|
|
||||||
|
When you create the cannon, you determine its appearance and whether it
|
||||||
|
has legs. You also decide which type it is, choosing from the options on
|
||||||
|
the Eldritch Cannons table. On each of your turns, you can take a bonus
|
||||||
|
action to cause the cannon to activate if you are within 60 feet of it. As
|
||||||
|
part of the same bonus action, you can direct the cannon to walk or climb
|
||||||
|
up to 15 feet to an unoccupied space, provided it has legs.
|
||||||
|
|
||||||
|
**Eldritch Cannons**
|
||||||
|
|
||||||
|
*Flamethrower*: The cannon exhales fire in an adjacent 15-foot cone that
|
||||||
|
you designate. Each creature in that area must make a Dexterity saving
|
||||||
|
throw against your spell save DC, taking 2d8 fire damage on a failed save
|
||||||
|
or half as much damage on a successful one. The fire ignites any flammable
|
||||||
|
objects in the area that aren't being worn or carried.
|
||||||
|
|
||||||
|
*Force Ballista*: Make a ranged spell attack, originating from the cannon,
|
||||||
|
at one creature or object within 120 feet of it. On a hit, the target takes
|
||||||
|
2d8 force damage, and if the target is a creature, it is pushed up to 5
|
||||||
|
feet away from the cannon.
|
||||||
|
|
||||||
|
*Protector*: The cannon emits a burst of positive energy
|
||||||
|
that grants itself and each creature of your choice within 10 feet of it a
|
||||||
|
number of temporary hit points equal to 1d8 + your Intelligence modifier
|
||||||
|
(minimum of +1)
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Eldritch Cannon"
|
||||||
|
source = "Artificer (Artillerist)"
|
||||||
|
|
||||||
|
|
||||||
|
class ArcaneFirearm(Feature):
|
||||||
|
"""At 5th level, you know how to turn a wand, staff, or rod into an arcane
|
||||||
|
firearm, a conduit for your destructive spells. When you finish a long
|
||||||
|
rest, you can use woodcarver's tools to carve special sigils into a wand,
|
||||||
|
staff, or rod and thereby turn it into your arcane firearm. The sigils
|
||||||
|
disappear from the object if you later carve them on a different item. The
|
||||||
|
sigils otherwise last indefinitely.
|
||||||
|
|
||||||
|
You can use your arcane firearm as a spellcasting focus for your artificer
|
||||||
|
spells. When you cast an artificer spell through the firearm, roll a d8,
|
||||||
|
and you gain a bonus to one of the spell's damage rolls equal to the
|
||||||
|
number rolled.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Arcane Firearm"
|
||||||
|
source = "Artificer (Artillerist)"
|
||||||
|
|
||||||
|
|
||||||
|
class ExplosiveCannon(Feature):
|
||||||
|
"""Starting at 9th level, every eldritch cannon you create is more
|
||||||
|
destructive:
|
||||||
|
|
||||||
|
• The cannon's damage rolls all increase by 1d8.
|
||||||
|
|
||||||
|
• As an action, you can command the cannon to detonate if you are within 60
|
||||||
|
feet of it. Doing so destroys the cannon and forces each creature within
|
||||||
|
20 feet of it to make a Dexterity saving throw against your spell save
|
||||||
|
DC, taking 3d8 force damage on a failed save or half as much damage on a
|
||||||
|
successful one.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Explosive Cannon"
|
||||||
|
source = "Artificer (Artillerist)"
|
||||||
|
|
||||||
|
|
||||||
|
class FortifiedPosition(Feature):
|
||||||
|
"""Starting at 15th level, you're a master at forming well-defended
|
||||||
|
emplacements using Eldritch Cannon:
|
||||||
|
|
||||||
|
• You and your allies have half cover while within 10 feet of a cannon you
|
||||||
|
create with Eldritch Cannon, as a result of a shimmering field of magical
|
||||||
|
protection that the cannon emits.
|
||||||
|
|
||||||
|
• You can now have two cannons at the same time. You can create two with
|
||||||
|
the same action (but not the same spell slot), and you can activate both
|
||||||
|
of them with the same bonus action. You determine whether the cannons are
|
||||||
|
identical to each other or different. You can't create a third cannon
|
||||||
|
while you have two.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Fortified Position"
|
||||||
|
source = "Artificer (Artillerist)"
|
||||||
|
|
||||||
|
|
||||||
|
# Battle Smith
|
||||||
|
class BattleSmithSpells(_SpecialistSpells):
|
||||||
|
"""Starting at 3rd level, you always have certain spells prepared after you
|
||||||
|
reach particular levels in this class, as shown in the Battle Smith Spells
|
||||||
|
table. These spells count as artificer spells for you, but they don't count
|
||||||
|
against the number of artificer spells you prepare.
|
||||||
|
"""
|
||||||
|
|
||||||
|
_name = "Battle Smith"
|
||||||
|
_spells = {
|
||||||
|
3: [spells.Heroism, spells.Shield],
|
||||||
|
5: [spells.BrandingSmite, spells.WardingBond],
|
||||||
|
9: [spells.AuraOfVitality, spells.ConjureBarrage],
|
||||||
|
13: [spells.AuraOfPurity, spells.FireShield],
|
||||||
|
17: [spells.BanishingSmite, spells.MassCureWounds]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class BattleSmithToolProficiency(Feature):
|
||||||
|
"""When you adopt this specialization at 3rd level, you gain proficiency
|
||||||
|
with smith's tools. If you already have this proficiency, you gain
|
||||||
|
proficiency with one other type of artisan's tools of your choice.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Tool Proficiency"
|
||||||
|
source = "Artificer (Battle Smith)"
|
||||||
|
|
||||||
|
|
||||||
|
class BattleReady(Feature):
|
||||||
|
"""When you reach 3rd level, your combat training and your experiments with
|
||||||
|
magic have paid off in two ways:
|
||||||
|
|
||||||
|
• You gain proficiency with martial weapons.
|
||||||
|
|
||||||
|
• When you attack with a magic weapon, you can use your Intelligence
|
||||||
|
modifier, instead of Strength or Dexterity modifier, for the attack and
|
||||||
|
damage rolls.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Battle Ready"
|
||||||
|
source = "Artificer (Battle Smith)"
|
||||||
|
|
||||||
|
|
||||||
|
class SteelDefender(Feature):
|
||||||
|
"""By 3rd level, your tinkering has borne you a faithful companion, a steel
|
||||||
|
defender. It is friendly to you and your companions, and it obeys your
|
||||||
|
commands. See this creature's game statistics in the steel defender stat
|
||||||
|
block. You determine the creature's appearance and whether it has two legs
|
||||||
|
or fo ur; your choice has no effect on its game statistics.
|
||||||
|
|
||||||
|
In combat, the steel defender shares your initiative count, but it takes
|
||||||
|
its turn immediately after yours. It can move and use its reaction on its
|
||||||
|
own, but the only action it takes on its turn is the Dodge action, unless
|
||||||
|
you take a bonus action on your turn to command it to take one of the
|
||||||
|
actions in its stat block or the Dash, Disengage, Help, Hide, or Search
|
||||||
|
action.
|
||||||
|
|
||||||
|
If the *mending* spell is cast on it, it regains 2d6 hit points. If it has
|
||||||
|
died within the last hour, you can use your smith's tools as an action to
|
||||||
|
revive it, provided you are within 5 feet of it and you expend a spell slot
|
||||||
|
of 1st level or higher. The steel defender returns to life after 1 minute
|
||||||
|
with all its hit points restored.
|
||||||
|
|
||||||
|
At the end of a long rest, you can create a new steel defender if you have
|
||||||
|
your smith's tools with you. If you already have a steel defender from this
|
||||||
|
feature, the first one immediately perishes.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Steel Defender"
|
||||||
|
source = "Artificer (Battle Smith)"
|
||||||
|
|
||||||
|
|
||||||
|
class ExtraAttackBattleSmith(Feature):
|
||||||
|
"""Starting at 5th level, you can attack twice, rather than once, whenever
|
||||||
|
you take the Attack action on your turn.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Extra Attack"
|
||||||
|
source = "Artificer (Battle Smith)"
|
||||||
|
|
||||||
|
|
||||||
|
class ArcaneJolt(Feature):
|
||||||
|
"""At 9th level, you learn new ways to channel arcane energy to harm or
|
||||||
|
heal. When either you hit a target with a magic weapon attack or your steel
|
||||||
|
defender hits a target, you can channel magical energy through the strike
|
||||||
|
to create one of the following effects:
|
||||||
|
|
||||||
|
• The target takes an extra 2d6 force damage.
|
||||||
|
|
||||||
|
• Choose one creature or object you can see within 30 feet of the target.
|
||||||
|
Healing energy flows into the chosen recipient, restoring 2d6 hit points
|
||||||
|
to it. You can use this energy a number of times equal to your
|
||||||
|
Intelligence modifier (minimum of once), but you can do so no more than
|
||||||
|
once on a turn. You regain all expended uses when you finish a long rest
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Arcane Jolt"
|
||||||
|
source = "Artificer (Battle Smith)"
|
||||||
|
|
||||||
|
|
||||||
|
class ImprovedDefender(Feature):
|
||||||
|
"""At 15th level, your Arcane jolt and steel defender become more
|
||||||
|
powerful:
|
||||||
|
|
||||||
|
• The extra damage and the healing of your Arcane jolt both increase to
|
||||||
|
4d6.
|
||||||
|
|
||||||
|
• Your steel defender gains a +2 bonus to Armor Class.
|
||||||
|
|
||||||
|
• Whenever your steel defender uses its Deflect Attack, the attacker takes
|
||||||
|
force damage equal to 1d4 +your Intelligence modifier.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Improved Defender"
|
||||||
|
source = "Artificer (Battle Smith)"
|
||||||
@@ -85,6 +85,9 @@ spells_prepared = {{ char.spells_prepared }}
|
|||||||
# Wild shapes for Druid
|
# Wild shapes for Druid
|
||||||
wild_shapes = {{ char.all_wild_shapes }} # Ex: ('ape', 'wolf', 'ankylosaurus')
|
wild_shapes = {{ char.all_wild_shapes }} # Ex: ('ape', 'wolf', 'ankylosaurus')
|
||||||
|
|
||||||
|
# Infusions for Artificer
|
||||||
|
infusions = {{ char.infusions_text }} # Ex: ('repeating shot', 'replicate magic item')
|
||||||
|
|
||||||
# Backstory
|
# Backstory
|
||||||
# Describe your backstory here
|
# Describe your backstory here
|
||||||
personality_traits = """{{ char.personality_traits}}"""
|
personality_traits = """{{ char.personality_traits}}"""
|
||||||
|
|||||||
@@ -92,6 +92,9 @@ spells = spells_prepared + __spells_unprepared
|
|||||||
# Wild shapes for Druid
|
# Wild shapes for Druid
|
||||||
wild_shapes = () # Ex: ('ape', 'wolf', 'ankylosaurus')
|
wild_shapes = () # Ex: ('ape', 'wolf', 'ankylosaurus')
|
||||||
|
|
||||||
|
# Infusions for Artificer
|
||||||
|
infusions = {{ char.infusions_text }} # Ex: ('repeating shot', 'replicate magic item')
|
||||||
|
|
||||||
# Backstory
|
# Backstory
|
||||||
# Describe your backstory here
|
# Describe your backstory here
|
||||||
personality_traits = """{{ char.personality_traits }}"""
|
personality_traits = """{{ char.personality_traits }}"""
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
\documentclass[10pt,twocolumn,lettersize]{article}
|
||||||
|
|
||||||
|
\newlength{\zerosep}
|
||||||
|
[% if use_dnd_decorations %]
|
||||||
|
\usepackage[layout=true]{dnd}
|
||||||
|
\setlength{\zerosep}{0em}
|
||||||
|
[% else %]
|
||||||
|
\usepackage[margin=1.5cm]{geometry}
|
||||||
|
\setlength{\zerosep}{-1em}
|
||||||
|
[% endif %]
|
||||||
|
|
||||||
|
\title{Infusion Descriptions}
|
||||||
|
\author{[[ character.name ]] (Artificer [[ character.Artificer.level ]] level)}
|
||||||
|
\date{}
|
||||||
|
|
||||||
|
\begin{document}
|
||||||
|
|
||||||
|
\maketitle
|
||||||
|
|
||||||
|
[% for inf in character.infusions %]
|
||||||
|
|
||||||
|
\section*{[[ inf.name ]]}
|
||||||
|
|
||||||
|
[% if inf.prerequisite %]%
|
||||||
|
|
||||||
|
\noindent
|
||||||
|
\textit{Prerequisite: [[ inf.prerequisite ]]}%
|
||||||
|
|
||||||
|
[% endif %]%
|
||||||
|
[% if inf.item %]%
|
||||||
|
|
||||||
|
\noindent
|
||||||
|
\textit{Item: [[ inf.item ]]}%
|
||||||
|
|
||||||
|
[% endif %]%
|
||||||
|
|
||||||
|
[[ inf.__doc__|rst_to_latex ]]
|
||||||
|
|
||||||
|
[% endfor %]
|
||||||
|
|
||||||
|
\end{document}
|
||||||
@@ -0,0 +1,184 @@
|
|||||||
|
class Infusion():
|
||||||
|
name = "Unknown infusion"
|
||||||
|
item = "Item to be infused"
|
||||||
|
prerequisite = ""
|
||||||
|
classes = ('Artificer',)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
indicator = ('$', self.special_material)
|
||||||
|
if indicator:
|
||||||
|
return self.name + f' ({"".join(indicator)})'
|
||||||
|
else:
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "\"{:s}\"".format(self.name)
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return (self.name == other.name)
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
@property
|
||||||
|
def special_material(self):
|
||||||
|
return ('worth at least' in self.item.lower())
|
||||||
|
|
||||||
|
|
||||||
|
class BootsOfTheWindingPath(Infusion):
|
||||||
|
"""While wearing these boots, a creature can teleport up to 15 feet as a
|
||||||
|
bonus action to an unoccupied space the creature can see. The creature
|
||||||
|
must have occupied that space at some point during the current turn.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Boots of the Winding Path"
|
||||||
|
item = "A pair of boots (requires attunement"
|
||||||
|
prerequisite = "6th-level artificer"
|
||||||
|
|
||||||
|
|
||||||
|
class EnhancedArcaneFocus(Infusion):
|
||||||
|
"""While holding this item, a creature gains a + 1 bonus to spell attack
|
||||||
|
rolls. In addition, the creature ignores half cover when making a spell
|
||||||
|
attack.
|
||||||
|
|
||||||
|
The bonus increases to +2 when you reach 10th level in this class.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Enhanced Arcane Focus"
|
||||||
|
item = "A rod, staff, or wand (requires attunement)"
|
||||||
|
|
||||||
|
|
||||||
|
class EnhancedDefense(Infusion):
|
||||||
|
"""A creature gains a + 1 bonus to Armor Class while wearing (armor) or
|
||||||
|
wielding (shield) the infused item.
|
||||||
|
|
||||||
|
The bonus increases to +2 when you reach 10th level in this class.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Enhanced Defense"
|
||||||
|
item = "A suit of armor or shield"
|
||||||
|
|
||||||
|
|
||||||
|
class EnhancedWeapon(Infusion):
|
||||||
|
"""This magic weapon grants a +1 bonus to attack and damage rolls made with
|
||||||
|
it.
|
||||||
|
|
||||||
|
The bonus increases to +2 when you reach 10th level in this class.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Enhanced Weapon"
|
||||||
|
item = "A simple or martial weapon"
|
||||||
|
|
||||||
|
|
||||||
|
class HomunculusServant(Infusion):
|
||||||
|
"""You learn intricate methods for magically creating a special homunculus
|
||||||
|
that serves you. The item you infuse serves as the creature's heart, around
|
||||||
|
which the creature's body instantly forms.
|
||||||
|
|
||||||
|
You determine the homunculus's appearance. Some artificers prefer
|
||||||
|
mechanical-looking birds, whereas some like winged vials or miniature,
|
||||||
|
animate cauldrons.
|
||||||
|
|
||||||
|
The homunculus is friendly to you and your companions, and it obeys your
|
||||||
|
commands. See this creature's game statistics in the Homunculus Servant
|
||||||
|
stat block.
|
||||||
|
|
||||||
|
In combat, the homunculus shares your initiative count, but it takes its
|
||||||
|
turn immediately after yours. It can move and use its reaction on its own,
|
||||||
|
but the only action it takes on its turn is the Dodgeaction, unless you
|
||||||
|
take a bonus action on your turn to command it to take the action in its
|
||||||
|
stat block or the Dash, Disengage, Help, Hide, or Search action.
|
||||||
|
|
||||||
|
The homunculus regains 2d6 hit points if the *mending* spell is cast on it.
|
||||||
|
If it dies, it vanishes, leaving its heart in its space.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Homunculus Servant"
|
||||||
|
item = "A gem worth at least 100gp or a dragonshard"
|
||||||
|
prerequisite = "6th-level artificer"
|
||||||
|
|
||||||
|
|
||||||
|
class RadiantWeapon(Infusion):
|
||||||
|
"""This magic weapon grants a + 1 bonus to attack and damage rolls made
|
||||||
|
with it. While holding it, the wielder can take a bonus action to cause it
|
||||||
|
to shed bright light in a 30-foot radius and dim light for an additional 30
|
||||||
|
feet. The wielder can extinguish the light as a bonus action.
|
||||||
|
|
||||||
|
The weapon has 4 charges. As a reaction immediately after being hit by an
|
||||||
|
attack, the wielder can expend 1 charge and cause the attacker to be
|
||||||
|
blinded until the end of the attacker's next turn, unless the attacker
|
||||||
|
succeeds on a Constitution saving throw against your spell save DC. The
|
||||||
|
weapon regains ld4 expended charges daily at dawn.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Radiant Weapon"
|
||||||
|
item = "A simple or martial weapon (requires attunement)"
|
||||||
|
prerequisite = "6th-level artificer"
|
||||||
|
|
||||||
|
|
||||||
|
class RepeatingShot(Infusion):
|
||||||
|
"""This magic weapon grants a + 1 bonus to attack and damage rolls made
|
||||||
|
with it when it's used to make a ranged attack, and it ignores the loading
|
||||||
|
property if it has it.
|
||||||
|
|
||||||
|
If you load no ammunition in the weapon, it produces its own, automatically
|
||||||
|
creating one piece of magic ammunition when you make a ranged attack with
|
||||||
|
it. The ammunition created by the weapon vanishes the instant after it hits
|
||||||
|
or misses a target.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Repeating Shot"
|
||||||
|
item = """A simple or martial weapon with the ammunition property (requires
|
||||||
|
attunement)"""
|
||||||
|
|
||||||
|
|
||||||
|
class ReplicateMagicItem(Infusion):
|
||||||
|
"""Using this infusion, you replicate a particular magic item. You can
|
||||||
|
learn this infusion multiple times; each time you do so, choose a magic
|
||||||
|
item that you can make with it, picking from the Replicable Items tables
|
||||||
|
below. A table's title tells you the level you must be in the class to
|
||||||
|
choose an item from the table.
|
||||||
|
|
||||||
|
In the tables, an item's entry tells you whether the item requires
|
||||||
|
attunement. See the item's description in the *Dungeon Master's Guide* for
|
||||||
|
more information about it, including the type of object required for its
|
||||||
|
making. If you have *Xanathar's Guide to Everything*, you can choose from
|
||||||
|
among the common magic items in that book when you pick a magic item you
|
||||||
|
can replicate with this infusion.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Replicate Magic Item"
|
||||||
|
|
||||||
|
|
||||||
|
class RepulsionShield(Infusion):
|
||||||
|
"""A creature gains a + 1 bonus to Armor Class while wielding this shield.
|
||||||
|
|
||||||
|
The shield has 4 charges. While holding it, the wielder can use a reaction
|
||||||
|
immediately after being hit by a melee attack to expend 1 of the shield's
|
||||||
|
charges and push the attacker up to 15 feet away. The shield regains ld4
|
||||||
|
expended charges daily at dawn.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Repulsion Shield"
|
||||||
|
item = "A shield (requires attunement)"
|
||||||
|
|
||||||
|
|
||||||
|
class ResistantArmor(Infusion):
|
||||||
|
"""While wearing this armor, a creature has resistance to one of the
|
||||||
|
following damage types, which you choose when you infuse the item: acid,
|
||||||
|
cold, fire, force, lightning, necrotic, poison, psychic, radiant, or
|
||||||
|
thunder.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Resistant Armor"
|
||||||
|
item = "A suit of armor (requires attunement)"
|
||||||
|
|
||||||
|
|
||||||
|
class ReturningWeapon(Infusion):
|
||||||
|
"""This magic weapon grants a + 1 bonus to attack and damage rolls made
|
||||||
|
with it, and it returns to the wielder's hand immediately after it is used
|
||||||
|
to make a ranged attack.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Returning Weapon"
|
||||||
|
item = "A simple or martial weapon with the thrown property"
|
||||||
@@ -79,6 +79,13 @@ def create_druid_shapes_pdf(character, basename, keep_temp_files=False, use_dnd_
|
|||||||
use_dnd_decorations=use_dnd_decorations)
|
use_dnd_decorations=use_dnd_decorations)
|
||||||
|
|
||||||
|
|
||||||
|
def create_infusions_pdf(character, basename, keep_temp_files=False, use_dnd_decorations=False):
|
||||||
|
template = jinja_env.get_template('infusions_template.tex')
|
||||||
|
return create_latex_pdf(character, basename, template,
|
||||||
|
keep_temp_files=keep_temp_files,
|
||||||
|
use_dnd_decorations=use_dnd_decorations)
|
||||||
|
|
||||||
|
|
||||||
def create_spellbook_pdf(character, basename, keep_temp_files=False, use_dnd_decorations=False):
|
def create_spellbook_pdf(character, basename, keep_temp_files=False, use_dnd_decorations=False):
|
||||||
template = jinja_env.get_template('spellbook_template.tex')
|
template = jinja_env.get_template('spellbook_template.tex')
|
||||||
return create_latex_pdf(character, basename, template,
|
return create_latex_pdf(character, basename, template,
|
||||||
@@ -496,6 +503,19 @@ def make_sheet(character_file, character=None, flatten=False, fancy_decorations=
|
|||||||
f'for {character.name}')
|
f'for {character.name}')
|
||||||
else:
|
else:
|
||||||
sheets.append(spellbook_base + '.pdf')
|
sheets.append(spellbook_base + '.pdf')
|
||||||
|
#Create a list of Artificer infusions
|
||||||
|
infusions = getattr(character, 'infusions', [])
|
||||||
|
if len(infusions) > 0:
|
||||||
|
infusions_base = os.path.splitext(character_file)[0] + '_infusions'
|
||||||
|
try:
|
||||||
|
create_infusions_pdf(character=character,
|
||||||
|
basename=infusions_base, keep_temp_files=debug,
|
||||||
|
use_dnd_decorations=fancy_decorations)
|
||||||
|
except exceptions.LatexNotFoundError as e:
|
||||||
|
log.warning('``pdflatex`` not available. Skipping infusions list '
|
||||||
|
f'for {character.name}')
|
||||||
|
else:
|
||||||
|
sheets.append(infusions_base + '.pdf')
|
||||||
# Create a list of Druid wild_shapes
|
# Create a list of Druid wild_shapes
|
||||||
wild_shapes = getattr(character, 'wild_shapes', [])
|
wild_shapes = getattr(character, 'wild_shapes', [])
|
||||||
if len(wild_shapes) > 0:
|
if len(wild_shapes) > 0:
|
||||||
|
|||||||
@@ -0,0 +1,113 @@
|
|||||||
|
"""This file describes the heroic adventurer Cemzack.
|
||||||
|
|
||||||
|
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.10.1"
|
||||||
|
|
||||||
|
name = "Cemzack"
|
||||||
|
player_name = ""
|
||||||
|
|
||||||
|
# Be sure to list Primary class first
|
||||||
|
classes = ['Artificer'] # ex: ['Wizard'] or ['Rogue', 'Fighter']
|
||||||
|
levels = [20] # ex: [10] or [3, 2]
|
||||||
|
subclasses = ["Artillerist"] # ex: ['Necromacy'] or ['Thief', None]
|
||||||
|
background = "Sailor"
|
||||||
|
race = "Rock Gnome"
|
||||||
|
alignment = "Neutral good"
|
||||||
|
|
||||||
|
xp = 0
|
||||||
|
hp_max = 149
|
||||||
|
inspiration = 0 # integer inspiration value
|
||||||
|
|
||||||
|
# Ability Scores
|
||||||
|
strength = 13
|
||||||
|
dexterity = 16
|
||||||
|
constitution = 18
|
||||||
|
intelligence = 20
|
||||||
|
wisdom = 12
|
||||||
|
charisma = 10
|
||||||
|
|
||||||
|
# Select what skills you're proficient with
|
||||||
|
# ex: skill_proficiencies = ('athletics', 'acrobatics', 'arcana')
|
||||||
|
skill_proficiencies = ('investigation', 'sleight of hand', 'athletics', 'perception')
|
||||||
|
|
||||||
|
# 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 = ('sharpshooter')
|
||||||
|
|
||||||
|
# If selecting among multiple feature options: ex Fighting Style
|
||||||
|
# Example (Fighting Style):
|
||||||
|
# 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 = """Common, Gnomish"""
|
||||||
|
|
||||||
|
# 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 = "Breastplate" # Eg "leather armor"
|
||||||
|
shield = "None" # 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
|
||||||
|
|
||||||
|
# Wild shapes for Druid
|
||||||
|
wild_shapes = () # Ex: ('ape', 'wolf', 'ankylosaurus')
|
||||||
|
|
||||||
|
# Infusions for Artificer
|
||||||
|
infusions = ('boots of the winding path', 'enhanced arcane focus',
|
||||||
|
'enhanced defense', 'enhanced weapon', 'repeating shot',
|
||||||
|
'homunculus servant', 'radiant weapon', 'replicate magic item',
|
||||||
|
'repulsion shield', 'resistant armor', 'returning weapon')
|
||||||
|
# Ex: ('repeating shot', 'replicate magic item')
|
||||||
|
|
||||||
|
# Backstory
|
||||||
|
# Describe your backstory here
|
||||||
|
personality_traits = """TODO: Describe how your character behaves, interacts with others"""
|
||||||
|
|
||||||
|
ideals = """TODO: Describe what values your character believes in."""
|
||||||
|
|
||||||
|
bonds = """TODO: Describe your character's commitments or ongoing quests."""
|
||||||
|
|
||||||
|
flaws = """TODO: Describe your character's interesting flaws."""
|
||||||
|
|
||||||
|
features_and_traits = """TODO: Describe other features and abilities your
|
||||||
|
character has."""
|
||||||
Reference in New Issue
Block a user