Package: dnd-character
dnd-characterA Python library to make 5e Dungeons & Dragons characters for use in another app. Characters are serializable into Python dicts so they can be saved and loaded however you wish.SRD rules are fetched from the5e SRD APIthe first time they're requested, then the JSON is cached locally for faster retrieval in the future. I've included thejson_cachecontaining the SRD inside the repo in case this API changes, but when the API does change I will update this library. So please pin your version if you want to avoid any breaking changes.You can use this library as a CLI tool to generate character sheets from the terminal; seepython -m dnd_character --helpfor details.Installation and UseInstall from PyPI usingpip install dnd-characterSeeexample.pyfor example code on how to use the library.Generate random character sheet text file withpython -m dnd_character --random > mycharactername.txtLicensesThe software is EPL-2.0 and the text for this license is inLICENSEas is standard for software. Originally forked fromPyDnD. The contents ofdnd_character/json_cacheare retrieved from5e-srd-api, and are covered by the Open Game License. Seednd_character/json_cache/OGLv1.0a.txtfor details.Example CodeCreating Characters and MonstersTheclassesmodule has functions for creating all 12 classes from the System Reference Document. Themonstersmodule has a factory function for creating monsters.fromdnd_character.classesimportBardfromdnd_character.monstersimportMonsterfromrandomimportrandintbrianna=Bard(name="Brianna",level=10,)zombie=Monster("zombie")attack_bonus=zombie.actions[0]["attack_bonus"]# Zombie rolls a d20 to attack a Bardifrandint(1,20)+attack_bonus>=brianna.armor_class:print(f"{brianna.name}was hit by{zombie.name}!")else:print(f"{brianna.name}bravely dodged the attack")Leveling and ExperienceThe library should help leveling up characters automatically if you manage the Character'sexperienceattribute. It's simpler to avoid modifying the level directly.fromdnd_characterimportCharacterthor=Character(name="Thor")assertthor.level==1thor.experience+=1000assertthor.level==3assertthor.experience.to_next_level==1700thor.experience+=thor.experience.to_next_levelassertthor.level==4Starting EquipmentCharacters initialized with a class will have the starting equipment of that class, and an attribute calledplayer_optionswhich lists the optional starting equipment.fromdnd_character.classesimportPaladinfromdnd_character.equipmentimportItemfrompprintimportpprintsturm=Paladin(dexterity=10)pprint(sturm.inventory)print(sturm.armor_class)# Remove Chain Mailsturm.remove_item(sturm.inventory[0])print(sturm.armor_class)# New Itemdragonlance=Item('lance')dragonlance.name="Dragonlance®"sturm.give_item(dragonlance)# View optional starting equipmentpprint(sturm.player_options)Using SpellsSpells are represented by _SPELL objects fromdnd_character.spellcasting. The best way to find spells is using thespells_for_class_levelfunction.fromdnd_character.spellcastingimportspells_for_class_levelcantrips=spells_for_class_level('wizard',0)print(f"Cantrips available to a Wizard:")forspellincantrips:print(spell)Characters have lists to store _SPELL objects:spells_preparedspells_knowncantrips_knownCharacters have aspell_slotsdictionary which shows thetotalspell slots. Depletion and rest mechanics are planned for a future version.fromdnd_characterimportWizardfromdnd_character.spellcastingimportSPELLS# Create wizard and teach Identify, a level 1 spellmy_wizard=Wizard(name="Gormwinkle")my_wizard.spells_prepared.append(SPELLS["identify"])# Get total spell slotsspell_slots_level_1=my_wizard.spell_slots["spell_slots_level_1"]print(f"{my_wizard.name}has{spell_slots_level_1}spell slots of 1st level")# Cast until wizard runs out of spell slotswhilespell_slots_level_1>0:print(f"Casting{SPELLS['identify'].name}!")spell_slots_level_1-=1There is currently no way to manage wizard spellbooks or class-specific features such as the Wizard's arcane recovery or the Sorcerer's metamagic.Character ObjectNormal initialization arguments for a Character object:name         (str)
age          (str)
gender       (str)
level        (int): starting level
hp           (int)
alignment    (str): character's two letter alignment (LE, CG, TN, etc.)
description  (str): physical description of player character
background   (str): one-word backstory (e.g., knight, chef, acolyte)
wealth       (int): if None, roll 4d10 for starting gp (gold pieces)
strength     (int): if None, roll 4d6 and drop the lowest
dexterity    (int): if None, roll 4d6 and drop the lowest
constitution (int): if None, roll 4d6 and drop the lowest
wisdom       (int): if None, roll 4d6 and drop the lowest
intelligence (int): if None, roll 4d6 and drop the lowest
charisma     (int): if None, roll 4d6 and drop the lowest
classs    (_CLASS): a D&D class object (e.g., CLASSES['bard'])In addition, the Character object can receive attributes that are normally set automatically, such as the UUID. This is for re-loading the objects from serialized data (viaCharacter(**characterData)) and probably aren't arguments you would write manually into your code.Serializing objectsAll objects in this library can be turned into Python dicts, which can then be turned back into objects. This means characters (along with their items and spells), and monsters as well.dict(object)creates a serializable dict that could be reloaded from text (e.g., suitable for conversion to and from JSON)repr(object)prints a string that would re-construct the Python object if pasted into a REPLstr(object)is not for serialization. It creates a "user-friendly" stringContributingI greatly appreciate feedback about desired features and information about how you're using this library. Please feel free to open an issue or pull request on GitHub! I would be happy to help merge any contributions no matter your skill level.