Add floor navigation system with up/down direction and respawn mechanics
- Added climbDirection state to track player movement direction - Added clearedFloors tracking for floor respawn system - Players can now manually navigate between floors using ascend/descend buttons - Floors respawn when player leaves and returns (for loot farming) - Enhanced LootInventory component with: - Full inventory management (materials, essence, equipment) - Search and filter functionality - Sorting by name, rarity, or count - Delete functionality with confirmation dialog - Added updateLootInventory function to store - Blueprints are now shown as permanent unlocks in inventory - Floor navigation UI shows direction toggle and respawn indicators
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
import type { GameState, GameAction, StudyTarget, SpellCost, SkillUpgradeChoice, EquipmentSlot, EquipmentInstance, EnchantmentDesign, DesignEffect } from './types';
|
||||
import type { GameState, GameAction, StudyTarget, SpellCost, SkillUpgradeChoice, EquipmentSlot, EquipmentInstance, EnchantmentDesign, DesignEffect, LootInventory } from './types';
|
||||
import {
|
||||
ELEMENTS,
|
||||
GUARDIANS,
|
||||
@@ -490,6 +490,11 @@ function makeInitial(overrides: Partial<GameState> = {}): GameState {
|
||||
activeSpell: 'manaBolt',
|
||||
currentAction: 'meditate',
|
||||
castProgress: 0,
|
||||
|
||||
// Floor Navigation
|
||||
climbDirection: 'up',
|
||||
clearedFloors: {},
|
||||
lastClearedFloor: null,
|
||||
|
||||
spells: startSpells,
|
||||
skills: overrides.skills || {},
|
||||
@@ -602,6 +607,13 @@ interface GameStore extends GameState, CraftingActions, FamiliarActions {
|
||||
commitSkillUpgrades: (skillId: string, upgradeIds: string[]) => void;
|
||||
tierUpSkill: (skillId: string) => void;
|
||||
|
||||
// Floor Navigation
|
||||
setClimbDirection: (direction: 'up' | 'down') => void;
|
||||
changeFloor: (direction: 'up' | 'down') => void;
|
||||
|
||||
// Inventory Management
|
||||
updateLootInventory: (inventory: LootInventory) => void;
|
||||
|
||||
// Computed getters
|
||||
getMaxMana: () => number;
|
||||
getRegen: () => number;
|
||||
@@ -967,6 +979,12 @@ export const useGameStore = create<GameStore>()(
|
||||
if (floorHP <= 0) {
|
||||
// Floor cleared
|
||||
const wasGuardian = GUARDIANS[currentFloor];
|
||||
const clearedFloors = state.clearedFloors;
|
||||
const climbDirection = state.climbDirection;
|
||||
|
||||
// Mark this floor as cleared (needs respawn if we leave and return)
|
||||
clearedFloors[currentFloor] = true;
|
||||
const lastClearedFloor = currentFloor;
|
||||
|
||||
// ─── Loot Drop System ───
|
||||
const lootDrops = rollLootDrops(currentFloor, !!wasGuardian, 0);
|
||||
@@ -1003,11 +1021,22 @@ export const useGameStore = create<GameStore>()(
|
||||
}
|
||||
}
|
||||
|
||||
currentFloor = currentFloor + 1;
|
||||
if (currentFloor > 100) {
|
||||
currentFloor = 100;
|
||||
}
|
||||
// Move to next floor based on direction
|
||||
const nextFloor = climbDirection === 'up'
|
||||
? Math.min(currentFloor + 1, 100)
|
||||
: Math.max(currentFloor - 1, 1);
|
||||
|
||||
currentFloor = nextFloor;
|
||||
floorMaxHP = getFloorMaxHP(currentFloor);
|
||||
|
||||
// Check if this floor was previously cleared (has enemies respawned?)
|
||||
// Floors respawn when you leave them and come back
|
||||
const floorWasCleared = clearedFloors[currentFloor];
|
||||
if (floorWasCleared) {
|
||||
// Floor has respawned - reset it but mark as uncleared
|
||||
delete clearedFloors[currentFloor];
|
||||
}
|
||||
|
||||
floorHP = floorMaxHP;
|
||||
maxFloorReached = Math.max(maxFloorReached, currentFloor);
|
||||
|
||||
@@ -1019,6 +1048,10 @@ export const useGameStore = create<GameStore>()(
|
||||
// Reset ALL spell progress on floor change
|
||||
equipmentSpellStates = equipmentSpellStates.map(s => ({ ...s, castProgress: 0 }));
|
||||
spellState = { ...spellState, castProgress: 0 };
|
||||
|
||||
// Update clearedFloors in the state
|
||||
set((s) => ({ ...s, clearedFloors, lastClearedFloor }));
|
||||
|
||||
break; // Exit the while loop - new floor
|
||||
}
|
||||
}
|
||||
@@ -1637,6 +1670,10 @@ export const useGameStore = create<GameStore>()(
|
||||
});
|
||||
},
|
||||
|
||||
updateLootInventory: (inventory: LootInventory) => {
|
||||
set({ lootInventory: inventory });
|
||||
},
|
||||
|
||||
startDesigningEnchantment: (name: string, equipmentTypeId: string, effects: DesignEffect[]) => {
|
||||
const state = get();
|
||||
|
||||
@@ -1874,6 +1911,47 @@ export const useGameStore = create<GameStore>()(
|
||||
if (!instance) return 0;
|
||||
return instance.totalCapacity - instance.usedCapacity;
|
||||
},
|
||||
|
||||
// ─── Floor Navigation ────────────────────────────────────────────────────────
|
||||
|
||||
setClimbDirection: (direction: 'up' | 'down') => {
|
||||
set({ climbDirection: direction });
|
||||
},
|
||||
|
||||
changeFloor: (direction: 'up' | 'down') => {
|
||||
const state = get();
|
||||
const currentFloor = state.currentFloor;
|
||||
|
||||
// Calculate next floor
|
||||
const nextFloor = direction === 'up'
|
||||
? Math.min(currentFloor + 1, 100)
|
||||
: Math.max(currentFloor - 1, 1);
|
||||
|
||||
// Can't stay on same floor
|
||||
if (nextFloor === currentFloor) return;
|
||||
|
||||
// Mark current floor as cleared (it will respawn when we come back)
|
||||
const clearedFloors = { ...state.clearedFloors };
|
||||
clearedFloors[currentFloor] = true;
|
||||
|
||||
// Check if next floor was cleared (needs respawn)
|
||||
const nextFloorCleared = clearedFloors[nextFloor];
|
||||
if (nextFloorCleared) {
|
||||
// Respawn the floor
|
||||
delete clearedFloors[nextFloor];
|
||||
}
|
||||
|
||||
set({
|
||||
currentFloor: nextFloor,
|
||||
floorMaxHP: getFloorMaxHP(nextFloor),
|
||||
floorHP: getFloorMaxHP(nextFloor),
|
||||
maxFloorReached: Math.max(state.maxFloorReached, nextFloor),
|
||||
clearedFloors,
|
||||
climbDirection: direction,
|
||||
equipmentSpellStates: state.equipmentSpellStates.map(s => ({ ...s, castProgress: 0 })),
|
||||
log: [`🚶 Moved to floor ${nextFloor}${nextFloorCleared ? ' (respawned)' : ''}.`, ...state.log.slice(0, 49)],
|
||||
});
|
||||
},
|
||||
}),
|
||||
{
|
||||
name: 'mana-loop-storage',
|
||||
@@ -1908,6 +1986,9 @@ export const useGameStore = create<GameStore>()(
|
||||
activeSpell: state.activeSpell,
|
||||
currentAction: state.currentAction,
|
||||
castProgress: state.castProgress,
|
||||
climbDirection: state.climbDirection,
|
||||
clearedFloors: state.clearedFloors,
|
||||
lastClearedFloor: state.lastClearedFloor,
|
||||
spells: state.spells,
|
||||
skills: state.skills,
|
||||
skillProgress: state.skillProgress,
|
||||
@@ -1928,6 +2009,19 @@ export const useGameStore = create<GameStore>()(
|
||||
designProgress: state.designProgress,
|
||||
preparationProgress: state.preparationProgress,
|
||||
applicationProgress: state.applicationProgress,
|
||||
// Loot system
|
||||
lootInventory: state.lootInventory,
|
||||
lootDropsToday: state.lootDropsToday,
|
||||
// Achievements
|
||||
achievements: state.achievements,
|
||||
totalDamageDealt: state.totalDamageDealt,
|
||||
totalSpellsCast: state.totalSpellsCast,
|
||||
totalCraftsCompleted: state.totalCraftsCompleted,
|
||||
// Familiars
|
||||
familiars: state.familiars,
|
||||
activeFamiliarSlots: state.activeFamiliarSlots,
|
||||
familiarSummonProgress: state.familiarSummonProgress,
|
||||
totalFamiliarXpEarned: state.totalFamiliarXpEarned,
|
||||
}),
|
||||
}
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user