mirror of
https://github.com/Threnklyn/dungeon-sheets.git
synced 2026-06-07 13:15:53 +02:00
Added saving throws and skills.
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
import re
|
||||
|
||||
from .stats import Stat
|
||||
from .stats import Ability, Skill
|
||||
from .dice import read_dice_str
|
||||
|
||||
dice_re = re.compile('(\d+)d(\d+)')
|
||||
@@ -25,13 +25,33 @@ class Character():
|
||||
# Hit points
|
||||
hp_max = 10
|
||||
hit_dice_faces = 2
|
||||
# Base stats (ability scores
|
||||
strength = Stat()
|
||||
dexterity = Stat()
|
||||
constitution = Stat()
|
||||
intelligence = Stat()
|
||||
wisdom = Stat()
|
||||
charisma = Stat()
|
||||
# Base stats (ability scores)
|
||||
strength = Ability()
|
||||
dexterity = Ability()
|
||||
constitution = Ability()
|
||||
intelligence = Ability()
|
||||
wisdom = Ability()
|
||||
charisma = Ability()
|
||||
saving_throw_proficiencies = []
|
||||
# Skills
|
||||
acrobatics = Skill(ability='dexterity')
|
||||
animal_handling = Skill(ability='wisdom')
|
||||
arcana = Skill(ability='intelligence')
|
||||
athletics = Skill(ability='strength')
|
||||
deception = Skill(ability='charisma')
|
||||
history = Skill(ability='intelligence')
|
||||
insight = Skill(ability='wisdom')
|
||||
intimidation = Skill(ability='charisma')
|
||||
investigation = Skill(ability='intelligence')
|
||||
medicine = Skill(ability='wisdom')
|
||||
nature = Skill(ability='intelligence')
|
||||
perception = Skill(ability='wisdom')
|
||||
performance = Skill(ability='charisma')
|
||||
persuasian = Skill(ability='charisma')
|
||||
religion = Skill(ability='intelligence')
|
||||
sleight_of_hand = Skill(ability='dexterity')
|
||||
stealth = Skill(ability='dexterity')
|
||||
survival = Skill(ability='wisdom')
|
||||
# Inventory
|
||||
cp = 0
|
||||
sp = 0
|
||||
@@ -79,6 +99,7 @@ class Character():
|
||||
class Barbarian(Character):
|
||||
class_name = 'Barbarian'
|
||||
hit_dice_faces = 12
|
||||
saving_throw_proficiencies = ['strength', 'constitution']
|
||||
|
||||
|
||||
class Bard(Character):
|
||||
@@ -119,6 +140,7 @@ class Ranger(Character):
|
||||
class Rogue(Character):
|
||||
class_name = 'Rogue'
|
||||
hit_dice_faces = 8
|
||||
saving_throw_proficiencies = ['dexterity', 'intelligence']
|
||||
|
||||
|
||||
class Sorceror(Character):
|
||||
|
||||
@@ -54,7 +54,7 @@ def create_fdf(character, fdfname):
|
||||
('Race ', character.race),
|
||||
('Alignment', character.alignment),
|
||||
('XP', character.xp),
|
||||
# Attributes
|
||||
# Abilities
|
||||
('ProfBonus', mod_str(character.proficiency_bonus)),
|
||||
('STRmod', str(character.strength.value)),
|
||||
('STR', mod_str(character.strength.modifier)),
|
||||
@@ -71,6 +71,33 @@ def create_fdf(character, fdfname):
|
||||
('AC', character.armor_class),
|
||||
('Initiative', mod_str(character.dexterity.modifier)),
|
||||
('Speed', character.speed),
|
||||
('Passive', 10 + character.perception),
|
||||
# Saving throws (proficiencies handled later)
|
||||
('ST Strength', mod_str(character.strength.saving_throw)),
|
||||
('ST Dexterity', mod_str(character.dexterity.saving_throw)),
|
||||
('ST Constitution', mod_str(character.constitution.saving_throw)),
|
||||
('ST Intelligence', mod_str(character.intelligence.saving_throw)),
|
||||
('ST Wisdom', mod_str(character.wisdom.saving_throw)),
|
||||
('ST Charisma', mod_str(character.charisma.saving_throw)),
|
||||
# Skills (proficiencies handled below)
|
||||
('Acrobatics', mod_str(character.acrobatics)),
|
||||
('Animal', mod_str(character.animal_handling)),
|
||||
('Arcana', mod_str(character.arcana)),
|
||||
('Athletics', mod_str(character.athletics)),
|
||||
('Deception ', mod_str(character.deception)),
|
||||
('History ', mod_str(character.history)),
|
||||
('Insight', mod_str(character.insight)),
|
||||
('Intimidation', mod_str(character.intimidation)),
|
||||
('Investigation ', mod_str(character.investigation)),
|
||||
('Medicine', mod_str(character.medicine)),
|
||||
('Nature', mod_str(character.nature)),
|
||||
('Perception ', mod_str(character.perception)),
|
||||
('Performance', mod_str(character.performance)),
|
||||
('Persuasion', mod_str(character.persuasian)),
|
||||
('Religion', mod_str(character.religion)),
|
||||
('SleightofHand', mod_str(character.sleight_of_hand)),
|
||||
('Stealth ', mod_str(character.stealth)),
|
||||
('Survival', mod_str(character.survival)),
|
||||
# Hit points
|
||||
('HDTotal', character.hit_dice),
|
||||
('HPMax', character.hp_max),
|
||||
@@ -81,6 +108,40 @@ def create_fdf(character, fdfname):
|
||||
('GP', character.gp),
|
||||
('PP', character.pp),
|
||||
]
|
||||
# Check boxes for proficiencies
|
||||
ST_boxes = {
|
||||
'strength': 'Check Box 11',
|
||||
'dexterity': 'Check Box 18',
|
||||
'constitution': 'Check Box 19',
|
||||
'intelligence': 'Check Box 20',
|
||||
'wisdom': 'Check Box 21',
|
||||
'charisma': 'Check Box 22',
|
||||
}
|
||||
for ability in character.saving_throw_proficiencies:
|
||||
fields.append((ST_boxes[ability], 'Yes'))
|
||||
skill_boxes = {
|
||||
'acrobatics': 'Check Box 23',
|
||||
'animal_handling': 'Check Box 24',
|
||||
'arcana': 'Check Box 25',
|
||||
'athletics': 'Check Box 26',
|
||||
'deception': 'Check Box 27',
|
||||
'history': 'Check Box 28',
|
||||
'insight': 'Check Box 29',
|
||||
'intimidation': 'Check Box 30',
|
||||
'investigation': 'Check Box 31',
|
||||
'medicine': 'Check Box 32',
|
||||
'nature': 'Check Box 33',
|
||||
'perception': 'Check Box 34',
|
||||
'performance': 'Check Box 35',
|
||||
'persuasian': 'Check Box 36',
|
||||
'religion': 'Check Box 37',
|
||||
'sleight_of_hand': 'Check Box 38',
|
||||
'stealth': 'Check Box 39',
|
||||
'survival': 'Check Box 40',
|
||||
}
|
||||
for skill in character.skill_proficiencies:
|
||||
fields.append((skill_boxes[skill], 'Yes'))
|
||||
# Create the actual FDF file
|
||||
fdf = forge_fdf("", fields, [], [], [])
|
||||
fdf_file = open(fdfname, "wb")
|
||||
fdf_file.write(fdf)
|
||||
|
||||
+43
-3
@@ -11,15 +11,55 @@ def mod_str(modifier):
|
||||
|
||||
|
||||
|
||||
class Stat():
|
||||
class Ability():
|
||||
value = 10
|
||||
ability_name = None
|
||||
character = None
|
||||
|
||||
def __init__(self, value=10):
|
||||
self.value = value
|
||||
|
||||
def __set_name__(self, character, name):
|
||||
self.ability_name = name
|
||||
|
||||
def __get__(self, character, Character):
|
||||
self.character = character
|
||||
return self
|
||||
|
||||
def __set__(self, obj, val):
|
||||
self.value = val
|
||||
|
||||
@property
|
||||
def modifier(self):
|
||||
return math.floor((self.value - 10) / 2)
|
||||
|
||||
def __set__(self, obj, val):
|
||||
self.value = val
|
||||
@property
|
||||
def saving_throw(self):
|
||||
modifier = self.modifier
|
||||
# Check for proficiency
|
||||
if self.ability_name is not None:
|
||||
is_proficient = (self.ability_name in self.character.saving_throw_proficiencies)
|
||||
if is_proficient:
|
||||
modifier += self.character.proficiency_bonus
|
||||
# Return the value
|
||||
return modifier
|
||||
|
||||
|
||||
class Skill():
|
||||
"""An ability-based skill, such as athletics."""
|
||||
|
||||
def __init__(self, ability):
|
||||
self.ability_name = ability
|
||||
|
||||
def __set_name__(self, character, name):
|
||||
self.skill_name = name
|
||||
self.character = character
|
||||
|
||||
def __get__(self, character, owner):
|
||||
ability = getattr(character, self.ability_name)
|
||||
modifier = ability.modifier
|
||||
# Check for proficiency
|
||||
is_proficient = self.skill_name in character.skill_proficiencies
|
||||
if is_proficient:
|
||||
modifier += character.proficiency_bonus
|
||||
return modifier
|
||||
|
||||
Binary file not shown.
+12
-4
@@ -1,5 +1,5 @@
|
||||
name = 'Mr. Stabby'
|
||||
character_class = 'fighter'
|
||||
character_class = 'rogue'
|
||||
player_name = 'Mark'
|
||||
background = "Criminal"
|
||||
race = "Lightfoot halfling"
|
||||
@@ -10,12 +10,20 @@ hp_max = 19
|
||||
speed = 25
|
||||
|
||||
# Ability Scores
|
||||
strength = 10
|
||||
dexterity = 15
|
||||
strength = 8
|
||||
dexterity = 16
|
||||
constitution = 12
|
||||
intelligence = 13
|
||||
wisdom = 9
|
||||
wisdom = 10
|
||||
charisma = 16
|
||||
skill_proficiencies = [
|
||||
'acrobatics',
|
||||
'deception',
|
||||
'investigation',
|
||||
'performance',
|
||||
'sleight_of_hand',
|
||||
'stealth'
|
||||
]
|
||||
|
||||
# Inventory
|
||||
cp = 950
|
||||
|
||||
@@ -4,6 +4,7 @@ from unittest import TestCase
|
||||
|
||||
from dungeonsheets.character import Character
|
||||
|
||||
|
||||
class TestCharacter(TestCase):
|
||||
"""Tests for the generic character base class."""
|
||||
|
||||
|
||||
+27
-3
@@ -1,6 +1,6 @@
|
||||
from unittest import TestCase
|
||||
|
||||
from dungeonsheets import stats
|
||||
from dungeonsheets import stats, character
|
||||
|
||||
class TestStats(TestCase):
|
||||
|
||||
@@ -9,6 +9,17 @@ class TestStats(TestCase):
|
||||
self.assertEqual(stats.mod_str(0), '0')
|
||||
self.assertEqual(stats.mod_str(2), '+2')
|
||||
|
||||
def test_saving_throw(self):
|
||||
stat = stats.Ability(14)
|
||||
self.assertEqual(stat.saving_throw, 2)
|
||||
# Now try it with an ST proficiency
|
||||
class MyClass():
|
||||
saving_throw_proficiencies = ['strength']
|
||||
proficiency_bonus = 2
|
||||
strength = stats.Ability(14)
|
||||
my_class = MyClass()
|
||||
self.assertEqual(my_class.strength.saving_throw, 4)
|
||||
|
||||
def test_modifier(self):
|
||||
ranges = [
|
||||
((1,), -5),
|
||||
@@ -29,7 +40,7 @@ class TestStats(TestCase):
|
||||
((30,), 10),
|
||||
]
|
||||
# Test the values for each modifier range
|
||||
stat = stats.Stat()
|
||||
stat = stats.Ability()
|
||||
for range_, target in ranges:
|
||||
for value in range_:
|
||||
stat.value = value
|
||||
@@ -40,9 +51,22 @@ class TestStats(TestCase):
|
||||
"""Verify that this class works as a data descriptor."""
|
||||
# Set up a dummy class
|
||||
class MyCharacter():
|
||||
stat = stats.Stat()
|
||||
stat = stats.Ability()
|
||||
char = MyCharacter()
|
||||
# Check that the stat works as expected once set
|
||||
char.stat = 15
|
||||
self.assertEqual(char.stat.value, 15)
|
||||
self.assertEqual(char.stat.modifier, 2)
|
||||
|
||||
def test_skill(self):
|
||||
"""Test for a skill, that depends on another ability."""
|
||||
class MyClass():
|
||||
dexterity = stats.Ability(14)
|
||||
acrobatics = stats.Skill(ability='dexterity')
|
||||
skill_proficiencies = []
|
||||
proficiency_bonus = 2
|
||||
my_class = MyClass()
|
||||
self.assertEqual(my_class.acrobatics, 2)
|
||||
# Check for a proficiency
|
||||
my_class.skill_proficiencies = ['acrobatics']
|
||||
self.assertEqual(my_class.acrobatics, 4)
|
||||
|
||||
Reference in New Issue
Block a user