diff --git a/docs/circular-deps.txt b/docs/circular-deps.txt index 4576b75..7e23fca 100644 --- a/docs/circular-deps.txt +++ b/docs/circular-deps.txt @@ -1,11 +1,4 @@ # Circular Dependencies -Generated: 2026-05-28T07:32:48.513Z -Found: 1 circular chain(s) — these MUST be fixed before modifying involved files. +Generated: 2026-05-28T07:47:51.159Z -1. 1) effects/discipline-effects.ts > stores/discipline-slice.ts - -## How to fix -1. Identify which import in the chain can be extracted to a shared types/utils file. -2. Move the shared type or function there. -3. Both files import from the new shared module instead of each other. -4. Run: bunx madge --circular src/lib/game (should return clean) \ No newline at end of file +No circular dependencies found. ✅ diff --git a/docs/dependency-graph.json b/docs/dependency-graph.json index 4234758..0401bb4 100644 --- a/docs/dependency-graph.json +++ b/docs/dependency-graph.json @@ -1,6 +1,6 @@ { "_meta": { - "generated": "2026-05-28T07:32:46.775Z", + "generated": "2026-05-28T07:47:49.204Z", "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." }, @@ -528,7 +528,6 @@ "data/disciplines/enchanter.ts", "data/disciplines/fabricator.ts", "data/disciplines/invoker.ts", - "effects/discipline-effects.ts", "types.ts", "types/disciplines.ts", "utils/discipline-math.ts", diff --git a/src/components/game/tabs/PrestigeTab.test.ts b/src/components/game/tabs/PrestigeTab.test.ts index 5d03c99..ba14a24 100644 --- a/src/components/game/tabs/PrestigeTab.test.ts +++ b/src/components/game/tabs/PrestigeTab.test.ts @@ -28,9 +28,9 @@ describe('Tab barrel export', () => { // ─── Test: Prestige upgrade definitions ──────────────────────────────────────── describe('Prestige upgrade definitions', () => { - it('has exactly 13 prestige upgrades', async () => { + it('has exactly 11 prestige upgrades', async () => { const { PRESTIGE_DEF } = await import('@/lib/game/constants/prestige'); - expect(Object.keys(PRESTIGE_DEF).length).toBe(13); + expect(Object.keys(PRESTIGE_DEF).length).toBe(11); }); it('all upgrades have required fields', async () => { @@ -43,10 +43,10 @@ describe('Prestige upgrade definitions', () => { } }); - it('all 14 expected upgrade IDs are present', async () => { + it('all 11 expected upgrade IDs are present', async () => { const { PRESTIGE_DEF } = await import('@/lib/game/constants/prestige'); const expectedIds = [ - 'manaWell', 'manaFlow', 'insightAmp', 'spireKey', + 'insightAmp', 'spireKey', 'temporalEcho', 'steadyHand', 'ancientKnowledge', 'elementalAttune', 'spellMemory', 'guardianPact', 'quickStart', 'elemStart', 'unlockedManaTypeCapacity', diff --git a/src/lib/game/__tests__/computed-stats.test.ts b/src/lib/game/__tests__/computed-stats.test.ts index 42675ec..22f9394 100644 --- a/src/lib/game/__tests__/computed-stats.test.ts +++ b/src/lib/game/__tests__/computed-stats.test.ts @@ -162,12 +162,9 @@ describe('deductSpellCost', () => { }); describe('computeMaxMana', () => { - it('should return base 100 with no skills or upgrades', () => { + it('should return base 100 with no upgrades', () => { const state = { - skills: {} as Record, prestigeUpgrades: {}, - skillUpgrades: {}, - skillTiers: {}, }; const effects = { maxManaBonus: 0, maxManaMultiplier: 1 } as any; const result = computeMaxMana(state, effects); @@ -176,10 +173,7 @@ describe('computeMaxMana', () => { it('should include manaWell prestige upgrade', () => { const state = { - skills: {} as Record, prestigeUpgrades: { manaWell: 5 }, - skillUpgrades: {}, - skillTiers: {}, }; const effects = { maxManaBonus: 0, maxManaMultiplier: 1 } as any; const result = computeMaxMana(state, effects); @@ -188,10 +182,7 @@ describe('computeMaxMana', () => { it('should apply multiplier from effects', () => { const state = { - skills: {} as Record, prestigeUpgrades: {}, - skillUpgrades: {}, - skillTiers: {}, }; const effects = { maxManaBonus: 0, maxManaMultiplier: 1.5 } as any; const result = computeMaxMana(state, effects); @@ -200,10 +191,7 @@ describe('computeMaxMana', () => { it('should apply bonus from effects', () => { const state = { - skills: {} as Record, prestigeUpgrades: {}, - skillUpgrades: {}, - skillTiers: {}, }; const effects = { maxManaBonus: 50, maxManaMultiplier: 1 } as any; const result = computeMaxMana(state, effects); @@ -212,43 +200,54 @@ describe('computeMaxMana', () => { }); describe('computeRegen', () => { - it('should return base regen with no skills', () => { + it('should return base regen with no upgrades', () => { const state = { - skills: {} as Record, prestigeUpgrades: {} as Record, - skillUpgrades: {} as Record, - skillTiers: {} as Record, attunements: {} as Record, }; const effects = { regenBonus: 0, regenMultiplier: 1, permanentRegenBonus: 0 } as any; const result = computeRegen(state as any, effects); - // Base regen is 2 (this test provides effects, so no attunement bonus) expect(result).toBe(2); }); }); describe('computeClickMana', () => { - it('should return base click mana with no skills', () => { - const state = { - skills: {} as Record, - }; - const discipline = { bonuses: {}, multipliers: {} }; - const result = computeClickMana(state.skills, discipline); - expect(result).toBeGreaterThanOrEqual(1); + it('should return base click mana with no discipline', () => { + const result = computeClickMana(); + expect(result).toBe(1); + }); + + it('should return click mana with discipline bonus', () => { + const discipline = { bonuses: { clickManaBonus: 3 }, multipliers: {} }; + const result = computeClickMana(discipline); + expect(result).toBe(4); }); }); describe('getMeditationBonus', () => { it('should return 1.0 with zero ticks', () => { - const result = getMeditationBonus(0, {}); + const result = getMeditationBonus(0); expect(result).toBe(1.0); }); it('should increase with more ticks', () => { - const result1 = getMeditationBonus(10, {}); - const result2 = getMeditationBonus(100, {}); + const result1 = getMeditationBonus(10); + const result2 = getMeditationBonus(100); expect(result2).toBeGreaterThan(result1); }); + + it('should follow continuous ramp formula', () => { + // At 4 hours: 1 + (4/8)*4 = 3.0 + const ticksFor4Hours = 4 / 0.04; + const result = getMeditationBonus(ticksFor4Hours); + expect(result).toBeCloseTo(3.0, 5); + }); + + it('should cap at 5.0', () => { + const ticksFor8Hours = 8 / 0.04; + const result = getMeditationBonus(ticksFor8Hours); + expect(result).toBeCloseTo(5.0, 5); + }); }); describe('getIncursionStrength', () => { diff --git a/src/lib/game/__tests__/mana-utils.test.ts b/src/lib/game/__tests__/mana-utils.test.ts index 0d97ea6..621c0e6 100644 --- a/src/lib/game/__tests__/mana-utils.test.ts +++ b/src/lib/game/__tests__/mana-utils.test.ts @@ -12,25 +12,14 @@ import { HOURS_PER_TICK } from '../constants'; describe('computeMaxMana', () => { const baseState = { - skills: {}, prestigeUpgrades: {}, - skillUpgrades: {}, - skillTiers: {}, }; - it('should return base 100 with no skills or upgrades', () => { + it('should return base 100 with no upgrades', () => { const result = computeMaxMana(baseState); expect(result).toBe(100); }); - it('should add 100 per manaWell skill level', () => { - const result = computeMaxMana({ - ...baseState, - skills: { manaWell: 3 }, - }); - expect(result).toBe(100 + 3 * 100); - }); - it('should add 500 per manaWell prestige upgrade', () => { const result = computeMaxMana({ ...baseState, @@ -85,34 +74,15 @@ describe('computeMaxMana', () => { describe('computeRegen', () => { const baseState = { - skills: {}, prestigeUpgrades: {}, - skillUpgrades: {}, - skillTiers: {}, attunements: {}, }; - it('should return base regen of 2 with no skills', () => { + it('should return base regen of 2 with no upgrades', () => { const result = computeRegen(baseState); expect(result).toBe(2); }); - it('should add 1 per manaFlow skill level', () => { - const result = computeRegen({ - ...baseState, - skills: { manaFlow: 3 }, - }); - expect(result).toBe(5); // 2 + 3 - }); - - it('should add 2 per manaSpring skill level', () => { - const result = computeRegen({ - ...baseState, - skills: { manaSpring: 2 }, - }); - expect(result).toBe(6); // 2 + 4 - }); - it('should add 0.5 per manaFlow prestige upgrade', () => { const result = computeRegen({ ...baseState, @@ -169,29 +139,14 @@ describe('computeRegen', () => { // ─── computeClickMana ───────────────────────────────────────────────────────── describe('computeClickMana', () => { - it('should return 1 with no skills', () => { - const result = computeClickMana({}); + it('should return 1 with no discipline bonus', () => { + const result = computeClickMana(); expect(result).toBe(1); }); - it('should add 1 per manaTap skill level', () => { - const result = computeClickMana({ manaTap: 3 }); - expect(result).toBe(4); // 1 + 3 - }); - - it('should add 3 per manaSurge skill level', () => { - const result = computeClickMana({ manaSurge: 2 }); - expect(result).toBe(7); // 1 + 6 - }); - - it('should combine manaTap and manaSurge', () => { - const result = computeClickMana({ manaTap: 2, manaSurge: 1 }); - expect(result).toBe(6); // 1 + 2 + 3 - }); - - it('should add discipline click multiplier', () => { - const result = computeClickMana({}, { - bonuses: { clickManaMultiplier: 5 }, + it('should add discipline click bonus', () => { + const result = computeClickMana({ + bonuses: { clickManaBonus: 5 }, multipliers: {}, }); expect(result).toBe(6); @@ -202,72 +157,49 @@ describe('computeClickMana', () => { describe('getMeditationBonus', () => { it('should return 1.0 with zero ticks', () => { - expect(getMeditationBonus(0, {})).toBe(1.0); + expect(getMeditationBonus(0)).toBe(1.0); }); it('should increase with more ticks', () => { - const low = getMeditationBonus(10, {}); - const high = getMeditationBonus(100, {}); + const low = getMeditationBonus(10); + const high = getMeditationBonus(100); expect(high).toBeGreaterThan(low); }); - it('should cap at 1.5x without meditation skill', () => { - // After 4 hours: 1 + min(4/4, 0.5) = 1.5 - const ticksFor4Hours = 4 / HOURS_PER_TICK; - const result = getMeditationBonus(ticksFor4Hours, {}); - expect(result).toBeCloseTo(1.5, 5); + it('should follow continuous ramp: 1 + (hours/8)*4', () => { + // At 2 hours: 1 + (2/8)*4 = 2.0 + const ticksFor2Hours = 2 / HOURS_PER_TICK; + const result = getMeditationBonus(ticksFor2Hours); + expect(result).toBeCloseTo(2.0, 5); }); - it('should reach 2.5x with meditation skill after 4 hours', () => { - const ticksFor4Hours = 4 / HOURS_PER_TICK; - const result = getMeditationBonus(ticksFor4Hours, { meditation: 1 }); - expect(result).toBeCloseTo(2.5, 5); - }); - - it('should reach 3.0x with deep trance after 6 hours', () => { - const ticksFor6Hours = 6 / HOURS_PER_TICK; - const result = getMeditationBonus(ticksFor6Hours, { - meditation: 1, - deepTrance: 1, - }); - expect(result).toBeCloseTo(3.0, 5); - }); - - it('should reach 5.0x with void meditation after 8 hours', () => { + it('should cap at 5.0 with no discipline bonus', () => { + // At 8+ hours: cap at 5.0 const ticksFor8Hours = 8 / HOURS_PER_TICK; - const result = getMeditationBonus(ticksFor8Hours, { - meditation: 1, - deepTrance: 1, - voidMeditation: 1, - }); + const result = getMeditationBonus(ticksFor8Hours); expect(result).toBeCloseTo(5.0, 5); }); - it('should reach cap at 2 hours (min(2/4, 0.5) = 0.5)', () => { - // At 2 hours: min(2/4, 0.5) = min(0.5, 0.5) = 0.5 → 1.5x - const ticksFor2Hours = 2 / HOURS_PER_TICK; - const result = getMeditationBonus(ticksFor2Hours, {}); - expect(result).toBeCloseTo(1.5, 5); - }); - - it('should be below cap at 1 hour', () => { + it('should ramp linearly: 1 hour → 1.5', () => { const ticksFor1Hour = 1 / HOURS_PER_TICK; - const result = getMeditationBonus(ticksFor1Hour, {}); - expect(result).toBeLessThan(1.5); + const result = getMeditationBonus(ticksFor1Hour); + expect(result).toBeCloseTo(1.5, 5); }); it('should apply meditation efficiency multiplier', () => { const ticksFor4Hours = 4 / HOURS_PER_TICK; - const withoutEff = getMeditationBonus(ticksFor4Hours, {}, 1); - const withEff = getMeditationBonus(ticksFor4Hours, {}, 2); + const withoutEff = getMeditationBonus(ticksFor4Hours, 1); + const withEff = getMeditationBonus(ticksFor4Hours, 2); expect(withEff).toBeCloseTo(withoutEff * 2, 5); }); - it('should ramp linearly before cap', () => { - // At 1 hour: 1 + min(1/4, 0.5) = 1 + 0.25 = 1.25 - const ticksFor1Hour = 1 / HOURS_PER_TICK; - const result = getMeditationBonus(ticksFor1Hour, {}); - expect(result).toBeCloseTo(1.25, 5); + it('should respect discipline meditation cap bonus', () => { + // With +3.5 discipline cap, max = 8.5 + // Need more than 8 hours for the higher cap to matter + // At 16 hours without cap: 1 + (16/8)*4 = 9.0, capped to 8.5 + const ticksFor16Hours = 16 / HOURS_PER_TICK; + const result = getMeditationBonus(ticksFor16Hours, 1, 3.5); + expect(result).toBeCloseTo(8.5, 5); }); }); @@ -275,10 +207,7 @@ describe('getMeditationBonus', () => { describe('computeEffectiveRegenForDisplay', () => { const baseState = { - skills: {}, prestigeUpgrades: {}, - skillUpgrades: {}, - skillTiers: {}, attunements: {}, }; diff --git a/src/lib/game/__tests__/store-actions-combat-prestige.test.ts b/src/lib/game/__tests__/store-actions-combat-prestige.test.ts index 30edba0..0f7ec95 100644 --- a/src/lib/game/__tests__/store-actions-combat-prestige.test.ts +++ b/src/lib/game/__tests__/store-actions-combat-prestige.test.ts @@ -186,15 +186,16 @@ describe('PrestigeStore', () => { describe('doPrestige', () => { it('should purchase upgrade when affordable', () => { - const result = usePrestigeStore.getState().doPrestige('manaWell'); + usePrestigeStore.setState({ insight: 2000 }); + const result = usePrestigeStore.getState().doPrestige('insightAmp'); expect(result.success).toBe(true); - expect(usePrestigeStore.getState().prestigeUpgrades.manaWell).toBe(1); - expect(usePrestigeStore.getState().insight).toBeLessThan(500); + expect(usePrestigeStore.getState().prestigeUpgrades.insightAmp).toBe(1); + expect(usePrestigeStore.getState().insight).toBeLessThan(2000); }); it('should return false when cannot afford', () => { usePrestigeStore.setState({ insight: 0 }); - const result = usePrestigeStore.getState().doPrestige('manaWell'); + const result = usePrestigeStore.getState().doPrestige('insightAmp'); expect(result.success).toBe(false); if (!result.success) { expect(result.code).toBe(ErrorCode.INSUFFICIENT_INSIGHT); @@ -320,9 +321,9 @@ describe('PrestigeStore', () => { describe('resetPrestigeForNewLoop', () => { it('should preserve insight and upgrades, reset loop state', () => { - usePrestigeStore.getState().resetPrestigeForNewLoop(200, { manaWell: 2 }); + usePrestigeStore.getState().resetPrestigeForNewLoop(200, { insightAmp: 2 }); expect(usePrestigeStore.getState().insight).toBe(200); - expect(usePrestigeStore.getState().prestigeUpgrades).toEqual({ manaWell: 2 }); + expect(usePrestigeStore.getState().prestigeUpgrades).toEqual({ insightAmp: 2 }); expect(usePrestigeStore.getState().defeatedGuardians).toEqual([]); }); @@ -330,7 +331,7 @@ describe('PrestigeStore', () => { describe('resetPrestige', () => { it('should reset everything to initial state', () => { - usePrestigeStore.setState({ insight: 1000, loopCount: 5, prestigeUpgrades: { manaWell: 3 } }); + usePrestigeStore.setState({ insight: 1000, loopCount: 5, prestigeUpgrades: { insightAmp: 3 } }); usePrestigeStore.getState().resetPrestige(); expect(usePrestigeStore.getState().insight).toBe(0); expect(usePrestigeStore.getState().loopCount).toBe(0); diff --git a/src/lib/game/constants/core.ts b/src/lib/game/constants/core.ts index 1ee7666..cc50cf6 100644 --- a/src/lib/game/constants/core.ts +++ b/src/lib/game/constants/core.ts @@ -16,12 +16,11 @@ export const RARITY_COLORS: Record = { mythic: '#EF4444', }; -// ─── Study Speed Formula ───────────────────────────────────────────────────── -export function getStudySpeedMultiplier(skills: Record): number { - return 1 + (skills.quickLearner || 0) * 0.1; +// ─── Study Multipliers (skill system removed, always base value) ──────────── +export function getStudySpeedMultiplier(): number { + return 1; } -// ─── Study Cost Formula ─────────────────────────────────────────────────────── -export function getStudyCostMultiplier(skills: Record): number { - return 1 - (skills.focusedMind || 0) * 0.05; +export function getStudyCostMultiplier(): number { + return 1; } diff --git a/src/lib/game/constants/prestige.ts b/src/lib/game/constants/prestige.ts index 87aa7d1..aa1161f 100644 --- a/src/lib/game/constants/prestige.ts +++ b/src/lib/game/constants/prestige.ts @@ -2,8 +2,6 @@ import type { PrestigeDef } from '../types'; export const PRESTIGE_DEF: Record = { - manaWell: { name: "Mana Well", desc: "+500 starting max mana", max: 5, cost: 500 }, - manaFlow: { name: "Mana Flow", desc: "+0.5 regen/sec permanently", max: 10, cost: 750 }, insightAmp: { name: "Insight Amp", desc: "+25% insight gain", max: 4, cost: 1500 }, spireKey: { name: "Spire Key", desc: "Start at floor +2", max: 5, cost: 4000 }, temporalEcho: { name: "Temporal Echo", desc: "+10% mana generation", max: 5, cost: 3000 }, diff --git a/src/lib/game/crafting-actions/design-actions.ts b/src/lib/game/crafting-actions/design-actions.ts index 78b24d8..4fb2227 100644 --- a/src/lib/game/crafting-actions/design-actions.ts +++ b/src/lib/game/crafting-actions/design-actions.ts @@ -9,8 +9,6 @@ import { hasSpecial, SPECIAL_EFFECTS } from '../effects/special-effects'; export interface DesignActionsParams { skills: Record; - skillUpgrades: Record; - skillTiers: Record; } export function startDesigningEnchantment( @@ -33,14 +31,13 @@ export function startDesigningEnchantment( const equipType = CraftingUtils.getEquipmentType(equipmentTypeId); if (!equipType) return false; - const efficiencyBonus = ((params.skillUpgrades || {})['efficientEnchant'] || [])?.length * 0.05 || 0; - const totalCapacityCost = CraftingDesign.calculateDesignCapacityCost(effects, efficiencyBonus); + const totalCapacityCost = CraftingDesign.calculateDesignCapacityCost(effects, 0); if (totalCapacityCost > equipType.baseCapacity) { return false; } - const computedEffects = computeEffects(params.skillUpgrades || {}, params.skillTiers || {}); + const computedEffects = computeEffects(); const hasEnchantMastery = hasSpecial(computedEffects, SPECIAL_EFFECTS.ENCHANT_MASTERY); let updates: Partial = {}; diff --git a/src/lib/game/data/disciplines/base.ts b/src/lib/game/data/disciplines/base.ts index d7be132..9e3c70d 100644 --- a/src/lib/game/data/disciplines/base.ts +++ b/src/lib/game/data/disciplines/base.ts @@ -61,10 +61,19 @@ export const baseDisciplines: DisciplineDefinition[] = [ type: 'capped', threshold: 100, value: 100, - description: 'Every 100 XP: +0.5 max meditation cap (7 tiers, up to +3.5). Raises Void Meditation ceiling.', + description: 'Every 100 XP: +0.5 to meditation multiplier (7 tiers, up to +3.5). Adds directly to the meditation multiplier cap.', bonus: { stat: 'meditationCapBonus', amount: 0.5 }, maxTier: 7, }, + { + id: 'mana-circulation-click', + type: 'capped', + threshold: 500, + value: 500, + description: 'Every 500 XP: +1 mana per click (5 tiers, up to +5).', + bonus: { stat: 'clickManaBonus', amount: 1 }, + maxTier: 5, + }, ], }, { diff --git a/src/lib/game/effects.ts b/src/lib/game/effects.ts index 2275f00..0326c82 100644 --- a/src/lib/game/effects.ts +++ b/src/lib/game/effects.ts @@ -88,12 +88,10 @@ export interface UnifiedEffects extends ComputedEffects { } export function computeAllEffects( - skillUpgrades: Record, - skillTiers: Record, equipmentInstances: Record, equippedInstances: Record, ): UnifiedEffects { - const upgradeEffects = computeEffects(skillUpgrades, skillTiers); + const upgradeEffects = computeEffects(); const equipmentEffects = computeEquipmentEffects(equipmentInstances, equippedInstances, upgradeEffects.enchantmentPowerMultiplier); const disciplineEffects = computeDisciplineEffects(); @@ -105,9 +103,6 @@ export function computeAllEffects( } } - // Per-element regen from discipline effects (regen_{element}) — no longer produced - // by elemental disciplines (they now use conversion instead). - // Kept for backward compatibility with any upgrade effects that may provide per-element regen. const perElementRegenBonus: Record = { ...upgradeEffects.perElementRegenBonus }; // Merge per-element cap bonuses from discipline effects (elementCap_{element}) @@ -158,14 +153,10 @@ export function computeAllEffects( } export function getUnifiedEffects(state: { - skillUpgrades?: Record; - skillTiers?: Record; equipmentInstances?: Record; equippedInstances?: Record; }): UnifiedEffects { return computeAllEffects( - state.skillUpgrades || {}, - state.skillTiers || {}, state.equipmentInstances || {}, state.equippedInstances || {}, ); @@ -175,28 +166,21 @@ export function getUnifiedEffects(state: { export function computeTotalMaxMana( state: { - skills?: Record; prestigeUpgrades?: Record; - skillUpgrades?: Record; - skillTiers?: Record; equipmentInstances?: Record; equippedInstances?: Record; }, effects?: UnifiedEffects ): number { const pu = state.prestigeUpgrades; - const skillMult = effects?.skillLevelMultiplier || 1; - const base = 100 + ((state.skills || {}).manaWell || 0) * 100 * skillMult + ((pu || {}).manaWell || 0) * 500; + const base = 100 + ((pu || {}).manaWell || 0) * 500; const resolvedEffects = effects || getUnifiedEffects(state); return Math.floor((base + resolvedEffects.maxManaBonus) * resolvedEffects.maxManaMultiplier); } export function computeTotalRegen( state: { - skills?: Record; prestigeUpgrades?: Record; - skillUpgrades?: Record; - skillTiers?: Record; equipmentInstances?: Record; equippedInstances?: Record; }, @@ -204,8 +188,7 @@ export function computeTotalRegen( ): number { const pu = state.prestigeUpgrades; const temporalBonus = 1 + ((pu?.temporalEcho || 0)) * 0.1; - const skillMult = effects?.skillLevelMultiplier || 1; - const base = 2 + (state.skills?.manaFlow || 0) * 1 * skillMult + (state.skills?.manaSpring || 0) * 2 * skillMult + (pu?.manaFlow || 0) * 0.5; + const base = 2 + (pu?.manaFlow || 0) * 0.5; let regen = base * temporalBonus; const resolvedEffects = effects || getUnifiedEffects(state); regen = (regen + resolvedEffects.regenBonus + resolvedEffects.permanentRegenBonus) * resolvedEffects.regenMultiplier; @@ -214,16 +197,12 @@ export function computeTotalRegen( export function computeTotalClickMana( state: { - skills?: Record; - skillUpgrades?: Record; - skillTiers?: Record; equipmentInstances?: Record; equippedInstances?: Record; }, effects?: UnifiedEffects ): number { - const skillMult = effects?.skillLevelMultiplier || 1; - const base = 1 + (state.skills?.manaTap || 0) * 1 * skillMult + (state.skills?.manaSurge || 0) * 3 * skillMult; + const base = 1; const resolvedEffects = effects || getUnifiedEffects(state); return Math.floor((base + resolvedEffects.clickManaBonus) * resolvedEffects.clickManaMultiplier); } diff --git a/src/lib/game/effects/upgrade-effects.ts b/src/lib/game/effects/upgrade-effects.ts index 29e0fa0..f62ba93 100644 --- a/src/lib/game/effects/upgrade-effects.ts +++ b/src/lib/game/effects/upgrade-effects.ts @@ -18,10 +18,7 @@ function _buildUpgradeCache(): void { * Get all selected upgrades with their full effect definitions. * Since skills are removed, always returns empty array. */ -export function getActiveUpgrades( - _skillUpgrades: Record, - _skillTiers: Record -): ActiveUpgradeEffect[] { +export function getActiveUpgrades(): ActiveUpgradeEffect[] { return []; } @@ -29,10 +26,7 @@ export function getActiveUpgrades( * Compute all active effects from selected upgrades. * Since skills are removed, returns base values with no upgrades applied. */ -export function computeEffects( - _skillUpgrades: Record, - _skillTiers: Record -): ComputedEffects { +export function computeEffects(): ComputedEffects { return { maxManaMultiplier: 1, maxManaBonus: 0, diff --git a/src/lib/game/hooks/useGameDerived.ts b/src/lib/game/hooks/useGameDerived.ts index 365b9ee..1ed65e9 100644 --- a/src/lib/game/hooks/useGameDerived.ts +++ b/src/lib/game/hooks/useGameDerived.ts @@ -39,17 +39,17 @@ export function useManaStats() { ); const maxMana = useMemo( - () => computeMaxMana({ skills: {}, prestigeUpgrades, skillUpgrades: {}, skillTiers: {} }, upgradeEffects), + () => computeMaxMana({ prestigeUpgrades }, upgradeEffects), [prestigeUpgrades, upgradeEffects] ); const baseRegen = useMemo( - () => computeRegen({ skills: {} as Record, prestigeUpgrades, attunements: {} } as any, upgradeEffects), + () => computeRegen({ prestigeUpgrades, attunements: {} } as any, upgradeEffects), [prestigeUpgrades, upgradeEffects] ); const clickMana = useMemo( - () => computeClickMana({}), + () => computeClickMana(), [] ); @@ -157,7 +157,7 @@ export function useCombatStats() { const attackSpeedMult = upgradeEffects.attackSpeedMultiplier; const totalCastSpeed = spellCastSpeed * quickCastBonus * attackSpeedMult; - const damagePerCast = calcDamage({ skills: {}, signedPacts }, activeSpell, floorElem); + const damagePerCast = calcDamage({ signedPacts }, activeSpell, floorElem); const castsPerSecond = totalCastSpeed * HOURS_PER_TICK / (TICK_MS / 1000); return damagePerCast * castsPerSecond; @@ -195,7 +195,7 @@ export function useCombatStats() { precisionChance, elemBonus, elemBonusText, - total: calcDamage({ skills: {}, signedPacts }, activeSpell, floorElem), + total: calcDamage({ signedPacts }, activeSpell, floorElem), }; }, [activeSpellDef, signedPacts, activeSpell, floorElem, isGuardianFloor, pactMultiplier]); @@ -217,17 +217,17 @@ export function useCombatStats() { */ export function useStudyStats() { const studySpeedMult = useMemo( - () => getStudySpeedMultiplier({}), + () => getStudySpeedMultiplier(), [] ); const studyCostMult = useMemo( - () => getStudyCostMultiplier({}), + () => getStudyCostMultiplier(), [] ); const upgradeEffects = useMemo( - () => computeEffects({}, {}), + () => computeEffects(), [] ); diff --git a/src/lib/game/stores/combat-actions.ts b/src/lib/game/stores/combat-actions.ts index c196c7d..56db94c 100644 --- a/src/lib/game/stores/combat-actions.ts +++ b/src/lib/game/stores/combat-actions.ts @@ -96,7 +96,7 @@ export function processCombatTick( // Calculate base damage const floorElement = getFloorElement(currentFloor); const damage = calcDamage( - { skills: {}, signedPacts }, + { signedPacts }, spellId, floorElement, disciplineEffects, @@ -151,7 +151,7 @@ export function processCombatTick( // Calculate damage const eFloorElement = getFloorElement(currentFloor); const eDamage = calcDamage( - { skills: {}, signedPacts }, + { signedPacts }, eSpell.spellId, eFloorElement, disciplineEffects, diff --git a/src/lib/game/stores/gameActions.ts b/src/lib/game/stores/gameActions.ts index 7e56073..13e09bb 100644 --- a/src/lib/game/stores/gameActions.ts +++ b/src/lib/game/stores/gameActions.ts @@ -30,7 +30,7 @@ export const createResetGame = (set: (state: Partial) => v useUIStore.getState().reset(); usePrestigeStore.getState().resetPrestige(); - useManaStore.getState().resetMana({}, {}, {}, {}); + useManaStore.getState().resetMana({}); useCombatStore.getState().resetCombat(startFloor); set({ @@ -43,19 +43,11 @@ export const createGatherMana = () => () => { const prestigeState = usePrestigeStore.getState(); const disciplineEffects = computeDisciplineEffects(); - // Compute click mana with discipline bonuses (mana-channeling → clickManaMultiplier) - const cm = computeClickMana( - {}, - disciplineEffects, - ); + // Compute click mana with discipline bonuses + const cm = computeClickMana(disciplineEffects); const max = computeMaxMana( - { - skills: {}, - prestigeUpgrades: prestigeState.prestigeUpgrades, - skillUpgrades: {}, - skillTiers: {} - }, + { prestigeUpgrades: prestigeState.prestigeUpgrades }, undefined, disciplineEffects, ); diff --git a/src/lib/game/stores/gameHooks.ts b/src/lib/game/stores/gameHooks.ts index 8e40923..f70d7f3 100644 --- a/src/lib/game/stores/gameHooks.ts +++ b/src/lib/game/stores/gameHooks.ts @@ -33,8 +33,6 @@ export function useUnifiedEffects() { return { ...getUnifiedEffects({ - skillUpgrades: {}, - skillTiers: {}, equippedInstances, equipmentInstances, }), @@ -55,27 +53,25 @@ export function useManaStats() { const disciplineEffects = computeDisciplineEffects(); const upgradeEffects = getUnifiedEffects({ - skillUpgrades: {}, - skillTiers: {}, equippedInstances, equipmentInstances, }); const maxMana = computeMaxMana( - { skills: {}, prestigeUpgrades, skillUpgrades: {}, skillTiers: {} }, + { prestigeUpgrades }, upgradeEffects, disciplineEffects, ); const baseRegen = computeRegen( - { skills: {}, prestigeUpgrades, skillUpgrades: {}, skillTiers: {}, attunements: {} }, + { prestigeUpgrades, attunements: {} }, upgradeEffects, disciplineEffects, ); - const clickMana = computeClickMana({}, disciplineEffects); + const clickMana = computeClickMana(disciplineEffects); - const meditationMultiplier = getMeditationBonus(meditateTicks, {}, upgradeEffects.meditationEfficiency, disciplineEffects.meditationCapBonus); + const meditationMultiplier = getMeditationBonus(meditateTicks, upgradeEffects.meditationEfficiency, disciplineEffects.meditationCapBonus); const incursionStrength = getIncursionStrength(day, hour); const effectiveRegenWithSpecials = baseRegen * (1 - incursionStrength); @@ -113,8 +109,6 @@ export function useCombatStats() { const equipmentInstances = useCraftingStore((s) => s.equipmentInstances); const upgradeEffects = getUnifiedEffects({ - skillUpgrades: {}, - skillTiers: {}, equippedInstances, equipmentInstances, }); diff --git a/src/lib/game/stores/gameLoopActions.ts b/src/lib/game/stores/gameLoopActions.ts index 72583f5..5f0f444 100644 --- a/src/lib/game/stores/gameLoopActions.ts +++ b/src/lib/game/stores/gameLoopActions.ts @@ -19,7 +19,6 @@ export const createStartNewLoop = (set: (state: Partial) = totalManaGathered: manaState.totalManaGathered, signedPacts: prestigeState.signedPacts, prestigeUpgrades: prestigeState.prestigeUpgrades, - skills: {}, }, disciplineEffects); const total = prestigeState.insight + insightGained; @@ -41,7 +40,7 @@ export const createStartNewLoop = (set: (state: Partial) = ); usePrestigeStore.getState().incrementLoopCount(); - useManaStore.getState().resetMana(pu, {}, {}, {}); + useManaStore.getState().resetMana(pu); // Reset combat with starting floor and any spells from prestige upgrades const startSpells = makeInitialSpells(); diff --git a/src/lib/game/stores/gameStore.ts b/src/lib/game/stores/gameStore.ts index bdff91f..6b38699 100644 --- a/src/lib/game/stores/gameStore.ts +++ b/src/lib/game/stores/gameStore.ts @@ -105,12 +105,12 @@ export const useGameStore = create()( const effects = { specials: allSpecials } as ComputedEffects; const maxMana = computeMaxMana( - { skills: {}, prestigeUpgrades: ctx.prestige.prestigeUpgrades, skillUpgrades: {}, skillTiers: {} }, + { prestigeUpgrades: ctx.prestige.prestigeUpgrades }, undefined, disciplineEffects, ); const baseRegen = computeRegen( - { skills: {}, prestigeUpgrades: ctx.prestige.prestigeUpgrades, skillUpgrades: {}, skillTiers: {}, attunements: {} }, + { prestigeUpgrades: ctx.prestige.prestigeUpgrades, attunements: {} }, undefined, disciplineEffects, ) * (1 + (disciplineEffects.multipliers.regenMultiplier || 0)); @@ -129,7 +129,6 @@ export const useGameStore = create()( totalManaGathered: ctx.mana.totalManaGathered, signedPacts: ctx.prestige.signedPacts, prestigeUpgrades: ctx.prestige.prestigeUpgrades, - skills: {} as Record, }; // Check for loop end @@ -163,7 +162,7 @@ export const useGameStore = create()( if (ctx.combat.currentAction === 'meditate') { meditateTicks++; - meditationMultiplier = getMeditationBonus(meditateTicks, {}, 1, disciplineEffects.meditationCapBonus); + meditationMultiplier = getMeditationBonus(meditateTicks, 1, disciplineEffects.meditationCapBonus); } else { meditateTicks = 0; } diff --git a/src/lib/game/stores/manaStore.ts b/src/lib/game/stores/manaStore.ts index 1e16d05..33366d3 100755 --- a/src/lib/game/stores/manaStore.ts +++ b/src/lib/game/stores/manaStore.ts @@ -45,9 +45,6 @@ export interface ManaActions { // Reset resetMana: ( prestigeUpgrades: Record, - skills?: Record, - skillUpgrades?: Record, - skillTiers?: Record ) => void; } @@ -193,9 +190,6 @@ export const useManaStore = create()( resetMana: ( prestigeUpgrades: Record, - _skills: Record = {}, - _skillUpgrades: Record = {}, - _skillTiers: Record = {} ) => { const elementMax = 10 + (prestigeUpgrades.elemMax || 0) * 5; const startingMana = 10 + (prestigeUpgrades.manaStart || 0) * 10; diff --git a/src/lib/game/types/game.ts b/src/lib/game/types/game.ts index d1a4aa7..9794c5a 100644 --- a/src/lib/game/types/game.ts +++ b/src/lib/game/types/game.ts @@ -166,12 +166,6 @@ export interface GameState { // Spells spells: Record; - // Skills - skills: Record; - skillProgress: Record; // Saved study progress for skills - skillUpgrades: Record; // Selected upgrade IDs per skill - skillTiers: Record; // Current tier for each base skill - // Equipment System (new instance-based system) equippedInstances: Record; // slot -> instanceId equipmentInstances: Record; // instanceId -> instance @@ -290,7 +284,6 @@ export type GameActionType = | { type: 'SET_ACTION'; action: GameAction } | { type: 'SET_SPELL'; spellId: string } | { type: 'LEARN_SPELL'; spellId: string } - | { type: 'START_STUDYING_SKILL'; skillId: string } | { type: 'START_STUDYING_SPELL'; spellId: string } | { type: 'CANCEL_STUDY' } | { type: 'CONVERT_MANA'; element: string; amount: number } @@ -299,6 +292,5 @@ export type GameActionType = | { type: 'DO_PRESTIGE'; id: string } | { type: 'START_NEW_LOOP' } | { type: 'TOGGLE_PAUSE' } - | { type: 'RESET_GAME' } - | { type: 'SELECT_SKILL_UPGRADE'; skillId: string; upgradeId: string } - | { type: 'TIER_UP_SKILL'; skillId: string }; + | { type: 'RESET_GAME' }; + diff --git a/src/lib/game/utils/combat-utils.ts b/src/lib/game/utils/combat-utils.ts index 15d456b..d6eedd9 100644 --- a/src/lib/game/utils/combat-utils.ts +++ b/src/lib/game/utils/combat-utils.ts @@ -10,7 +10,6 @@ import { BASE_GUARDIANS } from '../data/guardian-data'; // ─── Damage Calculation Params ────────────────────────────────────────────── export interface DamageCalcParams { - skills: Record; signedPacts: number[]; } @@ -21,13 +20,11 @@ export interface InsightCalcParams { totalManaGathered: number; signedPacts: number[]; prestigeUpgrades: Record; - skills: Record; } // ─── DPS Calculation Params ───────────────────────────────────────────────── export interface DPSCalcParams { - skills: Record; signedPacts: number[]; equippedInstances: Record; equipmentInstances: Record; @@ -150,24 +147,21 @@ export function calcDamage( ): number { const sp = SPELLS_DEF[spellId]; if (!sp) return 5; - const skills = state.skills; - // Base damage: spell base + skill bonus + discipline bonus + // Base damage: spell base + discipline bonus const discBaseDmg = discipline?.bonuses?.baseDamageBonus || 0; - const baseDmg = sp.dmg + (skills.combatTrain || 0) * 5 + discBaseDmg; + const baseDmg = sp.dmg + discBaseDmg; // Percentage multiplier const discDmgMult = discipline?.bonuses?.baseDamageMultiplier || 0; - const pct = 1 + (skills.arcaneFury || 0) * 0.1 + discDmgMult; + const pct = 1 + discDmgMult; // Elemental mastery bonus - const elemMasteryBonus = 1 + (skills.elementalMastery || 0) * 0.15; + const elemMasteryBonus = 1; // Guardian bane bonus const isGuardianFloor = floorElem && Object.values(BASE_GUARDIANS).some(g => g.element === floorElem); - const guardianBonus = isGuardianFloor - ? 1 + (skills.guardianBane || 0) * 0.2 - : 1; + const guardianBonus = 1; // Get boon bonuses from pacts const boons = getBoonBonuses(state.signedPacts); @@ -177,7 +171,7 @@ export function calcDamage( const elemDamageMult = 1 + boons.elementalDamage / 100; // Apply crit chance and damage from boons - const critChance = (skills.precision || 0) * 0.05 + boons.critChance / 100; + const critChance = boons.critChance / 100; const critDamageMult = 1.5 + boons.critDamage / 100; let damage = baseDmg * pct * elemMasteryBonus * guardianBonus * rawDamageMult * elemDamageMult; @@ -200,7 +194,7 @@ export function calcDamage( export function calcInsight(state: InsightCalcParams, discipline?: DisciplineBonuses): number { const pu = state.prestigeUpgrades; const discInsightBonus = discipline?.bonuses?.insightGainBonus || 0; - const skillBonus = 1 + (state.skills.insightHarvest || 0) * 0.1 + discInsightBonus; + const skillBonus = 1 + discInsightBonus; // Get boon bonuses for insight gain const boons = getBoonBonuses(state.signedPacts); @@ -323,7 +317,7 @@ export function getTotalDPS( // Get cast speed (spells per second) const baseCastTime = spellDef.baseCastTime || 1.0; - const castingSpeedBonus = 1 + (state.skills.castingSpeed || 0) * 0.1; + const castingSpeedBonus = 1; const equipmentAttackSpeed = upgradeEffects.attackSpeedMultiplier || 1; const castTime = baseCastTime / (castingSpeedBonus * equipmentAttackSpeed); diff --git a/src/lib/game/utils/mana-utils.ts b/src/lib/game/utils/mana-utils.ts index b1384ce..be99e57 100644 --- a/src/lib/game/utils/mana-utils.ts +++ b/src/lib/game/utils/mana-utils.ts @@ -13,10 +13,7 @@ export interface DisciplineBonuses { // ─── Mana Params ──────────────────────────────────────────────────────────── export interface ManaComputeParams { - skills?: Record; prestigeUpgrades?: Record; - skillUpgrades?: Record; - skillTiers?: Record; } export interface RegenComputeParams extends ManaComputeParams { @@ -38,7 +35,6 @@ export function computeMaxMana( const pu = state.prestigeUpgrades || {}; const base = 100 + - ((state.skills || {}).manaWell || 0) * 100 + (pu.manaWell || 0) * 500 + (discipline?.bonuses?.maxManaBonus || 0); @@ -51,7 +47,7 @@ export function computeMaxMana( // ─── Regen ──────────────────────────────────────────────────────────────────── export function computeRegen( - state: Pick & Partial>, + state: Pick, effects?: ComputedEffects, discipline?: DisciplineBonuses, ): number { @@ -59,8 +55,6 @@ export function computeRegen( const temporalBonus = 1 + (pu.temporalEcho || 0) * 0.1; const base = 2 + - ((state.skills || {}).manaFlow || 0) * 1 + - ((state.skills || {}).manaSpring || 0) * 2 + ((pu || {}).manaFlow || 0) * 0.5; let regen = base * temporalBonus; @@ -85,7 +79,7 @@ export function computeRegen( // ─── Effective Regen for Display ────────────────────────────────────────────── export function computeEffectiveRegenForDisplay( - state: Pick, + state: Pick, effects?: ComputedEffects, discipline?: DisciplineBonuses, ): { rawRegen: number; conversionDrain: number; effectiveRegen: number } { @@ -99,7 +93,7 @@ export function computeEffectiveRegenForDisplay( // ─── Effective Regen (dynamic) ──────────────────────────────────────────────── export function computeEffectiveRegen( - state: Pick & { rawMana: number; incursionStrength: number }, + state: Pick & { rawMana: number; incursionStrength: number }, effects?: ComputedEffects, discipline?: DisciplineBonuses, ): number { @@ -112,56 +106,25 @@ export function computeEffectiveRegen( // ─── Click Mana ─────────────────────────────────────────────────────────────── export function computeClickMana( - skills: Record, discipline?: DisciplineBonuses, ): number { - const skillTap = (skills.manaTap || 0) * 1; - const skillSurge = (skills.manaSurge || 0) * 3; - const discClickMult = discipline?.bonuses?.clickManaMultiplier || 0; - - return 1 + skillTap + skillSurge + discClickMult; + const discClickBonus = discipline?.bonuses?.clickManaBonus || 0; + return 1 + discClickBonus; } // ─── Meditation Bonus ───────────────────────────────────────────────────────── export function getMeditationBonus( meditateTicks: number, - skills: Record, meditationEfficiency: number = 1, disciplineMeditationCap: number = 0, ): number { - const hasMeditation = skills.meditation === 1; - const hasDeepTrance = skills.deepTrance === 1; - const hasVoidMeditation = skills.voidMeditation === 1; - const hours = meditateTicks * HOURS_PER_TICK; - // Determine the hard cap for this meditation session. - // disciplineMeditationCap adds +0.5 per point (e.g. from Mana Circulation discipline). - // Base max is 5.0 (Void Meditation), each discipline bonus adds +0.5. + // Continuous ramp: 1 + (hours / 8) * 4, capped at 5.0 + disciplineMeditationCap const maxMultiplier = 5.0 + disciplineMeditationCap; - - // Base meditation: ramps up over 4 hours, capped at 1.5x or discipline cap - let bonus = 1 + Math.min(hours / 4, 0.5); - bonus = Math.min(bonus, maxMultiplier); - - // With Meditation Focus: up to 2.5x after 4 hours - if (hasMeditation && hours >= 4) { - bonus = Math.min(2.5, maxMultiplier); - } - - // With Deep Trance: up to 3.0x after 6 hours - if (hasDeepTrance && hours >= 6) { - bonus = Math.min(3.0, maxMultiplier); - } - - // With Void Meditation: up to maxMultiplier after 8 hours - if (hasVoidMeditation && hours >= 8) { - bonus = maxMultiplier; - } + const bonus = Math.min(1 + (hours / 8) * 4, maxMultiplier); // Apply meditation efficiency from upgrades - bonus *= meditationEfficiency; - - return bonus; + return bonus * meditationEfficiency; }