mirror of
https://github.com/Threnklyn/dungeon-sheets.git
synced 2026-06-13 16:13:32 +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):
|
||||
return self.name
|
||||
|
||||
def __repr__(self):
|
||||
return "\"{:s}\"".format(self.name)
|
||||
|
||||
class WoodenShield(Shield):
|
||||
name = 'Wooden shield'
|
||||
@@ -55,6 +57,8 @@ class Armor():
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def __repr__(self):
|
||||
return "\"{:s}\"".format(self.name)
|
||||
|
||||
class NoArmor(Armor):
|
||||
name = "No armor"
|
||||
|
||||
@@ -5,11 +5,14 @@ import os
|
||||
import warnings
|
||||
from . import exceptions
|
||||
import importlib.util
|
||||
import jinja2
|
||||
import subprocess
|
||||
|
||||
from .stats import Ability, Skill, findattr
|
||||
from .dice import read_dice_str
|
||||
from . import (weapons, race, background, spells, armor, monsters,
|
||||
exceptions, classes, features)
|
||||
from .__init__ import __version__
|
||||
from .weapons import Weapon
|
||||
from .armor import Armor, NoArmor, Shield, NoShield
|
||||
|
||||
@@ -49,6 +52,7 @@ class Character():
|
||||
class_name = ""
|
||||
player_name = ""
|
||||
alignment = "Neutral"
|
||||
dungeonsheets_version = __version__
|
||||
class_list = []
|
||||
race = None
|
||||
background = None
|
||||
@@ -111,7 +115,8 @@ class Character():
|
||||
spells = tuple()
|
||||
spells_prepared = tuple()
|
||||
# Features IN MAJOR DEVELOPMENT
|
||||
other_features = ()
|
||||
custom_features = ()
|
||||
feature_choices = ()
|
||||
|
||||
def __init__(self, **attrs):
|
||||
"""Takes a bunch of attrs and passes them to ``set_attrs``"""
|
||||
@@ -150,6 +155,11 @@ class Character():
|
||||
@property
|
||||
def class_initialized(self):
|
||||
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
|
||||
def primary_class(self):
|
||||
@@ -176,7 +186,7 @@ class Character():
|
||||
|
||||
@property
|
||||
def features(self):
|
||||
fts = set(self.other_features)
|
||||
fts = set(self.custom_features)
|
||||
if not self.class_initialized:
|
||||
return fts
|
||||
for c in self.class_list:
|
||||
@@ -190,6 +200,10 @@ class Character():
|
||||
if self.background is not None:
|
||||
fts |= set(getattr(self.background, 'features', ()))
|
||||
return tuple(fts)
|
||||
|
||||
@property
|
||||
def custom_features_text(self):
|
||||
return tuple([f.name for f in self.custom_features])
|
||||
|
||||
@property
|
||||
def saving_throw_proficiencies(self):
|
||||
@@ -279,7 +293,7 @@ class Character():
|
||||
name=f, source='Unknown',
|
||||
__doc__="""Unknown Feature. Add to features.py"""))
|
||||
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'):
|
||||
# Create a list of actual spell objects
|
||||
_spells = []
|
||||
@@ -300,8 +314,8 @@ class Character():
|
||||
# Instantiate them all for the spells list
|
||||
self.spells = tuple(S() for S in _spells)
|
||||
else:
|
||||
# this is a list of spell classes
|
||||
self.spells_prepared = tuple(_spells)
|
||||
# Instantiate them all for the spells list
|
||||
self.spells_prepared = tuple(S() for S in _spells)
|
||||
else:
|
||||
if not hasattr(self, attr):
|
||||
warnings.warn(f"Setting unknown character attribute {attr}",
|
||||
@@ -401,7 +415,7 @@ class Character():
|
||||
directly.
|
||||
|
||||
"""
|
||||
if shield not in ('', None):
|
||||
if shield not in ('', 'None', None):
|
||||
try:
|
||||
NewShield = findattr(armor, shield)
|
||||
except AttributeError:
|
||||
@@ -519,7 +533,7 @@ class Character():
|
||||
raise ValueError(
|
||||
'level was not recognizable as an int: {:s}'.format(lvl))
|
||||
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)]
|
||||
# accept backwards compatability for single-class characters
|
||||
if len(class_list) == 0:
|
||||
@@ -532,7 +546,28 @@ class Character():
|
||||
char = cls(**char_props)
|
||||
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):
|
||||
"""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 }}'
|
||||
character_class = '{{ char.class_name }}'
|
||||
player_name = '{{ char.player_name }}'
|
||||
name = "{{ char.name }}"
|
||||
classes_levels = {{ char.classes_levels }}
|
||||
player_name = "{{ char.player_name }}"
|
||||
background = "{{ char.background.name }}"
|
||||
race = "{{ char.race.name }}"
|
||||
level = {{ char.level }}
|
||||
alignment = "{{ char.alignment }}"
|
||||
xp = {{ char.xp }}
|
||||
hp_max = {{ char.hp_max }}
|
||||
@@ -24,10 +23,23 @@ 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 = {{ 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
|
||||
languages = "{{ char.languages }}"
|
||||
languages = """{{ char.languages }}"""
|
||||
|
||||
# Inventory
|
||||
# TODO: Get yourself some money
|
||||
@@ -38,35 +50,30 @@ gp = 0
|
||||
pp = 0
|
||||
|
||||
# TODO: Put your equipped weapons and armor here
|
||||
weapons = () # Example: ('shortsword', 'longsword')
|
||||
armor = "" # Eg "light leather armor"
|
||||
shield = "" # Eg "shield"
|
||||
weapons = {{ char.weapons }} # Example: ('shortsword', 'longsword')
|
||||
armor = "{{ char.armor }}" # Eg "light leather armor"
|
||||
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
|
||||
# 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)
|
||||
spells_prepared = ()
|
||||
spells_prepared = {{ char.spells_prepared }}
|
||||
|
||||
# Backstory
|
||||
# TODO: Describe your backstory here
|
||||
personality_traits = """I am a leaf on the wind,
|
||||
watch how I...
|
||||
"""
|
||||
# Describe your backstory here
|
||||
personality_traits = """{{ char.personality_traits}}"""
|
||||
|
||||
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
|
||||
class Revisedranger(Ranger):
|
||||
class_name = 'Revised Ranger'
|
||||
class_name = 'Revisedranger'
|
||||
|
||||
@@ -14,7 +14,7 @@ import subprocess
|
||||
import npyscreen
|
||||
import jinja2
|
||||
|
||||
from dungeonsheets import character, race, dice, background
|
||||
from dungeonsheets import character, race, dice, background, classes
|
||||
|
||||
|
||||
def read_version():
|
||||
@@ -24,18 +24,18 @@ def read_version():
|
||||
|
||||
|
||||
char_classes = {
|
||||
'Barbarian': character.Barbarian,
|
||||
'Bard': character.Bard,
|
||||
'Cleric': character.Cleric,
|
||||
'Druid': character.Druid,
|
||||
'Fighter': character.Fighter,
|
||||
'Monk': character.Monk,
|
||||
'Paladin': character.Paladin,
|
||||
'Ranger': character.Ranger,
|
||||
'Rogue': character.Rogue,
|
||||
'Sorceror': character.Sorceror,
|
||||
'Warlock': character.Warlock,
|
||||
'Wizard': character.Wizard
|
||||
'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 = {
|
||||
|
||||
@@ -37,6 +37,9 @@ class Feature():
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def __repr__(self):
|
||||
return "\"{:s}\"".format(self.name)
|
||||
|
||||
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])
|
||||
for spell, field, chk_field in zip(spells, field_names, prep_names):
|
||||
fields[field] = str(spell)
|
||||
is_prepared = any([isinstance(spell, Spl)
|
||||
is_prepared = any([spell == Spl
|
||||
for Spl in char.spells_prepared])
|
||||
fields[chk_field] = CHECKBOX_ON if is_prepared else CHECKBOX_OFF
|
||||
# # Uncomment to post field names instead:
|
||||
|
||||
@@ -14,7 +14,9 @@ def create_spell(**params):
|
||||
NewSpell
|
||||
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
|
||||
|
||||
|
||||
@@ -41,8 +43,11 @@ class Spell():
|
||||
return s
|
||||
|
||||
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
|
||||
def component_string(self):
|
||||
s = f'{", ".join(self.components)}'
|
||||
|
||||
@@ -24,6 +24,12 @@ class Weapon():
|
||||
def is_ranged(self):
|
||||
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):
|
||||
name = "Club"
|
||||
|
||||
Reference in New Issue
Block a user