diff --git a/docs/task2_progress.md b/docs/task2_progress.md index 361f7df..1310b2e 100644 --- a/docs/task2_progress.md +++ b/docs/task2_progress.md @@ -1,6 +1,6 @@ # Task 2 Progress Tracking -**Last Updated**: 2026-04-26 10:35:00 +**Last Updated**: 2026-04-26 12:57:00 **Current Status**: In Progress ## Completed Tasks @@ -9,21 +9,22 @@ - [2026-04-25] Task 4: Equipment System - 2-Handed Weapons ✓ - [2026-04-25] Task 12: StatsTab - Lock Fire/Water/Air/Earth at start ✓ - [2026-04-26] Task 7: CRITICAL BUG FIX - Mana Well 'Deep Basin' upgrade ✓ +- [2026-04-26] Task 2: Research Locking - Prevent switching topics while study in progress ✓ +- [2026-04-26] Task 5: DebugTab Update - Invoker Debugging Buttons ✓ ## In Progress Tasks None currently ## Pending Tasks -1. Task 1: ActionButtons Rework [FAILED - sub-agent context too long] -2. Task 2: Research Locking - SkillsTab [Pending] -3. Task 3: SpireTab Overhaul [FAILED - sub-agent context too long] -4. Task 5: DebugTab Update - Invoker Debugging Buttons [Pending] -5. Task 6: System Integrity - Fix 'Show Component Names' [In Progress - investigating] -6. Task 8: Bug Fix: Combat UI - Casting Bar animation [FAILED - sub-agent context too long] -7. Task 10: Bug Fix: Crafting - Prepare/Design limits [Pending] +1. Task 1: ActionButtons Rework [Try context file approach] +2. Task 3: SpireTab Overhaul [Try context file approach] +3. Task 6: System Integrity - Fix 'Show Component Names' [In Progress - investigating] +4. Task 8: Bug Fix: Combat UI - Casting Bar animation [Try context file approach] +5. Task 10: Bug Fix: Crafting - Prepare/Design limits [Try again] -## Blocked Tasks -- Task 1, 3, 8: Sub-agent attempts failed due to context length limits (603k+ tokens) +## Failed Tasks (Context Length) +- Task 1, 3, 8, 10: Sub-agent attempts failed due to context length limits (423k-603k tokens > 262k limit) +- BUT Task 2 and Task 5 SUCCEEDED with context file approach! ## Commit History - 65b0f96: Remove Transference from LootTab, delete Ascension skills @@ -32,3 +33,7 @@ None currently - 2355be6: StatsTab - Lock Fire/Water/Air/Earth at start - f61ed00: FIX: Skill perks multiplier values (Deep Basin + others) - a6ce36b: WIP: Task 2 progress - investigating Show Component Names debug option +- 4193718: WIP: Task 2 - completed 5/12 tasks, investigating remaining +- fc9e4c8: Add context files for Task 2 sub-agents +- 229cb16: Task 2: Research Locking - prevent switching topics while study in progress +- 9f029d9: Task 2: DebugTab Update - add Invoker Debugging Buttons for Pacts diff --git a/src/app/page.tsx b/src/app/page.tsx index 9c200b0..9cb47a9 100755 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -12,7 +12,7 @@ import { Button } from '@/components/ui/button'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Badge } from '@/components/ui/badge'; -import { RotateCcw } from 'lucide-react'; +import { RotateCcw, Mountain, ChevronDown } from 'lucide-react'; import { TooltipProvider } from '@/components/ui/tooltip'; import { DebugName } from '@/lib/game/debug-context'; // Non-tab component imports @@ -181,7 +181,7 @@ export default function ManaLoopGame() { @@ -207,16 +207,34 @@ export default function ManaLoopGame() { /> - {/* Action Buttons */} - - - + {/* Climb the Spire Button - only show when not in Spire Mode */} + {!store.spireMode && ( + + + + )} + + {/* Action Buttons - only show when not in Spire Mode */} + {!store.spireMode && ( + + + + )} {/* Calendar */} @@ -230,140 +248,166 @@ export default function ManaLoopGame() { {/* Loot and Achievements moved to tabs */} - {/* Right Panel - Tabs */} -
- - - ⚔️ Spire - ✨ Attune - 🗿 Golems - 📚 Skills - 🔮 Spells - 🛡️ Gear - 🔧 Craft - 💎 Loot - 🏆 Achieve - 🔬 Lab - 📊 Stats - 🔧 Debug - 📖 Grimoire - + {/* Right Panel - Conditional rendering based on Spire Mode */} + {store.spireMode ? ( + /* Spire Mode - Simplified UI */ +
+ +
+

+ 🏔️ Spire Mode +

+ +
+ + }> + + +
+
+ ) : ( + /* Normal Mode - Tabs */ +
+ + + ⚔️ Spire + ✨ Attune + 🗿 Golems + 📚 Skills + 🔮 Spells + 🛡️ Gear + 🔧 Craft + 💎 Loot + 🏆 Achieve + 🔬 Lab + 📊 Stats + 🔧 Debug + 📖 Grimoire + - - - }> - - - - + + + }> + + + + - - - }> - - - - + + + }> + + + + - - - }> - - - - + + + }> + + + + - - - }> - - - - + + + }> + + + + - - - }> - - - - + + + }> + + + + - - - }> - - - - + + + }> + + + + - - - }> - - - - - - - - }> - - - - + + + }> + + + + + + + + }> + + + + - - - }> - - - - + + + }> + + + + - - - }> - - - - + + + }> + + + + - - - }> - - - - + + + }> + + + + - - - {renderGrimoireTab()} - - + + + {renderGrimoireTab()} + + - - - }> - - - - - -
+ + + }> + + + + +
+
+ )} diff --git a/src/components/game/ActionButtons.tsx b/src/components/game/ActionButtons.tsx index 7f305e3..f156ca0 100755 --- a/src/components/game/ActionButtons.tsx +++ b/src/components/game/ActionButtons.tsx @@ -1,86 +1,149 @@ 'use client'; -import { Button } from '@/components/ui/button'; -import { Sparkles, Swords, BookOpen, Target, FlaskConical } from 'lucide-react'; +import { Sparkles, Swords, BookOpen, Target, FlaskConical, Cog, Hammer } from 'lucide-react'; import type { GameAction } from '@/lib/game/types'; interface ActionButtonsProps { currentAction: GameAction; + currentStudyTarget: { type: 'skill' | 'spell'; id: string; progress: number; required: number } | null; designProgress: { progress: number; required: number } | null; + designProgress2: { progress: number; required: number } | null; preparationProgress: { progress: number; required: number } | null; applicationProgress: { progress: number; required: number } | null; - setAction: (action: GameAction) => void; + equipmentCraftingProgress: { progress: number; required: number } | null; +} + +// Map action IDs to labels and icons +const ACTION_CONFIG: Record = { + meditate: { label: 'Meditating', icon: Sparkles, color: 'text-blue-400' }, + climb: { label: 'Climbing', icon: Swords, color: 'text-green-400' }, + study: { label: 'Studying', icon: BookOpen, color: 'text-yellow-400' }, + design: { label: 'Designing Enchantment', icon: Target, color: 'text-purple-400' }, + prepare: { label: 'Preparing Equipment', icon: FlaskConical, color: 'text-purple-400' }, + enchant: { label: 'Enchanting', icon: Sparkles, color: 'text-purple-400' }, + craft: { label: 'Crafting Equipment', icon: Hammer, color: 'text-orange-400' }, + convert: { label: 'Converting Mana', icon: Cog, color: 'text-cyan-400' }, +}; + +function ProgressBar({ progress, required, label }: { progress: number; required: number; label?: string }) { + const percentage = Math.min(100, (progress / required) * 100); + return ( +
+ {label &&
{label}
} +
+
+
+
+ ); } export function ActionButtons({ currentAction, + currentStudyTarget, designProgress, + designProgress2, preparationProgress, applicationProgress, - setAction, + equipmentCraftingProgress, }: ActionButtonsProps) { - const actions: { id: GameAction; label: string; icon: typeof Swords }[] = [ - { id: 'meditate', label: 'Meditate', icon: Sparkles }, - { id: 'climb', label: 'Climb', icon: Swords }, - { id: 'study', label: 'Study', icon: BookOpen }, - ]; + const config = ACTION_CONFIG[currentAction] || { label: currentAction, icon: Sparkles, color: 'text-gray-400' }; + const Icon = config.icon; - const hasDesignProgress = designProgress !== null; - const hasPrepProgress = preparationProgress !== null; - const hasAppProgress = applicationProgress !== null; + // Calculate additional info for specific actions + const getActionDetails = () => { + switch (currentAction) { + case 'study': + if (currentStudyTarget) { + const progress = currentStudyTarget.progress; + const required = currentStudyTarget.required; + const percentage = Math.min(100, (progress / required) * 100); + return ( + + ); + } + break; + case 'design': + if (designProgress) { + return ( + + ); + } + break; + case 'prepare': + if (preparationProgress) { + return ( + + ); + } + break; + case 'enchant': + if (applicationProgress) { + return ( + + ); + } + break; + case 'craft': + if (equipmentCraftingProgress) { + return ( + + ); + } + break; + } + return null; + }; return (
-
- {actions.map(({ id, label, icon: Icon }) => ( - - ))} -
- - {/* Crafting actions row - shown when there's active crafting progress */} - {(hasDesignProgress || hasPrepProgress || hasAppProgress) && ( -
- - - +
+
+ + Current Activity
- )} +
+ {config.label} +
+ {getActionDetails()} + + {/* Show second design slot if active */} + {designProgress2 && ( +
+
+ + Second Design Slot +
+ +
+ )} +
); } diff --git a/src/components/game/tabs/SpireTab.tsx b/src/components/game/tabs/SpireTab.tsx index ab2be33..c625760 100755 --- a/src/components/game/tabs/SpireTab.tsx +++ b/src/components/game/tabs/SpireTab.tsx @@ -19,9 +19,10 @@ import { getUnifiedEffects } from '@/lib/game/effects'; interface SpireTabProps { store: GameStore; + simpleMode?: boolean; // When true, only show essential Spire info (for Spire Mode) } -export function SpireTab({ store }: SpireTabProps) { +export function SpireTab({ store, simpleMode = false }: SpireTabProps) { const floorElem = getFloorElement(store.currentFloor); const floorElemDef = ELEMENTS[floorElem]; const isGuardianFloor = !!GUARDIANS[store.currentFloor]; @@ -48,7 +49,7 @@ export function SpireTab({ store }: SpireTabProps) { return ( -
+
{/* Current Floor Card */} @@ -92,35 +93,39 @@ export function SpireTab({ store }: SpireTabProps) {
- - - {/* Floor Navigation - Direction indicator only */} -
-
- Direction -
- - - Up - - - - Down - + {!simpleMode && ( + <> + + + {/* Floor Navigation - Direction indicator only */} +
+
+ Direction +
+ + + Up + + + + Down + +
+
+ + {isFloorCleared && ( +
+ + Floor cleared! Advancing... +
+ )}
-
- - {isFloorCleared && ( -
- - Floor cleared! Advancing... -
- )} -
- - + + + + )}
Best: Floor {store.maxFloorReached} • @@ -205,8 +210,8 @@ export function SpireTab({ store }: SpireTabProps) { - {/* Summoned Golems Card */} - {store.golemancy.summonedGolems.length > 0 && ( + {/* Summoned Golems Card - Always show in simple mode, conditional in normal mode */} + {(simpleMode || store.golemancy.summonedGolems.length > 0) && ( @@ -257,8 +262,8 @@ export function SpireTab({ store }: SpireTabProps) { )} - {/* Current Study (if any) */} - {store.currentStudyTarget && ( + {/* Current Study (if any) - Only show in normal mode */} + {!simpleMode && store.currentStudyTarget && ( )} - {/* Crafting Progress (if any) */} - {(store.designProgress || store.preparationProgress || store.applicationProgress) && ( + {/* Crafting Progress (if any) - Only show in normal mode */} + {!simpleMode && (store.designProgress || store.preparationProgress || store.applicationProgress) && ( )} - {/* Activity Log */} - - - Activity Log - - - -
- {store.log.slice(0, 20).map((entry, i) => ( -
- {entry} -
- ))} -
-
-
-
+ {/* Activity Log - Only show in normal mode */} + {!simpleMode && ( + + + Activity Log + + + +
+ {store.log.slice(0, 20).map((entry, i) => ( +
+ {entry} +
+ ))} +
+
+
+
+ )}
); diff --git a/src/lib/game/store.ts b/src/lib/game/store.ts index d497d2e..e57db5e 100755 --- a/src/lib/game/store.ts +++ b/src/lib/game/store.ts @@ -749,6 +749,9 @@ function makeInitial(overrides: Partial = {}): GameState { // Mana Well Effects (Phase 4) manaHeartBonus: manaHeartBonus, // Cumulative +10% max mana per loop from MANA_HEART + + // Spire Mode - simplified UI for climbing + spireMode: false, }; } @@ -801,6 +804,10 @@ interface GameStore extends GameState, CraftingActions { getMeditationMultiplier: () => number; canCastSpell: (spellId: string) => boolean; getSkillUpgradeChoices: (skillId: string, milestone: 5 | 10) => { available: SkillUpgradeChoice[]; selected: string[] }; + + // Spire Mode actions + enterSpireMode: () => void; + exitSpireMode: () => void; } export const useGameStore = create()( @@ -833,6 +840,9 @@ export const useGameStore = create()( // Compute unified effects (includes skill upgrades AND equipment enchantments) const effects = getUnifiedEffects(state); + + // Track current action for potential auto-transitions + let currentAction = state.currentAction; const maxMana = computeMaxMana(state, effects); const baseRegen = computeRegen(state, effects); @@ -878,7 +888,7 @@ export const useGameStore = create()( let meditateTicks = state.meditateTicks; let meditationMultiplier = 1; - if (state.currentAction === 'meditate') { + if (currentAction === 'meditate') { meditateTicks++; meditationMultiplier = getMeditationBonus(meditateTicks, state.skills); @@ -973,7 +983,7 @@ export const useGameStore = create()( let unlockedEffects = state.unlockedEffects; let consecutiveStudyHours = state.consecutiveStudyHours; - if (state.currentAction === 'study' && currentStudyTarget) { + if (currentAction === 'study' && currentStudyTarget) { // Calculate base study speed let studySpeedMult = getStudySpeedMultiplier(skills); @@ -1076,11 +1086,13 @@ export const useGameStore = create()( log = [`📖 ${SPELLS_DEF[spellId]?.name} learned!`, ...log.slice(0, 49)]; } currentStudyTarget = null; + // Auto-transition to meditate when study completes + currentAction = 'meditate'; } } // Parallel Study processing (PARALLEL_STUDY special effect) let parallelStudyTarget = state.parallelStudyTarget; - if (parallelStudyTarget && state.currentAction === 'study') { + if (parallelStudyTarget && currentAction === 'study') { // Parallel study progresses at 50% speed const parallelProgressGain = HOURS_PER_TICK * 0.5; parallelStudyTarget = { @@ -1101,7 +1113,7 @@ export const useGameStore = create()( } // Convert action - auto convert mana - if (state.currentAction === 'convert') { + if (currentAction === 'convert') { const unlockedElements = Object.entries(elements) .filter(([, e]) => e.unlocked && e.current < e.max); @@ -1130,7 +1142,7 @@ export const useGameStore = create()( const floorElement = getFloorElement(currentFloor); // Handle puzzle rooms separately - if (state.currentAction === 'climb' && currentRoom.roomType === 'puzzle') { + if (currentAction === 'climb' && currentRoom.roomType === 'puzzle') { const progressSpeed = getPuzzleProgressSpeed( currentRoom.puzzleId || '', state.attunements @@ -1154,7 +1166,7 @@ export const useGameStore = create()( maxFloorReached = Math.max(maxFloorReached, currentFloor); castProgress = 0; } - } else if (state.currentAction === 'climb') { + } else if (currentAction === 'climb') { const spellId = state.activeSpell; const spellDef = SPELLS_DEF[spellId]; @@ -1358,7 +1370,7 @@ export const useGameStore = create()( const floorChanged = currentFloor !== golemancy.lastSummonFloor; const inCombatRoom = currentRoom.roomType !== 'puzzle'; - if (state.currentAction === 'climb' && inCombatRoom && floorChanged && maxGolemSlots > 0) { + if (currentAction === 'climb' && inCombatRoom && floorChanged && maxGolemSlots > 0) { // Determine which golems should be summoned const unlockedElementIds = Object.entries(elements) .filter(([, e]) => e.unlocked) @@ -1406,7 +1418,7 @@ export const useGameStore = create()( } // Process golem maintenance and attacks each tick - if (golemancy.summonedGolems.length > 0 && state.currentAction === 'climb' && inCombatRoom) { + if (golemancy.summonedGolems.length > 0 && currentAction === 'climb' && inCombatRoom) { const floorDuration = getGolemFloorDuration(skills); const survivingGolems: typeof golemancy.summonedGolems = []; let anyGolemDismissed = false; @@ -1525,7 +1537,7 @@ export const useGameStore = create()( } // Unsummon golems when not climbing or in puzzle room - if ((state.currentAction !== 'climb' || !inCombatRoom) && golemancy.summonedGolems.length > 0) { + if ((currentAction !== 'climb' || !inCombatRoom) && golemancy.summonedGolems.length > 0) { log = [`🗿 Golems returned to the earth.`, ...log.slice(0, 49)]; golemancy = { ...golemancy, @@ -1559,31 +1571,10 @@ export const useGameStore = create()( // Apply crafting updates if (craftingUpdates.rawMana !== undefined) rawMana = craftingUpdates.rawMana; if (craftingUpdates.log !== undefined) log = craftingUpdates.log; + + // If crafting slice set currentAction (e.g., auto-transition to meditate), use it if (craftingUpdates.currentAction !== undefined) { - set({ - ...craftingUpdates, - day, - hour, - rawMana, - meditateTicks, - totalManaGathered, - currentFloor, - floorHP, - floorMaxHP, - maxFloorReached, - signedPacts, - currentRoom, - incursionStrength, - currentStudyTarget, - skills, - skillProgress, - spells, - elements, - log, - castProgress, - golemancy, - }); - return; + currentAction = craftingUpdates.currentAction; } set({ @@ -1599,6 +1590,7 @@ export const useGameStore = create()( signedPacts, currentRoom, incursionStrength, + currentAction, currentStudyTarget, parallelStudyTarget, skills, @@ -1929,6 +1921,24 @@ export const useGameStore = create()( set(newState); }, + // Spire Mode - enter simplified UI for climbing + enterSpireMode: () => { + set((state) => ({ + spireMode: true, + currentAction: 'climb', + log: ['🏔️ Entered Spire Mode! The climb begins...', ...state.log.slice(0, 49)], + })); + }, + + // Exit Spire Mode - return to normal game UI + exitSpireMode: () => { + set((state) => ({ + spireMode: false, + currentAction: 'meditate', + log: ['⬇️ Climbed down from the Spire. Returning to normal view.', ...state.log.slice(0, 49)], + })); + }, + togglePause: () => { set((state) => ({ paused: !state.paused })); }, diff --git a/src/lib/game/types/game.ts b/src/lib/game/types/game.ts index 5c2ba11..38785b3 100644 --- a/src/lib/game/types/game.ts +++ b/src/lib/game/types/game.ts @@ -212,6 +212,9 @@ export interface GameState { // Loop insight (earned at end of current loop) loopInsight: number; + + // Spire Mode - simplified UI for climbing + spireMode: boolean; } // ─── Action Types for Store ─────────────────────────────────────────────