mirror of
https://github.com/Threnklyn/dungeon-sheets.git
synced 2026-05-19 04:33:26 +02:00
save function now works for a character... need to add defaults if options dont exist
This commit is contained in:
@@ -1,2 +1,8 @@
|
|||||||
from . import weapons, character
|
from . import weapons, character, features, race, background, spells
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
def read(fname):
|
||||||
|
return open(os.path.join(os.path.dirname(__file__), fname)).read()
|
||||||
|
|
||||||
|
__version__ = read('../VERSION')
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ class Shield():
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "\"{:s}\"".format(self.name)
|
||||||
|
|
||||||
class WoodenShield(Shield):
|
class WoodenShield(Shield):
|
||||||
name = 'Wooden shield'
|
name = 'Wooden shield'
|
||||||
@@ -55,6 +57,8 @@ class Armor():
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "\"{:s}\"".format(self.name)
|
||||||
|
|
||||||
class NoArmor(Armor):
|
class NoArmor(Armor):
|
||||||
name = "No armor"
|
name = "No armor"
|
||||||
|
|||||||
@@ -5,11 +5,14 @@ import os
|
|||||||
import warnings
|
import warnings
|
||||||
from . import exceptions
|
from . import exceptions
|
||||||
import importlib.util
|
import importlib.util
|
||||||
|
import jinja2
|
||||||
|
import subprocess
|
||||||
|
|
||||||
from .stats import Ability, Skill, findattr
|
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
|
||||||
|
|
||||||
@@ -49,6 +52,7 @@ class Character():
|
|||||||
class_name = ""
|
class_name = ""
|
||||||
player_name = ""
|
player_name = ""
|
||||||
alignment = "Neutral"
|
alignment = "Neutral"
|
||||||
|
dungeonsheets_version = __version__
|
||||||
class_list = []
|
class_list = []
|
||||||
race = None
|
race = None
|
||||||
background = None
|
background = None
|
||||||
@@ -111,7 +115,8 @@ class Character():
|
|||||||
spells = tuple()
|
spells = tuple()
|
||||||
spells_prepared = tuple()
|
spells_prepared = tuple()
|
||||||
# Features IN MAJOR DEVELOPMENT
|
# Features IN MAJOR DEVELOPMENT
|
||||||
other_features = ()
|
custom_features = ()
|
||||||
|
feature_choices = ()
|
||||||
|
|
||||||
def __init__(self, **attrs):
|
def __init__(self, **attrs):
|
||||||
"""Takes a bunch of attrs and passes them to ``set_attrs``"""
|
"""Takes a bunch of attrs and passes them to ``set_attrs``"""
|
||||||
@@ -150,6 +155,11 @@ class Character():
|
|||||||
@property
|
@property
|
||||||
def class_initialized(self):
|
def class_initialized(self):
|
||||||
return (self.num_classes > 0)
|
return (self.num_classes > 0)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def classes_levels(self):
|
||||||
|
return [c.class_name.lower() + ' ' + str(c.class_level)
|
||||||
|
for c in self.class_list]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def primary_class(self):
|
def primary_class(self):
|
||||||
@@ -176,7 +186,7 @@ class Character():
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def features(self):
|
def features(self):
|
||||||
fts = set(self.other_features)
|
fts = set(self.custom_features)
|
||||||
if not self.class_initialized:
|
if not self.class_initialized:
|
||||||
return fts
|
return fts
|
||||||
for c in self.class_list:
|
for c in self.class_list:
|
||||||
@@ -190,6 +200,10 @@ class Character():
|
|||||||
if self.background is not None:
|
if self.background is not None:
|
||||||
fts |= set(getattr(self.background, 'features', ()))
|
fts |= set(getattr(self.background, 'features', ()))
|
||||||
return tuple(fts)
|
return tuple(fts)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def custom_features_text(self):
|
||||||
|
return tuple([f.name for f in self.custom_features])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def saving_throw_proficiencies(self):
|
def saving_throw_proficiencies(self):
|
||||||
@@ -279,7 +293,7 @@ class Character():
|
|||||||
name=f, source='Unknown',
|
name=f, source='Unknown',
|
||||||
__doc__="""Unknown Feature. Add to features.py"""))
|
__doc__="""Unknown Feature. Add to features.py"""))
|
||||||
warnings.warn(msg)
|
warnings.warn(msg)
|
||||||
self.other_features = tuple(F() for F in _features)
|
self.custom_features = tuple(F() for F in _features)
|
||||||
elif (attr == 'spells') or (attr == 'spells_prepared'):
|
elif (attr == 'spells') or (attr == 'spells_prepared'):
|
||||||
# Create a list of actual spell objects
|
# Create a list of actual spell objects
|
||||||
_spells = []
|
_spells = []
|
||||||
@@ -300,8 +314,8 @@ class Character():
|
|||||||
# 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:
|
||||||
# this is a list of spell classes
|
# Instantiate them all for the spells list
|
||||||
self.spells_prepared = tuple(_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}",
|
||||||
@@ -401,7 +415,7 @@ class Character():
|
|||||||
directly.
|
directly.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if shield not in ('', None):
|
if shield not in ('', 'None', None):
|
||||||
try:
|
try:
|
||||||
NewShield = findattr(armor, shield)
|
NewShield = findattr(armor, shield)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
@@ -519,7 +533,7 @@ class Character():
|
|||||||
raise ValueError(
|
raise ValueError(
|
||||||
'level was not recognizable as an int: {:s}'.format(lvl))
|
'level was not recognizable as an int: {:s}'.format(lvl))
|
||||||
params = {}
|
params = {}
|
||||||
params['feature_choices'] = char_props.pop('feature_choices', [])
|
params['feature_choices'] = char_props.get('feature_choices', [])
|
||||||
class_list += [this_class(this_level, subclass=sub, **params)]
|
class_list += [this_class(this_level, subclass=sub, **params)]
|
||||||
# accept backwards compatability for single-class characters
|
# accept backwards compatability for single-class characters
|
||||||
if len(class_list) == 0:
|
if len(class_list) == 0:
|
||||||
@@ -532,7 +546,28 @@ class Character():
|
|||||||
char = cls(**char_props)
|
char = cls(**char_props)
|
||||||
return char
|
return char
|
||||||
|
|
||||||
|
def save(self, filename, template_file='character_template.txt'):
|
||||||
|
# Create the template context
|
||||||
|
context = dict(
|
||||||
|
char=self,
|
||||||
|
)
|
||||||
|
# Render the template
|
||||||
|
src_path = os.path.dirname(__file__)
|
||||||
|
text = jinja2.Environment(
|
||||||
|
loader=jinja2.FileSystemLoader(src_path or './')
|
||||||
|
).get_template(template_file).render(context)
|
||||||
|
# Save the file
|
||||||
|
with open(filename, mode='w') as f:
|
||||||
|
f.write(text)
|
||||||
|
|
||||||
|
def to_pdf(self, filename, **kwargs):
|
||||||
|
char_file = filename.replace('pdf', 'py')
|
||||||
|
self.save(char_file,
|
||||||
|
template_file=kwargs.get('template_file',
|
||||||
|
'character_template.txt'))
|
||||||
|
subprocess.call(['makesheets', char_file])
|
||||||
|
|
||||||
|
|
||||||
def read_character_file(filename):
|
def read_character_file(filename):
|
||||||
"""Create a character object from the given definition file.
|
"""Create a character object from the given definition file.
|
||||||
|
|
||||||
|
|||||||
@@ -5,14 +5,13 @@ sheet by running ``makesheets`` from the command line.
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
dungeonsheets_version = "{{ dungeonsheets_version }}"
|
dungeonsheets_version = "{{ char.dungeonsheets_version }}"
|
||||||
|
|
||||||
name = '{{ char.name }}'
|
name = "{{ char.name }}"
|
||||||
character_class = '{{ char.class_name }}'
|
classes_levels = {{ char.classes_levels }}
|
||||||
player_name = '{{ char.player_name }}'
|
player_name = "{{ char.player_name }}"
|
||||||
background = "{{ char.background.name }}"
|
background = "{{ char.background.name }}"
|
||||||
race = "{{ char.race.name }}"
|
race = "{{ char.race.name }}"
|
||||||
level = {{ char.level }}
|
|
||||||
alignment = "{{ char.alignment }}"
|
alignment = "{{ char.alignment }}"
|
||||||
xp = {{ char.xp }}
|
xp = {{ char.xp }}
|
||||||
hp_max = {{ char.hp_max }}
|
hp_max = {{ char.hp_max }}
|
||||||
@@ -24,10 +23,23 @@ constitution = {{ char.constitution.value }}
|
|||||||
intelligence = {{ char.intelligence.value }}
|
intelligence = {{ char.intelligence.value }}
|
||||||
wisdom = {{ char.wisdom.value }}
|
wisdom = {{ char.wisdom.value }}
|
||||||
charisma = {{ char.charisma.value }}
|
charisma = {{ char.charisma.value }}
|
||||||
|
|
||||||
|
# Select what skills you're proficient with
|
||||||
skill_proficiencies = {{ char.skill_proficiencies }}
|
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 = {{ char.custom_features }}
|
||||||
|
|
||||||
|
# If selecting among multiple feature options: ex Fighting Style
|
||||||
|
# Example (Fighting Style):
|
||||||
|
# feature_choices = ('Archery',)
|
||||||
|
feature_choices = {{ char.feature_choices }}
|
||||||
|
|
||||||
# Proficiencies and languages
|
# Proficiencies and languages
|
||||||
languages = "{{ char.languages }}"
|
languages = """{{ char.languages }}"""
|
||||||
|
|
||||||
# Inventory
|
# Inventory
|
||||||
# TODO: Get yourself some money
|
# TODO: Get yourself some money
|
||||||
@@ -38,35 +50,30 @@ gp = 0
|
|||||||
pp = 0
|
pp = 0
|
||||||
|
|
||||||
# TODO: Put your equipped weapons and armor here
|
# TODO: Put your equipped weapons and armor here
|
||||||
weapons = () # Example: ('shortsword', 'longsword')
|
weapons = {{ char.weapons }} # Example: ('shortsword', 'longsword')
|
||||||
armor = "" # Eg "light leather armor"
|
armor = "{{ char.armor }}" # Eg "light leather armor"
|
||||||
shield = "" # Eg "shield"
|
shield = "{{ char.shield }}" # Eg "shield"
|
||||||
|
|
||||||
equipment = "TODO: Describe your equipment from your {{ char.class_name }} class and {{ char.background.name }} background."
|
equipment = """{{ char.equipment }}"""
|
||||||
|
|
||||||
attacks_and_spellcasting = "TODO: Describe specifics for how your {{ char.class_name }} attacks."
|
attacks_and_spellcasting = """{{ char.attacks_and_spellcasting }}"""
|
||||||
|
|
||||||
# List of known spells
|
# List of known spells
|
||||||
# Example: spells = ('magic missile', 'mage armor')
|
# Example: spells = ('magic missile', 'mage armor')
|
||||||
spells = () # Todo: Learn some spells
|
spells = {{ char.spells }} # Todo: Learn some spells
|
||||||
|
|
||||||
# Which spells have been prepared (not including cantrips)
|
# Which spells have been prepared (not including cantrips)
|
||||||
spells_prepared = ()
|
spells_prepared = {{ char.spells_prepared }}
|
||||||
|
|
||||||
# Backstory
|
# Backstory
|
||||||
# TODO: Describe your backstory here
|
# Describe your backstory here
|
||||||
personality_traits = """I am a leaf on the wind,
|
personality_traits = """{{ char.personality_traits}}"""
|
||||||
watch how I...
|
|
||||||
"""
|
|
||||||
|
|
||||||
ideals = """
|
ideals = """{{ char.ideals }}"""
|
||||||
"""
|
|
||||||
|
|
||||||
bonds = """
|
bonds = """{{ char.bonds }}"""
|
||||||
"""
|
|
||||||
|
|
||||||
flaws = """
|
flaws = """{{ char.flaws }}"""
|
||||||
"""
|
|
||||||
|
|
||||||
features_and_traits = """
|
features_and_traits = """{{ char.features_and_traits }}"""
|
||||||
"""
|
|
||||||
|
|
||||||
|
|||||||
@@ -51,4 +51,4 @@ class Ranger(CharClass):
|
|||||||
|
|
||||||
# Custom Classes
|
# Custom Classes
|
||||||
class Revisedranger(Ranger):
|
class Revisedranger(Ranger):
|
||||||
class_name = 'Revised Ranger'
|
class_name = 'Revisedranger'
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import subprocess
|
|||||||
import npyscreen
|
import npyscreen
|
||||||
import jinja2
|
import jinja2
|
||||||
|
|
||||||
from dungeonsheets import character, race, dice, background
|
from dungeonsheets import character, race, dice, background, classes
|
||||||
|
|
||||||
|
|
||||||
def read_version():
|
def read_version():
|
||||||
@@ -24,18 +24,18 @@ def read_version():
|
|||||||
|
|
||||||
|
|
||||||
char_classes = {
|
char_classes = {
|
||||||
'Barbarian': character.Barbarian,
|
'Barbarian': classes.Barbarian,
|
||||||
'Bard': character.Bard,
|
'Bard': classes.Bard,
|
||||||
'Cleric': character.Cleric,
|
'Cleric': classes.Cleric,
|
||||||
'Druid': character.Druid,
|
'Druid': classes.Druid,
|
||||||
'Fighter': character.Fighter,
|
'Fighter': classes.Fighter,
|
||||||
'Monk': character.Monk,
|
'Monk': classes.Monk,
|
||||||
'Paladin': character.Paladin,
|
'Paladin': classes.Paladin,
|
||||||
'Ranger': character.Ranger,
|
'Ranger': classes.Ranger,
|
||||||
'Rogue': character.Rogue,
|
'Rogue': classes.Rogue,
|
||||||
'Sorceror': character.Sorceror,
|
'Sorceror': classes.Sorceror,
|
||||||
'Warlock': character.Warlock,
|
'Warlock': classes.Warlock,
|
||||||
'Wizard': character.Wizard
|
'Wizard': classes.Wizard
|
||||||
}
|
}
|
||||||
|
|
||||||
races = {
|
races = {
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ class Feature():
|
|||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "\"{:s}\"".format(self.name)
|
||||||
|
|
||||||
def weapon_func(self, weapon: weapons.Weapon, **kwargs):
|
def weapon_func(self, weapon: weapons.Weapon, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ def create_spells_pdf(char, basename, flatten=False):
|
|||||||
prep_names = tuple(f'Check Box {i}' for i in prep_numbers[level])
|
prep_names = tuple(f'Check Box {i}' for i in prep_numbers[level])
|
||||||
for spell, field, chk_field in zip(spells, field_names, prep_names):
|
for spell, field, chk_field in zip(spells, field_names, prep_names):
|
||||||
fields[field] = str(spell)
|
fields[field] = str(spell)
|
||||||
is_prepared = any([isinstance(spell, Spl)
|
is_prepared = any([spell == Spl
|
||||||
for Spl in char.spells_prepared])
|
for Spl in char.spells_prepared])
|
||||||
fields[chk_field] = CHECKBOX_ON if is_prepared else CHECKBOX_OFF
|
fields[chk_field] = CHECKBOX_ON if is_prepared else CHECKBOX_OFF
|
||||||
# # Uncomment to post field names instead:
|
# # Uncomment to post field names instead:
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ def create_spell(**params):
|
|||||||
NewSpell
|
NewSpell
|
||||||
New spell class, subclass of ``Spell``, with given params.
|
New spell class, subclass of ``Spell``, with given params.
|
||||||
"""
|
"""
|
||||||
NewSpell = type('UnknownSpell', (Spell,), params)
|
NewSpell = Spell
|
||||||
|
NewSpell.name = params.get('name', 'Unknown Spell')
|
||||||
|
NewSpell.level = params.get('level', 9)
|
||||||
return NewSpell
|
return NewSpell
|
||||||
|
|
||||||
|
|
||||||
@@ -41,8 +43,11 @@ class Spell():
|
|||||||
return s
|
return s
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f'<{self.name}>'
|
return "\"{:s}\"".format(self.name)
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return (self.name == other.name) and (self.level == other.level)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def component_string(self):
|
def component_string(self):
|
||||||
s = f'{", ".join(self.components)}'
|
s = f'{", ".join(self.components)}'
|
||||||
|
|||||||
@@ -24,6 +24,12 @@ class Weapon():
|
|||||||
def is_ranged(self):
|
def is_ranged(self):
|
||||||
return ('range' in self.properties.lower()) and ('thrown' not in self.properties.lower())
|
return ('range' in self.properties.lower()) and ('thrown' not in self.properties.lower())
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "\"{:s}\"".format(self.name)
|
||||||
|
|
||||||
|
|
||||||
class Club(Weapon):
|
class Club(Weapon):
|
||||||
name = "Club"
|
name = "Club"
|
||||||
|
|||||||
Reference in New Issue
Block a user