mirror of
https://github.com/Threnklyn/dungeon-sheets.git
synced 2026-06-07 21:23:31 +02:00
Added basic support for Races and some raw text boxes.
This commit is contained in:
@@ -1,3 +1,9 @@
|
|||||||
|
# Emacs temp files
|
||||||
|
*~
|
||||||
|
|
||||||
|
# Pytest
|
||||||
|
.pytest_cache/
|
||||||
|
|
||||||
# Byte-compiled / optimized / DLL files
|
# Byte-compiled / optimized / DLL files
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.py[cod]
|
*.py[cod]
|
||||||
|
|||||||
+53
-19
@@ -1,10 +1,12 @@
|
|||||||
"""Tools for describing a player character."""
|
"""Tools for describing a player character."""
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
import warnings
|
||||||
|
|
||||||
from .stats import Ability, Skill, findattr
|
from .stats import Ability, Skill, findattr
|
||||||
from .dice import read_dice_str
|
from .dice import read_dice_str
|
||||||
from . import weapons
|
from . import weapons, race
|
||||||
|
from .weapons import Weapon
|
||||||
|
|
||||||
dice_re = re.compile('(\d+)d(\d+)')
|
dice_re = re.compile('(\d+)d(\d+)')
|
||||||
|
|
||||||
@@ -20,9 +22,8 @@ class Character():
|
|||||||
background = ""
|
background = ""
|
||||||
level = 1
|
level = 1
|
||||||
alignment = "Neutral"
|
alignment = "Neutral"
|
||||||
race = "Human"
|
race = None
|
||||||
xp = 0
|
xp = 0
|
||||||
speed = 30 # In feet
|
|
||||||
# Hit points
|
# Hit points
|
||||||
hp_max = 10
|
hp_max = 10
|
||||||
hit_dice_faces = 2
|
hit_dice_faces = 2
|
||||||
@@ -35,7 +36,7 @@ class Character():
|
|||||||
charisma = Ability()
|
charisma = Ability()
|
||||||
saving_throw_proficiencies = []
|
saving_throw_proficiencies = []
|
||||||
skill_proficiencies = tuple()
|
skill_proficiencies = tuple()
|
||||||
weapon_proficienies = tuple()
|
weapon_proficiencies = tuple()
|
||||||
proficiencies_extra = tuple()
|
proficiencies_extra = tuple()
|
||||||
languages = ""
|
languages = ""
|
||||||
# Skills
|
# Skills
|
||||||
@@ -58,10 +59,12 @@ class Character():
|
|||||||
stealth = Skill(ability='dexterity')
|
stealth = Skill(ability='dexterity')
|
||||||
survival = Skill(ability='wisdom')
|
survival = Skill(ability='wisdom')
|
||||||
# Characteristics
|
# Characteristics
|
||||||
|
attacks_and_spellcasting = ""
|
||||||
personality_traits = ""
|
personality_traits = ""
|
||||||
ideals = ""
|
ideals = ""
|
||||||
bonds = ""
|
bonds = ""
|
||||||
flaws = ""
|
flaws = ""
|
||||||
|
features_and_traits = ""
|
||||||
# Inventory
|
# Inventory
|
||||||
cp = 0
|
cp = 0
|
||||||
sp = 0
|
sp = 0
|
||||||
@@ -77,6 +80,16 @@ class Character():
|
|||||||
self.weapons = []
|
self.weapons = []
|
||||||
self.set_attrs(**attrs)
|
self.set_attrs(**attrs)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"<{self.class_name}: {self.name}>"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def speed(self):
|
||||||
|
return self.race.speed
|
||||||
|
|
||||||
def set_attrs(self, **attrs):
|
def set_attrs(self, **attrs):
|
||||||
"""Bulk setting of attributes. Useful for loading a character from a
|
"""Bulk setting of attributes. Useful for loading a character from a
|
||||||
dictionary."""
|
dictionary."""
|
||||||
@@ -85,6 +98,9 @@ class Character():
|
|||||||
# Treat weapons specially
|
# Treat weapons specially
|
||||||
for weap in val:
|
for weap in val:
|
||||||
self.wield_weapon(weap)
|
self.wield_weapon(weap)
|
||||||
|
elif attr == 'race':
|
||||||
|
MyRace = findattr(race, val)
|
||||||
|
self.race = MyRace()
|
||||||
else:
|
else:
|
||||||
if not hasattr(self, attr):
|
if not hasattr(self, attr):
|
||||||
warnings.warn(f"Setting unknown character attribute {attr}",
|
warnings.warn(f"Setting unknown character attribute {attr}",
|
||||||
@@ -92,10 +108,29 @@ class Character():
|
|||||||
# Lookup general attributes
|
# Lookup general attributes
|
||||||
setattr(self, attr, val)
|
setattr(self, attr, val)
|
||||||
|
|
||||||
|
def is_proficient(self, weapon: Weapon):
|
||||||
|
"""Is the character proficient with this item?
|
||||||
|
|
||||||
|
Considers class proficiencies and race proficiencies.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
weapon
|
||||||
|
The weapon to be tested for proficiency.
|
||||||
|
|
||||||
|
"""
|
||||||
|
all_proficiencies = tuple(self.weapon_proficiencies)
|
||||||
|
all_proficiencies += tuple(getattr(self.race, 'weapon_proficiencies', tuple()))
|
||||||
|
is_proficient = any((isinstance(weapon, W) for W in all_proficiencies))
|
||||||
|
return is_proficient
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def proficiencies_text(self):
|
def proficiencies_text(self):
|
||||||
final_text = ""
|
final_text = ""
|
||||||
all_proficiencies = (self._proficiencies_text + self.proficiencies_extra)
|
all_proficiencies = self._proficiencies_text
|
||||||
|
if self.race is not None:
|
||||||
|
all_proficiencies += self.race.proficiencies_text
|
||||||
|
all_proficiencies += self.proficiencies_extra
|
||||||
# Create a single string out of all the proficiencies
|
# Create a single string out of all the proficiencies
|
||||||
for txt in all_proficiencies:
|
for txt in all_proficiencies:
|
||||||
if not final_text:
|
if not final_text:
|
||||||
@@ -133,8 +168,7 @@ class Character():
|
|||||||
weapon_.attack_bonus += ability_mod
|
weapon_.attack_bonus += ability_mod
|
||||||
weapon_.bonus_damage += ability_mod
|
weapon_.bonus_damage += ability_mod
|
||||||
# Check for prifiency
|
# Check for prifiency
|
||||||
is_proficient = (weapon_.__class__ in self.weapon_proficienies)
|
if self.is_proficient(weapon_):
|
||||||
if is_proficient:
|
|
||||||
weapon_.attack_bonus += self.proficiency_bonus
|
weapon_.attack_bonus += self.proficiency_bonus
|
||||||
# Save it to the array
|
# Save it to the array
|
||||||
self.weapons.append(weapon_)
|
self.weapons.append(weapon_)
|
||||||
@@ -172,7 +206,7 @@ class Barbarian(Character):
|
|||||||
saving_throw_proficiencies = ('strength', 'constitution')
|
saving_throw_proficiencies = ('strength', 'constitution')
|
||||||
_proficiencies_text = ('light armor', 'medium armor', 'shields',
|
_proficiencies_text = ('light armor', 'medium armor', 'shields',
|
||||||
'simple weapons', 'martial weapons')
|
'simple weapons', 'martial weapons')
|
||||||
weapon_proficienies = (weapons.simple_weapons + weapons.martial_weapons)
|
weapon_proficiencies = (weapons.simple_weapons + weapons.martial_weapons)
|
||||||
|
|
||||||
|
|
||||||
class Bard(Character):
|
class Bard(Character):
|
||||||
@@ -182,7 +216,7 @@ class Bard(Character):
|
|||||||
_proficiencies_text = (
|
_proficiencies_text = (
|
||||||
'Light armor', 'simple weapons', 'hand crossbows', 'longswords',
|
'Light armor', 'simple weapons', 'hand crossbows', 'longswords',
|
||||||
'rapiers', 'shortswords', 'three musical instruments of your choice')
|
'rapiers', 'shortswords', 'three musical instruments of your choice')
|
||||||
weapon_proficienies = ((weapons.HandCrossbow, weapons.Longsword,
|
weapon_proficiencies = ((weapons.HandCrossbow, weapons.Longsword,
|
||||||
weapons.Rapier, weapons.Shortsword) +
|
weapons.Rapier, weapons.Shortsword) +
|
||||||
weapons.simple_weapons)
|
weapons.simple_weapons)
|
||||||
|
|
||||||
@@ -193,7 +227,7 @@ class Cleric(Character):
|
|||||||
saving_throw_proficiencies = ('wisdom', 'charisma')
|
saving_throw_proficiencies = ('wisdom', 'charisma')
|
||||||
_proficiencies_text = ('light armor', 'medium armor', 'shields',
|
_proficiencies_text = ('light armor', 'medium armor', 'shields',
|
||||||
'all simple weapons')
|
'all simple weapons')
|
||||||
weapon_proficienies = weapons.simple_weapons
|
weapon_proficiencies = weapons.simple_weapons
|
||||||
|
|
||||||
|
|
||||||
class Druid(Character):
|
class Druid(Character):
|
||||||
@@ -205,7 +239,7 @@ class Druid(Character):
|
|||||||
'shields (druids will not wear armor or use shields made of metal)',
|
'shields (druids will not wear armor or use shields made of metal)',
|
||||||
'clubs', 'daggers', 'darts', 'javelins', 'maces', 'quarterstaffs',
|
'clubs', 'daggers', 'darts', 'javelins', 'maces', 'quarterstaffs',
|
||||||
'scimitars', 'sickles', 'slings', 'spears')
|
'scimitars', 'sickles', 'slings', 'spears')
|
||||||
weapon_proficienies = (weapons.Club, weapons.Dagger, weapons.Dart,
|
weapon_proficiencies = (weapons.Club, weapons.Dagger, weapons.Dart,
|
||||||
weapons.Javelin, weapons.Mace, weapons.Quarterstaff,
|
weapons.Javelin, weapons.Mace, weapons.Quarterstaff,
|
||||||
weapons.Scimitar, weapons.Sickle, weapons.Sling, weapons.Spear)
|
weapons.Scimitar, weapons.Sickle, weapons.Sling, weapons.Spear)
|
||||||
|
|
||||||
@@ -215,7 +249,7 @@ class Fighter(Character):
|
|||||||
hit_dice_faces = 10
|
hit_dice_faces = 10
|
||||||
saving_throw_proficiencies = ('strength', 'constitution')
|
saving_throw_proficiencies = ('strength', 'constitution')
|
||||||
_proficiencies_text = ('All armar', 'shields', 'simple weapons', 'martial weapons')
|
_proficiencies_text = ('All armar', 'shields', 'simple weapons', 'martial weapons')
|
||||||
weapon_proficienies = weapons.simple_weapons + weapons.martial_weapons
|
weapon_proficiencies = weapons.simple_weapons + weapons.martial_weapons
|
||||||
|
|
||||||
|
|
||||||
class Monk(Character):
|
class Monk(Character):
|
||||||
@@ -225,7 +259,7 @@ class Monk(Character):
|
|||||||
_proficiencies_text = (
|
_proficiencies_text = (
|
||||||
'simple weapons', 'shortswords',
|
'simple weapons', 'shortswords',
|
||||||
"one type of artisan's tools or one musical instrument")
|
"one type of artisan's tools or one musical instrument")
|
||||||
weapon_proficienies = (weapons.Shortsword,) + weapons.simple_weapons
|
weapon_proficiencies = (weapons.Shortsword,) + weapons.simple_weapons
|
||||||
|
|
||||||
|
|
||||||
class Paladin(Character):
|
class Paladin(Character):
|
||||||
@@ -234,7 +268,7 @@ class Paladin(Character):
|
|||||||
saving_throw_proficiencies = ('wisdom', 'charisma')
|
saving_throw_proficiencies = ('wisdom', 'charisma')
|
||||||
_proficiencies_text = ('All armor', 'shields', 'simple weapons',
|
_proficiencies_text = ('All armor', 'shields', 'simple weapons',
|
||||||
'martial weapons')
|
'martial weapons')
|
||||||
weapon_proficienies = weapons.simple_weapons + weapons.martial_weapons
|
weapon_proficiencies = weapons.simple_weapons + weapons.martial_weapons
|
||||||
|
|
||||||
|
|
||||||
class Ranger(Character):
|
class Ranger(Character):
|
||||||
@@ -243,7 +277,7 @@ class Ranger(Character):
|
|||||||
saving_throw_proficiencies = ('strength', 'dexterity')
|
saving_throw_proficiencies = ('strength', 'dexterity')
|
||||||
_proficiencies_text = ("light armor", "medium armor", "shields",
|
_proficiencies_text = ("light armor", "medium armor", "shields",
|
||||||
"simple weapons", "martial weapons")
|
"simple weapons", "martial weapons")
|
||||||
weapon_proficienies = weapons.simple_weapons + weapons.martial_weapons
|
weapon_proficiencies = weapons.simple_weapons + weapons.martial_weapons
|
||||||
|
|
||||||
|
|
||||||
class Rogue(Character):
|
class Rogue(Character):
|
||||||
@@ -253,7 +287,7 @@ class Rogue(Character):
|
|||||||
_proficiencies_text = (
|
_proficiencies_text = (
|
||||||
'light armor', 'simple weapons', 'hand crossbows', 'longswords',
|
'light armor', 'simple weapons', 'hand crossbows', 'longswords',
|
||||||
'rapiers', 'shortswords', "thieves' tools")
|
'rapiers', 'shortswords', "thieves' tools")
|
||||||
weapon_proficienies = (weapons.HandCrossbow, weapons.Longsword,
|
weapon_proficiencies = (weapons.HandCrossbow, weapons.Longsword,
|
||||||
weapons.Rapier, weapons.Shortsword) + weapons.simple_weapons
|
weapons.Rapier, weapons.Shortsword) + weapons.simple_weapons
|
||||||
|
|
||||||
|
|
||||||
@@ -263,7 +297,7 @@ class Sorceror(Character):
|
|||||||
saving_throw_proficiencies = ('constitution', 'charisma')
|
saving_throw_proficiencies = ('constitution', 'charisma')
|
||||||
_proficiencies_text = ('daggers', 'darts', 'slings',
|
_proficiencies_text = ('daggers', 'darts', 'slings',
|
||||||
'quarterstaffs', 'light crossbows')
|
'quarterstaffs', 'light crossbows')
|
||||||
weapon_proficienies = (weapons.Dagger, weapons.Dart,
|
weapon_proficiencies = (weapons.Dagger, weapons.Dart,
|
||||||
weapons.Sling, weapons.Quarterstaff,
|
weapons.Sling, weapons.Quarterstaff,
|
||||||
weapons.LightCrossbow)
|
weapons.LightCrossbow)
|
||||||
|
|
||||||
@@ -273,7 +307,7 @@ class Warlock(Character):
|
|||||||
hit_dice_faces = 8
|
hit_dice_faces = 8
|
||||||
saving_throw_proficiencies = ('wisdom', 'charisma')
|
saving_throw_proficiencies = ('wisdom', 'charisma')
|
||||||
_proficiencies_text = ("light Armor", "simple weapons")
|
_proficiencies_text = ("light Armor", "simple weapons")
|
||||||
weapon_proficienies = weapons.simple_weapons
|
weapon_proficiencies = weapons.simple_weapons
|
||||||
|
|
||||||
|
|
||||||
class Wizard(Character):
|
class Wizard(Character):
|
||||||
@@ -282,6 +316,6 @@ class Wizard(Character):
|
|||||||
saving_throw_proficiencies = ('intelligence', 'wisdom')
|
saving_throw_proficiencies = ('intelligence', 'wisdom')
|
||||||
_proficiencies_text = ('daggers', 'darts', 'slings',
|
_proficiencies_text = ('daggers', 'darts', 'slings',
|
||||||
'quarterstaffs', 'light crossbows')
|
'quarterstaffs', 'light crossbows')
|
||||||
weapon_proficienies = (weapons.Dagger, weapons.Dart,
|
weapon_proficiencies = (weapons.Dagger, weapons.Dart,
|
||||||
weapons.Sling, weapons.Quarterstaff,
|
weapons.Sling, weapons.Quarterstaff,
|
||||||
weapons.LightCrossbow)
|
weapons.LightCrossbow)
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ def create_fdf(character, fdfname):
|
|||||||
('ClassLevel', class_level),
|
('ClassLevel', class_level),
|
||||||
('Background', character.background),
|
('Background', character.background),
|
||||||
('PlayerName', character.player_name),
|
('PlayerName', character.player_name),
|
||||||
('Race ', character.race),
|
('Race ', str(character.race)),
|
||||||
('Alignment', character.alignment),
|
('Alignment', character.alignment),
|
||||||
('XP', character.xp),
|
('XP', character.xp),
|
||||||
# Abilities
|
# Abilities
|
||||||
@@ -111,11 +111,13 @@ def create_fdf(character, fdfname):
|
|||||||
# Hit points
|
# Hit points
|
||||||
('HDTotal', character.hit_dice),
|
('HDTotal', character.hit_dice),
|
||||||
('HPMax', character.hp_max),
|
('HPMax', character.hp_max),
|
||||||
# Personality traits
|
# Personality traits and other features
|
||||||
('PersonalityTraits ', text_box(character.personality_traits)),
|
('PersonalityTraits ', text_box(character.personality_traits)),
|
||||||
('Ideals', text_box(character.ideals)),
|
('Ideals', text_box(character.ideals)),
|
||||||
('Bonds', text_box(character.bonds)),
|
('Bonds', text_box(character.bonds)),
|
||||||
('Flaws', text_box(character.flaws)),
|
('Flaws', text_box(character.flaws)),
|
||||||
|
('AttacksSpellcasting', text_box(character.attacks_and_spellcasting)),
|
||||||
|
('Features and Traits', text_box(character.features_and_traits)),
|
||||||
# Inventory
|
# Inventory
|
||||||
('CP', character.cp),
|
('CP', character.cp),
|
||||||
('SP', character.sp),
|
('SP', character.sp),
|
||||||
|
|||||||
@@ -0,0 +1,124 @@
|
|||||||
|
from . import weapons
|
||||||
|
|
||||||
|
class Race():
|
||||||
|
name = "Unknown"
|
||||||
|
size = "medium"
|
||||||
|
speed = 30
|
||||||
|
proficiencies_text = tuple()
|
||||||
|
weapon_proficiences = tuple()
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"<self.name>"
|
||||||
|
|
||||||
|
|
||||||
|
# Dwarves
|
||||||
|
class Dwarf(Race):
|
||||||
|
name = "Dwarf"
|
||||||
|
size = "medium"
|
||||||
|
speed = 25
|
||||||
|
proficiencies_text = ('battleaxes', 'handaxes', 'throwing hammers', 'warhammers')
|
||||||
|
weapon_proficiences = (weapons.Battleaxe, weapons.Handaxe,
|
||||||
|
weapons.ThrowingHammer, weapons.Warhammer)
|
||||||
|
|
||||||
|
|
||||||
|
class HillDwarf(Dwarf):
|
||||||
|
name = "Hill Dwarf"
|
||||||
|
|
||||||
|
|
||||||
|
class MountainDwarf(Dwarf):
|
||||||
|
name = "Mountain Dwarf"
|
||||||
|
|
||||||
|
|
||||||
|
# Elves
|
||||||
|
class Elf(Race):
|
||||||
|
name = "Elf"
|
||||||
|
size = "medium"
|
||||||
|
speed = 30
|
||||||
|
|
||||||
|
|
||||||
|
class HighElf(Elf):
|
||||||
|
name = "High Elf"
|
||||||
|
weapon_proficiencies = (weapons.Longsword, weapons.Shortsword,
|
||||||
|
weapons.Shortbow, weapons.Longbow)
|
||||||
|
proficiencies_text = ('longswords', 'shortswords', 'shortbows', 'longbows')
|
||||||
|
|
||||||
|
|
||||||
|
class WoodElf(Elf):
|
||||||
|
name = "Wood Elf"
|
||||||
|
weapon_proficiencies = (weapons.Longsword, weapons.Shortsword,
|
||||||
|
weapons.Shortbow, weapons.Longbow)
|
||||||
|
proficiencies_text = ('longswords', 'shortswords', 'shortbows', 'longbows')
|
||||||
|
|
||||||
|
|
||||||
|
class DarkElf(Elf):
|
||||||
|
name = "Dark Elf"
|
||||||
|
weapon_proficiencies = (weapons.Rapier, weapons.Shortsword, weapons.HandCrossbow)
|
||||||
|
proficiencies_text = ('repiers', 'shortswords', 'hand crossbows')
|
||||||
|
|
||||||
|
|
||||||
|
# Halflings
|
||||||
|
class Halfling(Race):
|
||||||
|
name = "Halfling"
|
||||||
|
size = "small"
|
||||||
|
speed = 25
|
||||||
|
|
||||||
|
|
||||||
|
class LightfootHalfling(Halfling):
|
||||||
|
name = "Lightfoot Halfling"
|
||||||
|
|
||||||
|
|
||||||
|
class StoutHalfling(Halfling):
|
||||||
|
name = "Stout Halfling"
|
||||||
|
|
||||||
|
|
||||||
|
# Humans
|
||||||
|
class Human(Race):
|
||||||
|
name = "Human"
|
||||||
|
size = "medium"
|
||||||
|
speed = 30
|
||||||
|
|
||||||
|
|
||||||
|
# Dragonborn
|
||||||
|
class Dragonborn(Race):
|
||||||
|
name = "Dragonborn"
|
||||||
|
size = "medium"
|
||||||
|
speed = 30
|
||||||
|
|
||||||
|
|
||||||
|
# Gnomes
|
||||||
|
class Gnome(Race):
|
||||||
|
name = "Gnome"
|
||||||
|
size = "small"
|
||||||
|
speed = 25
|
||||||
|
|
||||||
|
|
||||||
|
class ForestGnome(Gnome):
|
||||||
|
name = "Forest Gnome"
|
||||||
|
|
||||||
|
|
||||||
|
class RockGnome(Gnome):
|
||||||
|
name = "Rock Gnome"
|
||||||
|
|
||||||
|
|
||||||
|
# Half-elves
|
||||||
|
class HalfElf(Race):
|
||||||
|
name = "Half-Elf"
|
||||||
|
size = "medium"
|
||||||
|
speed = 30
|
||||||
|
|
||||||
|
|
||||||
|
# Half-Orcs
|
||||||
|
class HalfOrc(Race):
|
||||||
|
name = "Half-Orc"
|
||||||
|
size = "medium"
|
||||||
|
speed = 30
|
||||||
|
|
||||||
|
|
||||||
|
# Tielflings
|
||||||
|
class Tiefling(Race):
|
||||||
|
name = "Tiefling"
|
||||||
|
size = "medium"
|
||||||
|
speed = 30
|
||||||
@@ -305,6 +305,16 @@ class Shortsword(Weapon):
|
|||||||
ability = 'strength'
|
ability = 'strength'
|
||||||
|
|
||||||
|
|
||||||
|
class ThrowingHammer(Weapon):
|
||||||
|
name = "Throwing Hammer"
|
||||||
|
cost = "15 gp"
|
||||||
|
base_damage = '1d6'
|
||||||
|
damage_type = "bludgeoning"
|
||||||
|
weight = 4
|
||||||
|
properties = "Thrown (range 60/120)"
|
||||||
|
ability = "strength"
|
||||||
|
|
||||||
|
|
||||||
class Trident(Weapon):
|
class Trident(Weapon):
|
||||||
name = "Trident"
|
name = "Trident"
|
||||||
cost = "5 gp"
|
cost = "5 gp"
|
||||||
@@ -403,8 +413,10 @@ simple_ranged_weapons = (LightCrossbow, Dart, Shortbow, Sling)
|
|||||||
simple_weapons = simple_melee_weapons + simple_ranged_weapons
|
simple_weapons = simple_melee_weapons + simple_ranged_weapons
|
||||||
|
|
||||||
martial_melee_weapons = (Battleaxe, Flail, Glaive, Greataxe,
|
martial_melee_weapons = (Battleaxe, Flail, Glaive, Greataxe,
|
||||||
Greatsword, Halberd, Lance, Longsword, Maul, Morningstar, Pike,
|
Greatsword, Halberd, Lance, Longsword, Maul,
|
||||||
Rapier, Scimitar, Shortsword, Trident, WarPick, Warhammer, Whip)
|
Morningstar, Pike, Rapier, Scimitar,
|
||||||
|
Shortsword, ThrowingHammer, Trident, WarPick,
|
||||||
|
Warhammer, Whip)
|
||||||
martial_ranged_weapons = (Blowgun, HandCrossbow, HeavyCrossbow,
|
martial_ranged_weapons = (Blowgun, HandCrossbow, HeavyCrossbow,
|
||||||
Longbow, Net)
|
Longbow, Net)
|
||||||
martial_weapons = martial_melee_weapons + martial_ranged_weapons
|
martial_weapons = martial_melee_weapons + martial_ranged_weapons
|
||||||
|
|||||||
Binary file not shown.
+39
-1
@@ -7,7 +7,6 @@ level = 3
|
|||||||
alignment = "Neutral"
|
alignment = "Neutral"
|
||||||
xp = 1984
|
xp = 1984
|
||||||
hp_max = 19
|
hp_max = 19
|
||||||
speed = 25
|
|
||||||
|
|
||||||
# Ability Scores
|
# Ability Scores
|
||||||
strength = 8
|
strength = 8
|
||||||
@@ -41,6 +40,45 @@ equipment = (
|
|||||||
tinderbox, waterskin, crowbar, set of dark common clothes
|
tinderbox, waterskin, crowbar, set of dark common clothes
|
||||||
including a hood, pouch.""")
|
including a hood, pouch.""")
|
||||||
|
|
||||||
|
attacks_and_spellcasting = (
|
||||||
|
"""Sneak Attack: Once per turn, when you hit a creature with a
|
||||||
|
Dexterity-based attack (such as with your shortsword or shortbow)
|
||||||
|
and you have advantage on the attack roll, you can deal an extra
|
||||||
|
1d6 damage to your target. You don’t need advantage if another
|
||||||
|
enemy of the target is within 5 feet of it and isn’t
|
||||||
|
incapacitated. You can’t deal the extra damage, however, if you
|
||||||
|
have disadvantage on the attack roll.""")
|
||||||
|
|
||||||
|
features_and_traits = (
|
||||||
|
"""Thieves' Cant: You know thieves’ cant, a secret mix of dialect,
|
||||||
|
jargon, and code that allows you to hide messages in seemingly
|
||||||
|
normal conversation. You also understand a set of secret signs and
|
||||||
|
symbols used to convey short, simple messages, such as whether an
|
||||||
|
area is dangerous, whether loot is nearby, or whether the people
|
||||||
|
in an area are easy marks or will provide a safe house for thieves
|
||||||
|
on the run.
|
||||||
|
|
||||||
|
Lucky: When you roll a natural 1 on an attack roll, ability check,
|
||||||
|
or saving throw, you can reroll the die and must use the new roll.
|
||||||
|
|
||||||
|
Brave: You have advantage on saving throws against being
|
||||||
|
frightened.
|
||||||
|
|
||||||
|
Halfling Nimbleness: You can move through the space of any
|
||||||
|
creature that is of a size larger than yours.
|
||||||
|
|
||||||
|
Naturally Stealthy: You can attempt to hide when you are obscured
|
||||||
|
by a creature that is at least one size larger than you.
|
||||||
|
|
||||||
|
Criminal Contact: You have a contact who acts as your liaison to a
|
||||||
|
network of other criminals. You know how to get messages to and
|
||||||
|
from your contact, even over great distances; you know the local
|
||||||
|
messengers, corrupt caravan masters, and seedy sailors who can
|
||||||
|
carry messages for you. You can move secret information or stolen
|
||||||
|
goods through your contact in exchange for money or other
|
||||||
|
information you seek.""")
|
||||||
|
|
||||||
|
|
||||||
# Backstory
|
# Backstory
|
||||||
personality_traits = """I never have a plan, but I’m great at making things up as I go
|
personality_traits = """I never have a plan, but I’m great at making things up as I go
|
||||||
along. Also, the best way to get me to do something is to tell me I
|
along. Also, the best way to get me to do something is to tell me I
|
||||||
|
|||||||
+37
-2
@@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
|
|
||||||
from dungeonsheets.character import Character
|
from dungeonsheets import race
|
||||||
|
from dungeonsheets.character import Character, Wizard
|
||||||
from dungeonsheets.weapons import Weapon, Shortsword
|
from dungeonsheets.weapons import Weapon, Shortsword
|
||||||
|
|
||||||
|
|
||||||
@@ -27,11 +28,14 @@ class TestCharacter(TestCase):
|
|||||||
char.set_attrs(weapons=['shortsword'])
|
char.set_attrs(weapons=['shortsword'])
|
||||||
self.assertEqual(len(char.weapons), 1)
|
self.assertEqual(len(char.weapons), 1)
|
||||||
self.assertTrue(isinstance(char.weapons[0], Shortsword))
|
self.assertTrue(isinstance(char.weapons[0], Shortsword))
|
||||||
|
# Check that race gets set to an object
|
||||||
|
char.set_attrs(race='high elf')
|
||||||
|
self.assertIsInstance(char.race, race.HighElf)
|
||||||
|
|
||||||
def test_wield_weapon(self):
|
def test_wield_weapon(self):
|
||||||
char = Character()
|
char = Character()
|
||||||
char.strength = 14
|
char.strength = 14
|
||||||
char.weapon_proficienies = [Shortsword]
|
char.weapon_proficiencies = [Shortsword]
|
||||||
# Add a weapon
|
# Add a weapon
|
||||||
char.wield_weapon('shortsword')
|
char.wield_weapon('shortsword')
|
||||||
self.assertEqual(len(char.weapons), 1)
|
self.assertEqual(len(char.weapons), 1)
|
||||||
@@ -46,6 +50,32 @@ class TestCharacter(TestCase):
|
|||||||
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_bonus, 5) # dex + prof
|
||||||
|
# Check if race weapon proficiencies are considered
|
||||||
|
char.weapons = []
|
||||||
|
char.weapon_proficiencies = []
|
||||||
|
char.race = race.HighElf()
|
||||||
|
char.wield_weapon('shortsword')
|
||||||
|
sword = char.weapons[0]
|
||||||
|
self.assertEqual(sword.attack_bonus, 5)
|
||||||
|
|
||||||
|
def test_str(self):
|
||||||
|
char = Wizard(name="Inara")
|
||||||
|
self.assertEqual(str(char), 'Inara')
|
||||||
|
self.assertEqual(repr(char), '<Wizard: Inara>')
|
||||||
|
|
||||||
|
def test_is_proficient(self):
|
||||||
|
char = Character()
|
||||||
|
char.weapon_proficiencies
|
||||||
|
sword = Shortsword()
|
||||||
|
# Check for not-proficient weapon
|
||||||
|
self.assertFalse(char.is_proficient(sword))
|
||||||
|
# Check if we're proficient in the weapon
|
||||||
|
char.weapon_proficiencies = [Shortsword]
|
||||||
|
self.assertTrue(char.is_proficient(sword))
|
||||||
|
# Now try it with a racial proficiency
|
||||||
|
char.weapon_proficiencies = tuple()
|
||||||
|
char.race = race.HighElf()
|
||||||
|
self.assertTrue(char.is_proficient(sword))
|
||||||
|
|
||||||
def test_proficiencies_text(self):
|
def test_proficiencies_text(self):
|
||||||
char = Character()
|
char = Character()
|
||||||
@@ -54,6 +84,11 @@ class TestCharacter(TestCase):
|
|||||||
# Check for extra proficiencies
|
# Check for extra proficiencies
|
||||||
char.proficiencies_extra = ("it's", "me")
|
char.proficiencies_extra = ("it's", "me")
|
||||||
self.assertEqual(char.proficiencies_text, "Hello, world, it's, me.")
|
self.assertEqual(char.proficiencies_text, "Hello, world, it's, me.")
|
||||||
|
# Check that race proficienceis are included
|
||||||
|
elf = race.HighElf()
|
||||||
|
char.race = elf
|
||||||
|
expected = "Hello, world, longswords, shortswords, shortbows, longbows, it's, me."
|
||||||
|
self.assertEqual(char.proficiencies_text, expected)
|
||||||
|
|
||||||
def test_proficiency_bonus(self):
|
def test_proficiency_bonus(self):
|
||||||
char = Character()
|
char = Character()
|
||||||
|
|||||||
Reference in New Issue
Block a user