Code Monkey home page Code Monkey logo

dungeon-sheets's Introduction

Dungeon Sheets

A tool to create character sheets and session notes for Dungeons and Dragons 5th edition (D&D 5e).

Build status

Test coverage status

Documentation Status

image

Documentation

Documentation can be found on readthedocs.

Docker

You can run this repository directly from a container.

Run the following in a directory with valid character files (such as the examples directory):

$ docker run -it -v $(pwd):/build ghcr.io/canismarko/dungeon-sheets:master

Installation

$ pip install dungeonsheets

Note

Dungeon sheets requires at least python 3.6. This is mostly due to the liberal use of f-strings. If you want to use it with previous versions of python 3, you'll probably have to replace all the f-strings with the older .format() method or string interpolation.

Optional External dependencies

  • You may use pdftk to generate the sheets in PDF format.
  • You will need pdflatex, and a few latex packages, installed to generate the PDF spell pages (optional).

If pdftk is available, it will be used for pdf generation. If not, a fallback python library (pdfrw) will be used. This has some limitations:

  • Produces v1.3 PDF files
  • Not able to flatten PDF forms
  • Will produce separate character-sheets, spell-lists and spell-books.

Different linux distributions have different names for packages. While pdftk is available in Debian and derivatives as pdftk, the package is not available in some RPM distributions, such as Fedora and CentOS. One alternative would be to build your PC sheets using docker.

If the pdflatex command is available on your system, spellcasters will include a spellbook with descriptions of each spell known. If not, then this feature will be skipped.

In order to properly format descriptions for spells/features/etc., some additional latex packages are needed. On Ubuntu these can be install with:

$ sudo apt-get -y install pdftk texlive-latex-base texlive-latex-extra texlive-fonts-recommended

Usage

Each character or set of GM notes is described by a python (or a VTTES JSON) file, which gives many attributes associated with the character. See examples for more information about the character descriptions.

The PDF's can then be generated using the makesheets command. If no filename is given, the current directory will be parsed and any valid files found will be processed. If the --recursive option is used, sub-folders will also be parsed.

$ cd examples
$ makesheets

dungeon-sheets contains definitions for standard weapons and spells, so attack bonuses and damage can be calculated automatically.

Consider using the -F option to include the excellent D&D 5e template for rendering spellbooks, druid wild forms and features pages (https://github.com/rpgtex/DND-5e-LaTeX-Template).

If you'd like a step-by-step walkthrough for creating a new character, just run create-character from a command line and a helpful menu system will take care of the basics for you.

Content Descriptions

The descriptions of content elements (e.g. classes, spells, etc.) are included in docstrings. The descriptions should ideally conform to reStructured text. This allows certain formatting elements to be properly parsed and rendered into LaTeX or HTML:

class Scrying(Spell):
  """You can see and hear a particular creature you choose that is on
  the same plane of existence as you. The target must make a W isdom
  saving throw, which is modified by how well you know the target
  and the sort of physical connection you have to it. If a target
  knows you're casting this spell, it can fail the saving throw
  voluntarily if it wants to be observed.

  Knowledge - Save Modifier
  -------------------------
  - Secondhand (you have heard of the target) - +5
  - Firsthand (you have met the target) - +0
  - Familiar (you know the target well) - -5

  Connection - Save Modifier
  --------------------------
  - Likeness or picture - -2
  - Possession or garment - -4
  - Body part, lock of hair, bit of nail, or the like - -10

  """
  name = "Scrying"
  level = 5
  ...

For content that is not part of the SRD, consider using other sources. As an example, parse5e can be used to retrieve spells.

dungeon-sheets's People

Contributors

94d90b08-c4ef-416c-bf7b-b6c5b7275e6a avatar agrgordon avatar allemangd avatar athos-ribeiro avatar bacook17 avatar bw-mutley avatar canismarko avatar cemkeylan avatar chaussebenjamin avatar danroscigno avatar geckon avatar jeromkiller avatar jonbrouse avatar jrmo14 avatar kloetzl avatar knightmustard avatar majamin avatar matsavage avatar meson800 avatar pjbrs avatar plsaddbloodhunter avatar rkubosz avatar stravajiaxen avatar threnklyn avatar tim-jackins avatar tlater avatar user18130814200115-2 avatar valentin-metz avatar vkerman avatar zarandya avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dungeon-sheets's Issues

Dwarf hit point bonus doesn't get added

Creating a level 1 Hill Dwarf (druid in this case) doesn't add the +1 hit point bonus this race receives. Seems the wisdom bonus doesn't get added either.

Tabaxi have Claws duplicated as a weapon

When a Tabaxi character is generated using create-character, the weapons line in the Python file looks e.g. like this:

weapons = ["Claws", "Shortbow", "Dagger", "Spear"]  # Example: ('shortsword', 'longsword')

And this is the respective section in the PDF:
screenshot_2019-08-12_2150_21:50RRR

After editing the Python file to this:

weapons = ["Shortbow", "Dagger", "Spear", "Claws"]  # Example: ('shortsword', 'longsword')

the PDF still contains the Claws in the first place:
screenshot_2019-08-12_2152_21:52RRR

Therefore, I assume that Claws are added automatically by makesheets no matter what the Python file contains which can cause trouble like in this case.

Armor wrongly calculated

Armor is wrongly calculated when Dex modifier is negative and Heavy Armor is worn. On page 145 PHB it says:

Heavy armor doesn't let you add your Dexterity modifier to your Armor Class, but it also doesn't penelize you if you Dexterity modifier is negative

This can be reproduced by creating a character with negative dex and a heavy armor.

Maybe a new release?

Hi @canismarko, do you by any chance plan to release a new version? Right now pip install dungeonsheets will get me version 0.9.4 released in last May and with that I won't get some pretty useful fixes made recently.

I mean, I know how to install and use the version from current master but it would make things easier.

Also, support for Python 3.8 would be awesome declared in the classifiers!

Thanks a lot in advance.

Handling external dependencies

As pointed in PR #1, there are external dependencies, such as pdftk, which is not readily available in some linux distributions.

I do enjoy the way this package works to build PC sheets, bit I myself cannot use it in my Fedora machine. I did get to build my sheet with docker though, using the following Dockerfile:

FROM debian:testing
RUN apt-get update -y
RUN apt-get install -y python3 pdftk python3-pip texlive-latex-base texlive-fonts-recommended
# Here we copy the whole dungeon-sheets directory into the image
COPY dungeon-sheets /dungeon-sheets
WORKDIR /dungeon-sheets
RUN python3 setup.py install
WORKDIR /sheets
COPY my_char_sheet.py /sheets
RUN makesheets my_char_sheet.py
CMD ['makesheets']

Now, when I wnt to extract the sheet, I can just use docker cp. To update the sheet, I can either rebuild the image or mount a volume somewhere with the updated sheed .py file. Of course this would need some improvements on the docker image side, but this is an alternative for ppl not running debian machines.

The other way around it would be to use something other than pdftk (which depends on old libraries), but this would require a lot of work :(

Hand crossbow isn't defined

I'm getting the following error while trying to add a hand crossbow to a character:

Traceback (most recent call last):
  File "/path/lib/python3.8/site-packages/dungeonsheets/character.py", line 646, in wield_weapon
    NewWeapon = findattr(weapons, weapon)
  File "/path/lib/python3.8/site-packages/dungeonsheets/stats.py", line 38, in findattr
    raise AttributeError(f'{obj} has no attribute {name}')
AttributeError: <module 'dungeonsheets.weapons' from '/path/lib/python3.8/site-packages/dungeonsheets/weapons.py'> has no attribute crossbow, hand

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/some-path/dungeon-sheets/dungeonsheets/create_character.py", line 739, in <module>
    main()
  File "/some-path/dungeon-sheets/dungeonsheets/create_character.py", line 731, in main
    my_app.run()
  File "/path/lib/python3.8/site-packages/npyscreen/apNPSApplication.py", line 30, in run
    return npyssafewrapper.wrapper(self.__remove_argument_call_main)
  File "/path/lib/python3.8/site-packages/npyscreen/npyssafewrapper.py", line 41, in wrapper
    wrapper_no_fork(call_function)
  File "/path/lib/python3.8/site-packages/npyscreen/npyssafewrapper.py", line 97, in wrapper_no_fork
    return_code = call_function(_SCREEN)    
  File "/path/lib/python3.8/site-packages/npyscreen/apNPSApplication.py", line 25, in __remove_argument_call_main
    return self.main()
  File "/path/lib/python3.8/site-packages/npyscreen/apNPSApplicationManaged.py", line 172, in main
    self._THISFORM.edit()
  File "/path/lib/python3.8/site-packages/npyscreen/fmActionForm.py", line 77, in edit
    self.edit_return_value = self.on_ok()
  File "/some-path/dungeon-sheets/dungeonsheets/create_character.py", line 594, in on_ok
    self.parentApp.character.wield_weapon(wpn)
  File "/path/lib/python3.8/site-packages/dungeonsheets/character.py", line 648, in wield_weapon
    raise AttributeError(f'Weapon "{weapon}" is not defined')
AttributeError: Weapon "crossbow, hand" is not defined

Cannot include the dndbook class

I tried adding -F on the commandline to include the dndbook class (as documented in the README) and got an error telling me that there is no such arg.
If you have to excellent dndbook LaTeX template, consider using the -F option to include this template for rendering spellbooks, druid wild forms and features pages

I am using release 0.10.1

Thanks so much for dungeon-sheets, it is really helping me learn DnD.

Missing druid template

Cannot create druids since the druid_shapes_template.tex file is missing.

$ makesheets examples/druid.py
Processing examples/druid...failed
Traceback (most recent call last):
  File "/usr/bin/makesheets", line 11, in <module>
    load_entry_point('dungeonsheets==0.6.1', 'console_scripts', 'makesheets')()
  File "/usr/lib/python3.7/site-packages/dungeonsheets-0.6.1-py3.7.egg/dungeonsheets/make_sheets.py", line 542, in main
    make_sheet(character_file=filename, flatten=(not args.editable))
  File "/usr/lib/python3.7/site-packages/dungeonsheets-0.6.1-py3.7.egg/dungeonsheets/make_sheets.py", line 484, in make_sheet
    create_druid_shapes_pdf(character=char, basename=shapes_base)
  File "/usr/lib/python3.7/site-packages/dungeonsheets-0.6.1-py3.7.egg/dungeonsheets/make_sheets.py", line 110, in create_druid_shapes_pdf
    template = jinja_env.get_template('druid_shapes_template.tex')
  File "/usr/lib/python3.7/site-packages/Jinja2-2.10-py3.7.egg/jinja2/environment.py", line 830, in get_template
    return self._load_template(name, self.make_globals(globals))
  File "/usr/lib/python3.7/site-packages/Jinja2-2.10-py3.7.egg/jinja2/environment.py", line 804, in _load_template
    template = self.loader.load(self, name, globals)
  File "/usr/lib/python3.7/site-packages/Jinja2-2.10-py3.7.egg/jinja2/loaders.py", line 113, in load
    source, filename, uptodate = self.get_source(environment, name)
  File "/usr/lib/python3.7/site-packages/Jinja2-2.10-py3.7.egg/jinja2/loaders.py", line 235, in get_source
    raise TemplateNotFound(template)
jinja2.exceptions.TemplateNotFound: druid_shapes_template.tex

More flexible interface for magic item bonuses

Follow up to #101

Need a way to specify:

  • Saving throw bonuses on a per-ability basis (7b5aac9)
  • Spellcasting DC bonus
  • Spellcasting attack bonus

Possible ways to do this:

  • Create a Character._magic_item_bonuses method that parses the magic items and figures out the bonuses.
  • Make properties (or mabye even methods) on the MagicItem class for each of the above properties.
  • Something else?

Clean up the licensing

Some of the content (everything from the SRD) is covered under the open gaming license, not the GPL. We should include both and indicate which file is covered by which license.

disguise self

I seem to bump into a bug when adding the 'Mask of Many Faces' warlock invocation. It times out on me.

Same thing happens if I try and add the disguise self spell directly.

Restore automated tests

I ran out of credits on travis, so tests have not been run automatically for several months. Maybe switch to github actions or something like that?

Easy inclusion of homebrew spells, etc

Love this repo!
Reading through the documentation, perhaps I missed something, but it doesn't seem like there is an easy way to include homebrew spells, features, classes, etc without actually changing the source code. It would be pretty cool if there was a cli option in makesheets where you could point to an external file containing additional spells that would get compiled in (perhaps even overriding the default spell to tweek mechanics).
e.g.

makesheets --homebrew homebrew_spells.py

Remove transparency of unprepared spells

What if we make unprepared spells also solid black as prepared spells?

I play in dnd campaigns as wizard and druid and I found a slight inconvenience. I have a list of known spells and prepared spells. Prepared spells are behaving as I want: spells are printed solid black and marked as prepared on character sheet.
The problem occurs with unprepared spells. These spells are listed and unmarked on spell card in character sheet but they are printed as grey/transparent in spell descriptions. I get the idea behind this -- it is meant to quickly search for a description of a prepared spell. But in a real life use case it is not working well, at least for me.
Let's say I attend a session with my printed character sheet with spells separated as prepared and unprepared. As session goes, there is at least one long rest, meaning that I change my prepared spells. Now one or some spells that I have prepared have a transparent and quite unreadable description.
IMO the best use of spells in character sheet is to make them all unprepared, but then they all print in unreadable gray. I can mark prepared spells on a printed sheet with a pencil and change them during session.

What we can make:

  • change the transparency/gray color to solid black for unprepared spells (permanent solution) or
  • add an option in character.py file for user to choose the color of unprepared spells

ps for a moment I thought that it could be a simplified spell list without separating it to prepared and unprepared, but for example my circle of spores druid has some spells that are always prepared, so imo we should keep the separation of prepared and unprepared spells

unicode characters create errors with pdflatex

When creating the wizard spellbook example sheet, pdflatex crashes because of unicode special characters in the python classes.

Reproduction:
makesheets wizard1.py - errors are in Teleport spell, when calling pdflatex manually:

pdflatex --output-directory $HOME/Documents/src/dungeon-sheets/examples wizard1_spellbook.tex

Versions:

pdflatex --version
pdfTeX 3.14159265-2.6-1.40.20

python --version
Python 3.8.1

Running under Linux.

All but two characters are special space characters 'U+2003' , see here. When replaced pdflatex works fine.

Here is a list of occurences:

dungeonsheets/spells/spells_a.py:165:    Weapons. You grow claws, fangs, spines, horns, or a different natural weapon of 
dungeonsheets/spells/spells_a.py:246:    turns, you can use your actions to transform affected creatures into new forms. 
dungeonsheets/spells/spells_a.py:260:     
dungeonsheets/spells/spells_a.py:431:     Any 
dungeonsheets/spells/spells_a.py:483:    antipathy or sympathy as the aura’s effect. 
dungeonsheets/spells/spells_a.py:487:     creatures of the kind you designated to feel an intense urge to leave the area 
dungeonsheets/spells/spells_a.py:488:    and avoid the target. When such a creature can see the target or comes within 60
dungeonsheets/spells/spells_a.py:489:     feet of it, the creature must succeed on a Wisdom saving throw or 
dungeonsheets/spells/spells_a.py:490:    become frightened. The creature remains frightened while it can see the target 
dungeonsheets/spells/spells_a.py:491:    or is within 60 feet of it. While frightened by the target, the creature must 
dungeonsheets/spells/spells_a.py:492:    use its movement to move to the nearest safe spot from which it can’t see the 
dungeonsheets/spells/spells_a.py:493:    target. If the creature moves more than 60 feet from the target and can’t see 
dungeonsheets/spells/spells_a.py:494:    it, the creature is no longer frightened, but the creature becomes frightened 
dungeonsheets/spells/spells_a.py:495:    again if it regains sight of the target or moves within 60 feet of it. 
dungeonsheets/spells/spells_a.py:499:    The enchantment causes the specified creatures to feel an intense 
dungeonsheets/spells/spells_a.py:500:    urge to approach the target while within 60 feet of it or able to see it. When 
dungeonsheets/spells/spells_a.py:501:    such a creature can see the target or comes within 60 feet o fit, the creature 
dungeonsheets/spells/spells_a.py:502:    must succeed on a Wisdom saving throw or use its movement on each of its turns 
dungeonsheets/spells/spells_a.py:503:    to enter the area or move within reach of the target. When the creature has done
dungeonsheets/spells/spells_a.py:504:     so, it can’t willingly move away from the target. If the target damages or 
dungeonsheets/spells/spells_a.py:505:    otherwise harms an affected creature, the affected creature can make a 
dungeonsheets/spells/spells_a.py:506:    Wisdom saving throw to end the effect, as described below. 
dungeonsheets/spells/spells_a.py:510:    If an affected creature ends its turn while not within 60 feet of the target 
dungeonsheets/spells/spells_a.py:511:    or able to see it, the creature makes a Wisdom saving throw. On a successful 
dungeonsheets/spells/spells_a.py:512:    save, the creature is no longer affected by the target and recognizes the 
dungeonsheets/spells/spells_a.py:513:    feeling of repugnance or attraction as magical. In addition, a creature affected
dungeonsheets/spells/spells_a.py:514:     by the spell is allowed another Wisdom saving throw every 24 hours while the 
dungeonsheets/spells/spells_a.py:515:    spell persists. 
dungeonsheets/spells/spells_a.py:516:    A creature that successfully saves against this effect is 
dungeonsheets/spells/spells_a.py:517:    immune to it for 1 minute, after which time it can be affected again.
dungeonsheets/spells/spells_a.py:562:     The portals are two-
dungeonsheets/spells/spells_a.py:566:     
dungeonsheets/spells/spells_a.py:659:    """You and up to eight willing creatures within range project your astral bodies 
dungeonsheets/spells/spells_a.py:660:    into the Astral Plane (the spell fails and the casting is wasted if you are 
dungeonsheets/spells/spells_a.py:661:    already on that plane). 
dungeonsheets/spells/spells_a.py:662:    The material body you leave behind is unconscious and 
dungeonsheets/spells/spells_a.py:663:    in a state of suspended animation; it doesn’t need food or air and doesn’t age. 
dungeonsheets/spells/spells_a.py:666:    Your astral body resembles your mortal form in almost every way, replicating 
dungeonsheets/spells/spells_a.py:667:    your game statistics and possessions. The principal difference is the addition 
dungeonsheets/spells/spells_a.py:668:    of a silvery cord that extends from between your shoulder blades and trails 
dungeonsheets/spells/spells_a.py:669:    behind you, fading to invisibility after 1 foot. This cord is your tether to 
dungeonsheets/spells/spells_a.py:670:    your material body. As long as the tether remains intact, you can find your 
dungeonsheets/spells/spells_a.py:671:    way home. If the cord is cut something that can happen only when an effect 
dungeonsheets/spells/spells_a.py:672:    specifically states that it does your soul and body are separated, killing you 
dungeonsheets/spells/spells_a.py:673:    instantly. 
dungeonsheets/spells/spells_a.py:675:    Your astral form can freely travel through the Astral Plane and can
dungeonsheets/spells/spells_a.py:676:     pass through portals there leading to any other plane. If you enter a new plane
dungeonsheets/spells/spells_a.py:677:     or return to the plane you were on when casting this spell, your body 
dungeonsheets/spells/spells_a.py:678:    and possessions are transported along the silver cord, allowing you to re-enter 
dungeonsheets/spells/spells_a.py:679:    your body as you enter the new plane. Your astral form is a separate 
dungeonsheets/spells/spells_a.py:680:    incarnation. Any damage or other effects that apply to it have no effect on 
dungeonsheets/spells/spells_a.py:681:    your physical body, nor do they persist when you return to it. The spell ends 
dungeonsheets/spells/spells_a.py:682:    for you and your companions when you use your action to dismiss it. When the 
dungeonsheets/spells/spells_a.py:683:    spell ends, the affected creature returns to its physical body, and it awakens. 
dungeonsheets/spells/spells_a.py:686:    The spell might also end early for you or one of your companions. A successful
dungeonsheets/spells/spells_a.py:687:     dispel magic spell used against an astral or physical body ends the spell for 
dungeonsheets/spells/spells_a.py:688:    that creature. If a creature’s original body or its astral form drops to 0 hit 
dungeonsheets/spells/spells_a.py:689:    points, the spell ends for that creature. If the spell ends and the silver cord 
dungeonsheets/spells/spells_a.py:690:    is intact, the cord pulls the creature’s astral form back to its body, ending 
dungeonsheets/spells/spells_a.py:691:    its state of suspended animation. If you are returned to your body prematurely, 
dungeonsheets/spells/spells_a.py:692:    your companions remain in their astral forms and must find their own way back to
dungeonsheets/spells/spells_a.py:693:     their bodies, usually by dropping to 0 hit points.
dungeonsheets/spells/spells_b.py:211:    Clenched Fist 
dungeonsheets/spells/spells_b.py:269:     When a creature enters the wall’s area for the first time on a turn
dungeonsheets/spells/spells_c.py:421:     At any time after the clone matures, if 
dungeonsheets/spells/spells_c.py:534:    Approach The target moves toward you 
dungeonsheets/spells/spells_c.py:537:    Drop The target drops whatever it is holding and then ends its turn.
dungeonsheets/spells/spells_c.py:539:    Flee The target spends its turn moving away from you by the fastest available 
dungeonsheets/spells/spells_c.py:541:    Grovel The target falls prone and then ends its turn.
dungeonsheets/spells/spells_c.py:542:    Halt The target 
dungeonsheets/spells/spells_c.py:743:     1. The creature uses 
dungeonsheets/spells/spells_c.py:747:     
dungeonsheets/spells/spells_c.py:755:     9-10. The creature can act and move 
dungeonsheets/spells/spells_c.py:950:     You choose one the following options for what appears: 
dungeonsheets/spells/spells_c.py:1014:     •  One 
dungeonsheets/spells/spells_c.py:1016:     •  Two fey creatures of challenge 
dungeonsheets/spells/spells_c.py:1018:     •  Four fey creatures of challenge rating 1/2 or lower 
dungeonsheets/spells/spells_c.py:1019:     •  
dungeonsheets/spells/spells_c.py:1064:     the spell ends. The DM answers each question with one word, such as yes, �
dungeonsheets/spells/spells_c.py:1065:    no, maybe, never, irrelevant, or unclear (if the entity doesn’t know �
dungeonsheets/spells/spells_c.py:1098:    Sickness 
dungeonsheets/spells/spells_c.py:1103:    Filth Fever 
dungeonsheets/spells/spells_c.py:1144:    You cast that spell called the �
dungeonsheets/spells/spells_c.py:1145:    contingent spell as part of casting contingency, expending spell slots for �
dungeonsheets/spells/spells_c.py:1249:    Redirect Flow 
dungeonsheets/spells/spells_c.py:1258:    Whirlpool 
dungeonsheets/spells/spells_c.py:1274:    vortex, the object takes 2d8 bludgeoning damage, this damage occurs each round 
dungeonsheets/spells/spells_c.py:1523:    Destroy Water 
dungeonsheets/spells/spells_d.py:66:    illuminate it. 
dungeonsheets/spells/spells_d.py:379:    as "200 feet straight downward" or "upward to the northwest at a 45-degree �
dungeonsheets/spells/spells_d.py:380:    angle, 300 feet". �
dungeonsheets/spells/spells_d.py:405:    """You make yourself – including your clothing, armor, weapons, and other �
dungeonsheets/spells/spells_d.py:406:    belongings on your person – look different until the spell ends or until you �
dungeonsheets/spells/spells_d.py:480:    Break  Enchantment 
dungeonsheets/spells/spells_d.py:486:    Dismissal 
dungeonsheets/spells/spells_d.py:605:     •  50 hit 
dungeonsheets/spells/spells_d.py:607:     •  40 hit points or fewer: deafened and
dungeonsheets/spells/spells_d.py:609:     •  30 hit points or fewer: blinded, deafened, and 
dungeonsheets/spells/spells_d.py:611:     •  20 hit points or fewer: killed instantly 
dungeonsheets/spells/spells_d.py:687:    and general course of action, such as "Attack that creature", "Run over �
dungeonsheets/spells/spells_d.py:688:    there", or "Fetch that object". If the creature completes the order and �
dungeonsheets/spells/spells_d.py:728:    general course of action, such as "Attack that creature", "Run over there", �
dungeonsheets/spells/spells_d.py:729:    or "Fetch that object". If the creature completes the order and doesn’t �
dungeonsheets/spells/spells_d.py:924:    manifest as a golden orb  for clear skies, a cloud for rain, falling snowflakes 
dungeonsheets/spells/spells_d.py:930:    the sound of a small animal, or the faint odor of skunk. The effect  must fit in
dungeonsheets/spells/spells_e.py:270:    Enlarge 
dungeonsheets/spells/spells_e.py:281:    Reduce 
dungeonsheets/spells/spells_e.py:498:    Asleep 
dungeonsheets/spells/spells_e.py:503:    Panicked 
dungeonsheets/spells/spells_e.py:510:    Sickened 
dungeonsheets/spells/spells_f.py:467:    spreads around corners. It ignites flammable objects in the area that aren’t 
dungeonsheets/spells/spells_g.py:493:     Place dancing lights in four corridors. You can designate a simple program that
dungeonsheets/spells/spells_g.py:498:    • Place stinking cloud in two locations. The vapors appear in the 
dungeonsheets/spells/spells_g.py:499:    places you designate; they return within 10 minutes if dispersed by wind while 
dungeonsheets/spells/spells_g.py:500:    guards and wards lasts.
dungeonsheets/spells/spells_g.py:503:    • Place a suggestion in one location. You select an area of up to 5 feet 
dungeonsheets/spells/spells_g.py:506:    suggestion mentally.
dungeonsheets/spells/spells_g.py:508:    The whole warded area radiates magic. A dispel magic cast 
dungeonsheets/spells/spells_g.py:509:    on a specific effect, if successful, removes only that effect.
dungeonsheets/spells/spells_g.py:511:    permanently guarded and warded structure by casting this spell there every 
dungeonsheets/spells/spells_g.py:512:    day for one year.
dungeonsheets/spells/spells_i.py:169:    """You create a magical restraint to hold a creature that you can see within range.
dungeonsheets/spells/spells_i.py:171:    The target must succeed on a Wisdom saving throw or be bound by the spell; if 
dungeonsheets/spells/spells_i.py:172:    it succeeds, it is immune to this spell if you cast it again. While affected by 
dungeonsheets/spells/spells_i.py:173:    this spell, the creature doesn't need to breathe, eat, or drink, and it doesn’t 
dungeonsheets/spells/spells_i.py:174:    age. Divination spells can’t locate or perceive the target.
dungeonsheets/spells/spells_i.py:177:    spell, you choose one of the following forms of imprisonment. 
dungeonsheets/spells/spells_i.py:181:    target is entombed far beneath the earth in a sphere of magical force that is 
dungeonsheets/spells/spells_i.py:182:    just large enough to contain the target. Nothing can pass through the 
dungeonsheets/spells/spells_i.py:183:    sphere, nor can any creature teleport or use planar travel to get into or out of
dungeonsheets/spells/spells_i.py:185:    The special component for this version of the spell is a small mithral orb.
dungeonsheets/spells/spells_i.py:189:    Heavy chains, firmly rooted in the ground, hold the target in place. 
dungeonsheets/spells/spells_i.py:191:    any means until then.
dungeonsheets/spells/spells_i.py:193:    a fine chain of precious metal.
dungeonsheets/spells/spells_i.py:197:    into a tiny demiplane that is warded against teleportation and planar travel. 
dungeonsheets/spells/spells_i.py:198:    The demiplane can be a labyrinth, a cage, a tower, or any similar confined 
dungeonsheets/spells/spells_i.py:199:    structure or area of your choice.
dungeonsheets/spells/spells_i.py:201:    spell is a miniature representation of the prison made from jade.
dungeonsheets/spells/spells_i.py:205:    The target shrinks to a height of 1 inch and is imprisoned inside a 
dungeonsheets/spells/spells_i.py:207:    normally (allowing the target to see out and other creatures to see in), but 
dungeonsheets/spells/spells_i.py:208:    nothing else can pass through, even by means of teleportation or planar travel. 
dungeonsheets/spells/spells_i.py:209:    The gemstone can’t be cut or broken while the spell remains in effect.
dungeonsheets/spells/spells_i.py:211:    special component for this version of the spell is a large, transparent 
dungeonsheets/spells/spells_i.py:212:    gemstone, such as a corundum, diamond, or ruby.
dungeonsheets/spells/spells_i.py:218:    spell consists of rare soporific herbs. 
dungeonsheets/spells/spells_i.py:222:     the spell, in any of its versions, you can specify a condition that will cause 
dungeonsheets/spells/spells_i.py:223:    the spell to end and release the target. The condition can be as specific or as 
dungeonsheets/spells/spells_i.py:224:    elaborate as you choose, but the DM must agree that the condition is reasonable 
dungeonsheets/spells/spells_i.py:225:    and has a likelihood of coming to pass. The conditions can be based on a 
dungeonsheets/spells/spells_i.py:226:    creature’s name, identity, or deity but otherwise must be based on 
dungeonsheets/spells/spells_i.py:227:    observable actions or qualities and not based on intangibles such as level, 
dungeonsheets/spells/spells_i.py:231:    cast as a 9th-level spell, targeting either the prison or the special component 
dungeonsheets/spells/spells_i.py:234:    You can use a particular special component to create only 
dungeonsheets/spells/spells_i.py:235:    one prison at a time. If you cast the spell again using the same component, the 
dungeonsheets/spells/spells_m.py:857:    to the terrain’s true form however, all other elements of the illusion remain, 
dungeonsheets/spells/spells_m.py:858:    so while the creature is aware of the illusion’s presence, the creature can 
dungeonsheets/spells/spells_m.py:859:    still physically interact with the illusion.
dungeonsheets/spells/spells_p.py:69:    exists and comes up with some other explanation for its fallit was pushed, it �
dungeonsheets/spells/spells_p.py:471:     -You create an 
dungeonsheets/spells/spells_p.py:596:    """A shimmering, multicolored plane of light forms a vertical opaque wallup to 90 �
dungeonsheets/spells/spells_p.py:597:    feet long, 30 feet high, and 1 inch thickcentered on a point you can seewithin �
dungeonsheets/spells/spells_r.py:161:    d100  Race
dungeonsheets/spells/spells_s.py:96:    Knowledge                 Save 
dungeonsheets/spells/spells_s.py:100:    the target)      +0
dungeonsheets/spells/spells_s.py:105:    Likeness or picture               -2
dungeonsheets/spells/spells_s.py:1510:    turns, if able. 
dungeonsheets/spells/spells_t.py:114:        Mishap  Similar Area  Off Target  On Target
dungeonsheets/spells/spells_t.py:115:    Permanent circle   —       — 
dungeonsheets/spells/spells_t.py:116:            —     01-100
dungeonsheets/spells/spells_t.py:117:    Associated object    —       —       —       01-100
dungeonsheets/spells/spells_t.py:119:    familiar     01-05      06-13     14-24    25-100
dungeonsheets/spells/spells_t.py:120:    Seen casually     01-33      
dungeonsheets/spells/spells_t.py:122:    Viewed once    01-43      44-53     54-73    74-100
dungeonsheets/spells/spells_t.py:124:    Description       01-43      44-53     54-73    74-100
dungeonsheets/spells/spells_t.py:126:          51-100      —      —
dungeonsheets/spells/spells_w.py:480:    3d6 × 10 feet away from it in a random direction.

Can't run make_sheets.py directly

There are relative imports and maybe other issues. I'm willing to fix it.

@canismarko I have two questions.

  • Are you against me removing relative imports in the whole project if possible? They can be a bit messy sometimes.
  • Are you against me moving the two runnables (create_character.py and make_sheets.py) into the top project directory which is a bit more common alignment?

Thanks for your response!

Homebrew: Cannot specify a weapon subclass

I am trying to add a new weapon, and I would like to be able to mark it as a SimpleWeapon as my char is proficient with SimpleWeapons. I tried the below, but it fails, and I cannot figure out how to include SimpleWeapon. Is there a way to specify that a weapon is a simpleweapon?

class BlueSting(mechanics.SimpleWeapon):
    name = "Blue Sting"
    cost = "1000 gp"
    base_damage = "1d6"
    attack_bonus = 1
    damage_bonus = 1
    damage_type = "p"
    weight = 1
    ability = "dexterity"

Clean up portrait handling

@vincentmalloy added the ability to include character portraits. There's a few things to improve when there's time:

  • Allow other file extensions (and maybe even specific filenames)
  • Make sure it plays well with other image dimensions.
  • Include portraits in the new epub output.

create-character errors out at end

I set up a venv and installed dungeonsheets. I ran through the create-character utility and when I got to the end, instead of writing out my character.py file, I got the following error:

Traceback (most recent call last):
  File "/usr/local/bin/create-character", line 10, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.7/site-packages/dungeonsheets/create_character.py", line 383, in main
    my_app.save_character()
  File "/usr/local/lib/python3.7/site-packages/dungeonsheets/create_character.py", line 79, in save_character
    ).get_template(src_filename).render(context)
  File "/usr/local/lib/python3.7/site-packages/jinja2/environment.py", line 830, in get_template
    return self._load_template(name, self.make_globals(globals))
  File "/usr/local/lib/python3.7/site-packages/jinja2/environment.py", line 804, in _load_template
    template = self.loader.load(self, name, globals)
  File "/usr/local/lib/python3.7/site-packages/jinja2/loaders.py", line 113, in load
    source, filename, uptodate = self.get_source(environment, name)
  File "/usr/local/lib/python3.7/site-packages/jinja2/loaders.py", line 187, in get_source
    raise TemplateNotFound(template)
jinja2.exceptions.TemplateNotFound: character_template.txt

Anyone else get this?

Multiclass attribute override issues

First of all, thank you for such a complete system, but I'm afraid my first test character was doomed to break it as all users tend to do. So far, I've been able to correct a few of the issues, but I've been unable to figure these out. I'm working with a Lizardfolk Bard 1 / Monk 1 here so don't feel bad about not expecting these triggers.

  1. Moderate issue: When multiclassed into Monk, unarmed attacks should get the max(str,dex) attack and damage bonus option but this does not seem to apply to Bite (I have not verified Claws/Talons yet, but assume they have the same issue). My attempts to correct this issue have worked for standard weapons, but I haven't found the solution for skills like Bite yet. Other weapons show the correct values, so it isn't a major problem but accuracy would be preferred.
  2. Minor annoyance: Speed is fixed to a single line so "30 (30 swim)" is hard to read on the created pdf. I have not found a way to make this a multiline entry that is more legible.
  3. Found and fixed: Lizardfolk were missing the "num_skill_choices = 2" option for their skill choices on character creation in race.py.
  4. Found and fixed: Natural Armor and Unarmored Defense shouldn't both apply, but I was getting a +1ac boost when I multi-classed. I added "and not char.has_feature(NaturalArmor)" to line 149 of stats.py which of course only meets my criteria, but fixed it for this case. There are likely others that need a better solution.
  5. Found and fixed: proficiencies_text was duplicated for anything both classes used. I added"all_proficiences = list(set(all_proficiences))" at line 616 in character.py as a quick fix, but both lists still get the initial capitalization so it still looks a bit weird.

Magic Itens don't add Saving Throws bonuses

Magic itens like Ring of Protection gives Saving Throw bonuses but dungeon-sheets does not register them. I've fixed it locally by including a st_bonus attribute for items with this property and modifying the Ability class in the same way it is done for AC bonus:

saving_throw = modifier
for mitem in entity.magic_items:
    if hasattr(mitem, "st_bonus"):
        saving_throw += mitem.st_bonus

Compatibility with foundry VTT export

Dungeonsheets can import .json objects from foundry vtt, but they don't quite work properly in some edge cases. Here are the current problems.

  • "Enlarge/Reduce" does not map to "Enlargereduce" spell.
  • Sollys's Rival Intern background
  • Sollys's weapons imported from roll20 to foundry.
  • Handir's unarmed strike
  • Prepared spells (Phifarix)

Add capability to rst_to_latex parser

The rst_to_latex function takes reStructured text and converts it to LaTeX. Currently, it only supports some reST features, which means the LaTeX output is poorly formatted. We should expand the features that get parsed so the spell/etc. descriptions are more readable.

  • bullet lists
  • enumerated lists
  • definition lists
  • field lists
  • tables
  • block quotes
  • bold
  • italics
  • Headings
  • verb

Purpose of parse_json.py?

Hi what is the purpose of parse_json.py?

First of all, it uses an absolute path apparently only valid on @canismarko's computer:

INFILE = '/home/mwolf/Documents/dungeons_and_dragons/spells.json'

Also, there is a syntax error in the regex there:

components_re = re.compile('([VSM])?[, ]*([VSM])?[, ]*([VSM])?[, ]*'
                           '(?:\(([-a-zA-Z ,.0-9;\'-()]+)\))?')

Why is Human race missing?

I can only see this:

Screenshot from 2020-04-29 23-37-04

Why is Human race missing? I mean from the sources I know that Rashemi is the same but what is the reason behind this? Thanks a lot in advance!

Can you tell me how to format my equipment list please?

Hi,
Thanks again for Dungeon Sheets. I am really enjoying using it, and I am learning quite a bit about the DnD rules by working through this. Here is how my equipment list looks now:

image

I would like to be able to format it like the way you have the features (right column) formated (as a bulleted list). If you could point me to a file to edit I will give it a shot and write a pull request. It has been ten or fifteen years since I wrote any LaTeX, but I will give it a go!

Add support for climbing speed

Speed, swimming speed and flying speed are all supported by monsters.py. It would be nice to have also climbing speed there.

Many Sources Missing

Over the past few years, Wizards of the Coast has launched several books that provided extra classes and other such information, such as Eberron: Rising From The Last War, which introduced the Warforged race and the Artificer class officially into D&D's set.

Duplicated racial and class-based skills

I can see this while creating a kenku monk:
Screenshot from 2020-04-26 01-26-49

I suppose the duplication comes from the fact that it's listed lower case in race and upper case in class, e.g. acrobatics v. Acrobatics. But that remains to be confirmed.

create-character fails if no armor option is selected

Traceback (most recent call last):
  File "/home/theger/tmp/dungeon-sheets/venv/bin/create-character", line 11, in <module>
    sys.exit(main())
  File "/home/theger/tmp/dungeon-sheets/venv/lib64/python3.6/site-packages/dungeonsheets/create_character.py", line 732, in main
    my_app.run()
  File "/home/theger/tmp/dungeon-sheets/venv/lib64/python3.6/site-packages/npyscreen/apNPSApplication.py", line 30, in run
    return npyssafewrapper.wrapper(self.__remove_argument_call_main)
  File "/home/theger/tmp/dungeon-sheets/venv/lib64/python3.6/site-packages/npyscreen/npyssafewrapper.py", line 41, in wrapper
    wrapper_no_fork(call_function)
  File "/home/theger/tmp/dungeon-sheets/venv/lib64/python3.6/site-packages/npyscreen/npyssafewrapper.py", line 97, in wrapper_no_fork
    return_code = call_function(_SCREEN)    
  File "/home/theger/tmp/dungeon-sheets/venv/lib64/python3.6/site-packages/npyscreen/apNPSApplication.py", line 25, in __remove_argument_call_main
    return self.main()
  File "/home/theger/tmp/dungeon-sheets/venv/lib64/python3.6/site-packages/npyscreen/apNPSApplicationManaged.py", line 172, in main
    self._THISFORM.edit()
  File "/home/theger/tmp/dungeon-sheets/venv/lib64/python3.6/site-packages/npyscreen/fmActionForm.py", line 77, in edit
    self.edit_return_value = self.on_ok()
  File "/home/theger/tmp/dungeon-sheets/venv/lib64/python3.6/site-packages/dungeonsheets/create_character.py", line 632, in on_ok
    my_armor = self.armor.get_selected_objects()[0]
IndexError: list index out of range

Either selecting one option (e.g. "no armor") should be enforced, or one of the options should be made default, or at least this should fail gracefully.

Combine hit dice for multiclassing

From @pucknut2k1: Not a significant issue, but Bard and Monk both use a 1d8 Hit Die. After Multiclassing, it lists as 1d8 + 1d8 rather than 2d8. I have not investigated this yet to see how difficult it would be to rectify.

`makesheets` on examples failing

 $ git clone https://github.com/bacook17/dungeon-sheets
Cloning into 'dungeon-sheets'...
remote: Enumerating objects: 1273, done.
remote: Total 1273 (delta 0), reused 0 (delta 0), pack-reused 1273
Receiving objects: 100% (1273/1273), 8.50 MiB | 1.50 MiB/s, done.
Resolving deltas: 100% (943/943), done.

 $ cd dungeon-sheets/examples/

 $ ls
barbarian1.pdf  bard2.py        druid2.pdf      makefile        multiclass1.py  ranger2.pdf     rogue2.py       warlock2.pdf
barbarian1.py   cleric1.pdf     druid2.py       monk1.pdf       multiclass2.pdf ranger2.py      sorceror1.pdf   warlock2.py
barbarian2.pdf  cleric1.py      druid3.py       monk1.py        multiclass2.py  ranger3.pdf     sorceror1.py    wizard1.pdf
barbarian2.py   cleric2.pdf     fighter1.pdf    monk2.pdf       paladin1.py     ranger3.py      sorceror2.pdf   wizard1.py
bard1.pdf       cleric2.py      fighter1.py     monk2.py        paladin2.py     rogue1.pdf      sorceror2.py    wizard2.pdf
bard1.py        druid1.pdf      fighter2.pdf    multiclass      ranger1.pdf     rogue1.py       warlock1.pdf    wizard2.py
bard2.pdf       druid1.py       fighter2.py     multiclass1.pdf ranger1.py      rogue2.pdf      warlock1.py

 $ makesheets
Processing rogue2...done
Processing barbarian1...done
Processing fighter2...done
Processing warlock1...done
Processing wizard2...done
Processing sorceror1...done
Processing paladin1...done
Processing ranger2...done
Processing monk1...done
Processing ranger3...done
Processing druid1...done
Processing multiclass1...failed
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.7/bin/makesheets", line 8, in <module>
    sys.exit(main())
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/dungeonsheets/make_sheets.py", line 554, in main
    make_sheet(character_file=filename, flatten=(not args.editable), debug=args.debug)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/dungeonsheets/make_sheets.py", line 453, in make_sheet
    character = _char.Character.load(character_file)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/dungeonsheets/character.py", line 722, in load
    char = Character(**char_props)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/dungeonsheets/character.py", line 159, in __init__
    self.set_attrs(**attrs)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/dungeonsheets/character.py", line 474, in set_attrs
    self.wear_armor(val)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/dungeonsheets/character.py", line 610, in wear_armor
    NewArmor = findattr(armor, new_armor)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/dungeonsheets/stats.py", line 38, in findattr
    raise AttributeError(f'{obj} has no attribute {name}')
AttributeError: <module 'dungeonsheets.armor' from '/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/dungeonsheets/armor.py'> has no attribute studded armor

Unnecessary dashes

There is a lot of words like Du-elists or darkvi-sion probably due to copy-and-pasting. Let me fix that ;)

create-character: typo ("featurs") makes it fail

Traceback (most recent call last):
  File "/home/theger/tmp/dungeon-sheets/venv/bin/create-character", line 11, in <module>
    sys.exit(main())
  File "/home/theger/tmp/dungeon-sheets/venv/lib64/python3.6/site-packages/dungeonsheets/create_character.py", line 732, in main
    my_app.run()
  File "/home/theger/tmp/dungeon-sheets/venv/lib64/python3.6/site-packages/npyscreen/apNPSApplication.py", line 30, in run
    return npyssafewrapper.wrapper(self.__remove_argument_call_main)
  File "/home/theger/tmp/dungeon-sheets/venv/lib64/python3.6/site-packages/npyscreen/npyssafewrapper.py", line 41, in wrapper
    wrapper_no_fork(call_function)
  File "/home/theger/tmp/dungeon-sheets/venv/lib64/python3.6/site-packages/npyscreen/npyssafewrapper.py", line 97, in wrapper_no_fork
    return_code = call_function(_SCREEN)    
  File "/home/theger/tmp/dungeon-sheets/venv/lib64/python3.6/site-packages/npyscreen/apNPSApplication.py", line 25, in __remove_argument_call_main
    return self.main()
  File "/home/theger/tmp/dungeon-sheets/venv/lib64/python3.6/site-packages/npyscreen/apNPSApplicationManaged.py", line 172, in main
    self._THISFORM.edit()
  File "/home/theger/tmp/dungeon-sheets/venv/lib64/python3.6/site-packages/npyscreen/fmActionForm.py", line 77, in edit
    self.edit_return_value = self.on_ok()
  File "/home/theger/tmp/dungeon-sheets/venv/lib64/python3.6/site-packages/dungeonsheets/create_character.py", line 702, in on_ok
    self.parentApp.character.features_and_traits = self.featurs.value
AttributeError: 'PersonalityForm' object has no attribute 'featurs'

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.