diff --git a/docs/circular-deps.txt b/docs/circular-deps.txt index 47ac179..abb0d12 100644 --- a/docs/circular-deps.txt +++ b/docs/circular-deps.txt @@ -1,4 +1,4 @@ # Circular Dependencies -Generated: 2026-05-30T08:40:53.794Z +Generated: 2026-05-30T13:27:24.782Z No circular dependencies found. ✅ diff --git a/docs/dependency-graph.json b/docs/dependency-graph.json index b819c0d..9df2d07 100644 --- a/docs/dependency-graph.json +++ b/docs/dependency-graph.json @@ -1,6 +1,6 @@ { "_meta": { - "generated": "2026-05-30T08:40:52.033Z", + "generated": "2026-05-30T13:27:23.117Z", "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/e2e/playtest.spec.ts b/e2e/playtest.spec.ts new file mode 100644 index 0000000..ba4c64c --- /dev/null +++ b/e2e/playtest.spec.ts @@ -0,0 +1,621 @@ +import { test, expect, type Page } from '@playwright/test'; + +// Use the deployed production URL +test.use({ + baseURL: 'https://manaloop.tailf367e3.ts.net/', +}); + +// Helper: Clear localStorage and reload for fresh game +async function startFreshGame(page: Page) { + await page.goto('/'); + await page.evaluate(() => localStorage.clear()); + await page.reload(); + await page.waitForLoadState('networkidle'); +} + +// Helper: Run debug command via console +async function runDebug(page: Page, cmd: string) { + await page.evaluate((c) => { + // @ts-expect-error - debug function on window + if (typeof window.__debug === 'function') window.__debug(c); + }, cmd); +} + +// Helper: Wait for game to tick a few times +async function waitForTicks(page: Page, ms = 1000) { + await page.waitForTimeout(ms); +} + +test.describe('Mana Loop - Comprehensive Playtest', () => { + + // ========================================================================= + // SECTION 1: Basic UI & Starting State + // ========================================================================= + test.describe('1 - Basic UI & Starting State', () => { + test.beforeEach(async ({ page }) => { + await startFreshGame(page); + }); + + test('game loads without console errors', async ({ page }) => { + const errors: string[] = []; + page.on('console', (msg) => { + if (msg.type() === 'error') errors.push(msg.text()); + }); + await waitForTicks(page, 2000); + const reactErrors = errors.filter(e => + e.includes('React') || e.includes('Minified') || e.includes('Error #') || e.includes('Maximum update depth') + ); + expect(reactErrors, `React errors found: ${JSON.stringify(reactErrors)}`).toHaveLength(0); + }); + + test('ManaDisplay is visible and shows Transference mana', async ({ page }) => { + await waitForTicks(page, 500); + // Mana display should show Transference mana pool + const manaDisplay = page.locator('text=Transference').first(); + await expect(manaDisplay).toBeVisible({ timeout: 10000 }); + }); + + test('TimeDisplay shows correct starting time', async ({ page }) => { + await waitForTicks(page, 500); + // Should start at day 1 + const bodyText = await page.textContent('body'); + expect(bodyText).toContain('Day 1'); + }); + + test('Activity log is present and shows start message', async ({ page }) => { + await waitForTicks(page, 500); + const bodyText = await page.textContent('body'); + // Activity log should have some content + expect(bodyText).toBeTruthy(); + }); + }); + + // ========================================================================= + // SECTION 2 - Stats Tab (Known bugs #208 and #210) + // ========================================================================= + test.describe('2 - Stats Tab', () => { + test.beforeEach(async ({ page }) => { + await startFreshGame(page); + }); + + test('navigate to Stats tab', async ({ page }) => { + await waitForTicks(page, 500); + const statsTab = page.getByRole('tab', { name: /stats/i }); + if (await statsTab.isVisible()) { + await statsTab.click(); + await waitForTicks(page, 300); + // Should not crash + const bodyText = await page.textContent('body'); + expect(bodyText).toBeTruthy(); + } + }); + + test('KNOWN BUG #208: Meditation multiplier shows 0x instead of 1x', async ({ page }) => { + await waitForTicks(page, 500); + const statsTab = page.getByRole('tab', { name: /stats/i }); + if (await statsTab.isVisible()) { + await statsTab.click(); + await waitForTicks(page, 500); + const bodyText = await page.textContent('body') || ''; + // The bug: Meditation Multiplier shows "0x" instead of "1.00x" + // This test documents the current state + if (bodyText.includes('Meditation')) { + console.log('STATS: Meditation text found, checking value...'); + // Capture the actual state for reporting + } + } + }); + + test('KNOWN BUG #208: Effective Regen shows 0/hr', async ({ page }) => { + await waitForTicks(page, 500); + const statsTab = page.getByRole('tab', { name: /stats/i }); + if (await statsTab.isVisible()) { + await statsTab.click(); + await waitForTicks(page, 500); + const bodyText = await page.textContent('body') || ''; + if (bodyText.includes('Effective Regen') || bodyText.includes('Base Regen')) { + console.log('STATS: Regen stats found'); + } + } + }); + + test('KNOWN BUG #210: Total Max Mana ignores discipline bonuses', async ({ page }) => { + await waitForTicks(page, 500); + // Navigate to stats + const statsTab = page.getByRole('tab', { name: /stats/i }); + if (await statsTab.isVisible()) { + await statsTab.click(); + await waitForTicks(page, 300); + // Check if Total Max Mana is shown + const bodyText = await page.textContent('body') || ''; + console.log('STATS: Max Mana section - checking for discipline bonus inclusion'); + } + }); + }); + + // ========================================================================= + // SECTION 3 - Spire/Climbing (Known bug #209) + // ========================================================================= + test.describe('3 - Spire / Climbing', () => { + test.beforeEach(async ({ page }) => { + await startFreshGame(page); + }); + + test('KNOWN BUG #209: Climb the Spire should not crash with React error #185', async ({ page }) => { + const errors: string[] = []; + page.on('console', (msg) => { + if (msg.type() === 'error') errors.push(msg.text()); + }); + await waitForTicks(page, 500); + + // Look for "Climb the Spire" button or Spire tab + const spireTab = page.getByRole('tab', { name: /spire/i }); + const climbButton = page.getByRole('button', { name: /climb/i }); + + if (await spireTab.isVisible({ timeout: 5000 })) { + await spireTab.click(); + await waitForTicks(page, 300); + } + + if (await climbButton.isVisible({ timeout: 5000 })) { + await climbButton.click(); + await waitForTicks(page, 2000); + + const reactErrors = errors.filter(e => + e.includes('Maximum update depth') || e.includes('Error #185') + ); + // This is a known bug - we expect it to fail + if (reactErrors.length > 0) { + console.log('KNOWN BUG #209 CONFIRMED: Spire crash detected'); + } else { + console.log('KNOWN BUG #209: No crash detected - may be fixed'); + } + } else { + console.log('Climb the Spire button not found - may need setup'); + } + }); + }); + + // ========================================================================= + // SECTION 4 - Disciplines Tab + // ========================================================================= + test.describe('4 - Disciplines', () => { + test.beforeEach(async ({ page }) => { + await startFreshGame(page); + }); + + test('navigate to Disciplines tab without crash', async ({ page }) => { + const errors: string[] = []; + page.on('console', (msg) => { + if (msg.type() === 'error') errors.push(msg.text()); + }); + await waitForTicks(page, 500); + + const discTab = page.getByRole('tab', { name: /disciplines/i }); + if (await discTab.isVisible({ timeout: 5000 })) { + await discTab.click(); + await waitForTicks(page, 500); + const reactErrors = errors.filter(e => + e.includes('React') || e.includes('Minified') || e.includes('Error #') + ); + expect(reactErrors, `React errors in Disciplines: ${JSON.stringify(reactErrors)}`).toHaveLength(0); + } + }); + + test('Raw Mana Mastery discipline is available', async ({ page }) => { + await waitForTicks(page, 500); + const discTab = page.getByRole('tab', { name: /disciplines/i }); + if (await discTab.isVisible({ timeout: 5000 })) { + await discTab.click(); + await waitForTicks(page, 300); + const bodyText = await page.textContent('body') || ''; + // Raw Mana Mastery should be available since Enchanter is attuned + if (bodyText.includes('Raw Mana Mastery')) { + console.log('DISCIPLINE: Raw Mana Mastery found'); + } + } + }); + }); + + // ========================================================================= + // SECTION 5 - Crafting Tab + // ========================================================================= + test.describe('5 - Crafting System', () => { + test.beforeEach(async ({ page }) => { + await startFreshGame(page); + }); + + test('navigate to Crafting tab without crash', async ({ page }) => { + const errors: string[] = []; + page.on('console', (msg) => { + if (msg.type() === 'error') errors.push(msg.text()); + }); + await waitForTicks(page, 500); + + const craftTab = page.getByRole('tab', { name: /craft/i }); + if (await craftTab.isVisible({ timeout: 5000 })) { + await craftTab.click(); + await waitForTicks(page, 500); + const reactErrors = errors.filter(e => + e.includes('React') || e.includes('Minified') || e.includes('Error #') + ); + expect(reactErrors, `React errors in Crafting: ${JSON.stringify(reactErrors)}`).toHaveLength(0); + } + }); + + test('Enchant sub-tab exists and is clickable', async ({ page }) => { + await waitForTicks(page, 500); + const craftTab = page.getByRole('tab', { name: /craft/i }); + if (await craftTab.isVisible({ timeout: 5000 })) { + await craftTab.click(); + await waitForTicks(page, 300); + // Look for Enchant sub-tab or section + const bodyText = await page.textContent('body') || ''; + expect(bodyText).toBeTruthy(); + } + }); + }); + + // ========================================================================= + // SECTION 6 - Equipment Tab + // ========================================================================= + test.describe('6 - Equipment & Inventory', () => { + test.beforeEach(async ({ page }) => { + await startFreshGame(page); + }); + + test('navigate to Equipment tab without crash', async ({ page }) => { + const errors: string[] = []; + page.on('console', (msg) => { + if (msg.type() === 'error') errors.push(msg.text()); + }); + await waitForTicks(page, 500); + + const equipTab = page.getByRole('tab', { name: /equipment/i }); + if (await equipTab.isVisible({ timeout: 5000 })) { + await equipTab.click(); + await waitForTicks(page, 500); + const reactErrors = errors.filter(e => + e.includes('React') || e.includes('Minified') || e.includes('Error #') + ); + expect(reactErrors, `React errors in Equipment: ${JSON.stringify(reactErrors)}`).toHaveLength(0); + } + }); + + test('starting equipment includes Basic Staff, Civilian Shirt, Civilian Shoes', async ({ page }) => { + await waitForTicks(page, 500); + const equipTab = page.getByRole('tab', { name: /equipment/i }); + if (await equipTab.isVisible({ timeout: 5000 })) { + await equipTab.click(); + await waitForTicks(page, 300); + const bodyText = await page.textContent('body') || ''; + // Check for starting equipment + console.log('EQUIPMENT: Checking starting equipment...'); + if (bodyText.includes('Basic Staff')) { + console.log('EQUIPMENT: Basic Staff found ✓'); + } + if (bodyText.includes('Civilian Shirt')) { + console.log('EQUIPMENT: Civilian Shirt found ✓'); + } + if (bodyText.includes('Civilian Shoes') || bodyText.includes('Civilian')) { + console.log('EQUIPMENT: Civilian gear found ✓'); + } + } + }); + }); + + // ========================================================================= + // SECTION 7 - Attunements Tab + // ========================================================================= + test.describe('7 - Attunements', () => { + test.beforeEach(async ({ page }) => { + await startFreshGame(page); + }); + + test('navigate to Attunements tab without crash', async ({ page }) => { + const errors: string[] = []; + page.on('console', (msg) => { + if (msg.type() === 'error') errors.push(msg.text()); + }); + await waitForTicks(page, 500); + + const attuneTab = page.getByRole('tab', { name: /attun/i }); + if (await attuneTab.isVisible({ timeout: 5000 })) { + await attuneTab.click(); + await waitForTicks(page, 500); + const reactErrors = errors.filter(e => + e.includes('React') || e.includes('Minified') || e.includes('Error #') + ); + expect(reactErrors, `React errors in Attunements: ${JSON.stringify(reactErrors)}`).toHaveLength(0); + } + }); + + test('Enchanter is attuned at level 1 by default', async ({ page }) => { + await waitForTicks(page, 500); + const attuneTab = page.getByRole('tab', { name: /attun/i }); + if (await attuneTab.isVisible({ timeout: 5000 })) { + await attuneTab.click(); + await waitForTicks(page, 300); + const bodyText = await page.textContent('body') || ''; + if (bodyText.includes('Enchanter')) { + console.log('ATTUNEMENT: Enchanter found ✓'); + } + } + }); + }); + + // ========================================================================= + // SECTION 8 - Spells Tab + // ========================================================================= + test.describe('8 - Spells Tab', () => { + test.beforeEach(async ({ page }) => { + await startFreshGame(page); + }); + + test('navigate to Spells tab without crash', async ({ page }) => { + const errors: string[] = []; + page.on('console', (msg) => { + if (msg.type() === 'error') errors.push(msg.text()); + }); + await waitForTicks(page, 500); + + const spellsTab = page.getByRole('tab', { name: /spell/i }); + if (await spellsTab.isVisible({ timeout: 5000 })) { + await spellsTab.click(); + await waitForTicks(page, 500); + const reactErrors = errors.filter(e => + e.includes('React') || e.includes('Minified') || e.includes('Error #') + ); + expect(reactErrors, `React errors in Spells: ${JSON.stringify(reactErrors)}`).toHaveLength(0); + } + }); + }); + + // ========================================================================= + // SECTION 9 - Prestige Tab + // ========================================================================= + test.describe('9 - Prestige Tab', () => { + test.beforeEach(async ({ page }) => { + await startFreshGame(page); + }); + + test('navigate to Prestige tab without crash', async ({ page }) => { + const errors: string[] = []; + page.on('console', (msg) => { + if (msg.type() === 'error') errors.push(msg.text()); + }); + await waitForTicks(page, 500); + + const prestigeTab = page.getByRole('tab', { name: /prestige/i }); + if (await prestigeTab.isVisible({ timeout: 5000 })) { + await prestigeTab.click(); + await waitForTicks(page, 500); + const reactErrors = errors.filter(e => + e.includes('React') || e.includes('Minified') || e.includes('Error #') + ); + expect(reactErrors, `React errors in Prestige: ${JSON.stringify(reactErrors)}`).toHaveLength(0); + } + }); + }); + + // ========================================================================= + // SECTION 10 - Golemancy Tab + // ========================================================================= + test.describe('10 - Golemancy Tab', () => { + test.beforeEach(async ({ page }) => { + await startFreshGame(page); + }); + + test('navigate to Golemancy tab without crash', async ({ page }) => { + const errors: string[] = []; + page.on('console', (msg) => { + if (msg.type() === 'error') errors.push(msg.text()); + }); + await waitForTicks(page, 500); + + const golemTab = page.getByRole('tab', { name: /golem/i }); + if (await golemTab.isVisible({ timeout: 5000 })) { + await golemTab.click(); + await waitForTicks(page, 500); + const reactErrors = errors.filter(e => + e.includes('React') || e.includes('Minified') || e.includes('Error #') + ); + expect(reactErrors, `React errors in Golemancy: ${JSON.stringify(reactErrors)}`).toHaveLength(0); + } + }); + }); + + // ========================================================================= + // SECTION 11 - Guardian Pacts Tab + // ========================================================================= + test.describe('11 - Guardian Pacts Tab', () => { + test.beforeEach(async ({ page }) => { + await startFreshGame(page); + }); + + test('navigate to Guardian Pacts tab without crash', async ({ page }) => { + const errors: string[] = []; + page.on('console', (msg) => { + if (msg.type() === 'error') errors.push(msg.text()); + }); + await waitForTicks(page, 500); + + const pactsTab = page.getByRole('tab', { name: /pact/i }); + if (await pactsTab.isVisible({ timeout: 5000 })) { + await pactsTab.click(); + await waitForTicks(page, 500); + const reactErrors = errors.filter(e => + e.includes('React') || e.includes('Minified') || e.includes('Error #') + ); + expect(reactErrors, `React errors in Guardian Pacts: ${JSON.stringify(reactErrors)}`).toHaveLength(0); + } + }); + }); + + // ========================================================================= + // SECTION 12 - Grimoire Tab + // ========================================================================= + test.describe('12 - Grimoire Tab', () => { + test.beforeEach(async ({ page }) => { + await startFreshGame(page); + }); + + test('navigate to Grimoire tab without crash', async ({ page }) => { + const errors: string[] = []; + page.on('console', (msg) => { + if (msg.type() === 'error') errors.push(msg.text()); + }); + await waitForTicks(page, 500); + + const grimoireTab = page.getByRole('tab', { name: /grimoire/i }); + if (await grimoireTab.isVisible({ timeout: 5000 })) { + await grimoireTab.click(); + await waitForTicks(page, 500); + const reactErrors = errors.filter(e => + e.includes('React') || e.includes('Minified') || e.includes('Error #') + ); + expect(reactErrors, `React errors in Grimoire: ${JSON.stringify(reactErrors)}`).toHaveLength(0); + } + }); + }); + + // ========================================================================= + // SECTION 13 - Achievements Tab + // ========================================================================= + test.describe('13 - Achievements Tab', () => { + test.beforeEach(async ({ page }) => { + await startFreshGame(page); + }); + + test('navigate to Achievements tab without crash', async ({ page }) => { + const errors: string[] = []; + page.on('console', (msg) => { + if (msg.type() === 'error') errors.push(msg.text()); + }); + await waitForTicks(page, 500); + + const achTab = page.getByRole('tab', { name: /achievement/i }); + if (await achTab.isVisible({ timeout: 5000 })) { + await achTab.click(); + await waitForTicks(page, 500); + const reactErrors = errors.filter(e => + e.includes('React') || e.includes('Minified') || e.includes('Error #') + ); + expect(reactErrors, `React errors in Achievements: ${JSON.stringify(reactErrors)}`).toHaveLength(0); + } + }); + }); + + // ========================================================================= + // SECTION 14 - Debug Tab & Cheats + // ========================================================================= + test.describe('14 - Debug Tab & Cheats', () => { + test.beforeEach(async ({ page }) => { + await startFreshGame(page); + }); + + test('navigate to Debug tab without crash', async ({ page }) => { + const errors: string[] = []; + page.on('console', (msg) => { + if (msg.type() === 'error') errors.push(msg.text()); + }); + await waitForTicks(page, 500); + + const debugTab = page.getByRole('tab', { name: /debug/i }); + if (await debugTab.isVisible({ timeout: 5000 })) { + await debugTab.click(); + await waitForTicks(page, 500); + const reactErrors = errors.filter(e => + e.includes('React') || e.includes('Minified') || e.includes('Error #') + ); + expect(reactErrors, `React errors in Debug: ${JSON.stringify(reactErrors)}`).toHaveLength(0); + } + }); + }); + + // ========================================================================= + // SECTION 15 - Deep Bug Hunting with Debug Console + // ========================================================================= + test.describe('15 - Deep Bug Hunting (Debug Mode)', () => { + test.beforeEach(async ({ page }) => { + await startFreshGame(page); + }); + + test('mana regen values in ManaDisplay are correct', async ({ page }) => { + await waitForTicks(page, 1000); + const bodyText = await page.textContent('body') || ''; + // Check that mana regen shows positive values for Transference + // Look for regen rate patterns like "+X/hr" + console.log('HUNT: Checking mana regen display values'); + const matches = bodyText.match(/\+[\d.]+(\/hr)?/g); + console.log(`HUNT: Found regen patterns: ${JSON.stringify(matches)}`); + }); + + test('element tab shows correct element unlock status', async ({ page }) => { + const errors: string[] = []; + page.on('console', (msg) => { + if (msg.type() === 'error') errors.push(msg.text()); + }); + await waitForTicks(page, 500); + + // Try to find element-related tabs + const elemTab = page.getByRole('tab', { name: /element/i }); + if (await elemTab.isVisible({ timeout: 3000 })) { + await elemTab.click(); + await waitForTicks(page, 500); + const reactErrors = errors.filter(e => + e.includes('React') || e.includes('Minified') || e.includes('Error #') + ); + expect(reactErrors, `React errors in Elements: ${JSON.stringify(reactErrors)}`).toHaveLength(0); + } + }); + + test('mana values stay consistent after multiple ticks', async ({ page }) => { + await waitForTicks(page, 500); + // Take a snapshot of mana values + const bodyBefore = await page.textContent('body') || ''; + await waitForTicks(page, 2000); + const bodyAfter = await page.textContent('body') || ''; + // Game should still be running (no crash) + expect(bodyAfter).toBeTruthy(); + console.log('HUNT: Game still running after 2 seconds of ticking ✓'); + }); + + test('all navigations work in sequence without crash', async ({ page }) => { + const errors: string[] = []; + page.on('console', (msg) => { + if (msg.type() === 'error') errors.push(msg.text()); + }); + await waitForTicks(page, 500); + + const tabs = [ + 'stats', 'equipment', 'attunements', 'crafting', 'disciplines', + 'spells', 'prestige', 'golemancy', 'pacts', 'achievements', + 'grimoire', 'debug' + ]; + + const visitedTabs: string[] = []; + const crashTabs: string[] = []; + + for (const tabName of tabs) { + const tab = page.getByRole('tab', { name: new RegExp(tabName, 'i') }); + if (await tab.isVisible({ timeout: 2000 })) { + const preErrors = [...errors]; + await tab.click(); + await waitForTicks(page, 300); + const newErrors = errors.filter(e => !preErrors.includes(e)); + const reactErrors = newErrors.filter(e => + e.includes('React') || e.includes('Minified') || e.includes('Error #') + ); + if (reactErrors.length > 0) { + crashTabs.push(tabName); + } + visitedTabs.push(tabName); + } + } + + console.log(`HUNT: Visited tabs: ${visitedTabs.join(', ')}`); + console.log(`HUNT: Tabs with React errors: ${crashTabs.join(', ')}`); + }); + }); +}); diff --git a/playwright.config.ts b/playwright.config.ts index 1deae92..95b5b56 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -2,15 +2,16 @@ import { defineConfig, devices } from '@playwright/test'; export default defineConfig({ testDir: 'e2e', - fullyParallel: true, + fullyParallel: false, forbidOnly: !!process.env.CI, - retries: process.env.CI ? 2 : 0, - workers: process.env.CI ? 1 : undefined, + retries: 0, + workers: 1, + timeout: 60000, reporter: 'html', use: { - baseURL: 'http://localhost:3000', + baseURL: 'https://manaloop.tailf367e3.ts.net/', trace: 'on-first-retry', - screenshot: 'only-on-failure', + screenshot: 'on', video: 'retain-on-failure', }, projects: [ @@ -19,4 +20,4 @@ export default defineConfig({ use: { ...devices['Desktop Chrome'] }, }, ], -}); \ No newline at end of file +}); diff --git a/scorecard.png b/scorecard.png index e9b7fe2..2eff492 100644 Binary files a/scorecard.png and b/scorecard.png differ diff --git a/src/components/game/debug/GameStateDebug.tsx b/src/components/game/debug/GameStateDebug.tsx index 023f53f..2f1bd43 100644 --- a/src/components/game/debug/GameStateDebug.tsx +++ b/src/components/game/debug/GameStateDebug.tsx @@ -10,7 +10,7 @@ import { RotateCcw, AlertTriangle, Zap, Clock, Settings, Eye, } from 'lucide-react'; import { DebugName, useDebug } from '@/components/game/debug/debug-context'; -import { useGameStore, useManaStore, useUIStore, useCombatStore } from '@/lib/game/stores'; +import { useGameStore, useManaStore, useUIStore } from '@/lib/game/stores'; import { computeMaxMana } from '@/lib/game/stores'; // ─── Warning Banner ────────────────────────────────────────────────────────── diff --git a/src/components/game/tabs/AttunementsTab.tsx b/src/components/game/tabs/AttunementsTab.tsx index 3bef068..72b3aef 100644 --- a/src/components/game/tabs/AttunementsTab.tsx +++ b/src/components/game/tabs/AttunementsTab.tsx @@ -5,7 +5,6 @@ import { ATTUNEMENTS_DEF, ATTUNEMENT_SLOT_NAMES, getAttunementXPForLevel, MAX_AT import type { AttunementDef, AttunementState } from '@/lib/game/types'; import { Card, CardContent } from '@/components/ui/card'; import { Badge } from '@/components/ui/badge'; -import { Progress } from '@/components/ui/progress'; import { DebugName } from '@/components/game/debug/debug-context'; import { fmt } from '@/lib/game/stores'; diff --git a/src/components/game/tabs/CraftingTab/FabricatorSubTab.tsx b/src/components/game/tabs/CraftingTab/FabricatorSubTab.tsx index ee84da4..880de14 100644 --- a/src/components/game/tabs/CraftingTab/FabricatorSubTab.tsx +++ b/src/components/game/tabs/CraftingTab/FabricatorSubTab.tsx @@ -9,12 +9,7 @@ import { ScrollArea } from '@/components/ui/scroll-area'; import { Separator } from '@/components/ui/separator'; import { Anvil, FlaskConical, Hammer, Package, Sparkles, Sword } from 'lucide-react'; import { MaterialRecipeCard } from './MaterialRecipeCard'; -import { - FABRICATOR_RECIPES, - MATERIAL_RECIPES, - getRecipesByManaType, - canCraftRecipe, -} from '@/lib/game/data/fabricator-recipes'; +import { FABRICATOR_RECIPES, MATERIAL_RECIPES, canCraftRecipe } from '@/lib/game/data/fabricator-recipes'; import { MANA_TYPE_LABELS } from '@/lib/game/data/fabricator-recipe-types'; import { LOOT_DROPS, LOOT_RARITY_COLORS } from '@/lib/game/data/loot-drops'; import { useCraftingStore, useManaStore } from '@/lib/game/stores'; diff --git a/src/components/game/tabs/DebugTab/GameStateDebugSection.tsx b/src/components/game/tabs/DebugTab/GameStateDebugSection.tsx index 400eb36..dce1519 100644 --- a/src/components/game/tabs/DebugTab/GameStateDebugSection.tsx +++ b/src/components/game/tabs/DebugTab/GameStateDebugSection.tsx @@ -10,7 +10,7 @@ import { RotateCcw, AlertTriangle, Zap, Clock, Eye, } from 'lucide-react'; import { DebugName, useDebug } from '@/components/game/debug/debug-context'; -import { useGameStore, useManaStore, useUIStore, useCombatStore } from '@/lib/game/stores'; +import { useGameStore, useManaStore, useUIStore } from '@/lib/game/stores'; import { computeMaxMana } from '@/lib/game/stores'; // ─── Display Options ───────────────────────────────────────────────────────── diff --git a/src/components/game/tabs/DisciplineCard.tsx b/src/components/game/tabs/DisciplineCard.tsx index e5caa6a..e9abbad 100644 --- a/src/components/game/tabs/DisciplineCard.tsx +++ b/src/components/game/tabs/DisciplineCard.tsx @@ -1,6 +1,5 @@ import React, { useMemo } from 'react'; import type { DisciplineDefinition } from '@/lib/game/types/disciplines'; -import type { ManaType } from '@/lib/game/types/elements'; import { ELEMENTS } from '@/lib/game/constants/elements'; import { calculateStatBonus, calculateManaDrain } from '@/lib/game/utils/discipline-math'; import clsx from 'clsx'; @@ -43,7 +42,7 @@ export const DisciplineCard: React.FC = ({ const manaIcon = elementDef?.sym ?? '✦'; const manaName = elementDef?.name ?? manaType; const isActive = activeIds.includes(id); - const activeNotPaused = activeIds.filter((aid) => { + const _activeNotPaused = activeIds.filter((aid) => { // Count how many active disciplines are not paused return aid === id ? !isPaused : true; }).length; diff --git a/src/lib/game/crafting-fabricator.ts b/src/lib/game/crafting-fabricator.ts index 1d439c5..92aa6cd 100644 --- a/src/lib/game/crafting-fabricator.ts +++ b/src/lib/game/crafting-fabricator.ts @@ -6,8 +6,6 @@ import type { ElementState } from './types'; import type { FabricatorRecipe } from './data/fabricator-recipes'; import { FABRICATOR_RECIPES } from './data/fabricator-recipes'; import { useManaStore } from './stores/manaStore'; -import { useCombatStore } from './stores/combatStore'; -import { useUIStore } from './stores/uiStore'; // ─── Lookup ─────────────────────────────────────────────────────────────────── diff --git a/src/lib/game/data/guardian-encounters.ts b/src/lib/game/data/guardian-encounters.ts index 870fb6c..e3b901e 100644 --- a/src/lib/game/data/guardian-encounters.ts +++ b/src/lib/game/data/guardian-encounters.ts @@ -73,7 +73,6 @@ export function getGuardianHP(floor: number): number { // ─── Tier Helpers ─────────────────────────────────────────────────────────────── -const BASE_ELEMENTS = ['fire', 'water', 'air', 'earth', 'light', 'dark', 'death']; const COMPOSITE_ELEMENTS = ['metal', 'sand', 'lightning', 'frost', 'blackflame', 'radiantflames', 'miasma', 'shadowglass']; const EXOTIC_ELEMENTS = ['crystal', 'stellar', 'void', 'soul', 'time', 'plasma']; diff --git a/test-results/.last-run.json b/test-results/.last-run.json deleted file mode 100644 index cbcc1fb..0000000 --- a/test-results/.last-run.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "status": "passed", - "failedTests": [] -} \ No newline at end of file