Fixed tests: needed defaults for making character sheets for NPCs (e.g. GM notes).

This commit is contained in:
Mark Wolfman
2022-01-22 14:49:13 -06:00
parent a30dc28100
commit 23b4bd2559
9 changed files with 69 additions and 14 deletions
+2 -2
View File
@@ -467,11 +467,11 @@ class Character(Creature):
@property @property
def spellcasting_classes_excluding_warlock(self): def spellcasting_classes_excluding_warlock(self):
return [c for c in self.spellcasting_classes if not type(c) == classes.Warlock] return [c for c in self.spellcasting_classes if not type(c) == classes.Warlock]
@property @property
def is_spellcaster(self): def is_spellcaster(self):
return len(self.spellcasting_classes) > 0 return len(self.spellcasting_classes) > 0
def spell_slots(self, spell_level): def spell_slots(self, spell_level):
warlock_slots = 0 warlock_slots = 0
for c in self.spellcasting_classes: for c in self.spellcasting_classes:
+4 -1
View File
@@ -105,7 +105,6 @@ class Content(ABC):
attrs = {"name": mechanic_name, "__doc__": msg, "source": "Unknown"} attrs = {"name": mechanic_name, "__doc__": msg, "source": "Unknown"}
Mechanic = type(class_name, (SuperClass,), attrs) Mechanic = type(class_name, (SuperClass,), attrs)
return Mechanic return Mechanic
class Creature(Content): class Creature(Content):
@@ -213,3 +212,7 @@ class Creature(Content):
self.medicine, self.nature, self.perception, self.medicine, self.nature, self.perception,
self.performance, self.persuasion, self.religion, self.performance, self.persuasion, self.religion,
self.sleight_of_hand, self.stealth, self.survival] self.sleight_of_hand, self.stealth, self.survival]
@property
def is_spellcaster(self):
raise NotImplementedError
+2 -1
View File
@@ -3,7 +3,7 @@ import re
from jinja2 import Environment, PackageLoader from jinja2 import Environment, PackageLoader
from dungeonsheets.stats import mod_str, ability_mod_str, stat_abbreviation from dungeonsheets.stats import mod_str, ability_mod_str, stat_abbreviation, str_to_list
from dungeonsheets.encounter import xp_thresholds from dungeonsheets.encounter import xp_thresholds
from dungeonsheets.monsters import challenge_rating_to_xp from dungeonsheets.monsters import challenge_rating_to_xp
@@ -37,4 +37,5 @@ def jinja_environment():
jinja_env.filters["stat_abbreviation"] = stat_abbreviation jinja_env.filters["stat_abbreviation"] = stat_abbreviation
jinja_env.filters["challenge_rating_to_xp"] = challenge_rating_to_xp jinja_env.filters["challenge_rating_to_xp"] = challenge_rating_to_xp
jinja_env.filters["xp_thresholds"] = xp_thresholds jinja_env.filters["xp_thresholds"] = xp_thresholds
jinja_env.filters["str_to_list"] = str_to_list
return jinja_env return jinja_env
@@ -49,7 +49,7 @@
<dt>Current Hit Points</dt> <dt>Current Hit Points</dt>
<dd>[[ character.hp_current ]]&nbsp;</dd> <dd>[[ character.hp_current ]]&nbsp;</dd>
<dt>Temporary Hit Points</dt> <dt>Temporary Hit Points</dt>
<dd>[% if character.hp_temp > 0 %][[ character.hp_temp ]][% endif %]&nbsp;</dd> <dd>[[ character | selectattr('hp_temp', 0) ]]&nbsp;</dd>
<dt>Hit Dice Total</dt> <dt>Hit Dice Total</dt>
<dd>[[ character.hit_dice ]]</dd> <dd>[[ character.hit_dice ]]</dd>
@@ -126,12 +126,10 @@
<li>[[ character.ep ]] EP</li> <li>[[ character.ep ]] EP</li>
<li>[[ character.gp ]] GP</li> <li>[[ character.gp ]] GP</li>
<li>[[ character.pp ]] PP</li> <li>[[ character.pp ]] PP</li>
[% set inventory_items = character.magic_items_text.split(',') %] [% for item in character | str_to_list('magic_items_text') %]
[% for item in inventory_items %]
<li>[[ item ]]</li> <li>[[ item ]]</li>
[% endfor %] [% endfor %]
[% set inventory_items = character.equipment.split(',') %] [% for item in character | str_to_list('equipment') %]
[% for item in inventory_items %]
<li>[[ item ]]</li> <li>[[ item ]]</li>
[% endfor %] [% endfor %]
</ul> </ul>
+2 -2
View File
@@ -387,12 +387,12 @@ def make_character_content(
content_suffix=content_format, content_suffix=content_format,
use_dnd_decorations=fancy_decorations)) use_dnd_decorations=fancy_decorations))
# Create a list of subcasses, features, spells, etc # Create a list of subcasses, features, spells, etc
if character.subclasses: if len(getattr(character, 'subclasses', [])) > 0:
content.append(create_subclasses_content(character, content.append(create_subclasses_content(character,
content_suffix=content_format, content_suffix=content_format,
use_dnd_decorations=fancy_decorations) use_dnd_decorations=fancy_decorations)
) )
if character.features: if len(getattr(character, 'features', [])) > 0:
content.append( content.append(
create_features_content(character, content_suffix=content_format, use_dnd_decorations=fancy_decorations) create_features_content(character, content_suffix=content_format, use_dnd_decorations=fancy_decorations)
) )
+4
View File
@@ -106,3 +106,7 @@ class Monster(Creature, metaclass=SpellFactory):
def has_feature(self, *args, **kwargs): def has_feature(self, *args, **kwargs):
return False return False
@property
def is_spellcaster(self):
return len(self.spells) > 0
+37 -1
View File
@@ -32,7 +32,43 @@ log = logging.getLogger(__name__)
def mod_str(modifier): def mod_str(modifier):
"""Converts a modifier to a string, eg 2 -> '+2'.""" """Converts a modifier to a string, eg 2 -> '+2'."""
return "{:+d}".format(modifier) try:
s = "{:+d}".format(modifier)
except TypeError:
s = "N/A"
return s
def str_to_list(obj, attr: str, sep: str = ","):
"""Find the string *obj.attr* if it exists, and returns it as a
list.
Parameters
==========
obj
Any python object, presumably with an attribute *attr*.
attr
The name of the attribute to look up.
sep
The separator to use for splitting the string.
Returns
=======
items
A sequence of the items retrieved from *obj.attr* string. If
*obj.attr* does not exist, an empty list will be returned. If
*obj.attr* is not a string, then it will be presumed to be a
sequence already and returned as is.
"""
string = getattr(obj, attr, [])
if hasattr(string, "split"):
# Convert the string to a list
lst = [s.strip() for s in string.split(sep)]
else:
# A non-string attribute was given, so just return it
lst = string
return lst
def ability_mod_str(character, ability): def ability_mod_str(character, ability):
+2 -2
View File
@@ -5,7 +5,7 @@ monsters, etc.
""" """
from dungeonsheets import mechanics, monsters from dungeonsheets import mechanics, monsters as _monsters
dungeonsheets_version = "0.14.0" dungeonsheets_version = "0.14.0"
@@ -18,6 +18,6 @@ haryk_omanie = mechanics.Character(
name="Haryk Omanie", name="Haryk Omanie",
) )
party = ["rogue1.py", "paladin2.py", haryk_omanie, monsters.Veteran] party = ["rogue1.py", "paladin2.py", haryk_omanie, _monsters.Veteran]
random_tables = ["conjure animals"] random_tables = ["conjure animals"]
+13
View File
@@ -8,6 +8,19 @@ class TestStats(TestCase):
self.assertEqual(stats.mod_str(-3), "-3") self.assertEqual(stats.mod_str(-3), "-3")
self.assertEqual(stats.mod_str(0), "+0") self.assertEqual(stats.mod_str(0), "+0")
self.assertEqual(stats.mod_str(2), "+2") self.assertEqual(stats.mod_str(2), "+2")
self.assertEqual(stats.mod_str(None), "N/A")
def test_str_to_list(self):
char = character.Character(equipment="a, b, c")
# Regular string
self.assertEqual(stats.str_to_list(char, "equipment"), ["a", "b", "c"])
# Alternate separator
char.equipment = "a; b; c"
self.assertEqual(stats.str_to_list(char, "equipment", sep=";"), ["a", "b", "c"])
# No attribute
self.assertEqual(stats.str_to_list(char, "inventory"), [])
# Not a string
self.assertEqual(stats.str_to_list(char, "hp_max"), char.hp_max)
def test_saving_throw(self): def test_saving_throw(self):
# Try it with an ST proficiency # Try it with an ST proficiency