ca86b6268c
Build and Publish Mana Loop Docker Image / build-and-publish (push) Failing after 55s
- Fix broken barrel exports in components/game/index.ts - Remove skill system from stores (gameStore, gameActions, gameLoopActions, gameHooks, craftingStore, combat) - Remove skill system from components (page.tsx, LeftPanel, StatsTab, SpellsTab, EnchantmentDesigner, EnchantmentPreparer, GameContext/Provider) - Delete dead code: stats/ directory, attunements/ directory, layout/ Header+TabBar, shared/ StudyProgress+UpgradeDialog duplicates, effects.ts.fix, study-slice.ts, navigation-slice.ts - Delete legacy store/ and store-modules/ directories, redirect remaining callers - Merge root formatting.ts into utils/formatting.ts - Move effects files (dynamic-compute, upgrade-effects, special-effects, upgrade-effects.types) into effects/ directory - Move debug-context.tsx into components/game/debug/ - Create tabs/index.ts barrel for tab components - Fix page.tsx lazy imports to use tabs barrel - Fix all broken import paths across codebase - Remove SKILLS_DEF and skill-evolution references - Trim store.ts to under 400 lines by removing dead skill actions
257 lines
8.6 KiB
TypeScript
257 lines
8.6 KiB
TypeScript
'use client';
|
|
|
|
import { useMemo, type ReactNode } from 'react';
|
|
import { useManaStore } from '@/lib/game/stores/manaStore';
|
|
import { usePrestigeStore } from '@/lib/game/stores/prestigeStore';
|
|
import { useUIStore } from '@/lib/game/stores/uiStore';
|
|
import { useCombatStore } from '@/lib/game/stores/combatStore';
|
|
import { useGameStore } from '@/lib/game/stores/gameStore';
|
|
import { computeEffects } from '@/lib/game/effects/upgrade-effects';
|
|
import { hasSpecial, SPECIAL_EFFECTS } from '@/lib/game/effects/special-effects';
|
|
import {
|
|
computeMaxMana,
|
|
computeRegen,
|
|
computeClickMana,
|
|
getMeditationBonus,
|
|
canAffordSpellCost,
|
|
calcDamage,
|
|
getFloorElement,
|
|
getBoonBonuses,
|
|
getIncursionStrength,
|
|
} from '@/lib/game/utils';
|
|
import {
|
|
ELEMENTS,
|
|
GUARDIANS,
|
|
SPELLS_DEF,
|
|
} from '@/lib/game/constants';
|
|
import type { ElementDef, GuardianDef, SpellDef, GameAction } from '@/lib/game/types';
|
|
import type { UnifiedStore, GameContextValue } from './types';
|
|
import { GameContext } from './context-create';
|
|
|
|
function createUnifiedStore(
|
|
gameStore: ReturnType<typeof useGameStore.getState>,
|
|
manaState: ReturnType<typeof useManaStore.getState>,
|
|
prestigeState: ReturnType<typeof usePrestigeStore.getState>,
|
|
uiState: ReturnType<typeof useUIStore.getState>,
|
|
combatState: ReturnType<typeof useCombatStore.getState>
|
|
): UnifiedStore {
|
|
return {
|
|
// From gameStore
|
|
day: gameStore.day,
|
|
hour: gameStore.hour,
|
|
incursionStrength: gameStore.incursionStrength,
|
|
containmentWards: gameStore.containmentWards,
|
|
initialized: gameStore.initialized,
|
|
tick: gameStore.tick,
|
|
resetGame: gameStore.resetGame,
|
|
gatherMana: gameStore.gatherMana,
|
|
startNewLoop: gameStore.startNewLoop,
|
|
|
|
// From manaStore
|
|
rawMana: manaState.rawMana,
|
|
meditateTicks: manaState.meditateTicks,
|
|
totalManaGathered: manaState.totalManaGathered,
|
|
elements: manaState.elements,
|
|
setRawMana: manaState.setRawMana,
|
|
addRawMana: manaState.addRawMana,
|
|
spendRawMana: manaState.spendRawMana,
|
|
convertMana: manaState.convertMana,
|
|
unlockElement: manaState.unlockElement,
|
|
craftComposite: manaState.craftComposite,
|
|
|
|
// From prestigeStore
|
|
loopCount: prestigeState.loopCount,
|
|
insight: prestigeState.insight,
|
|
totalInsight: prestigeState.totalInsight,
|
|
loopInsight: prestigeState.loopInsight,
|
|
prestigeUpgrades: prestigeState.prestigeUpgrades,
|
|
memorySlots: prestigeState.memorySlots,
|
|
pactSlots: prestigeState.pactSlots,
|
|
memories: prestigeState.memories,
|
|
defeatedGuardians: prestigeState.defeatedGuardians,
|
|
signedPacts: prestigeState.signedPacts,
|
|
pactRitualFloor: prestigeState.pactRitualFloor,
|
|
pactRitualProgress: prestigeState.pactRitualProgress,
|
|
doPrestige: prestigeState.doPrestige,
|
|
addMemory: prestigeState.addMemory,
|
|
removeMemory: prestigeState.removeMemory,
|
|
clearMemories: prestigeState.clearMemories,
|
|
startPactRitual: prestigeState.startPactRitual,
|
|
cancelPactRitual: prestigeState.cancelPactRitual,
|
|
removePact: prestigeState.removePact,
|
|
defeatGuardian: prestigeState.defeatGuardian,
|
|
|
|
// From combatStore
|
|
currentFloor: combatState.currentFloor,
|
|
floorHP: combatState.floorHP,
|
|
floorMaxHP: combatState.floorMaxHP,
|
|
maxFloorReached: combatState.maxFloorReached,
|
|
activeSpell: combatState.activeSpell,
|
|
currentAction: combatState.currentAction,
|
|
castProgress: combatState.castProgress,
|
|
spells: combatState.spells,
|
|
setAction: combatState.setAction,
|
|
setSpell: combatState.setSpell,
|
|
learnSpell: combatState.learnSpell,
|
|
advanceFloor: combatState.advanceFloor,
|
|
|
|
// From uiStore
|
|
log: uiState.logs,
|
|
paused: uiState.paused,
|
|
gameOver: uiState.gameOver,
|
|
victory: uiState.victory,
|
|
addLog: uiState.addLog,
|
|
togglePause: uiState.togglePause,
|
|
setPaused: uiState.setPaused,
|
|
setGameOver: uiState.setGameOver,
|
|
};
|
|
}
|
|
|
|
export function GameProvider({ children }: { children: ReactNode }) {
|
|
// Get all individual stores
|
|
const gameStore = useGameStore();
|
|
const manaState = useManaStore();
|
|
const prestigeState = usePrestigeStore();
|
|
const uiState = useUIStore();
|
|
const combatState = useCombatStore();
|
|
|
|
// Create unified store object for backward compatibility
|
|
const unifiedStore = useMemo(
|
|
() => createUnifiedStore(gameStore, manaState, prestigeState, uiState, combatState),
|
|
[gameStore, manaState, prestigeState, uiState, combatState]
|
|
);
|
|
|
|
// Computed effects from upgrades
|
|
const upgradeEffects = useMemo(
|
|
() => computeEffects({}, {}),
|
|
[]
|
|
);
|
|
|
|
// Create a minimal state object for compute functions
|
|
const stateForCompute = useMemo(() => ({
|
|
prestigeUpgrades: prestigeState.prestigeUpgrades,
|
|
signedPacts: prestigeState.signedPacts,
|
|
rawMana: manaState.rawMana,
|
|
meditateTicks: manaState.meditateTicks,
|
|
incursionStrength: gameStore.incursionStrength,
|
|
}), [prestigeState, manaState, gameStore.incursionStrength]);
|
|
|
|
// Derived stats
|
|
const maxMana = useMemo(
|
|
() => computeMaxMana(stateForCompute, upgradeEffects),
|
|
[stateForCompute, upgradeEffects]
|
|
);
|
|
|
|
const baseRegen = useMemo(
|
|
() => computeRegen(stateForCompute, upgradeEffects),
|
|
[stateForCompute, upgradeEffects]
|
|
);
|
|
|
|
const clickMana = useMemo(() => computeClickMana(stateForCompute), [stateForCompute]);
|
|
|
|
// Floor element from combat store
|
|
const floorElem = useMemo(() => getFloorElement(combatState.currentFloor), [combatState.currentFloor]);
|
|
const floorElemDef = ELEMENTS[floorElem];
|
|
const isGuardianFloor = !!GUARDIANS[combatState.currentFloor];
|
|
const currentGuardian = GUARDIANS[combatState.currentFloor];
|
|
const activeSpellDef = SPELLS_DEF[combatState.activeSpell];
|
|
|
|
const meditationMultiplier = useMemo(
|
|
() => getMeditationBonus(manaState.meditateTicks, {}, upgradeEffects.meditationEfficiency),
|
|
[manaState.meditateTicks, upgradeEffects.meditationEfficiency]
|
|
);
|
|
|
|
const incursionStrength = useMemo(
|
|
() => getIncursionStrength(gameStore.day, gameStore.hour),
|
|
[gameStore.day, gameStore.hour]
|
|
);
|
|
|
|
const studySpeedMult = 1;
|
|
|
|
const studyCostMult = 1;
|
|
|
|
// Effective regen calculations
|
|
const effectiveRegenWithSpecials = baseRegen * (1 - incursionStrength);
|
|
|
|
const manaCascadeBonus = hasSpecial(upgradeEffects, SPECIAL_EFFECTS.MANA_CASCADE)
|
|
? Math.floor(maxMana / 100) * 0.1
|
|
: 0;
|
|
|
|
const manaWaterfallBonus = hasSpecial(upgradeEffects, SPECIAL_EFFECTS.MANA_WATERFALL)
|
|
? Math.floor(maxMana / 100) * 0.25
|
|
: 0;
|
|
|
|
const effectiveRegen = (effectiveRegenWithSpecials + manaCascadeBonus + manaWaterfallBonus) * meditationMultiplier;
|
|
|
|
// Has special flags for UI
|
|
const hasManaWaterfall = hasSpecial(upgradeEffects, SPECIAL_EFFECTS.MANA_WATERFALL);
|
|
const hasFlowSurge = hasSpecial(upgradeEffects, SPECIAL_EFFECTS.FLOW_SURGE);
|
|
const hasManaOverflow = hasSpecial(upgradeEffects, SPECIAL_EFFECTS.MANA_OVERFLOW);
|
|
const hasEternalFlow = hasSpecial(upgradeEffects, SPECIAL_EFFECTS.ETERNAL_FLOW);
|
|
|
|
// Active boons
|
|
const activeBoons = useMemo(
|
|
() => getBoonBonuses(prestigeState.signedPacts),
|
|
[prestigeState.signedPacts]
|
|
);
|
|
|
|
// DPS calculation - based on active spell, attack speed, and damage
|
|
const dps = useMemo(() => {
|
|
if (!activeSpellDef) return 0;
|
|
const baseDmg = calcDamage(
|
|
{ signedPacts: prestigeState.signedPacts },
|
|
combatState.activeSpell,
|
|
floorElem
|
|
);
|
|
const dmgWithEffects = baseDmg * upgradeEffects.baseDamageMultiplier + upgradeEffects.baseDamageBonus;
|
|
const attackSpeed = (1 + 0 * 0.05) * upgradeEffects.attackSpeedMultiplier;
|
|
const castSpeed = activeSpellDef.castSpeed || 1;
|
|
return dmgWithEffects * attackSpeed * castSpeed;
|
|
}, [activeSpellDef, prestigeState.signedPacts, floorElem, upgradeEffects, combatState.activeSpell]);
|
|
|
|
// Helper functions
|
|
const canCastSpell = (spellId: string): boolean => {
|
|
const spell = SPELLS_DEF[spellId];
|
|
if (!spell) return false;
|
|
return canAffordSpellCost(spell.cost, manaState.rawMana, manaState.elements);
|
|
};
|
|
|
|
const value: GameContextValue = {
|
|
store: unifiedStore,
|
|
manaStore: manaState,
|
|
prestigeStore: prestigeState,
|
|
uiStore: uiState,
|
|
combatStore: combatState,
|
|
upgradeEffects,
|
|
maxMana,
|
|
baseRegen,
|
|
clickMana,
|
|
floorElem,
|
|
floorElemDef,
|
|
isGuardianFloor,
|
|
currentGuardian,
|
|
activeSpellDef,
|
|
meditationMultiplier,
|
|
incursionStrength,
|
|
studySpeedMult,
|
|
studyCostMult,
|
|
effectiveRegenWithSpecials,
|
|
manaCascadeBonus,
|
|
manaWaterfallBonus,
|
|
effectiveRegen,
|
|
hasManaWaterfall,
|
|
hasFlowSurge,
|
|
hasManaOverflow,
|
|
hasEternalFlow,
|
|
dps,
|
|
activeBoons,
|
|
canCastSpell,
|
|
hasSpecial,
|
|
SPECIAL_EFFECTS,
|
|
};
|
|
|
|
return <GameContext.Provider value={value}>{children}</GameContext.Provider>;
|
|
}
|
|
|
|
GameProvider.displayName = "GameProvider";
|