From a80fa8199383c1100d9bdfd7406fbe356b50116f Mon Sep 17 00:00:00 2001 From: Ben Cook Date: Wed, 2 Jan 2019 17:55:22 -0500 Subject: [PATCH] updated create-character to include weapons and armor --- dungeonsheets/armor.py | 31 ++++---- dungeonsheets/character.py | 1 - dungeonsheets/create_character.py | 97 ++++++++++++++++++++++++-- dungeonsheets/forms/empty_template.txt | 6 +- 4 files changed, 114 insertions(+), 21 deletions(-) diff --git a/dungeonsheets/armor.py b/dungeonsheets/armor.py index 1d161b6..2991fbd 100644 --- a/dungeonsheets/armor.py +++ b/dungeonsheets/armor.py @@ -55,7 +55,7 @@ class Armor(): dexterity_mod_max = None strength_required = None stealth_disadvantage = False - weight = 0 # In lbs + weight = 0 # In lbs def __str__(self): return self.name @@ -65,23 +65,23 @@ class Armor(): class NoArmor(Armor): - name = "No armor" + name = "No Armor" class LightArmor(Armor): - name = "Generic Light Armor" + name = "Light Armor" class MediumArmor(Armor): - name = "Generic Medium Armor" + name = "Medium Armor" class HeavyArmor(Armor): - name = "Generic Heavy Armor" + name = "Heavy Armor" class PaddedArmor(LightArmor): - name = "Padded armor" + name = "Padded Armor" cost = "5 gp" base_armor_class = 11 weight = 8 @@ -89,21 +89,21 @@ class PaddedArmor(LightArmor): class LeatherArmor(LightArmor): - name = "Leather armor" + name = "Leather Armor" cost = "10 gp" base_armor_class = 11 weight = 10 -class StuddedArmor(LightArmor): - name = "Studded leather armor" +class StuddedLeatherArmor(LightArmor): + name = "Studded Leather Armor" cost = "45 gp" base_armor_class = 12 weight = 13 class HideArmor(MediumArmor): - name = "Hide armor" + name = "Hide Armor" cost = "10 gp" base_armor_class = 12 dexterity_mod_max = 2 @@ -111,7 +111,7 @@ class HideArmor(MediumArmor): class ChainShirt(MediumArmor): - name = "Chain shirt" + name = "Chain Shirt" cost = "50 gp" base_armor_class = 13 dexterity_mod_max = 2 @@ -119,7 +119,7 @@ class ChainShirt(MediumArmor): class ScaleMail(MediumArmor): - name = "Scale mail" + name = "Scale Mail" cost = "50 gp" base_armor_class = 14 dexterity_mod_max = 2 @@ -145,7 +145,7 @@ class HalfPlate(MediumArmor): class RingMail(HeavyArmor): - name = "Ring mail" + name = "Ring Mail" cost = "30 gp" base_armor_class = 14 dexterity_mod_max = 0 @@ -191,3 +191,8 @@ class ElvenChain(MediumArmor): dexerity_mod_max = 2 weight = 20 + +light_armors = [PaddedArmor, LeatherArmor, StuddedLeatherArmor] +medium_armors = [HideArmor, ChainShirt, ScaleMail, Breastplate, HalfPlate] +heavy_armors = [RingMail, ChainMail, SplintArmor, PlateMail] +all_armors = light_armors + medium_armors + heavy_armors diff --git a/dungeonsheets/character.py b/dungeonsheets/character.py index acc18fa..8651f97 100644 --- a/dungeonsheets/character.py +++ b/dungeonsheets/character.py @@ -720,7 +720,6 @@ class Character(): make_sheet(filename, character=self, flatten=kwargs.get('flatten', True)) - def read_character_file(filename): """Create a character object from the given definition file. diff --git a/dungeonsheets/create_character.py b/dungeonsheets/create_character.py index 7cf35e0..0f958b4 100755 --- a/dungeonsheets/create_character.py +++ b/dungeonsheets/create_character.py @@ -14,7 +14,8 @@ import subprocess import npyscreen import jinja2 -from dungeonsheets import character, race, dice, background, classes +from dungeonsheets import (character, race, dice, background, classes, weapons, + armor) def read_version(): @@ -29,6 +30,9 @@ races = {r.name: r for r in race.available_races} backgrounds = {b.name: b for b in background.available_backgrounds} +all_weapons = (weapons.simple_melee_weapons + weapons.martial_melee_weapons + + weapons.simple_ranged_weapons + weapons.martial_ranged_weapons) + class LinkedListForm(npyscreen.ActionForm): prev_page = None @@ -85,7 +89,7 @@ class App(npyscreen.NPSAppManaged): # Create the PDF character sheet if self.getForm('SAVE').make_pdf.value: log.debug("Creating PDF") - self.character.to_pdf(filename, template_file='empty_template.txt') + self.character.to_pdf(filename) subprocess.call(['makesheets', filename]) def update_max_hp(self): @@ -122,11 +126,15 @@ class App(npyscreen.NPSAppManaged): name="Choose ability scores:", formid='ABILITIES') self.addForm("SKILLS", SkillForm, name="Choose skill proficiencies", formid='SKILLS') + self.addForm("WEAPONS", WeaponForm, name="Choose weapons", + formid='WEAPONS') + self.addForm("ARMOR", ArmorForm, name="Choose armor", + formid='ARMOR') self.addForm("SAVE", SaveForm, name="Save character:", formid='SAVE') # Initialized the DoublyLinkedList - forms = ['MAIN', 'RACE', 'CLASS1', 'BACKGROUND', - 'ALIGNMENT', 'ABILITIES', 'SKILLS', 'SAVE'] + forms = ['MAIN', 'RACE', 'CLASS1', 'BACKGROUND', 'ALIGNMENT', + 'ABILITIES', 'SKILLS', 'WEAPONS', 'ARMOR', 'SAVE'] for i in range(len(forms)-1): form = self.getForm(forms[i]) form.add_next(forms[i+1]) @@ -522,6 +530,7 @@ class SkillForm(LinkedListForm): race_skills = tuple(self.parentApp.character.race.skill_proficiencies) all_skills = new_skills + bg_skills + race_skills self.parentApp.character.skill_proficiencies = all_skills + self.parentApp.getForm('WEAPONS').update_options() log.debug(f"Skill proficiencies: {all_skills}") super().to_next() @@ -529,6 +538,85 @@ class SkillForm(LinkedListForm): super().to_prev() +class WeaponForm(LinkedListForm): + def create(self): + self.instructions = self.add( + npyscreen.FixedText, editbale=False, + value=("Please select your weapons.")) + self.remaining = self.add( + npyscreen.TitleText, name="Remaining:", + value=3, editable=False) + self.weapons = self.add( + npyscreen.TitleMultiSelect, name="Weapons:", + values=tuple([wpn.name for wpn in all_weapons]), + value_changed_callback=self.update_remaining) + + def on_ok(self): + new_weapons = self.weapons.get_selected_objects() + if new_weapons is not None: + new_weapons = tuple(s.lower() for s in new_weapons) + else: + new_weapons = () + for wpn in new_weapons: + self.parentApp.character.wield_weapon(wpn) + log.debug(f"Weapons wielded: {new_weapons}") + super().to_next() + + def update_remaining(self, widget=None): + num_choices = 3 + num_selected = len(self.weapons.value) + remaining = num_choices - num_selected + log.debug(f'Remaining: {remaining}') + self.remaining.value = str(remaining) + self.display() + + def update_options(self): + available_weapons = [] + for wpn in all_weapons: + if self.parentApp.character.is_proficient(wpn()): + available_weapons.append(wpn.name) + self.weapons.values = available_weapons + self.parentApp.getForm('ARMOR').update_options() + self.display() + + def on_cancel(self): + super().to_prev() + + +class ArmorForm(LinkedListForm): + def create(self): + self.instructions = self.add( + npyscreen.FixedText, editbale=False, + value=("Please select your armor.")) + self.shield = self.add(npyscreen.Checkbox, name="Shield? ", + value=False) + self.armor = self.add( + npyscreen.TitleSelectOne, name="Armor:", + values=tuple([a.name for a in armor.all_armors])) + + def on_ok(self): + my_armor = self.armor.get_selected_objects()[0] + if my_armor.lower() is not "no armor": + self.parentApp.character.wear_armor(my_armor) + if self.shield.value: + self.parentApp.character.wield_shield('shield') + super().to_next() + + def update_options(self): + available_armors = [armor.NoArmor] + if 'light armor' in self.parentApp.character.proficiencies_text.lower(): + available_armors.extend(armor.light_armors) + if 'medium armor' in self.parentApp.character.proficiencies_text.lower(): + available_armors.extend(armor.medium_armors) + if 'heavy armor' in self.parentApp.character.proficiencies_text.lower(): + available_armors.extend(armor.heavy_armors) + self.armor.values = [a.name for a in available_armors] + self.display() + + def on_cancel(self): + super().to_prev() + + class SaveForm(LinkedListForm): def create(self): self.instructions = self.add( @@ -540,6 +628,7 @@ class SaveForm(LinkedListForm): npyscreen.TitleText, name='Filename:') self.make_pdf = self.add(npyscreen.Checkbox, name="Create PDF:", value=True) + def on_ok(self): super().to_next() diff --git a/dungeonsheets/forms/empty_template.txt b/dungeonsheets/forms/empty_template.txt index 4c81cf0..41ff46f 100644 --- a/dungeonsheets/forms/empty_template.txt +++ b/dungeonsheets/forms/empty_template.txt @@ -69,10 +69,10 @@ gp = 0 pp = 0 # TODO: Put your equipped weapons and armor here -weapons = () # Example: ('shortsword', 'longsword') +weapons = {{ char.weapons }} # Example: ('shortsword', 'longsword') magic_items = () # Example: ('ring of protection',) -armor = "" # Eg "leather armor" -shield = "" # Eg "shield" +armor = "{{ char.armor }}" # Eg "leather armor" +shield = "{{ char.shield }}" # Eg "shield" equipment = """TODO: list the equipment and magic items your character carries"""