fix: migrate golemancy/activity/achievements, fix CraftingTab/SkillsTab/SpireTab/GolemancyTab/AchievementsTab store reads
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 2m1s

This commit is contained in:
Refactoring Agent
2026-05-05 16:11:28 +02:00
parent ed616738fd
commit ed69a8f2b4
9 changed files with 352 additions and 140 deletions
+117
View File
@@ -0,0 +1,117 @@
// ─── Combat Actions ─────────────────────────────────────────────────────────────
// Extracted combat logic from combatStore.ts
import { SPELLS_DEF, GUARDIANS, HOURS_PER_TICK } from '../constants';
import type { CombatState } from './combatStore';
import type { SpellState } from '../types';
import { getFloorMaxHP, getFloorElement, calcDamage, canAffordSpellCost, deductSpellCost } from '../utils';
import { usePrestigeStore } from './prestigeStore';
export function processCombatTick(
get: () => CombatState,
set: (state: Partial<CombatState>) => void,
skills: Record<string, number>,
rawMana: number,
elements: Record<string, { current: number; max: number; unlocked: boolean }>,
maxMana: number,
attackSpeedMult: number,
onFloorCleared: (floor: number, wasGuardian: boolean) => void,
onDamageDealt: (damage: number) => {
rawMana: number;
elements: Record<string, { current: number; max: number; unlocked: boolean }>;
modifiedDamage?: number;
},
) {
const state = get();
const logMessages: string[] = [];
let totalManaGathered = 0;
if (state.currentAction !== 'climb') {
return { rawMana, elements, logMessages, totalManaGathered };
}
const spellId = state.activeSpell;
const spellDef = SPELLS_DEF[spellId];
if (!spellDef) {
return { rawMana, elements, logMessages, totalManaGathered };
}
// Calculate cast speed
const baseAttackSpeed = 1 + (skills.quickCast || 0) * 0.05;
const totalAttackSpeed = baseAttackSpeed * attackSpeedMult;
const spellCastSpeed = spellDef.castSpeed || 1;
const progressPerTick = HOURS_PER_TICK * spellCastSpeed * totalAttackSpeed;
let castProgress = (state.castProgress || 0) + progressPerTick;
let floorHP = state.floorHP;
let currentFloor = state.currentFloor;
let floorMaxHP = state.floorMaxHP;
// Process complete casts
while (castProgress >= 1 && canAffordSpellCost(spellDef.cost, rawMana, elements)) {
// Deduct spell cost
const afterCost = deductSpellCost(spellDef.cost, rawMana, elements);
rawMana = afterCost.rawMana;
elements = afterCost.elements;
totalManaGathered += spellDef.cost.amount;
// Calculate base damage
const floorElement = getFloorElement(currentFloor);
const damage = calcDamage(
{ skills, signedPacts: usePrestigeStore.getState().signedPacts },
spellId,
floorElement,
);
// Let gameStore apply damage modifiers (executioner, berserker, spell echo)
const result = onDamageDealt(damage);
rawMana = result.rawMana;
elements = result.elements;
const finalDamage = result.modifiedDamage || damage;
// Apply damage
floorHP = Math.max(0, floorHP - finalDamage);
castProgress -= 1;
// Check if floor is cleared
if (floorHP <= 0) {
const wasGuardian = GUARDIANS[currentFloor];
onFloorCleared(currentFloor, !!wasGuardian);
currentFloor = Math.min(currentFloor + 1, 100);
floorMaxHP = getFloorMaxHP(currentFloor);
floorHP = floorMaxHP;
castProgress = 0;
if (wasGuardian) {
logMessages.push(`⚔️ ${wasGuardian.name} defeated!`);
} else if (currentFloor % 5 === 0) {
logMessages.push(`🏰 Floor ${currentFloor - 1} cleared!`);
}
}
}
set({
currentFloor,
floorHP,
floorMaxHP: getFloorMaxHP(currentFloor),
maxFloorReached: Math.max(state.maxFloorReached, currentFloor),
castProgress,
});
return { rawMana, elements, logMessages, totalManaGathered };
}
// Helper function to create initial spells
export function makeInitialSpells(spellsToKeep: string[] = []): Record<string, SpellState> {
const startSpells: Record<string, SpellState> = {
manaBolt: { learned: true, level: 1, studyProgress: 0 },
};
// Add kept spells
for (const spellId of spellsToKeep) {
startSpells[spellId] = { learned: true, level: 1, studyProgress: 0 };
}
return startSpells;
}