From 288b090ca90a77bbee9f385b6754aed3d0a85380 Mon Sep 17 00:00:00 2001 From: Mark Wolfman Date: Tue, 7 Sep 2021 19:55:28 -0500 Subject: [PATCH 1/2] Added some content, and now restores the TEXINPUTS environmental after building. --- dungeonsheets/features/rogue.py | 12 ++++ dungeonsheets/latex.py | 10 ++- dungeonsheets/magic_items.py | 123 ++++++++++++++++++++++++++++++++ 3 files changed, 143 insertions(+), 2 deletions(-) diff --git a/dungeonsheets/features/rogue.py b/dungeonsheets/features/rogue.py index 4b36e70..2e90892 100644 --- a/dungeonsheets/features/rogue.py +++ b/dungeonsheets/features/rogue.py @@ -360,6 +360,18 @@ class InsightfulFighting(Feature): source = "Rogue (Inquisitive)" +# Optional class feature from *Tasha's Guide to Everything* +class SteadyAim(Feature): + """As a bonus action, you give yourself advantage on your next attack + roll on the current turn. You can use this bonus action only if + you haven't moved during this turn, and after you use the bonus + action, your speed is 0 until the end of the current turn. + + """ + name = "Steady Aim" + source = "Rogue (3rd level, optional)" + + class SteadyEye(Feature): """Starting at 9th level, you have advantage on any Wisdom (Perception) or Intelligence (Investigation) check if you move no more than half your speed diff --git a/dungeonsheets/latex.py b/dungeonsheets/latex.py index 600e950..27ba295 100644 --- a/dungeonsheets/latex.py +++ b/dungeonsheets/latex.py @@ -72,11 +72,15 @@ def create_latex_pdf( module_root = Path(__file__).parent / "modules/" module_dirs = [module_root / mdir for mdir in ["DND-5e-LaTeX-Template"]] log.debug(f"Loading additional modules from {module_dirs}.") - environment['TEXINPUTS'] = f".:{':'.join(str(d) for d in module_dirs)}:" + tex_env + texinputs = f".:{':'.join(str(d) for d in module_dirs)}:{module_root}:{tex_env}" + environment['TEXINPUTS'] = texinputs passes = 2 if use_dnd_decorations else 1 log.debug(tex_command_line) log.debug("LaTeX command: %s" % " ".join(tex_command_line)) - log.debug("LaTeX environ: %s" % environment) + log.debug("LaTeX TEXINPUTS: %s" % texinputs) + log.debug("LaTeX environ:") + for key, val in environment.items(): + log.debug(" %s: %s" % (key, val)) try: for i in range(passes): result = subprocess.run( @@ -99,6 +103,8 @@ def create_latex_pdf( for line in tex_error_msg.split("\n"): log.error(line) raise exceptions.LatexError(err_msg) + finally: + environment['TEXINPUTS'] = tex_env def tex_error(logfile: Path) -> str: diff --git a/dungeonsheets/magic_items.py b/dungeonsheets/magic_items.py index 8df31cd..99e4f85 100644 --- a/dungeonsheets/magic_items.py +++ b/dungeonsheets/magic_items.py @@ -102,7 +102,29 @@ class RingOfProtection(MagicItem): item_type = "Ring" +class CloakOfTheBat(MagicItem): + """While wearing this cloak, you have advantage on Dexterity (Stealth) + checks. In an area of dim light or darkness, you can grip the + edges of the cloak with both hands and use it to fly at a speed of + 40 feet. If you ever fail to grip the cloak's edges while flying + in this way, or if you are no longer in dim light or darkness, you + lose this flying speed. + + While wearing the cloak in an area of dim light or darkness, you + can use your action to cast polymorph on yourself, transforming + into a bat. While you are in the form of the bat, you retain your + Intelligence, Wisdom, and Charisma scores. The cloak can't be used + this way again until the next dawn. + + """ + requires_attunement = True + name = "Cloak of the Bat" + item_type = "Cloak" + + + class DecanterOfEndlessWater(MagicItem): + """This stoppered flask sloshes when shaken, as if it contains water. The decanter weighs 2 pounds. @@ -321,3 +343,104 @@ class PearlOfPower(MagicItem): requires_attunement = True name = "Pearl of Power" + + +class PotionOfHealing(MagicItem): + """You regain hit points when you drink this potion. The number of hit + points depends on the potion’s rarity, as shown in the Potions of + Healing table. Whatever its potency, the potion’s red liquid + glimmers when agitated. + + **Potions of Healing** + + +-----------------+-----------+-------------+ + | Potion of ... | Rarity | HP Regained | + +=================+===========+=============+ + |Healing | Common | 2d4 + 2 | + +-----------------+-----------+-------------+ + |Greater healing | Uncommon | 4d4 + 4 | + +-----------------+-----------+-------------+ + |Superior healing | Rare | 8d4 + 8 | + +-----------------+-----------+-------------+ + |Supreme healing | Very rare | 10d4 + 20 | + +-----------------+-----------+-------------+ + + """ + rarity = "common" + name = "Potion of Healing" + item_type = "Potion" + + +class PotionOfGreaterHealing(PotionOfHealing): + """You regain hit points when you drink this potion. The number of hit + points depends on the potion’s rarity, as shown in the Potions of + Healing table. Whatever its potency, the potion’s red liquid + glimmers when agitated. + + **Potions of Healing** + + +-----------------+-----------+-----------------+ + | Potion of ... | Rarity | HP Regained | + +=================+===========+=================+ + |Healing | Common | ``2d4 + 2`` | + +-----------------+-----------+-----------------+ + |Greater healing | Uncommon | ``4d4 + 4`` | + +-----------------+-----------+-----------------+ + |Superior healing | Rare | ``8d4 + 8`` | + +-----------------+-----------+-----------------+ + |Supreme healing | Very rare | ``10d4 + 20`` | + +-----------------+-----------+-----------------+ + + """ + name = "Potion of Greater Healing" + rarity = "uncommon" + + +class PotionOfSuperiorHealing(PotionOfHealing): + """You regain hit points when you drink this potion. The number of hit + points depends on the potion’s rarity, as shown in the Potions of + Healing table. Whatever its potency, the potion’s red liquid + glimmers when agitated. + + **Potions of Healing** + + +-----------------+-----------+-------------+ + | Potion of ... | Rarity | HP Regained | + +=================+===========+=============+ + |Healing | Common | 2d4 + 2 | + +-----------------+-----------+-------------+ + |Greater healing | Uncommon | 4d4 + 4 | + +-----------------+-----------+-------------+ + |Superior healing | Rare | 8d4 + 8 | + +-----------------+-----------+-------------+ + |Supreme healing | Very rare | 10d4 + 20 | + +-----------------+-----------+-------------+ + + """ + name = "Potion of Superior Healing" + rarity = "rare" + + +class PotionOfSupremeHealing(PotionOfHealing): + """You regain hit points when you drink this potion. The number of hit + points depends on the potion’s rarity, as shown in the Potions of + Healing table. Whatever its potency, the potion’s red liquid + glimmers when agitated. + + **Potions of Healing** + + +-----------------+-----------+-------------+ + | Potion of ... | Rarity | HP Regained | + +=================+===========+=============+ + |Healing | Common | 2d4 + 2 | + +-----------------+-----------+-------------+ + |Greater healing | Uncommon | 4d4 + 4 | + +-----------------+-----------+-------------+ + |Superior healing | Rare | 8d4 + 8 | + +-----------------+-----------+-------------+ + |Supreme healing | Very rare | 10d4 + 20 | + +-----------------+-----------+-------------+ + + """ + name = "Potion of Supreme Healing" + rarity = "very rare" From 4f8a0e442b5d0112d446c592d8b5da687dc8e3f6 Mon Sep 17 00:00:00 2001 From: Mark Wolfman Date: Tue, 7 Sep 2021 20:10:53 -0500 Subject: [PATCH 2/2] When resolving +1 weapons, replaced check for inheritance from Weapon with check for *improved_version* method. Fixes https://github.com/canismarko/dungeon-sheets/issues/112 --- VERSION | 2 +- dungeonsheets/content_registry.py | 9 ++------- dungeonsheets/make_sheets.py | 1 - tests/test_content_registry.py | 19 ++++++++++++++++++- tests/test_make_sheets.py | 4 ++-- 5 files changed, 23 insertions(+), 12 deletions(-) diff --git a/VERSION b/VERSION index 07feb82..14a8c24 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.17.0 \ No newline at end of file +0.17.1 \ No newline at end of file diff --git a/dungeonsheets/content_registry.py b/dungeonsheets/content_registry.py index 2f7879e..93a11da 100644 --- a/dungeonsheets/content_registry.py +++ b/dungeonsheets/content_registry.py @@ -136,13 +136,8 @@ class ContentRegistry: else: attr = found_attrs[0] # Apply weapon/etc. bonuses - if bonus > 0: - if ( - issubclass(attr, weapons.Weapon) - or issubclass(attr, armor.Shield) - or issubclass(attr, armor.Armor) - ): - attr = attr.improved_version(bonus) + if bonus > 0 and hasattr(attr, 'improved_version'): + attr = attr.improved_version(bonus) return attr diff --git a/dungeonsheets/make_sheets.py b/dungeonsheets/make_sheets.py index 639bf49..b7e7115 100644 --- a/dungeonsheets/make_sheets.py +++ b/dungeonsheets/make_sheets.py @@ -113,7 +113,6 @@ def create_random_tables_content( ) -> str: template = jinja_env.get_template(f"random_tables_template.{suffix}") return template.render( - conjure_animals=True, tables=tables, use_dnd_decorations=use_dnd_decorations, ) diff --git a/tests/test_content_registry.py b/tests/test_content_registry.py index 7aa628e..d6a4a17 100644 --- a/tests/test_content_registry.py +++ b/tests/test_content_registry.py @@ -2,7 +2,7 @@ from unittest import TestCase from dungeonsheets.content_registry import ContentRegistry -from dungeonsheets import monsters +from dungeonsheets import monsters, weapons class TestContentRegistry(TestCase): @@ -62,3 +62,20 @@ class TestContentRegistry(TestCase): # Direct access self.assertEqual(creg.findattr("my_attr", valid_classes=[int]), test_module.my_attr) + def test_findattr_magic_weapon(self): + creg = ContentRegistry() + creg.add_module(weapons) + # First test with a non-magical weapon + shortsword = creg.findattr("shortsword") + self.assertIs(shortsword, weapons.Shortsword) + # Now test with a magical weapon + magic_shortsword = creg.findattr("shortsword + 1") + self.assertTrue(issubclass(magic_shortsword, weapons.Shortsword), + "Improved version is not subclass of base.") + self.assertEqual(magic_shortsword.attack_bonus, 1) + self.assertEqual(magic_shortsword.damage_bonus, 1) + # Make sure some other item that can't be "improved" still works + creg = ContentRegistry() + creg.add_module(monsters) + lich = creg.findattr("lich+1") + self.assertIs(lich, monsters.Lich) diff --git a/tests/test_make_sheets.py b/tests/test_make_sheets.py index c8091b8..5d914df 100644 --- a/tests/test_make_sheets.py +++ b/tests/test_make_sheets.py @@ -2,7 +2,7 @@ import unittest import os from pathlib import Path -from dungeonsheets import make_sheets, character, monsters +from dungeonsheets import make_sheets, character, monsters, random_tables EG_DIR = Path(__file__).parent.parent.resolve() / "examples" @@ -283,7 +283,7 @@ class TexCreatorTestCase(unittest.TestCase): def test_random_tables_tex(self): tex = make_sheets.create_random_tables_content( + tables=[random_tables.ConjureAnimals], suffix="tex", - conjure_animals=True, ) self.assertIn(r"\subsection*{Conjure Animals}", tex)