Files
Mana-Loop/docs/specs/mana-conversion-spec.md
T
n8n-gitea c22f9c3bd5
Build and Publish Mana Loop Docker Image / build-and-publish (push) Failing after 1m2s
feat: add mana conversion system spec and ticket
2026-06-04 13:24:15 +02:00

428 lines
16 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.
# Mana Conversion System — Specification
## Overview
This spec defines a unified mana conversion system that replaces the current fragmented approach (attunement conversions, discipline conversions, manual conversion, and guardian pact conversions). All conversion types use the same core mechanics: consuming source mana types to produce a destination mana type, with costs deducted from **regen** (not from the mana pool directly).
---
## 1. Element Distance from Raw Mana
Every mana type has a **distance** from raw mana. This value is used in two places:
1. Calculating conversion cost ratios
2. Calculating meditation multiplier strength for that element's conversion
### Distance Table
| Element | Category | Distance |
|---------|----------|----------|
| Raw | — | 0 |
| Fire, Water, Air, Earth, Light, Dark, Death | Base | 1 |
| Transference | Utility | 1 |
| Metal, Sand, Lightning, Frost, BlackFlame, RadiantFlames, Miasma, ShadowGlass | Composite | 2 |
| Crystal, Stellar, Void, Soul, Plasma | Exotic (tier 1) | 3 |
| Time | Exotic (tier 2) | 4 |
### Reusable Function
```typescript
// src/lib/game/utils/element-distance.ts
export function getElementDistance(elementId: string): number
```
Returns the distance for any element. If a composite element's recipe contains components at different distances, the element's distance = max(component distances) + 1.
---
## 2. Conversion Cost Ratios
All conversions produce **1 unit** of destination mana. The cost depends on the destination's distance from raw.
### Cost Formula
For a destination element at distance `d`:
- **Raw mana cost** = `10^(d+1)`
- Distance 1 (base): `10^2 = 100` raw per 1 element
- Distance 2 (composite): `10^3 = 1,000` raw per 1 element
- Distance 3 (exotic): `10^4 = 10,000` raw per 1 element
- Distance 4 (time): `10^5 = 100,000` raw per 1 element
- **Each component mana cost** = `10 * (d + 1)` per 1 destination element
- Distance 1: `10 * 2 = 20` of that element per 1 destination
- Distance 2: `10 * 3 = 30` of that element per 1 destination
- Distance 3: `10 * 4 = 40` of that element per 1 destination
- Distance 4: `10 * 5 = 50` of that element per 1 destination
### Cost Table (per 1 unit of destination mana)
| Destination | Distance | Raw Cost | Each Component Cost | Components |
|-------------|----------|----------|---------------------|------------|
| Fire (base) | 1 | 100 | — | — |
| Transference | 1 | 100 | — | — |
| Metal | 2 | 1,000 | 30 fire + 30 earth | fire, earth |
| Sand | 2 | 1,000 | 30 earth + 30 water | earth, water |
| Lightning | 2 | 1,000 | 30 fire + 30 air | fire, air |
| Frost | 2 | 1,000 | 30 air + 30 water | air, water |
| BlackFlame | 2 | 1,000 | 30 dark + 30 fire | dark, fire |
| Radiant Flames | 2 | 1,000 | 30 light + 30 fire | light, fire |
| Miasma | 2 | 1,000 | 30 air + 30 death | air, death |
| Shadow Glass | 2 | 1,000 | 30 earth + 30 dark | earth, dark |
| Crystal | 3 | 10,000 | 40 sand + 40 light | sand, light |
| Stellar | 3 | 10,000 | 40 plasma + 40 light | plasma, light |
| Void | 3 | 10,000 | 40 dark + 40 death | dark, death |
| Soul | 3 | 10,000 | 40 light + 40 dark + 40 transference | light, dark, transference |
| Plasma | 3 | 10,000 | 40 lightning + 40 fire + 40 transference | lightning, fire, transference |
| Time | 4 | 100,000 | 50 soul + 50 sand + 50 transference | soul, sand, transference |
### Key Constraint
Raw mana cost is always **greater** than any individual component cost. This is inherent in the formula: `10^(d+1)` for raw vs `10*(d+1)` for each component.
---
## 3. Conversion Rate — Unified Formula
All three sources (disciplines, attunements, guardian pacts) contribute to a single **base conversion rate** for each element. This rate is then exponentially boosted by attunement levels and pact bonuses.
### Formula
```
finalRate = (disciplineRate + attunementBaseRate + pactBaseRate) ^ (1 + attunementLevelBonus + pactLevelBonus)
```
Where:
- `disciplineRate` = sum of conversion rates from active disciplines for this element (see §4)
- `attunementBaseRate` = sum of base conversion rates from attunements for this element (see §5)
- `pactBaseRate` = sum of base conversion rates from guardian pacts for this element (see §6)
- `attunementLevelBonus` = sum of relevant attunement levels (e.g., Enchanter level for transference, Fabricator level for earth)
- `pactLevelBonus` = count of pacts with guardians that have this element as primary × Invoker attunement level
### Example
A player with:
- Fire Conversion discipline active (rate = 0.5)
- Enchanter attunement level 3 (no fire base rate, but level contributes to exponent if fire is the attunement's primary)
- Fabricator attunement level 2 (earth primary, so contributes to earth conversions)
- 2 fire-type guardian pacts, Invoker level 3
For **fire mana** conversion:
```
baseRate = 0.5 (discipline) + 0 (no attunement base for fire) + 0 (no pact base for fire)
exponent = 1 + 0 (no attunement has fire as primary) + 0 (no fire-type pact bonus)
finalRate = 0.5^1 = 0.5/hr
```
For **metal mana** conversion (fire + earth):
```
baseRate = 0.35 (metal discipline) + 0 (no attunement base) + 0 (no pact base)
exponent = 1 + 2 (Fabricator level 2, earth is a component of metal) + 0
finalRate = 0.35^3 = 0.0429/hr
```
Wait — this produces *lower* rates at higher levels, which is wrong. The exponent should be a **multiplier**, not an exponent on the rate. Let me restate:
### Corrected Formula
```
finalRate = (disciplineRate + attunementBaseRate + pactBaseRate) × (1 + attunementLevelBonus + pactLevelBonus)
```
Where the multiplier is additive:
- `attunementLevelBonus` = sum of relevant attunement levels × 0.5 (each level adds +50% to rate)
- `pactLevelBonus` = count of pacts with this element × Invoker level × 0.25
So:
```
finalRate = baseRate × (1 + Σ(attunementLevel_i × 0.5) + Σ(pactCount_element × invokerLevel × 0.25))
```
### Revised Example
For **metal mana** with Metal Conversion discipline (0.35/hr), Fabricator level 2:
```
baseRate = 0.35
multiplier = 1 + (2 × 0.5) = 2.0
finalRate = 0.35 × 2.0 = 0.70/hr
```
For **transference mana** with Transference Conversion discipline (0.4/hr), Enchanter level 3:
```
baseRate = 0.4
multiplier = 1 + (3 × 0.5) = 2.5
finalRate = 0.4 × 2.5 = 1.0/hr
```
---
## 4. Discipline Contributions
Each conversion discipline provides a **base rate** that scales with XP.
### Base Rates (per hour)
| Element | Base Rate | Difficulty Factor | Scaling Factor |
|---------|-----------|-------------------|----------------|
| Fire, Water, Air, Earth, Light, Dark, Death | 0.5 | 120 | 60 |
| Transference | 0.4 | 100 | 50 |
| Metal, Sand, Lightning, Frost | 0.35 | 160 | 80 |
| BlackFlame, RadiantFlames, Miasma, ShadowGlass | 0.30 | 170 | 85 |
| Crystal, Void | 0.25 | 220 | 110 |
| Stellar, Soul, Plasma | 0.20 | 240 | 120 |
| Time | 0.15 | 260 | 130 |
### XP Scaling
The discipline's effective rate bonus follows the standard stat bonus formula:
```
statBonus = baseValue × (XP / scalingFactor)^0.65
```
The discipline's total contribution to the base rate is:
```
disciplineRate = baseRate + statBonus
```
### Perks
Each discipline has perks that add flat bonuses to the rate:
- **`once` perk**: grants `+baseRate` to the conversion rate at threshold XP
- **`infinite` perk**: every N XP grants `+baseRate × 0.5` to the conversion rate
---
## 5. Attunement Contributions
Attunements provide a **base conversion rate** for their primary mana type, plus a **level-based multiplier** to all conversions involving their element.
### Attunement Base Rates
| Attunement | Primary Mana | Base Rate (per hour) |
|------------|--------------|---------------------|
| Enchanter | Transference | 0.2 |
| Fabricator | Earth | 0.25 |
| Invoker | None | 0 |
### Attunement Level Multiplier
Each attunement level adds +0.5 to the multiplier for conversions where the attunement's primary element is either:
- The destination element, OR
- A component element of the destination
Example: Fabricator (earth) level 3 boosts:
- Earth conversions (earth is destination)
- Metal conversions (earth is component)
- Sand conversions (earth is component)
- Shadow Glass conversions (earth is component)
But NOT fire conversions (earth is not involved).
---
## 6. Guardian Pact Contributions
Guardian pacts provide:
1. A **base conversion rate** for the guardian's element
2. A **level bonus** to the multiplier, scaled by Invoker attunement level
### Pact Base Rate
Each signed pact grants `+0.15/hr` base rate for the guardian's primary element.
### Pact Level Bonus
For each signed pact whose guardian has element E as primary:
```
pactLevelBonus_E += invokerLevel × 0.25
```
So an Invoker at level 4 with 2 fire-type pacts grants:
```
pactLevelBonus_fire = 2 × 4 × 0.25 = 2.0
```
This adds to the multiplier for fire conversions and any composite that uses fire.
---
## 7. Meditation Multiplier
Meditation boosts conversion rates, but the boost is reduced for elements further from raw.
### Formula
```
meditationBoost = 1 + (meditationMultiplier - 1) / distance
```
Where `distance` is the destination element's distance from raw mana.
| Element Distance | Meditation Strength |
|-----------------|-------------------|
| 1 (base) | Full: `meditationMultiplier` |
| 2 (composite) | Half: `1 + (med - 1) / 2` |
| 3 (exotic) | Third: `1 + (med - 1) / 3` |
| 4 (time) | Quarter: `1 + (med - 1) / 4` |
For elements with components at different distances, use the **highest** distance value (i.e., the weakest meditation boost).
---
## 8. Regen Deduction Model
All conversion costs are deducted from **mana regen**, not from the mana pool directly. This means:
1. Each element has a **gross regen** (from attunements, upgrades, etc.)
2. Conversions that consume this element as a source **reduce** the effective regen
3. The remaining regen is the **net regen** that actually adds to the pool
### Raw Mana
```
rawNetRegen = rawGrossRegen
- Σ (conversionRate_destination × rawCost_destination) for all active conversions
```
### Element Mana (e.g., fire)
```
fireNetRegen = fireGrossRegen
+ fireProducedRate (from raw→fire conversion)
- Σ (conversionRate_destination × fireCost_destination) for all conversions using fire as component
```
### Display Format
Each element's regen display shows:
```
Fire Mana Regen:
+0.50/hr converted from raw mana (Fire Conversion discipline, rate × attunement multiplier × meditation)
-0.15/hr being converted into Metal mana (30 per unit × 0.005 units/hr)
-0.10/hr being converted into Lightning mana (30 per unit × 0.0033 units/hr)
─────────────────
+0.25/hr net fire mana regen
```
---
## 9. Insufficient Regen — Auto-Pause
If a conversion's source cost exceeds the **gross regen** of that source type, the conversion is **completely disabled** (not partially throttled).
### Conditions
A conversion for element E is paused if:
```
conversionRate_E × sourceCost_source > sourceGrossRegen
```
for **any** source type (raw or component element) in the conversion.
### UI Warning
When a conversion is paused due to insufficient regen:
- The conversion's entry in the stats tab shows a **red warning**: "⚠️ PAUSED: Insufficient [source] regen (need X/hr, have Y/hr)"
- The mana display for the source element shows a warning icon next to the draining conversion
### Auto-Resume
When regen increases (e.g., attunement levels up, new discipline XP gained, meditation active), paused conversions automatically resume if the regen now covers the cost.
---
## 10. No Manual Conversion
The existing `convertMana` action and `processConvertAction` are **removed**. All mana conversion happens passively through the unified system. The "convert" player action is removed from the action buttons.
---
## 11. Stats Tab Display
The Stats tab includes a new **Conversion Stats** section showing:
### Per-Element Conversion Table
For each element with active conversions:
```
┌─────────────────────────────────────────────────────────────┐
│ 🔥 FIRE MANA CONVERSION │
│ │
│ Base Rate: 0.50/hr (Fire Conversion discipline) │
│ Attunement Bonus: ×1.00 (no attunement for fire) │
│ Pact Bonus: ×1.00 (0 fire-type pacts) │
│ Meditation: ×1.00 (not meditating) │
│ ───────────────────────────────────────── │
│ Effective Rate: 0.50/hr → produces 0.50 fire/hr │
│ │
│ Costs (deducted from raw regen): │
│ Raw: 100 × 0.50 = 50.0 raw/hr │
│ │
│ Drained by downstream conversions: │
│ → Metal: 30 × 0.005 = 0.15 fire/hr │
│ → Lightning: 30 × 0.003 = 0.10 fire/hr │
│ │
│ Net Fire Regen: +0.50 - 0.15 - 0.10 = +0.25 fire/hr │
└─────────────────────────────────────────────────────────────┘
```
### Formula Summary
A collapsible formula reference is shown at the top:
```
Conversion Rate Formula:
finalRate = (disciplineRate + attunementBase + pactBase) × attunementMult × pactMult × meditationMult
Where:
attunementMult = 1 + Σ(relevantAttunementLevel × 0.5)
pactMult = 1 + Σ(pactCount_element × invokerLevel × 0.25)
meditationMult = 1 + (meditationMultiplier - 1) / elementDistance
Cost per 1 unit of destination:
rawCost = 10^(distance+1)
componentCost = 10 × (distance+1) per component
All costs deducted from source regen (not from mana pool).
Conversions pause if source regen < conversion cost.
```
---
## 12. Implementation Notes
### New Files
- `src/lib/game/utils/element-distance.ts``getElementDistance()` function
- `src/lib/game/utils/conversion-rates.ts` — Unified conversion rate calculator
- `src/lib/game/data/conversion-costs.ts` — Cost ratio table per element
### Modified Files
- `src/lib/game/data/disciplines/elemental-regen.ts` — Update base rates, remove drain model
- `src/lib/game/data/disciplines/elemental-regen-advanced.ts` — Update base rates, remove drain model
- `src/lib/game/data/attunements.ts` — Update conversion rates to match new system
- `src/lib/game/effects/discipline-effects.ts` — Update conversion computation
- `src/lib/game/stores/gameStore.ts` — Replace tick conversion logic with unified system
- `src/lib/game/stores/manaStore.ts` — Remove `convertMana`, `processConvertAction`, `craftComposite`
- `src/lib/game/stores/prestigeStore.ts` — Add pact conversion rate data
- `src/components/game/tabs/StatsTab/ElementStatsSection.tsx` — Add conversion display
- `src/components/game/ManaDisplay.tsx` — Add per-element regen breakdown
### Removed
- Manual conversion (`convertMana`, `processConvertAction`)
- Composite crafting via `craftComposite` (replaced by passive conversion)
- The "convert" action from player actions
- Per-tick mana pool deduction for conversions (replaced by regen deduction)
---
## 13. Migration Notes
Existing save data will need migration:
- Active discipline conversion rates are preserved (the XP and discipline IDs stay the same)
- Attunement conversion rates are recalculated from the new base rates
- Any manually-converted element mana in pools is preserved
- The `convertMana` and `craftComposite` store actions are kept as no-ops for save compatibility but have no UI