fix: resolve 22 remaining issues - type exports, dead code, state mutations, orphaned components
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m19s

This commit is contained in:
2026-05-18 21:03:43 +02:00
parent a9918e83a6
commit c3a5f333da
31 changed files with 108 additions and 1519 deletions
@@ -45,7 +45,7 @@ export function equipItem(
const instance = state.equipmentInstances[instanceId];
if (!instance) return false;
if (!CraftingUtils.canEquipInSlot(instance, slot, state.equippedInstances)) {
if (!CraftingUtils.canEquipInSlot(instance, slot, state.equippedInstances, state.equipmentInstances)) {
return false;
}
+4 -2
View File
@@ -123,7 +123,8 @@ export function refundCraftMaterials(recipe: CraftingRecipe, refundRate: number
export function canEquipInSlot(
instance: EquipmentInstance,
slot: EquipmentSlot,
currentlyEquipped: Record<EquipmentSlot, string | null>
currentlyEquipped: Record<EquipmentSlot, string | null>,
instances: Record<string, EquipmentInstance> = {},
): boolean {
const type = EQUIPMENT_TYPES[instance.typeId];
if (!type) return false;
@@ -145,7 +146,8 @@ export function canEquipInSlot(
}
if (slot === 'offHand' && currentlyEquipped.mainHand) {
const mainHandType = EQUIPMENT_TYPES[currentlyEquipped.mainHand];
const mainHandInstance = instances[currentlyEquipped.mainHand];
const mainHandType = mainHandInstance ? EQUIPMENT_TYPES[mainHandInstance.typeId] : undefined;
if (mainHandType?.twoHanded) {
return false;
}
@@ -1,34 +0,0 @@
type DisciplineDefinition = {
name: string;
attunement: DisciplinesAttunementType;
manaType: ManaType;
baseCost: number;
description: string;
requires?: DisciplineDefinition[];
};
enum DisciplinesAttunementType {
base,
enchanter,
fabricator,
invoker
};
export const baseDisciplines: DisciplineDefinition[] = [
{
name: "Embercraft",
attunement: DisciplinesAttunementType.base,
manaType: "fire",
baseCost: 10,
description: "Basic flame projection with autocrit on combustion explosion",
requires: []
},
{
name: "Earthbind",
attunement: DisciplinesAttunementType.base,
manaType: "earth",
baseCost: 12,
description: "Basic mana chains with passive ground stability",
requires: []
}
];
@@ -1,34 +0,0 @@
type DisciplineDefinition = {
name: string;
attunement: DisciplinesAttunementType;
manaType: ManaType;
baseCost: number;
description: string;
requires?: DisciplineDefinition[];
};
enum DisciplinesAttunementType {
base,
enchanter,
fabricator,
invoker
};
export const enchanterDisciplines: DisciplineDefinition[] = [
{
name: "Soulforge",
attunement: DisciplinesAttunementType.enchanter,
manaType: "light",
baseCost: 25,
description: "Mana chains that create permanent elemental storage nodes",
requires: [{name: "Embercraft"}]
},
{
name: "Mana Prism",
attunement: DisciplinesAttunementType.enchanter,
manaType: "light",
baseCost: 30,
description: "Prismatic mana focusing that reflexes attacks as fixed ratio",
requires: [{name: "Soulforge"}]
}
];
@@ -1,21 +0,0 @@
import type { DisciplineDefinition } from '../../types/disciplines';
const fabricatorDisciplines: DisciplineDefinition[] = [
{
name: 'Metalworking',
attunement: 'fabricator',
manaType: 'metal',
baseCosts: { mana: 28, time: 7 },
description: 'Increase metal equipment crafting speed',
thresholds: { xp: 140, interval: 70 }
},
{
name: 'Crystal Shaping',
attunement: 'fabricator',
manaType: 'crystal',
baseCosts: { mana: 30, time: 8 },
description: 'Increase crystal equipment durability',
thresholds: { xp: 160, interval: 80 }
}
];
export default fabricatorDisciplines;
@@ -1,21 +0,0 @@
import type { DisciplineDefinition } from '../../types/disciplines';
const invokerDisciplines: DisciplineDefinition[] = [
{
name: 'Lightning Surge',
attunement: 'invoker',
manaType: 'lightning',
baseCost: 30,
description: 'Boost lightning spell damage',
thresholds: { xp: 150, interval: 75 }
},
{
name: 'Void Echo',
attunement: 'invoker',
manaType: 'void',
baseCost: 35,
description: 'Increase void spell cast speed',
thresholds: { xp: 180, interval: 90 }
}
];
export default invokerDisciplines;
+1
View File
@@ -3,6 +3,7 @@
// Import types
import type { EnchantmentEffectCategory, EnchantmentEffectDef } from '../enchantment-types'
import type { EquipmentCategory } from '../equipment'
// Import all category-specific effect collections
import { SPELL_EFFECTS } from './spell-effects'
+9 -11
View File
@@ -1,13 +1,11 @@
// ─── Upgrade Effect Types ────────────────────────────────────────────────────
// Type interfaces for upgrade effects
import type { SkillUpgradeChoice, SkillUpgradeEffect } from './types';
export interface ActiveUpgradeEffect {
upgradeId: string;
skillId: string;
milestone: 5 | 10;
effect: SkillUpgradeEffect;
effect: string;
name: string;
desc: string;
}
@@ -23,7 +21,7 @@ export interface ComputedEffects {
meditationEfficiency: number;
spellCostMultiplier: number;
conversionEfficiency: number;
// Combat effects
baseDamageMultiplier: number;
baseDamageBonus: number;
@@ -31,33 +29,33 @@ export interface ComputedEffects {
critChanceBonus: number;
critDamageMultiplier: number;
elementalDamageMultiplier: number;
// Study effects
studySpeedMultiplier: number;
studyCostMultiplier: number;
progressRetention: number;
instantStudyChance: number;
freeStudyChance: number;
// Element effects
elementCapMultiplier: number;
elementCapBonus: number;
perElementCapBonus: Record<string, number>;
conversionCostMultiplier: number;
doubleCraftChance: number;
// Special values
permanentRegenBonus: number;
// Special effect flags
specials: Set<string>;
// All active upgrades for display
activeUpgrades: ActiveUpgradeEffect[];
// DEEP_UNDERSTANDING: +10% bonus from all skill levels
skillLevelMultiplier: number;
// Enchantment Power
enchantmentPowerMultiplier: number;
}
-4
View File
@@ -51,8 +51,6 @@ export function processCombatTick(
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(
@@ -107,8 +105,6 @@ export function processCombatTick(
const eAfterCost = deductSpellCost(eSpellDef.cost, rawMana, elements);
rawMana = eAfterCost.rawMana;
elements = eAfterCost.elements;
totalManaGathered += eSpellDef.cost.amount;
// Calculate damage
const eFloorElement = getFloorElement(currentFloor);
const eDamage = calcDamage(
+1 -1
View File
@@ -274,7 +274,7 @@ export const useCombatStore = create<CombatState>()(
currentFloor: state.currentFloor,
maxFloorReached: state.maxFloorReached,
spells: state.spells,
activeSpell: state.activeAction,
activeSpell: state.activeSpell,
}),
}
)
+5 -4
View File
@@ -80,9 +80,10 @@ export const useDisciplineStore = create<DisciplineStore>()(
let rawMana = mana.rawMana;
const elements = { ...mana.elements };
let newXP = s.totalXP;
const newDisciplines = { ...s.disciplines };
for (const id of s.activeIds) {
const disc = s.disciplines[id];
const disc = newDisciplines[id];
if (!disc) continue;
if (disc.paused) continue;
@@ -94,7 +95,7 @@ export const useDisciplineStore = create<DisciplineStore>()(
const available = def.manaType === 'raw' ? rawMana : element?.current;
if (!available || available < drain) {
disc.paused = true;
newDisciplines[id] = { ...disc, paused: true };
continue;
}
@@ -104,7 +105,7 @@ export const useDisciplineStore = create<DisciplineStore>()(
elements[def.manaType].current -= drain;
}
disc.xp += 1;
newDisciplines[id] = { ...disc, xp: disc.xp + 1 };
newXP += 1;
}
@@ -114,7 +115,7 @@ export const useDisciplineStore = create<DisciplineStore>()(
);
set({
disciplines: s.disciplines,
disciplines: newDisciplines,
totalXP: newXP,
concurrentLimit: Math.max(s.concurrentLimit, newLimit),
});
+1 -1
View File
@@ -18,7 +18,7 @@ export const createResetGame = (set: (state: any) => void, initialState: any) =>
const startFloor = 1;
useUIStore.getState().resetUI();
useUIStore.getState().reset();
usePrestigeStore.getState().resetPrestige();
useManaStore.getState().resetMana({}, {}, {}, {});
useCombatStore.getState().resetCombat(startFloor);
-1
View File
@@ -206,7 +206,6 @@ export const useGameStore = create<GameCoordinatorStore>()(
// Combat - delegate to combatStore
if (combatState.currentAction === 'climb') {
const combatResult = useCombatStore.getState().processCombatTick(
{},
rawMana,
elements,
maxMana,
+7 -17
View File
@@ -13,7 +13,7 @@ export interface UIState {
paused: boolean;
gameOver: boolean;
victory: boolean;
// Actions
addLog: (message: string) => void;
clearLogs: () => void;
@@ -21,7 +21,6 @@ export interface UIState {
setPaused: (paused: boolean) => void;
setGameOver: (gameOver: boolean, victory?: boolean) => void;
reset: () => void;
resetUI: () => void;
}
const MAX_LOGS = 50;
@@ -31,29 +30,29 @@ export const useUIStore = create<UIState>((set) => ({
paused: false,
gameOver: false,
victory: false,
addLog: (message: string) => {
set((state) => ({
logs: [message, ...state.logs.slice(0, MAX_LOGS - 1)],
}));
},
clearLogs: () => {
set({ logs: [] });
},
togglePause: () => {
set((state) => ({ paused: !state.paused }));
},
setPaused: (paused: boolean) => {
set({ paused });
},
setGameOver: (gameOver: boolean, victory: boolean = false) => {
set({ gameOver, victory });
},
reset: () => {
set({
logs: ['✨ The loop begins. You start with Mana Bolt. Gather your strength, mage.'],
@@ -62,13 +61,4 @@ export const useUIStore = create<UIState>((set) => ({
victory: false,
});
},
resetUI: () => {
set({
logs: ['✨ The loop begins. You start with Mana Bolt. Gather your strength, mage.'],
paused: false,
gameOver: false,
victory: false,
});
},
}));
+2
View File
@@ -2,6 +2,8 @@
export type ElementCategory = 'base' | 'utility' | 'composite' | 'exotic';
export type ManaType = 'raw' | 'fire' | 'water' | 'air' | 'earth' | 'light' | 'dark' | 'death' | 'transference' | 'metal' | 'sand' | 'lightning' | 'crystal' | 'stellar' | 'void';
export interface ElementDef {
name: string;
sym: string;
+18 -1
View File
@@ -43,7 +43,6 @@ export interface EnemyState {
maxHP: number;
armor: number; // Damage reduction (0-1)
dodgeChance: number; // For speed rooms (0-1)
healthRegen?: number; // HP regenerated per tick (0-1 as percentage of max HP)
barrier?: number; // Shield that absorbs damage before HP (0-1 as percentage of max HP)
element: string;
}
@@ -262,6 +261,24 @@ export interface GameState {
// ─── Action Types for Store ─────────────────────────────────────────────
export interface PrestigeDef {
name: string;
desc: string;
max: number;
cost: number;
}
export interface LootDrop {
id: string;
name: string;
rarity: string;
type: string;
minFloor: number;
dropChance: number;
guardianOnly?: boolean;
amount?: { min: number; max: number };
}
export type GameActionType =
| { type: 'TICK' }
| { type: 'GATHER_MANA' }
+3 -1
View File
@@ -3,7 +3,7 @@
// Re-export all types from domain-specific files
// Element types
export type { ElementCategory, ElementDef, ElementState } from './elements';
export type { ElementCategory, ElementDef, ElementState, ManaType } from './elements';
// Attunement types
export type { AttunementSlot, AttunementDef, AttunementState, GuardianBoon, GuardianDef } from './attunements';
@@ -46,4 +46,6 @@ export type {
GameActionType,
ActivityEventType,
ActivityLogEntry,
PrestigeDef,
LootDrop,
} from './game';
+1
View File
@@ -21,6 +21,7 @@ export interface SpellDef {
isAoe?: boolean; // AOE spell that hits multiple enemies
aoeTargets?: number; // Number of enemies hit by AOE
isWeaponEnchant?: boolean; // Can be used as weapon enchantment (magic swords)
grimoire?: boolean; // Whether this spell appears in the grimoire
}
export interface SpellEffect {
-18
View File
@@ -61,20 +61,6 @@ export function getDodgeChance(floor: number): number {
);
}
// Get health regen for an enemy (0-1 as percentage of max HP per tick)
export function getEnemyHealthRegen(floor: number, element: string): number {
// Higher floors have a chance for enemies with health regen
if (floor < 15) return 0;
// Health regen becomes more common on higher floors
const regenChance = Math.min(0.3, (floor - 15) * 0.005); // Max 30% chance
if (Math.random() > regenChance) return 0;
// Scale regen with floor (0.5% to 3% of max HP per tick)
const floorProgress = Math.min(1, (floor - 15) / 85);
return 0.005 + floorProgress * 0.025;
}
// Get barrier for an enemy (0-1 as percentage of max HP)
export function getEnemyBarrier(floor: number, element: string): number {
// Barrier appears on higher floors, more common with certain elements
@@ -110,7 +96,6 @@ export function generateSwarmEnemies(floor: number): EnemyState[] {
maxHP: Math.floor(baseHP * SWARM_CONFIG.hpMultiplier),
armor: SWARM_CONFIG.armorBase + Math.floor(floor / 10) * SWARM_CONFIG.armorPerFloor,
dodgeChance: 0,
healthRegen: getEnemyHealthRegen(floor, element),
barrier: getEnemyBarrier(floor, element),
element,
});
@@ -136,7 +121,6 @@ export function generateFloorState(floor: number): FloorState {
maxHP: guardian.hp,
armor: guardian.armor || 0,
dodgeChance: 0,
healthRegen: 0.01, // Guardians have 1% HP regen per tick
barrier: 0,
element: guardian.element,
}],
@@ -159,7 +143,6 @@ export function generateFloorState(floor: number): FloorState {
maxHP: baseHP,
armor: getFloorArmor(floor),
dodgeChance: getDodgeChance(floor),
healthRegen: getEnemyHealthRegen(floor, element),
barrier: getEnemyBarrier(floor, element),
element,
}],
@@ -192,7 +175,6 @@ export function generateFloorState(floor: number): FloorState {
maxHP: baseHP,
armor: getFloorArmor(floor),
dodgeChance: 0,
healthRegen: getEnemyHealthRegen(floor, element),
barrier: getEnemyBarrier(floor, element),
element,
}],