From 7d1bfbe4dcd0124cd63ac6caed08911d9baa3d53 Mon Sep 17 00:00:00 2001 From: Refactoring Agent <[email protected]> Date: Fri, 24 Apr 2026 14:45:07 +0200 Subject: [PATCH] Phase 3: Extract sub-components from StatsTab.tsx --- docs/phase3-progress.md | 43 ++- .../game/stats/CombatStatsSection.tsx | 64 +++ .../game/stats/ManaStatsSection.tsx | 217 +++++++++++ .../game/stats/StudyStatsSection.tsx | 55 +++ .../game/stats/UpgradeEffectsSection.tsx | 82 ++++ src/components/game/stats/index.tsx | 11 + src/components/game/tabs/StatsTab.tsx | 363 ++---------------- 7 files changed, 480 insertions(+), 355 deletions(-) create mode 100644 src/components/game/stats/CombatStatsSection.tsx create mode 100644 src/components/game/stats/ManaStatsSection.tsx create mode 100644 src/components/game/stats/StudyStatsSection.tsx create mode 100644 src/components/game/stats/UpgradeEffectsSection.tsx create mode 100644 src/components/game/stats/index.tsx diff --git a/docs/phase3-progress.md b/docs/phase3-progress.md index cd73b80..d237058 100644 --- a/docs/phase3-progress.md +++ b/docs/phase3-progress.md @@ -1,6 +1,6 @@ -# Phase 3: Refactor Large Files - Progress +# Phase 3: Refactor Large Files - Progress # -## Completed Refactorings (All Committed & Pushed) +## Completed Refactorings (All Committed & Pushed!) ### 1. `types.ts` (516 lines) ✅ - **Commit**: `eb81ccb Phase 3: Split types.ts into domain-specific files` @@ -29,10 +29,20 @@ ### 6. `utils.ts` (372 lines) ✅ - **Commit**: `23d0a12 Phase 3: Split utils.ts by responsibility` -- **Result**: Split into `utils/formatting.ts`, `floor-utils.ts`, `mana-utils.ts`, `combat-utils.ts`, `index.ts` (some overlap with computed-stats, but consistent) +- **Result**: Split into `utils/formatting.ts`, `floor-utils.ts`, `mana-utils.ts`, `combat-utils.ts`, `index.ts` - **Build**: ✅ Passes -## Failed Refactorings +### 7. `DebugTab.tsx` (700 lines) ✅ +- **Commit**: Phase 3: Split DebugTab.tsx into functional components` +- **Result**: Split into `debug/GameStateDebug.tsx`, `SkillDebug.tsx`, `ElementDebug.tsx`, `AttunementDebug.tsx`, `GolemDebug.tsx`, `index.tsx` +- **Build**: ✅ Passes + +### 8. `page.tsx` (465 lines) ✅ +- **Commit**: `eea5ed1 Phase 3: Lazy load tabs in page.tsx` +- **Result**: Lazy loads all tab components using React.lazy() and Suspense +- **Build**: ✅ Passes + +## Failed Refactorings! ### 1. `store.ts` (2464 lines) ❌ - **Issue**: Sub-agent made changes that broke build (`Cannot read properties of undefined (reading 'mainHand')`) @@ -45,24 +55,21 @@ ### 3. `gameStore.ts` (509 lines) ❌ - **Issue**: Sub-agent returned empty result (context limits or other issue) -- **Status**: Will try again with simpler prompt, or flag as "sub-agent unstable for this file" +- **Status**: Flagged as "unstable sub-agent behavior" -## Next Files to Refactor +## Next Files to Refactor! ### High Priority (Smaller, Likely to Work) -1. `src/components/game/tabs/DebugTab.tsx` (700 lines) - Split by functional area -2. `src/app/page.tsx` (465 lines) - Lazy load tabs - -### Medium Priority -3. `src/components/game/StatsTab.tsx` (551 lines) - Extract sub-components +1. `src/components/game/StatsTab.tsx` (551 lines) - Extract sub-components (NEXT TARGET!) +2. `src/components/game/tabs/StatsTab.tsx` (545 lines) - Extract sub-components +3. `src/components/game/tabs/CraftingTab.tsx` (already split) - done 4. `src/lib/game/stores/index.test.ts` (maybe not needed) -## Build Status +## Build Status! ✅ Build passes after each successful refactoring -✅ All commits pushed to remote (`git push origin master` successful) +✅ All commits pushed to remote! -## Notes -- Sub-agents work best with files under ~1500 lines with focused prompts -- Files over 2000 lines consistently fail (context limits) -- Some files around 500 lines also fail occasionally (unstable sub-agent behavior) -- When in doubt, flag it and move on (per user instructions) +## Notes! +- Sub-agents work best with files under ~1500 lines with focused prompts! +- Files over 2000 lines consistently fail (context limits)! +- When in doubt, flag it and move on (per user instructions)! diff --git a/src/components/game/stats/CombatStatsSection.tsx b/src/components/game/stats/CombatStatsSection.tsx new file mode 100644 index 0000000..cb14a9f --- /dev/null +++ b/src/components/game/stats/CombatStatsSection.tsx @@ -0,0 +1,64 @@ +'use client'; + +import { GUARDIANS } from '@/lib/game/constants'; +import { fmtDec } from '@/lib/game/store'; +import type { GameStore } from '@/lib/game/types'; +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; +import { Swords } from 'lucide-react'; + +export interface CombatStatsSectionProps { + store: GameStore; +} + +export function CombatStatsSection({ store }: CombatStatsSectionProps) { + return ( + + + + + Combat Stats + + + +
+
+
+ Combat Training Bonus: + +{(store.skills.combatTrain || 0) * 5} +
+
+ Arcane Fury Multiplier: + ×{fmtDec(1 + (store.skills.arcaneFury || 0) * 0.1, 2)} +
+
+ Elemental Mastery: + ×{fmtDec(1 + (store.skills.elementalMastery || 0) * 0.15, 2)} +
+
+ Guardian Bane: + ×{fmtDec(1 + (store.skills.guardianBane || 0) * 0.2, 2)} (vs guardians) +
+
+
+
+ Critical Hit Chance: + {((store.skills.precision || 0) * 5)}% +
+
+ Critical Multiplier: + 1.5x +
+
+ Spell Echo Chance: + {((store.skills.spellEcho || 0) * 10)}% +
+
+ Pact Multiplier: + ×{fmtDec(store.signedPacts.reduce((m, f) => m * (GUARDIANS[f]?.pact || 1), 1), 2)} +
+
+
+
+
+ ); +} diff --git a/src/components/game/stats/ManaStatsSection.tsx b/src/components/game/stats/ManaStatsSection.tsx new file mode 100644 index 0000000..dbfe1d9 --- /dev/null +++ b/src/components/game/stats/ManaStatsSection.tsx @@ -0,0 +1,217 @@ +'use client'; + +import { getTierMultiplier } from '@/lib/game/skill-evolution'; +import { hasSpecial, SPECIAL_EFFECTS } from '@/lib/game/effects'; +import { fmt, fmtDec } from '@/lib/game/store'; +import type { GameStore, UnifiedEffects } from '@/lib/game/types'; +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; +import { Separator } from '@/components/ui/separator'; +import { Droplet } from 'lucide-react'; + +export interface ManaStatsSectionProps { + store: GameStore; + upgradeEffects: UnifiedEffects; + maxMana: number; + baseRegen: number; + clickMana: number; + meditationMultiplier: number; + effectiveRegen: number; + incursionStrength: number; + manaCascadeBonus: number; +} + +export function ManaStatsSection({ + store, + upgradeEffects, + maxMana, + baseRegen, + clickMana, + meditationMultiplier, + effectiveRegen, + incursionStrength, + manaCascadeBonus, +}: ManaStatsSectionProps) { + return ( + + + + + Mana Stats + + + +
+
+
+ Base Max Mana: + 100 +
+
+ Mana Well Bonus: + + {(() => { + const mw = store.skillTiers?.manaWell || 1; + const tieredSkillId = mw > 1 ? `manaWell_t${mw}` : 'manaWell'; + const level = store.skills[tieredSkillId] || store.skills.manaWell || 0; + const tierMult = getTierMultiplier(tieredSkillId); + return `+${fmt(level * 100 * tierMult)} (${level} lvl × 100 × ${tierMult}x tier)`; + })()} + +
+
+ Prestige Mana Well: + +{fmt((store.prestigeUpgrades.manaWell || 0) * 500)} +
+ {upgradeEffects.maxManaBonus > 0 && ( +
+ Upgrade Mana Bonus: + +{fmt(upgradeEffects.maxManaBonus)} +
+ )} + {upgradeEffects.maxManaMultiplier > 1 && ( +
+ Upgrade Mana Multiplier: + ×{fmtDec(upgradeEffects.maxManaMultiplier, 2)} +
+ )} +
+ Total Max Mana: + {fmt(maxMana)} +
+
+
+
+ Base Regen: + 2/hr +
+
+ Mana Flow Bonus: + + {(() => { + const mf = store.skillTiers?.manaFlow || 1; + const tieredSkillId = mf > 1 ? `manaFlow_t${mf}` : 'manaFlow'; + const level = store.skills[tieredSkillId] || store.skills.manaFlow || 0; + const tierMult = getTierMultiplier(tieredSkillId); + return `+${fmtDec(level * 1 * tierMult)}/hr (${level} lvl × 1 × ${tierMult}x tier)`; + })()} + +
+
+ Mana Spring Bonus: + +{(store.skills.manaSpring || 0) * 2}/hr +
+
+ Prestige Mana Flow: + +{fmtDec((store.prestigeUpgrades.manaFlow || 0) * 0.5)}/hr +
+
+ Temporal Echo: + ×{fmtDec(1 + (store.prestigeUpgrades.temporalEcho || 0) * 0.1, 2)} +
+
+ Base Regen: + {fmtDec(baseRegen, 2)}/hr +
+ {upgradeEffects.regenBonus > 0 && ( +
+ Upgrade Regen Bonus: + +{fmtDec(upgradeEffects.regenBonus, 2)}/hr +
+ )} + {upgradeEffects.permanentRegenBonus > 0 && ( +
+ Permanent Regen Bonus: + +{fmtDec(upgradeEffects.permanentRegenBonus, 2)}/hr +
+ )} + {upgradeEffects.regenMultiplier > 1 && ( +
+ Upgrade Regen Multiplier: + ×{fmtDec(upgradeEffects.regenMultiplier, 2)} +
+ )} +
+
+ + {upgradeEffects.activeUpgrades.length > 0 && ( + <> +
+ Active Skill Upgrades +
+
+ {upgradeEffects.activeUpgrades.map((upgrade, idx) => ( +
+ {upgrade.name} + {upgrade.desc} +
+ ))} +
+ + + )} +
+
+
+ Click Mana Value: + +{clickMana} +
+
+ Mana Tap Bonus: + +{store.skills.manaTap || 0} +
+
+ Mana Surge Bonus: + +{(store.skills.manaSurge || 0) * 3} +
+
+ Mana Overflow: + ×{fmtDec(1 + (store.skills.manaOverflow || 0) * 0.25, 2)} +
+
+
+
+ Meditation Multiplier: + 1.5 ? 'text-purple-400' : 'text-gray-300'}`}> + {fmtDec(meditationMultiplier, 2)}x + +
+
+ Effective Regen: + {fmtDec(effectiveRegen, 2)}/hr +
+ {incursionStrength > 0 && !hasSpecial(upgradeEffects, SPECIAL_EFFECTS.STEADY_STREAM) && ( +
+ Incursion Penalty: + -{Math.round(incursionStrength * 100)}% +
+ )} + {hasSpecial(upgradeEffects, SPECIAL_EFFECTS.STEADY_STREAM) && incursionStrength > 0 && ( +
+ Steady Stream: + Immune to incursion +
+ )} + {manaCascadeBonus > 0 && ( +
+ Mana Cascade Bonus: + +{fmtDec(manaCascadeBonus, 2)}/hr +
+ )} + {hasSpecial(upgradeEffects, SPECIAL_EFFECTS.MANA_TORRENT) && store.rawMana > maxMana * 0.75 && ( +
+ Mana Torrent: + +50% regen (high mana) +
+ )} + {hasSpecial(upgradeEffects, SPECIAL_EFFECTS.DESPERATE_WELLS) && store.rawMana < maxMana * 0.25 && ( +
+ Desperate Wells: + +50% regen (low mana) +
+ )} +
+
+
+
+ ); +} diff --git a/src/components/game/stats/StudyStatsSection.tsx b/src/components/game/stats/StudyStatsSection.tsx new file mode 100644 index 0000000..4fda5cf --- /dev/null +++ b/src/components/game/stats/StudyStatsSection.tsx @@ -0,0 +1,55 @@ +'use client'; + +import { fmtDec } from '@/lib/game/store'; +import type { GameStore } from '@/lib/game/types'; +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; +import { BookOpen } from 'lucide-react'; + +export interface StudyStatsSectionProps { + store: GameStore; + studySpeedMult: number; + studyCostMult: number; +} + +export function StudyStatsSection({ store, studySpeedMult, studyCostMult }: StudyStatsSectionProps) { + return ( + + + + + Study Stats + + + +
+
+
+ Study Speed: + ×{fmtDec(studySpeedMult, 2)} +
+
+ Quick Learner Bonus: + +{((store.skills.quickLearner || 0) * 10)}% +
+
+
+
+ Study Cost: + {Math.round(studyCostMult * 100)}% +
+
+ Focused Mind Bonus: + -{((store.skills.focusedMind || 0) * 5)}% +
+
+
+
+ Progress Retention: + {Math.round((1 + (store.skills.knowledgeRetention || 0) * 0.2) * 100)}% +
+
+
+
+
+ ); +} diff --git a/src/components/game/stats/UpgradeEffectsSection.tsx b/src/components/game/stats/UpgradeEffectsSection.tsx new file mode 100644 index 0000000..3c49c65 --- /dev/null +++ b/src/components/game/stats/UpgradeEffectsSection.tsx @@ -0,0 +1,82 @@ +'use client'; + +import { SKILL_EVOLUTION_PATHS, getTierMultiplier } from '@/lib/game/skill-evolution'; +import { SKILLS_DEF } from '@/lib/game/constants'; +import type { GameStore, SkillUpgradeChoice } from '@/lib/game/types'; +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; +import { Badge } from '@/components/ui/badge'; +import { Star } from 'lucide-react'; + +export interface UpgradeEffectsSectionProps { + store: GameStore; +} + +// Helper function to get all selected skill upgrades +function getAllSelectedUpgrades(store: GameStore) { + const upgrades: { skillId: string; upgrade: SkillUpgradeChoice }[] = []; + for (const [skillId, selectedIds] of Object.entries(store.skillUpgrades)) { + const baseSkillId = skillId.includes('_t') ? skillId.split('_t')[0] : skillId; + const path = SKILL_EVOLUTION_PATHS[baseSkillId]; + if (!path) continue; + for (const tier of path.tiers) { + if (tier.skillId === skillId) { + for (const upgradeId of selectedIds) { + const upgrade = tier.upgrades.find(u => u.id === upgradeId); + if (upgrade) { + upgrades.push({ skillId, upgrade }); + } + } + } + } + } + return upgrades; +} + +export function UpgradeEffectsSection({ store }: UpgradeEffectsSectionProps) { + const selectedUpgrades = getAllSelectedUpgrades(store); + + return ( + + + + + Active Skill Upgrades ({selectedUpgrades.length}) + + + + {selectedUpgrades.length === 0 ? ( +
No skill upgrades selected yet. Level skills to 5 or 10 to choose upgrades.
+ ) : ( +
+ {selectedUpgrades.map(({ skillId, upgrade }) => ( +
+
+ {upgrade.name} + + {SKILLS_DEF[skillId]?.name || skillId} + +
+
{upgrade.desc}
+ {upgrade.effect.type === 'multiplier' && ( +
+ +{Math.round((upgrade.effect.value! - 1) * 100)}% {upgrade.effect.stat} +
+ )} + {upgrade.effect.type === 'bonus' && ( +
+ +{upgrade.effect.value} {upgrade.effect.stat} +
+ )} + {upgrade.effect.type === 'special' && ( +
+ ⚡ {upgrade.effect.specialDesc || 'Special effect active'} +
+ )} +
+ ))} +
+ )} +
+
+ ); +} diff --git a/src/components/game/stats/index.tsx b/src/components/game/stats/index.tsx new file mode 100644 index 0000000..6b51408 --- /dev/null +++ b/src/components/game/stats/index.tsx @@ -0,0 +1,11 @@ +export { ManaStatsSection } from './ManaStatsSection'; +export type { ManaStatsSectionProps } from './ManaStatsSection'; + +export { CombatStatsSection } from './CombatStatsSection'; +export type { CombatStatsSectionProps } from './CombatStatsSection'; + +export { StudyStatsSection } from './StudyStatsSection'; +export type { StudyStatsSectionProps } from './StudyStatsSection'; + +export { UpgradeEffectsSection } from './UpgradeEffectsSection'; +export type { UpgradeEffectsSectionProps } from './UpgradeEffectsSection'; diff --git a/src/components/game/tabs/StatsTab.tsx b/src/components/game/tabs/StatsTab.tsx index 5a674e4..8123151 100755 --- a/src/components/game/tabs/StatsTab.tsx +++ b/src/components/game/tabs/StatsTab.tsx @@ -1,14 +1,17 @@ 'use client'; -import { ELEMENTS, GUARDIANS, SKILLS_DEF } from '@/lib/game/constants'; -import { SKILL_EVOLUTION_PATHS, getTierMultiplier } from '@/lib/game/skill-evolution'; +import { ELEMENTS, GUARDIANS } from '@/lib/game/constants'; +import { getTierMultiplier } from '@/lib/game/skill-evolution'; import { hasSpecial, SPECIAL_EFFECTS } from '@/lib/game/effects'; import { fmt, fmtDec } from '@/lib/game/store'; -import type { SkillUpgradeChoice, GameStore, UnifiedEffects } from '@/lib/game/types'; +import type { GameStore, UnifiedEffects } from '@/lib/game/types'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; -import { Badge } from '@/components/ui/badge'; import { Separator } from '@/components/ui/separator'; -import { Droplet, Swords, BookOpen, FlaskConical, Trophy, RotateCcw, Star } from 'lucide-react'; +import { FlaskConical, Trophy, RotateCcw } from 'lucide-react'; +import { ManaStatsSection } from '../stats/ManaStatsSection'; +import { CombatStatsSection } from '../stats/CombatStatsSection'; +import { StudyStatsSection } from '../stats/StudyStatsSection'; +import { UpgradeEffectsSection } from '../stats/UpgradeEffectsSection'; export interface StatsTabProps { store: GameStore; @@ -46,303 +49,30 @@ export function StatsTab({ return 10 + level * 50 * tierMult + (store.prestigeUpgrades.elementalAttune || 0) * 25; })(); - // Get all selected skill upgrades - const getAllSelectedUpgrades = () => { - const upgrades: { skillId: string; upgrade: SkillUpgradeChoice }[] = []; - for (const [skillId, selectedIds] of Object.entries(store.skillUpgrades)) { - const baseSkillId = skillId.includes('_t') ? skillId.split('_t')[0] : skillId; - const path = SKILL_EVOLUTION_PATHS[baseSkillId]; - if (!path) continue; - for (const tier of path.tiers) { - if (tier.skillId === skillId) { - for (const upgradeId of selectedIds) { - const upgrade = tier.upgrades.find(u => u.id === upgradeId); - if (upgrade) { - upgrades.push({ skillId, upgrade }); - } - } - } - } - } - return upgrades; - }; - - const selectedUpgrades = getAllSelectedUpgrades(); - return (
{/* Mana Stats */} - - - - - Mana Stats - - - -
-
-
- Base Max Mana: - 100 -
-
- Mana Well Bonus: - - {(() => { - const mw = store.skillTiers?.manaWell || 1; - const tieredSkillId = mw > 1 ? `manaWell_t${mw}` : 'manaWell'; - const level = store.skills[tieredSkillId] || store.skills.manaWell || 0; - const tierMult = getTierMultiplier(tieredSkillId); - return `+${fmt(level * 100 * tierMult)} (${level} lvl × 100 × ${tierMult}x tier)`; - })()} - -
-
- Prestige Mana Well: - +{fmt((store.prestigeUpgrades.manaWell || 0) * 500)} -
- {upgradeEffects.maxManaBonus > 0 && ( -
- Upgrade Mana Bonus: - +{fmt(upgradeEffects.maxManaBonus)} -
- )} - {upgradeEffects.maxManaMultiplier > 1 && ( -
- Upgrade Mana Multiplier: - ×{fmtDec(upgradeEffects.maxManaMultiplier, 2)} -
- )} -
- Total Max Mana: - {fmt(maxMana)} -
-
-
-
- Base Regen: - 2/hr -
-
- Mana Flow Bonus: - - {(() => { - const mf = store.skillTiers?.manaFlow || 1; - const tieredSkillId = mf > 1 ? `manaFlow_t${mf}` : 'manaFlow'; - const level = store.skills[tieredSkillId] || store.skills.manaFlow || 0; - const tierMult = getTierMultiplier(tieredSkillId); - return `+${fmtDec(level * 1 * tierMult)}/hr (${level} lvl × 1 × ${tierMult}x tier)`; - })()} - -
-
- Mana Spring Bonus: - +{(store.skills.manaSpring || 0) * 2}/hr -
-
- Prestige Mana Flow: - +{fmtDec((store.prestigeUpgrades.manaFlow || 0) * 0.5)}/hr -
-
- Temporal Echo: - ×{fmtDec(1 + (store.prestigeUpgrades.temporalEcho || 0) * 0.1, 2)} -
-
- Base Regen: - {fmtDec(baseRegen, 2)}/hr -
- {upgradeEffects.regenBonus > 0 && ( -
- Upgrade Regen Bonus: - +{fmtDec(upgradeEffects.regenBonus, 2)}/hr -
- )} - {upgradeEffects.permanentRegenBonus > 0 && ( -
- Permanent Regen Bonus: - +{fmtDec(upgradeEffects.permanentRegenBonus, 2)}/hr -
- )} - {upgradeEffects.regenMultiplier > 1 && ( -
- Upgrade Regen Multiplier: - ×{fmtDec(upgradeEffects.regenMultiplier, 2)} -
- )} -
-
- - {upgradeEffects.activeUpgrades.length > 0 && ( - <> -
- Active Skill Upgrades -
-
- {upgradeEffects.activeUpgrades.map((upgrade, idx) => ( -
- {upgrade.name} - {upgrade.desc} -
- ))} -
- - - )} -
-
-
- Click Mana Value: - +{clickMana} -
-
- Mana Tap Bonus: - +{store.skills.manaTap || 0} -
-
- Mana Surge Bonus: - +{(store.skills.manaSurge || 0) * 3} -
-
- Mana Overflow: - ×{fmtDec(1 + (store.skills.manaOverflow || 0) * 0.25, 2)} -
-
-
-
- Meditation Multiplier: - 1.5 ? 'text-purple-400' : 'text-gray-300'}`}> - {fmtDec(meditationMultiplier, 2)}x - -
-
- Effective Regen: - {fmtDec(effectiveRegen, 2)}/hr -
- {incursionStrength > 0 && !hasSpecial(upgradeEffects, SPECIAL_EFFECTS.STEADY_STREAM) && ( -
- Incursion Penalty: - -{Math.round(incursionStrength * 100)}% -
- )} - {hasSpecial(upgradeEffects, SPECIAL_EFFECTS.STEADY_STREAM) && incursionStrength > 0 && ( -
- Steady Stream: - Immune to incursion -
- )} - {manaCascadeBonus > 0 && ( -
- Mana Cascade Bonus: - +{fmtDec(manaCascadeBonus, 2)}/hr -
- )} - {hasSpecial(upgradeEffects, SPECIAL_EFFECTS.MANA_TORRENT) && store.rawMana > maxMana * 0.75 && ( -
- Mana Torrent: - +50% regen (high mana) -
- )} - {hasSpecial(upgradeEffects, SPECIAL_EFFECTS.DESPERATE_WELLS) && store.rawMana < maxMana * 0.25 && ( -
- Desperate Wells: - +50% regen (low mana) -
- )} -
-
-
-
+ {/* Combat Stats */} - - - - - Combat Stats - - - -
-
-
- Combat Training Bonus: - +{(store.skills.combatTrain || 0) * 5} -
-
- Arcane Fury Multiplier: - ×{fmtDec(1 + (store.skills.arcaneFury || 0) * 0.1, 2)} -
-
- Elemental Mastery: - ×{fmtDec(1 + (store.skills.elementalMastery || 0) * 0.15, 2)} -
-
- Guardian Bane: - ×{fmtDec(1 + (store.skills.guardianBane || 0) * 0.2, 2)} (vs guardians) -
-
-
-
- Critical Hit Chance: - {((store.skills.precision || 0) * 5)}% -
-
- Critical Multiplier: - 1.5x -
-
- Spell Echo Chance: - {((store.skills.spellEcho || 0) * 10)}% -
-
- Pact Multiplier: - ×{fmtDec(store.signedPacts.reduce((m, f) => m * (GUARDIANS[f]?.pact || 1), 1), 2)} -
-
-
-
-
+ {/* Study Stats */} - - - - - Study Stats - - - -
-
-
- Study Speed: - ×{fmtDec(studySpeedMult, 2)} -
-
- Quick Learner Bonus: - +{((store.skills.quickLearner || 0) * 10)}% -
-
-
-
- Study Cost: - {Math.round(studyCostMult * 100)}% -
-
- Focused Mind Bonus: - -{((store.skills.focusedMind || 0) * 5)}% -
-
-
-
- Progress Retention: - {Math.round((1 + (store.skills.knowledgeRetention || 0) * 0.2) * 100)}% -
-
-
-
-
+ {/* Element Stats */} @@ -406,48 +136,7 @@ export function StatsTab({ {/* Active Upgrades */} - - - - - Active Skill Upgrades ({selectedUpgrades.length}) - - - - {selectedUpgrades.length === 0 ? ( -
No skill upgrades selected yet. Level skills to 5 or 10 to choose upgrades.
- ) : ( -
- {selectedUpgrades.map(({ skillId, upgrade }) => ( -
-
- {upgrade.name} - - {SKILLS_DEF[skillId]?.name || skillId} - -
-
{upgrade.desc}
- {upgrade.effect.type === 'multiplier' && ( -
- +{Math.round((upgrade.effect.value! - 1) * 100)}% {upgrade.effect.stat} -
- )} - {upgrade.effect.type === 'bonus' && ( -
- +{upgrade.effect.value} {upgrade.effect.stat} -
- )} - {upgrade.effect.type === 'special' && ( -
- ⚡ {upgrade.effect.specialDesc || 'Special effect active'} -
- )} -
- ))} -
- )} -
-
+ {/* Pact Bonuses */}