discussing and modifying character object

This commit is contained in:
Mechseroms 2025-11-02 11:12:06 -06:00
parent 4358b68d6a
commit 1d0a2b5fdf
3 changed files with 239 additions and 144 deletions

View File

@ -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)
- @name: Character name
- @level: Character level
- @race: Chosen race (grants features/traits)
- @subrace: Optional, for races with subtypes
- @class: Chosen class
- @subclass: Optional archetype/subclass
- @background: Character background (e.g., Soldier, Sage)
- @alignment: Law/Chaos & Good/Evil axis
- @size: (e.g., Medium, Small)
- @age: Character's age
- @gender: Gender identity
- @height: Physical height
- @weight: Physical weight
- @deity: (optional)
- @name: Character name (save)
- @level: Character level (save)
- @race: Chosen race (grants features/traits) (save)
- @subrace: Optional, for races with subtypes (save)
- @class: Chosen class (save)
- @subclass: Optional archetype/subclass (save)
- @background: Character background (e.g., Soldier, Sage) (save)
- @alignment: Law/Chaos & Good/Evil axis (save)
- @size: (e.g., Medium, Small) (save)
- @age: Character's age (save)
- @gender: Gender identity (save)
- @height: Physical height (save)
- @weight: Physical weight (save)
- @deity: (optional) (save)
---
## Core Abilities (Derived, Priority 1—calculate first)
### Base Scores
- @strength::base
- @dexterity::base
- @constitution::base
- @intelligence::base
- @wisdom::base
- @charisma::base
- @armor::base
- @strength::base (save)
- @dexterity::base (save)
- @constitution::base (save)
- @intelligence::base (save)
- @wisdom::base (save)
- @charisma::base (save)
- @armor::base (save if you allow a base AC override, else derived)
### Effective Scores (after modifiers, racial/class bonuses, etc.)
- @strength
- @dexterity
- @constitution
- @intelligence
- @wisdom
- @charisma
- @armor
- @strength (derived)
- @dexterity (derived)
- @constitution (derived)
- @intelligence (derived)
- @wisdom (derived)
- @charisma (derived)
- @armor (derived; unless house rule for persistent AC overrides)
### Modifiers
- @strength::modifier
- @dexterity::modifier
- @constitution::modifier
- @intelligence::modifier
- @wisdom::modifier
- @charisma::modifier
- @strength::modifier (derived)
- @dexterity::modifier (derived)
- @constitution::modifier (derived)
- @intelligence::modifier (derived)
- @wisdom::modifier (derived)
- @charisma::modifier (derived)
### General
- @proficiency: Proficiency bonus (scales with level)
- @inspiration: Boolean (True/False)
- @experience: XP points
- @proficiency: Proficiency bonus (derived from level)
- @inspiration: Boolean (True/False) (save)
- @experience: XP points (save)
---
## Proficiencies & Languages
- @proficiencies::armor
- @proficiencies::weapons
- @proficiencies::tools
- @languages
- @proficiencies::armor (save)
- @proficiencies::weapons (save)
- @proficiencies::tools (save)
- @languages (save)
---
## Saving Throws (Priority 2)
- @strength_save
- @dexterity_save
- @constitution_save
- @intelligence_save
- @wisdom_save
- @charisma_save
- @strength_save (derived)
- @dexterity_save (derived)
- @constitution_save (derived)
- @intelligence_save (derived)
- @wisdom_save (derived)
- @charisma_save (derived)
---
## HP, Initiative, Related (Priority 2)
- @hp (current)
- @hp_max
- @hp_temp
- @hit_die (e.g., d8, d10; and total available)
- @initiative (includes initiative modifier)
- @armor (effective AC)
- @hp (current) (save, often derived on session start)
- @hp_max (derived)
- @hp_temp (save)
- @hit_die (e.g., d8, d10; and total available) (save)
- @initiative (includes initiative modifier) (derived)
- @armor (effective AC) (derived)
### Death Saves
- @deathsaves::successes
- @deathsaves::failures
- @deathsaves::successes (save; reset between combats/long rests)
- @deathsaves::failures (save; reset between combats/long rests)
---
## Resistances & Immunities (Priority 2)
- @fire_resistance
- @poison_resistance
- @psychic_resistance
- @cold_resistance
- @thunder_resistance
- @acid_resistance
- @force_resistance
- @radiant_resistance
- @necrotic_resistance
- @bludgeoning_resistance
- @piercing_resistance
- @slashing_resistance
- ... (more as needed)
- @immunities (list)
- @vulnerabilities (list)
- @fire_resistance (derived from features, else save if affected in play)
- @poison_resistance (derived)
- @psychic_resistance (derived)
- @cold_resistance (derived)
- @thunder_resistance (derived)
- @acid_resistance (derived)
- @force_resistance (derived)
- @radiant_resistance (derived)
- @necrotic_resistance (derived)
- @bludgeoning_resistance (derived)
- @piercing_resistance (derived)
- @slashing_resistance (derived)
- ... (more as needed) (derived)
- @immunities (list) (save if gained or lost in play; else derived)
- @vulnerabilities (list) (save if gained or lost in play; else derived)
---
## Senses & Mobility (Priority 2)
- @speed::base (default/unencumbered movement)
- @speed::type (flying, climbing, swimming—if applicable)
- @darkvision
- @blindsight
- @tremorsense
- @truesight
- @passive_perception
- @speed::base (save)
- @speed::type (save)
- @darkvision (derived, unless modified at runtime; else save)
- @blindsight (derived)
- @tremorsense (derived)
- @truesight (derived)
- @passive_perception (derived)
---
## Skills (Priority 2)
#### Strength
- @athletics
- @athletics (derived)
#### Dexterity
- @acrobatics
- @sleight_of_hand
- @stealth
- @acrobatics (derived)
- @sleight_of_hand (derived)
- @stealth (derived)
#### Intelligence
- @arcana
- @history
- @investigation
- @nature
- @religion
- @arcana (derived)
- @history (derived)
- @investigation (derived)
- @nature (derived)
- @religion (derived)
#### Wisdom
- @animal_handling
- @insight
- @medicine
- @perception
- @survival
- @animal_handling (derived)
- @insight (derived)
- @medicine (derived)
- @perception (derived)
- @survival (derived)
#### Charisma
- @deception
- @intimidation
- @performance
- @persuasion
- @deception (derived)
- @intimidation (derived)
- @performance (derived)
- @persuasion (derived)
---
## Passives / Post-Derived Attributes (Priority 3)
- @athletics#passive
- @acrobatics#passive
- @sleight_of_hand#passive
- @stealth#passive
- @arcana#passive
- @history#passive
- @investigation#passive
- @nature#passive
- @religion#passive
- @animal_handling#passive
- @insight#passive
- @medicine#passive
- @perception#passive
- @survival#passive
- @deception#passive
- @intimidation#passive
- @performance#passive
- @persuasion#passive
- @passive_perception
- @passive_investigation
- @passive_insight
- @athletics#passive (derived)
- @acrobatics#passive (derived)
- @sleight_of_hand#passive (derived)
- @stealth#passive (derived)
- @arcana#passive (derived)
- @history#passive (derived)
- @investigation#passive (derived)
- @nature#passive (derived)
- @religion#passive (derived)
- @animal_handling#passive (derived)
- @insight#passive (derived)
- @medicine#passive (derived)
- @perception#passive (derived)
- @survival#passive (derived)
- @deception#passive (derived)
- @intimidation#passive (derived)
- @performance#passive (derived)
- @persuasion#passive (derived)
- @passive_perception (derived)
- @passive_investigation (derived)
- @passive_insight (derived)
---
## Spellcasting (if applicable)
- @spellcasting_ability (e.g., Intelligence)
- @spell_save_dc
- @spell_attack_bonus
- @known_spells (list)
- @prepared_spells (if required)
- @spell_slots (level-indexed: e.g., 1st:2, 2nd:1)
- @cantrips (list)
- @spellcasting_class
- @spellcasting_ability (e.g., Intelligence) (save)
- @spell_save_dc (derived)
- @spell_attack_bonus (derived)
- @known_spells (list) (save)
- @prepared_spells (if required) (save)
- @spell_slots (level-indexed: e.g., 1st:2, 2nd:1) (save; because depleted/used in play)
- @cantrips (list) (save)
- @spellcasting_class (save)
---
## Condition Tracking
- @exhaustion_level
- @conditions_active (list; e.g., blinded, charmed, frightened, etc.)
- @exhaustion_level (save)
- @conditions_active (list; e.g., blinded, charmed, frightened, etc.) (save)
---
## Currency & Inventory
- @cp (copper)
- @sp (silver)
- @ep (electrum)
- @gp (gold)
- @pp (platinum)
- @equipment (list or structured)
- @cp (copper) (save)
- @sp (silver) (save)
- @ep (electrum) (save)
- @gp (gold) (save)
- @pp (platinum) (save)
- @equipment (list or structured) (save)
---
## Features & Traits
- @features (class, race, background features—list)
- @feats (optional/variant rule)
- @traits (racial, personality, ideals, bonds, flaws)
- @personality_traits
- @ideals
- @bonds
- @flaws
- @features (class, race, background features—list) (save; usually as UUIDs/IDs, never as a derived calculation)
- @traits (racial, personality, ideals, bonds, flaws) (save, if you want to store narrative/roleplay traits)
- @personality_traits (save)
- @ideals (save)
- @bonds (save)
- @flaws (save)
---
## Others & Miscellaneous
- @notes (free text)
- @custom_attributes (dict or list)
- @notes (free text) (save)
- @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. Heres 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.
---

View File

@ -1,5 +1,42 @@
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
class Character:
@ -150,7 +187,6 @@ class Character:
equipment: 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)
personality_traits: List[str] = field(default_factory=list)
ideals: List[str] = field(default_factory=list)
@ -159,3 +195,7 @@ class Character:
notes: str = ""
custom_attributes: Dict[str, Any] = field(default_factory=dict)
def apply_features(character: Character, features: List[Feature]):
for feature in features:
feature.apply(character)

View File

@ -146,7 +146,6 @@
"equipment": [],
"features": [],
"feats": [],
"traits": [],
"personality_traits": [],
"ideals": [],