Files
Mana-Loop/docs/specs/attunements/attunement-system-spec.md
T
n8n-gitea 573130cdb1
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m24s
fix: attunement system spec-vs-code discrepancies (issue #331)
- Fix conversion rate level scaling from linear (1+level*0.5) to exponential (1.5^(level-1)) in conversion-rates.ts
- Fix getAttunementLevelMultiplier formula to match spec §4.3
- Add level-up logging in attunementStore.ts via combat store addActivityLog
- Clarify getAttunementConversionRate returns flat base rate (level scaling applied separately)
- Update spec §8 to describe time-based puzzle room system matching code implementation
- Add 17 regression tests verifying exponential scaling, base rate behavior, and spec table values
2026-06-08 22:08:17 +02:00

353 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Attunement System — Design Spec
> Describes the three-attunement class system: Enchanter, Invoker, and Fabricator.
> Covers slot assignments, unlock conditions, leveling, regen/conversion scaling,
> discipline pool gating, and interaction with mana conversion and the incursion system.
---
## 1. Objective
Attunements are class-like specializations that gate access to discipline pools and
unique capabilities. A player can have multiple attunements active simultaneously,
each contributing raw mana regen and (for Enchanter and Fabricator) automatic mana
conversion. Attunements level up independently through attunement-specific XP sources,
scaling their regen and conversion rates exponentially.
**Design goals:**
- Three distinct attunements with unique identities and roles
- Attunements unlock over time, expanding the player's options
- Leveling provides meaningful exponential scaling without being mandatory
- Discipline pool access is gated behind attunement unlock status
- Invoker's lack of primary mana creates a distinct pact-dependent playstyle
---
## 2. The Three Attunements
### 2.1 Enchanter (Right Hand) — Starting Attunement
| Property | Value |
|---|---|
| **ID** | `enchanter` |
| **Slot** | `rightHand` |
| **Icon** | `✨` |
| **Color** | `#1ABC9C` (Teal) |
| **Primary Mana** | `transference` |
| **Raw Mana Regen** | +0.5/hour (base) |
| **Conversion Rate** | 0.2 raw→transference/hour (base) |
| **Unlock** | Starting (unlocked by default) |
| **Capabilities** | `['enchanting']` |
| **Skill Categories** | `['enchant', 'effectResearch']` |
**Disciplines:** 10 disciplines across 4 files (core: 4, utility: 2, spells: 3, special: 1)
### 2.2 Invoker (Chest) — Locked
| Property | Value |
|---|---|
| **ID** | `invoker` |
| **Slot** | `chest` |
| **Icon** | `💜` |
| **Color** | `#9B59B6` (Purple) |
| **Primary Mana** | None (gains elemental mana from pacts) |
| **Raw Mana Regen** | +0.3/hour (base) |
| **Conversion Rate** | None (0 at all levels) |
| **Unlock** | Defeat first Guardian |
| **Capabilities** | `['pacts', 'guardianPowers', 'elementalMastery']` |
| **Skill Categories** | `['invocation', 'pact']` |
**Disciplines:** 2 disciplines
### 2.3 Fabricator (Left Hand) — Locked
| Property | Value |
|---|---|
| **ID** | `fabricator` |
| **Slot** | `leftHand` |
| **Icon** | `⚒️` |
| **Color** | `#F4A261` (Earth) |
| **Primary Mana** | `earth` |
| **Raw Mana Regen** | +0.4/hour (base) |
| **Conversion Rate** | 0.25 raw→earth/hour (base) |
| **Unlock** | Prove crafting worth |
| **Capabilities** | `['golemCrafting', 'gearCrafting', 'earthShaping']` |
| **Skill Categories** | `['fabrication', 'golemancy']` |
**Disciplines:** 5 disciplines
---
## 3. Unlock Conditions
| Attunement | Condition | Implementation |
|---|---|---|
| **Enchanter** | Starting | Present in initial state: `{ active: true, level: 1, experience: 0 }` |
| **Invoker** | Defeat first Guardian | Descriptive: `"Defeat your first guardian and choose the path of the Invoker"` |
| **Fabricator** | Prove crafting worth | Descriptive: `"Prove your worth as a crafter"` |
Unlocking is performed via `debugUnlockAttunement(attunementId)` in the store, which
initializes the attunement at `{ active: true, level: 1, experience: 0 }`. The
conditions are currently descriptive strings rather than hard-coded mechanical checks.
---
## 4. Attunement Leveling
### 4.1 XP Thresholds
```
Level 1: 0 XP (starting)
Level 2: 1,000 XP
Level ≥ 3: Math.floor(1000 * Math.pow(2, level - 2) * 1.25)
```
| Level | XP Threshold | Cumulative XP |
|---|---|---|
| 1 | 0 | 0 |
| 2 | 1,000 | 1,000 |
| 3 | 2,500 | 3,500 |
| 4 | 5,000 | 8,500 |
| 5 | 10,000 | 18,500 |
| 6 | 20,000 | 38,500 |
| 7 | 40,000 | 78,500 |
| 8 | 80,000 | 158,500 |
| 9 | 160,000 | 318,500 |
| 10 | 320,000 | 638,500 |
**Max Level:** `MAX_ATTUNEMENT_LEVEL = 10`
### 4.2 Level-Up Mechanism
```
addAttunementXP(attunementId, amount):
state.experience += amount
while state.experience >= xpForNextLevel && level < MAX:
state.experience -= xpForNextLevel
level += 1
log("Attunement leveled up!")
```
XP does **not** roll over beyond the threshold check — the threshold amount is
subtracted and any remainder carries into the next level.
### 4.3 Regen and Conversion Rate Scaling
Both raw mana regen and conversion rate use the same exponential formula:
```
scaledValue = baseValue × 1.5^(level - 1)
```
**Effective raw mana regen by level (per attunement):**
| Level | Enchanter (0.5) | Invoker (0.3) | Fabricator (0.4) |
|---|---|---|---|
| 1 | 0.500/hr | 0.300/hr | 0.400/hr |
| 2 | 0.750/hr | 0.450/hr | 0.600/hr |
| 3 | 1.125/hr | 0.675/hr | 0.900/hr |
| 4 | 1.688/hr | 1.013/hr | 1.350/hr |
| 5 | 2.531/hr | 1.519/hr | 2.025/hr |
| 6 | 3.797/hr | 2.278/hr | 3.038/hr |
| 7 | 5.695/hr | 3.417/hr | 4.556/hr |
| 8 | 8.543/hr | 5.126/hr | 6.834/hr |
| 9 | 12.814/hr | 7.689/hr | 10.252/hr |
| 10 | 19.221/hr | 11.533/hr | 15.377/hr |
**Effective conversion rate by level:**
| Level | Enchanter (0.2) | Fabricator (0.25) |
|---|---|---|
| 1 | 0.200/hr | 0.250/hr |
| 2 | 0.300/hr | 0.375/hr |
| 3 | 0.450/hr | 0.563/hr |
| 4 | 0.675/hr | 0.844/hr |
| 5 | 1.013/hr | 1.266/hr |
| 6 | 1.519/hr | 1.898/hr |
| 7 | 2.278/hr | 2.848/hr |
| 8 | 3.417/hr | 4.271/hr |
| 9 | 5.126/hr | 6.407/hr |
| 10 | 7.689/hr | 9.610/hr |
Invoker has `conversionRate = 0` at all levels — no auto-conversion.
**Total regen** = sum of `baseRegen × 1.5^(level-1)` across all active attunements.
**Total conversion drain** = sum of `baseConversionRate × 1.5^(level-1)` across active attunements
that have a non-zero conversion rate. This drain is applied to the raw mana pool.
---
## 5. Attunement XP Gain Sources
### 5.1 Enchanting → Enchanter XP
```typescript
calculateEnchantingXP(capacityUsed: number): number {
return Math.max(1, Math.floor(capacityUsed / 10));
}
```
- 1 Enchanter XP per 10 capacity used (floored), minimum 1 XP per enchant.
### 5.2 Other Sources
The `addAttunementXP(attunementId, amount)` store action is the generic mechanism.
Any system can call it to award XP to any attunement. In the codebase as-is,
only enchanting has an explicit calculation function. Invoker and Fabricator XP
gain is expected to be called from their respective systems (pact signing and
item fabrication) but explicit calculation functions are not yet defined.
---
## 6. Discipline Pool Gating
### 6.1 Skill Categories
Attunements gate discipline access through **skill categories**:
| Category | Disciplines |
|---|---|
| Always available | `mana`, `study`, `research` |
| Enchanter | `enchant`, `effectResearch` |
| Invoker | `invocation`, `pact` |
| Fabricator | `fabrication`, `golemancy` |
The function `getAvailableSkillCategories()` iterates all **active** attunements,
collects their `skillCategories` into a Set, and returns the deduplicated array.
### 6.2 Discipline Pool Counts per Attunement
| Attunement | File | Count |
|---|---|---|
| Enchanter Core | `enchanter.ts` | 4 |
| Enchanter Utility | `enchanter-utility.ts` | 2 |
| Enchanter Spells | `enchanter-spells.ts` | 3 |
| Enchanter Special | `enchanter-special.ts` | 1 |
| Invoker | `invoker.ts` | 2 |
| Fabricator | `fabricator.ts` | 5 |
| **Attunement-gated total** | | **17** |
The remaining 47 disciplines are available regardless of attunement status (base,
elemental, elemental-regen, elemental-regen-advanced pools).
### 6.3 Capability Gating
Each attunement grants `capabilities` that unlock specific game systems:
| Capability | System |
|---|---|
| `enchanting` | Enchantment Design/Prepare/Apply pipeline |
| `pacts` | Guardian pact signing and boon system |
| `guardianPowers` | Guardian power access |
| `elementalMastery` | Element mastery bonuses |
| `golemCrafting` | Golem summoning (Golemancy) |
| `gearCrafting` | Gear fabrication recipes |
| `earthShaping` | Earth mana shaping |
---
## 7. Mana Conversion Interaction
### 7.1 Conversion Flow
Each tick, the mana system:
1. Computes total raw regen (base + attunement regen + discipline bonus + equipment) × temporalEcho × meditationMultiplier
2. Subtracts incursion reduction: `× (1 - incursionStrength)`
3. Computes total conversion drain: sum of all active attunement conversion rates
4. Applies: `rawMana += totalRegen - totalConversionDrain` (per tick)
5. For each attunement with conversion: adds `conversionRate × HOURS_PER_TICK` to the target element
### 7.2 Invoker's Unique Position
The Invoker has **no automatic conversion**`conversionRate = 0`. Instead, it gains
elemental mana types exclusively by signing Guardian pacts. Each guardian's
`unlocksMana` array is resolved through `resolveMultiUnlockChain(element)`, which
unlocks the guardian's element and all base components.
Example: Signing a Metal guardian (floor 90) unlocks `fire`, `earth`, and `metal`.
### 7.3 Conversion and Incursion
Incursion reduces net raw mana regeneration:
```
effectiveRegen = max(0, baseRegen × (1 - incursionStrength) × meditationMult - totalConversionPerTick)
```
As incursion strength approaches 95% (day 30), conversion drains can exceed regen,
causing raw mana to decrease. Since conversion is contingent on available raw mana,
attunement conversion effectively stalls during peak incursion if the raw pool is
insufficient.
---
## 8. Puzzle Room Interaction
From `spire-climbing-spec.md` §4.3, puzzle rooms appear on every 7th floor and have
per-attunement variants:
| Room Type | Description |
|---|---|
| `enchanter_trial` | Enchanter-themed puzzle challenge |
| `fabricator_trial` | Fabricator-themed puzzle challenge |
| `invoker_trial` | Invoker-themed puzzle challenge |
| `hybrid_enchanter_fabricator` | Dual attunement challenge |
| `hybrid_enchanter_invoker` | Dual attunement challenge |
| `hybrid_fabricator_invoker` | Dual attunement challenge |
**Time-based progression system:** Each puzzle room has a base time requirement
that varies by floor range (4h for floors 120, 8h for 2150, 16h for 51100,
24h for 101+). Each relevant attunement reduces the total time needed, up to
a maximum 90% reduction shared across all relevant attunements. Progress
accumulates at `HOURS_PER_TICK` (0.04h) per tick. The room completes when
`puzzleProgress >= puzzleRequired`.
---
## 9. State Fields
```typescript
interface AttunementState {
id: string;
active: boolean;
level: number; // 110
experience: number; // current XP toward next level
}
// Initial state (prestige):
attunements: {
enchanter: { id: 'enchanter', active: true, level: 1, experience: 0 }
}
```
---
## 10. Acceptance Criteria
| # | Criterion |
|---|---|
| AC-1 | Enchanter is the only active attunement at game start (level 1, 0 XP). |
| AC-2 | Invoker and Fabricator are locked until unlocked; their unlock conditions are displayed in the Attunements tab. |
| AC-3 | Attunement XP accumulates and triggers level-ups at the correct thresholds; each level requires the exact XP specified in the formula. |
| AC-4 | Regen and conversion rates scale by `1.5^(level-1)` — a level 10 Enchanter converts at 7.69 raw→transference/hour. |
| AC-5 | Both raw regen and conversion from all active attunements are summed and applied each tick. |
| AC-6 | Invoker has no automatic mana conversion at any level. |
| AC-7 | Enchanting awards Enchanter XP at 1 per 10 capacity used (minimum 1). |
| AC-8 | Attunement skill categories correctly gate discipline pool access — Enchanter disciplines require Enchanter to be active. |
| AC-9 | Attunement tab shows unlocked/locked visual distinction, XP progress bar, level badge, and all attunement capabilities. |
| AC-10 | Puzzle rooms on every 7th floor use per-attunement room types with the correct progress scaling. |
| AC-11 | Incursion correctly reduces net raw mana regeneration, potentially stalling conversion at peak incursion. |
---
## 11. Files Reference
| File | Role |
|---|---|
| `src/lib/game/data/attunements.ts` | Attunement definitions (the 3 attunements) |
| `src/lib/game/stores/attunementStore.ts` | Attunement state, leveling, XP, unlock |
| `src/lib/game/types/attunements.ts` | Attunement type definitions |
| `src/components/game/tabs/AttunementsTab.tsx` | Attunement UI display |
| `src/lib/game/stores/manaStore.ts` | Mana regen, conversion, incursion effects |
| `docs/specs/spire-climbing-spec.md` | Puzzle room types per attunement |