diff --git a/dungeonsheets/make_sheets.py b/dungeonsheets/make_sheets.py index 8532877..82fd931 100644 --- a/dungeonsheets/make_sheets.py +++ b/dungeonsheets/make_sheets.py @@ -52,6 +52,31 @@ def load_character_file(filename): return char_props +def create_spellbook_pdf(character, basename): + from jinja2 import Environment, PackageLoader + env = Environment( + loader=PackageLoader('dungeonsheets', ''), + block_start_string='[%', + block_end_string='%]', + variable_start_string='[[', + variable_end_string=']]', + ) + template = env.get_template('spellbook_template.tex') + tex = template.render(character=character) + # Create tex document + tex_file = f'{basename}.tex' + with open(tex_file, mode='w') as f: + f.write(tex) + # Compile the PDF + pdf_file = f'{basename}.pdf' + result = subprocess.call(['pdflatex', tex_file], stdout=subprocess.DEVNULL) + # Remove temporary files + if result == 0: + os.remove(tex_file) + os.remove(f'{basename}.aux') + os.remove(f'{basename}.log') + + def create_spells_pdf(character, basename, flatten=False): class_level = (character.class_name + ' ' + str(character.level)) spell_level = lambda x : (x or '') @@ -285,9 +310,14 @@ def make_sheet(character_file, flatten=False): sheets = [char_base + '.pdf'] create_character_pdf(character=char, basename=char_base, flatten=flatten) if char.is_spellcaster: + # Create spell sheet spell_base = os.path.splitext(character_file)[0] + '_spells' create_spells_pdf(character=char, basename=spell_base, flatten=flatten) sheets.append(spell_base + '.pdf') + # Create spell book + spellbook_base = os.path.splitext(character_file)[0] + '_spellbook' + create_spellbook_pdf(character=char, basename=spellbook_base) + sheets.append(spellbook_base + '.pdf') # Combine sheets into final pdf final_pdf = os.path.splitext(character_file)[0] + '.pdf' popenargs = ('pdftk', *sheets, 'cat', 'output', final_pdf) diff --git a/dungeonsheets/spellbook_template.tex b/dungeonsheets/spellbook_template.tex new file mode 100644 index 0000000..cd0b9a4 --- /dev/null +++ b/dungeonsheets/spellbook_template.tex @@ -0,0 +1,47 @@ +\documentclass[twocolumn,lettersize]{article} + +%% \usepackage{fullpage} +\usepackage[margin=1.5cm]{geometry} +\usepackage[dvipsnames]{color} +\definecolor{mygrey}{gray}{0.7} + +\title{Spells and Incantations} + +\author{[[ character.name ]]} + +\begin{document} + +\maketitle + +[% for spl in character.spells %] + [% if spl.__class__ in character.spells_prepared %] + { + [% elif spl.level == 0 %] + { + [% else %] + {\color{mygrey} + [% endif %] + + \section*{[[ spl.name ]]} + + [% if spl.level > 0 %] % + \textit{[[ spl.magic_school ]] Level [[ spl.level ]]} % + [% else %] % + \textit{[[ spl.magic_school ]] Cantrip} % + [% endif %] % + [% if spl.ritual %] % + \textit{(ritual)} + [% endif %] + + \noindent + \textbf{Casting Time:} [[ spl.casting_time ]] \\ + \textbf{Range:} [[ spl.casting_range ]] \\ + \textbf{Components:} [[ spl.component_string() ]] \\ + \textbf{Duration:} [[ spl.duration ]] + + [[ spl.__doc__ ]] + + } %\color +[% endfor %] + +\end{document} diff --git a/dungeonsheets/spells.py b/dungeonsheets/spells.py index d15e92e..dabd929 100644 --- a/dungeonsheets/spells.py +++ b/dungeonsheets/spells.py @@ -24,6 +24,7 @@ class Spell(): casting_time = "1 action" casting_range = "60 ft" components = ("V", "S") + materials = "" duration = "instantaneous" concentration = False ritual = False @@ -41,6 +42,13 @@ class Spell(): def __repr__(self): return f'<{self.name}>' + + def component_string(self): + s = f'{", ".join(self.components)}' + if "M" in self.components: + s += f' ({self.materials})' + return s + class AcidArrow(Spell): @@ -3609,6 +3617,7 @@ class Prestidigitation(Spell): or a surface for 1 hour. - You create a nonmagical trinket or an illusory image that can fit in your hand and that lasts until the end of your next turn. + If you cast this spell multiple times, you can have up to three of its non-instantaneous effects active at a time, and you can dismiss such an effect as an action. diff --git a/examples/rogue.pdf b/examples/rogue.pdf index a92a86b..84e9039 100644 Binary files a/examples/rogue.pdf and b/examples/rogue.pdf differ diff --git a/examples/warlock.pdf b/examples/warlock.pdf index 36e131b..bf6595d 100644 Binary files a/examples/warlock.pdf and b/examples/warlock.pdf differ diff --git a/examples/wizard.pdf b/examples/wizard.pdf index 832e3bb..8310cf6 100644 Binary files a/examples/wizard.pdf and b/examples/wizard.pdf differ diff --git a/examples/wizard.py b/examples/wizard.py index 10a8581..38a3f58 100644 --- a/examples/wizard.py +++ b/examples/wizard.py @@ -44,7 +44,7 @@ equipment = ( spells = ('blindness deafness', 'burning hands', 'detect magic', 'false life', 'mage armor', 'mage hand', 'magic missile', 'prestidigitation', 'ray of frost', 'ray of sickness', 'shield', - 'shocking grasp', 'sleep', 'some other spell') + 'shocking grasp', 'sleep',) # Which spells have been prepared (not including cantrips) spells_prepared = ('blindness deafness', 'false life', 'mage armor', 'ray of sickness', 'shield', 'sleep',) diff --git a/setup.py b/setup.py index be982d5..bc7a045 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ def read(fname): setup(name='dungeonsheets', - version='0.3.0', + version='0.4.0', description='Dungeons and Dragons 5e Character Tools', long_description=read('README.rst'), long_description_content_type='text/x-rst', @@ -20,7 +20,8 @@ setup(name='dungeonsheets', download_url = 'https://github.com/canismarko/dungeon-sheets/archive/master.zip', packages=['dungeonsheets'], package_data={ - 'dungeonsheets': ['blank-character-sheet-default.pdf', 'blank-spell-sheet-default.pdf'] + 'dungeonsheets': ['blank-character-sheet-default.pdf', 'blank-spell-sheet-default.pdf', + 'spellbook_template.tex'] }, install_requires=[ 'fdfgen', 'npyscreen', 'jinja2',