fix: use actual meditationMultiplier and baseRegen in ElementStatsSection; add cost breakdown per spec §11
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m19s
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m19s
This commit is contained in:
@@ -51,6 +51,8 @@ export function StatsTab() {
|
||||
/>
|
||||
<ElementStatsSection
|
||||
elemMax={elemMax}
|
||||
meditationMultiplier={manaStats.meditationMultiplier}
|
||||
baseRegen={manaStats.baseRegen}
|
||||
/>
|
||||
<LoopStatsSection />
|
||||
</div>
|
||||
|
||||
@@ -15,9 +15,11 @@ import type { ElementState } from '@/lib/game/types';
|
||||
|
||||
interface ElementStatsSectionProps {
|
||||
elemMax: number;
|
||||
meditationMultiplier: number;
|
||||
baseRegen: number;
|
||||
}
|
||||
|
||||
export function ElementStatsSection({ elemMax }: ElementStatsSectionProps) {
|
||||
export function ElementStatsSection({ elemMax, meditationMultiplier, baseRegen }: ElementStatsSectionProps) {
|
||||
const prestigeUpgrades = usePrestigeStore((s) => s.prestigeUpgrades);
|
||||
const signedPacts = usePrestigeStore((s) => s.signedPacts);
|
||||
const elements = useManaStore((s) => s.elements);
|
||||
@@ -48,9 +50,9 @@ export function ElementStatsSection({ elemMax }: ElementStatsSectionProps) {
|
||||
signedPacts,
|
||||
pactElementMap,
|
||||
invokerLevel,
|
||||
meditationMultiplier: 1,
|
||||
meditationMultiplier,
|
||||
grossRegen,
|
||||
rawGrossRegen: 2,
|
||||
rawGrossRegen: baseRegen,
|
||||
});
|
||||
}, [disciplines, attunements, signedPacts]);
|
||||
|
||||
@@ -123,7 +125,7 @@ export function ElementStatsSection({ elemMax }: ElementStatsSectionProps) {
|
||||
<div className="text-xs font-medium mb-2" style={{ color: 'var(--text-muted)' }}>Conversion Breakdown:</div>
|
||||
<div className="space-y-2">
|
||||
{activeConversions.map((entry) => (
|
||||
<ConversionRow key={entry.element} entry={entry} />
|
||||
<ConversionRow key={entry.element} entry={entry} elementDrain={conversionData.elementDrain} />
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
@@ -134,8 +136,31 @@ export function ElementStatsSection({ elemMax }: ElementStatsSectionProps) {
|
||||
);
|
||||
}
|
||||
|
||||
function ConversionRow({ entry }: { entry: { element: string; distance: number; disciplineRate: number; attunementBase: number; pactBase: number; baseRate: number; attunementMult: number; pactMult: number; meditationMult: number; finalRate: number; paused: boolean; pauseReason: string | null } }) {
|
||||
function ConversionRow({ entry, elementDrain }: {
|
||||
entry: {
|
||||
element: string;
|
||||
distance: number;
|
||||
disciplineRate: number;
|
||||
attunementBase: number;
|
||||
pactBase: number;
|
||||
baseRate: number;
|
||||
attunementMult: number;
|
||||
pactMult: number;
|
||||
meditationMult: number;
|
||||
finalRate: number;
|
||||
paused: boolean;
|
||||
pauseReason: string | null;
|
||||
rawCost: number;
|
||||
componentCosts: Record<string, number>;
|
||||
};
|
||||
elementDrain: Record<string, number>;
|
||||
}) {
|
||||
const def = ELEMENTS[entry.element];
|
||||
const effectiveRate = entry.paused ? 0 : entry.finalRate;
|
||||
const rawDrain = effectiveRate * entry.rawCost;
|
||||
const isComponentDrained = Object.keys(entry.componentCosts).length > 0 &&
|
||||
Object.keys(elementDrain).length > 0;
|
||||
|
||||
return (
|
||||
<div className="p-2 rounded text-xs" style={{ border: `1px solid ${def?.color}20`, background: 'var(--bg-sunken)/30' }}>
|
||||
<div className="flex items-center gap-1 mb-1" style={{ color: def?.color }}>
|
||||
@@ -144,6 +169,7 @@ function ConversionRow({ entry }: { entry: { element: string; distance: number;
|
||||
<span style={{ color: 'var(--text-muted)' }}>(d={entry.distance})</span>
|
||||
{entry.paused && <span style={{ color: 'var(--color-error)' }}>⏸️ PAUSED</span>}
|
||||
</div>
|
||||
{/* Rate breakdown */}
|
||||
<div className="grid grid-cols-2 gap-x-4 gap-y-0.5" style={{ color: 'var(--text-muted)' }}>
|
||||
<div>Discipline: <span style={{ color: 'var(--color-success)' }}>+{fmtDec(entry.disciplineRate, 2)}/hr</span></div>
|
||||
<div>Attunement: <span style={{ color: 'var(--color-success)' }}>+{fmtDec(entry.attunementBase, 2)}/hr</span></div>
|
||||
@@ -154,6 +180,32 @@ function ConversionRow({ entry }: { entry: { element: string; distance: number;
|
||||
<div>Med mult: <span>×{fmtDec(entry.meditationMult, 2)}</span></div>
|
||||
<div>Final: <span style={{ color: entry.paused ? 'var(--color-error)' : 'var(--color-success)' }}>{entry.paused ? '0.00' : fmtDec(entry.finalRate, 2)}/hr</span></div>
|
||||
</div>
|
||||
{/* Cost breakdown (per spec §11) */}
|
||||
{!entry.paused && effectiveRate > 0 && (
|
||||
<div className="mt-1.5 pt-1.5 border-t border-[var(--border-subtle)]">
|
||||
<div className="mb-0.5" style={{ color: 'var(--text-muted)' }}>Costs (deducted from regen):</div>
|
||||
<div className="grid grid-cols-2 gap-x-4 gap-y-0.5" style={{ color: 'var(--text-muted)' }}>
|
||||
<div>Raw: <span style={{ color: 'var(--color-warning)' }}>-{fmtDec(rawDrain, 2)} raw/hr</span> <span style={{ color: 'var(--text-muted)' }}>({entry.rawCost} × {fmtDec(effectiveRate, 2)})</span></div>
|
||||
{Object.entries(entry.componentCosts).map(([comp, cost]) => {
|
||||
const compDrain = effectiveRate * cost;
|
||||
const compDef = ELEMENTS[comp];
|
||||
return (
|
||||
<div key={comp}>
|
||||
<span style={{ color: compDef?.color }}>{compDef?.sym} {comp}:</span>{' '}
|
||||
<span style={{ color: 'var(--color-warning)' }}>-{fmtDec(compDrain, 2)}/hr</span>{' '}
|
||||
<span style={{ color: 'var(--text-muted)' }}>({cost} × {fmtDec(effectiveRate, 2)})</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{/* Downstream drain (this element consumed by higher conversions) */}
|
||||
{isComponentDrained && elementDrain[entry.element] > 0 && (
|
||||
<div className="mt-1" style={{ color: 'var(--color-warning)' }}>
|
||||
↓ Drained by downstream: -{fmtDec(elementDrain[entry.element], 2)} {def?.name}/hr
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{entry.paused && entry.pauseReason && (
|
||||
<div className="mt-1" style={{ color: 'var(--color-error)' }}>⚠️ {entry.pauseReason}</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user