Files
Mana-Loop/docs/task5/subtask_16_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

7.8 KiB

Task 16: Gate Mana Capacity Research Visibility by Unlocked Mana Type (PRIORITY 4b)

Context Summary

1. How Research Nodes Are Currently Filtered/Displayed

Location: /home/user/repos/Mana-Loop/src/components/game/tabs/SkillsTab.tsx

Current Filtering Mechanism:

  • Skills are organized by categories defined in SKILL_CATEGORIES (from /home/user/repos/Mana-Loop/src/lib/game/constants/skills.ts)
  • The SkillsTab component uses getAvailableSkillCategories(store.attunements || {}) to determine which skill categories to display
  • getAvailableSkillCategories (from /home/user/repos/Mana-Loop/src/lib/game/data/attunements.ts) returns categories based on active attunements:
    • Always available: 'mana', 'study', 'research', 'ascension'
    • Enchanter attunement adds: 'enchant', 'effectResearch'
    • Invoker attunement adds: 'invocation', 'pact'
    • Fabricator attunement adds: 'fabrication', 'golemancy'
    • Legacy: 'craft'

Skill Display Logic (SkillsTab.tsx lines 200-220):

const availableCategories = getAvailableSkillCategories(store.attunements || {});
return SKILL_CATEGORIES
  .filter(cat => availableCategories.includes(cat.id))
  .map((cat) => {
    const skillsInCat = Object.entries(SKILLS_DEF).filter(([, def]) => def.cat === cat.id);
    // ... render skills
  });

Prerequisites Checking (SkillsTab.tsx lines 269-280):

  • Skills check def.req (skill prerequisites)
  • Skills check def.attunementReq (attunement level requirements)
  • Skills with element costs check if player has enough element mana (but skill is still VISIBLE)

Key Point: Mana capacity research skills (e.g., fireManaCap, waterManaCap) are currently ALWAYS visible in the "Mana" category (which is always available). They just show as "cannot study" if the player lacks the required element mana.


2. Unlocked Mana Types State

Location: /home/user/repos/Mana-Loop/src/lib/game/store.ts and /home/user/repos/Mana-Loop/src/lib/game/types/elements.ts

GameState Elements Structure:

elements: Record<string, ElementState>;

ElementState Interface:

interface ElementState {
  current: number;    // Current mana amount
  max: number;         // Maximum capacity
  unlocked: boolean;   // Whether this element type is unlocked
}

Base Unlocked Elements:

  • Defined in /home/user/repos/Mana-Loop/src/lib/game/constants/elements.ts
  • BASE_UNLOCKED_ELEMENTS = ['transference'] - Only transference is unlocked at game start

Element Unlocking Mechanisms:

  1. unlockElement(element) action (store.ts line 2123): Costs 500 raw mana, sets unlocked: true
  2. craftComposite(target) action: Automatically unlocks composite elements when crafted
  3. Enchanter attunement: Auto-unlocks transference element (store.ts line 695)

All Element Types (from ELEMENTS constant):

  • Base: fire, water, air, earth, light, dark, death
  • Utility: transference
  • Composite: metal (fire+earth), sand (earth+water), lightning (fire+air)
  • Exotic: crystal (sand+sand+light), stellar (fire+fire+light), void (dark+dark+death)

3. Mana Capacity Research Skills

Location: /home/user/repos/Mana-Loop/src/lib/game/constants/skills.ts

Mana Capacity Research Nodes (lines 9-21):

// Per-mana-type capacity upgrades (Bug 9)
fireManaCap:    { name: "Fire Mana Capacity +10%", desc: "...", cat: "mana", max: 10, base: 200, studyTime: 4, cost: { type: 'element', element: 'fire', amount: 100 } },
waterManaCap:   { name: "Water Mana Capacity +10%", cat: "mana", cost: { type: 'element', element: 'water', amount: 100 } },
airManaCap:     { name: "Air Mana Capacity +10%", cat: "mana", cost: { type: 'element', element: 'air', amount: 100 } },
earthManaCap:   { name: "Earth Mana Capacity +10%", cat: "mana", cost: { type: 'element', element: 'earth', amount: 100 } },
lightManaCap:   { name: "Light Mana Capacity +10%", cat: "mana", cost: { type: 'element', element: 'light', amount: 150 } },
darkManaCap:    { name: "Dark Mana Capacity +10%", cat: "mana", cost: { type: 'element', element: 'dark', amount: 150 } },
deathManaCap:   { name: "Death Mana Capacity +10%", cat: "mana", cost: { type: 'element', element: 'death', amount: 200 } },
// Composite element capacity upgrades
metalManaCap:   { name: "Metal Mana Capacity +10%", cat: "mana", cost: { type: 'element', element: 'metal', amount: 250 } },
sandManaCap:    { name: "Sand Mana Capacity +10%", cat: "mana", cost: { type: 'element', element: 'sand', amount: 250 } },
lightningManaCap: { name: "Lightning Mana Capacity +10%", cat: "mana", cost: { type: 'element', element: 'lightning', amount: 250 } },
// Utility mana capacity upgrades
transferenceManaCap: { name: "Transference Mana Capacity +10%", cat: "mana", cost: { type: 'element', element: 'transference', amount: 100 } },

Key Observation: Each mana capacity skill has:

  • cost.type: 'element'
  • cost.element: The element type this skill applies to
  • cost.amount: The element mana required to study

4. How to Gate Capacity Research by Unlocked Mana Type

Objective: Hide mana capacity research skills unless the corresponding element type is unlocked.

Implementation Approach:

  1. In SkillsTab.tsx, add filtering logic for mana capacity skills:

    When rendering skills in the "mana" category, check if the skill:

    • Has def.cost?.type === 'element'
    • AND store.elements[def.cost.element]?.unlocked === true
  2. Modified SkillsTab rendering (around line 220):

    {skillsInCat.map(([id, def]) => {
      // GATE MANA CAPACITY SKILLS BY UNLOCKED ELEMENT
      if (def.cost?.type === 'element') {
        const element = store.elements[def.cost.element];
        if (!element?.unlocked) {
          return null; // Don't render this skill
        }
      }
      // ... rest of skill rendering
    })}
    
  3. Alternative: Filter at category level (less granular):

    • Could filter skillsInCat before mapping:
    const visibleSkills = skillsInCat.filter(([id, def]) => {
      if (def.cost?.type === 'element') {
        return store.elements[def.cost.element]?.unlocked;
      }
      return true; // Show non-element-cost skills
    });
    
  4. Optional: Show locked state instead of hiding:

    • Could show a "locked" badge or tooltip explaining the element needs to be unlocked first
    • This would require modifying the skill rendering to handle a "locked due to element not unlocked" state

5. Files to Modify

  1. /home/user/repos/Mana-Loop/src/components/game/tabs/SkillsTab.tsx

    • Add filtering logic to hide mana capacity research skills when the corresponding element is not unlocked
    • Location: Around line 220 in the skillsInCat.map() function
  2. No backend/store changes needed - The unlocked state already exists in store.elements. This is purely a UI/display change.


6. Testing Considerations

  • Test that fireManaCap is hidden when store.elements['fire'].unlocked === false
  • Test that fireManaCap becomes visible after calling store.unlockElement('fire')
  • Test that non-element-cost skills (like manaWell, manaFlow) are always visible
  • Test composite element skills (metalManaCap, etc.) hide/show correctly
  • Test that the "Mana" category still shows other non-gated skills even when some are hidden

This task is related to:

  • Task 9 (Bug 9): Per-mana-type capacity upgrades - the skills being gated were added in this task
  • Task 12 (Bug 12): Research moved to Mana category - this is why capacity research is in the "mana" category

Summary: The gating logic needs to be added to SkillsTab.tsx to filter out mana capacity research skills (*ManaCap) when store.elements[element].unlocked is false. The state already tracks unlocked elements, so no store changes are needed.