mirror of
https://github.com/Threnklyn/dungeon-sheets.git
synced 2026-05-18 20:23:27 +02:00
Merge branch 'canismarko:master' into master
This commit is contained in:
@@ -136,12 +136,7 @@ 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)
|
||||
):
|
||||
if bonus > 0 and hasattr(attr, 'improved_version'):
|
||||
attr = attr.improved_version(bonus)
|
||||
return attr
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -73,11 +73,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(
|
||||
@@ -100,6 +104,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:
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -114,7 +114,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,
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user