refactor: split bloated state types into State + Actions interfaces (issue #102)
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m19s

- CombatState: split into CombatState (data) + CombatActions + CombatStore
- PrestigeState: split into PrestigeState (data) + PrestigeActions + PrestigeStore
- ManaState: split into ManaState (data) + ManaActions + ManaStore
- GameState: deprecated, removed from barrel exports
- crafting-actions: updated to use CraftingState instead of GameState
- combat-utils/mana-utils: replaced Pick<GameState,...> with focused interfaces
- DisciplineCardProps: split into Definition + Runtime + Callbacks
- stores/index.ts: now exports both State and Actions types
This commit is contained in:
2026-05-20 21:05:22 +02:00
parent ee893e8973
commit 8a7ddaae27
24 changed files with 411 additions and 321 deletions
+38 -26
View File
@@ -1,6 +1,6 @@
// ─── Mana & Regen Utilities ──────────────────────────────────────────────────
import type { GameState } from '../types';
import type { AttunementState } from '../types';
import type { ComputedEffects } from '../effects/upgrade-effects.types';
import { HOURS_PER_TICK } from '../constants';
import { getTotalAttunementRegen, getTotalAttunementConversionDrain } from '../data/attunements';
@@ -10,8 +10,28 @@ export interface DisciplineBonuses {
multipliers: Record<string, number>;
}
// ─── Mana Params ────────────────────────────────────────────────────────────
export interface ManaComputeParams {
skills: Record<string, number>;
prestigeUpgrades: Record<string, number>;
skillUpgrades?: Record<string, string[]>;
skillTiers?: Record<string, number>;
}
export interface RegenComputeParams extends ManaComputeParams {
attunements: Record<string, AttunementState>;
}
export interface EffectiveRegenParams extends RegenComputeParams {
rawMana: number;
incursionStrength: number;
}
// ─── Max Mana ────────────────────────────────────────────────────────────────
export function computeMaxMana(
state: Pick<GameState, 'skills' | 'prestigeUpgrades' | 'skillUpgrades' | 'skillTiers'>,
state: Pick<ManaComputeParams, 'skills' | 'prestigeUpgrades'> & Partial<Pick<ManaComputeParams, 'skillUpgrades' | 'skillTiers'>>,
effects?: ComputedEffects,
discipline?: DisciplineBonuses,
): number {
@@ -22,17 +42,16 @@ export function computeMaxMana(
((pu || {}).manaWell || 0) * 500 +
(discipline?.bonuses?.maxManaBonus || 0);
// Apply upgrade effects if provided
if (effects) {
return Math.floor((base + effects.maxManaBonus) * effects.maxManaMultiplier);
}
return base;
}
// computeElementMax has been removed — element max is computed in manaStore.ts
// ─── Regen ────────────────────────────────────────────────────────────────────
export function computeRegen(
state: Pick<GameState, 'skills' | 'prestigeUpgrades' | 'skillUpgrades' | 'skillTiers' | 'attunements'>,
state: Pick<RegenComputeParams, 'skills' | 'prestigeUpgrades' | 'attunements'> & Partial<Pick<RegenComputeParams, 'skillUpgrades' | 'skillTiers'>>,
effects?: ComputedEffects,
discipline?: DisciplineBonuses,
): number {
@@ -63,55 +82,48 @@ export function computeRegen(
return regen;
}
// Compute the effective regen (raw regen minus conversion drains) for display purposes
// ─── Effective Regen for Display ──────────────────────────────────────────────
export function computeEffectiveRegenForDisplay(
state: Pick<GameState, 'skills' | 'prestigeUpgrades' | 'skillUpgrades' | 'skillTiers' | 'attunements'>,
state: Pick<RegenComputeParams, 'skills' | 'prestigeUpgrades' | 'attunements'>,
effects?: ComputedEffects,
discipline?: DisciplineBonuses,
): { rawRegen: number; conversionDrain: number; effectiveRegen: number } {
// Get the full raw regen (without conversion drain)
const rawRegen = computeRegen(state, effects, discipline);
// Calculate conversion drain
const conversionDrain = getTotalAttunementConversionDrain(state.attunements || {});
// Effective regen is what actually increases raw mana
const effectiveRegen = Math.max(0, rawRegen - conversionDrain);
return { rawRegen, conversionDrain, effectiveRegen };
}
/**
* Compute regen with dynamic special effects (needs current mana, max mana, incursion)
*/
// ─── Effective Regen (dynamic) ────────────────────────────────────────────────
export function computeEffectiveRegen(
state: Pick<GameState, 'skills' | 'prestigeUpgrades' | 'rawMana' | 'incursionStrength' | 'skillUpgrades' | 'skillTiers' | 'attunements'>,
state: Pick<RegenComputeParams, 'skills' | 'prestigeUpgrades' | 'attunements'> & { rawMana: number; incursionStrength: number },
effects?: ComputedEffects,
discipline?: DisciplineBonuses,
): number {
// Base regen from existing function
let regen = computeRegen(state, effects, discipline);
const incursionStrength = state.incursionStrength || 0;
// Apply incursion penalty
regen *= (1 - incursionStrength);
return regen;
}
// ─── Click Mana ───────────────────────────────────────────────────────────────
export function computeClickMana(
state: Pick<GameState, 'skills'>,
skills: Record<string, number>,
discipline?: DisciplineBonuses,
): number {
const skillTap = ((state.skills || {}).manaTap || 0) * 1;
const skillSurge = ((state.skills || {}).manaSurge || 0) * 3;
const skillTap = (skills.manaTap || 0) * 1;
const skillSurge = (skills.manaSurge || 0) * 3;
const discClickMult = discipline?.bonuses?.clickManaMultiplier || 0;
return 1 + skillTap + skillSurge + discClickMult;
}
// Meditation bonus now affects regen rate directly
// ─── Meditation Bonus ─────────────────────────────────────────────────────────
export function getMeditationBonus(meditateTicks: number, skills: Record<string, number>, meditationEfficiency: number = 1): number {
const hasMeditation = skills.meditation === 1;
const hasDeepTrance = skills.deepTrance === 1;
@@ -137,7 +149,7 @@ export function getMeditationBonus(meditateTicks: number, skills: Record<string,
bonus = 5.0;
}
// Apply meditation efficiency from upgrades (Deep Wellspring, etc.)
// Apply meditation efficiency from upgrades
bonus *= meditationEfficiency;
return bonus;