def create_character_pdf(character, basename, flatten=False): # Prepare the list of fields class_level = (character.class_name + ' ' + str(character.level)) fields = [ # Character description ('CharacterName', character.name), ('ClassLevel', class_level), ('Background', character.background), ('PlayerName', character.player_name), ('Race ', str(character.race)), ('Alignment', character.alignment), ('XP', character.xp), # Abilities ('ProfBonus', mod_str(character.proficiency_bonus)), ('STRmod', str(character.strength.value)), ('STR', mod_str(character.strength.modifier)), ('DEXmod ', character.dexterity.value), ('DEX', mod_str(character.dexterity.modifier)), ('CONmod', character.constitution.value), ('CON', mod_str(character.constitution.modifier)), ('INTmod', character.intelligence.value), ('INT', mod_str(character.intelligence.modifier)), ('WISmod', character.wisdom.value), ('WIS', mod_str(character.wisdom.modifier)), ('CHamod', character.charisma.value), ('CHA', mod_str(character.charisma.modifier)), ('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), # Personality traits and other features ('PersonalityTraits ', text_box(character.personality_traits)), ('Ideals', text_box(character.ideals)), ('Bonds', text_box(character.bonds)), ('Flaws', text_box(character.flaws)), ('Features and Traits', text_box(character.features_and_traits)), # Inventory ('CP', character.cp), ('SP', character.sp), ('EP', character.ep), ('GP', character.gp), ('PP', character.pp), ('Equipment', text_box(character.equipment)), ] # 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', } # Add skill proficienies for skill in character.skill_proficiencies: fields.append((skill_boxes[skill.replace(' ', '_')], 'Yes')) # Add weapons weapon_fields = [ ('Wpn Name', 'Wpn1 AtkBonus', 'Wpn1 Damage'), ('Wpn Name 2', 'Wpn2 AtkBonus ', 'Wpn2 Damage '), ('Wpn Name 3', 'Wpn3 AtkBonus ', 'Wpn3 Damage '), ] for _fields, weapon in zip(weapon_fields, character.weapons): name_field, atk_field, dmg_field = _fields fields.append((name_field, weapon.name)) fields.append((atk_field, mod_str(weapon.attack_bonus))) fields.append((dmg_field, f'{weapon.damage} {weapon.damage_type}')) # Other attack information attack_str = f'Armor: {character.armor}' attack_str += f'Shield: {character.shield}\n\n' attack_str += character.attacks_and_spellcasting fields.append(('AttacksSpellcasting', text_box(attack_str))) # Other proficiencies and languages prof_text = "Proficiencies:\n" + text_box(character.proficiencies_text) prof_text += "\n\nLanguages:\n" + text_box(character.languages) fields.append(('ProficienciesLang', prof_text)) # Prepare the actual PDF dirname = os.path.dirname(os.path.abspath(__file__)) src_pdf = os.path.join(dirname, 'blank-character-sheet-default.pdf') return make_pdf(fields, src_pdf=src_pdf, basename=basename, flatten=flatten)
def create_spells_pdf(character, basename, flatten=False): class_level = (character.class_name + ' ' + str(character.level)) spell_level = lambda x: (x or '') sc_ab = getattr(character, character.spellcasting_ability) fields = [ ('Spellcasting Class 2', class_level), # ("SpellcastingAbility 2", character.spellcasting_ability.capitalize()), ("SpellcastingAbility 2", sc_ab.modifier), ('SpellSaveDC 2', character.spell_save_dc), ('SpellAtkBonus 2', mod_str(character.spell_attack_bonus)), # Number of spell slots ('SlotsTotal 19', spell_level(character.spell_slots(1))), ('SlotsTotal 20', spell_level(character.spell_slots(2))), ('SlotsTotal 21', spell_level(character.spell_slots(3))), ('SlotsTotal 22', spell_level(character.spell_slots(4))), ('SlotsTotal 23', spell_level(character.spell_slots(5))), ('SlotsTotal 24', spell_level(character.spell_slots(6))), ('SlotsTotal 25', spell_level(character.spell_slots(7))), ('SlotsTotal 26', spell_level(character.spell_slots(8))), ('SlotsTotal 27', spell_level(character.spell_slots(9))), ] # Cantrips cantrip_fields = (f'Spells 10{i}' for i in (14, 16, 17, 18, 19, 20, 21, 22)) cantrips = (spl for spl in character.spells if spl.level == 0) for spell, field_name in zip(cantrips, cantrip_fields): fields.append((field_name, str(spell))) # Spells for each level field_numbers = { 1: ( 1015, 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, ), 2: ( 1046, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, ), 3: ( 1048, 1047, 1049, 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, ), 4: ( 1061, 1060, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, ), 5: ( 1074, 1073, 1075, 1076, 1077, 1078, 1079, 1080, 1081, ), 6: ( 1083, 1082, 1084, 1085, 1086, 1087, 1088, 1089, 1090, ), 7: ( 1092, 1091, 1093, 1094, 1095, 1096, 1097, 1098, 1099, ), 8: ( 10101, 10100, 10102, 10103, 10104, 10105, 10106, ), 9: (10108, 10107, 10109, 101010, 101011, 101012, 101013), } prep_numbers = { 1: ( 251, 309, 3010, 3011, 3012, 3013, 3014, 3015, 3016, 3017, 3018, 3019, ), 2: ( 313, 310, 3020, 3021, 3022, 3023, 3024, 3025, 3026, 3027, 3028, 3029, 3030, ), 3: ( 315, 314, 3031, 3032, 3033, 3034, 3035, 3036, 3037, 3038, 3039, 3040, 3041, ), 4: ( 317, 316, 3042, 3043, 3044, 3045, 3046, 3047, 3048, 3049, 3050, 3051, 3052, ), 5: ( 319, 318, 3053, 3054, 3055, 3056, 3057, 3058, 3059, ), 6: ( 321, 320, 3060, 3061, 3062, 3063, 3064, 3065, 3066, ), 7: ( 323, 322, 3067, 3068, 3069, 3070, 3071, 3072, 3073, ), 8: ( 325, 324, 3074, 3075, 3076, 3077, 3078, ), 9: ( 327, 326, 3079, 3080, 3081, 3082, 3083, ), } for level in field_numbers.keys(): spells = tuple(spl for spl in character.spells if spl.level == level) field_names = tuple(f'Spells {i}' for i in field_numbers[level]) prep_names = tuple(f'Check Box {i}' for i in prep_numbers[level]) for spell, field, chk_field in zip(spells, field_names, prep_names): fields.append((field, str(spell))) is_prepared = any( [isinstance(spell, Spl) for Spl in character.spells_prepared]) fields.append((chk_field, is_prepared)) # # Uncomment to post field names instead: # for field in field_names: # fields.append((field, field)) # Make the actual pdf dirname = os.path.dirname(os.path.abspath(__file__)) src_pdf = os.path.join(dirname, 'blank-spell-sheet-default.pdf') make_pdf(fields, src_pdf=src_pdf, basename=basename, flatten=flatten)
def test_mod_str(self): self.assertEqual(stats.mod_str(-3), "-3") self.assertEqual(stats.mod_str(0), "+0") self.assertEqual(stats.mod_str(2), "+2")
def create_character_pdf_template(character, basename, flatten=False): # Prepare the list of fields fields = { # Character description "CharacterName": character.name, "ClassLevel": character.classes_and_levels, "Background": str(character.background), "PlayerName": character.player_name, "Race ": str(character.race), "Alignment": character.alignment, "XP": str(character.xp), "Inspiration": str("Yes" if character.inspiration else "No"), # Abilities "ProfBonus": mod_str(character.proficiency_bonus), "STRmod": str(character.strength.value), "STR": mod_str(character.strength.modifier), "DEXmod ": str(character.dexterity.value), "DEX": mod_str(character.dexterity.modifier), "CONmod": str(character.constitution.value), "CON": mod_str(character.constitution.modifier), "INTmod": str(character.intelligence.value), "INT": mod_str(character.intelligence.modifier), "WISmod": str(character.wisdom.value), "WIS": mod_str(character.wisdom.modifier), "CHamod": str(character.charisma.value), "CHA": mod_str(character.charisma.modifier), "AC": str(character.armor_class), "Initiative": str(character.initiative), "Speed": str(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.persuasion), "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": str(character.hp_max), # Personality traits and other features "PersonalityTraits ": text_box(character.personality_traits), "Ideals": text_box(character.ideals), "Bonds": text_box(character.bonds), "Flaws": text_box(character.flaws), "Features and Traits": text_box(character.features_text + character.features_and_traits), # Inventory "CP": character.cp, "SP": character.sp, "EP": character.ep, "GP": character.gp, "PP": character.pp, "Equipment": text_box(character.magic_items_text + character.equipment), } # 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[ST_boxes[ability]] = CHECKBOX_ON # Add skill proficiencies 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", "persuasion": "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: try: fields[skill_boxes[skill.replace(" ", "_").lower()]] = CHECKBOX_ON except KeyError: raise KeyError(f"Unknown skill: '{skill}'") # Add weapons weapon_fields = [ ("Wpn Name", "Wpn1 AtkBonus", "Wpn1 Damage"), ("Wpn Name 2", "Wpn2 AtkBonus ", "Wpn2 Damage "), ("Wpn Name 3", "Wpn3 AtkBonus ", "Wpn3 Damage "), ] if len(character.weapons) == 0: character.wield_weapon("unarmed") for _fields, weapon in zip(weapon_fields, character.weapons): name_field, atk_field, dmg_field = _fields fields[name_field] = weapon.name fields[atk_field] = "{:+d}".format(weapon.attack_modifier) fields[dmg_field] = f"{weapon.damage}/{weapon.damage_type}" # Other attack information attack = [] if character.armor: attack.append(f"Armor: {character.armor}") if character.shield: attack.append(f"Shield: {character.shield}") attack.append(character.attacks_and_spellcasting) attack_str = "\n\n".join(attack) fields["AttacksSpellcasting"] = text_box(attack_str) # Other proficiencies and languages prof_text = "Proficiencies:\n" + text_box(character.proficiencies_text) prof_text += "\n\nLanguages:\n" + text_box(character.languages) fields["ProficienciesLang"] = prof_text # Prepare the actual PDF dirname = os.path.join(os.path.dirname(os.path.abspath(__file__)), "forms/") src_pdf = os.path.join(dirname, "blank-character-sheet-default.pdf") return make_pdf(fields, src_pdf=src_pdf, basename=basename, flatten=flatten)
def create_spells_pdf_template(character, basename, flatten=False): classes_and_levels = " / ".join( [c.name + " " + str(c.level) for c in character.spellcasting_classes]) abilities = " / ".join([ c.spellcasting_ability.upper()[:3] for c in character.spellcasting_classes ]) DCs = " / ".join([ str(character.spell_save_dc(c)) for c in character.spellcasting_classes ]) bonuses = " / ".join([ mod_str(character.spell_attack_bonus(c)) for c in character.spellcasting_classes ]) def spell_level(x): return x or 0 fields = { "Spellcasting Class 2": classes_and_levels, "SpellcastingAbility 2": abilities, "SpellSaveDC 2": DCs, "SpellAtkBonus 2": bonuses, # Number of spell slots "SlotsTotal 19": spell_level(character.spell_slots(1)), "SlotsTotal 20": spell_level(character.spell_slots(2)), "SlotsTotal 21": spell_level(character.spell_slots(3)), "SlotsTotal 22": spell_level(character.spell_slots(4)), "SlotsTotal 23": spell_level(character.spell_slots(5)), "SlotsTotal 24": spell_level(character.spell_slots(6)), "SlotsTotal 25": spell_level(character.spell_slots(7)), "SlotsTotal 26": spell_level(character.spell_slots(8)), "SlotsTotal 27": spell_level(character.spell_slots(9)), } # Cantrips cantrip_fields = (f"Spells 10{i}" for i in (14, 16, 17, 18, 19, 20, 21, 22)) cantrips = (spl for spl in character.spells if spl.level == 0) for spell, field_name in zip(cantrips, cantrip_fields): fields[field_name] = str(spell) # Spells for each level field_numbers = { 1: ( 1015, 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, ), 2: ( 1046, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, ), 3: ( 1048, 1047, 1049, 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, ), 4: ( 1061, 1060, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, ), 5: ( 1074, 1073, 1075, 1076, 1077, 1078, 1079, 1080, 1081, ), 6: ( 1083, 1082, 1084, 1085, 1086, 1087, 1088, 1089, 1090, ), 7: ( 1092, 1091, 1093, 1094, 1095, 1096, 1097, 1098, 1099, ), 8: ( 10101, 10100, 10102, 10103, 10104, 10105, 10106, ), 9: (10108, 10107, 10109, 101010, 101011, 101012, 101013), } prep_numbers = { 1: ( 251, 309, 3010, 3011, 3012, 3013, 3014, 3015, 3016, 3017, 3018, 3019, ), 2: ( 313, 310, 3020, 3021, 3022, 3023, 3024, 3025, 3026, 3027, 3028, 3029, 3030, ), 3: ( 315, 314, 3031, 3032, 3033, 3034, 3035, 3036, 3037, 3038, 3039, 3040, 3041, ), 4: ( 317, 316, 3042, 3043, 3044, 3045, 3046, 3047, 3048, 3049, 3050, 3051, 3052, ), 5: ( 319, 318, 3053, 3054, 3055, 3056, 3057, 3058, 3059, ), 6: ( 321, 320, 3060, 3061, 3062, 3063, 3064, 3065, 3066, ), 7: ( 323, 322, 3067, 3068, 3069, 3070, 3071, 3072, 3073, ), 8: ( 325, 324, 3074, 3075, 3076, 3077, 3078, ), 9: ( 327, 326, 3079, 3080, 3081, 3082, 3083, ), } for level in field_numbers.keys(): spells = tuple(spl for spl in character.spells if spl.level == level) field_names = tuple(f"Spells {i}" for i in field_numbers[level]) prep_names = tuple(f"Check Box {i}" for i in prep_numbers[level]) for spell, field, chk_field in zip(spells, field_names, prep_names): fields[field] = str(spell) is_prepared = any( [spell == Spl for Spl in character.spells_prepared]) fields[chk_field] = CHECKBOX_ON if is_prepared else CHECKBOX_OFF # # Uncomment to post field names instead: # for field in field_names: # fields.append((field, field)) # Make the actual pdf dirname = os.path.join(os.path.dirname(os.path.abspath(__file__)), "forms/") src_pdf = os.path.join(dirname, "blank-spell-sheet-default.pdf") make_pdf(fields, src_pdf=src_pdf, basename=basename, flatten=flatten)
def create_character_pdf(character, basename, flatten=False): # Prepare the list of fields fields = { # Character description 'CharacterName': character.name, 'ClassLevel': character.classes_and_levels, 'Background': str(character.background), 'PlayerName': character.player_name, 'Race ': str(character.race), 'Alignment': character.alignment, 'XP': str(character.xp), 'Inspiration': str('Yes' if character.inspiration else 'No'), # Abilities 'ProfBonus': mod_str(character.proficiency_bonus), 'STRmod': str(character.strength.value), 'STR': mod_str(character.strength.modifier), 'DEXmod ': str(character.dexterity.value), 'DEX': mod_str(character.dexterity.modifier), 'CONmod': str(character.constitution.value), 'CON': mod_str(character.constitution.modifier), 'INTmod': str(character.intelligence.value), 'INT': mod_str(character.intelligence.modifier), 'WISmod': str(character.wisdom.value), 'WIS': mod_str(character.wisdom.modifier), 'CHamod': str(character.charisma.value), 'CHA': mod_str(character.charisma.modifier), 'AC': str(character.armor_class), 'Initiative': str(character.initiative), 'Speed': str(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.persuasion), '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': str(character.hp_max), # Personality traits and other features 'PersonalityTraits ': text_box(character.personality_traits), 'Ideals': text_box(character.ideals), 'Bonds': text_box(character.bonds), 'Flaws': text_box(character.flaws), 'Features and Traits': text_box(character.features_text + character.features_and_traits), # Inventory 'CP': character.cp, 'SP': character.sp, 'EP': character.ep, 'GP': character.gp, 'PP': character.pp, 'Equipment': text_box(character.magic_items_text + character.equipment), } # 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[ST_boxes[ability]] = CHECKBOX_ON # Add skill proficiencies 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', 'persuasion': '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: try: fields[skill_boxes[skill.replace(' ', '_').lower()]] = CHECKBOX_ON except KeyError: raise KeyError(f"Unknown skill: '{skill}'") # Add weapons weapon_fields = [ ('Wpn Name', 'Wpn1 AtkBonus', 'Wpn1 Damage'), ('Wpn Name 2', 'Wpn2 AtkBonus ', 'Wpn2 Damage '), ('Wpn Name 3', 'Wpn3 AtkBonus ', 'Wpn3 Damage '), ] if len(character.weapons) == 0: character.wield_weapon('unarmed') for _fields, weapon in zip(weapon_fields, character.weapons): name_field, atk_field, dmg_field = _fields fields[name_field] = weapon.name fields[atk_field] = '{:+d}'.format(weapon.attack_modifier) fields[dmg_field] = f'{weapon.damage}/{weapon.damage_type}' # Other attack information attack = [] if character.armor: attack.append(f'Armor: {character.armor}') if character.shield: attack.append(f'Shield: {character.shield}') attack.append(character.attacks_and_spellcasting) attack_str = '\n\n'.join(attack) fields['AttacksSpellcasting'] = text_box(attack_str) # Other proficiencies and languages prof_text = "Proficiencies:\n" + text_box(character.proficiencies_text) prof_text += "\n\nLanguages:\n" + text_box(character.languages) fields['ProficienciesLang'] = prof_text # Prepare the actual PDF dirname = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'forms/') src_pdf = os.path.join(dirname, 'blank-character-sheet-default.pdf') return make_pdf(fields, src_pdf=src_pdf, basename=basename, flatten=flatten)
def test_mod_str(self): self.assertEqual(stats.mod_str(-3), '-3') self.assertEqual(stats.mod_str(0), '0') self.assertEqual(stats.mod_str(2), '+2')