313 lines
9.6 KiB
Markdown
313 lines
9.6 KiB
Markdown
# 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
|