From c9a0eb1f0e843bcdf54e81e7ed8dae071783460d Mon Sep 17 00:00:00 2001 From: Mark Wolfman Date: Thu, 10 Mar 2022 14:17:26 -0600 Subject: [PATCH] Added ability to define magic weapons by multiple inheritence. --- docs/advanced_features.rst | 27 +++++++++++++++++++++++++++ dungeonsheets/character.py | 2 +- dungeonsheets/content.py | 9 ++++++++- dungeonsheets/exceptions.py | 4 ++++ dungeonsheets/magic_items.py | 14 ++++++++++++-- dungeonsheets/stats.py | 10 +++++++--- dungeonsheets/weapons.py | 11 +++++++++++ examples/artificer1.py | 2 +- examples/barbarian1.py | 2 +- examples/barbarian2.py | 2 +- examples/bard1.py | 2 +- examples/bard2.py | 2 +- examples/bloodhunter1.py | 2 +- examples/cleric1.py | 2 +- examples/cleric2.py | 2 +- examples/druid1.py | 2 +- examples/druid2.py | 2 +- examples/druid3.py | 2 +- examples/fighter1.py | 2 +- examples/fighter2.py | 2 +- examples/homebrew.py | 8 +++++--- examples/monk1.py | 2 +- examples/monk2.py | 2 +- examples/multiclass1.py | 2 +- examples/multiclass2.py | 2 +- examples/paladin1.py | 2 +- examples/paladin2.py | 2 +- examples/ranger1.py | 2 +- examples/ranger2.py | 2 +- examples/ranger3.py | 2 +- examples/rogue1.py | 2 +- examples/rogue2.py | 2 +- examples/sorceror1.py | 2 +- examples/sorceror2.py | 2 +- examples/warlock1.py | 2 +- examples/warlock2.py | 2 +- examples/wizard1.py | 2 +- examples/wizard2.py | 2 +- tests/test_character.py | 9 +++++++++ tests/test_magic_items.py | 4 ++-- tests/test_weapon.py | 26 ++++++++++++++++++++++++++ 41 files changed, 142 insertions(+), 42 deletions(-) diff --git a/docs/advanced_features.rst b/docs/advanced_features.rst index 81b921a..73100e2 100644 --- a/docs/advanced_features.rst +++ b/docs/advanced_features.rst @@ -67,6 +67,33 @@ the global content manager, so in the above example ``weapons = [my_homebrew.DullSword]`` and ``weapons = ["dull sword"]`` are equivalent. See the :ref:`homebrew example` example for more examples. + +Magic Weapons +------------- + +A common situation is the creation of homebrew weapons. With multiple +inheritance, it is possible to include such a magic weapon as both a +weapon and magic item: + +.. code:: python + + from dungeonsheets import mechanics + + class DullSword(mechanics.Weapon, mechanics.MagicItem): + """This magical sword does remarkably little damage.""" + name = "dull sword" + # Weapon attributes, e.g. + damage_bonus = -1 + attack_bonus = -1 + # Magical item attributes, e.g. + item_type = "weapon" + st_bonus_all = -1 + + weapons = [DullSword] + magic_items = [DullSword] + + + Strings ------- diff --git a/dungeonsheets/character.py b/dungeonsheets/character.py index a076112..f931759 100644 --- a/dungeonsheets/character.py +++ b/dungeonsheets/character.py @@ -562,7 +562,7 @@ class Character(Creature): SuperClass=magic_items.MagicItem, warning_message=msg, ) - self.magic_items.append(ThisMagicItem(owner=self)) + self.magic_items.append(ThisMagicItem(wielder=self)) elif attr == "weapon_proficiencies": self.other_weapon_proficiencies = () msg = 'Magic Item "{}" not defined. Please add it to ``weapons.py``' diff --git a/dungeonsheets/content.py b/dungeonsheets/content.py index 6f79943..6fc37ce 100644 --- a/dungeonsheets/content.py +++ b/dungeonsheets/content.py @@ -5,6 +5,7 @@ import warnings from abc import ABC from pathlib import Path +from dungeonsheets import exceptions from dungeonsheets.stats import Ability, ArmorClass, Initiative, Speed, Skill from dungeonsheets.content_registry import find_content @@ -100,7 +101,13 @@ class Content(ABC): # Create a generic message so we can make a docstring later. msg = f'Mechanic "{mechanic}" not defined. Please add it.' # Create generic mechanic from the factory - class_name = "".join([s.title() for s in mechanic.split("_")]) + try: + class_name = "".join([s.title() for s in mechanic.split("_")]) + except AttributeError: + raise exceptions.InvalidContentType( + f"``{mechanic}`` must either be string-like, " + f"or inherit from {SuperClass}. " + ) mechanic_name = mechanic.replace("_", " ").title() attrs = {"name": mechanic_name, "__doc__": msg, "source": "Unknown"} Mechanic = type(class_name, (SuperClass,), attrs) diff --git a/dungeonsheets/exceptions.py b/dungeonsheets/exceptions.py index 4273f93..628a88a 100644 --- a/dungeonsheets/exceptions.py +++ b/dungeonsheets/exceptions.py @@ -35,3 +35,7 @@ class ContentNotFound(ValueError): class AmbiguousContent(ValueError): """Multiple valid content entries were found.""" + +class InvalidContentType(ValueError): + """Trying to resolve content that is either not a string, or not + related to the acceptable classes.""" diff --git a/dungeonsheets/magic_items.py b/dungeonsheets/magic_items.py index 4f658f2..4700ce9 100644 --- a/dungeonsheets/magic_items.py +++ b/dungeonsheets/magic_items.py @@ -61,8 +61,8 @@ class MagicItem: st_bonus_wisdom: Optional[int] = None st_bonus_charisma: Optional[int] = None - def __init__(self, owner=None): - self.owner = owner + def __init__(self, wielder=None): + self.wielder = wielder def __str__(self): return self.name @@ -430,7 +430,17 @@ class ShieldOfFaces(MagicItem): name = "Shield of Faces" +class GlovesOfThievery(MagicItem): + """These gloves are invisible while worn. While wearing them, you gain + a +5 bonus to Dexterity (Sleight of Hand) checks and Dexterity + checks made to pick locks.""" + name = "Gloves of Thievery" + rarity = "Uncommon" + item_type = "Wondrous item" + + class GlowingSword(MagicItem): + """ This strange longsword glows at odd times. """ diff --git a/dungeonsheets/stats.py b/dungeonsheets/stats.py index d1e6087..c610916 100644 --- a/dungeonsheets/stats.py +++ b/dungeonsheets/stats.py @@ -192,13 +192,15 @@ class Skill: @property def is_proficient(self): # Check for proficiency - proficiencies = [p.replace("_", " ") for p in self.actor.skill_proficiencies] - is_proficient = self.skill_name in proficiencies + proficiencies = [p.replace("_", " ").lower() for p in self.actor.skill_proficiencies] + is_proficient = self.skill_name.lower() in proficiencies return is_proficient @property def is_expertise(self): - return self.skill_name in self.actor.skill_expertise + expertises = [p.replace("_", " ").lower() for p in self.actor.skill_expertise] + is_expertise = self.skill_name.lower() in expertises + return is_expertise @property def proficiency_modifier(self): @@ -218,6 +220,8 @@ class Skill: def modifier(self): ability = getattr(self.actor, self.ability_name) modifier = ability.modifier + self.proficiency_modifier + # if self.skill_name == "deception": + # import pdb; pdb.set_trace() log.info("%s modifier for '%s': %d", self, self.actor.name, modifier) return modifier diff --git a/dungeonsheets/weapons.py b/dungeonsheets/weapons.py index 4df001f..da01a0c 100644 --- a/dungeonsheets/weapons.py +++ b/dungeonsheets/weapons.py @@ -5,6 +5,17 @@ default_content_registry.add_module(__name__) class Weapon: + """A weapon that be used to deal damage. + + Attributes + ========== + + Parameters + ========== + wielder + The character (or NPC) that is using the weapon. + + """ name = "" cost = "0 gp" base_damage = "1d4" diff --git a/examples/artificer1.py b/examples/artificer1.py index 6b43b6e..32b3a78 100644 --- a/examples/artificer1.py +++ b/examples/artificer1.py @@ -55,7 +55,7 @@ feature_choices = () # Weapons/other proficiencies not given by class/race/background weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff') -_proficiencies_text = () # ex: ("thieves' tools",) +proficiencies_text = () # ex: ("thieves' tools",) # Proficiencies and languages languages = """Common, Gnomish""" diff --git a/examples/barbarian1.py b/examples/barbarian1.py index fc61d88..25b6b43 100644 --- a/examples/barbarian1.py +++ b/examples/barbarian1.py @@ -55,7 +55,7 @@ feature_choices = () # Weapons/other proficiencies not given by class/race/background weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff') -_proficiencies_text = () # ex: ("thieves' tools",) +proficiencies_text = () # ex: ("thieves' tools",) # Proficiencies and languages languages = """Draconic, Elvish, Common, Dwarvish""" diff --git a/examples/barbarian2.py b/examples/barbarian2.py index 28d1792..023796c 100644 --- a/examples/barbarian2.py +++ b/examples/barbarian2.py @@ -55,7 +55,7 @@ feature_choices = ('bear aspect', 'tiger spirit', 'elk attunement') # Weapons/other proficiencies not given by class/race/background weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff') -_proficiencies_text = () # ex: ("thieves' tools",) +proficiencies_text = () # ex: ("thieves' tools",) # Proficiencies and languages languages = """Common, Dwarvish""" diff --git a/examples/bard1.py b/examples/bard1.py index f749f06..b3dabe0 100644 --- a/examples/bard1.py +++ b/examples/bard1.py @@ -55,7 +55,7 @@ feature_choices = () # Weapons/other proficiencies not given by class/race/background weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff') -_proficiencies_text = () # ex: ("thieves' tools",) +proficiencies_text = () # ex: ("thieves' tools",) # Proficiencies and languages languages = """Common, Elvish, [choose one]""" diff --git a/examples/bard2.py b/examples/bard2.py index f16cef6..969497b 100644 --- a/examples/bard2.py +++ b/examples/bard2.py @@ -55,7 +55,7 @@ feature_choices = () # Weapons/other proficiencies not given by class/race/background weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff') -_proficiencies_text = () # ex: ("thieves' tools",) +proficiencies_text = () # ex: ("thieves' tools",) # Proficiencies and languages languages = """Common, Elvish""" diff --git a/examples/bloodhunter1.py b/examples/bloodhunter1.py index 5330526..742d543 100644 --- a/examples/bloodhunter1.py +++ b/examples/bloodhunter1.py @@ -57,7 +57,7 @@ feature_choices = () # Weapons/other proficiencies not given by class/race/background weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff') -_proficiencies_text = () # ex: ("thieves' tools",) +proficiencies_text = () # ex: ("thieves' tools",) # Proficiencies and languages languages = """Elvish, Common, Draconic""" diff --git a/examples/cleric1.py b/examples/cleric1.py index d990240..2f6a5e5 100644 --- a/examples/cleric1.py +++ b/examples/cleric1.py @@ -55,7 +55,7 @@ feature_choices = () # Weapons/other proficiencies not given by class/race/background weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff') -_proficiencies_text = () # ex: ("thieves' tools",) +proficiencies_text = () # ex: ("thieves' tools",) # Proficiencies and languages languages = """Common, Elvish""" diff --git a/examples/cleric2.py b/examples/cleric2.py index 37184cc..4487f72 100644 --- a/examples/cleric2.py +++ b/examples/cleric2.py @@ -55,7 +55,7 @@ feature_choices = () # Weapons/other proficiencies not given by class/race/background weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff') -_proficiencies_text = () # ex: ("thieves' tools",) +proficiencies_text = () # ex: ("thieves' tools",) # Proficiencies and languages languages = """Common, Halfling""" diff --git a/examples/druid1.py b/examples/druid1.py index 31dd492..1d313c9 100644 --- a/examples/druid1.py +++ b/examples/druid1.py @@ -55,7 +55,7 @@ feature_choices = () # Weapons/other proficiencies not given by class/race/background weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff') -_proficiencies_text = () # ex: ("thieves' tools",) +proficiencies_text = () # ex: ("thieves' tools",) # Proficiencies and languages languages = """Common, Halfling""" diff --git a/examples/druid2.py b/examples/druid2.py index 5b2294c..0afa106 100644 --- a/examples/druid2.py +++ b/examples/druid2.py @@ -55,7 +55,7 @@ feature_choices = () # Weapons/other proficiencies not given by class/race/background weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff') -_proficiencies_text = () # ex: ("thieves' tools",) +proficiencies_text = () # ex: ("thieves' tools",) # Proficiencies and languages languages = """[choose one], [choose one], Common, [choose one]""" diff --git a/examples/druid3.py b/examples/druid3.py index 651df4b..4048f36 100644 --- a/examples/druid3.py +++ b/examples/druid3.py @@ -55,7 +55,7 @@ feature_choices = ('underdark',) # Weapons/other proficiencies not given by class/race/background weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff') -_proficiencies_text = () # ex: ("thieves' tools",) +proficiencies_text = () # ex: ("thieves' tools",) # Proficiencies and languages languages = """Common, Elvish""" diff --git a/examples/fighter1.py b/examples/fighter1.py index f3d5f59..0cdb867 100644 --- a/examples/fighter1.py +++ b/examples/fighter1.py @@ -57,7 +57,7 @@ feature_choices = () # Weapons/other proficiencies not given by class/race/background weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff') -_proficiencies_text = () # ex: ("thieves' tools",) +proficiencies_text = () # ex: ("thieves' tools",) # Proficiencies and languages languages = """Elvish, Common, Draconic""" diff --git a/examples/fighter2.py b/examples/fighter2.py index 341145c..c150395 100644 --- a/examples/fighter2.py +++ b/examples/fighter2.py @@ -55,7 +55,7 @@ feature_choices = () # Weapons/other proficiencies not given by class/race/background weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff') -_proficiencies_text = () # ex: ("thieves' tools",) +proficiencies_text = () # ex: ("thieves' tools",) # Proficiencies and languages languages = """[choose one], Common, Gnomish""" diff --git a/examples/homebrew.py b/examples/homebrew.py index f2ef0d4..ae3254e 100644 --- a/examples/homebrew.py +++ b/examples/homebrew.py @@ -60,13 +60,15 @@ features = (Juggler, "master_of_ceremonies") feature_choices = () -class DullSword(mechanics.Weapon): +class DullSword(mechanics.Weapon, mechanics.MagicItem): """Bonk things with it.""" name = "Dullsword" + damage_bonus = -1 + # Weapons/other proficiencies not given by class/race/background weapon_proficiencies = (DullSword,) # ex: ('shortsword', 'quarterstaff') -_proficiencies_text = () # ex: ("thieves' tools",) +proficiencies_text = ("dull sword",) # ex: ("thieves' tools",) # Proficiencies and languages languages = """[choose one], Common, Primoridal""" @@ -97,7 +99,7 @@ class LegoShield(mechanics.Shield): weapons = (DullSword, "rusty_shiv", _campaign.BrightSword) # Example: ('shortsword', 'longsword') -magic_items = (RobeOfBreadSummoning, "staff_of_the_arbor_abode") +magic_items = (RobeOfBreadSummoning, "staff_of_the_arbor_abode", DullSword) armor = PlasticArmor # Eg "leather armor" shield = LegoShield # Eg "shield" diff --git a/examples/monk1.py b/examples/monk1.py index ae6ed48..acbf46e 100644 --- a/examples/monk1.py +++ b/examples/monk1.py @@ -57,7 +57,7 @@ feature_choices = () # Weapons/other proficiencies not given by class/race/background weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff') -_proficiencies_text = () # ex: ("thieves' tools",) +proficiencies_text = () # ex: ("thieves' tools",) # Proficiencies and languages languages = """Common, Gnomish""" diff --git a/examples/monk2.py b/examples/monk2.py index 5c8b0f3..1ee0299 100644 --- a/examples/monk2.py +++ b/examples/monk2.py @@ -55,7 +55,7 @@ feature_choices = () # Weapons/other proficiencies not given by class/race/background weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff') -_proficiencies_text = () # ex: ("thieves' tools",) +proficiencies_text = () # ex: ("thieves' tools",) # Proficiencies and languages languages = """Common, Elvish, [choose one]""" diff --git a/examples/multiclass1.py b/examples/multiclass1.py index e46908b..7087c29 100644 --- a/examples/multiclass1.py +++ b/examples/multiclass1.py @@ -55,7 +55,7 @@ feature_choices = ('dueling',) # Weapons/other proficiencies not given by class/race/background weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff') -_proficiencies_text = () # ex: ("thieves' tools",) +proficiencies_text = () # ex: ("thieves' tools",) # Proficiencies and languages languages = """Common, Elvish""" diff --git a/examples/multiclass2.py b/examples/multiclass2.py index 1c12913..770d5d0 100644 --- a/examples/multiclass2.py +++ b/examples/multiclass2.py @@ -55,7 +55,7 @@ feature_choices = () # Weapons/other proficiencies not given by class/race/background weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff') -_proficiencies_text = () # ex: ("thieves' tools",) +proficiencies_text = () # ex: ("thieves' tools",) # Proficiencies and languages languages = """Common, Orc""" diff --git a/examples/paladin1.py b/examples/paladin1.py index bb5bc98..8fe3eec 100644 --- a/examples/paladin1.py +++ b/examples/paladin1.py @@ -55,7 +55,7 @@ feature_choices = ('great-weapon master', ) # Weapons/other proficiencies not given by class/race/background weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff') -_proficiencies_text = () # ex: ("thieves' tools",) +proficiencies_text = () # ex: ("thieves' tools",) # Proficiencies and languages languages = """Dwarvish, Common, Infernal""" diff --git a/examples/paladin2.py b/examples/paladin2.py index 75310c8..83005b9 100644 --- a/examples/paladin2.py +++ b/examples/paladin2.py @@ -55,7 +55,7 @@ feature_choices = ('defense',) # Weapons/other proficiencies not given by class/race/background weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff') -_proficiencies_text = () # ex: ("thieves' tools",) +proficiencies_text = () # ex: ("thieves' tools",) # Proficiencies and languages languages = """Dwarvish, Common, Infernal""" diff --git a/examples/ranger1.py b/examples/ranger1.py index 75d2e91..04eee11 100644 --- a/examples/ranger1.py +++ b/examples/ranger1.py @@ -56,7 +56,7 @@ feature_choices = ('escape the horde', 'archery', 'giant killer', 'volley', # Weapons/other proficiencies not given by class/race/background weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff') -_proficiencies_text = () # ex: ("thieves' tools",) +proficiencies_text = () # ex: ("thieves' tools",) # Proficiencies and languages languages = """Common, Elvish""" diff --git a/examples/ranger2.py b/examples/ranger2.py index 96b59d5..f2e0699 100644 --- a/examples/ranger2.py +++ b/examples/ranger2.py @@ -55,7 +55,7 @@ feature_choices = ('dueling',) # Weapons/other proficiencies not given by class/race/background weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff') -_proficiencies_text = () # ex: ("thieves' tools",) +proficiencies_text = () # ex: ("thieves' tools",) # Proficiencies and languages languages = """Dwarvish, Common, Draconic""" diff --git a/examples/ranger3.py b/examples/ranger3.py index ca50fa8..0ba04c2 100644 --- a/examples/ranger3.py +++ b/examples/ranger3.py @@ -55,7 +55,7 @@ feature_choices = ('two-weapon fighting',) # Weapons/other proficiencies not given by class/race/background weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff') -_proficiencies_text = () # ex: ("thieves' tools",) +proficiencies_text = () # ex: ("thieves' tools",) # Proficiencies and languages languages = """celestial, elvish, Common, Primoridal""" diff --git a/examples/rogue1.py b/examples/rogue1.py index e79cb74..e39eba4 100644 --- a/examples/rogue1.py +++ b/examples/rogue1.py @@ -55,7 +55,7 @@ feature_choices = () # Weapons/other proficiencies not given by class/race/background weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff') -_proficiencies_text = () # ex: ("thieves' tools",) +proficiencies_text = () # ex: ("thieves' tools",) # Proficiencies and languages languages = """[choose one], Common, Aarakocra, Auran""" diff --git a/examples/rogue2.py b/examples/rogue2.py index a00ffa8..d8de953 100644 --- a/examples/rogue2.py +++ b/examples/rogue2.py @@ -55,7 +55,7 @@ feature_choices = () # Weapons/other proficiencies not given by class/race/background weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff') -_proficiencies_text = () # ex: ("thieves' tools",) +proficiencies_text = () # ex: ("thieves' tools",) # Proficiencies and languages languages = """[choose one], Common, Gnomish, Undercommon""" diff --git a/examples/sorceror1.py b/examples/sorceror1.py index 2d9e228..1d69b33 100644 --- a/examples/sorceror1.py +++ b/examples/sorceror1.py @@ -55,7 +55,7 @@ feature_choices = () # Weapons/other proficiencies not given by class/race/background weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff') -_proficiencies_text = () # ex: ("thieves' tools",) +proficiencies_text = () # ex: ("thieves' tools",) # Proficiencies and languages languages = """[choose one], Common, Primordial""" diff --git a/examples/sorceror2.py b/examples/sorceror2.py index e9120cd..c0ec0ae 100644 --- a/examples/sorceror2.py +++ b/examples/sorceror2.py @@ -55,7 +55,7 @@ feature_choices = () # Weapons/other proficiencies not given by class/race/background weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff') -_proficiencies_text = () # ex: ("thieves' tools",) +proficiencies_text = () # ex: ("thieves' tools",) # Proficiencies and languages languages = """[choose one], [choose one], Common, Celestial""" diff --git a/examples/warlock1.py b/examples/warlock1.py index a3c59f2..e82aaab 100644 --- a/examples/warlock1.py +++ b/examples/warlock1.py @@ -57,7 +57,7 @@ feature_choices = ('pact of the blade',) # Weapons/other proficiencies not given by class/race/background weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff') -_proficiencies_text = () # ex: ("thieves' tools",) +proficiencies_text = () # ex: ("thieves' tools",) # Proficiencies and languages languages = """Elvish, Common, Auran""" diff --git a/examples/warlock2.py b/examples/warlock2.py index ac75f7c..837b806 100644 --- a/examples/warlock2.py +++ b/examples/warlock2.py @@ -56,7 +56,7 @@ feature_choices = ('pact of the tome',) # Weapons/other proficiencies not given by class/race/background weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff') -_proficiencies_text = () # ex: ("thieves' tools",) +proficiencies_text = () # ex: ("thieves' tools",) # Proficiencies and languages languages = """Celestial, Dwarvish, Common, Elvish, Giant""" diff --git a/examples/wizard1.py b/examples/wizard1.py index d9913d4..ec9884f 100644 --- a/examples/wizard1.py +++ b/examples/wizard1.py @@ -55,7 +55,7 @@ feature_choices = () # Weapons/other proficiencies not given by class/race/background weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff') -_proficiencies_text = () # ex: ("thieves' tools",) +proficiencies_text = () # ex: ("thieves' tools",) # Proficiencies and languages languages = """[choose one], Common, Primoridal""" diff --git a/examples/wizard2.py b/examples/wizard2.py index fb1d951..78136bb 100644 --- a/examples/wizard2.py +++ b/examples/wizard2.py @@ -55,7 +55,7 @@ feature_choices = () # Weapons/other proficiencies not given by class/race/background weapon_proficiencies = () # ex: ('shortsword', 'quarterstaff') -_proficiencies_text = () # ex: ("thieves' tools",) +proficiencies_text = () # ex: ("thieves' tools",) # Proficiencies and languages languages = """Common, Orc""" diff --git a/tests/test_character.py b/tests/test_character.py index 9cd4fd4..77e4a15 100644 --- a/tests/test_character.py +++ b/tests/test_character.py @@ -10,6 +10,7 @@ from dungeonsheets.character import ( Druid, ) from dungeonsheets.weapons import Weapon, Shortsword +from dungeonsheets.magic_items import MagicItem from dungeonsheets.armor import Armor, LeatherArmor, Shield @@ -43,6 +44,11 @@ class TestCharacter(TestCase): char.set_attrs(armor="leather armor", shield="shield") self.assertFalse(isinstance(char.armor, str)) self.assertFalse(isinstance(char.shield, str)) + # Check that magic item gets set_attrs + MagicWeapon = type("MagicWeapon", (Weapon, MagicItem), + dict(damage_bonus=2, attack_bonus=2, + st_bonus_all=3)) + char.set_attrs(magic_items=[MagicWeapon]) # Check that race gets set to an object char.set_attrs(race="high elf") self.assertIsInstance(char.race, race.HighElf) @@ -51,6 +57,9 @@ class TestCharacter(TestCase): self.assertTrue(char.inspiration) char.set_attrs(inspiration=False) self.assertFalse(char.inspiration) + # Check that proficiencies text gets included + char.set_attrs(proficiencies_text=("dull sword",)) + self.assertIn("dull sword", char.proficiencies_text.lower()) def test_homebrew_spells(self): char = Character() diff --git a/tests/test_magic_items.py b/tests/test_magic_items.py index ab99013..f3add79 100644 --- a/tests/test_magic_items.py +++ b/tests/test_magic_items.py @@ -13,7 +13,7 @@ class MyMagicItem(magic_items.MagicItem): class MagicItemTests(unittest.TestCase): def test_st_bonus_all(self): char = Character() - my_item = MyMagicItem(owner=char) + my_item = MyMagicItem(wielder=char) char.magic_items = [my_item] # Test an item that confers no saving throw bonus bonus = my_item.st_bonus() @@ -25,7 +25,7 @@ class MagicItemTests(unittest.TestCase): def test_st_bonus_by_ability(self): char = Character(strength=10) - my_item = MyMagicItem(owner=char) + my_item = MyMagicItem(wielder=char) char.magic_items = [my_item] # Test an item with nonsense ability with self.assertRaises(AttributeError): diff --git a/tests/test_weapon.py b/tests/test_weapon.py index 65723a2..468c974 100644 --- a/tests/test_weapon.py +++ b/tests/test_weapon.py @@ -1,5 +1,6 @@ import unittest +from dungeonsheets.magic_items import MagicItem from dungeonsheets.weapons import Weapon @@ -11,3 +12,28 @@ class WeaponTestCase(unittest.TestCase): # Now add some bonus damage weapon.damage_bonus = 2 self.assertEqual(weapon.damage, "1d6+2") + + +class MagicWeaponTestCase(unittest.TestCase): + """Check that a magic weapon works as intended.""" + def test_class_inheritance_weapon_first(self): + """Test that the class inheritance works correctly for multiclassing.""" + MagicWeapon = type("MagicWeapon", (Weapon, MagicItem), + dict(damage_bonus=2, attack_bonus=2, + st_bonus_all=3)) + weapon = MagicWeapon(wielder=None) + # CHeck some weapon traits + self.assertEqual(weapon.damage, "1d4+2") + # Check some magic item traits + self.assertEqual(weapon.st_bonus_all, 3) + + def test_class_inheritance_magic_item_first(self): + """Test that the class inheritance works correctly for multiclassing.""" + MagicWeapon = type("MagicWeapon", (MagicItem, Weapon), + dict(damage_bonus=2, attack_bonus=2, + st_bonus_all=3)) + weapon = MagicWeapon(wielder=None) + # CHeck some weapon traits + self.assertEqual(weapon.damage, "1d4+2") + # Check some magic item traits + self.assertEqual(weapon.st_bonus_all, 3)