From c22f9c3bd5d78c5f9c5efb5cc24bae464a31240d Mon Sep 17 00:00:00 2001 From: n8n-gitea Date: Thu, 4 Jun 2026 13:24:15 +0200 Subject: [PATCH] feat: add mana conversion system spec and ticket --- docs/circular-deps.txt | 2 +- docs/dependency-graph.json | 2 +- docs/project-structure.txt | 1 + docs/specs/mana-conversion-spec.md | 427 +++++++++++++++++++++++++++++ 4 files changed, 430 insertions(+), 2 deletions(-) create mode 100644 docs/specs/mana-conversion-spec.md diff --git a/docs/circular-deps.txt b/docs/circular-deps.txt index e802214..50dec10 100644 --- a/docs/circular-deps.txt +++ b/docs/circular-deps.txt @@ -1,4 +1,4 @@ # Circular Dependencies -Generated: 2026-06-04T09:16:19.999Z +Generated: 2026-06-04T09:37:34.683Z No circular dependencies found. ✅ diff --git a/docs/dependency-graph.json b/docs/dependency-graph.json index 6354d02..ef37d35 100644 --- a/docs/dependency-graph.json +++ b/docs/dependency-graph.json @@ -1,6 +1,6 @@ { "_meta": { - "generated": "2026-06-04T09:16:18.073Z", + "generated": "2026-06-04T09:37:32.833Z", "description": "Import dependency graph for src/lib/game. Keys are files, values are arrays of files they import.", "usage": "To find what a file affects, search for its path in the VALUES. To find what a file depends on, look at its KEY entry." }, diff --git a/docs/project-structure.txt b/docs/project-structure.txt index bd9fdb1..08ef869 100644 --- a/docs/project-structure.txt +++ b/docs/project-structure.txt @@ -27,6 +27,7 @@ Mana-Loop/ │ │ │ │ │ └── pact-system-spec.md │ │ │ │ └── invoker-spec.md │ │ │ └── attunement-system-spec.md +│ │ ├── mana-conversion-spec.md │ │ ├── spire-climbing-spec.md │ │ └── spire-combat-spec.md │ ├── GAME_BRIEFING.md diff --git a/docs/specs/mana-conversion-spec.md b/docs/specs/mana-conversion-spec.md new file mode 100644 index 0000000..2214455 --- /dev/null +++ b/docs/specs/mana-conversion-spec.md @@ -0,0 +1,427 @@ +# 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