mirror of
https://github.com/Threnklyn/dungeon-sheets.git
synced 2026-06-07 05:03:31 +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,24 +734,24 @@ 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
|
||||||
that might change the outcome, such as the casting of additional
|
that might change the outcome, such as the casting of additional
|
||||||
spells or the loss or gain of a companion. If you cast the spell
|
spells or the loss or gain of a companion. If you cast the spell
|
||||||
two or more times before completing your next long rest, there is
|
two or more times before completing your next long rest, there is
|
||||||
a cumulative 25 percent chance for each casting after the first
|
a cumulative 25 percent chance for each casting after the first
|
||||||
that you get a random reading. The DM makes this roll in secret.
|
that you get a random reading. The DM makes this roll in secret.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
name = "Augury"
|
name = "Augury"
|
||||||
level = 2
|
level = 2
|
||||||
|
|||||||
@@ -214,28 +214,30 @@ 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
|
||||||
feet of it. Make a new attack roll against the new target, and
|
feet of it. Make a new attack roll against the new target, and
|
||||||
make a new damage roll, which could cause the chaotic energy to
|
make a new damage roll, which could cause the chaotic energy to
|
||||||
leap again. A creature can be targeted only once by each casting
|
leap again. A creature can be targeted only once by each casting
|
||||||
of this spell.
|
of this spell.
|
||||||
|
|
||||||
**At Higher Levels:** When you cast this spell using a spell slot of
|
**At Higher Levels:** When you cast this spell using a spell slot of
|
||||||
2nd level or higher, each target takes 1d6 extra damage of the
|
2nd level or higher, each target takes 1d6 extra damage of the
|
||||||
type rolled for each slot level above 1st.
|
type rolled for each slot level above 1st.
|
||||||
@@ -619,22 +621,20 @@ class CommuneWithNature(Spell):
|
|||||||
natural underground settings, the radius is limited to 300
|
natural underground settings, the radius is limited to 300
|
||||||
feet. The spell doesn't function where nature has been replaced by
|
feet. The spell doesn't function where nature has been replaced by
|
||||||
construction, such as in dungeons and towns.
|
construction, such as in dungeons and towns.
|
||||||
|
|
||||||
You instantly gain knowledge of up to three facts of your choice
|
You instantly gain knowledge of up to three facts of your choice
|
||||||
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,
|
- influence from other planes of existence
|
||||||
or undead
|
- buildings
|
||||||
- influence from other planes of existence
|
|
||||||
- buildings
|
|
||||||
|
|
||||||
For example, you could determine the location of powerful undead
|
For example, you could determine the location of powerful undead
|
||||||
in the area, the location of major sources of safe drinking water,
|
in the area, the location of major sources of safe drinking water,
|
||||||
and the location of any nearby towns.
|
and the location of any nearby towns.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
name = "Commune With Nature"
|
name = "Commune With Nature"
|
||||||
level = 5
|
level = 5
|
||||||
@@ -1211,21 +1211,22 @@ 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.
|
||||||
- You instantaneously extinguish the flames within the cube.
|
- You instantaneously extinguish the flames within the cube.
|
||||||
- You double or halve the area of bright light and dim light cast
|
- You double or halve the area of bright light and dim light cast
|
||||||
by the flame, change its color, or both. The change lasts for 1
|
by the flame, change its color, or both. The change lasts for 1
|
||||||
hour.
|
hour.
|
||||||
- You cause simple shapes - such as the vague form of a creature,
|
- You cause simple shapes - such as the vague form of a creature,
|
||||||
an inanimate object, or a location - to appear within the flames
|
an inanimate object, or a location - to appear within the flames
|
||||||
and animate as you like. The shapes last for 1 hour. If you
|
and animate as you like. The shapes last for 1 hour. If you
|
||||||
cast this spell multiple times, you can have up to three
|
cast this spell multiple times, you can have up to three
|
||||||
non-instantaneous
|
non-instantaneous
|
||||||
|
|
||||||
"""
|
"""
|
||||||
name = "Control Flames"
|
name = "Control Flames"
|
||||||
level = 0
|
level = 0
|
||||||
|
|||||||
@@ -441,25 +441,26 @@ class GuardianOfNature(Spell):
|
|||||||
powerful guardian. The transformation lasts until the spell
|
powerful guardian. The transformation lasts until the spell
|
||||||
ends. You choose one of the following forms to assume: Primal
|
ends. You choose one of the following forms to assume: Primal
|
||||||
Beast or Great Tree.
|
Beast or Great Tree.
|
||||||
|
|
||||||
**Primal Beast.** Bestial fur covers your body, your facial
|
**Primal Beast.** Bestial fur covers your body, your facial
|
||||||
features become feral, and you gain the following benefits:
|
features become feral, and you gain the following benefits:
|
||||||
|
|
||||||
- Your walking speed increases by 10 feet.
|
- Your walking speed increases by 10 feet.
|
||||||
- You gain darkvision with a range of 120 feet.
|
- You gain darkvision with a range of 120 feet.
|
||||||
- You make Strength-based attack rolls with advantage.
|
- You make Strength-based attack rolls with advantage.
|
||||||
- Your melee weapon attacks deal an extra 1d6 force damage on a
|
- Your melee weapon attacks deal an extra 1d6 force damage on a
|
||||||
hit.
|
hit.
|
||||||
|
|
||||||
**Great Tree.** Your skin appears barky, leaves sprout from your
|
**Great Tree.** Your skin appears barky, leaves sprout from your
|
||||||
hair, and you gain the following benefits:
|
hair, and you gain the following benefits:
|
||||||
|
|
||||||
- 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.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
name = "Guardian Of Nature"
|
name = "Guardian Of Nature"
|
||||||
level = 4
|
level = 4
|
||||||
@@ -480,57 +481,49 @@ class GuardsAndWards(Spell):
|
|||||||
tall, and shaped as you desire. You can ward several stories of a
|
tall, and shaped as you desire. You can ward several stories of a
|
||||||
stronghold by dividing the area among them, as long as you can
|
stronghold by dividing the area among them, as long as you can
|
||||||
walk into each contiguous area while you are casting the spell.
|
walk into each contiguous area while you are casting the spell.
|
||||||
|
|
||||||
When you cast this spell, you can specify individuals that are
|
When you cast this spell, you can specify individuals that are
|
||||||
unaffected by any or all of the effects that you choose. You can
|
unaffected by any or all of the effects that you choose. You can
|
||||||
also specify a password that, when spoken aloud, makes the speaker
|
also specify a password that, when spoken aloud, makes the speaker
|
||||||
immune to these effects.
|
immune to these effects.
|
||||||
|
|
||||||
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
|
||||||
|
bottom, as the web spell. These strands regrow in 10 minutes if
|
||||||
Stairs: Webs fill all stairs in the warded area from top to
|
they are burned or torn away while guards and wards lasts.
|
||||||
bottom, as the web spell. These strands regrow in 10 minutes if
|
- **Other Spell Effect.** You can place your choice of one of the
|
||||||
they are burned or torn away while guards and wards lasts.
|
following magical effects within the warded area of the
|
||||||
|
stronghold.
|
||||||
Other Spell Effect: You can place your choice of one of the
|
|
||||||
following magical effects within the warded area of the
|
- Place dancing lights in four corridors. You can designate a
|
||||||
stronghold.
|
simple program that the lights repeat as long as guards and
|
||||||
|
wards lasts.
|
||||||
- Place dancing lights in four corridors. You can designate a
|
- Place magic mouth in two locations.
|
||||||
simple program that the lights repeat as long as guards and
|
- Place stinking cloud in two locations. The vapors appear in
|
||||||
wards lasts.
|
the places you designate; they return within 10 minutes if
|
||||||
|
dispersed by wind while guards and wards lasts.
|
||||||
- Place magic mouth in two locations.
|
- Place a constant gust of wind in one corridor or room.
|
||||||
|
- Place a suggestion in one location. You select an area of up
|
||||||
- Place stinking cloud in two locations. The vapors appear in the
|
to 5 feet square, and any creature that enters or passes
|
||||||
places you designate; they return within 10 minutes if dispersed
|
through the area receives the suggestion mentally.
|
||||||
by wind while guards and wards lasts.
|
|
||||||
|
|
||||||
- Place a constant gust of wind in one corridor or room.
|
|
||||||
|
|
||||||
- Place a suggestion in one location. You select an area of up to
|
|
||||||
5 feet square, and any creature that enters or passes through
|
|
||||||
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"
|
||||||
level = 6
|
level = 6
|
||||||
@@ -619,19 +612,17 @@ class GuidingHand(Spell):
|
|||||||
class Gust(Spell):
|
class Gust(Spell):
|
||||||
"""You seize the air and compel it to create one of the following
|
"""You seize the air and compel it to create one of the following
|
||||||
effects at a point you can see within range:
|
effects at a point you can see within range:
|
||||||
|
|
||||||
- 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.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
name = "Gust"
|
name = "Gust"
|
||||||
level = 0
|
level = 0
|
||||||
|
|||||||
@@ -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