Create character now does class skills and saves the results.

This commit is contained in:
Mark Wolfman
2018-04-23 00:28:39 -05:00
parent 624eb620a6
commit 31f5a32b17
5 changed files with 179 additions and 8 deletions
+32 -1
View File
@@ -40,6 +40,8 @@ class Character():
charisma = Ability() charisma = Ability()
saving_throw_proficiencies = [] saving_throw_proficiencies = []
skill_proficiencies = tuple() skill_proficiencies = tuple()
class_skill_choices = tuple()
num_skill_choices = 2
weapon_proficiencies = tuple() weapon_proficiencies = tuple()
proficiencies_extra = tuple() proficiencies_extra = tuple()
languages = "" languages = ""
@@ -304,6 +306,8 @@ class Barbarian(Character):
_proficiencies_text = ('light armor', 'medium armor', 'shields', _proficiencies_text = ('light armor', 'medium armor', 'shields',
'simple weapons', 'martial weapons') 'simple weapons', 'martial weapons')
weapon_proficiencies = (weapons.simple_weapons + weapons.martial_weapons) weapon_proficiencies = (weapons.simple_weapons + weapons.martial_weapons)
class_skill_choices = ('Animal Handling', 'Athletics',
'Intimidation', 'Nature', 'Perception', 'Survival')
class Bard(Character): class Bard(Character):
@@ -316,6 +320,12 @@ class Bard(Character):
weapon_proficiencies = ((weapons.HandCrossbow, weapons.Longsword, weapon_proficiencies = ((weapons.HandCrossbow, weapons.Longsword,
weapons.Rapier, weapons.Shortsword) + weapons.Rapier, weapons.Shortsword) +
weapons.simple_weapons) weapons.simple_weapons)
class_skill_choices = ('Acrobatics', 'Animal Handling', 'Arcana',
'Athletics', 'Deception', 'History', 'Insight',
'Intimidation', 'Investigation', 'Medicine', 'Nature',
'Perception', 'Performance', 'Persuasion', 'Religion',
'Sleight of Hand', 'Stealth', 'Survival')
num_skill_choices = 3
class Cleric(Character): class Cleric(Character):
@@ -325,6 +335,8 @@ class Cleric(Character):
_proficiencies_text = ('light armor', 'medium armor', 'shields', _proficiencies_text = ('light armor', 'medium armor', 'shields',
'all simple weapons') 'all simple weapons')
weapon_proficiencies = weapons.simple_weapons weapon_proficiencies = weapons.simple_weapons
class_skill_choices = ('History', 'Insight', 'Medicine',
'Persuasion', 'Religion')
class Druid(Character): class Druid(Character):
@@ -339,6 +351,8 @@ class Druid(Character):
weapon_proficiencies = (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)
class_skill_choices = ('Arcana', 'Animal Handling', 'Insight',
'Medicine', 'Nature', 'Perception', 'Religion', 'Survival')
class Fighter(Character): class Fighter(Character):
@@ -347,6 +361,9 @@ class Fighter(Character):
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_proficiencies = weapons.simple_weapons + weapons.martial_weapons weapon_proficiencies = weapons.simple_weapons + weapons.martial_weapons
class_skill_choices = ('Acrobatics', 'Animal Handling',
'Athletics', 'History', 'Insight', 'Intimidation', 'Perception',
'Survival')
class Monk(Character): class Monk(Character):
@@ -357,7 +374,7 @@ class Monk(Character):
'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_proficiencies = (weapons.Shortsword,) + weapons.simple_weapons weapon_proficiencies = (weapons.Shortsword,) + weapons.simple_weapons
class_skill_choices = ('Acrobatics', 'Athletics', 'History', 'Insight', 'Religion', 'Stealth')
class Paladin(Character): class Paladin(Character):
class_name = 'Paladin' class_name = 'Paladin'
@@ -366,6 +383,8 @@ class Paladin(Character):
_proficiencies_text = ('All armor', 'shields', 'simple weapons', _proficiencies_text = ('All armor', 'shields', 'simple weapons',
'martial weapons') 'martial weapons')
weapon_proficiencies = weapons.simple_weapons + weapons.martial_weapons weapon_proficiencies = weapons.simple_weapons + weapons.martial_weapons
class_skill_choices = ("Athletics", 'Insight', 'Intimidation',
'Medicine', 'Persuasion', 'Religion')
class Ranger(Character): class Ranger(Character):
@@ -375,6 +394,9 @@ class Ranger(Character):
_proficiencies_text = ("light armor", "medium armor", "shields", _proficiencies_text = ("light armor", "medium armor", "shields",
"simple weapons", "martial weapons") "simple weapons", "martial weapons")
weapon_proficiencies = weapons.simple_weapons + weapons.martial_weapons weapon_proficiencies = weapons.simple_weapons + weapons.martial_weapons
class_skill_choices = ('Animal Handling', 'Athletics', 'Insight',
'Investigation', 'Nature', 'Perception', 'Stealth', 'Survival')
num_skill_choices = 3
class Rogue(Character): class Rogue(Character):
@@ -386,6 +408,9 @@ class Rogue(Character):
'rapiers', 'shortswords', "thieves' tools") 'rapiers', 'shortswords', "thieves' tools")
weapon_proficiencies = (weapons.HandCrossbow, weapons.Longsword, weapon_proficiencies = (weapons.HandCrossbow, weapons.Longsword,
weapons.Rapier, weapons.Shortsword) + weapons.simple_weapons weapons.Rapier, weapons.Shortsword) + weapons.simple_weapons
class_skill_choices = ('Acrobatics', 'Athletics', 'Deception',
'Insight', 'Intimidation', 'Investigation', 'Perception',
'Performance', 'Persuasion', 'Sleight of Hand', 'Stealth')
class Sorceror(Character): class Sorceror(Character):
@@ -397,6 +422,8 @@ class Sorceror(Character):
weapon_proficiencies = (weapons.Dagger, weapons.Dart, weapon_proficiencies = (weapons.Dagger, weapons.Dart,
weapons.Sling, weapons.Quarterstaff, weapons.Sling, weapons.Quarterstaff,
weapons.LightCrossbow) weapons.LightCrossbow)
class_skill_choices = ('Arcana', 'Deception', 'Insight',
'Intimidation' ,'Persuasion', 'Religion')
class Warlock(Character): class Warlock(Character):
@@ -404,6 +431,8 @@ 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")
class_skill_choices = ('Arcana', 'Deception', 'History',
'Intimidation', 'Investigation', 'Nature', 'Religion')
weapon_proficiencies = weapons.simple_weapons weapon_proficiencies = weapons.simple_weapons
spellcasting_ability = 'charisma' spellcasting_ability = 'charisma'
spell_slots_by_level = { spell_slots_by_level = {
@@ -439,6 +468,8 @@ class Wizard(Character):
weapon_proficiencies = (weapons.Dagger, weapons.Dart, weapon_proficiencies = (weapons.Dagger, weapons.Dart,
weapons.Sling, weapons.Quarterstaff, weapons.Sling, weapons.Quarterstaff,
weapons.LightCrossbow) weapons.LightCrossbow)
class_skill_choices = ('Arcana', 'History', 'Investigation',
'Medicine', 'Religion')
spellcasting_ability = 'intelligence' spellcasting_ability = 'intelligence'
spell_slots_by_level = { spell_slots_by_level = {
# char_lvl: (cantrips, 1st, 2nd, 3rd, ...) # char_lvl: (cantrips, 1st, 2nd, 3rd, ...)
+94
View File
@@ -0,0 +1,94 @@
name = '{{ char.name }}'
character_class = '{{ char.class_name }}'
player_name = '{{ char.player_name }}'
background = "{{ char.background }}"
race = "{{ char.race.name }}"
level = {{ char.level }}
alignment = "{{ char.alignment }}"
xp = {{ char.xp }}
hp_max = {{ char.hp_max }}
# Ability Scores
strength = {{ char.strength.value }}
dexterity = {{ char.dexterity.value }}
constitution = {{ char.constitution.value }}
intelligence = {{ char.intelligence.value }}
wisdom = {{ char.wisdom.value }}
charisma = {{ char.charisma.value }}
skill_proficiencies = (
# Put your skill proficiencies here, including the {{ char.race }} race.
)
# Proficiencies and languages
languages = "Common, Elvish, Draconic, Dwarvish, Goblin."
# Inventory
cp = 0
sp = 0
ep = 0
gp = 0
pp = 0
weapons = ('shortsword', 'longsword')
equipment = (
"""Gallon of ale, red cloak, shortsword, longsword, jar of salt, vodka
(500mL), potion of vitality, wand of magic missiles (7/7),
component pouch, spellbook, backpack, bottle of ink, ink pen, 10
sheets of parchment, small knife, tome of historical lore, holy
symbol, prayer book, set of common clothes, pouch.""")
# List of known spells
spells = ('blindness deafness', 'burning hands', 'detect magic',
'false life', 'mage armor', 'mage hand', 'magic missile',
'prestidigitation', 'ray of frost', 'ray of sickness', 'shield',
'shocking grasp', 'sleep', 'some other spell')
# Which spells have been prepared (not including cantrips)
spells_prepared = ('blindness deafness', 'false life', 'mage armor',
'ray of sickness', 'shield', 'sleep',)
# Backstory
personality_traits = """I use polysyllabic words that convey the impression of
erudition. Also, Ive spent so long in the temple that I have little
experience dealing with people on a casual basis."""
ideals = """Knowledge. The path to power and self-improvement is through
knowledge."""
bonds = """The tome I carry with me is the record of my lifes work so far,
and no vault is secure enough to keep it safe."""
flaws = """Ill do just about anything to uncover historical secrets that
would add to my research."""
features_and_traits = (
"""Spellcasting Ability: Intelligence is your spellcasting ability for
your spells. The saving throw DC to resist a spell you cast is
13. Your attack bonus when you make an attack with a spell is
+5. See the rulebook for rules on casting your spells.
Arcane Recovery: You can regain some of your magical energy by
studying your spellbook. Once per day during a short rest, you can
choose to recover expended spell slots with a combined level equal
to or less than half your wizard level (rounded up).
Darkvision: You see in dim light within a 60-foot radius of you as
if it were bright light, and in darkness in that radius as if it
were dim light. You cant discern color in darkness, only shades
of gray.
Fey Ancestry: You have advantage on saving throws against being
charmed, and magic cant put you to sleep.
Trance: Elves dont need to sleep. They meditate deeply, remaining
semiconscious, for 4 hours a day and gain the same benefit a human
does from 8 hours of sleep.
Shelter of the Faithful: As a servant of Oghma, you command the
respect of those who share your faith, and you can perform the
rites of Oghma. You and your companions can expect to receive free
healing and care at a temple, shrine, or other established
presence of Oghmas faith. Those who share your religion will
support you (and only you) at a modest lifestyle. You also have
ties to the temple of Oghma in Neverwinter, where you have a
residence. When you are in Neverwinter, you can call upon the
priests there for assistance that wont endanger them.""")
+50 -6
View File
@@ -7,9 +7,11 @@ logging.basicConfig(filename='character_creater.log', level=logging.DEBUG)
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
import math import math
import os
from random import randint
import npyscreen import npyscreen
from random import randint import jinja2
from dungeonsheets import character, race, dice from dungeonsheets import character, race, dice
@@ -48,11 +50,24 @@ races = {
class App(npyscreen.NPSAppManaged): class App(npyscreen.NPSAppManaged):
# STARTING_FORM = 'CLASS' # STARTING_FORM = 'SKILLS'
character = None character = None
def save_character(self): def save_character(self):
pass # Create the template context
context = dict(
char=self.character
)
# Render the template
src_path = os.path.dirname(__file__)
src_filename = 'character_template.txt'
text = jinja2.Environment(
loader=jinja2.FileSystemLoader(src_path or './')
).get_template(src_filename).render(context)
# Save the file
filename = self.getForm("SAVE").filename.value
with open(filename, mode='w') as f:
f.write(text)
@property @property
def character_class(self, *args, **kwargs): def character_class(self, *args, **kwargs):
@@ -87,15 +102,44 @@ class App(npyscreen.NPSAppManaged):
max_hp_fld.value = str(max_hp) max_hp_fld.value = str(max_hp)
def onStart(self): def onStart(self):
self.character = character.Character()
self.addForm("MAIN", BasicInfoForm, name="Basic Info:") self.addForm("MAIN", BasicInfoForm, name="Basic Info:")
self.addForm("CLASS", CharacterClassForm, name="Select your character's class:") self.addForm("CLASS", CharacterClassForm, name="Select your character's class:")
self.addForm("RACE", RaceForm, name="Select your character's race:") self.addForm("RACE", RaceForm, name="Select your character's race:")
self.addForm("ALIGNMENT", AlignmentForm, name="Select your character's alignment:") self.addForm("ALIGNMENT", AlignmentForm, name="Select your character's alignment:")
self.addForm("ABILITIES", AbilityScoreForm, name="Choose ability scores:") self.addForm("ABILITIES", AbilityScoreForm, name="Choose ability scores:")
self.addForm("BACKGROUND", BackgroundForm, name="Choose background:") self.addForm("BACKGROUND", BackgroundForm, name="Choose background:")
self.addForm("SKILLS", SkillForm, name="Choose skill proficiencies")
self.addForm("SAVE", SaveForm, name="Save character:") self.addForm("SAVE", SaveForm, name="Save character:")
class SkillForm(npyscreen.ActionForm):
def while_editing(self):
self.skill_proficiencies.set_values(self.parentApp.character.class_skill_choices)
self.update_remaining()
def update_remaining(self, widget=None):
remaining = self.parentApp.character.num_skill_choices - len(self.skill_proficiencies.value)
log.debug(f'Remaining: {remaining}')
self.remaining.value = str(remaining)
self.display()
def create(self):
self.remaining = self.add(
npyscreen.TitleText, name="Remaining:",
value=0, editable=False)
self.skill_proficiencies = self.add(
npyscreen.TitleMultiSelect, name="Skill Proficiencies:",
values=self.parentApp.character.class_skill_choices,
value_changed_callback=self.update_remaining)
def on_ok(self):
self.parentApp.setNextForm('SAVE')
def on_cancel(self):
self.parentApp.setNextForm('BACKGROUND')
class AbilityScoreForm(npyscreen.ActionForm): class AbilityScoreForm(npyscreen.ActionForm):
def roll_dice(self): def roll_dice(self):
"""Get six ability scores that can then be assigned to abilities.""" """Get six ability scores that can then be assigned to abilities."""
@@ -194,7 +238,7 @@ class BackgroundForm(npyscreen.ActionForm):
background = self.backgrounds[self.background.value] background = self.backgrounds[self.background.value]
self.parentApp.character.background = background self.parentApp.character.background = background
log.debug("Selected character background: %s", background) log.debug("Selected character background: %s", background)
self.parentApp.setNextForm('SAVE') self.parentApp.setNextForm('SKILLS')
def on_cancel(self): def on_cancel(self):
self.parentApp.setNextForm('ABILITIES') self.parentApp.setNextForm('ABILITIES')
@@ -260,7 +304,7 @@ class BasicInfoForm(npyscreen.ActionForm):
self.parentApp.setNextForm('CLASS') self.parentApp.setNextForm('CLASS')
def on_cancel(self): def on_cancel(self):
self.parentApp.setNextForm('SAVE') self.parentApp.setNextForm(None)
class SaveForm(npyscreen.ActionForm): class SaveForm(npyscreen.ActionForm):
@@ -273,7 +317,7 @@ class SaveForm(npyscreen.ActionForm):
self.parentApp.setNextForm(None) self.parentApp.setNextForm(None)
def on_cancel(self): def on_cancel(self):
self.parentApp.setNextForm('BACKGROUND') self.parentApp.setNextForm('SKILLS')
my_app = App() my_app = App()
+2
View File
@@ -1,2 +1,4 @@
certifi>=2018.1.18 certifi>=2018.1.18
fdfgen>=0.16 fdfgen>=0.16
npyscreen
jinja
+1 -1
View File
@@ -23,7 +23,7 @@ setup(name='dungeonsheets',
'dungeonsheets': ['blank-character-sheet-default.pdf', 'blank-spell-sheet-default.pdf'] 'dungeonsheets': ['blank-character-sheet-default.pdf', 'blank-spell-sheet-default.pdf']
}, },
install_requires=[ install_requires=[
'fdfgen', 'npyscreen', 'fdfgen', 'npyscreen', 'jinja',
], ],
entry_points={ entry_points={
'console_scripts': [ 'console_scripts': [