From 4f932b68107b6c9d749b8be566d3ce4cd9fd7e43 Mon Sep 17 00:00:00 2001 From: n8n-gitea Date: Mon, 18 May 2026 19:38:22 +0200 Subject: [PATCH] fix: remove dead GameContext system and orphaned MemorySlotPicker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GameContext (Provider, hooks, context-create, types) was never wired into the app — no layout or page wrapped children with GameProvider. The only consumer, MemorySlotPicker, was itself orphaned (never imported/rendered). The app uses direct Zustand hooks throughout. Removes 6 dead files. Fixes #65 --- docs/circular-deps.txt | 2 +- docs/dependency-graph.json | 2 +- docs/project-structure.txt | 7 - src/components/game/GameContext.tsx | 10 - src/components/game/GameContext/Provider.tsx | 256 ------------------ .../game/GameContext/context-create.ts | 4 - src/components/game/GameContext/hooks.ts | 13 - src/components/game/GameContext/types.ts | 131 --------- .../game/shared/MemorySlotPicker.tsx | 202 -------------- 9 files changed, 2 insertions(+), 625 deletions(-) delete mode 100755 src/components/game/GameContext.tsx delete mode 100644 src/components/game/GameContext/Provider.tsx delete mode 100644 src/components/game/GameContext/context-create.ts delete mode 100644 src/components/game/GameContext/hooks.ts delete mode 100644 src/components/game/GameContext/types.ts delete mode 100755 src/components/game/shared/MemorySlotPicker.tsx diff --git a/docs/circular-deps.txt b/docs/circular-deps.txt index 815ccf1..788af98 100644 --- a/docs/circular-deps.txt +++ b/docs/circular-deps.txt @@ -1,5 +1,5 @@ # Circular Dependencies -Generated: 2026-05-18T13:14:04.833Z +Generated: 2026-05-18T15:51:10.807Z Found: 1 circular chain(s) — these MUST be fixed before modifying involved files. 1. Processed 123 files (1.2s) (29 warnings) diff --git a/docs/dependency-graph.json b/docs/dependency-graph.json index 6f31360..862da18 100644 --- a/docs/dependency-graph.json +++ b/docs/dependency-graph.json @@ -1,6 +1,6 @@ { "_meta": { - "generated": "2026-05-18T13:14:03.496Z", + "generated": "2026-05-18T15:51:09.351Z", "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 dae851f..afffcb2 100644 --- a/docs/project-structure.txt +++ b/docs/project-structure.txt @@ -63,11 +63,6 @@ Mana-Loop/ │ │ └── page.tsx │ ├── components/ │ │ ├── game/ -│ │ │ ├── GameContext/ -│ │ │ │ ├── Provider.tsx -│ │ │ │ ├── context-create.ts -│ │ │ │ ├── hooks.ts -│ │ │ │ └── types.ts │ │ │ ├── LootInventory/ │ │ │ │ ├── BlueprintsSection.tsx │ │ │ │ ├── EquipmentItem.tsx @@ -106,7 +101,6 @@ Mana-Loop/ │ │ │ │ ├── debug-context.tsx │ │ │ │ └── index.tsx │ │ │ ├── shared/ -│ │ │ │ └── MemorySlotPicker.tsx │ │ │ ├── tabs/ │ │ │ │ ├── ActivityLog.tsx │ │ │ │ ├── DisciplinesTab.tsx @@ -118,7 +112,6 @@ Mana-Loop/ │ │ │ ├── CalendarDisplay.tsx │ │ │ ├── ConfirmDialog.tsx │ │ │ ├── CraftingProgress.tsx -│ │ │ ├── GameContext.tsx │ │ │ ├── GameToast.tsx │ │ │ ├── ManaDisplay.tsx │ │ │ ├── SpellsTab.tsx diff --git a/src/components/game/GameContext.tsx b/src/components/game/GameContext.tsx deleted file mode 100755 index 112ae09..0000000 --- a/src/components/game/GameContext.tsx +++ /dev/null @@ -1,10 +0,0 @@ -'use client'; - -// Re-export everything from the modular GameContext files -export { GameProvider, GameProvider as default } from './GameContext/Provider'; -export { useGameContext } from './GameContext/hooks'; -export { GameContext } from './GameContext/context-create'; -export type { GameContextValue, UnifiedStore } from './GameContext/types'; - -// Re-export useGameLoop for convenience -export { useGameLoop } from '@/lib/game/stores/gameHooks'; diff --git a/src/components/game/GameContext/Provider.tsx b/src/components/game/GameContext/Provider.tsx deleted file mode 100644 index 04d8c1a..0000000 --- a/src/components/game/GameContext/Provider.tsx +++ /dev/null @@ -1,256 +0,0 @@ -'use client'; - -import { useMemo, type ReactNode } from 'react'; -import { useManaStore } from '@/lib/game/stores/manaStore'; -import { usePrestigeStore } from '@/lib/game/stores/prestigeStore'; -import { useUIStore } from '@/lib/game/stores/uiStore'; -import { useCombatStore } from '@/lib/game/stores/combatStore'; -import { useGameStore } from '@/lib/game/stores/gameStore'; -import { computeEffects } from '@/lib/game/effects/upgrade-effects'; -import { hasSpecial, SPECIAL_EFFECTS } from '@/lib/game/effects/special-effects'; -import { - computeMaxMana, - computeRegen, - computeClickMana, - getMeditationBonus, - canAffordSpellCost, - calcDamage, - getFloorElement, - getBoonBonuses, - getIncursionStrength, -} from '@/lib/game/utils'; -import { - ELEMENTS, - GUARDIANS, - SPELLS_DEF, -} from '@/lib/game/constants'; -import type { ElementDef, GuardianDef, SpellDef, GameAction } from '@/lib/game/types'; -import type { UnifiedStore, GameContextValue } from './types'; -import { GameContext } from './context-create'; - -function createUnifiedStore( - gameStore: ReturnType, - manaState: ReturnType, - prestigeState: ReturnType, - uiState: ReturnType, - combatState: ReturnType -): UnifiedStore { - return { - // From gameStore - day: gameStore.day, - hour: gameStore.hour, - incursionStrength: gameStore.incursionStrength, - containmentWards: gameStore.containmentWards, - initialized: gameStore.initialized, - tick: gameStore.tick, - resetGame: gameStore.resetGame, - gatherMana: gameStore.gatherMana, - startNewLoop: gameStore.startNewLoop, - - // From manaStore - rawMana: manaState.rawMana, - meditateTicks: manaState.meditateTicks, - totalManaGathered: manaState.totalManaGathered, - elements: manaState.elements, - setRawMana: manaState.setRawMana, - addRawMana: manaState.addRawMana, - spendRawMana: manaState.spendRawMana, - convertMana: manaState.convertMana, - unlockElement: manaState.unlockElement, - craftComposite: manaState.craftComposite, - - // From prestigeStore - loopCount: prestigeState.loopCount, - insight: prestigeState.insight, - totalInsight: prestigeState.totalInsight, - loopInsight: prestigeState.loopInsight, - prestigeUpgrades: prestigeState.prestigeUpgrades, - memorySlots: prestigeState.memorySlots, - pactSlots: prestigeState.pactSlots, - memories: prestigeState.memories, - defeatedGuardians: prestigeState.defeatedGuardians, - signedPacts: prestigeState.signedPacts, - pactRitualFloor: prestigeState.pactRitualFloor, - pactRitualProgress: prestigeState.pactRitualProgress, - doPrestige: prestigeState.doPrestige, - addMemory: prestigeState.addMemory, - removeMemory: prestigeState.removeMemory, - clearMemories: prestigeState.clearMemories, - startPactRitual: prestigeState.startPactRitual, - cancelPactRitual: prestigeState.cancelPactRitual, - removePact: prestigeState.removePact, - defeatGuardian: prestigeState.defeatGuardian, - - // From combatStore - currentFloor: combatState.currentFloor, - floorHP: combatState.floorHP, - floorMaxHP: combatState.floorMaxHP, - maxFloorReached: combatState.maxFloorReached, - activeSpell: combatState.activeSpell, - currentAction: combatState.currentAction, - castProgress: combatState.castProgress, - spells: combatState.spells, - setAction: combatState.setAction, - setSpell: combatState.setSpell, - learnSpell: combatState.learnSpell, - advanceFloor: combatState.advanceFloor, - - // From uiStore - log: uiState.logs, - paused: uiState.paused, - gameOver: uiState.gameOver, - victory: uiState.victory, - addLog: uiState.addLog, - togglePause: uiState.togglePause, - setPaused: uiState.setPaused, - setGameOver: uiState.setGameOver, - }; -} - -export function GameProvider({ children }: { children: ReactNode }) { - // Get all individual stores - const gameStore = useGameStore(); - const manaState = useManaStore(); - const prestigeState = usePrestigeStore(); - const uiState = useUIStore(); - const combatState = useCombatStore(); - - // Create unified store object for backward compatibility - const unifiedStore = useMemo( - () => createUnifiedStore(gameStore, manaState, prestigeState, uiState, combatState), - [gameStore, manaState, prestigeState, uiState, combatState] - ); - - // Computed effects from upgrades - const upgradeEffects = useMemo( - () => computeEffects({}, {}), - [] - ); - - // Create a minimal state object for compute functions - const stateForCompute = useMemo(() => ({ - prestigeUpgrades: prestigeState.prestigeUpgrades, - signedPacts: prestigeState.signedPacts, - rawMana: manaState.rawMana, - meditateTicks: manaState.meditateTicks, - incursionStrength: gameStore.incursionStrength, - }), [prestigeState, manaState, gameStore.incursionStrength]); - - // Derived stats - const maxMana = useMemo( - () => computeMaxMana(stateForCompute, upgradeEffects), - [stateForCompute, upgradeEffects] - ); - - const baseRegen = useMemo( - () => computeRegen(stateForCompute, upgradeEffects), - [stateForCompute, upgradeEffects] - ); - - const clickMana = useMemo(() => computeClickMana(stateForCompute), [stateForCompute]); - - // Floor element from combat store - const floorElem = useMemo(() => getFloorElement(combatState.currentFloor), [combatState.currentFloor]); - const floorElemDef = ELEMENTS[floorElem]; - const isGuardianFloor = !!GUARDIANS[combatState.currentFloor]; - const currentGuardian = GUARDIANS[combatState.currentFloor]; - const activeSpellDef = SPELLS_DEF[combatState.activeSpell]; - - const meditationMultiplier = useMemo( - () => getMeditationBonus(manaState.meditateTicks, {}, upgradeEffects.meditationEfficiency), - [manaState.meditateTicks, upgradeEffects.meditationEfficiency] - ); - - const incursionStrength = useMemo( - () => getIncursionStrength(gameStore.day, gameStore.hour), - [gameStore.day, gameStore.hour] - ); - - const studySpeedMult = 1; - - const studyCostMult = 1; - - // Effective regen calculations - const effectiveRegenWithSpecials = baseRegen * (1 - incursionStrength); - - const manaCascadeBonus = hasSpecial(upgradeEffects, SPECIAL_EFFECTS.MANA_CASCADE) - ? Math.floor(maxMana / 100) * 0.1 - : 0; - - const manaWaterfallBonus = hasSpecial(upgradeEffects, SPECIAL_EFFECTS.MANA_WATERFALL) - ? Math.floor(maxMana / 100) * 0.25 - : 0; - - const effectiveRegen = (effectiveRegenWithSpecials + manaCascadeBonus + manaWaterfallBonus) * meditationMultiplier; - - // Has special flags for UI - const hasManaWaterfall = hasSpecial(upgradeEffects, SPECIAL_EFFECTS.MANA_WATERFALL); - const hasFlowSurge = hasSpecial(upgradeEffects, SPECIAL_EFFECTS.FLOW_SURGE); - const hasManaOverflow = hasSpecial(upgradeEffects, SPECIAL_EFFECTS.MANA_OVERFLOW); - const hasEternalFlow = hasSpecial(upgradeEffects, SPECIAL_EFFECTS.ETERNAL_FLOW); - - // Active boons - const activeBoons = useMemo( - () => getBoonBonuses(prestigeState.signedPacts), - [prestigeState.signedPacts] - ); - - // DPS calculation - based on active spell, attack speed, and damage - const dps = useMemo(() => { - if (!activeSpellDef) return 0; - const baseDmg = calcDamage( - { signedPacts: prestigeState.signedPacts }, - combatState.activeSpell, - floorElem - ); - const dmgWithEffects = baseDmg * upgradeEffects.baseDamageMultiplier + upgradeEffects.baseDamageBonus; - const attackSpeed = (1 + 0 * 0.05) * upgradeEffects.attackSpeedMultiplier; - const castSpeed = activeSpellDef.castSpeed || 1; - return dmgWithEffects * attackSpeed * castSpeed; - }, [activeSpellDef, prestigeState.signedPacts, floorElem, upgradeEffects, combatState.activeSpell]); - - // Helper functions - const canCastSpell = (spellId: string): boolean => { - const spell = SPELLS_DEF[spellId]; - if (!spell) return false; - return canAffordSpellCost(spell.cost, manaState.rawMana, manaState.elements); - }; - - const value: GameContextValue = { - store: unifiedStore, - manaStore: manaState, - prestigeStore: prestigeState, - uiStore: uiState, - combatStore: combatState, - upgradeEffects, - maxMana, - baseRegen, - clickMana, - floorElem, - floorElemDef, - isGuardianFloor, - currentGuardian, - activeSpellDef, - meditationMultiplier, - incursionStrength, - studySpeedMult, - studyCostMult, - effectiveRegenWithSpecials, - manaCascadeBonus, - manaWaterfallBonus, - effectiveRegen, - hasManaWaterfall, - hasFlowSurge, - hasManaOverflow, - hasEternalFlow, - dps, - activeBoons, - canCastSpell, - hasSpecial, - SPECIAL_EFFECTS, - }; - - return {children}; -} - -GameProvider.displayName = "GameProvider"; diff --git a/src/components/game/GameContext/context-create.ts b/src/components/game/GameContext/context-create.ts deleted file mode 100644 index 877225f..0000000 --- a/src/components/game/GameContext/context-create.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { createContext } from 'react'; -import type { GameContextValue } from './types'; - -export const GameContext = createContext(null); diff --git a/src/components/game/GameContext/hooks.ts b/src/components/game/GameContext/hooks.ts deleted file mode 100644 index c4d12cf..0000000 --- a/src/components/game/GameContext/hooks.ts +++ /dev/null @@ -1,13 +0,0 @@ -'use client'; - -import { useContext } from 'react'; -import { GameContext } from './context-create'; -import type { GameContextValue } from './types'; - -export function useGameContext(): GameContextValue { - const context = useContext(GameContext); - if (!context) { - throw new Error('useGameContext must be used within a GameProvider'); - } - return context; -} diff --git a/src/components/game/GameContext/types.ts b/src/components/game/GameContext/types.ts deleted file mode 100644 index 3d3f07a..0000000 --- a/src/components/game/GameContext/types.ts +++ /dev/null @@ -1,131 +0,0 @@ -import type { ElementDef, GuardianDef, SpellDef, GameAction } from '@/lib/game/types'; -import { useManaStore } from '@/lib/game/stores/manaStore'; -import { usePrestigeStore } from '@/lib/game/stores/prestigeStore'; -import { useUIStore } from '@/lib/game/stores/uiStore'; -import { useCombatStore } from '@/lib/game/stores/combatStore'; -import { computeEffects } from '@/lib/game/effects/upgrade-effects'; -import { hasSpecial, SPECIAL_EFFECTS } from '@/lib/game/effects/special-effects'; -import { getBoonBonuses } from '@/lib/game/utils'; - -// Define a unified store type that combines all stores -export interface UnifiedStore { - // From gameStore (coordinator) - day: number; - hour: number; - incursionStrength: number; - containmentWards: number; - initialized: boolean; - tick: () => void; - resetGame: () => void; - gatherMana: () => void; - startNewLoop: () => void; - - // From manaStore - rawMana: number; - meditateTicks: number; - totalManaGathered: number; - elements: Record; - setRawMana: (amount: number) => void; - addRawMana: (amount: number, max: number) => void; - spendRawMana: (amount: number) => boolean; - convertMana: (element: string, amount: number) => boolean; - unlockElement: (element: string, cost: number) => boolean; - craftComposite: (target: string, recipe: string[]) => boolean; - - // From prestigeStore - loopCount: number; - insight: number; - totalInsight: number; - loopInsight: number; - prestigeUpgrades: Record; - memorySlots: number; - pactSlots: number; - memories: Array<{ skillId: string; level: number; tier: number; upgrades: string[] }>; - defeatedGuardians: number[]; - signedPacts: number[]; - pactRitualFloor: number | null; - pactRitualProgress: number; - doPrestige: (id: string) => void; - addMemory: (memory: { skillId: string; level: number; tier: number; upgrades: string[] }) => void; - removeMemory: (skillId: string) => void; - clearMemories: () => void; - startPactRitual: (floor: number, rawMana: number) => boolean; - cancelPactRitual: () => void; - removePact: (floor: number) => void; - defeatGuardian: (floor: number) => void; - - // From combatStore - currentFloor: number; - floorHP: number; - floorMaxHP: number; - maxFloorReached: number; - activeSpell: string; - currentAction: GameAction; - castProgress: number; - spells: Record; - setAction: (action: GameAction) => void; - setSpell: (spellId: string) => void; - learnSpell: (spellId: string) => void; - advanceFloor: () => void; - - // From uiStore - log: string[]; - paused: boolean; - gameOver: boolean; - victory: boolean; - addLog: (message: string) => void; - togglePause: () => void; - setPaused: (paused: boolean) => void; - setGameOver: (gameOver: boolean, victory?: boolean) => void; -} - -export interface GameContextValue { - // Unified store for backward compatibility - store: UnifiedStore; - - // Individual stores for direct access if needed - manaStore: ReturnType; - prestigeStore: ReturnType; - uiStore: ReturnType; - combatStore: ReturnType; - - // Computed effects from upgrades - upgradeEffects: ReturnType; - - // Derived stats - maxMana: number; - baseRegen: number; - clickMana: number; - floorElem: string; - floorElemDef: ElementDef | undefined; - isGuardianFloor: boolean; - currentGuardian: GuardianDef | undefined; - activeSpellDef: SpellDef | undefined; - meditationMultiplier: number; - incursionStrength: number; - studySpeedMult: number; - studyCostMult: number; - - // Effective regen calculations - effectiveRegenWithSpecials: number; - manaCascadeBonus: number; - manaWaterfallBonus: number; - effectiveRegen: number; - - // Has special flags - hasManaWaterfall: boolean; - hasFlowSurge: boolean; - hasManaOverflow: boolean; - hasEternalFlow: boolean; - - // DPS calculation - dps: number; - - // Boons - activeBoons: ReturnType; - - // Helpers - canCastSpell: (spellId: string) => boolean; - hasSpecial: (effects: ReturnType, specialId: string) => boolean; - SPECIAL_EFFECTS: typeof SPECIAL_EFFECTS; -} diff --git a/src/components/game/shared/MemorySlotPicker.tsx b/src/components/game/shared/MemorySlotPicker.tsx deleted file mode 100755 index ab873da..0000000 --- a/src/components/game/shared/MemorySlotPicker.tsx +++ /dev/null @@ -1,202 +0,0 @@ -'use client'; - -import { useState, useMemo } from 'react'; -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; -import { Button } from '@/components/ui/button'; -import { Badge } from '@/components/ui/badge'; -import { ScrollArea } from '@/components/ui/scroll-area'; -import { Save, Trash2, Star } from 'lucide-react'; -import { useGameContext } from '../GameContext'; -import type { Memory } from '@/lib/game/types'; - -interface MemorySlotPickerProps { - onConfirm?: () => void; -} - -export function MemorySlotPicker({ onConfirm }: MemorySlotPickerProps) { - const { store } = useGameContext(); - const [selectedSkills, setSelectedSkills] = useState(store.memories || []); - - // Get all skills that have progress and can be saved - const saveableSkills = useMemo(() => { - const skills: { skillId: string; level: number; tier: number; upgrades: string[]; name: string }[] = []; - - for (const [skillId, level] of Object.entries(store.skills)) { - if (level && level > 0) { - const baseSkillId = skillId; - const tier = store.skillTiers?.[baseSkillId] || 1; - const tieredSkillId = tier > 1 ? `${baseSkillId}_t${tier}` : baseSkillId; - const upgrades = store.skillUpgrades?.[tieredSkillId] || []; - - // Only include if it's a base skill (not a tiered variant in the skills object) - if (skillId === baseSkillId || skillId.includes('_t')) { - // Get the actual skill ID and level - const actualLevel = store.skills[tieredSkillId] || store.skills[baseSkillId] || 0; - if (actualLevel > 0) { - skills.push({ - skillId: baseSkillId, - level: actualLevel, - tier, - upgrades, - name: baseSkillId, - }); - } - } - } - } - - // Remove duplicates and keep highest tier/level - const uniqueSkills = new Map(); - for (const skill of skills) { - const existing = uniqueSkills.get(skill.skillId); - if (!existing || skill.tier > existing.tier || (skill.tier === existing.tier && skill.level > existing.level)) { - uniqueSkills.set(skill.skillId, skill); - } - } - - return Array.from(uniqueSkills.values()).sort((a, b) => { - // Sort by tier then level then name - if (a.tier !== b.tier) return b.tier - a.tier; - if (a.level !== b.level) return b.level - a.level; - return a.name.localeCompare(b.name); - }); - }, [store.skills, store.skillTiers, store.skillUpgrades]); - - const isSkillSelected = (skillId: string) => selectedSkills.some(m => m.skillId === skillId); - - const canAddMore = selectedSkills.length < store.memorySlots; - - const toggleSkill = (skillId: string) => { - const existingIndex = selectedSkills.findIndex(m => m.skillId === skillId); - - if (existingIndex >= 0) { - // Remove it - setSelectedSkills(selectedSkills.filter((_, i) => i !== existingIndex)); - } else if (canAddMore) { - // Add it - const skill = saveableSkills.find(s => s.skillId === skillId); - if (skill) { - setSelectedSkills([...selectedSkills, { - skillId: skill.skillId, - level: skill.level, - tier: skill.tier, - upgrades: skill.upgrades, - }]); - } - } - }; - - const handleConfirm = () => { - // Clear and re-add selected memories - store.clearMemories(); - for (const memory of selectedSkills) { - store.addMemory(memory); - } - onConfirm?.(); - }; - - return ( - - - - - Memory Slots ({selectedSkills.length}/{store.memorySlots}) - - - -

- Select skills to preserve in your memory. Saved skills will retain their level, tier, and upgrades in the next loop. -

- - {/* Selected Skills */} - {selectedSkills.length > 0 && ( -
-
Saved to Memory:
-
- {selectedSkills.map((memory) => ( - toggleSkill(memory.skillId)} - > - {memory.skillId} - {' '}Lv.{memory.level} - {memory.tier > 1 && ` T${memory.tier}`} - {memory.upgrades.length > 0 && ` (${memory.upgrades.length}⭐)`} - - - ))} -
-
- )} - - {/* Available Skills */} -
Skills to Save:
- -
- {saveableSkills.length === 0 ? ( -
- No skills with progress to save -
- ) : ( - saveableSkills.map((skill) => { - const isSelected = isSkillSelected(skill.skillId); - const tierMult = 1; - - return ( -
toggleSkill(skill.skillId)} - > -
-
- {skill.name} - {skill.tier > 1 && ( - - Tier {skill.tier} ({tierMult}x) - - )} -
-
- Lv.{skill.level} - {skill.upgrades.length > 0 && ( - - - {skill.upgrades.length} - - )} -
-
- {skill.upgrades.length > 0 && ( -
- Upgrades: {skill.upgrades.length} selected -
- )} -
- ); - }) - )} -
-
- - {/* Confirm Button */} - -
-
- ); -} - -MemorySlotPicker.displayName = "MemorySlotPicker";