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
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m19s
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -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'
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -274,7 +274,7 @@ export const useCombatStore = create<CombatState>()(
|
||||
currentFloor: state.currentFloor,
|
||||
maxFloorReached: state.maxFloorReached,
|
||||
spells: state.spells,
|
||||
activeSpell: state.activeAction,
|
||||
activeSpell: state.activeSpell,
|
||||
}),
|
||||
}
|
||||
)
|
||||
|
||||
@@ -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),
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,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;
|
||||
|
||||
@@ -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,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';
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
}],
|
||||
|
||||
Reference in New Issue
Block a user