Available Scripts
MANDATORY by scenario — read before implementing:
- Templates / base attributes → [basestatsresource.gd](scripts/basestatsresource.gd)
- Runtime stack + reactive recalc → [statscomponentreactive.gd](scripts/statscomponentreactive.gd) + [statmodifierstacking.gd](scripts/statmodifierstacking.gd)
- Buff/debuff data → [statuseffectdata.gd](scripts/statuseffectdata.gd) (Type.ADDITIVE / MULTIPLICATIVE / OVERRIDE)
- Combat math → [damageformulahandler.gd](scripts/damageformulahandler.gd)
[basestatsresource.gd](scripts/basestatsresource.gd)
Core data container for base attributes (Str, Dex, Int) and derived scaling rules.
[statuseffectdata.gd](scripts/statuseffectdata.gd)
Serialized buff/debuff definition using StatusEffectData.Type { ADDITIVE, MULTIPLICATIVE, OVERRIDE }.
[statscomponentreactive.gd](scripts/statscomponentreactive.gd)
Orchestrator for JIT (Just-In-Time) stat calculation with active modifier stacking.
[expprogressionresource.gd](scripts/expprogressionresource.gd)
Data-driven level-up curve definition using growth factors and base XP.
[dynamicstatlabelsync.gd](scripts/dynamicstatlabelsync.gd)
Reactive UI hook for syncing Labels to stat changes without polling.
[damageformulahandler.gd](scripts/damageformulahandler.gd)
Centralized RefCounted utility for complex combat math and damage calculations.
[statmodifierstacking.gd](scripts/statmodifierstacking.gd)
Logic for handling unique vs. stackable buffs and refreshing durations.
[resourcestatinheritance.gd](scripts/resourcestatinheritance.gd)
Pattern for extending base stats with specialized attributes (Elemental Resists).
[persistentcharacterstats.gd](scripts/persistentcharacterstats.gd)
Managing the serialization of character progression to .tres files.
[levelupsystem.gd](scripts/levelupsystem.gd)
Logic for awarding experience and triggering level-up benefits.
[rpgstatresource.gd](scripts/rpgstatresource.gd)
Capped base stat Resource with setter clamps + stat_changed signal.
[derivedstatresource.gd](scripts/derivedstatresource.gd)
Derived stat that recalculates when base stat dependencies change.
[equipmenttooltiphelper.gd](scripts/equipmenttooltiphelper.gd)
BBCode equipment comparison tooltips (makecustom_tooltip).
NEVER Do in RPG Stats
- NEVER use integers for percentages — Always use
float (0.0–1.0 or 0.0–100.0) to avoid truncation.
- NEVER modify current_health without emitting signals — UI desyncs without broadcasts.
- NEVER rely solely on additive modifiers — Use multiplicative or hybrid scaling for long progressions.
- NEVER add modifiers without a unique ID or Key — Required to remove specific effects.
- NEVER use exponential XP formulas without a growth cap — Uncapped
pow() overflows or soft-locks levels.
- NEVER forget to clamp derived values — Negative vitality must not yield negative max HP (
maxi(val, 1)).
- NEVER perform heavy stat recalculations in
_process() — Recalc only on modifier/base change (reactive).
- NEVER hardcode stat names in logic — Use StringNames or enums.
- NEVER store temporary runtime buffs in a permanent Save Resource — Strip short-duration modifiers before serialize.
- NEVER calculate damage directly in the Character script — Centralize in [damageformulahandler.gd](scripts/damageformulahandler.gd).
- NEVER invent Dictionary-only modifier APIs in examples — Align with
StatusEffectData.Type and the stacking scripts.
Decision Tree
| Layer |
Responsibility |
Script |
| Resource template |
Designer-authored base attributes, curves, inheritance |
[basestatsresource.gd](scripts/basestatsresource.gd), [expprogressionresource.gd](scripts/expprogressionresource.gd), [resourcestatinheritance.gd](scripts/resourcestatinheritance.gd) |
| Runtime StatsComponent |
Duplicate/instance template, apply/remove modifiers, emit signals, JIT derived stats |
MANDATORY [statscomponentreactive.gd](scripts/statscomponentreactive.gd) + [statmodifierstacking.gd](scripts/statmodifierstacking.gd) |
| StatusEffectData |
Typed buff rows (ADDITIVE / MULTIPLICATIVE / OVERRIDE) |
[statuseffectdata.gd](scripts/statuseffectdata.gd) |
| DamageFormula (RefCounted) |
Pure combat math shared by Player/NPC |
MANDATORY [damageformulahandler.gd](scripts/damageformulahandler.gd) |
| Persistence |
Save progression; strip runtime buffs first |
[persistentcharacterstats.gd](scripts/persistentcharacterstats.gd) |
| UI sync |
Labels listen to signals — no polling |
[dynamicstatlabelsync.gd](scripts/dynamicstatlabelsync.gd) |
Do not paste beginner class_name Stats / Dictionary equipment tutorials — route to the scripts above.
API alignment (StatusEffectData)
# Author buffs as Resources — not ad-hoc Dictionary modifiers
var haste := StatusEffectData.new()
haste.name = "Haste"
haste.type = StatusEffectData.Type.MULTIPLICATIVE
haste.attribute = "speed"
haste.value = 1.25
haste.duration = 8.0
var flat_str := StatusEffectData.new()
flat_str.type = StatusEffectData.Type.ADDITIVE
flat_str.attribute = "strength"
flat_str.value = 5.0
var break_def := StatusEffectData.new()
break_def.type = StatusEffectData.Type.OVERRIDE
break_def.attribute = "defense"
break_def.value = 0.0
Stacking / refresh / unique-vs-stackable behavior: MANDATORY [statmodifierstacking.gd](scripts/statmodifierstacking.gd). Apply through [statscomponentreactive.gd](scripts/statscomponentreactive.gd) so derived stats recalc once per change.
Elite reminders (script-backed)
- Caps — [rpgstatresource.gd](scripts/rpgstatresource.gd); clamp on setters; never allow overflow attributes.
- Dependency graphs — [derivedstatresource.gd](scripts/derivedstatresource.gd); derived stats recalc from signals when bases change — never
_process.
- Equipment — Register/remove modifier IDs on equip/unequip via stacking API; tooltips via [equipmenttooltiphelper.gd](scripts/equipmenttooltiphelper.gd).
Deep dive (load on demand)
Equipment hooks, damage formula, skill gates, elite cap/derived/tooltip patterns — [references/elite-stat-patterns.md](references/elite-stat-patterns.md).
Reference
Progressive disclosure: open Official Documentation links only when researching a specific API; load Related Skills when routing to a peer domain — do not preload the whole lattice.
Official Documentation
- Resources — why base stats, curves, and status effects belong on
Resource templates you duplicate or instance per character.
- Resource —
duplicate(), resourcelocaltoscene, and shared-vs-unique semantics that prevent every enemy sharing one HP Resource.
- GDScript exported properties —
@export / @exportgroup so designers tune attributes and scaling in the Inspector without code edits.
- Using signals —
statchanged / statsrecalculated so UI and derived stats react without process polling.
- Saving games — serialize progression Resources and strip runtime-only buffs before write.
- File paths in Godot projects —
user:// vs res:// for persistent character .tres saves.
- ResourceSaver — write character stats Resources to disk after level-ups.
- ResourceLoader —
exists / load paths when restoring progression on boot.
- RefCounted — keep damage formulas and pure combat math off the scene tree.
- Random number generation — seeded crit / variance rolls that stay reproducible in balance tests.
- Label — bind text to signal-driven attribute refresh for HUD sync.
- SceneTree —
createtimer for timed buff expiry without a per-effect Node.
Related Skills
Prerequisites
Complements
Downstream / consumers
Master
- godot-master — library router and mirrored module entry for cross-skill discovery.