mirror of
https://github.com/Threnklyn/dungeon-sheets.git
synced 2026-06-06 21:01:26 +02:00
fully tested new multiclass create-characters, with features for races and backgrounds
This commit is contained in:
@@ -1,8 +1,14 @@
|
|||||||
from . import weapons, character, features, race, background, spells
|
__all__ = ('__version__', 'Character', 'weapons', 'features',
|
||||||
|
'character', 'race', 'background', 'spells')
|
||||||
|
|
||||||
|
from . import weapons, features, race, background, spells
|
||||||
|
from .character import Character
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
def read(fname):
|
def read(fname):
|
||||||
return open(os.path.join(os.path.dirname(__file__), fname)).read()
|
return open(os.path.join(os.path.dirname(__file__), fname)).read()
|
||||||
|
|
||||||
|
|
||||||
__version__ = read('../VERSION')
|
__version__ = read('../VERSION')
|
||||||
|
|||||||
+119
-12
@@ -11,6 +11,9 @@ class Background():
|
|||||||
features = ()
|
features = ()
|
||||||
languages = ()
|
languages = ()
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.features = tuple([f() for f in self.features])
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
@@ -19,17 +22,20 @@ class Acolyte(Background):
|
|||||||
name = "Acolyte"
|
name = "Acolyte"
|
||||||
skill_proficiencies = ('insight', 'religion')
|
skill_proficiencies = ('insight', 'religion')
|
||||||
languages = ("[choose one]", "[choose one]")
|
languages = ("[choose one]", "[choose one]")
|
||||||
|
features = (feats.ShelterOfTheFaithful,)
|
||||||
|
|
||||||
|
|
||||||
class Charlatan(Background):
|
class Charlatan(Background):
|
||||||
name = "Charlatan"
|
name = "Charlatan"
|
||||||
skill_proficiencies = ('deception', 'sleight of hand')
|
skill_proficiencies = ('deception', 'sleight of hand')
|
||||||
|
features = (feats.FalseIdentity,)
|
||||||
|
|
||||||
|
|
||||||
class Criminal(Background):
|
class Criminal(Background):
|
||||||
name = "Criminal"
|
name = "Criminal"
|
||||||
skill_proficiencies = ('deception', 'stealth')
|
skill_proficiencies = ('deception', 'stealth')
|
||||||
|
features = (feats.CriminalContact,)
|
||||||
|
|
||||||
|
|
||||||
class Spy(Criminal):
|
class Spy(Criminal):
|
||||||
name = "Spy"
|
name = "Spy"
|
||||||
@@ -38,21 +44,24 @@ class Spy(Criminal):
|
|||||||
class Entertainer(Background):
|
class Entertainer(Background):
|
||||||
name = "Entertainer"
|
name = "Entertainer"
|
||||||
skill_proficiencies = ('acrobatics', 'performance')
|
skill_proficiencies = ('acrobatics', 'performance')
|
||||||
|
features = (feats.ByPopularDemand,)
|
||||||
|
|
||||||
|
|
||||||
class Gladiator(Entertainer):
|
class Gladiator(Entertainer):
|
||||||
name = "Gladiator"
|
name = "Gladiator"
|
||||||
|
|
||||||
|
|
||||||
class FolkHero(Background):
|
class FolkHero(Background):
|
||||||
name = "Folk Hero"
|
name = "Folk Hero"
|
||||||
skill_proficiencies = ('animal handling', 'survival')
|
skill_proficiencies = ('animal handling', 'survival')
|
||||||
|
features = (feats.RusticHospitality,)
|
||||||
|
|
||||||
|
|
||||||
class GuildArtisan(Background):
|
class GuildArtisan(Background):
|
||||||
name = "Guild Artisan"
|
name = "Guild Artisan"
|
||||||
skill_proficiencies = ('insight', 'persuasion')
|
skill_proficiencies = ('insight', 'persuasion')
|
||||||
languages = ("[choose one]", "[choose one]")
|
languages = ("[choose one]", "[choose one]")
|
||||||
|
features = (feats.GuildMembership,)
|
||||||
|
|
||||||
|
|
||||||
class GuildMerchant(GuildArtisan):
|
class GuildMerchant(GuildArtisan):
|
||||||
@@ -63,12 +72,14 @@ class Hermit(Background):
|
|||||||
name = "Hermit"
|
name = "Hermit"
|
||||||
skill_proficiencies = ("medicine", "religion")
|
skill_proficiencies = ("medicine", "religion")
|
||||||
languages = ("[choose one]", )
|
languages = ("[choose one]", )
|
||||||
|
features = (feats.Discovery,)
|
||||||
|
|
||||||
|
|
||||||
class Noble(Background):
|
class Noble(Background):
|
||||||
name = "Noble"
|
name = "Noble"
|
||||||
skill_proficiencies = ("history", 'persuasion')
|
skill_proficiencies = ("history", 'persuasion')
|
||||||
languages = ("[choose one]", )
|
languages = ("[choose one]", )
|
||||||
|
features = (feats.PositionOfPrivilege,)
|
||||||
|
|
||||||
|
|
||||||
class Knight(Noble):
|
class Knight(Noble):
|
||||||
@@ -79,17 +90,20 @@ class Outlander(Background):
|
|||||||
name = "Outlander"
|
name = "Outlander"
|
||||||
skill_proficiencies = ('athletics', 'survival')
|
skill_proficiencies = ('athletics', 'survival')
|
||||||
languages = ("[choose one]", )
|
languages = ("[choose one]", )
|
||||||
|
features = (feats.Wanderer,)
|
||||||
|
|
||||||
|
|
||||||
class Sage(Background):
|
class Sage(Background):
|
||||||
name = "Sage"
|
name = "Sage"
|
||||||
skill_proficiencies = ('arcana', 'history')
|
skill_proficiencies = ('arcana', 'history')
|
||||||
languages = ("[choose one]", '[choose one]')
|
languages = ("[choose one]", '[choose one]')
|
||||||
|
features = (feats.Researcher,)
|
||||||
|
|
||||||
|
|
||||||
class Sailor(Background):
|
class Sailor(Background):
|
||||||
name = "Sailor"
|
name = "Sailor"
|
||||||
skill_proficiencies = ('athletics', 'perception')
|
skill_proficiencies = ('athletics', 'perception')
|
||||||
|
features = (feats.ShipsPassage,)
|
||||||
|
|
||||||
|
|
||||||
class Pirate(Sailor):
|
class Pirate(Sailor):
|
||||||
@@ -99,29 +113,122 @@ class Pirate(Sailor):
|
|||||||
class Soldier(Background):
|
class Soldier(Background):
|
||||||
name = "Soldier"
|
name = "Soldier"
|
||||||
skill_proficiencies = ('athletics', 'intimidation')
|
skill_proficiencies = ('athletics', 'intimidation')
|
||||||
|
features = (feats.MilitaryRank,)
|
||||||
|
|
||||||
|
|
||||||
class Urchin(Background):
|
class Urchin(Background):
|
||||||
name = "Urchin"
|
name = "Urchin"
|
||||||
skill_proficiencies = ('sleight of hand', 'stealth')
|
skill_proficiencies = ('sleight of hand', 'stealth')
|
||||||
|
features = (feats.CitySecrets,)
|
||||||
|
|
||||||
|
|
||||||
|
# Sword's Coast Adventurers Guide
|
||||||
|
class CityWatch(Background):
|
||||||
|
name = "City Watch"
|
||||||
|
skill_proficiencies = ('athletics', 'insight')
|
||||||
|
languages = ('[choose one]', '[choose one]')
|
||||||
|
features = (feats.WatchersEye,)
|
||||||
|
|
||||||
|
|
||||||
|
class ClanCrafter(Background):
|
||||||
|
name = "Clan Crafter"
|
||||||
|
skill_proficiencies = ('history', 'insight')
|
||||||
|
languages = ('Dwarvish')
|
||||||
|
features = (feats.RespectOfTheStoutFolk,)
|
||||||
|
|
||||||
|
|
||||||
|
class CloisteredScholar(Background):
|
||||||
|
name = "Cloistered Scholar"
|
||||||
|
skill_proficiencies = ('history',)
|
||||||
|
skill_choices = ('arcana', 'nature', 'religion')
|
||||||
|
num_skill_choices = 1
|
||||||
|
languages = ('[choose one]', '[choose one]')
|
||||||
|
features = (feats.LibraryAccess,)
|
||||||
|
|
||||||
|
|
||||||
|
class Courtier(Background):
|
||||||
|
name = "Courtier"
|
||||||
|
skill_proficiencies = ("insight", 'persuasion')
|
||||||
|
languages = ('[choose one]', '[choose one]')
|
||||||
|
features = (feats.CourtFunctionary,)
|
||||||
|
|
||||||
|
|
||||||
|
class FactionAgent(Background):
|
||||||
|
name = "Faction Agent"
|
||||||
|
skill_proficiencies = ('insight',)
|
||||||
|
skill_choices = ('animal handling', 'arcana', 'deception',
|
||||||
|
'history', 'intimidation', 'investigation',
|
||||||
|
'medicine', 'nature', 'perception', 'performance',
|
||||||
|
'persuasion', 'religion', 'survival')
|
||||||
|
num_skill_choices = 1
|
||||||
|
languages = ('[choose one]', '[choose one]')
|
||||||
|
features = (feats.SafeHaven,)
|
||||||
|
|
||||||
|
|
||||||
|
class FarTraveler(Background):
|
||||||
|
name = 'Far Traveler'
|
||||||
|
skill_proficiencies = ('insight', 'perception')
|
||||||
|
languages = ('[choose one]',)
|
||||||
|
features = (feats.AllEyesOnYou,)
|
||||||
|
|
||||||
|
|
||||||
|
class Inheritor(Background):
|
||||||
|
name = "Inheritor"
|
||||||
|
skill_proficiencies = ('survival',)
|
||||||
|
skill_choices = ('arcana', 'history', 'religion')
|
||||||
|
num_skill_choices = 1
|
||||||
|
languages = ('[choose one]',)
|
||||||
|
features = (feats.Inheritance,)
|
||||||
|
|
||||||
|
|
||||||
|
class KnightOfTheOrder(Background):
|
||||||
|
name = "Knight of the Order"
|
||||||
|
skill_proficiencies = ('persuasion',)
|
||||||
|
skill_choices = ('arcana', 'history', 'nature', 'religion')
|
||||||
|
num_skill_choices = 1
|
||||||
|
languages = ('[choose one]')
|
||||||
|
features = (feats.KnightlyRegard,)
|
||||||
|
|
||||||
|
|
||||||
|
class MercenaryVeteran(Background):
|
||||||
|
name = "Mercenary Veteran"
|
||||||
|
skill_proficiencies = ('athletics', 'persuasion')
|
||||||
|
features = (feats.MercenaryLife,)
|
||||||
|
|
||||||
|
|
||||||
class UrbanBountyHunter(Background):
|
class UrbanBountyHunter(Background):
|
||||||
name = 'Urban Bounty Hunter'
|
name = 'Urban Bounty Hunter'
|
||||||
skill_proficiencies = ()
|
skill_proficiencies = ()
|
||||||
skill_choices = ('Deception', 'Insight', 'Persuasion', 'Stealth')
|
skill_choices = ('Deception', 'Insight', 'Persuasion', 'Stealth')
|
||||||
num_skill_choices = 2
|
num_skill_choices = 2
|
||||||
|
features = (feats.EarToTheGround,)
|
||||||
|
|
||||||
|
|
||||||
|
class UthgardtTribeMember(Background):
|
||||||
|
name = "Uthgardt Tribe Member"
|
||||||
|
skill_profifiencies = ('athletics', 'survival')
|
||||||
|
languages = ('[choose one]')
|
||||||
|
features = (feats.UthgardtHeritage,)
|
||||||
|
|
||||||
|
|
||||||
|
class WaterdhavianNoble(Background):
|
||||||
|
name = "Waterdhavian Noble"
|
||||||
|
skill_proficiencies = ('history', 'persuasion')
|
||||||
|
languages = ('[choose one]')
|
||||||
|
features = (feats.KeptInStyle,)
|
||||||
|
|
||||||
class FarTraveler(Background):
|
|
||||||
name = 'Far Traveler'
|
PHB_backgrounds = [Acolyte, Charlatan, Criminal, Spy, Entertainer,
|
||||||
skill_proficiencies = ('insight', 'perception')
|
Gladiator, FolkHero, GuildArtisan, GuildMerchant,
|
||||||
languages = ('[choose one]',)
|
Hermit, Noble, Knight, Outlander, Sage, Sailor,
|
||||||
|
Pirate, Soldier, Urchin]
|
||||||
|
|
||||||
|
SCAG_backgrounds = [CityWatch, ClanCrafter, CloisteredScholar, Courtier,
|
||||||
|
FactionAgent, FarTraveler, Inheritor, KnightOfTheOrder,
|
||||||
|
MercenaryVeteran, UrbanBountyHunter, UthgardtTribeMember,
|
||||||
|
WaterdhavianNoble]
|
||||||
|
|
||||||
available_backgrounds = [Acolyte, Charlatan, Criminal, Spy, Entertainer,
|
available_backgrounds = PHB_backgrounds + SCAG_backgrounds
|
||||||
Gladiator, FolkHero, GuildArtisan, GuildMerchant,
|
|
||||||
Hermit, Noble, Knight, Outlander, Sage, Sailor,
|
|
||||||
Pirate, Soldier, Urchin, UrbanBountyHunter,
|
|
||||||
FarTraveler]
|
|
||||||
|
|
||||||
|
__all__ = tuple([b.name for b in available_backgrounds]) + (
|
||||||
|
'PHB_backgrounds', 'SCAG_backgrounds', 'available_backgrounds')
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
"""Tools for describing a player character."""
|
"""Tools for describing a player character."""
|
||||||
|
__all__ = ('Character',)
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
@@ -12,10 +13,17 @@ from .stats import Ability, Skill, findattr
|
|||||||
from .dice import read_dice_str
|
from .dice import read_dice_str
|
||||||
from . import (weapons, race, background, spells, armor, monsters,
|
from . import (weapons, race, background, spells, armor, monsters,
|
||||||
exceptions, classes, features)
|
exceptions, classes, features)
|
||||||
from .__init__ import __version__
|
|
||||||
from .weapons import Weapon
|
from .weapons import Weapon
|
||||||
from .armor import Armor, NoArmor, Shield, NoShield
|
from .armor import Armor, NoArmor, Shield, NoShield
|
||||||
|
|
||||||
|
|
||||||
|
def read(fname):
|
||||||
|
return open(os.path.join(os.path.dirname(__file__), fname)).read()
|
||||||
|
|
||||||
|
|
||||||
|
__version__ = read('../VERSION')
|
||||||
|
|
||||||
|
|
||||||
dice_re = re.compile('(\d+)d(\d+)')
|
dice_re = re.compile('(\d+)d(\d+)')
|
||||||
|
|
||||||
multiclass_spellslots_by_level = {
|
multiclass_spellslots_by_level = {
|
||||||
@@ -112,8 +120,8 @@ class Character():
|
|||||||
_proficiencies_text = tuple()
|
_proficiencies_text = tuple()
|
||||||
# Magic
|
# Magic
|
||||||
spellcasting_ability = None
|
spellcasting_ability = None
|
||||||
spells = tuple()
|
_spells = tuple()
|
||||||
spells_prepared = tuple()
|
_spells_prepared = tuple()
|
||||||
# Features IN MAJOR DEVELOPMENT
|
# Features IN MAJOR DEVELOPMENT
|
||||||
custom_features = ()
|
custom_features = ()
|
||||||
feature_choices = ()
|
feature_choices = ()
|
||||||
@@ -132,7 +140,7 @@ class Character():
|
|||||||
# instantiate any spells not listed properly
|
# instantiate any spells not listed properly
|
||||||
for S in self.spells_prepared:
|
for S in self.spells_prepared:
|
||||||
if S not in [type(spl) for spl in self.spells]:
|
if S not in [type(spl) for spl in self.spells]:
|
||||||
self.spells += (S(),)
|
self._spells += (S(),)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
@@ -249,6 +257,28 @@ class Character():
|
|||||||
else:
|
else:
|
||||||
return multiclass_spellslots_by_level[eff_level][spell_level]
|
return multiclass_spellslots_by_level[eff_level][spell_level]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def spells(self):
|
||||||
|
spells = set(self._spells)
|
||||||
|
for f in self.features:
|
||||||
|
spells |= set(f.spells_known) | set(f.spells_prepared)
|
||||||
|
for c in self.spellcasting_classes:
|
||||||
|
spells |= set(c.spells_known) | set(c.spells_prepared)
|
||||||
|
if self.race is not None:
|
||||||
|
spells |= set(self.race.spells_known) | set(self.race.spells_prepared)
|
||||||
|
return tuple(spells)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def spells_prepared(self):
|
||||||
|
spells = set(self._spells_prepared)
|
||||||
|
for f in self.features:
|
||||||
|
spells |= set(f.spells_prepared)
|
||||||
|
for c in self.spellcasting_classes:
|
||||||
|
spells |= set(c.spells_prepared)
|
||||||
|
if self.race is not None:
|
||||||
|
spells |= set(self.race.spells_prepared)
|
||||||
|
return tuple(spells)
|
||||||
|
|
||||||
def set_attrs(self, **attrs):
|
def set_attrs(self, **attrs):
|
||||||
"""Bulk setting of attributes. Useful for loading a character from a
|
"""Bulk setting of attributes. Useful for loading a character from a
|
||||||
dictionary."""
|
dictionary."""
|
||||||
@@ -322,10 +352,10 @@ class Character():
|
|||||||
# Save list of spells to character atribute
|
# Save list of spells to character atribute
|
||||||
if attr == 'spells':
|
if attr == 'spells':
|
||||||
# Instantiate them all for the spells list
|
# Instantiate them all for the spells list
|
||||||
self.spells = tuple(S() for S in _spells)
|
self._spells = tuple(S() for S in _spells)
|
||||||
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)
|
||||||
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}",
|
||||||
@@ -571,11 +601,12 @@ class Character():
|
|||||||
f.write(text)
|
f.write(text)
|
||||||
|
|
||||||
def to_pdf(self, filename, **kwargs):
|
def to_pdf(self, filename, **kwargs):
|
||||||
char_file = filename.replace('pdf', 'py')
|
if filename.endswith('.pdf'):
|
||||||
self.save(char_file,
|
filename = filename.replace('pdf', 'py')
|
||||||
|
self.save(filename,
|
||||||
template_file=kwargs.get('template_file',
|
template_file=kwargs.get('template_file',
|
||||||
'character_template.txt'))
|
'character_template.txt'))
|
||||||
subprocess.call(['makesheets', char_file])
|
subprocess.call(['makesheets', filename)
|
||||||
|
|
||||||
|
|
||||||
def read_character_file(filename):
|
def read_character_file(filename):
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
__all__ = ('CharClass', 'Barbarian', 'Bard', 'Cleric', 'Druid', 'Fighter',
|
__all__ = ('CharClass', 'Barbarian', 'Bard', 'Cleric', 'Druid', 'Fighter',
|
||||||
'Monk', 'Paladin', 'Ranger', 'Rogue', 'Sorceror', 'Warlock',
|
'Monk', 'Paladin', 'Ranger', 'Rogue', 'Sorceror', 'Warlock',
|
||||||
'Wizard', 'Revisedranger')
|
'Wizard', 'Revisedranger', 'available_classes')
|
||||||
|
|
||||||
from .classes import CharClass
|
from .classes import CharClass
|
||||||
from .barbarian import Barbarian
|
from .barbarian import Barbarian
|
||||||
@@ -15,3 +15,6 @@ from .rogue import Rogue
|
|||||||
from .sorceror import Sorceror
|
from .sorceror import Sorceror
|
||||||
from .warlock import Warlock
|
from .warlock import Warlock
|
||||||
from .wizard import Wizard
|
from .wizard import Wizard
|
||||||
|
|
||||||
|
available_classes = [Barbarian, Bard, Cleric, Druid, Fighter, Monk, Ranger,
|
||||||
|
Rogue, Sorceror, Warlock, Wizard, Revisedranger]
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ class CharClass():
|
|||||||
num_skill_choices = 2
|
num_skill_choices = 2
|
||||||
spellcasting_ability = None
|
spellcasting_ability = None
|
||||||
spell_slots_by_level = None
|
spell_slots_by_level = None
|
||||||
|
spells_known = ()
|
||||||
|
spells_prepared = ()
|
||||||
subclass = None
|
subclass = None
|
||||||
subclasses_available = ()
|
subclasses_available = ()
|
||||||
features_by_level = defaultdict(list)
|
features_by_level = defaultdict(list)
|
||||||
|
|||||||
@@ -23,26 +23,11 @@ def read_version():
|
|||||||
return version
|
return version
|
||||||
|
|
||||||
|
|
||||||
char_classes = {
|
char_classes = {c.class_name: c for c in classes.available_classes}
|
||||||
'Barbarian': classes.Barbarian,
|
|
||||||
'Bard': classes.Bard,
|
|
||||||
'Cleric': classes.Cleric,
|
|
||||||
'Druid': classes.Druid,
|
|
||||||
'Fighter': classes.Fighter,
|
|
||||||
'Monk': classes.Monk,
|
|
||||||
'Paladin': classes.Paladin,
|
|
||||||
'Ranger': classes.Ranger,
|
|
||||||
'Rogue': classes.Rogue,
|
|
||||||
'Sorceror': classes.Sorceror,
|
|
||||||
'Warlock': classes.Warlock,
|
|
||||||
'Wizard': classes.Wizard
|
|
||||||
}
|
|
||||||
|
|
||||||
races = race.race_dict
|
races = {r.name: r for r in race.available_races}
|
||||||
|
|
||||||
|
backgrounds = {b.name: b for b in background.available_backgrounds}
|
||||||
backgrounds = background.available_backgrounds
|
|
||||||
backgrounds = {bg.name: bg for bg in backgrounds}
|
|
||||||
|
|
||||||
|
|
||||||
class App(npyscreen.NPSAppManaged):
|
class App(npyscreen.NPSAppManaged):
|
||||||
@@ -53,10 +38,11 @@ class App(npyscreen.NPSAppManaged):
|
|||||||
def save_character(self):
|
def save_character(self):
|
||||||
# Save the file
|
# Save the file
|
||||||
filename = self.getForm("SAVE").filename.value
|
filename = self.getForm("SAVE").filename.value
|
||||||
self.character.save(filename)
|
self.character.save(filename, template_file='empty_template.tex')
|
||||||
# Create the PDF character sheet
|
# Create the PDF character sheet
|
||||||
if self.getForm('SAVE').make_pdf.value:
|
if self.getForm('SAVE').make_pdf.value:
|
||||||
log.debug("Creating PDF")
|
log.debug("Creating PDF")
|
||||||
|
self.character.to_pdf(filename, template_file='empty_template.tex')
|
||||||
subprocess.call(['makesheets', filename])
|
subprocess.call(['makesheets', filename])
|
||||||
|
|
||||||
def update_max_hp(self):
|
def update_max_hp(self):
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
"""This file describes the heroic adventurer {{ char.name }}.
|
||||||
|
|
||||||
|
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 = "{{ char.dungeonsheets_version }}"
|
||||||
|
|
||||||
|
name = "{{ char.name }}"
|
||||||
|
classes_levels = {{ char.classes_levels }}
|
||||||
|
player_name = "{{ char.player_name }}"
|
||||||
|
background = "{{ char.background.name }}"
|
||||||
|
race = "{{ char.race.name }}"
|
||||||
|
alignment = "{{ char.alignment }}"
|
||||||
|
xp = {{ char.xp }}
|
||||||
|
hp_max = {{ char.hp_max }}
|
||||||
|
|
||||||
|
# Ability Scores
|
||||||
|
strength = {{ char.strength.value }}
|
||||||
|
dexterity = {{ char.dexterity.value }}
|
||||||
|
constitution = {{ char.constitution.value }}
|
||||||
|
intelligence = {{ char.intelligence.value }}
|
||||||
|
wisdom = {{ char.wisdom.value }}
|
||||||
|
charisma = {{ char.charisma.value }}
|
||||||
|
|
||||||
|
# Select what skills you're proficient with
|
||||||
|
skill_proficiencies = {{ char.skill_proficiencies }}
|
||||||
|
|
||||||
|
# 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 = """{{ char.languages }}"""
|
||||||
|
|
||||||
|
# Inventory
|
||||||
|
# TODO: Get yourself some money
|
||||||
|
cp = 0
|
||||||
|
sp = 0
|
||||||
|
ep = 0
|
||||||
|
gp = 0
|
||||||
|
pp = 0
|
||||||
|
|
||||||
|
# TODO: Put your equipped weapons and armor here
|
||||||
|
weapons = () # Example: ('shortsword', 'longsword')
|
||||||
|
armor = "" # Eg "light leather armor"
|
||||||
|
shield = "" # Eg "shield"
|
||||||
|
|
||||||
|
equipment = """TODO: list the equipment and magic items your character carries"""
|
||||||
|
|
||||||
|
attacks_and_spellcasting = """TODO: Describe how your character usually attacks
|
||||||
|
or uses spells."""
|
||||||
|
|
||||||
|
# List of known spells
|
||||||
|
# Example: spells_prepared = ('magic missile', 'mage armor')
|
||||||
|
spells_prepared = () # Todo: Learn some spells
|
||||||
|
|
||||||
|
# Which spells have not been prepared
|
||||||
|
__spells_unprepared = ()
|
||||||
|
|
||||||
|
# all spells known
|
||||||
|
spells = spells_prepared + __spells_unprepared
|
||||||
|
|
||||||
|
# Backstory
|
||||||
|
# Describe your backstory here
|
||||||
|
personality_traits = """TODO: How does your character behave? See the PHB for
|
||||||
|
examples of all the sections below"""
|
||||||
|
|
||||||
|
ideals = """TODO: What does your character believe in?"""
|
||||||
|
|
||||||
|
bonds = """TODO: Describe what debts your character has to pay,
|
||||||
|
and other commitments or ongoing quests they have."""
|
||||||
|
|
||||||
|
flaws = """TODO: Describe your characters interesting flaws.
|
||||||
|
"""
|
||||||
|
|
||||||
|
features_and_traits = """TODO: Describe other features and abilities your
|
||||||
|
character has."""
|
||||||
|
|
||||||
@@ -0,0 +1,387 @@
|
|||||||
|
from .features import Feature
|
||||||
|
|
||||||
|
|
||||||
|
class ShelterOfTheFaithful(Feature):
|
||||||
|
"""As an acolyte, you command the respect of those who share your faith, and
|
||||||
|
you can perform the religious ceremonies of your deity. You and your
|
||||||
|
adventuring companions can expect to receive free healing and care at a
|
||||||
|
temple, shrine, or other established presence of your faith, though you
|
||||||
|
must provide any material components needed for spells. Those who share
|
||||||
|
your religion will support you (but only you) at a modest lifestyle.
|
||||||
|
|
||||||
|
You might also have ties to a specific temple dedicated to your chosen
|
||||||
|
deity or pantheon, and you have a residence there. This could be the temple
|
||||||
|
where you used to serve, if you remain on good terms with it, or a temple
|
||||||
|
where you have found a new home. While near your temple, you can call upon
|
||||||
|
the priests for assistance, provided the assistance you ask for is not
|
||||||
|
hazardous and you remain in good standing with your temple.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Shelter of the Faithful"
|
||||||
|
source = "Background (Acolyte)"
|
||||||
|
|
||||||
|
|
||||||
|
class FalseIdentity(Feature):
|
||||||
|
"""You have created a second identity that includes documentation, established
|
||||||
|
acquaintances, and disguises that allow you to assume that
|
||||||
|
persona. Additionally, you can forge documents including official papers
|
||||||
|
and personal letters, as long as you have seen an example of the kind of
|
||||||
|
document or the handwriting you are trying to copy.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "False Identity"
|
||||||
|
source = "Background (Charlattan)"
|
||||||
|
|
||||||
|
|
||||||
|
class CriminalContact(Feature):
|
||||||
|
"""You have a reliable and trustworthy contact who acts as your liaison to a
|
||||||
|
network o f other criminals. You know how to get messages to and from your
|
||||||
|
contact, even over great distances; specifically, you know the local
|
||||||
|
messengers, corrupt caravan masters, and seedy sailors who can deliver
|
||||||
|
messages for you.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Criminal Contact"
|
||||||
|
source = "Background (Criminal)"
|
||||||
|
|
||||||
|
|
||||||
|
class ByPopularDemand(Feature):
|
||||||
|
"""You can always find a place to perform, usually in an inn or tavern but
|
||||||
|
possibly with a circus, at a theater, or even in a noble’s court. At such a
|
||||||
|
place, you receive free lodging and food of a modest or comfortable
|
||||||
|
standard (depending on the quality of the establishment), as long as you
|
||||||
|
perform each night. In addition, your performance makes you something of a
|
||||||
|
local figure. When strangers recognize you in a town where you have
|
||||||
|
performed, they typically take a liking to you.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "By Popular Demand"
|
||||||
|
source = "Background (Entertainer)"
|
||||||
|
|
||||||
|
|
||||||
|
class RusticHospitality(Feature):
|
||||||
|
"""Since you come from the ranks of the common folk, you fit in among them
|
||||||
|
with ease. You can find a place to hide, rest, or recuperate among other
|
||||||
|
commoners, unless you have shown yourself to be a danger to them. They will
|
||||||
|
shield you from the law or anyone else searching for you, though they will
|
||||||
|
not risk their lives for you.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Rustic Hospitality"
|
||||||
|
source = "Background (Folk Hero)"
|
||||||
|
|
||||||
|
|
||||||
|
class GuildMembership(Feature):
|
||||||
|
"""As an established and respected member of a guild, you can rely on certain
|
||||||
|
benefits that membership provides. Your fellow guild members will provide
|
||||||
|
you with lodging and food if necessary, and pay for your funeral if
|
||||||
|
needed. In some cities and towns, a guildhall offers a central place to
|
||||||
|
meet other members of your profession, which can be a good place to meet
|
||||||
|
potential patrons, allies, or hirelings.
|
||||||
|
|
||||||
|
Guilds often wield tremendous political power. If you are accused of a
|
||||||
|
crime, your guild will support you if a good case can be made for your
|
||||||
|
innocence or the crime is justifiable. You can also gain access to powerful
|
||||||
|
political figures through the guild, if you are a member in good
|
||||||
|
standing. Such connections might require the donation of money or magic
|
||||||
|
items to the guild’s coffers.
|
||||||
|
|
||||||
|
You must pay dues of 5 gp per month to the guild. If you miss payments, you
|
||||||
|
must make up back dues to remain in the guild’s good graces.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Guild Membership"
|
||||||
|
source = "Background (Guild Artisan)"
|
||||||
|
|
||||||
|
|
||||||
|
class Discovery(Feature):
|
||||||
|
"""The quiet seclusion of your extended hermitage gave you access to a unique
|
||||||
|
and powerful discovery. The exact nature of this revelation depends on the
|
||||||
|
nature of your seclusion. It might be a great truth about the cosmos, the
|
||||||
|
deities, the powerful beings of the outer planes, or the forces of
|
||||||
|
nature. It could be a site that no one else has ever seen. You might have
|
||||||
|
uncovered a fact that has long been forgotten, or unearthed some relic of
|
||||||
|
the past that could rewrite history. It might be information that would be
|
||||||
|
damaging to the people who or consigned you to exile, and hence the reason
|
||||||
|
for your return to society.
|
||||||
|
|
||||||
|
Work with your DM to determine the details of
|
||||||
|
your discovery and its impact on the campaign.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Discovery"
|
||||||
|
source = "Background (Hermit)"
|
||||||
|
|
||||||
|
|
||||||
|
class PositionOfPrivilege(Feature):
|
||||||
|
"""Thanks to your noble birth, people are inclined to think the best of
|
||||||
|
you. You are welcome in high society, and people assume you have the right
|
||||||
|
to be wherever you are. The common folk make every effort to accommodate
|
||||||
|
you and avoid your displeasure, and other people of high birth treat you as
|
||||||
|
a member of the same social sphere. You can secure an audience with a local
|
||||||
|
noble if you need to.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Position of Privilege"
|
||||||
|
source = "Background (Noble)"
|
||||||
|
|
||||||
|
|
||||||
|
class Wanderer(Feature):
|
||||||
|
"""You have an excellent memory for maps and geography, and you can always
|
||||||
|
recall the general layout of terrain, settlements, and other features
|
||||||
|
around you. In addition, you can find food and fresh water for yourself and
|
||||||
|
up to five other people each day, provided that the land offers berries,
|
||||||
|
small game, water, and so forth.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Wanderer"
|
||||||
|
source = "Background (Outlander)"
|
||||||
|
|
||||||
|
|
||||||
|
class Researcher(Feature):
|
||||||
|
"""When you attempt to learn or recall a piece of lore, if you do not know
|
||||||
|
that information, you often know where and from whom you can obtain
|
||||||
|
it. Usually, this information comes from a library, scriptorium,
|
||||||
|
university, or a sage or other learned person or creature. Your DM might
|
||||||
|
rule that the knowledge you seek is secreted away in an almost inaccessible
|
||||||
|
place, or that it simply cannot be found. Unearthing the deepest secrets of
|
||||||
|
the multiverse can require an adventure or even a whole campaign.
|
||||||
|
"""
|
||||||
|
name = "Researcher"
|
||||||
|
source = "Background (Sage)"
|
||||||
|
|
||||||
|
|
||||||
|
class ShipsPassage(Feature):
|
||||||
|
"""When you need to, you can secure free passage on a sailing ship for
|
||||||
|
yourself and your adventuring companions. You might sail on the ship you
|
||||||
|
served on, or another ship you have good relations with (perhaps one
|
||||||
|
captained by a former crewmate). Because you’re calling in a favor, you
|
||||||
|
can’t be certain of a schedule or route that will meet your every
|
||||||
|
need. Your Dungeon Master will determine how long it takes to get where you
|
||||||
|
need to go. In return for your free passage, you and your companions are
|
||||||
|
expected to assist the crew during the voyage
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Ship's Passage"
|
||||||
|
source = "Background (Sailor)"
|
||||||
|
|
||||||
|
|
||||||
|
class MilitaryRank(Feature):
|
||||||
|
"""You have a military rank from your career as a soldier. Soldiers loyal to
|
||||||
|
your former military organization still recognize your authority and
|
||||||
|
influence, and they defer to you if they are of a lower rank. You can
|
||||||
|
invoke your rank to exert influence over other soldiers and requisition
|
||||||
|
simple equipment or horses for temporary use. You can also usually gain
|
||||||
|
access to friendly military encampments and fortresses where your rank is
|
||||||
|
recognized.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Military Rank"
|
||||||
|
source = "Background (Soldier)"
|
||||||
|
|
||||||
|
|
||||||
|
class CitySecrets(Feature):
|
||||||
|
"""You know the secret patterns and flow to cities and can find passages
|
||||||
|
through the urban sprawl that others would miss. When you are not in
|
||||||
|
combat, you (and companions you lead) can travel between any two locations
|
||||||
|
in the city twice as fast as your speed would normally allow.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "City Secrets"
|
||||||
|
source = "Background (Urchin)"
|
||||||
|
|
||||||
|
|
||||||
|
# Swords Coast Adventurer's Guide
|
||||||
|
class AllEyesOnYou(Feature):
|
||||||
|
"""Your accent, mannerisms, figures of speech, and per- haps even your
|
||||||
|
appearance all mark you as foreign. Curious glances are directed your way
|
||||||
|
wherever you go, which can be a nuisance, but you also gain the friendly
|
||||||
|
interest of scholars and others intrigued by far-off lands, to say nothing
|
||||||
|
of everyday folk who are eager to hear stories of your homeland.
|
||||||
|
|
||||||
|
You can parley this attention into access to people and places you might
|
||||||
|
not otherwise have, for you and your traveling companions. Noble lords,
|
||||||
|
scholars, and merchant princes, to name a few, might be interested in
|
||||||
|
hearing about your distant homeland and people.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "All Eyes on You"
|
||||||
|
source = "Background (Far Traveler)"
|
||||||
|
|
||||||
|
|
||||||
|
class EarToTheGround(Feature):
|
||||||
|
"""You are in frequent contact with people in the segment of society that your
|
||||||
|
chosen quarries move through. These people might be associated with the
|
||||||
|
criminal underworld, the rough-and-tumble folk of the streets, or members
|
||||||
|
of high society. This connection comes in the form of a contact in any city
|
||||||
|
you visit, a person who provides information about the people and places of
|
||||||
|
the local area.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Ear to the Ground"
|
||||||
|
source = "Background (Urban Bounty Hunter)"
|
||||||
|
|
||||||
|
|
||||||
|
class WatchersEye(Feature):
|
||||||
|
"""Your experience in enforcing the law, and dealing with lawbreakers, gives
|
||||||
|
you a feel for local laws and crimi- nals. You can easily find the local
|
||||||
|
outpost of the watch or a simila r organization, and just as easily pick
|
||||||
|
out the dens of criminal activity in a community, although you're more
|
||||||
|
likely to be welcome in the former locations rather than the latter.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Watcher's Eye"
|
||||||
|
source = "Background (City Watch)"
|
||||||
|
|
||||||
|
|
||||||
|
class RespectOfTheStoutFolk(Feature):
|
||||||
|
"""As well respected as clan crafters are among outsiders, no one esteems them
|
||||||
|
quite so highly as dwarves do. You always have free room and board in any
|
||||||
|
place where shield dwarves or gold dwarves dwell, and the individu- als in
|
||||||
|
such a settlement might vie among themselves to determine who can offer you
|
||||||
|
(and possibly your compa- triots) the finest accommodations and assistance.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Respect of the Stout Folk"
|
||||||
|
source = "Background (Clan Crafter)"
|
||||||
|
|
||||||
|
|
||||||
|
class LibraryAccess(Feature):
|
||||||
|
"""Though others must often endure extensive interviews and significant fees to
|
||||||
|
gain access to even the most common archives in your library, you have free
|
||||||
|
and easy access to the majority of the library, though it might also have
|
||||||
|
repositories of lore that are too valuable, magical, or secret to permit
|
||||||
|
anyone immediate access.
|
||||||
|
|
||||||
|
You have a working knowledge of your cloister's personnel and bureaucracy,
|
||||||
|
and you know how to navigate those connections with some ease.
|
||||||
|
|
||||||
|
Additionally, you are likely to gain preferential treatment at other
|
||||||
|
libraries across the Realms, as profes- sional courtesy shown to a fellow
|
||||||
|
scholar.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Library Access"
|
||||||
|
source = "Background (Cloistered Scholar)"
|
||||||
|
|
||||||
|
|
||||||
|
class CourtFunctionary(Feature):
|
||||||
|
"""Your knowledge of how bureaucracies function lets you gain access to the
|
||||||
|
records and inner workings of any no- ble court or government you
|
||||||
|
encounter. You know who the movers and shakers are, whom to go to for the
|
||||||
|
favors you seek, and what the current intrigues of interest in the group
|
||||||
|
are.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Court Functionary"
|
||||||
|
source = "Background (Courtier)"
|
||||||
|
|
||||||
|
|
||||||
|
class SafeHaven(Feature):
|
||||||
|
"""As a faction agent, you have access to a secret network of supporters and
|
||||||
|
operatives who can provide assis- tance on your adventures. You know a set
|
||||||
|
of secret signs and passwords you can use to identify such operatives , who
|
||||||
|
can provide you with access to a hidden safe house, free room and board, or
|
||||||
|
assistance in finding informa- tion. These agents never risk their lives
|
||||||
|
for you or risk revealing their true identities.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Save Haven"
|
||||||
|
source = "Background (Faction Agent)"
|
||||||
|
|
||||||
|
|
||||||
|
class Inheritance(Feature):
|
||||||
|
"""Choose or randomly determine your inheritance from among the possibilities
|
||||||
|
in the table in SCAG. Work with your Dungeon Master to come up with
|
||||||
|
details: Why is your inheritance so important, and what is its full story?
|
||||||
|
You might prefer for the DM to invent these details as part of the game,
|
||||||
|
allowing you to learn more about your inheritance as your character does.
|
||||||
|
|
||||||
|
The Dungeon Master is free to use your inheritance as a story hook, sending
|
||||||
|
you on quests to learn more about its history or true nature, or
|
||||||
|
confronting you with foes who want to claim it for themselves or prevent
|
||||||
|
you from learning what you seek. The DM also determines the properties of
|
||||||
|
your inheritance and how they figure into the item's history and
|
||||||
|
importance. For instance, the object might be a minor magic item, or one
|
||||||
|
that begins with a modest ability and increases in potency with the passage
|
||||||
|
of time. Or, the true nature of your inheritance might not be apparent at
|
||||||
|
first and is revealed only when certain conditions are met.
|
||||||
|
|
||||||
|
When you begin your adventuring career, you can decide whether to tell your
|
||||||
|
companions about your inheritance right away. Rather than attracting
|
||||||
|
attention to yourself, you might want to keep your inheritance a secret
|
||||||
|
until you learn more about what it means to you and what it can do for you.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Inheritance"
|
||||||
|
source = "Background (Inheritor)"
|
||||||
|
|
||||||
|
|
||||||
|
class KnightlyRegard(Feature):
|
||||||
|
"""You receive shelter and succor from members of your knightly order and those
|
||||||
|
who are sympathetic to its aims. If your order is a religious one, you can
|
||||||
|
gain aid from temples and other religious communities of your
|
||||||
|
deity. Knights of civic orders can get help from the com- munity- whether a
|
||||||
|
lone settlement or a great nation- that they serve, and knights of
|
||||||
|
philosophical orders can find help from those they have aided in pursuit of
|
||||||
|
their ideals , and those who share those ideals.
|
||||||
|
|
||||||
|
This help comes in the form of shelter and meals, and healing when
|
||||||
|
appropriate, as well as occasionally risky assistance, such as a band of
|
||||||
|
local citizens rallying to aid a sorely pressed knight in a fight , or
|
||||||
|
those who sup- port the order helping to smuggle a knight out of town when
|
||||||
|
he or she is being hunted unjustly.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Knightly Regard"
|
||||||
|
source = "Background (Knight of the Order)"
|
||||||
|
|
||||||
|
|
||||||
|
class MercenaryLife(Feature):
|
||||||
|
"""You know the mercenary life as only someone who has experienced it can. You
|
||||||
|
are able to identify mercenary companies by their emblems, and you know a
|
||||||
|
little about any such company, including the names and reputations of its
|
||||||
|
commanders and leaders, and who has hired them recently. You can find the
|
||||||
|
taverns and festhalls where mercenaries abide in any area, as long as you
|
||||||
|
speak the language. You can find mercenary work between adven- tures
|
||||||
|
sufficient to maintain a comfortable lifestyle (see "Practicing a
|
||||||
|
Profession" under "Downtime Activities" in chapter 8 of the Player's
|
||||||
|
Handbook).
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Mercenary Life"
|
||||||
|
source = "Background (Mercenary Veteran)"
|
||||||
|
|
||||||
|
|
||||||
|
class UthgardtHeritage(Feature):
|
||||||
|
"""You have an excellent knowledge of not only your tribe's territory, but also
|
||||||
|
the terrain and natural resources of the rest of the North. You are
|
||||||
|
familiar enough with any wilderness area that you find twice as much food
|
||||||
|
and water as you normally would when you forage there.
|
||||||
|
|
||||||
|
Additionally, you can call upon the hospitality of your people, and those
|
||||||
|
folk allied with your tribe, often including members of druid circles,
|
||||||
|
tribes of nomadic elves, the Harpers, and the priesthoods devoted to the
|
||||||
|
gods of the First Circle.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Uthgardt Heritage"
|
||||||
|
source = "Background (Uthgardt Tribe Member)"
|
||||||
|
|
||||||
|
|
||||||
|
class KeptInStyle(Feature):
|
||||||
|
"""While you are in Waterdeep or elsewhere in the North your house sees to your
|
||||||
|
everyday needs. Your name and signet are sufficient to cover most of your
|
||||||
|
expenses; the inns, taverns, and festhalls you frequent are glad to re-
|
||||||
|
cord your debt and send an accounting to your family's estate in Waterdeep
|
||||||
|
to settle what you owe.
|
||||||
|
|
||||||
|
This advantage enables you to live a comfortable life- style without having
|
||||||
|
to pay 2 gp a day for it, or reduces the cost of a wealthy or aristocratic
|
||||||
|
lifestyle by that amount. You may not maintain a less affluent lifestyle
|
||||||
|
and use the difference as income-the benefit is a line of credit, not an
|
||||||
|
actual monetary reward.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Kept in Style"
|
||||||
|
source = "Background (Waterdhavian Noble)"
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ class Feature():
|
|||||||
"""
|
"""
|
||||||
name = "Generic Feature"
|
name = "Generic Feature"
|
||||||
source = '' # race, class, background, etc.
|
source = '' # race, class, background, etc.
|
||||||
|
spells_known = ()
|
||||||
|
spells_prepared = ()
|
||||||
needs_implementation = False # Set to True if need to find way to compute stats
|
needs_implementation = False # Set to True if need to find way to compute stats
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
|
|||||||
@@ -125,6 +125,7 @@ class SunlightSensitivity(Feature):
|
|||||||
name = "Sunlight Sensitivity"
|
name = "Sunlight Sensitivity"
|
||||||
source = "Race (Dark Elf)"
|
source = "Race (Dark Elf)"
|
||||||
|
|
||||||
|
|
||||||
class DrowMagic(Feature):
|
class DrowMagic(Feature):
|
||||||
"""You know the dancing lights cantrip. When you reach 3rd level, you can
|
"""You know the dancing lights cantrip. When you reach 3rd level, you can
|
||||||
cast the faerie fire spell once per day. When you reach 5th level, you can
|
cast the faerie fire spell once per day. When you reach 5th level, you can
|
||||||
@@ -259,7 +260,6 @@ class NaturalIllusionist(Feature):
|
|||||||
"""
|
"""
|
||||||
name = "Natural Illusionist"
|
name = "Natural Illusionist"
|
||||||
source = "Race (Forest Gnome)"
|
source = "Race (Forest Gnome)"
|
||||||
needs_implementation = True
|
|
||||||
|
|
||||||
|
|
||||||
class SpeakWithSmallBeasts(Feature):
|
class SpeakWithSmallBeasts(Feature):
|
||||||
@@ -357,6 +357,7 @@ class InfernalLegacy(Feature):
|
|||||||
"""
|
"""
|
||||||
name = "Infernal Legacy"
|
name = "Infernal Legacy"
|
||||||
source = "Race (Tiefling)"
|
source = "Race (Tiefling)"
|
||||||
|
needs_implementation = True
|
||||||
|
|
||||||
|
|
||||||
# Aasimar
|
# Aasimar
|
||||||
@@ -385,7 +386,6 @@ class LightBearer(Feature):
|
|||||||
"""
|
"""
|
||||||
name = "Light Bearer"
|
name = "Light Bearer"
|
||||||
source = "Race (Aasimar)"
|
source = "Race (Aasimar)"
|
||||||
needs_implementation = True
|
|
||||||
|
|
||||||
|
|
||||||
class RadiantSoul(Feature):
|
class RadiantSoul(Feature):
|
||||||
|
|||||||
@@ -97,8 +97,7 @@ def create_latex_pdf(char, basename, template):
|
|||||||
f'{basename_}.log']
|
f'{basename_}.log']
|
||||||
for filename in filenames:
|
for filename in filenames:
|
||||||
if os.path.exists(filename):
|
if os.path.exists(filename):
|
||||||
pass
|
os.remove(filename)
|
||||||
#os.remove(filename)
|
|
||||||
# Compile the PDF
|
# Compile the PDF
|
||||||
pdf_file = f'{basename}.pdf'
|
pdf_file = f'{basename}.pdf'
|
||||||
output_dir = os.path.abspath(os.path.dirname(pdf_file))
|
output_dir = os.path.abspath(os.path.dirname(pdf_file))
|
||||||
|
|||||||
+28
-34
@@ -1,4 +1,4 @@
|
|||||||
from . import weapons
|
from . import (weapons, spells)
|
||||||
from . import features as feats
|
from . import features as feats
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
@@ -22,6 +22,8 @@ class Race():
|
|||||||
wisdom_bonus = 0
|
wisdom_bonus = 0
|
||||||
charisma_bonus = 0
|
charisma_bonus = 0
|
||||||
hit_point_bonus = 0
|
hit_point_bonus = 0
|
||||||
|
spells_known = ()
|
||||||
|
spells_prepared = ()
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.features = tuple([f() for f in self.features])
|
self.features = tuple([f() for f in self.features])
|
||||||
@@ -99,6 +101,8 @@ class DarkElf(Elf):
|
|||||||
charisma_bonus = 1
|
charisma_bonus = 1
|
||||||
features = (feats.SuperiorDarkvision, feats.FeyAncestry, feats.Trance,
|
features = (feats.SuperiorDarkvision, feats.FeyAncestry, feats.Trance,
|
||||||
feats.SunlightSensitivity, feats.DrowMagic)
|
feats.SunlightSensitivity, feats.DrowMagic)
|
||||||
|
spells_known = (spells.DancingLights(),)
|
||||||
|
spells_prepared = (spells.DancingLights(),)
|
||||||
|
|
||||||
|
|
||||||
# Halflings
|
# Halflings
|
||||||
@@ -164,6 +168,8 @@ class ForestGnome(Gnome):
|
|||||||
dexterity_bonus = 1
|
dexterity_bonus = 1
|
||||||
features = Gnome.features + (feats.NaturalIllusionist,
|
features = Gnome.features + (feats.NaturalIllusionist,
|
||||||
feats.SpeakWithSmallBeasts)
|
feats.SpeakWithSmallBeasts)
|
||||||
|
spells_known = (spells.MinorIllusion(),)
|
||||||
|
spells_prepared = (spells.MinorIllusion(),)
|
||||||
|
|
||||||
|
|
||||||
class RockGnome(Gnome):
|
class RockGnome(Gnome):
|
||||||
@@ -230,6 +236,8 @@ class Aasimar(Race):
|
|||||||
languages = ("Common", "Celestial")
|
languages = ("Common", "Celestial")
|
||||||
features = (feats.Darkvision, feats.CelestialResistance,
|
features = (feats.Darkvision, feats.CelestialResistance,
|
||||||
feats.HealingHands, feats.LightBearer)
|
feats.HealingHands, feats.LightBearer)
|
||||||
|
spells_known = (spells.Light(),)
|
||||||
|
spells_prepared = (spells.Light(),)
|
||||||
|
|
||||||
|
|
||||||
# Protector Aasimar
|
# Protector Aasimar
|
||||||
@@ -334,8 +342,10 @@ class Triton(Race):
|
|||||||
features = (feats.Amphibious, feats.ControlAirAndWater,
|
features = (feats.Amphibious, feats.ControlAirAndWater,
|
||||||
feats.EmissaryOfTheSea, feats.GuardiansOfTheDepths)
|
feats.EmissaryOfTheSea, feats.GuardiansOfTheDepths)
|
||||||
languages = ("Common", "Primordial")
|
languages = ("Common", "Primordial")
|
||||||
|
spells_known = (spells.FogCloud(),)
|
||||||
|
spells_prepared = (spells.FogCloud(),)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Aarakocra
|
# Aarakocra
|
||||||
class Aarakocra(Race):
|
class Aarakocra(Race):
|
||||||
name = 'Aarakocra'
|
name = 'Aarakocra'
|
||||||
@@ -350,6 +360,7 @@ class Aarakocra(Race):
|
|||||||
|
|
||||||
# Genasi
|
# Genasi
|
||||||
class Genasi(Race):
|
class Genasi(Race):
|
||||||
|
name = "Genasi"
|
||||||
constitution_bonus = 2
|
constitution_bonus = 2
|
||||||
size = 'medium'
|
size = 'medium'
|
||||||
speed = 30
|
speed = 30
|
||||||
@@ -357,61 +368,44 @@ class Genasi(Race):
|
|||||||
|
|
||||||
|
|
||||||
class AirGenasi(Genasi):
|
class AirGenasi(Genasi):
|
||||||
|
name = "Air Genasi"
|
||||||
dexterity_bonus = 1
|
dexterity_bonus = 1
|
||||||
features = (feats.UnendingBreath,
|
features = (feats.UnendingBreath,
|
||||||
feats.MingleWithTheWind)
|
feats.MingleWithTheWind)
|
||||||
|
|
||||||
|
|
||||||
class EarthGenasi(Genasi):
|
class EarthGenasi(Genasi):
|
||||||
|
name = "Earth Genasi"
|
||||||
strength_bonus = 1
|
strength_bonus = 1
|
||||||
features = (feats.EarthWalk, feats.MergeWithStone)
|
features = (feats.EarthWalk, feats.MergeWithStone)
|
||||||
|
|
||||||
|
|
||||||
class FireGenasi(Genasi):
|
class FireGenasi(Genasi):
|
||||||
|
name = "Fire Genasi"
|
||||||
intelligence_bonus = 1
|
intelligence_bonus = 1
|
||||||
features = (feats.Darkvision, feats.FireResistance,
|
features = (feats.Darkvision, feats.FireResistance,
|
||||||
feats.ReachToTheBlaze)
|
feats.ReachToTheBlaze)
|
||||||
|
|
||||||
|
|
||||||
class WaterGenasi(Genasi):
|
class WaterGenasi(Genasi):
|
||||||
|
name = "Water Genasi"
|
||||||
wisdom_bonus = 1
|
wisdom_bonus = 1
|
||||||
speed = "30 (30 swim)"
|
speed = "30 (30 swim)"
|
||||||
features = (feats.AcidResistance, feats.Amphibious,
|
features = (feats.AcidResistance, feats.Amphibious,
|
||||||
feats.CallToTheWave)
|
feats.CallToTheWave)
|
||||||
|
|
||||||
|
|
||||||
race_dict = {
|
PHB_races = [HillDwarf, MountainDwarf, HighElf, WoodElf, DarkElf,
|
||||||
"Hill Dwarf": HillDwarf,
|
LightfootHalfling, StoutHalfling, Human, Dragonborn,
|
||||||
'Mountain Dwarf': MountainDwarf,
|
ForestGnome, RockGnome, HalfElf, HalfOrc, Tiefling]
|
||||||
'High Elf': HighElf,
|
|
||||||
'Wood Elf': WoodElf,
|
|
||||||
'Dark Elf': DarkElf,
|
|
||||||
'Lightfoot Halfling': LightfootHalfling,
|
|
||||||
'Stout Halfling': StoutHalfling,
|
|
||||||
'Human': Human,
|
|
||||||
'Dragonborn': Dragonborn,
|
|
||||||
'Forest Gnome': ForestGnome,
|
|
||||||
'Rock Gnome': RockGnome,
|
|
||||||
'Deep Gnome': DeepGnome,
|
|
||||||
'Half-Elf': HalfElf,
|
|
||||||
'Half-Orc': HalfOrc,
|
|
||||||
'Tiefling': Tiefling,
|
|
||||||
'Fallen Aasimar': FallenAasimar,
|
|
||||||
'Protector Aasimar': ProtectorAasimar,
|
|
||||||
'Scourge Aasimar': ScourgeAasimar,
|
|
||||||
'Firbolg': Firbolg,
|
|
||||||
'Goliath': Goliath,
|
|
||||||
'Lizardfolk': Lizardfolk,
|
|
||||||
'Kenku': Kenku,
|
|
||||||
'Tabaxi': Tabaxi,
|
|
||||||
'Triton': Triton,
|
|
||||||
'Aarakocra': Aarakocra,
|
|
||||||
'Fire Genasi': FireGenasi,
|
|
||||||
'Earth Genasi': EarthGenasi,
|
|
||||||
'Water Genasi': WaterGenasi,
|
|
||||||
'Air Genasi': AirGenasi,
|
|
||||||
}
|
|
||||||
|
|
||||||
__all__ = tuple(race_dict.keys())
|
VOLO_races = [ProtectorAasimar, ScourgeAasimar, FallenAasimar,
|
||||||
|
Firbolg, Goliath, Lizardfolk, Kenku, Tabaxi, Triton]
|
||||||
|
|
||||||
|
EE_races = [Aarakocra, DeepGnome, AirGenasi, FireGenasi, EarthGenasi,
|
||||||
|
WaterGenasi]
|
||||||
|
|
||||||
|
available_races = PHB_races + VOLO_races + EE_races
|
||||||
|
|
||||||
|
__all__ = tuple([r.name for r in available_races]) + (
|
||||||
|
'available_races', 'PHB_races', 'VOLO_races', 'EE_races')
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
\maketitle
|
\maketitle
|
||||||
|
|
||||||
[% for spl in character.spells %]
|
[% for spl in character.spells %]
|
||||||
[% if spl.__class__ in character.spells_prepared %]
|
[% if spl in character.spells_prepared %]
|
||||||
{
|
{
|
||||||
[% elif spl.level == 0 %]
|
[% elif spl.level == 0 %]
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -47,6 +47,9 @@ class Spell():
|
|||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
return (self.name == other.name) and (self.level == other.level)
|
return (self.name == other.name) and (self.level == other.level)
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return 0
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def component_string(self):
|
def component_string(self):
|
||||||
|
|||||||
@@ -1704,6 +1704,25 @@ class DetectMagic(Spell):
|
|||||||
classes = ('Bard', 'Cleric', 'Druid', 'Paladin', 'Ranger', 'Sorceror', 'Wizard', )
|
classes = ('Bard', 'Cleric', 'Druid', 'Paladin', 'Ranger', 'Sorceror', 'Wizard', )
|
||||||
|
|
||||||
|
|
||||||
|
class DetectPoisonAndDisease(Spell):
|
||||||
|
"""For the duration, you can sense the presence and location of poisons,
|
||||||
|
poisonous creatures, and diseases within 30 feet of you. You also identify
|
||||||
|
the kind of poison, poisonous creature, or disease in each case.
|
||||||
|
|
||||||
|
The spell can penetrate most barriers, but is blocked by 1 foot of stone, 1
|
||||||
|
inch of common metal, a thin sheet of lead, or 3 feet of wood or dirt.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Detect Poison and Disease"
|
||||||
|
level = 1
|
||||||
|
casting_time = '1 action'
|
||||||
|
casting_range = "Self (30 feet)"
|
||||||
|
components = ("V", "S", "M")
|
||||||
|
materials = "a yew leaf"
|
||||||
|
magic_school = "Divination"
|
||||||
|
classes = ("Cleric", 'Druid', 'Paladin', 'Ranger')
|
||||||
|
|
||||||
|
|
||||||
class DimensionDoor(Spell):
|
class DimensionDoor(Spell):
|
||||||
"""You teleport yourself from your current location to any other spot
|
"""You teleport yourself from your current location to any other spot
|
||||||
within range. You arrive at exactly the spot desired. It can be a
|
within range. You arrive at exactly the spot desired. It can be a
|
||||||
|
|||||||
@@ -174,7 +174,23 @@ class Etherealness(Spell):
|
|||||||
materials = ""
|
materials = ""
|
||||||
duration = "Up to 8 hours"
|
duration = "Up to 8 hours"
|
||||||
magic_school = "Transmutation"
|
magic_school = "Transmutation"
|
||||||
classes = ()
|
classes = ("Bard", 'Cleric', 'Sorceror', 'Warlock', 'Wizard')
|
||||||
|
|
||||||
|
|
||||||
|
class ExpeditiousRetreat(Spell):
|
||||||
|
"""This spell allows you to move at an incredible pace. When you cast this
|
||||||
|
spell, and then as a bonus action on each of your turns until the spell
|
||||||
|
ends, you can take the Dash action.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Expeditious Retreat"
|
||||||
|
level = 1
|
||||||
|
casting_time = '1 bonus action'
|
||||||
|
components = ('V', 'S')
|
||||||
|
duration = "Concentration, up to 10 minutes"
|
||||||
|
casting_range = "self"
|
||||||
|
magic_school = "Transmutation"
|
||||||
|
classes = ("Sorceror", "Warlock", "Wizard")
|
||||||
|
|
||||||
|
|
||||||
class Eyebite(Spell):
|
class Eyebite(Spell):
|
||||||
@@ -468,6 +484,28 @@ class FindSteed(Spell):
|
|||||||
magic_school = "Conjuration"
|
magic_school = "Conjuration"
|
||||||
classes = ('Paladin', )
|
classes = ('Paladin', )
|
||||||
|
|
||||||
|
|
||||||
|
class FogCloud(Spell):
|
||||||
|
"""You create a 20-foot-radius sphere of fog centered on a point within
|
||||||
|
range. The sphere spreads around corners, and its area is heavily obscured,
|
||||||
|
It lasts for the duration or until a wind of moderate or greater speed (at
|
||||||
|
least 10 miles per hour) disperses it.
|
||||||
|
|
||||||
|
At Higher Level:
|
||||||
|
|
||||||
|
When you cast this spell using a spell slot of 2nd level or higher, the
|
||||||
|
radius of the fog increases by 20 feet for each slot level above 1st.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Fog Cloud"
|
||||||
|
level = 1
|
||||||
|
casting_time = "1 action"
|
||||||
|
casting_range = "120 feet"
|
||||||
|
components = ("V", "S")
|
||||||
|
duration = "Concentration, up to 1 hour"
|
||||||
|
magic_school = "Conjuration"
|
||||||
|
classes = ('Druid', 'Ranger', 'Sorceror', 'Wizard')
|
||||||
|
|
||||||
|
|
||||||
class Foresight(Spell):
|
class Foresight(Spell):
|
||||||
"""You touch a willing creature and bestow a limited ability to see
|
"""You touch a willing creature and bestow a limited ability to see
|
||||||
@@ -681,6 +719,35 @@ class GuidingBolt(Spell):
|
|||||||
classes = ()
|
classes = ()
|
||||||
|
|
||||||
|
|
||||||
|
class GustOfWind(Spell):
|
||||||
|
"""A line of strong wind 60 feet long and 10 feet wide blasts from you in a
|
||||||
|
direction you choose for the spell’s duration. Each creature that starts
|
||||||
|
its turn in the line must succeed on a Strength saving throw or be pushed
|
||||||
|
15 feet away from you in a direction following the line.
|
||||||
|
|
||||||
|
Any creature in the line must spend 2 feet of movement for every 1 foot it
|
||||||
|
moves when moving closer to you.
|
||||||
|
|
||||||
|
The gust disperses gas or vapor, and it extinguishes candles, torches, and
|
||||||
|
similar unprotected flames in the area. It causes protected flames, such as
|
||||||
|
those of lanterns, to dance wildly and has a 50 percent chance to
|
||||||
|
extinguish them.
|
||||||
|
|
||||||
|
As a bonus action on each of your turns before the spell ends, you can
|
||||||
|
change the direction in which the line blasts from you.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Gust of Wind"
|
||||||
|
level = 2
|
||||||
|
casting_time = "1 action"
|
||||||
|
casting_range = "Self (60-foot line)"
|
||||||
|
components = ("V", 'S', 'M')
|
||||||
|
materials = "A legume seed"
|
||||||
|
duration = "Concentration, up to 1 minute"
|
||||||
|
magic_school = "Evocation"
|
||||||
|
classes = ("Druid", "Sorceror", 'Wizard')
|
||||||
|
|
||||||
|
|
||||||
class Harm(Spell):
|
class Harm(Spell):
|
||||||
"""You unleash a virulent disease on a creature that you can see
|
"""You unleash a virulent disease on a creature that you can see
|
||||||
within range. The target must make a Constitution saving throw. On
|
within range. The target must make a Constitution saving throw. On
|
||||||
@@ -872,6 +939,32 @@ class HolyAura(Spell):
|
|||||||
classes = ()
|
classes = ()
|
||||||
|
|
||||||
|
|
||||||
|
class HuntersMark(Spell):
|
||||||
|
"""You choose a creature you can see within range and mystically mark it as
|
||||||
|
your quarry. Until the spell ends, you deal an extra 1d6 damage to the
|
||||||
|
target whenever you hit it with a weapon attack, and you have advantage on
|
||||||
|
any Wisdom (Perception) or Wisdom (Survival) check you make to find it. If
|
||||||
|
the target drops to 0 hit points before this spell ends, you can use a
|
||||||
|
bonus action on a subsequent turn of yours to mark a new creature.
|
||||||
|
|
||||||
|
At Higher Level:
|
||||||
|
|
||||||
|
When you cast this spell using a spell slot of 3rd or 4th level, you can
|
||||||
|
maintain your concentration on the spell for up to 8 hours. When you use a
|
||||||
|
spell slot of 5th level or higher, you can maintain your concentration on
|
||||||
|
the spell for up to 24 hours.
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = "Hunter's Mark"
|
||||||
|
level = 1
|
||||||
|
casting_time = "1 bonus action"
|
||||||
|
casting_range = "90 feet"
|
||||||
|
components = ("V")
|
||||||
|
duration = "Concentration, up to 1 hour"
|
||||||
|
magic_school = "Diviniation"
|
||||||
|
classes = ("Ranger",)
|
||||||
|
|
||||||
|
|
||||||
class IceStorm(Spell):
|
class IceStorm(Spell):
|
||||||
"""A hail of rock-hard ice pounds to the ground in a 20-foot-radius,
|
"""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
|
40-foot-high cylinder centered on a point within range. Each
|
||||||
|
|||||||
Reference in New Issue
Block a user