Home · Architecture · Combat · Extensions · Known gaps · Source index
Registries and Content
Generic registry
src/registry.rs defines one Registry<K> used for four content families. K: ContentKind declares factory argument and output types. Each registered definition stores:
- Interned stable string name.
- Dense, type-distinct
Id<K>. - Display name.
- Integer priority.
Send + Syncfactory closure.stable name --intern--> u32 | +--> Id<WeaponContent> +--> Id<EnemyContent> +--> Id<DamageContent> +--> Id<StatusContent>
The marker type makes IDs with equal numeric indices incompatible across registries. Manual Copy, Eq, Hash, and Debug implementations avoid imposing trait bounds on the zero-sized marker.
Operations and constraints
| Operation | Behavior |
|---|---|
register |
Intern name, insert/replace definition, append ID to all |
make |
Index definition and invoke factory; invalid ID panics |
display_name / priority |
Index definition; invalid ID panics |
id_of |
Resolve stable name, returning Option |
all |
Return IDs in registration order |
Registering the same name twice reuses the ID and replaces the definition but appends a duplicate ID to all. There is no duplicate guard, removal, versioning, serialization, mod loading, or registry-wide sort.
Content families
| Registry | Factory input | Factory output | Seeded definitions |
|---|---|---|---|
| Weapon | tier u32 |
boxed ProjectileBehavior |
impact, poison_coating |
| Enemy | tier u32 |
Enemy |
blob |
| Damage | potency u32 |
boxed DamageBehavior |
physical, poison |
| Status | tier u32 |
boxed StatusBehavior |
poison |
Weapons
WeaponRegistry::new first resolves physical and poison IDs from the already-built damage registry, then captures those typed IDs in factories:
| Stable name | Display | Factory | Behavior priority |
|---|---|---|---|
impact |
Impact | TowerBaseWeapon::create(tier, physical) |
IMPACT (100) |
poison_coating |
Poison Coating | PoisonCoating::create(tier, poison) |
DEFAULT (0) |
The registry definition priority is currently set to DEFAULT for both entries and is not used when assembling a shot. Actual behavior objects report their own priorities and are sorted in src/systems.rs.
Enemies
EnemyRegistry registers only blob. make_kind invokes the factory and stamps the actual EnemyID over EnemyID::PLACEHOLDER. A blob factory computes:
HP = round(1.0 × 1.6^tier)
XP = round(1.0 × 1.3^tier)
It attaches SplitOnDeath::create(3) and SeekCenter::create(0). See src/enemies/blob.rs.
Damage
The damage registry seeds physical and poison behavior factories. The Acid damage behavior exists in src/behavior/damage.rs but is not registered; old integer constants Damage::PHYSICAL and Damage::ACID are also unused. More importantly, registered DamageBehavior::compute objects are never constructed or invoked by live combat. Current damage semantics come from DamageMap plus the enemy resistance map.
Statuses
The status registry seeds a poison factory producing fixed PeriodDamage: amount = 3, one-second interval, five-second lifetime, and Source::None. Its tick formula is (amount / interval) × dt, so this definition deals about 3 damage per second and about 15 over five seconds before resistance (with a possible final-frame overshoot because expiry tests duration > lifetime). Live Poison Coating bypasses this registry and constructs a tier-scaled status directly with the projectile source. Thus StatusRegistry is initialized and stored but not used on the current gameplay path.
Construction order
World::new enforces dependencies manually:
DamageRegistry::new
-> WeaponRegistry::new(&damage)
-> EnemyRegistry::new
-> StatusRegistry::new(&damage)
-> Tower::new(&weapons)
Missing required stable names panic through expect or unwrap. There is no explicit validation phase.
Crate integration
Weapon offers use weapon_registry.all() and deterministic modulo selection. Three independent rolls allow repeats. An empty registry would panic; the built-in registry is non-empty. A selected ID is passed to Tower::equip, which adds tier 1 or increments the existing tier. Display names come from the registry.
Live, partial, unwired
Live: typed IDs, name lookup, weapon factories at fire time, enemy factory at wave spawn/replication, crate display and selection.
Partial: priority is duplicated between definitions and behavior objects; repeated registration can duplicate catalog entries; constructors assume built-ins exist.
Unwired: damage behavior factories, status factory use in gameplay, dynamic content from Lua/Serde/JSON, external registration, hot reload.
See World and Entities for how IDs are stored and Behavior System for the objects factories produce.
Home · Architecture · Combat · Extensions · Known gaps · Source index