@@ -29,13 +21,10 @@ export function LabTab({ store }: LabTabProps) {
.filter(([, state]) => state.unlocked)
.map(([id, state]) => {
const def = ELEMENTS[id];
- const isSelected = convertTarget === id;
return (
setConvertTarget(id)}
+ className="p-2 rounded border border-gray-700 bg-gray-800/50"
>
{def?.sym}
{def?.name}
@@ -46,47 +35,6 @@ export function LabTab({ store }: LabTabProps) {
);
- // Render locked elements (can be unlocked)
- const renderLockedElements = () => {
- const lockedElements = Object.entries(store.elements)
- .filter(([, state]) => !state.unlocked)
- .filter(([id]) => !ELEMENTS[id]?.recipe); // Only show base elements (no recipe = base)
-
- if (lockedElements.length === 0) return null;
-
- return (
-
-
- Unlock Elements
-
-
-
- {lockedElements.map(([id, state]) => {
- const def = ELEMENTS[id];
- const canUnlock = store.rawMana >= UNLOCK_COST;
- return (
-
-
- {def?.sym}
- {def?.name}
-
-
-
- );
- })}
-
-
-
- );
- };
-
// Render composite crafting
const renderCompositeCrafting = () => {
const compositeElements = Object.entries(ELEMENTS)
@@ -134,6 +82,21 @@ export function LabTab({ store }: LabTabProps) {
);
};
+ // Check if there are any unlocked elements
+ const hasUnlockedElements = Object.values(store.elements).some(e => e.unlocked);
+
+ if (!hasUnlockedElements) {
+ return (
+
+
+
+ No elemental mana available. Elements are unlocked through gameplay.
+
+
+
+ );
+ }
+
return (
{/* Elemental Mana Display */}
@@ -146,48 +109,6 @@ export function LabTab({ store }: LabTabProps) {
- {/* Element Conversion */}
-
-
- Element Conversion
-
-
-
- Convert raw mana to elemental mana (100:1 ratio)
-
-
-
-
-
-
-
-
-
-
- {/* Unlock Elements */}
- {renderLockedElements()}
-
{/* Composite Crafting */}
{renderCompositeCrafting()}
diff --git a/src/components/game/tabs/SpireTab.tsx b/src/components/game/tabs/SpireTab.tsx
index 9e34fdd..a0a045e 100755
--- a/src/components/game/tabs/SpireTab.tsx
+++ b/src/components/game/tabs/SpireTab.tsx
@@ -8,13 +8,15 @@ import { ScrollArea } from '@/components/ui/scroll-area';
import { Separator } from '@/components/ui/separator';
import { TooltipProvider } from '@/components/ui/tooltip';
import { Swords, BookOpen, ChevronUp, ChevronDown, RotateCcw, X } from 'lucide-react';
-import type { GameState, GameAction, EquipmentSpellState, StudyTarget } from '@/lib/game/types';
+import type { GameStore } from '@/lib/game/types';
import { ELEMENTS, GUARDIANS, SPELLS_DEF, SKILLS_DEF } from '@/lib/game/constants';
-import { fmt, fmtDec, getFloorElement, calcDamage, canAffordSpellCost } from '@/lib/game/store';
+import { fmt, fmtDec, getFloorElement, canAffordSpellCost } from '@/lib/game/store';
import { formatSpellCost, getSpellCostColor, formatStudyTime } from '@/lib/game/formatting';
import { ComboMeter, CraftingProgress, StudyProgress } from '@/components/game';
import { ENCHANTMENT_EFFECTS } from '@/lib/game/data/enchantment-effects';
import { EQUIPMENT_TYPES } from '@/lib/game/data/equipment';
+import { getUnifiedEffects } from '@/lib/game/effects';
+import { getTotalDPS } from '@/lib/game/store';
// Helper to get active spells from equipped caster weapons
function getActiveEquipmentSpells(
@@ -49,30 +51,10 @@ function getActiveEquipmentSpells(
}
interface SpireTabProps {
- store: GameState & {
- setAction: (action: GameAction) => void;
- setSpell: (spellId: string) => void;
- cancelStudy: () => void;
- cancelParallelStudy: () => void;
- setClimbDirection: (direction: 'up' | 'down') => void;
- changeFloor: (direction: 'up' | 'down') => void;
- cancelDesign?: () => void;
- cancelPreparation?: () => void;
- pauseApplication?: () => void;
- resumeApplication?: () => void;
- cancelApplication?: () => void;
- };
- totalDPS: number;
- studySpeedMult: number;
- incursionStrength: number;
+ store: GameStore;
}
-export function SpireTab({
- store,
- totalDPS,
- studySpeedMult,
- incursionStrength,
-}: SpireTabProps) {
+export function SpireTab({ store }: SpireTabProps) {
const floorElem = getFloorElement(store.currentFloor);
const floorElemDef = ELEMENTS[floorElem];
const isGuardianFloor = !!GUARDIANS[store.currentFloor];
@@ -82,9 +64,14 @@ export function SpireTab({
// Check if current floor is cleared (for respawn indicator)
const isFloorCleared = clearedFloors[store.currentFloor];
-
+
// Get active equipment spells
const activeEquipmentSpells = getActiveEquipmentSpells(store.equippedInstances, store.equipmentInstances);
+
+ // Get upgrade effects and DPS
+ const upgradeEffects = getUnifiedEffects(store);
+ const totalDPS = getTotalDPS(store, upgradeEffects, floorElem);
+ const studySpeedMult = 1; // Base study speed
const canCastSpell = (spellId: string): boolean => {
const spell = SPELLS_DEF[spellId];
@@ -140,59 +127,28 @@ export function SpireTab({
- {/* Floor Navigation Controls */}
+ {/* Floor Navigation - Direction indicator only */}
-
Auto-Direction
+
Direction
-
-
+
-
-
-
-
-
{isFloorCleared && (
- Floor will respawn when you leave and return
+ Floor cleared! Advancing...
)}
@@ -239,7 +195,7 @@ export function SpireTab({
- ⚔️ {fmt(calcDamage(store, spellId, floorElem))} dmg •
+ ⚔️ {fmt(totalDPS)} DPS •
{' '}{formatSpellCost(spellDef.cost)}
@@ -273,16 +229,7 @@ export function SpireTab({
})}
) : (
- No spells on equipped weapons. Enchant a staff with spell effects.
- )}
-
- {incursionStrength > 0 && (
- No spells on equipped weapons. Enchant a staff with spell effects in the Crafting tab.
)}
@@ -316,7 +263,7 @@ export function SpireTab({
variant="ghost"
size="sm"
className="h-6 w-6 p-0 text-gray-400 hover:text-white"
- onClick={() => store.cancelParallelStudy()}
+ onClick={() => store.cancelParallelStudy?.()}
>