From c5672f950f3bef558dcd1b6297e3c05d0ed9242e Mon Sep 17 00:00:00 2001 From: Mark Wolfman Date: Wed, 16 Jun 2021 10:03:35 -0500 Subject: [PATCH] Fixed broken test and added ability to put session summary into GM notes. --- dungeonsheets/__init__.py | 2 +- dungeonsheets/background.py | 3 +- dungeonsheets/character.py | 41 +++++++++++-------- dungeonsheets/content_registry.py | 35 ++++++++++++---- dungeonsheets/features/backgrounds.py | 3 +- dungeonsheets/fill_pdf_template.py | 22 ++++++---- .../forms/party_summary_template.tex | 12 ++++++ dungeonsheets/homebrew.py | 1 - dungeonsheets/make_sheets.py | 25 ++++++----- dungeonsheets/monsters/monsters.py | 2 +- dungeonsheets/monsters/monsters_a.py | 5 ++- dungeonsheets/monsters/monsters_b.py | 8 +++- dungeonsheets/monsters/monsters_d.py | 6 +-- dungeonsheets/monsters/monsters_e.py | 4 +- dungeonsheets/monsters/monsters_s.py | 13 ++++-- dungeonsheets/readers.py | 9 ++-- dungeonsheets/stats.py | 13 +++--- examples/gm-session-notes.py | 2 + tests/test_make_sheets.py | 10 ++++- tests/test_monsters.py | 20 ++++----- 20 files changed, 156 insertions(+), 80 deletions(-) diff --git a/dungeonsheets/__init__.py b/dungeonsheets/__init__.py index 574f7e6..d5ebfc6 100644 --- a/dungeonsheets/__init__.py +++ b/dungeonsheets/__init__.py @@ -7,7 +7,7 @@ __all__ = ( "race", "background", "spells", - "import_homebrew" + "import_homebrew", ) from dungeonsheets import background, features, race, spells, weapons, mechanics diff --git a/dungeonsheets/background.py b/dungeonsheets/background.py index 562a8ec..773a3c4 100644 --- a/dungeonsheets/background.py +++ b/dungeonsheets/background.py @@ -108,8 +108,9 @@ class RivalIntern(Background): the knowledge you gained there for an advantage at Acquisitions Incorporated. Either way, you're now bringing your talents to the company, ready to put your skills lo use. - + """ + name = "Rival Intern" skill_proficiencies = ("history", "investigation") proficiencies_text = ("One type of artisan's tools",) diff --git a/dungeonsheets/character.py b/dungeonsheets/character.py index bbc9271..afe28ca 100644 --- a/dungeonsheets/character.py +++ b/dungeonsheets/character.py @@ -77,13 +77,13 @@ def _resolve_mechanic(mechanic, SuperClass, warning_message=None): used by a character:: >>> _resolve_mechanic("mage_hand", SuperClass=spells.Spell) - + >>> _resolve_mechanic("mage_hand", SuperClass=None) - + >>> from dungeonsheets import spells >>> class MySpell(spells.Spell): pass >>> _resolve_mechanic(MySpell, SuperClass=spells.Spell) - + >>> _resolve_mechanic("hocus pocus", SuperClass=spells.Spell) The acceptable entries for *mechanic*, in priority order, are: @@ -175,18 +175,18 @@ class Character(Entity): # Appearance # portrait = placeholder not sure how to implement age = 0 - height = '' - weight = '' - eyes = '' - skin = '' - hair = '' + height = "" + weight = "" + eyes = "" + skin = "" + hair = "" # Background - allies = '' - faction_name = '' + allies = "" + faction_name = "" # faction_symbol = placeholder not sure how to implement - backstory = '' - other_feats_traits = '' - treasure = '' + backstory = "" + other_feats_traits = "" + treasure = "" def __init__( self, @@ -344,7 +344,9 @@ class Character(Entity): self._race = newrace(owner=self) elif isinstance(newrace, str): try: - self._race = find_content(newrace, valid_classes=[race.Race])(owner=self) + self._race = find_content(newrace, valid_classes=[race.Race])( + owner=self + ) except AttributeError: msg = f'Race "{newrace}" not defined. Please add it to ``race.py``' self._race = race.Race(owner=self) @@ -365,7 +367,9 @@ class Character(Entity): self._background = bg(owner=self) elif isinstance(bg, str): try: - self._background = find_content(bg, valid_classes=[background.Background])(owner=self) + self._background = find_content( + bg, valid_classes=[background.Background] + )(owner=self) except AttributeError: msg = ( f'Background "{bg}" not defined. Please add it to ``background.py``' @@ -634,7 +638,12 @@ class Character(Entity): self.other_weapon_proficiencies = () msg = 'Magic Item "{}" not defined. Please add it to ``weapons.py``' wps = set( - [_resolve_mechanic(w, SuperClass=weapons.Weapon, warning_message=msg) for w in val] + [ + _resolve_mechanic( + w, SuperClass=weapons.Weapon, warning_message=msg + ) + for w in val + ] ) wps -= set(self.weapon_proficiencies) self.other_weapon_proficiencies = list(wps) diff --git a/dungeonsheets/content_registry.py b/dungeonsheets/content_registry.py index 92cfe2c..0751029 100644 --- a/dungeonsheets/content_registry.py +++ b/dungeonsheets/content_registry.py @@ -3,29 +3,39 @@ from functools import lru_cache import importlib.util from typing import Union, List, Optional -from dungeonsheets import weapons, monsters, race, background, armor, spells, infusions, magic_items, features +from dungeonsheets import ( + weapons, + monsters, + race, + background, + armor, + spells, + infusions, + magic_items, + features, +) -class ContentRegistry(): +class ContentRegistry: modules = None def __init__(self): self.modules = [] - + def add_module(self, new_module): if new_module not in self.modules: self.modules.append(new_module) def findattr(self, name, valid_classes=[]): """Resolve the name of a piece of content to the corresponding Class. - + Similar to builtin getattr(obj, name) but more forgiving to whitespace and capitalization. valid_classes If given, only subclasses of classes in this list will be returned. - + """ # Come up with several options name = name.strip() @@ -36,7 +46,9 @@ class ContentRegistry(): bonus = i name = name.replace(f"+{i}", "").replace(f"+ {i}", "") break - py_name = name.replace("-", "_").replace(" ", "_").replace("'", "").replace("/", "") + py_name = ( + name.replace("-", "_").replace(" ", "_").replace("'", "").replace("/", "") + ) camel_case = "".join([s.capitalize() for s in py_name.split("_")]) # Check each module in the registry found_attrs = [] @@ -51,7 +63,12 @@ class ContentRegistry(): if len(valid_classes) > 0: is_valid = [False for attr in found_attrs] for cls in valid_classes: - is_valid = [v or isinstance(attr, cls) or (isinstance(attr, type) and issubclass(attr, cls)) for v, attr in zip(is_valid, found_attrs)] + is_valid = [ + v + or isinstance(attr, cls) + or (isinstance(attr, type) and issubclass(attr, cls)) + for v, attr in zip(is_valid, found_attrs) + ] found_attrs = [attr for attr, v in zip(found_attrs, is_valid) if v] # Check that we found a valid, unique attribute if len(found_attrs) == 0: @@ -94,7 +111,7 @@ def find_content(name: str, valid_classes: Optional[List]): valid_classes A list of parent classes to look for. If ``None`` or ``[]``, all classes will be considered valid. - + """ if valid_classes is None: valid_classes = [] @@ -112,7 +129,7 @@ def import_homebrew(filepath: Union[str, Path]): ========== filepath The location of the python file containing the homebrew content. - + Returns ======= mod diff --git a/dungeonsheets/features/backgrounds.py b/dungeonsheets/features/backgrounds.py index 13c61f8..d1d09a9 100644 --- a/dungeonsheets/features/backgrounds.py +++ b/dungeonsheets/features/backgrounds.py @@ -342,8 +342,9 @@ class InsideInformant(Feature): """You have connections to your previous employer or other groups you dealt with during your previous employment. You can communicate with your contacts, gaining information at the DM's discretion. - + """ + name = "Inside Informant" source = "Background (Rival Intern)" diff --git a/dungeonsheets/fill_pdf_template.py b/dungeonsheets/fill_pdf_template.py index ddfea3c..8468a18 100644 --- a/dungeonsheets/fill_pdf_template.py +++ b/dungeonsheets/fill_pdf_template.py @@ -87,7 +87,9 @@ def create_character_pdf_template(character, basename, flatten=False): # Hit points "HDTotal": character.hit_dice, "HPMax": str(character.hp_max), - "HPCurrent": str(character.hp_current) if character.hp_current is not None else "", + "HPCurrent": str(character.hp_current) + if character.hp_current is not None + else "", "HPTemp": str(character.hp_temp) if character.hp_temp > 0 else "", # Personality traits and other features "PersonalityTraits ": text_box(character.personality_traits), @@ -148,7 +150,7 @@ def create_character_pdf_template(character, basename, flatten=False): ("Wpn Name 2", "Wpn2 AtkBonus ", "Wpn2 Damage "), ("Wpn Name 3", "Wpn3 AtkBonus ", "Wpn3 Damage "), ] - if len(character.weapons) == 0 or hasattr(character, 'Monk'): + if len(character.weapons) == 0 or hasattr(character, "Monk"): character.wield_weapon("unarmed") for _fields, weapon in zip(weapon_fields, character.weapons): name_field, atk_field, dmg_field = _fields @@ -156,8 +158,10 @@ def create_character_pdf_template(character, basename, flatten=False): fields[atk_field] = "{:+d}".format(weapon.attack_modifier) fields[dmg_field] = f"{weapon.damage}/{weapon.damage_type}" # Additional attacks beyond 3 - attack = [f"{w.name}: Atk {w.attack_modifier:+d}, Dam {w.damage}/{w.damage_type}" - for w in character.weapons[len(weapon_fields):]] + attack = [ + f"{w.name}: Atk {w.attack_modifier:+d}, Dam {w.damage}/{w.damage_type}" + for w in character.weapons[len(weapon_fields):] + ] # Other attack information if character.armor: attack.append(f"Armor: {character.armor}") @@ -192,7 +196,7 @@ def create_personality_pdf_template(character, basename, flatten=False): "FactionName": character.faction_name, "Backstory": text_box(character.backstory), "Feat+Traits": text_box(character.other_feats_traits), - "Treasure": text_box(character.treasure) + "Treasure": text_box(character.treasure), } # Prepare the actual PDF dirname = os.path.join(os.path.dirname(os.path.abspath(__file__)), "forms/") @@ -464,9 +468,11 @@ def create_spells_pdf_template(character, basename, flatten=False): # Determine if we should omit un-prepared spells to save space if len(spells) > len(field_numbers[level]): spells = [s for s in spells if s in character.spells_prepared] - warnings.warn(f"{character.name} knows more spells than the number of " - "lines available in spell sheet. Limited to prepared " - "spells only.") + warnings.warn( + f"{character.name} knows more spells than the number of " + "lines available in spell sheet. Limited to prepared " + "spells only." + ) # Build the list of PDF controls to set/toggle field_names = [f"Spells {i}" for i in field_numbers[level]] prep_names = tuple(f"Check Box {i}" for i in prep_numbers[level]) diff --git a/dungeonsheets/forms/party_summary_template.tex b/dungeonsheets/forms/party_summary_template.tex index 05dfcbb..ab84147 100644 --- a/dungeonsheets/forms/party_summary_template.tex +++ b/dungeonsheets/forms/party_summary_template.tex @@ -1,3 +1,13 @@ +[% if summary %] + + \section*{Summary} + + [[ summary | rst_to_latex ]] + +[% endif %] + +[% if party %] + \section*{Party} [% if use_dnd_decorations %] @@ -55,3 +65,5 @@ [% endfor %] \end{tabular} [% endif %] + +[% endif %] diff --git a/dungeonsheets/homebrew.py b/dungeonsheets/homebrew.py index 1aad6aa..5795688 100644 --- a/dungeonsheets/homebrew.py +++ b/dungeonsheets/homebrew.py @@ -1,2 +1 @@ """Tools useful for defining homebrew content.""" - diff --git a/dungeonsheets/make_sheets.py b/dungeonsheets/make_sheets.py index f1fd482..5a41eb4 100755 --- a/dungeonsheets/make_sheets.py +++ b/dungeonsheets/make_sheets.py @@ -93,11 +93,15 @@ def create_monsters_tex( def create_party_summary_tex( - party: Sequence[Entity], - use_dnd_decorations: bool = False, + party: Sequence[Entity], + summary_rst: str, + use_dnd_decorations: bool = False, ) -> str: + log.debug("Preparing summary table for party: %s", party) template = jinja_env.get_template("party_summary_template.tex") - return template.render(party=party, use_dnd_decorations=use_dnd_decorations) + return template.render( + party=party, summary=summary_rst, use_dnd_decorations=use_dnd_decorations + ) def create_spellbook_tex( @@ -196,7 +200,7 @@ def make_gm_sheet( title=gm_props["session_title"], ) ] - # Add the party stats table + # Add the party stats table and session summary party = [] for char_file in gm_props.get("party", []): # Resolve the file path @@ -208,10 +212,12 @@ def make_gm_sheet( character_props = readers.read_sheet_file(char_file) member = _char.Character.load(character_props) party.append(member) - if len(party) > 0: - tex.append( - create_party_summary_tex(party, use_dnd_decorations=fancy_decorations) + summary = gm_props.get("summary", "") + tex.append( + create_party_summary_tex( + party, summary_rst=summary, use_dnd_decorations=fancy_decorations ) + ) # Add the monsters monsters_ = [] for monster in gm_props.get("monsters", []): @@ -222,10 +228,7 @@ def make_gm_sheet( try: MyMonster = find_content(monster, valid_classes=[monsters.Monster]) except AttributeError: - msg = ( - f"Monster '{monster}' not found. Please add it to" - " ``monsters.py``" - ) + msg = f"Monster '{monster}' not found. Please add it to ``monsters.py``" warnings.warn(msg) continue else: diff --git a/dungeonsheets/monsters/monsters.py b/dungeonsheets/monsters/monsters.py index 786c9f9..a745cc5 100644 --- a/dungeonsheets/monsters/monsters.py +++ b/dungeonsheets/monsters/monsters.py @@ -21,7 +21,7 @@ class Monster(Entity): saving_throws = "" # TODO: Consider refactoring stats.Speed to consider all of these # just like we do stats.Ability - + swim_speed = 0 fly_speed = 0 climb_speed = 0 diff --git a/dungeonsheets/monsters/monsters_a.py b/dungeonsheets/monsters/monsters_a.py index 7855d0c..efeecac 100644 --- a/dungeonsheets/monsters/monsters_a.py +++ b/dungeonsheets/monsters/monsters_a.py @@ -48,7 +48,7 @@ class Aboleth(Monster): charmed target is under the aboleth's control and can't take reactions, and the aboleth and the target can communicate telepathically with each other over any distance. - + Whenever the charmed target takes damage, the target can repeat the saving throw. On a success, the effect ends. No more than once every 24 hours, the target can also repeat the saving throw @@ -79,7 +79,7 @@ class Aboleth(Monster): class Acolyte(Monster): """Spellcasting - + The acolyte is a 1st-level spellcaster. Its spellcasting ability is Wisdom (spell save DC 12, +4 to hit with spell attacks). The acolyte has following cleric spells prepared: @@ -92,6 +92,7 @@ class Acolyte(Monster): (1d4) bludgeoning damage. """ + name = "Acolyte" description = "Medium humanoid, any alignment" challenge_rating = 0.25 diff --git a/dungeonsheets/monsters/monsters_b.py b/dungeonsheets/monsters/monsters_b.py index f940763..d7eb1c7 100644 --- a/dungeonsheets/monsters/monsters_b.py +++ b/dungeonsheets/monsters/monsters_b.py @@ -450,6 +450,7 @@ class BlackEarthGuard(Monster): burrowsharks. """ + name = "Black Earth Guard" description = "Medium humanoid (human), neutral evil" challenge_rating = 2 @@ -507,6 +508,7 @@ class BlackEarthPriest(Monster): over the rest of Ogrémoch's followers. """ + name = "Black Earth Priest" description = "Medium humanoid (human), neutral evil" challenge_rating = 3 @@ -551,8 +553,9 @@ class BlackPudding(Monster): dissolved and takes a permanent and cumulative -1 penalty to the AC it offers. The armor is destroyed if the penalty reduces its AC to 10. - + """ + name = "Black Pudding" description = "Large ooze, unaligned" challenge_rating = 4 @@ -885,6 +888,7 @@ class Burrowshark(Monster): neither moved nor knocked prone. """ + name = "Burrowshark" description = "Medium humanoid (human), neutral evil" challenge_rating = 4 @@ -927,6 +931,7 @@ class Bulette(Monster): prone in the bulette's space. """ + name = "Bulette" description = "Large monstrosity, unaligned" challenge_rating = 5 @@ -944,5 +949,6 @@ class Bulette(Monster): swim_speed = 0 fly_speed = 0 climb_speed = 0 + burrow_speed = 40 hp_max = 94 hit_dice = "9d10+45" diff --git a/dungeonsheets/monsters/monsters_d.py b/dungeonsheets/monsters/monsters_d.py index ff69f8c..d84944a 100644 --- a/dungeonsheets/monsters/monsters_d.py +++ b/dungeonsheets/monsters/monsters_d.py @@ -20,7 +20,7 @@ class Dao(Monster): The dao's innate spellcasting ability is Charisma (spell save DC 14, +6 to hit with spell attacks). It can innately cast the following spells, requiring no material components: - + At will: detect evil and good, detect magic, stone shape. 3/day each: passwall, move earth, tongues. 1/day each: conjure elemental (earth elemental only), gaseous form, invisibility, @@ -38,8 +38,9 @@ class Dao(Monster): target. *Hit:* 20 (4d6 + 6) bludgeoning damage. If the target is a Huge or smaller creature, it must succeed on a DC 18 Strength check or be knocked prone. - + """ + name = "Dao" description = "Large elemental, neutral evil" challenge_rating = 11 @@ -64,7 +65,6 @@ class Dao(Monster): hit_dice = "15d10 + 105" - class Darkmantle(Monster): """ **Echolocation**: The darkmantle can't use its blindsight while deafened. diff --git a/dungeonsheets/monsters/monsters_e.py b/dungeonsheets/monsters/monsters_e.py index 88c22fe..cc621f2 100644 --- a/dungeonsheets/monsters/monsters_e.py +++ b/dungeonsheets/monsters/monsters_e.py @@ -48,8 +48,9 @@ class EarthElemental(Monster): Slam. Melee Weapon Attack: +8 to hit, reach 10 ft., one target. Hit: 14 (2d8 + 5) bludgeoning damage. - + """ + name = "Earth Elemental" description = "Large elemental, neutral" challenge_rating = 5 @@ -92,6 +93,7 @@ class EarthElementalMyrmidon(Monster): creators. """ + name = "Earth Elemental Myrmidon" description = "Medium elemental, neutral" challenge_rating = 7 diff --git a/dungeonsheets/monsters/monsters_s.py b/dungeonsheets/monsters/monsters_s.py index b0104da..287ac6f 100644 --- a/dungeonsheets/monsters/monsters_s.py +++ b/dungeonsheets/monsters/monsters_s.py @@ -316,6 +316,7 @@ class ShadowDemon(Monster): creature. *Hit:* 10 (2d6+3) psychic damage or, if the demon had advantage on the attack roll, 17 (4d6+3) psychic damage. """ + name = "Shadow Demon" description = "Medium fiend (demon), chaotic evil" challenge_rating = 4 @@ -323,9 +324,14 @@ class ShadowDemon(Monster): skills = "Stealth +7" saving_throws = "Dex +5, Cha +4" damage_vulnerabilities = "radiant" - damage_resistances = "acid, fire, necrotic, thunder; bludgeoning, piercing, and slashing from nonmagical attacks" + damage_resistances = ( + "acid, fire, necrotic, thunder; bludgeoning, piercing, and slashing from" + " nonmagical attacks" + ) damage_immunities = "cold, lightning, poison" - condition_immunities = "exhaustion, grappled, paralyzed, petrified, poisoned, prone, restrained" + condition_immunities = ( + "exhaustion, grappled, paralyzed, petrified, poisoned, prone, restrained" + ) senses = "Darkvision 120 ft., Passive Perception 11" languages = "Abyssal, telepathy 120 ft." strength = Ability(1) @@ -812,6 +818,7 @@ class StoneGolem(Monster): **Slow**: The golem targets one or more creatures it can see within 10 ft. of it. Each target must make a DC 17 Wisdom saving throw against this magic. On a failed save, a target can't use reactions, its speed is halved, and it can't make more than one attack on its turn. In addition, the target can take either an action or a bonus action on its turn, not both. These effects last for 1 minute. A target can repeat the saving throw at the end of each of its turns, ending the effect on itself on a success. """ + name = "Stone Golem" description = "Large construct, unaligned" challenge_rating = 10 @@ -874,6 +881,7 @@ class Stonemelder(Monster): it serves as a conduit for Ogrémoch's wrath. """ + name = "Stonemelder" description = "Medium humanoid (human), neutral evil" challenge_rating = 4 @@ -895,7 +903,6 @@ class Stonemelder(Monster): hit_dice = "10d8 + 30" - class StormGiant(Monster): """ **Amphibious**: The giant can breathe air and water. diff --git a/dungeonsheets/readers.py b/dungeonsheets/readers.py index 404ba19..658b52f 100644 --- a/dungeonsheets/readers.py +++ b/dungeonsheets/readers.py @@ -45,7 +45,7 @@ def read_sheet_file(filename: Union[str, Path]) -> dict: these_props = reader() # Resolve parent_sheets char_props = {} - parent_sheets = these_props.pop('parent_sheets', []) + parent_sheets = these_props.pop("parent_sheets", []) for parent_sheet in parent_sheets: parent_sheet = (filename.parent / parent_sheet).resolve() if parent_sheet != filename: @@ -322,7 +322,7 @@ class FoundryCharacterReader(JSONCharacterReader): "unarmed strike (monk)", "", ] - + def _skill_proficiency_value(self, key: str) -> float: proficiency_labels = { "acrobatics": "acr", @@ -386,7 +386,10 @@ class FoundryCharacterReader(JSONCharacterReader): """Iterator over the weapons the character is carrying in her inventory.""" items = self.json_data()["items"] for item in items: - is_valid_weapon = (item["type"] == "weapon" and item["name"].lower() not in self._invalid_weapons) + is_valid_weapon = ( + item["type"] == "weapon" + and item["name"].lower() not in self._invalid_weapons + ) if is_valid_weapon: yield item["name"].lower() diff --git a/dungeonsheets/stats.py b/dungeonsheets/stats.py index 9ac80bb..465e9b5 100644 --- a/dungeonsheets/stats.py +++ b/dungeonsheets/stats.py @@ -3,7 +3,7 @@ from collections import namedtuple from math import ceil import logging -from dungeonsheets.armor import Armor, HeavyArmor, NoArmor, NoShield, Shield +from dungeonsheets.armor import HeavyArmor, NoArmor, NoShield from dungeonsheets.features import ( AmbushMaster, Defense, @@ -25,7 +25,6 @@ from dungeonsheets.features import ( UnarmoredDefenseMonk, UnarmoredMovement, ) -from dungeonsheets.weapons import Weapon log = logging.getLogger(__name__) @@ -89,14 +88,15 @@ class Skill: self.character = entity def __get__(self, entity, owner): - log.debug("Getting skill '%s' for '%s'", - self.skill_name, entity.name) + log.debug("Getting skill '%s' for '%s'", self.skill_name, entity.name) ability = getattr(entity, self.ability_name) modifier = ability.modifier # Check for proficiency proficiencies = [p.replace("_", " ") for p in entity.skill_proficiencies] is_proficient = self.skill_name in proficiencies - log.debug("%s is proficient in %s: %s", entity.name, self.skill_name, is_proficient) + log.debug( + "%s is proficient in %s: %s", entity.name, self.skill_name, is_proficient + ) if is_proficient: modifier += entity.proficiency_bonus elif entity.has_feature(JackOfAllTrades): @@ -109,8 +109,7 @@ class Skill: is_expert = self.skill_name in entity.skill_expertise if is_expert: modifier += entity.proficiency_bonus - log.debug("'%s' modifier for '%s': %d", - self.skill_name, entity.name, modifier) + log.info("'%s' modifier for '%s': %d", self.skill_name, entity.name, modifier) return modifier diff --git a/examples/gm-session-notes.py b/examples/gm-session-notes.py index c206f7a..362547f 100644 --- a/examples/gm-session-notes.py +++ b/examples/gm-session-notes.py @@ -9,6 +9,8 @@ dungeonsheets_version = "0.15.0" sheet_type = "gm" +summary = """The party is about the enter the dungeon of *eternal tortuosity*.""" + session_title = "Objects in Space - Session 1" parent_sheets = ["gm-campaign-notes.py"] diff --git a/tests/test_make_sheets.py b/tests/test_make_sheets.py index 70330ed..574d551 100644 --- a/tests/test_make_sheets.py +++ b/tests/test_make_sheets.py @@ -174,6 +174,14 @@ class TexCreatorTestCase(unittest.TestCase): def test_create_party_summary_tex(self): char = self.new_character() - tex = make_sheets.create_party_summary_tex(party=[char]) + tex = make_sheets.create_party_summary_tex(party=[char], summary_rst="") self.assertIn(r"\section*{Party}", tex) self.assertIn(char.name, tex) + + def test_create_summary_tex(self): + rst = "The party's create *adventure*." + tex = make_sheets.create_party_summary_tex(party=[], summary_rst=rst) + self.assertIn(r"\section*{Summary}", tex) + # Check that the RST is parsed + self.assertIn(r"\emph{adventure}", tex) + diff --git a/tests/test_monsters.py b/tests/test_monsters.py index 88ce3ed..e3fe4fd 100644 --- a/tests/test_monsters.py +++ b/tests/test_monsters.py @@ -274,16 +274,16 @@ class AutoGeneratedMonsters(TestCase): monsters.StoneGolem, monsters.StormGiant, monsters.SuccubusIncubus, - monsters.SwarmofBats, - monsters.SwarmofBeetles, - monsters.SwarmofCentipedes, - monsters.SwarmofInsects, - monsters.SwarmofPoisonousSnakes, - monsters.SwarmofQuippers, - monsters.SwarmofRats, - monsters.SwarmofRavens, - monsters.SwarmofSpiders, - monsters.SwarmofWasps, + monsters.SwarmOfBats, + monsters.SwarmOfBeetles, + monsters.SwarmOfCentipedes, + monsters.SwarmOfInsects, + monsters.SwarmOfPoisonousSnakes, + monsters.SwarmOfQuippers, + monsters.SwarmOfRats, + monsters.SwarmOfRavens, + monsters.SwarmOfSpiders, + monsters.SwarmOfWasps, monsters.Tarrasque, monsters.Thug, monsters.Tiger,