mirror of
https://github.com/Threnklyn/dungeon-sheets.git
synced 2026-06-07 13:15:53 +02:00
Monster stat blocks now include XP alongside challenge rating.
This commit is contained in:
@@ -4,6 +4,7 @@ from jinja2 import Environment, PackageLoader
|
||||
|
||||
|
||||
from dungeonsheets.stats import mod_str, ability_mod_str, stat_abbreviation
|
||||
from dungeonsheets.monsters import challenge_rating_to_xp
|
||||
|
||||
|
||||
# A dice string, with optional backticks: ``1d6 + 3``
|
||||
@@ -33,4 +34,5 @@ def jinja_environment():
|
||||
jinja_env.filters["mod_str"] = mod_str
|
||||
jinja_env.filters["ability_mod_str"] = ability_mod_str
|
||||
jinja_env.filters["stat_abbreviation"] = stat_abbreviation
|
||||
jinja_env.filters["challenge_rating_to_xp"] = challenge_rating_to_xp
|
||||
return jinja_env
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
[% if monster.damage_vulnerabilities != "" %]<dt>Damage Vulnerabilities</dt><dd>[[ monster.damage_vulnerabilities ]]</dd>[% endif %]
|
||||
[% if monster.condition_immunities != "" %]<dt>Condition Immunuties</dt><dd>[[ monster.condition_immunities ]]</dd>[% endif %]
|
||||
[% if monster.saving_throws != "" %]<dt>Saving Throws</dt><dd>[[ monster.saving_throws ]]</dd>[% endif %]
|
||||
<dt>Challenge<dd>[[ monster.challenge_rating ]] </dd>
|
||||
<dt>Challenge<dd>[[ monster.challenge_rating ]] ([[ monster.challenge_rating | challenge_rating_to_xp ]] XP)</dd>
|
||||
</dl>
|
||||
|
||||
[% if monster.spells | length > 0 %]
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
condition-immunities = {[[ monster.condition_immunities ]]},
|
||||
senses = {[[ monster.senses ]]},
|
||||
languages = {[% if monster.languages %][[ monster.languages ]][% else %] --- [% endif %]},
|
||||
challenge = {[[ monster.challenge_rating ]]},
|
||||
challenge = {[[ monster.challenge_rating ]] ([[ monster.challenge_rating | challenge_rating_to_xp ]] XP)},
|
||||
]
|
||||
%\DndMonsterSection{Actions}
|
||||
[[ monster.__doc__ | rst_to_latex(top_heading_level=2) ]]
|
||||
@@ -88,7 +88,7 @@
|
||||
[% if monster.damage_vulnerabilities != "" %]\item [Damage Vulnerabilities:] [[ monster.damage_vulnerabilities ]][% endif %]
|
||||
[% if monster.condition_immunities != "" %]\item [Condition Immunuties:] [[ monster.condition_immunities ]][% endif %]
|
||||
[% if monster.saving_throws != "" %]\item [Saving Throws:] [[ monster.saving_throws ]][% endif %]
|
||||
\item [Challenge:] [[ monster.challenge_rating ]]
|
||||
\item [Challenge:] [[ monster.challenge_rating ]] ([[ monster.challenge_rating | challenge_rating_to_xp ]] XP)
|
||||
\end{description}
|
||||
|
||||
\vspace{0.2cm}
|
||||
|
||||
@@ -10,6 +10,53 @@ from dungeonsheets.content import Creature
|
||||
from dungeonsheets.spells import Spell
|
||||
|
||||
|
||||
xp_by_challenge_rating = {
|
||||
0: 10,
|
||||
(1 / 8): 25,
|
||||
(1 / 4): 50,
|
||||
(1 / 2): 100,
|
||||
1: 200,
|
||||
2: 450,
|
||||
3: 700,
|
||||
4: 1100,
|
||||
5: 1800,
|
||||
6: 2300,
|
||||
7: 2900,
|
||||
8: 3900,
|
||||
9: 5000,
|
||||
10: 5900,
|
||||
11: 7200,
|
||||
12: 8400,
|
||||
13: 10000,
|
||||
14: 11500,
|
||||
15: 13000,
|
||||
16: 15000,
|
||||
17: 18000,
|
||||
18: 20000,
|
||||
19: 22000,
|
||||
20: 25000,
|
||||
21: 33000,
|
||||
22: 41000,
|
||||
23: 50000,
|
||||
24: 62000,
|
||||
25: 75000,
|
||||
26: 90000,
|
||||
27: 105000,
|
||||
28: 120000,
|
||||
29: 130000,
|
||||
30: 155000,
|
||||
}
|
||||
|
||||
|
||||
def challenge_rating_to_xp(cr):
|
||||
"""Determine the XP awarded for slaying a monster with the given
|
||||
challenge rating *cr*.
|
||||
|
||||
"""
|
||||
xp = xp_by_challenge_rating[cr]
|
||||
return "{:,}".format(xp)
|
||||
|
||||
|
||||
class SpellFactory(ABCMeta):
|
||||
"""Meta class to resolve spell strings into the ``spells.Spell``.
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ class VashtaNerada(monsters.Monster):
|
||||
damage_immunities = "Bludgeoning"
|
||||
damage_resistances = "Lightning"
|
||||
damage_vulnerabilities = "Wood-based"
|
||||
challenge_rating = 93
|
||||
challenge_rating = 30
|
||||
spells = ["wish"]
|
||||
|
||||
|
||||
@@ -159,6 +159,7 @@ class HtmlCreatorTestCase(unittest.TestCase):
|
||||
self.assertIn(r"Damage Vulnerabilities", html)
|
||||
self.assertIn(r"Senses", html)
|
||||
self.assertIn(r"Challenge", html)
|
||||
self.assertIn(r"(155,000 XP)", html)
|
||||
self.assertIn(r"Languages", html)
|
||||
self.assertIn(r"Skills", html)
|
||||
self.assertIn(r"petrified", html)
|
||||
@@ -252,6 +253,7 @@ class TexCreatorTestCase(unittest.TestCase):
|
||||
self.assertIn(r"Damage Vulnerabilities:", tex)
|
||||
self.assertIn(r"Senses:", tex)
|
||||
self.assertIn(r"Challenge:", tex)
|
||||
self.assertIn(r"(155,000 XP)", tex)
|
||||
self.assertIn(r"Languages:", tex)
|
||||
self.assertIn(r"Skills:", tex)
|
||||
# Check fancy extended properties
|
||||
|
||||
@@ -362,3 +362,8 @@ class MonsterSpellcastingTests(TestCase):
|
||||
msg="Monster spell is not a class")
|
||||
self.assertTrue(issubclass(MyMonster.spells[0], spells.Spell))
|
||||
|
||||
|
||||
class ChallengeRatingTests(TestCase):
|
||||
def test_challenge_rating_to_xp(self):
|
||||
self.assertEqual(monsters.challenge_rating_to_xp(1 / 8), "25")
|
||||
self.assertEqual(monsters.challenge_rating_to_xp(30), "155,000")
|
||||
|
||||
Reference in New Issue
Block a user