mirror of
https://github.com/Threnklyn/dungeon-sheets.git
synced 2026-06-03 19:38:30 +02:00
Some more advanced characteristics, different player classes, and a CLI interface.
This commit is contained in:
+90
-12
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user