Files
Mana-Loop/docs/task6/subtask_1_context.md
T
Refactoring Agent 03815f27ee
Build and Publish Mana Loop Docker Image / build-and-publish (push) Failing after 5m57s
feat: add prestige system and skill upgrades with comprehensive documentation
2026-05-01 15:18:09 +02:00

313 lines
9.6 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.
# Task6-1 Context: Proposal 1 - Unlocked Mana Type Capacity
## Overview
Gathered context for implementing Proposal 1: Unlocked Mana Type Capacity. This proposal likely relates to either:
1. Increasing the mana capacity (max) of unlocked mana types
2. Increasing the number of mana types that can be unlocked
## 1. Existing Prestige Upgrade Structure
**File:** `src/lib/game/constants/prestige.ts`
### PrestigeDef Interface (from `src/lib/game/types/skills.ts`)
```typescript
export interface PrestigeDef {
name: string;
desc: string;
max: number;
cost: number;
}
```
### Current Prestige Upgrades (relevant to mana/elements)
```typescript
export const PRESTIGE_DEF: Record<string, PrestigeDef> = {
// ... other upgrades ...
// Existing elemental capacity upgrade
elementalAttune: {
name: "Elemental Attunement",
desc: "+25 elemental mana cap",
max: 10,
cost: 600
},
// Starting elemental mana upgrade
elemStart: {
name: "Elem. Start",
desc: "Start with 5 of each unlocked element",
max: 3,
cost: 800
},
// ... other upgrades ...
};
```
**Key observations:**
- All prestige upgrades use the same structure: name, description, max level, cost
- `elementalAttune` already provides +25 elemental mana cap per level (max 10 levels = +250 cap)
- `elemStart` gives starting elemental mana when a new loop begins
- Upgrades are stored as `Record<string, number>` where the value is the current level
---
## 2. How Mana Type Unlocks Are Tracked
### Element State Structure
**File:** `src/lib/game/types/elements.ts`
```typescript
export interface ElementState {
current: number;
max: number;
unlocked: boolean;
}
```
### Elements Storage in GameState
**File:** `src/lib/game/types/game.ts`
```typescript
export interface GameState {
// ...
elements: Record<string, ElementState>;
// ...
}
```
### Base Unlocked Elements
**File:** `src/lib/game/constants/elements.ts`
```typescript
export const BASE_UNLOCKED_ELEMENTS = ['transference'];
```
**Key observations:**
- Only `transference` starts unlocked by default
- All other 12 elements (fire, water, air, earth, light, dark, death, metal, sand, lightning, crystal, stellar, void) start locked
- Elements have a boolean `unlocked` field - no partial unlocking or limits on number of unlocked types
### Unlocking New Elements
**File:** `src/lib/game/store.ts` (lines 2176-2195)
```typescript
unlockElement: (element: string) => {
const state = get();
if (state.elements[element]?.unlocked) return;
const cost = 500;
if (state.rawMana < cost) return;
// ELEMENTAL_AFFINITY: New elements start with 10 capacity
const effects = getUnifiedEffects(state.skillUpgrades, state.skillTiers);
const newElementMax = hasSpecial(effects, SPECIAL_EFFECTS.ELEMENTAL_AFFINITY) ? 10 : 0;
set({
rawMana: state.rawMana - cost,
elements: {
...state.elements,
[element]: { ...state.elements[element], unlocked: true, max: newElementMax },
},
log: [`${ELEMENTS[element].name} affinity unlocked!`, ...state.log.slice(0, 49)],
});
},
```
**Key observations:**
- Unlocking an element costs 500 raw mana
- When unlocked, the element gets `unlocked: true`
- New elements start with `max: 0` unless ELEMENTAL_AFFINITY special effect is active (then max: 10)
- No limit on the NUMBER of elements that can be unlocked - players can unlock all 12+ types
### Element Definitions
**File:** `src/lib/game/constants/elements.ts`
Total element types:
- **Base (7):** fire, water, air, earth, light, dark, death
- **Utility (1):** transference
- **Composite (3):** metal, sand, lightning
- **Exotic (3):** crystal, stellar, void
**Total: 14 element types** (13 unlockable + transference which starts unlocked)
---
## 3. How Mana Capacity Is Applied
### computeElementMax Function
**File:** `src/lib/game/store.ts` (lines 415-432)
```typescript
export function computeElementMax(
state: Pick<GameState, 'skills' | 'prestigeUpgrades' | 'skillUpgrades' | 'skillTiers'>,
effects?: ComputedEffects | UnifiedEffects,
element?: string
): number {
const pu = state.prestigeUpgrades;
const base = 10 + (state.skills.elemAttune || 0) * 50 + (pu.elementalAttune || 0) * 25;
// Apply upgrade effects if provided
if (effects) {
let bonus = effects.elementCapBonus; // Global bonus
// Add per-element bonus if element is specified and available
if (element && (effects as UnifiedEffects).perElementCapBonus) {
const perElementBonus = (effects as UnifiedEffects).perElementCapBonus[element];
if (perElementBonus) {
bonus += perElementBonus;
}
}
return Math.floor((base + bonus) * effects.elementCapMultiplier);
}
return base;
}
```
**Key observations:**
- Base capacity formula: `10 + (elemAttune skill levels * 50) + (elementalAttune prestige levels * 25)`
- Effects system can modify capacity via:
- `elementCapBonus`: Global flat bonus
- `elementCapMultiplier`: Global multiplier
- `perElementCapBonus[element]`: Per-element flat bonus (from equipment)
- **Currently, all unlocked elements share the SAME max capacity** (calculated once and applied to all)
- The `perElementCapBonus` exists but is currently only used for equipment effects
### Usage in Store Initialization
**File:** `src/lib/game/store.ts` (lines 670-710)
```typescript
function makeInitial(overrides: Partial<GameState> = {}): GameState {
const pu = overrides.prestigeUpgrades || {};
// ...
const elemMax = computeElementMax(
{ skills: overrides.skills || {}, prestigeUpgrades: pu, skillUpgrades: overrides.skillUpgrades, skillTiers: overrides.skillTiers },
effects
);
const elements: Record<string, { current: number; max: number; unlocked: boolean }> = {};
Object.keys(ELEMENTS).forEach((k) => {
const isUnlocked = BASE_UNLOCKED_ELEMENTS.includes(k);
let startAmount = 0;
// Start with some elemental mana if elemStart upgrade
if (isUnlocked && pu.elemStart) {
startAmount = pu.elemStart * 5;
}
elements[k] = {
current: overrides.elements?.[k]?.current ?? startAmount,
max: elemMax, // <-- Same max for ALL elements
unlocked: isUnlocked,
};
});
// ...
}
```
**Key observation:** The same `elemMax` is applied to ALL elements regardless of type or unlock status.
---
## 4. Save Data Structure (Cross-Loop Persistence)
### GameState Prestige-Related Fields
**File:** `src/lib/game/types/game.ts`
```typescript
export interface GameState {
// ...
// Prestige
insight: number;
totalInsight: number;
prestigeUpgrades: Record<string, number>;
memorySlots: number;
memories: string[];
// Elements
elements: Record<string, ElementState>;
// ...
}
```
### What Persists Through Loops
**File:** `src/lib/game/store.ts` (lines 2255-2290)
```typescript
startNewLoop: () => {
const state = get();
const insightGained = state.loopInsight || calcInsight(state);
const total = state.insight + insightGained;
// ... (keep some spells through temporal memory)
const newState = makeInitial({
loopCount: state.loopCount + 1,
insight: total,
totalInsight: (state.totalInsight || 0) + insightGained,
prestigeUpgrades: state.prestigeUpgrades, // <-- PERSISTS
memories: state.memories,
skills: state.skills,
manaHeartBonus: newHeartBonus,
});
// ...
set(newState);
},
```
**Key observations:**
- `prestigeUpgrades` (all upgrade levels) persist through loops
- `insight` and `totalInsight` persist and accumulate
- `elements` are NOT persisted - they are reinitialized in `makeInitial()`
- On new loop, element unlocks are lost (player must re-unlock elements)
- `BASE_UNLOCKED_ELEMENTS` and `pu.elemStart` determine which elements start unlocked/have starting mana
### Purchasing Prestige Upgrades
**File:** `src/lib/game/store.ts` (lines 2235-2250)
```typescript
doPrestige: (id: string) => {
// ...
const lvl = state.prestigeUpgrades[id] || 0;
if (lvl >= pd.max || state.insight < pd.cost) return;
const newPU = { ...state.prestigeUpgrades, [id]: lvl + 1 };
set({
insight: state.insight - pd.cost,
prestigeUpgrades: newPU,
// ...
});
},
```
**Key observations:**
- Upgrades purchased with `insight` currency
- Each level costs the same amount (flat cost model)
- Max level check prevents over-purchasing
- New upgrade level is saved to `prestigeUpgrades` record
---
## Summary of Key Points for Task6-1
1. **Prestige upgrades** follow a simple structure: `{ name, desc, max, cost }`
2. **Element capacity** is currently global (same for all elements), calculated from:
- Base: 10
- Skill: `elemAttune` levels × 50
- Prestige: `elementalAttune` levels × 25
- Effects: bonuses and multipliers
3. **Element unlocks** are per-type (boolean), cost 500 raw mana each
4. **No limit** on number of unlocked element types currently exists
5. **Per-element capacity** bonuses exist in effects system (`perElementCapBonus`) but aren't widely used
6. **Cross-loop persistence:** prestige upgrades and insight persist; element unlocks do NOT persist
7. **14 total element types** available (13 unlockable + transference)
## Questions for Implementation
Depending on what "Unlocked Mana Type Capacity" means:
**If it means increasing capacity (max mana) of unlocked types:**
- Could add a new prestige upgrade similar to `elementalAttune`
- Could modify the `computeElementMax` function
- Could add per-element capacity tracking
**If it means increasing the NUMBER of types that can be unlocked:**
- Need to add a limit/cap on unlocked types (currently unlimited)
- Need to add a prestige upgrade to increase this limit
- Need to modify `unlockElement` to check against the limit