mirror of
https://github.com/Threnklyn/dungeon-sheets.git
synced 2026-06-05 20:38:26 +02:00
added primary ability and new AC and speed calculations
This commit is contained in:
@@ -9,3 +9,19 @@ Add race / class AC bonuses
|
||||
Add features
|
||||
**hard** integrate features automatically into math
|
||||
Add Inspiration points
|
||||
|
||||
|
||||
Weird features will have to:
|
||||
--Update Speed (Fast Movement / Unarmored Movement)
|
||||
--Access current level and class levels
|
||||
--Give advantage to initiative
|
||||
--Add to proficiencies (Jack of All Trades, Remarkable Athelete)
|
||||
--Double proficiencies (Expertiese)
|
||||
--Add extra skill proficiencies (College of Lore, Blessings of Knowledge...optional)
|
||||
--Add extra proficiencies
|
||||
--Add extra spells known/prepared
|
||||
--Select among multiple options
|
||||
--Select many options (maneuvers)
|
||||
--Update damage / bonus to weapons (Martial Arts)
|
||||
--Add to HP Max (Draconic Bloodline, Dwarven Toughness)
|
||||
|
||||
|
||||
+39
-23
@@ -10,6 +10,7 @@ class Shield():
|
||||
def __repr__(self):
|
||||
return "\"{:s}\"".format(self.name)
|
||||
|
||||
|
||||
class WoodenShield(Shield):
|
||||
name = 'Wooden shield'
|
||||
|
||||
@@ -42,6 +43,8 @@ class Armor():
|
||||
Minimum strength needed to use this armor properly.
|
||||
stealth_disadvantage : bool
|
||||
If true, the armor causes disadvantage on stealth rolls.
|
||||
weight_class : str
|
||||
light, medium, or heavy
|
||||
weight : int
|
||||
In lbs.
|
||||
|
||||
@@ -60,33 +63,46 @@ class Armor():
|
||||
def __repr__(self):
|
||||
return "\"{:s}\"".format(self.name)
|
||||
|
||||
|
||||
class NoArmor(Armor):
|
||||
name = "No armor"
|
||||
|
||||
|
||||
class LightPaddedArmor(Armor):
|
||||
name = "Light padded armor"
|
||||
class LightArmor(Armor):
|
||||
name = "Generic Light Armor"
|
||||
|
||||
|
||||
class MediumArmor(Armor):
|
||||
name = "Generic Medium Armor"
|
||||
|
||||
|
||||
class HeavyArmor(Armor):
|
||||
name = "Generic Heavy Armor"
|
||||
|
||||
|
||||
class PaddedArmor(LightArmor):
|
||||
name = "Padded armor"
|
||||
cost = "5 gp"
|
||||
base_armor_class = 11
|
||||
weight = 8
|
||||
stealth_disadvantage = True
|
||||
|
||||
|
||||
class LeatherArmor(Armor):
|
||||
class LeatherArmor(LightArmor):
|
||||
name = "Leather armor"
|
||||
cost = "10 gp"
|
||||
base_armor_class = 11
|
||||
weight = 10
|
||||
|
||||
|
||||
class StuddedArmor(Armor):
|
||||
name = "Studded armor"
|
||||
class StuddedArmor(LightArmor):
|
||||
name = "Studded leather armor"
|
||||
cost = "45 gp"
|
||||
base_armor_class = 12
|
||||
weight = 13
|
||||
|
||||
|
||||
class HideArmor(Armor):
|
||||
class HideArmor(MediumArmor):
|
||||
name = "Hide armor"
|
||||
cost = "10 gp"
|
||||
base_armor_class = 12
|
||||
@@ -94,16 +110,16 @@ class HideArmor(Armor):
|
||||
weight = 12
|
||||
|
||||
|
||||
class MediumChainShirtArmor(Armor):
|
||||
name = "Medium chain shirt armor"
|
||||
class ChainShirt(MediumArmor):
|
||||
name = "Chain shirt"
|
||||
cost = "50 gp"
|
||||
base_armor_class = 13
|
||||
dexterity_mod_max = 2
|
||||
weight = 20
|
||||
|
||||
|
||||
class MediumScaleMailArmor(Armor):
|
||||
name = "Medium scale mail armor"
|
||||
class ScaleMail(MediumArmor):
|
||||
name = "Scale mail"
|
||||
cost = "50 gp"
|
||||
base_armor_class = 14
|
||||
dexterity_mod_max = 2
|
||||
@@ -111,16 +127,16 @@ class MediumScaleMailArmor(Armor):
|
||||
weight = 45
|
||||
|
||||
|
||||
class MediumBrassplateArmor(Armor):
|
||||
name = "Medium brassplate armor"
|
||||
class Breastplate(MediumArmor):
|
||||
name = "Breastplate"
|
||||
cost = "400 gp"
|
||||
base_armor_class = 14
|
||||
dexterity_mod_max = 2
|
||||
weight = 20
|
||||
|
||||
|
||||
class MediumHalfPlateArmor(Armor):
|
||||
name = "Medium half plate armor"
|
||||
class HalfPlate(MediumArmor):
|
||||
name = "Half Plate"
|
||||
cost = "750 gp"
|
||||
base_armor_class = 15
|
||||
dexterity_mod_max = 2
|
||||
@@ -128,8 +144,8 @@ class MediumHalfPlateArmor(Armor):
|
||||
weight = 40
|
||||
|
||||
|
||||
class HeavyRingMailArmor(Armor):
|
||||
name = "Heavy ring mail armor"
|
||||
class RingMail(HeavyArmor):
|
||||
name = "Ring mail"
|
||||
cost = "30 gp"
|
||||
base_armor_class = 14
|
||||
dexterity_mod_max = 0
|
||||
@@ -137,8 +153,8 @@ class HeavyRingMailArmor(Armor):
|
||||
weight = 40
|
||||
|
||||
|
||||
class HeavyChainMailArmor(Armor):
|
||||
name = "Heavy chain mail armor"
|
||||
class ChainMail(HeavyArmor):
|
||||
name = "Chain Mail"
|
||||
cost = "75 gp"
|
||||
base_armor_class = 16
|
||||
dexterity_mod_max = 0
|
||||
@@ -147,8 +163,8 @@ class HeavyChainMailArmor(Armor):
|
||||
weight = 55
|
||||
|
||||
|
||||
class HeavySplintArmor(Armor):
|
||||
name = "Heavy splint armor"
|
||||
class SplintArmor(HeavyArmor):
|
||||
name = "Splint Armor"
|
||||
cost = "200 gp"
|
||||
base_armor_class = 17
|
||||
dexterity_mod_max = 0
|
||||
@@ -157,8 +173,8 @@ class HeavySplintArmor(Armor):
|
||||
weight = 60
|
||||
|
||||
|
||||
class HeavyPlateArmor(Armor):
|
||||
name = "Heavy plate armor"
|
||||
class PlateMail(HeavyArmor):
|
||||
name = "Plate Mail"
|
||||
cost = "1,500 gp"
|
||||
base_armor_class = 18
|
||||
dexterity_mod_max = 0
|
||||
@@ -168,7 +184,7 @@ class HeavyPlateArmor(Armor):
|
||||
|
||||
|
||||
# Custom Armor
|
||||
class ElvenChain(Armor):
|
||||
class ElvenChain(MediumArmor):
|
||||
name = 'Elven Chain'
|
||||
cost = '5,000 gp'
|
||||
base_armor_class = 14
|
||||
|
||||
@@ -3,6 +3,7 @@ from . import features as feats
|
||||
|
||||
class Background():
|
||||
name = "Generic background"
|
||||
owner = None
|
||||
skill_proficiencies = ()
|
||||
weapon_proficiencies = ()
|
||||
proficiencies_text = ()
|
||||
@@ -11,9 +12,10 @@ class Background():
|
||||
features = ()
|
||||
languages = ()
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, owner):
|
||||
self.owner = owner
|
||||
cls = type(self)
|
||||
self.features = tuple([f() for f in cls.features])
|
||||
self.features = tuple([f(owner=self.owner) for f in cls.features])
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
+20
-37
@@ -9,7 +9,7 @@ import importlib.util
|
||||
import jinja2
|
||||
import subprocess
|
||||
|
||||
from .stats import Ability, Skill, findattr
|
||||
from .stats import Ability, Skill, findattr, ArmorClass, Speed
|
||||
from .dice import read_dice_str
|
||||
from . import (weapons, race, background, spells, armor, monsters,
|
||||
exceptions, classes, features)
|
||||
@@ -75,6 +75,8 @@ class Character():
|
||||
intelligence = Ability()
|
||||
wisdom = Ability()
|
||||
charisma = Ability()
|
||||
armor_class = ArmorClass()
|
||||
speed = Speed()
|
||||
_saving_throw_proficiencies = []
|
||||
other_weapon_proficiencies = tuple()
|
||||
skill_proficiencies = tuple()
|
||||
@@ -117,6 +119,7 @@ class Character():
|
||||
pp = 0
|
||||
equipment = ""
|
||||
weapons = [] # Replaced in __init__ constructor
|
||||
magic_items = []
|
||||
armor = None
|
||||
shield = None
|
||||
_proficiencies_text = tuple()
|
||||
@@ -130,7 +133,6 @@ class Character():
|
||||
|
||||
def __init__(self, **attrs):
|
||||
"""Takes a bunch of attrs and passes them to ``set_attrs``"""
|
||||
self.weapons = []
|
||||
# make sure class, race, background are set first
|
||||
my_classes = attrs.pop('classes', [])
|
||||
my_levels = attrs.pop('levels', [])
|
||||
@@ -164,15 +166,16 @@ class Character():
|
||||
def race(self, newrace):
|
||||
if isinstance(newrace, race.Race):
|
||||
self._race = newrace
|
||||
self._race.owner = self
|
||||
elif isinstance(newrace, type) and issubclass(newrace, race.Race):
|
||||
self._race = newrace()
|
||||
self._race = newrace(owner=self)
|
||||
elif isinstance(newrace, str):
|
||||
try:
|
||||
self._race = findattr(race, newrace)()
|
||||
self._race = findattr(race, newrace)(owner=self)
|
||||
except AttributeError:
|
||||
msg = (f'Race "{newrace}" not defined. '
|
||||
f'Please add it to ``race.py``')
|
||||
self._race = race.Race()
|
||||
self._race = race.Race(owner=self)
|
||||
warnings.warn(msg)
|
||||
|
||||
@property
|
||||
@@ -183,15 +186,16 @@ class Character():
|
||||
def background(self, bg):
|
||||
if isinstance(bg, background.Background):
|
||||
self._background = bg
|
||||
self._background.owner = self
|
||||
elif isinstance(bg, type) and issubclass(bg, background.Background):
|
||||
self._background = bg()
|
||||
self._background = bg(owner=self)
|
||||
elif isinstance(bg, str):
|
||||
try:
|
||||
self._background = findattr(background, bg)()
|
||||
self._background = findattr(background, bg)(owner=self)
|
||||
except AttributeError:
|
||||
msg = (f'Background "{bg}" not defined. '
|
||||
f'Please add it to ``background.py``')
|
||||
self._background = background.Background()
|
||||
self._background = background.Background(owner=self)
|
||||
warnings.warn(msg)
|
||||
|
||||
@property
|
||||
@@ -218,10 +222,6 @@ class Character():
|
||||
def subclasses(self):
|
||||
return list([c.subclass or '' for c in self.class_list])
|
||||
|
||||
@property
|
||||
def speed(self):
|
||||
return getattr(self.race, 'speed', 30)
|
||||
|
||||
@property
|
||||
def level(self):
|
||||
if self.num_classes == 0:
|
||||
@@ -367,9 +367,16 @@ class Character():
|
||||
if attr == 'dungeonsheets_version':
|
||||
pass # Maybe we'll verify this later?
|
||||
elif attr == 'weapons':
|
||||
if isinstance(val, str):
|
||||
val = [val]
|
||||
# Treat weapons specially
|
||||
for weap in val:
|
||||
self.wield_weapon(weap)
|
||||
elif attr == 'magic_items':
|
||||
if isinstance(val, str):
|
||||
val = [val]
|
||||
for mitem in val:
|
||||
self.magic_items.append(mitem(owner=self))
|
||||
elif attr == 'weapon_proficiencies':
|
||||
self.other_weapon_proficiencies = tuple([findattr(weapons, w)
|
||||
for w in val])
|
||||
@@ -398,7 +405,7 @@ class Character():
|
||||
name=f, source='Unknown',
|
||||
__doc__="""Unknown Feature. Add to features.py"""))
|
||||
warnings.warn(msg)
|
||||
self.custom_features += tuple(F() for F in _features)
|
||||
self.custom_features += tuple(F(owner=self) for F in _features)
|
||||
elif (attr == 'spells') or (attr == 'spells_prepared'):
|
||||
# Create a list of actual spell objects
|
||||
_spells = []
|
||||
@@ -600,30 +607,6 @@ class Character():
|
||||
prof = 6
|
||||
return prof
|
||||
|
||||
@property
|
||||
def default_AC(self):
|
||||
"""Armor class, including contributions from worn armor and shield."""
|
||||
# Retrieve current armor (or a generic armor substitute)
|
||||
armor = self.armor if self.armor is not None else NoArmor()
|
||||
shield = self.shield if self.shield is not None else NoShield()
|
||||
# Calculate and apply modifiers
|
||||
if armor.dexterity_mod_max is None:
|
||||
modifier = self.dexterity.modifier
|
||||
else:
|
||||
modifier = min(self.dexterity.modifier, armor.dexterity_mod_max)
|
||||
# Calculate final armor class
|
||||
ac = armor.base_armor_class + shield.base_armor_class + modifier
|
||||
return ac
|
||||
|
||||
@property
|
||||
def armor_class(self):
|
||||
"""Armor class, including any applicable features"""
|
||||
if hasattr(self, 'force_AC'):
|
||||
return self.force_AC
|
||||
ac = [self.default_AC]
|
||||
ac += [f.AC_func(self) for f in self.features]
|
||||
return max(ac)
|
||||
|
||||
def can_assume_shape(self, shape: monsters.Monster):
|
||||
for c in self.class_list:
|
||||
if isinstance(c, classes.Druid):
|
||||
|
||||
@@ -100,7 +100,8 @@ class Barbarian(CharClass):
|
||||
name = 'Barbarian'
|
||||
hit_dice_faces = 12
|
||||
saving_throw_proficiencies = ('strength', 'constitution')
|
||||
weapon_proficiencies = (weapons.simple_weapons + weapons.martial_weapons)
|
||||
primary_abilities = ('strength',)
|
||||
weapon_proficiencies = (weapons.SimpleWeapon + weapons.MartialWearpon)
|
||||
_proficiencies_text = ('light armor', 'medium armor', 'shields',
|
||||
'simple weapons', 'martial weapons')
|
||||
multiclass_weapon_proficiencies = weapon_proficiencies
|
||||
|
||||
@@ -117,12 +117,13 @@ class Bard(CharClass):
|
||||
name = 'Bard'
|
||||
hit_dice_faces = 8
|
||||
saving_throw_proficiencies = ('dexterity', 'charisma')
|
||||
primary_abilities = ('charisma',)
|
||||
_proficiencies_text = (
|
||||
'Light armor', 'simple weapons', 'hand crossbows', 'longswords',
|
||||
'rapiers', 'shortswords', 'three musical instruments of your choice')
|
||||
weapon_proficiencies = ((weapons.HandCrossbow, weapons.Longsword,
|
||||
weapons.Rapier, weapons.Shortsword) +
|
||||
weapons.simple_weapons)
|
||||
weapons.SimpleWeapon)
|
||||
class_skill_choices = ('Acrobatics', 'Animal Handling', 'Arcana',
|
||||
'Athletics', 'Deception', 'History', 'Insight',
|
||||
'Intimidation', 'Investigation', 'Medicine',
|
||||
|
||||
@@ -13,6 +13,8 @@ class CharClass():
|
||||
_proficiencies_text = ()
|
||||
multiclass_weapon_proficiencies = ()
|
||||
_multiclass_proficiencies_text = ()
|
||||
saving_throw_proficiencies = ()
|
||||
primary_abilities = ()
|
||||
languages = ()
|
||||
class_skill_choices = ()
|
||||
num_skill_choices = 2
|
||||
@@ -34,10 +36,10 @@ class CharClass():
|
||||
fs = []
|
||||
for f in cls.features_by_level[i]:
|
||||
if issubclass(f, FeatureSelector):
|
||||
fs.append(f(feature_choices=feature_choices))
|
||||
fs.append(f(owner=self.owner,
|
||||
feature_choices=feature_choices))
|
||||
elif issubclass(f, Feature):
|
||||
fs.append(f())
|
||||
fs = [f() for f in cls.features_by_level[i]]
|
||||
fs.append(f(owner=self.owner))
|
||||
self.features_by_level[i] = fs
|
||||
for k, v in params.items():
|
||||
setattr(self, k, v)
|
||||
@@ -58,14 +60,14 @@ class CharClass():
|
||||
return None
|
||||
for sc in self.subclasses_available:
|
||||
if subclass_str.lower() in sc.name.lower():
|
||||
return sc(level=self.level)
|
||||
return sc(owner=self.owner)
|
||||
return None
|
||||
|
||||
def apply_subclass(self):
|
||||
if self.subclass is None:
|
||||
return
|
||||
for i in range(1, 21):
|
||||
self.features_by_level[i] += ([f() for f in
|
||||
self.features_by_level[i] += ([f(owner=self.owner) for f in
|
||||
self.subclass.features_by_level[i]])
|
||||
for attr in ('weapon_proficiencies', '_proficiencies_text',
|
||||
'spells_known', 'spells_prepared'):
|
||||
@@ -112,9 +114,9 @@ class SubClass():
|
||||
spells_known = ()
|
||||
spells_prepared = ()
|
||||
|
||||
def __init__(self, level):
|
||||
def __init__(self, owner):
|
||||
self.owner = owner
|
||||
self.__doc__ = self.__doc__ or SubClass.__doc__
|
||||
self.level = level
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@@ -184,9 +184,10 @@ class Cleric(CharClass):
|
||||
name = 'Cleric'
|
||||
hit_dice_faces = 8
|
||||
saving_throw_proficiencies = ('wisdom', 'charisma')
|
||||
primary_abilities = ('wisdom',)
|
||||
_proficiencies_text = ('light armor', 'medium armor', 'shields',
|
||||
'all simple weapons')
|
||||
weapon_proficiencies = weapons.simple_weapons
|
||||
weapon_proficiencies = (weapons.SimpleWeapon,)
|
||||
multiclass_weapon_proficiencies = ()
|
||||
_multiclass_proficiencies_text = ('light armor', 'medium armor', 'shields')
|
||||
class_skill_choices = ('History', 'Insight', 'Medicine',
|
||||
|
||||
@@ -87,6 +87,7 @@ class Druid(CharClass):
|
||||
_circle = ''
|
||||
hit_dice_faces = 8
|
||||
saving_throw_proficiencies = ('intelligence', 'wisdom')
|
||||
primary_abilities = ('wisdom',)
|
||||
languages = 'Druidic'
|
||||
_proficiencies_text = (
|
||||
'Light armor', 'medium armor',
|
||||
|
||||
@@ -166,9 +166,10 @@ class Fighter(CharClass):
|
||||
name = 'Fighter'
|
||||
hit_dice_faces = 10
|
||||
saving_throw_proficiencies = ('strength', 'constitution')
|
||||
primary_abilities = ('strength', 'dexterity',)
|
||||
_proficiencies_text = ('All armor', 'shields', 'simple weapons',
|
||||
'martial weapons')
|
||||
weapon_proficiencies = weapons.simple_weapons + weapons.martial_weapons
|
||||
weapon_proficiencies = (weapons.SimpleWeapon, weapons.MartialWeapon)
|
||||
multiclass_weapon_proficiencies = weapon_proficiencies
|
||||
_multiclass_proficiencies_text = ('light armor', 'medium armor',
|
||||
'shields', 'simple weapons',
|
||||
|
||||
@@ -111,10 +111,12 @@ class Monk(CharClass):
|
||||
name = 'Monk'
|
||||
hit_dice_faces = 8
|
||||
saving_throw_proficiencies = ('strength', 'dexterity')
|
||||
primary_abilities = ('dexterity', 'wisdom')
|
||||
_proficiencies_text = (
|
||||
'simple weapons', 'shortswords', 'unarmed',
|
||||
"one type of artisan's tools or one musical instrument")
|
||||
weapon_proficiencies = (weapons.Shortsword, weapons.Unarmed) + weapons.simple_weapons
|
||||
weapon_proficiencies = (weapons.Shortsword, weapons.Unarmed,
|
||||
weapons.SimpleWeapon)
|
||||
multiclass_weapon_proficiencies = weapon_proficiencies
|
||||
_multiclass_proficiencies_text = ('simple weapons', 'shortswords',
|
||||
'unarmed')
|
||||
@@ -125,7 +127,7 @@ class Monk(CharClass):
|
||||
LongDeathWay, DrunkenMasterWay,
|
||||
KenseiWay)
|
||||
features_by_level = defaultdict(list)
|
||||
features_by_level[1] = [features.UnarmoredDefense,
|
||||
features_by_level[1] = [features.UnarmoredDefenseMonk,
|
||||
features.MartialArts]
|
||||
|
||||
def __init__(self, level, subclass=None, **params):
|
||||
|
||||
@@ -223,9 +223,10 @@ class Paladin(CharClass):
|
||||
name = 'Paladin'
|
||||
hit_dice_faces = 10
|
||||
saving_throw_proficiencies = ('wisdom', 'charisma')
|
||||
primary_abilities = ('strength', 'charisma')
|
||||
_proficiencies_text = ('All armor', 'shields', 'simple weapons',
|
||||
'martial weapons')
|
||||
weapon_proficiencies = weapons.simple_weapons + weapons.martial_weapons
|
||||
weapon_proficiencies = (weapons.SimpleWeapon, weapons.MartialWeapon)
|
||||
multiclass_weapon_proficiencies = weapon_proficiencies
|
||||
_multiclass_proficiencies_text = ('light armor', 'medium armor', 'shields',
|
||||
'simple weapons', 'martial weapons')
|
||||
|
||||
@@ -75,9 +75,10 @@ class Ranger(CharClass):
|
||||
name = 'Ranger'
|
||||
hit_dice_faces = 10
|
||||
saving_throw_proficiencies = ('strength', 'dexterity')
|
||||
primary_abilities = ('dexterity', 'wisdom')
|
||||
_proficiencies_text = ("light armor", "medium armor", "shields",
|
||||
"simple weapons", "martial weapons")
|
||||
weapon_proficiencies = weapons.simple_weapons + weapons.martial_weapons
|
||||
weapon_proficiencies = (weapons.SimpleWeapon, weapons.MartialWeapon)
|
||||
multiclass_weapon_proficiencies = weapon_proficiencies
|
||||
_multiclass_proficiencies_text = ('light armor', 'medium armor', 'shields',
|
||||
'simple weapons', 'martial weapons',
|
||||
|
||||
@@ -119,12 +119,13 @@ class Rogue(CharClass):
|
||||
name = 'Rogue'
|
||||
hit_dice_faces = 8
|
||||
saving_throw_proficiencies = ('dexterity', 'intelligence')
|
||||
primary_abilities = ('dexterity',)
|
||||
_proficiencies_text = (
|
||||
'light armor', 'simple weapons', 'hand crossbows', 'longswords',
|
||||
'rapiers', 'shortswords', "thieves' tools")
|
||||
weapon_proficiencies = weapons.simple_weapons + (
|
||||
weapons.HandCrossbow, weapons.Longsword, weapons.Rapier,
|
||||
weapons.Shortsword)
|
||||
weapon_proficiencies = (weapons,SimpleWeapon, weapons.HandCrossbow,
|
||||
weapons.Longsword, weapons.Rapier,
|
||||
weapons.Shortsword)
|
||||
multiclass_weapon_proficiencies = ()
|
||||
_multiclass_proficiencies_text = ('light armor', "thieves' tools",
|
||||
'[choose one skill from Rogue list]')
|
||||
|
||||
@@ -95,6 +95,7 @@ class Sorceror(CharClass):
|
||||
name = 'Sorceror'
|
||||
hit_dice_faces = 6
|
||||
saving_throw_proficiencies = ('constitution', 'charisma')
|
||||
primary_abilities = ('charisma',)
|
||||
_proficiencies_text = ('daggers', 'darts', 'slings',
|
||||
'quarterstaffs', 'light crossbows')
|
||||
weapon_proficiencies = (weapons.Dagger, weapons.Dart,
|
||||
|
||||
@@ -116,11 +116,12 @@ class Warlock(CharClass):
|
||||
name = 'Warlock'
|
||||
hit_dice_faces = 8
|
||||
saving_throw_proficiencies = ('wisdom', 'charisma')
|
||||
primary_abilities = ('charisma',)
|
||||
_proficiencies_text = ("light Armor", "simple weapons")
|
||||
class_skill_choices = ('Arcana', 'Deception', 'History',
|
||||
'Intimidation', 'Investigation', 'Nature',
|
||||
'Religion')
|
||||
weapon_proficiencies = weapons.simple_weapons
|
||||
weapon_proficiencies = (weapons.SimpleWeapon,)
|
||||
multiclass_weapon_proficiencies = weapon_proficiencies
|
||||
_multiclass_proficiencies_text = ('light armor', 'simple weapons')
|
||||
features_by_level = defaultdict(list)
|
||||
|
||||
@@ -160,6 +160,7 @@ class Wizard(CharClass):
|
||||
name = 'Wizard'
|
||||
hit_dice_faces = 6
|
||||
saving_throw_proficiencies = ('intelligence', 'wisdom')
|
||||
primary_abilities = ('intelligence',)
|
||||
_proficiencies_text = ('daggers', 'darts', 'slings',
|
||||
'quarterstaffs', 'light crossbows')
|
||||
weapon_proficiencies = (weapons.Dagger, weapons.Dart,
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
from .features import Feature
|
||||
from .. import (weapons, armor)
|
||||
|
||||
|
||||
class UnarmoredDefenseBarbarian(Feature):
|
||||
"""While you are not wearing any armor, your Armor Class equals 10 + your
|
||||
Dexterity modifier + your Constitution modifier. You can use a shield and
|
||||
still gain this benefit.
|
||||
|
||||
This bonus is computed in the AC given on the Character Sheet above.
|
||||
|
||||
"""
|
||||
name = "Unarmored Defense"
|
||||
source = 'Barbarian'
|
||||
|
||||
|
||||
class FastMovement(Feature):
|
||||
"""Starting at 5th level, your speed increases by 10 feet while you aren’t
|
||||
wearing heavy armor.
|
||||
|
||||
"""
|
||||
name = "Fast Movement"
|
||||
source = "Barbarian"
|
||||
|
||||
@@ -26,11 +26,15 @@ class Feature():
|
||||
Provide full text of rules in documentation
|
||||
"""
|
||||
name = "Generic Feature"
|
||||
owner = None
|
||||
source = '' # race, class, background, etc.
|
||||
spells_known = ()
|
||||
spells_prepared = ()
|
||||
needs_implementation = False # Set to True if need to find way to compute stats
|
||||
|
||||
def __init__(self, owner):
|
||||
self.owner = owner
|
||||
|
||||
def __eq__(self, other):
|
||||
return (self.name == other.name) and (self.source == other.source)
|
||||
|
||||
@@ -62,26 +66,6 @@ class Feature():
|
||||
"""
|
||||
return weapon
|
||||
|
||||
def AC_func(self, char, **kwargs):
|
||||
"""
|
||||
Return the alternative AC from having this feat
|
||||
|
||||
The character will take max AC from all available feats / standard AC,
|
||||
so the default is to output very low AC
|
||||
|
||||
Parameters
|
||||
----------
|
||||
char
|
||||
Character object, to check for necessary abilities, etc.
|
||||
kwargs
|
||||
Any other key-word arguments the function may require
|
||||
|
||||
Returns
|
||||
-------
|
||||
AC : integer armor class from this feature
|
||||
"""
|
||||
return -100
|
||||
|
||||
|
||||
class FeatureSelector(Feature):
|
||||
"""
|
||||
@@ -89,11 +73,13 @@ class FeatureSelector(Feature):
|
||||
"""
|
||||
options = dict()
|
||||
|
||||
def __init__(self, feature_choices=[]):
|
||||
def __init__(self, owner, feature_choices=[]):
|
||||
self.owner = owner
|
||||
keep_source = self.source
|
||||
# Look for matching feature_choices
|
||||
for selection in feature_choices:
|
||||
if selection.lower() in self.options():
|
||||
feature_choices.remove(selection)
|
||||
new_feat = self.options[selection.lower()]
|
||||
self.__dict__.update(new_feat.__dict__)
|
||||
new_feat.__init__(self)
|
||||
|
||||
@@ -2,24 +2,16 @@ from .features import Feature
|
||||
from .. import (weapons, armor)
|
||||
|
||||
|
||||
class UnarmoredDefense(Feature):
|
||||
class UnarmoredDefenseMonk(Feature):
|
||||
"""Beginning at 1st level, while you are wearing no armor and not wearing a
|
||||
shield, your AC equals 10 + your Dexterity modifier + your Wisdom modifier.
|
||||
|
||||
This bonus is computed in the AC given on the Character Sheet above.
|
||||
|
||||
"""
|
||||
name = "Unarmored Defense"
|
||||
source = 'Monk'
|
||||
|
||||
def AC_func(self, char, **kwargs):
|
||||
no_armor = ((char.armor is None)
|
||||
or (isinstance(char.armor, armor.NoAmor)))
|
||||
no_shield = ((char.shield is None)
|
||||
or (isinstance(char.shield, armor.NoShield)))
|
||||
if no_armor and no_shield:
|
||||
return 10 + char.dexterity.modifier + char.wisdom.modifier
|
||||
else:
|
||||
return -100
|
||||
|
||||
|
||||
class MartialArts(Feature):
|
||||
"""At 1st level, your practice of martial arts gives you mastery of combat
|
||||
@@ -50,13 +42,17 @@ class MartialArts(Feature):
|
||||
"""
|
||||
name = "Martial Arts"
|
||||
source = 'Monk'
|
||||
die_by_level = {1: 'd4', 2: 'd4', 3: 'd4', 4: 'd4',
|
||||
5: 'd6', 6: 'd6', 7: 'd6', 8: 'd6',
|
||||
9: 'd6', 10: 'd6', 11: 'd8', 12: 'd8',
|
||||
13: 'd8', 14: 'd8', 15: 'd8', 16: 'd8',
|
||||
17: 'd10', 18: 'd10', 19: 'd10', 20: 'd10'}
|
||||
level = 1
|
||||
|
||||
die = 'd4'
|
||||
|
||||
def __init__(self, owner):
|
||||
self.owner = owner
|
||||
if self.owner.level >= 5:
|
||||
self.die = 'd6'
|
||||
if self.owner.level >= 11:
|
||||
self.die = 'd8'
|
||||
if self.owner.level >= 17:
|
||||
self.die = 'd10'
|
||||
|
||||
def weapon_func(self, weapon: weapons.Weapon, char=None, **kwargs):
|
||||
"""
|
||||
Update increasing damage dice and DEX mod of Monk weapons
|
||||
@@ -68,10 +64,32 @@ class MartialArts(Feature):
|
||||
if char is None:
|
||||
return weapon
|
||||
# check if new damage is better than default
|
||||
new_die = int(self.die_by_level[self.level].strip('d'))
|
||||
if new_die > int(weapon.base_damage.split('d')[-1]):
|
||||
weapon.base_damage = '1d' + str(new_die)
|
||||
if self.die > int(weapon.base_damage.split('d')[-1]):
|
||||
weapon.base_damage = '1d' + str(self.die)
|
||||
weapon.is_finesse = True
|
||||
return weapon
|
||||
|
||||
|
||||
class UnarmoredMovement(Feature):
|
||||
"""Starting at 2nd level, your speed increases by 10 feet while you are not
|
||||
wearing armor or wielding a shield. This bonus increases when you reach
|
||||
certain monk levels, as shown in the Monk table.
|
||||
|
||||
At 9th level, you gain the ability to move along vertical surfaces and
|
||||
across liquids on your turn without falling during the move.
|
||||
|
||||
"""
|
||||
name = "Unarmored Movement"
|
||||
source = "Monk"
|
||||
speed_bonus = 10
|
||||
|
||||
def __init__(self, owner):
|
||||
self.owner = owner
|
||||
if self.owner.level >= 6:
|
||||
self.speed_bonus = 15
|
||||
if self.owner.level >= 10:
|
||||
self.speed_bonus = 20
|
||||
if self.owner.level >= 14:
|
||||
self.speed_bonus = 25
|
||||
if self.owner.level >= 18:
|
||||
self.speed_bonus = 30
|
||||
|
||||
@@ -40,15 +40,6 @@ class Defense(Feature):
|
||||
name = "Fighting Style (Defense)"
|
||||
source = "Ranger"
|
||||
|
||||
def AC_func(self, char, **kwargs):
|
||||
"""
|
||||
Apply a +1 bonus if wearing armor
|
||||
"""
|
||||
if (char.armor is None) or (isinstance(char.armor, armor.NoArmor)):
|
||||
return char.default_AC
|
||||
else:
|
||||
return char.default_AC + 1
|
||||
|
||||
|
||||
class Dueling(Feature):
|
||||
"""When you are wielding a melee weapon in one hand and no other weapons, you
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
from .features import Feature
|
||||
|
||||
|
||||
class DraconicResilience(Feature):
|
||||
"""As magic flows through your body, it causes physical traits of your dragon
|
||||
ancestors to emerge. At 1st level, your hit point maximum increases by 1
|
||||
and increases by 1 again whenever you gain a level in this class.
|
||||
|
||||
Additionally, parts of your skin are covered by a thin sheen of dragon-like
|
||||
scales. When you aren’t wearing armor, your AC equals 13 + your Dexterity
|
||||
modifier.
|
||||
|
||||
This bonus is computed in the AC given on the Character Sheet above.
|
||||
|
||||
"""
|
||||
name = "Draconic Resilience"
|
||||
source = "Sorceror (Draconic Bloodline)"
|
||||
|
||||
@@ -10,9 +10,10 @@ dungeonsheets_version = "{{ char.dungeonsheets_version }}"
|
||||
name = "{{ char.name }}"
|
||||
player_name = "{{ char.player_name }}"
|
||||
|
||||
classes = {{ char.class_names }}
|
||||
levels = {{ char.levels }}
|
||||
subclasses = {{ char.subclasses }}
|
||||
# Be sure to list Primary class first
|
||||
classes = {{ char.class_names }} # ex: ['Wizard'] or ['Rogue', 'Fighter']
|
||||
levels = {{ char.levels }} # ex: [10] or [3, 2]
|
||||
subclasses = {{ char.subclasses }} # ex: ['Necromacy'] or ['Thief', None]
|
||||
background = "{{ char.background.name }}"
|
||||
race = "{{ char.race.name }}"
|
||||
alignment = "{{ char.alignment }}"
|
||||
@@ -28,6 +29,7 @@ wisdom = {{ char.wisdom.value }}
|
||||
charisma = {{ char.charisma.value }}
|
||||
|
||||
# Select what skills you're proficient with
|
||||
# ex: skill_proficiencies = ('athletics', 'acrobatics', 'arcana')
|
||||
skill_proficiencies = {{ char.skill_proficiencies }}
|
||||
|
||||
# Named features / feats that aren't part of your classes,
|
||||
@@ -54,6 +56,7 @@ pp = 0
|
||||
|
||||
# TODO: Put your equipped weapons and armor here
|
||||
weapons = {{ char.weapons }} # Example: ('shortsword', 'longsword')
|
||||
magic_items = {{ char.magic_items }} # Example: ('ring of protection',)
|
||||
armor = "{{ char.armor }}" # Eg "light leather armor"
|
||||
shield = "{{ char.shield }}" # Eg "shield"
|
||||
|
||||
|
||||
@@ -13,9 +13,10 @@ dungeonsheets_version = "{{ char.dungeonsheets_version }}"
|
||||
name = "{{ char.name }}"
|
||||
player_name = "{{ char.player_name }}"
|
||||
|
||||
classes = {{ char.class_names }}
|
||||
levels = {{ char.levels }}
|
||||
subclasses = {{ char.subclasses }}
|
||||
# Be sure to list Primary class first
|
||||
classes = {{ char.class_names }} # ex: ['Wizard'] or ['Rogue', 'Fighter']
|
||||
levels = {{ char.levels }} # ex: [10] or [3, 2]
|
||||
subclasses = {{ char.subclasses }} # ex: ['Necromacy'] or ['Thief', None]
|
||||
background = "{{ char.background.name }}"
|
||||
race = "{{ char.race.name }}"
|
||||
alignment = "{{ char.alignment }}"
|
||||
@@ -31,10 +32,10 @@ wisdom = {{ char.wisdom.value }}
|
||||
charisma = {{ char.charisma.value }}
|
||||
|
||||
# Select what skills you're proficient with
|
||||
# ex: skill_proficiencies = ('athletics', 'acrobatics', 'arcana')
|
||||
skill_proficiencies = {{ char.skill_proficiencies }}
|
||||
|
||||
# Named features / feats that aren't part of your classes,
|
||||
# race, or background.
|
||||
# Named features / feats that aren't part of your classes, race, or background.
|
||||
# Example:
|
||||
# features = ('Tavern Brawler',) # take the optional Feat from PHB
|
||||
features = ()
|
||||
@@ -57,6 +58,7 @@ pp = 0
|
||||
|
||||
# TODO: Put your equipped weapons and armor here
|
||||
weapons = () # Example: ('shortsword', 'longsword')
|
||||
magic_items = () # Example: ('ring of protection',)
|
||||
armor = "" # Eg "light leather armor"
|
||||
shield = "" # Eg "shield"
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
class MagicItem():
|
||||
"""
|
||||
Generic Magic Item. Add description here.
|
||||
|
||||
"""
|
||||
name = ''
|
||||
ac_bonus = 0
|
||||
requires_attunement = False
|
||||
rarity = ''
|
||||
|
||||
|
||||
class RingOfProtection(MagicItem):
|
||||
"""
|
||||
You gain a +1 bonus to AC and Saving Throws while wearing this ring.
|
||||
|
||||
"""
|
||||
name = "Ring of Protection"
|
||||
ac_bonus = 1
|
||||
requires_attunement = True
|
||||
rarity = 'Rare'
|
||||
@@ -7,6 +7,7 @@ class Race():
|
||||
name = "Unknown"
|
||||
size = "medium"
|
||||
speed = 30
|
||||
owner = None
|
||||
languages = ('Common', )
|
||||
proficiencies_text = tuple()
|
||||
weapon_proficiences = tuple()
|
||||
@@ -25,13 +26,14 @@ class Race():
|
||||
spells_known = ()
|
||||
spells_prepared = ()
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, owner):
|
||||
self.owner = owner
|
||||
cls = type(self)
|
||||
# Instantiate the features
|
||||
self.features = tuple([f() for f in cls.features])
|
||||
self.features = tuple([f(owner=self.owner) for f in cls.features])
|
||||
self.features_by_level = defaultdict(list)
|
||||
for i in range(1, 21):
|
||||
self.features_by_level[i] = [f()for f in
|
||||
self.features_by_level[i] = [f(owner=self.owner)for f in
|
||||
cls.features_by_level[i]]
|
||||
|
||||
def __str__(self):
|
||||
|
||||
+68
-5
@@ -1,5 +1,10 @@
|
||||
import math
|
||||
from collections import namedtuple
|
||||
from .armor import NoArmor, NoShield, HeavyArmor
|
||||
from . import (weapons)
|
||||
from .features import (UnarmoredDefenseMonk, UnarmoredDefenseBarbarian,
|
||||
DraconicResilience, Defense, FastMovement,
|
||||
UnarmoredMovement)
|
||||
|
||||
|
||||
def findattr(obj, name):
|
||||
@@ -20,16 +25,18 @@ def findattr(obj, name):
|
||||
raise AttributeError(f'{obj} has no attribute {name}')
|
||||
return attr
|
||||
|
||||
|
||||
def mod_str(modifier):
|
||||
"""Converts a modifier to a string, eg 2 -> '+2'."""
|
||||
if modifier > 0:
|
||||
mod_str = '+' + str(modifier)
|
||||
return '{:+d}'.format(modifier)
|
||||
if modifier == 0:
|
||||
return str(modifier)
|
||||
else:
|
||||
mod_str = str(modifier)
|
||||
return mod_str
|
||||
return '{:+}'.format(modifier)
|
||||
|
||||
|
||||
AbilityScore = namedtuple('AbilityScore', ('value', 'modifier', 'saving_throw'))
|
||||
AbilityScore = namedtuple('AbilityScore',
|
||||
('value', 'modifier', 'saving_throw'))
|
||||
|
||||
|
||||
class Ability():
|
||||
@@ -93,3 +100,59 @@ class Skill():
|
||||
if is_expert:
|
||||
modifier += character.proficiency_bonus
|
||||
return modifier
|
||||
|
||||
|
||||
class ArmorClass():
|
||||
"""
|
||||
The Armor Class of a character
|
||||
"""
|
||||
|
||||
def __get__(self, char, Character):
|
||||
armor = char.armor or NoArmor()
|
||||
ac = armor.base_armor_class
|
||||
shield = char.shield or NoShield()
|
||||
ac += shield.base_armor_class
|
||||
# calculate and apply modifiers
|
||||
if armor.dexterity_mod_max is None:
|
||||
ac += char.dexterity.modifier
|
||||
else:
|
||||
ac += min(char.dexterity.modifier, armor.dexterity_mod_max)
|
||||
# Compute feature-specific additions
|
||||
if any([isinstance(f, UnarmoredDefenseMonk) for f in char.features]):
|
||||
if (isinstance(armor, NoArmor) and isinstance(shield, NoShield)):
|
||||
ac += char.wisdom.modifier
|
||||
if any([isinstance(f, UnarmoredDefenseBarbarian) for f in char.features]):
|
||||
if isinstance(armor, NoArmor):
|
||||
ac += char.constitution.modifier
|
||||
if any([isinstance(f, DraconicResilience) for f in char.features]):
|
||||
if isinstance(armor, NoArmor):
|
||||
ac += 3
|
||||
if any([isinstance(f, Defense) for f in char.features]):
|
||||
if not isinstance(armor, NoArmor):
|
||||
ac += 1
|
||||
# Check if any magic items add to AC
|
||||
for mitem in char.magic_items:
|
||||
if hasattr(mitem, 'ac_bonus'):
|
||||
ac += mitem.ac_bonus
|
||||
return ac
|
||||
|
||||
|
||||
class Speed():
|
||||
"""
|
||||
The speed of a character
|
||||
"""
|
||||
|
||||
def __get__(self, char, Character):
|
||||
base_speed = char.race.speed
|
||||
other_speed = ''
|
||||
if isinstance(base_speed, str):
|
||||
base_speed = int(base_speed[:2]) # ignore other speeds, like fly
|
||||
other_speed = base_speed[2:]
|
||||
if any([isinstance(f, FastMovement) for f in char.features]):
|
||||
if not isinstance(char.armor, HeavyArmor):
|
||||
base_speed += 10
|
||||
if isinstance(char.armor, NoArmor) or (char.armor is None):
|
||||
for f in char.features:
|
||||
if isinstance(f, UnarmoredMovement):
|
||||
base_speed += f.speed_bonus
|
||||
return '{:d}{:s}'.format(base_speed, other_speed)
|
||||
|
||||
+61
-49
@@ -20,18 +20,30 @@ class Weapon():
|
||||
dam_str += mod_str(self.bonus_damage)
|
||||
return dam_str
|
||||
|
||||
@property
|
||||
def is_ranged(self):
|
||||
return ('range' in self.properties.lower()) and ('thrown' not in self.properties.lower())
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def __repr__(self):
|
||||
return "\"{:s}\"".format(self.name)
|
||||
|
||||
|
||||
class MeleeWeapon(Weapon):
|
||||
name = "Melee Weapons"
|
||||
|
||||
|
||||
class RangedWeapon(Weapon):
|
||||
name = "Ranged Weapons"
|
||||
|
||||
|
||||
class SimpleWeapon(Weapon):
|
||||
name = "Simple Weapons"
|
||||
|
||||
|
||||
class MartialWeapon(Weapon):
|
||||
name = "Martial Weapons"
|
||||
|
||||
|
||||
class Club(Weapon):
|
||||
class Club(SimpleWeapon, MeleeWeapon):
|
||||
name = "Club"
|
||||
cost = "1 sp"
|
||||
base_damage = "1d4"
|
||||
@@ -41,7 +53,7 @@ class Club(Weapon):
|
||||
ability = 'strength'
|
||||
|
||||
|
||||
class Dagger(Weapon):
|
||||
class Dagger(SimpleWeapon, MeleeWeapon):
|
||||
name = "Dagger"
|
||||
cost = "2 gp"
|
||||
base_damage = "1d4"
|
||||
@@ -52,7 +64,7 @@ class Dagger(Weapon):
|
||||
ability = 'strength'
|
||||
|
||||
|
||||
class Greatclub(Weapon):
|
||||
class Greatclub(SimpleWeapon, MeleeWeapon):
|
||||
name = "Greatclub"
|
||||
cost = "2 sp"
|
||||
base_damage = "1d8"
|
||||
@@ -62,7 +74,7 @@ class Greatclub(Weapon):
|
||||
ability = 'strength'
|
||||
|
||||
|
||||
class Handaxe(Weapon):
|
||||
class Handaxe(SimpleWeapon, MeleeWeapon):
|
||||
name = "Handaxe"
|
||||
cost = "5 gp"
|
||||
base_damage = "1d6"
|
||||
@@ -72,7 +84,7 @@ class Handaxe(Weapon):
|
||||
ability = 'strength'
|
||||
|
||||
|
||||
class Javelin(Weapon):
|
||||
class Javelin(SimpleWeapon, MeleeWeapon):
|
||||
name = "Javelin"
|
||||
cost = "5 sp"
|
||||
base_damage = "1d6"
|
||||
@@ -82,7 +94,7 @@ class Javelin(Weapon):
|
||||
ability = 'strength'
|
||||
|
||||
|
||||
class LightHammer(Weapon):
|
||||
class LightHammer(SimpleWeapon, MeleeWeapon):
|
||||
name = "Light hammer"
|
||||
cost = "2 gp"
|
||||
base_damage = "1d4"
|
||||
@@ -92,7 +104,7 @@ class LightHammer(Weapon):
|
||||
ability = 'strength'
|
||||
|
||||
|
||||
class Mace(Weapon):
|
||||
class Mace(SimpleWeapon, MeleeWeapon):
|
||||
name = "Mace"
|
||||
cost = "5 gp"
|
||||
base_damage = "1d6"
|
||||
@@ -102,7 +114,7 @@ class Mace(Weapon):
|
||||
ability = 'strength'
|
||||
|
||||
|
||||
class Quarterstaff(Weapon):
|
||||
class Quarterstaff(SimpleWeapon, MeleeWeapon):
|
||||
name = "Quarterstaff"
|
||||
cost = "2 sp"
|
||||
base_damage = "1d6"
|
||||
@@ -112,7 +124,7 @@ class Quarterstaff(Weapon):
|
||||
ability = 'strength'
|
||||
|
||||
|
||||
class Sickle(Weapon):
|
||||
class Sickle(SimpleWeapon, MeleeWeapon):
|
||||
name = "Sickle"
|
||||
cost = "1 gp"
|
||||
base_damage = "1d4"
|
||||
@@ -122,7 +134,7 @@ class Sickle(Weapon):
|
||||
ability = 'strength'
|
||||
|
||||
|
||||
class Spear(Weapon):
|
||||
class Spear(SimpleWeapon, MeleeWeapon):
|
||||
name = "Spear"
|
||||
cost = "1 gp"
|
||||
base_damage = "1d6"
|
||||
@@ -132,7 +144,7 @@ class Spear(Weapon):
|
||||
ability = 'strength'
|
||||
|
||||
|
||||
class LightCrossbow(Weapon):
|
||||
class LightCrossbow(SimpleWeapon, RangedWeapon):
|
||||
name = "Light crossbow"
|
||||
cost = "25 gp"
|
||||
base_damage = "1d8"
|
||||
@@ -142,7 +154,7 @@ class LightCrossbow(Weapon):
|
||||
ability = 'dexterity'
|
||||
|
||||
|
||||
class Dart(Weapon):
|
||||
class Dart(SimpleWeapon, RangedWeapon):
|
||||
name = "Dart"
|
||||
cost = "5 cp"
|
||||
base_damage = "1d4"
|
||||
@@ -153,7 +165,7 @@ class Dart(Weapon):
|
||||
ability = 'dexterity'
|
||||
|
||||
|
||||
class Shortbow(Weapon):
|
||||
class Shortbow(SimpleWeapon, RangedWeapon):
|
||||
name = "Shortbow"
|
||||
cost = "25 gp"
|
||||
base_damage = "1d6"
|
||||
@@ -163,7 +175,7 @@ class Shortbow(Weapon):
|
||||
ability = 'dexterity'
|
||||
|
||||
|
||||
class Sling(Weapon):
|
||||
class Sling(SimpleWeapon, RangedWeapon):
|
||||
name = "Sling"
|
||||
cost = "1 sp"
|
||||
base_damage = "1d4"
|
||||
@@ -173,7 +185,7 @@ class Sling(Weapon):
|
||||
ability = 'dexterity'
|
||||
|
||||
|
||||
class Battleaxe(Weapon):
|
||||
class Battleaxe(MartialWeapon, MeleeWeapon):
|
||||
name = "Battleaxe"
|
||||
cost = "10 gp"
|
||||
base_damage = "1d8"
|
||||
@@ -183,7 +195,7 @@ class Battleaxe(Weapon):
|
||||
ability = 'strength'
|
||||
|
||||
|
||||
class Flail(Weapon):
|
||||
class Flail(MartialWeapon, MeleeWeapon):
|
||||
name = "Flail"
|
||||
cost = "10gp"
|
||||
base_damage = "1d8"
|
||||
@@ -193,7 +205,7 @@ class Flail(Weapon):
|
||||
ability = 'strength'
|
||||
|
||||
|
||||
class Glaive(Weapon):
|
||||
class Glaive(MartialWeapon, MeleeWeapon):
|
||||
name = "Glaive"
|
||||
cost = "20 gp"
|
||||
base_damage = "1d10"
|
||||
@@ -203,7 +215,7 @@ class Glaive(Weapon):
|
||||
ability = 'strength'
|
||||
|
||||
|
||||
class Greataxe(Weapon):
|
||||
class Greataxe(MartialWeapon, MeleeWeapon):
|
||||
name = "Greataxe"
|
||||
cost = "30 gp"
|
||||
base_damage = "1d12"
|
||||
@@ -213,7 +225,7 @@ class Greataxe(Weapon):
|
||||
ability = 'strength'
|
||||
|
||||
|
||||
class Greatsword(Weapon):
|
||||
class Greatsword(MartialWeapon, MeleeWeapon):
|
||||
name = "Greatsword"
|
||||
cost = "50 gp"
|
||||
base_damage = "2d6"
|
||||
@@ -223,7 +235,7 @@ class Greatsword(Weapon):
|
||||
ability = 'strength'
|
||||
|
||||
|
||||
class Halberd(Weapon):
|
||||
class Halberd(MartialWeapon, MeleeWeapon):
|
||||
name = "Halberd"
|
||||
cost = "20 gp"
|
||||
base_damage = "1d10"
|
||||
@@ -233,7 +245,7 @@ class Halberd(Weapon):
|
||||
ability = 'strength'
|
||||
|
||||
|
||||
class Lance(Weapon):
|
||||
class Lance(MartialWeapon, MeleeWeapon):
|
||||
name = "Lance"
|
||||
cost = "10gp"
|
||||
base_damage = "1d12"
|
||||
@@ -243,7 +255,7 @@ class Lance(Weapon):
|
||||
ability = 'strength'
|
||||
|
||||
|
||||
class Longsword(Weapon):
|
||||
class Longsword(MartialWeapon, MeleeWeapon):
|
||||
name = "Longsword"
|
||||
cost = "15 gp"
|
||||
base_damage = "1d8"
|
||||
@@ -253,7 +265,7 @@ class Longsword(Weapon):
|
||||
ability = 'strength'
|
||||
|
||||
|
||||
class Maul(Weapon):
|
||||
class Maul(MartialWeapon, MeleeWeapon):
|
||||
name = "Maul"
|
||||
cost = "10 gp"
|
||||
base_damage = "2d6"
|
||||
@@ -263,7 +275,7 @@ class Maul(Weapon):
|
||||
ability = 'strength'
|
||||
|
||||
|
||||
class Morningstar(Weapon):
|
||||
class Morningstar(MartialWeapon, MeleeWeapon):
|
||||
name = "Morningstar"
|
||||
cost = "15 gp"
|
||||
base_damage = "1d8"
|
||||
@@ -273,7 +285,7 @@ class Morningstar(Weapon):
|
||||
ability = 'strength'
|
||||
|
||||
|
||||
class Pike(Weapon):
|
||||
class Pike(MartialWeapon, MeleeWeapon):
|
||||
name = "Pike"
|
||||
cost = "5 gp"
|
||||
base_damage = "1d10"
|
||||
@@ -283,7 +295,7 @@ class Pike(Weapon):
|
||||
ability = 'strength'
|
||||
|
||||
|
||||
class Rapier(Weapon):
|
||||
class Rapier(MartialWeapon, MeleeWeapon):
|
||||
name = "Rapier"
|
||||
cost = "25 gp"
|
||||
base_damage = "1d8"
|
||||
@@ -294,7 +306,7 @@ class Rapier(Weapon):
|
||||
ability = 'strength'
|
||||
|
||||
|
||||
class Scimitar(Weapon):
|
||||
class Scimitar(MartialWeapon, MeleeWeapon):
|
||||
name = "Scimitar"
|
||||
cost = "25 gp"
|
||||
base_damage = "1d6"
|
||||
@@ -305,7 +317,7 @@ class Scimitar(Weapon):
|
||||
ability = 'strength'
|
||||
|
||||
|
||||
class Shortsword(Weapon):
|
||||
class Shortsword(MartialWeapon, MeleeWeapon):
|
||||
name = "Shortsword"
|
||||
cost = "10 gp"
|
||||
base_damage = "1d6"
|
||||
@@ -316,7 +328,7 @@ class Shortsword(Weapon):
|
||||
ability = 'strength'
|
||||
|
||||
|
||||
class ThrowingHammer(Weapon):
|
||||
class ThrowingHammer(MartialWeapon, MeleeWeapon):
|
||||
name = "Throwing Hammer"
|
||||
cost = "15 gp"
|
||||
base_damage = '1d6'
|
||||
@@ -326,7 +338,7 @@ class ThrowingHammer(Weapon):
|
||||
ability = "strength"
|
||||
|
||||
|
||||
class Trident(Weapon):
|
||||
class Trident(MartialWeapon, MeleeWeapon):
|
||||
name = "Trident"
|
||||
cost = "5 gp"
|
||||
base_damage = "1d6"
|
||||
@@ -336,7 +348,7 @@ class Trident(Weapon):
|
||||
ability = 'strength'
|
||||
|
||||
|
||||
class WarPick(Weapon):
|
||||
class WarPick(MartialWeapon, MeleeWeapon):
|
||||
name = "War pick"
|
||||
cost = "5 gp"
|
||||
base_damage = "1d8"
|
||||
@@ -346,7 +358,7 @@ class WarPick(Weapon):
|
||||
ability = 'strength'
|
||||
|
||||
|
||||
class Warhammer(Weapon):
|
||||
class Warhammer(MartialWeapon, MeleeWeapon):
|
||||
name = "Warhammer"
|
||||
cost = "15 gp"
|
||||
base_damage = "1d8"
|
||||
@@ -356,7 +368,7 @@ class Warhammer(Weapon):
|
||||
ability = 'strength'
|
||||
|
||||
|
||||
class Whip(Weapon):
|
||||
class Whip(MartialWeapon, MeleeWeapon):
|
||||
name = "Whip"
|
||||
cost = "2 gp"
|
||||
base_damage = "1d4"
|
||||
@@ -367,7 +379,7 @@ class Whip(Weapon):
|
||||
ability = 'strength'
|
||||
|
||||
|
||||
class Blowgun(Weapon):
|
||||
class Blowgun(MartialWeapon, RangedWeapon):
|
||||
name = "Blowgun"
|
||||
cost = "10 gp"
|
||||
base_damage = "1"
|
||||
@@ -377,7 +389,7 @@ class Blowgun(Weapon):
|
||||
ability = 'dexterity'
|
||||
|
||||
|
||||
class HandCrossbow(Weapon):
|
||||
class HandCrossbow(MartialWeapon, RangedWeapon):
|
||||
name = "Crossbow, hand"
|
||||
cost = "75 gp"
|
||||
base_damage = "1d6"
|
||||
@@ -387,7 +399,7 @@ class HandCrossbow(Weapon):
|
||||
ability = 'dexterity'
|
||||
|
||||
|
||||
class HeavyCrossbow(Weapon):
|
||||
class HeavyCrossbow(MartialWeapon, RangedWeapon):
|
||||
name = "Crossbow, heavy"
|
||||
cost = "50 gp"
|
||||
base_damage = "1d10"
|
||||
@@ -397,7 +409,7 @@ class HeavyCrossbow(Weapon):
|
||||
ability = 'dexterity'
|
||||
|
||||
|
||||
class Longbow(Weapon):
|
||||
class Longbow(MartialWeapon, RangedWeapon):
|
||||
name = "Longbow"
|
||||
cost = "50 gp"
|
||||
base_damage = "1d8"
|
||||
@@ -407,7 +419,7 @@ class Longbow(Weapon):
|
||||
ability = 'dexterity'
|
||||
|
||||
|
||||
class Net(Weapon):
|
||||
class Net(MartialWeapon, RangedWeapon):
|
||||
name = "Net"
|
||||
cost = "1 gp"
|
||||
base_damage = "-"
|
||||
@@ -417,7 +429,7 @@ class Net(Weapon):
|
||||
ability = 'strength'
|
||||
|
||||
|
||||
class Unarmed(Weapon):
|
||||
class Unarmed(MeleeWeapon):
|
||||
name = "Unarmed"
|
||||
cost = "0 gp"
|
||||
base_damage = "1"
|
||||
@@ -428,7 +440,7 @@ class Unarmed(Weapon):
|
||||
|
||||
|
||||
# Custom weapons
|
||||
class HeavyRight(Weapon):
|
||||
class HeavyRight(MeleeWeapon):
|
||||
base_damage = "1d4"
|
||||
name = "Heavy Right"
|
||||
damage_type = 'b'
|
||||
@@ -436,7 +448,7 @@ class HeavyRight(Weapon):
|
||||
attack_bonus = -5 # Heavy weapon master
|
||||
|
||||
|
||||
class HeavyLeft(Weapon):
|
||||
class HeavyLeft(MeleeWeapon):
|
||||
base_damage = "1d4"
|
||||
name = "Heavy Left"
|
||||
damage_type = 'b'
|
||||
@@ -444,7 +456,7 @@ class HeavyLeft(Weapon):
|
||||
attack_bonus = -5 # Heavy weapon master
|
||||
|
||||
|
||||
class Bite(Weapon):
|
||||
class Bite(MeleeWeapon):
|
||||
name = "Bite"
|
||||
base_damage = "1d4"
|
||||
damage_type = 'p'
|
||||
@@ -454,7 +466,7 @@ class Bite(Weapon):
|
||||
ability = "strength"
|
||||
|
||||
|
||||
class Talons(Weapon):
|
||||
class Talons(MeleeWeapon):
|
||||
name = 'Talons'
|
||||
base_damage = '1d4'
|
||||
damage_type = 's'
|
||||
@@ -464,7 +476,7 @@ class Talons(Weapon):
|
||||
ability = 'strength'
|
||||
|
||||
|
||||
class Claws(Weapon):
|
||||
class Claws(MeleeWeapon):
|
||||
name = 'Claws'
|
||||
base_damage = '1d4'
|
||||
damage_type = 's'
|
||||
@@ -474,7 +486,7 @@ class Claws(Weapon):
|
||||
ability = 'strength'
|
||||
|
||||
|
||||
class Firearm(Weapon):
|
||||
class Firearm(RangedWeapon):
|
||||
name = 'Firearm'
|
||||
ability = 'dexterity'
|
||||
damage_type = 'p'
|
||||
|
||||
Reference in New Issue
Block a user