fix: remove discipline pool-drain model, add conversion stats UI per mana-conversion-spec
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m17s
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m17s
DISC-2: Removed old pool-drain model from discipline-slice.ts processTick() - Disciplines no longer drain rawMana or element pools - canProceedDiscipline() no longer checks mana sufficiency - Removed auto-pause on insufficient mana from processTick() - Removed drain display and auto-paused message from DisciplineCard.tsx - Removed auto-paused log from gameStore.ts tick() DISC-4: Audited crafting pipeline — no composite crafting logic remains - craftComposite already removed from manaStore.ts (comment only) - No other composite crafting references found DISC-5: Added collapsible formula reference to Conversion Stats section - Shows unified formula, multipliers, cost formulas, and constraints DISC-6: Added per-element net regen summary line - Shows 'Net Fire Regen: +0.50/hr − 0.15/hr = +0.35/hr' per element DISC-7: Created dedicated 'Conversion Stats' section in Stats tab - Renamed from 'Conversion Breakdown' to dedicated section header DISC-8: Added detailed per-element regen breakdown to ManaDisplay - Each element card now expandable to show produced rate and downstream drains - New ElementRegenBreakdown type and elementRegenBreakdown prop Tests: Updated 4 test files to reflect new no-drain behavior - All 1090 tests pass
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useState, useEffect, useMemo } from 'react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Mountain } from 'lucide-react';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
@@ -9,11 +9,15 @@ import { ActionButtons } from '@/components/game';
|
||||
import { AttunementStatus } from '@/components/game/AttunementStatus';
|
||||
import { ActivityLogPanel } from '@/components/game/ActivityLogPanel';
|
||||
import { DebugName } from '@/components/game/debug/debug-context';
|
||||
import { useGameStore, useManaStore, useCombatStore, useCraftingStore, usePrestigeStore } from '@/lib/game/stores';
|
||||
import { useGameStore, useManaStore, useCombatStore, useCraftingStore, usePrestigeStore, useAttunementStore } from '@/lib/game/stores';
|
||||
import { getUnifiedEffects } from '@/lib/game/effects';
|
||||
import { getMeditationBonus, getIncursionStrength } from '@/lib/game/stores';
|
||||
import { computeTotalMaxMana, computeTotalRegen, computeTotalClickMana } from '@/lib/game/effects';
|
||||
import { computeDisciplineEffects } from '@/lib/game/effects/discipline-effects';
|
||||
import { computeConversionRates } from '@/lib/game/utils/conversion-rates';
|
||||
import { getGuardianForFloor } from '@/lib/game/data/guardian-encounters';
|
||||
import { ATTUNEMENTS_DEF } from '@/lib/game/data/attunements';
|
||||
import type { ElementRegenBreakdown } from '@/components/game/ManaDisplay';
|
||||
|
||||
export function LeftPanel() {
|
||||
const [isGathering, setIsGathering] = useState(false);
|
||||
@@ -23,6 +27,8 @@ export function LeftPanel() {
|
||||
const meditateTicks = useManaStore((s) => s.meditateTicks);
|
||||
const elementRegen = useManaStore((s) => s.elementRegen);
|
||||
const prestigeUpgrades = usePrestigeStore((s) => s.prestigeUpgrades);
|
||||
const signedPacts = usePrestigeStore((s) => s.signedPacts);
|
||||
const attunements = useAttunementStore((s) => s.attunements);
|
||||
const equippedInstances = useCraftingStore((s) => s.equippedInstances);
|
||||
const equipmentInstances = useCraftingStore((s) => s.equipmentInstances);
|
||||
const gatherMana = useGameStore((s) => s.gatherMana);
|
||||
@@ -64,6 +70,51 @@ export function LeftPanel() {
|
||||
const incursionStrength = getIncursionStrength(useGameStore((s) => s.day), useGameStore((s) => s.hour));
|
||||
const effectiveRegen = baseRegen * (1 - incursionStrength) * meditationMultiplier;
|
||||
|
||||
// Compute per-element regen breakdown for ManaDisplay (DISC-8)
|
||||
const elementRegenBreakdown = useMemo((): Record<string, ElementRegenBreakdown> | undefined => {
|
||||
const pactElementMap: Record<number, string> = {};
|
||||
for (const floor of signedPacts) {
|
||||
const g = getGuardianForFloor(floor);
|
||||
if (g?.element?.length) pactElementMap[floor] = g.element[0];
|
||||
}
|
||||
const grossRegen: Record<string, number> = {};
|
||||
for (const [id, state] of Object.entries(attunements)) {
|
||||
if (!state.active) continue;
|
||||
const def = ATTUNEMENTS_DEF[id];
|
||||
if (def?.primaryManaType) {
|
||||
grossRegen[def.primaryManaType] = (grossRegen[def.primaryManaType] || 0)
|
||||
+ (def.conversionRate || 0);
|
||||
}
|
||||
}
|
||||
const invokerLevel = attunements.invoker?.active ? (attunements.invoker.level || 1) : 0;
|
||||
const conversionResult = computeConversionRates({
|
||||
disciplineEffects,
|
||||
attunements,
|
||||
signedPacts,
|
||||
pactElementMap,
|
||||
invokerLevel,
|
||||
meditationMultiplier,
|
||||
grossRegen,
|
||||
rawGrossRegen: baseRegen,
|
||||
});
|
||||
const breakdown: Record<string, ElementRegenBreakdown> = {};
|
||||
for (const [elem, entry] of Object.entries(conversionResult.rates)) {
|
||||
if (entry.paused) continue;
|
||||
const drains: Record<string, number> = {};
|
||||
// This element is drained when it's a component of a higher conversion
|
||||
for (const [destElem, destEntry] of Object.entries(conversionResult.rates)) {
|
||||
if (destEntry.paused) continue;
|
||||
if (destEntry.componentCosts[elem]) {
|
||||
drains[destElem] = (drains[destElem] || 0) + destEntry.finalRate * destEntry.componentCosts[elem];
|
||||
}
|
||||
}
|
||||
if (entry.finalRate > 0 || Object.keys(drains).length > 0) {
|
||||
breakdown[elem] = { produced: entry.finalRate, drains };
|
||||
}
|
||||
}
|
||||
return Object.keys(breakdown).length > 0 ? breakdown : undefined;
|
||||
}, [disciplineEffects, attunements, signedPacts, meditationMultiplier, baseRegen]);
|
||||
|
||||
return (
|
||||
<div className="md:w-80 space-y-3 flex-shrink-0 p-1">
|
||||
{/* 1. Mana Display */}
|
||||
@@ -79,6 +130,7 @@ export function LeftPanel() {
|
||||
onGatherEnd={handleGatherEnd}
|
||||
elements={elements}
|
||||
elementRegen={elementRegen}
|
||||
elementRegenBreakdown={elementRegenBreakdown}
|
||||
/>
|
||||
</DebugName>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user