mirror of
https://github.com/Threnklyn/dungeon-sheets.git
synced 2026-06-07 21:23:31 +02:00
updated how weapons are handled
This commit is contained in:
@@ -617,30 +617,17 @@ class Character():
|
|||||||
"""
|
"""
|
||||||
# Retrieve the weapon class from the weapons module
|
# Retrieve the weapon class from the weapons module
|
||||||
if isinstance(weapon, weapons.Weapon):
|
if isinstance(weapon, weapons.Weapon):
|
||||||
weapon_ = type(weapon)()
|
weapon_ = type(weapon)(wielder=self)
|
||||||
elif isinstance(weapon, str):
|
elif isinstance(weapon, str):
|
||||||
try:
|
try:
|
||||||
NewWeapon = findattr(weapons, weapon)
|
NewWeapon = findattr(weapons, weapon)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise AttributeError(f'Weapon "{weapon}" is not defined')
|
raise AttributeError(f'Weapon "{weapon}" is not defined')
|
||||||
weapon_ = NewWeapon()
|
weapon_ = NewWeapon(wielder=self)
|
||||||
elif issubclass(weapon, weapons.Weapon):
|
elif issubclass(weapon, weapons.Weapon):
|
||||||
weapon_ = weapon()
|
weapon_ = weapon(wielder=self)
|
||||||
else:
|
else:
|
||||||
raise AttributeError(f'Weapon "{weapon}" is not defined')
|
raise AttributeError(f'Weapon "{weapon}" is not defined')
|
||||||
# check if features add any bonuses
|
|
||||||
for f in self.features:
|
|
||||||
weapon_ = f.weapon_func(weapon_)
|
|
||||||
# Set weapon attributes based on character
|
|
||||||
if weapon_.is_finesse:
|
|
||||||
ability_mod = max(self.strength.modifier, self.dexterity.modifier)
|
|
||||||
else:
|
|
||||||
ability_mod = getattr(self, weapon_.ability).modifier
|
|
||||||
weapon_.attack_bonus += ability_mod
|
|
||||||
weapon_.bonus_damage += ability_mod
|
|
||||||
# Check for prifiency
|
|
||||||
if self.is_proficient(weapon_):
|
|
||||||
weapon_.attack_bonus += self.proficiency_bonus
|
|
||||||
# Save it to the array
|
# Save it to the array
|
||||||
self.weapons.append(weapon_)
|
self.weapons.append(weapon_)
|
||||||
|
|
||||||
|
|||||||
@@ -59,14 +59,8 @@ class Feature():
|
|||||||
The weapon to be tested for special bonuses
|
The weapon to be tested for special bonuses
|
||||||
kwargs
|
kwargs
|
||||||
Any other key-word arguments the function may require
|
Any other key-word arguments the function may require
|
||||||
|
|
||||||
Returns
|
|
||||||
-------
|
|
||||||
weapon
|
|
||||||
Updated weapon (perhaps changed damage bonus, etc.)
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return weapon
|
pass
|
||||||
|
|
||||||
|
|
||||||
class FeatureSelector(Feature):
|
class FeatureSelector(Feature):
|
||||||
|
|||||||
@@ -64,7 +64,6 @@ class MartialArts(Feature):
|
|||||||
if int(self.die[1:]) > int(weapon.base_damage.split('d')[-1]):
|
if int(self.die[1:]) > int(weapon.base_damage.split('d')[-1]):
|
||||||
weapon.base_damage = '1' + str(self.die)
|
weapon.base_damage = '1' + str(self.die)
|
||||||
weapon.is_finesse = True
|
weapon.is_finesse = True
|
||||||
return weapon
|
|
||||||
|
|
||||||
|
|
||||||
class Ki(Feature):
|
class Ki(Feature):
|
||||||
|
|||||||
@@ -72,7 +72,6 @@ class Archery(Feature):
|
|||||||
"""
|
"""
|
||||||
if isinstance(weapon, weapons.RangedWeapon):
|
if isinstance(weapon, weapons.RangedWeapon):
|
||||||
weapon.attack_bonus += 2
|
weapon.attack_bonus += 2
|
||||||
return weapon
|
|
||||||
|
|
||||||
|
|
||||||
class Defense(Feature):
|
class Defense(Feature):
|
||||||
@@ -98,8 +97,7 @@ class Dueling(Feature):
|
|||||||
"""
|
"""
|
||||||
if (isinstance(weapon, weapons.MeleeWeapon)
|
if (isinstance(weapon, weapons.MeleeWeapon)
|
||||||
and "two-handed" not in weapon.properties.lower()):
|
and "two-handed" not in weapon.properties.lower()):
|
||||||
weapon.bonus_damage += 2
|
weapon.damage_bonus += 2
|
||||||
return weapon
|
|
||||||
|
|
||||||
|
|
||||||
class TwoWeaponFighting(Feature):
|
class TwoWeaponFighting(Feature):
|
||||||
|
|||||||
@@ -468,14 +468,13 @@ class HexWarrior(Feature):
|
|||||||
it is higher than STR/DEX bonus
|
it is higher than STR/DEX bonus
|
||||||
"""
|
"""
|
||||||
if weapon.is_finesse:
|
if weapon.is_finesse:
|
||||||
existing_mod = max(self.owner.strength.modifier,
|
abils = {'strength': self.owner.strength.modifier,
|
||||||
self.owner.dexterity.modifier)
|
'dexterity': self.owner.dexterity.modifier,
|
||||||
|
'charisma': self.owner.charisma.modifier}
|
||||||
else:
|
else:
|
||||||
existing_mod = self.owner.strength.modifier
|
abils = {weapon.ability: getattr(self.owner, weapon.ability).modifier,
|
||||||
cha_mod = self.owner.charisma.modifier
|
'charisma': self.owner.charisma.modifier}
|
||||||
if cha_mod > existing_mod:
|
weapon.ability = max(abils, key=abils.get)
|
||||||
weapon.attack_bonus += (cha_mod - existing_mod)
|
|
||||||
return weapon
|
|
||||||
|
|
||||||
|
|
||||||
class AccursedSpecter(Feature):
|
class AccursedSpecter(Feature):
|
||||||
@@ -958,11 +957,9 @@ class ImprovedPactWeapon(Invocation):
|
|||||||
"""
|
"""
|
||||||
Add +1 to attack and damage if magic is not already magic
|
Add +1 to attack and damage if magic is not already magic
|
||||||
"""
|
"""
|
||||||
if weapon.magic_bonus <= 1:
|
if (weapon.attack_bonus == 0) or (weapon.bonus_damage == 0):
|
||||||
weapon.magic_bonus = 1
|
|
||||||
weapon.attack_bonus += 1
|
weapon.attack_bonus += 1
|
||||||
weapon.bonus_damage += 1
|
weapon.bonus_damage += 1
|
||||||
return weapon
|
|
||||||
|
|
||||||
|
|
||||||
class LanceOfLethargy(Invocation):
|
class LanceOfLethargy(Invocation):
|
||||||
|
|||||||
@@ -308,7 +308,7 @@ def create_character_pdf(character, basename, flatten=False):
|
|||||||
for _fields, weapon in zip(weapon_fields, character.weapons):
|
for _fields, weapon in zip(weapon_fields, character.weapons):
|
||||||
name_field, atk_field, dmg_field = _fields
|
name_field, atk_field, dmg_field = _fields
|
||||||
fields[name_field] = weapon.name
|
fields[name_field] = weapon.name
|
||||||
fields[atk_field] = '{:+d}'.format(weapon.attack_bonus)
|
fields[atk_field] = '{:+d}'.format(weapon.attack_modifier)
|
||||||
fields[dmg_field] = f'{weapon.damage}/{weapon.damage_type}'
|
fields[dmg_field] = f'{weapon.damage}/{weapon.damage_type}'
|
||||||
# Other attack information
|
# Other attack information
|
||||||
attack_str = f'Armor: {character.armor}'
|
attack_str = f'Armor: {character.armor}'
|
||||||
|
|||||||
+43
-10
@@ -2,24 +2,54 @@ class Weapon():
|
|||||||
name = ""
|
name = ""
|
||||||
cost = "0 gp"
|
cost = "0 gp"
|
||||||
base_damage = "1d4"
|
base_damage = "1d4"
|
||||||
bonus_damage = 0
|
damage_bonus = 0
|
||||||
damage_type = "p"
|
|
||||||
attack_bonus = 0
|
attack_bonus = 0
|
||||||
magic_bonus = 0
|
damage_type = "p"
|
||||||
weight = 1 # In lbs
|
weight = 1 # In lbs
|
||||||
properties = "Light"
|
properties = ""
|
||||||
ability = 'strength'
|
ability = 'strength'
|
||||||
is_finesse = False
|
is_finesse = False
|
||||||
|
features_applied = False
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, wielder=None):
|
||||||
self.attack_bonus += self.magic_bonus
|
self.wielder = wielder
|
||||||
self.bonus_damage += self.magic_bonus
|
|
||||||
|
def apply_features(self):
|
||||||
|
if (not self.features_applied) and (self.wielder is not None):
|
||||||
|
self.features_applied = True
|
||||||
|
for f in self.wielder.features:
|
||||||
|
f.weapon_func(self)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ability_mod(self):
|
||||||
|
if self.wielder is None:
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
if self.is_finesse:
|
||||||
|
return max(self.wielder.strength.modifier,
|
||||||
|
self.wielder.dexterity.modifier)
|
||||||
|
else:
|
||||||
|
return getattr(self.wielder, self.ability).modifier
|
||||||
|
|
||||||
|
@property
|
||||||
|
def attack_modifier(self):
|
||||||
|
self.apply_features()
|
||||||
|
mod = self.attack_bonus
|
||||||
|
if self.wielder is not None:
|
||||||
|
mod += self.ability_mod
|
||||||
|
if self.wielder.is_proficient(self):
|
||||||
|
mod += self.wielder.proficiency_bonus
|
||||||
|
return mod
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def damage(self):
|
def damage(self):
|
||||||
|
self.apply_features()
|
||||||
dam_str = str(self.base_damage)
|
dam_str = str(self.base_damage)
|
||||||
if self.bonus_damage != 0:
|
bonus = self.damage_bonus
|
||||||
dam_str += '{:+d}'.format(self.bonus_damage)
|
if self.wielder is not None:
|
||||||
|
bonus += self.ability_mod
|
||||||
|
if bonus != 0:
|
||||||
|
dam_str += '{:+d}'.format(bonus)
|
||||||
return dam_str
|
return dam_str
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
@@ -31,10 +61,12 @@ class Weapon():
|
|||||||
|
|
||||||
class MeleeWeapon(Weapon):
|
class MeleeWeapon(Weapon):
|
||||||
name = "Melee Weapons"
|
name = "Melee Weapons"
|
||||||
|
ability = 'strength'
|
||||||
|
|
||||||
|
|
||||||
class RangedWeapon(Weapon):
|
class RangedWeapon(Weapon):
|
||||||
name = "Ranged Weapons"
|
name = "Ranged Weapons"
|
||||||
|
ability = 'dexterity'
|
||||||
|
|
||||||
|
|
||||||
class SimpleWeapon(Weapon):
|
class SimpleWeapon(Weapon):
|
||||||
@@ -523,7 +555,8 @@ class Musket(Firearm):
|
|||||||
# Magic Items
|
# Magic Items
|
||||||
class FlameTongue(Greatsword):
|
class FlameTongue(Greatsword):
|
||||||
name = "Flame Tongue +1"
|
name = "Flame Tongue +1"
|
||||||
magic_bonus = 1
|
damage_bonus = 1
|
||||||
|
attack_bonus = 1
|
||||||
base_damage = "4d6"
|
base_damage = "4d6"
|
||||||
damage_type = 'f'
|
damage_type = 'f'
|
||||||
|
|
||||||
|
|||||||
@@ -48,21 +48,21 @@ class TestCharacter(TestCase):
|
|||||||
sword = char.weapons[0]
|
sword = char.weapons[0]
|
||||||
self.assertTrue(isinstance(sword, Weapon))
|
self.assertTrue(isinstance(sword, Weapon))
|
||||||
self.assertTrue(isinstance(sword, Shortsword))
|
self.assertTrue(isinstance(sword, Shortsword))
|
||||||
self.assertEqual(sword.attack_bonus, 4) # str + prof
|
self.assertEqual(sword.attack_modifier, 4) # str + prof
|
||||||
self.assertEqual(sword.bonus_damage, 2) # str
|
self.assertEqual(sword.damage, '1d6+2') # str
|
||||||
# Check if dexterity is used if it's higher (Finesse weapon)
|
# Check if dexterity is used if it's higher (Finesse weapon)
|
||||||
char.weapons = []
|
char.weapons = []
|
||||||
char.dexterity = 16
|
char.dexterity = 16
|
||||||
char.wield_weapon('shortsword')
|
char.wield_weapon('shortsword')
|
||||||
sword = char.weapons[0]
|
sword = char.weapons[0]
|
||||||
self.assertEqual(sword.attack_bonus, 5) # dex + prof
|
self.assertEqual(sword.attack_modifier, 5) # dex + prof
|
||||||
# Check if race weapon proficiencies are considered
|
# Check if race weapon proficiencies are considered
|
||||||
char.weapons = []
|
char.weapons = []
|
||||||
char.weapon_proficiencies = []
|
char.weapon_proficiencies = []
|
||||||
char.race = race.HighElf()
|
char.race = race.HighElf()
|
||||||
char.wield_weapon('shortsword')
|
char.wield_weapon('shortsword')
|
||||||
sword = char.weapons[0]
|
sword = char.weapons[0]
|
||||||
self.assertEqual(sword.attack_bonus, 5)
|
self.assertEqual(sword.attack_modifier, 5)
|
||||||
|
|
||||||
def test_str(self):
|
def test_str(self):
|
||||||
char = Wizard(name="Inara")
|
char = Wizard(name="Inara")
|
||||||
|
|||||||
@@ -9,5 +9,5 @@ class WeaponTestCase(unittest.TestCase):
|
|||||||
weapon.base_damage = '1d6'
|
weapon.base_damage = '1d6'
|
||||||
self.assertEqual(weapon.damage, '1d6')
|
self.assertEqual(weapon.damage, '1d6')
|
||||||
# Now add some bonus damage
|
# Now add some bonus damage
|
||||||
weapon.bonus_damage = 2
|
weapon.damage_bonus = 2
|
||||||
self.assertEqual(weapon.damage, '1d6+2')
|
self.assertEqual(weapon.damage, '1d6+2')
|
||||||
|
|||||||
Reference in New Issue
Block a user