fix: mana conversion attunement rate now uses flat base + linear multiplier per spec
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m17s

This commit is contained in:
2026-06-07 23:06:03 +02:00
parent e5097211ba
commit a11ea065eb
6 changed files with 13 additions and 11 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
# Circular Dependencies # Circular Dependencies
Generated: 2026-06-07T14:14:38.464Z Generated: 2026-06-07T16:09:18.340Z
No circular dependencies found. ✅ No circular dependencies found. ✅
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_meta": { "_meta": {
"generated": "2026-06-07T14:14:36.561Z", "generated": "2026-06-07T16:09:16.437Z",
"description": "Import dependency graph for src/lib/game. Keys are files, values are arrays of files they import.", "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." "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."
}, },
@@ -9,7 +9,7 @@ import { usePrestigeStore, useManaStore, useAttunementStore, useDisciplineStore,
import { computeDisciplineEffects } from '@/lib/game/effects/discipline-effects'; import { computeDisciplineEffects } from '@/lib/game/effects/discipline-effects';
import { computeConversionRates } from '@/lib/game/utils/conversion-rates'; import { computeConversionRates } from '@/lib/game/utils/conversion-rates';
import { getGuardianForFloor } from '@/lib/game/data/guardian-encounters'; import { getGuardianForFloor } from '@/lib/game/data/guardian-encounters';
import { ATTUNEMENTS_DEF, getAttunementConversionRate } from '@/lib/game/data/attunements'; import { ATTUNEMENTS_DEF } from '@/lib/game/data/attunements';
import { useMemo } from 'react'; import { useMemo } from 'react';
import type { ElementState } from '@/lib/game/types'; import type { ElementState } from '@/lib/game/types';
@@ -38,7 +38,7 @@ export function ElementStatsSection({ elemMax }: ElementStatsSectionProps) {
const def = ATTUNEMENTS_DEF[id]; const def = ATTUNEMENTS_DEF[id];
if (def?.primaryManaType) { if (def?.primaryManaType) {
grossRegen[def.primaryManaType] = (grossRegen[def.primaryManaType] || 0) grossRegen[def.primaryManaType] = (grossRegen[def.primaryManaType] || 0)
+ getAttunementConversionRate(id, state.level || 1); + (def.conversionRate || 0);
} }
} }
const invokerLevel = attunements.invoker?.active ? (attunements.invoker.level || 1) : 0; const invokerLevel = attunements.invoker?.active ? (attunements.invoker.level || 1) : 0;
+4 -3
View File
@@ -66,13 +66,14 @@ describe('Attunement Mana Type Unlocking', () => {
const enchanter = ATTUNEMENTS_DEF['enchanter']; const enchanter = ATTUNEMENTS_DEF['enchanter'];
expect(enchanter.conversionRate).toBeGreaterThan(0); expect(enchanter.conversionRate).toBeGreaterThan(0);
// Get scaled conversion rate at level 1 // Base conversion rate is flat (not scaled by level)
// Level scaling is applied as a multiplier in computeConversionRates(), not here
const level1Rate = getAttunementConversionRate('enchanter', 1); const level1Rate = getAttunementConversionRate('enchanter', 1);
expect(level1Rate).toBe(enchanter.conversionRate); expect(level1Rate).toBe(enchanter.conversionRate);
// Higher level should have higher rate // Flat rate: same at all levels (level multiplier applied separately)
const level5Rate = getAttunementConversionRate('enchanter', 5); const level5Rate = getAttunementConversionRate('enchanter', 5);
expect(level5Rate).toBeGreaterThan(level1Rate); expect(level5Rate).toBe(level1Rate);
}); });
it('should have raw mana regen for all attunements', () => { it('should have raw mana regen for all attunements', () => {
+3 -2
View File
@@ -99,12 +99,13 @@ export function getTotalAttunementRegen(attunements: Record<string, { active: bo
/** /**
* Get the attunement base conversion rate for a specific attunement. * Get the attunement base conversion rate for a specific attunement.
* This is the base rate contribution to the unified conversion system. * This is the flat base rate contribution to the unified conversion system.
* Level scaling is applied as a multiplier in computeConversionRates(), not here.
*/ */
export function getAttunementConversionRate(attunementId: string, level: number): number { export function getAttunementConversionRate(attunementId: string, level: number): number {
const def = ATTUNEMENTS_DEF[attunementId]; const def = ATTUNEMENTS_DEF[attunementId];
if (!def || def.conversionRate <= 0) return 0; if (!def || def.conversionRate <= 0) return 0;
return def.conversionRate * Math.pow(1.5, (level || 1) - 1); return def.conversionRate;
} }
/** /**
+2 -2
View File
@@ -19,7 +19,7 @@ import { useCombatStore } from './combatStore';
import { useAttunementStore } from './attunementStore'; import { useAttunementStore } from './attunementStore';
import { useCraftingStore } from './craftingStore'; import { useCraftingStore } from './craftingStore';
import { useDisciplineStore } from './discipline-slice'; import { useDisciplineStore } from './discipline-slice';
import { ATTUNEMENTS_DEF, getAttunementConversionRate } from '../data/attunements'; import { ATTUNEMENTS_DEF } from '../data/attunements';
import { createResetGame, createGatherMana } from './gameActions'; import { createResetGame, createGatherMana } from './gameActions';
import { createSafeStorage } from '../utils/safe-persist'; import { createSafeStorage } from '../utils/safe-persist';
import { createStartNewLoop } from './gameLoopActions'; import { createStartNewLoop } from './gameLoopActions';
@@ -369,7 +369,7 @@ function buildConversionParams(
const def = ATTUNEMENTS_DEF[id]; const def = ATTUNEMENTS_DEF[id];
if (def?.primaryManaType) { if (def?.primaryManaType) {
grossRegen[def.primaryManaType] = (grossRegen[def.primaryManaType] || 0) grossRegen[def.primaryManaType] = (grossRegen[def.primaryManaType] || 0)
+ getAttunementConversionRate(id, state.level || 1); + (def.conversionRate || 0);
} }
} }
return { pactElementMap, grossRegen }; return { pactElementMap, grossRegen };