Some more advanced characteristics, different player classes, and a CLI interface.

This commit is contained in:
Mark Wolfman
2018-03-25 23:59:48 -05:00
parent 7862d14c9d
commit d680cdc296
9 changed files with 183 additions and 56 deletions
+90 -12
View File
@@ -16,15 +16,15 @@ class Character():
name = ""
class_name = ""
player_name = ""
background = ""
level = 1
alignment = 'true neutral'
alignment = "Neutral"
race = "Human"
xp = 0
armor_class = 10
speed = 30 # In feet
# Hit points
hp_max = 10
hit_dice_num = 1
hit_dice_faces = 8
hit_dice_faces = 2
# Base stats (ability scores
strength = Stat()
dexterity = Stat()
@@ -32,7 +32,13 @@ class Character():
intelligence = Stat()
wisdom = Stat()
charisma = Stat()
# Inventory
cp = 0
sp = 0
ep = 0
gp = 0
pp = 0
def __init__(self, **attrs):
"""Takes a bunch of attrs and passes them to ``set_attrs``"""
self.set_attrs(**attrs)
@@ -42,16 +48,88 @@ class Character():
dictionary."""
for attr, val in attrs.items():
setattr(self, attr, val)
@property
def hit_dice(self):
"""What type and how many dice to use for re-gaining hit points.
To change, set hit_dice_num and hit_dice_faces."""
return f"{self.hit_dice_num}d{self.hit_dice_faces}"
return f"{self.level}d{self.hit_dice_faces}"
@hit_dice.setter
def hit_dice(self, val):
dice = read_dice_str(val)
self.hit_dice_faces = dice.faces
self.hit_dice_num = dice.num
@property
def proficiency_bonus(self):
if self.level < 5:
prof = 2
elif 5 <= self.level < 9:
prof = 3
elif 9 <= self.level < 13:
prof = 4
elif 13 <= self.level < 17:
prof = 5
elif 17 <= self.level:
prof = 6
return prof
@property
def armor_class(self):
"""Armor class, without items."""
return 10 + self.dexterity.modifier
class Barbarian(Character):
class_name = 'Barbarian'
hit_dice_faces = 12
class Bard(Character):
class_name = 'Bard'
hit_dice_faces = 8
class Cleric(Character):
class_name = 'Cleric'
hit_dice_faces = 8
class Druid(Character):
class_name = 'Druid'
hit_dice_faces = 8
class Fighter(Character):
class_name = 'Fighter'
hit_dice_faces = 10
class Monk(Character):
class_name = 'Monk'
hit_dice_faces = 8
class Paladin(Character):
class_name = 'Paladin'
hit_dice_faces = 10
class Ranger(Character):
class_name = 'Ranger'
hit_dice_faces = 10
class Rogue(Character):
class_name = 'Rogue'
hit_dice_faces = 8
class Sorceror(Character):
class_name = 'Sorceror'
hit_dice_faces = 6
class Warlock(Character):
class_name = 'Warlock'
hit_dice_faces = 8
class Wizard(Character):
class_name = 'Wizard'
hit_dice_faces = 6
+30 -10
View File
@@ -1,12 +1,14 @@
#!/usr/bin/env python
import argparse
import importlib.util
import os
import subprocess
from fdfgen import forge_fdf
from dungeonsheets.character import Character
from dungeonsheets import character
from dungeonsheets.stats import mod_str
"""Program to take character definitions and build a PDF of the
character sheet."""
@@ -53,22 +55,31 @@ def create_fdf(character, fdfname):
('Alignment', character.alignment),
('XP', character.xp),
# Attributes
('ProfBonus', mod_str(character.proficiency_bonus)),
('STRmod', str(character.strength.value)),
('STR', character.strength.modifier_string),
('STR', mod_str(character.strength.modifier)),
('DEXmod ', character.dexterity.value),
('DEX', character.dexterity.modifier_string),
('DEX', mod_str(character.dexterity.modifier)),
('CONmod', character.constitution.value),
('CON', character.constitution.modifier_string),
('CON', mod_str(character.constitution.modifier)),
('INTmod', character.intelligence.value),
('INT', character.intelligence.modifier_string),
('INT', mod_str(character.intelligence.modifier)),
('WISmod', character.wisdom.value),
('WIS', character.wisdom.modifier_string),
('WIS', mod_str(character.wisdom.modifier)),
('CHamod', character.charisma.value),
('CHA', character.charisma.modifier_string),
('CHA', mod_str(character.charisma.modifier)),
('AC', character.armor_class),
('Initiative', mod_str(character.dexterity.modifier)),
('Speed', character.speed),
# Hit points
('HDTotal', character.hit_dice),
('HPMax', character.hp_max),
# Inventory
('CP', character.cp),
('SP', character.sp),
('EP', character.ep),
('GP', character.gp),
('PP', character.pp),
]
fdf = forge_fdf("", fields, [], [], [])
fdf_file = open(fdfname, "wb")
@@ -87,7 +98,9 @@ def make_sheet(character_file, flatten=False):
"""
# Create a character from the character definition
char_props = load_character_file(character_file)
char = Character(**char_props)
class_name = char_props.pop('character_class').lower().capitalize()
CharClass = getattr(character, class_name)
char = CharClass(**char_props)
# Set the fields in the FDF
fdfname = os.path.splitext(character_file)[0] + '.fdf'
create_fdf(character=char, fdfname=fdfname)
@@ -106,7 +119,14 @@ def make_sheet(character_file, flatten=False):
def main():
make_sheet('examples/rogue.py')
# Prepare an argument parser
parser = argparse.ArgumentParser(
description='Prepare Dungeons and Dragons character sheets as PDFs')
parser.add_argument('filename', type=str, help="Python file with character definition")
parser.add_argument('--flatten', '-F', action="store_true", help="Remove the PDF fields once processed.")
args = parser.parse_args()
# Process the requested file
make_sheet(character_file=args.filename, flatten=args.flatten)
if __name__ == '__main__':
+12 -15
View File
@@ -1,5 +1,16 @@
import math
def mod_str(modifier):
"""Converts a modifier to a string, eg 2 -> '+2'."""
if modifier > 0:
mod_str = '+' + str(modifier)
else:
mod_str = str(modifier)
return mod_str
class Stat():
value = 10
@@ -9,20 +20,6 @@ class Stat():
@property
def modifier(self):
return math.floor((self.value - 10) / 2)
@property
def modifier_string(self):
"""Similar to ``modifier`` but as a string.
This also adds a '+' if necessary.
"""
mod = self.modifier
if mod > 0:
mod_str = '+' + str(mod)
else:
mod_str = str(mod)
return mod_str
def __set__(self, obj, val):
self.value = val