canismarko / dungeon-sheets

A tool to create character sheets and GM session notes for Dungeons and Dragons fifth edition (D&D 5e).
https://dungeon-sheets.readthedocs.io/en/latest/
GNU General Public License v3.0
160 stars 66 forks source link

Easy inclusion of homebrew spells, etc #89

Closed jonathanvanschenck closed 3 years ago

jonathanvanschenck commented 3 years ago

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
canismarko commented 3 years ago

Glad you like it. I actually thought there was a way to do this, but it looks like it got broken at some point. And yes, you're right in that it isn't documented.

My original plan was to define the homebrew spell (or item, etc.) in the character file itself, then to let it be included directly in the list of spells, something like this:

from dungeonsheets.spells import Spell
class MagicFlask(Spell):
    """A spectral, floating hand appears at a point you choose within
    range holding a flask of finely distilled spirits.

    The flask lasts for the duration or until you dismiss it as an
    action. The flask vanishes if it is ever more than 30 feet away
    from you or if you cast this spell again.

    You can use your action to take a sip of the flask or provide a
    sip to a willing target. You can move the hand up to 30 feet each
    time you use it.

    """
    name = "Magic Flask"
    level = 0
    casting_time = "1 action"
    casting_range = "30 feet"
    components = ('V', 'S')
    materials = """"""
    duration = "1 minute"
    ritual = False
    magic_school = "Conjuration"
    classes = ('Bard', 'Warlock', 'Wizard')

# List of known spells
# Example: spells_prepared = ('magic missile', 'mage armor')
spells_prepared = ('acid splash', 'animate_objects', 'ray of frost', 'light', 'friends',
                   'disguise self', 'identify', 'jump',
                   'blur', 'knock', 'shatter',
                   'blink', 'fly', 'slow',
                   'blight', 'ice storm',
                   'cone of cold', 'magic jar',
                   'teleport', 'maze', 'wish', MagicFlask)  # Todo: Learn some spells

Would that work for you? I think the benefit there is that you can still compile the character sheet with a simple $ makesheets, rather than having to remember to build it with the --homebrew flag.

geckon commented 3 years ago

Hi, my 2 cents: Defining spells directly in a character file is not very practical if you want to have one collection of homebrew spells and use it in many characters. On the other hand something like from my_homebrew import * could work too, right?

jonathanvanschenck commented 3 years ago

Oh, very cool. Yes, I could probably make do with relative imports from my_homebrew import * like geckon suggested. My thought with the CLI was that as a DM managing multiple games/NPC/PC, I could essentially create an environment for each of my games that has a homebrew folder, separate folders for each character, and then batch compile them all. Thanks for the quick response!

canismarko commented 3 years ago

Yeah, the star import should work with the idea I have in mind. Currently the one annoying part would be you get a handful of warnings because it tries to set each homebrew thing as an attribute on the character. Should be solvable with some type checking.

canismarko commented 3 years ago

Ok, so I have a prototype for this working for homebrewed spells. Shouldn't be too difficult to extend it to other mechanics (weapons, infusions, etc). I do plan to spend a little bit of time first standardizing how the different mechanics are resolved so it's not a hodge-podge of complexity.

I think I will suppress the "Setting unknown character attribute" warning if the attribute starts with an underscore, or if it is a class. The second one would alsoincorrectly ignore warnings if someone misspells certain attributes when using homebrew items, eg: shiled = MyHomebrewShield, but that seems like a worthwhile trade-off. Thoughts?

canismarko commented 3 years ago

I got it added. Here's an example character file with the homebrew. You should also be able to have it in a separate file and import it into your character file. I'll write the documentation and bump the version soon.

https://github.com/canismarko/dungeon-sheets/blob/master/examples/homebrewelda.py

canismarko commented 3 years ago

Documentation is done: https://dungeon-sheets.readthedocs.io/en/latest/character_files.html#homebrew

And I bumped the version and uploaded it to pypi.

I'm going to close this issue. If there's something I missed, or if this solution doesn't meet your use case and we need to revisit the --homebrew option, let me know.

jonathanvanschenck commented 3 years ago

This is perfect! Thanks!