tassaron / dnd-character

library for making Dungeons & Dragons 5e characters as serializable data
https://pypi.org/project/dnd-character/
Eclipse Public License 2.0
45 stars 17 forks source link

Missing class-specific features #19

Closed tassaron closed 1 year ago

tassaron commented 1 year ago

These are currently not stored in the Character object, although they exist in the class data.

>>> from pprint import pprint
>>> from dnd_character.SRD import SRD_class_levels
>>> for classs in SRD_class_levels:
...     print(f"SRD_class_levels[{classs}][0]['class_specific'] = ")
...     pprint(SRD_class_levels[classs][0]['class_specific'])
...     print()
... 

SRD_class_levels[barbarian][0]['class_specific'] = 
{'brutal_critical_dice': 0, 'rage_count': 2, 'rage_damage_bonus': 2}

SRD_class_levels[bard][0]['class_specific'] = 
{'bardic_inspiration_die': 6,
 'magical_secrets_max_5': 0,
 'magical_secrets_max_7': 0,
 'magical_secrets_max_9': 0,
 'song_of_rest_die': 0}

SRD_class_levels[cleric][0]['class_specific'] = 
{'channel_divinity_charges': 0, 'destroy_undead_cr': 0}

SRD_class_levels[druid][0]['class_specific'] = 
{'wild_shape_fly': False, 'wild_shape_max_cr': 0, 'wild_shape_swim': False}

SRD_class_levels[fighter][0]['class_specific'] = 
{'action_surges': 0, 'extra_attacks': 0, 'indomitable_uses': 0}

SRD_class_levels[monk][0]['class_specific'] = 
{'ki_points': 0,
 'martial_arts': {'dice_count': 1, 'dice_value': 4},
 'unarmored_movement': 0}

SRD_class_levels[paladin][0]['class_specific'] = 
{'aura_range': 0}

SRD_class_levels[ranger][0]['class_specific'] = 
{'favored_enemies': 1, 'favored_terrain': 1}

SRD_class_levels[rogue][0]['class_specific'] = 
{'sneak_attack': {'dice_count': 1, 'dice_value': 6}}

SRD_class_levels[sorcerer][0]['class_specific'] = 
{'creating_spell_slots': [], 'metamagic_known': 0, 'sorcery_points': 0}

SRD_class_levels[warlock][0]['class_specific'] = 
{'invocations_known': 0,
 'mystic_arcanum_level_6': 0,
 'mystic_arcanum_level_7': 0,
 'mystic_arcanum_level_8': 0,
 'mystic_arcanum_level_9': 0}

SRD_class_levels[wizard][0]['class_specific'] = 
{'arcane_recovery_levels': 1}
gergo-szabo commented 1 year ago

Some of these class features would deserve some supporting features. For example monk ki point managment. Others are not so important because they are not dynamic. Eg.: Rouge sneak attack information -> 1d6

gergo-szabo commented 1 year ago

I propose to store these class specific features with some extra data. In many cases the values show the maximum count for a special ability (barbarian - rage_count). I would modify the keys from: {'brutal_critical_dice': 0, 'rage_count': 2, 'rage_damage_bonus': 2} to: {'brutal_critical_dice': 0, 'max_rage_count': 2, 'available_rage_count': 2, 'rage_damage_bonus': 2}

If you agree then I will implement the Character.class_specific_features variable and the mechanisms to get the class/level relevant values. Also I would prepare for the short/long rest with some mechnism to refresh the available type keys.

gergo-szabo commented 1 year ago

Also there are class specific "counters" which are not present in these SRD dicts but are connected to the stored values. For example: Bards can give inspiration number of times equal to Charisma modifier between two long rest but only the bardic_inspiration_die value is stored. Shall we add these mechanisms to the dicts? Or just mark them with a placeholder? Or ignore for now?

tassaron commented 1 year ago

Yes, I agree that anything capable of being depleted should be split into "maximum" and "available" values.

Your example of the bardic inspiration uses also sounds good to me. Anything that is class-specific and useful to track could be stored in this key.

The naming of class_specific_features is a little strange, though. It's kind of like the data equivalent to class_features which has the descriptions of these features. So maybe class_features_data? It's not a great name either, but I think I prefer it.

Tests would be needed to verify the connection between class feature descriptions and data. For example, one test would be checking that Bard has bardic_inspiration_die == 6 in class_features_data when they have the bardic-inspiration-d6 key in their class_features (I don't mind adding tests myself like I did before, but it's good to know)