discussing and modifying character object
This commit is contained in:
parent
4358b68d6a
commit
1d0a2b5fdf
@ -5,217 +5,273 @@ This document outlines all the core and expanded character attributes that shoul
|
|||||||
---
|
---
|
||||||
|
|
||||||
## Base Attributes (Not Derived; static unless leveled up/class change)
|
## Base Attributes (Not Derived; static unless leveled up/class change)
|
||||||
- @name: Character name
|
- @name: Character name (save)
|
||||||
- @level: Character level
|
- @level: Character level (save)
|
||||||
- @race: Chosen race (grants features/traits)
|
- @race: Chosen race (grants features/traits) (save)
|
||||||
- @subrace: Optional, for races with subtypes
|
- @subrace: Optional, for races with subtypes (save)
|
||||||
- @class: Chosen class
|
- @class: Chosen class (save)
|
||||||
- @subclass: Optional archetype/subclass
|
- @subclass: Optional archetype/subclass (save)
|
||||||
- @background: Character background (e.g., Soldier, Sage)
|
- @background: Character background (e.g., Soldier, Sage) (save)
|
||||||
- @alignment: Law/Chaos & Good/Evil axis
|
- @alignment: Law/Chaos & Good/Evil axis (save)
|
||||||
- @size: (e.g., Medium, Small)
|
- @size: (e.g., Medium, Small) (save)
|
||||||
- @age: Character's age
|
- @age: Character's age (save)
|
||||||
- @gender: Gender identity
|
- @gender: Gender identity (save)
|
||||||
- @height: Physical height
|
- @height: Physical height (save)
|
||||||
- @weight: Physical weight
|
- @weight: Physical weight (save)
|
||||||
- @deity: (optional)
|
- @deity: (optional) (save)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Core Abilities (Derived, Priority 1—calculate first)
|
## Core Abilities (Derived, Priority 1—calculate first)
|
||||||
### Base Scores
|
### Base Scores
|
||||||
- @strength::base
|
- @strength::base (save)
|
||||||
- @dexterity::base
|
- @dexterity::base (save)
|
||||||
- @constitution::base
|
- @constitution::base (save)
|
||||||
- @intelligence::base
|
- @intelligence::base (save)
|
||||||
- @wisdom::base
|
- @wisdom::base (save)
|
||||||
- @charisma::base
|
- @charisma::base (save)
|
||||||
- @armor::base
|
- @armor::base (save if you allow a base AC override, else derived)
|
||||||
|
|
||||||
### Effective Scores (after modifiers, racial/class bonuses, etc.)
|
### Effective Scores (after modifiers, racial/class bonuses, etc.)
|
||||||
- @strength
|
- @strength (derived)
|
||||||
- @dexterity
|
- @dexterity (derived)
|
||||||
- @constitution
|
- @constitution (derived)
|
||||||
- @intelligence
|
- @intelligence (derived)
|
||||||
- @wisdom
|
- @wisdom (derived)
|
||||||
- @charisma
|
- @charisma (derived)
|
||||||
- @armor
|
- @armor (derived; unless house rule for persistent AC overrides)
|
||||||
|
|
||||||
### Modifiers
|
### Modifiers
|
||||||
- @strength::modifier
|
- @strength::modifier (derived)
|
||||||
- @dexterity::modifier
|
- @dexterity::modifier (derived)
|
||||||
- @constitution::modifier
|
- @constitution::modifier (derived)
|
||||||
- @intelligence::modifier
|
- @intelligence::modifier (derived)
|
||||||
- @wisdom::modifier
|
- @wisdom::modifier (derived)
|
||||||
- @charisma::modifier
|
- @charisma::modifier (derived)
|
||||||
|
|
||||||
### General
|
### General
|
||||||
- @proficiency: Proficiency bonus (scales with level)
|
- @proficiency: Proficiency bonus (derived from level)
|
||||||
- @inspiration: Boolean (True/False)
|
- @inspiration: Boolean (True/False) (save)
|
||||||
- @experience: XP points
|
- @experience: XP points (save)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Proficiencies & Languages
|
## Proficiencies & Languages
|
||||||
- @proficiencies::armor
|
- @proficiencies::armor (save)
|
||||||
- @proficiencies::weapons
|
- @proficiencies::weapons (save)
|
||||||
- @proficiencies::tools
|
- @proficiencies::tools (save)
|
||||||
- @languages
|
- @languages (save)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Saving Throws (Priority 2)
|
## Saving Throws (Priority 2)
|
||||||
- @strength_save
|
- @strength_save (derived)
|
||||||
- @dexterity_save
|
- @dexterity_save (derived)
|
||||||
- @constitution_save
|
- @constitution_save (derived)
|
||||||
- @intelligence_save
|
- @intelligence_save (derived)
|
||||||
- @wisdom_save
|
- @wisdom_save (derived)
|
||||||
- @charisma_save
|
- @charisma_save (derived)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## HP, Initiative, Related (Priority 2)
|
## HP, Initiative, Related (Priority 2)
|
||||||
- @hp (current)
|
- @hp (current) (save, often derived on session start)
|
||||||
- @hp_max
|
- @hp_max (derived)
|
||||||
- @hp_temp
|
- @hp_temp (save)
|
||||||
- @hit_die (e.g., d8, d10; and total available)
|
- @hit_die (e.g., d8, d10; and total available) (save)
|
||||||
- @initiative (includes initiative modifier)
|
- @initiative (includes initiative modifier) (derived)
|
||||||
- @armor (effective AC)
|
- @armor (effective AC) (derived)
|
||||||
|
|
||||||
### Death Saves
|
### Death Saves
|
||||||
- @deathsaves::successes
|
- @deathsaves::successes (save; reset between combats/long rests)
|
||||||
- @deathsaves::failures
|
- @deathsaves::failures (save; reset between combats/long rests)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Resistances & Immunities (Priority 2)
|
## Resistances & Immunities (Priority 2)
|
||||||
- @fire_resistance
|
- @fire_resistance (derived from features, else save if affected in play)
|
||||||
- @poison_resistance
|
- @poison_resistance (derived)
|
||||||
- @psychic_resistance
|
- @psychic_resistance (derived)
|
||||||
- @cold_resistance
|
- @cold_resistance (derived)
|
||||||
- @thunder_resistance
|
- @thunder_resistance (derived)
|
||||||
- @acid_resistance
|
- @acid_resistance (derived)
|
||||||
- @force_resistance
|
- @force_resistance (derived)
|
||||||
- @radiant_resistance
|
- @radiant_resistance (derived)
|
||||||
- @necrotic_resistance
|
- @necrotic_resistance (derived)
|
||||||
- @bludgeoning_resistance
|
- @bludgeoning_resistance (derived)
|
||||||
- @piercing_resistance
|
- @piercing_resistance (derived)
|
||||||
- @slashing_resistance
|
- @slashing_resistance (derived)
|
||||||
- ... (more as needed)
|
- ... (more as needed) (derived)
|
||||||
- @immunities (list)
|
- @immunities (list) (save if gained or lost in play; else derived)
|
||||||
- @vulnerabilities (list)
|
- @vulnerabilities (list) (save if gained or lost in play; else derived)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Senses & Mobility (Priority 2)
|
## Senses & Mobility (Priority 2)
|
||||||
- @speed::base (default/unencumbered movement)
|
- @speed::base (save)
|
||||||
- @speed::type (flying, climbing, swimming—if applicable)
|
- @speed::type (save)
|
||||||
- @darkvision
|
- @darkvision (derived, unless modified at runtime; else save)
|
||||||
- @blindsight
|
- @blindsight (derived)
|
||||||
- @tremorsense
|
- @tremorsense (derived)
|
||||||
- @truesight
|
- @truesight (derived)
|
||||||
- @passive_perception
|
- @passive_perception (derived)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Skills (Priority 2)
|
## Skills (Priority 2)
|
||||||
#### Strength
|
#### Strength
|
||||||
- @athletics
|
- @athletics (derived)
|
||||||
|
|
||||||
#### Dexterity
|
#### Dexterity
|
||||||
- @acrobatics
|
- @acrobatics (derived)
|
||||||
- @sleight_of_hand
|
- @sleight_of_hand (derived)
|
||||||
- @stealth
|
- @stealth (derived)
|
||||||
|
|
||||||
#### Intelligence
|
#### Intelligence
|
||||||
- @arcana
|
- @arcana (derived)
|
||||||
- @history
|
- @history (derived)
|
||||||
- @investigation
|
- @investigation (derived)
|
||||||
- @nature
|
- @nature (derived)
|
||||||
- @religion
|
- @religion (derived)
|
||||||
|
|
||||||
#### Wisdom
|
#### Wisdom
|
||||||
- @animal_handling
|
- @animal_handling (derived)
|
||||||
- @insight
|
- @insight (derived)
|
||||||
- @medicine
|
- @medicine (derived)
|
||||||
- @perception
|
- @perception (derived)
|
||||||
- @survival
|
- @survival (derived)
|
||||||
|
|
||||||
#### Charisma
|
#### Charisma
|
||||||
- @deception
|
- @deception (derived)
|
||||||
- @intimidation
|
- @intimidation (derived)
|
||||||
- @performance
|
- @performance (derived)
|
||||||
- @persuasion
|
- @persuasion (derived)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Passives / Post-Derived Attributes (Priority 3)
|
## Passives / Post-Derived Attributes (Priority 3)
|
||||||
- @athletics#passive
|
- @athletics#passive (derived)
|
||||||
- @acrobatics#passive
|
- @acrobatics#passive (derived)
|
||||||
- @sleight_of_hand#passive
|
- @sleight_of_hand#passive (derived)
|
||||||
- @stealth#passive
|
- @stealth#passive (derived)
|
||||||
- @arcana#passive
|
- @arcana#passive (derived)
|
||||||
- @history#passive
|
- @history#passive (derived)
|
||||||
- @investigation#passive
|
- @investigation#passive (derived)
|
||||||
- @nature#passive
|
- @nature#passive (derived)
|
||||||
- @religion#passive
|
- @religion#passive (derived)
|
||||||
- @animal_handling#passive
|
- @animal_handling#passive (derived)
|
||||||
- @insight#passive
|
- @insight#passive (derived)
|
||||||
- @medicine#passive
|
- @medicine#passive (derived)
|
||||||
- @perception#passive
|
- @perception#passive (derived)
|
||||||
- @survival#passive
|
- @survival#passive (derived)
|
||||||
- @deception#passive
|
- @deception#passive (derived)
|
||||||
- @intimidation#passive
|
- @intimidation#passive (derived)
|
||||||
- @performance#passive
|
- @performance#passive (derived)
|
||||||
- @persuasion#passive
|
- @persuasion#passive (derived)
|
||||||
- @passive_perception
|
- @passive_perception (derived)
|
||||||
- @passive_investigation
|
- @passive_investigation (derived)
|
||||||
- @passive_insight
|
- @passive_insight (derived)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Spellcasting (if applicable)
|
## Spellcasting (if applicable)
|
||||||
- @spellcasting_ability (e.g., Intelligence)
|
- @spellcasting_ability (e.g., Intelligence) (save)
|
||||||
- @spell_save_dc
|
- @spell_save_dc (derived)
|
||||||
- @spell_attack_bonus
|
- @spell_attack_bonus (derived)
|
||||||
- @known_spells (list)
|
- @known_spells (list) (save)
|
||||||
- @prepared_spells (if required)
|
- @prepared_spells (if required) (save)
|
||||||
- @spell_slots (level-indexed: e.g., 1st:2, 2nd:1)
|
- @spell_slots (level-indexed: e.g., 1st:2, 2nd:1) (save; because depleted/used in play)
|
||||||
- @cantrips (list)
|
- @cantrips (list) (save)
|
||||||
- @spellcasting_class
|
- @spellcasting_class (save)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Condition Tracking
|
## Condition Tracking
|
||||||
- @exhaustion_level
|
- @exhaustion_level (save)
|
||||||
- @conditions_active (list; e.g., blinded, charmed, frightened, etc.)
|
- @conditions_active (list; e.g., blinded, charmed, frightened, etc.) (save)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Currency & Inventory
|
## Currency & Inventory
|
||||||
- @cp (copper)
|
- @cp (copper) (save)
|
||||||
- @sp (silver)
|
- @sp (silver) (save)
|
||||||
- @ep (electrum)
|
- @ep (electrum) (save)
|
||||||
- @gp (gold)
|
- @gp (gold) (save)
|
||||||
- @pp (platinum)
|
- @pp (platinum) (save)
|
||||||
- @equipment (list or structured)
|
- @equipment (list or structured) (save)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Features & Traits
|
## Features & Traits
|
||||||
- @features (class, race, background features—list)
|
- @features (class, race, background features—list) (save; usually as UUIDs/IDs, never as a derived calculation)
|
||||||
- @feats (optional/variant rule)
|
- @traits (racial, personality, ideals, bonds, flaws) (save, if you want to store narrative/roleplay traits)
|
||||||
- @traits (racial, personality, ideals, bonds, flaws)
|
- @personality_traits (save)
|
||||||
- @personality_traits
|
- @ideals (save)
|
||||||
- @ideals
|
- @bonds (save)
|
||||||
- @bonds
|
- @flaws (save)
|
||||||
- @flaws
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Others & Miscellaneous
|
## Others & Miscellaneous
|
||||||
- @notes (free text)
|
- @notes (free text) (save)
|
||||||
- @custom_attributes (dict or list)
|
- @custom_attributes (dict or list) (save)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Recommended Attribute Application & Calculation Order in D&D 5e
|
||||||
|
|
||||||
|
When building or advancing a character, the order in which features (including class, race, background, feats, etc.) are applied is critically important for mathematically correct results. Here’s the optimal order to apply these steps in any automated or manual pipeline:
|
||||||
|
|
||||||
|
### 1. Base Values
|
||||||
|
- Start with all attributes at their neutral defaults (from template.json or your starting schema).
|
||||||
|
- Set character-level information (`name`, `race`, `class`, `background`, etc.) and ability base scores (from point array/rolled stats).
|
||||||
|
|
||||||
|
### 2. Apply Racial and Background Features
|
||||||
|
- Apply all racial and background features and their effects (most commonly ability score increases (ASIs), senses, languages, and a few resistances or proficiencies).
|
||||||
|
- All static bonuses to scores or proficiencies from race/subrace and background get merged in.
|
||||||
|
|
||||||
|
### 3. Apply Class and Subclass Features
|
||||||
|
- Apply features from main class and subclass (including ASIs offered at certain levels via class progression, class proficiencies, and hit die type, etc).
|
||||||
|
- Ensure proficiency bonus and proficiency-lists are now set, as they affect saving throws, skills, and attacks.
|
||||||
|
|
||||||
|
### 4. Apply Feats and Optional Features
|
||||||
|
- Add in features/feats selected by the player (such as additional ASIs, new proficiencies, special rules, etc.).
|
||||||
|
- Apply any miscellaneous or homebrew features/effects here.
|
||||||
|
|
||||||
|
### 5. Calculate Derived and Secondary Stats
|
||||||
|
- Now that all bonuses are applied:
|
||||||
|
- Calculate modifiers for abilities (e.g., `modifier = floor((score - 10) / 2)`).
|
||||||
|
- Recompute max HP, initiative, AC, proficiency bonus, and other directly derived stats.
|
||||||
|
- Compute saving throws using the base stat modifier and proficiency if relevant.
|
||||||
|
|
||||||
|
### 6. Calculate Skills
|
||||||
|
- Compute each skill (e.g., `athletics`, `perception`) using the appropriate stat modifier(s) and proficiency bonus if applicable.
|
||||||
|
- Passive skills (e.g., `passive_perception`) are computed from active skills and modifiers — so must come after.
|
||||||
|
|
||||||
|
### 7. Final Derived/Dependent Values
|
||||||
|
- Any features or effects with logic that depends on already-calculated derived values (like “your proficiency bonus equals your Wisdom modifier,” or “your AC is 10 + Dexterity modifier + Constitution modifier”) must be applied now.
|
||||||
|
- Set final values for resistances, senses, special movement, etc.
|
||||||
|
|
||||||
|
### 8. Equipment, Spellcasting, and Other
|
||||||
|
- Add any changes or bonuses from starting equipment or attunements (if applicable).
|
||||||
|
- Spell slots, spells known, etc. should be finalized after class and subclass effects are complete.
|
||||||
|
|
||||||
|
### Order Summary Table
|
||||||
|
| Step | Key Calculation |
|
||||||
|
|----------------------------|-------------------------------------------|
|
||||||
|
| 1. Base values | Initial population, base stats set |
|
||||||
|
| 2. Race/Backgrounds | ASIs, languages, simple traits |
|
||||||
|
| 3. Class & Subclass | Class features, proficiencies, hit dice |
|
||||||
|
| 4. Feats & Optionals | Feat/modifiers, optional rules |
|
||||||
|
| 5. Derived attributes | Modifiers, HP, AC, saving throws |
|
||||||
|
| 6. Skills | Skill values, passives |
|
||||||
|
| 7. Final dependencies | Effects dependent on other derived stats |
|
||||||
|
| 8. Equipment/Spells | Inventory, spellcasting |
|
||||||
|
|
||||||
|
### Why This Order Works
|
||||||
|
- All stat boosts and proficiencies are resolved *before* using them in formulas for derived or secondary stats.
|
||||||
|
- Features that depend on other features (such as subclass features referencing class values, or feats modifying what skills are available) always work as intended.
|
||||||
|
- No recalculation is needed—just process each group in order.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,42 @@
|
|||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from typing import List, Dict, Any
|
from typing import List, Dict, Any, Union
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Effect:
|
||||||
|
attribute: str # name of attribute to change
|
||||||
|
operation: str # 'add', 'subtract', 'set', 'append'
|
||||||
|
value: Any # value to apply
|
||||||
|
|
||||||
|
def apply(self, character: 'Character'):
|
||||||
|
# Handle numeric attributes
|
||||||
|
if self.operation == 'add':
|
||||||
|
setattr(character, self.attribute, getattr(character, self.attribute) + self.value)
|
||||||
|
elif self.operation == 'subtract':
|
||||||
|
setattr(character, self.attribute, getattr(character, self.attribute) - self.value)
|
||||||
|
elif self.operation == 'set':
|
||||||
|
setattr(character, self.attribute, self.value)
|
||||||
|
elif self.operation == 'append':
|
||||||
|
current = getattr(character, self.attribute)
|
||||||
|
if isinstance(current, list):
|
||||||
|
if isinstance(self.value, list):
|
||||||
|
current.extend(self.value)
|
||||||
|
else:
|
||||||
|
current.append(self.value)
|
||||||
|
setattr(character, self.attribute, current)
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Attribute '{self.attribute}' is not a list.")
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Unknown operation: {self.operation}")
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Feature:
|
||||||
|
name: str
|
||||||
|
description: str
|
||||||
|
effects: List[Effect] = field(default_factory=list)
|
||||||
|
|
||||||
|
def apply(self, character: 'Character'):
|
||||||
|
for effect in self.effects:
|
||||||
|
effect.apply(character)
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Character:
|
class Character:
|
||||||
@ -150,7 +187,6 @@ class Character:
|
|||||||
equipment: List[str] = field(default_factory=list)
|
equipment: List[str] = field(default_factory=list)
|
||||||
|
|
||||||
features: List[str] = field(default_factory=list)
|
features: List[str] = field(default_factory=list)
|
||||||
feats: List[str] = field(default_factory=list)
|
|
||||||
traits: List[str] = field(default_factory=list)
|
traits: List[str] = field(default_factory=list)
|
||||||
personality_traits: List[str] = field(default_factory=list)
|
personality_traits: List[str] = field(default_factory=list)
|
||||||
ideals: List[str] = field(default_factory=list)
|
ideals: List[str] = field(default_factory=list)
|
||||||
@ -159,3 +195,7 @@ class Character:
|
|||||||
|
|
||||||
notes: str = ""
|
notes: str = ""
|
||||||
custom_attributes: Dict[str, Any] = field(default_factory=dict)
|
custom_attributes: Dict[str, Any] = field(default_factory=dict)
|
||||||
|
|
||||||
|
def apply_features(character: Character, features: List[Feature]):
|
||||||
|
for feature in features:
|
||||||
|
feature.apply(character)
|
||||||
|
|||||||
@ -146,7 +146,6 @@
|
|||||||
"equipment": [],
|
"equipment": [],
|
||||||
|
|
||||||
"features": [],
|
"features": [],
|
||||||
"feats": [],
|
|
||||||
"traits": [],
|
"traits": [],
|
||||||
"personality_traits": [],
|
"personality_traits": [],
|
||||||
"ideals": [],
|
"ideals": [],
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user