def make_character_sheet( char_file: Union[str, Path], character: Optional[Character] = None, flatten: bool = False, output_format: str = "pdf", fancy_decorations: bool = False, debug: bool = False, use_tex_template: bool = False, ): """Prepare a PDF character sheet from the given character file. Parameters ---------- basename The basename for saving files (PDFs, etc). character If provided, will not load from the character file, just use file for PDF name flatten If true, the resulting PDF will look better and won't be fillable form. output_format Either "pdf" or "epub" to generate a PDF file or an EPUB file. fancy_decorations Use fancy page layout and decorations for extra sheets, namely the dnd style file: https://github.com/rpgtex/DND-5e-LaTeX-Template. debug Provide extra info and preserve temporary files. """ # Load properties from file if character is None: character_props = readers.read_sheet_file(char_file) character = _char.Character.load(character_props) # Load image file if present portrait_file = "" if character.portrait: portrait_file = char_file.stem + ".jpeg" # Set the fields in the FDF basename = char_file.stem char_base = basename + "_char" person_base = basename + "_person" sheets = [char_base + ".pdf"] pages = [] # Prepare the tex/html content content_suffix = format_suffixes[output_format] # Create a list of features and magic items content = make_character_content(character=character, content_format=content_suffix, fancy_decorations=fancy_decorations) # Typeset combined LaTeX file if output_format == "pdf": if use_tex_template: msavage_sheet(character=character, basename=char_base, portrait_file=portrait_file, debug=debug) # Fillable PDF forms else: sheets.append(person_base + ".pdf") char_pdf = create_character_pdf_template(character=character, basename=char_base, flatten=flatten) pages.append(char_pdf) person_pdf = create_personality_pdf_template( character=character, basename=person_base, portrait_file=portrait_file, flatten=flatten) pages.append(person_pdf) if character.is_spellcaster and not (use_tex_template): # Create spell sheet spell_base = "{:s}_spells".format(basename) create_spells_pdf_template(character=character, basename=spell_base, flatten=flatten) sheets.append(spell_base + ".pdf") # Combined with additional LaTeX pages with detailed character info features_base = "{:s}_features".format(basename) try: if len(content) > 2: latex.create_latex_pdf( tex="".join(content), basename=features_base, keep_temp_files=debug, use_dnd_decorations=fancy_decorations, ) sheets.append(features_base + ".pdf") final_pdf = f"{basename}.pdf" merge_pdfs(sheets, final_pdf, clean_up=not (debug)) except exceptions.LatexNotFoundError: log.warning( f"``pdflatex`` not available. Skipping features for {character.name}" ) elif output_format == "epub": epub.create_epub( chapters={character.name: "".join(content)}, basename=basename, title=character.name, use_dnd_decorations=fancy_decorations, ) else: raise exceptions.UnknownOutputFormat( f"Unknown output format requested: {output_format}. Valid options are:" " 'pdf', 'epub'")
def make_gm_sheet( gm_file: Union[str, Path], output_format: str = "pdf", fancy_decorations: bool = False, debug: bool = False, ): """Prepare a PDF character sheet from the given character file. Parameters ---------- gm_file The file with the gm_sheet definitions. output_format Either "pdf" or "epub" to generate a PDF file or an EPUB file. fancy_decorations Use fancy page layout and decorations for extra sheets, namely the dnd style file: https://github.com/rpgtex/DND-5e-LaTeX-Template. debug Provide extra info and preserve temporary files. """ # Parse the GM file and filename gm_file = Path(gm_file) basename = gm_file.stem gm_props = readers.read_sheet_file(gm_file) session_title = gm_props.pop("session_title", f"GM Notes: {basename}") # Create the intro tex content_suffix = format_suffixes[output_format] content = [ jinja_env.get_template(f"preamble.{content_suffix}").render( use_dnd_decorations=fancy_decorations, title=session_title, ) ] # Add the party stats table and session summary party = [] for char_file in gm_props.pop("party", []): # Check if it's already resolved if isinstance(char_file, Creature): member = char_file elif isinstance(char_file, type) and issubclass(char_file, Creature): # Needs to be instantiated member = char_file() else: # Resolve the file path char_file = Path(char_file) if not char_file.is_absolute(): char_file = gm_file.parent / char_file char_file = char_file.resolve() # Load the character file log.debug(f"Loading party member: {char_file}") character_props = readers.read_sheet_file(char_file) member = _char.Character.load(character_props) party.append(member) summary = gm_props.pop("summary", "") content.append( create_party_summary_content( party, summary_rst=summary, suffix=content_suffix, use_dnd_decorations=fancy_decorations, )) # Parse any extra homebrew sections, etc. content.append( create_extra_gm_content(sections=gm_props.pop("extra_content", []), suffix=content_suffix, use_dnd_decorations=fancy_decorations)) # Add the monsters monsters_ = [] for monster in gm_props.pop("monsters", []): if isinstance(monster, monsters.Monster): # It's already a monster, so just add it new_monster = monster else: try: MyMonster = find_content(monster, valid_classes=[monsters.Monster]) except exceptions.ContentNotFound: msg = f"Monster '{monster}' not found. Please add it to ``monsters.py``" warnings.warn(msg) continue else: new_monster = MyMonster() monsters_.append(new_monster) if len(monsters_) > 0: content.append( create_monsters_content(monsters_, suffix=content_suffix, use_dnd_decorations=fancy_decorations)) # Add the random tables tables = [ find_content(s, valid_classes=[random_tables.RandomTable]) for s in gm_props.pop("random_tables", []) ] content.append( create_random_tables_content( tables=tables, suffix=content_suffix, use_dnd_decorations=fancy_decorations, )) # Add the closing TeX content.append( jinja_env.get_template(f"postamble.{format_suffixes[output_format]}"). render(use_dnd_decorations=fancy_decorations)) # Warn about any unhandled sheet properties gm_props.pop("dungeonsheets_version") gm_props.pop("sheet_type") if len(gm_props.keys()) > 0: msg = f"Unhandled attributes in '{str(gm_file)}': {','.join(gm_props.keys())}" log.warning(msg) warnings.warn(msg) # Produce the combined output depending on the format requested if output_format == "pdf": # Typeset combined LaTeX file try: if len(content) > 2: latex.create_latex_pdf( tex="".join(content), basename=basename, keep_temp_files=debug, use_dnd_decorations=fancy_decorations, ) except exceptions.LatexNotFoundError: log.warning(f"``pdflatex`` not available. Skipping {basename}") elif output_format == "epub": chapters = {session_title: "".join(content)} # Make sheets in the epub for each party member for char in party: char_html = make_character_content( char, "html", fancy_decorations=fancy_decorations) chapters[char.name] = "".join(char_html) # Create the combined HTML file epub.create_epub( chapters=chapters, basename=basename, title=session_title, use_dnd_decorations=fancy_decorations, ) else: raise exceptions.UnknownOutputFormat( f"Unknown output format requested: {output_format}. Valid options are:" " 'pdf', 'epub'")