mirror of
https://github.com/Threnklyn/dungeon-sheets.git
synced 2026-06-07 13:15:53 +02:00
Added a test to check that all spells are valid rst.
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
from dungeonsheets.spells.spells import Spell, create_spell
|
from dungeonsheets.spells.spells import Spell, create_spell, all_spells
|
||||||
|
|
||||||
from dungeonsheets.spells.spells_a import *
|
from dungeonsheets.spells.spells_a import *
|
||||||
from dungeonsheets.spells.spells_b import *
|
from dungeonsheets.spells.spells_b import *
|
||||||
from dungeonsheets.spells.spells_c import *
|
from dungeonsheets.spells.spells_c import *
|
||||||
|
|||||||
@@ -1,3 +1,14 @@
|
|||||||
|
from dungeonsheets import spells
|
||||||
|
|
||||||
|
|
||||||
|
def all_spells():
|
||||||
|
"""Generate all the valid spell classes so far defined."""
|
||||||
|
for spell_name, spell in spells.__dict__.items():
|
||||||
|
# Check if it's (a) a class and (b) a subclass of ``Spell``
|
||||||
|
if isinstance(spell, type) and issubclass(spell, Spell):
|
||||||
|
yield spell
|
||||||
|
|
||||||
|
|
||||||
def create_spell(**params):
|
def create_spell(**params):
|
||||||
"""Create a new subclass of ``Spell`` with given default parameters.
|
"""Create a new subclass of ``Spell`` with given default parameters.
|
||||||
|
|
||||||
|
|||||||
@@ -734,15 +734,15 @@ class AstralProjection(Spell):
|
|||||||
|
|
||||||
|
|
||||||
class Augury(Spell):
|
class Augury(Spell):
|
||||||
"""By casting gem-inlaid sticks, rolling dragon bones, laying out ornate cards, or
|
"""By casting gem-inlaid sticks, rolling dragon bones, laying out
|
||||||
employing some other divining tool, you receive an omen from an otherworldly
|
ornate cards, or employing some other divining tool, you receive
|
||||||
entity about the results of a specific course of action that you plan to take
|
an omen from an otherworldly entity about the results of a
|
||||||
within the next 30 minutes. The DM chooses from the following possible omens:
|
specific course of action that you plan to take within the next 30
|
||||||
|
minutes. The DM chooses from the following possible omens:
|
||||||
|
|
||||||
- Weal, for good results
|
- Weal, for good results
|
||||||
- Woe, for bad results
|
- Woe, for bad results
|
||||||
- Weal and woe, for both good
|
- Weal and woe, for both good and bad results
|
||||||
and bad results
|
|
||||||
- Nothing, for results that aren't especially good or bad
|
- Nothing, for results that aren't especially good or bad
|
||||||
|
|
||||||
The spell doesn't take into account any possible circumstances
|
The spell doesn't take into account any possible circumstances
|
||||||
|
|||||||
@@ -214,20 +214,22 @@ class ChainLightning(Spell):
|
|||||||
class ChaosBolt(Spell):
|
class ChaosBolt(Spell):
|
||||||
"""You hurl an undulating, warbling mass of chaotic energy at one
|
"""You hurl an undulating, warbling mass of chaotic energy at one
|
||||||
creature in range. Make a ranged spell attack against the
|
creature in range. Make a ranged spell attack against the
|
||||||
target. On a hit, the target takes 2d8 + 1d6 damage. Choose one of
|
target. On a hit, the target takes ``2d8+1d6`` damage. Choose one
|
||||||
the dSs. The number rolled on that die determines the attacks
|
of the d8s. The number rolled on that die determines the attacks
|
||||||
damage type, as shown below.
|
damage type, as shown below.
|
||||||
|
|
||||||
d8 / Damage Type
|
== ===========
|
||||||
1 / Acid
|
d8 Damage Type
|
||||||
2
|
== ===========
|
||||||
/ Cold
|
1 Acid
|
||||||
3 / Fire
|
2 Cold
|
||||||
4 / Force
|
3 Fire
|
||||||
5 / Lightning
|
4 Force
|
||||||
6 / Poison
|
5 Lightning
|
||||||
7 / Psychic
|
6 Poison
|
||||||
8 / Thunder
|
7 Psychic
|
||||||
|
8 Thunder
|
||||||
|
== ===========
|
||||||
|
|
||||||
If you roll the same number on both d8s, the chaotic energy leaps
|
If you roll the same number on both d8s, the chaotic energy leaps
|
||||||
from the target to a different creature of your choice within 30
|
from the target to a different creature of your choice within 30
|
||||||
@@ -624,10 +626,8 @@ class CommuneWithNature(Spell):
|
|||||||
about any of the following subjects as they relate to the area:
|
about any of the following subjects as they relate to the area:
|
||||||
|
|
||||||
- terrain and bodies of water
|
- terrain and bodies of water
|
||||||
- prevalent plants,
|
- prevalent plants, minerals, animals, or peoples
|
||||||
minerals, animals, or peoples
|
- powerful celestials, fey, fiends, elementals, or undead
|
||||||
- powerful celestials, fey, fiends, elementals,
|
|
||||||
or undead
|
|
||||||
- influence from other planes of existence
|
- influence from other planes of existence
|
||||||
- buildings
|
- buildings
|
||||||
|
|
||||||
@@ -1211,8 +1211,9 @@ class ContinualFlame(Spell):
|
|||||||
|
|
||||||
|
|
||||||
class ControlFlames(Spell):
|
class ControlFlames(Spell):
|
||||||
"""You choose a nonmagical flame that you can see within range and that fits within
|
"""You choose a nonmagical flame that you can see within range and
|
||||||
a 5-foot cube. You affect it in one of the following ways:
|
that fits within a 5-foot cube. You affect it in one of the
|
||||||
|
following ways:
|
||||||
|
|
||||||
- You instantaneously expand the flame 5 feet in one direction,
|
- You instantaneously expand the flame 5 feet in one direction,
|
||||||
provided that wood or other fuel is present in the new location.
|
provided that wood or other fuel is present in the new location.
|
||||||
|
|||||||
@@ -456,7 +456,8 @@ class GuardianOfNature(Spell):
|
|||||||
|
|
||||||
- You gain 10 temporary hit points.
|
- You gain 10 temporary hit points.
|
||||||
- You make Constitution saving throws with advantage.
|
- You make Constitution saving throws with advantage.
|
||||||
- You make Dexterity- and Wisdom-based attack rolls with advantage.
|
- You make Dexterity- and Wisdom-based attack rolls with
|
||||||
|
advantage.
|
||||||
- While you are on the ground, the ground within 15 feet of you is
|
- While you are on the ground, the ground within 15 feet of you is
|
||||||
difficult terrain for your enemies.
|
difficult terrain for your enemies.
|
||||||
|
|
||||||
@@ -489,47 +490,39 @@ class GuardsAndWards(Spell):
|
|||||||
Guards and wards creates the following effects within the warded
|
Guards and wards creates the following effects within the warded
|
||||||
area.
|
area.
|
||||||
|
|
||||||
Corridors: Fog fills all the warded corridors, making them heavily
|
- **Corridors.** Fog fills all the warded corridors, making them
|
||||||
obscured. In addition, at each intersection or branching passage
|
heavily obscured. In addition, at each intersection or branching
|
||||||
offering a choice of direction, there is a 50 percent chance that
|
passage offering a choice of direction, there is a 50 percent
|
||||||
a creature other than you will believe it is going in the opposite
|
chance that a creature other than you will believe it is going
|
||||||
direction from the one it chooses.
|
in the opposite direction from the one it chooses.
|
||||||
|
- **Doors.** All doors in the warded area are magically locked, as
|
||||||
Doors: All doors in the warded area are magically locked, as if
|
if sealed by an arcane lock spell. In addition, you can cover up
|
||||||
sealed by an arcane lock spell. In addition, you can cover up to
|
to ten doors with an illusion (equivalent to the illusory object
|
||||||
ten doors with an illusion (equivalent to the illusory object
|
|
||||||
function of the m inor illusion spell) to make them appear as
|
function of the m inor illusion spell) to make them appear as
|
||||||
plain sections of wall.
|
plain sections of wall.
|
||||||
|
- **Stairs.** Webs fill all stairs in the warded area from top to
|
||||||
Stairs: Webs fill all stairs in the warded area from top to
|
|
||||||
bottom, as the web spell. These strands regrow in 10 minutes if
|
bottom, as the web spell. These strands regrow in 10 minutes if
|
||||||
they are burned or torn away while guards and wards lasts.
|
they are burned or torn away while guards and wards lasts.
|
||||||
|
- **Other Spell Effect.** You can place your choice of one of the
|
||||||
Other Spell Effect: You can place your choice of one of the
|
|
||||||
following magical effects within the warded area of the
|
following magical effects within the warded area of the
|
||||||
stronghold.
|
stronghold.
|
||||||
|
|
||||||
- Place dancing lights in four corridors. You can designate a
|
- Place dancing lights in four corridors. You can designate a
|
||||||
simple program that the lights repeat as long as guards and
|
simple program that the lights repeat as long as guards and
|
||||||
wards lasts.
|
wards lasts.
|
||||||
|
|
||||||
- Place magic mouth in two locations.
|
- Place magic mouth in two locations.
|
||||||
|
- Place stinking cloud in two locations. The vapors appear in
|
||||||
- Place stinking cloud in two locations. The vapors appear in the
|
the places you designate; they return within 10 minutes if
|
||||||
places you designate; they return within 10 minutes if dispersed
|
dispersed by wind while guards and wards lasts.
|
||||||
by wind while guards and wards lasts.
|
|
||||||
|
|
||||||
- Place a constant gust of wind in one corridor or room.
|
- Place a constant gust of wind in one corridor or room.
|
||||||
|
- Place a suggestion in one location. You select an area of up
|
||||||
- Place a suggestion in one location. You select an area of up to
|
to 5 feet square, and any creature that enters or passes
|
||||||
5 feet square, and any creature that enters or passes through
|
through the area receives the suggestion mentally.
|
||||||
the area receives the suggestion mentally.
|
|
||||||
|
|
||||||
The whole warded area radiates magic. A dispel magic cast on a
|
The whole warded area radiates magic. A dispel magic cast on a
|
||||||
specific effect, if successful, removes only that effect.
|
specific effect, if successful, removes only that effect. You can
|
||||||
|
create a permanently guarded and warded structure by casting this
|
||||||
You can create a permanently guarded and warded structure by
|
spell there every day for one year.
|
||||||
casting this spell there every day for one year.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
name = "Guards And Wards"
|
name = "Guards And Wards"
|
||||||
@@ -622,12 +615,10 @@ class Gust(Spell):
|
|||||||
|
|
||||||
- One Medium or smaller creature that you choose must succeed on a
|
- One Medium or smaller creature that you choose must succeed on a
|
||||||
Strength saving throw or be pushed up to 5 feet away from you.
|
Strength saving throw or be pushed up to 5 feet away from you.
|
||||||
|
|
||||||
- You create a small blast of air capable of moving one object
|
- You create a small blast of air capable of moving one object
|
||||||
that is neither held nor carried and that weighs no more than 5
|
that is neither held nor carried and that weighs no more than 5
|
||||||
pounds. The object is pushed up to 10 feet away from you. It
|
pounds. The object is pushed up to 10 feet away from you. It
|
||||||
isn't pushed with enough force to cause damage.
|
isn't pushed with enough force to cause damage.
|
||||||
|
|
||||||
- You create a harmless sensory affect using air, such as causing
|
- You create a harmless sensory affect using air, such as causing
|
||||||
leaves to rustle, wind to slam shutters shut, or your clothing
|
leaves to rustle, wind to slam shutters shut, or your clothing
|
||||||
to ripple in a breeze.
|
to ripple in a breeze.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import os
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from dungeonsheets import make_sheets, character
|
from dungeonsheets import make_sheets, character, spells
|
||||||
|
|
||||||
EG_DIR = os.path.abspath(os.path.join(os.path.split(__file__)[0], '../examples/'))
|
EG_DIR = os.path.abspath(os.path.join(os.path.split(__file__)[0], '../examples/'))
|
||||||
CHARFILE = os.path.join(EG_DIR, 'rogue1.py')
|
CHARFILE = os.path.join(EG_DIR, 'rogue1.py')
|
||||||
@@ -136,3 +136,9 @@ class MarkdownTestCase(unittest.TestCase):
|
|||||||
self.assertNotIn("endfoot", tex)
|
self.assertNotIn("endfoot", tex)
|
||||||
self.assertNotIn("endhead", tex)
|
self.assertNotIn("endhead", tex)
|
||||||
self.assertNotIn("endfirsthead", tex)
|
self.assertNotIn("endfirsthead", tex)
|
||||||
|
|
||||||
|
def test_rst_all_spells(self):
|
||||||
|
for spell in spells.all_spells():
|
||||||
|
tex = make_sheets.rst_to_latex(spell.__doc__)
|
||||||
|
self.assertNotIn("DUadmonition", tex,
|
||||||
|
f"spell {spell} is not valid reStructured text")
|
||||||
|
|||||||
+13
-1
@@ -2,11 +2,23 @@
|
|||||||
|
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
|
|
||||||
from dungeonsheets.spells import create_spell, Spell
|
from dungeonsheets import spells
|
||||||
|
from dungeonsheets.spells import create_spell, Spell, all_spells
|
||||||
|
|
||||||
|
|
||||||
class TestSpells(TestCase):
|
class TestSpells(TestCase):
|
||||||
"""Tests for spells and spell-related activities."""
|
"""Tests for spells and spell-related activities."""
|
||||||
|
def test_all_spells(self):
|
||||||
|
# Make sure only spells are returned
|
||||||
|
for ThisSpell in all_spells():
|
||||||
|
self.assertTrue(isinstance(ThisSpell, type),
|
||||||
|
f"``all_spells`` returned {ThisSpell} (not a class)")
|
||||||
|
self.assertTrue(issubclass(ThisSpell, Spell),
|
||||||
|
f"``all_spells`` returned {ThisSpell} (not a spell)")
|
||||||
|
# Pick a couple of known spells to spot-check for
|
||||||
|
all_the_spells = list(all_spells())
|
||||||
|
self.assertIn(spells.MagicMissile, all_the_spells)
|
||||||
|
self.assertIn(spells.Thunderwave, all_the_spells)
|
||||||
|
|
||||||
def test_create_spell(self):
|
def test_create_spell(self):
|
||||||
NewSpell = create_spell(name="Hello world")
|
NewSpell = create_spell(name="Hello world")
|
||||||
|
|||||||
Reference in New Issue
Block a user